Fix more -Wstrict-prototypes warnings.
[wine] / dlls / ddraw / surface_main.c
1 /*              DirectDrawSurface base implementation
2  *
3  * Copyright 1997-2000 Marcus Meissner
4  * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include "config.h"
22
23 #include <assert.h>
24 #include <string.h>
25
26 #define COBJMACROS
27 #define CONST_VTABLE
28
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31
32 #include "winerror.h"
33 #include "wine/debug.h"
34 #include "ddraw_private.h"
35 #include "opengl_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
38 WINE_DECLARE_DEBUG_CHANNEL(ddraw_flip);
39 WINE_DECLARE_DEBUG_CHANNEL(ddraw_fps);
40
41 /** Creation/Destruction functions */
42
43 HRESULT
44 Main_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl *This,
45                                  IDirectDrawImpl *pDD,
46                                  const DDSURFACEDESC2 *pDDSD)
47 {
48     TRACE("(%p)->(%p,%p)\n", This, pDD, pDDSD);
49
50     if (pDDSD != &This->surface_desc) {
51         This->surface_desc.dwSize = sizeof(This->surface_desc);
52         DD_STRUCT_COPY_BYSIZE(&(This->surface_desc),pDDSD);
53     }
54     This->uniqueness_value = 1; /* unchecked */
55     This->ref = 1;
56
57     This->local.lpSurfMore = &This->more;
58     This->local.lpGbl = &This->global;
59     This->local.dwProcessId = GetCurrentProcessId();
60     This->local.dwFlags = 0; /* FIXME */
61     This->local.ddsCaps.dwCaps = This->surface_desc.ddsCaps.dwCaps;
62     /* FIXME: more local stuff */
63     This->more.lpDD_lcl = &pDD->local;
64     This->more.ddsCapsEx.dwCaps2 = This->surface_desc.ddsCaps.dwCaps2;
65     This->more.ddsCapsEx.dwCaps3 = This->surface_desc.ddsCaps.dwCaps3;
66     This->more.ddsCapsEx.dwCaps4 = This->surface_desc.ddsCaps.dwCaps4;
67     /* FIXME: more more stuff */
68     This->gmore = &This->global_more;
69     This->global.u3.lpDD = pDD->local.lpGbl;
70     /* FIXME: more global stuff */
71
72     This->final_release = Main_DirectDrawSurface_final_release;
73     This->late_allocate = Main_DirectDrawSurface_late_allocate;
74     This->attach = Main_DirectDrawSurface_attach;
75     This->detach = Main_DirectDrawSurface_detach;
76     This->lock_update = Main_DirectDrawSurface_lock_update;
77     This->unlock_update = Main_DirectDrawSurface_unlock_update;
78     This->lose_surface = Main_DirectDrawSurface_lose_surface;
79     This->set_palette    = Main_DirectDrawSurface_set_palette;
80     This->update_palette = Main_DirectDrawSurface_update_palette;
81     This->get_display_window = Main_DirectDrawSurface_get_display_window;
82     This->get_gamma_ramp = Main_DirectDrawSurface_get_gamma_ramp;
83     This->set_gamma_ramp = Main_DirectDrawSurface_set_gamma_ramp;
84
85     ICOM_INIT_INTERFACE(This, IDirectDrawSurface3,
86                         DDRAW_IDDS3_Thunk_VTable);
87     ICOM_INIT_INTERFACE(This, IDirectDrawGammaControl,
88                         DDRAW_IDDGC_VTable);
89
90     /* There is no generic implementation of IDDS7 or texture */
91
92     Main_DirectDraw_AddSurface(pDD, This);
93     return DD_OK;
94 }
95
96 void Main_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This)
97 {
98     Main_DirectDraw_RemoveSurface(This->ddraw_owner, This);
99 }
100
101 HRESULT Main_DirectDrawSurface_late_allocate(IDirectDrawSurfaceImpl* This)
102 {
103     return DD_OK;
104 }
105
106 static void Main_DirectDrawSurface_Destroy(IDirectDrawSurfaceImpl* This)
107 {
108     if (This->palette) {
109         IDirectDrawPalette_Release(ICOM_INTERFACE(This->palette, IDirectDrawPalette));
110         This->palette = NULL;
111     }
112     This->final_release(This);
113     if (This->private != This+1) HeapFree(GetProcessHeap(), 0, This->private);
114     if (This->tex_private) HeapFree(GetProcessHeap(), 0, This->tex_private);
115     HeapFree(GetProcessHeap(), 0, This);
116 }
117
118 void Main_DirectDrawSurface_ForceDestroy(IDirectDrawSurfaceImpl* This)
119 {
120     WARN("destroying surface %p with refcnt %lu\n", This, This->ref);
121     Main_DirectDrawSurface_Destroy(This);
122 }
123
124 ULONG WINAPI Main_DirectDrawSurface_Release(LPDIRECTDRAWSURFACE7 iface)
125 {
126     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
127     ULONG ref = InterlockedDecrement(&This->ref);
128
129     TRACE("(%p)->(): decreasing from %ld\n", This, ref + 1);
130     
131     if (ref == 0)
132     {
133         if (This->aux_release)
134             This->aux_release(This->aux_ctx, This->aux_data);
135         Main_DirectDrawSurface_Destroy(This);
136
137         TRACE("released surface %p\n", This);
138         
139         return 0;
140     }
141
142     return ref;
143 }
144
145 ULONG WINAPI Main_DirectDrawSurface_AddRef(LPDIRECTDRAWSURFACE7 iface)
146 {
147     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
148     ULONG ref = InterlockedIncrement(&This->ref);
149
150     TRACE("(%p)->(): increasing from %ld\n", This, ref - 1);
151     
152     return ref;
153 }
154
155 HRESULT WINAPI
156 Main_DirectDrawSurface_QueryInterface(LPDIRECTDRAWSURFACE7 iface, REFIID riid,
157                                       LPVOID* ppObj)
158 {
159     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
160     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppObj);
161
162     *ppObj = NULL;
163
164     if (IsEqualGUID(&IID_IUnknown, riid)
165         || IsEqualGUID(&IID_IDirectDrawSurface7, riid)
166         || IsEqualGUID(&IID_IDirectDrawSurface4, riid))
167     {
168         InterlockedIncrement(&This->ref);
169         *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface7);
170         return S_OK;
171     }
172     else if (IsEqualGUID(&IID_IDirectDrawSurface, riid)
173              || IsEqualGUID(&IID_IDirectDrawSurface2, riid)
174              || IsEqualGUID(&IID_IDirectDrawSurface3, riid))
175     {
176         InterlockedIncrement(&This->ref);
177         *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface3);
178         return S_OK;
179     }
180     else if (IsEqualGUID(&IID_IDirectDrawGammaControl, riid))
181     {
182         InterlockedIncrement(&This->ref);
183         *ppObj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
184         return S_OK;
185     }
186 #ifdef HAVE_OPENGL
187     /* interfaces following here require OpenGL */
188     if( !opengl_initialized )
189         return E_NOINTERFACE;
190
191     if ( IsEqualGUID( &IID_D3DDEVICE_OpenGL, riid ) ||
192           IsEqualGUID( &IID_IDirect3DHALDevice, riid) )
193     {
194         IDirect3DDeviceImpl *d3ddevimpl;
195         HRESULT ret_value;
196
197         ret_value = d3ddevice_create(&d3ddevimpl, This->ddraw_owner, This, 1);
198         if (FAILED(ret_value)) return ret_value;
199
200         *ppObj = ICOM_INTERFACE(d3ddevimpl, IDirect3DDevice);
201         TRACE(" returning Direct3DDevice interface at %p.\n", *ppObj);
202         
203         InterlockedIncrement(&This->ref); /* No idea if this is correct.. Need to check using real Windows */
204         return ret_value;
205     }
206     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
207              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
208     {
209         HRESULT ret_value = S_OK;
210
211         /* Note: this is not exactly how Windows does it... But this seems not to hurt the only
212                  application I know creating a texture without this flag set and it will prevent
213                  bugs in other parts of Wine.
214         */
215         This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_TEXTURE;
216
217         /* In case the texture surface was created before the D3D creation */
218         if (This->tex_private == NULL) {
219             if (This->ddraw_owner->d3d_private == NULL) {
220                 ERR("Texture created with no D3D object yet.. Not supported !\n");
221                 return E_NOINTERFACE;
222             }
223
224             ret_value = This->ddraw_owner->d3d_create_texture(This->ddraw_owner, This, FALSE, This->mip_main);
225             if (FAILED(ret_value)) return ret_value;
226         }
227         if (IsEqualGUID( &IID_IDirect3DTexture, riid )) {
228             *ppObj = ICOM_INTERFACE(This, IDirect3DTexture);
229             TRACE(" returning Direct3DTexture interface at %p.\n", *ppObj);
230         } else {
231             *ppObj = ICOM_INTERFACE(This, IDirect3DTexture2);
232             TRACE(" returning Direct3DTexture2 interface at %p.\n", *ppObj);
233         }
234         InterlockedIncrement(&This->ref);
235         return ret_value;
236     }
237 #endif
238
239     return E_NOINTERFACE;
240 }
241
242 /*** Callbacks */
243
244 BOOL
245 Main_DirectDrawSurface_attach(IDirectDrawSurfaceImpl *This,
246                               IDirectDrawSurfaceImpl *to)
247 {
248     return TRUE;
249 }
250
251 BOOL Main_DirectDrawSurface_detach(IDirectDrawSurfaceImpl *This)
252 {
253     return TRUE;
254 }
255
256 void
257 Main_DirectDrawSurface_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect,
258         DWORD dwFlags)
259 {
260 }
261
262 void
263 Main_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This,
264                                      LPCRECT pRect)
265 {
266 }
267
268 void
269 Main_DirectDrawSurface_lose_surface(IDirectDrawSurfaceImpl* This)
270 {
271 }
272
273 void
274 Main_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This,
275                                    IDirectDrawPaletteImpl* pal)
276 {
277 }
278
279 void
280 Main_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This,
281                                       IDirectDrawPaletteImpl* pal,
282                                       DWORD dwStart, DWORD dwCount,
283                                       LPPALETTEENTRY palent)
284 {
285 }
286
287 HWND
288 Main_DirectDrawSurface_get_display_window(IDirectDrawSurfaceImpl* This)
289 {
290     return 0;
291 }
292
293 HRESULT
294 Main_DirectDrawSurface_get_gamma_ramp(IDirectDrawSurfaceImpl* This,
295                                       DWORD dwFlags,
296                                       LPDDGAMMARAMP lpGammaRamp)
297 {
298     HDC hDC;
299     HRESULT hr;
300     hr = This->get_dc(This, &hDC);
301     if (FAILED(hr)) return hr;
302     hr = GetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
303     This->release_dc(This, hDC);
304     return hr;
305 }
306
307 HRESULT
308 Main_DirectDrawSurface_set_gamma_ramp(IDirectDrawSurfaceImpl* This,
309                                       DWORD dwFlags,
310                                       LPDDGAMMARAMP lpGammaRamp)
311 {
312     HDC hDC;
313     HRESULT hr;
314     hr = This->get_dc(This, &hDC);
315     if (FAILED(hr)) return hr;
316     hr = SetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
317     This->release_dc(This, hDC);
318     return hr;
319 }
320
321
322 /*** Interface functions */
323
324 HRESULT WINAPI
325 Main_DirectDrawSurface_AddAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
326                                           LPDIRECTDRAWSURFACE7 pAttach)
327 {
328     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
329     IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
330                                                IDirectDrawSurface7, pAttach);
331
332     TRACE("(%p)->(%p)\n",This,pAttach);
333
334     /* Does windows check this? */
335     if (surf == This)
336         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
337
338     /* Does windows check this? */
339     if (surf->ddraw_owner != This->ddraw_owner)
340         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
341
342     if (surf->surface_owner != NULL)
343         return DDERR_SURFACEALREADYATTACHED; /* unchecked */
344
345     /* TODO MSDN: "You can attach only z-buffer surfaces with this method."
346      * But apparently backbuffers and mipmaps can be attached too. */
347
348     /* Set MIPMAPSUBLEVEL if this seems to be one */
349     if (This->surface_desc.ddsCaps.dwCaps &
350         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
351         surf->surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
352         /* FIXME: we should probably also add to dwMipMapCount of this
353          * and all parent surfaces (update create_texture if you do) */
354     }
355
356     /* Callback to allow the surface to do something special now that it is
357      * attached. (e.g. maybe the Z-buffer tells the renderer to use it.) */
358     if (!surf->attach(surf, This))
359         return DDERR_CANNOTATTACHSURFACE;
360
361     /* check: Where should it go in the chain? This puts it on the head. */
362     if (This->attached)
363         This->attached->prev_attached = surf;
364     surf->next_attached = This->attached;
365     surf->prev_attached = NULL;
366     This->attached = surf;
367     surf->surface_owner = This;
368
369     IDirectDrawSurface7_AddRef(pAttach);
370
371     return DD_OK;
372 }
373
374 /* MSDN: "not currently implemented." */
375 HRESULT WINAPI
376 Main_DirectDrawSurface_AddOverlayDirtyRect(LPDIRECTDRAWSURFACE7 iface,
377                                            LPRECT pRect)
378 {
379     TRACE("(%p)->(%p)\n",iface,pRect);
380     return DDERR_UNSUPPORTED; /* unchecked */
381 }
382
383 /* MSDN: "not currently implemented." */
384 HRESULT WINAPI
385 Main_DirectDrawSurface_BltBatch(LPDIRECTDRAWSURFACE7 iface,
386                                 LPDDBLTBATCH pBatch, DWORD dwCount,
387                                 DWORD dwFlags)
388 {
389     TRACE("(%p)->(%p,%ld,%08lx)\n",iface,pBatch,dwCount,dwFlags);
390     return DDERR_UNSUPPORTED; /* unchecked */
391 }
392
393 HRESULT WINAPI
394 Main_DirectDrawSurface_ChangeUniquenessValue(LPDIRECTDRAWSURFACE7 iface)
395 {
396     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
397     volatile IDirectDrawSurfaceImpl* vThis = This;
398
399     TRACE("(%p)\n",This);
400     /* A uniquness value of 0 is apparently special.
401      * This needs to be checked. */
402     while (1)
403     {
404         DWORD old_uniqueness_value = vThis->uniqueness_value;
405         DWORD new_uniqueness_value = old_uniqueness_value+1;
406
407         if (old_uniqueness_value == 0) break;
408         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
409
410         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
411                                        old_uniqueness_value,
412                                        new_uniqueness_value)
413             == old_uniqueness_value)
414             break;
415     }
416
417     return DD_OK;
418 }
419
420 HRESULT WINAPI
421 Main_DirectDrawSurface_DeleteAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
422                                              DWORD dwFlags,
423                                              LPDIRECTDRAWSURFACE7 pAttach)
424 {
425     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
426     IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
427                                                IDirectDrawSurface7, pAttach);
428
429     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pAttach);
430
431     if (!surf || (surf->surface_owner != This))
432         return DDERR_SURFACENOTATTACHED; /* unchecked */
433
434     surf->detach(surf);
435
436     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
437     if (This->surface_desc.ddsCaps.dwCaps &
438         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
439         surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
440         /* FIXME: we should probably also subtract from dwMipMapCount of this
441          * and all parent surfaces */
442     }
443
444     if (surf->next_attached)
445         surf->next_attached->prev_attached = surf->prev_attached;
446     if (surf->prev_attached)
447         surf->prev_attached->next_attached = surf->next_attached;
448     if (This->attached == surf)
449         This->attached = surf->next_attached;
450
451     IDirectDrawSurface7_Release(pAttach);
452
453     return DD_OK;
454 }
455
456 HRESULT WINAPI
457 Main_DirectDrawSurface_EnumAttachedSurfaces(LPDIRECTDRAWSURFACE7 iface,
458                                             LPVOID context,
459                                             LPDDENUMSURFACESCALLBACK7 cb)
460 {
461     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
462     IDirectDrawSurfaceImpl* surf;
463
464     TRACE("(%p)->(%p,%p)\n",This,context,cb);
465
466     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
467     {
468         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
469         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &surf->surface_desc,
470                context) == DDENUMRET_CANCEL)
471             break;
472     }
473
474     return DD_OK;
475 }
476
477 HRESULT WINAPI
478 Main_DirectDrawSurface_EnumOverlayZOrders(LPDIRECTDRAWSURFACE7 iface,
479                                           DWORD dwFlags, LPVOID context,
480                                           LPDDENUMSURFACESCALLBACK7 cb)
481 {
482     TRACE("(%p)->(%08lx,%p,%p)\n",iface,dwFlags,context,cb);
483     return DD_OK;
484 }
485
486 BOOL Main_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
487                                       IDirectDrawSurfaceImpl* back,
488                                       DWORD dwFlags)
489 {
490     /* uniqueness_value? */
491     /* This is necessary. But is it safe? */
492     {
493         HDC tmp = front->hDC;
494         front->hDC = back->hDC;
495         back->hDC = tmp;
496     }
497
498     {
499         BOOL tmp = front->dc_in_use;
500         front->dc_in_use = back->dc_in_use;
501         back->dc_in_use = tmp;
502     }
503
504     {
505         FLATPTR tmp = front->global.fpVidMem;
506         front->global.fpVidMem = back->global.fpVidMem;
507         back->global.fpVidMem = tmp;
508     }
509
510     {
511         ULONG_PTR tmp = front->global_more.hKernelSurface;
512         front->global_more.hKernelSurface = back->global_more.hKernelSurface;
513         back->global_more.hKernelSurface = tmp;
514     }
515
516     return TRUE;
517 }
518
519 /* This is unnecessarely complicated :-) */
520 #define MEASUREMENT_WINDOW 5
521 #define NUMBER_OF_WINDOWS 10
522
523 static LONGLONG perf_freq;
524 static LONGLONG perf_storage[NUMBER_OF_WINDOWS];
525 static LONGLONG prev_time = 0;
526 static unsigned int current_window;
527 static unsigned int measurements_in_window;
528 static unsigned int valid_windows;
529
530 HRESULT WINAPI
531 Main_DirectDrawSurface_Flip(LPDIRECTDRAWSURFACE7 iface,
532                             LPDIRECTDRAWSURFACE7 override, DWORD dwFlags)
533 {
534     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
535     IDirectDrawSurfaceImpl* target;
536     HRESULT hr;
537
538     TRACE("(%p)->(%p,%08lx)\n",This,override,dwFlags);
539
540     if (TRACE_ON(ddraw_fps)) {
541         LONGLONG current_time;
542         LONGLONG frame_duration;
543         QueryPerformanceCounter((LARGE_INTEGER *) &current_time);
544
545         if (prev_time != 0) {
546             LONGLONG total_time = 0;
547             int tot_meas;
548             
549             frame_duration = current_time - prev_time;
550             prev_time = current_time;
551             
552             perf_storage[current_window] += frame_duration;
553             measurements_in_window++;
554             
555             if (measurements_in_window >= MEASUREMENT_WINDOW) {
556                 current_window++;
557                 valid_windows++;
558
559                 if (valid_windows < NUMBER_OF_WINDOWS) {
560                     unsigned int i;
561                     tot_meas = valid_windows * MEASUREMENT_WINDOW;
562                     for (i = 0; i < valid_windows; i++) {
563                         total_time += perf_storage[i];
564                     }
565                 } else {
566                     int i;
567                     tot_meas = NUMBER_OF_WINDOWS * MEASUREMENT_WINDOW;
568                     for (i = 0; i < NUMBER_OF_WINDOWS; i++) {
569                         total_time += perf_storage[i];
570                     }
571                 }
572
573                 TRACE_(ddraw_fps)(" %9.5f\n", (double) (perf_freq * tot_meas) / (double) total_time);
574                 
575                 if (current_window >= NUMBER_OF_WINDOWS) {
576                     current_window = 0;
577                 }
578                 perf_storage[current_window] = 0;
579                 measurements_in_window = 0;
580             }
581         } else {
582             prev_time = current_time;
583             memset(perf_storage, 0, sizeof(perf_storage));
584             current_window = 0;
585             valid_windows = 0;
586             measurements_in_window = 0;
587             QueryPerformanceFrequency((LARGE_INTEGER *) &perf_freq);
588         }
589     }
590     
591     /* MSDN: "This method can be called only for a surface that has the
592      * DDSCAPS_FLIP and DDSCAPS_FRONTBUFFER capabilities." */
593     if ((This->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
594         != (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
595         return DDERR_NOTFLIPPABLE;
596
597     if (This->aux_flip)
598         if (This->aux_flip(This->aux_ctx, This->aux_data))
599             return DD_OK;
600
601     /* 1. find the flip target */
602     /* XXX I don't think this algorithm works for more than 1 backbuffer. */
603     if (override == NULL)
604     {
605         static DDSCAPS2 back_caps = { DDSCAPS_BACKBUFFER };
606         LPDIRECTDRAWSURFACE7 tgt;
607
608         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &back_caps, &tgt);
609         if (FAILED(hr)) return DDERR_NOTFLIPPABLE; /* unchecked */
610
611         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
612                              tgt);
613         IDirectDrawSurface7_Release(tgt);
614     }
615     else
616     {
617         BOOL on_chain = FALSE;
618         IDirectDrawSurfaceImpl* surf;
619
620         /* MSDN: "The method fails if the specified [override] surface is not
621          * a member of the flipping chain." */
622
623         /* Verify that override is on this flip chain. We assume that
624          * surf is the head of the flipping chain, because it's the front
625          * buffer. */
626         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
627                              override);
628
629         /* Either target is (indirectly) attached to This or This is
630          * (indirectly) attached to target. */
631         for (surf = target; surf != NULL; surf = surf->surface_owner)
632         {
633             if (surf == This)
634             {
635                 on_chain = TRUE;
636                 break;
637             }
638         }
639
640         if (!on_chain)
641             return DDERR_INVALIDPARAMS; /* unchecked */
642     }
643
644     TRACE("flip to backbuffer: %p\n",target);
645     if (TRACE_ON(ddraw_flip)) {
646         static unsigned int flip_count = 0;
647         IDirectDrawPaletteImpl *palette;
648         char buf[32];
649         FILE *f;
650
651         /* Hack for paletted games... */
652         palette = target->palette;
653         target->palette = This->palette;
654         
655         sprintf(buf, "flip_%08d.ppm", flip_count++);
656         TRACE_(ddraw_flip)("Dumping file %s to disk.\n", buf);
657         f = fopen(buf, "wb");
658         DDRAW_dump_surface_to_disk(target, f, 8);
659         target->palette = palette;
660     }
661
662     if (This->flip_data(This, target, dwFlags))
663         This->flip_update(This, dwFlags);
664     
665     return DD_OK;
666 }
667
668 static PrivateData* find_private_data(IDirectDrawSurfaceImpl *This,
669                                       REFGUID tag)
670 {
671     PrivateData* data;
672     for (data = This->private_data; data != NULL; data = data->next)
673     {
674         if (IsEqualGUID(&data->tag, tag)) break;
675     }
676
677     return data;
678 }
679
680 HRESULT WINAPI
681 Main_DirectDrawSurface_FreePrivateData(LPDIRECTDRAWSURFACE7 iface, REFGUID tag)
682 {
683     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
684     PrivateData *data;
685
686     data = find_private_data(This, tag);
687     if (data == NULL) return DDERR_NOTFOUND;
688
689     if (data->prev)
690         data->prev->next = data->next;
691     if (data->next)
692         data->next->prev = data->prev;
693
694     if (data->flags & DDSPD_IUNKNOWNPTR)
695     {
696         if (data->ptr.object != NULL)
697             IUnknown_Release(data->ptr.object);
698     }
699     else
700         HeapFree(GetProcessHeap(), 0, data->ptr.data);
701
702     HeapFree(GetProcessHeap(), 0, data);
703
704     return DD_OK;
705 }
706
707 HRESULT WINAPI
708 Main_DirectDrawSurface_GetAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
709                                           LPDDSCAPS2 pCaps,
710                                           LPDIRECTDRAWSURFACE7* ppSurface)
711 {
712     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
713     IDirectDrawSurfaceImpl* surf;
714     IDirectDrawSurfaceImpl* found = NULL;
715     DDSCAPS2 our_caps;
716     
717     if (TRACE_ON(ddraw)) {
718         TRACE("(%p)->Looking for caps: %lx,%lx,%lx,%lx output: %p\n",This,pCaps->dwCaps, pCaps->dwCaps2,
719               pCaps->dwCaps3, pCaps->dwCaps4, ppSurface);
720         TRACE("   Caps are : "); DDRAW_dump_DDSCAPS2(pCaps); TRACE("\n");
721     }
722
723     our_caps = *pCaps;
724     if ((This->ddraw_owner->local.dwLocalFlags & DDRAWILCL_DIRECTDRAW7) == 0) {
725         /* As this is not a DirectDraw7 application, remove the garbage that some games
726            put in the new fields of the DDSCAPS2 structure. */
727         our_caps.dwCaps2 = 0;
728         our_caps.dwCaps3 = 0;
729         our_caps.dwCaps4 = 0;
730         if (TRACE_ON(ddraw)) {
731             TRACE("   Real caps are : "); DDRAW_dump_DDSCAPS2(&our_caps); TRACE("\n");
732         }
733     }
734     
735     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
736     {
737         if (TRACE_ON(ddraw)) {
738             TRACE("Surface: (%p) caps: %lx,%lx,%lx,%lx \n",surf ,
739                   surf->surface_desc.ddsCaps.dwCaps,
740                   surf->surface_desc.ddsCaps.dwCaps2,
741                   surf->surface_desc.ddsCaps.dwCaps3,
742                   surf->surface_desc.ddsCaps.dwCaps4);
743             TRACE("   Surface caps are : "); DDRAW_dump_DDSCAPS2(&(surf->surface_desc.ddsCaps)); TRACE("\n");
744         }
745         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
746             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2))
747         {
748             /* MSDN: "This method fails if more than one surface is attached
749              * that matches the capabilities requested." */
750             if (found != NULL)
751             {
752                 FIXME("More than one attached surface matches requested caps.  What should we do here?\n");
753                 /* Previous code returned 'DDERR_NOTFOUND'.  That appears not
754                    to be correct, given what 3DMark expects from MipMapped surfaces.
755                    We shall just continue instead. */
756             }
757
758             found = surf;
759         }
760     }
761
762     if (found == NULL) {
763         TRACE("Did not find any valid surface\n");
764         return DDERR_NOTFOUND;
765     }
766
767     *ppSurface = ICOM_INTERFACE(found, IDirectDrawSurface7);
768
769     if (TRACE_ON(ddraw)) {
770         TRACE("Returning surface %p with description : \n", *ppSurface);
771         DDRAW_dump_surface_desc(&(found->surface_desc));
772     }
773     
774     /* XXX d3dframe.cpp sometimes AddRefs things that it gets from us. */
775     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(found, IDirectDrawSurface7));
776     return DD_OK;
777 }
778
779 HRESULT WINAPI
780 Main_DirectDrawSurface_GetBltStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
781 {
782     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
783
784     switch (dwFlags)
785     {
786     case DDGBS_CANBLT:
787     case DDGBS_ISBLTDONE:
788         return DD_OK;
789
790     default:
791         return DDERR_INVALIDPARAMS;
792     }
793 }
794
795 HRESULT WINAPI
796 Main_DirectDrawSurface_GetCaps(LPDIRECTDRAWSURFACE7 iface, LPDDSCAPS2 pCaps)
797 {
798     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
799
800     TRACE("(%p)->(%p)\n",This,pCaps);
801     *pCaps = This->surface_desc.ddsCaps;
802     return DD_OK;
803 }
804
805 HRESULT WINAPI
806 Main_DirectDrawSurface_GetClipper(LPDIRECTDRAWSURFACE7 iface,
807                                   LPDIRECTDRAWCLIPPER* ppClipper)
808 {
809     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
810
811     TRACE("(%p)->(%p)\n",This,ppClipper);
812     if (This->clipper == NULL)
813         return DDERR_NOCLIPPERATTACHED;
814
815     *ppClipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
816     IDirectDrawClipper_AddRef(ICOM_INTERFACE(This->clipper,
817                                              IDirectDrawClipper));
818     return DD_OK;
819 }
820
821 HRESULT WINAPI
822 Main_DirectDrawSurface_GetColorKey(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags,
823                                    LPDDCOLORKEY pCKey)
824 {
825     /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key
826      * isn't there? That's like saying that an int isn't there. (Which MS
827      * has done in other docs.) */
828
829     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
830
831     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
832     if (TRACE_ON(ddraw)) {
833         TRACE(" - colorkey flags : ");
834         DDRAW_dump_colorkeyflag(dwFlags);
835     }
836
837     switch (dwFlags)
838     {
839     case DDCKEY_DESTBLT:
840         *pCKey = This->surface_desc.ddckCKDestBlt;
841         break;
842
843     case DDCKEY_DESTOVERLAY:
844         *pCKey = This->surface_desc.u3.ddckCKDestOverlay;
845         break;
846
847     case DDCKEY_SRCBLT:
848         *pCKey = This->surface_desc.ddckCKSrcBlt;
849         break;
850
851     case DDCKEY_SRCOVERLAY:
852         *pCKey = This->surface_desc.ddckCKSrcOverlay;
853         break;
854
855     default:
856         return DDERR_INVALIDPARAMS;
857     }
858
859     return DD_OK;
860 }
861
862 /* XXX We need to do something with the DC if the surface gets lost. */
863 HRESULT WINAPI
864 Main_DirectDrawSurface_GetDC(LPDIRECTDRAWSURFACE7 iface, HDC *phDC)
865 {
866     DDSURFACEDESC2 ddsd;
867     HRESULT hr;
868     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
869
870     TRACE("(%p)->(%p)\n",This,phDC);
871     CHECK_LOST(This);
872
873     LOCK_OBJECT(This);
874
875     if (This->dc_in_use)
876     {
877         UNLOCK_OBJECT(This);
878         return DDERR_DCALREADYCREATED;
879     }
880
881     /* Lock as per MSDN.
882      * Strange: Lock lists DDERR_SURFACEBUSY as an error, meaning that another
883      * thread has it locked, but GetDC does not. */
884     ddsd.dwSize = sizeof(ddsd);
885     hr = IDirectDrawSurface7_Lock(iface, NULL, &ddsd, 0, 0);
886     if (FAILED(hr))
887     {
888         UNLOCK_OBJECT(This);
889         return hr;
890     }
891
892     hr = This->get_dc(This, &This->hDC);
893     if (SUCCEEDED(hr))
894     {
895         TRACE("returning %p\n",This->hDC);
896
897         *phDC = This->hDC;
898         This->dc_in_use = TRUE;
899     }
900     else WARN("No DC! Prepare for trouble\n");
901
902     UNLOCK_OBJECT(This);
903     return hr;
904 }
905
906 HRESULT WINAPI
907 Main_DirectDrawSurface_GetDDInterface(LPDIRECTDRAWSURFACE7 iface, LPVOID* pDD)
908 {
909     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
910
911     TRACE("(%p)->(%p)\n",This,pDD);
912     *pDD = ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7);
913     IDirectDraw7_AddRef(ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7));
914     return DD_OK;
915 }
916
917 HRESULT WINAPI
918 Main_DirectDrawSurface_GetFlipStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
919 {
920     /* XXX: DDERR_INVALIDSURFACETYPE */
921
922     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
923     switch (dwFlags)
924     {
925     case DDGFS_CANFLIP:
926     case DDGFS_ISFLIPDONE:
927         return DD_OK;
928
929     default:
930         return DDERR_INVALIDPARAMS;
931     }
932 }
933
934 HRESULT WINAPI
935 Main_DirectDrawSurface_GetLOD(LPDIRECTDRAWSURFACE7 iface, LPDWORD pdwMaxLOD)
936 {
937     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
938
939     TRACE("(%p)->(%p)\n",This,pdwMaxLOD);
940     CHECK_TEXTURE(This);
941
942     *pdwMaxLOD = This->max_lod;
943     return DD_OK;
944 }
945
946 HRESULT WINAPI
947 Main_DirectDrawSurface_GetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
948                                           LPLONG pX, LPLONG pY)
949 {
950     return DDERR_NOTAOVERLAYSURFACE;
951 }
952
953 HRESULT WINAPI
954 Main_DirectDrawSurface_GetPalette(LPDIRECTDRAWSURFACE7 iface,
955                                   LPDIRECTDRAWPALETTE* ppPalette)
956 {
957     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
958
959     TRACE("(%p)->(%p)\n",This,ppPalette);
960     if (This->palette == NULL)
961         return DDERR_NOPALETTEATTACHED;
962
963     *ppPalette = ICOM_INTERFACE(This->palette, IDirectDrawPalette);
964     IDirectDrawPalette_AddRef(ICOM_INTERFACE(This->palette,
965                                              IDirectDrawPalette));
966     return DD_OK;
967 }
968
969 HRESULT WINAPI
970 Main_DirectDrawSurface_GetPixelFormat(LPDIRECTDRAWSURFACE7 iface,
971                                       LPDDPIXELFORMAT pDDPixelFormat)
972 {
973     /* What is DDERR_INVALIDSURFACETYPE for here? */
974     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
975
976     TRACE("(%p)->(%p)\n",This,pDDPixelFormat);
977     DD_STRUCT_COPY_BYSIZE(pDDPixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
978     return DD_OK;
979 }
980
981 HRESULT WINAPI
982 Main_DirectDrawSurface_GetPriority(LPDIRECTDRAWSURFACE7 iface,
983                                    LPDWORD pdwPriority)
984 {
985     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
986
987     TRACE("(%p)->(%p)\n",This,pdwPriority);
988     CHECK_TEXTURE(This);
989
990     *pdwPriority = This->priority;
991     return DD_OK;
992 }
993
994 HRESULT WINAPI
995 Main_DirectDrawSurface_GetPrivateData(LPDIRECTDRAWSURFACE7 iface,
996                                       REFGUID tag, LPVOID pBuffer,
997                                       LPDWORD pcbBufferSize)
998 {
999     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1000     PrivateData* data;
1001
1002     TRACE("(%p)->(%p), size = %ld\n", This, pBuffer, *pcbBufferSize);
1003
1004     data = find_private_data(This, tag);
1005     if (data == NULL) return DDERR_NOTFOUND;
1006
1007     /* This may not be right. */
1008     if ((data->flags & DDSPD_VOLATILE)
1009         && data->uniqueness_value != This->uniqueness_value)
1010         return DDERR_EXPIRED;
1011
1012     if (*pcbBufferSize < data->size)
1013     {
1014         *pcbBufferSize = data->size;
1015         return DDERR_MOREDATA;
1016     }
1017
1018     if (data->flags & DDSPD_IUNKNOWNPTR)
1019     {
1020         *(LPUNKNOWN *)pBuffer = data->ptr.object;
1021         IUnknown_AddRef(data->ptr.object);
1022     }
1023     else
1024     {
1025         memcpy(pBuffer, data->ptr.data, data->size);
1026     }
1027
1028     return DD_OK;
1029 }
1030
1031 HRESULT WINAPI
1032 Main_DirectDrawSurface_GetSurfaceDesc(LPDIRECTDRAWSURFACE7 iface,
1033                                       LPDDSURFACEDESC2 pDDSD)
1034 {
1035     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1036
1037     TRACE("(%p)->(%p)\n",This,pDDSD);
1038     if ((pDDSD->dwSize < sizeof(DDSURFACEDESC)) ||
1039         (pDDSD->dwSize > sizeof(DDSURFACEDESC2))) {
1040         ERR("Impossible/Strange struct size %ld.\n",pDDSD->dwSize);
1041         return DDERR_GENERIC;
1042     }
1043
1044     DD_STRUCT_COPY_BYSIZE(pDDSD,&This->surface_desc);
1045     if (TRACE_ON(ddraw)) {
1046       DDRAW_dump_surface_desc(pDDSD);
1047     }
1048     return DD_OK;
1049 }
1050
1051 HRESULT WINAPI
1052 Main_DirectDrawSurface_GetUniquenessValue(LPDIRECTDRAWSURFACE7 iface,
1053                                           LPDWORD pValue)
1054 {
1055     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1056
1057     TRACE("(%p)->(%p)\n",This,pValue);
1058     *pValue = This->uniqueness_value;
1059     return DD_OK;
1060 }
1061
1062 HRESULT WINAPI
1063 Main_DirectDrawSurface_Initialize(LPDIRECTDRAWSURFACE7 iface,
1064                                   LPDIRECTDRAW pDD, LPDDSURFACEDESC2 pDDSD)
1065 {
1066     TRACE("(%p)->(%p,%p)\n",iface,pDD,pDDSD);
1067     return DDERR_ALREADYINITIALIZED;
1068 }
1069
1070 HRESULT WINAPI
1071 Main_DirectDrawSurface_IsLost(LPDIRECTDRAWSURFACE7 iface)
1072 {
1073     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1074
1075     TRACE("(%p) is%s lost\n",This, (This->lost ? "" : " not"));
1076     return This->lost ? DDERR_SURFACELOST : DD_OK;
1077 }
1078
1079
1080 /* XXX This doesn't actually do any locking or keep track of the locked
1081  * rectangles. The behaviour is poorly documented. */
1082 HRESULT WINAPI
1083 Main_DirectDrawSurface_Lock(LPDIRECTDRAWSURFACE7 iface, LPRECT prect,
1084                             LPDDSURFACEDESC2 pDDSD, DWORD flags, HANDLE h)
1085 {
1086     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1087
1088     if (TRACE_ON(ddraw)) {
1089         TRACE("(%p)->Lock(%p,%p,%08lx,%08lx)\n",This,prect,pDDSD,flags,(DWORD)h);
1090         TRACE(" - locking flags : "); DDRAW_dump_lockflag(flags);
1091     }
1092     if (WARN_ON(ddraw)) {
1093         if (flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY)) {
1094             WARN(" - unsupported locking flag : "); DDRAW_dump_lockflag(flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY));
1095         }
1096     }
1097
1098     /* If the surface is already locked, return busy */
1099     if (This->locked) {
1100         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1101         return DDERR_SURFACEBUSY;
1102     }
1103
1104     /* First, copy the Surface description */
1105     DD_STRUCT_COPY_BYSIZE(pDDSD,&(This->surface_desc));
1106
1107     /* Used to optimize the D3D Device locking */
1108     This->lastlocktype = flags & (DDLOCK_READONLY|DDLOCK_WRITEONLY);
1109     
1110     /* If asked only for a part, change the surface pointer.
1111      * (Not documented.) */
1112     if (prect != NULL) {
1113         TRACE(" lprect: %ldx%ld-%ldx%ld\n",
1114                 prect->left,prect->top,prect->right,prect->bottom);
1115         /* First do some sanity checkings on the rectangle we receive.
1116            DungeonSiege seems to gives us once a very bad rectangle for example */
1117         if ((prect->top < 0) ||
1118             (prect->left < 0) ||
1119             (prect->bottom < 0) ||
1120             (prect->right < 0) ||
1121             (prect->left >= prect->right) ||
1122             (prect->top >= prect->bottom) ||
1123             (prect->left >= This->surface_desc.dwWidth) ||
1124             (prect->right > This->surface_desc.dwWidth) ||
1125             (prect->top >= This->surface_desc.dwHeight) ||
1126             (prect->bottom > This->surface_desc.dwHeight)) {
1127             ERR(" Invalid values in LPRECT !!!\n");
1128             return DDERR_INVALIDPARAMS;
1129         }
1130
1131         This->lock_update(This, prect, flags);
1132
1133         if (pDDSD->u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) {
1134             int blksize;
1135             switch(pDDSD->u4.ddpfPixelFormat.dwFourCC) {
1136                 case MAKE_FOURCC('D','X','T','1') : blksize = 8; break;
1137                 case MAKE_FOURCC('D','X','T','3') : blksize = 16; break;
1138                 case MAKE_FOURCC('D','X','T','5') : blksize = 16; break;
1139                 default: return DDERR_INVALIDPIXELFORMAT;
1140             }
1141             pDDSD->lpSurface = (char *)This->surface_desc.lpSurface
1142                 + prect->top/4 * (pDDSD->dwWidth+3)/4 * blksize
1143                 + prect->left/4 * blksize;
1144         } else
1145             pDDSD->lpSurface = (char *)This->surface_desc.lpSurface
1146                 + prect->top * This->surface_desc.u1.lPitch
1147                 + prect->left * GET_BPP(This->surface_desc);
1148     } else {
1149         This->lock_update(This, NULL, flags);
1150     }
1151
1152     This->locked = TRUE;
1153
1154     TRACE("locked surface returning description : \n");
1155     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(pDDSD);
1156     
1157     return DD_OK;
1158 }
1159
1160 HRESULT WINAPI
1161 Main_DirectDrawSurface_PageLock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
1162 {
1163     /* Some surface types should return DDERR_CANTPAGELOCK. */
1164     return DD_OK;
1165 }
1166
1167 HRESULT WINAPI
1168 Main_DirectDrawSurface_PageUnlock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
1169 {
1170     /* Some surface types should return DDERR_CANTPAGEUNLOCK, and we should
1171      * keep track so we can return DDERR_NOTPAGELOCKED as appropriate. */
1172     return DD_OK;
1173 }
1174
1175 HRESULT WINAPI
1176 Main_DirectDrawSurface_ReleaseDC(LPDIRECTDRAWSURFACE7 iface, HDC hDC)
1177 {
1178     HRESULT hr;
1179     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1180
1181     TRACE("(%p)->(%p)\n",This,hDC);
1182
1183     if (!This->dc_in_use || This->hDC != hDC)
1184         return DDERR_INVALIDPARAMS;
1185
1186     This->release_dc(This, hDC);
1187
1188     hr = IDirectDrawSurface7_Unlock(iface, NULL);
1189     if (FAILED(hr)) return hr;
1190
1191     This->dc_in_use = FALSE;
1192     This->hDC = 0;
1193
1194     return DD_OK;
1195 }
1196
1197 /* Restore */
1198
1199 HRESULT WINAPI
1200 Main_DirectDrawSurface_SetClipper(LPDIRECTDRAWSURFACE7 iface,
1201                                   LPDIRECTDRAWCLIPPER pDDClipper)
1202 {
1203     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1204
1205     TRACE("(%p)->(%p)\n",This,pDDClipper);
1206     if (pDDClipper == ICOM_INTERFACE(This->clipper, IDirectDrawClipper))
1207         return DD_OK;
1208
1209     if (This->clipper != NULL)
1210         IDirectDrawClipper_Release(ICOM_INTERFACE(This->clipper,
1211                                                   IDirectDrawClipper));
1212
1213     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper,
1214                                 pDDClipper);
1215     if (pDDClipper != NULL)
1216         IDirectDrawClipper_AddRef(pDDClipper);
1217
1218     return DD_OK;
1219 }
1220
1221 HRESULT WINAPI
1222 Main_DirectDrawSurface_SetColorKey(LPDIRECTDRAWSURFACE7 iface,
1223                                    DWORD dwFlags, LPDDCOLORKEY pCKey)
1224 {
1225     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1226     
1227     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
1228
1229     if (TRACE_ON(ddraw)) {
1230         TRACE(" - colorkey flags : ");
1231         DDRAW_dump_colorkeyflag(dwFlags);
1232     }
1233
1234     if ((dwFlags & DDCKEY_COLORSPACE) != 0) {
1235         FIXME(" colorkey value not supported (%08lx) !\n", dwFlags);
1236         return DDERR_INVALIDPARAMS;
1237     }
1238     
1239     /* TODO: investigate if this function can take multiple bits set at the same
1240              time (ie setting multiple colorkey values at the same time with only
1241              one API call).
1242     */
1243     if (pCKey) {
1244         switch (dwFlags & ~DDCKEY_COLORSPACE) {
1245             case DDCKEY_DESTBLT:
1246                 This->surface_desc.ddckCKDestBlt = *pCKey;
1247                 This->surface_desc.dwFlags |= DDSD_CKDESTBLT;
1248                 break;
1249
1250             case DDCKEY_DESTOVERLAY:
1251                 This->surface_desc.u3.ddckCKDestOverlay = *pCKey;
1252                 This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
1253                 break;
1254
1255             case DDCKEY_SRCOVERLAY:
1256                 This->surface_desc.ddckCKSrcOverlay = *pCKey;
1257                 This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
1258                 break;
1259
1260             case DDCKEY_SRCBLT:
1261                 This->surface_desc.ddckCKSrcBlt = *pCKey;
1262                 This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
1263                 break;
1264
1265             default:
1266                 return DDERR_INVALIDPARAMS;
1267         }
1268     } else {
1269         switch (dwFlags & ~DDCKEY_COLORSPACE) {
1270             case DDCKEY_DESTBLT:
1271                 This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
1272                 break;
1273
1274             case DDCKEY_DESTOVERLAY:
1275                 This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
1276                 break;
1277
1278             case DDCKEY_SRCOVERLAY:
1279                 This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
1280                 break;
1281
1282             case DDCKEY_SRCBLT:
1283                 This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
1284                 break;
1285
1286             default:
1287                 return DDERR_INVALIDPARAMS;
1288         }
1289     }
1290
1291     if (This->aux_setcolorkey_cb) This->aux_setcolorkey_cb(This, dwFlags, pCKey);
1292
1293     return DD_OK;
1294 }
1295
1296 HRESULT WINAPI
1297 Main_DirectDrawSurface_SetLOD(LPDIRECTDRAWSURFACE7 iface, DWORD dwMaxLOD)
1298 {
1299     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1300
1301     TRACE("(%p)->(%08lx)\n",This,dwMaxLOD);
1302     CHECK_TEXTURE(This);
1303
1304     This->max_lod = dwMaxLOD;
1305     return DD_OK;
1306 }
1307
1308 HRESULT WINAPI
1309 Main_DirectDrawSurface_SetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
1310                                           LONG X, LONG Y)
1311 {
1312     return DDERR_NOTAOVERLAYSURFACE;
1313 }
1314
1315 HRESULT WINAPI
1316 Main_DirectDrawSurface_SetPalette(LPDIRECTDRAWSURFACE7 iface,
1317                                   LPDIRECTDRAWPALETTE pPalette)
1318 {
1319     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1320     IDirectDrawPalette *pal_to_rel = NULL;
1321
1322     TRACE("(%p)->(%p)\n",This,pPalette);
1323     if (pPalette == ICOM_INTERFACE(This->palette, IDirectDrawPalette))
1324         return DD_OK;
1325
1326     if (This->palette != NULL) {
1327         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1328             This->palette->global.dwFlags &= ~DDPCAPS_PRIMARYSURFACE;
1329         pal_to_rel = ICOM_INTERFACE(This->palette, IDirectDrawPalette);
1330     }
1331
1332     This->palette = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette,
1333                                 pPalette);
1334     if (pPalette != NULL) {
1335         IDirectDrawPalette_AddRef(pPalette);
1336         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1337             This->palette->global.dwFlags |= DDPCAPS_PRIMARYSURFACE;
1338     }
1339
1340     This->set_palette(This, This->palette);
1341
1342     /* Do the palette release at the end to prevent doing some 'loop' when removing
1343      * the surface maintaining the last reference on a palette.
1344      */
1345     if (pal_to_rel != NULL)
1346         IDirectDrawPalette_Release(pal_to_rel);
1347
1348     return DD_OK;
1349 }
1350
1351 HRESULT WINAPI
1352 Main_DirectDrawSurface_SetPriority(LPDIRECTDRAWSURFACE7 iface,
1353                                    DWORD dwPriority)
1354 {
1355     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1356
1357     TRACE("(%p)->(%08lx)\n",This,dwPriority);
1358     CHECK_TEXTURE(This);
1359
1360     This->priority = dwPriority;
1361     return DD_OK;
1362 }
1363
1364 /* Be careful when locking this: it is risky to call the object's AddRef
1365  * or Release holding a lock. */
1366 HRESULT WINAPI
1367 Main_DirectDrawSurface_SetPrivateData(LPDIRECTDRAWSURFACE7 iface,
1368                                       REFGUID tag, LPVOID pData,
1369                                       DWORD cbSize, DWORD dwFlags)
1370 {
1371     PrivateData* data;
1372     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1373
1374     TRACE("(%p)->(%p), size=%ld\n", This, pData, cbSize);
1375
1376     data = find_private_data(This, tag);
1377     if (data == NULL)
1378     {
1379         data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
1380         if (data == NULL) return DDERR_OUTOFMEMORY;
1381
1382         data->tag = *tag;
1383         data->flags = dwFlags;
1384         data->uniqueness_value = This->uniqueness_value;
1385
1386         if (dwFlags & DDSPD_IUNKNOWNPTR)
1387         {
1388             data->ptr.object = (LPUNKNOWN)pData;
1389             data->size = sizeof(LPUNKNOWN);
1390             IUnknown_AddRef(data->ptr.object);
1391         }
1392         else
1393         {
1394             data->ptr.data = HeapAlloc(GetProcessHeap(), 0, cbSize);
1395             if (data->ptr.data == NULL)
1396             {
1397                 HeapFree(GetProcessHeap(), 0, data);
1398                 return DDERR_OUTOFMEMORY;
1399             }
1400
1401             data->size = cbSize;
1402             memcpy(data->ptr.data, pData, data->size);
1403         }
1404
1405         /* link it in */
1406         data->next = This->private_data;
1407         data->prev = NULL;
1408         if (This->private_data)
1409             This->private_data->prev = data;
1410         This->private_data = data;
1411
1412         return DD_OK;
1413     }
1414     else
1415     {
1416         /* I don't actually know how windows handles this case. The only
1417          * reason I don't just call FreePrivateData is because I want to
1418          * guarantee SetPrivateData working when using LPUNKNOWN or data
1419          * that is no larger than the old data. */
1420
1421         FIXME("Replacing existing private data not implemented yet.\n");
1422         return E_FAIL;
1423     }
1424 }
1425
1426 /* SetSurfaceDesc */
1427
1428 HRESULT WINAPI
1429 Main_DirectDrawSurface_Unlock(LPDIRECTDRAWSURFACE7 iface, LPRECT pRect)
1430 {
1431     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1432
1433     TRACE("(%p)->Unlock(%p)\n",This,pRect);
1434
1435     if (!This->locked) {
1436         WARN("Surface not locked - returing DDERR_NOTLOCKED\n");
1437         return DDERR_NOTLOCKED;
1438     }
1439
1440     This->locked = FALSE;
1441     This->unlock_update(This, pRect);
1442     if (This->aux_unlock)
1443         This->aux_unlock(This->aux_ctx, This->aux_data, pRect);
1444
1445     return DD_OK;
1446 }
1447
1448 HRESULT WINAPI
1449 Main_DirectDrawSurface_UpdateOverlay(LPDIRECTDRAWSURFACE7 iface,
1450                                      LPRECT pSrcRect,
1451                                      LPDIRECTDRAWSURFACE7 pDstSurface,
1452                                      LPRECT pDstRect, DWORD dwFlags,
1453                                      LPDDOVERLAYFX pFX)
1454 {
1455     return DDERR_UNSUPPORTED;
1456 }
1457
1458 /* MSDN: "not currently implemented." */
1459 HRESULT WINAPI
1460 Main_DirectDrawSurface_UpdateOverlayDisplay(LPDIRECTDRAWSURFACE7 iface,
1461                                             DWORD dwFlags)
1462 {
1463     return DDERR_UNSUPPORTED;
1464 }
1465
1466 HRESULT WINAPI
1467 Main_DirectDrawSurface_UpdateOverlayZOrder(LPDIRECTDRAWSURFACE7 iface,
1468                                            DWORD dwFlags,
1469                                            LPDIRECTDRAWSURFACE7 pDDSRef)
1470 {
1471     return DDERR_NOTAOVERLAYSURFACE;
1472 }