x11: Support _NET_WM_USER_TIME and give _NET_ACTIVE_WINDOW a valid timestamp. Fixes Bugzilla #3056.
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
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 2080096..e69111c 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -513,6 +513,23 @@ ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev)
}
static void
+X11_UpdateUserTime(SDL_WindowData *data, const unsigned long latest)
+{
+ if (latest && (latest != data->user_time)) {
+ SDL_VideoData *videodata = data->videodata;
+ Display *display = videodata->display;
+ X11_XChangeProperty(display, data->xwindow, videodata->_NET_WM_USER_TIME,
+ XA_CARDINAL, 32, PropModeReplace,
+ (const unsigned char *) &latest, 1);
+ #if DEBUG_XEVENTS
+ printf("window %p: updating _NET_WM_USER_TIME to %lu\n", data, latest);
+ #endif
+ data->user_time = latest;
+ }
+}
+
+
+static void
X11_DispatchEvent(_THIS)
{
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
@@ -773,6 +790,7 @@ X11_DispatchEvent(_THIS)
}
}
+ X11_UpdateUserTime(data, xevent.xkey.time);
}
break;
@@ -1001,6 +1019,7 @@ X11_DispatchEvent(_THIS)
}
SDL_SendMouseButton(data->window, 0, SDL_PRESSED, button);
}
+ X11_UpdateUserTime(data, xevent.xbutton.time);
}
break;
@@ -1027,7 +1046,7 @@ X11_DispatchEvent(_THIS)
char *name = X11_XGetAtomName(display, xevent.xproperty.atom);
if (name) {
- printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed");
+ printf("window %p: PropertyNotify: %s %s time=%lu\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent.xproperty.time);
X11_XFree(name);
}
@@ -1095,6 +1114,17 @@ X11_DispatchEvent(_THIS)
}
#endif /* DEBUG_XEVENTS */
+ /* Take advantage of this moment to make sure user_time has a
+ valid timestamp from the X server, so if we later try to
+ raise/restore this window, _NET_ACTIVE_WINDOW can have a
+ non-zero timestamp, even if there's never been a mouse or
+ key press to this window so far. Note that we don't try to
+ set _NET_WM_USER_TIME here, though. That's only for legit
+ user interaction with the window. */
+ if (!data->user_time) {
+ data->user_time = xevent.xproperty.time;
+ }
+
if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
/* Get the new state from the window manager.
Compositing window managers can alter visibility of windows
diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c
index 01f8ae6..412d7a8 100644
--- a/src/video/x11/SDL_x11video.c
+++ b/src/video/x11/SDL_x11video.c
@@ -397,6 +397,7 @@ X11_VideoInit(_THIS)
GET_ATOM(_NET_WM_ICON_NAME);
GET_ATOM(_NET_WM_ICON);
GET_ATOM(_NET_WM_PING);
+ GET_ATOM(_NET_WM_USER_TIME);
GET_ATOM(_NET_ACTIVE_WINDOW);
GET_ATOM(UTF8_STRING);
GET_ATOM(PRIMARY);
diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h
index 2083def..9cdc4d3 100644
--- a/src/video/x11/SDL_x11video.h
+++ b/src/video/x11/SDL_x11video.h
@@ -100,6 +100,7 @@ typedef struct SDL_VideoData
Atom _NET_WM_ICON_NAME;
Atom _NET_WM_ICON;
Atom _NET_WM_PING;
+ Atom _NET_WM_USER_TIME;
Atom _NET_ACTIVE_WINDOW;
Atom UTF8_STRING;
Atom PRIMARY;
diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c
index afc8021..b5753db 100644
--- a/src/video/x11/SDL_x11window.c
+++ b/src/video/x11/SDL_x11window.c
@@ -944,6 +944,8 @@ SetWindowActive(_THIS, SDL_Window * window)
Atom _NET_ACTIVE_WINDOW = data->videodata->_NET_ACTIVE_WINDOW;
if (X11_IsWindowMapped(_this, window)) {
+ SDL_assert(data->user_time != 0); /* should be set by _some_ event by now. */
+ /*printf("SDL Window %p: sending _NET_ACTIVE_WINDOW with timestamp %lu\n", window, data->user_time);*/
XEvent e;
SDL_zero(e);
@@ -952,7 +954,7 @@ SetWindowActive(_THIS, SDL_Window * window)
e.xclient.format = 32;
e.xclient.window = data->xwindow;
e.xclient.data.l[0] = 1; /* source indication. 1 = application */
- e.xclient.data.l[1] = CurrentTime;
+ e.xclient.data.l[1] = data->user_time;
e.xclient.data.l[2] = 0;
X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h
index efe7ec0..ce19499 100644
--- a/src/video/x11/SDL_x11window.h
+++ b/src/video/x11/SDL_x11window.h
@@ -60,6 +60,7 @@ typedef struct
Uint32 pending_focus_time;
XConfigureEvent last_xconfigure;
struct SDL_VideoData *videodata;
+ unsigned long user_time;
Atom xdnd_req;
Window xdnd_source;
#if SDL_VIDEO_OPENGL_EGL