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 | |
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')
-rw-r--r-- | src/x11.c | 67 | ||||
-rw-r--r-- | src/x11.h | 3 |
2 files changed, 56 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; @@ -21,11 +21,14 @@ typedef struct { Atom CLIPBOARD; Atom UTF8_STRING; + Atom WM_CLIENT_MACHINE; Atom WM_PROTOCOLS; Atom WM_DELETE_WINDOW; Atom PUGL_CLIENT_MSG; Atom NET_CLOSE_WINDOW; Atom NET_WM_NAME; + Atom NET_WM_PID; + Atom NET_WM_PING; Atom NET_WM_STATE; Atom NET_WM_STATE_ABOVE; Atom NET_WM_STATE_BELOW; |