From: Rémi Bernon rbernon@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;