diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 5300982d6b2..7c3b2d5ade3 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -761,12 +761,20 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) } else if (protocol == x11drv_atom(WM_TAKE_FOCUS)) { - HWND last_focus = x11drv_thread_data()->last_focus; + HWND last_focus = x11drv_thread_data()->last_focus, foreground = NtUserGetForegroundWindow(); - TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n", - hwnd, NtUserIsWindowEnabled(hwnd), NtUserIsWindowVisible(hwnd), - (int)NtUserGetWindowLongW(hwnd, GWL_STYLE), - get_focus(), get_active_window(), NtUserGetForegroundWindow(), last_focus ); + if (window_has_pending_wm_state( hwnd, -1 )) + { + WARN( "Ignoring window %p/%lx WM_TAKE_FOCUS serial %lu, event_time %ld, foreground %p during WM_STATE change\n", + hwnd, event->window, event->serial, event_time, foreground ); + return; + } + + TRACE( "window %p/%lx WM_TAKE_FOCUS serial %lu, event_time %ld, foreground %p\n", hwnd, event->window, + event->serial, event_time, foreground ); + TRACE( " enabled %u, visible %u, style %#x, focus %p, active %p, last %p\n", + NtUserIsWindowEnabled( hwnd ), NtUserIsWindowVisible( hwnd ), (int)NtUserGetWindowLongW( hwnd, GWL_STYLE ), + get_focus(), get_active_window(), last_focus ); if (can_activate_window(hwnd)) { @@ -783,7 +791,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) } else if (hwnd == NtUserGetDesktopWindow()) { - hwnd = NtUserGetForegroundWindow(); + hwnd = foreground; if (!hwnd) hwnd = last_focus; if (!hwnd) hwnd = NtUserGetDesktopWindow(); set_focus( event->display, hwnd, event_time ); @@ -845,14 +853,23 @@ BOOL is_current_process_focused(void) */ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) { + HWND foreground = NtUserGetForegroundWindow(); XFocusChangeEvent *event = &xev->xfocus; BOOL was_grabbed; + if (event->detail == NotifyPointer) return FALSE; if (!hwnd) return FALSE; - TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] ); + if (window_has_pending_wm_state( hwnd, -1 )) + { + WARN( "Ignoring window %p/%lx FocusIn serial %lu, detail %s, mode %s, foreground %p during WM_STATE change\n", + hwnd, event->window, event->serial, focus_details[event->detail], focus_modes[event->mode], foreground ); + return FALSE; + } + + TRACE( "window %p/%lx FocusIn serial %lu, detail %s, mode %s, foreground %p\n", hwnd, event->window, + event->serial, focus_details[event->detail], focus_modes[event->mode], foreground ); - if (event->detail == NotifyPointer) return FALSE; /* when focusing in the virtual desktop window, re-apply the cursor clipping rect */ if (is_virtual_desktop() && hwnd == NtUserGetDesktopWindow()) reapply_cursor_clipping(); if (hwnd == NtUserGetDesktopWindow()) return FALSE; @@ -921,10 +938,9 @@ static void focus_out( Display *display , HWND hwnd ) */ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) { + HWND foreground = NtUserGetForegroundWindow(); XFocusChangeEvent *event = &xev->xfocus; - TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] ); - if (event->detail == NotifyPointer) { if (!hwnd && event->window == x11drv_thread_data()->clip_window) @@ -938,6 +954,16 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) } if (!hwnd) return FALSE; + if (window_has_pending_wm_state( hwnd, NormalState )) /* ignore FocusOut only if the window is being shown */ + { + WARN( "Ignoring window %p/%lx FocusOut serial %lu, detail %s, mode %s, foreground %p during WM_STATE change\n", + hwnd, event->window, event->serial, focus_details[event->detail], focus_modes[event->mode], foreground ); + return FALSE; + } + + TRACE( "window %p/%lx FocusOut serial %lu, detail %s, mode %s, foreground %p\n", hwnd, event->window, + event->serial, focus_details[event->detail], focus_modes[event->mode], foreground ); + /* in virtual desktop mode or when keyboard is grabbed, release any cursor grab but keep the clipping rect */ keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed; if (is_virtual_desktop() || keyboard_grabbed) ungrab_clipping_window(); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 02a1eb13c48..aa1eee354ac 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1418,8 +1418,8 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state ) 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\n", data->hwnd, data->whole_window, - old_state, new_state, data->wm_state_serial ); + TRACE( "window %p/%lx, requesting WM_STATE %#x -> %#x serial %lu, foreground %p\n", data->hwnd, data->whole_window, + old_state, new_state, data->wm_state_serial, NtUserGetForegroundWindow() ); switch (MAKELONG(old_state, new_state)) { @@ -1593,6 +1593,19 @@ void window_configure_notify( struct x11drv_win_data *data, unsigned long serial *expect_serial = 0; } +BOOL window_has_pending_wm_state( HWND hwnd, UINT state ) +{ + struct x11drv_win_data *data; + BOOL pending; + + if (!(data = get_win_data( hwnd ))) return FALSE; + if (state != -1 && data->pending_state.wm_state != state) pending = FALSE; + else pending = !!data->wm_state_serial; + release_win_data( data ); + + return pending; +} + /*********************************************************************** * make_window_embedded */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index f1f0f97486b..aecd49ac042 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -659,6 +659,7 @@ extern void set_gl_drawable_parent( HWND hwnd, HWND parent ); extern void destroy_gl_drawable( HWND hwnd ); extern void destroy_vk_surface( HWND hwnd ); +extern BOOL window_has_pending_wm_state( HWND hwnd, UINT state ); extern void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ); extern void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ); extern void window_configure_notify( struct x11drv_win_data *data, unsigned long serial, const RECT *rect );