/* Send the close-button protocol to one PID-checked X11 window. */ #include #include #include #include #include static unsigned long parse_id(const char *text) { char *end; errno = 0; unsigned long value = strtoul(text, &end, 0); if (errno || *end || end == text || !value || *text == '-') { fprintf(stderr, "Invalid positive window ID or PID: %s\n", text); exit(2); } return value; } int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "Usage: %s WINDOW_ID EXPECTED_PID\n", argv[0]); return 2; } Window window = parse_id(argv[1]); unsigned long expected_pid = parse_id(argv[2]); Display *display = XOpenDisplay(NULL); if (!display) { fprintf(stderr, "Cannot open DISPLAY\n"); return 1; } Atom type; int format; unsigned long count, remaining; unsigned char *data = NULL; int result = XGetWindowProperty(display, window, XInternAtom(display, "_NET_WM_PID", False), 0, 1, False, XA_CARDINAL, &type, &format, &count, &remaining, &data); int matches = result == Success && type == XA_CARDINAL && format == 32 && count == 1 && data && *(unsigned long *)data == expected_pid; if (data) XFree(data); if (!matches) { fprintf(stderr, "Window does not belong to expected PID %lu\n", expected_pid); XCloseDisplay(display); return 1; } Atom protocol = XInternAtom(display, "WM_DELETE_WINDOW", False); Atom *protocols = NULL; int protocol_count = 0, supports_close = 0; if (XGetWMProtocols(display, window, &protocols, &protocol_count)) { for (int i = 0; i < protocol_count; i++) supports_close |= protocols[i] == protocol; XFree(protocols); } if (!supports_close) { fprintf(stderr, "Window does not advertise WM_DELETE_WINDOW\n"); XCloseDisplay(display); return 1; } XEvent event = {0}; event.xclient.type = ClientMessage; event.xclient.window = window; event.xclient.message_type = XInternAtom(display, "WM_PROTOCOLS", False); event.xclient.format = 32; event.xclient.data.l[0] = protocol; event.xclient.data.l[1] = CurrentTime; int sent = XSendEvent(display, window, False, NoEventMask, &event); XSync(display, False); XCloseDisplay(display); printf("WM_DELETE_WINDOW sent=%d window=%lu pid=%lu\n", sent, window, expected_pid); return sent ? 0 : 1; }