From a0e878aafb43d7887708c1899ecf044e4fb35093 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 28 Mar 2015 00:48:03 -0400 Subject: [PATCH] Minor input grab clarifications. Clarify that grabbing the mouse only works with one window at a time; this was always true at the system level, though SDL could previously get confused by multiple simultaneous grabs, so now we explicitly break any existing grab before starting a new one and document it as such. Also track the window that is currently grabbed, and provide an API to query for that window. This makes it easy to automate mouse ungrabbing at breakpoints with gdb7's scripting, since the scripts can now know which window to ungrab. In 2.1, we should probably change this API to SDL_GrabInput(win) and SDL_UngrabInput(void), or something. --- include/SDL_video.h | 12 ++++++++++++ src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + src/video/SDL_sysvideo.h | 1 + src/video/SDL_video.c | 23 ++++++++++++++++++++++- 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/SDL_video.h b/include/SDL_video.h index 782fcb0fb663f..fe1386889b63f 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -722,6 +722,9 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurfaceRects(SDL_Window * window, * \param window The window for which the input grab mode should be set. * \param grabbed This is SDL_TRUE to grab input, and SDL_FALSE to release input. * + * If the caller enables a grab while another window is currently grabbed, + * the other window loses its grab in favor of the caller's window. + * * \sa SDL_GetWindowGrab() */ extern DECLSPEC void SDLCALL SDL_SetWindowGrab(SDL_Window * window, @@ -736,6 +739,15 @@ extern DECLSPEC void SDLCALL SDL_SetWindowGrab(SDL_Window * window, */ extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowGrab(SDL_Window * window); +/** + * \brief Get the window that currently has an input grab enabled. + * + * \return This returns the window if input is grabbed, and NULL otherwise. + * + * \sa SDL_SetWindowGrab() + */ +extern DECLSPEC SDL_Window * SDLCALL SDL_GetGrabbedWindow(void); + /** * \brief Set the brightness (gamma correction) for a window. * diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 8bcde6312d33e..dcc6d4677693f 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -591,3 +591,4 @@ #define SDL_QueueAudio SDL_QueueAudio_REAL #define SDL_GetQueuedAudioSize SDL_GetQueuedAudioSize_REAL #define SDL_ClearQueuedAudio SDL_ClearQueuedAudio_REAL +#define SDL_GetGrabbedWindow SDL_GetGrabbedWindow_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index c41cdc9f027c0..6408e3f892d7c 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -623,3 +623,4 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_HasAVX2,(void),(),return) SDL_DYNAPI_PROC(int,SDL_QueueAudio,(SDL_AudioDeviceID a, const void *b, Uint32 c),(a,b,c),return) SDL_DYNAPI_PROC(Uint32,SDL_GetQueuedAudioSize,(SDL_AudioDeviceID a),(a),return) SDL_DYNAPI_PROC(void,SDL_ClearQueuedAudio,(SDL_AudioDeviceID a),(a),) +SDL_DYNAPI_PROC(SDL_Window*,SDL_GetGrabbedWindow,(void),(),return) diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 6966f2bd331e7..9b2f7d17049ec 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -274,6 +274,7 @@ struct SDL_VideoDevice int num_displays; SDL_VideoDisplay *displays; SDL_Window *windows; + SDL_Window *grabbed_window; Uint8 window_magic; Uint32 next_object_id; char * clipboard_text; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index b93c11e7613fc..c8cb2fac80d25 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -2116,6 +2116,7 @@ void SDL_UpdateWindowGrab(SDL_Window * window) { if (_this->SetWindowGrab) { + SDL_Window *grabbed_window; SDL_bool grabbed; if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) && (window->flags & SDL_WINDOW_INPUT_FOCUS)) { @@ -2123,6 +2124,19 @@ SDL_UpdateWindowGrab(SDL_Window * window) } else { grabbed = SDL_FALSE; } + + grabbed_window = _this->grabbed_window; + if (grabbed) { + if (grabbed_window && (grabbed_window != window)) { + /* stealing a grab from another window! */ + grabbed_window->flags &= ~SDL_WINDOW_INPUT_GRABBED; + _this->SetWindowGrab(_this, grabbed_window, SDL_FALSE); + } + _this->grabbed_window = window; + } else if (grabbed_window == window) { + _this->grabbed_window = NULL; /* ungrabbing. */ + } + _this->SetWindowGrab(_this, window, grabbed); } } @@ -2147,8 +2161,15 @@ SDL_bool SDL_GetWindowGrab(SDL_Window * window) { CHECK_WINDOW_MAGIC(window, SDL_FALSE); + SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0)); + return window == _this->grabbed_window; +} - return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0); +SDL_Window * +SDL_GetGrabbedWindow(void) +{ + SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0)); + return _this->grabbed_window; } void