From ff1b5e1bf7971fb87c77fd9b17fe05ec5a14dbba Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 24 Jul 2021 15:10:57 -0700
Subject: [PATCH] Implemented the window flash operations for X11
---
src/video/x11/SDL_x11events.c | 13 +++++++++
src/video/x11/SDL_x11sym.h | 3 ++-
src/video/x11/SDL_x11window.c | 50 +++++++++++++++++++++++++----------
src/video/x11/SDL_x11window.h | 2 ++
4 files changed, 53 insertions(+), 15 deletions(-)
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 8c654f23d3..8d19a2e6d6 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 6433b93106..9a46802cd6 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 9a09fee48a..4ce299f03e 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 25d12dd8d2..3b2da5d2b1 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