xprop-sink
lightweight, streaming X11 property updater
git clone https://9o.is/git/xprop-sink.git
xprop-sink.c
(1724B)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <X11/Xlib.h>
5 #include <X11/Xatom.h>
6
7 static int running = 1;
8
9 void
10 usage(const char *prog)
11 {
12 fprintf(stderr, "Usage: %s <window_id> <property_name>\n", prog);
13 }
14
15 int
16 handle_x_errors(Display *dpy, XErrorEvent *ev)
17 {
18 (void)dpy;
19 if (ev->error_code == BadWindow)
20 running = 0;
21 return 0;
22 }
23
24 int
25 main(int argc, char **argv)
26 {
27 Display *dpy;
28 Window win;
29 XWindowAttributes wa;
30 Atom atom;
31 char *endptr, buffer[1024];
32 size_t len;
33 int c;
34
35 if (argc != 3) {
36 usage(argv[0]);
37 return 1;
38 }
39
40 win = (Window) strtol(argv[1], &endptr, 0);
41 if (*endptr != '\0' || win == 0) {
42 fprintf(stderr, "Error: Invalid Window ID\n");
43 usage(argv[0]);
44 return 1;
45 }
46
47 dpy = XOpenDisplay(NULL);
48 if (!dpy) {
49 fprintf(stderr, "Error: Cannot open X display\n");
50 return 1;
51 }
52
53 XSetErrorHandler(handle_x_errors);
54
55 atom = XInternAtom(dpy, argv[2], False);
56 if (atom == None) {
57 fprintf(stderr, "Error: Cannot create X atom\n");
58 return 1;
59 }
60
61 if (!XGetWindowAttributes(dpy, win, &wa)) {
62 fprintf(stderr, "Error: Window not found\n");
63 return 1;
64 }
65
66 setvbuf(stdin, NULL, _IONBF, 0);
67
68 while (running && fgets(buffer, sizeof(buffer), stdin)) {
69 len = strlen(buffer);
70
71 // If line exceeds buffer size, the remainder drained and ignored
72 if (len == sizeof(buffer) - 1 && buffer[len-1] != '\n') {
73 while ((c = getchar()) != '\n' && c != EOF);
74 continue;
75 }
76
77 len = strlen(buffer);
78 buffer[strcspn(buffer, "\r\n")] = 0;
79
80 if (!XGetWindowAttributes(dpy, win, &wa))
81 break;
82
83 if (len > 0) {
84 XChangeProperty(dpy, win, atom, XA_STRING, 8,
85 PropModeReplace, (unsigned char *)buffer, (int)len);
86 XFlush(dpy);
87 }
88 }
89
90 XCloseDisplay(dpy);
91 return 0;
92 }