Module: wine Branch: master Commit: bd3ec1a973fef5ff46a6242aa4e04dd4b7a40799 URL: http://source.winehq.org/git/wine.git/?a=commit;h=bd3ec1a973fef5ff46a6242aa4...
Author: Alexandre Julliard julliard@winehq.org Date: Wed Apr 13 20:18:30 2011 +0200
winex11: Retrieve raw mouse events through XInput2 while the cursor is clipped.
---
dlls/winex11.drv/event.c | 2 +- dlls/winex11.drv/mouse.c | 178 +++++++++++++++++++++++++++++++++++++++- dlls/winex11.drv/x11drv.h | 3 + dlls/winex11.drv/x11drv_main.c | 1 + 4 files changed, 179 insertions(+), 5 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index d3ed4b0..62aea5e 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -795,7 +795,7 @@ static void X11DRV_MapNotify( HWND hwnd, XEvent *event ) */ static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event ) { - if (event->xany.window == clip_window) clipping_cursor = 0; + if (event->xany.window == clip_window) clipping_window_unmapped(); }
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index e3774dc..a1c913f 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -128,6 +128,17 @@ static XContext cursor_context; static RECT clip_rect; static Cursor create_cursor( HANDLE handle );
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H +static BOOL xinput2_available; +static int xinput2_opcode; +static int xinput2_core_pointer; +#define MAKE_FUNCPTR(f) static typeof(f) * p##f +MAKE_FUNCPTR(XIFreeDeviceInfo); +MAKE_FUNCPTR(XIQueryDevice); +MAKE_FUNCPTR(XIQueryVersion); +MAKE_FUNCPTR(XISelectEvents); +#undef MAKE_FUNCPTR +#endif
/*********************************************************************** * X11DRV_Xcursor_Init @@ -239,6 +250,124 @@ void sync_window_cursor( Window window ) }
/*********************************************************************** + * enable_xinput2 + */ +static void enable_xinput2(void) +{ +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + struct x11drv_thread_data *data = x11drv_thread_data(); + XIDeviceInfo *devices; + XIEventMask mask; + unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; + int i, count; + + if (!xinput2_available) return; + + if (data->xi2_state == xi_unknown) + { + int major = 2, minor = 0; + wine_tsx11_lock(); + if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; + else + { + data->xi2_state = xi_unavailable; + WARN( "X Input 2 not available\n" ); + } + wine_tsx11_unlock(); + } + if (data->xi2_state == xi_unavailable) return; + + wine_tsx11_lock(); + devices = pXIQueryDevice( data->display, XIAllDevices, &count ); + for (i = 0; i < count; ++i) + { + if (devices[i].use != XIMasterPointer) continue; + TRACE( "Using %u (%s) as core pointer\n", + devices[i].deviceid, debugstr_a(devices[i].name) ); + xinput2_core_pointer = devices[i].deviceid; + break; + } + + mask.mask = mask_bits; + mask.mask_len = sizeof(mask_bits); + memset( mask_bits, 0, sizeof(mask_bits) ); + + XISetMask( mask_bits, XI_RawButtonPress ); + XISetMask( mask_bits, XI_RawButtonRelease ); + XISetMask( mask_bits, XI_RawMotion ); + + for (i = 0; i < count; ++i) + { + if (devices[i].use == XISlavePointer && devices[i].attachment == xinput2_core_pointer) + { + TRACE( "Device %u (%s) is attached to the core pointer\n", + devices[i].deviceid, debugstr_a(devices[i].name) ); + mask.deviceid = devices[i].deviceid; + pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); + data->xi2_state = xi_enabled; + } + } + + pXIFreeDeviceInfo( devices ); + wine_tsx11_unlock(); +#endif +} + +/*********************************************************************** + * disable_xinput2 + */ +static void disable_xinput2(void) +{ +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + struct x11drv_thread_data *data = x11drv_thread_data(); + XIEventMask mask; + XIDeviceInfo *devices; + int i, count; + + if (data->xi2_state != xi_enabled) return; + + TRACE( "disabling\n" ); + data->xi2_state = xi_disabled; + + mask.mask = NULL; + mask.mask_len = 0; + + wine_tsx11_lock(); + devices = pXIQueryDevice( data->display, XIAllDevices, &count ); + for (i = 0; i < count; ++i) + { + if (devices[i].use == XISlavePointer && devices[i].attachment == xinput2_core_pointer) + { + mask.deviceid = devices[i].deviceid; + pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); + } + } + pXIFreeDeviceInfo( devices ); + wine_tsx11_unlock(); +#endif +} + +/*********************************************************************** + * clipping_window_unmapped + * + * Turn off clipping when the window got unmapped. + */ +void clipping_window_unmapped(void) +{ + struct x11drv_thread_data *data = x11drv_thread_data(); + + clipping_cursor = 0; + if (data->xi2_state == xi_enabled) + { + RECT rect; + GetClipCursor( &rect ); + if (EqualRect( &rect, &clip_rect )) return; /* still clipped */ + disable_xinput2(); + } +} + + +/*********************************************************************** * send_mouse_input * * Update the various window states on a mouse event. @@ -254,7 +383,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU { input->u.mi.dx += clip_rect.left; input->u.mi.dy += clip_rect.top; - __wine_send_input( hwnd, input ); + if (x11drv_thread_data()->xi2_state != xi_enabled) __wine_send_input( hwnd, input ); return; }
@@ -913,14 +1042,16 @@ void CDECL X11DRV_SetCursor( HCURSOR handle ) */ BOOL CDECL X11DRV_SetCursorPos( INT x, INT y ) { - Display *display = thread_init_display(); + struct x11drv_thread_data *data = x11drv_init_thread_data(); + + if (data->xi2_state == xi_enabled) return TRUE;
TRACE( "warping to (%d,%d)\n", x, y );
wine_tsx11_lock(); - XWarpPointer( display, root_window, root_window, 0, 0, 0, 0, + XWarpPointer( data->display, root_window, root_window, 0, 0, 0, 0, x - virtual_screen_rect.left, y - virtual_screen_rect.top ); - XFlush( display ); /* avoids bad mouse lag in games that do their own mouse warping */ + XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */ wine_tsx11_unlock(); return TRUE; } @@ -983,6 +1114,7 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip )
if (clipping_cursor) { + enable_xinput2(); sync_window_cursor( clip_window ); clip_rect = *clip; return TRUE; @@ -996,6 +1128,7 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ) XUnmapWindow( display, clip_window ); wine_tsx11_unlock(); clipping_cursor = 0; + disable_xinput2(); return TRUE; }
@@ -1175,6 +1308,42 @@ static void X11DRV_RawMotion( XIRawEvent *event )
/*********************************************************************** + * X11DRV_XInput2_Init + */ +void X11DRV_XInput2_Init(void) +{ +#if defined(SONAME_LIBXI) && defined(HAVE_X11_EXTENSIONS_XINPUT2_H) + int event, error; + void *libxi_handle = wine_dlopen( SONAME_LIBXI, RTLD_NOW, NULL, 0 ); + + if (!libxi_handle) + { + WARN( "couldn't load %s\n", SONAME_LIBXI ); + return; + } +#define LOAD_FUNCPTR(f) \ + if (!(p##f = wine_dlsym( libxi_handle, #f, NULL, 0))) \ + { \ + WARN("Failed to load %s.\n", #f); \ + return; \ + } + + LOAD_FUNCPTR(XIFreeDeviceInfo); + LOAD_FUNCPTR(XIQueryDevice); + LOAD_FUNCPTR(XIQueryVersion); + LOAD_FUNCPTR(XISelectEvents); +#undef LOAD_FUNCPTR + + wine_tsx11_lock(); + xinput2_available = XQueryExtension( gdi_display, "XInputExtension", &xinput2_opcode, &event, &error ); + wine_tsx11_unlock(); +#else + TRACE( "X Input 2 support not compiled in.\n" ); +#endif +} + + +/*********************************************************************** * X11DRV_GenericEvent */ void X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) @@ -1183,6 +1352,7 @@ void X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) XGenericEventCookie *event = &xev->xcookie;
if (!event->data) return; + if (event->extension != xinput2_opcode) return;
switch (event->evtype) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index ae91fc9..8d05e27 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -258,6 +258,7 @@ extern void X11DRV_OpenGL_Cleanup(void); extern void X11DRV_Xcursor_Init(void); extern void X11DRV_BITMAP_Init(void); extern void X11DRV_FONT_Init( int log_pixels_x, int log_pixels_y ); +extern void X11DRV_XInput2_Init(void);
extern int bitmap_info_size( const BITMAPINFO * info, WORD coloruse ); extern XImage *X11DRV_DIB_CreateXImage( int width, int height, int depth ); @@ -550,6 +551,7 @@ struct x11drv_thread_data XFontSet font_set; /* international text drawing font set */ Window selection_wnd; /* window used for selection interactions */ HKL kbd_layout; /* active keyboard layout */ + enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ };
extern struct x11drv_thread_data *x11drv_init_thread_data(void); @@ -823,6 +825,7 @@ extern void X11DRV_ResetSelectionOwner(void); extern void CDECL X11DRV_SetFocus( HWND hwnd ); extern void set_window_cursor( Window window, HCURSOR handle ); extern void sync_window_cursor( Window window ); +extern void clipping_window_unmapped(void); extern BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ); extern void X11DRV_InitKeyboard( Display *display ); extern DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 9ac20c3..cb6d793 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -595,6 +595,7 @@ static BOOL process_attach(void) #ifdef SONAME_LIBXCOMPOSITE X11DRV_XComposite_Init(); #endif + X11DRV_XInput2_Init();
#ifdef HAVE_XKB if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL );