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 );