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+ function on macOS 10.12+
- [Cocoa] Bugfix: Running in AppSandbox would emit warnings (#816,#882) - [Cocoa] Bugfix: Running in AppSandbox would emit warnings (#816,#882)
- [Cocoa] Bugfix: Windows created after the first were not cascaded (#195) - [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] Added support for `EGL_KHR_get_all_proc_addresses` (#871)
- [EGL] Bugfix: The test for `EGL_RGB_BUFFER` was invalid - [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.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 // Check for RandR extension
if (XRRQueryExtension(_glfw.x11.display, if (XRRQueryExtension(_glfw.x11.display,
&_glfw.x11.randr.eventBase, &_glfw.x11.randr.eventBase,

View File

@ -47,6 +47,9 @@
// The Xinerama extension provides legacy monitor indices // The Xinerama extension provides legacy monitor indices
#include <X11/extensions/Xinerama.h> #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_window_t;
typedef XID xcb_visualid_t; typedef XID xcb_visualid_t;
typedef struct xcb_connection_t xcb_connection_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 XF86VidModeSetGammaRamp _glfw.x11.vidmode.SetGammaRamp
#define XF86VidModeGetGammaRampSize _glfw.x11.vidmode.GetGammaRampSize #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 VkXlibSurfaceCreateFlagsKHR;
typedef VkFlags VkXcbSurfaceCreateFlagsKHR; typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
@ -269,6 +277,18 @@ typedef struct _GLFWlibraryX11
PFN_XF86VidModeGetGammaRampSize GetGammaRampSize; PFN_XF86VidModeGetGammaRampSize GetGammaRampSize;
} vidmode; } vidmode;
struct {
GLFWbool available;
void* handle;
int majorOpcode;
int eventBase;
int errorBase;
int major;
int minor;
PFN_XIQueryVersion QueryVersion;
PFN_XISelectEvents SelectEvents;
} xi;
} _GLFWlibraryX11; } _GLFWlibraryX11;
// X11-specific per-monitor data // 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 (_glfw.x11.xi.available)
if (window == NULL)
{ {
// This is an event for a window that has already been destroyed _GLFWwindow* window = _glfw.x11.disabledCursorWindow;
return;
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) switch (event->type)
@ -1170,6 +1204,8 @@ static void processEvent(XEvent *event)
{ {
if (_glfw.x11.disabledCursorWindow != window) if (_glfw.x11.disabledCursorWindow != window)
return; return;
if (_glfw.x11.xi.available)
return;
const int dx = x - window->x11.lastCursorPosX; const int dx = x - window->x11.lastCursorPosX;
const int dy = y - window->x11.lastCursorPosY; const int dy = y - window->x11.lastCursorPosY;
@ -2157,6 +2193,8 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
void _glfwPlatformPollEvents(void) void _glfwPlatformPollEvents(void)
{ {
_GLFWwindow* window;
#if defined(__linux__) #if defined(__linux__)
_glfwDetectJoystickConnectionLinux(); _glfwDetectJoystickConnectionLinux();
#endif #endif
@ -2168,8 +2206,20 @@ void _glfwPlatformPollEvents(void)
processEvent(&event); processEvent(&event);
} }
if (_glfw.x11.disabledCursorWindow) window = _glfw.x11.disabledCursorWindow;
centerCursor(_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); XFlush(_glfw.x11.display);
} }
@ -2239,6 +2289,19 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{ {
if (mode == GLFW_CURSOR_DISABLED) 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; _glfw.x11.disabledCursorWindow = window;
_glfwPlatformGetCursorPos(window, _glfwPlatformGetCursorPos(window,
&_glfw.x11.restoreCursorPosX, &_glfw.x11.restoreCursorPosX,
@ -2253,6 +2316,18 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
} }
else if (_glfw.x11.disabledCursorWindow == window) 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; _glfw.x11.disabledCursorWindow = NULL;
XUngrabPointer(_glfw.x11.display, CurrentTime); XUngrabPointer(_glfw.x11.display, CurrentTime);
_glfwPlatformSetCursorPos(window, _glfwPlatformSetCursorPos(window,