From 6df5e1e53595914cef1ec1fb62dee127512ebb02 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 4 Jan 2016 16:25:27 -0500 Subject: [PATCH] x11: Support _NET_WM_USER_TIME and give _NET_ACTIVE_WINDOW a valid timestamp. Fixes Bugzilla #3056. --- src/video/x11/SDL_x11events.c | 32 +++++++++++++++++++++++++++++++- src/video/x11/SDL_x11video.c | 1 + src/video/x11/SDL_x11video.h | 1 + src/video/x11/SDL_x11window.c | 4 +++- src/video/x11/SDL_x11window.h | 1 + 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 208009607fa24..e69111cb90c4b 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -512,6 +512,23 @@ ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev) return SDL_FALSE; } +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) { @@ -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 01f8ae60f8ec8..412d7a89e18b2 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 2083defd2fcca..9cdc4d31622f8 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 afc802198efef..b5753db4d96ee 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 efe7ec0f089b1..ce19499db2f6c 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