From: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/winex11.drv/event.c | 183 ++++++++++++++++++---------------------
1 file changed, 84 insertions(+), 99 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index 79b5cbe501b..87a1b111fe0 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -300,54 +300,100 @@ static BOOL handle_delayed_event( Display *display, XEvent *event
)
return queued;
}
-enum event_merge_action
+static BOOL is_mergeable_raw_motion( XEvent *event )
{
- MERGE_DISCARD, /* discard the old event */
- MERGE_HANDLE, /* handle the old event */
- MERGE_KEEP, /* keep the old event for future merging */
- MERGE_IGNORE /* ignore the new event, keep the old one */
-};
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
+ if (event->type != GenericEvent) return FALSE;
+ if (event->xcookie.extension != xinput2_opcode) return FALSE;
+ if (event->xcookie.evtype != XI_RawMotion) return FALSE;
+ if (x11drv_thread_data()->warp_serial) return FALSE;
+ return TRUE;
+#endif
+ return FALSE;
+}
-/***********************************************************************
- * merge_raw_motion_events
- */
#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
-static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent
*next )
+static void merge_xi_valuator_states( XIValuatorState *dst, const XIValuatorState *src
)
{
int i, j, k;
+ for (i = j = k = 0; i < 8; i++)
+ {
+ if (XIMaskIsSet( src->mask, i )) dst->values[j] += src->values[k++];
+ if (XIMaskIsSet( dst->mask, i )) j++;
+ }
+}
+
+static int merge_xi_raw_events( XIRawEvent *prev, XIRawEvent *next )
+{
unsigned char mask;
- if (!prev->valuators.mask_len) return MERGE_HANDLE;
- if (!next->valuators.mask_len) return MERGE_HANDLE;
+ if (!prev->valuators.mask_len) return 1; /* keep next */
+ if (!next->valuators.mask_len) return -1; /* keep prev */
mask = prev->valuators.mask[0] | next->valuators.mask[0];
- if (mask == next->valuators.mask[0]) /* keep next */
+ if (mask == next->valuators.mask[0])
{
- for (i = j = k = 0; i < 8; i++)
- {
- if (XIMaskIsSet( prev->valuators.mask, i ))
- next->valuators.values[j] += prev->valuators.values[k++];
- if (XIMaskIsSet( next->valuators.mask, i )) j++;
- }
- TRACE( "merging duplicate GenericEvent\n" );
- return MERGE_DISCARD;
+ merge_xi_valuator_states( &next->valuators, &prev->valuators );
+ return 1; /* keep next */
}
- if (mask == prev->valuators.mask[0]) /* keep prev */
+ if (mask == prev->valuators.mask[0])
{
- for (i = j = k = 0; i < 8; i++)
- {
- if (XIMaskIsSet( next->valuators.mask, i ))
- prev->valuators.values[j] += next->valuators.values[k++];
- if (XIMaskIsSet( prev->valuators.mask, i )) j++;
- }
- TRACE( "merging duplicate GenericEvent\n" );
- return MERGE_IGNORE;
+ merge_xi_valuator_states( &prev->valuators, &next->valuators );
+ return -1; /* keep prev */
}
/* can't merge events with disjoint masks */
- return MERGE_HANDLE;
+ return 0;
}
#endif
+/* merge XIRawEvent events when process or wineserver don't keep up */
+static BOOL merge_raw_motion_events( Display *display, XEvent *prev, XEvent *next )
+{
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
+ BOOL queued = FALSE;
+ int ret;
+
+ /* allow merging XI_RawMotion across MotionNotify events */
+ if (next->type == MotionNotify) return FALSE;
+ if (!is_mergeable_raw_motion( next )) return handle_delayed_event( display, prev );
+
+ if (!is_mergeable_raw_motion( prev )) ret = 0;
+ else ret = merge_xi_raw_events( prev->xcookie.data, next->xcookie.data );
+
+ if (!ret) queued |= handle_delayed_event( display, prev );
+ else
+ {
+ WARN( "discarding duplicate XIRawEvent for window %lx\n",
next->xany.window );
+ if (ret != -1) free_event_data( prev );
+ else free_event_data( next );
+ }
+
+ TRACE( "delaying XIRawEvent for window %lx for merging\n",
next->xany.window );
+ if (ret != -1) *prev = *next;
+ next->type = 0;
+ return queued;
+#endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */
+ return FALSE;
+}
+
+/* merge MotionNotify events when process or wineserver don't keep up */
+static BOOL merge_motion_events( Display *display, XEvent *prev, XEvent *next )
+{
+ BOOL queued = FALSE;
+
+ /* allow merging MotionNotify across XI_RawMotion events */
+ if (is_mergeable_raw_motion( next )) return FALSE;
+ if (next->type != MotionNotify) return handle_delayed_event( display, prev );
+
+ if (!prev->type || prev->xany.window != next->xany.window) queued |=
handle_delayed_event( display, prev );
+ else WARN( "discarding duplicate MotionNotify for window %lx\n",
next->xany.window );
+
+ TRACE( "delaying MotionNotify for window %lx for merging\n",
next->xany.window );
+ *prev = *next;
+ next->type = 0;
+ return queued;
+}
+
/* merge ConfigureNotify events to reduce the chances of window resize feedback loops
*/
static BOOL merge_configure_events( Display *display, XEvent *prev, XEvent *next )
{
@@ -366,68 +412,21 @@ static BOOL merge_configure_events( Display *display, XEvent *prev,
XEvent *next
return queued;
}
-/***********************************************************************
- * merge_events
- *
- * Try to merge 2 consecutive events.
- */
-static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
-{
- switch (prev->type)
- {
- case MotionNotify:
- switch (next->type)
- {
- case MotionNotify:
- if (prev->xany.window == next->xany.window)
- {
- TRACE( "discarding duplicate MotionNotify for window %lx\n",
prev->xany.window );
- return MERGE_DISCARD;
- }
- break;
-#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
- case GenericEvent:
- if (next->xcookie.extension != xinput2_opcode) break;
- if (next->xcookie.evtype != XI_RawMotion) break;
- if (x11drv_thread_data()->warp_serial) break;
- return MERGE_KEEP;
- }
- break;
- case GenericEvent:
- if (prev->xcookie.extension != xinput2_opcode) break;
- if (prev->xcookie.evtype != XI_RawMotion) break;
- switch (next->type)
- {
- case GenericEvent:
- if (next->xcookie.extension != xinput2_opcode) break;
- if (next->xcookie.evtype != XI_RawMotion) break;
- if (x11drv_thread_data()->warp_serial) break;
- return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data
);
-#endif
- }
- break;
- }
- return MERGE_HANDLE;
-}
-
-
/***********************************************************************
* ProcessEvents (X11DRV.@)
*/
BOOL X11DRV_ProcessEvents( DWORD mask )
{
- XEvent event, prev_configure = {0}, prev_event;
+ XEvent event, prev_configure = {0}, prev_motion = {0}, prev_raw_motion = {0};
struct x11drv_thread_data *thread_data;
Display *display;
int count = 0;
BOOL queued = FALSE;
- enum event_merge_action action = MERGE_DISCARD;
if (!(thread_data = x11drv_thread_data())) return FALSE;
if (thread_data->current_event) mask = 0; /* don't process nested events */
display = thread_data->display;
- prev_event.type = 0;
while (XCheckIfEvent( display, &event, filter_event, (XPointer)(UINT_PTR)mask
))
{
count++;
@@ -463,28 +462,14 @@ BOOL X11DRV_ProcessEvents( DWORD mask )
}
get_event_data( &event );
queued |= merge_configure_events( display, &prev_configure, &event );
- if (!event.type) action = MERGE_IGNORE;
- else if (prev_event.type) action = merge_events( &prev_event, &event );
- switch( action )
- {
- case MERGE_HANDLE: /* handle prev, keep new */
- queued |= handle_delayed_event( display, &prev_event );
- prev_event = event;
- break;
- case MERGE_DISCARD: /* discard prev, keep new */
- free_event_data( &prev_event );
- prev_event = event;
- break;
- case MERGE_KEEP: /* handle new, keep prev for future merging */
- queued |= call_event_handler( display, &event );
- /* fall through */
- case MERGE_IGNORE: /* ignore new, keep prev for future merging */
- free_event_data( &event );
- break;
- }
+ if (event.type) queued |= merge_raw_motion_events( display, &prev_raw_motion,
&event );
+ if (event.type) queued |= merge_motion_events( display, &prev_motion,
&event );
+ if (event.type) queued |= call_event_handler( display, &event );
+ free_event_data( &event );
}
queued |= handle_delayed_event( display, &prev_configure );
- queued |= handle_delayed_event( display, &prev_event );
+ queued |= handle_delayed_event( display, &prev_raw_motion );
+ queued |= handle_delayed_event( display, &prev_motion );
XFlush( gdi_display );
if (count) TRACE( "processed %d events, returning %d\n", count, queued );
return queued;
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/2698