Add support for _NET_WM_PING to X11 backend.

This way if the game is not responding for some reason and you click on X, after a few seconds an 'application not responding' dialog appears. Well, if your window manager supports it that is.
This commit is contained in:
UnknownShadow200 2020-02-08 15:20:38 +11:00
parent 8d3ec0faa0
commit 7886dbb14e

View File

@ -659,7 +659,7 @@ static int win_screen;
static Window win_rootWin, win_handle; static Window win_rootWin, win_handle;
static XVisualInfo win_visual; static XVisualInfo win_visual;
static Atom wm_destroy, net_wm_state; static Atom wm_destroy, net_wm_state, net_wm_ping;
static Atom net_wm_state_minimized; static Atom net_wm_state_minimized;
static Atom net_wm_state_fullscreen; static Atom net_wm_state_fullscreen;
@ -768,6 +768,7 @@ static void Window_RegisterAtoms(void) {
Display* display = win_display; Display* display = win_display;
wm_destroy = XInternAtom(display, "WM_DELETE_WINDOW", true); wm_destroy = XInternAtom(display, "WM_DELETE_WINDOW", true);
net_wm_state = XInternAtom(display, "_NET_WM_STATE", false); net_wm_state = XInternAtom(display, "_NET_WM_STATE", false);
net_wm_ping = XInternAtom(display, "_NET_WM_PING", false);
net_wm_state_minimized = XInternAtom(display, "_NET_WM_STATE_MINIMIZED", false); net_wm_state_minimized = XInternAtom(display, "_NET_WM_STATE_MINIMIZED", false);
net_wm_state_fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", false); net_wm_state_fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", false);
@ -809,6 +810,7 @@ void Window_Init(void) {
void Window_Create(int width, int height) { void Window_Create(int width, int height) {
XSetWindowAttributes attributes = { 0 }; XSetWindowAttributes attributes = { 0 };
XSizeHints hints = { 0 }; XSizeHints hints = { 0 };
Atom protocols[2];
struct GraphicsMode mode; struct GraphicsMode mode;
cc_uintptr addr; cc_uintptr addr;
int supported, x, y; int supported, x, y;
@ -843,7 +845,10 @@ void Window_Create(int width, int height) {
XSetWMNormalHints(win_display, win_handle, &hints); XSetWMNormalHints(win_display, win_handle, &hints);
/* Register for window destroy notification */ /* Register for window destroy notification */
XSetWMProtocols(win_display, win_handle, &wm_destroy, 1); protocols[0] = wm_destroy;
protocols[1] = net_wm_ping;
XSetWMProtocols(win_display, win_handle, protocols, 2);
/* Request that auto-repeat is only set on devices that support it physically. /* Request that auto-repeat is only set on devices that support it physically.
This typically means that it's turned off for keyboards (which is what we want). This typically means that it's turned off for keyboards (which is what we want).
We prefer this method over XAutoRepeatOff/On, because the latter needs to We prefer this method over XAutoRepeatOff/On, because the latter needs to
@ -1001,6 +1006,22 @@ static cc_bool Window_GetPendingEvent(XEvent* e) {
XCheckTypedWindowEvent(win_display, win_handle, SelectionRequest, e); XCheckTypedWindowEvent(win_display, win_handle, SelectionRequest, e);
} }
static void HandleWMDestroy(void) {
Platform_LogConst("Exit message received.");
Event_RaiseVoid(&WindowEvents.Closing);
/* sync and discard all events queued */
XSync(win_display, true);
XDestroyWindow(win_display, win_handle);
Window_Exists = false;
}
static void HandleWMPing(XEvent* e) {
e->xany.window = win_rootWin;
XSendEvent(win_display, win_rootWin, false,
SubstructureRedirectMask | SubstructureNotifyMask, e);
}
void Window_ProcessEvents(void) { void Window_ProcessEvents(void) {
XEvent e; XEvent e;
while (Window_Exists) { while (Window_Exists) {
@ -1008,14 +1029,11 @@ void Window_ProcessEvents(void) {
switch (e.type) { switch (e.type) {
case ClientMessage: case ClientMessage:
if (e.xclient.data.l[0] != wm_destroy) break; if (e.xclient.data.l[0] == wm_destroy) {
Platform_LogConst("Exit message received."); HandleWMDestroy();
Event_RaiseVoid(&WindowEvents.Closing); } else if (e.xclient.data.l[0] == net_wm_ping) {
HandleWMPing(&e);
/* sync and discard all events queued */ }
XSync(win_display, true);
XDestroyWindow(win_display, win_handle);
Window_Exists = false;
break; break;
case DestroyNotify: case DestroyNotify:
@ -1315,8 +1333,8 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
X11Button ok = { 0 }; X11Button ok = { 0 };
X11Textbox body = { 0 }; X11Textbox body = { 0 };
Atom protocols[2];
XFontStruct* font; XFontStruct* font;
Atom wmDelete;
int x, y, width, height; int x, y, width, height;
XSizeHints hints = { 0 }; XSizeHints hints = { 0 };
int mouseX = -1, mouseY = -1, over; int mouseX = -1, mouseY = -1, over;
@ -1326,8 +1344,9 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
XMapWindow(dpy, w->win); XMapWindow(dpy, w->win);
XStoreName(dpy, w->win, title); XStoreName(dpy, w->win, title);
wmDelete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); protocols[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", false);
XSetWMProtocols(dpy, w->win, &wmDelete, 1); protocols[1] = XInternAtom(dpy, "_NET_WM_PING", false);
XSetWMProtocols(dpy, w->win, protocols, 2);
font = XQueryFont(dpy, XGContextFromGC(w->gc)); font = XQueryFont(dpy, XGContextFromGC(w->gc));
if (!font) return; if (!font) return;
@ -1401,7 +1420,9 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
break; break;
case ClientMessage: case ClientMessage:
if (e.xclient.data.l[0] == wmDelete) return; /* { WM_DELETE_WINDOW, _NET_WM_PING } */
if (e.xclient.data.l[0] == protocols[0]) return;
if (e.xclient.data.l[0] == protocols[1]) HandleWMPing(&e);
break; break;
case MotionNotify: case MotionNotify: