ohmu
·
2026-07-25
1// Created by https://github.com/onodera-punpun
2
3#include <string.h>
4#include <stdbool.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <err.h>
8#include <xcb/xcb.h>
9#include <xcb/xcb_icccm.h>
10
11#include "util.h"
12
13static xcb_connection_t *conn;
14
15static void usage(char *);
16
17static void
18usage (char *name)
19{
20 fprintf(stderr, "usage: %s <wid> [wid...]\n", name);
21 exit(1);
22}
23
24static
25xcb_atom_t xcb_atom_get(xcb_connection_t *conn, char *name)
26{
27 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(conn ,0, strlen(name), name);
28 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, cookie, NULL);
29
30 if (!reply)
31 return XCB_ATOM_STRING;
32
33 return reply->atom;
34}
35
36void
37delete_window(xcb_window_t win)
38{
39 xcb_client_message_event_t ev;
40
41 ev.response_type = XCB_CLIENT_MESSAGE;
42 ev.sequence = 0;
43 ev.format = 32;
44 ev.window = win;
45 ev.type = xcb_atom_get(conn, "WM_PROTOCOLS");
46 ev.data.data32[0] = xcb_atom_get(conn, "WM_DELETE_WINDOW");
47 ev.data.data32[1] = XCB_CURRENT_TIME;
48
49 xcb_send_event(conn, 0, win, XCB_EVENT_MASK_NO_EVENT, (char *)&ev);
50}
51
52int
53main(int argc, char **argv)
54{
55 xcb_window_t win = 0;
56
57 if (argc < 2)
58 usage(argv[0]);
59
60 init_xcb(&conn);
61
62 /* assume remaining arguments are windows */
63 while (*argv)
64 win = strtoul(*argv++, NULL, 16);
65
66 xcb_icccm_get_wm_protocols_reply_t reply;
67 unsigned int i = 0;
68 bool got = false;
69
70 if (xcb_icccm_get_wm_protocols_reply(conn, xcb_icccm_get_wm_protocols(conn, win, xcb_atom_get(conn, "WM_PROTOCOLS")), &reply, NULL)) {
71 for (; i != reply.atoms_len; ++i)
72 if ((got = reply.atoms[i] == xcb_atom_get(conn, "WM_DELETE_WINDOW")))
73 break;
74
75 xcb_icccm_get_wm_protocols_reply_wipe(&reply);
76 }
77
78 if (got)
79 delete_window(win);
80 else
81 xcb_kill_client(conn, win);
82
83 xcb_flush(conn);
84
85 kill_xcb(&conn);
86
87 return 0;
88}