+/*
+ * On-screen Display -- Support Functions for Clients
+ *
+ * (c) 2010 Martin Mares <mj@ucw.cz>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <poll.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#undef DEBUG
+#include "osd.h"
+
+static Display *dpy;
+static Atom pty;
+
+#define MAX_MSG_SIZE 1024
+
+struct osd_msg {
+ int cnt;
+ char buf[MAX_MSG_SIZE];
+};
+
+void
+osd_init(void)
+{
+ if (dpy)
+ return;
+
+ dpy = XOpenDisplay(NULL);
+ if (!dpy)
+ die("Cannot open display");
+
+ pty = XInternAtom(dpy, "OSD_QUEUE", False);
+ if (!pty)
+ die("Cannot intern OSD_QUEUE atom");
+}
+
+struct osd_msg *
+osd_new_msg(void)
+{
+ struct osd_msg *msg = xmalloc(sizeof(*msg));
+ msg->cnt = 0;
+ return msg;
+}
+
+void
+osd_add_line(struct osd_msg *msg, char *key, char *val)
+{
+ if (!key)
+ key = "";
+ msg->cnt += snprintf(msg->buf + msg->cnt, MAX_MSG_SIZE - msg->cnt - 1, "%s:%s\n", key, val);
+ if (msg->cnt > MAX_MSG_SIZE - 1)
+ die("OSD message too long (at most %d bytes)", MAX_MSG_SIZE);
+}
+
+void
+osd_send(struct osd_msg *msg)
+{
+ osd_init();
+ msg->buf[msg->cnt++] = '\n';
+ if (!XChangeProperty(dpy, DefaultRootWindow(dpy), pty, XA_STRING, 8, PropModeAppend, (unsigned char *) msg->buf, msg->cnt))
+ die("XChangeProperty failed");
+ XFlush(dpy);
+ free(msg);
+}
+
+void
+osd_fork(void)
+{
+ osd_init();
+ pid_t pid = fork();
+ if (pid < 0)
+ die("Cannot fork: %m");
+ if (pid > 0)
+ exit(0);
+ setsid();
+}
+
+void
+osd_wait(int delay)
+{
+ DBG("Waiting for %d seconds\n", delay);
+ timestamp_t wait_until = get_current_time() + delay*1000;
+
+ struct pollfd pfd = {
+ .fd = ConnectionNumber(dpy),
+ .events = POLLIN,
+ };
+
+ for (;;)
+ {
+ timestamp_t now = get_current_time();
+ if (now >= wait_until)
+ return;
+
+ DBG("... waiting for %d ms\n", (int)(wait_until - now));
+ poll(&pfd, 1, wait_until - now);
+ if (pfd.revents & POLLIN)
+ {
+ XEvent ev;
+ while (XPending(dpy))
+ XNextEvent(dpy, &ev);
+ }
+ }
+}