This fixes window size being broken when dragged over multiple monitors with different scales and adds support for padded fullscreen windows when physical display mode aspect ratio doesn't match the emulated one.
-- v2: winex11: Update the Win32 window state outside of event handlers. user32/tests: Workaround a FVWM maximized window state bug. winex11: Delay window config request when restoring from fullscreen/maximized. winex11: Avoid sending WM_WINDOWPOSCHANGING when applying window manager config. winex11: Generate GravityNotify events instead of ConfigureNotify. winex11: Introduce a new get_window_state_updates helper.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 21 +++++++-------------- dlls/winex11.drv/window.c | 18 ++++++++++++++++-- dlls/winex11.drv/x11drv.h | 3 +-- 3 files changed, 24 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 0a91148acde..1008769f0b9 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1123,11 +1123,10 @@ 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 (!get_window_state_updates( hwnd, &state_cmd, &config_cmd, &rect )) return FALSE; + if (state_cmd) { if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); @@ -1140,7 +1139,7 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) else send_message( hwnd, WM_SYSCOMMAND, LOWORD(config_cmd), 0 ); }
- return config_cmd || state_cmd; + return TRUE; }
@@ -1209,13 +1208,10 @@ 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 ); - - 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 (!get_window_state_updates( hwnd, &state_cmd, &config_cmd, &rect )) return; + if (state_cmd) { if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); @@ -1249,13 +1245,10 @@ static void handle_net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) 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 (!get_window_state_updates( hwnd, &state_cmd, &config_cmd, &rect )) return; + if (state_cmd) { if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 2beb0853c7d..370ef36ee23 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1502,7 +1502,7 @@ static void unmap_window( HWND hwnd ) release_win_data( data ); }
-UINT window_update_client_state( struct x11drv_win_data *data ) +static UINT window_update_client_state( struct x11drv_win_data *data ) { UINT old_style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
@@ -1544,7 +1544,7 @@ UINT window_update_client_state( struct x11drv_win_data *data ) return 0; }
-UINT window_update_client_config( struct x11drv_win_data *data ) +static 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; @@ -1585,6 +1585,20 @@ UINT window_update_client_config( struct x11drv_win_data *data ) return MAKELONG(SC_MOVE, flags); }
+BOOL get_window_state_updates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect ) +{ + struct x11drv_win_data *data; + + if (!(data = get_win_data( hwnd ))) return FALSE; + + *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 ); + return *state_cmd || *config_cmd; +} + void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ) { UINT *desired = &data->desired_state.wm_state, *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 38503667f23..5641ea407f8 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -662,8 +662,7 @@ 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 ); -extern UINT window_update_client_state( struct x11drv_win_data *data ); -extern UINT window_update_client_config( struct x11drv_win_data *data ); +extern BOOL get_window_state_updates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect );
extern Window init_clip_window(void); extern void update_user_time( Time time );
From: Rémi Bernon rbernon@codeweavers.com
In order to better distinguish them from the ConfigureNotify events sent by the WM.
Some window managers (openbox) send a sequence of ConfigureNotify to top-level window frames when restoring them from minimized state, for animation purposes, and they shouldn't be reflected on the Win32 side.
We do not need to update the Win32 state when top-level windows frame is being moved, as the WM will send us a ConfigureNotify later and we only need to keep track of its position for mouse event coordinates.
Handle the generated GravityNotify events for embedded windows only, to match their Win32 state/config with their X state/config. --- dlls/winex11.drv/event.c | 103 +++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 32 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 1008769f0b9..9b9d626fc9a 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -86,6 +86,7 @@ static BOOL X11DRV_Expose( HWND hwnd, XEvent *event ); static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ); static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event ); static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *event ); +static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *event ); static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *event ); static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *event ); static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *event ); @@ -118,7 +119,7 @@ static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] = X11DRV_ReparentNotify, /* 21 ReparentNotify */ X11DRV_ConfigureNotify, /* 22 ConfigureNotify */ NULL, /* 23 ConfigureRequest */ - NULL, /* 24 GravityNotify */ + X11DRV_GravityNotify, /* 24 GravityNotify */ NULL, /* 25 ResizeRequest */ NULL, /* 26 CirculateNotify */ NULL, /* 27 CirculateRequest */ @@ -171,41 +172,24 @@ static inline void free_event_data( XEvent *event ) #endif }
-static void host_window_send_configure_events( struct host_window *win, Display *display, unsigned long serial, XEvent *previous ) +static void host_window_send_gravity_events( struct host_window *win, Display *display, unsigned long serial, XEvent *previous ) { - XConfigureEvent configure = {.type = ConfigureNotify, .serial = serial, .display = display}; + XGravityEvent event = {.type = GravityNotify, .serial = serial, .display = display}; unsigned int i;
for (i = 0; i < win->children_count; i++) { RECT rect = win->children[i].rect; - struct x11drv_win_data *data; - HWND hwnd; - - configure.event = win->children[i].window; - configure.window = configure.event; - configure.x = rect.left; - configure.y = rect.top; - configure.width = rect.right - rect.left; - configure.height = rect.bottom - rect.top; - configure.send_event = 0; - - /* Only send a fake event if we're not expecting one from a state/config request. - * We may know what was requested, but not what the WM will decide to reply, and our - * fake event might trigger some undesired changes before the real ConfigureNotify. - */ - if (!XFindContext( configure.display, configure.window, winContext, (char **)&hwnd ) && - (data = get_win_data( hwnd ))) - { - /* embedded windows won't receive synthetic ConfigureNotify and are positioned by the WM */ - BOOL has_serial = !data->embedded && (data->wm_state_serial || data->configure_serial); - release_win_data( data ); - if (has_serial) continue; - }
- if (previous->type == ConfigureNotify && previous->xconfigure.window == configure.window) continue; - TRACE( "generating ConfigureNotify for window %p/%lx, rect %s\n", hwnd, configure.window, wine_dbgstr_rect(&rect) ); - XPutBackEvent( configure.display, (XEvent *)&configure ); + event.event = win->children[i].window; + event.window = event.event; + event.x = rect.left; + event.y = rect.top; + event.send_event = 0; + + if (previous->type == ConfigureNotify && previous->xconfigure.window == event.window) continue; + TRACE( "generating GravityNotify for window %lx, rect %s\n", event.window, wine_dbgstr_rect(&rect) ); + XPutBackEvent( event.display, (XEvent *)&event ); } }
@@ -226,7 +210,7 @@ static BOOL host_window_filter_event( XEvent *event, XEvent *previous ) XReparentEvent *reparent = (XReparentEvent *)event; TRACE( "host window %p/%lx ReparentNotify, parent %lx\n", win, win->window, reparent->parent ); host_window_set_parent( win, reparent->parent ); - host_window_send_configure_events( win, event->xany.display, event->xany.serial, previous ); + host_window_send_gravity_events( win, event->xany.display, event->xany.serial, previous ); break; } case GravityNotify: @@ -235,7 +219,7 @@ static BOOL host_window_filter_event( XEvent *event, XEvent *previous ) OffsetRect( &win->rect, gravity->x - win->rect.left, gravity->y - win->rect.top ); if (win->parent) win->rect = host_window_configure_child( win->parent, win->window, win->rect, FALSE ); TRACE( "host window %p/%lx GravityNotify, rect %s\n", win, win->window, wine_dbgstr_rect(&win->rect) ); - host_window_send_configure_events( win, event->xany.display, event->xany.serial, previous ); + host_window_send_gravity_events( win, event->xany.display, event->xany.serial, previous ); break; } case ConfigureNotify: @@ -244,7 +228,7 @@ static BOOL host_window_filter_event( XEvent *event, XEvent *previous ) SetRect( &win->rect, configure->x, configure->y, configure->x + configure->width, configure->y + configure->height ); if (win->parent) win->rect = host_window_configure_child( win->parent, win->window, win->rect, configure->send_event ); TRACE( "host window %p/%lx ConfigureNotify, rect %s\n", win, win->window, wine_dbgstr_rect(&win->rect) ); - host_window_send_configure_events( win, event->xany.display, event->xany.serial, previous ); + host_window_send_gravity_events( win, event->xany.display, event->xany.serial, previous ); break; } } @@ -1109,6 +1093,7 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) if (!hwnd) return FALSE; if (!(data = get_win_data( hwnd ))) return FALSE;
+ /* update our view of the window tree for mouse event coordinate mapping */ if (data->whole_window && data->parent && !data->parent_invalid) { SetRect( &rect, event->x, event->y, event->x + event->width, event->y + event->height ); @@ -1142,6 +1127,60 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) return TRUE; }
+/*********************************************************************** + * X11DRV_GravityNotify + */ +static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *xev ) +{ + XGravityEvent *event = &xev->xgravity; + struct x11drv_win_data *data; + RECT rect; + POINT pos = {event->x, event->y}; + UINT config_cmd, state_cmd; + + if (!hwnd) return FALSE; + if (!(data = get_win_data( hwnd ))) return FALSE; + rect = data->rects.window; + + /* update our view of the window tree for mouse event coordinate mapping */ + if (data->whole_window && data->parent && !data->parent_invalid) + { + OffsetRect( &rect, event->x - rect.left, event->y - rect.top ); + host_window_configure_child( data->parent, data->whole_window, rect, event->send_event ); + } + + /* only handle GravityNotify events, that we generate ourselves, for embedded windows, + * top-level windows will receive the WM synthetic ConfigureNotify events instead. + */ + if (data->embedded) + { + /* synthetic events are already in absolute coordinates */ + if (!event->send_event) pos = host_window_map_point( data->parent, event->x, event->y ); + else if (is_virtual_desktop()) FIXME( "synthetic event mapping not implemented\n" ); + + pos = root_to_virtual_screen( pos.x, pos.y ); + OffsetRect( &rect, pos.x - rect.left, pos.y - rect.top ); + window_configure_notify( data, event->serial, &rect ); + } + + release_win_data( data ); + + if (!get_window_state_updates( hwnd, &state_cmd, &config_cmd, &rect )) return FALSE; + + 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 TRUE; +}
/*********************************************************************** * get_window_wm_state
From: Rémi Bernon rbernon@codeweavers.com
It sometimes create a feedback loop, trying to override the window manager config changes. --- dlls/winex11.drv/window.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 370ef36ee23..44330b6213a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1546,6 +1546,7 @@ static UINT window_update_client_state( struct x11drv_win_data *data )
static UINT window_update_client_config( struct x11drv_win_data *data ) { + static const UINT fullscreen_mask = (1 << NET_WM_STATE_MAXIMIZED) | (1 << NET_WM_STATE_FULLSCREEN); UINT old_style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ), flags; RECT rect, old_rect = data->rects.window, new_rect;
@@ -1580,6 +1581,9 @@ static UINT window_update_client_config( struct x11drv_win_data *data )
if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) == (SWP_NOSIZE | SWP_NOMOVE)) return 0;
+ /* avoid event feedback loops from window rect adjustments of maximized / fullscreen windows */ + if (data->current_state.net_wm_state & fullscreen_mask) flags |= SWP_NOSENDCHANGING; + 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);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 44330b6213a..f5edfe4ed64 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1276,6 +1276,7 @@ static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_stat
static void window_set_config( struct x11drv_win_data *data, const RECT *new_rect, BOOL above ) { + static const UINT fullscreen_mask = (1 << NET_WM_STATE_MAXIMIZED) | (1 << NET_WM_STATE_FULLSCREEN); UINT style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ), mask = 0; const RECT *old_rect = &data->pending_state.rect; XWindowChanges changes; @@ -1284,6 +1285,18 @@ static void window_set_config( struct x11drv_win_data *data, const RECT *new_rec if (!data->whole_window) return; /* no window, nothing to update */ if (EqualRect( old_rect, new_rect )) return; /* rects are the same, nothing to update */
+ if (data->pending_state.wm_state == NormalState && data->net_wm_state_serial && + !(data->pending_state.net_wm_state & fullscreen_mask) && + (data->current_state.net_wm_state & fullscreen_mask)) + { + /* Some window managers are sending a ConfigureNotify event with the fullscreen size when + * exiting a fullscreen window, with a serial that we cannot predict. Handling that event + * will override the Win32 window size and make the window fullscreen again. + */ + WARN( "window %p/%lx is exiting maximize/fullscreen, delaying request\n", data->hwnd, data->whole_window ); + return; + } + /* resizing a managed maximized window is not allowed */ if (!(style & WS_MAXIMIZE) || !data->managed) { @@ -1639,6 +1652,7 @@ void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, /* 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 ); + window_set_config( data, &data->desired_state.rect, FALSE ); }
void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ) @@ -1675,6 +1689,7 @@ void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long ser /* 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 ); + window_set_config( data, &data->desired_state.rect, FALSE ); }
void window_configure_notify( struct x11drv_win_data *data, unsigned long serial, const RECT *value )
From: Rémi Bernon rbernon@codeweavers.com
This adds a todo_wine because it exhibits a FVWM bug: the window manager doesn't keep the _NET_WM_STATE maximized bits, and instead simply resize the windows.
The missing events don't matter too much, although they would prevent us from serializing the updates with other changes, but it also makes it impossible to figure whether the windows are actually maximized or not.
For visible windows, the message we send to the window manager simply doesn't trigger any PropertyNotify event. The update is considered as pending until the maximized style is cleared, and we never try to remove the maximized state from the Win32 state.
For hidden windows, the _NET_WM_STATE property is changed directly, this sticks and we receive a corresponding PropertyNotify event. However, as soon as the window is mapped, FVWM removes the bits and we receive another PropertyNotify event accordingly. This can only be considered as a genuine state update, and we clear the maximized state from the Win32 side accordingly.
Previously, as the state updates were not re-entrant, the update didn't trigger another window manager state/config update and the window stayed in an inconsistent state, which somehow passed the tests.
As the updates are now re-entrant, the window manager is notified of the maximized state removal, and resizes the window to its normal size, then fails the tests. --- dlls/user32/tests/win.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 5f30818a830..c2da0b04dad 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -6034,6 +6034,14 @@ static void test_AWRwindow(LPCSTR class, LONG style, LONG exStyle, BOOL menu) ok(hwnd != NULL, "Failed to create window class=%s, style=0x%08lx, exStyle=0x%08lx\n", class, style, exStyle);
ShowWindow(hwnd, SW_SHOW); + flush_events(TRUE); + + /* retry setting the maximized state to workaround a FVWM bug */ + if ((style & WS_MAXIMIZE) && !(GetWindowLongW(hwnd, GWL_STYLE) & WS_MAXIMIZE)) + { + ShowWindow(hwnd, SW_MAXIMIZE); + flush_events(TRUE); + }
test_nonclient_area(hwnd);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/driver.c | 9 +++++- dlls/win32u/message.c | 18 +++++++++++ dlls/win32u/spy.c | 1 + dlls/winex11.drv/event.c | 68 ++++----------------------------------- dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/window.c | 9 +++++- dlls/winex11.drv/x11drv.h | 1 + include/ntuser.h | 1 + include/wine/gdi_driver.h | 1 + 9 files changed, 45 insertions(+), 64 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 92bad66fc2f..3ba5402b82e 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -876,7 +876,12 @@ static BOOL nulldrv_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, c return TRUE; }
-extern BOOL nulldrv_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask ) +static BOOL nulldrv_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask ) +{ + return FALSE; +} + +static BOOL nulldrv_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect ) { return FALSE; } @@ -1279,6 +1284,7 @@ static const struct user_driver_funcs lazy_load_driver = nulldrv_WindowMessage, nulldrv_WindowPosChanging, nulldrv_GetWindowStyleMasks, + nulldrv_GetWindowStateUpdates, nulldrv_CreateWindowSurface, nulldrv_MoveWindowBits, nulldrv_WindowPosChanged, @@ -1367,6 +1373,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(WindowMessage); SET_USER_FUNC(WindowPosChanging); SET_USER_FUNC(GetWindowStyleMasks); + SET_USER_FUNC(GetWindowStateUpdates); SET_USER_FUNC(CreateWindowSurface); SET_USER_FUNC(MoveWindowBits); SET_USER_FUNC(WindowPosChanged); diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 044310a2f0e..4d5abfa4aab 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2127,6 +2127,24 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR if (!ime_hwnd || ime_hwnd == NtUserGetParent( hwnd )) return 0; return send_message( ime_hwnd, WM_IME_NOTIFY, wparam, lparam ); } + case WM_WINE_WINDOW_STATE_CHANGED: + { + UINT state_cmd, config_cmd; + RECT window_rect; + + if (!user_driver->pGetWindowStateUpdates( hwnd, &state_cmd, &config_cmd, &window_rect )) return 0; + 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, window_rect, HIWORD(config_cmd), FALSE ); + else send_message( hwnd, WM_SYSCOMMAND, LOWORD(config_cmd), 0 ); + } + return 0; + } case WM_WINE_UPDATEWINDOWSTATE: update_window_state( hwnd ); return 0; diff --git a/dlls/win32u/spy.c b/dlls/win32u/spy.c index f44771fdb90..4afe4917e78 100644 --- a/dlls/win32u/spy.c +++ b/dlls/win32u/spy.c @@ -1140,6 +1140,7 @@ static const char * const WINEMessageTypeNames[SPY_MAX_WINEMSGNUM + 1] = "WM_WINE_KEYBOARD_LL_HOOK", "WM_WINE_MOUSE_LL_HOOK", "WM_WINE_IME_NOTIFY", + "WM_WINE_WINDOW_STATE_CHANGED", "WM_WINE_UPDATEWINDOWSTATE", };
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 9b9d626fc9a..aee4a827b52 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1088,7 +1088,6 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) struct x11drv_win_data *data; RECT rect; POINT pos = {event->x, event->y}; - UINT config_cmd, state_cmd;
if (!hwnd) return FALSE; if (!(data = get_win_data( hwnd ))) return FALSE; @@ -1110,21 +1109,7 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
release_win_data( data );
- if (!get_window_state_updates( hwnd, &state_cmd, &config_cmd, &rect )) return FALSE; - - 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 TRUE; + return NtUserPostMessage( hwnd, WM_WINE_WINDOW_STATE_CHANGED, 0, 0 ); }
/*********************************************************************** @@ -1136,7 +1121,6 @@ static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *xev ) struct x11drv_win_data *data; RECT rect; POINT pos = {event->x, event->y}; - UINT config_cmd, state_cmd;
if (!hwnd) return FALSE; if (!(data = get_win_data( hwnd ))) return FALSE; @@ -1165,21 +1149,7 @@ static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
release_win_data( data );
- if (!get_window_state_updates( hwnd, &state_cmd, &config_cmd, &rect )) return FALSE; - - 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 TRUE; + return NtUserPostMessage( hwnd, WM_WINE_WINDOW_STATE_CHANGED, 0, 0 ); }
/*********************************************************************** @@ -1241,27 +1211,14 @@ static int get_window_xembed_info( Display *display, Window 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; - RECT rect; + UINT value = 0;
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 ); release_win_data( data );
- if (!get_window_state_updates( hwnd, &state_cmd, &config_cmd, &rect )) return; - - 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 ); - } + NtUserPostMessage( hwnd, WM_WINE_WINDOW_STATE_CHANGED, 0, 0 ); }
static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event ) @@ -1278,27 +1235,14 @@ 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, config_cmd = 0; - RECT rect; + UINT value = 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 ); release_win_data( data );
- if (!get_window_state_updates( hwnd, &state_cmd, &config_cmd, &rect )) return; - - 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 ); - } + NtUserPostMessage( hwnd, WM_WINE_WINDOW_STATE_CHANGED, 0, 0 ); }
/*********************************************************************** diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index e0f465a2771..37971dc8236 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -447,6 +447,7 @@ static const struct user_driver_funcs x11drv_funcs = .pWindowMessage = X11DRV_WindowMessage, .pWindowPosChanging = X11DRV_WindowPosChanging, .pGetWindowStyleMasks = X11DRV_GetWindowStyleMasks, + .pGetWindowStateUpdates = X11DRV_GetWindowStateUpdates, .pCreateWindowSurface = X11DRV_CreateWindowSurface, .pMoveWindowBits = X11DRV_MoveWindowBits, .pWindowPosChanged = X11DRV_WindowPosChanged, diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index f5edfe4ed64..793f0417c91 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1602,10 +1602,15 @@ static UINT window_update_client_config( struct x11drv_win_data *data ) return MAKELONG(SC_MOVE, flags); }
-BOOL get_window_state_updates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect ) +/*********************************************************************** + * GetWindowStateUpdates (X11DRV.@) + */ +BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect ) { struct x11drv_win_data *data;
+ TRACE( "hwnd %p, state_cmd %p, config_cmd %p, rect %p\n", hwnd, state_cmd, config_cmd, rect ); + if (!(data = get_win_data( hwnd ))) return FALSE;
*state_cmd = window_update_client_state( data ); @@ -1613,6 +1618,8 @@ BOOL get_window_state_updates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, REC *rect = window_rect_from_visible( &data->rects, data->current_state.rect );
release_win_data( data ); + + TRACE( "returning state_cmd %#x, config_cmd %#x, rect %s\n", *state_cmd, *config_cmd, wine_dbgstr_rect(rect) ); return *state_cmd || *config_cmd; }
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 5641ea407f8..4df9d6e937d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -243,6 +243,7 @@ extern void X11DRV_UpdateLayeredWindow( HWND hwnd, UINT flags ); extern LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ); extern BOOL X11DRV_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects ); extern BOOL X11DRV_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask ); +extern BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect ); extern BOOL X11DRV_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface ); extern void X11DRV_MoveWindowBits( HWND hwnd, const struct window_rects *old_rects, const struct window_rects *new_rects, const RECT *valid_rects ); diff --git a/include/ntuser.h b/include/ntuser.h index 3d981927395..3db46268b10 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -605,6 +605,7 @@ enum wine_internal_message WM_WINE_KEYBOARD_LL_HOOK, WM_WINE_MOUSE_LL_HOOK, WM_WINE_IME_NOTIFY, + WM_WINE_WINDOW_STATE_CHANGED, WM_WINE_UPDATEWINDOWSTATE, WM_WINE_FIRST_DRIVER_MSG = 0x80001000, /* range of messages reserved for the USER driver */ WM_WINE_CLIPCURSOR = 0x80001ff0, /* internal driver notification messages */ diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 09b5dd1e73f..9c0e000d7a8 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -385,6 +385,7 @@ struct user_driver_funcs LRESULT (*pWindowMessage)(HWND,UINT,WPARAM,LPARAM); BOOL (*pWindowPosChanging)(HWND,UINT,BOOL,const struct window_rects *); BOOL (*pGetWindowStyleMasks)(HWND,UINT,UINT,UINT*,UINT*); + BOOL (*pGetWindowStateUpdates)(HWND,UINT*,UINT*,RECT*); BOOL (*pCreateWindowSurface)(HWND,BOOL,const RECT *,struct window_surface**); void (*pMoveWindowBits)(HWND,const struct window_rects *,const struct window_rects *,const RECT *); void (*pWindowPosChanged)(HWND,HWND,HWND,UINT,BOOL,const struct window_rects*,struct window_surface*);
v2: Apply the Win32 window state/config updates outside of winex11 event handlers. Workaround a couple of WM bugs that would otherwise fail some tests.