This should at least fix foreground window inconsistencies between Wine and X11, when _NET_ACTIVE_WINDOW is supported by the WM, allowing us to then better implement focus tracking (to avoid changing focus when not desired), as well as SWP_NOACTIVATE.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 100 +++++++++++++++----------------------- 1 file changed, 39 insertions(+), 61 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 7ae1d8ef66a..428c7108c98 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1649,38 +1649,51 @@ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, return *state_cmd || *config_cmd; }
-void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ) +static BOOL handle_state_change( unsigned long serial, unsigned long *expect_serial, UINT size, const void *value, + void *desired, void *pending, void *current, const char *expected, + const char *prefix, const char *received, const char *reason ) { - UINT *desired = &data->desired_state.wm_state, *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 "; + else if (!*expect_serial && !memcmp( current, value, size )) reason = "no-op ";
if (reason) { - WARN( "Ignoring window %p/%lx %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected ); - return; + WARN( "Ignoring %s%s%s%s\n", prefix, reason, received, expected ); + return FALSE; }
if (!*expect_serial) reason = "unexpected "; - else if (*pending != value) reason = "mismatch "; + else if (memcmp( pending, value, size )) reason = "mismatch ";
- if (!reason) TRACE( "window %p/%lx, %s%s\n", data->hwnd, data->whole_window, received, expected ); + if (!reason) TRACE( "%s%s%s\n", prefix, received, expected ); else { - WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected ); - *desired = *pending = value; /* avoid requesting the same state again */ + WARN( "%s%s%s%s\n", prefix, reason, received, expected ); + /* avoid requesting the same state again */ + memcpy( desired, value, size ); + memcpy( pending, value, size ); }
- *current = value; + memcpy( current, value, size ); *expect_serial = 0; + return TRUE; +} + +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; + unsigned long *expect_serial = &data->wm_state_serial; + const char *reason = NULL, *expected, *received, *prefix; + + prefix = wine_dbg_sprintf( "window %p/%lx ", data->hwnd, data->whole_window ); + received = wine_dbg_sprintf( "WM_STATE %#x/%lu", value, serial ); + expected = *expect_serial ? wine_dbg_sprintf( ", expected %#x/%lu", *pending, *expect_serial ) : ""; + /* ignore Metacity/Mutter transient NormalState during WithdrawnState <-> IconicState transitions */ + if (value == NormalState && *current + *pending == IconicState) reason = "transient "; + + if (!handle_state_change( serial, expect_serial, sizeof(value), &value, desired, pending, + current, expected, prefix, received, reason )) + return;
/* send any pending changes from the desired state */ window_set_wm_state( data, data->desired_state.wm_state ); @@ -1692,32 +1705,15 @@ void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long ser { UINT *desired = &data->desired_state.net_wm_state, *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; + const char *expected, *received, *prefix;
+ prefix = wine_dbg_sprintf( "window %p/%lx ", data->hwnd, data->whole_window ); 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 ); + if (!handle_state_change( serial, expect_serial, sizeof(value), &value, desired, pending, + current, expected, prefix, received, NULL )) 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 ); - *desired = *pending = value; /* avoid requesting the same state again */ - } - - *current = value; - *expect_serial = 0;
/* send any pending changes from the desired state */ window_set_wm_state( data, data->desired_state.wm_state ); @@ -1729,32 +1725,14 @@ void window_configure_notify( struct x11drv_win_data *data, unsigned long serial { RECT *desired = &data->desired_state.rect, *pending = &data->pending_state.rect, *current = &data->current_state.rect; unsigned long *expect_serial = &data->configure_serial; - const char *reason = NULL, *expected, *received; + const char *expected, *received, *prefix;
+ prefix = wine_dbg_sprintf( "window %p/%lx ", data->hwnd, data->whole_window ); 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 ); - *desired = *pending = *value; /* avoid requesting the same state again */ - } - - *current = *value; - *expect_serial = 0; + handle_state_change( serial, expect_serial, sizeof(*value), value, desired, pending, + current, expected, prefix, received, NULL ); }
BOOL window_has_pending_wm_state( HWND hwnd, UINT state )
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 28 ++++++++++++++++++++++++++++ dlls/winex11.drv/window.c | 16 ++++++++++++++++ dlls/winex11.drv/x11drv.h | 8 +++++++- dlls/winex11.drv/x11drv_main.c | 1 + 4 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 428dcb7b8b7..977a11a989b 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1204,6 +1204,23 @@ static int get_window_xembed_info( Display *display, Window window ) return ret; }
+static Window get_net_active_window( Display *display ) +{ + unsigned long count, remaining; + Window window = None, *value; + int format; + Atom type; + + if (!XGetWindowProperty( display, DefaultRootWindow( display ), x11drv_atom(_NET_ACTIVE_WINDOW), 0, + 65536 / sizeof(Window), False, XA_WINDOW, &type, &format, &count, + &remaining, (unsigned char **)&value )) + { + if (type == XA_WINDOW && format == 32) window = *value; + XFree( value ); + } + + return window; +}
/*********************************************************************** * handle_wm_state_notify @@ -1262,6 +1279,16 @@ static void handle_net_supported_notify( XPropertyEvent *event ) if (event->state == PropertyNewValue) net_supported_init( data ); }
+static void handle_net_active_window( HWND hwnd, XPropertyEvent *event ) +{ + Window window = None; + + if (event->state == PropertyNewValue) window = get_net_active_window( event->display ); + net_active_window_notify( event->serial, window, event->time ); + + NtUserPostMessage( hwnd, WM_WINE_WINDOW_STATE_CHANGED, 0, 0 ); +} + /*********************************************************************** * X11DRV_PropertyNotify */ @@ -1274,6 +1301,7 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev ) 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_SUPPORTED)) handle_net_supported_notify( event ); + if (event->atom == x11drv_atom(_NET_ACTIVE_WINDOW)) handle_net_active_window( hwnd, event );
return TRUE; } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 428c7108c98..6a400b24f03 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1735,6 +1735,22 @@ void window_configure_notify( struct x11drv_win_data *data, unsigned long serial current, expected, prefix, received, NULL ); }
+void net_active_window_notify( unsigned long serial, Window value, Time time ) +{ + struct x11drv_thread_data *data = x11drv_thread_data(); + Window *desired = &data->desired_net_active_window, *pending = &data->pending_net_active_window, *current = &data->current_net_active_window; + unsigned long *expect_serial = &data->net_active_window_serial; + const char *expected, *received; + + received = wine_dbg_sprintf( "_NET_ACTIVE_WINDOW %lx/%lu", value, serial ); + expected = *expect_serial ? wine_dbg_sprintf( ", expected %lx/%lu", *pending, *expect_serial ) : ""; + if (!handle_state_change( serial, expect_serial, sizeof(value), &value, desired, pending, + current, expected, "", received, NULL )) + return; + + TRACE( "_NET_ACTIVE_WINDOW changed to %lx\n", value ); +} + BOOL window_has_pending_wm_state( HWND hwnd, UINT state ) { struct x11drv_win_data *data; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 8e383ae4c48..029648837cb 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -403,6 +403,11 @@ struct x11drv_thread_data XIValuatorClassInfo y_valuator; int xinput2_pointer; /* XInput2 master pointer device id */ #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ + + Window desired_net_active_window; /* active window tracking the desired / win32 state */ + Window pending_net_active_window; /* active window tracking the pending / requested state */ + Window current_net_active_window; /* active window tracking the current X11 state */ + unsigned long net_active_window_serial; /* serial of last pending _NET_ACTIVE_WINDOW request */ };
extern struct x11drv_thread_data *x11drv_init_thread_data(void); @@ -485,6 +490,7 @@ enum x11drv_atoms XATOM__ICC_PROFILE, XATOM__KDE_NET_WM_STATE_SKIP_SWITCHER, XATOM__MOTIF_WM_HINTS, + XATOM__NET_ACTIVE_WINDOW, XATOM__NET_STARTUP_INFO_BEGIN, XATOM__NET_STARTUP_INFO, XATOM__NET_SUPPORTED, @@ -666,8 +672,8 @@ 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 BOOL get_window_state_updates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect );
+extern void net_active_window_notify( unsigned long serial, Window window, Time time ); extern void net_supported_init( struct x11drv_thread_data *data );
extern Window init_clip_window(void); diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e58d3afca63..179cdfab5da 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -126,6 +126,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "_ICC_PROFILE", "_KDE_NET_WM_STATE_SKIP_SWITCHER", "_MOTIF_WM_HINTS", + "_NET_ACTIVE_WINDOW", "_NET_STARTUP_INFO_BEGIN", "_NET_STARTUP_INFO", "_NET_SUPPORTED",
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 31 ++++++++++++++++++++++++++++--- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 1 + 3 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 6a400b24f03..94098d75e0c 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -156,7 +156,7 @@ static unsigned int find_host_window_child( struct host_window *win, Window chil return i; }
-static int host_window_error( Display *display, XErrorEvent *event, void *arg ) +static int bad_window_error( Display *display, XErrorEvent *event, void *arg ) { return (event->error_code == BadWindow); } @@ -175,7 +175,7 @@ struct host_window *get_host_window( Window window, BOOL create ) if (!create || !(win = calloc( 1, sizeof(*win) ))) return NULL; win->window = window;
- X11DRV_expect_error( data->display, host_window_error, NULL ); + X11DRV_expect_error( data->display, bad_window_error, NULL ); XSelectInput( data->display, window, StructureNotifyMask ); if (!XGetWindowAttributes( data->display, window, &attr )) memset( &attr, 0, sizeof(attr) ); if (!XQueryTree( data->display, window, &xroot, &xparent, &xchildren, &nchildren )) xparent = root_window; @@ -308,6 +308,28 @@ static void remove_startup_notification(Display *display, Window window) } }
+HWND hwnd_from_window( Display *display, Window window ) +{ + unsigned long count, remaining; + unsigned long *xhwnd; + HWND hwnd = (HWND)-1; + int format; + Atom type; + + if (!window) return 0; + if (!XFindContext( display, window, winContext, (char **)&hwnd )) return hwnd; + + X11DRV_expect_error( display, bad_window_error, NULL ); + if (!XGetWindowProperty( display, window, x11drv_atom(_WINE_HWND), 0, 65536, False, XA_CARDINAL, + &type, &format, &count, &remaining, (unsigned char **)&xhwnd )) + { + if (type == XA_CARDINAL && format == 32) hwnd = ULongToHandle(*xhwnd); + XFree( xhwnd ); + } + if (X11DRV_check_error()) return (HWND)-1; + return hwnd; +} + static BOOL is_managed( HWND hwnd ) { struct x11drv_win_data *data = get_win_data( hwnd ); @@ -1748,7 +1770,7 @@ void net_active_window_notify( unsigned long serial, Window value, Time time ) current, expected, "", received, NULL )) return;
- TRACE( "_NET_ACTIVE_WINDOW changed to %lx\n", value ); + TRACE( "_NET_ACTIVE_WINDOW changed to %p/%lx\n", hwnd_from_window( data->display, value ), value ); }
BOOL window_has_pending_wm_state( HWND hwnd, UINT state ) @@ -2095,6 +2117,7 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colo */ static void create_whole_window( struct x11drv_win_data *data ) { + unsigned long xhwnd = (UINT_PTR)data->hwnd; int cx, cy, mask; XSetWindowAttributes attr; WCHAR text[1024]; @@ -2133,6 +2156,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; + XChangeProperty( data->display, data->whole_window, x11drv_atom(_WINE_HWND), XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&xhwnd, 1 ); SetRect( &data->current_state.rect, pos.x, pos.y, pos.x + cx, pos.y + cy ); data->pending_state.rect = data->current_state.rect; data->desired_state.rect = data->current_state.rect; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 029648837cb..79703708496 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -520,6 +520,7 @@ enum x11drv_atoms XATOM__NET_WM_WINDOW_TYPE_UTILITY, XATOM__NET_WORKAREA, XATOM__GTK_WORKAREAS_D0, + XATOM__WINE_HWND, XATOM__XEMBED, XATOM__XEMBED_INFO, XATOM_XdndAware, diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 179cdfab5da..c0d20d0b719 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -156,6 +156,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "_NET_WM_WINDOW_TYPE_UTILITY", "_NET_WORKAREA", "_GTK_WORKAREAS_D0", + "_WINE_HWND", "_XEMBED", "_XEMBED_INFO", "XdndAware",
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 94098d75e0c..c3840a2722f 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1659,16 +1659,20 @@ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, { 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 ); + *state_cmd = *config_cmd = 0;
- release_win_data( data ); + if ((data = get_win_data( hwnd ))) + { + *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 ); + }
- TRACE( "hwnd %p, returning state_cmd %#x, config_cmd %#x, rect %s\n", hwnd, *state_cmd, *config_cmd, wine_dbgstr_rect(rect) ); - return *state_cmd || *config_cmd; + if (!*state_cmd && !*config_cmd) return FALSE; + TRACE( "hwnd %p, returning state_cmd %#x, config_cmd %#x, rect %s\n", + hwnd, *state_cmd, *config_cmd, wine_dbgstr_rect(rect) ); + return TRUE; }
static BOOL handle_state_change( unsigned long serial, unsigned long *expect_serial, UINT size, const void *value,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/driver.c | 2 +- dlls/win32u/message.c | 7 +++++-- dlls/winex11.drv/window.c | 9 +++++---- dlls/winex11.drv/x11drv.h | 2 +- include/wine/gdi_driver.h | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 22e48fa6782..abee66c0419 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -881,7 +881,7 @@ static BOOL nulldrv_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, U return FALSE; }
-static BOOL nulldrv_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect ) +static BOOL nulldrv_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect, HWND *foreground ) { return FALSE; } diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 5a5c26d9947..8047e01cb61 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2177,15 +2177,18 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR { UINT state_cmd, config_cmd; RECT window_rect; + HWND foreground;
- if (!user_driver->pGetWindowStateUpdates( hwnd, &state_cmd, &config_cmd, &window_rect )) return 0; + if (!user_driver->pGetWindowStateUpdates( hwnd, &state_cmd, &config_cmd, &window_rect, &foreground )) return 0; + if (foreground) NtUserSetForegroundWindow( foreground ); if (state_cmd) { if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 );
/* state change might have changed the window config already, check again */ - user_driver->pGetWindowStateUpdates( hwnd, &state_cmd, &config_cmd, &window_rect ); + user_driver->pGetWindowStateUpdates( hwnd, &state_cmd, &config_cmd, &window_rect, &foreground ); + if (foreground) NtUserSetForegroundWindow( foreground ); if (state_cmd) WARN( "window %p state needs another update, ignoring\n", hwnd ); } if (config_cmd) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index c3840a2722f..0b4c55f134f 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1655,11 +1655,12 @@ static UINT window_update_client_config( struct x11drv_win_data *data ) /*********************************************************************** * GetWindowStateUpdates (X11DRV.@) */ -BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect ) +BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect, HWND *foreground ) { struct x11drv_win_data *data;
*state_cmd = *config_cmd = 0; + *foreground = 0;
if ((data = get_win_data( hwnd ))) { @@ -1669,9 +1670,9 @@ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, release_win_data( data ); }
- if (!*state_cmd && !*config_cmd) return FALSE; - TRACE( "hwnd %p, returning state_cmd %#x, config_cmd %#x, rect %s\n", - hwnd, *state_cmd, *config_cmd, wine_dbgstr_rect(rect) ); + if (!*state_cmd && !*config_cmd && !*foreground) return FALSE; + TRACE( "hwnd %p, returning state_cmd %#x, config_cmd %#x, rect %s, foreground %p\n", + hwnd, *state_cmd, *config_cmd, wine_dbgstr_rect(rect), *foreground ); return TRUE; }
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 79703708496..c6730e51c7d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -243,7 +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_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect, HWND *foreground ); 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/wine/gdi_driver.h b/include/wine/gdi_driver.h index 51a095fd2b0..930ccd4c39b 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -385,7 +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 (*pGetWindowStateUpdates)(HWND,UINT*,UINT*,RECT*,HWND*); 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
Repurposing the SetFocus callback. --- dlls/win32u/driver.c | 6 +++--- dlls/win32u/input.c | 8 +++++--- dlls/winemac.drv/gdi.c | 2 +- dlls/winemac.drv/macdrv.h | 2 +- dlls/winemac.drv/window.c | 6 +++--- dlls/winex11.drv/event.c | 17 +++-------------- dlls/winex11.drv/init.c | 2 +- dlls/winex11.drv/x11drv.h | 2 +- include/wine/gdi_driver.h | 2 +- 9 files changed, 19 insertions(+), 28 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index abee66c0419..2677606a8fc 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -824,7 +824,7 @@ static void nulldrv_SetDesktopWindow( HWND hwnd ) { }
-static void nulldrv_SetFocus( HWND hwnd ) +static void nulldrv_ActivateWindow( HWND hwnd, HWND previous ) { }
@@ -1280,7 +1280,7 @@ static const struct user_driver_funcs lazy_load_driver = nulldrv_ScrollDC, nulldrv_SetCapture, loaderdrv_SetDesktopWindow, - nulldrv_SetFocus, + nulldrv_ActivateWindow, loaderdrv_SetLayeredWindowAttributes, nulldrv_SetParent, loaderdrv_SetWindowRgn, @@ -1377,7 +1377,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(ScrollDC); SET_USER_FUNC(SetCapture); SET_USER_FUNC(SetDesktopWindow); - SET_USER_FUNC(SetFocus); + SET_USER_FUNC(ActivateWindow); SET_USER_FUNC(SetLayeredWindowAttributes); SET_USER_FUNC(SetParent); SET_USER_FUNC(SetWindowRgn); diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ad4ba4d77c5..7a2edb4c110 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1947,8 +1947,6 @@ static HWND set_focus_window( HWND hwnd ) } if (is_window(hwnd)) { - user_driver->pSetFocus(hwnd); - ime_hwnd = get_default_ime_window( hwnd ); if (ime_hwnd) send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_ACTIVATE, @@ -2067,7 +2065,11 @@ BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus, DWORD new }
done: - if (hwnd) clip_fullscreen_window( hwnd, FALSE ); + if (hwnd) + { + if (hwnd == NtUserGetForegroundWindow()) user_driver->pActivateWindow( hwnd, previous ); + clip_fullscreen_window( hwnd, FALSE ); + } return TRUE; }
diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index 4921fc2f170..d58e0fd280f 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -286,7 +286,7 @@ static const struct user_driver_funcs macdrv_funcs = .pSetCursor = macdrv_SetCursor, .pSetCursorPos = macdrv_SetCursorPos, .pSetDesktopWindow = macdrv_SetDesktopWindow, - .pSetFocus = macdrv_SetFocus, + .pActivateWindow = macdrv_ActivateWindow, .pSetLayeredWindowAttributes = macdrv_SetLayeredWindowAttributes, .pSetParent = macdrv_SetParent, .pSetWindowRgn = macdrv_SetWindowRgn, diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 4457a7e186c..b6eeb4ecb8e 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -136,7 +136,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect) extern LRESULT macdrv_DesktopWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); extern void macdrv_DestroyWindow(HWND hwnd); extern void macdrv_SetDesktopWindow(HWND hwnd); -extern void macdrv_SetFocus(HWND hwnd); +extern void macdrv_ActivateWindow(HWND hwnd, HWND previous); extern void macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags); extern void macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent); diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 115820ec376..8314d7dbf19 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1388,11 +1388,11 @@ void macdrv_DestroyWindow(HWND hwnd)
/***************************************************************** - * SetFocus (MACDRV.@) + * ActivateWindow (MACDRV.@) * - * Set the Mac focus. + * Set the Mac active window. */ -void macdrv_SetFocus(HWND hwnd) +void macdrv_ActivateWindow(HWND hwnd, HWND previous) { struct macdrv_thread_data *thread_data = macdrv_thread_data();
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 977a11a989b..e0d15e55f26 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1308,25 +1308,14 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
/***************************************************************** - * SetFocus (X11DRV.@) + * ActivateWindow (X11DRV.@) * * Set the X focus. */ -void X11DRV_SetFocus( HWND hwnd ) +void X11DRV_ActivateWindow( HWND hwnd, HWND previous ) { struct x11drv_win_data *data; - - HWND parent; - - for (;;) - { - if (!(data = get_win_data( hwnd ))) return; - if (data->embedded) break; - parent = NtUserGetAncestor( hwnd, GA_PARENT ); - if (!parent || parent == NtUserGetDesktopWindow()) break; - release_win_data( data ); - hwnd = parent; - } + if (!(data = get_win_data( hwnd ))) return; if (!data->managed || data->embedder) set_input_focus( data ); release_win_data( data ); } diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index a0bfab2fb46..13dae3ad661 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -454,7 +454,7 @@ static const struct user_driver_funcs x11drv_funcs = .pScrollDC = X11DRV_ScrollDC, .pSetCapture = X11DRV_SetCapture, .pSetDesktopWindow = X11DRV_SetDesktopWindow, - .pSetFocus = X11DRV_SetFocus, + .pActivateWindow = X11DRV_ActivateWindow, .pSetLayeredWindowAttributes = X11DRV_SetLayeredWindowAttributes, .pSetParent = X11DRV_SetParent, .pSetWindowIcon = X11DRV_SetWindowIcon, diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index c6730e51c7d..c9c5fae3636 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -706,7 +706,7 @@ extern XContext winContext; extern XContext cursor_context;
extern BOOL is_current_process_focused(void); -extern void X11DRV_SetFocus( HWND hwnd ); +extern void X11DRV_ActivateWindow( HWND hwnd, HWND previous ); extern void set_window_cursor( Window window, HCURSOR handle ); extern void reapply_cursor_clipping(void); extern void ungrab_clipping_window(void); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 930ccd4c39b..c70c7e80996 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -372,7 +372,7 @@ struct user_driver_funcs BOOL (*pScrollDC)(HDC,INT,INT,HRGN); void (*pSetCapture)(HWND,UINT); void (*pSetDesktopWindow)(HWND); - void (*pSetFocus)(HWND); + void (*pActivateWindow)(HWND,HWND); void (*pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD); void (*pSetParent)(HWND,HWND,HWND); void (*pSetWindowRgn)(HWND,HRGN,BOOL);
From: Rémi Bernon rbernon@codeweavers.com
When supported, instead of tracking window focus only. --- dlls/winex11.drv/event.c | 29 +++++++++++++++----------- dlls/winex11.drv/window.c | 44 ++++++++++++++++++++++++++++++++++++++- dlls/winex11.drv/x11drv.h | 2 ++ 3 files changed, 62 insertions(+), 13 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index e0d15e55f26..4ccd77fcb37 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -640,23 +640,25 @@ static void set_input_focus( struct x11drv_win_data *data ) /********************************************************************** * set_focus */ -static void set_focus( Display *display, HWND hwnd, Time time ) +static void set_focus( Display *display, HWND focus, Time time ) { - HWND focus; Window win; GUITHREADINFO threadinfo;
- TRACE( "setting foreground window to %p\n", hwnd ); - NtUserSetForegroundWindow( hwnd ); + TRACE( "setting foreground window to %p\n", focus );
- threadinfo.cbSize = sizeof(threadinfo); - NtUserGetGUIThreadInfo( 0, &threadinfo ); - focus = threadinfo.hwndFocus; - if (!focus) focus = threadinfo.hwndActive; - if (focus) focus = NtUserGetAncestor( focus, GA_ROOT ); - win = X11DRV_get_whole_window(focus); + if (!is_netwm_supported( x11drv_atom(_NET_ACTIVE_WINDOW) )) + { + NtUserSetForegroundWindow( focus ); + + threadinfo.cbSize = sizeof(threadinfo); + NtUserGetGUIThreadInfo( 0, &threadinfo ); + focus = threadinfo.hwndFocus; + if (!focus) focus = threadinfo.hwndActive; + if (focus) focus = NtUserGetAncestor( focus, GA_ROOT ); + }
- if (win) + if ((win = X11DRV_get_whole_window( focus ))) { TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time ); XSetInputFocus( display, win, RevertToParent, time ); @@ -901,7 +903,7 @@ static void focus_out( Display *display , HWND hwnd ) /* don't reset the foreground window, if the window which is getting the focus is a Wine window */
- if (!is_current_process_focused()) + if (!is_netwm_supported( x11drv_atom(_NET_ACTIVE_WINDOW) ) && !is_current_process_focused()) { /* Abey : 6-Oct-99. Check again if the focus out window is the Foreground window, because in most cases the messages sent @@ -1315,6 +1317,9 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev ) void X11DRV_ActivateWindow( HWND hwnd, HWND previous ) { struct x11drv_win_data *data; + + set_net_active_window( hwnd, previous ); + if (!(data = get_win_data( hwnd ))) return; if (!data->managed || data->embedder) set_input_focus( data ); release_win_data( data ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 0b4c55f134f..7e69aadcff3 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1657,11 +1657,21 @@ static UINT window_update_client_config( struct x11drv_win_data *data ) */ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, RECT *rect, HWND *foreground ) { + struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_win_data *data; + Window window;
*state_cmd = *config_cmd = 0; *foreground = 0;
+ if (NtUserGetWindowThread( NtUserGetForegroundWindow(), NULL ) == GetCurrentThreadId() && + !thread_data->net_active_window_serial && (window = thread_data->current_net_active_window)) + { + *foreground = hwnd_from_window( thread_data->display, window ); + if (*foreground == (HWND)-1) *foreground = NtUserGetDesktopWindow(); + if (*foreground == NtUserGetForegroundWindow()) *foreground = 0; + } + if ((data = get_win_data( hwnd ))) { *state_cmd = window_update_client_state( data ); @@ -1778,6 +1788,38 @@ void net_active_window_notify( unsigned long serial, Window value, Time time ) TRACE( "_NET_ACTIVE_WINDOW changed to %p/%lx\n", hwnd_from_window( data->display, value ), value ); }
+void set_net_active_window( HWND hwnd, HWND previous ) +{ + struct x11drv_thread_data *data = x11drv_thread_data(); + Window window; + XEvent xev; + + if (hwnd == NtUserGetDesktopWindow()) return; + if (!is_netwm_supported( x11drv_atom(_NET_ACTIVE_WINDOW) )) return; + if (!(window = X11DRV_get_whole_window( hwnd ))) return; + if (data->pending_net_active_window == window) return; + + xev.xclient.type = ClientMessage; + xev.xclient.window = window; + xev.xclient.message_type = x11drv_atom(_NET_ACTIVE_WINDOW); + xev.xclient.serial = 0; + xev.xclient.display = data->display; + xev.xclient.send_event = True; + xev.xclient.format = 32; + xev.xclient.data.l[0] = 2; /* source: pager */ + xev.xclient.data.l[1] = 0; /* timestamp */ + xev.xclient.data.l[2] = X11DRV_get_whole_window( previous ); /* current active */ + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + data->pending_net_active_window = window; + data->net_active_window_serial = NextRequest( data->display ); + TRACE( "requesting _NET_ACTIVE_WINDOW %p/%lx serial %lu\n", hwnd, window, data->net_active_window_serial ); + XSendEvent( data->display, DefaultRootWindow( data->display ), False, + SubstructureRedirectMask | SubstructureNotifyMask, &xev ); + XFlush( data->display ); +} + BOOL window_has_pending_wm_state( HWND hwnd, UINT state ) { struct x11drv_win_data *data; @@ -3322,7 +3364,7 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) /*********************************************************************** * is_netwm_supported */ -static BOOL is_netwm_supported( Atom atom ) +BOOL is_netwm_supported( Atom atom ) { struct x11drv_thread_data *data = x11drv_thread_data(); BOOL supported; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index c9c5fae3636..d67f85d9103 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -674,8 +674,10 @@ extern void window_wm_state_notify( struct x11drv_win_data *data, unsigned long 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 set_net_active_window( HWND hwnd, HWND previous ); extern void net_active_window_notify( unsigned long serial, Window window, Time time ); extern void net_supported_init( struct x11drv_thread_data *data ); +extern BOOL is_netwm_supported( Atom atom );
extern Window init_clip_window(void); extern void update_user_time( Time time );
This finally fix the winex11/dinput alt-tabbing issue of https://bugs.winehq.org/show_bug.cgi?id=55336.
But it seems full-screen games won't minimize anymore, and thus stay on top, at least on KDE Wayland.
This merge request was closed by Rémi Bernon.