Implemented the window flash operations for X11
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 8c654f2..8d19a2e 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 6433b93..9a46802 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 9a09fee..4ce299f 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);
-
- 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 = X11_XGetWMHints(display, data->xwindow);
+ if (!wmhints) {
+ return SDL_SetError("Couldn't get WM hints");
+ }
+
+ 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 25d12dd..3b2da5d 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