From: Rémi Bernon rbernon@codeweavers.com
Setting a __wine_x11_focus_time window property to indicate the time of the last NormalState for any window, 0 if the window is currently not in NormalState, and -1 if the state change is transient. --- dlls/winex11.drv/event.c | 6 +++--- dlls/winex11.drv/window.c | 19 ++++++++++++++++++- dlls/winex11.drv/x11drv.h | 3 ++- 3 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 646ba4c140a..8ccd81bbe80 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -757,7 +757,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) { HWND last_focus = x11drv_thread_data()->last_focus, foreground = NtUserGetForegroundWindow();
- if (window_has_pending_wm_state( hwnd, -1 )) + if (window_has_pending_wm_state( hwnd, -1 ) || !window_should_take_focus( hwnd, foreground, event_time )) { 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 ); @@ -1233,7 +1233,7 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event )
if (!(data = get_win_data( hwnd ))) return; if (event->state == PropertyNewValue) value = get_window_wm_state( event->display, event->window ); - window_wm_state_notify( data, event->serial, value ); + window_wm_state_notify( data, event->serial, value, event->time ); release_win_data( data );
NtUserPostMessage( hwnd, WM_WINE_WINDOW_STATE_CHANGED, 0, 0 ); @@ -1246,7 +1246,7 @@ static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event )
if (!(data = get_win_data( hwnd ))) return; if (event->state == PropertyNewValue) value = get_window_xembed_info( event->display, event->window ); - window_wm_state_notify( data, event->serial, value ? NormalState : WithdrawnState ); + window_wm_state_notify( data, event->serial, value ? NormalState : WithdrawnState, event->time ); release_win_data( data ); }
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8ce9c16d673..0007024475c 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -108,6 +108,8 @@ static const WCHAR whole_window_prop[] = {'_','_','w','i','n','e','_','x','1','1','_','w','h','o','l','e','_','w','i','n','d','o','w',0}; static const WCHAR clip_window_prop[] = {'_','_','w','i','n','e','_','x','1','1','_','c','l','i','p','_','w','i','n','d','o','w',0}; +static const WCHAR focus_time_prop[] = + {'_','_','w','i','n','e','_','x','1','1','_','f','o','c','u','s','_','t','i','m','e',0};
static pthread_mutex_t win_data_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -1464,6 +1466,9 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state ) break; }
+ if (new_state == NormalState) NtUserSetProp( data->hwnd, focus_time_prop, (HANDLE)-1 ); + else NtUserRemoveProp( data->hwnd, focus_time_prop ); + if (new_state != NormalState && data->has_focus && data->hwnd != foreground) { Window window = X11DRV_get_whole_window( foreground ); @@ -1642,7 +1647,7 @@ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, return *state_cmd || *config_cmd; }
-void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ) +void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value, Time time ) { UINT *desired = &data->desired_state.wm_state, *pending = &data->pending_state.wm_state, *current = &data->current_state.wm_state; unsigned long *expect_serial = &data->wm_state_serial; @@ -1679,6 +1684,9 @@ void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, window_set_wm_state( data, data->desired_state.wm_state ); window_set_net_wm_state( data, data->desired_state.net_wm_state ); window_set_config( data, &data->desired_state.rect, FALSE ); + + if (data->current_state.wm_state == NormalState) NtUserSetProp( data->hwnd, focus_time_prop, (HANDLE)time ); + else if (!data->wm_state_serial) NtUserRemoveProp( data->hwnd, focus_time_prop ); }
void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ) @@ -1763,6 +1771,15 @@ BOOL window_has_pending_wm_state( HWND hwnd, UINT state ) return pending; }
+/* returns whether the window should accept focus instead of the current foreground window */ +BOOL window_should_take_focus( HWND hwnd, HWND foreground, Time time ) +{ + Time focus_time; + if (hwnd == foreground) return TRUE; + focus_time = (UINT_PTR)NtUserGetProp( foreground, focus_time_prop ); + return !focus_time || (int)(focus_time - time) < 0; +} + /*********************************************************************** * make_window_embedded */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 55c5fc10f3c..d1cf5d46f6f 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -662,8 +662,9 @@ 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_should_take_focus( HWND hwnd, HWND foreground, Time time ); 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_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value, Time time ); 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 ); extern BOOL get_window_state_updates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect );