Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/dxgi/swapchain.c | 2 + dlls/wined3d/swapchain.c | 132 +++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d.spec | 2 + dlls/wined3d/wined3d_private.h | 19 +++++ include/wine/wined3d.h | 2 + 5 files changed, 157 insertions(+)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 030bb67c22..4c90012b86 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -221,6 +221,7 @@ static ULONG STDMETHODCALLTYPE d3d11_swapchain_Release(IDXGISwapChain1 *iface) } if (swapchain->factory) IDXGIFactory_Release(swapchain->factory); + wined3d_swapchain_disable_window_hook(swapchain->wined3d_swapchain); wined3d_swapchain_decref(swapchain->wined3d_swapchain); if (device) IWineDXGIDevice_Release(device); @@ -849,6 +850,7 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi } } wined3d_mutex_unlock(); + wined3d_swapchain_enable_window_hook(swapchain->wined3d_swapchain);
return S_OK;
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 808602cb15..be0610d087 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -28,6 +28,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d); WINE_DECLARE_DEBUG_CHANNEL(fps);
+static struct list hooked_swapchains = LIST_INIT(hooked_swapchains); +static struct list window_hooks = LIST_INIT(window_hooks); + static void wined3d_swapchain_destroy_object(void *object) { swapchain_destroy_contexts(object); @@ -1492,3 +1495,132 @@ HRESULT CDECL wined3d_swapchain_set_fullscreen(struct wined3d_swapchain *swapcha
return WINED3D_OK; } + +static LRESULT CALLBACK window_hook_proc(int code, WPARAM wparam, LPARAM lparam) +{ + struct wined3d_window_association *association_entry; + struct wined3d_hooked_swapchain *swapchain_entry; + struct wined3d_swapchain_desc swapchain_desc; + MSG *msg = (MSG *)lparam; + BOOL handled = FALSE; + BOOL skip = FALSE; + + /* Handle Alt+Enter */ + if (code == HC_ACTION && msg->message == WM_SYSKEYDOWN && msg->wParam == VK_RETURN + && (msg->lParam & (KF_ALTDOWN << 16))) + { + wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(swapchain_entry, &hooked_swapchains, struct wined3d_hooked_swapchain, entry) + { + if (swapchain_entry->swapchain->device_window != msg->hwnd) + continue; + + LIST_FOR_EACH_ENTRY(association_entry, &window_associations, struct wined3d_window_association, entry) + { + if (association_entry->hwnd == msg->hwnd + && (association_entry->flags & (WINED3D_MWA_NO_WINDOW_CHANGES | WINED3D_MWA_NO_ALT_ENTER))) + { + skip = TRUE; + break; + } + } + + if (!skip) + { + wined3d_swapchain_get_desc(swapchain_entry->swapchain, &swapchain_desc); + swapchain_desc.windowed = !swapchain_desc.windowed; + wined3d_swapchain_set_fullscreen(swapchain_entry->swapchain, &swapchain_desc, NULL); + } + + handled = TRUE; + break; + } + wined3d_mutex_unlock(); + } + + return handled ? 1 : CallNextHookEx(0, code, wparam, lparam); +} + +void CDECL wined3d_swapchain_enable_window_hook(struct wined3d_swapchain *swapchain) +{ + struct wined3d_hooked_swapchain *swapchain_entry; + struct wined3d_swapchain_window_hook *hook_entry; + BOOL has_hook = FALSE; + + if (!(swapchain_entry = heap_alloc_zero(sizeof(*swapchain_entry)))) + return; + + swapchain_entry->swapchain = swapchain; + swapchain_entry->thread_id = GetWindowThreadProcessId(swapchain->device_window, NULL); + wined3d_mutex_lock(); + list_add_head(&hooked_swapchains, &swapchain_entry->entry); + /* Add hook for new thread if needed */ + LIST_FOR_EACH_ENTRY(hook_entry, &window_hooks, struct wined3d_swapchain_window_hook, entry) + { + if (hook_entry->thread_id == swapchain_entry->thread_id) + { + has_hook = TRUE; + break; + } + } + + if (!has_hook) + { + if (!(hook_entry = heap_alloc_zero(sizeof(*hook_entry)))) + { + list_remove(&swapchain_entry->entry); + heap_free(swapchain_entry); + wined3d_mutex_unlock(); + return; + } + + hook_entry->thread_id = swapchain_entry->thread_id; + hook_entry->hook = SetWindowsHookExW(WH_GETMESSAGE, window_hook_proc, 0, hook_entry->thread_id); + list_add_head(&window_hooks, &hook_entry->entry); + } + wined3d_mutex_unlock(); +} + +void CDECL wined3d_swapchain_disable_window_hook(struct wined3d_swapchain *swapchain) +{ + struct wined3d_hooked_swapchain *swapchain_entry, *swapchain_entry2; + struct wined3d_swapchain_window_hook *hook_entry, *hook_entry2; + BOOL hook_in_use = FALSE; + DWORD thread_id = 0; + + wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY_SAFE(swapchain_entry, swapchain_entry2, &hooked_swapchains, struct wined3d_hooked_swapchain, entry) + { + if (swapchain_entry->swapchain == swapchain) + { + thread_id = swapchain_entry->thread_id; + list_remove(&swapchain_entry->entry); + heap_free(swapchain_entry); + break; + } + } + /* Check if hook is still used by other swapchains */ + LIST_FOR_EACH_ENTRY(swapchain_entry, &hooked_swapchains, struct wined3d_hooked_swapchain, entry) + { + if (swapchain_entry->thread_id == thread_id) + { + hook_in_use = TRUE; + break; + } + } + /* Remove hook if it's not longer used by any thread */ + if (!hook_in_use) + { + LIST_FOR_EACH_ENTRY_SAFE(hook_entry, hook_entry2, &window_hooks, struct wined3d_swapchain_window_hook, entry) + { + if (hook_entry->thread_id == thread_id) + { + list_remove(&hook_entry->entry); + UnhookWindowsHookEx(hook_entry->hook); + heap_free(hook_entry); + break; + } + } + } + wined3d_mutex_unlock(); +} diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 733eedb485..f93c8d38fe 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -263,6 +263,8 @@
@ cdecl wined3d_swapchain_create(ptr ptr ptr ptr ptr) @ cdecl wined3d_swapchain_decref(ptr) +@ cdecl wined3d_swapchain_disable_window_hook(ptr) +@ cdecl wined3d_swapchain_enable_window_hook(ptr) @ cdecl wined3d_swapchain_get_back_buffer(ptr long) @ cdecl wined3d_swapchain_get_device(ptr) @ cdecl wined3d_swapchain_get_display_mode(ptr ptr ptr) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index f277d898f3..ec920536c9 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -4177,6 +4177,25 @@ struct wined3d_swapchain HWND backup_wnd; };
+struct wined3d_hooked_swapchain +{ + struct wined3d_swapchain *swapchain; + DWORD thread_id; + struct list entry; +}; + +struct wined3d_swapchain_window_hook +{ + HHOOK hook; + DWORD thread_id; + struct list entry; +}; + +/* Equivalences of DXGI_MWA_* flags */ +#define WINED3D_MWA_NO_WINDOW_CHANGES 0x1 +#define WINED3D_MWA_NO_ALT_ENTER 0x2 +#define WINED3D_MWA_NO_PRINT_SCREEN 0x4 + void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activate) DECLSPEC_HIDDEN; struct wined3d_context *swapchain_get_context(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; void swapchain_destroy_contexts(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 8514860a79..e41a9080df 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2664,6 +2664,8 @@ ULONG __cdecl wined3d_stateblock_incref(struct wined3d_stateblock *stateblock); HRESULT __cdecl wined3d_swapchain_create(struct wined3d_device *device, struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_swapchain **swapchain); ULONG __cdecl wined3d_swapchain_decref(struct wined3d_swapchain *swapchain); +void __cdecl wined3d_swapchain_disable_window_hook(struct wined3d_swapchain *swapchain); +void __cdecl wined3d_swapchain_enable_window_hook(struct wined3d_swapchain *swapchain); struct wined3d_texture * __cdecl wined3d_swapchain_get_back_buffer(const struct wined3d_swapchain *swapchain, UINT backbuffer_idx); struct wined3d_device * __cdecl wined3d_swapchain_get_device(const struct wined3d_swapchain *swapchain);