x11: Optimize SDL_GetGlobalMouseState() a little.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 22 Apr 2015 16:50:48 -0400
changeset 100183c1384edf9fa
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
     1.1 --- a/src/video/x11/SDL_x11mouse.c	Tue Apr 21 10:14:17 2015 -0400
     1.2 +++ b/src/video/x11/SDL_x11mouse.c	Wed Apr 22 16:50:48 2015 -0400
     1.3 @@ -366,39 +366,52 @@
     1.4  static Uint32
     1.5  X11_GetGlobalMouseState(int *x, int *y)
     1.6  {
     1.7 +    SDL_VideoData *videodata = (SDL_VideoData *) SDL_GetVideoDevice()->driverdata;
     1.8      Display *display = GetDisplay();
     1.9      const int num_screens = SDL_GetNumVideoDisplays();
    1.10      int i;
    1.11  
    1.12      /* !!! FIXME: should we XSync() here first? */
    1.13  
    1.14 -    for (i = 0; i < num_screens; i++) {
    1.15 -        SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i);
    1.16 -        if (data != NULL) {
    1.17 -            Window root, child;
    1.18 -            int rootx, rooty, winx, winy;
    1.19 -            unsigned int mask;
    1.20 -            if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) {
    1.21 -                XWindowAttributes root_attrs;
    1.22 -                Uint32 retval = 0;
    1.23 -                retval |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0;
    1.24 -                retval |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0;
    1.25 -                retval |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0;
    1.26 -                /* SDL_DisplayData->x,y point to screen origin, and adding them to mouse coordinates relative to root window doesn't do the right thing
    1.27 -                 * (observed on dual monitor setup with primary display being the rightmost one - mouse was offset to the right).
    1.28 -                 *
    1.29 -                 * Adding root position to root-relative coordinates seems to be a better way to get absolute position. */
    1.30 -                X11_XGetWindowAttributes(display, root, &root_attrs);
    1.31 -                *x = root_attrs.x + rootx;
    1.32 -                *y = root_attrs.y + rooty;
    1.33 -                return retval;
    1.34 +#if !SDL_VIDEO_DRIVER_X11_XINPUT2
    1.35 +    videodata->global_mouse_changed = SDL_TRUE;
    1.36 +#endif
    1.37 +
    1.38 +    /* check if we have this cached since XInput last saw the mouse move. */
    1.39 +    /* !!! FIXME: can we just calculate this from XInput's events? */
    1.40 +    if (videodata->global_mouse_changed) {
    1.41 +        for (i = 0; i < num_screens; i++) {
    1.42 +            SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i);
    1.43 +            if (data != NULL) {
    1.44 +                Window root, child;
    1.45 +                int rootx, rooty, winx, winy;
    1.46 +                unsigned int mask;
    1.47 +                if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) {
    1.48 +                    XWindowAttributes root_attrs;
    1.49 +                    Uint32 buttons = 0;
    1.50 +                    buttons |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0;
    1.51 +                    buttons |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0;
    1.52 +                    buttons |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0;
    1.53 +                    /* SDL_DisplayData->x,y point to screen origin, and adding them to mouse coordinates relative to root window doesn't do the right thing
    1.54 +                     * (observed on dual monitor setup with primary display being the rightmost one - mouse was offset to the right).
    1.55 +                     *
    1.56 +                     * Adding root position to root-relative coordinates seems to be a better way to get absolute position. */
    1.57 +                    X11_XGetWindowAttributes(display, root, &root_attrs);
    1.58 +                    videodata->global_mouse_position.x = root_attrs.x + rootx;
    1.59 +                    videodata->global_mouse_position.y = root_attrs.y + rooty;
    1.60 +                    videodata->global_mouse_buttons = buttons;
    1.61 +                    videodata->global_mouse_changed = SDL_FALSE;
    1.62 +                    break;
    1.63 +                }
    1.64              }
    1.65          }
    1.66      }
    1.67  
    1.68 -    SDL_assert(0 && "The pointer wasn't on any X11 screen?!");
    1.69 +    SDL_assert(!videodata->global_mouse_changed);  /* The pointer wasn't on any X11 screen?! */
    1.70  
    1.71 -    return 0;
    1.72 +    *x = videodata->global_mouse_position.x;
    1.73 +    *y = videodata->global_mouse_position.y;
    1.74 +    return videodata->global_mouse_buttons;
    1.75  }
    1.76  
    1.77  
     2.1 --- a/src/video/x11/SDL_x11video.c	Tue Apr 21 10:14:17 2015 -0400
     2.2 +++ b/src/video/x11/SDL_x11video.c	Wed Apr 22 16:50:48 2015 -0400
     2.3 @@ -175,6 +175,8 @@
     2.4      }
     2.5      device->driverdata = data;
     2.6  
     2.7 +    data->global_mouse_changed = SDL_TRUE;
     2.8 +
     2.9      /* FIXME: Do we need this?
    2.10         if ( (SDL_strncmp(X11_XDisplayName(display), ":", 1) == 0) ||
    2.11         (SDL_strncmp(X11_XDisplayName(display), "unix:", 5) == 0) ) {
     3.1 --- a/src/video/x11/SDL_x11video.h	Tue Apr 21 10:14:17 2015 -0400
     3.2 +++ b/src/video/x11/SDL_x11video.h	Wed Apr 22 16:50:48 2015 -0400
     3.3 @@ -118,6 +118,10 @@
     3.4      SDL_bool selection_waiting;
     3.5  
     3.6      Uint32 last_mode_change_deadline;
     3.7 +
     3.8 +    SDL_bool global_mouse_changed;
     3.9 +    SDL_Point global_mouse_position;
    3.10 +    Uint32 global_mouse_buttons;
    3.11  } SDL_VideoData;
    3.12  
    3.13  extern SDL_bool X11_UseDirectColorVisuals(void);
     4.1 --- a/src/video/x11/SDL_x11xinput2.c	Tue Apr 21 10:14:17 2015 -0400
     4.2 +++ b/src/video/x11/SDL_x11xinput2.c	Wed Apr 22 16:50:48 2015 -0400
     4.3 @@ -118,6 +118,8 @@
     4.4      eventmask.mask = mask;
     4.5  
     4.6      XISetMask(mask, XI_RawMotion);
     4.7 +    XISetMask(mask, XI_RawButtonPress);
     4.8 +    XISetMask(mask, XI_RawButtonRelease);
     4.9  
    4.10      if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
    4.11          return;
    4.12 @@ -140,6 +142,8 @@
    4.13              static Time prev_time = 0;
    4.14              static double prev_rel_coords[2];
    4.15  
    4.16 +            videodata->global_mouse_changed = SDL_TRUE;
    4.17 +
    4.18              if (!mouse->relative_mode || mouse->relative_mode_warp) {
    4.19                  return 0;
    4.20              }
    4.21 @@ -158,6 +162,12 @@
    4.22              return 1;
    4.23              }
    4.24              break;
    4.25 +
    4.26 +        case XI_RawButtonPress:
    4.27 +        case XI_RawButtonRelease:
    4.28 +            videodata->global_mouse_changed = SDL_TRUE;
    4.29 +            break;
    4.30 +
    4.31  #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
    4.32          case XI_TouchBegin: {
    4.33              const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;