From 66ea7419541d01ea378523d106e8946b667cbe61 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sat, 17 Jul 2010 16:37:06 +0200 Subject: [PATCH] Initial commit. --- Makefile | 14 ++++ osdc.c | 54 ++++++++++++++ osdd.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ send.c | 67 +++++++++++++++++ send.h | 12 +++ util.c | 31 ++++++++ util.h | 18 +++++ 7 files changed, 413 insertions(+) create mode 100644 Makefile create mode 100644 osdc.c create mode 100644 osdd.c create mode 100644 send.c create mode 100644 send.h create mode 100644 util.c create mode 100644 util.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d5f5351 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Wundef -Wredundant-decls -std=gnu99 + +all: osdd osdc + +osdd: osdd.o util.o +osdc: osdc.o util.o send.o + +osdd.o: CFLAGS+=$(shell xosd-config --cflags) +osdd: LDFLAGS+=$(shell xosd-config --libs) + +osdc: LDFLAGS+=-lX11 + +clean: + rm -f *~ *.o TAGS core osdd diff --git a/osdc.c b/osdc.c new file mode 100644 index 0000000..27b6c63 --- /dev/null +++ b/osdc.c @@ -0,0 +1,54 @@ +/* + * On-screen Display Client + * + * (c) 2010 Martin Mares + */ + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "send.h" + +static void NONRET +usage(void) +{ + fprintf(stderr, "Usage: osdc [--= | ]*\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + struct osd_msg *m = osd_new_msg(); + + int more_opts = 1; + for (int i=1; imax_light = now + atoi(val); + else if (!strcmp(key, "min-duration")) + msg->min_light = now + atoi(val); + + line = nl; + } + + if (msg->min_light > msg->max_light) + msg->min_light = msg->max_light; +} + +static void +hide_msg(struct msg *msg) +{ + xosd_scroll(osd, MAX_LINES); + xosd_hide(osd); + free(msg); +} + +/*** The message queue ***/ + +static struct msg *current_msg, *first_msg, *last_msg; + +static void +enqueue_msg(unsigned char *buf, int len) +{ + DBG("[%.*s]\n", len, buf); + if (!len || buf[len-1] != '\n') + return; + + struct msg *msg = xmalloc(sizeof(*msg) + len); + memcpy(msg->text, buf, len); + msg->text[len] = 0; + + if (first_msg) + last_msg->next = msg; + else + first_msg = msg; + last_msg = msg; + msg->next = NULL; +} + +static void +parse_input(unsigned char *buf, int len) +{ + /* The property might contain several messages concatenated. Split them. */ + while (len > 0) + { + if (buf[0] == '\n') + { + buf++, len--; + continue; + } + int i = 0; + while (i < len && (buf[i] != '\n' || (i && buf[i-1] != '\n'))) + i++; + enqueue_msg(buf, i); + buf += i, len -= i; + } +} + +/*** Main loop ***/ + +int +main(void) +{ + XInitThreads(); + + Display *dpy = XOpenDisplay(NULL); + if (!dpy) + die("Cannot open display"); + Window win = DefaultRootWindow(dpy); + + Atom pty = XInternAtom(dpy, "OSD_QUEUE", False); + if (!pty) + die("Cannot intern OSD_QUEUE atom"); + + XSelectInput(dpy, win, PropertyChangeMask); + XDeleteProperty(dpy, win, pty); + XFlush(dpy); + + osd = xosd_create(4); + if (!osd) + die("Cannot initialize OSD"); + xosd_set_font(osd, "-bitstream-bitstream vera sans-bold-r-normal-*-*-320-*-*-p-*-*"); + xosd_set_outline_offset(osd, 2); + xosd_set_outline_colour(osd, "black"); + xosd_set_pos(osd, XOSD_middle); + xosd_set_align(osd, XOSD_center); + + struct pollfd pfd = { + .fd = ConnectionNumber(dpy), + .events = POLLIN, + }; + + for (;;) + { + struct timeval tv; + gettimeofday(&tv, NULL); + now = (timestamp_t) tv.tv_sec * 1000 + tv.tv_usec / 1000; + + timestamp_t wait_until = now - 1; + if (!current_msg && first_msg) + { + current_msg = first_msg; + first_msg = first_msg->next; + display_msg(current_msg); + } + if (current_msg) + { + if (first_msg) + wait_until = current_msg->min_light; + else + wait_until = current_msg->max_light; + if (wait_until <= now) + { + hide_msg(current_msg); + current_msg = NULL; + continue; + } + } + + DBG("Waiting for %d ms\n", (int)(wait_until - now)); + poll(&pfd, 1, wait_until - now); + if (pfd.revents & POLLIN) + { + while (XPending(dpy)) + { + XEvent ev; + XNextEvent(dpy, &ev); + if (ev.type != PropertyNotify) + continue; + XPropertyEvent *p = &ev.xproperty; + if (p->window == win && p->atom == pty) + { + Atom pty_type; + int pty_fmt; + unsigned long pty_items, pty_remains; + unsigned char *pty_buf = NULL; + XGetWindowProperty(dpy, win, pty, 0, 4096, True, XA_STRING, &pty_type, &pty_fmt, &pty_items, &pty_remains, &pty_buf); + if (pty_type == XA_STRING && pty_fmt == 8 && pty_items) + { + DBG("Received: <%.*s>\n", (int) pty_items, pty_buf); + parse_input(pty_buf, pty_items); + } + if (pty_buf) + XFree(pty_buf); + } + } + } + } +} diff --git a/send.c b/send.c new file mode 100644 index 0000000..aab11a7 --- /dev/null +++ b/send.c @@ -0,0 +1,67 @@ +/* + * On-screen Display Client -- Sending Messages + * + * (c) 2010 Martin Mares + */ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "send.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) +{ + 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) +{ + if (!dpy) + 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); +} diff --git a/send.h b/send.h new file mode 100644 index 0000000..e01022d --- /dev/null +++ b/send.h @@ -0,0 +1,12 @@ +/* + * On-screen Display Client -- Sending Messages + * + * (c) 2010 Martin Mares + */ + +void osd_init(void); + +struct osd_msg; +struct osd_msg *osd_new_msg(void); +void osd_add_line(struct osd_msg *msg, char *key, char *val); +void osd_send(struct osd_msg *msg); diff --git a/util.c b/util.c new file mode 100644 index 0000000..fdf8b76 --- /dev/null +++ b/util.c @@ -0,0 +1,31 @@ +/* + * On-screen Display Daemon -- Utility Functions + * + * (c) 2010 Martin Mares + */ + +#include +#include +#include + +#include "util.h" + +void __attribute__((noreturn)) __attribute__((format(printf,1,2))) +die(char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + fputs("osdd: ", stderr); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + exit(1); +} + +void * +xmalloc(int size) +{ + void *p = malloc(size); + if (!p) + die("Failed to allocate %d bytes of memory", size); + return p; +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..23645aa --- /dev/null +++ b/util.h @@ -0,0 +1,18 @@ +/* + * On-screen Display Daemon -- Utility Functions + * + * (c) 2010 Martin Mares + */ + +#define NONRET __attribute__((noreturn)) +#define FORMAT_CHECK(func,i,j) __attribute__((format(func,i,j))) + +void NONRET FORMAT_CHECK(printf,1,2) die(char *fmt, ...); + +#ifdef DEBUG +#define DBG(f...) printf(f) +#else +#define DBG(f...) do { } while(0) +#endif + +void *xmalloc(int size); -- 2.39.2