| /* User-based primary surface driver | |
| * | |
| * Copyright 2000-2001 TransGaming Technologies Inc. | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include "config.h" | |
| #include <assert.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "winerror.h" | |
| #include "wine/debug.h" | |
| #include "ddraw_private.h" | |
| #include "dsurface/main.h" | |
| #include "dsurface/dib.h" | |
| #include "dsurface/user.h" | |
| #include "dsurface/wndproc.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(ddraw); | |
| /* if you use OWN_WINDOW, don't use SYNC_UPDATE, or you may get trouble */ | |
| /* #define SYNC_UPDATE */ | |
| /* | |
| * FIXME: This does not work any more because the created window has its own | |
| * thread queue that cannot be manipulated by application threads. | |
| * #define OWN_WINDOW | |
| */ | |
| #ifdef OWN_WINDOW | |
| static void User_create_own_window(IDirectDrawSurfaceImpl* This); | |
| static void User_destroy_own_window(IDirectDrawSurfaceImpl* This); | |
| #endif | |
| #ifndef SYNC_UPDATE | |
| static DWORD CALLBACK User_update_thread(LPVOID); | |
| #endif | |
| static void User_copy_to_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc); | |
| static HWND get_display_window(IDirectDrawSurfaceImpl* This, LPPOINT pt); | |
| static ICOM_VTABLE(IDirectDrawSurface7) User_IDirectDrawSurface7_VTable; | |
| HRESULT | |
| User_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl* This, | |
| IDirectDrawImpl* pDD, | |
| const DDSURFACEDESC2* pDDSD) | |
| { | |
| USER_PRIV_VAR(priv, This); | |
| HRESULT hr; | |
| TRACE("(%p,%p,%p)\n",This,pDD,pDDSD); | |
| hr = DIB_DirectDrawSurface_Construct(This, pDD, pDDSD); | |
| if (FAILED(hr)) return hr; | |
| ICOM_INIT_INTERFACE(This, IDirectDrawSurface7, | |
| User_IDirectDrawSurface7_VTable); | |
| This->final_release = User_DirectDrawSurface_final_release; | |
| This->duplicate_surface = User_DirectDrawSurface_duplicate_surface; | |
| This->lock_update = User_DirectDrawSurface_lock_update; | |
| This->unlock_update = User_DirectDrawSurface_unlock_update; | |
| This->flip_data = User_DirectDrawSurface_flip_data; | |
| This->flip_update = User_DirectDrawSurface_flip_update; | |
| This->get_dc = User_DirectDrawSurface_get_dc; | |
| This->release_dc = User_DirectDrawSurface_release_dc; | |
| This->set_palette = User_DirectDrawSurface_set_palette; | |
| This->update_palette = User_DirectDrawSurface_update_palette; | |
| This->get_gamma_ramp = User_DirectDrawSurface_get_gamma_ramp; | |
| This->set_gamma_ramp = User_DirectDrawSurface_set_gamma_ramp; | |
| This->get_display_window = User_DirectDrawSurface_get_display_window; | |
| if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | |
| { | |
| #ifdef OWN_WINDOW | |
| DirectDrawSurface_RegisterClass(); | |
| #endif | |
| #ifndef SYNC_UPDATE | |
| InitializeCriticalSection(&priv->user.crit); | |
| priv->user.refresh_event = CreateEventA(NULL, TRUE, FALSE, NULL); | |
| priv->user.update_event = CreateEventA(NULL, FALSE, FALSE, NULL); | |
| priv->user.update_thread = CreateThread(NULL, 0, User_update_thread, This, 0, NULL); | |
| #ifdef OWN_WINDOW | |
| if (This->ddraw_owner->cooperative_level & DDSCL_FULLSCREEN) { | |
| /* wait for window creation (or update thread destruction) */ | |
| while (WaitForMultipleObjects(1, &priv->user.update_thread, FALSE, 100) == WAIT_TIMEOUT) | |
| if (This->more.lpDDRAWReserved) break; | |
| if (!This->more.lpDDRAWReserved) { | |
| ERR("window creation failed\n"); | |
| } | |
| } | |
| #endif | |
| #else | |
| #ifdef OWN_WINDOW | |
| User_create_own_window(This); | |
| #endif | |
| #endif | |
| if (!This->more.lpDDRAWReserved) | |
| This->more.lpDDRAWReserved = (LPVOID)pDD->window; | |
| } | |
| return DIB_DirectDrawSurface_alloc_dc(This, &priv->user.cached_dc); | |
| } | |
| HRESULT | |
| User_DirectDrawSurface_Create(IDirectDrawImpl *pDD, | |
| const DDSURFACEDESC2 *pDDSD, | |
| LPDIRECTDRAWSURFACE7 *ppSurf, | |
| IUnknown *pUnkOuter) | |
| { | |
| IDirectDrawSurfaceImpl* This; | |
| HRESULT hr; | |
| assert(pUnkOuter == NULL); | |
| This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | |
| sizeof(*This) + sizeof(User_DirectDrawSurfaceImpl)); | |
| if (This == NULL) return E_OUTOFMEMORY; | |
| This->private = (User_DirectDrawSurfaceImpl*)(This+1); | |
| hr = User_DirectDrawSurface_Construct(This, pDD, pDDSD); | |
| if (FAILED(hr)) | |
| HeapFree(GetProcessHeap(), 0, This); | |
| else | |
| *ppSurf = ICOM_INTERFACE(This, IDirectDrawSurface7); | |
| return hr; | |
| } | |
| void User_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This) | |
| { | |
| USER_PRIV_VAR(priv, This); | |
| if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | |
| { | |
| #ifndef SYNC_UPDATE | |
| HANDLE event = priv->user.update_event; | |
| priv->user.update_event = 0; | |
| SetEvent(event); | |
| TRACE("waiting for update thread to terminate...\n"); | |
| #ifdef OWN_WINDOW | |
| /* dispatch any waiting sendmessages */ | |
| { | |
| MSG msg; | |
| PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE); | |
| } | |
| /* to avoid deadlocks, allow SendMessages from update thread | |
| * through while we wait for it */ | |
| while (MsgWaitForMultipleObjects(1, &priv->user.update_thread, FALSE, | |
| INFINITE, QS_SENDMESSAGE) == WAIT_OBJECT_0+1) | |
| { | |
| MSG msg; | |
| PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE); | |
| } | |
| #else | |
| WaitForSingleObject(priv->user.update_thread,INFINITE); | |
| #endif | |
| TRACE("update thread terminated\n"); | |
| CloseHandle(event); | |
| CloseHandle(priv->user.update_thread); | |
| CloseHandle(priv->user.refresh_event); | |
| DeleteCriticalSection(&priv->user.crit); | |
| #else | |
| #ifdef OWN_WINDOW | |
| User_destroy_own_window(This); | |
| #endif | |
| #endif | |
| This->more.lpDDRAWReserved = 0; | |
| #ifdef OWN_WINDOW | |
| DirectDrawSurface_UnregisterClass(); | |
| #endif | |
| } | |
| DIB_DirectDrawSurface_free_dc(This, priv->user.cached_dc); | |
| DIB_DirectDrawSurface_final_release(This); | |
| } | |
| static int User_DirectDrawSurface_init_wait(IDirectDrawSurfaceImpl* This) | |
| { | |
| USER_PRIV_VAR(priv, This); | |
| int need_wait; | |
| EnterCriticalSection(&priv->user.crit); | |
| priv->user.wait_count++; | |
| need_wait = priv->user.in_refresh; | |
| LeaveCriticalSection(&priv->user.crit); | |
| return need_wait; | |
| } | |
| static void User_DirectDrawSurface_end_wait(IDirectDrawSurfaceImpl* This) | |
| { | |
| USER_PRIV_VAR(priv, This); | |
| EnterCriticalSection(&priv->user.crit); | |
| if (!--priv->user.wait_count) | |
| ResetEvent(priv->user.refresh_event); | |
| LeaveCriticalSection(&priv->user.crit); | |
| } | |
| static void User_DirectDrawSurface_wait_update(IDirectDrawSurfaceImpl* This) | |
| { | |
| USER_PRIV_VAR(priv, This); | |
| if (priv->user.in_refresh) { | |
| if (User_DirectDrawSurface_init_wait(This)) | |
| WaitForSingleObject(priv->user.refresh_event, 2); | |
| User_DirectDrawSurface_end_wait(This); | |
| } | |
| } | |
| void User_DirectDrawSurface_lock_update(IDirectDrawSurfaceImpl* This, | |
| LPCRECT pRect, DWORD dwFlags) | |
| { | |
| #if 0 | |
| if (!(dwFlags & DDLOCK_WRITEONLY)) | |
| User_copy_from_screen(This, pRect); | |
| #endif | |
| if (dwFlags & DDLOCK_WAIT) User_DirectDrawSurface_wait_update(This); | |
| if (pRect) { | |
| This->lastlockrect = *pRect; | |
| } else { | |
| This->lastlockrect.left = This->lastlockrect.right = 0; | |
| } | |
| } | |
| void User_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This, | |
| LPCRECT pRect) | |
| { | |
| if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | |
| { | |
| #ifdef SYNC_UPDATE | |
| User_copy_to_screen(This, pRect); | |
| #else | |
| USER_PRIV_VAR(priv, This); | |
| SetEvent(priv->user.update_event); | |
| #endif | |
| } | |
| } | |
| void User_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This, | |
| IDirectDrawPaletteImpl* pal) | |
| { | |
| USER_PRIV_VAR(priv, This); | |
| if (!pal) { | |
| FIXME("selecting null palette\n"); | |
| /* I don't think selecting GDI object 0 will work, we should select | |
| * the original palette, returned by the first SelectPalette */ | |
| SelectPalette(priv->user.cached_dc, 0, FALSE); | |
| return; | |
| } | |
| SelectPalette(priv->user.cached_dc, pal->hpal, FALSE); | |
| DIB_DirectDrawSurface_set_palette(This, pal); | |
| } | |
| void User_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This, | |
| IDirectDrawPaletteImpl* pal, | |
| DWORD dwStart, DWORD dwCount, | |
| LPPALETTEENTRY palent) | |
| { | |
| #ifndef SYNC_UPDATE | |
| USER_PRIV_VAR(priv, This); | |
| #endif | |
| DIB_DirectDrawSurface_update_palette(This, pal, dwStart, dwCount, palent); | |
| /* FIXME: realize palette on display window */ | |
| #ifndef SYNC_UPDATE | |
| /* with async updates, it's probably cool to force an update */ | |
| SetEvent(priv->user.update_event); | |
| #endif | |
| } | |
| HRESULT User_DirectDrawSurface_duplicate_surface(IDirectDrawSurfaceImpl* This, | |
| LPDIRECTDRAWSURFACE7* ppDup) | |
| { | |
| return User_DirectDrawSurface_Create(This->ddraw_owner, | |
| &This->surface_desc, ppDup, NULL); | |
| } | |
| BOOL User_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front, | |
| IDirectDrawSurfaceImpl* back, | |
| DWORD dwFlags) | |
| { | |
| USER_PRIV_VAR(front_priv, front); | |
| USER_PRIV_VAR(back_priv, back); | |
| { | |
| HDC tmp; | |
| tmp = front_priv->user.cached_dc; | |
| front_priv->user.cached_dc = back_priv->user.cached_dc; | |
| back_priv->user.cached_dc = tmp; | |
| } | |
| return DIB_DirectDrawSurface_flip_data(front, back, dwFlags); | |
| } | |
| void User_DirectDrawSurface_flip_update(IDirectDrawSurfaceImpl* This, DWORD dwFlags) | |
| { | |
| #ifdef SYNC_UPDATE | |
| This->lastlockrect.left = This->lastlockrect.right = 0; | |
| assert(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE); | |
| User_copy_to_screen(This,NULL); | |
| #else | |
| USER_PRIV_VAR(priv, This); | |
| assert(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE); | |
| if (dwFlags & DDFLIP_WAIT) User_DirectDrawSurface_wait_update(This); | |
| This->lastlockrect.left = This->lastlockrect.right = 0; | |
| SetEvent(priv->user.update_event); | |
| #endif | |
| } | |
| HRESULT User_DirectDrawSurface_get_dc(IDirectDrawSurfaceImpl* This, HDC* phDC) | |
| { | |
| USER_PRIV_VAR(priv, This); | |
| *phDC = priv->user.cached_dc; | |
| return S_OK; | |
| } | |
| HRESULT User_DirectDrawSurface_release_dc(IDirectDrawSurfaceImpl* This, | |
| HDC hDC) | |
| { | |
| return S_OK; | |
| } | |
| HRESULT User_DirectDrawSurface_get_gamma_ramp(IDirectDrawSurfaceImpl* This, | |
| DWORD dwFlags, | |
| LPDDGAMMARAMP lpGammaRamp) | |
| { | |
| if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | |
| { | |
| POINT offset; | |
| HWND hDisplayWnd; | |
| HDC hDisplayDC; | |
| HRESULT hr; | |
| hDisplayWnd = get_display_window(This, &offset); | |
| hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE); | |
| hr = GetDeviceGammaRamp(hDisplayDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED; | |
| ReleaseDC(hDisplayWnd, hDisplayDC); | |
| return hr; | |
| } | |
| return Main_DirectDrawSurface_get_gamma_ramp(This, dwFlags, lpGammaRamp); | |
| } | |
| HRESULT User_DirectDrawSurface_set_gamma_ramp(IDirectDrawSurfaceImpl* This, | |
| DWORD dwFlags, | |
| LPDDGAMMARAMP lpGammaRamp) | |
| { | |
| if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | |
| { | |
| POINT offset; | |
| HWND hDisplayWnd; | |
| HDC hDisplayDC; | |
| HRESULT hr; | |
| hDisplayWnd = get_display_window(This, &offset); | |
| hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE); | |
| hr = SetDeviceGammaRamp(hDisplayDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED; | |
| ReleaseDC(hDisplayWnd, hDisplayDC); | |
| return hr; | |
| } | |
| return Main_DirectDrawSurface_set_gamma_ramp(This, dwFlags, lpGammaRamp); | |
| } | |
| /* Returns the window that hosts the display. | |
| * *pt is set to the upper left position of the window relative to the | |
| * upper left corner of the surface. */ | |
| static HWND get_display_window(IDirectDrawSurfaceImpl* This, LPPOINT pt) | |
| { | |
| memset(pt, 0, sizeof(*pt)); | |
| if (This->ddraw_owner->cooperative_level & DDSCL_FULLSCREEN) | |
| { | |
| #ifdef OWN_WINDOW | |
| USER_PRIV_VAR(priv, This); | |
| #if 1 | |
| SetWindowPos(priv->user.window, HWND_TOP, 0, 0, 0, 0, | |
| SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE| | |
| SWP_NOREDRAW|SWP_NOSENDCHANGING|SWP_NOSIZE); | |
| #endif | |
| return priv->user.window; | |
| #else | |
| return This->ddraw_owner->window; | |
| #endif | |
| } | |
| else | |
| { | |
| if (This->clipper != NULL) | |
| { | |
| /* looks silly, but since we don't have the clipper locked */ | |
| HWND hWnd = This->clipper->hWnd; | |
| if (hWnd != 0) | |
| { | |
| ClientToScreen(hWnd, pt); | |
| return hWnd; | |
| } | |
| else | |
| { | |
| static BOOL warn = 0; | |
| if (!warn++) FIXME("clipper clip lists not supported\n"); | |
| return GetDesktopWindow(); | |
| } | |
| } | |
| else | |
| { | |
| static BOOL warn = 0; | |
| if (!warn++) WARN("hosting on root\n"); | |
| return GetDesktopWindow(); | |
| } | |
| } | |
| } | |
| HWND User_DirectDrawSurface_get_display_window(IDirectDrawSurfaceImpl* This) | |
| { | |
| POINT offset; | |
| return get_display_window(This, &offset); | |
| } | |
| #ifdef OWN_WINDOW | |
| static void User_create_own_window(IDirectDrawSurfaceImpl* This) | |
| { | |
| USER_PRIV_VAR(priv, This); | |
| if (This->ddraw_owner->cooperative_level & DDSCL_FULLSCREEN) | |
| { | |
| priv->user.window = CreateWindowExA(WS_EX_TOPMOST | | |
| WS_EX_LAYERED | | |
| WS_EX_TRANSPARENT, | |
| "WINE_DDRAW", "DirectDraw", | |
| WS_POPUP, | |
| 0, 0, | |
| This->surface_desc.dwWidth, | |
| This->surface_desc.dwHeight, | |
| GetDesktopWindow(), | |
| 0, 0, This); | |
| This->more.lpDDRAWReserved = (LPVOID)priv->user.window; | |
| SetWindowPos(priv->user.window, HWND_TOP, 0, 0, 0, 0, | |
| SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE| | |
| SWP_NOREDRAW|SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_SHOWWINDOW); | |
| UpdateWindow(priv->user.window); | |
| } | |
| } | |
| static void User_destroy_own_window(IDirectDrawSurfaceImpl* This) | |
| { | |
| USER_PRIV_VAR(priv, This); | |
| if (priv->user.window) | |
| { | |
| SetWindowPos(priv->user.window, 0, 0, 0, 0, 0, | |
| SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOZORDER| | |
| SWP_NOREDRAW|SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_HIDEWINDOW); | |
| This->more.lpDDRAWReserved = NULL; | |
| DestroyWindow(priv->user.window); | |
| priv->user.window = 0; | |
| } | |
| } | |
| #endif | |
| #ifndef SYNC_UPDATE | |
| static DWORD CALLBACK User_update_thread(LPVOID arg) | |
| { | |
| IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)arg; | |
| USER_PRIV_VAR(priv, This); | |
| volatile HANDLE *pActive = (volatile HANDLE *)&priv->user.update_event; | |
| HANDLE event = *pActive; | |
| #ifdef OWN_WINDOW | |
| User_create_own_window(This); | |
| #endif | |
| /* the point of this is that many games lock the primary surface | |
| * multiple times per frame; this thread will then simply copy as | |
| * often as it can without keeping the main thread waiting for | |
| * each unlock, thus keeping the frame rate high */ | |
| do { | |
| #ifdef OWN_WINDOW | |
| DWORD ret = MsgWaitForMultipleObjects(1, &event, FALSE, INFINITE, QS_ALLINPUT); | |
| MSG msg; | |
| while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) | |
| { | |
| switch (msg.message) { | |
| case WM_PAINT: | |
| DispatchMessageA(&msg); | |
| break; | |
| default: | |
| /* since we risk getting keyboard messages posted to us, | |
| * repost posted messages to cooperative window */ | |
| PostMessageA(This->ddraw_owner->window, msg.message, msg.wParam, msg.lParam); | |
| } | |
| } | |
| #else | |
| DWORD ret = WaitForSingleObject(event, INFINITE); | |
| #endif | |
| if (ret == WAIT_OBJECT_0) | |
| { | |
| if (*pActive) { | |
| priv->user.in_refresh = TRUE; | |
| User_copy_to_screen(This, NULL); | |
| EnterCriticalSection(&priv->user.crit); | |
| priv->user.in_refresh = FALSE; | |
| if (priv->user.wait_count) | |
| SetEvent(priv->user.refresh_event); | |
| LeaveCriticalSection(&priv->user.crit); | |
| } else | |
| break; | |
| } | |
| else if (ret != WAIT_OBJECT_0+1) break; | |
| } while (TRUE); | |
| SetEvent(priv->user.refresh_event); | |
| #ifdef OWN_WINDOW | |
| User_destroy_own_window(This); | |
| #endif | |
| return 0; | |
| } | |
| #endif | |
| static void User_copy_to_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc) | |
| { | |
| if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | |
| { | |
| POINT offset; | |
| HWND hDisplayWnd; | |
| HDC hDisplayDC; | |
| HDC hSurfaceDC; | |
| RECT drawrect; | |
| if (FAILED(This->get_dc(This, &hSurfaceDC))) | |
| return; | |
| hDisplayWnd = get_display_window(This, &offset); | |
| hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE); | |
| #if 0 | |
| /* FIXME: this doesn't work... if users really want to run | |
| * X in 8bpp, then we need to call directly into display.drv | |
| * (or Wine's equivalent), and force a private colormap | |
| * without default entries. */ | |
| if (This->palette) { | |
| SelectPalette(hDisplayDC, This->palette->hpal, FALSE); | |
| RealizePalette(hDisplayDC); /* sends messages => deadlocks */ | |
| } | |
| #endif | |
| drawrect.left = 0; | |
| drawrect.right = This->surface_desc.dwWidth; | |
| drawrect.top = 0; | |
| drawrect.bottom = This->surface_desc.dwHeight; | |
| if (This->clipper) { | |
| RECT xrc; | |
| HWND hwnd = This->clipper->hWnd; | |
| if (hwnd && GetClientRect(hwnd,&xrc)) { | |
| OffsetRect(&xrc,offset.x,offset.y); | |
| IntersectRect(&drawrect,&drawrect,&xrc); | |
| } | |
| } | |
| if (rc) | |
| IntersectRect(&drawrect,&drawrect,rc); | |
| else { | |
| /* Only use this if the caller did not pass a rectangle, since | |
| * due to double locking this could be the wrong one ... */ | |
| if (This->lastlockrect.left != This->lastlockrect.right) | |
| IntersectRect(&drawrect,&drawrect,&This->lastlockrect); | |
| } | |
| BitBlt(hDisplayDC, | |
| drawrect.left-offset.x, drawrect.top-offset.y, | |
| drawrect.right-drawrect.left, drawrect.bottom-drawrect.top, | |
| hSurfaceDC, | |
| drawrect.left, drawrect.top, | |
| SRCCOPY | |
| ); | |
| ReleaseDC(hDisplayWnd, hDisplayDC); | |
| } | |
| } | |
| #if 0 | |
| static void User_copy_from_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc) | |
| { | |
| if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) | |
| { | |
| POINT offset; | |
| HWND hDisplayWnd = get_display_window(This, &offset); | |
| HDC hDisplayDC = GetDC(hDisplayWnd); | |
| RECT drawrect; | |
| drawrect.left = 0; | |
| drawrect.right = This->surface_desc.dwWidth; | |
| drawrect.top = 0; | |
| drawrect.bottom = This->surface_desc.dwHeight; | |
| if (rc) | |
| IntersectRect(&drawrect,&drawrect,rc); | |
| BitBlt(This->hDC, | |
| drawrect.left, drawrect.top, | |
| drawrect.right-drawrect.left, drawrect.bottom-drawrect.top, | |
| hDisplayDC, | |
| drawrect.left+offset.x, drawrect.top+offset.y, | |
| SRCCOPY | |
| ); | |
| ReleaseDC(hDisplayWnd, hDisplayDC); | |
| } | |
| } | |
| #endif | |
| static ICOM_VTABLE(IDirectDrawSurface7) User_IDirectDrawSurface7_VTable = | |
| { | |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE | |
| Main_DirectDrawSurface_QueryInterface, | |
| Main_DirectDrawSurface_AddRef, | |
| Main_DirectDrawSurface_Release, | |
| Main_DirectDrawSurface_AddAttachedSurface, | |
| Main_DirectDrawSurface_AddOverlayDirtyRect, | |
| DIB_DirectDrawSurface_Blt, | |
| Main_DirectDrawSurface_BltBatch, | |
| DIB_DirectDrawSurface_BltFast, | |
| Main_DirectDrawSurface_DeleteAttachedSurface, | |
| Main_DirectDrawSurface_EnumAttachedSurfaces, | |
| Main_DirectDrawSurface_EnumOverlayZOrders, | |
| Main_DirectDrawSurface_Flip, | |
| Main_DirectDrawSurface_GetAttachedSurface, | |
| Main_DirectDrawSurface_GetBltStatus, | |
| Main_DirectDrawSurface_GetCaps, | |
| Main_DirectDrawSurface_GetClipper, | |
| Main_DirectDrawSurface_GetColorKey, | |
| Main_DirectDrawSurface_GetDC, | |
| Main_DirectDrawSurface_GetFlipStatus, | |
| Main_DirectDrawSurface_GetOverlayPosition, | |
| Main_DirectDrawSurface_GetPalette, | |
| Main_DirectDrawSurface_GetPixelFormat, | |
| Main_DirectDrawSurface_GetSurfaceDesc, | |
| Main_DirectDrawSurface_Initialize, | |
| Main_DirectDrawSurface_IsLost, | |
| Main_DirectDrawSurface_Lock, | |
| Main_DirectDrawSurface_ReleaseDC, | |
| DIB_DirectDrawSurface_Restore, | |
| Main_DirectDrawSurface_SetClipper, | |
| Main_DirectDrawSurface_SetColorKey, | |
| Main_DirectDrawSurface_SetOverlayPosition, | |
| Main_DirectDrawSurface_SetPalette, | |
| Main_DirectDrawSurface_Unlock, | |
| Main_DirectDrawSurface_UpdateOverlay, | |
| Main_DirectDrawSurface_UpdateOverlayDisplay, | |
| Main_DirectDrawSurface_UpdateOverlayZOrder, | |
| Main_DirectDrawSurface_GetDDInterface, | |
| Main_DirectDrawSurface_PageLock, | |
| Main_DirectDrawSurface_PageUnlock, | |
| DIB_DirectDrawSurface_SetSurfaceDesc, | |
| Main_DirectDrawSurface_SetPrivateData, | |
| Main_DirectDrawSurface_GetPrivateData, | |
| Main_DirectDrawSurface_FreePrivateData, | |
| Main_DirectDrawSurface_GetUniquenessValue, | |
| Main_DirectDrawSurface_ChangeUniquenessValue, | |
| Main_DirectDrawSurface_SetPriority, | |
| Main_DirectDrawSurface_GetPriority, | |
| Main_DirectDrawSurface_SetLOD, | |
| Main_DirectDrawSurface_GetLOD | |
| }; |