[PATCH 3/5] dxgi: Implement Alt+Enter handling.

Zhiyi Zhang zzhang at codeweavers.com
Tue Apr 23 07:59:01 CDT 2019


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/dxgi/swapchain.c | 163 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 163 insertions(+)

diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 53da2081e8..9f8539fd28 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -39,6 +39,159 @@
 WINE_DEFAULT_DEBUG_CHANNEL(dxgi);
 WINE_DECLARE_DEBUG_CHANNEL(winediag);
 
+extern const WCHAR wine_dxgi_associated_factory_propW[];
+extern const WCHAR wine_dxgi_associated_flags_propW[];
+
+static struct list dxgi_swapchain_list = LIST_INIT(dxgi_swapchain_list);
+static struct list dxgi_hook_list = LIST_INIT(dxgi_hook_list);
+
+struct dxgi_swapchain_entry
+{
+    IDXGISwapChain1 *swapchain;
+    DWORD thread_id;
+    struct list entry;
+};
+
+struct dxgi_hook_entry
+{
+    HHOOK hook;
+    DWORD thread_id;
+    struct list entry;
+};
+
+static LRESULT CALLBACK associated_window_hook_proc(int code, WPARAM wparam, LPARAM lparam)
+{
+    struct dxgi_swapchain_entry *swapchain_entry;
+    IDXGIFactory *dxgi_factory;
+    MSG *msg = (MSG *)lparam;
+    HANDLE factory_handle;
+    BOOL skip = FALSE;
+    BOOL fullscreen;
+    DWORD flags;
+    HWND hwnd;
+
+    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, &dxgi_swapchain_list, struct dxgi_swapchain_entry, entry)
+        {
+            if (FAILED(IDXGISwapChain1_GetHwnd(swapchain_entry->swapchain, &hwnd)) || hwnd != msg->hwnd)
+                continue;
+
+            if (FAILED(IDXGISwapChain1_GetParent(swapchain_entry->swapchain, &IID_IDXGIFactory, (void **)&dxgi_factory)))
+                continue;
+            IDXGIFactory_Release(dxgi_factory);
+
+            factory_handle = GetPropW(hwnd, wine_dxgi_associated_factory_propW);
+            flags = (DWORD)(UINT_PTR)GetPropW(hwnd, wine_dxgi_associated_flags_propW);
+
+            if (factory_handle && factory_handle != dxgi_factory)
+                continue;
+
+            if (flags & (DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER))
+                break;
+
+            if (SUCCEEDED(IDXGISwapChain1_GetFullscreenState(swapchain_entry->swapchain, &fullscreen, NULL)))
+                IDXGISwapChain1_SetFullscreenState(swapchain_entry->swapchain, !fullscreen, NULL);
+            skip = TRUE;
+            break;
+        }
+        wined3d_mutex_unlock();
+    }
+
+    return skip ? 1 : CallNextHookEx(0, code, wparam, lparam);
+}
+
+static void add_associated_window_hook(IDXGISwapChain1 *swapchain, HWND hwnd)
+{
+    struct dxgi_swapchain_entry *swapchain_entry;
+    struct dxgi_hook_entry *hook_entry;
+    BOOL has_hook = FALSE;
+
+    if (!hwnd)
+        return;
+
+    if (!(swapchain_entry = heap_alloc_zero(sizeof(*swapchain_entry))))
+        return;
+
+    swapchain_entry->swapchain = swapchain;
+    swapchain_entry->thread_id = GetWindowThreadProcessId(hwnd, NULL);
+    wined3d_mutex_lock();
+    list_add_head(&dxgi_swapchain_list, &swapchain_entry->entry);
+    /* Add hook for current thread if needed */
+    LIST_FOR_EACH_ENTRY(hook_entry, &dxgi_hook_list, struct dxgi_hook_entry, entry)
+    {
+        if (hook_entry->thread_id == swapchain_entry->thread_id)
+        {
+            has_hook = TRUE;
+            break;
+        }
+    }
+    wined3d_mutex_unlock();
+
+    if (!has_hook)
+    {
+        if (!(hook_entry = heap_alloc_zero(sizeof(*hook_entry))))
+        {
+            wined3d_mutex_lock();
+            list_remove(&swapchain_entry->entry);
+            wined3d_mutex_unlock();
+            heap_free(swapchain_entry);
+            return;
+        }
+
+        hook_entry->thread_id = swapchain_entry->thread_id;
+        hook_entry->hook = SetWindowsHookExW(WH_GETMESSAGE, associated_window_hook_proc, 0, hook_entry->thread_id);
+        wined3d_mutex_lock();
+        list_add_head(&dxgi_hook_list, &hook_entry->entry);
+        wined3d_mutex_unlock();
+    }
+}
+
+static void remove_associated_window_hook(IDXGISwapChain1 *swapchain)
+{
+    struct dxgi_swapchain_entry *swapchain_entry, *swapchain_entry2;
+    struct dxgi_hook_entry *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, &dxgi_swapchain_list, struct dxgi_swapchain_entry, 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, &dxgi_swapchain_list, struct dxgi_swapchain_entry, 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, &dxgi_hook_list, struct dxgi_hook_entry, 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();
+}
+
 static DXGI_SWAP_EFFECT dxgi_swap_effect_from_wined3d(enum wined3d_swap_effect swap_effect)
 {
     switch (swap_effect)
@@ -214,6 +367,9 @@ static ULONG STDMETHODCALLTYPE d3d11_swapchain_Release(IDXGISwapChain1 *iface)
     if (!refcount)
     {
         IWineDXGIDevice *device = swapchain->device;
+
+        remove_associated_window_hook(iface);
+
         if (swapchain->target)
         {
             WARN("Releasing fullscreen swapchain.\n");
@@ -842,8 +998,11 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi
             goto cleanup;
         }
     }
+
     wined3d_mutex_unlock();
 
+    add_associated_window_hook(&swapchain->IDXGISwapChain1_iface, desc->device_window);
+
     return S_OK;
 
 cleanup:
@@ -1770,6 +1929,8 @@ static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain)
     const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
     void *vulkan_module = vk_funcs->vulkan_module;
 
+    remove_associated_window_hook((IDXGISwapChain1*)&swapchain->IDXGISwapChain3_iface);
+
     d3d12_swapchain_destroy_buffers(swapchain, TRUE);
 
     if (swapchain->command_queue)
@@ -2731,6 +2892,8 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
 
     IWineDXGIFactory_AddRef(swapchain->factory = factory);
 
+    add_associated_window_hook((IDXGISwapChain1*)&swapchain->IDXGISwapChain3_iface, window);
+
     return S_OK;
 }
 
-- 
2.20.1





More information about the wine-devel mailing list