diff --git a/include/SDL_video.h b/include/SDL_video.h index 0c05a0937..896f30321 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -65,6 +65,7 @@ typedef struct * \sa SDL_CreateWindow() * \sa SDL_CreateWindowFrom() * \sa SDL_DestroyWindow() + * \sa SDL_FlashWindow() * \sa SDL_GetWindowData() * \sa SDL_GetWindowFlags() * \sa SDL_GetWindowGrab() @@ -1509,6 +1510,18 @@ extern DECLSPEC int SDLCALL SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *callback_data); +/** + * Request a window to give a signal, e.g. a visual signal, to demand attention from the user. + * + * \returns 0 on success or a negative error code on failure; call + * SDL_GetError() for more information. + * + * \param window the window to request the flashing for + * \param flash_count number of times the window gets flashed on systems that support flashing the + * window multiple times, like Windows, else it is ignored + */ +extern DECLSPEC int SDLCALL SDL_FlashWindow(SDL_Window * window, Uint32 flash_count); + /** * Destroy a window. * diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 157730806..99662c036 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -811,3 +811,4 @@ #define SDL_GetAudioDeviceSpec SDL_GetAudioDeviceSpec_REAL #define SDL_TLSCleanup SDL_TLSCleanup_REAL #define SDL_SetWindowAlwaysOnTop SDL_SetWindowAlwaysOnTop_REAL +#define SDL_FlashWindow SDL_FlashWindow_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index a3113d1da..17e7eb317 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -876,3 +876,4 @@ 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, Uint32 b),(a, b),return) diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 8395e8680..4491a4e59 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -240,6 +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, Uint32 flash_count); /* * * */ /* diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index a5cbe6962..d029f4673 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -2792,6 +2792,18 @@ SDL_GetGrabbedWindow(void) return _this->grabbed_window; } +int +SDL_FlashWindow(SDL_Window * window, Uint32 flash_count) +{ + CHECK_WINDOW_MAGIC(window, -1); + + if (_this->FlashWindow) { + return _this->FlashWindow(_this, window, flash_count); + } + + return SDL_Unsupported(); +} + void SDL_OnWindowShown(SDL_Window * window) { diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index 4956ced70..a80c20c7a 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -176,6 +176,7 @@ WIN_CreateDevice(int devindex) device->OnWindowEnter = WIN_OnWindowEnter; device->SetWindowHitTest = WIN_SetWindowHitTest; device->AcceptDragAndDrop = WIN_AcceptDragAndDrop; + device->FlashWindow = WIN_FlashWindow; 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 51d0c1111..16401a57b 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -1084,6 +1084,24 @@ WIN_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept) DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE); } +int +WIN_FlashWindow(_THIS, SDL_Window * window, Uint32 flash_count) +{ + HWND hwnd; + FLASHWINFO desc; + + hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + desc.cbSize = sizeof(desc); + desc.hwnd = hwnd; + desc.dwFlags = FLASHW_TRAY; + desc.uCount = flash_count; /* flash x times */ + desc.dwTimeout = 0; + + FlashWindowEx(&desc); + + return 0; +} + #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 fe7f825ff..1e8f3d318 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -86,6 +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, Uint32 flash_count); #endif /* SDL_windowswindow_h_ */ diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index 2dc7013da..e8b969311 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -254,6 +254,7 @@ X11_CreateDevice(int devindex) device->GetWindowWMInfo = X11_GetWindowWMInfo; device->SetWindowHitTest = X11_SetWindowHitTest; device->AcceptDragAndDrop = X11_AcceptDragAndDrop; + device->FlashWindow = X11_FlashWindow; 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 8ed2a4437..a6a0b55b1 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -1747,6 +1747,30 @@ X11_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept) } } +int +X11_FlashWindow(_THIS, SDL_Window * window, Uint32 flash_count) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; + Display *display = data->videodata->display; + + Atom demands_attention = X11_XInternAtom(display, "_NET_WM_STATE_DEMANDS_ATTENTION", 1); + Atom wm_state = X11_XInternAtom(display, "_NET_WM_STATE", 1); + + XEvent snd_ntfy_ev = {ClientMessage}; + snd_ntfy_ev.xclient.window = data->xwindow; + snd_ntfy_ev.xclient.message_type = wm_state; + snd_ntfy_ev.xclient.format = 32; + snd_ntfy_ev.xclient.data.l[0] = 1; /* _NET_WM_STATE_ADD */ + snd_ntfy_ev.xclient.data.l[1] = demands_attention; + snd_ntfy_ev.xclient.data.l[2] = 0; + snd_ntfy_ev.xclient.data.l[3] = 1; /* normal application */ + snd_ntfy_ev.xclient.data.l[4] = 0; + X11_XSendEvent(display, RootWindow(display, displaydata->screen), False, SubstructureNotifyMask | SubstructureRedirectMask, &snd_ntfy_ev); + + return 0; +} + #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 98c150088..4e9764c43 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -107,6 +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, Uint32 flash_count); #endif /* SDL_x11window_h_ */