mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-19 17:06:04 -07:00
winex11: Request window state updates asynchronously.
This commit is contained in:
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
|
@ -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);
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
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.@)
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue