Yet another attempt at making things better.
This uses a simpler delaying method than the previous implementations, by resending delayed FocusIn/WM_TAKE_FOCUS events to the window so it reprocesses it a bit later and retry grabbing the pointer until it succeeds.
Rémi Bernon (8): Revert "winex11.drv: Retry last ClipCursor when grab is released." Revert "winex11.drv: Only grab or warp the cursor when keyboard isn't grabbed." winex11.drv: Merge FocusIn/FocusOut NotifyGrab/NotifyUngrab cases. winex11.drv: Pass XEvent instead of XClientMessageEvent to handlers. winex11.drv: Wait for pointer grab on FocusIn/WM_TAKE_FOCUS events. winex11.drv: Release pointer grab on focus change. winex11.drv: Release pointer grab on FocusOut events. winex11.drv: Restore pointer grab on FocusIn events.
dlls/winex11.drv/event.c | 118 ++++++++++++++++++++------------------ dlls/winex11.drv/mouse.c | 36 ------------ dlls/winex11.drv/window.c | 3 + dlls/winex11.drv/x11drv.h | 13 ++--- dlls/winex11.drv/xdnd.c | 11 ++-- 5 files changed, 78 insertions(+), 103 deletions(-)
-- 2.23.0
This reverts commit 92177b0b161e91f1d609615d89d8e3199feea33f.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/event.c | 8 -------- dlls/winex11.drv/mouse.c | 24 ------------------------ dlls/winex11.drv/x11drv.h | 1 - 3 files changed, 33 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 25730192d3d..6df5b9bcb2d 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -789,7 +789,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) break; case NotifyUngrab: keyboard_grabbed = FALSE; - retry_grab_clipping_window(); return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ }
@@ -891,13 +890,6 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) break; case NotifyGrab: keyboard_grabbed = TRUE; - - /* This will do nothing due to keyboard_grabbed == TRUE, but it - * will save the current clipping rect so we can restore it on - * FocusIn with NotifyUngrab mode. - */ - retry_grab_clipping_window(); - return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ }
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 15e5c04a41e..4411382d3f1 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -125,9 +125,6 @@ XContext cursor_context = 0; static HWND cursor_window; static HCURSOR last_cursor; static DWORD last_cursor_change; -static RECT last_clip_rect; -static HWND last_clip_foreground_window; -static BOOL last_clip_refused; static RECT clip_rect; static Cursor create_cursor( HANDLE handle );
@@ -398,15 +395,8 @@ static BOOL grab_clipping_window( const RECT *clip ) if (keyboard_grabbed) { WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); - last_clip_refused = TRUE; - last_clip_foreground_window = GetForegroundWindow(); - last_clip_rect = *clip; return FALSE; } - else - { - last_clip_refused = FALSE; - }
/* enable XInput2 unless we are already clipping */ if (!data->clip_hwnd) enable_xinput2(); @@ -481,20 +471,6 @@ void reset_clipping_window(void) ClipCursor( NULL ); /* make sure the clip rectangle is reset too */ }
-/*********************************************************************** - * retry_grab_clipping_window - * - * Restore the current clip rectangle or retry the last one if it has - * been refused because of an active keyboard grab. - */ -void retry_grab_clipping_window(void) -{ - if (clipping_cursor) - ClipCursor( &clip_rect ); - else if (last_clip_refused && GetForegroundWindow() == last_clip_foreground_window) - ClipCursor( &last_clip_rect ); -} - BOOL CDECL X11DRV_ClipCursor( const RECT *clip );
/*********************************************************************** diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 135faa8989b..607ff474e2a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -625,7 +625,6 @@ extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN; extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN; extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN; extern void reset_clipping_window(void) DECLSPEC_HIDDEN; -extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN;
This reverts commit 54f8077c41f715cfcf9c2bc016d964b720911326.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/event.c | 11 ----------- dlls/winex11.drv/mouse.c | 12 ------------ dlls/winex11.drv/x11drv.h | 1 - 3 files changed, 24 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 6df5b9bcb2d..ae6860f372e 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -155,9 +155,6 @@ static const char * event_names[MAX_EVENT_HANDLERS] = "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent" };
-/* is someone else grabbing the keyboard, for example the WM, when manipulating the window */ -BOOL keyboard_grabbed = FALSE; - int xinput2_opcode = 0;
/* return the name of an X event */ @@ -779,16 +776,12 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) { case NotifyGrab: /* these are received when moving undecorated managed windows on mutter */ - keyboard_grabbed = TRUE; return FALSE; case NotifyWhileGrabbed: - keyboard_grabbed = TRUE; break; case NotifyNormal: - keyboard_grabbed = FALSE; break; case NotifyUngrab: - keyboard_grabbed = FALSE; return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ }
@@ -880,16 +873,12 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) { case NotifyUngrab: /* these are received when moving undecorated managed windows on mutter */ - keyboard_grabbed = FALSE; return FALSE; case NotifyNormal: - keyboard_grabbed = FALSE; break; case NotifyWhileGrabbed: - keyboard_grabbed = TRUE; break; case NotifyGrab: - keyboard_grabbed = TRUE; return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ }
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 4411382d3f1..8f3118e04eb 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -392,12 +392,6 @@ static BOOL grab_clipping_window( const RECT *clip ) GetModuleHandleW(0), NULL ))) return TRUE;
- if (keyboard_grabbed) - { - WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); - return FALSE; - } - /* enable XInput2 unless we are already clipping */ if (!data->clip_hwnd) enable_xinput2();
@@ -1445,12 +1439,6 @@ BOOL CDECL X11DRV_SetCursorPos( INT x, INT y ) struct x11drv_thread_data *data = x11drv_init_thread_data(); POINT pos = virtual_screen_to_root( x, y );
- if (keyboard_grabbed) - { - WARN( "refusing to warp to %u, %u\n", pos.x, pos.y ); - return FALSE; - } - if (!clipping_cursor && XGrabPointer( data->display, root_window, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 607ff474e2a..b0c79e37bb2 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -382,7 +382,6 @@ extern Colormap default_colormap DECLSPEC_HIDDEN; extern XPixmapFormatValues **pixmap_formats DECLSPEC_HIDDEN; extern Window root_window DECLSPEC_HIDDEN; extern BOOL clipping_cursor DECLSPEC_HIDDEN; -extern BOOL keyboard_grabbed DECLSPEC_HIDDEN; extern unsigned int screen_bpp DECLSPEC_HIDDEN; extern BOOL use_xkb DECLSPEC_HIDDEN; extern BOOL usexrandr DECLSPEC_HIDDEN;
The return value was different as well, this makes it more consistent.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/event.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index ae6860f372e..a4a6ad8d601 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -772,18 +772,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == GetDesktopWindow()) return FALSE;
- switch (event->mode) - { - case NotifyGrab: - /* these are received when moving undecorated managed windows on mutter */ - return FALSE; - case NotifyWhileGrabbed: - break; - case NotifyNormal: - break; - case NotifyUngrab: - return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ - } + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ + if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE;
if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic ); if (use_take_focus) @@ -869,18 +859,8 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) } if (!hwnd) return FALSE;
- switch (event->mode) - { - case NotifyUngrab: - /* these are received when moving undecorated managed windows on mutter */ - return FALSE; - case NotifyNormal: - break; - case NotifyWhileGrabbed: - break; - case NotifyGrab: - return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ - } + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ + if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE;
focus_out( event->display, hwnd ); return TRUE;
This is to avoid a dubious cast from XClientMessageEvent to XEvent in next patch.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/event.c | 20 +++++++++++++------- dlls/winex11.drv/x11drv.h | 8 ++++---- dlls/winex11.drv/xdnd.c | 11 +++++++---- 3 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index a4a6ad8d601..07777952400 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -618,8 +618,10 @@ static void set_focus( Display *display, HWND hwnd, Time time ) /********************************************************************** * handle_manager_message */ -static void handle_manager_message( HWND hwnd, XClientMessageEvent *event ) +static void handle_manager_message( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; + if (hwnd != GetDesktopWindow()) return; if (systray_atom && event->data.l[1] == systray_atom) change_systray_owner( event->display, event->data.l[2] ); @@ -629,8 +631,9 @@ static void handle_manager_message( HWND hwnd, XClientMessageEvent *event ) /********************************************************************** * handle_wm_protocols */ -static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) +static void handle_wm_protocols( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; Atom protocol = (Atom)event->data.l[0]; Time event_time = (Time)event->data.l[1];
@@ -1642,8 +1645,10 @@ static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event ) /********************************************************************** * handle_xembed_protocol */ -static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) +static void handle_xembed_protocol( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; + switch (event->data.l[1]) { case XEMBED_EMBEDDED_NOTIFY: @@ -1698,8 +1703,9 @@ static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) /********************************************************************** * handle_dnd_protocol */ -static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) +static void handle_dnd_protocol( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; Window root, child; int root_x, root_y, child_x, child_y; unsigned int u; @@ -1718,8 +1724,8 @@ static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
struct client_message_handler { - int atom; /* protocol atom */ - void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */ + int atom; /* protocol atom */ + void (*handler)(HWND, XEvent *); /* corresponding handler function */ };
static const struct client_message_handler client_messages[] = @@ -1755,7 +1761,7 @@ static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev ) { if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM]) { - client_messages[i].handler( hwnd, event ); + client_messages[i].handler( hwnd, xev ); return TRUE; } } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index b0c79e37bb2..9b70f53d382 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -238,10 +238,10 @@ extern BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, DWORD dwReadLen) DECLSPEC_HIDDEN; extern void IME_SetResultString(LPWSTR lpResult, DWORD dwResultlen) DECLSPEC_HIDDEN;
-extern void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; -extern void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; -extern void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; -extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; +extern void X11DRV_XDND_EnterEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; +extern void X11DRV_XDND_PositionEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; +extern void X11DRV_XDND_DropEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; +extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; extern void X11DRV_CLIPBOARD_ImportSelection( Display *display, Window win, Atom selection, Atom *targets, UINT count, void (*callback)( Atom, UINT, HANDLE )) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index 8dc4a5bce23..117f4de0736 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -192,8 +192,9 @@ static long X11DRV_XDND_DROPEFFECTToXdndAction(DWORD effect) * * Handle an XdndEnter event. */ -void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) +void X11DRV_XDND_EnterEvent( HWND hWnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; int version; Atom *xdndtypes; unsigned long count = 0; @@ -291,8 +292,9 @@ static HWND window_accepting_files(HWND hwnd) * * Handle an XdndPosition event. */ -void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) +void X11DRV_XDND_PositionEvent( HWND hWnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; XClientMessageEvent e; int accept = 0; /* Assume we're not accepting */ IDropTarget *dropTarget = NULL; @@ -405,8 +407,9 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) * * Handle an XdndDrop event. */ -void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) +void X11DRV_XDND_DropEvent( HWND hWnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; XClientMessageEvent e; IDropTarget *dropTarget; DWORD effect = XDNDDropEffect; @@ -499,7 +502,7 @@ void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) * * Handle an XdndLeave event. */ -void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event ) +void X11DRV_XDND_LeaveEvent( HWND hWnd, XEvent *xev ) { IDropTarget *dropTarget;
The FocusIn/WM_TAKE_FOCUS events are received as soon as a window is clicked, but when some modifier key is pressed or when the click is on the window frame, the WM may still be controlling the window size or position. It usually grabs the cursor while doing so - and if not then there's apparently nothing we can do.
When using undecorated mode we handle this case "correctly" by going through the corresponding Windows non-client message loop until mouse buttons are released, but when using decorated windows the window decoration is empty from the Wine perspective and any window event is considered as happening in the client area.
This leads to some issues when the window is moved or resized, with applications applying clipping rectangles immediately and not updating it on subsequent window move/resize messages. Delaying the WM_ACTIVATE until the WM releases its grab and the window move is complete helps solving this situation.
This delay is implemented here by resending the FocusIn/WM_TAKE_FOCUS events to the window until the cursor can be grabbed and then processing them normally.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/event.c | 46 ++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 07777952400..426ac785082 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -311,6 +311,24 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE } #endif
+static int try_grab_pointer( Display *display ) +{ + if (!grab_pointer) + return 1; + + /* if we are already clipping the cursor in the current thread, we should not + * call XGrabPointer here or it would change the confine-to window. */ + if (clipping_cursor && x11drv_thread_data()->clip_hwnd) + return 1; + + if (XGrabPointer( display, root_window, False, 0, GrabModeAsync, GrabModeAsync, + None, None, CurrentTime ) != GrabSuccess) + return 0; + + XUngrabPointer( display, CurrentTime ); + return 1; +} + /*********************************************************************** * merge_events * @@ -591,12 +609,18 @@ 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( XEvent *event, HWND hwnd, Time time ) { HWND focus; Window win; GUITHREADINFO threadinfo;
+ if (!try_grab_pointer( event->xany.display )) + { + XSendEvent( event->xany.display, event->xany.window, False, 0, event ); + return; + } + TRACE( "setting foreground window to %p\n", hwnd ); SetForegroundWindow( hwnd );
@@ -610,7 +634,7 @@ static void set_focus( Display *display, HWND hwnd, Time time ) if (win) { TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time ); - XSetInputFocus( display, win, RevertToParent, time ); + XSetInputFocus( event->xany.display, win, RevertToParent, time ); } }
@@ -709,7 +733,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) MAKELONG(HTCAPTION,WM_LBUTTONDOWN) ); if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) { - set_focus( event->display, hwnd, event_time ); + set_focus( xev, hwnd, event_time ); return; } } @@ -718,7 +742,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) hwnd = GetForegroundWindow(); if (!hwnd) hwnd = last_focus; if (!hwnd) hwnd = GetDesktopWindow(); - set_focus( event->display, hwnd, event_time ); + set_focus( xev, hwnd, event_time ); return; } /* try to find some other window to give the focus to */ @@ -726,7 +750,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT ); if (!hwnd) hwnd = GetActiveWindow(); if (!hwnd) hwnd = last_focus; - if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time ); + if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, event_time ); } else if (protocol == x11drv_atom(_NET_WM_PING)) { @@ -791,9 +815,17 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT ); if (!hwnd) hwnd = GetActiveWindow(); if (!hwnd) hwnd = x11drv_thread_data()->last_focus; - if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime ); + if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime ); + return TRUE; + } + + if (!try_grab_pointer( event->display )) + { + XSendEvent( event->display, event->window, False, 0, xev ); + return FALSE; } - else SetForegroundWindow( hwnd ); + + SetForegroundWindow( hwnd ); return TRUE; }
When using WM_TAKE_FOCUS, the foreground window will only receive the FocusOut message after we have called XSetInputFocus. As we are waiting for the cursor to be released, we have to tell it to release its grab so we can try to grab it ourselves.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/event.c | 2 ++ dlls/winex11.drv/window.c | 3 +++ dlls/winex11.drv/x11drv.h | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 426ac785082..a02f697a77d 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -617,6 +617,8 @@ static void set_focus( XEvent *event, HWND hwnd, Time time )
if (!try_grab_pointer( event->xany.display )) { + /* ask the foreground window to release its grab before trying to get ours */ + SendMessageW( GetForegroundWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 ); XSendEvent( event->xany.display, event->xany.window, False, 0, event ); return; } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 4e01eb201c9..c3db32c85cb 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2739,6 +2739,9 @@ LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) return 0; case WM_X11DRV_CLIP_CURSOR: return clip_cursor_notify( hwnd, (HWND)wp, (HWND)lp ); + case WM_X11DRV_RELEASE_CURSOR: + ungrab_clipping_window(); + return 0; default: FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp ); return 0; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9b70f53d382..a0c8cfda025 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -533,7 +533,8 @@ enum x11drv_window_messages WM_X11DRV_SET_WIN_REGION, WM_X11DRV_RESIZE_DESKTOP, WM_X11DRV_SET_CURSOR, - WM_X11DRV_CLIP_CURSOR + WM_X11DRV_CLIP_CURSOR, + WM_X11DRV_RELEASE_CURSOR };
/* _NET_WM_STATE properties that we keep track of */
When a window receives FocusOut event, whether it is because the WM is grabbing the keyboard or because of an actual input focus change, we should release the pointer grab.
We will re-apply it on FocusIn event if it is necessary from Wine's perspective.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/event.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index a02f697a77d..9f0d68f26f8 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -896,6 +896,8 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) } if (!hwnd) return FALSE;
+ if (hwnd == GetForegroundWindow()) ungrab_clipping_window(); + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE;
We introduced unnecessary complexity by adding the last_clip_* state, we can instead use the ClipCursor state.
This restores the ClipCursor on FocusIn events by sending a WM_X11DRV_CLIP_CURSOR message to the foreground window, which will query the current clipping rect from the server and apply it.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/event.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 9f0d68f26f8..08b985107ce 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -801,6 +801,9 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == GetDesktopWindow()) return FALSE;
+ /* ask the foreground window to re-apply the current ClipCursor rect */ + SendMessageW( GetForegroundWindow(), WM_X11DRV_CLIP_CURSOR, 0, 0 ); + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE;