From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/winex11.drv/event.c | 12 ++++++++ dlls/winex11.drv/window.c | 58 ++++++++++++++++++++++++++++++--------- dlls/winex11.drv/x11drv.h | 3 ++ 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 2983d7bfe8a..2656ebeebaa 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1276,6 +1276,17 @@ static void handle_net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) NtUserPostMessage( hwnd, WM_WINE_WINDOW_STATE_CHANGED, 0, 0 ); } +static void handle_monitor_notify( HWND hwnd, XPropertyEvent *event ) +{ + struct x11drv_win_data *data; + long indices[4] = {0}; + + if (!(data = get_win_data( hwnd ))) return; + if (event->state == PropertyNewValue) get_window_monitors( event->display, event->window, indices ); + window_monitors_notify( data, event->serial, indices ); + release_win_data( data ); +} + static void handle_wm_hints_notify( HWND hwnd, XPropertyEvent *event ) { struct x11drv_win_data *data; @@ -1350,6 +1361,7 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev ) if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event ); 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 ); + if (event->atom == x11drv_atom(_NET_WM_FULLSCREEN_MONITORS)) handle_monitor_notify( hwnd, event ); if (event->atom == x11drv_atom(WM_HINTS)) handle_wm_hints_notify( hwnd, event ); if (event->atom == x11drv_atom(_MOTIF_WM_HINTS)) handle_mwm_hints_notify( hwnd, event ); if (event->atom == x11drv_atom(WM_NORMAL_HINTS)) handle_wm_normal_hints_notify( hwnd, event ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index a83359b2d74..b377b1e4a7e 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1271,7 +1271,7 @@ void window_set_user_time( struct x11drv_win_data *data, Time time, BOOL init ) 32, PropModeReplace, (unsigned char *)&time, 1 ); } -static void window_set_net_wm_fullscreen_monitors( struct x11drv_win_data *data, const struct monitor_indices *new_monitors ) +static void window_set_monitors( struct x11drv_win_data *data, const struct monitor_indices *new_monitors ) { const struct monitor_indices *old_monitors = &data->pending_state.monitors; data->desired_state.monitors = *new_monitors; @@ -1284,8 +1284,9 @@ static void window_set_net_wm_fullscreen_monitors( struct x11drv_win_data *data, if (data->pending_state.wm_state == WithdrawnState) { memcpy( &data->pending_state.monitors, new_monitors, sizeof(*new_monitors) ); - TRACE( "window %p/%lx, requesting _NET_WM_FULLSCREEN_MONITORS %s serial %lu\n", data->hwnd, data->whole_window, - debugstr_monitor_indices( new_monitors ), NextRequest( data->display ) ); + data->monitors_serial = NextRequest( data->display ); + TRACE( "window %p/%lx, requesting _NET_WM_FULLSCREEN_MONITORS %s serial %lu\n", data->hwnd, + data->whole_window, debugstr_monitor_indices( new_monitors ), data->monitors_serial ); XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_FULLSCREEN_MONITORS), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)new_monitors->indices, 4 ); } @@ -1304,19 +1305,17 @@ static void window_set_net_wm_fullscreen_monitors( struct x11drv_win_data *data, memcpy( xev.xclient.data.l, new_monitors->indices, sizeof(new_monitors->indices) ); memcpy( &data->pending_state.monitors, new_monitors, sizeof(*new_monitors) ); - TRACE( "window %p/%lx, requesting _NET_WM_FULLSCREEN_MONITORS %s serial %lu\n", data->hwnd, data->whole_window, - debugstr_monitor_indices( new_monitors ), NextRequest( data->display ) ); + data->monitors_serial = NextRequest( data->display ); + TRACE( "window %p/%lx, requesting _NET_WM_FULLSCREEN_MONITORS %s serial %lu\n", data->hwnd, + data->whole_window, debugstr_monitor_indices( new_monitors ), data->monitors_serial ); XSendEvent( data->display, DefaultRootWindow( data->display ), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev ); } - - /* assume it changes immediately, we don't track the property for now */ - memcpy( &data->current_state.monitors, new_monitors, sizeof(*new_monitors) ); } /* Update _NET_WM_FULLSCREEN_MONITORS when _NET_WM_STATE_FULLSCREEN is set to support fullscreen * windows spanning multiple monitors */ -static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) +static void update_fullscreen_monitors( struct x11drv_win_data *data ) { struct monitor_indices monitors = {0}; @@ -1325,7 +1324,7 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) * indices because of stale xinerama monitor information */ if (!X11DRV_DisplayDevices_SupportEventHandlers()) return; if (!xinerama_get_fullscreen_monitors( &data->rects.visible, &monitors.generation, monitors.indices )) return; - window_set_net_wm_fullscreen_monitors( data, &monitors ); + window_set_monitors( data, &monitors ); } static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_state ) @@ -1512,7 +1511,7 @@ static void update_net_wm_states( struct x11drv_win_data *data ) } window_set_net_wm_state( data, new_state ); - update_net_wm_fullscreen_monitors( data ); + update_fullscreen_monitors( data ); } /*********************************************************************** @@ -1554,6 +1553,20 @@ UINT get_window_net_wm_state( Display *display, Window window ) return new_state; } +void get_window_monitors( Display *display, Window window, long *indices ) +{ + unsigned long count, remaining; + long *value; + int format; + Atom type; + + if (!XGetWindowProperty( display, window, x11drv_atom( _NET_WM_FULLSCREEN_MONITORS ), 0, 65536, False, + XA_CARDINAL, &type, &format, &count, &remaining, (unsigned char **)&value )) + { + if (type == XA_CARDINAL && format == 32) memcpy( indices, value, 4 * sizeof(*indices) ); + XFree( value ); + } +} /*********************************************************************** * set_xembed_flags @@ -1602,7 +1615,7 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state, B set_wm_hints( data ); update_net_wm_states( data ); sync_window_style( data ); - update_net_wm_fullscreen_monitors( data ); + update_fullscreen_monitors( data ); break; case MAKELONG(IconicState, NormalState): case MAKELONG(NormalState, IconicState): @@ -1849,7 +1862,7 @@ static void window_request_desired_state( struct x11drv_win_data *data ) { window_set_wm_state( data, data->desired_state.wm_state, data->desired_state.activate ); window_set_net_wm_state( data, data->desired_state.net_wm_state ); - window_set_net_wm_fullscreen_monitors( data, &data->desired_state.monitors ); + window_set_monitors( data, &data->desired_state.monitors ); window_set_mwm_hints( data, &data->desired_state.mwm_hints ); window_set_config( data, data->desired_state.rect, FALSE ); } @@ -1897,6 +1910,25 @@ void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long ser window_request_desired_state( data ); } +void window_monitors_notify( struct x11drv_win_data *data, unsigned long serial, const long *indices ) +{ + struct monitor_indices *desired = &data->desired_state.monitors, *pending = &data->pending_state.monitors, *current = &data->current_state.monitors; + const struct monitor_indices value = {pending->generation, {indices[0], indices[1], indices[2], indices[3]}}; + unsigned long *expect_serial = &data->monitors_serial; + const char *expected, *received, *prefix; + + prefix = wine_dbg_sprintf( "window %p/%lx ", data->hwnd, data->whole_window ); + received = wine_dbg_sprintf( "_NET_WM_FULLSCREEN_MONITORS %s/%lu", debugstr_monitor_indices( &value ), serial ); + expected = *expect_serial ? wine_dbg_sprintf( ", expected %s/%lu", debugstr_monitor_indices( pending ), *expect_serial ) : ""; + + if (!handle_state_change( serial, expect_serial, sizeof(value), &value, desired, pending, + current, expected, prefix, received, NULL )) + return; + + /* send any pending changes from the desired state */ + window_request_desired_state( data ); +} + void window_wm_hints_notify( struct x11drv_win_data *data, unsigned long serial, const XWMHints *value ) { XWMHints *desired = &data->desired_state.wm_hints, *pending = &data->pending_state.wm_hints, *current = &data->current_state.wm_hints; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 8b0c0a62f91..24d2d276eb1 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -690,6 +690,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 monitors_serial; /* serial of last pending _NET_WM_FULLSCREEN_MONITORS request */ unsigned long wm_hints_serial; /* serial of last pending WM_HINTS request */ unsigned long mwm_hints_serial; /* serial of last pending _MOTIF_WM_HINTS request */ unsigned long wm_normal_hints_serial;/* serial of last pending WM_NORMAL_HINTS request */ @@ -708,6 +709,7 @@ extern BOOL window_should_take_focus( HWND hwnd, Time time ); 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, Time time ); extern void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ); +extern void window_monitors_notify( struct x11drv_win_data *data, unsigned long serial, const long *value ); extern void window_wm_hints_notify( struct x11drv_win_data *data, unsigned long serial, const XWMHints *hints ); extern void window_mwm_hints_notify( struct x11drv_win_data *data, unsigned long serial, const MwmHints *hints ); extern void window_wm_normal_hints_notify( struct x11drv_win_data *data, unsigned long serial, const XSizeHints *hints ); @@ -723,6 +725,7 @@ extern BOOL is_net_supported( Atom atom ); extern Window init_clip_window(void); extern void window_set_user_time( struct x11drv_win_data *data, Time time, BOOL init ); extern UINT get_window_net_wm_state( Display *display, Window window ); +extern void get_window_monitors( Display *display, Window window, long *indices ); extern void make_window_embedded( struct x11drv_win_data *data ); extern Window create_client_window( HWND hwnd, RECT client_rect, const XVisualInfo *visual, Colormap colormap ); extern void detach_client_window( struct x11drv_win_data *data, Window client_window ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10620