x11: Optimize SDL_GetGlobalMouseState() a little.

Use XInput2 to mark the global mouse state as dirty so we don't have to make
a bunch of roundtrips to the X server when nothing has changed.
Ryan C. Gordon 2015-04-22 16:50:48 -04:00
parent 14e007772a
commit 8875a4014f
4 changed files with 51 additions and 22 deletions

View File

@ -366,39 +366,52 @@ X11_CaptureMouse(SDL_Window *window)
static Uint32 static Uint32
X11_GetGlobalMouseState(int *x, int *y) X11_GetGlobalMouseState(int *x, int *y)
{ {
SDL_VideoData *videodata = (SDL_VideoData *) SDL_GetVideoDevice()->driverdata;
Display *display = GetDisplay(); Display *display = GetDisplay();
const int num_screens = SDL_GetNumVideoDisplays(); const int num_screens = SDL_GetNumVideoDisplays();
int i; int i;
/* !!! FIXME: should we XSync() here first? */ /* !!! FIXME: should we XSync() here first? */
for (i = 0; i < num_screens; i++) { #if !SDL_VIDEO_DRIVER_X11_XINPUT2
SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i); videodata->global_mouse_changed = SDL_TRUE;
if (data != NULL) { #endif
Window root, child;
int rootx, rooty, winx, winy; /* check if we have this cached since XInput last saw the mouse move. */
unsigned int mask; /* !!! FIXME: can we just calculate this from XInput's events? */
if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) { if (videodata->global_mouse_changed) {
XWindowAttributes root_attrs; for (i = 0; i < num_screens; i++) {
Uint32 retval = 0; SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i);
retval |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0; if (data != NULL) {
retval |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0; Window root, child;
retval |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0; int rootx, rooty, winx, winy;
/* SDL_DisplayData->x,y point to screen origin, and adding them to mouse coordinates relative to root window doesn't do the right thing unsigned int mask;
* (observed on dual monitor setup with primary display being the rightmost one - mouse was offset to the right). if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) {
* XWindowAttributes root_attrs;
* Adding root position to root-relative coordinates seems to be a better way to get absolute position. */ Uint32 buttons = 0;
X11_XGetWindowAttributes(display, root, &root_attrs); buttons |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0;
*x = root_attrs.x + rootx; buttons |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0;
*y = root_attrs.y + rooty; buttons |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0;
return retval; /* SDL_DisplayData->x,y point to screen origin, and adding them to mouse coordinates relative to root window doesn't do the right thing
* (observed on dual monitor setup with primary display being the rightmost one - mouse was offset to the right).
*
* Adding root position to root-relative coordinates seems to be a better way to get absolute position. */
X11_XGetWindowAttributes(display, root, &root_attrs);
videodata->global_mouse_position.x = root_attrs.x + rootx;
videodata->global_mouse_position.y = root_attrs.y + rooty;
videodata->global_mouse_buttons = buttons;
videodata->global_mouse_changed = SDL_FALSE;
break;
}
} }
} }
} }
SDL_assert(0 && "The pointer wasn't on any X11 screen?!"); SDL_assert(!videodata->global_mouse_changed); /* The pointer wasn't on any X11 screen?! */
return 0; *x = videodata->global_mouse_position.x;
*y = videodata->global_mouse_position.y;
return videodata->global_mouse_buttons;
} }

View File

@ -175,6 +175,8 @@ X11_CreateDevice(int devindex)
} }
device->driverdata = data; device->driverdata = data;
data->global_mouse_changed = SDL_TRUE;
/* FIXME: Do we need this? /* FIXME: Do we need this?
if ( (SDL_strncmp(X11_XDisplayName(display), ":", 1) == 0) || if ( (SDL_strncmp(X11_XDisplayName(display), ":", 1) == 0) ||
(SDL_strncmp(X11_XDisplayName(display), "unix:", 5) == 0) ) { (SDL_strncmp(X11_XDisplayName(display), "unix:", 5) == 0) ) {

View File

@ -118,6 +118,10 @@ typedef struct SDL_VideoData
SDL_bool selection_waiting; SDL_bool selection_waiting;
Uint32 last_mode_change_deadline; Uint32 last_mode_change_deadline;
SDL_bool global_mouse_changed;
SDL_Point global_mouse_position;
Uint32 global_mouse_buttons;
} SDL_VideoData; } SDL_VideoData;
extern SDL_bool X11_UseDirectColorVisuals(void); extern SDL_bool X11_UseDirectColorVisuals(void);

View File

@ -118,6 +118,8 @@ X11_InitXinput2(_THIS)
eventmask.mask = mask; eventmask.mask = mask;
XISetMask(mask, XI_RawMotion); XISetMask(mask, XI_RawMotion);
XISetMask(mask, XI_RawButtonPress);
XISetMask(mask, XI_RawButtonRelease);
if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) { if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
return; return;
@ -140,6 +142,8 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
static Time prev_time = 0; static Time prev_time = 0;
static double prev_rel_coords[2]; static double prev_rel_coords[2];
videodata->global_mouse_changed = SDL_TRUE;
if (!mouse->relative_mode || mouse->relative_mode_warp) { if (!mouse->relative_mode || mouse->relative_mode_warp) {
return 0; return 0;
} }
@ -158,6 +162,12 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
return 1; return 1;
} }
break; break;
case XI_RawButtonPress:
case XI_RawButtonRelease:
videodata->global_mouse_changed = SDL_TRUE;
break;
#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
case XI_TouchBegin: { case XI_TouchBegin: {
const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data; const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;