[PATCH v2 3/3] winex11.drv: Remove topmost state for DXGI fullscreen windows when focus is lost.
Gabriel Ivăncescu
gabrielopcode at gmail.com
Fri Jan 29 08:08:24 CST 2021
This is what Windows' DWM does to DXGI fullscreen windows when e.g. Alt-Tab
is released.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
Handling it in FocusOut seems like the closest option, although we have to
workaround the Z-order by bringing the focused window to the top, because it
should actually happen before the focus change, but that's out of our control.
dlls/dxgi/swapchain.c | 19 ++++++++++++--
dlls/winex11.drv/event.c | 48 ++++++++++++++++++++++++++++++++--
dlls/winex11.drv/x11drv.h | 1 +
dlls/winex11.drv/x11drv_main.c | 1 +
4 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 5611c83..48e2949 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -38,6 +38,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(dxgi);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
+static const WCHAR wine_dxgi_fs_propW[] = { '_','_','w','i','n','e','_','d','x','g','i','_','f','u','l','l','s','c','r','e','e','n',0 };
+
static DXGI_SWAP_EFFECT dxgi_swap_effect_from_wined3d(enum wined3d_swap_effect swap_effect)
{
switch (swap_effect)
@@ -242,6 +244,7 @@ static ULONG STDMETHODCALLTYPE d3d11_swapchain_Release(IDXGISwapChain1 *iface)
if (!refcount)
{
IWineDXGIDevice *device = swapchain->device;
+ RemovePropW(d3d11_swapchain_get_hwnd(swapchain), wine_dxgi_fs_propW);
if (swapchain->target)
{
WARN("Releasing fullscreen swapchain.\n");
@@ -443,8 +446,11 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_SetFullscreen
return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
}
- if (!fullscreen)
+ if (fullscreen)
+ SetPropW(d3d11_swapchain_get_hwnd(swapchain), wine_dxgi_fs_propW, (HANDLE)TRUE);
+ else
{
+ RemovePropW(d3d11_swapchain_get_hwnd(swapchain), wine_dxgi_fs_propW);
IDXGIOutput_Release(target);
target = NULL;
}
@@ -926,6 +932,8 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi
}
wined3d_mutex_unlock();
+ if (fullscreen)
+ SetPropW(d3d11_swapchain_get_hwnd(swapchain), wine_dxgi_fs_propW, (HANDLE)TRUE);
return S_OK;
cleanup:
@@ -1958,6 +1966,7 @@ static ULONG STDMETHODCALLTYPE d3d12_swapchain_Release(IDXGISwapChain4 *iface)
if (!refcount)
{
+ RemovePropW(swapchain->window, wine_dxgi_fs_propW);
d3d12_swapchain_destroy(swapchain);
heap_free(swapchain);
}
@@ -2294,8 +2303,12 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreen
goto fail;
fullscreen_desc->Windowed = wined3d_desc.windowed;
- if (!fullscreen)
+
+ if (fullscreen)
+ SetPropW(swapchain->window, wine_dxgi_fs_propW, (HANDLE)TRUE);
+ else
{
+ RemovePropW(swapchain->window, wine_dxgi_fs_propW);
IDXGIOutput_Release(target);
target = NULL;
}
@@ -3203,6 +3216,8 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
IWineDXGIFactory_AddRef(swapchain->factory = factory);
+ if (!fullscreen_desc->Windowed)
+ SetPropW(swapchain->window, wine_dxgi_fs_propW, (HANDLE)TRUE);
return S_OK;
}
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index d21d2a7..e37c0f4 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -817,6 +817,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
*/
static void focus_out( Display *display , HWND hwnd )
{
+ static const WCHAR wine_dxgi_fs_propW[] = { '_','_','w','i','n','e','_','d','x','g','i','_','f','u','l','l','s','c','r','e','e','n',0 };
+ struct x11drv_win_data *data;
HWND hwnd_tmp;
Window focus_win;
int revert;
@@ -835,10 +837,52 @@ static void focus_out( Display *display , HWND hwnd )
if (hwnd != GetForegroundWindow()) return;
SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
+ XGetInputFocus( display, &focus_win, &revert );
+
+ /* when focus is changed by the WM (e.g. alt-tab) while a
+ dxgi fullscreen window is active, remove its topmost */
+ if ((GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST) &&
+ GetPropW( hwnd, wine_dxgi_fs_propW ))
+ {
+ SetWindowPos( hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING );
+
+ if ((data = get_win_data( hwnd )))
+ {
+ int format, screen = data->vis.screen;
+ unsigned long count, remaining;
+ Window active_win = None;
+ XWindowAttributes attr;
+ XWindowChanges changes;
+ unsigned char *prop;
+ Atom type;
+
+ /* reset the input focus in case the WM changed it */
+ release_win_data( data );
+ XSetInputFocus( display, focus_win, RevertToParent, CurrentTime );
+
+ /* move the active window to the top so it's not below the ex-topmost window */
+ if (!XGetWindowProperty( display, DefaultRootWindow(display), x11drv_atom(_NET_ACTIVE_WINDOW),
+ 0, 1, False, XA_WINDOW, &type, &format, &count, &remaining, &prop ))
+ {
+ if (type == XA_WINDOW && format == 32 && count == 1)
+ active_win = *(long*)prop;
+ XFree(prop);
+ }
+
+ if (XGetWindowAttributes( display, active_win != None ? active_win : focus_win, &attr ) &&
+ XScreenNumberOfScreen( attr.screen ) == screen)
+ {
+ changes.stack_mode = Above;
+ if (active_win != None)
+ XReconfigureWMWindow( display, active_win, screen, CWStackMode, &changes );
+ else if (focus_win)
+ XConfigureWindow( display, focus_win, CWStackMode, &changes );
+ }
+ }
+ }
+
/* don't reset the foreground window, if the window which is
getting the focus is a Wine window */
-
- XGetInputFocus( display, &focus_win, &revert );
if (focus_win)
{
if (XFindContext( display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 4585597..be3a30b 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -437,6 +437,7 @@ enum x11drv_atoms
XATOM_DndSelection,
XATOM__ICC_PROFILE,
XATOM__MOTIF_WM_HINTS,
+ XATOM__NET_ACTIVE_WINDOW,
XATOM__NET_STARTUP_INFO_BEGIN,
XATOM__NET_STARTUP_INFO,
XATOM__NET_SUPPORTED,
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index 9ec4c7a..3fcb117 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -150,6 +150,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
"DndSelection",
"_ICC_PROFILE",
"_MOTIF_WM_HINTS",
+ "_NET_ACTIVE_WINDOW",
"_NET_STARTUP_INFO_BEGIN",
"_NET_STARTUP_INFO",
"_NET_SUPPORTED",
--
2.29.2
More information about the wine-devel
mailing list