From 67f246e568dad4bb2f892bcbc47798acbea4198d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 24 May 2014 01:30:37 -0400 Subject: [PATCH 01/26] Implemented SDL_CaptureMouse(). --- include/SDL_mouse.h | 31 ++++++++ include/SDL_video.h | 3 +- src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + src/events/SDL_keyboard.c | 11 +++ src/events/SDL_mouse.c | 102 +++++++++++++++++---------- src/events/SDL_mouse_c.h | 3 + src/test/SDL_test_common.c | 10 +++ src/video/SDL_video.c | 12 ++++ src/video/windows/SDL_windowsmouse.c | 14 ++++ src/video/x11/SDL_x11mouse.c | 24 +++++++ 11 files changed, 174 insertions(+), 38 deletions(-) diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h index ebfd18fa7..571754ad2 100644 --- a/include/SDL_mouse.h +++ b/include/SDL_mouse.h @@ -116,6 +116,37 @@ extern DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window * window, */ extern DECLSPEC int SDLCALL SDL_SetRelativeMouseMode(SDL_bool enabled); +/** + * \brief Capture the mouse, to track input outside an SDL window. + * + * \param enabled Whether or not to enable capturing + * + * Capturing enables your app to obtain mouse events globally, instead of + * just within your window. Not all video targets support this function. + * When capturing is enabled, the current window will get all mouse events, + * but unlike relative mode, no change is made to the cursor and it is + * not restrained to your window. + * + * This function may also deny mouse input to other windows--both those in + * your application and others on the system--so you should use this + * function sparingly, and in small bursts. For example, you might want to + * track the mouse while the user is dragging something, until the user + * releases a mouse button. It is not recommended that you capture the mouse + * for long periods of time, such as the entire time your app is running. + * + * While captured, mouse events still report coordinates relative to the + * current (foreground) window, but those coordinates may be outside the + * bounds of the window (including negative values). Capturing is only + * allowed for the foreground window. If the window loses focus while + * capturing, the capture will be disabled automatically. + * + * While capturing is enabled, the current window will have the + * SDL_WINDOW_MOUSE_CAPTURE flag set. + * + * \return 0 on success, or -1 if not supported. + */ +extern DECLSPEC int SDLCALL SDL_CaptureMouse(SDL_bool enabled); + /** * \brief Query whether relative mouse mode is enabled. * diff --git a/include/SDL_video.h b/include/SDL_video.h index 607062cb5..107c8381b 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -108,7 +108,8 @@ typedef enum SDL_WINDOW_MOUSE_FOCUS = 0x00000400, /**< window has mouse focus */ SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ), SDL_WINDOW_FOREIGN = 0x00000800, /**< window not created by SDL */ - SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000 /**< window should be created in high-DPI mode if supported */ + SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, /**< window should be created in high-DPI mode if supported */ + SDL_WINDOW_MOUSE_CAPTURE = 0x00004000 /**< window has mouse captured (unrelated to INPUT_GRABBED) */ } SDL_WindowFlags; /** diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 52b3d454e..6f74d135f 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -579,3 +579,4 @@ #define SDL_WinRTGetFSPathUNICODE SDL_WinRTGetFSPathUNICODE_REAL #define SDL_WinRTGetFSPathUTF8 SDL_WinRTGetFSPathUTF8_REAL #define SDL_WinRTRunApp SDL_WinRTRunApp_REAL +#define SDL_CaptureMouse SDL_CaptureMouse_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index d84a93885..63d67e55b 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -612,3 +612,4 @@ SDL_DYNAPI_PROC(const wchar_t*,SDL_WinRTGetFSPathUNICODE,(SDL_WinRT_Path a),(a), SDL_DYNAPI_PROC(const char*,SDL_WinRTGetFSPathUTF8,(SDL_WinRT_Path a),(a),return) 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) diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index d5443893b..ed4043e9c 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -25,6 +25,7 @@ #include "SDL_timer.h" #include "SDL_events.h" #include "SDL_events_c.h" +#include "SDL_assert.h" #include "../video/SDL_sysvideo.h" @@ -619,6 +620,16 @@ SDL_SetKeyboardFocus(SDL_Window * window) /* See if the current window has lost focus */ if (keyboard->focus && keyboard->focus != window) { + + /* new window shouldn't think it has mouse captured. */ + SDL_assert(!window || !(window->flags & SDL_WINDOW_MOUSE_CAPTURE)); + + /* old window must lose an existing mouse capture. */ + if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) { + SDL_CaptureMouse(SDL_FALSE); /* drop the capture. */ + SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE)); + } + SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0); diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 3f82b4ee8..3ed1d1418 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -140,30 +140,17 @@ static SDL_bool SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate) { SDL_Mouse *mouse = SDL_GetMouse(); - int w, h; - SDL_bool inWindow; + SDL_bool inWindow = SDL_TRUE; - SDL_GetWindowSize(window, &w, &h); - if (x < 0 || y < 0 || x >= w || y >= h) { - inWindow = SDL_FALSE; - } else { - inWindow = SDL_TRUE; + if ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0) { + int w, h; + SDL_GetWindowSize(window, &w, &h); + if (x < 0 || y < 0 || x >= w || y >= h) { + inWindow = SDL_FALSE; + } } -/* Linux doesn't give you mouse events outside your window unless you grab - the pointer. - - Windows doesn't give you mouse events outside your window unless you call - SetCapture(). - - Both of these are slightly scary changes, so for now we'll punt and if the - mouse leaves the window you'll lose mouse focus and reset button state. -*/ -#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW - if (!inWindow && !buttonstate) { -#else if (!inWindow) { -#endif if (window == mouse->focus) { #ifdef DEBUG_MOUSE printf("Mouse left window, synthesizing move & focus lost event\n"); @@ -204,7 +191,6 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ int posted; int xrel; int yrel; - int x_max = 0, y_max = 0; if (mouse->relative_mode_warp) { int center_x = 0, center_y = 0; @@ -246,24 +232,29 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ mouse->y += yrel; } - /* !!! FIXME: shouldn't this be (window) instead of (mouse->focus)? */ - SDL_GetWindowSize(mouse->focus, &x_max, &y_max); - --x_max; - --y_max; + /* make sure that the pointers find themselves inside the windows, + unless we have the mouse captured. */ + if ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0) { + int x_max = 0, y_max = 0; - /* make sure that the pointers find themselves inside the windows */ - if (mouse->x > x_max) { - mouse->x = x_max; - } - if (mouse->x < 0) { - mouse->x = 0; - } + // !!! FIXME: shouldn't this be (window) instead of (mouse->focus)? + SDL_GetWindowSize(mouse->focus, &x_max, &y_max); + --x_max; + --y_max; - if (mouse->y > y_max) { - mouse->y = y_max; - } - if (mouse->y < 0) { - mouse->y = 0; + if (mouse->x > x_max) { + mouse->x = x_max; + } + if (mouse->x < 0) { + mouse->x = 0; + } + + if (mouse->y > y_max) { + mouse->y = y_max; + } + if (mouse->y < 0) { + mouse->y = 0; + } } mouse->xdelta += xrel; @@ -426,6 +417,7 @@ SDL_MouseQuit(void) SDL_Cursor *cursor, *next; SDL_Mouse *mouse = SDL_GetMouse(); + SDL_CaptureMouse(SDL_FALSE); SDL_SetRelativeMouseMode(SDL_FALSE); SDL_ShowCursor(1); @@ -572,6 +564,42 @@ SDL_GetRelativeMouseMode() return mouse->relative_mode; } +int +SDL_CaptureMouse(SDL_bool enabled) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Window *focusWindow; + SDL_bool isCaptured; + + if (!mouse->CaptureMouse) { + return SDL_Unsupported(); + } + + focusWindow = SDL_GetKeyboardFocus(); + + isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE); + if (isCaptured == enabled) { + return 0; /* already done! */ + } + + if (enabled) { + if (!focusWindow) { + return SDL_SetError("No window has focus"); + } else if (mouse->CaptureMouse(focusWindow) == -1) { + return -1; /* CaptureMouse() should call SetError */ + } + focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE; + } else { + if (mouse->CaptureMouse(NULL) == -1) { + return -1; /* CaptureMouse() should call SetError */ + } + focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; + } + + return 0; +} + + SDL_Cursor * SDL_CreateCursor(const Uint8 * data, const Uint8 * mask, int w, int h, int hot_x, int hot_y) diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index e0d917cbc..34cd259e6 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -63,6 +63,9 @@ typedef struct /* Set relative mode */ int (*SetRelativeMouseMode) (SDL_bool enabled); + /* Set mouse capture */ + int (*CaptureMouse) (SDL_Window * window); + /* 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 6fa984b6a..e304a76e0 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -999,10 +999,12 @@ default: return "???"; static void SDLTest_PrintEvent(SDL_Event * event) { +#if 0 if ((event->type == SDL_MOUSEMOTION) || (event->type == SDL_FINGERMOTION)) { /* Mouse and finger motion are really spammy */ return; } +#endif switch (event->type) { case SDL_WINDOWEVENT: @@ -1379,6 +1381,14 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done) } } } + if (withShift) { + SDL_Window *current_win = SDL_GetKeyboardFocus(); + if (current_win) { + const SDL_bool shouldCapture = (SDL_GetWindowFlags(current_win) & SDL_WINDOW_MOUSE_CAPTURE) == 0; + const int rc = SDL_CaptureMouse(shouldCapture); + printf("%sapturing mouse %s!\n", shouldCapture ? "C" : "Unc", (rc == 0) ? "succeeded" : "failed"); + } + } break; case SDLK_v: if (withControl) { diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index f8556a6d9..aa729cf3b 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -3269,12 +3269,17 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) int retval = -1; SDL_bool relative_mode; int show_cursor_prev; + SDL_bool mouse_captured; + SDL_Window *current_window; if (!messageboxdata) { return SDL_InvalidParamError("messageboxdata"); } + current_window = SDL_GetKeyboardFocus(); + mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0); relative_mode = SDL_GetRelativeMouseMode(); + SDL_CaptureMouse(SDL_FALSE); SDL_SetRelativeMouseMode(SDL_FALSE); show_cursor_prev = SDL_ShowCursor(1); @@ -3326,6 +3331,13 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) SDL_SetError("No message system available"); } + if (current_window) { + SDL_RaiseWindow(current_window); + if (mouse_captured) { + SDL_CaptureMouse(SDL_TRUE); + } + } + SDL_ShowCursor(show_cursor_prev); SDL_SetRelativeMouseMode(relative_mode); diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index b49249db6..1f38dcd55 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -219,6 +219,19 @@ WIN_SetRelativeMouseMode(SDL_bool enabled) return 0; } +static int +WIN_CaptureMouse(SDL_Window *window) +{ + if (!window) { + ReleaseCapture(); + } else { + const SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + SetCapture(data->hwnd); + } + + return 0; +} + void WIN_InitMouse(_THIS) { @@ -230,6 +243,7 @@ WIN_InitMouse(_THIS) mouse->FreeCursor = WIN_FreeCursor; mouse->WarpMouse = WIN_WarpMouse; mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode; + mouse->CaptureMouse = WIN_CaptureMouse; SDL_SetDefaultCursor(WIN_CreateDefaultCursor()); diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c index 38bb86656..74dc8789c 100644 --- a/src/video/x11/SDL_x11mouse.c +++ b/src/video/x11/SDL_x11mouse.c @@ -330,6 +330,29 @@ X11_SetRelativeMouseMode(SDL_bool enabled) return -1; } +static int +X11_CaptureMouse(SDL_Window *window) +{ + Display *display = GetDisplay(); + + if (window) { + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + const unsigned int mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask; + const int rc = X11_XGrabPointer(display, data->xwindow, False, + mask, GrabModeAsync, GrabModeAsync, + None, None, CurrentTime); + if (rc != GrabSuccess) { + return SDL_SetError("X server refused mouse capture"); + } + } else { + X11_XUngrabPointer(display, CurrentTime); + } + + X11_XSync(display, False); + + return 0; +} + void X11_InitMouse(_THIS) { @@ -341,6 +364,7 @@ X11_InitMouse(_THIS) mouse->FreeCursor = X11_FreeCursor; mouse->WarpMouse = X11_WarpMouse; mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode; + mouse->CaptureMouse = X11_CaptureMouse; SDL_SetDefaultCursor(X11_CreateDefaultCursor()); } From 88528c10e8de3eabc3b18b5d6f6bb50e1adc1af7 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 24 May 2014 18:23:39 -0400 Subject: [PATCH 02/26] Implement SDL_CaptureMouse() for Mac OS X. --- src/video/cocoa/SDL_cocoamouse.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index f5b54ed38..2f9d8d352 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -274,6 +274,14 @@ Cocoa_SetRelativeMouseMode(SDL_bool enabled) return 0; } +static int +Cocoa_CaptureMouse(SDL_Window *window) +{ + /* our Cocoa event code already tracks the mouse outside the window, + so all we have to do here is say "okay" and do what we always do. */ + return 0; +} + void Cocoa_InitMouse(_THIS) { @@ -287,6 +295,7 @@ Cocoa_InitMouse(_THIS) mouse->FreeCursor = Cocoa_FreeCursor; mouse->WarpMouse = Cocoa_WarpMouse; mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode; + mouse->CaptureMouse = Cocoa_CaptureMouse; SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor()); From 6baa90e0ecdb5fbebd64ff7eb00ec58e72f990c6 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 24 May 2014 18:23:56 -0400 Subject: [PATCH 03/26] Flip this around to do the simpler condition first. --- src/video/cocoa/SDL_cocoawindow.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index ba3059789..2b273f8a0 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -745,8 +745,8 @@ SetWindowStyle(SDL_Window * window, unsigned int style) x = (int)point.x; y = (int)(window->h - point.y); - if (x < 0 || x >= window->w || y < 0 || y >= window->h) { - if (window->flags & SDL_WINDOW_INPUT_GRABBED) { + if (window->flags & SDL_WINDOW_INPUT_GRABBED) { + if (x < 0 || x >= window->w || y < 0 || y >= window->h) { if (x < 0) { x = 0; } else if (x >= window->w) { From 5f9c366fe2deffd6eb64e2cd2284df882aa170ca Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 27 May 2014 00:26:47 -0400 Subject: [PATCH 04/26] Added SDL_PointInRect(). --HG-- extra : amend_source : dda056b2033a9b6b370eefd66ac9653a5050a476 --- include/SDL_rect.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/SDL_rect.h b/include/SDL_rect.h index 0a95a3344..e170a0163 100644 --- a/include/SDL_rect.h +++ b/include/SDL_rect.h @@ -43,6 +43,7 @@ extern "C" { * \brief The structure that defines a point * * \sa SDL_EnclosePoints + * \sa SDL_PointInRect */ typedef struct SDL_Point { @@ -66,6 +67,15 @@ typedef struct SDL_Rect int w, h; } SDL_Rect; +/** + * \brief Returns true if point resides inside a rectangle. + */ +SDL_FORCE_INLINE SDL_bool SDL_PointInRect(const SDL_Point *p, const SDL_Rect *r) +{ + return ( (p->x >= r->x) && (p->x < (r->x + r->w)) && + (p->y >= r->y) && (p->y < (r->y + r->h)) ); +} + /** * \brief Returns true if the rectangle has no area. */ From cce4ce44d48ce6d04626645f1f9ad09ce6e4fd89 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 27 May 2014 01:27:42 -0400 Subject: [PATCH 05/26] First shot at SDL_SetWindowDragAreas(). Only Cocoa implemented right now. --HG-- extra : amend_source : b178ad0ae25b933b284ed1bda89df750ddd27fb3 --- .hgignore | 1 + include/SDL_video.h | 38 +++++++++++++ src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + src/video/SDL_sysvideo.h | 6 ++ src/video/SDL_video.c | 37 ++++++++++++ src/video/cocoa/SDL_cocoavideo.m | 1 + src/video/cocoa/SDL_cocoawindow.h | 9 ++- src/video/cocoa/SDL_cocoawindow.m | 60 ++++++++++++++++++++ test/Makefile.in | 4 ++ test/testdragareas.c | 93 +++++++++++++++++++++++++++++++ 11 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 test/testdragareas.c diff --git a/.hgignore b/.hgignore index c04bfc01a..37ab96a3d 100644 --- a/.hgignore +++ b/.hgignore @@ -55,6 +55,7 @@ test/loopwave test/testatomic test/testaudioinfo test/testautomation +test/testdragareas test/testdraw2 test/testerror test/testfile diff --git a/include/SDL_video.h b/include/SDL_video.h index 107c8381b..f096d7ff0 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -791,6 +791,44 @@ extern DECLSPEC int SDLCALL SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * green, Uint16 * blue); +/** + * \brief Define regions of a window that can be used to drag it. + * + * Normally windows are dragged by decorations provided by the system + * window manager (usually, a title bar), but for some apps, it makes sense + * to drag them from somewhere else inside the window itself; for example, + * one might have a borderless window that wants to be draggable from any + * part, or simulate its own title bar, etc. + * + * This method designates pieces of a given window as "drag areas," which + * will move the window when the user drags with his mouse, as if she had + * used the titlebar. + * + * You may specify multiple drag areas, disconnected or overlapping. This + * function accepts an array of rectangles. Each call to this function will + * replace any previously-defined drag areas. To disable drag areas on a + * window, call this function with a NULL array of zero elements. + * + * Drag areas do not automatically resize. If your window changes dimensions + * you should plan to re-call this function with new drag areas if + * appropriate. + * + * Mouse input may not be delivered to your application if it is within + * a drag area; the OS will often apply that input to moving the window and + * not deliver it to the application. + * + * Platforms that don't support this functionality will return -1 + * unconditionally, even if you're attempting to disable drag areas. + * + * \param window The window to set drag areas on. + * \param areas An array of SDL_Rects containing num_areas elements. + * \param num_areas The number of elements in the areas parameter. + * \return 0 on success, -1 on error (including unsupported). + */ +extern DECLSPEC int SDLCALL SDL_SetWindowDragAreas(SDL_Window * window, + const SDL_Rect *areas, + int num_areas); + /** * \brief Destroy a window. */ diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 6f74d135f..b44378d51 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -580,3 +580,4 @@ #define SDL_WinRTGetFSPathUTF8 SDL_WinRTGetFSPathUTF8_REAL #define SDL_WinRTRunApp SDL_WinRTRunApp_REAL #define SDL_CaptureMouse SDL_CaptureMouse_REAL +#define SDL_SetWindowDragAreas SDL_SetWindowDragAreas_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 63d67e55b..232a8e927 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -613,3 +613,4 @@ SDL_DYNAPI_PROC(const char*,SDL_WinRTGetFSPathUTF8,(SDL_WinRT_Path a),(a),return 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_SetWindowDragAreas,(SDL_Window *a, const SDL_Rect *b, int c),(a,b,c),return) diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 35dd940c7..17a316490 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -97,6 +97,9 @@ struct SDL_Window SDL_WindowShaper *shaper; + int num_drag_areas; + SDL_Rect *drag_areas; + SDL_WindowUserData *data; void *driverdata; @@ -261,6 +264,9 @@ struct SDL_VideoDevice /* MessageBox */ int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid); + /* Drag areas. Note that (areas) and (num_areas) are also copied to the SDL_Window for you after this call. */ + int (*SetWindowDragAreas)(SDL_Window * window, const SDL_Rect *areas, int num_areas); + /* * * */ /* Data common to all drivers */ SDL_bool suspend_screensaver; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index aa729cf3b..3476fa748 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1410,6 +1410,11 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags) SDL_SetWindowIcon(window, icon); SDL_FreeSurface(icon); } + + if (window->num_drag_areas > 0) { + _this->SetWindowDragAreas(window, window->drag_areas, window->num_drag_areas); + } + SDL_FinishWindowCreation(window, flags); return 0; @@ -2305,6 +2310,8 @@ SDL_DestroyWindow(SDL_Window * window) _this->windows = window->next; } + SDL_free(window->drag_areas); + SDL_free(window); } @@ -3380,4 +3387,34 @@ SDL_ShouldAllowTopmost(void) return SDL_TRUE; } +int +SDL_SetWindowDragAreas(SDL_Window * window, const SDL_Rect *_areas, int num_areas) +{ + SDL_Rect *areas = NULL; + + CHECK_WINDOW_MAGIC(window, -1); + + if (!_this->SetWindowDragAreas) { + return SDL_Unsupported(); + } + + if (num_areas > 0) { + const size_t len = sizeof (SDL_Rect) * num_areas; + areas = (SDL_Rect *) SDL_malloc(len); + if (!areas) { + return SDL_OutOfMemory(); + } + SDL_memcpy(areas, _areas, len); + } + + if (_this->SetWindowDragAreas(window, areas, num_areas) == -1) { + SDL_free(areas); + return -1; + } + + SDL_free(window->drag_areas); + window->drag_areas = areas; + window->num_drag_areas = num_areas; +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index 6766b71bb..a24770b4d 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -108,6 +108,7 @@ Cocoa_CreateDevice(int devindex) device->SetWindowGrab = Cocoa_SetWindowGrab; device->DestroyWindow = Cocoa_DestroyWindow; device->GetWindowWMInfo = Cocoa_GetWindowWMInfo; + device->SetWindowDragAreas = Cocoa_SetWindowDragAreas; device->shape_driver.CreateShaper = Cocoa_CreateShaper; device->shape_driver.SetWindowShape = Cocoa_SetWindowShape; diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h index a4ec07d72..bfa461054 100644 --- a/src/video/cocoa/SDL_cocoawindow.h +++ b/src/video/cocoa/SDL_cocoawindow.h @@ -45,6 +45,7 @@ typedef enum PendingWindowOperation pendingWindowOperation; BOOL isMoving; int pendingWindowWarpX, pendingWindowWarpY; + BOOL isDragAreaRunning; } -(void) listen:(SDL_WindowData *) data; @@ -75,6 +76,9 @@ typedef enum -(void) windowDidExitFullScreen:(NSNotification *) aNotification; -(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions; +/* See if event is in a drag area, toggle on window dragging. */ +-(BOOL) processDragArea:(NSEvent *)theEvent; + /* Window event handling */ -(void) mouseDown:(NSEvent *) theEvent; -(void) rightMouseDown:(NSEvent *) theEvent; @@ -115,6 +119,7 @@ struct SDL_WindowData SDL_bool inWindowMove; Cocoa_WindowListener *listener; struct SDL_VideoData *videodata; + NSView *dragarea; }; extern int Cocoa_CreateWindow(_THIS, SDL_Window * window); @@ -138,8 +143,8 @@ extern int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * r extern int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp); extern void Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed); extern void Cocoa_DestroyWindow(_THIS, SDL_Window * window); -extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, - struct SDL_SysWMinfo *info); +extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); +extern int Cocoa_SetWindowDragAreas(SDL_Window *window, const SDL_Rect *areas, int num_areas); #endif /* _SDL_cocoawindow_h */ diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 2b273f8a0..3d94b133b 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -180,6 +180,7 @@ SetWindowStyle(SDL_Window * window, unsigned int style) inFullscreenTransition = NO; pendingWindowOperation = PENDING_OPERATION_NONE; isMoving = NO; + isDragAreaRunning = NO; center = [NSNotificationCenter defaultCenter]; @@ -656,10 +657,46 @@ SetWindowStyle(SDL_Window * window, unsigned int style) /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/ } +- (BOOL)processDragArea:(NSEvent *)theEvent +{ + const int num_areas = _data->window->num_drag_areas; + + SDL_assert(isDragAreaRunning == [_data->nswindow isMovableByWindowBackground]); + SDL_assert((num_areas > 0) || !isDragAreaRunning); + + if (num_areas > 0) { /* if no drag areas, skip this. */ + int i; + const NSPoint location = [theEvent locationInWindow]; + const SDL_Point point = { (int) location.x, _data->window->h - (((int) location.y)-1) }; + const SDL_Rect *areas = _data->window->drag_areas; + for (i = 0; i < num_areas; i++) { + if (SDL_PointInRect(&point, &areas[i])) { + if (!isDragAreaRunning) { + isDragAreaRunning = YES; + [_data->nswindow setMovableByWindowBackground:YES]; + } + return YES; /* started a new drag! */ + } + } + } + + if (isDragAreaRunning) { + isDragAreaRunning = NO; + [_data->nswindow setMovableByWindowBackground:NO]; + return YES; /* was dragging, drop event. */ + } + + return NO; /* not a drag area, carry on. */ +} + - (void)mouseDown:(NSEvent *)theEvent { int button; + if ([self processDragArea:theEvent]) { + return; /* dragging, drop event. */ + } + switch ([theEvent buttonNumber]) { case 0: if (([theEvent modifierFlags] & NSControlKeyMask) && @@ -698,6 +735,10 @@ SetWindowStyle(SDL_Window * window, unsigned int style) { int button; + if ([self processDragArea:theEvent]) { + return; /* stopped dragging, drop event. */ + } + switch ([theEvent buttonNumber]) { case 0: if (wasCtrlLeft) { @@ -737,6 +778,10 @@ SetWindowStyle(SDL_Window * window, unsigned int style) NSPoint point; int x, y; + if ([self processDragArea:theEvent]) { + return; /* dragging, drop event. */ + } + if (mouse->relative_mode) { return; } @@ -883,6 +928,7 @@ SetWindowStyle(SDL_Window * window, unsigned int style) /* The default implementation doesn't pass rightMouseDown to responder chain */ - (void)rightMouseDown:(NSEvent *)theEvent; +- (BOOL)mouseDownCanMoveWindow; @end @implementation SDLView @@ -891,6 +937,14 @@ SetWindowStyle(SDL_Window * window, unsigned int style) [[self nextResponder] rightMouseDown:theEvent]; } +- (BOOL)mouseDownCanMoveWindow +{ + /* Always say YES, but this doesn't do anything until we call + -[NSWindow setMovableByWindowBackground:YES], which we ninja-toggle + during mouse events when we're using a drag area. */ + return YES; +} + - (void)resetCursorRects { [super resetCursorRects]; @@ -1544,6 +1598,12 @@ Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state) return succeeded; } +int +Cocoa_SetWindowDragAreas(SDL_Window * window, const SDL_Rect *areas, int num_areas) +{ + return 0; /* just succeed, the real work is done elsewhere. */ +} + #endif /* SDL_VIDEO_DRIVER_COCOA */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/test/Makefile.in b/test/Makefile.in index 7ed1a7ac9..a0476137f 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -12,6 +12,7 @@ TARGETS = \ loopwave$(EXE) \ testaudioinfo$(EXE) \ testautomation$(EXE) \ + testdragareas$(EXE) \ testdraw2$(EXE) \ testdrawchessboard$(EXE) \ testdropfile$(EXE) \ @@ -108,6 +109,9 @@ testintersections$(EXE): $(srcdir)/testintersections.c testrelative$(EXE): $(srcdir)/testrelative.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) +testdragareas$(EXE): $(srcdir)/testdragareas.c + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + testdraw2$(EXE): $(srcdir)/testdraw2.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) diff --git a/test/testdragareas.c b/test/testdragareas.c new file mode 100644 index 000000000..776f06131 --- /dev/null +++ b/test/testdragareas.c @@ -0,0 +1,93 @@ +#include +#include "SDL.h" + +/* !!! FIXME: rewrite this to be wired in to test framework. */ + +int main(int argc, char **argv) +{ + int done = 0; + SDL_Window *window; + SDL_Renderer *renderer; + + const SDL_Rect drag_areas[] = { + { 20, 20, 100, 100 }, + { 200, 70, 100, 100 }, + { 400, 90, 100, 100 } + }; + + const SDL_Rect *areas = drag_areas; + int numareas = SDL_arraysize(drag_areas); + + /* !!! FIXME: check for errors. */ + SDL_Init(SDL_INIT_VIDEO); + window = SDL_CreateWindow("Drag the red boxes", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_BORDERLESS); + renderer = SDL_CreateRenderer(window, -1, 0); + + if (SDL_SetWindowDragAreas(window, areas, numareas) == -1) { + fprintf(stderr, "Setting drag areas failed!\n"); + SDL_Quit(); + return 1; + } + + while (!done) + { + SDL_SetRenderDrawColor(renderer, 0, 0, 127, 255); + SDL_RenderClear(renderer); + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + SDL_RenderFillRects(renderer, areas, SDL_arraysize(drag_areas)); + SDL_RenderPresent(renderer); + + SDL_Event e; + int nothing_to_do = 1; + while (SDL_PollEvent(&e)) { + nothing_to_do = 0; + + switch (e.type) + { + case SDL_MOUSEBUTTONDOWN: + printf("button down!\n"); + break; + + case SDL_MOUSEBUTTONUP: + printf("button up!\n"); + break; + + case SDL_WINDOWEVENT: + if (e.window.event == SDL_WINDOWEVENT_MOVED) { + printf("Window event moved to (%d, %d)!\n", (int) e.window.data1, (int) e.window.data2); + } + break; + + case SDL_KEYDOWN: + if (e.key.keysym.sym == SDLK_ESCAPE) { + done = 1; + } else if (e.key.keysym.sym == SDLK_x) { + if (!areas) { + areas = drag_areas; + numareas = SDL_arraysize(drag_areas); + } else { + areas = NULL; + numareas = 0; + } + if (SDL_SetWindowDragAreas(window, areas, numareas) == -1) { + fprintf(stderr, "Setting drag areas failed!\n"); + SDL_Quit(); + return 1; + } + } + break; + + case SDL_QUIT: + done = 1; + break; + } + } + + if (nothing_to_do) { + SDL_Delay(50); + } + } + + SDL_Quit(); + return 0; +} From 738e84c26b4922fd0b4c47d244d72b240e29e65e Mon Sep 17 00:00:00 2001 From: Damian Kaczmarek Date: Tue, 27 May 2014 14:41:16 -0400 Subject: [PATCH 06/26] Initial work on X11 implementation of SDL_SetWindowDragAreas(). --- src/video/x11/SDL_x11events.c | 48 +++++++++++++++++++++++++++++++++++ src/video/x11/SDL_x11video.c | 1 + src/video/x11/SDL_x11window.c | 6 +++++ src/video/x11/SDL_x11window.h | 1 + 4 files changed, 56 insertions(+) diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 50e73946d..db6a301d1 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -272,6 +272,51 @@ X11_DispatchUnmapNotify(SDL_WindowData *data) SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0); } +static void +InitiateWindowMove(SDL_Window *window) +{ + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + SDL_GetWindowWMInfo(window, &info); + Display *display = info.info.x11.display; + + int bx, by, dx, dy; + SDL_GetWindowPosition(window, &bx, &by); + SDL_GetMouseState(&dx, &dy); + X11_XUngrabPointer(display, 0L); + X11_XFlush(display); + + XEvent evt; + evt.xclient.type = ClientMessage; + evt.xclient.window = info.info.x11.window; + evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", False); + evt.xclient.format = 32; + evt.xclient.data.l[0] = bx + dx; + evt.xclient.data.l[1] = by + dy; + evt.xclient.data.l[2] = 8; /* _NET_WM_MOVERESIZE_MOVE */ + evt.xclient.data.l[3] = Button1; + evt.xclient.data.l[4] = 0; + X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); + + X11_XSync(display, 0); +} + +static void +ProcessDragArea(SDL_WindowData* data) +{ + SDL_Window* window = data->window; + SDL_Mouse* mouse = SDL_GetMouse(); + int i; + const int num_areas = window->num_drag_areas; + const SDL_Point point = {mouse->x, mouse->y}; + const SDL_Rect *areas = window->drag_areas; + for(i = 0;i < num_areas;++i) { + if (SDL_PointInRect(&point, &areas[i])) { + InitiateWindowMove(window); + } + } +} + static void X11_DispatchEvent(_THIS) { @@ -709,6 +754,9 @@ X11_DispatchEvent(_THIS) if (X11_IsWheelEvent(display,&xevent,&ticks)) { SDL_SendMouseWheel(data->window, 0, 0, ticks); } else { + if(xevent.xbutton.button == SDL_BUTTON_LEFT) { + ProcessDragArea(data); + } SDL_SendMouseButton(data->window, 0, SDL_PRESSED, xevent.xbutton.button); } } diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index ca9faee31..4cece018e 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -457,6 +457,7 @@ X11_CreateDevice(int devindex) device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer; device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer; device->GetWindowWMInfo = X11_GetWindowWMInfo; + device->SetWindowDragAreas = X11_SetWindowDragAreas; device->shape_driver.CreateShaper = X11_CreateShaper; device->shape_driver.SetWindowShape = X11_SetWindowShape; diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index b4de15be8..2c0c9e41b 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -1444,6 +1444,12 @@ X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) } } +int +X11_SetWindowDragAreas(SDL_Window *window, const SDL_Rect *areas, int num_areas) +{ + return 0; // nothing to do, will be handled in event handler +} + #endif /* SDL_VIDEO_DRIVER_X11 */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index cf0d7f799..6a00c1a66 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -93,6 +93,7 @@ extern void X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed); extern void X11_DestroyWindow(_THIS, SDL_Window * window); extern SDL_bool X11_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); +extern int X11_SetWindowDragAreas(SDL_Window *window, const SDL_Rect *areas, int num_areas); #endif /* _SDL_x11window_h */ From 1b809cc89671e761f2e66e55f8ec690ecfc5007d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 27 May 2014 15:40:03 -0400 Subject: [PATCH 07/26] Some updates for the X11 drag areas work. --- src/video/x11/SDL_x11events.c | 53 +++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index db6a301d1..fc96d1b26 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -273,27 +273,24 @@ X11_DispatchUnmapNotify(SDL_WindowData *data) } static void -InitiateWindowMove(SDL_Window *window) +InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point) { - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - SDL_GetWindowWMInfo(window, &info); - Display *display = info.info.x11.display; + SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + SDL_Window* window = data->window; + Display *display = viddata->display; - int bx, by, dx, dy; - SDL_GetWindowPosition(window, &bx, &by); - SDL_GetMouseState(&dx, &dy); + /* !!! FIXME: we need to regrab this if necessary when the drag is done. */ X11_XUngrabPointer(display, 0L); X11_XFlush(display); XEvent evt; evt.xclient.type = ClientMessage; - evt.xclient.window = info.info.x11.window; + evt.xclient.window = data->xwindow; evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", False); evt.xclient.format = 32; - evt.xclient.data.l[0] = bx + dx; - evt.xclient.data.l[1] = by + dy; - evt.xclient.data.l[2] = 8; /* _NET_WM_MOVERESIZE_MOVE */ + evt.xclient.data.l[0] = window->x + point->x; + evt.xclient.data.l[1] = window->y + point->y; + evt.xclient.data.l[2] = 8; /* _NET_WM_MOVERESIZE_MOVE */ /* !!! FIXME: hardcoded 8? */ evt.xclient.data.l[3] = Button1; evt.xclient.data.l[4] = 0; X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); @@ -301,20 +298,26 @@ InitiateWindowMove(SDL_Window *window) X11_XSync(display, 0); } -static void -ProcessDragArea(SDL_WindowData* data) +static SDL_bool +ProcessDragArea(_THIS, const SDL_WindowData *data, const XEvent *xev) { - SDL_Window* window = data->window; - SDL_Mouse* mouse = SDL_GetMouse(); - int i; + const SDL_Window *window = data->window; const int num_areas = window->num_drag_areas; - const SDL_Point point = {mouse->x, mouse->y}; - const SDL_Rect *areas = window->drag_areas; - for(i = 0;i < num_areas;++i) { - if (SDL_PointInRect(&point, &areas[i])) { - InitiateWindowMove(window); + + if (num_areas > 0) { + const SDL_Point point = { xev->xbutton.x, xev->xbutton.y }; + const SDL_Rect *areas = window->drag_areas; + int i; + + for (i = 0; i < num_areas; i++) { + if (SDL_PointInRect(&point, &areas[i])) { + InitiateWindowMove(_this, data, &point); + return SDL_TRUE; /* dragging, drop this event. */ + } } } + + return SDL_FALSE; /* not a drag area. */ } static void @@ -754,8 +757,10 @@ X11_DispatchEvent(_THIS) if (X11_IsWheelEvent(display,&xevent,&ticks)) { SDL_SendMouseWheel(data->window, 0, 0, ticks); } else { - if(xevent.xbutton.button == SDL_BUTTON_LEFT) { - ProcessDragArea(data); + if(xevent.xbutton.button == Button1) { + if (ProcessDragArea(_this, data, &xevent)) { + break; /* don't pass this event on to app. */ + } } SDL_SendMouseButton(data->window, 0, SDL_PRESSED, xevent.xbutton.button); } From 51a004c734d0c1c76599c40e723975ec148ccbcb Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 27 May 2014 15:47:25 -0400 Subject: [PATCH 08/26] Don't hardcode an 8 here. --- src/video/x11/SDL_x11events.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index fc96d1b26..3d0de138b 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -40,6 +40,10 @@ #include +#ifndef _NET_WM_MOVERESIZE_MOVE +#define _NET_WM_MOVERESIZE_MOVE 8 +#endif + typedef struct { unsigned char *data; int format, count; @@ -290,7 +294,7 @@ InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point) evt.xclient.format = 32; evt.xclient.data.l[0] = window->x + point->x; evt.xclient.data.l[1] = window->y + point->y; - evt.xclient.data.l[2] = 8; /* _NET_WM_MOVERESIZE_MOVE */ /* !!! FIXME: hardcoded 8? */ + evt.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE; evt.xclient.data.l[3] = Button1; evt.xclient.data.l[4] = 0; X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); From 9e98d09104891db10695cc0b673da0c97b8fbbd2 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 28 May 2014 01:22:47 -0400 Subject: [PATCH 09/26] Changed drag area API to a hit-testing API. There were several good arguments for this: it's how Windows works with WM_NCHITTEST, SDL doesn't need to manage a list of rects, it allows more control over the regions (how do you use rects to cleanly surround a circular button?), the callback can be more optimized than a iterating a list of rects, and you don't have to send an updated list of rects whenever the window resizes or layout changes. --HG-- rename : test/testdragareas.c => test/testhittesting.c --- .hgignore | 2 +- include/SDL_video.h | 62 ++++++++++++---------- src/dynapi/SDL_dynapi_overrides.h | 2 +- src/dynapi/SDL_dynapi_procs.h | 2 +- src/video/SDL_sysvideo.h | 8 +-- src/video/SDL_video.c | 33 ++++-------- src/video/cocoa/SDL_cocoavideo.m | 2 +- src/video/cocoa/SDL_cocoawindow.h | 5 +- src/video/cocoa/SDL_cocoawindow.m | 32 +++++------ src/video/x11/SDL_x11events.c | 21 +++----- src/video/x11/SDL_x11video.c | 2 +- src/video/x11/SDL_x11window.c | 4 +- src/video/x11/SDL_x11window.h | 2 +- test/Makefile.in | 4 +- test/{testdragareas.c => testhittesting.c} | 41 ++++++++------ 15 files changed, 106 insertions(+), 116 deletions(-) rename test/{testdragareas.c => testhittesting.c} (78%) diff --git a/.hgignore b/.hgignore index 37ab96a3d..881425470 100644 --- a/.hgignore +++ b/.hgignore @@ -55,7 +55,6 @@ test/loopwave test/testatomic test/testaudioinfo test/testautomation -test/testdragareas test/testdraw2 test/testerror test/testfile @@ -64,6 +63,7 @@ test/testgesture test/testgl2 test/testgles test/testhaptic +test/testhittesting test/testiconv test/testime test/testintersections diff --git a/include/SDL_video.h b/include/SDL_video.h index f096d7ff0..6ccb115b3 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -791,43 +791,51 @@ extern DECLSPEC int SDLCALL SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * green, Uint16 * blue); +typedef enum +{ + SDL_HITTEST_NORMAL, /**< Region is normal. No special properties. */ + SDL_HITTEST_DRAGGABLE, /**< Region can drag entire window. */ + /* !!! FIXME: resize enums here. */ +} SDL_HitTestResult; + +typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(SDL_Window *win, + const SDL_Point *area, + void *data); + /** - * \brief Define regions of a window that can be used to drag it. + * \brief Provide a callback that decides if a window region has special properties. * - * Normally windows are dragged by decorations provided by the system - * window manager (usually, a title bar), but for some apps, it makes sense - * to drag them from somewhere else inside the window itself; for example, - * one might have a borderless window that wants to be draggable from any - * part, or simulate its own title bar, etc. + * Normally windows are dragged and resized by decorations provided by the + * system window manager (a title bar, borders, etc), but for some apps, it + * makes sense to drag them from somewhere else inside the window itself; for + * example, one might have a borderless window that wants to be draggable + * from any part, or simulate its own title bar, etc. * - * This method designates pieces of a given window as "drag areas," which - * will move the window when the user drags with his mouse, as if she had - * used the titlebar. - * - * You may specify multiple drag areas, disconnected or overlapping. This - * function accepts an array of rectangles. Each call to this function will - * replace any previously-defined drag areas. To disable drag areas on a - * window, call this function with a NULL array of zero elements. - * - * Drag areas do not automatically resize. If your window changes dimensions - * you should plan to re-call this function with new drag areas if - * appropriate. + * This function lets the app provide a callback that designates pieces of + * a given window as special. This callback is run during event processing + * if we need to tell the OS to treat a region of the window specially; the + * use of this callback is known as "hit testing." * * Mouse input may not be delivered to your application if it is within - * a drag area; the OS will often apply that input to moving the window and - * not deliver it to the application. + * a special area; the OS will often apply that input to moving the window or + * resizing the window and not deliver it to the application. + * + * Specifying NULL for a callback disables hit-testing. Hit-testing is + * disabled by default. * * Platforms that don't support this functionality will return -1 - * unconditionally, even if you're attempting to disable drag areas. + * unconditionally, even if you're attempting to disable hit-testing. * - * \param window The window to set drag areas on. - * \param areas An array of SDL_Rects containing num_areas elements. - * \param num_areas The number of elements in the areas parameter. + * Your callback may fire at any time. + * + * \param window The window to set hit-testing on. + * \param callback The callback to call when doing a hit-test. + * \param callback_data An app-defined void pointer passed to the callback. * \return 0 on success, -1 on error (including unsupported). */ -extern DECLSPEC int SDLCALL SDL_SetWindowDragAreas(SDL_Window * window, - const SDL_Rect *areas, - int num_areas); +extern DECLSPEC int SDLCALL SDL_SetWindowHitTest(SDL_Window * window, + SDL_HitTest callback, + void *callback_data); /** * \brief Destroy a window. diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index b44378d51..ce1117529 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -580,4 +580,4 @@ #define SDL_WinRTGetFSPathUTF8 SDL_WinRTGetFSPathUTF8_REAL #define SDL_WinRTRunApp SDL_WinRTRunApp_REAL #define SDL_CaptureMouse SDL_CaptureMouse_REAL -#define SDL_SetWindowDragAreas SDL_SetWindowDragAreas_REAL +#define SDL_SetWindowHitTest SDL_SetWindowHitTest_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 232a8e927..ba78b98ad 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -613,4 +613,4 @@ SDL_DYNAPI_PROC(const char*,SDL_WinRTGetFSPathUTF8,(SDL_WinRT_Path a),(a),return 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_SetWindowDragAreas,(SDL_Window *a, const SDL_Rect *b, int c),(a,b,c),return) +SDL_DYNAPI_PROC(int,SDL_SetWindowHitTest,(SDL_Window *a, SDL_HitTest b, void *c),(a,b,c),return) diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 17a316490..7029738a7 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -97,8 +97,8 @@ struct SDL_Window SDL_WindowShaper *shaper; - int num_drag_areas; - SDL_Rect *drag_areas; + SDL_HitTest hit_test; + void *hit_test_data; SDL_WindowUserData *data; @@ -264,8 +264,8 @@ struct SDL_VideoDevice /* MessageBox */ int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid); - /* Drag areas. Note that (areas) and (num_areas) are also copied to the SDL_Window for you after this call. */ - int (*SetWindowDragAreas)(SDL_Window * window, const SDL_Rect *areas, int num_areas); + /* Hit-testing */ + int (*SetWindowHitTest)(SDL_Window * window, SDL_bool enabled); /* * * */ /* Data common to all drivers */ diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 3476fa748..86365d07c 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1411,8 +1411,8 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags) SDL_FreeSurface(icon); } - if (window->num_drag_areas > 0) { - _this->SetWindowDragAreas(window, window->drag_areas, window->num_drag_areas); + if (window->hit_test > 0) { + _this->SetWindowHitTest(window, SDL_TRUE); } SDL_FinishWindowCreation(window, flags); @@ -2310,8 +2310,6 @@ SDL_DestroyWindow(SDL_Window * window) _this->windows = window->next; } - SDL_free(window->drag_areas); - SDL_free(window); } @@ -3388,33 +3386,20 @@ SDL_ShouldAllowTopmost(void) } int -SDL_SetWindowDragAreas(SDL_Window * window, const SDL_Rect *_areas, int num_areas) +SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata) { - SDL_Rect *areas = NULL; - CHECK_WINDOW_MAGIC(window, -1); - if (!_this->SetWindowDragAreas) { + if (!_this->SetWindowHitTest) { return SDL_Unsupported(); - } - - if (num_areas > 0) { - const size_t len = sizeof (SDL_Rect) * num_areas; - areas = (SDL_Rect *) SDL_malloc(len); - if (!areas) { - return SDL_OutOfMemory(); - } - SDL_memcpy(areas, _areas, len); - } - - if (_this->SetWindowDragAreas(window, areas, num_areas) == -1) { - SDL_free(areas); + } else if (_this->SetWindowHitTest(window, callback != NULL) == -1) { return -1; } - SDL_free(window->drag_areas); - window->drag_areas = areas; - window->num_drag_areas = num_areas; + window->hit_test = callback; + window->hit_test_data = userdata; + + return 0; } /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index a24770b4d..41670378f 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -108,7 +108,7 @@ Cocoa_CreateDevice(int devindex) device->SetWindowGrab = Cocoa_SetWindowGrab; device->DestroyWindow = Cocoa_DestroyWindow; device->GetWindowWMInfo = Cocoa_GetWindowWMInfo; - device->SetWindowDragAreas = Cocoa_SetWindowDragAreas; + device->SetWindowHitTest = Cocoa_SetWindowHitTest; device->shape_driver.CreateShaper = Cocoa_CreateShaper; device->shape_driver.SetWindowShape = Cocoa_SetWindowShape; diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h index bfa461054..de75092ca 100644 --- a/src/video/cocoa/SDL_cocoawindow.h +++ b/src/video/cocoa/SDL_cocoawindow.h @@ -77,7 +77,7 @@ typedef enum -(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions; /* See if event is in a drag area, toggle on window dragging. */ --(BOOL) processDragArea:(NSEvent *)theEvent; +-(BOOL) processHitTest:(NSEvent *)theEvent; /* Window event handling */ -(void) mouseDown:(NSEvent *) theEvent; @@ -119,7 +119,6 @@ struct SDL_WindowData SDL_bool inWindowMove; Cocoa_WindowListener *listener; struct SDL_VideoData *videodata; - NSView *dragarea; }; extern int Cocoa_CreateWindow(_THIS, SDL_Window * window); @@ -144,7 +143,7 @@ extern int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp); extern void Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed); extern void Cocoa_DestroyWindow(_THIS, SDL_Window * window); extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); -extern int Cocoa_SetWindowDragAreas(SDL_Window *window, const SDL_Rect *areas, int num_areas); +extern int Cocoa_SetWindowHitTest(SDL_Window *window, SDL_bool enabled); #endif /* _SDL_cocoawindow_h */ diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 3d94b133b..18ae07dbb 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -657,26 +657,20 @@ SetWindowStyle(SDL_Window * window, unsigned int style) /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/ } -- (BOOL)processDragArea:(NSEvent *)theEvent +- (BOOL)processHitTest:(NSEvent *)theEvent { - const int num_areas = _data->window->num_drag_areas; - SDL_assert(isDragAreaRunning == [_data->nswindow isMovableByWindowBackground]); - SDL_assert((num_areas > 0) || !isDragAreaRunning); - if (num_areas > 0) { /* if no drag areas, skip this. */ - int i; + if (_data->window->hit_test) { /* if no hit-test, skip this. */ const NSPoint location = [theEvent locationInWindow]; const SDL_Point point = { (int) location.x, _data->window->h - (((int) location.y)-1) }; - const SDL_Rect *areas = _data->window->drag_areas; - for (i = 0; i < num_areas; i++) { - if (SDL_PointInRect(&point, &areas[i])) { - if (!isDragAreaRunning) { - isDragAreaRunning = YES; - [_data->nswindow setMovableByWindowBackground:YES]; - } - return YES; /* started a new drag! */ + const SDL_HitTestResult rc = _data->window->hit_test(_data->window, &point, _data->window->hit_test_data); + if (rc == SDL_HITTEST_DRAGGABLE) { + if (!isDragAreaRunning) { + isDragAreaRunning = YES; + [_data->nswindow setMovableByWindowBackground:YES]; } + return YES; /* dragging! */ } } @@ -686,14 +680,14 @@ SetWindowStyle(SDL_Window * window, unsigned int style) return YES; /* was dragging, drop event. */ } - return NO; /* not a drag area, carry on. */ + return NO; /* not a special area, carry on. */ } - (void)mouseDown:(NSEvent *)theEvent { int button; - if ([self processDragArea:theEvent]) { + if ([self processHitTest:theEvent]) { return; /* dragging, drop event. */ } @@ -735,7 +729,7 @@ SetWindowStyle(SDL_Window * window, unsigned int style) { int button; - if ([self processDragArea:theEvent]) { + if ([self processHitTest:theEvent]) { return; /* stopped dragging, drop event. */ } @@ -778,7 +772,7 @@ SetWindowStyle(SDL_Window * window, unsigned int style) NSPoint point; int x, y; - if ([self processDragArea:theEvent]) { + if ([self processHitTest:theEvent]) { return; /* dragging, drop event. */ } @@ -1599,7 +1593,7 @@ Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state) } int -Cocoa_SetWindowDragAreas(SDL_Window * window, const SDL_Rect *areas, int num_areas) +Cocoa_SetWindowHitTest(SDL_Window * window, SDL_bool enabled) { return 0; /* just succeed, the real work is done elsewhere. */ } diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 3d0de138b..45b6083c1 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -303,21 +303,16 @@ InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point) } static SDL_bool -ProcessDragArea(_THIS, const SDL_WindowData *data, const XEvent *xev) +ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev) { - const SDL_Window *window = data->window; - const int num_areas = window->num_drag_areas; + SDL_Window *window = data->window; - if (num_areas > 0) { + if (window->hit_test) { const SDL_Point point = { xev->xbutton.x, xev->xbutton.y }; - const SDL_Rect *areas = window->drag_areas; - int i; - - for (i = 0; i < num_areas; i++) { - if (SDL_PointInRect(&point, &areas[i])) { - InitiateWindowMove(_this, data, &point); - return SDL_TRUE; /* dragging, drop this event. */ - } + const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); + if (rc == SDL_HITTEST_DRAGGABLE) { + InitiateWindowMove(_this, data, &point); + return SDL_TRUE; /* dragging, drop this event. */ } } @@ -762,7 +757,7 @@ X11_DispatchEvent(_THIS) SDL_SendMouseWheel(data->window, 0, 0, ticks); } else { if(xevent.xbutton.button == Button1) { - if (ProcessDragArea(_this, data, &xevent)) { + if (ProcessHitTest(_this, data, &xevent)) { break; /* don't pass this event on to app. */ } } diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index 4cece018e..d1b043c55 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -457,7 +457,7 @@ X11_CreateDevice(int devindex) device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer; device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer; device->GetWindowWMInfo = X11_GetWindowWMInfo; - device->SetWindowDragAreas = X11_SetWindowDragAreas; + device->SetWindowHitTest = X11_SetWindowHitTest; device->shape_driver.CreateShaper = X11_CreateShaper; device->shape_driver.SetWindowShape = X11_SetWindowShape; diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 2c0c9e41b..fe883cb41 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -1445,9 +1445,9 @@ X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) } int -X11_SetWindowDragAreas(SDL_Window *window, const SDL_Rect *areas, int num_areas) +X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled) { - return 0; // nothing to do, will be handled in event handler + return 0; /* just succeed, the real work is done elsewhere. */ } #endif /* SDL_VIDEO_DRIVER_X11 */ diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index 6a00c1a66..789d2f7cc 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -93,7 +93,7 @@ extern void X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed); extern void X11_DestroyWindow(_THIS, SDL_Window * window); extern SDL_bool X11_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); -extern int X11_SetWindowDragAreas(SDL_Window *window, const SDL_Rect *areas, int num_areas); +extern int X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled); #endif /* _SDL_x11window_h */ diff --git a/test/Makefile.in b/test/Makefile.in index a0476137f..227bd0eb0 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -12,7 +12,6 @@ TARGETS = \ loopwave$(EXE) \ testaudioinfo$(EXE) \ testautomation$(EXE) \ - testdragareas$(EXE) \ testdraw2$(EXE) \ testdrawchessboard$(EXE) \ testdropfile$(EXE) \ @@ -24,6 +23,7 @@ TARGETS = \ testgles$(EXE) \ testgles2$(EXE) \ testhaptic$(EXE) \ + testhittesting$(EXE) \ testrumble$(EXE) \ testhotplug$(EXE) \ testthread$(EXE) \ @@ -109,7 +109,7 @@ testintersections$(EXE): $(srcdir)/testintersections.c testrelative$(EXE): $(srcdir)/testrelative.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) -testdragareas$(EXE): $(srcdir)/testdragareas.c +testhittesting$(EXE): $(srcdir)/testhittesting.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) testdraw2$(EXE): $(srcdir)/testdraw2.c diff --git a/test/testdragareas.c b/test/testhittesting.c similarity index 78% rename from test/testdragareas.c rename to test/testhittesting.c index 776f06131..1e3867862 100644 --- a/test/testdragareas.c +++ b/test/testhittesting.c @@ -3,28 +3,42 @@ /* !!! FIXME: rewrite this to be wired in to test framework. */ +const SDL_Rect drag_areas[] = { + { 20, 20, 100, 100 }, + { 200, 70, 100, 100 }, + { 400, 90, 100, 100 } +}; + +static const SDL_Rect *areas = drag_areas; +static int numareas = SDL_arraysize(drag_areas); + +static SDL_HitTestResult +hitTest(SDL_Window *window, const SDL_Point *pt, void *data) +{ + int i; + for (i = 0; i < numareas; i++) { + if (SDL_PointInRect(pt, &areas[i])) { + return SDL_HITTEST_DRAGGABLE; + } + } + + return SDL_HITTEST_NORMAL; +} + + int main(int argc, char **argv) { int done = 0; SDL_Window *window; SDL_Renderer *renderer; - const SDL_Rect drag_areas[] = { - { 20, 20, 100, 100 }, - { 200, 70, 100, 100 }, - { 400, 90, 100, 100 } - }; - - const SDL_Rect *areas = drag_areas; - int numareas = SDL_arraysize(drag_areas); - /* !!! FIXME: check for errors. */ SDL_Init(SDL_INIT_VIDEO); window = SDL_CreateWindow("Drag the red boxes", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_BORDERLESS); renderer = SDL_CreateRenderer(window, -1, 0); - if (SDL_SetWindowDragAreas(window, areas, numareas) == -1) { - fprintf(stderr, "Setting drag areas failed!\n"); + if (SDL_SetWindowHitTest(window, hitTest, NULL) == -1) { + fprintf(stderr, "Enabling hit-testing failed!\n"); SDL_Quit(); return 1; } @@ -69,11 +83,6 @@ int main(int argc, char **argv) areas = NULL; numareas = 0; } - if (SDL_SetWindowDragAreas(window, areas, numareas) == -1) { - fprintf(stderr, "Setting drag areas failed!\n"); - SDL_Quit(); - return 1; - } } break; From bcf0b098790fe95d4e5bcf3c8a2b524a40d1f71b Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 28 May 2014 01:27:27 -0400 Subject: [PATCH 10/26] Added a few debug printf() calls. --- test/testhittesting.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/testhittesting.c b/test/testhittesting.c index 1e3867862..5d347ad6d 100644 --- a/test/testhittesting.c +++ b/test/testhittesting.c @@ -18,10 +18,12 @@ hitTest(SDL_Window *window, const SDL_Point *pt, void *data) int i; for (i = 0; i < numareas; i++) { if (SDL_PointInRect(pt, &areas[i])) { + printf("HIT-TEST: DRAGGABLE\n"); return SDL_HITTEST_DRAGGABLE; } } + printf("HIT-TEST: NORMAL\n"); return SDL_HITTEST_NORMAL; } From c6b34e9e1e18eba340cf59645ed059cc4fa48365 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 29 May 2014 13:38:39 -0400 Subject: [PATCH 11/26] Tweaked hit-testing documentation. --HG-- extra : rebase_source : df2f9ccdddf408e5aaf7e788a1983ce8fef13d46 --- include/SDL_video.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/include/SDL_video.h b/include/SDL_video.h index 6ccb115b3..7d52e6a51 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -791,6 +791,11 @@ extern DECLSPEC int SDLCALL SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * green, Uint16 * blue); +/** + * \brief Possible return values from the SDL_HitTest callback. + * + * \sa SDL_HitTest + */ typedef enum { SDL_HITTEST_NORMAL, /**< Region is normal. No special properties. */ @@ -798,6 +803,11 @@ typedef enum /* !!! FIXME: resize enums here. */ } SDL_HitTestResult; +/** + * \brief Callback used for hit-testing. + * + * \sa SDL_SetWindowHitTest + */ typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(SDL_Window *win, const SDL_Point *area, void *data); @@ -826,7 +836,13 @@ typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(SDL_Window *win, * Platforms that don't support this functionality will return -1 * unconditionally, even if you're attempting to disable hit-testing. * - * Your callback may fire at any time. + * Your callback may fire at any time, and its firing does not indicate any + * specific behavior (for example, on Windows, this certainly might fire + * when the OS is deciding whether to drag your window, but it fires for lots + * of other reasons, too, some unrelated to anything you probably care about + * _and when the mouse isn't actually at the location it is testing_). + * Since this can fire at any time, you should try to keep your callback + * efficient, devoid of allocations, etc. * * \param window The window to set hit-testing on. * \param callback The callback to call when doing a hit-test. From 7cc0821ab0a5713f96698df61cd588c6f1258e63 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 29 May 2014 13:39:02 -0400 Subject: [PATCH 12/26] First shot (not even compiled) at Windows hit-testing support. --HG-- extra : rebase_source : 0563e3a3584a43403b46a8e89477deba4c502430 --- src/video/windows/SDL_windowsevents.c | 15 +++++++++++++++ src/video/windows/SDL_windowsvideo.c | 1 + src/video/windows/SDL_windowswindow.c | 6 ++++++ src/video/windows/SDL_windowswindow.h | 1 + 4 files changed, 23 insertions(+) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 78eeff9b5..48cf350d3 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -865,6 +865,21 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; } break; + + case WM_NCHITTEST: + { + SDL_Window *window = data->window; + if (window->hit_test) { + const SDL_Point point = { (int) LOWORD(lParam), (int) HIWORD(lParam) }; + const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); + if (rc == SDL_HITTEST_DRAGGABLE) { + return HTCAPTION; + } + // if we didn't return, this will call DefWindowProc below. + } + } + break; + } /* If there's a window proc, assume it's going to handle messages */ diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index 9ab1f4c1a..2bc220eb2 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -121,6 +121,7 @@ WIN_CreateDevice(int devindex) device->UpdateWindowFramebuffer = WIN_UpdateWindowFramebuffer; device->DestroyWindowFramebuffer = WIN_DestroyWindowFramebuffer; device->OnWindowEnter = WIN_OnWindowEnter; + device->SetWindowHitTest = WIN_SetWindowHitTest; device->shape_driver.CreateShaper = Win32_CreateShaper; device->shape_driver.SetWindowShape = Win32_SetWindowShape; diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 38e97a71f..25372f957 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -782,6 +782,12 @@ WIN_UpdateClipCursor(SDL_Window *window) } } +int +WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled) +{ + return 0; /* just succeed, the real work is done elsewhere. */ +} + #endif /* SDL_VIDEO_DRIVER_WINDOWS */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index c42888744..7fcb17440 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -68,6 +68,7 @@ extern SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); extern void WIN_OnWindowEnter(_THIS, SDL_Window * window); extern void WIN_UpdateClipCursor(SDL_Window *window); +extern int WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled); #endif /* _SDL_windowswindow_h */ From 719a77b576dc3a92533dcd2af333e30eadad4088 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 30 May 2014 01:48:08 -0400 Subject: [PATCH 13/26] Make some printf() calls into SDL_Log() so I can see them on Windows. :) --- src/test/SDL_test_common.c | 2 +- test/testhittesting.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index e304a76e0..2c4cabc7c 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1386,7 +1386,7 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done) if (current_win) { const SDL_bool shouldCapture = (SDL_GetWindowFlags(current_win) & SDL_WINDOW_MOUSE_CAPTURE) == 0; const int rc = SDL_CaptureMouse(shouldCapture); - printf("%sapturing mouse %s!\n", shouldCapture ? "C" : "Unc", (rc == 0) ? "succeeded" : "failed"); + SDL_Log("%sapturing mouse %s!\n", shouldCapture ? "C" : "Unc", (rc == 0) ? "succeeded" : "failed"); } } break; diff --git a/test/testhittesting.c b/test/testhittesting.c index 5d347ad6d..4ac535caf 100644 --- a/test/testhittesting.c +++ b/test/testhittesting.c @@ -18,12 +18,12 @@ hitTest(SDL_Window *window, const SDL_Point *pt, void *data) int i; for (i = 0; i < numareas; i++) { if (SDL_PointInRect(pt, &areas[i])) { - printf("HIT-TEST: DRAGGABLE\n"); + SDL_Log("HIT-TEST: DRAGGABLE\n"); return SDL_HITTEST_DRAGGABLE; } } - printf("HIT-TEST: NORMAL\n"); + SDL_Log("HIT-TEST: NORMAL\n"); return SDL_HITTEST_NORMAL; } @@ -40,7 +40,7 @@ int main(int argc, char **argv) renderer = SDL_CreateRenderer(window, -1, 0); if (SDL_SetWindowHitTest(window, hitTest, NULL) == -1) { - fprintf(stderr, "Enabling hit-testing failed!\n"); + SDL_Log("Enabling hit-testing failed!\n"); SDL_Quit(); return 1; } @@ -61,16 +61,16 @@ int main(int argc, char **argv) switch (e.type) { case SDL_MOUSEBUTTONDOWN: - printf("button down!\n"); + SDL_Log("button down!\n"); break; case SDL_MOUSEBUTTONUP: - printf("button up!\n"); + SDL_Log("button up!\n"); break; case SDL_WINDOWEVENT: if (e.window.event == SDL_WINDOWEVENT_MOVED) { - printf("Window event moved to (%d, %d)!\n", (int) e.window.data1, (int) e.window.data2); + SDL_Log("Window event moved to (%d, %d)!\n", (int) e.window.data1, (int) e.window.data2); } break; From 9fb513d81ffd80b490c0ff454ee642664b4991ab Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 30 May 2014 01:48:26 -0400 Subject: [PATCH 14/26] Patched to compile on Visual Studio. --- test/testhittesting.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/testhittesting.c b/test/testhittesting.c index 4ac535caf..f6ae4ee70 100644 --- a/test/testhittesting.c +++ b/test/testhittesting.c @@ -47,14 +47,15 @@ int main(int argc, char **argv) while (!done) { + SDL_Event e; + int nothing_to_do = 1; + SDL_SetRenderDrawColor(renderer, 0, 0, 127, 255); SDL_RenderClear(renderer); SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); SDL_RenderFillRects(renderer, areas, SDL_arraysize(drag_areas)); SDL_RenderPresent(renderer); - SDL_Event e; - int nothing_to_do = 1; while (SDL_PollEvent(&e)) { nothing_to_do = 0; From 9efc4a5fdd8a551de563c65bff69d1f18d8dcc90 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 30 May 2014 01:49:26 -0400 Subject: [PATCH 15/26] Fixed hit-testing on Windows. Needed to convert from screen to client coords. --- src/video/windows/SDL_windowsevents.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 48cf350d3..b04a7a20e 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -870,10 +870,13 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { SDL_Window *window = data->window; if (window->hit_test) { - const SDL_Point point = { (int) LOWORD(lParam), (int) HIWORD(lParam) }; - const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); - if (rc == SDL_HITTEST_DRAGGABLE) { - return HTCAPTION; + POINT winpoint = { (int) LOWORD(lParam), (int) HIWORD(lParam) }; + if (ScreenToClient(data->hwnd, &winpoint)) { + const SDL_Point point = { (int) winpoint.x, (int) winpoint.y }; + const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); + if (rc == SDL_HITTEST_DRAGGABLE) { + return HTCAPTION; + } } // if we didn't return, this will call DefWindowProc below. } From be872bff15966a60d2358972ab083b3e565b61ee Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 30 May 2014 01:51:13 -0400 Subject: [PATCH 16/26] Fixed up SDL_CaptureMouse() on Windows to work like I expected. This would have been a one-line patch to the documentation (specifying that captures only work as long as the left mouse button is pressed), but I didn't like that, so I got a little crazy about this instead. --- src/video/windows/SDL_windowsevents.c | 55 ++++++++++++++------ src/video/windows/SDL_windowsmouse.c | 75 +++++++++++++++++++-------- 2 files changed, 93 insertions(+), 37 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index b04a7a20e..6b7621505 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -30,6 +30,7 @@ #include "../../events/SDL_events_c.h" #include "../../events/SDL_touch_c.h" #include "../../events/scancodes_windows.h" +#include "SDL_assert.h" /* Dropfile support */ #include @@ -428,33 +429,55 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) HRAWINPUT hRawInput = (HRAWINPUT)lParam; RAWINPUT inp; UINT size = sizeof(inp); + const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp; + const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0); - if (!mouse->relative_mode || mouse->relative_mode_warp || mouse->focus != data->window) { - break; + if (!isRelative || mouse->focus != data->window) { + if (!isCapture) { + break; + } } GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER)); /* Mouse data */ if (inp.header.dwType == RIM_TYPEMOUSE) { - RAWMOUSE* mouse = &inp.data.mouse; + if (isRelative) { + RAWMOUSE* mouse = &inp.data.mouse; + + if ((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) { + SDL_SendMouseMotion(data->window, 0, 1, (int)mouse->lLastX, (int)mouse->lLastY); + } else { + /* synthesize relative moves from the abs position */ + static SDL_Point initialMousePoint; + if (initialMousePoint.x == 0 && initialMousePoint.y == 0) { + initialMousePoint.x = mouse->lLastX; + initialMousePoint.y = mouse->lLastY; + } + + SDL_SendMouseMotion(data->window, 0, 1, (int)(mouse->lLastX-initialMousePoint.x), (int)(mouse->lLastY-initialMousePoint.y) ); - if ((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) { - SDL_SendMouseMotion(data->window, 0, 1, (int)mouse->lLastX, (int)mouse->lLastY); - } else { - /* synthesize relative moves from the abs position */ - static SDL_Point initialMousePoint; - if (initialMousePoint.x == 0 && initialMousePoint.y == 0) { initialMousePoint.x = mouse->lLastX; initialMousePoint.y = mouse->lLastY; } - - SDL_SendMouseMotion(data->window, 0, 1, (int)(mouse->lLastX-initialMousePoint.x), (int)(mouse->lLastY-initialMousePoint.y) ); - - initialMousePoint.x = mouse->lLastX; - initialMousePoint.y = mouse->lLastY; + WIN_CheckRawMouseButtons( mouse->usButtonFlags, data ); + } else if (isCapture) { + /* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */ + POINT pt; + HWND hwnd = data->hwnd; + GetCursorPos(&pt); + if (WindowFromPoint(pt) != hwnd) { /* if in the window, WM_MOUSEMOVE, etc, will cover it. */ + ScreenToClient(data->hwnd, &pt); + SDL_SendMouseMotion(data->window, 0, 0, (int) pt.x, (int) pt.y); + SDL_SendMouseButton(data->window, 0, GetKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT); + SDL_SendMouseButton(data->window, 0, GetKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT); + SDL_SendMouseButton(data->window, 0, GetKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE); + SDL_SendMouseButton(data->window, 0, GetKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1); + SDL_SendMouseButton(data->window, 0, GetKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2); + } + } else { + SDL_assert(0 && "Shouldn't happen"); } - WIN_CheckRawMouseButtons( mouse->usButtonFlags, data ); } } break; @@ -499,7 +522,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) #ifdef WM_MOUSELEAVE case WM_MOUSELEAVE: - if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode) { + if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) { if (!IsIconic(hwnd)) { POINT cursorPos; GetCursorPos(&cursorPos); diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index 1f38dcd55..0abd21240 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -30,6 +30,44 @@ HCURSOR SDL_cursor = NULL; +static int rawInputEnableCount = 0; + +static int +ToggleRawInput(SDL_bool enabled) +{ + RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */ + + if (enabled) { + rawInputEnableCount++; + if (rawInputEnableCount > 1) { + return 0; /* already done. */ + } + } else { + if (rawInputEnableCount == 0) { + return 0; /* already done. */ + } + rawInputEnableCount--; + if (rawInputEnableCount > 0) { + return 0; /* not time to disable yet */ + } + } + + if (!enabled) { + rawMouse.dwFlags |= RIDEV_REMOVE; + } + + /* (Un)register raw input for mice */ + if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) { + + /* Only return an error when registering. If we unregister and fail, + then it's probably that we unregistered twice. That's OK. */ + if (enabled) { + return SDL_Unsupported(); + } + } + return 0; +} + static SDL_Cursor * WIN_CreateDefaultCursor() @@ -201,35 +239,25 @@ WIN_WarpMouse(SDL_Window * window, int x, int y) static int WIN_SetRelativeMouseMode(SDL_bool enabled) { - RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */ - - if (!enabled) { - rawMouse.dwFlags |= RIDEV_REMOVE; - } - - /* (Un)register raw input for mice */ - if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) { - - /* Only return an error when registering. If we unregister and fail, - then it's probably that we unregistered twice. That's OK. */ - if (enabled) { - return SDL_Unsupported(); - } - } - return 0; + return ToggleRawInput(enabled); } static int WIN_CaptureMouse(SDL_Window *window) { if (!window) { - ReleaseCapture(); - } else { - const SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - SetCapture(data->hwnd); + SDL_Window *focusWin = SDL_GetKeyboardFocus(); + if (focusWin) { + SDL_WindowData *data = (SDL_WindowData *)focusWin->driverdata; + WIN_OnWindowEnter(SDL_GetVideoDevice(), focusWin); /* make sure WM_MOUSELEAVE messages are (re)enabled. */ + } } - return 0; + /* While we were thinking of SetCapture() when designing this API in SDL, + we didn't count on the fact that SetCapture() only tracks while the + left mouse button is held down! Instead, we listen for raw mouse input + and manually query the mouse when it leaves the window. :/ */ + return ToggleRawInput(window != NULL); } void @@ -259,6 +287,11 @@ WIN_QuitMouse(_THIS) mouse->def_cursor = NULL; mouse->cur_cursor = NULL; } + + if (rawInputEnableCount) { /* force RAWINPUT off here. */ + rawInputEnableCount = 1; + ToggleRawInput(SDL_FALSE); + } } #endif /* SDL_VIDEO_DRIVER_WINDOWS */ From 5319c669a66230eb61d552a2e8ab014287ea5cf4 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 30 May 2014 09:50:47 -0400 Subject: [PATCH 17/26] Fixed using SDL_PointInRect() from C++. --- include/SDL_rect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SDL_rect.h b/include/SDL_rect.h index e170a0163..6bfce3115 100644 --- a/include/SDL_rect.h +++ b/include/SDL_rect.h @@ -73,7 +73,7 @@ typedef struct SDL_Rect SDL_FORCE_INLINE SDL_bool SDL_PointInRect(const SDL_Point *p, const SDL_Rect *r) { return ( (p->x >= r->x) && (p->x < (r->x + r->w)) && - (p->y >= r->y) && (p->y < (r->y + r->h)) ); + (p->y >= r->y) && (p->y < (r->y + r->h)) ) ? SDL_TRUE : SDL_FALSE; } /** From 0c8f5f80b1e2dfb01e87624a80b558ca6c35d425 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 5 Jun 2014 00:02:42 -0400 Subject: [PATCH 18/26] Added some (harmlessly) missing braces. --- src/events/SDL_mouse.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 3ed1d1418..757c63490 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -474,11 +474,13 @@ SDL_WarpMouseInWindow(SDL_Window * window, int x, int y) { SDL_Mouse *mouse = SDL_GetMouse(); - if ( window == NULL ) + if ( window == NULL ) { window = mouse->focus; + } - if ( window == NULL ) + if ( window == NULL ) { return; + } if (mouse->WarpMouse) { mouse->WarpMouse(window, x, y); From c076f51669748994d636a5b200c660c6c5c04b53 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 5 Jun 2014 00:03:33 -0400 Subject: [PATCH 19/26] Implemented SDL_GetAbsoluteMouseState(). X11 only for now, but this should be doable on every platform, I think. --- include/SDL_mouse.h | 25 +++++++++++++++++++++++ src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + src/events/SDL_mouse.c | 24 ++++++++++++++++++++++ src/events/SDL_mouse_c.h | 3 +++ src/test/SDL_test_common.c | 13 ++++++++++++ src/video/x11/SDL_x11mouse.c | 34 +++++++++++++++++++++++++++++++ 7 files changed, 101 insertions(+) diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h index 571754ad2..fdb68f040 100644 --- a/include/SDL_mouse.h +++ b/include/SDL_mouse.h @@ -77,6 +77,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. * diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index ce1117529..aa996399e 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 ba78b98ad..1df122257 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 757c63490..970cc78c1 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 34cd259e6..70b3ec0b3 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 2c4cabc7c..fa6c1fea9 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 74dc8789c..7386da5fb 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()); } From 3465f8e461b2e5e934c506eeea741fc85bee8c24 Mon Sep 17 00:00:00 2001 From: Ionut Leonte Date: Thu, 5 Jun 2014 00:45:16 -0400 Subject: [PATCH 20/26] Added SDL_HITTEST_RESIZE_*, and implemented for X11. --- include/SDL_video.h | 9 ++- src/video/x11/SDL_x11events.c | 119 ++++++++++++++++++++++++++++++++-- test/testhittesting.c | 24 ++++++- 3 files changed, 144 insertions(+), 8 deletions(-) diff --git a/include/SDL_video.h b/include/SDL_video.h index 7d52e6a51..4a2fb0458 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -800,7 +800,14 @@ typedef enum { SDL_HITTEST_NORMAL, /**< Region is normal. No special properties. */ SDL_HITTEST_DRAGGABLE, /**< Region can drag entire window. */ - /* !!! FIXME: resize enums here. */ + SDL_HITTEST_RESIZE_TOPLEFT, + SDL_HITTEST_RESIZE_TOP, + SDL_HITTEST_RESIZE_TOPRIGHT, + SDL_HITTEST_RESIZE_RIGHT, + SDL_HITTEST_RESIZE_BOTTOMRIGHT, + SDL_HITTEST_RESIZE_BOTTOM, + SDL_HITTEST_RESIZE_BOTTOMLEFT, + SDL_HITTEST_RESIZE_LEFT } SDL_HitTestResult; /** diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 45b6083c1..0e788b523 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -40,8 +40,40 @@ #include +#ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_TOP +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_TOPRIGHT +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_RIGHT +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOM +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_LEFT +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 +#endif + #ifndef _NET_WM_MOVERESIZE_MOVE -#define _NET_WM_MOVERESIZE_MOVE 8 +#define _NET_WM_MOVERESIZE_MOVE 8 #endif typedef struct { @@ -290,7 +322,7 @@ InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point) XEvent evt; evt.xclient.type = ClientMessage; evt.xclient.window = data->xwindow; - evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", False); + evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); evt.xclient.format = 32; evt.xclient.data.l[0] = window->x + point->x; evt.xclient.data.l[1] = window->y + point->y; @@ -302,21 +334,96 @@ InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point) X11_XSync(display, 0); } +static void +InitiateWindowResize(_THIS, const SDL_WindowData *data, const SDL_Point *point, int direction) +{ + SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + SDL_Window* window = data->window; + Display *display = viddata->display; + + if (direction < _NET_WM_MOVERESIZE_SIZE_TOPLEFT || direction > _NET_WM_MOVERESIZE_SIZE_LEFT) + return; + + /* !!! FIXME: we need to regrab this if necessary when the drag is done. */ + X11_XUngrabPointer(display, 0L); + X11_XFlush(display); + + XEvent evt; + evt.xclient.type = ClientMessage; + evt.xclient.window = data->xwindow; + evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); + evt.xclient.format = 32; + evt.xclient.data.l[0] = window->x + point->x; + evt.xclient.data.l[1] = window->y + point->y; + evt.xclient.data.l[2] = direction; + evt.xclient.data.l[3] = Button1; + evt.xclient.data.l[4] = 0; + X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); + + X11_XSync(display, 0); +} + static SDL_bool ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev) { SDL_Window *window = data->window; + SDL_bool ret = SDL_FALSE; if (window->hit_test) { const SDL_Point point = { xev->xbutton.x, xev->xbutton.y }; const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); - if (rc == SDL_HITTEST_DRAGGABLE) { - InitiateWindowMove(_this, data, &point); - return SDL_TRUE; /* dragging, drop this event. */ + switch (rc) { + case SDL_HITTEST_DRAGGABLE: { + InitiateWindowMove(_this, data, &point); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_TOPLEFT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPLEFT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_TOP: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOP); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_TOPRIGHT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPRIGHT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_RIGHT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_RIGHT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_BOTTOMRIGHT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_BOTTOM: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOM); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_BOTTOMLEFT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_LEFT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_LEFT); + ret = SDL_TRUE; + } + break; + default: + break; } } - return SDL_FALSE; /* not a drag area. */ + return ret; } static void diff --git a/test/testhittesting.c b/test/testhittesting.c index f6ae4ee70..5f2f274d4 100644 --- a/test/testhittesting.c +++ b/test/testhittesting.c @@ -3,6 +3,8 @@ /* !!! FIXME: rewrite this to be wired in to test framework. */ +#define RESIZE_BORDER 20 + const SDL_Rect drag_areas[] = { { 20, 20, 100, 100 }, { 200, 70, 100, 100 }, @@ -16,6 +18,8 @@ static SDL_HitTestResult hitTest(SDL_Window *window, const SDL_Point *pt, void *data) { int i; + int w, h; + for (i = 0; i < numareas; i++) { if (SDL_PointInRect(pt, &areas[i])) { SDL_Log("HIT-TEST: DRAGGABLE\n"); @@ -23,6 +27,24 @@ hitTest(SDL_Window *window, const SDL_Point *pt, void *data) } } + SDL_GetWindowSize(window, &w, &h); + if (pt->x < RESIZE_BORDER && pt->y < RESIZE_BORDER) + return SDL_HITTEST_RESIZE_TOPLEFT; + if (pt->x > RESIZE_BORDER && pt->x < w - RESIZE_BORDER && pt->y < RESIZE_BORDER) + return SDL_HITTEST_RESIZE_TOP; + if (pt->x > w - RESIZE_BORDER && pt->y < RESIZE_BORDER) + return SDL_HITTEST_RESIZE_TOPRIGHT; + if (pt->x > w - RESIZE_BORDER && pt->y > RESIZE_BORDER && pt->y < h - RESIZE_BORDER) + return SDL_HITTEST_RESIZE_RIGHT; + if (pt->x > w - RESIZE_BORDER && pt->y > h - RESIZE_BORDER) + return SDL_HITTEST_RESIZE_BOTTOMRIGHT; + if (pt->x < w - RESIZE_BORDER && pt->x > RESIZE_BORDER && pt->y > h - RESIZE_BORDER) + return SDL_HITTEST_RESIZE_BOTTOM; + if (pt->x < RESIZE_BORDER && pt->y > h - RESIZE_BORDER) + return SDL_HITTEST_RESIZE_BOTTOMLEFT; + if (pt->x < RESIZE_BORDER && pt->y < h - RESIZE_BORDER && pt->y > RESIZE_BORDER) + return SDL_HITTEST_RESIZE_LEFT; + SDL_Log("HIT-TEST: NORMAL\n"); return SDL_HITTEST_NORMAL; } @@ -36,7 +58,7 @@ int main(int argc, char **argv) /* !!! FIXME: check for errors. */ SDL_Init(SDL_INIT_VIDEO); - window = SDL_CreateWindow("Drag the red boxes", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_BORDERLESS); + window = SDL_CreateWindow("Drag the red boxes", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE); renderer = SDL_CreateRenderer(window, -1, 0); if (SDL_SetWindowHitTest(window, hitTest, NULL) == -1) { From efa3e07bc98d74b7a63eaabb1f236d37a1cd8bbd Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 5 Jun 2014 00:49:25 -0400 Subject: [PATCH 21/26] Minor tweaks to testhittesting. --- test/testhittesting.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/test/testhittesting.c b/test/testhittesting.c index 5f2f274d4..5e32be42d 100644 --- a/test/testhittesting.c +++ b/test/testhittesting.c @@ -28,22 +28,29 @@ hitTest(SDL_Window *window, const SDL_Point *pt, void *data) } SDL_GetWindowSize(window, &w, &h); - if (pt->x < RESIZE_BORDER && pt->y < RESIZE_BORDER) - return SDL_HITTEST_RESIZE_TOPLEFT; - if (pt->x > RESIZE_BORDER && pt->x < w - RESIZE_BORDER && pt->y < RESIZE_BORDER) - return SDL_HITTEST_RESIZE_TOP; - if (pt->x > w - RESIZE_BORDER && pt->y < RESIZE_BORDER) - return SDL_HITTEST_RESIZE_TOPRIGHT; - if (pt->x > w - RESIZE_BORDER && pt->y > RESIZE_BORDER && pt->y < h - RESIZE_BORDER) - return SDL_HITTEST_RESIZE_RIGHT; - if (pt->x > w - RESIZE_BORDER && pt->y > h - RESIZE_BORDER) - return SDL_HITTEST_RESIZE_BOTTOMRIGHT; - if (pt->x < w - RESIZE_BORDER && pt->x > RESIZE_BORDER && pt->y > h - RESIZE_BORDER) - return SDL_HITTEST_RESIZE_BOTTOM; - if (pt->x < RESIZE_BORDER && pt->y > h - RESIZE_BORDER) - return SDL_HITTEST_RESIZE_BOTTOMLEFT; - if (pt->x < RESIZE_BORDER && pt->y < h - RESIZE_BORDER && pt->y > RESIZE_BORDER) - return SDL_HITTEST_RESIZE_LEFT; + + #define REPORT_RESIZE_HIT(name) { \ + SDL_Log("HIT-TEST: RESIZE_" #name "\n"); \ + return SDL_HITTEST_RESIZE_##name; \ + } + + if (pt->x < RESIZE_BORDER && pt->y < RESIZE_BORDER) { + REPORT_RESIZE_HIT(TOPLEFT); + } else if (pt->x > RESIZE_BORDER && pt->x < w - RESIZE_BORDER && pt->y < RESIZE_BORDER) { + REPORT_RESIZE_HIT(TOP); + } else if (pt->x > w - RESIZE_BORDER && pt->y < RESIZE_BORDER) { + REPORT_RESIZE_HIT(TOPRIGHT); + } else if (pt->x > w - RESIZE_BORDER && pt->y > RESIZE_BORDER && pt->y < h - RESIZE_BORDER) { + REPORT_RESIZE_HIT(RIGHT); + } else if (pt->x > w - RESIZE_BORDER && pt->y > h - RESIZE_BORDER) { + REPORT_RESIZE_HIT(BOTTOMRIGHT); + } else if (pt->x < w - RESIZE_BORDER && pt->x > RESIZE_BORDER && pt->y > h - RESIZE_BORDER) { + REPORT_RESIZE_HIT(BOTTOM); + } else if (pt->x < RESIZE_BORDER && pt->y > h - RESIZE_BORDER) { + REPORT_RESIZE_HIT(BOTTOMLEFT); + } else if (pt->x < RESIZE_BORDER && pt->y < h - RESIZE_BORDER && pt->y > RESIZE_BORDER) { + REPORT_RESIZE_HIT(LEFT); + } SDL_Log("HIT-TEST: NORMAL\n"); return SDL_HITTEST_NORMAL; From 0dc198273c2c1fa1ef2272aacf022e9df93cbea1 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 5 Jun 2014 00:54:43 -0400 Subject: [PATCH 22/26] Wired up Windows resize hit testing. --- src/video/windows/SDL_windowsevents.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 6b7621505..29be44bef 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -897,11 +897,19 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (ScreenToClient(data->hwnd, &winpoint)) { const SDL_Point point = { (int) winpoint.x, (int) winpoint.y }; const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); - if (rc == SDL_HITTEST_DRAGGABLE) { - return HTCAPTION; + switch (rc) { + case SDL_HITTEST_DRAGGABLE: return HTCAPTION; + case SDL_HITTEST_RESIZE_TOPLEFT: return HTTOPLEFT; + case SDL_HITTEST_RESIZE_TOP: return HTTOP; + case SDL_HITTEST_RESIZE_TOPRIGHT: return HTTOPRIGHT; + case SDL_HITTEST_RESIZE_RIGHT: return HTRIGHT; + case SDL_HITTEST_RESIZE_BOTTOMRIGHT: return HTBOTTOMRIGHT; + case SDL_HITTEST_RESIZE_BOTTOM: return HTBOTTOM; + case SDL_HITTEST_RESIZE_BOTTOMLEFT: return HTBOTTOMLEFT; + case SDL_HITTEST_RESIZE_LEFT: return HTLEFT; } } - // if we didn't return, this will call DefWindowProc below. + /* If we didn't return, this will call DefWindowProc below. */ } } break; From 7412b88af0abed1e73b9f868633e0c345e2b6cdf Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 11 Jun 2014 00:12:06 -0400 Subject: [PATCH 23/26] This should probably query async button state. --- src/video/windows/SDL_windowsevents.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 29be44bef..801aeb89e 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -469,11 +469,11 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (WindowFromPoint(pt) != hwnd) { /* if in the window, WM_MOUSEMOVE, etc, will cover it. */ ScreenToClient(data->hwnd, &pt); SDL_SendMouseMotion(data->window, 0, 0, (int) pt.x, (int) pt.y); - SDL_SendMouseButton(data->window, 0, GetKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT); - SDL_SendMouseButton(data->window, 0, GetKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT); - SDL_SendMouseButton(data->window, 0, GetKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE); - SDL_SendMouseButton(data->window, 0, GetKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1); - SDL_SendMouseButton(data->window, 0, GetKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2); + SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT); + SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT); + SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE); + SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1); + SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2); } } else { SDL_assert(0 && "Shouldn't happen"); From e0460846e5e32427730102a8c771fa368b24e956 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 11 Jun 2014 00:12:19 -0400 Subject: [PATCH 24/26] Implement Windows GetAbsoluteMouseState(). --- src/video/windows/SDL_windowsmouse.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index 0abd21240..8bb4106e2 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -260,6 +260,24 @@ WIN_CaptureMouse(SDL_Window *window) return ToggleRawInput(window != NULL); } +static Uint32 +WIN_GetAbsoluteMouseState(int *x, int *y) +{ + Uint32 retval = 0; + POINT pt = { 0, 0 }; + GetCursorPos(&pt); + *x = (int) pt.x; + *y = (int) pt.y; + + retval |= GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0; + retval |= GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0; + retval |= GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_BUTTON_MMASK : 0; + retval |= GetAsyncKeyState(VK_X1BUTTON) & 0x8000 ? SDL_BUTTON_X1MASK : 0; + retval |= GetAsyncKeyState(VK_X2BUTTON) & 0x8000 ? SDL_BUTTON_X2MASK : 0; + + return retval; +} + void WIN_InitMouse(_THIS) { @@ -272,6 +290,7 @@ WIN_InitMouse(_THIS) mouse->WarpMouse = WIN_WarpMouse; mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode; mouse->CaptureMouse = WIN_CaptureMouse; + mouse->GetAbsoluteMouseState = WIN_GetAbsoluteMouseState; SDL_SetDefaultCursor(WIN_CreateDefaultCursor()); From 8f47d6cd20996a092cd2f5b7deb0af68cdaca368 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 11 Jun 2014 00:40:19 -0400 Subject: [PATCH 25/26] Implemented Cocoa GetAbsoluteMouseState(). --- src/video/cocoa/SDL_cocoamouse.m | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index 2f9d8d352..c14f22637 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -282,6 +282,31 @@ Cocoa_CaptureMouse(SDL_Window *window) return 0; } +static Uint32 +Cocoa_GetAbsoluteMouseState(int *x, int *y) +{ + const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons]; + const NSPoint cocoaLocation = [NSEvent mouseLocation]; + Uint32 retval = 0; + + for (NSScreen *screen in [NSScreen screens]) { + NSRect frame = [screen frame]; + if (NSPointInRect(cocoaLocation, frame)) { + *x = (int) cocoaLocation.x; + *y = (int) ((frame.origin.y + frame.size.height) - cocoaLocation.y); + break; + } + } + + retval |= (cocoaButtons & (1 << 0)) ? SDL_BUTTON_LMASK : 0; + retval |= (cocoaButtons & (1 << 1)) ? SDL_BUTTON_RMASK : 0; + retval |= (cocoaButtons & (1 << 2)) ? SDL_BUTTON_MMASK : 0; + retval |= (cocoaButtons & (1 << 3)) ? SDL_BUTTON_X1MASK : 0; + retval |= (cocoaButtons & (1 << 4)) ? SDL_BUTTON_X2MASK : 0; + + return retval; +} + void Cocoa_InitMouse(_THIS) { @@ -296,6 +321,7 @@ Cocoa_InitMouse(_THIS) mouse->WarpMouse = Cocoa_WarpMouse; mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode; mouse->CaptureMouse = Cocoa_CaptureMouse; + mouse->GetAbsoluteMouseState = Cocoa_GetAbsoluteMouseState; SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor()); From 8bd36ba18fce656e8e34d6486e3bb5c7da92e9c3 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 25 Jun 2014 16:16:55 -0400 Subject: [PATCH 26/26] Changed SDL_GetAbsoluteMouseState() to SDL_GetGlobalMouseState(). This matches naming conventions in the main repository, between SDL_GetRelativeMouseState() and SDL_WarpMouseGlobal(). --- include/SDL_mouse.h | 2 +- src/dynapi/SDL_dynapi_overrides.h | 2 +- src/dynapi/SDL_dynapi_procs.h | 2 +- src/events/SDL_mouse.c | 6 +++--- src/events/SDL_mouse_c.h | 2 +- src/test/SDL_test_common.c | 2 +- src/video/cocoa/SDL_cocoamouse.m | 4 ++-- src/video/windows/SDL_windowsmouse.c | 4 ++-- src/video/x11/SDL_x11mouse.c | 4 ++-- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h index fdb68f040..855e97b08 100644 --- a/include/SDL_mouse.h +++ b/include/SDL_mouse.h @@ -100,7 +100,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetMouseState(int *x, int *y); * * \sa SDL_GetMouseState */ -extern DECLSPEC Uint32 SDLCALL SDL_GetAbsoluteMouseState(int *x, int *y); +extern DECLSPEC Uint32 SDLCALL SDL_GetGlobalMouseState(int *x, int *y); /** * \brief Retrieve the relative state of the mouse. diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index aa996399e..668cf8d3d 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -581,4 +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 +#define SDL_GetGlobalMouseState SDL_GetGlobalMouseState_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 1df122257..eb820bf25 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -614,4 +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) +SDL_DYNAPI_PROC(Uint32,SDL_GetGlobalMouseState,(int *a, int *b),(a,b),return) diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 970cc78c1..4ebfcca94 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -470,7 +470,7 @@ SDL_GetRelativeMouseState(int *x, int *y) } Uint32 -SDL_GetAbsoluteMouseState(int *x, int *y) +SDL_GetGlobalMouseState(int *x, int *y) { SDL_Mouse *mouse = SDL_GetMouse(); int tmpx, tmpy; @@ -485,12 +485,12 @@ SDL_GetAbsoluteMouseState(int *x, int *y) *x = *y = 0; - if (!mouse->GetAbsoluteMouseState) { + if (!mouse->GetGlobalMouseState) { SDL_assert(0 && "This should really be implemented for every target."); return 0; } - return mouse->GetAbsoluteMouseState(x, y); + return mouse->GetGlobalMouseState(x, y); } void diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index 70b3ec0b3..61553d44f 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -67,7 +67,7 @@ typedef struct 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); + Uint32 (*GetGlobalMouseState) (int *x, int *y); /* Data common to all mice */ SDL_MouseID mouseID; diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index fa6c1fea9..d05c60938 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1492,7 +1492,7 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done) if (withControl) { /* Ctrl-A reports absolute mouse position. */ int x, y; - const Uint32 mask = SDL_GetAbsoluteMouseState(&x, &y); + const Uint32 mask = SDL_GetGlobalMouseState(&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]" : "", diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index c14f22637..dbd26aee8 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -283,7 +283,7 @@ Cocoa_CaptureMouse(SDL_Window *window) } static Uint32 -Cocoa_GetAbsoluteMouseState(int *x, int *y) +Cocoa_GetGlobalMouseState(int *x, int *y) { const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons]; const NSPoint cocoaLocation = [NSEvent mouseLocation]; @@ -321,7 +321,7 @@ Cocoa_InitMouse(_THIS) mouse->WarpMouse = Cocoa_WarpMouse; mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode; mouse->CaptureMouse = Cocoa_CaptureMouse; - mouse->GetAbsoluteMouseState = Cocoa_GetAbsoluteMouseState; + mouse->GetGlobalMouseState = Cocoa_GetGlobalMouseState; SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor()); diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index 8bb4106e2..1e5b8bd4a 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -261,7 +261,7 @@ WIN_CaptureMouse(SDL_Window *window) } static Uint32 -WIN_GetAbsoluteMouseState(int *x, int *y) +WIN_GetGlobalMouseState(int *x, int *y) { Uint32 retval = 0; POINT pt = { 0, 0 }; @@ -290,7 +290,7 @@ WIN_InitMouse(_THIS) mouse->WarpMouse = WIN_WarpMouse; mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode; mouse->CaptureMouse = WIN_CaptureMouse; - mouse->GetAbsoluteMouseState = WIN_GetAbsoluteMouseState; + mouse->GetGlobalMouseState = WIN_GetGlobalMouseState; SDL_SetDefaultCursor(WIN_CreateDefaultCursor()); diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c index 7386da5fb..16894d670 100644 --- a/src/video/x11/SDL_x11mouse.c +++ b/src/video/x11/SDL_x11mouse.c @@ -354,7 +354,7 @@ X11_CaptureMouse(SDL_Window *window) } static Uint32 -X11_GetAbsoluteMouseState(int *x, int *y) +X11_GetGlobalMouseState(int *x, int *y) { Display *display = GetDisplay(); const int num_screens = SDL_GetNumVideoDisplays(); @@ -398,7 +398,7 @@ X11_InitMouse(_THIS) mouse->WarpMouse = X11_WarpMouse; mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode; mouse->CaptureMouse = X11_CaptureMouse; - mouse->GetAbsoluteMouseState = X11_GetAbsoluteMouseState; + mouse->GetGlobalMouseState = X11_GetGlobalMouseState; SDL_SetDefaultCursor(X11_CreateDefaultCursor()); }