diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index c960ace3d1..705a00289f 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -90,8 +90,10 @@ static void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface) mode.Format = This->orig_fmt; IWineD3DDevice_SetDisplayMode((IWineD3DDevice *)This->device, 0, &mode); } - HeapFree(GetProcessHeap(), 0, This->context); + wined3d_unregister_window(This->win_handle); + + HeapFree(GetProcessHeap(), 0, This->context); HeapFree(GetProcessHeap(), 0, This); } @@ -676,6 +678,12 @@ HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface window = present_parameters->hDeviceWindow ? present_parameters->hDeviceWindow : device->createParms.hFocusWindow; + if (!wined3d_register_window(window, swapchain)) + { + ERR("Failed to register window %p.\n", window); + return E_FAIL; + } + swapchain->device = device; swapchain->parent = parent; swapchain->ref = 1; @@ -907,6 +915,8 @@ err: if (swapchain->frontBuffer) IWineD3DSurface_Release(swapchain->frontBuffer); + wined3d_unregister_window(window); + return hr; } @@ -951,3 +961,15 @@ void get_drawable_size_swapchain(struct wined3d_context *context, UINT *width, U *width = surface->currentDesc.Width; *height = surface->currentDesc.Height; } + +LRESULT swapchain_process_message(IWineD3DSwapChainImpl *swapchain, HWND window, + UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc) +{ + if (message == WM_DESTROY) + { + TRACE("unregister window %p.\n", window); + wined3d_unregister_window(window); + } + + return CallWindowProcW(proc, window, message, wparam, lparam); +} diff --git a/dlls/wined3d/swapchain_gdi.c b/dlls/wined3d/swapchain_gdi.c index c437b419f8..ed42f55426 100644 --- a/dlls/wined3d/swapchain_gdi.c +++ b/dlls/wined3d/swapchain_gdi.c @@ -70,6 +70,8 @@ static void WINAPI IWineGDISwapChainImpl_Destroy(IWineD3DSwapChain *iface) IWineD3DDevice_SetDisplayMode((IWineD3DDevice *)This->device, 0, &mode); } + wined3d_unregister_window(This->win_handle); + HeapFree(GetProcessHeap(), 0, This->context); HeapFree(GetProcessHeap(), 0, This); } diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c index 5f19c26ab7..d84ad2f963 100644 --- a/dlls/wined3d/wined3d_main.c +++ b/dlls/wined3d/wined3d_main.c @@ -29,6 +29,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d); +struct wined3d_wndproc +{ + HWND window; + WNDPROC proc; + IWineD3DSwapChainImpl *swapchain; +}; + +struct wined3d_wndproc_table +{ + struct wined3d_wndproc *entries; + unsigned int count; + unsigned int size; +}; + +static struct wined3d_wndproc_table wndproc_table; + int num_lock = 0; void (*CDECL wine_tsx11_lock_ptr)(void) = NULL; void (*CDECL wine_tsx11_unlock_ptr)(void) = NULL; @@ -325,6 +341,7 @@ static BOOL wined3d_init(HINSTANCE hInstDLL) static BOOL wined3d_destroy(HINSTANCE hInstDLL) { DWORD wined3d_context_tls_idx = context_get_tls_idx(); + unsigned int i; if (!TlsFree(wined3d_context_tls_idx)) { @@ -332,6 +349,13 @@ static BOOL wined3d_destroy(HINSTANCE hInstDLL) ERR("Failed to free context TLS index, err %#x.\n", err); } + for (i = 0; i < wndproc_table.count; ++i) + { + struct wined3d_wndproc *entry = &wndproc_table.entries[i]; + SetWindowLongPtrW(entry->window, GWLP_WNDPROC, (LONG_PTR)entry->proc); + } + HeapFree(GetProcessHeap(), 0, wndproc_table.entries); + HeapFree(GetProcessHeap(), 0, wined3d_settings.logo); UnregisterClassA(WINED3D_OPENGL_WINDOW_CLASS_NAME, hInstDLL); @@ -348,6 +372,104 @@ void WINAPI wined3d_mutex_unlock(void) LeaveCriticalSection(&wined3d_cs); } +static struct wined3d_wndproc *wined3d_find_wndproc(HWND window) +{ + unsigned int i; + + for (i = 0; i < wndproc_table.count; ++i) + { + if (wndproc_table.entries[i].window == window) + { + return &wndproc_table.entries[i]; + } + } + + return NULL; +} + +static LRESULT CALLBACK wined3d_wndproc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) +{ + IWineD3DSwapChainImpl *swapchain; + struct wined3d_wndproc *entry; + WNDPROC proc; + + wined3d_mutex_lock(); + entry = wined3d_find_wndproc(window); + + if (!entry) + { + wined3d_mutex_unlock(); + ERR("Window %p is not registered with wined3d.\n", window); + return DefWindowProcW(window, message, wparam, lparam); + } + + swapchain = entry->swapchain; + proc = entry->proc; + wined3d_mutex_unlock(); + + return swapchain_process_message(swapchain, window, message, wparam, lparam, proc); +} + +BOOL wined3d_register_window(HWND window, IWineD3DSwapChainImpl *swapchain) +{ + struct wined3d_wndproc *entry; + + wined3d_mutex_lock(); + + if (wndproc_table.size == wndproc_table.count) + { + unsigned int new_size = max(1, wndproc_table.size * 2); + struct wined3d_wndproc *new_entries; + + if (!wndproc_table.entries) new_entries = HeapAlloc(GetProcessHeap(), 0, new_size * sizeof(*new_entries)); + else new_entries = HeapReAlloc(GetProcessHeap(), 0, wndproc_table.entries, new_size * sizeof(*new_entries)); + + if (!new_entries) + { + wined3d_mutex_unlock(); + ERR("Failed to grow table.\n"); + return FALSE; + } + + wndproc_table.entries = new_entries; + wndproc_table.size = new_size; + } + + entry = &wndproc_table.entries[wndproc_table.count++]; + entry->window = window; + entry->proc = (WNDPROC)SetWindowLongPtrW(window, GWLP_WNDPROC, (LONG_PTR)wined3d_wndproc); + entry->swapchain = swapchain; + + wined3d_mutex_unlock(); + + return TRUE; +} + +void wined3d_unregister_window(HWND window) +{ + unsigned int i; + + wined3d_mutex_lock(); + for (i = 0; i < wndproc_table.count; ++i) + { + if (wndproc_table.entries[i].window == window) + { + struct wined3d_wndproc *entry = &wndproc_table.entries[i]; + struct wined3d_wndproc *last = &wndproc_table.entries[--wndproc_table.count]; + + if (GetWindowLongPtrW(window, GWLP_WNDPROC) == (LONG_PTR)wined3d_wndproc) + SetWindowLongPtrW(window, GWLP_WNDPROC, (LONG_PTR)entry->proc); + if (entry != last) *entry = *last; + wined3d_mutex_unlock(); + + return; + } + } + wined3d_mutex_unlock(); + + ERR("Window %p is not registered with wined3d.\n", window); +} + /* At process attach */ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index e0b4ab1b14..cd4cf6fc39 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -816,6 +816,7 @@ typedef struct IWineD3DStateBlockImpl IWineD3DStateBlockImpl; typedef struct IWineD3DSurfaceImpl IWineD3DSurfaceImpl; typedef struct IWineD3DPaletteImpl IWineD3DPaletteImpl; typedef struct IWineD3DDeviceImpl IWineD3DDeviceImpl; +typedef struct IWineD3DSwapChainImpl IWineD3DSwapChainImpl; /* Global variables */ extern const float identity[16] DECLSPEC_HIDDEN; @@ -1439,6 +1440,8 @@ typedef struct IWineD3DImpl extern const IWineD3DVtbl IWineD3D_Vtbl DECLSPEC_HIDDEN; +BOOL wined3d_register_window(HWND window, struct IWineD3DSwapChainImpl *swapchain) DECLSPEC_HIDDEN; +void wined3d_unregister_window(HWND window) DECLSPEC_HIDDEN; BOOL InitAdapters(IWineD3DImpl *This) DECLSPEC_HIDDEN; /* A helper function that dumps a resource list */ @@ -2397,7 +2400,7 @@ extern const IWineD3DRendertargetViewVtbl wined3d_rendertarget_view_vtbl DECLSPE * IWineD3DSwapChainImpl implementation structure (extends IUnknown) */ -typedef struct IWineD3DSwapChainImpl +struct IWineD3DSwapChainImpl { /*IUnknown part*/ const IWineD3DSwapChainVtbl *lpVtbl; @@ -2422,7 +2425,7 @@ typedef struct IWineD3DSwapChainImpl unsigned int num_contexts; HWND win_handle; -} IWineD3DSwapChainImpl; +}; const IWineD3DSwapChainVtbl IWineGDISwapChain_Vtbl DECLSPEC_HIDDEN; void x11_copy_to_screen(IWineD3DSwapChainImpl *This, const RECT *rc) DECLSPEC_HIDDEN; @@ -2452,8 +2455,10 @@ HRESULT WINAPI IWineD3DBaseSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, struct wined3d_context *swapchain_create_context_for_thread(IWineD3DSwapChain *iface) DECLSPEC_HIDDEN; HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface_type, IWineD3DDeviceImpl *device, WINED3DPRESENT_PARAMETERS *present_parameters, IUnknown *parent) DECLSPEC_HIDDEN; -void swapchain_setup_fullscreen_window(IWineD3DSwapChainImpl *swapchain, UINT w, UINT h) DECLSPEC_HIDDEN; +LRESULT swapchain_process_message(IWineD3DSwapChainImpl *device, HWND window, + UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc) DECLSPEC_HIDDEN; void swapchain_restore_fullscreen_window(IWineD3DSwapChainImpl *swapchain) DECLSPEC_HIDDEN; +void swapchain_setup_fullscreen_window(IWineD3DSwapChainImpl *swapchain, UINT w, UINT h) DECLSPEC_HIDDEN; #define DEFAULT_REFRESH_RATE 0