This completely refactors the winex11 window state tracking, keeping track of the desired/pending/current window state and config in a fully asynchronous way, and avoiding duplicate requests. I believe this mitigates various race conditions that we're suffering from, solving most spurious event feedback loops when the X11 state is being applied while some win32 state change is being requested, and fixing the spurious d3d/ddraw/user32 test failures.
-- v7: winex11: Request window state updates asynchronously. winex11: Update the window client config on window state changes. winex11: Wait for pending ConfigureNotify before updating the client state. winex11: Wait for pending _NET_WM_STATE before updating the client state. winex11: Ignore focus changes during WM_STATE transitions. winex11: Introduce a new window_update_client_config helper. winex11: Introduce a new window_update_client_state helper. winex11: Use the new window state tracker to get WM_STATE value. winex11: Use the new window state tracker to get _NET_WM_STATE value. d3d9/tests: Flush events after minimizing and restoring focus window.
From: Rémi Bernon rbernon@codeweavers.com
Minimizing the window might trigger a focus change to the dummy window, while restoring and setting foreground should change the foreground back to the focus window.
However, the X window manager will instead send WM_TAKE_FOCUS event to the dummy window and to the focus window concurrently, and the dummy window might reply to it *after* we've restored the foreground to the focus window. This will later cause the device window to fail to get foreground, and the tests to randomly fail. --- dlls/d3d9/tests/d3d9ex.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/d3d9/tests/d3d9ex.c b/dlls/d3d9/tests/d3d9ex.c index 06105c25d66..f65996a8ed1 100644 --- a/dlls/d3d9/tests/d3d9ex.c +++ b/dlls/d3d9/tests/d3d9ex.c @@ -3145,7 +3145,9 @@ static void test_wndproc(void) * immediately restores the device on activation. There are plenty of WM_WINDOWPOSCHANGED * messages that are generated by ShowWindow, so testing for their absence is pointless. */ ShowWindow(focus_window, SW_MINIMIZE); + flush_events(); ShowWindow(focus_window, SW_RESTORE); + flush_events(); SetForegroundWindow(focus_window); flush_events();
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 8 +++----- dlls/winex11.drv/window.c | 8 ++------ dlls/winex11.drv/x11drv.h | 1 - 3 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 5300982d6b2..cada76a6329 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1142,13 +1142,12 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); if ((style & WS_CAPTION) == WS_CAPTION || !data->is_fullscreen) { - data->net_wm_state = get_window_net_wm_state( event->display, data->whole_window ); - if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && !(style & WS_MAXIMIZE)) + if ((data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && !(style & WS_MAXIMIZE)) { TRACE( "window %p/%lx is maximized\n", data->hwnd, data->whole_window ); config_cmd = SC_MAXIMIZE; } - else if (!(data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && (style & WS_MAXIMIZE)) + else if (!(data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && (style & WS_MAXIMIZE)) { TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window ); config_cmd = SC_RESTORE; @@ -1268,8 +1267,7 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat if (data->iconic && data->wm_state == NormalState) /* restore window */ { data->iconic = FALSE; - data->net_wm_state = get_window_net_wm_state( event->display, data->whole_window ); - if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED))) + if ((style & WS_CAPTION) == WS_CAPTION && (data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED))) { if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED)) { diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 02a1eb13c48..df5eeb5bc46 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1160,7 +1160,7 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) long monitors[4]; XEvent xev;
- if (!(data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) || is_virtual_desktop() + if (!(data->pending_state.net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) || is_virtual_desktop() || NtUserGetWindowLongW( data->hwnd, GWL_STYLE ) & WS_MINIMIZE) return;
@@ -1328,7 +1328,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->net_wm_state & ((1 << NET_WM_STATE_FULLSCREEN)|(1 << NET_WM_STATE_MAXIMIZED)); + new_state |= data->pending_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) @@ -1352,7 +1352,6 @@ static void update_net_wm_states( struct x11drv_win_data *data ) }
window_set_net_wm_state( data, new_state ); - data->net_wm_state = new_state; update_net_wm_fullscreen_monitors( data ); }
@@ -1490,7 +1489,6 @@ static void unmap_window( HWND hwnd ) TRACE( "win %p/%lx\n", data->hwnd, data->whole_window ); window_set_wm_state( data, WithdrawnState ); data->mapped = FALSE; - data->net_wm_state = 0; } release_win_data( data ); } @@ -1600,7 +1598,6 @@ void make_window_embedded( struct x11drv_win_data *data ) { /* the window cannot be mapped before being embedded */ window_set_wm_state( data, WithdrawnState ); - data->net_wm_state = 0; data->embedded = TRUE; data->managed = TRUE; sync_window_style( data ); @@ -2012,7 +2009,6 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des data->whole_window = data->client_window = 0; data->whole_colormap = 0; data->wm_state = WithdrawnState; - data->net_wm_state = 0; data->mapped = FALSE;
memset( &data->pending_state, 0, sizeof(data->pending_state) ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index f1f0f97486b..bf0fe26f925 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -634,7 +634,6 @@ struct x11drv_win_data 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 */ - DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ Window embedder; /* window id of embedder */ Pixmap icon_pixmap; Pixmap icon_mask;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index cada76a6329..d155ebbf33f 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1264,7 +1264,7 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat
style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
- if (data->iconic && data->wm_state == NormalState) /* restore window */ + if (data->iconic && data->current_state.wm_state == NormalState) /* restore window */ { data->iconic = FALSE; if ((style & WS_CAPTION) == WS_CAPTION && (data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED))) @@ -1285,7 +1285,7 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat } } } - else if (!data->iconic && data->wm_state == IconicState) + else if (!data->iconic && data->current_state.wm_state == IconicState) { data->iconic = TRUE; if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 40 ++------------------------------------- dlls/winex11.drv/window.c | 38 +++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 2 ++ 3 files changed, 42 insertions(+), 38 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index d155ebbf33f..540c9b30a1f 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1231,7 +1231,7 @@ static int get_window_xembed_info( Display *display, Window window ) static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window ) { struct x11drv_win_data *data; - UINT style, value = 0, state_cmd = 0; + UINT value = 0, state_cmd = 0;
if (!(data = get_win_data( hwnd ))) return; if (event->state == PropertyNewValue) value = get_window_wm_state( event->display, event->window ); @@ -1252,49 +1252,13 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat TRACE( "%p/%lx: new WM_STATE %d from %d\n", data->hwnd, data->whole_window, new_state, old_state ); data->wm_state = new_state; - /* ignore the initial state transition out of withdrawn state */ - /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */ - if (!old_state) goto done; } } break; }
- if (!update_window || !data->managed || !data->mapped) goto done; + if (update_window) state_cmd = window_update_client_state( data );
- style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); - - if (data->iconic && data->current_state.wm_state == NormalState) /* restore window */ - { - data->iconic = FALSE; - if ((style & WS_CAPTION) == WS_CAPTION && (data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED))) - { - if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED)) - { - TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window ); - state_cmd = SC_MAXIMIZE; - } - } - else - { - if (style & (WS_MINIMIZE | WS_MAXIMIZE)) - { - BOOL activate = (style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE); - TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window ); - state_cmd = MAKELONG(SC_RESTORE, activate); - } - } - } - else if (!data->iconic && data->current_state.wm_state == IconicState) - { - data->iconic = TRUE; - if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED)) - { - TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window ); - state_cmd = SC_MINIMIZE; - } - } -done: release_win_data( data );
if (state_cmd) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index df5eeb5bc46..686b93e855f 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1493,6 +1493,44 @@ static void unmap_window( HWND hwnd ) release_win_data( data ); }
+UINT window_update_client_state( struct x11drv_win_data *data ) +{ + UINT old_style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); + + if (!data->managed) return 0; /* unmanaged windows are managed by the Win32 side */ + if (!data->mapped) return 0; /* ignore state changes on invisible windows */ + + if (data->iconic && data->current_state.wm_state == NormalState) /* restore window */ + { + data->iconic = FALSE; + if ((old_style & WS_CAPTION) == WS_CAPTION && (data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED))) + { + if ((old_style & WS_MAXIMIZEBOX) && !(old_style & WS_DISABLED)) + { + TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window ); + return SC_MAXIMIZE; + } + } + else if (old_style & (WS_MINIMIZE | WS_MAXIMIZE)) + { + BOOL activate = (old_style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE); + TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window ); + return MAKELONG(SC_RESTORE, activate); + } + } + else if (!data->iconic && data->current_state.wm_state == IconicState) + { + data->iconic = TRUE; + if ((old_style & WS_MINIMIZEBOX) && !(old_style & WS_DISABLED)) + { + TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window ); + return SC_MINIMIZE; + } + } + + return 0; +} + 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; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index bf0fe26f925..e73941a7578 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -661,6 +661,8 @@ extern void destroy_vk_surface( HWND hwnd ); 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 ); +extern UINT window_update_client_state( 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 );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 67 ++------------------------------------- dlls/winex11.drv/window.c | 39 +++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 43 insertions(+), 64 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 540c9b30a1f..7535e89ed50 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1078,8 +1078,7 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) struct x11drv_win_data *data; RECT rect; POINT pos = {event->x, event->y}; - UINT style, flags = 0, config_cmd = 0; - int cx, cy, x, y; + UINT config_cmd;
if (!hwnd) return FALSE; if (!(data = get_win_data( hwnd ))) return FALSE; @@ -1098,68 +1097,8 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) SetRect( &rect, pos.x, pos.y, pos.x + event->width, pos.y + event->height ); window_configure_notify( data, event->serial, &rect );
- if (!data->mapped || data->iconic) goto done; - if (!data->whole_window || !data->managed) goto done; - if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0) - { - TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n", - hwnd, data->whole_window, event->x, event->y, event->width, event->height, - event->serial, data->configure_serial ); - goto done; - } - - rect = window_rect_from_visible( &data->rects, rect ); - - TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n", - hwnd, data->whole_window, (int)rect.left, (int)rect.top, - (int)(rect.right-rect.left), (int)(rect.bottom-rect.top), - event->x, event->y, event->width, event->height ); - - /* Compare what has changed */ - - x = rect.left; - y = rect.top; - cx = rect.right - rect.left; - cy = rect.bottom - rect.top; - flags = SWP_NOACTIVATE | SWP_NOZORDER; - - if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */ - - if (data->rects.window.left == x && data->rects.window.top == y) flags |= SWP_NOMOVE; - else - TRACE( "%p moving from (%d,%d) to (%d,%d)\n", - hwnd, (int)data->rects.window.left, (int)data->rects.window.top, x, y ); - - if ((data->rects.window.right - data->rects.window.left == cx && - data->rects.window.bottom - data->rects.window.top == cy) || - IsRectEmpty( &data->rects.window )) - flags |= SWP_NOSIZE; - else - TRACE( "%p resizing from (%dx%d) to (%dx%d)\n", - hwnd, (int)(data->rects.window.right - data->rects.window.left), - (int)(data->rects.window.bottom - data->rects.window.top), cx, cy ); - - style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); - if ((style & WS_CAPTION) == WS_CAPTION || !data->is_fullscreen) - { - if ((data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && !(style & WS_MAXIMIZE)) - { - TRACE( "window %p/%lx is maximized\n", data->hwnd, data->whole_window ); - config_cmd = SC_MAXIMIZE; - } - else if (!(data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && (style & WS_MAXIMIZE)) - { - TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window ); - config_cmd = SC_RESTORE; - } - } - if (!config_cmd && (flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE)) - { - TRACE( "window %p/%lx config changed %s -> %s, flags %#x\n", data->hwnd, data->whole_window, - wine_dbgstr_rect(&data->rects.window), wine_dbgstr_rect(&rect), flags ); - config_cmd = MAKELONG(SC_MOVE, flags); - } -done: + config_cmd = window_update_client_config( data ); + rect = window_rect_from_visible( &data->rects, data->current_state.rect ); release_win_data( data );
if (config_cmd) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 686b93e855f..6e7a2f6b050 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1531,6 +1531,45 @@ UINT window_update_client_state( struct x11drv_win_data *data ) return 0; }
+UINT window_update_client_config( struct x11drv_win_data *data ) +{ + UINT old_style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ), flags; + RECT rect, old_rect = data->rects.window, new_rect; + + if (!data->managed) return 0; /* unmanaged windows are managed by the Win32 side */ + if (!data->mapped) return 0; /* ignore config changes on invisible windows */ + if (data->iconic) return 0; /* ignore config changes on minimized windows */ + + if (data->configure_serial) return 0; /* another config update is pending, wait for it to complete */ + + if ((old_style & WS_CAPTION) == WS_CAPTION || !data->is_fullscreen) + { + if ((data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && !(old_style & WS_MAXIMIZE)) + { + TRACE( "window %p/%lx is maximized\n", data->hwnd, data->whole_window ); + return SC_MAXIMIZE; + } + if (!(data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && (old_style & WS_MAXIMIZE)) + { + TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window ); + return SC_RESTORE; + } + } + + flags = SWP_NOACTIVATE | SWP_NOZORDER; + rect = new_rect = window_rect_from_visible( &data->rects, data->current_state.rect ); + if (new_rect.left == old_rect.left && new_rect.top == old_rect.top) flags |= SWP_NOMOVE; + else OffsetRect( &rect, old_rect.left - new_rect.left, old_rect.top - new_rect.top ); + if (rect.right == old_rect.right && rect.bottom == old_rect.bottom) flags |= SWP_NOSIZE; + else if (IsRectEmpty( &rect )) flags |= SWP_NOSIZE; + + if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) == (SWP_NOSIZE | SWP_NOMOVE)) return 0; + + TRACE( "window %p/%lx config changed %s -> %s, flags %#x\n", data->hwnd, data->whole_window, + wine_dbgstr_rect(&old_rect), wine_dbgstr_rect(&new_rect), flags ); + return MAKELONG(SC_MOVE, flags); +} + 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; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index e73941a7578..d5f487d8247 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -662,6 +662,7 @@ extern void window_wm_state_notify( struct x11drv_win_data *data, unsigned long 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 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);
From: Rémi Bernon rbernon@codeweavers.com
When WM_STATE is being quickly updated, and depending on the WM we might receive transient focus changes, which will disrupt the Win32 state and make us randomly lose focus.
Ignore them instead, when a window is being shown, and wait for WM_STATE to be updated and stable. We will eventually receive a WM_TAKE_FOCUS / FocusIn event *after* a window has been shown.
When a window is hidden or minimized, we will receive the FocusOut event during the WM_STATE transition, and can safely handle it in this case, as we should have done all the Win32 side effects and have changed the foreground window already.
When there's no window state change pending, the focus change event is unexpected, coming from the user or WM, and we handle it normally. --- dlls/winex11.drv/event.c | 46 ++++++++++++++++++++++++++++++--------- dlls/winex11.drv/window.c | 17 +++++++++++++-- dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 52 insertions(+), 12 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 7535e89ed50..82e82e6bc71 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 6e7a2f6b050..bd13761aff4 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1417,8 +1417,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)) { @@ -1668,6 +1668,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 d5f487d8247..fbaa416c617 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -658,6 +658,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 );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 10 +++++++++- dlls/winex11.drv/window.c | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 82e82e6bc71..7a9626b4542 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1247,12 +1247,20 @@ static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event ) static void handle_net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) { struct x11drv_win_data *data; - UINT value = 0; + UINT value = 0, state_cmd = 0;
if (!(data = get_win_data( hwnd ))) return; if (event->state == PropertyNewValue) value = get_window_net_wm_state( event->display, event->window ); window_net_wm_state_notify( data, event->serial, value ); + + state_cmd = window_update_client_state( data ); release_win_data( data ); + + if (state_cmd) + { + if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); + send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 ); + } }
/*********************************************************************** diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index bd13761aff4..783f498678f 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1500,6 +1500,9 @@ UINT window_update_client_state( struct x11drv_win_data *data ) if (!data->managed) return 0; /* unmanaged windows are managed by the Win32 side */ if (!data->mapped) return 0; /* ignore state changes on invisible windows */
+ if (data->wm_state_serial) return 0; /* another WM_STATE update is pending, wait for it to complete */ + if (data->net_wm_state_serial) return 0; /* another _NET_WM_STATE update is pending, wait for it to complete */ + if (data->iconic && data->current_state.wm_state == NormalState) /* restore window */ { data->iconic = FALSE;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 11 +++++++++-- dlls/winex11.drv/window.c | 1 + 2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 7a9626b4542..70836a887f0 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1104,7 +1104,7 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) struct x11drv_win_data *data; RECT rect; POINT pos = {event->x, event->y}; - UINT config_cmd; + UINT config_cmd, state_cmd;
if (!hwnd) return FALSE; if (!(data = get_win_data( hwnd ))) return FALSE; @@ -1123,17 +1123,24 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) SetRect( &rect, pos.x, pos.y, pos.x + event->width, pos.y + event->height ); window_configure_notify( data, event->serial, &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 );
+ if (state_cmd) + { + if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); + send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 ); + } + if (config_cmd) { if (LOWORD(config_cmd) == SC_MOVE) NtUserSetRawWindowPos( hwnd, rect, HIWORD(config_cmd), FALSE ); else send_message( hwnd, WM_SYSCOMMAND, LOWORD(config_cmd), 0 ); }
- return !!config_cmd; + return config_cmd || state_cmd; }
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 783f498678f..63477c14a8a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1502,6 +1502,7 @@ UINT window_update_client_state( struct x11drv_win_data *data )
if (data->wm_state_serial) return 0; /* another WM_STATE update is pending, wait for it to complete */ if (data->net_wm_state_serial) return 0; /* another _NET_WM_STATE update is pending, wait for it to complete */ + if (data->configure_serial) return 0; /* another config update is pending, wait for it to complete */
if (data->iconic && data->current_state.wm_state == NormalState) /* restore window */ {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 28 +++++++++++++++++++++++++--- dlls/winex11.drv/window.c | 2 ++ 2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 70836a887f0..cc4869c4666 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1203,7 +1203,8 @@ static int get_window_xembed_info( Display *display, Window window ) static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window ) { struct x11drv_win_data *data; - UINT value = 0, state_cmd = 0; + UINT value = 0, state_cmd = 0, config_cmd = 0; + RECT rect;
if (!(data = get_win_data( hwnd ))) return; if (event->state == PropertyNewValue) value = get_window_wm_state( event->display, event->window ); @@ -1229,7 +1230,12 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat break; }
- if (update_window) state_cmd = window_update_client_state( data ); + 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 );
@@ -1238,6 +1244,12 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 ); } + + if (config_cmd) + { + if (LOWORD(config_cmd) == SC_MOVE) NtUserSetRawWindowPos( hwnd, rect, HIWORD(config_cmd), FALSE ); + else send_message( hwnd, WM_SYSCOMMAND, LOWORD(config_cmd), 0 ); + } }
static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event ) @@ -1254,13 +1266,17 @@ static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event ) static void handle_net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) { struct x11drv_win_data *data; - UINT value = 0, state_cmd = 0; + UINT value = 0, state_cmd = 0, config_cmd = 0; + RECT rect;
if (!(data = get_win_data( hwnd ))) return; if (event->state == PropertyNewValue) value = get_window_net_wm_state( event->display, event->window ); window_net_wm_state_notify( data, event->serial, value );
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 );
if (state_cmd) @@ -1268,6 +1284,12 @@ static void handle_net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 ); } + + if (config_cmd) + { + if (LOWORD(config_cmd) == SC_MOVE) NtUserSetRawWindowPos( hwnd, rect, HIWORD(config_cmd), FALSE ); + else send_message( hwnd, WM_SYSCOMMAND, LOWORD(config_cmd), 0 ); + } }
/*********************************************************************** diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 63477c14a8a..2fa4d8fc0e0 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1544,6 +1544,8 @@ UINT window_update_client_config( struct x11drv_win_data *data ) if (!data->mapped) return 0; /* ignore config changes on invisible windows */ if (data->iconic) return 0; /* ignore config changes on minimized windows */
+ if (data->wm_state_serial) return 0; /* another WM_STATE update is pending, wait for it to complete */ + if (data->net_wm_state_serial) return 0; /* another _NET_WM_STATE update is pending, wait for it to complete */ if (data->configure_serial) return 0; /* another config update is pending, wait for it to complete */
if ((old_style & WS_CAPTION) == WS_CAPTION || !data->is_fullscreen)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 101 +++----------------------------------- dlls/winex11.drv/window.c | 44 ++++++++++++----- dlls/winex11.drv/x11drv.h | 3 +- 3 files changed, 38 insertions(+), 110 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index cc4869c4666..0a91148acde 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -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.@) * diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 2fa4d8fc0e0..2beb0853c7d 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -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; @@ -1438,6 +1446,11 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state ) if (!data->embedded) XIconifyWindow( data->display, data->whole_window, data->vis.screen ); break; } + + /* override redirect windows won't receive WM_STATE property changes */ + if (!data->managed) data->wm_state_serial = 0; + + XFlush( data->display ); }
@@ -1449,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;
@@ -1463,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; @@ -1480,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) @@ -1578,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;
@@ -1603,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;
@@ -1635,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;
@@ -1667,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; @@ -1680,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 );
@@ -2050,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 ); @@ -2104,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; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index fbaa416c617..38503667f23 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -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 );