diff options
author | David Robillard <d@drobilla.net> | 2023-01-08 09:37:26 -0500 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2023-01-08 09:46:11 -0500 |
commit | 2881f3defa1d89b2c6808db2344ea6e525aefd28 (patch) | |
tree | d415604d2a8ed31c450f93325a70e66165c99b41 /src/x11.c | |
parent | 92b5ab6bdfc8450ed3c4e4e7006cee949386dcd4 (diff) | |
download | pugl-2881f3defa1d89b2c6808db2344ea6e525aefd28.tar.gz pugl-2881f3defa1d89b2c6808db2344ea6e525aefd28.tar.bz2 pugl-2881f3defa1d89b2c6808db2344ea6e525aefd28.zip |
X11: Add support for _NET_WM_PING protocol
This is mainly used to allow the window manager to close locked or otherwise
misbehaving windows. The PID and hostname properties are both required to
properly support this, but may also be used for other things.
Diffstat (limited to 'src/x11.c')
-rw-r--r-- | src/x11.c | 67 |
1 files changed, 53 insertions, 14 deletions
@@ -41,6 +41,7 @@ #include <stdlib.h> #include <string.h> #include <time.h> +#include <unistd.h> #ifndef MIN # define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -157,14 +158,17 @@ puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags) // Intern the various atoms we'll need - impl->atoms.CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0); - impl->atoms.UTF8_STRING = XInternAtom(display, "UTF8_STRING", 0); - impl->atoms.WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", 0); - impl->atoms.WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", 0); - impl->atoms.PUGL_CLIENT_MSG = XInternAtom(display, "_PUGL_CLIENT_MSG", 0); - impl->atoms.NET_CLOSE_WINDOW = XInternAtom(display, "_NET_CLOSE_WINDOW", 0); - impl->atoms.NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", 0); - impl->atoms.NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", 0); + impl->atoms.CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0); + impl->atoms.UTF8_STRING = XInternAtom(display, "UTF8_STRING", 0); + impl->atoms.WM_CLIENT_MACHINE = XInternAtom(display, "WM_CLIENT_MACHINE", 0); + impl->atoms.WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", 0); + impl->atoms.WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", 0); + impl->atoms.PUGL_CLIENT_MSG = XInternAtom(display, "_PUGL_CLIENT_MSG", 0); + impl->atoms.NET_CLOSE_WINDOW = XInternAtom(display, "_NET_CLOSE_WINDOW", 0); + impl->atoms.NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", 0); + impl->atoms.NET_WM_PID = XInternAtom(display, "_NET_WM_PID", 0); + impl->atoms.NET_WM_PING = XInternAtom(display, "_NET_WM_PING", 0); + impl->atoms.NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", 0); impl->atoms.NET_WM_STATE_ABOVE = XInternAtom(display, "_NET_WM_STATE_ABOVE", 0); @@ -583,14 +587,38 @@ puglRealize(PuglView* const view) puglSetWindowTitle(view, view->title); } - if (parent == root) { - XSetWMProtocols(display, impl->win, &atoms->WM_DELETE_WINDOW, 1); - } - if (view->transientParent) { puglSetTransientParent(view, view->transientParent); } + // Set PID and hostname so the window manager can access our process + char hostname[256] = {0}; + const long pid = (long)getpid(); + if (pid > 0 && !gethostname(hostname, sizeof(hostname))) { + hostname[sizeof(hostname) - 1] = '\0'; + XChangeProperty(display, + impl->win, + atoms->WM_CLIENT_MACHINE, + XA_STRING, + 8, + PropModeReplace, + (const uint8_t*)hostname, + (int)strlen(hostname)); + + XChangeProperty(display, + impl->win, + atoms->NET_WM_PID, + XA_CARDINAL, + 32, + PropModeReplace, + (const uint8_t*)&pid, + 1); + } + + // Set supported WM protocols + Atom protocols[] = {atoms->NET_WM_PING, atoms->WM_DELETE_WINDOW}; + XSetWMProtocols(display, impl->win, protocols, (parent == root) ? 2 : 1); + // Create input context if (world->impl->xim) { impl->xic = XCreateIC(world->impl->xim, @@ -913,13 +941,24 @@ setClipboardFormats(PuglView* const view, static PuglEvent translateClientMessage(PuglView* const view, XClientMessageEvent message) { - const PuglX11Atoms* const atoms = &view->world->impl->atoms; - PuglEvent event = {{PUGL_NOTHING, 0}}; + Display* const display = view->world->impl->display; + const PuglX11Atoms* const atoms = &view->world->impl->atoms; + PuglEvent event = {{PUGL_NOTHING, 0}}; if (message.message_type == atoms->WM_PROTOCOLS) { const Atom protocol = (Atom)message.data.l[0]; if (protocol == atoms->WM_DELETE_WINDOW) { event.type = PUGL_CLOSE; + } else if (protocol == atoms->NET_WM_PING) { + const Window root = RootWindow(display, view->impl->screen); + XEvent reply = {ClientMessage}; + reply.xclient = message; + reply.xclient.window = root; + XSendEvent(display, + root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &reply); } } else if (message.message_type == atoms->PUGL_CLIENT_MSG) { event.type = PUGL_CLIENT; |