ntdll: Implement DVD_ReadStructure.
[wine] / dlls / ddraw / surface_user.c
1 /*      User-based primary surface driver
2  *
3  * Copyright 2000-2001 TransGaming Technologies Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "winerror.h"
27 #include "wine/debug.h"
28 #include "ddraw_private.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
31
32 /* if you use OWN_WINDOW, don't use SYNC_UPDATE, or you may get trouble */
33 /* #define SYNC_UPDATE */
34 /*
35  * FIXME: This does not work any more because the created window has its own
36  *        thread queue that cannot be manipulated by application threads.
37  * #define OWN_WINDOW
38  */
39
40 #ifdef OWN_WINDOW
41 static void User_create_own_window(IDirectDrawSurfaceImpl* This);
42 static void User_destroy_own_window(IDirectDrawSurfaceImpl* This);
43 #endif
44 #ifndef SYNC_UPDATE
45 static DWORD CALLBACK User_update_thread(LPVOID);
46 #endif
47 static void User_copy_to_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc);
48
49 static HWND get_display_window(IDirectDrawSurfaceImpl* This, LPPOINT pt);
50
51 static const IDirectDrawSurface7Vtbl User_IDirectDrawSurface7_VTable;
52
53 HRESULT
54 User_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl* This,
55                                  IDirectDrawImpl* pDD,
56                                  const DDSURFACEDESC2* pDDSD)
57 {
58     USER_PRIV_VAR(priv, This);
59     HRESULT hr;
60
61     TRACE("(%p,%p,%p)\n",This,pDD,pDDSD);
62     hr = DIB_DirectDrawSurface_Construct(This, pDD, pDDSD);
63     if (FAILED(hr)) return hr;
64
65     ICOM_INIT_INTERFACE(This, IDirectDrawSurface7,
66                         User_IDirectDrawSurface7_VTable);
67
68     This->final_release = User_DirectDrawSurface_final_release;
69     This->duplicate_surface = User_DirectDrawSurface_duplicate_surface;
70
71     This->lock_update   = User_DirectDrawSurface_lock_update;
72     This->unlock_update = User_DirectDrawSurface_unlock_update;
73
74     This->flip_data   = User_DirectDrawSurface_flip_data;
75     This->flip_update = User_DirectDrawSurface_flip_update;
76
77     This->get_dc     = User_DirectDrawSurface_get_dc;
78     This->release_dc = User_DirectDrawSurface_release_dc;
79
80     This->set_palette    = User_DirectDrawSurface_set_palette;
81     This->update_palette = User_DirectDrawSurface_update_palette;
82
83     This->get_gamma_ramp = User_DirectDrawSurface_get_gamma_ramp;
84     This->set_gamma_ramp = User_DirectDrawSurface_set_gamma_ramp;
85
86     This->get_display_window = User_DirectDrawSurface_get_display_window;
87
88     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
89     {
90 #ifdef OWN_WINDOW
91         DirectDrawSurface_RegisterClass();
92 #endif
93 #ifndef SYNC_UPDATE
94         InitializeCriticalSection(&priv->user.crit);
95         priv->user.refresh_event = CreateEventW(NULL, TRUE, FALSE, NULL);
96         priv->user.update_event = CreateEventW(NULL, FALSE, FALSE, NULL);
97         priv->user.update_thread = CreateThread(NULL, 0, User_update_thread, This, 0, NULL);
98 #ifdef OWN_WINDOW
99         if (This->ddraw_owner->cooperative_level & DDSCL_FULLSCREEN) {
100             /* wait for window creation (or update thread destruction) */
101             while (WaitForMultipleObjects(1, &priv->user.update_thread, FALSE, 100) == WAIT_TIMEOUT)
102                 if (This->more.lpDDRAWReserved) break;
103             if (!This->more.lpDDRAWReserved) {
104                 ERR("window creation failed\n");
105             }
106         }
107 #endif
108 #else
109 #ifdef OWN_WINDOW
110         User_create_own_window(This);
111 #endif
112 #endif
113         if (!This->more.lpDDRAWReserved)
114             This->more.lpDDRAWReserved = (LPVOID)pDD->window;
115     }
116
117     return DIB_DirectDrawSurface_alloc_dc(This, &priv->user.cached_dc);
118 }
119
120 HRESULT
121 User_DirectDrawSurface_Create(IDirectDrawImpl *pDD,
122                               const DDSURFACEDESC2 *pDDSD,
123                               LPDIRECTDRAWSURFACE7 *ppSurf,
124                               IUnknown *pUnkOuter)
125 {
126     IDirectDrawSurfaceImpl* This;
127     HRESULT hr;
128     assert(pUnkOuter == NULL);
129
130     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
131                      sizeof(*This) + sizeof(User_DirectDrawSurfaceImpl));
132     if (This == NULL) return E_OUTOFMEMORY;
133
134     This->private = (User_DirectDrawSurfaceImpl*)(This+1);
135
136     hr = User_DirectDrawSurface_Construct(This, pDD, pDDSD);
137     if (FAILED(hr))
138         HeapFree(GetProcessHeap(), 0, This);
139     else
140         *ppSurf = ICOM_INTERFACE(This, IDirectDrawSurface7);
141
142     return hr;
143 }
144
145 void User_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This)
146 {
147     USER_PRIV_VAR(priv, This);
148
149     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
150     {
151 #ifndef SYNC_UPDATE
152         HANDLE event = priv->user.update_event;
153         priv->user.update_event = 0;
154         SetEvent(event);
155         TRACE("waiting for update thread to terminate...\n");
156 #ifdef OWN_WINDOW
157         /* dispatch any waiting sendmessages */
158         {
159             MSG msg;
160             PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
161         }
162         /* to avoid deadlocks, allow SendMessages from update thread
163          * through while we wait for it */
164         while (MsgWaitForMultipleObjects(1, &priv->user.update_thread, FALSE,
165                                          INFINITE, QS_SENDMESSAGE) == WAIT_OBJECT_0+1)
166         {
167             MSG msg;
168             PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
169         }
170 #else
171         WaitForSingleObject(priv->user.update_thread,INFINITE);
172 #endif
173         TRACE("update thread terminated\n");
174         CloseHandle(event);
175         CloseHandle(priv->user.update_thread);
176         CloseHandle(priv->user.refresh_event);
177         DeleteCriticalSection(&priv->user.crit);
178 #else
179 #ifdef OWN_WINDOW
180         User_destroy_own_window(This);
181 #endif
182 #endif
183         This->more.lpDDRAWReserved = 0;
184 #ifdef OWN_WINDOW
185         DirectDrawSurface_UnregisterClass();
186 #endif
187     }
188     DIB_DirectDrawSurface_free_dc(This, priv->user.cached_dc);
189     DIB_DirectDrawSurface_final_release(This);
190 }
191
192 static int User_DirectDrawSurface_init_wait(IDirectDrawSurfaceImpl* This)
193 {
194     USER_PRIV_VAR(priv, This);
195     int need_wait;
196     EnterCriticalSection(&priv->user.crit);
197     priv->user.wait_count++;
198     need_wait = priv->user.in_refresh;
199     LeaveCriticalSection(&priv->user.crit);
200     return need_wait;
201 }
202
203 static void User_DirectDrawSurface_end_wait(IDirectDrawSurfaceImpl* This)
204 {
205     USER_PRIV_VAR(priv, This);
206     EnterCriticalSection(&priv->user.crit);
207     if (!--priv->user.wait_count)
208         ResetEvent(priv->user.refresh_event);
209     LeaveCriticalSection(&priv->user.crit);
210 }
211
212 static void User_DirectDrawSurface_wait_update(IDirectDrawSurfaceImpl* This)
213 {
214     USER_PRIV_VAR(priv, This);
215     if (priv->user.in_refresh) {
216         if (User_DirectDrawSurface_init_wait(This))
217             WaitForSingleObject(priv->user.refresh_event, 2);
218         User_DirectDrawSurface_end_wait(This);
219     }
220 }
221
222 void User_DirectDrawSurface_lock_update(IDirectDrawSurfaceImpl* This,
223                                         LPCRECT pRect, DWORD dwFlags)
224 {
225 #if 0
226     if (!(dwFlags & DDLOCK_WRITEONLY))
227         User_copy_from_screen(This, pRect);
228 #endif
229     if (dwFlags & DDLOCK_WAIT) User_DirectDrawSurface_wait_update(This);
230
231     if (pRect) {
232         This->lastlockrect = *pRect;
233     } else {
234         This->lastlockrect.left = This->lastlockrect.right = 0;
235     }
236 }
237
238 void User_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This,
239                                           LPCRECT pRect)
240 {
241     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
242     {
243 #ifdef SYNC_UPDATE
244         User_copy_to_screen(This, pRect);
245 #else
246         USER_PRIV_VAR(priv, This);
247         SetEvent(priv->user.update_event);
248 #endif
249     }
250 }
251
252 void User_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This,
253                                         IDirectDrawPaletteImpl* pal)
254 {
255     USER_PRIV_VAR(priv, This);
256
257     if (!pal) {
258         FIXME("selecting null palette\n");
259         /* I don't think selecting GDI object 0 will work, we should select
260          * the original palette, returned by the first SelectPalette */
261         SelectPalette(priv->user.cached_dc, 0, FALSE);
262         return;
263     }
264
265     SelectPalette(priv->user.cached_dc, pal->hpal, FALSE);
266
267     DIB_DirectDrawSurface_set_palette(This, pal);
268 }
269
270 void User_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This,
271                                            IDirectDrawPaletteImpl* pal,
272                                            DWORD dwStart, DWORD dwCount,
273                                            LPPALETTEENTRY palent)
274 {
275 #ifndef SYNC_UPDATE
276     USER_PRIV_VAR(priv, This);
277 #endif
278
279     DIB_DirectDrawSurface_update_palette(This, pal, dwStart, dwCount, palent);
280     /* FIXME: realize palette on display window */
281
282 #ifndef SYNC_UPDATE
283     /* with async updates, it's probably cool to force an update */
284     SetEvent(priv->user.update_event);
285 #endif
286 }
287
288 HRESULT User_DirectDrawSurface_duplicate_surface(IDirectDrawSurfaceImpl* This,
289                                                  LPDIRECTDRAWSURFACE7* ppDup)
290 {
291     return User_DirectDrawSurface_Create(This->ddraw_owner,
292                                          &This->surface_desc, ppDup, NULL);
293 }
294
295 BOOL User_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
296                                       IDirectDrawSurfaceImpl* back,
297                                       DWORD dwFlags)
298 {
299     USER_PRIV_VAR(front_priv, front);
300     USER_PRIV_VAR(back_priv, back);
301
302     {
303         HDC tmp;
304         tmp = front_priv->user.cached_dc;
305         front_priv->user.cached_dc = back_priv->user.cached_dc;
306         back_priv->user.cached_dc = tmp;
307     }
308
309     return DIB_DirectDrawSurface_flip_data(front, back, dwFlags);
310 }
311
312 void User_DirectDrawSurface_flip_update(IDirectDrawSurfaceImpl* This, DWORD dwFlags)
313 {
314 #ifdef SYNC_UPDATE
315     This->lastlockrect.left = This->lastlockrect.right = 0;
316     assert(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
317     User_copy_to_screen(This,NULL);
318 #else
319     USER_PRIV_VAR(priv, This);
320     assert(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
321     if (dwFlags & DDFLIP_WAIT) User_DirectDrawSurface_wait_update(This);
322     This->lastlockrect.left = This->lastlockrect.right = 0;
323     SetEvent(priv->user.update_event);
324 #endif
325 }
326
327 HRESULT User_DirectDrawSurface_get_dc(IDirectDrawSurfaceImpl* This, HDC* phDC)
328 {
329     USER_PRIV_VAR(priv, This);
330
331     *phDC = priv->user.cached_dc;
332     return S_OK;
333 }
334
335 HRESULT User_DirectDrawSurface_release_dc(IDirectDrawSurfaceImpl* This,
336                                           HDC hDC)
337 {
338     return S_OK;
339 }
340
341 HRESULT User_DirectDrawSurface_get_gamma_ramp(IDirectDrawSurfaceImpl* This,
342                                               DWORD dwFlags,
343                                               LPDDGAMMARAMP lpGammaRamp)
344 {
345     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
346     {
347         POINT offset;
348         HWND hDisplayWnd;
349         HDC hDisplayDC;
350         HRESULT hr;
351         hDisplayWnd = get_display_window(This, &offset);
352         hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
353         hr = GetDeviceGammaRamp(hDisplayDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
354         ReleaseDC(hDisplayWnd, hDisplayDC);
355         return hr;
356     }
357     return Main_DirectDrawSurface_get_gamma_ramp(This, dwFlags, lpGammaRamp);
358 }
359
360 HRESULT User_DirectDrawSurface_set_gamma_ramp(IDirectDrawSurfaceImpl* This,
361                                               DWORD dwFlags,
362                                               LPDDGAMMARAMP lpGammaRamp)
363 {
364     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
365     {
366         POINT offset;
367         HWND hDisplayWnd;
368         HDC hDisplayDC;
369         HRESULT hr;
370         hDisplayWnd = get_display_window(This, &offset);
371         hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
372         hr = SetDeviceGammaRamp(hDisplayDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
373         ReleaseDC(hDisplayWnd, hDisplayDC);
374         return hr;
375     }
376     return Main_DirectDrawSurface_set_gamma_ramp(This, dwFlags, lpGammaRamp);
377 }
378
379 /* Returns the window that hosts the display.
380  * *pt is set to the upper left position of the window relative to the
381  * upper left corner of the surface. */
382 static HWND get_display_window(IDirectDrawSurfaceImpl* This, LPPOINT pt)
383 {
384     memset(pt, 0, sizeof(*pt));
385
386     if (This->ddraw_owner->cooperative_level & DDSCL_FULLSCREEN)
387     {
388 #ifdef OWN_WINDOW
389         USER_PRIV_VAR(priv, This);
390 #if 1
391         SetWindowPos(priv->user.window, HWND_TOP, 0, 0, 0, 0,
392                      SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|
393                      SWP_NOREDRAW|SWP_NOSENDCHANGING|SWP_NOSIZE);
394 #endif
395         return priv->user.window;
396 #else
397         return This->ddraw_owner->window;
398 #endif
399     }
400     else
401     {
402         if (This->clipper != NULL)
403         {
404             /* looks silly, but since we don't have the clipper locked */
405             HWND hWnd = This->clipper->hWnd;
406
407             if (hWnd != 0)
408             {
409                 ClientToScreen(hWnd, pt);
410                 return hWnd;
411             }
412             else
413             {
414                 static BOOL warn = 0;
415                 if (!warn++) FIXME("clipper clip lists not supported\n");
416
417                 return GetDesktopWindow();
418             }
419         }
420         else
421         {
422             static BOOL warn = 0;
423             if (!warn++) WARN("hosting on root\n");
424
425             return GetDesktopWindow();
426         }
427     }
428 }
429
430 HWND User_DirectDrawSurface_get_display_window(IDirectDrawSurfaceImpl* This)
431 {
432     POINT offset;
433     return get_display_window(This, &offset);
434 }
435
436 #ifdef OWN_WINDOW
437 static void User_create_own_window(IDirectDrawSurfaceImpl* This)
438 {
439     USER_PRIV_VAR(priv, This);
440
441     if (This->ddraw_owner->cooperative_level & DDSCL_FULLSCREEN)
442     {
443         priv->user.window = CreateWindowExA(WS_EX_TOPMOST |
444                                             WS_EX_LAYERED |
445                                             WS_EX_TRANSPARENT,
446                                             "WINE_DDRAW", "DirectDraw",
447                                             WS_POPUP,
448                                             0, 0,
449                                             This->surface_desc.dwWidth,
450                                             This->surface_desc.dwHeight,
451                                             GetDesktopWindow(),
452                                             0, 0, This);
453         This->more.lpDDRAWReserved = (LPVOID)priv->user.window;
454         SetWindowPos(priv->user.window, HWND_TOP, 0, 0, 0, 0,
455                      SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|
456                      SWP_NOREDRAW|SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_SHOWWINDOW);
457         UpdateWindow(priv->user.window);
458     }
459 }
460
461 static void User_destroy_own_window(IDirectDrawSurfaceImpl* This)
462 {
463     USER_PRIV_VAR(priv, This);
464
465     if (priv->user.window)
466     {
467         SetWindowPos(priv->user.window, 0, 0, 0, 0, 0,
468                      SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOZORDER|
469                      SWP_NOREDRAW|SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_HIDEWINDOW);
470         This->more.lpDDRAWReserved = NULL;
471         DestroyWindow(priv->user.window);
472         priv->user.window = 0;
473     }
474 }
475 #endif
476
477 #ifndef SYNC_UPDATE
478 static DWORD CALLBACK User_update_thread(LPVOID arg)
479 {
480     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)arg;
481     USER_PRIV_VAR(priv, This);
482     volatile HANDLE *pActive = (volatile HANDLE *)&priv->user.update_event;
483     HANDLE event = *pActive;
484
485 #ifdef OWN_WINDOW
486     User_create_own_window(This);
487 #endif
488
489     /* the point of this is that many games lock the primary surface
490      * multiple times per frame; this thread will then simply copy as
491      * often as it can without keeping the main thread waiting for
492      * each unlock, thus keeping the frame rate high */
493     do {
494 #ifdef OWN_WINDOW
495         DWORD ret = MsgWaitForMultipleObjects(1, &event, FALSE, INFINITE, QS_ALLINPUT);
496         MSG msg;
497
498         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
499         {
500             switch (msg.message) {
501             case WM_PAINT:
502                 DispatchMessageA(&msg);
503                 break;
504             default:
505                 /* since we risk getting keyboard messages posted to us,
506                  * repost posted messages to cooperative window */
507                 PostMessageA(This->ddraw_owner->window, msg.message, msg.wParam, msg.lParam);
508             }
509         }
510 #else
511         DWORD ret = WaitForSingleObject(event, INFINITE);
512 #endif
513         if (ret == WAIT_OBJECT_0)
514         {
515             if (*pActive) {
516                 priv->user.in_refresh = TRUE;
517                 User_copy_to_screen(This, NULL);
518                 EnterCriticalSection(&priv->user.crit);
519                 priv->user.in_refresh = FALSE;
520                 if (priv->user.wait_count)
521                     SetEvent(priv->user.refresh_event);
522                 LeaveCriticalSection(&priv->user.crit);
523             } else
524                 break;
525         }
526         else if (ret != WAIT_OBJECT_0+1) break;
527     } while (TRUE);
528
529     SetEvent(priv->user.refresh_event);
530 #ifdef OWN_WINDOW
531     User_destroy_own_window(This);
532 #endif
533
534     return 0;
535 }
536 #endif
537
538 static void User_copy_to_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc)
539 {
540     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
541     {
542         POINT offset;
543         HWND hDisplayWnd;
544         HDC hDisplayDC;
545         HDC hSurfaceDC;
546         RECT drawrect;
547
548         if (FAILED(This->get_dc(This, &hSurfaceDC)))
549             return;
550
551         hDisplayWnd = get_display_window(This, &offset);
552         hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
553 #if 0
554         /* FIXME: this doesn't work... if users really want to run
555          * X in 8bpp, then we need to call directly into display.drv
556          * (or Wine's equivalent), and force a private colormap
557          * without default entries. */
558         if (This->palette) {
559             SelectPalette(hDisplayDC, This->palette->hpal, FALSE);
560             RealizePalette(hDisplayDC); /* sends messages => deadlocks */
561         }
562 #endif
563         drawrect.left   = 0;
564         drawrect.right  = This->surface_desc.dwWidth;
565         drawrect.top    = 0;
566         drawrect.bottom = This->surface_desc.dwHeight;
567
568         if (This->clipper) {
569             RECT xrc;
570             HWND hwnd = This->clipper->hWnd;
571             if (hwnd && GetClientRect(hwnd,&xrc)) {
572                 OffsetRect(&xrc,offset.x,offset.y);
573                 IntersectRect(&drawrect,&drawrect,&xrc);
574             }
575         }
576         if (rc)
577             IntersectRect(&drawrect,&drawrect,rc);
578         else {
579             /* Only use this if the caller did not pass a rectangle, since
580              * due to double locking this could be the wrong one ... */
581             if (This->lastlockrect.left != This->lastlockrect.right)
582                 IntersectRect(&drawrect,&drawrect,&This->lastlockrect);
583         }
584         BitBlt(hDisplayDC,
585                 drawrect.left-offset.x, drawrect.top-offset.y,
586                 drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
587                 hSurfaceDC,
588                 drawrect.left, drawrect.top,
589                 SRCCOPY
590         );
591         ReleaseDC(hDisplayWnd, hDisplayDC);
592     }
593 }
594
595 #if 0
596 static void User_copy_from_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc)
597 {
598     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
599     {
600         POINT offset;
601         HWND hDisplayWnd = get_display_window(This, &offset);
602         HDC hDisplayDC = GetDC(hDisplayWnd);
603         RECT drawrect;
604
605         drawrect.left   = 0;
606         drawrect.right  = This->surface_desc.dwWidth;
607         drawrect.top    = 0;
608         drawrect.bottom = This->surface_desc.dwHeight;
609         if (rc)
610             IntersectRect(&drawrect,&drawrect,rc);
611
612         BitBlt(This->hDC,
613             drawrect.left, drawrect.top,
614             drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
615             hDisplayDC,
616             drawrect.left+offset.x, drawrect.top+offset.y,
617             SRCCOPY
618         );
619         ReleaseDC(hDisplayWnd, hDisplayDC);
620     }
621 }
622 #endif
623
624 static const IDirectDrawSurface7Vtbl User_IDirectDrawSurface7_VTable =
625 {
626     Main_DirectDrawSurface_QueryInterface,
627     Main_DirectDrawSurface_AddRef,
628     Main_DirectDrawSurface_Release,
629     Main_DirectDrawSurface_AddAttachedSurface,
630     Main_DirectDrawSurface_AddOverlayDirtyRect,
631     DIB_DirectDrawSurface_Blt,
632     Main_DirectDrawSurface_BltBatch,
633     DIB_DirectDrawSurface_BltFast,
634     Main_DirectDrawSurface_DeleteAttachedSurface,
635     Main_DirectDrawSurface_EnumAttachedSurfaces,
636     Main_DirectDrawSurface_EnumOverlayZOrders,
637     Main_DirectDrawSurface_Flip,
638     Main_DirectDrawSurface_GetAttachedSurface,
639     Main_DirectDrawSurface_GetBltStatus,
640     Main_DirectDrawSurface_GetCaps,
641     Main_DirectDrawSurface_GetClipper,
642     Main_DirectDrawSurface_GetColorKey,
643     Main_DirectDrawSurface_GetDC,
644     Main_DirectDrawSurface_GetFlipStatus,
645     Main_DirectDrawSurface_GetOverlayPosition,
646     Main_DirectDrawSurface_GetPalette,
647     Main_DirectDrawSurface_GetPixelFormat,
648     Main_DirectDrawSurface_GetSurfaceDesc,
649     Main_DirectDrawSurface_Initialize,
650     Main_DirectDrawSurface_IsLost,
651     Main_DirectDrawSurface_Lock,
652     Main_DirectDrawSurface_ReleaseDC,
653     DIB_DirectDrawSurface_Restore,
654     Main_DirectDrawSurface_SetClipper,
655     Main_DirectDrawSurface_SetColorKey,
656     Main_DirectDrawSurface_SetOverlayPosition,
657     Main_DirectDrawSurface_SetPalette,
658     Main_DirectDrawSurface_Unlock,
659     Main_DirectDrawSurface_UpdateOverlay,
660     Main_DirectDrawSurface_UpdateOverlayDisplay,
661     Main_DirectDrawSurface_UpdateOverlayZOrder,
662     Main_DirectDrawSurface_GetDDInterface,
663     Main_DirectDrawSurface_PageLock,
664     Main_DirectDrawSurface_PageUnlock,
665     DIB_DirectDrawSurface_SetSurfaceDesc,
666     Main_DirectDrawSurface_SetPrivateData,
667     Main_DirectDrawSurface_GetPrivateData,
668     Main_DirectDrawSurface_FreePrivateData,
669     Main_DirectDrawSurface_GetUniquenessValue,
670     Main_DirectDrawSurface_ChangeUniquenessValue,
671     Main_DirectDrawSurface_SetPriority,
672     Main_DirectDrawSurface_GetPriority,
673     Main_DirectDrawSurface_SetLOD,
674     Main_DirectDrawSurface_GetLOD
675 };