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, another one may receive WM_TAKE_FOCUS, and in the next change we want to rely on the foreground window activation time to make a decision on whether the foreground window is temporarily unmapping itself. It needs to be the same as the window with X input focus, or we won't know which window activation time to check. --- 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 30b49e6ccfd..ec714d144fb 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 422f1ea5b5b..0d90707eb1c 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1406,6 +1406,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 */ @@ -1428,6 +1429,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 995df13e843..0f4e33dd9c0 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -635,6 +635,7 @@ struct x11drv_win_data UINT net_wm_fullscreen_monitors_set : 1; /* is _NET_WM_FULLSCREEN_MONITORS set */ UINT is_fullscreen : 1; /* is the window visible rect fullscreen */ 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;