[PATCH v3 03/10] winex11.drv: Wait for the WM to release the cursor before handling FocusIn events.
Rémi Bernon
rbernon at codeweavers.com
Mon Oct 7 08:02:09 CDT 2019
The FocusIn/WM_TAKE_FOCUS events are sent as soon as a window title bar
is clicked, but sometimes the WM is still controlling the window
position. Waiting for the cursor grab to be released before sending
WM_ACTIVATE message helps solving this situation.
We pass through any NotifyGrab/NotifyUngrab focus events unless we are
delaying a FocusIn event. In this case, we have to merge these
notifications to reproduce the keyboard grab state as we cannot process
them out of order.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/winex11.drv/event.c | 64 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 62 insertions(+), 2 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index 0fb91265a69..055125533cd 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -314,15 +314,75 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE
}
#endif
+static int try_grab_pointer( Display *display )
+{
+ if (clipping_cursor)
+ return 1;
+
+ if (XGrabPointer( display, root_window, False, 0, GrabModeAsync, GrabModeAsync,
+ None, None, CurrentTime ) != GrabSuccess)
+ return 0;
+
+ XUngrabPointer( display, CurrentTime );
+ return 1;
+}
+
/***********************************************************************
* merge_events
*
* Try to merge 2 consecutive events.
*/
-static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
+static enum event_merge_action merge_events( Display *display, XEvent *prev, XEvent *next )
{
switch (prev->type)
{
+ case FocusIn:
+ if (root_window != DefaultRootWindow( display ))
+ break;
+ if (prev->xfocus.detail == NotifyPointer || prev->xfocus.detail == NotifyPointerRoot)
+ break;
+ if (prev->xfocus.mode == NotifyGrab || prev->xfocus.mode == NotifyUngrab)
+ break;
+
+ switch (next->type)
+ {
+ case FocusIn:
+ case FocusOut:
+ if (next->xfocus.detail == NotifyPointer || next->xfocus.detail == NotifyPointerRoot)
+ return MERGE_KEEP;
+ if (prev->xany.window != next->xany.window)
+ break;
+
+ /* merge grab notifications with the delayed focus event */
+ if (next->xfocus.mode == NotifyGrab)
+ {
+ prev->xfocus.mode = NotifyWhileGrabbed;
+ return MERGE_IGNORE;
+ }
+ else if (next->xfocus.mode == NotifyUngrab)
+ {
+ prev->xfocus.mode = NotifyNormal;
+ return MERGE_IGNORE;
+ }
+
+ if (next->type == FocusOut)
+ {
+ prev->type = 0; /* FocusIn/FocusOut sequence, discard prev as well */
+ TRACE( "Discarding FocusIn/FocusOut sequence for window %lx\n", prev->xany.window );
+ return MERGE_IGNORE;
+ }
+ else
+ {
+ TRACE( "Discarding old FocusIn event for window %lx\n", prev->xany.window );
+ return MERGE_DISCARD;
+ }
+ }
+
+ if (try_grab_pointer( display ))
+ break;
+
+ TRACE( "Unable to grab pointer yet, delaying FocusIn event\n" );
+ return MERGE_KEEP;
case ConfigureNotify:
switch (next->type)
{
@@ -409,7 +469,7 @@ static inline BOOL merge_and_handle_events( Display *display, XEvent *prev, XEve
enum event_merge_action action = MERGE_DISCARD;
BOOL queued = FALSE;
- if (prev->type) action = merge_events( prev, next );
+ if (prev->type) action = merge_events( display, prev, next );
switch( action )
{
case MERGE_HANDLE: /* handle prev, keep new */
--
2.23.0
More information about the wine-devel
mailing list