From 5669743a435f8fe9ea43e5f6b49601ba9dabe2ae Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 19 May 2022 09:45:57 -0700 Subject: [PATCH] Make sure SDL_CaptureMouse() is only called on the main thread Windows handles mouse capture on a per-thread basis, and capture must be done on the thread used to create a window. Fixes https://github.com/libsdl-org/SDL/issues/5577 --- src/events/SDL_mouse.c | 11 +++++++++++ src/video/SDL_sysvideo.h | 3 +++ src/video/SDL_video.c | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index e6bb09607..dfa9a6c42 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -1069,6 +1069,17 @@ SDL_CaptureMouse(SDL_bool enabled) return SDL_Unsupported(); } +#ifdef __WIN32__ + /* Windows mouse capture is tied to the current thread, and must be called + * from the thread that created the window being captured. Since we update + * the mouse capture state from the event processing, any application state + * changes must be processed on that thread as well. + */ + if (!SDL_OnVideoThread()) { + return SDL_SetError("SDL_CaptureMouse() must be called on the main thread"); + } +#endif /* __WIN32__ */ + if (enabled && SDL_GetKeyboardFocus() == NULL) { return SDL_SetError("No window has focus"); } diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 70a499178..b1876b2b8 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -333,6 +333,7 @@ struct SDL_VideoDevice /* * * */ /* Data common to all drivers */ + SDL_threadID thread; SDL_bool checked_texture_framebuffer; SDL_bool is_dummy; SDL_bool suspend_screensaver; @@ -461,6 +462,8 @@ extern VideoBootStrap NGAGE_bootstrap; extern VideoBootStrap OS2DIVE_bootstrap; extern VideoBootStrap OS2VMAN_bootstrap; +/* Use SDL_OnVideoThread() sparingly, to avoid regressions in use cases that currently happen to work */ +extern SDL_bool SDL_OnVideoThread(void); extern SDL_VideoDevice *SDL_GetVideoDevice(void); extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode); extern int SDL_AddVideoDisplay(const SDL_VideoDisplay * display, SDL_bool send_event); diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 305ed7a59..58f9d7466 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -470,6 +470,7 @@ SDL_VideoInit(const char *driver_name) _this = video; _this->name = bootstrap[i]->name; _this->next_object_id = 1; + _this->thread = SDL_ThreadID(); /* Set some very sane GL defaults */ @@ -549,6 +550,12 @@ SDL_GetVideoDevice(void) return _this; } +SDL_bool +SDL_OnVideoThread() +{ + return (_this && SDL_ThreadID() == _this->thread) ? SDL_TRUE : SDL_FALSE; +} + int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode) {