aboutsummaryrefslogtreecommitdiffstats
path: root/src/x11.c
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2023-01-08 09:37:26 -0500
committerDavid Robillard <d@drobilla.net>2023-01-08 09:46:11 -0500
commit2881f3defa1d89b2c6808db2344ea6e525aefd28 (patch)
treed415604d2a8ed31c450f93325a70e66165c99b41 /src/x11.c
parent92b5ab6bdfc8450ed3c4e4e7006cee949386dcd4 (diff)
downloadpugl-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.c67
1 files changed, 53 insertions, 14 deletions
diff --git a/src/x11.c b/src/x11.c
index 4e8d591..ce9387b 100644
--- a/src/x11.c
+++ b/src/x11.c
@@ -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;