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