[PATCH 5/5] dxgi: Implement fullscreen window occlusion detection.

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


When Windows detected a fullscreen window occlusion, it will
set the fullscreen window to windowed and return DXGI_STATUS_OCCLUDED
in IDXGISwapChain::Present.

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

diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 9f8539fd28..d1df1ad726 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -265,6 +265,42 @@ BOOL dxgi_validate_swapchain_desc(const DXGI_SWAP_CHAIN_DESC1 *desc)
     return TRUE;
 }
 
+/* A correct occlusion detection method must consider following scenarios:
+ *
+ * 1. On multiple monitors system. For example, the full-screen is on primary display, any window on
+ *    on secondary monitor shouldn't be able to occlude the full-screen window, regardless being foreground or active.
+ * 2. A non-Wine window, e.g., a X window occludes the full-screen window should be detected.
+ *
+ * Current method will incorrectly report occluded status where a window on a secondary monitor becomes foreground,
+ * which shouldn't be too harmful though. The actual implementation on Window probably has help from DWM.
+ *
+ * X11 VisibilityNotify is not useful here. The events doesn't work as expected.
+ */
+static BOOL dxgi_is_window_occluded(HWND hwnd)
+{
+    RECT fullscreen_rect;
+    RECT intersect_rect;
+    RECT window_rect;
+    HWND previous_hwnd;
+
+    if (GetForegroundWindow() != hwnd)
+        return TRUE;
+
+    /* Check if windows with higher z-order intersect with the full-screen window */
+    GetWindowRect(hwnd, &fullscreen_rect);
+    previous_hwnd = GetWindow(hwnd, GW_HWNDPREV);
+    while (previous_hwnd)
+    {
+        GetWindowRect(previous_hwnd, &window_rect);
+        if (IntersectRect(&intersect_rect, &window_rect, &fullscreen_rect))
+            return TRUE;
+
+        previous_hwnd = GetWindow(previous_hwnd, GW_HWNDPREV);
+    }
+
+    return FALSE;
+}
+
 static HRESULT dxgi_get_output_from_window(IDXGIAdapter *adapter, HWND window, IDXGIOutput **dxgi_output)
 {
     DXGI_OUTPUT_DESC desc;
@@ -456,12 +492,27 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDevice(IDXGISwapChain1 *ifac
 static HRESULT d3d11_swapchain_present(struct d3d11_swapchain *swapchain,
         unsigned int sync_interval, unsigned int flags)
 {
+    BOOL fullscreen = FALSE;
+    HRESULT hr;
+    HWND hwnd;
+
     if (sync_interval > 4)
     {
         WARN("Invalid sync interval %u.\n", sync_interval);
         return DXGI_ERROR_INVALID_CALL;
     }
 
+    hr = IDXGISwapChain1_GetFullscreenState(&swapchain->IDXGISwapChain1_iface, &fullscreen, NULL);
+    if (SUCCEEDED(hr) && fullscreen)
+    {
+        hr = IDXGISwapChain1_GetHwnd(&swapchain->IDXGISwapChain1_iface, &hwnd);
+        if (SUCCEEDED(hr) && dxgi_is_window_occluded(hwnd))
+        {
+            IDXGISwapChain1_SetFullscreenState(&swapchain->IDXGISwapChain1_iface, FALSE, NULL);
+            return DXGI_STATUS_OCCLUDED;
+        }
+    }
+
     if (flags & ~DXGI_PRESENT_TEST)
         FIXME("Unimplemented flags %#x.\n", flags);
     if (flags & DXGI_PRESENT_TEST)
@@ -2118,8 +2169,10 @@ static VkResult d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain,
 static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
         unsigned int sync_interval, unsigned int flags)
 {
+    BOOL fullscreen = FALSE;
     VkQueue vk_queue;
     VkResult vr;
+    HWND hwnd;
     HRESULT hr;
 
     if (sync_interval > 4)
@@ -2128,6 +2181,17 @@ static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
         return DXGI_ERROR_INVALID_CALL;
     }
 
+    hr = IDXGISwapChain3_GetFullscreenState(&swapchain->IDXGISwapChain3_iface, &fullscreen, NULL);
+    if (SUCCEEDED(hr) && fullscreen)
+    {
+        hr = IDXGISwapChain3_GetHwnd(&swapchain->IDXGISwapChain3_iface, &hwnd);
+        if (SUCCEEDED(hr) && dxgi_is_window_occluded(hwnd))
+        {
+            IDXGISwapChain3_SetFullscreenState(&swapchain->IDXGISwapChain3_iface, FALSE, NULL);
+            return DXGI_STATUS_OCCLUDED;
+        }
+    }
+
     if (flags & ~DXGI_PRESENT_TEST)
         FIXME("Unimplemented flags %#x.\n", flags);
     if (flags & DXGI_PRESENT_TEST)
-- 
2.20.1




More information about the wine-devel mailing list