Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
icculus committed Apr 22, 2015
1 parent 14e0077 commit 8875a40
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 22 deletions.
57 changes: 35 additions & 22 deletions src/video/x11/SDL_x11mouse.c
Expand Up @@ -366,39 +366,52 @@ X11_CaptureMouse(SDL_Window *window)
static Uint32
X11_GetGlobalMouseState(int *x, int *y)
{
SDL_VideoData *videodata = (SDL_VideoData *) SDL_GetVideoDevice()->driverdata;
Display *display = GetDisplay();
const int num_screens = SDL_GetNumVideoDisplays();
int i;

/* !!! FIXME: should we XSync() here first? */

for (i = 0; i < num_screens; i++) {
SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i);
if (data != NULL) {
Window root, child;
int rootx, rooty, winx, winy;
unsigned int mask;
if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) {
XWindowAttributes root_attrs;
Uint32 retval = 0;
retval |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0;
retval |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0;
retval |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0;
/* 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);
*x = root_attrs.x + rootx;
*y = root_attrs.y + rooty;
return retval;
#if !SDL_VIDEO_DRIVER_X11_XINPUT2
videodata->global_mouse_changed = SDL_TRUE;
#endif

/* check if we have this cached since XInput last saw the mouse move. */
/* !!! FIXME: can we just calculate this from XInput's events? */
if (videodata->global_mouse_changed) {
for (i = 0; i < num_screens; i++) {
SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i);
if (data != NULL) {
Window root, child;
int rootx, rooty, winx, winy;
unsigned int mask;
if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) {
XWindowAttributes root_attrs;
Uint32 buttons = 0;
buttons |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0;
buttons |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0;
buttons |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0;
/* 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;
}


Expand Down
2 changes: 2 additions & 0 deletions src/video/x11/SDL_x11video.c
Expand Up @@ -175,6 +175,8 @@ X11_CreateDevice(int devindex)
}
device->driverdata = data;

data->global_mouse_changed = SDL_TRUE;

/* FIXME: Do we need this?
if ( (SDL_strncmp(X11_XDisplayName(display), ":", 1) == 0) ||
(SDL_strncmp(X11_XDisplayName(display), "unix:", 5) == 0) ) {
Expand Down
4 changes: 4 additions & 0 deletions src/video/x11/SDL_x11video.h
Expand Up @@ -118,6 +118,10 @@ typedef struct SDL_VideoData
SDL_bool selection_waiting;

Uint32 last_mode_change_deadline;

SDL_bool global_mouse_changed;
SDL_Point global_mouse_position;
Uint32 global_mouse_buttons;
} SDL_VideoData;

extern SDL_bool X11_UseDirectColorVisuals(void);
Expand Down
10 changes: 10 additions & 0 deletions src/video/x11/SDL_x11xinput2.c
Expand Up @@ -118,6 +118,8 @@ X11_InitXinput2(_THIS)
eventmask.mask = mask;

XISetMask(mask, XI_RawMotion);
XISetMask(mask, XI_RawButtonPress);
XISetMask(mask, XI_RawButtonRelease);

if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
return;
Expand All @@ -140,6 +142,8 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
static Time prev_time = 0;
static double prev_rel_coords[2];

videodata->global_mouse_changed = SDL_TRUE;

if (!mouse->relative_mode || mouse->relative_mode_warp) {
return 0;
}
Expand All @@ -158,6 +162,12 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
return 1;
}
break;

case XI_RawButtonPress:
case XI_RawButtonRelease:
videodata->global_mouse_changed = SDL_TRUE;
break;

#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
case XI_TouchBegin: {
const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
Expand Down

0 comments on commit 8875a40

Please sign in to comment.