diff --git a/include/SDL_hints.h b/include/SDL_hints.h index eaed22a00..549ed6626 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -1440,15 +1440,6 @@ extern "C" { */ #define SDL_HINT_WAVE_TRUNCATION "SDL_WAVE_TRUNCATION" -/** - * \brief Controls the number of times a window flashes with SDL_FlashWindow() - * - * On Windows, if this variable is set, the SDL_FlashWindow() call will flash - * the specified number of times. Otherwise the window will flash until it - * becomes the foreground window. - */ -#define SDL_HINT_WINDOW_FLASH_COUNT "SDL_WINDOW_FLASH_COUNT" - /** * \brief Tell SDL not to name threads on Windows with the 0x406D1388 Exception. * The 0x406D1388 Exception is a trick used to inform Visual Studio of a diff --git a/include/SDL_test_common.h b/include/SDL_test_common.h index ff6c97574..97f036d23 100644 --- a/include/SDL_test_common.h +++ b/include/SDL_test_common.h @@ -64,6 +64,7 @@ typedef struct const char *window_title; const char *window_icon; Uint32 window_flags; + SDL_bool flash_on_focus_loss; int window_x; int window_y; int window_w; diff --git a/include/SDL_video.h b/include/SDL_video.h index afced02c7..73bc660cc 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -188,6 +188,9 @@ typedef enum SDL_DISPLAYEVENT_DISCONNECTED /**< Display has been removed from the system */ } SDL_DisplayEventID; +/** + * \brief Display orientation + */ typedef enum { SDL_ORIENTATION_UNKNOWN, /**< The display orientation can't be determined */ @@ -197,6 +200,16 @@ typedef enum SDL_ORIENTATION_PORTRAIT_FLIPPED /**< The display is in portrait mode, upside down */ } SDL_DisplayOrientation; +/** + * \brief Window flash operation + */ +typedef enum +{ + SDL_FLASH_CANCEL, /**< Cancel any window flash state */ + SDL_FLASH_BRIEFLY, /**< Flash the window briefly to get attention */ + SDL_FLASH_UNTIL_FOCUSED, /**< Flash the window until it gets focus */ +} SDL_FlashOperation; + /** * \brief An opaque handle to an OpenGL context. */ @@ -1511,10 +1524,11 @@ extern DECLSPEC int SDLCALL SDL_SetWindowHitTest(SDL_Window * window, * Request a window to demand attention from the user. * * \param window the window to be flashed + * \param the flash operation * \returns 0 on success or a negative error code on failure; call * SDL_GetError() for more information. */ -extern DECLSPEC int SDLCALL SDL_FlashWindow(SDL_Window * window); +extern DECLSPEC int SDLCALL SDL_FlashWindow(SDL_Window * window, SDL_FlashOperation operation); /** * Destroy a window. diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index d6ff46353..f878b5e77 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -876,6 +876,6 @@ SDL_DYNAPI_PROC(int,SDL_AndroidShowToast,(const char *a, int b, int c, int d, in SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceSpec,(int a, int b, SDL_AudioSpec *c),(a,b,c),return) SDL_DYNAPI_PROC(void,SDL_TLSCleanup,(void),(),) SDL_DYNAPI_PROC(void,SDL_SetWindowAlwaysOnTop,(SDL_Window *a, SDL_bool b),(a,b),) -SDL_DYNAPI_PROC(int,SDL_FlashWindow,(SDL_Window *a),(a),return) +SDL_DYNAPI_PROC(int,SDL_FlashWindow,(SDL_Window *a, SDL_FlashOperation b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_GameControllerSendEffect,(SDL_GameController *a, const void *b, int c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_JoystickSendEffect,(SDL_Joystick *a, const void *b, int c),(a,b,c),return) diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 94ec47c3e..5fea48ff0 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -37,7 +37,7 @@ static const char *video_usage[] = { "[--scale N]", "[--depth N]", "[--refresh R]", "[--vsync]", "[--noframe]", "[--resizable]", "[--minimize]", "[--maximize]", "[--grab]", "[--keyboard-grab]", "[--shown]", "[--hidden]", "[--input-focus]", "[--mouse-focus]", - "[--allow-highdpi]", "[--usable-bounds]" + "[--flash-on-focus-loss]", "[--allow-highdpi]", "[--usable-bounds]" }; static const char *audio_usage[] = { @@ -441,6 +441,10 @@ SDLTest_CommonArg(SDLTest_CommonState * state, int index) state->window_flags |= SDL_WINDOW_MOUSE_FOCUS; return 1; } + if (SDL_strcasecmp(argv[index], "--flash-on-focus-loss") == 0) { + state->flash_on_focus_loss = SDL_TRUE; + return 1; + } if (SDL_strcasecmp(argv[index], "--grab") == 0) { state->window_flags |= SDL_WINDOW_MOUSE_GRABBED; return 1; @@ -1808,6 +1812,16 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done) } } break; + case SDL_WINDOWEVENT_FOCUS_LOST: + if (state->flash_on_focus_loss) { + SDL_Window *window = SDL_GetWindowFromID(event->window.windowID); + if (window) { + SDL_FlashWindow(window, SDL_FLASH_UNTIL_FOCUSED); + } + } + break; + default: + break; } break; case SDL_KEYDOWN: { @@ -1963,7 +1977,7 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done) /* Ctrl-F flash the window */ SDL_Window *window = SDL_GetWindowFromID(event->key.windowID); if (window) { - SDL_FlashWindow(window); + SDL_FlashWindow(window, SDL_FLASH_BRIEFLY); } } break; diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 50010a23f..0be19c128 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -240,7 +240,7 @@ struct SDL_VideoDevice int (*UpdateWindowFramebuffer) (_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects); void (*DestroyWindowFramebuffer) (_THIS, SDL_Window * window); void (*OnWindowEnter) (_THIS, SDL_Window * window); - int (*FlashWindow) (_THIS, SDL_Window * window); + int (*FlashWindow) (_THIS, SDL_Window * window, SDL_FlashOperation operation); /* * * */ /* diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 49ebbc231..47f19b188 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -2793,12 +2793,12 @@ SDL_GetGrabbedWindow(void) } int -SDL_FlashWindow(SDL_Window * window) +SDL_FlashWindow(SDL_Window * window, SDL_FlashOperation operation) { CHECK_WINDOW_MAGIC(window, -1); if (_this->FlashWindow) { - return _this->FlashWindow(_this, window); + return _this->FlashWindow(_this, window, operation); } return SDL_Unsupported(); diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h index ed53fecc2..e14bb1d47 100644 --- a/src/video/cocoa/SDL_cocoawindow.h +++ b/src/video/cocoa/SDL_cocoawindow.h @@ -117,6 +117,7 @@ struct SDL_WindowData NSMutableArray *nscontexts; SDL_bool created; SDL_bool inWindowFullscreenTransition; + NSInteger flash_request; Cocoa_WindowListener *listener; struct SDL_VideoData *videodata; #if SDL_VIDEO_OPENGL_EGL @@ -151,7 +152,7 @@ extern void Cocoa_DestroyWindow(_THIS, SDL_Window * window); extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); extern int Cocoa_SetWindowHitTest(SDL_Window *window, SDL_bool enabled); extern void Cocoa_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept); -extern int Cocoa_FlashWindow(_THIS, SDL_Window * window); +extern int Cocoa_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation); #endif /* SDL_cocoawindow_h_ */ diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 43aad092f..4586073b5 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -2117,11 +2117,30 @@ Cocoa_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept) } int -Cocoa_FlashWindow(_THIS, SDL_Window *window) +Cocoa_FlashWindow(_THIS, SDL_Window *window, SDL_FlashOperation operation) { @autoreleasepool { /* Note that this is app-wide and not window-specific! */ - [NSApp requestUserAttention:NSInformationalRequest]; + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + + if (data->flash_request) { + [NSApp cancelUserAttentionRequest:data->flash_request]; + data->flash_request = 0; + } + + switch (operation) { + case SDL_FLASH_CANCEL: + /* Canceled above */ + break; + case SDL_FLASH_BRIEFLY: + data->flash_request = [NSApp requestUserAttention:NSInformationalRequest]; + break; + case SDL_FLASH_UNTIL_FOCUSED: + data->flash_request = [NSApp requestUserAttention:NSCriticalRequest]; + break; + default: + return SDL_Unsupported(); + } return 0; }} diff --git a/src/video/uikit/SDL_uikitevents.m b/src/video/uikit/SDL_uikitevents.m index 54f88879c..6d78685d2 100644 --- a/src/video/uikit/SDL_uikitevents.m +++ b/src/video/uikit/SDL_uikitevents.m @@ -196,7 +196,7 @@ static void UpdateMouseGrab() static int SetGCMouseRelativeMode(SDL_bool enabled) { - mouse_relative_mode = enabled; + mouse_relative_mode = enabled; UpdateMouseGrab(); return 0; } diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 773cc461e..960e3c927 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -920,7 +920,7 @@ Wayland_RaiseWindow(_THIS, SDL_Window *window) } int -Wayland_FlashWindow(_THIS, SDL_Window *window) +Wayland_FlashWindow(_THIS, SDL_Window *window, SDL_FlashOperation operation) { Wayland_activate_window(_this->driverdata, window->driverdata, diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index 873ea0270..5956cf352 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -113,7 +113,7 @@ extern void Wayland_SuspendScreenSaver(_THIS); extern SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info); extern int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled); -extern int Wayland_FlashWindow(_THIS, SDL_Window * window); +extern int Wayland_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation); extern void Wayland_HandlePendingResize(SDL_Window *window); diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 96eb67d0c..93d1903a7 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -1064,19 +1064,26 @@ WIN_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept) } int -WIN_FlashWindow(_THIS, SDL_Window * window) +WIN_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation) { FLASHWINFO desc; - const char *hint = SDL_GetHint(SDL_HINT_WINDOW_FLASH_COUNT); SDL_zero(desc); desc.cbSize = sizeof(desc); desc.hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; - desc.dwFlags = FLASHW_TRAY; - if (hint && *hint) { - desc.uCount = SDL_atoi(hint); - } else { - desc.dwFlags |= FLASHW_TIMERNOFG; + switch (operation) { + case SDL_FLASH_CANCEL: + desc.dwFlags = FLASHW_STOP; + break; + case SDL_FLASH_BRIEFLY: + desc.dwFlags = FLASHW_TRAY; + desc.uCount = 1; + break; + case SDL_FLASH_UNTIL_FOCUSED: + desc.dwFlags = (FLASHW_TRAY | FLASHW_TIMERNOFG); + break; + default: + return SDL_Unsupported(); } FlashWindowEx(&desc); diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index 335326a76..700566e9c 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -86,7 +86,7 @@ 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); extern void WIN_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept); -extern int WIN_FlashWindow(_THIS, SDL_Window * window); +extern int WIN_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation); #endif /* SDL_windowswindow_h_ */ diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index d041dd991..9a09fee48 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -1749,7 +1749,7 @@ X11_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept) } int -X11_FlashWindow(_THIS, SDL_Window * window) +X11_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index ad465636d..25d12dd8d 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -107,7 +107,7 @@ extern SDL_bool X11_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); extern int X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled); extern void X11_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept); -extern int X11_FlashWindow(_THIS, SDL_Window * window); +extern int X11_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation); #endif /* SDL_x11window_h_ */