From: Vincent Povirk Subject: winex11.drv: Track external changes to _NET_WM_STATE in net_wm_state. Message-Id: Date: Wed, 1 Jul 2015 14:03:22 -0500 In some cases, WM's will modify the _NET_WM_STATE of our own windows. Most notably, this can happen when the WM maximizes our window, but mutter has been known to alter the fullscreen state as well. If we want to reconfigure our window later, we'll probably have to remove these states, which means we need to remember that they were set. We already read _NET_WM_STATE to determine when the WM maximizes our window, but we don't track this information in net_wm_state, which means we can never unmaximize the window, only the WM can. To see this problem in action: * Open winecfg and turn off "Allow the window manager to decorate the windows" * Open notepad. * Drag the titlebar to the top of the screen to maximize the window. * Click on the restore button to unmaximize. That last step doesn't currently work. From 2653c94c58220fddffd60a62e0f83e7e881b4d58 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Wed, 1 Jul 2015 13:43:48 -0500 Subject: [PATCH] winex11.drv: Track external changes to _NET_WM_STATE in net_wm_state. --- dlls/winex11.drv/event.c | 35 +++---------------------- dlls/winex11.drv/window.c | 67 ++++++++++++++++++++++++++++++++++++++--------- dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index a1abfe7..ee30259 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -949,35 +949,6 @@ static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event ) /*********************************************************************** - * is_net_wm_state_maximized - */ -static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data ) -{ - Atom type, *state; - int format, ret = 0; - unsigned long i, count, remaining; - - if (!data->whole_window) return FALSE; - - if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0, - 65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count, - &remaining, (unsigned char **)&state )) - { - if (type == XA_ATOM && format == 32) - { - for (i = 0; i < count; i++) - { - if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) || - state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ)) - ret++; - } - } - XFree( state ); - } - return (ret == 2); -} - -/*********************************************************************** * reparent_notify */ static void reparent_notify( Display *display, HWND hwnd, Window xparent, int x, int y ) @@ -1132,7 +1103,8 @@ void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) style = GetWindowLongW( data->hwnd, GWL_STYLE ); if ((style & WS_CAPTION) == WS_CAPTION) { - if (is_net_wm_state_maximized( event->display, data )) + read_net_wm_states( event->display, data ); + if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED))) { if (!(style & WS_MAXIMIZE)) { @@ -1267,7 +1239,8 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat if (data->iconic && data->wm_state == NormalState) /* restore window */ { data->iconic = FALSE; - if ((style & WS_CAPTION) == WS_CAPTION && is_net_wm_state_maximized( event->display, data )) + read_net_wm_states( event->display, data ); + if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED))) { if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED)) { diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 69f6446..50c3290 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -65,6 +65,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(x11drv); #define _NET_WM_STATE_ADD 1 #define _NET_WM_STATE_TOGGLE 2 +static const unsigned int net_wm_state_atoms[NB_NET_WM_STATES] = +{ + XATOM__NET_WM_STATE_FULLSCREEN, + XATOM__NET_WM_STATE_ABOVE, + XATOM__NET_WM_STATE_MAXIMIZED_VERT, + XATOM__NET_WM_STATE_SKIP_PAGER, + XATOM__NET_WM_STATE_SKIP_TASKBAR +}; + #define SWP_AGG_NOPOSCHANGE (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER) /* is cursor clipping active? */ @@ -960,15 +969,6 @@ void update_user_time( Time time ) */ void update_net_wm_states( struct x11drv_win_data *data ) { - static const unsigned int state_atoms[NB_NET_WM_STATES] = - { - XATOM__NET_WM_STATE_FULLSCREEN, - XATOM__NET_WM_STATE_ABOVE, - XATOM__NET_WM_STATE_MAXIMIZED_VERT, - XATOM__NET_WM_STATE_SKIP_PAGER, - XATOM__NET_WM_STATE_SKIP_TASKBAR - }; - DWORD i, style, ex_style, new_state = 0; if (!data->managed) return; @@ -1005,8 +1005,8 @@ void update_net_wm_states( struct x11drv_win_data *data ) 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[state_atoms[i] - FIRST_XATOM]; - if (state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT) + 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); } XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_STATE), XA_ATOM, @@ -1034,8 +1034,8 @@ void update_net_wm_states( struct x11drv_win_data *data ) (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[state_atoms[i] - FIRST_XATOM]; - xev.xclient.data.l[2] = ((state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT) ? + 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); XSendEvent( data->display, root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev ); @@ -1044,6 +1044,47 @@ void update_net_wm_states( struct x11drv_win_data *data ) data->net_wm_state = new_state; } +/*********************************************************************** + * read_net_wm_states + */ +void read_net_wm_states( Display* display, struct x11drv_win_data *data ) +{ + Atom type, *state; + int format; + unsigned long i, j, count, remaining; + DWORD new_state = 0; + BOOL maximized_horz = FALSE; + + if (!data->whole_window) return; + + if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0, + 65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count, + &remaining, (unsigned char **)&state )) + { + if (type == XA_ATOM && format == 32) + { + for (i = 0; i < count; i++) + { + if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ)) + maximized_horz = TRUE; + for (j=0; j < NB_NET_WM_STATES; j++) + { + if (state[i] == X11DRV_Atoms[net_wm_state_atoms[j] - FIRST_XATOM]) + { + new_state |= 1 << j; + } + } + } + } + XFree( state ); + } + + if (!maximized_horz) + new_state &= ~(1 << NET_WM_STATE_MAXIMIZED); + + data->net_wm_state = new_state; +} + /*********************************************************************** * set_xembed_flags diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 213f610..cb4b0bb 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -576,6 +576,7 @@ extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN; extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN; extern Window init_clip_window(void) DECLSPEC_HIDDEN; extern void update_user_time( Time time ) DECLSPEC_HIDDEN; +extern void read_net_wm_states( Display *display, struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern void update_net_wm_states( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern Window create_client_window( struct x11drv_win_data *data, const XVisualInfo *visual ) DECLSPEC_HIDDEN; -- 2.1.4