This is in preparation for receiving XI2 touch events. The version change is necessary as the events aren't sent at all otherwise.
-- v2: winex11: Simplify XInput2 device valuator lookup. winex11: Always listen to XInput2 device changes events. winex11: Initialize XInput2 extension on every thread. winex11: Advertise XInput2 version 2.2 support. winex11: Process XInput2 events with QS_INPUT filter.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index aafb89a4fed..8b02361aaff 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -233,9 +233,6 @@ static Bool filter_event( Display *display, XEvent *event, char *arg ) case ButtonPress: case ButtonRelease: return (mask & QS_MOUSEBUTTON) != 0; -#ifdef GenericEvent - case GenericEvent: -#endif case MotionNotify: case EnterNotify: case LeaveNotify: @@ -250,6 +247,13 @@ static Bool filter_event( Display *display, XEvent *event, char *arg ) case PropertyNotify: case ClientMessage: return (mask & QS_POSTMESSAGE) != 0; +#ifdef GenericEvent + case GenericEvent: +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + if (event->xcookie.extension == xinput2_opcode) return (mask & QS_INPUT) != 0; +#endif + /* fallthrough */ +#endif default: return (mask & QS_SENDMESSAGE) != 0; }
From: Rémi Bernon rbernon@codeweavers.com
This is the required version for XInput2 touch events. It also allows to greatly simplify the code by listening to master device events only and get rid of device id tracking:
Under XInput2 protocol version < 2.1, RawEvents are not supposed to be sent if a pointer grab is active. However slave device events are still received regardless of this specification and Wine implemented a workaround to receive RawEvents during pointer grabs by listening to these slave device events.
By advertising the support of XInput2 version >= 2.1, where RawEvents are sent even during pointer grabs, we ensure to receive the RawMotion even if a mouse grab is active. --- dlls/winex11.drv/mouse.c | 50 +++++++-------------------------------- dlls/winex11.drv/x11drv.h | 5 +--- 2 files changed, 9 insertions(+), 46 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 612fff9995c..f02ca5355c5 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -268,7 +268,7 @@ static void enable_xinput2(void)
if (data->xi2_state == xi_unknown) { - int major = 2, minor = 0; + int major = 2, minor = 2; if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; else { @@ -277,11 +277,11 @@ static void enable_xinput2(void) } } if (data->xi2_state == xi_unavailable) return; - if (!pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) return; + if (!pXIGetClientPointer( data->display, None, &data->xinput2_pointer )) return;
mask.mask = mask_bits; mask.mask_len = sizeof(mask_bits); - mask.deviceid = XIAllDevices; + mask.deviceid = XIAllMasterDevices; memset( mask_bits, 0, sizeof(mask_bits) ); XISetMask( mask_bits, XI_DeviceChanged ); XISetMask( mask_bits, XI_RawMotion ); @@ -289,20 +289,10 @@ static void enable_xinput2(void)
pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
- pointer_info = pXIQueryDevice( data->display, data->xi2_core_pointer, &count ); + pointer_info = pXIQueryDevice( data->display, data->xinput2_pointer, &count ); update_relative_valuators( pointer_info->classes, pointer_info->num_classes ); pXIFreeDeviceInfo( pointer_info );
- /* This device info list is only used to find the initial current slave if - * no XI_DeviceChanged events happened. If any hierarchy change occurred that - * might be relevant here (eg. user switching mice after (un)plugging), a - * XI_DeviceChanged event will point us to the right slave. So this list is - * safe to be obtained statically at enable_xinput2() time. - */ - if (data->xi2_devices) pXIFreeDeviceInfo( data->xi2_devices ); - data->xi2_devices = pXIQueryDevice( data->display, XIAllDevices, &data->xi2_device_count ); - data->xi2_current_slave = 0; - data->xi2_state = xi_enabled; }
@@ -324,17 +314,14 @@ static void disable_xinput2(void)
mask.mask = NULL; mask.mask_len = 0; - mask.deviceid = XIAllDevices; + mask.deviceid = XIAllMasterDevices;
pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - pXIFreeDeviceInfo( data->xi2_devices ); data->x_valuator.number = -1; data->y_valuator.number = -1; data->x_valuator.value = 0; data->y_valuator.value = 0; - data->xi2_devices = NULL; - data->xi2_core_pointer = 0; - data->xi2_current_slave = 0; + data->xinput2_pointer = 0; #endif }
@@ -1643,11 +1630,8 @@ static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev ) XIDeviceChangedEvent *event = xev->data; struct x11drv_thread_data *data = x11drv_thread_data();
- if (event->deviceid != data->xi2_core_pointer) return FALSE; - if (event->reason != XISlaveSwitch) return FALSE; - + if (event->deviceid != data->xinput2_pointer) return FALSE; update_relative_valuators( event->classes, event->num_classes ); - data->xi2_current_slave = event->sourceid; return TRUE; }
@@ -1663,25 +1647,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) if (x->number < 0 || y->number < 0) return FALSE; if (!event->valuators.mask_len) return FALSE; if (thread_data->xi2_state != xi_enabled) return FALSE; - - /* If there is no slave currently detected, no previous motion nor device - * change events were received. Look it up now on the device list in this - * case. - */ - if (!thread_data->xi2_current_slave) - { - XIDeviceInfo *devices = thread_data->xi2_devices; - - for (i = 0; i < thread_data->xi2_device_count; i++) - { - if (devices[i].use != XISlavePointer) continue; - if (devices[i].deviceid != event->deviceid) continue; - if (devices[i].attachment != thread_data->xi2_core_pointer) continue; - thread_data->xi2_current_slave = event->deviceid; - break; - } - } - if (event->deviceid != thread_data->xi2_current_slave) return FALSE; + if (event->deviceid != thread_data->xinput2_pointer) return FALSE;
virtual_rect = NtUserGetVirtualScreenRect();
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index d5edb9ba377..dbf7d07e3d4 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -394,12 +394,9 @@ struct x11drv_thread_data BOOL clipping_cursor; /* whether thread is currently clipping the cursor */ #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ - void *xi2_devices; /* list of XInput2 devices (valid when state is enabled) */ - int xi2_device_count; XIValuatorClassInfo x_valuator; XIValuatorClassInfo y_valuator; - int xi2_core_pointer; /* XInput2 core pointer id */ - int xi2_current_slave; /* Current slave driving the Core pointer */ + int xinput2_pointer; /* XInput2 master pointer device id */ #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ };
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/mouse.c | 53 ++++++++++++++++++---------------- dlls/winex11.drv/x11drv.h | 5 ++-- dlls/winex11.drv/x11drv_main.c | 3 +- 3 files changed, 33 insertions(+), 28 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f02ca5355c5..3036f3db9e3 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -266,17 +266,6 @@ static void enable_xinput2(void)
if (!xinput2_available) return;
- if (data->xi2_state == xi_unknown) - { - int major = 2, minor = 2; - if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; - else - { - data->xi2_state = xi_unavailable; - WARN( "X Input 2 not available\n" ); - } - } - if (data->xi2_state == xi_unavailable) return; if (!pXIGetClientPointer( data->display, None, &data->xinput2_pointer )) return;
mask.mask = mask_bits; @@ -292,8 +281,6 @@ static void enable_xinput2(void) pointer_info = pXIQueryDevice( data->display, data->xinput2_pointer, &count ); update_relative_valuators( pointer_info->classes, pointer_info->num_classes ); pXIFreeDeviceInfo( pointer_info ); - - data->xi2_state = xi_enabled; }
#endif @@ -307,10 +294,7 @@ static void disable_xinput2(void) struct x11drv_thread_data *data = x11drv_thread_data(); XIEventMask mask;
- if (data->xi2_state != xi_enabled) return; - - TRACE( "disabling\n" ); - data->xi2_state = xi_disabled; + if (!xinput2_available) return;
mask.mask = NULL; mask.mask_len = 0; @@ -326,6 +310,26 @@ static void disable_xinput2(void) }
+/*********************************************************************** + * x11drv_xinput_init + */ +void x11drv_xinput2_init( struct x11drv_thread_data *data ) +{ +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + int major = 2, minor = 2; + + if (!xinput2_available || pXIQueryVersion( data->display, &major, &minor )) + { + WARN( "XInput 2.0 not available\n" ); + xinput2_available = FALSE; + return; + } + + TRACE( "XInput2 %d.%d available\n", major, minor ); +#endif +} + + /*********************************************************************** * grab_clipping_window * @@ -352,17 +356,16 @@ static BOOL grab_clipping_window( const RECT *clip ) WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); return FALSE; } - - /* enable XInput2 unless we are already clipping */ - if (!data->clipping_cursor) enable_xinput2(); - - if (data->xi2_state != xi_enabled) + if (!xinput2_available) { WARN( "XInput2 not supported, refusing to clip to %s\n", wine_dbgstr_rect(clip) ); NtUserClipCursor( NULL ); return TRUE; }
+ /* enable XInput2 unless we are already clipping */ + if (!data->clipping_cursor) enable_xinput2(); + TRACE( "clipping to %s win %lx\n", wine_dbgstr_rect(clip), clip_window );
if (!data->clipping_cursor) XUnmapWindow( data->display, clip_window ); @@ -1646,7 +1649,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input )
if (x->number < 0 || y->number < 0) return FALSE; if (!event->valuators.mask_len) return FALSE; - if (thread_data->xi2_state != xi_enabled) return FALSE; + if (!xinput2_available) return FALSE; if (event->deviceid != thread_data->xinput2_pointer) return FALSE;
virtual_rect = NtUserGetVirtualScreenRect(); @@ -1721,9 +1724,9 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
/*********************************************************************** - * X11DRV_XInput2_Init + * x11drv_xinput2_load */ -void X11DRV_XInput2_Init(void) +void x11drv_xinput2_load(void) { #if defined(SONAME_LIBXI) && defined(HAVE_X11_EXTENSIONS_XINPUT2_H) int event, error; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index dbf7d07e3d4..e8a87283fe2 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -263,7 +263,6 @@ extern void X11DRV_ThreadDetach(void); /* X11 driver internal functions */
extern void X11DRV_Xcursor_Init(void); -extern void X11DRV_XInput2_Init(void);
extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image, const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits, @@ -393,7 +392,6 @@ struct x11drv_thread_data Window clip_window; /* window used for cursor clipping */ BOOL clipping_cursor; /* whether thread is currently clipping the cursor */ #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ XIValuatorClassInfo x_valuator; XIValuatorClassInfo y_valuator; int xinput2_pointer; /* XInput2 master pointer device id */ @@ -575,6 +573,9 @@ extern BOOL X11DRV_MappingNotify( HWND hWnd, XEvent *event ); extern BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *event );
extern int xinput2_opcode; +extern void x11drv_xinput2_load(void); +extern void x11drv_xinput2_init( struct x11drv_thread_data *data ); + extern Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ); extern void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event );
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 25a36cb8c0c..097dd9c3dc8 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -697,7 +697,7 @@ static NTSTATUS x11drv_init( void *arg ) #ifdef SONAME_LIBXCOMPOSITE X11DRV_XComposite_Init(); #endif - X11DRV_XInput2_Init(); + x11drv_xinput2_load();
XkbUseExtension( gdi_display, NULL, NULL ); X11DRV_InitKeyboard( gdi_display ); @@ -786,6 +786,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) NtUserGetThreadInfo()->driver_data = (UINT_PTR)data;
if (use_xim) xim_thread_attach( data ); + x11drv_xinput2_init( data );
return data; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/mouse.c | 41 +++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 3036f3db9e3..143837adede 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -260,14 +260,10 @@ static void enable_xinput2(void) { struct x11drv_thread_data *data = x11drv_thread_data(); XIEventMask mask; - XIDeviceInfo *pointer_info; unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; - int count;
if (!xinput2_available) return;
- if (!pXIGetClientPointer( data->display, None, &data->xinput2_pointer )) return; - mask.mask = mask_bits; mask.mask_len = sizeof(mask_bits); mask.deviceid = XIAllMasterDevices; @@ -275,12 +271,7 @@ static void enable_xinput2(void) XISetMask( mask_bits, XI_DeviceChanged ); XISetMask( mask_bits, XI_RawMotion ); XISetMask( mask_bits, XI_ButtonPress ); - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - - pointer_info = pXIQueryDevice( data->display, data->xinput2_pointer, &count ); - update_relative_valuators( pointer_info->classes, pointer_info->num_classes ); - pXIFreeDeviceInfo( pointer_info ); }
#endif @@ -292,20 +283,17 @@ static void disable_xinput2(void) { #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H struct x11drv_thread_data *data = x11drv_thread_data(); + unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; XIEventMask mask;
if (!xinput2_available) return;
- mask.mask = NULL; - mask.mask_len = 0; + mask.mask = mask_bits; + mask.mask_len = sizeof(mask_bits); mask.deviceid = XIAllMasterDevices; - + memset( mask_bits, 0, sizeof(mask_bits) ); + XISetMask( mask_bits, XI_DeviceChanged ); pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - data->x_valuator.number = -1; - data->y_valuator.number = -1; - data->x_valuator.value = 0; - data->y_valuator.value = 0; - data->xinput2_pointer = 0; #endif }
@@ -316,7 +304,10 @@ static void disable_xinput2(void) void x11drv_xinput2_init( struct x11drv_thread_data *data ) { #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; int major = 2, minor = 2; + XIEventMask mask; + int count;
if (!xinput2_available || pXIQueryVersion( data->display, &major, &minor )) { @@ -325,6 +316,22 @@ void x11drv_xinput2_init( struct x11drv_thread_data *data ) return; }
+ mask.mask = mask_bits; + mask.mask_len = sizeof(mask_bits); + mask.deviceid = XIAllMasterDevices; + memset( mask_bits, 0, sizeof(mask_bits) ); + XISetMask( mask_bits, XI_DeviceChanged ); + pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); + + if (!pXIGetClientPointer( data->display, None, &data->xinput2_pointer )) + WARN( "Failed to get xinput2 master pointer device\n" ); + else + { + XIDeviceInfo *pointer_info = pXIQueryDevice( data->display, data->xinput2_pointer, &count ); + update_relative_valuators( pointer_info->classes, pointer_info->num_classes ); + pXIFreeDeviceInfo( pointer_info ); + } + TRACE( "XInput2 %d.%d available\n", major, minor ); #endif }
From: Rémi Bernon rbernon@codeweavers.com
Valuator names aren't well specified, and although they are usually named "Rel X/Y" or "Abs X/Y", there are cases where the names are different.
Lets just assume that the first two valuators are the X/Y axes, as it seems to be generally the case. --- dlls/winex11.drv/mouse.c | 21 ++++++++++----------- dlls/winex11.drv/x11drv.h | 2 -- dlls/winex11.drv/x11drv_main.c | 2 -- 3 files changed, 10 insertions(+), 15 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 143837adede..bdbd559b107 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -228,26 +228,25 @@ void set_window_cursor( Window window, HCURSOR handle ) /*********************************************************************** * update_relative_valuators */ -static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuators) +static void update_relative_valuators( XIAnyClassInfo **classes, int num_classes ) { struct x11drv_thread_data *thread_data = x11drv_thread_data(); - int i; + XIValuatorClassInfo *valuator;
thread_data->x_valuator.number = -1; thread_data->y_valuator.number = -1;
- for (i = 0; i < n_valuators; i++) + while (num_classes--) { - XIValuatorClassInfo *class = (XIValuatorClassInfo *)valuators[i]; - if (valuators[i]->type != XIValuatorClass) continue; - if (class->label == x11drv_atom( Rel_X ) || - (!class->label && class->number == 0 && class->mode == XIModeRelative)) - thread_data->x_valuator = *class; - else if (class->label == x11drv_atom( Rel_Y ) || - (!class->label && class->number == 1 && class->mode == XIModeRelative)) - thread_data->y_valuator = *class; + valuator = (XIValuatorClassInfo *)classes[num_classes]; + if (classes[num_classes]->type != XIValuatorClass) continue; + if (valuator->number == 0 && valuator->mode == XIModeRelative) thread_data->x_valuator = *valuator; + if (valuator->number == 1 && valuator->mode == XIModeRelative) thread_data->y_valuator = *valuator; }
+ if (thread_data->x_valuator.number < 0 || thread_data->y_valuator.number < 0) + WARN( "X/Y axis valuators not found, ignoring RawMotion events\n" ); + thread_data->x_valuator.value = 0; thread_data->y_valuator.value = 0; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index e8a87283fe2..71a3582ff76 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -471,8 +471,6 @@ enum x11drv_atoms XATOM_RAW_ASCENT, XATOM_RAW_DESCENT, XATOM_RAW_CAP_HEIGHT, - XATOM_Rel_X, - XATOM_Rel_Y, XATOM_WM_PROTOCOLS, XATOM_WM_DELETE_WINDOW, XATOM_WM_STATE, diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 097dd9c3dc8..0925fe54b9c 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -142,8 +142,6 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "RAW_ASCENT", "RAW_DESCENT", "RAW_CAP_HEIGHT", - "Rel X", - "Rel Y", "WM_PROTOCOLS", "WM_DELETE_WINDOW", "WM_STATE",
v2: Also remove the now unnecessary X11 atoms.
Test failure is in ntdll:threadpool, unrelated.