winex11: Request window state updates asynchronously.

This commit is contained in:
Rémi Bernon 2024-11-14 11:53:52 +01:00 committed by Alexandre Julliard
parent d8b5a3ae12
commit 0cda918561
Notes: Alexandre Julliard 2024-11-18 23:18:45 +01:00
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/wine/merge_requests/6569
4 changed files with 37 additions and 115 deletions

View file

@ -4067,11 +4067,8 @@ static void test_SetForegroundWindow(HWND hwnd)
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
if (0) check_wnd_state(hwnd2, hwnd2, hwnd2, 0);
/* FIXME: these tests are failing because of a race condition
* between internal focus state applied immediately and X11 focus
* message coming late */
todo_wine ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow());
todo_wine ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus());
ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow());
ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus());
SetForegroundWindow(hwnd);
check_wnd_state(hwnd, hwnd, hwnd, 0);

View file

@ -1200,7 +1200,7 @@ static int get_window_xembed_info( Display *display, Window window )
*
* Handle a PropertyNotify for WM_STATE.
*/
static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event )
{
struct x11drv_win_data *data;
UINT value = 0, state_cmd = 0, config_cmd = 0;
@ -1208,34 +1208,11 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat
if (!(data = get_win_data( hwnd ))) return;
if (event->state == PropertyNewValue) value = get_window_wm_state( event->display, event->window );
if (update_window) window_wm_state_notify( data, event->serial, value );
window_wm_state_notify( data, event->serial, value );
switch(event->state)
{
case PropertyDelete:
TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
data->wm_state = WithdrawnState;
break;
case PropertyNewValue:
{
int old_state = data->wm_state;
int new_state = get_window_wm_state( event->display, data->whole_window );
if (new_state != -1 && new_state != data->wm_state)
{
TRACE( "%p/%lx: new WM_STATE %d from %d\n",
data->hwnd, data->whole_window, new_state, old_state );
data->wm_state = new_state;
}
}
break;
}
if (update_window)
{
state_cmd = window_update_client_state( data );
config_cmd = window_update_client_config( data );
rect = window_rect_from_visible( &data->rects, data->current_state.rect );
}
state_cmd = window_update_client_state( data );
config_cmd = window_update_client_config( data );
rect = window_rect_from_visible( &data->rects, data->current_state.rect );
release_win_data( data );
@ -1300,79 +1277,13 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
XPropertyEvent *event = &xev->xproperty;
if (!hwnd) return FALSE;
if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event );
if (event->atom == x11drv_atom(_XEMBED_INFO)) handle_xembed_info_notify( hwnd, event );
if (event->atom == x11drv_atom(_NET_WM_STATE)) handle_net_wm_state_notify( hwnd, event );
return TRUE;
}
/* event filter to wait for a WM_STATE change notification on a window */
static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
{
if (event->xany.window != (Window)arg) return 0;
return (event->type == DestroyNotify ||
(event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
}
/***********************************************************************
* wait_for_withdrawn_state
*/
void wait_for_withdrawn_state( HWND hwnd, BOOL set )
{
Display *display = thread_display();
struct x11drv_win_data *data;
DWORD end = NtGetTickCount() + 2000;
TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
for (;;)
{
XEvent event;
Window window;
int count = 0;
if (!(data = get_win_data( hwnd ))) break;
if (!data->managed || data->embedded || data->display != display) break;
if (!(window = data->whole_window)) break;
if (!data->mapped == !set)
{
TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
break;
}
if ((data->wm_state == WithdrawnState) != !set)
{
TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
break;
}
release_win_data( data );
while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
{
count++;
if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
if (event.type == DestroyNotify) call_event_handler( display, &event );
else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
}
if (!count)
{
struct pollfd pfd;
int timeout = end - NtGetTickCount();
pfd.fd = ConnectionNumber(display);
pfd.events = POLLIN;
if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
{
FIXME( "window %p/%lx wait timed out\n", hwnd, window );
return;
}
}
}
release_win_data( data );
}
/*****************************************************************
* SetFocus (X11DRV.@)
*

View file

@ -1213,7 +1213,10 @@ static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_stat
{
UINT i, count, old_state = data->pending_state.net_wm_state;
data->desired_state.net_wm_state = new_state;
if (!data->whole_window) return; /* no window, nothing to update */
if (data->wm_state_serial) return; /* another WM_STATE update is pending, wait for it to complete */
/* we ignore and override previous _NET_WM_STATE update requests */
if (old_state == new_state) return; /* states are the same, nothing to update */
if (data->pending_state.wm_state == IconicState) return; /* window is iconic, don't update its state now */
@ -1267,6 +1270,8 @@ static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_stat
SubstructureRedirectMask | SubstructureNotifyMask, &xev );
}
}
XFlush( data->display );
}
static void window_set_config( struct x11drv_win_data *data, const RECT *new_rect, BOOL above )
@ -1275,6 +1280,7 @@ static void window_set_config( struct x11drv_win_data *data, const RECT *new_rec
const RECT *old_rect = &data->pending_state.rect;
XWindowChanges changes;
data->desired_state.rect = *new_rect;
if (!data->whole_window) return; /* no window, nothing to update */
if (EqualRect( old_rect, new_rect )) return; /* rects are the same, nothing to update */
@ -1328,7 +1334,7 @@ static void update_net_wm_states( struct x11drv_win_data *data )
style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
if (style & WS_MINIMIZE)
new_state |= data->pending_state.net_wm_state & ((1 << NET_WM_STATE_FULLSCREEN)|(1 << NET_WM_STATE_MAXIMIZED));
new_state |= data->desired_state.net_wm_state & ((1 << NET_WM_STATE_FULLSCREEN)|(1 << NET_WM_STATE_MAXIMIZED));
if (data->is_fullscreen)
{
if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION)
@ -1412,7 +1418,9 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state )
{
UINT old_state = data->pending_state.wm_state;
data->desired_state.wm_state = new_state;
if (!data->whole_window) return; /* no window, nothing to update */
if (data->wm_state_serial) return; /* another WM_STATE update is pending, wait for it to complete */
if (old_state == new_state) return; /* states are the same, nothing to update */
data->pending_state.wm_state = new_state;
@ -1441,6 +1449,8 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state )
/* override redirect windows won't receive WM_STATE property changes */
if (!data->managed) data->wm_state_serial = 0;
XFlush( data->display );
}
@ -1452,7 +1462,6 @@ static void map_window( HWND hwnd, DWORD new_style )
struct x11drv_win_data *data;
make_owner_managed( hwnd );
wait_for_withdrawn_state( hwnd, TRUE );
if (!(data = get_win_data( hwnd ))) return;
@ -1466,7 +1475,6 @@ static void map_window( HWND hwnd, DWORD new_style )
sync_window_style( data );
window_set_wm_state( data, (new_style & WS_MINIMIZE) ? IconicState : NormalState );
XFlush( data->display );
data->mapped = TRUE;
data->iconic = (new_style & WS_MINIMIZE) != 0;
@ -1483,8 +1491,6 @@ static void unmap_window( HWND hwnd )
{
struct x11drv_win_data *data;
wait_for_withdrawn_state( hwnd, FALSE );
if (!(data = get_win_data( hwnd ))) return;
if (data->mapped)
@ -1581,7 +1587,7 @@ UINT window_update_client_config( struct x11drv_win_data *data )
void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value )
{
UINT *pending = &data->pending_state.wm_state, *current = &data->current_state.wm_state;
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;
const char *reason = NULL, *expected, *received;
@ -1606,16 +1612,20 @@ void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial,
else
{
WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected );
*pending = value; /* avoid requesting the same state again */
*desired = *pending = value; /* avoid requesting the same state again */
}
*current = value;
*expect_serial = 0;
/* send any pending changes from the desired state */
window_set_wm_state( data, data->desired_state.wm_state );
window_set_net_wm_state( data, data->desired_state.net_wm_state );
}
void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value )
{
UINT *pending = &data->pending_state.net_wm_state, *current = &data->current_state.net_wm_state;
UINT *desired = &data->desired_state.net_wm_state, *pending = &data->pending_state.net_wm_state, *current = &data->current_state.net_wm_state;
unsigned long *expect_serial = &data->net_wm_state_serial;
const char *reason = NULL, *expected, *received;
@ -1638,16 +1648,20 @@ void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long ser
else
{
WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected );
*pending = value; /* avoid requesting the same state again */
*desired = *pending = value; /* avoid requesting the same state again */
}
*current = value;
*expect_serial = 0;
/* send any pending changes from the desired state */
window_set_wm_state( data, data->desired_state.wm_state );
window_set_net_wm_state( data, data->desired_state.net_wm_state );
}
void window_configure_notify( struct x11drv_win_data *data, unsigned long serial, const RECT *value )
{
RECT *pending = &data->pending_state.rect, *current = &data->current_state.rect;
RECT *desired = &data->desired_state.rect, *pending = &data->pending_state.rect, *current = &data->current_state.rect;
unsigned long *expect_serial = &data->configure_serial;
const char *reason = NULL, *expected, *received;
@ -1670,7 +1684,7 @@ void window_configure_notify( struct x11drv_win_data *data, unsigned long serial
else
{
WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected );
*pending = *value; /* avoid requesting the same state again */
*desired = *pending = *value; /* avoid requesting the same state again */
}
*current = *value;
@ -1683,7 +1697,7 @@ BOOL window_has_pending_wm_state( HWND hwnd, UINT state )
BOOL pending;
if (!(data = get_win_data( hwnd ))) return FALSE;
if (state != -1 && data->pending_state.wm_state != state) pending = FALSE;
if (state != -1 && data->desired_state.wm_state != state) pending = FALSE;
else pending = !!data->wm_state_serial;
release_win_data( data );
@ -2053,6 +2067,7 @@ static void create_whole_window( struct x11drv_win_data *data )
if (!data->whole_window) goto done;
SetRect( &data->current_state.rect, pos.x, pos.y, pos.x + cx, pos.y + cy );
data->pending_state.rect = data->current_state.rect;
data->desired_state.rect = data->current_state.rect;
x11drv_xinput2_enable( data->display, data->whole_window );
set_initial_wm_hints( data->display, data->whole_window );
@ -2107,9 +2122,9 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des
if (data->whole_colormap) XFreeColormap( data->display, data->whole_colormap );
data->whole_window = data->client_window = 0;
data->whole_colormap = 0;
data->wm_state = WithdrawnState;
data->mapped = FALSE;
memset( &data->desired_state, 0, sizeof(data->desired_state) );
memset( &data->pending_state, 0, sizeof(data->pending_state) );
memset( &data->current_state, 0, sizeof(data->current_state) );
data->wm_state_serial = 0;

View file

@ -633,13 +633,13 @@ 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 */
int wm_state; /* current value of the WM_STATE property */
Window embedder; /* window id of embedder */
Pixmap icon_pixmap;
Pixmap icon_mask;
unsigned long *icon_bits;
unsigned int icon_size;
struct window_state desired_state; /* window state tracking the desired / win32 state */
struct window_state pending_state; /* window state tracking the pending / requested state */
struct window_state current_state; /* window state tracking the current X11 state */
unsigned long wm_state_serial; /* serial of last pending WM_STATE request */
@ -665,7 +665,6 @@ extern void window_configure_notify( struct x11drv_win_data *data, unsigned long
extern UINT window_update_client_state( struct x11drv_win_data *data );
extern UINT window_update_client_config( struct x11drv_win_data *data );
extern void wait_for_withdrawn_state( HWND hwnd, BOOL set );
extern Window init_clip_window(void);
extern void update_user_time( Time time );
extern UINT get_window_net_wm_state( Display *display, Window window );