2 * On-screen Display Daemon
4 * (c) 2010 Martin Mares <mj@ucw.cz>
15 #include <X11/Xatom.h>
23 typedef uint64_t timestamp_t;
24 static timestamp_t now;
26 /*** Displaying of messages ***/
30 timestamp_t min_light, max_light;
35 display_msg(struct msg *msg)
37 msg->min_light = msg->max_light = now + 1000;
39 char *line = msg->text;
43 // The parser it destructive, but it does not harm, since we display each message only once.
44 char *nl = strchr(line, '\n');
48 char *val = strchr(line, ':');
63 xosd_display(osd, row++, XOSD_string, val);
65 else if (!strcmp(key, "duration"))
66 msg->max_light = now + atoi(val);
67 else if (!strcmp(key, "min-duration"))
68 msg->min_light = now + atoi(val);
73 if (msg->min_light > msg->max_light)
74 msg->min_light = msg->max_light;
78 hide_msg(struct msg *msg)
80 xosd_scroll(osd, MAX_LINES);
85 /*** The message queue ***/
87 static struct msg *current_msg, *first_msg, *last_msg;
90 enqueue_msg(unsigned char *buf, int len)
92 DBG("[%.*s]\n", len, buf);
93 if (!len || buf[len-1] != '\n')
96 struct msg *msg = xmalloc(sizeof(*msg) + len);
97 memcpy(msg->text, buf, len);
101 last_msg->next = msg;
109 parse_input(unsigned char *buf, int len)
111 /* The property might contain several messages concatenated. Split them. */
120 while (i < len && (buf[i] != '\n' || (i && buf[i-1] != '\n')))
134 Display *dpy = XOpenDisplay(NULL);
136 die("Cannot open display");
137 Window win = DefaultRootWindow(dpy);
139 Atom pty = XInternAtom(dpy, "OSD_QUEUE", False);
141 die("Cannot intern OSD_QUEUE atom");
143 XSelectInput(dpy, win, PropertyChangeMask);
144 XDeleteProperty(dpy, win, pty);
147 osd = xosd_create(4);
149 die("Cannot initialize OSD");
150 xosd_set_font(osd, "-bitstream-bitstream vera sans-bold-r-normal-*-*-320-*-*-p-*-*");
151 xosd_set_outline_offset(osd, 2);
152 xosd_set_outline_colour(osd, "black");
153 xosd_set_pos(osd, XOSD_middle);
154 xosd_set_align(osd, XOSD_center);
156 struct pollfd pfd = {
157 .fd = ConnectionNumber(dpy),
164 gettimeofday(&tv, NULL);
165 now = (timestamp_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
167 timestamp_t wait_until = now - 1;
168 if (!current_msg && first_msg)
170 current_msg = first_msg;
171 first_msg = first_msg->next;
172 display_msg(current_msg);
177 wait_until = current_msg->min_light;
179 wait_until = current_msg->max_light;
180 if (wait_until <= now)
182 hide_msg(current_msg);
188 DBG("Waiting for %d ms\n", (int)(wait_until - now));
189 poll(&pfd, 1, wait_until - now);
190 if (pfd.revents & POLLIN)
192 while (XPending(dpy))
195 XNextEvent(dpy, &ev);
196 if (ev.type != PropertyNotify)
198 XPropertyEvent *p = &ev.xproperty;
199 if (p->window == win && p->atom == pty)
203 unsigned long pty_items, pty_remains;
204 unsigned char *pty_buf = NULL;
205 XGetWindowProperty(dpy, win, pty, 0, 4096, True, XA_STRING, &pty_type, &pty_fmt, &pty_items, &pty_remains, &pty_buf);
206 if (pty_type == XA_STRING && pty_fmt == 8 && pty_items)
208 DBG("Received: <%.*s>\n", (int) pty_items, pty_buf);
209 parse_input(pty_buf, pty_items);