Keep track of per-column information inside the listview.
[wine] / dlls / ddraw / dsurface / 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 #include "winerror.h"
23
24 #include <assert.h>
25 #include <string.h>
26
27 #include "mesa_private.h"
28 #include "wine/debug.h"
29 #include "ddraw_private.h"
30 #include "dsurface/main.h"
31 #include "ddraw/main.h"
32 #include "dsurface/thunks.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
35
36 /** Creation/Destruction functions */
37
38 HRESULT
39 Main_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl *This,
40                                  IDirectDrawImpl *pDD,
41                                  const DDSURFACEDESC2 *pDDSD)
42 {
43     if (pDDSD != &This->surface_desc) {
44         This->surface_desc.dwSize = sizeof(This->surface_desc);
45         DD_STRUCT_COPY_BYSIZE(&(This->surface_desc),pDDSD);
46     }
47     This->uniqueness_value = 1; /* unchecked */
48     This->ref = 1;
49
50     This->local.lpSurfMore = &This->more;
51     This->local.lpGbl = &This->global;
52     This->local.dwProcessId = GetCurrentProcessId();
53     This->local.dwFlags = 0; /* FIXME */
54     This->local.ddsCaps.dwCaps = This->surface_desc.ddsCaps.dwCaps;
55     /* FIXME: more local stuff */
56     This->more.lpDD_lcl = &pDD->local;
57     This->more.ddsCapsEx.dwCaps2 = This->surface_desc.ddsCaps.dwCaps2;
58     This->more.ddsCapsEx.dwCaps3 = This->surface_desc.ddsCaps.dwCaps3;
59     This->more.ddsCapsEx.dwCaps4 = This->surface_desc.ddsCaps.dwCaps4;
60     /* FIXME: more more stuff */
61     This->gmore = &This->global_more;
62     This->global.u3.lpDD = pDD->local.lpGbl;
63     /* FIXME: more global stuff */
64
65     This->final_release = Main_DirectDrawSurface_final_release;
66     This->late_allocate = Main_DirectDrawSurface_late_allocate;
67     This->attach = Main_DirectDrawSurface_attach;
68     This->detach = Main_DirectDrawSurface_detach;
69     This->lock_update = Main_DirectDrawSurface_lock_update;
70     This->unlock_update = Main_DirectDrawSurface_unlock_update;
71     This->lose_surface = Main_DirectDrawSurface_lose_surface;
72     This->set_palette    = Main_DirectDrawSurface_set_palette;
73     This->update_palette = Main_DirectDrawSurface_update_palette;
74     This->get_display_window = Main_DirectDrawSurface_get_display_window;
75     This->get_gamma_ramp = Main_DirectDrawSurface_get_gamma_ramp;
76     This->set_gamma_ramp = Main_DirectDrawSurface_set_gamma_ramp;
77
78     ICOM_INIT_INTERFACE(This, IDirectDrawSurface3,
79                         DDRAW_IDDS3_Thunk_VTable);
80     ICOM_INIT_INTERFACE(This, IDirectDrawGammaControl,
81                         DDRAW_IDDGC_VTable);
82     /* There is no generic implementation of IDDS7 */
83
84     Main_DirectDraw_AddSurface(pDD, This);
85     return DD_OK;
86 }
87
88 void Main_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This)
89 {
90     Main_DirectDraw_RemoveSurface(This->ddraw_owner, This);
91 }
92
93 HRESULT Main_DirectDrawSurface_late_allocate(IDirectDrawSurfaceImpl* This)
94 {
95     return DD_OK;
96 }
97
98 static void Main_DirectDrawSurface_Destroy(IDirectDrawSurfaceImpl* This)
99 {
100     This->final_release(This);
101     if (This->private != This+1) HeapFree(GetProcessHeap(), 0, This->private);
102     HeapFree(GetProcessHeap(), 0, This);
103 }
104
105 void Main_DirectDrawSurface_ForceDestroy(IDirectDrawSurfaceImpl* This)
106 {
107     WARN("destroying surface %p with refcnt %lu\n", This, This->ref);
108     Main_DirectDrawSurface_Destroy(This);
109 }
110
111 ULONG WINAPI Main_DirectDrawSurface_Release(LPDIRECTDRAWSURFACE7 iface)
112 {
113     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
114
115     if (--This->ref == 0)
116     {
117         if (This->aux_release)
118             This->aux_release(This->aux_ctx, This->aux_data);
119         Main_DirectDrawSurface_Destroy(This);
120         return 0;
121     }
122
123     return This->ref;
124 }
125
126 ULONG WINAPI Main_DirectDrawSurface_AddRef(LPDIRECTDRAWSURFACE7 iface)
127 {
128     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
129
130     return ++This->ref;
131 }
132
133 HRESULT WINAPI
134 Main_DirectDrawSurface_QueryInterface(LPDIRECTDRAWSURFACE7 iface, REFIID riid,
135                                       LPVOID* ppObj)
136 {
137     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
138     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppObj);
139
140     if (IsEqualGUID(&IID_IUnknown, riid)
141         || IsEqualGUID(&IID_IDirectDrawSurface7, riid)
142         || IsEqualGUID(&IID_IDirectDrawSurface4, riid))
143     {
144         This->ref++;
145         *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface7);
146         return S_OK;
147     }
148     else if (IsEqualGUID(&IID_IDirectDrawSurface, riid)
149              || IsEqualGUID(&IID_IDirectDrawSurface2, riid)
150              || IsEqualGUID(&IID_IDirectDrawSurface3, riid))
151     {
152         This->ref++;
153         *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface3);
154         return S_OK;
155     }
156     else if (IsEqualGUID(&IID_IDirectDrawGammaControl, riid))
157     {
158         This->ref++;
159         *ppObj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
160         return S_OK;
161     }
162 #ifdef HAVE_OPENGL
163     else if ( IsEqualGUID( &IID_D3DDEVICE_OpenGL, riid ) )
164     {
165         This->ref++;
166         return is_OpenGL_dx3(riid, This, (IDirect3DDeviceImpl**)ppObj)?S_OK:E_NOINTERFACE;
167     }
168     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ))
169     {
170         LPDIRECT3DTEXTURE iface;
171         This->ref++;
172         iface = d3dtexture_create(This);
173         if (iface) {
174           *ppObj = (LPVOID)iface;
175           return S_OK;
176         } else
177           return E_NOINTERFACE;
178     }    
179     else if (IsEqualGUID( &IID_IDirect3DTexture2, riid ))
180     {
181         LPDIRECT3DTEXTURE2 iface;
182         This->ref++;
183         iface = d3dtexture2_create(This);
184         if (iface) {
185           *ppObj = (LPVOID)iface;
186           return S_OK;
187         } else
188           return E_NOINTERFACE;
189     }    
190 #endif
191     else
192         return E_NOINTERFACE;
193 }
194
195 /*** Callbacks */
196
197 BOOL
198 Main_DirectDrawSurface_attach(IDirectDrawSurfaceImpl *This,
199                               IDirectDrawSurfaceImpl *to)
200 {
201     return TRUE;
202 }
203
204 BOOL Main_DirectDrawSurface_detach(IDirectDrawSurfaceImpl *This)
205 {
206     return TRUE;
207 }
208
209 void
210 Main_DirectDrawSurface_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect,
211         DWORD dwFlags)
212 {
213 }
214
215 void
216 Main_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This,
217                                      LPCRECT pRect)
218 {
219 }
220
221 void
222 Main_DirectDrawSurface_lose_surface(IDirectDrawSurfaceImpl* This)
223 {
224 }
225
226 void
227 Main_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This,
228                                    IDirectDrawPaletteImpl* pal)
229 {
230 }
231
232 void
233 Main_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This,
234                                       IDirectDrawPaletteImpl* pal,
235                                       DWORD dwStart, DWORD dwCount,
236                                       LPPALETTEENTRY palent)
237 {
238 }
239
240 HWND
241 Main_DirectDrawSurface_get_display_window(IDirectDrawSurfaceImpl* This)
242 {
243     return 0;
244 }
245
246 HRESULT
247 Main_DirectDrawSurface_get_gamma_ramp(IDirectDrawSurfaceImpl* This,
248                                       DWORD dwFlags,
249                                       LPDDGAMMARAMP lpGammaRamp)
250 {
251     HDC hDC;
252     HRESULT hr;
253     hr = This->get_dc(This, &hDC);
254     if (FAILED(hr)) return hr;
255     hr = GetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
256     This->release_dc(This, hDC);
257     return hr;
258 }
259
260 HRESULT
261 Main_DirectDrawSurface_set_gamma_ramp(IDirectDrawSurfaceImpl* This,
262                                       DWORD dwFlags,
263                                       LPDDGAMMARAMP lpGammaRamp)
264 {
265     HDC hDC;
266     HRESULT hr;
267     hr = This->get_dc(This, &hDC);
268     if (FAILED(hr)) return hr;
269     hr = SetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
270     This->release_dc(This, hDC);
271     return hr;
272 }
273
274
275 /*** Interface functions */
276
277 HRESULT WINAPI
278 Main_DirectDrawSurface_AddAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
279                                           LPDIRECTDRAWSURFACE7 pAttach)
280 {
281     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
282     IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
283                                                IDirectDrawSurface7, pAttach);
284
285     TRACE("(%p)->(%p)\n",This,pAttach);
286
287     /* Does windows check this? */
288     if (surf == This)
289         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
290
291     /* Does windows check this? */
292     if (surf->ddraw_owner != This->ddraw_owner)
293         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
294
295     if (surf->surface_owner != NULL)
296         return DDERR_SURFACEALREADYATTACHED; /* unchecked */
297
298     /* TODO MSDN: "You can attach only z-buffer surfaces with this method."
299      * But apparently backbuffers and mipmaps can be attached too. */
300
301     /* Set MIPMAPSUBLEVEL if this seems to be one */
302     if (This->surface_desc.ddsCaps.dwCaps &
303         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
304         surf->surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
305         /* FIXME: we should probably also add to dwMipMapCount of this
306          * and all parent surfaces (update create_texture if you do) */
307     }
308
309     /* Callback to allow the surface to do something special now that it is
310      * attached. (e.g. maybe the Z-buffer tells the renderer to use it.) */
311     if (!surf->attach(surf, This))
312         return DDERR_CANNOTATTACHSURFACE;
313
314     /* check: Where should it go in the chain? This puts it on the head. */
315     if (This->attached)
316         This->attached->prev_attached = surf;
317     surf->next_attached = This->attached;
318     surf->prev_attached = NULL;
319     This->attached = surf;
320     surf->surface_owner = This;
321
322     IDirectDrawSurface7_AddRef(pAttach);
323
324     return DD_OK;
325 }
326
327 /* MSDN: "not currently implemented." */
328 HRESULT WINAPI
329 Main_DirectDrawSurface_AddOverlayDirtyRect(LPDIRECTDRAWSURFACE7 iface,
330                                            LPRECT pRect)
331 {
332     TRACE("(%p)->(%p)\n",iface,pRect);
333     return DDERR_UNSUPPORTED; /* unchecked */
334 }
335
336 /* MSDN: "not currently implemented." */
337 HRESULT WINAPI
338 Main_DirectDrawSurface_BltBatch(LPDIRECTDRAWSURFACE7 iface,
339                                 LPDDBLTBATCH pBatch, DWORD dwCount,
340                                 DWORD dwFlags)
341 {
342     TRACE("(%p)->(%p,%ld,%08lx)\n",iface,pBatch,dwCount,dwFlags);
343     return DDERR_UNSUPPORTED; /* unchecked */
344 }
345
346 HRESULT WINAPI
347 Main_DirectDrawSurface_ChangeUniquenessValue(LPDIRECTDRAWSURFACE7 iface)
348 {
349     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
350     volatile IDirectDrawSurfaceImpl* vThis = This;
351
352     TRACE("(%p)\n",This);
353     /* A uniquness value of 0 is apparently special.
354      * This needs to be checked. */
355     while (1)
356     {
357         DWORD old_uniqueness_value = vThis->uniqueness_value;
358         DWORD new_uniqueness_value = old_uniqueness_value+1;
359
360         if (old_uniqueness_value == 0) break;
361         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
362
363         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
364                                        old_uniqueness_value,
365                                        new_uniqueness_value)
366             == old_uniqueness_value)
367             break;
368     }
369
370     return DD_OK;
371 }
372
373 HRESULT WINAPI
374 Main_DirectDrawSurface_DeleteAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
375                                              DWORD dwFlags,
376                                              LPDIRECTDRAWSURFACE7 pAttach)
377 {
378     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
379     IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
380                                                IDirectDrawSurface7, pAttach);
381
382     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pAttach);
383
384     if (!surf || (surf->surface_owner != This))
385         return DDERR_SURFACENOTATTACHED; /* unchecked */
386
387     surf->detach(surf);
388
389     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
390     if (This->surface_desc.ddsCaps.dwCaps &
391         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
392         surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
393         /* FIXME: we should probably also subtract from dwMipMapCount of this
394          * and all parent surfaces */
395     }
396
397     if (surf->next_attached)
398         surf->next_attached->prev_attached = surf->prev_attached;
399     if (surf->prev_attached)
400         surf->prev_attached->next_attached = surf->next_attached;
401     if (This->attached == surf)
402         This->attached = surf->next_attached;
403
404     IDirectDrawSurface7_Release(pAttach);
405
406     return DD_OK;
407 }
408
409 HRESULT WINAPI
410 Main_DirectDrawSurface_EnumAttachedSurfaces(LPDIRECTDRAWSURFACE7 iface,
411                                             LPVOID context,
412                                             LPDDENUMSURFACESCALLBACK7 cb)
413 {
414     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
415     IDirectDrawSurfaceImpl* surf;
416
417     TRACE("(%p)->(%p,%p)\n",This,context,cb);
418
419     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
420     {
421         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
422         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &surf->surface_desc,
423                context) == DDENUMRET_CANCEL)
424             break;
425     }
426
427     return DD_OK;
428 }
429
430 HRESULT WINAPI
431 Main_DirectDrawSurface_EnumOverlayZOrders(LPDIRECTDRAWSURFACE7 iface,
432                                           DWORD dwFlags, LPVOID context,
433                                           LPDDENUMSURFACESCALLBACK7 cb)
434 {
435     TRACE("(%p)->(%08lx,%p,%p)\n",iface,dwFlags,context,cb);
436     return DD_OK;
437 }
438
439 BOOL Main_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
440                                       IDirectDrawSurfaceImpl* back,
441                                       DWORD dwFlags)
442 {
443     /* uniqueness_value? */
444     /* This is necessary. But is it safe? */
445     {
446         HDC tmp = front->hDC;
447         front->hDC = back->hDC;
448         back->hDC = tmp;
449     }
450
451     {
452         BOOL tmp = front->dc_in_use;
453         front->dc_in_use = back->dc_in_use;
454         back->dc_in_use = tmp;
455     }
456
457     {
458         FLATPTR tmp = front->global.fpVidMem;
459         front->global.fpVidMem = back->global.fpVidMem;
460         back->global.fpVidMem = tmp;
461     }
462
463     {
464         ULONG_PTR tmp = front->global_more.hKernelSurface;
465         front->global_more.hKernelSurface = back->global_more.hKernelSurface;
466         back->global_more.hKernelSurface = tmp;
467     }
468
469     return TRUE;
470 }
471
472 HRESULT WINAPI
473 Main_DirectDrawSurface_Flip(LPDIRECTDRAWSURFACE7 iface,
474                             LPDIRECTDRAWSURFACE7 override, DWORD dwFlags)
475 {
476     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
477     IDirectDrawSurfaceImpl* target;
478     HRESULT hr;
479
480     TRACE("(%p)->(%p,%08lx)\n",This,override,dwFlags);
481
482     /* MSDN: "This method can be called only for a surface that has the
483      * DDSCAPS_FLIP and DDSCAPS_FRONTBUFFER capabilities." */
484     if ((This->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
485         != (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
486         return DDERR_NOTFLIPPABLE;
487
488     if (This->aux_flip)
489         if (This->aux_flip(This->aux_ctx, This->aux_data))
490             return DD_OK;
491
492     /* 1. find the flip target */
493     /* XXX I don't think this algorithm works for more than 1 backbuffer. */
494     if (override == NULL)
495     {
496         static DDSCAPS2 back_caps = { DDSCAPS_BACKBUFFER };
497         LPDIRECTDRAWSURFACE7 tgt;
498
499         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &back_caps, &tgt);
500         if (FAILED(hr)) return DDERR_NOTFLIPPABLE; /* unchecked */
501
502         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
503                              tgt);
504         IDirectDrawSurface7_Release(tgt);
505     }
506     else
507     {
508         BOOL on_chain = FALSE;
509         IDirectDrawSurfaceImpl* surf;
510
511         /* MSDN: "The method fails if the specified [override] surface is not
512          * a member of the flipping chain." */
513
514         /* Verify that override is on this flip chain. We assume that
515          * surf is the head of the flipping chain, because it's the front
516          * buffer. */
517         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
518                              override);
519
520         /* Either target is (indirectly) attached to This or This is
521          * (indirectly) attached to target. */
522         for (surf = target; surf != NULL; surf = surf->surface_owner)
523         {
524             if (surf == This)
525             {
526                 on_chain = TRUE;
527                 break;
528             }
529         }
530
531         if (!on_chain)
532             return DDERR_INVALIDPARAMS; /* unchecked */
533     }
534
535     TRACE("flip to backbuffer: %p\n",target);
536     if (This->flip_data(This, target, dwFlags))
537         This->flip_update(This, dwFlags);
538
539     return DD_OK;
540 }
541
542 static PrivateData* find_private_data(IDirectDrawSurfaceImpl *This,
543                                       REFGUID tag)
544 {
545     PrivateData* data;
546     for (data = This->private_data; data != NULL; data = data->next)
547     {
548         if (IsEqualGUID(&data->tag, tag)) break;
549     }
550
551     return data;
552 }
553
554 HRESULT WINAPI
555 Main_DirectDrawSurface_FreePrivateData(LPDIRECTDRAWSURFACE7 iface, REFGUID tag)
556 {
557     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
558     PrivateData *data;
559
560     data = find_private_data(This, tag);
561     if (data == NULL) return DDERR_NOTFOUND;
562
563     if (data->prev)
564         data->prev->next = data->next;
565     if (data->next)
566         data->next->prev = data->prev;
567
568     if (data->flags & DDSPD_IUNKNOWNPTR)
569     {
570         if (data->ptr.object != NULL)
571             IUnknown_Release(data->ptr.object);
572     }
573     else
574         HeapFree(GetProcessHeap(), 0, data->ptr.data);
575
576     HeapFree(GetProcessHeap(), 0, data);
577
578     return DD_OK;
579 }
580
581 HRESULT WINAPI
582 Main_DirectDrawSurface_GetAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
583                                           LPDDSCAPS2 pCaps,
584                                           LPDIRECTDRAWSURFACE7* ppSurface)
585 {
586     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
587     IDirectDrawSurfaceImpl* surf;
588     IDirectDrawSurfaceImpl* found = NULL;
589
590     TRACE("(%p)->Looking for caps: %lx,%lx,%lx,%lx output: %p\n",This,pCaps->dwCaps, pCaps->dwCaps2,
591           pCaps->dwCaps3, pCaps->dwCaps4, ppSurface);
592
593     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
594     {
595         TRACE("Surface: (%p) caps: %lx,%lx,%lx,%lx \n",surf ,
596                surf->surface_desc.ddsCaps.dwCaps,
597                surf->surface_desc.ddsCaps.dwCaps2,
598                surf->surface_desc.ddsCaps.dwCaps3,
599                surf->surface_desc.ddsCaps.dwCaps4);
600         if (((surf->surface_desc.ddsCaps.dwCaps & pCaps->dwCaps) == pCaps->dwCaps)
601            && ((surf->surface_desc.ddsCaps.dwCaps2 & pCaps->dwCaps2) == pCaps->dwCaps2))
602         {
603             /* MSDN: "This method fails if more than one surface is attached
604              * that matches the capabilities requested." */
605             if (found != NULL)
606             {
607                 FIXME("More than one attached surface matches requested caps.  What should we do here?\n");
608                 /* Previous code returned 'DDERR_NOTFOUND'.  That appears not
609                    to be correct, given what 3DMark expects from MipMapped surfaces.
610                    We shall just continue instead. */
611             }
612
613             found = surf;
614         }
615     }
616
617     if (found == NULL)
618         return DDERR_NOTFOUND;
619
620     *ppSurface = ICOM_INTERFACE(found, IDirectDrawSurface7);
621
622     /* XXX d3dframe.cpp sometimes AddRefs things that it gets from us. */
623     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(found, IDirectDrawSurface7));
624     return DD_OK;
625 }
626
627 HRESULT WINAPI
628 Main_DirectDrawSurface_GetBltStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
629 {
630     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
631
632     switch (dwFlags)
633     {
634     case DDGBS_CANBLT:
635     case DDGBS_ISBLTDONE:
636         return DD_OK;
637
638     default:
639         return DDERR_INVALIDPARAMS;
640     }
641 }
642
643 HRESULT WINAPI
644 Main_DirectDrawSurface_GetCaps(LPDIRECTDRAWSURFACE7 iface, LPDDSCAPS2 pCaps)
645 {
646     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
647
648     TRACE("(%p)->(%p)\n",This,pCaps);
649     *pCaps = This->surface_desc.ddsCaps;
650     return DD_OK;
651 }
652
653 HRESULT WINAPI
654 Main_DirectDrawSurface_GetClipper(LPDIRECTDRAWSURFACE7 iface,
655                                   LPDIRECTDRAWCLIPPER* ppClipper)
656 {
657     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
658
659     TRACE("(%p)->(%p)\n",This,ppClipper);
660     if (This->clipper == NULL)
661         return DDERR_NOCLIPPERATTACHED;
662
663     *ppClipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
664     IDirectDrawClipper_AddRef(ICOM_INTERFACE(This->clipper,
665                                              IDirectDrawClipper));
666     return DD_OK;
667 }
668
669 HRESULT WINAPI
670 Main_DirectDrawSurface_GetColorKey(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags,
671                                    LPDDCOLORKEY pCKey)
672 {
673     /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key
674      * isn't there? That's like saying that an int isn't there. (Which MS
675      * has done in other docs.) */
676
677     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
678
679     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
680     switch (dwFlags)
681     {
682     case DDCKEY_DESTBLT:
683         *pCKey = This->surface_desc.ddckCKDestBlt;
684         break;
685
686     case DDCKEY_DESTOVERLAY:
687         *pCKey = This->surface_desc.u3.ddckCKDestOverlay;
688         break;
689
690     case DDCKEY_SRCBLT:
691         *pCKey = This->surface_desc.ddckCKSrcBlt;
692         break;
693
694     case DDCKEY_SRCOVERLAY:
695         *pCKey = This->surface_desc.ddckCKSrcOverlay;
696         break;
697
698     default:
699         return DDERR_INVALIDPARAMS;
700     }
701
702     return DD_OK;
703 }
704
705 /* XXX We need to do something with the DC if the surface gets lost. */
706 HRESULT WINAPI
707 Main_DirectDrawSurface_GetDC(LPDIRECTDRAWSURFACE7 iface, HDC *phDC)
708 {
709     DDSURFACEDESC2 ddsd;
710     HRESULT hr;
711     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
712
713     TRACE("(%p)->(%p)\n",This,phDC);
714     CHECK_LOST(This);
715
716     LOCK_OBJECT(This);
717
718     if (This->dc_in_use)
719     {
720         UNLOCK_OBJECT(This);
721         return DDERR_DCALREADYCREATED;
722     }
723
724     /* Lock as per MSDN.
725      * Strange: Lock lists DDERR_SURFACEBUSY as an error, meaning that another
726      * thread has it locked, but GetDC does not. */
727     ddsd.dwSize = sizeof(ddsd);
728     hr = IDirectDrawSurface7_Lock(iface, NULL, &ddsd, DDLOCK_READONLY, 0);
729     if (FAILED(hr))
730     {
731         UNLOCK_OBJECT(This);
732         return hr;
733     }
734
735     hr = This->get_dc(This, &This->hDC);
736     if (SUCCEEDED(hr))
737     {
738         TRACE("returning %p\n",This->hDC);
739
740         *phDC = This->hDC;
741         This->dc_in_use = TRUE;
742     }
743     else WARN("No DC! Prepare for trouble\n");
744
745     UNLOCK_OBJECT(This);
746     return hr;
747 }
748
749 HRESULT WINAPI
750 Main_DirectDrawSurface_GetDDInterface(LPDIRECTDRAWSURFACE7 iface, LPVOID* pDD)
751 {
752     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
753
754     TRACE("(%p)->(%p)\n",This,pDD);
755     *pDD = ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7);
756     IDirectDraw7_AddRef(ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7));
757     return DD_OK;
758 }
759
760 HRESULT WINAPI
761 Main_DirectDrawSurface_GetFlipStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
762 {
763     /* XXX: DDERR_INVALIDSURFACETYPE */
764
765     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
766     switch (dwFlags)
767     {
768     case DDGFS_CANFLIP:
769     case DDGFS_ISFLIPDONE:
770         return DD_OK;
771
772     default:
773         return DDERR_INVALIDPARAMS;
774     }
775 }
776
777 HRESULT WINAPI
778 Main_DirectDrawSurface_GetLOD(LPDIRECTDRAWSURFACE7 iface, LPDWORD pdwMaxLOD)
779 {
780     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
781
782     TRACE("(%p)->(%p)\n",This,pdwMaxLOD);
783     CHECK_TEXTURE(This);
784
785     *pdwMaxLOD = This->max_lod;
786     return DD_OK;
787 }
788
789 HRESULT WINAPI
790 Main_DirectDrawSurface_GetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
791                                           LPLONG pX, LPLONG pY)
792 {
793     return DDERR_NOTAOVERLAYSURFACE;
794 }
795
796 HRESULT WINAPI
797 Main_DirectDrawSurface_GetPalette(LPDIRECTDRAWSURFACE7 iface,
798                                   LPDIRECTDRAWPALETTE* ppPalette)
799 {
800     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
801
802     TRACE("(%p)->(%p)\n",This,ppPalette);
803     if (This->palette == NULL)
804         return DDERR_NOPALETTEATTACHED;
805
806     *ppPalette = ICOM_INTERFACE(This->palette, IDirectDrawPalette);
807     IDirectDrawPalette_AddRef(ICOM_INTERFACE(This->palette,
808                                              IDirectDrawPalette));
809     return DD_OK;
810 }
811
812 HRESULT WINAPI
813 Main_DirectDrawSurface_GetPixelFormat(LPDIRECTDRAWSURFACE7 iface,
814                                       LPDDPIXELFORMAT pDDPixelFormat)
815 {
816     /* What is DDERR_INVALIDSURFACETYPE for here? */
817     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
818
819     TRACE("(%p)->(%p)\n",This,pDDPixelFormat);
820     DD_STRUCT_COPY_BYSIZE(pDDPixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
821     return DD_OK;
822 }
823
824 HRESULT WINAPI
825 Main_DirectDrawSurface_GetPriority(LPDIRECTDRAWSURFACE7 iface,
826                                    LPDWORD pdwPriority)
827 {
828     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
829
830     TRACE("(%p)->(%p)\n",This,pdwPriority);
831     CHECK_TEXTURE(This);
832
833     *pdwPriority = This->priority;
834     return DD_OK;
835 }
836
837 HRESULT WINAPI
838 Main_DirectDrawSurface_GetPrivateData(LPDIRECTDRAWSURFACE7 iface,
839                                       REFGUID tag, LPVOID pBuffer,
840                                       LPDWORD pcbBufferSize)
841 {
842     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
843     PrivateData* data;
844
845     data = find_private_data(This, tag);
846     if (data == NULL) return DDERR_NOTFOUND;
847
848     /* This may not be right. */
849     if ((data->flags & DDSPD_VOLATILE)
850         && data->uniqueness_value != This->uniqueness_value)
851         return DDERR_EXPIRED;
852
853     if (*pcbBufferSize < data->size)
854     {
855         *pcbBufferSize = data->size;
856         return DDERR_MOREDATA;
857     }
858
859     if (data->flags & DDSPD_IUNKNOWNPTR)
860     {
861         *(LPUNKNOWN *)pBuffer = data->ptr.object;
862         IUnknown_AddRef(data->ptr.object);
863     }
864     else
865     {
866         memcpy(pBuffer, data->ptr.data, data->size);
867     }
868
869     return DD_OK;
870 }
871
872 HRESULT WINAPI
873 Main_DirectDrawSurface_GetSurfaceDesc(LPDIRECTDRAWSURFACE7 iface,
874                                       LPDDSURFACEDESC2 pDDSD)
875 {
876     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
877
878     TRACE("(%p)->(%p)\n",This,pDDSD);
879     if ((pDDSD->dwSize < sizeof(DDSURFACEDESC)) ||
880         (pDDSD->dwSize > sizeof(DDSURFACEDESC2))) {
881         ERR("Impossible/Strange struct size %ld.\n",pDDSD->dwSize);
882         return DDERR_GENERIC;
883     }
884
885     DD_STRUCT_COPY_BYSIZE(pDDSD,&This->surface_desc);
886     if (TRACE_ON(ddraw)) {
887       DDRAW_dump_surface_desc(pDDSD);
888     }
889     return DD_OK;
890 }
891
892 HRESULT WINAPI
893 Main_DirectDrawSurface_GetUniquenessValue(LPDIRECTDRAWSURFACE7 iface,
894                                           LPDWORD pValue)
895 {
896     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
897
898     TRACE("(%p)->(%p)\n",This,pValue);
899     *pValue = This->uniqueness_value;
900     return DD_OK;
901 }
902
903 HRESULT WINAPI
904 Main_DirectDrawSurface_Initialize(LPDIRECTDRAWSURFACE7 iface,
905                                   LPDIRECTDRAW pDD, LPDDSURFACEDESC2 pDDSD)
906 {
907     TRACE("(%p)->(%p,%p)\n",iface,pDD,pDDSD);
908     return DDERR_ALREADYINITIALIZED;
909 }
910
911 HRESULT WINAPI
912 Main_DirectDrawSurface_IsLost(LPDIRECTDRAWSURFACE7 iface)
913 {
914     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
915
916     TRACE("(%p) is%s lost\n",This, (This->lost ? "" : " not"));
917     return This->lost ? DDERR_SURFACELOST : DD_OK;
918 }
919
920
921 /* XXX This doesn't actually do any locking or keep track of the locked
922  * rectangles. The behaviour is poorly documented. */
923 HRESULT WINAPI
924 Main_DirectDrawSurface_Lock(LPDIRECTDRAWSURFACE7 iface, LPRECT prect,
925                             LPDDSURFACEDESC2 pDDSD, DWORD flags, HANDLE h)
926 {
927     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
928
929     TRACE("(%p)->Lock(%p,%p,%08lx,%08lx)\n",This,prect,pDDSD,flags,(DWORD)h);
930
931     if (flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY))
932         WARN("(%p)->Lock(%p,%p,%08lx,%08lx)\n",
933                  This,prect,pDDSD,flags,(DWORD)h);
934
935     /* First, copy the Surface description */
936     DD_STRUCT_COPY_BYSIZE(pDDSD,&(This->surface_desc));
937
938     TRACE("locked surface returning description : \n");
939     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(pDDSD);
940     
941     /* If asked only for a part, change the surface pointer.
942      * (Not documented.) */
943     if (prect != NULL) {
944         TRACE(" lprect: %dx%d-%dx%d\n",
945                 prect->top,prect->left,prect->bottom,prect->right
946         );
947         if ((prect->top < 0) ||
948             (prect->left < 0) ||
949             (prect->bottom < 0) ||
950             (prect->right < 0)) {
951           ERR(" Negative values in LPRECT !!!\n");
952           return DDERR_INVALIDPARAMS;
953        }
954
955         This->lock_update(This, prect, flags);
956
957         pDDSD->lpSurface = (char *)This->surface_desc.lpSurface
958             + prect->top * This->surface_desc.u1.lPitch
959             + prect->left * GET_BPP(This->surface_desc);
960     } else {
961         This->lock_update(This, NULL, flags);
962     }
963
964     return DD_OK;
965 }
966
967 HRESULT WINAPI
968 Main_DirectDrawSurface_PageLock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
969 {
970     /* Some surface types should return DDERR_CANTPAGELOCK. */
971     return DD_OK;
972 }
973
974 HRESULT WINAPI
975 Main_DirectDrawSurface_PageUnlock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
976 {
977     /* Some surface types should return DDERR_CANTPAGEUNLOCK, and we should
978      * keep track so we can return DDERR_NOTPAGELOCKED as appropriate. */
979     return DD_OK;
980 }
981
982 HRESULT WINAPI
983 Main_DirectDrawSurface_ReleaseDC(LPDIRECTDRAWSURFACE7 iface, HDC hDC)
984 {
985     HRESULT hr;
986     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
987
988     TRACE("(%p)->(%p)\n",This,hDC);
989
990     if (!This->dc_in_use || This->hDC != hDC)
991         return DDERR_INVALIDPARAMS;
992
993     This->release_dc(This, hDC);
994
995     hr = IDirectDrawSurface7_Unlock(iface, NULL);
996     if (FAILED(hr)) return hr;
997
998     This->dc_in_use = FALSE;
999     This->hDC = 0;
1000
1001     return DD_OK;
1002 }
1003
1004 /* Restore */
1005
1006 HRESULT WINAPI
1007 Main_DirectDrawSurface_SetClipper(LPDIRECTDRAWSURFACE7 iface,
1008                                   LPDIRECTDRAWCLIPPER pDDClipper)
1009 {
1010     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1011
1012     TRACE("(%p)->(%p)\n",This,pDDClipper);
1013     if (pDDClipper == ICOM_INTERFACE(This->clipper, IDirectDrawClipper))
1014         return DD_OK;
1015
1016     if (This->clipper != NULL)
1017         IDirectDrawClipper_Release(ICOM_INTERFACE(This->clipper,
1018                                                   IDirectDrawClipper));
1019
1020     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper,
1021                                 pDDClipper);
1022     if (pDDClipper != NULL)
1023         IDirectDrawClipper_AddRef(pDDClipper);
1024
1025     return DD_OK;
1026 }
1027
1028 HRESULT WINAPI
1029 Main_DirectDrawSurface_SetColorKey(LPDIRECTDRAWSURFACE7 iface,
1030                                    DWORD dwFlags, LPDDCOLORKEY pCKey)
1031 {
1032     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1033
1034     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
1035     if (pCKey == NULL)
1036     {
1037         FIXME("supposedly removing color key %lu\n",
1038               dwFlags & ~DDCKEY_COLORSPACE);
1039         return DD_OK;
1040     }
1041
1042     switch (dwFlags & ~DDCKEY_COLORSPACE)
1043     {
1044     case DDCKEY_DESTBLT:
1045         This->surface_desc.ddckCKDestBlt = *pCKey;
1046         break;
1047
1048     case DDCKEY_DESTOVERLAY:
1049         This->surface_desc.u3.ddckCKDestOverlay = *pCKey;
1050         break;
1051
1052     case DDCKEY_SRCOVERLAY:
1053         This->surface_desc.ddckCKSrcOverlay = *pCKey;
1054         break;
1055
1056     case DDCKEY_SRCBLT:
1057         This->surface_desc.ddckCKSrcBlt = *pCKey;
1058         break;
1059
1060     default:
1061         return DDERR_INVALIDPARAMS;
1062     }
1063
1064     return DD_OK;
1065 }
1066
1067 HRESULT WINAPI
1068 Main_DirectDrawSurface_SetLOD(LPDIRECTDRAWSURFACE7 iface, DWORD dwMaxLOD)
1069 {
1070     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1071
1072     TRACE("(%p)->(%08lx)\n",This,dwMaxLOD);
1073     CHECK_TEXTURE(This);
1074
1075     This->max_lod = dwMaxLOD;
1076     return DD_OK;
1077 }
1078
1079 HRESULT WINAPI
1080 Main_DirectDrawSurface_SetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
1081                                           LONG X, LONG Y)
1082 {
1083     return DDERR_NOTAOVERLAYSURFACE;
1084 }
1085
1086 HRESULT WINAPI
1087 Main_DirectDrawSurface_SetPalette(LPDIRECTDRAWSURFACE7 iface,
1088                                   LPDIRECTDRAWPALETTE pPalette)
1089 {
1090     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1091
1092     TRACE("(%p)->(%p)\n",This,pPalette);
1093     if (pPalette == ICOM_INTERFACE(This->palette, IDirectDrawPalette))
1094         return DD_OK;
1095
1096     if (This->palette != NULL) {
1097         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1098             This->palette->global.dwFlags &= ~DDPCAPS_PRIMARYSURFACE;
1099         IDirectDrawPalette_Release(ICOM_INTERFACE(This->palette,
1100                                                   IDirectDrawPalette));
1101     }
1102
1103     This->palette = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette,
1104                                 pPalette);
1105     if (pPalette != NULL) {
1106         IDirectDrawPalette_AddRef(pPalette);
1107         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1108             This->palette->global.dwFlags |= DDPCAPS_PRIMARYSURFACE;
1109     }
1110
1111     This->set_palette(This, This->palette);
1112
1113     return DD_OK;
1114 }
1115
1116 HRESULT WINAPI
1117 Main_DirectDrawSurface_SetPriority(LPDIRECTDRAWSURFACE7 iface,
1118                                    DWORD dwPriority)
1119 {
1120     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1121
1122     TRACE("(%p)->(%08lx)\n",This,dwPriority);
1123     CHECK_TEXTURE(This);
1124
1125     This->priority = dwPriority;
1126     return DD_OK;
1127 }
1128
1129 /* Be careful when locking this: it is risky to call the object's AddRef
1130  * or Release holding a lock. */
1131 HRESULT WINAPI
1132 Main_DirectDrawSurface_SetPrivateData(LPDIRECTDRAWSURFACE7 iface,
1133                                       REFGUID tag, LPVOID pData,
1134                                       DWORD cbSize, DWORD dwFlags)
1135 {
1136     PrivateData* data;
1137     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1138
1139     data = find_private_data(This, tag);
1140     if (data == NULL)
1141     {
1142         data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
1143         if (data == NULL) return DDERR_OUTOFMEMORY;
1144
1145         data->tag = *tag;
1146         data->flags = dwFlags;
1147         data->uniqueness_value = This->uniqueness_value;
1148
1149         if (dwFlags & DDSPD_IUNKNOWNPTR)
1150         {
1151             data->ptr.object = (LPUNKNOWN)pData;
1152             data->size = sizeof(LPUNKNOWN);
1153             IUnknown_AddRef(data->ptr.object);
1154         }
1155         else
1156         {
1157             data->ptr.data = HeapAlloc(GetProcessHeap(), 0, cbSize);
1158             if (data->ptr.data == NULL)
1159             {
1160                 HeapFree(GetProcessHeap(), 0, data);
1161                 return DDERR_OUTOFMEMORY;
1162             }
1163         }
1164
1165         /* link it in */
1166         data->next = This->private_data;
1167         data->prev = NULL;
1168         if (This->private_data)
1169             This->private_data->prev = data;
1170         This->private_data = data;
1171
1172         return DD_OK;
1173     }
1174     else
1175     {
1176         /* I don't actually know how windows handles this case. The only
1177          * reason I don't just call FreePrivateData is because I want to
1178          * guarantee SetPrivateData working when using LPUNKNOWN or data
1179          * that is no larger than the old data. */
1180
1181         return E_FAIL;
1182     }
1183 }
1184
1185 /* SetSurfaceDesc */
1186
1187 HRESULT WINAPI
1188 Main_DirectDrawSurface_Unlock(LPDIRECTDRAWSURFACE7 iface, LPRECT pRect)
1189 {
1190     ICOM_THIS(IDirectDrawSurfaceImpl,iface);
1191
1192     TRACE("(%p)->Unlock(%p)\n",This,pRect);
1193
1194     This->unlock_update(This, pRect);
1195     if (This->aux_unlock)
1196         This->aux_unlock(This->aux_ctx, This->aux_data, pRect);
1197
1198     return DD_OK;
1199 }
1200
1201 HRESULT WINAPI
1202 Main_DirectDrawSurface_UpdateOverlay(LPDIRECTDRAWSURFACE7 iface,
1203                                      LPRECT pSrcRect,
1204                                      LPDIRECTDRAWSURFACE7 pDstSurface,
1205                                      LPRECT pDstRect, DWORD dwFlags,
1206                                      LPDDOVERLAYFX pFX)
1207 {
1208     return DDERR_UNSUPPORTED;
1209 }
1210
1211 /* MSDN: "not currently implemented." */
1212 HRESULT WINAPI
1213 Main_DirectDrawSurface_UpdateOverlayDisplay(LPDIRECTDRAWSURFACE7 iface,
1214                                             DWORD dwFlags)
1215 {
1216     return DDERR_UNSUPPORTED;
1217 }
1218
1219 HRESULT WINAPI
1220 Main_DirectDrawSurface_UpdateOverlayZOrder(LPDIRECTDRAWSURFACE7 iface,
1221                                            DWORD dwFlags,
1222                                            LPDIRECTDRAWSURFACE7 pDDSRef)
1223 {
1224     return DDERR_NOTAOVERLAYSURFACE;
1225 }