diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 8c654f23d..8d19a2e6d 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -404,6 +404,9 @@ X11_DispatchFocusIn(_THIS, SDL_WindowData *data) #ifdef SDL_USE_IME SDL_IME_SetFocus(SDL_TRUE); #endif + if (data->flashing_window) { + X11_FlashWindow(_this, data->window, SDL_FLASH_CANCEL); + } } static void @@ -1548,6 +1551,7 @@ X11_PumpEvents(_THIS) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; XEvent xevent; + int i; if (data->last_mode_change_deadline) { if (SDL_TICKS_PASSED(SDL_GetTicks(), data->last_mode_change_deadline)) { @@ -1586,6 +1590,15 @@ X11_PumpEvents(_THIS) /* FIXME: Only need to do this when there are pending focus changes */ X11_HandleFocusChanges(_this); + + /* FIXME: Only need to do this when there are flashing windows */ + for (i = 0; i < data->numwindows; ++i) { + if (data->windowlist[i] != NULL && + data->windowlist[i]->flash_cancel_time && + SDL_TICKS_PASSED(SDL_GetTicks(), data->windowlist[i]->flash_cancel_time)) { + X11_FlashWindow(_this, data->windowlist[i]->window, SDL_FLASH_CANCEL); + } + } } diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index 6433b9310..9a46802cd 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -119,8 +119,9 @@ SDL_X11_SYM(int,XSetSelectionOwner,(Display* a,Atom b,Window c,Time d),(a,b,c,d) SDL_X11_SYM(int,XSetTransientForHint,(Display* a,Window b,Window c),(a,b,c),return) SDL_X11_SYM(void,XSetTextProperty,(Display* a,Window b,XTextProperty* c,Atom d),(a,b,c,d),) SDL_X11_SYM(int,XSetWindowBackground,(Display* a,Window b,unsigned long c),(a,b,c),return) -SDL_X11_SYM(void,XSetWMProperties,(Display* a,Window b,XTextProperty* c,XTextProperty* d,char** e,int f,XSizeHints* g,XWMHints* h,XClassHint* i),(a,b,c,d,e,f,g,h,i),) +SDL_X11_SYM(void,XSetWMHints,(Display* a,Window b,XWMHints* c),(a,b,c),) SDL_X11_SYM(void,XSetWMNormalHints,(Display* a,Window b,XSizeHints* c),(a,b,c),) +SDL_X11_SYM(void,XSetWMProperties,(Display* a,Window b,XTextProperty* c,XTextProperty* d,char** e,int f,XSizeHints* g,XWMHints* h,XClassHint* i),(a,b,c,d,e,f,g,h,i),) SDL_X11_SYM(Status,XSetWMProtocols,(Display* a,Window b,Atom* c,int d),(a,b,c,d),return) SDL_X11_SYM(int,XStoreColors,(Display* a,Colormap b,XColor* c,int d),(a,b,c,d),return) SDL_X11_SYM(int,XStoreName,(Display* a,Window b,_Xconst char* c),(a,b,c),return) diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 9a09fee48..4ce299f03 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -1752,23 +1752,45 @@ int 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; Display *display = data->videodata->display; + XWMHints *wmhints; - Atom demands_attention = X11_XInternAtom(display, "_NET_WM_STATE_DEMANDS_ATTENTION", 1); - Atom wm_state = X11_XInternAtom(display, "_NET_WM_STATE", 1); + wmhints = X11_XGetWMHints(display, data->xwindow); + if (!wmhints) { + return SDL_SetError("Couldn't get WM hints"); + } - 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); + wmhints->flags &= ~XUrgencyHint; + data->flashing_window = SDL_FALSE; + data->flash_cancel_time = 0; + switch (operation) { + case SDL_FLASH_CANCEL: + /* Taken care of above */ + break; + case SDL_FLASH_BRIEFLY: + if (!(window->flags & SDL_WINDOW_INPUT_FOCUS)) { + wmhints->flags |= XUrgencyHint; + data->flashing_window = SDL_TRUE; + /* On Ubuntu 21.04 this causes a dialog to pop up, so leave it up for a full second so users can see it */ + data->flash_cancel_time = SDL_GetTicks() + 1000; + if (!data->flash_cancel_time) { + data->flash_cancel_time = 1; + } + } + break; + case SDL_FLASH_UNTIL_FOCUSED: + if (!(window->flags & SDL_WINDOW_INPUT_FOCUS)) { + wmhints->flags |= XUrgencyHint; + data->flashing_window = SDL_TRUE; + } + break; + default: + break; + } + + X11_XSetWMHints(display, data->xwindow, wmhints); + X11_XFree(wmhints); return 0; } diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index 25d12dd8d..3b2da5d2b 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -68,6 +68,8 @@ typedef struct unsigned long user_time; Atom xdnd_req; Window xdnd_source; + SDL_bool flashing_window; + Uint32 flash_cancel_time; #if SDL_VIDEO_OPENGL_EGL EGLSurface egl_surface; #endif