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.
-- v3: winex11: Remove now unnecessary WindowPosChanged re-entry guards. 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 7aaa1284164..6e09dede3ca 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 9e8164f873a..c7aa36caf9a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1499,7 +1499,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 );
@@ -1540,7 +1540,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; @@ -1580,6 +1580,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 85cb4071866..403698ad39a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -660,8 +660,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 6e09dede3ca..894514c3d6f 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 c7aa36caf9a..a01c3e9010c 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1542,6 +1542,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;
@@ -1575,6 +1576,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 a01c3e9010c..a431a82cf8f 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) { @@ -1634,6 +1647,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 ) @@ -1670,6 +1684,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 f66a769258c..055a1d6155c 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2126,6 +2126,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 894514c3d6f..65b31518691 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 a431a82cf8f..6b9cb7c8c72 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1597,10 +1597,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 ); @@ -1608,6 +1613,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 403698ad39a..26afcb56415 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 a07c3d407a2..01fdd4b17e4 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -612,6 +612,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*);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 6b9cb7c8c72..07807e0eb4c 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2909,12 +2909,10 @@ BOOL X11DRV_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, UINT *sty void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, const struct window_rects *new_rects, struct window_surface *surface ) { - struct x11drv_thread_data *thread_data; struct x11drv_win_data *data; UINT new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE ), old_style; struct window_rects old_rects; BOOL was_fullscreen; - int event_type;
if (!(data = get_win_data( hwnd ))) return;
@@ -2923,8 +2921,6 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN if (data->desired_state.wm_state == IconicState) old_style |= WS_MINIMIZE; if (data->desired_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) old_style |= WS_MAXIMIZE;
- thread_data = x11drv_thread_data(); - old_rects = data->rects; was_fullscreen = data->is_fullscreen; data->rects = *new_rects; @@ -2947,23 +2943,10 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN return; }
- /* check if we are currently processing an event relevant to this window */ - event_type = 0; - if (thread_data && - thread_data->current_event && - thread_data->current_event->xany.window == data->whole_window) - { - event_type = thread_data->current_event->type; - if (event_type != ConfigureNotify && event_type != PropertyNotify && - event_type != GravityNotify && event_type != ReparentNotify) - event_type = 0; /* ignore other events */ - } - - if ((old_style & WS_VISIBLE) && event_type != ReparentNotify) + if (old_style & WS_VISIBLE) { if (((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE)) || - (!event_type && !(new_style & WS_MINIMIZE) && - !is_window_rect_mapped( &new_rects->window ) && is_window_rect_mapped( &old_rects.window ))) + (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &new_rects->window ) && is_window_rect_mapped( &old_rects.window ))) { release_win_data( data ); unmap_window( hwnd ); @@ -2973,8 +2956,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN }
/* don't change position if we are about to minimize or maximize a managed window */ - if (!event_type && - !(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE)))) + if (!(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE)))) { sync_window_position( data, swp_flags ); #ifdef HAVE_LIBXSHAPE @@ -3017,7 +2999,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN else { if (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)) set_wm_hints( data ); - if (!event_type) update_net_wm_states( data ); + update_net_wm_states( data ); } }
v3: Rebase and remove now unnecessary winex11 WindowPosChanged re-entry guards.