aboutsummaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--src/x11.c67
-rw-r--r--src/x11.h3
2 files changed, 56 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;
diff --git a/src/x11.h b/src/x11.h
index e90694a..b2c0e54 100644
--- a/src/x11.h
+++ b/src/x11.h
@@ -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;