Commit b861efde14f093864396bf04acb4f3ae1cf4569d

Ryan C. Gordon 2014-06-05T00:03:33

Implemented SDL_GetAbsoluteMouseState(). X11 only for now, but this should be doable on every platform, I think.

diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h
index 571754a..fdb68f0 100644
--- a/include/SDL_mouse.h
+++ b/include/SDL_mouse.h
@@ -78,6 +78,31 @@ extern DECLSPEC SDL_Window * SDLCALL SDL_GetMouseFocus(void);
 extern DECLSPEC Uint32 SDLCALL SDL_GetMouseState(int *x, int *y);
 
 /**
+ *  \brief Get the current state of the mouse, in relation to the desktop
+ *
+ *  This works just like SDL_GetMouseState(), but the coordinates will be
+ *  reported relative to the top-left of the desktop. This can be useful if
+ *  you need to track the mouse outside of a specific window and
+ *  SDL_CaptureMouse() doesn't fit your needs. For example, it could be
+ *  useful if you need to track the mouse while dragging a window, where
+ *  coordinates relative to a window might not be in sync at all times.
+ *
+ *  \note SDL_GetMouseState() returns the mouse position as SDL understands
+ *        it from the last pump of the event queue. This function, however,
+ *        queries the OS for the current mouse position, and as such, might
+ *        be a slightly less efficient function. Unless you know what you're
+ *        doing and have a good reason to use this function, you probably want
+ *        SDL_GetMouseState() instead.
+ *
+ *  \param x Returns the current X coord, relative to the desktop. Can be NULL.
+ *  \param y Returns the current Y coord, relative to the desktop. Can be NULL.
+ *  \return The current button state as a bitmask, which can be tested using the SDL_BUTTON(X) macros.
+ *
+ *  \sa SDL_GetMouseState
+ */
+extern DECLSPEC Uint32 SDLCALL SDL_GetAbsoluteMouseState(int *x, int *y);
+
+/**
  *  \brief Retrieve the relative state of the mouse.
  *
  *  The current button state is returned as a button bitmask, which can
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index ce11175..aa99639 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -581,3 +581,4 @@
 #define SDL_WinRTRunApp SDL_WinRTRunApp_REAL
 #define SDL_CaptureMouse SDL_CaptureMouse_REAL
 #define SDL_SetWindowHitTest SDL_SetWindowHitTest_REAL
+#define SDL_GetAbsoluteMouseState SDL_GetAbsoluteMouseState_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index ba78b98..1df1222 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -614,3 +614,4 @@ SDL_DYNAPI_PROC(int,SDL_WinRTRunApp,(int a, char **b, void *c),(a,b,c),return)
 #endif
 SDL_DYNAPI_PROC(int,SDL_CaptureMouse,(SDL_bool a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_SetWindowHitTest,(SDL_Window *a, SDL_HitTest b, void *c),(a,b,c),return)
+SDL_DYNAPI_PROC(Uint32,SDL_GetAbsoluteMouseState,(int *a, int *b),(a,b),return)
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index 757c634..970cc78 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -469,6 +469,30 @@ SDL_GetRelativeMouseState(int *x, int *y)
     return mouse->buttonstate;
 }
 
+Uint32
+SDL_GetAbsoluteMouseState(int *x, int *y)
+{
+    SDL_Mouse *mouse = SDL_GetMouse();
+    int tmpx, tmpy;
+
+    /* make sure these are never NULL for the backend implementations... */
+    if (!x) {
+        x = &tmpx;
+    }
+    if (!y) {
+        y = &tmpy;
+    }
+
+    *x = *y = 0;
+
+    if (!mouse->GetAbsoluteMouseState) {
+        SDL_assert(0 && "This should really be implemented for every target.");
+        return 0;
+    }
+
+    return mouse->GetAbsoluteMouseState(x, y);
+}
+
 void
 SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
 {
diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h
index 34cd259..70b3ec0 100644
--- a/src/events/SDL_mouse_c.h
+++ b/src/events/SDL_mouse_c.h
@@ -66,6 +66,9 @@ typedef struct
     /* Set mouse capture */
     int (*CaptureMouse) (SDL_Window * window);
 
+    /* Get absolute mouse coordinates. (x) and (y) are never NULL and set to zero before call. */
+    Uint32 (*GetAbsoluteMouseState) (int *x, int *y);
+
     /* Data common to all mice */
     SDL_MouseID mouseID;
     SDL_Window *focus;
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index 2c4cabc..fa6c1fe 100644
--- a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -1488,6 +1488,19 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done)
                 }
             }
             break;
+        case SDLK_a:
+            if (withControl) {
+                /* Ctrl-A reports absolute mouse position. */
+                int x, y;
+                const Uint32 mask = SDL_GetAbsoluteMouseState(&x, &y);
+                SDL_Log("ABSOLUTE MOUSE: (%d, %d)%s%s%s%s%s\n", x, y,
+                        (mask & SDL_BUTTON_LMASK) ? " [LBUTTON]" : "",
+                        (mask & SDL_BUTTON_MMASK) ? " [MBUTTON]" : "",
+                        (mask & SDL_BUTTON_RMASK) ? " [RBUTTON]" : "",
+                        (mask & SDL_BUTTON_X1MASK) ? " [X2BUTTON]" : "",
+                        (mask & SDL_BUTTON_X2MASK) ? " [X2BUTTON]" : "");
+            }
+            break;
         case SDLK_0:
             if (withControl) {
                 SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c
index 74dc878..7386da5 100644
--- a/src/video/x11/SDL_x11mouse.c
+++ b/src/video/x11/SDL_x11mouse.c
@@ -353,6 +353,39 @@ X11_CaptureMouse(SDL_Window *window)
     return 0;
 }
 
+static Uint32
+X11_GetAbsoluteMouseState(int *x, int *y)
+{
+    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)) {
+                Uint32 retval = 0;
+                retval |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0;
+                retval |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0;
+                retval |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0;
+                *x = data->x + rootx;
+                *y = data->y + rooty;
+                return retval;
+            }
+        }
+    }
+
+    SDL_assert(0 && "The pointer wasn't on any X11 screen?!");
+
+    return 0;
+}
+
+
 void
 X11_InitMouse(_THIS)
 {
@@ -365,6 +398,7 @@ X11_InitMouse(_THIS)
     mouse->WarpMouse = X11_WarpMouse;
     mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode;
     mouse->CaptureMouse = X11_CaptureMouse;
+    mouse->GetAbsoluteMouseState = X11_GetAbsoluteMouseState;
 
     SDL_SetDefaultCursor(X11_CreateDefaultCursor());
 }