ohmu
·
2026-07-25
1/* See LICENSE file for copyright and license details. */
2
3#include <err.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <xcb/xcb.h>
8#include <xcb/xcb_aux.h>
9
10#include "util.h"
11#include "arg.h"
12
13#define MAXLEN 512
14
15static xcb_connection_t *conn;
16
17void
18usage(char *name)
19{
20 fprintf(stderr, "%s [-d] atom[=value] wid\n", name);
21}
22
23xcb_atom_t
24add_atom(xcb_atom_t type, char *name, size_t len)
25{
26 xcb_atom_t atom;
27 xcb_intern_atom_cookie_t c;
28 xcb_intern_atom_reply_t *r;
29
30 c = xcb_intern_atom(conn, 0, len, name);
31 r = xcb_intern_atom_reply(conn, c, NULL);
32 if (!r)
33 return 0;
34
35 atom = r->atom;
36 free(r);
37
38 return atom;
39}
40
41int
42set_atom(xcb_window_t wid, xcb_atom_t atom, xcb_atom_t type, size_t len, void *data)
43{
44 int errcode;
45 xcb_void_cookie_t c;
46 xcb_generic_error_t *e;
47
48 c = xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE,
49 wid, atom, type, 8, len, data);
50 e = xcb_request_check(conn, c);
51 if (!e)
52 return 0;
53
54 errcode = e->error_code;
55 free(e);
56
57 return errcode;
58}
59
60int
61get_atom(xcb_window_t wid, xcb_atom_t atom, char *data, xcb_atom_t *type)
62{
63 size_t n;
64 xcb_get_property_cookie_t c;
65 xcb_get_property_reply_t *r;
66
67 c = xcb_get_property(conn, 0, wid, atom, XCB_ATOM_ANY, 0, MAXLEN);
68 r = xcb_get_property_reply(conn, c, NULL);
69 if (!r)
70 return -1;
71
72 if (!(n = xcb_get_property_value_length(r))) {
73 free(r);
74 return -1;
75 }
76
77 strncpy(data, xcb_get_property_value(r), n);
78 data[n] = 0;
79
80 *type = r->type;
81
82 free(r);
83
84 return 0;
85}
86
87
88int
89main(int argc, char **argv)
90{
91 int i, dflag = 0;
92 char *key, *val, *argv0;
93 char data[MAXLEN];
94 xcb_window_t wid;
95 xcb_atom_t atom;
96
97 ARGBEGIN {
98 case 'd':
99 dflag = 1;
100 break;
101 default:
102 usage(argv0);
103 return -1;
104 } ARGEND;
105
106 if (argc < 1)
107 return -1;
108
109 key = strtok(argv[0], "=");
110 val = strtok(NULL, "=");
111
112 init_xcb(&conn);
113
114 for (i = 0; i < argc - 1; i++) {
115 wid = strtoul(argv[i+1], NULL, 16);
116
117 /* retrieve atom ID from server */
118 atom = add_atom(XCB_ATOM_STRING, key, strlen(key));
119 if (!atom)
120 return -1;
121
122 /* set property on window (must be a string) */
123 if (val)
124 set_atom(wid, atom, XCB_ATOM_STRING, strlen(val), val);
125
126 /* remove property from window */
127 if (dflag)
128 xcb_delete_property(conn, wid, atom);
129
130 /* retrieve and print atom value to stdout */
131 xcb_atom_t type;
132 if (!get_atom(wid, atom, data, &type))
133 switch (type) {
134 case XCB_ATOM_INTEGER:
135 printf("%d\n", *data);
136 break;
137 default:
138 printf("%s\n", data);
139 }
140 }
141
142 kill_xcb(&conn);
143
144 return 0;
145}