x11: Optimize SDL_GetGlobalMouseState() a little.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 22 Apr 2015 16:50:48 -0400
changeset 10018 3c1384edf9fa
parent 10017 363c41b866cd
child 10019 36f7e8084508
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.
src/video/x11/SDL_x11mouse.c
src/video/x11/SDL_x11video.c
src/video/x11/SDL_x11video.h
src/video/x11/SDL_x11xinput2.c
--- a/src/video/x11/SDL_x11mouse.c	Tue Apr 21 10:14:17 2015 -0400
+++ b/src/video/x11/SDL_x11mouse.c	Wed Apr 22 16:50:48 2015 -0400
@@ -366,39 +366,52 @@
 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;
 }
 
 
--- a/src/video/x11/SDL_x11video.c	Tue Apr 21 10:14:17 2015 -0400
+++ b/src/video/x11/SDL_x11video.c	Wed Apr 22 16:50:48 2015 -0400
@@ -175,6 +175,8 @@
     }
     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) ) {
--- a/src/video/x11/SDL_x11video.h	Tue Apr 21 10:14:17 2015 -0400
+++ b/src/video/x11/SDL_x11video.h	Wed Apr 22 16:50:48 2015 -0400
@@ -118,6 +118,10 @@
     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);
--- a/src/video/x11/SDL_x11xinput2.c	Tue Apr 21 10:14:17 2015 -0400
+++ b/src/video/x11/SDL_x11xinput2.c	Wed Apr 22 16:50:48 2015 -0400
@@ -118,6 +118,8 @@
     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;
@@ -140,6 +142,8 @@
             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;
             }
@@ -158,6 +162,12 @@
             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;