From 7886dbb14eb60f1d60336811bd2d49d83d15087f Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 8 Feb 2020 15:20:38 +1100 Subject: [PATCH] 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. --- src/Window.c | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/src/Window.c b/src/Window.c index d38d253ac..9315a5964 100644 --- a/src/Window.c +++ b/src/Window.c @@ -659,7 +659,7 @@ static int win_screen; static Window win_rootWin, win_handle; 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_fullscreen; @@ -768,6 +768,7 @@ static void Window_RegisterAtoms(void) { Display* display = win_display; wm_destroy = XInternAtom(display, "WM_DELETE_WINDOW", true); 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_fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", false); @@ -809,6 +810,7 @@ void Window_Init(void) { void Window_Create(int width, int height) { XSetWindowAttributes attributes = { 0 }; XSizeHints hints = { 0 }; + Atom protocols[2]; struct GraphicsMode mode; cc_uintptr addr; int supported, x, y; @@ -843,7 +845,10 @@ void Window_Create(int width, int height) { XSetWMNormalHints(win_display, win_handle, &hints); /* 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. 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 @@ -1001,6 +1006,22 @@ static cc_bool Window_GetPendingEvent(XEvent* 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) { XEvent e; while (Window_Exists) { @@ -1008,14 +1029,11 @@ void Window_ProcessEvents(void) { switch (e.type) { case ClientMessage: - if (e.xclient.data.l[0] != wm_destroy) break; - 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; + if (e.xclient.data.l[0] == wm_destroy) { + HandleWMDestroy(); + } else if (e.xclient.data.l[0] == net_wm_ping) { + HandleWMPing(&e); + } break; case DestroyNotify: @@ -1315,8 +1333,8 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) { X11Button ok = { 0 }; X11Textbox body = { 0 }; + Atom protocols[2]; XFontStruct* font; - Atom wmDelete; int x, y, width, height; XSizeHints hints = { 0 }; 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); XStoreName(dpy, w->win, title); - wmDelete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(dpy, w->win, &wmDelete, 1); + protocols[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", false); + protocols[1] = XInternAtom(dpy, "_NET_WM_PING", false); + XSetWMProtocols(dpy, w->win, protocols, 2); font = XQueryFont(dpy, XGContextFromGC(w->gc)); if (!font) return; @@ -1401,7 +1420,9 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) { break; 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; case MotionNotify: