X11: Use XI_RawMotion for disabled cursor motion

Related to #125.
This commit is contained in:
Camilla Löwy 2017-01-12 20:31:59 +01:00
parent 918b4e81d2
commit a570d0a129
4 changed files with 129 additions and 7 deletions

View File

@ -168,6 +168,7 @@ information on what to include when reporting a bug.
function on macOS 10.12+
- [Cocoa] Bugfix: Running in AppSandbox would emit warnings (#816,#882)
- [Cocoa] Bugfix: Windows created after the first were not cascaded (#195)
- [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125)
- [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871)
- [EGL] Bugfix: The test for `EGL_RGB_BUFFER` was invalid

View File

@ -477,6 +477,32 @@ static GLFWbool initExtensions(void)
&_glfw.x11.vidmode.errorBase);
}
_glfw.x11.xi.handle = dlopen("libXi.so", RTLD_LAZY | RTLD_GLOBAL);
if (_glfw.x11.xi.handle)
{
_glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion)
dlsym(_glfw.x11.xi.handle, "XIQueryVersion");
_glfw.x11.xi.SelectEvents = (PFN_XISelectEvents)
dlsym(_glfw.x11.xi.handle, "XISelectEvents");
if (XQueryExtension(_glfw.x11.display,
"XInputExtension",
&_glfw.x11.xi.majorOpcode,
&_glfw.x11.xi.eventBase,
&_glfw.x11.xi.errorBase))
{
_glfw.x11.xi.major = 2;
_glfw.x11.xi.minor = 0;
if (XIQueryVersion(_glfw.x11.display,
&_glfw.x11.xi.major,
&_glfw.x11.xi.minor) == Success)
{
_glfw.x11.xi.available = GLFW_TRUE;
}
}
}
// Check for RandR extension
if (XRRQueryExtension(_glfw.x11.display,
&_glfw.x11.randr.eventBase,

View File

@ -47,6 +47,9 @@
// The Xinerama extension provides legacy monitor indices
#include <X11/extensions/Xinerama.h>
// The XInput extension provides raw mouse motion input
#include <X11/extensions/XInput2.h>
typedef XID xcb_window_t;
typedef XID xcb_visualid_t;
typedef struct xcb_connection_t xcb_connection_t;
@ -61,6 +64,11 @@ typedef Bool (* PFN_XF86VidModeGetGammaRampSize)(Display*,int,int*);
#define XF86VidModeSetGammaRamp _glfw.x11.vidmode.SetGammaRamp
#define XF86VidModeGetGammaRampSize _glfw.x11.vidmode.GetGammaRampSize
typedef Status (* PFN_XIQueryVersion)(Display*,int*,int*);
typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
#define XIQueryVersion _glfw.x11.xi.QueryVersion
#define XISelectEvents _glfw.x11.xi.SelectEvents
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
@ -269,6 +277,18 @@ typedef struct _GLFWlibraryX11
PFN_XF86VidModeGetGammaRampSize GetGammaRampSize;
} vidmode;
struct {
GLFWbool available;
void* handle;
int majorOpcode;
int eventBase;
int errorBase;
int major;
int minor;
PFN_XIQueryVersion QueryVersion;
PFN_XISelectEvents SelectEvents;
} xi;
} _GLFWlibraryX11;
// X11-specific per-monitor data

View File

@ -920,14 +920,48 @@ static void processEvent(XEvent *event)
}
}
if (event->type != GenericEvent)
if (event->type == GenericEvent)
{
window = findWindowByHandle(event->xany.window);
if (window == NULL)
if (_glfw.x11.xi.available)
{
// This is an event for a window that has already been destroyed
return;
_GLFWwindow* window = _glfw.x11.disabledCursorWindow;
if (window &&
event->xcookie.extension == _glfw.x11.xi.majorOpcode &&
XGetEventData(_glfw.x11.display, &event->xcookie) &&
event->xcookie.evtype == XI_RawMotion)
{
XIRawEvent* re = event->xcookie.data;
if (re->valuators.mask_len)
{
const double* values = re->raw_values;
double xpos = window->virtualCursorPosX;
double ypos = window->virtualCursorPosY;
if (XIMaskIsSet(re->valuators.mask, 0))
{
xpos += *values;
values++;
}
if (XIMaskIsSet(re->valuators.mask, 1))
ypos += *values;
_glfwInputCursorPos(window, xpos, ypos);
}
}
XFreeEventData(_glfw.x11.display, &event->xcookie);
}
return;
}
window = findWindowByHandle(event->xany.window);
if (window == NULL)
{
// This is an event for a window that has already been destroyed
return;
}
switch (event->type)
@ -1170,6 +1204,8 @@ static void processEvent(XEvent *event)
{
if (_glfw.x11.disabledCursorWindow != window)
return;
if (_glfw.x11.xi.available)
return;
const int dx = x - window->x11.lastCursorPosX;
const int dy = y - window->x11.lastCursorPosY;
@ -2157,6 +2193,8 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
void _glfwPlatformPollEvents(void)
{
_GLFWwindow* window;
#if defined(__linux__)
_glfwDetectJoystickConnectionLinux();
#endif
@ -2168,8 +2206,20 @@ void _glfwPlatformPollEvents(void)
processEvent(&event);
}
if (_glfw.x11.disabledCursorWindow)
centerCursor(_glfw.x11.disabledCursorWindow);
window = _glfw.x11.disabledCursorWindow;
if (window)
{
int width, height;
_glfwPlatformGetWindowSize(window, &width, &height);
// NOTE: Re-center the cursor only if it has moved since the last call,
// to avoid breaking glfwWaitEvents with MotionNotify
if (window->x11.lastCursorPosX != width / 2 ||
window->x11.lastCursorPosY != height / 2)
{
_glfwPlatformSetCursorPos(window, width / 2, height / 2);
}
}
XFlush(_glfw.x11.display);
}
@ -2239,6 +2289,19 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{
if (mode == GLFW_CURSOR_DISABLED)
{
if (_glfw.x11.xi.available)
{
XIEventMask em;
unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
em.deviceid = XIAllMasterDevices;
em.mask_len = sizeof(mask);
em.mask = mask;
XISetMask(mask, XI_RawMotion);
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
}
_glfw.x11.disabledCursorWindow = window;
_glfwPlatformGetCursorPos(window,
&_glfw.x11.restoreCursorPosX,
@ -2253,6 +2316,18 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
}
else if (_glfw.x11.disabledCursorWindow == window)
{
if (_glfw.x11.xi.available)
{
XIEventMask em;
unsigned char mask[] = { 0 };
em.deviceid = XIAllMasterDevices;
em.mask_len = sizeof(mask);
em.mask = mask;
XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
}
_glfw.x11.disabledCursorWindow = NULL;
XUngrabPointer(_glfw.x11.display, CurrentTime);
_glfwPlatformSetCursorPos(window,