This should be functionally no-op as the new state tracker has no side effect other than printing traces. It introduces a new pending/current states on the win data to track the requested changes, as well as the associated request serial for each of the property being changed.
Later, this tracker will help making the requests more asynchronous (removing the need for wait_for_withdrawn_state), avoid duplicate requests, and better decide whether the received updates are expected or should be applied back to the win32 window state:
- any update that is older than our last request, expected and matching our request, or unexpected but no-op can be ignored, - any update that wasn't requested or doesn't match the request (because the WM decided so) will need to be applied on the win32 state.
Tracking the current X11 window state separately will also allow us to later delay these updates on the win32 state, possibly by posting an internal message for win32u to call us back to get the necessary changes, when every other message has been processed and avoid calling SetWindowPos / syscommand directly from within the driver event handlers.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 8 ++++-- dlls/winex11.drv/window.c | 60 +++++++++++++++++++++++++++++++++++++-- dlls/winex11.drv/x11drv.h | 10 +++++++ 3 files changed, 72 insertions(+), 6 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 30c86503266..589da2d723e 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1192,10 +1192,12 @@ static int get_window_wm_state( Display *display, Window window ) */ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window ) { - struct x11drv_win_data *data = get_win_data( hwnd ); - UINT style; + struct x11drv_win_data *data; + UINT style, value = 0;
- if (!data) return; + 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 );
switch(event->state) { diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 179bffb2f7d..0d7f8536372 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1375,7 +1375,12 @@ static void map_window( HWND hwnd, DWORD new_style ) sync_window_style( data );
if (data->embedded) set_xembed_flags( data, XEMBED_MAPPED ); - else XMapWindow( data->display, data->whole_window ); + else + { + data->pending_state.wm_state = data->iconic ? IconicState : NormalState; + data->wm_state_serial = NextRequest( data->display ); + XMapWindow( data->display, data->whole_window ); + } XFlush( data->display );
data->mapped = TRUE; @@ -1402,8 +1407,13 @@ static void unmap_window( HWND hwnd ) TRACE( "win %p/%lx\n", data->hwnd, data->whole_window );
if (data->embedded) set_xembed_flags( data, 0 ); - else if (!data->managed) XUnmapWindow( data->display, data->whole_window ); - else XWithdrawWindow( data->display, data->whole_window, data->vis.screen ); + else + { + data->pending_state.wm_state = WithdrawnState; + data->wm_state_serial = NextRequest( data->display ); + if (!data->managed) XUnmapWindow( data->display, data->whole_window ); + else XWithdrawWindow( data->display, data->whole_window, data->vis.screen ); + }
data->mapped = FALSE; data->net_wm_state = 0; @@ -1411,6 +1421,39 @@ static void unmap_window( HWND hwnd ) release_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; + unsigned long *expect_serial = &data->wm_state_serial; + const char *reason = NULL, *expected, *received; + + received = wine_dbg_sprintf( "WM_STATE %#x/%lu", value, serial ); + expected = *expect_serial ? wine_dbg_sprintf( ", expected %#x/%lu", *pending, *expect_serial ) : ""; + + if (serial < *expect_serial) reason = "old "; + else if (!*expect_serial && *current == value) reason = "no-op "; + /* ignore Metacity/Mutter transient NormalState during WithdrawnState <-> IconicState transitions */ + else if (value == NormalState && *current + *pending == IconicState) reason = "transient "; + + if (reason) + { + WARN( "Ignoring window %p/%lx %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected ); + return; + } + + if (!*expect_serial) reason = "unexpected "; + else if (*pending != value) reason = "mismatch "; + + if (!reason) TRACE( "window %p/%lx, %s%s\n", data->hwnd, data->whole_window, received, expected ); + 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 */ + } + + *current = value; + *expect_serial = 0; +}
/*********************************************************************** * make_window_embedded @@ -1420,6 +1463,8 @@ void make_window_embedded( struct x11drv_win_data *data ) /* the window cannot be mapped before being embedded */ if (data->mapped) { + data->pending_state.wm_state = WithdrawnState; + data->wm_state_serial = NextRequest( data->display ); if (!data->managed) XUnmapWindow( data->display, data->whole_window ); else XWithdrawWindow( data->display, data->whole_window, data->vis.screen ); data->net_wm_state = 0; @@ -1868,6 +1913,11 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des data->wm_state = WithdrawnState; data->net_wm_state = 0; data->mapped = FALSE; + + memset( &data->pending_state, 0, sizeof(data->pending_state) ); + memset( &data->current_state, 0, sizeof(data->current_state) ); + data->wm_state_serial = 0; + if (data->xic) { XUnsetICFocus( data->xic ); @@ -2722,10 +2772,14 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, BOOL set_wm_hints( data ); data->iconic = (new_style & WS_MINIMIZE) != 0; TRACE( "changing win %p iconic state to %u\n", data->hwnd, data->iconic ); + + data->pending_state.wm_state = data->iconic ? IconicState : NormalState; + data->wm_state_serial = NextRequest( data->display ); if (data->iconic) XIconifyWindow( data->display, data->whole_window, data->vis.screen ); else if (is_window_rect_mapped( &new_rects->window )) XMapWindow( data->display, data->whole_window ); + update_net_wm_states( data ); } else diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 07bb7849313..53fb5cc30e1 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -602,6 +602,11 @@ enum x11drv_net_wm_state NB_NET_WM_STATES };
+struct window_state +{ + UINT wm_state; +}; + /* x11drv private window data */ struct x11drv_win_data { @@ -634,6 +639,10 @@ struct x11drv_win_data Pixmap icon_mask; unsigned long *icon_bits; unsigned int icon_size; + + 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 */ };
extern struct x11drv_win_data *get_win_data( HWND hwnd ); @@ -647,6 +656,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 void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ); 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 | 36 ++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/window.c | 22 +++++++++------------- 2 files changed, 45 insertions(+), 13 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 589da2d723e..dc7030ea04a 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1184,6 +1184,31 @@ static int get_window_wm_state( Display *display, Window window ) return ret; }
+/*********************************************************************** + * get_window_xembed_info + */ +static int get_window_xembed_info( Display *display, Window window ) +{ + struct + { + unsigned long version; + unsigned long flags; + } *state; + Atom type; + int format, ret = -1; + unsigned long count, remaining; + + if (!XGetWindowProperty( display, window, x11drv_atom(_XEMBED_INFO), 0, 65535, False, x11drv_atom(_XEMBED_INFO), + &type, &format, &count, &remaining, (unsigned char **)&state )) + { + if (type == x11drv_atom(_XEMBED_INFO) && get_property_size( format, count ) >= sizeof(*state)) + ret = state->flags; + XFree( state ); + } + + return ret; +} +
/*********************************************************************** * handle_wm_state_notify @@ -1271,6 +1296,16 @@ done: release_win_data( data ); }
+static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event ) +{ + struct x11drv_win_data *data; + UINT value = 0; + + if (!(data = get_win_data( hwnd ))) return; + if (event->state == PropertyNewValue) value = get_window_xembed_info( event->display, event->window ); + window_wm_state_notify( data, event->serial, value ? NormalState : WithdrawnState ); + release_win_data( data ); +}
/*********************************************************************** * X11DRV_PropertyNotify @@ -1281,6 +1316,7 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
if (!hwnd) return FALSE; if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE ); + if (event->atom == x11drv_atom(_XEMBED_INFO)) handle_xembed_info_notify( hwnd, event ); return TRUE; }
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 0d7f8536372..eb93a2a2e51 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1374,13 +1374,10 @@ static void map_window( HWND hwnd, DWORD new_style ) update_net_wm_states( data ); sync_window_style( data );
+ data->pending_state.wm_state = data->iconic ? IconicState : NormalState; + data->wm_state_serial = NextRequest( data->display ); if (data->embedded) set_xembed_flags( data, XEMBED_MAPPED ); - else - { - data->pending_state.wm_state = data->iconic ? IconicState : NormalState; - data->wm_state_serial = NextRequest( data->display ); - XMapWindow( data->display, data->whole_window ); - } + else XMapWindow( data->display, data->whole_window ); XFlush( data->display );
data->mapped = TRUE; @@ -1406,14 +1403,11 @@ static void unmap_window( HWND hwnd ) { TRACE( "win %p/%lx\n", data->hwnd, data->whole_window );
+ data->pending_state.wm_state = WithdrawnState; + data->wm_state_serial = NextRequest( data->display ); if (data->embedded) set_xembed_flags( data, 0 ); - else - { - data->pending_state.wm_state = WithdrawnState; - data->wm_state_serial = NextRequest( data->display ); - if (!data->managed) XUnmapWindow( data->display, data->whole_window ); - else XWithdrawWindow( data->display, data->whole_window, data->vis.screen ); - } + else if (!data->managed) XUnmapWindow( data->display, data->whole_window ); + else XWithdrawWindow( data->display, data->whole_window, data->vis.screen );
data->mapped = FALSE; data->net_wm_state = 0; @@ -1472,6 +1466,8 @@ void make_window_embedded( struct x11drv_win_data *data ) data->embedded = TRUE; data->managed = TRUE; sync_window_style( data ); + data->pending_state.wm_state = NormalState; + data->wm_state_serial = NextRequest( data->display ); set_xembed_flags( data, (data->mapped || data->embedder) ? XEMBED_MAPPED : 0 ); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 71 +++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 33 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index eb93a2a2e51..b23b0682999 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1344,14 +1344,44 @@ static void set_xembed_flags( struct x11drv_win_data *data, unsigned long flags { unsigned long info[2];
- if (!data->whole_window) return; - info[0] = 0; /* protocol version */ info[1] = flags; XChangeProperty( data->display, data->whole_window, x11drv_atom(_XEMBED_INFO), x11drv_atom(_XEMBED_INFO), 32, PropModeReplace, (unsigned char*)info, 2 ); }
+static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state ) +{ + UINT old_state = data->pending_state.wm_state; + + if (!data->whole_window) return; /* no window, nothing to update */ + if (old_state == new_state) return; /* states are the same, nothing to update */ + + 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 ); + + switch (MAKELONG(old_state, new_state)) + { + case MAKELONG(WithdrawnState, IconicState): + case MAKELONG(WithdrawnState, NormalState): + case MAKELONG(IconicState, NormalState): + if (data->embedded) set_xembed_flags( data, XEMBED_MAPPED ); + else XMapWindow( data->display, data->whole_window ); + break; + case MAKELONG(NormalState, WithdrawnState): + case MAKELONG(IconicState, WithdrawnState): + if (data->embedded) set_xembed_flags( data, 0 ); + else if (!data->managed) XUnmapWindow( data->display, data->whole_window ); + else XWithdrawWindow( data->display, data->whole_window, data->vis.screen ); + break; + case MAKELONG(NormalState, IconicState): + if (!data->embedded) XIconifyWindow( data->display, data->whole_window, data->vis.screen ); + break; + } +} +
/*********************************************************************** * map_window @@ -1374,10 +1404,7 @@ static void map_window( HWND hwnd, DWORD new_style ) update_net_wm_states( data ); sync_window_style( data );
- data->pending_state.wm_state = data->iconic ? IconicState : NormalState; - data->wm_state_serial = NextRequest( data->display ); - if (data->embedded) set_xembed_flags( data, XEMBED_MAPPED ); - else XMapWindow( data->display, data->whole_window ); + window_set_wm_state( data, (new_style & WS_MINIMIZE) ? IconicState : NormalState ); XFlush( data->display );
data->mapped = TRUE; @@ -1402,13 +1429,7 @@ static void unmap_window( HWND hwnd ) if (data->mapped) { TRACE( "win %p/%lx\n", data->hwnd, data->whole_window ); - - data->pending_state.wm_state = WithdrawnState; - data->wm_state_serial = NextRequest( data->display ); - if (data->embedded) set_xembed_flags( data, 0 ); - else if (!data->managed) XUnmapWindow( data->display, data->whole_window ); - else XWithdrawWindow( data->display, data->whole_window, data->vis.screen ); - + window_set_wm_state( data, WithdrawnState ); data->mapped = FALSE; data->net_wm_state = 0; } @@ -1455,20 +1476,12 @@ void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, void make_window_embedded( struct x11drv_win_data *data ) { /* the window cannot be mapped before being embedded */ - if (data->mapped) - { - data->pending_state.wm_state = WithdrawnState; - data->wm_state_serial = NextRequest( data->display ); - if (!data->managed) XUnmapWindow( data->display, data->whole_window ); - else XWithdrawWindow( data->display, data->whole_window, data->vis.screen ); - data->net_wm_state = 0; - } + window_set_wm_state( data, WithdrawnState ); + data->net_wm_state = 0; data->embedded = TRUE; data->managed = TRUE; sync_window_style( data ); - data->pending_state.wm_state = NormalState; - data->wm_state_serial = NextRequest( data->display ); - set_xembed_flags( data, (data->mapped || data->embedder) ? XEMBED_MAPPED : 0 ); + window_set_wm_state( data, NormalState ); }
@@ -2767,15 +2780,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, BOOL { set_wm_hints( data ); data->iconic = (new_style & WS_MINIMIZE) != 0; - TRACE( "changing win %p iconic state to %u\n", data->hwnd, data->iconic ); - - data->pending_state.wm_state = data->iconic ? IconicState : NormalState; - data->wm_state_serial = NextRequest( data->display ); - if (data->iconic) - XIconifyWindow( data->display, data->whole_window, data->vis.screen ); - else if (is_window_rect_mapped( &new_rects->window )) - XMapWindow( data->display, data->whole_window ); - + window_set_wm_state( data, (new_style & WS_MINIMIZE) ? IconicState : NormalState ); update_net_wm_states( data ); } else
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 84 +++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 38 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index b23b0682999..7e5495df391 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1209,49 +1209,15 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) data->net_wm_fullscreen_monitors_set = TRUE; }
-/*********************************************************************** - * update_net_wm_states - */ -static void update_net_wm_states( struct x11drv_win_data *data ) +static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_state ) { - UINT i, style, ex_style, new_state = 0; - - if (!data->managed || data->embedded) return; - if (data->whole_window == root_window) - { - update_desktop_fullscreen(data->display); - return; - } - - 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)); - if (data->is_fullscreen) - { - if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) - new_state |= (1 << NET_WM_STATE_MAXIMIZED); - else if (!(style & WS_MINIMIZE)) - new_state |= (1 << NET_WM_STATE_FULLSCREEN); - } - else if (style & WS_MAXIMIZE) - new_state |= (1 << NET_WM_STATE_MAXIMIZED); + UINT i, count;
- ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); - if (ex_style & WS_EX_TOPMOST) - new_state |= (1 << NET_WM_STATE_ABOVE); - if (!data->add_taskbar) - { - if (data->skip_taskbar || (ex_style & WS_EX_NOACTIVATE) - || (ex_style & WS_EX_TOOLWINDOW && !(ex_style & WS_EX_APPWINDOW))) - new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR) | (1 << NET_WM_STATE_SKIP_PAGER) | (1 << KDE_NET_WM_STATE_SKIP_SWITCHER); - else if (!(ex_style & WS_EX_APPWINDOW) && NtUserGetWindowRelative( data->hwnd, GW_OWNER )) - new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR); - } + if (!data->whole_window) return; /* no window, nothing to update */
if (!data->mapped) /* set the _NET_WM_STATE atom directly */ { - Atom atoms[NB_NET_WM_STATES+1]; - DWORD count; + Atom atoms[NB_NET_WM_STATES + 1];
for (i = count = 0; i < NB_NET_WM_STATES; i++) { @@ -1293,6 +1259,48 @@ static void update_net_wm_states( struct x11drv_win_data *data ) SubstructureRedirectMask | SubstructureNotifyMask, &xev ); } } +} + +/*********************************************************************** + * update_net_wm_states + */ +static void update_net_wm_states( struct x11drv_win_data *data ) +{ + UINT style, ex_style, new_state = 0; + + if (!data->managed || data->embedded) return; + if (data->whole_window == root_window) + { + update_desktop_fullscreen(data->display); + return; + } + + 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)); + if (data->is_fullscreen) + { + if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) + new_state |= (1 << NET_WM_STATE_MAXIMIZED); + else if (!(style & WS_MINIMIZE)) + new_state |= (1 << NET_WM_STATE_FULLSCREEN); + } + else if (style & WS_MAXIMIZE) + new_state |= (1 << NET_WM_STATE_MAXIMIZED); + + ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); + if (ex_style & WS_EX_TOPMOST) + new_state |= (1 << NET_WM_STATE_ABOVE); + if (!data->add_taskbar) + { + if (data->skip_taskbar || (ex_style & WS_EX_NOACTIVATE) + || (ex_style & WS_EX_TOOLWINDOW && !(ex_style & WS_EX_APPWINDOW))) + new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR) | (1 << NET_WM_STATE_SKIP_PAGER) | (1 << KDE_NET_WM_STATE_SKIP_SWITCHER); + else if (!(ex_style & WS_EX_APPWINDOW) && NtUserGetWindowRelative( data->hwnd, GW_OWNER )) + new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR); + } + + window_set_net_wm_state( data, new_state ); data->net_wm_state = new_state; update_net_wm_fullscreen_monitors( data ); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 12 ++++++++++ dlls/winex11.drv/window.c | 49 ++++++++++++++++++++++++++++++++++----- dlls/winex11.drv/x11drv.h | 3 +++ 3 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index dc7030ea04a..de9d9e21abf 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1307,6 +1307,17 @@ static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event ) release_win_data( data ); }
+static void handle_net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) +{ + struct x11drv_win_data *data; + 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 ); +} + /*********************************************************************** * X11DRV_PropertyNotify */ @@ -1317,6 +1328,7 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev ) if (!hwnd) return FALSE; if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE ); 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; }
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 7e5495df391..c6c44bcb59a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1222,12 +1222,15 @@ static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_stat for (i = count = 0; i < NB_NET_WM_STATES; i++) { if (!(new_state & (1 << i))) continue; - TRACE( "setting wm state %u for unmapped window %p/%lx\n", - i, data->hwnd, data->whole_window ); atoms[count++] = X11DRV_Atoms[net_wm_state_atoms[i] - FIRST_XATOM]; if (net_wm_state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT) atoms[count++] = x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ); } + + data->pending_state.net_wm_state = new_state; + data->net_wm_state_serial = NextRequest( data->display ); + TRACE( "window %p/%lx, requesting _NET_WM_STATE %#x serial %lu\n", data->hwnd, data->whole_window, + data->pending_state.net_wm_state, data->net_wm_state_serial ); XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_STATE), XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, count ); } @@ -1247,14 +1250,15 @@ static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_stat
for (i = 0; i < NB_NET_WM_STATES; i++) { - TRACE( "setting wm state %u for window %p/%lx to %u prev %u\n", - i, data->hwnd, data->whole_window, - (new_state & (1 << i)) != 0, (data->net_wm_state & (1 << i)) != 0 ); - xev.xclient.data.l[0] = (new_state & (1 << i)) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; xev.xclient.data.l[1] = X11DRV_Atoms[net_wm_state_atoms[i] - FIRST_XATOM]; xev.xclient.data.l[2] = ((net_wm_state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT) ? x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ) : 0); + + data->pending_state.net_wm_state = new_state; + data->net_wm_state_serial = NextRequest( data->display ); + TRACE( "window %p/%lx, requesting _NET_WM_STATE %#x serial %lu\n", data->hwnd, data->whole_window, + data->pending_state.net_wm_state, data->net_wm_state_serial ); XSendEvent( data->display, root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev ); } @@ -1478,6 +1482,38 @@ void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, *expect_serial = 0; }
+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; + unsigned long *expect_serial = &data->net_wm_state_serial; + const char *reason = NULL, *expected, *received; + + received = wine_dbg_sprintf( "_NET_WM_STATE %#x/%lu", value, serial ); + expected = *expect_serial ? wine_dbg_sprintf( ", expected %#x/%lu", *pending, *expect_serial ) : ""; + + if (serial < *expect_serial) reason = "old "; + else if (!*expect_serial && *current == value) reason = "no-op "; + + if (reason) + { + WARN( "Ignoring window %p/%lx %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected ); + return; + } + + if (!*expect_serial) reason = "unexpected "; + else if (*pending != value) reason = "mismatch "; + + if (!reason) TRACE( "window %p/%lx, %s%s\n", data->hwnd, data->whole_window, received, expected ); + 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 */ + } + + *current = value; + *expect_serial = 0; +} + /*********************************************************************** * make_window_embedded */ @@ -1934,6 +1970,7 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des memset( &data->pending_state, 0, sizeof(data->pending_state) ); memset( &data->current_state, 0, sizeof(data->current_state) ); data->wm_state_serial = 0; + data->net_wm_state_serial = 0;
if (data->xic) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 53fb5cc30e1..05c8115d2e3 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -605,6 +605,7 @@ enum x11drv_net_wm_state struct window_state { UINT wm_state; + UINT net_wm_state; };
/* x11drv private window data */ @@ -643,6 +644,7 @@ struct x11drv_win_data 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 */ + unsigned long net_wm_state_serial; /* serial of last pending _NET_WM_STATE request */ };
extern struct x11drv_win_data *get_win_data( HWND hwnd ); @@ -657,6 +659,7 @@ extern void destroy_gl_drawable( HWND hwnd ); 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 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/window.c | 96 ++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 52 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index c6c44bcb59a..11304531f69 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1265,6 +1265,46 @@ 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 ) +{ + UINT style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ), mask = 0; + XWindowChanges changes; + + if (!data->whole_window) return; /* no window, nothing to update */ + + /* resizing a managed maximized window is not allowed */ + if (!(style & WS_MAXIMIZE) || !data->managed) + { + changes.width = new_rect->right - new_rect->left; + changes.height = new_rect->bottom - new_rect->top; + /* if window rect is empty force size to 1x1 */ + if (changes.width <= 0 || changes.height <= 0) changes.width = changes.height = 1; + if (changes.width > 65535) changes.width = 65535; + if (changes.height > 65535) changes.height = 65535; + mask |= CWWidth | CWHeight; + } + + /* only the size is allowed to change for the desktop window or systray docked windows */ + if (data->whole_window != root_window && !data->embedded) + { + POINT pt = virtual_screen_to_root( new_rect->left, new_rect->top ); + changes.x = pt.x; + changes.y = pt.y; + mask |= CWX | CWY; + } + + if (above) + { + changes.stack_mode = Above; + mask |= CWStackMode; + } + + data->configure_serial = NextRequest( data->display ); + TRACE( "window %p/%lx, requesting config %s above %u, serial %lu\n", data->hwnd, data->whole_window, + wine_dbgstr_rect(new_rect), above, data->configure_serial ); + XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); +} + /*********************************************************************** * update_net_wm_states */ @@ -1538,43 +1578,17 @@ static void sync_window_position( struct x11drv_win_data *data, UINT swp_flags ) { DWORD style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); DWORD ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); - XWindowChanges changes; - unsigned int mask = 0; + BOOL above = FALSE;
if (data->managed && data->iconic) return;
- /* resizing a managed maximized window is not allowed */ - if (!(style & WS_MAXIMIZE) || !data->managed) - { - changes.width = data->rects.visible.right - data->rects.visible.left; - changes.height = data->rects.visible.bottom - data->rects.visible.top; - /* if window rect is empty force size to 1x1 */ - if (changes.width <= 0 || changes.height <= 0) changes.width = changes.height = 1; - if (changes.width > 65535) changes.width = 65535; - if (changes.height > 65535) changes.height = 65535; - mask |= CWWidth | CWHeight; - } - - /* only the size is allowed to change for the desktop window or systray docked windows */ - if (data->whole_window != root_window && !data->embedded) - { - POINT pt = virtual_screen_to_root( data->rects.visible.left, data->rects.visible.top ); - changes.x = pt.x; - changes.y = pt.y; - mask |= CWX | CWY; - } - if (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)) { /* find window that this one must be after */ HWND prev = NtUserGetWindowRelative( data->hwnd, GW_HWNDPREV ); while (prev && !(NtUserGetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE)) prev = NtUserGetWindowRelative( prev, GW_HWNDPREV ); - if (!prev) /* top child */ - { - changes.stack_mode = Above; - mask |= CWStackMode; - } + if (!prev) above = TRUE; /* top child */ /* should use stack_mode Below but most window managers don't get it right */ /* and Above with a sibling doesn't work so well either, so we ignore it */ } @@ -1582,14 +1596,7 @@ static void sync_window_position( struct x11drv_win_data *data, UINT swp_flags ) set_size_hints( data, style ); set_mwm_hints( data, style, ex_style ); update_net_wm_states( data ); - data->configure_serial = NextRequest( data->display ); - XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); - - TRACE( "win %p/%lx pos %d,%d,%dx%d after %lx changes=%x serial=%lu\n", - data->hwnd, data->whole_window, (int)data->rects.visible.left, (int)data->rects.visible.top, - (int)(data->rects.visible.right - data->rects.visible.left), - (int)(data->rects.visible.bottom - data->rects.visible.top), - changes.sibling, mask, data->configure_serial ); + window_set_config( data, &data->rects.visible, above ); }
@@ -3072,22 +3079,7 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) { /* update the full screen state */ update_net_wm_states( data ); - - if (data->whole_window) - { - /* sync window position with the new virtual screen rect */ - POINT old_pos = {.x = data->rects.visible.left - wp, .y = data->rects.visible.top - lp}; - POINT pos = virtual_screen_to_root( data->rects.visible.left, data->rects.visible.top ); - XWindowChanges changes = {.x = pos.x, .y = pos.y}; - UINT mask = 0; - - if (old_pos.x != pos.x) mask |= CWX; - if (old_pos.y != pos.y) mask |= CWY; - - data->configure_serial = NextRequest( data->display ); - XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); - } - + window_set_config( data, &data->rects.visible, FALSE ); release_win_data( data ); } return 0;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 1 + dlls/winex11.drv/window.c | 36 ++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 4 +++- 3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index de9d9e21abf..21bc5fc2813 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1081,6 +1081,7 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
pos = root_to_virtual_screen( pos.x, pos.y ); 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; diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 11304531f69..fbb40a61ee4 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1299,6 +1299,7 @@ static void window_set_config( struct x11drv_win_data *data, const RECT *new_rec mask |= CWStackMode; }
+ data->pending_state.rect = *new_rect; data->configure_serial = NextRequest( data->display ); TRACE( "window %p/%lx, requesting config %s above %u, serial %lu\n", data->hwnd, data->whole_window, wine_dbgstr_rect(new_rect), above, data->configure_serial ); @@ -1554,6 +1555,38 @@ void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long ser *expect_serial = 0; }
+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; + unsigned long *expect_serial = &data->configure_serial; + const char *reason = NULL, *expected, *received; + + received = wine_dbg_sprintf( "config %s/%lu", wine_dbgstr_rect(value), serial ); + expected = *expect_serial ? wine_dbg_sprintf( ", expected %s/%lu", wine_dbgstr_rect(pending), *expect_serial ) : ""; + + if (serial < *expect_serial) reason = "old "; + else if (!*expect_serial && EqualRect( current, value )) reason = "no-op "; + + if (reason) + { + WARN( "Ignoring window %p/%lx %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected ); + return; + } + + if (!*expect_serial) reason = "unexpected "; + else if (EqualRect( pending, value )) reason = "mismatch "; + + if (!reason) TRACE( "window %p/%lx, %s%s\n", data->hwnd, data->whole_window, received, expected ); + 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 */ + } + + *current = *value; + *expect_serial = 0; +} + /*********************************************************************** * make_window_embedded */ @@ -1916,6 +1949,8 @@ static void create_whole_window( struct x11drv_win_data *data ) cx, cy, 0, data->vis.depth, InputOutput, data->vis.visual, mask, &attr ); 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;
x11drv_xinput2_enable( data->display, data->whole_window ); set_initial_wm_hints( data->display, data->whole_window ); @@ -1978,6 +2013,7 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des memset( &data->current_state, 0, sizeof(data->current_state) ); data->wm_state_serial = 0; data->net_wm_state_serial = 0; + data->configure_serial = 0;
if (data->xic) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 05c8115d2e3..86749b1211f 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -606,6 +606,7 @@ struct window_state { UINT wm_state; UINT net_wm_state; + RECT rect; };
/* x11drv private window data */ @@ -635,7 +636,6 @@ struct x11drv_win_data 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 */ - unsigned long configure_serial; /* serial number of last configure request */ Pixmap icon_pixmap; Pixmap icon_mask; unsigned long *icon_bits; @@ -645,6 +645,7 @@ struct x11drv_win_data struct window_state current_state; /* window state tracking the current X11 state */ unsigned long wm_state_serial; /* serial of last pending WM_STATE request */ unsigned long net_wm_state_serial; /* serial of last pending _NET_WM_STATE request */ + unsigned long configure_serial; /* serial of last pending configure request */ };
extern struct x11drv_win_data *get_win_data( HWND hwnd ); @@ -660,6 +661,7 @@ 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 void wait_for_withdrawn_state( HWND hwnd, BOOL set ); extern Window init_clip_window(void); extern void update_user_time( Time time );