2 * On-screen Display Daemon
4 * (c) 2010 Martin Mares <mj@ucw.cz>
16 #include <X11/Xatom.h>
23 static int num_lines = 4;
24 static char *font_name = "-bitstream-bitstream vera sans-bold-r-normal-*-*-320-*-*-p-*-*";
25 static char *default_color = "green";
26 static char *default_outline_color = "black";
28 typedef uint64_t timestamp_t;
29 static timestamp_t now;
31 /*** Displaying of messages ***/
35 timestamp_t min_light, max_light;
40 display_msg(struct msg *msg)
42 msg->min_light = msg->max_light = now + 1000;
43 xosd_set_colour(osd, default_color);
44 xosd_set_outline_colour(osd, default_outline_color);
46 char *line = msg->text;
50 // The parser it destructive, but it does not do any harm, since we display each message only once.
51 char *nl = strchr(line, '\n');
55 char *val = strchr(line, ':');
70 xosd_display(osd, row++, XOSD_string, val);
72 else if (!strcmp(key, "percentage") || !strcmp(key, "percent"))
75 xosd_display(osd, row++, XOSD_percentage, atoi(val));
77 else if (!strcmp(key, "slider"))
80 xosd_display(osd, row++, XOSD_slider, atoi(val));
82 else if (!strcmp(key, "duration"))
83 msg->max_light = now + atoi(val);
84 else if (!strcmp(key, "min-duration"))
85 msg->min_light = now + atoi(val);
86 else if (!strcmp(key, "color"))
87 xosd_set_colour(osd, val);
88 else if (!strcmp(key, "outline-color"))
89 xosd_set_outline_colour(osd, val);
94 if (msg->min_light > msg->max_light)
95 msg->min_light = msg->max_light;
99 hide_msg(struct msg *msg)
101 for (int i=0; i<num_lines; i++)
102 xosd_display(osd, i, XOSD_string, "");
107 /*** The message queue ***/
109 static struct msg *current_msg, *first_msg, *last_msg;
112 enqueue_msg(unsigned char *buf, int len)
114 DBG("[%.*s]\n", len, buf);
115 if (!len || buf[len-1] != '\n')
118 struct msg *msg = xmalloc(sizeof(*msg) + len);
119 memcpy(msg->text, buf, len);
123 last_msg->next = msg;
131 parse_input(unsigned char *buf, int len)
133 /* The property might contain several messages concatenated. Split them. */
142 while (i < len && (buf[i] != '\n' || (i && buf[i-1] != '\n')))
151 static const char short_opts[] = "c:f:l:o:";
153 static const struct option long_opts[] = {
154 { "color", required_argument, NULL, 'c' },
155 { "font", required_argument, NULL, 'f' },
156 { "lines", required_argument, NULL, 'l' },
157 { "outline-color", required_argument, NULL, 'o' },
158 { NULL, 0, NULL, 0 },
164 fprintf(stderr, "Usage: osdd <options>\n\n\
166 -c, --color=<c>\t\tDefault color (#rgb, #rrggbb or a name from rgb.txt)\n\
167 -f, --font=<f>\t\tFont to use for the OSD\n\
168 -l, --lines=<n>\t\tNumber of lines of the OSD\n\
169 -o, --outline-color=<c>\tDefault outline color\n\
175 parse_opts(int argc, char **argv)
178 while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0)
182 default_color = optarg;
188 num_lines = atoi(optarg);
193 default_outline_color = optarg;
206 main(int argc, char **argv)
208 parse_opts(argc, argv);
211 Display *dpy = XOpenDisplay(NULL);
213 die("Cannot open display");
214 Window win = DefaultRootWindow(dpy);
216 Atom pty = XInternAtom(dpy, "OSD_QUEUE", False);
218 die("Cannot intern OSD_QUEUE atom");
220 XSelectInput(dpy, win, PropertyChangeMask);
221 XDeleteProperty(dpy, win, pty);
224 osd = xosd_create(num_lines);
226 die("Cannot initialize OSD");
227 xosd_set_font(osd, font_name);
228 xosd_set_outline_offset(osd, 2);
229 xosd_set_pos(osd, XOSD_middle);
230 xosd_set_align(osd, XOSD_center);
232 struct pollfd pfd = {
233 .fd = ConnectionNumber(dpy),
240 gettimeofday(&tv, NULL);
241 now = (timestamp_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
243 timestamp_t wait_until = now - 1;
244 if (!current_msg && first_msg)
246 current_msg = first_msg;
247 first_msg = first_msg->next;
248 display_msg(current_msg);
253 wait_until = current_msg->min_light;
255 wait_until = current_msg->max_light;
256 if (wait_until <= now)
258 hide_msg(current_msg);
264 DBG("Waiting for %d ms\n", (int)(wait_until - now));
265 poll(&pfd, 1, wait_until - now);
266 if (pfd.revents & POLLIN)
268 while (XPending(dpy))
271 XNextEvent(dpy, &ev);
272 if (ev.type != PropertyNotify)
274 XPropertyEvent *p = &ev.xproperty;
275 if (p->window == win && p->atom == pty)
279 unsigned long pty_items, pty_remains;
280 unsigned char *pty_buf = NULL;
281 XGetWindowProperty(dpy, win, pty, 0, 4096, True, XA_STRING, &pty_type, &pty_fmt, &pty_items, &pty_remains, &pty_buf);
282 if (pty_type == XA_STRING && pty_fmt == 8 && pty_items)
283 parse_input(pty_buf, pty_items);