From: Rémi Bernon rbernon@codeweavers.com
SetForegroundWindow calls aren't reflected to the X11 side, and we're sometimes becoming inconsistent between the X focused window and the Win32 foreground window.
When a window gets unmapped, the window manager will send WM_TAKE_FOCUS to a different window, which may not be the foreground window from the Win32 point of view. Requesting input focus to our foreground before unmapping the focused window effectively resyncs the state. --- dlls/winex11.drv/event.c | 10 ++++++++-- dlls/winex11.drv/window.c | 8 ++++++++ dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index cc11285d0c6..646ba4c140a 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -849,10 +849,13 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) { HWND foreground = NtUserGetForegroundWindow(); XFocusChangeEvent *event = &xev->xfocus; + struct x11drv_win_data *data; BOOL was_grabbed;
if (event->detail == NotifyPointer) return FALSE; - if (!hwnd) return FALSE; + if (!(data = get_win_data( hwnd ))) return FALSE; + data->has_focus = 1; + release_win_data( data );
if (window_has_pending_wm_state( hwnd, -1 )) { @@ -934,6 +937,7 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) { HWND foreground = NtUserGetForegroundWindow(); XFocusChangeEvent *event = &xev->xfocus; + struct x11drv_win_data *data;
if (event->detail == NotifyPointer) { @@ -946,7 +950,9 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) } return TRUE; } - if (!hwnd) return FALSE; + if (!(data = get_win_data( hwnd ))) return FALSE; + data->has_focus = 0; + release_win_data( data );
if (window_has_pending_wm_state( hwnd, NormalState )) /* ignore FocusOut only if the window is being shown */ { diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 32c3800abfe..8ce9c16d673 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1441,6 +1441,7 @@ static void set_xembed_flags( struct x11drv_win_data *data, unsigned long flags static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state ) { UINT old_state = data->pending_state.wm_state; + HWND foreground = NtUserGetForegroundWindow();
data->desired_state.wm_state = new_state; if (!data->whole_window) return; /* no window, nothing to update */ @@ -1463,6 +1464,13 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state ) break; }
+ if (new_state != NormalState && data->has_focus && data->hwnd != foreground) + { + Window window = X11DRV_get_whole_window( foreground ); + WARN( "Inconsistent input focus, activating window %p/%lx\n", foreground, window ); + XSetInputFocus( data->display, window, RevertToParent, CurrentTime ); + } + data->pending_state.wm_state = new_state; data->wm_state_serial = NextRequest( data->display ); TRACE( "window %p/%lx, requesting WM_STATE %#x -> %#x serial %lu, foreground %p\n", data->hwnd, data->whole_window, diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index ee5bbe07dd4..55c5fc10f3c 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -636,6 +636,7 @@ struct x11drv_win_data UINT is_fullscreen : 1; /* is the window visible rect fullscreen */ UINT is_offscreen : 1; /* has been moved offscreen by the window manager */ UINT parent_invalid : 1; /* is the parent host window possibly invalid */ + UINT has_focus : 1; /* does window have X input focus */ Window embedder; /* window id of embedder */ Pixmap icon_pixmap; Pixmap icon_mask;