X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=osdd.c;h=a3364fc8526306a91996b5fdd65a551b3d78a9cf;hb=7a1095480979e4500f62b74c67941512941b9c57;hp=800f6ab9467a61e81fde8f394a7cb8886e547233;hpb=66ea7419541d01ea378523d106e8946b667cbe61;p=osdd.git diff --git a/osdd.c b/osdd.c index 800f6ab..a3364fc 100644 --- a/osdd.c +++ b/osdd.c @@ -1,28 +1,118 @@ /* * On-screen Display Daemon * - * (c) 2010 Martin Mares + * (c) 2010--2014 Martin Mares */ #include #include #include -#include +#include #include -#include -#include +#include +#include #include #include -#define DEBUG +#undef DEBUG #include "util.h" +#include "display.h" -static xosd *osd; -#define MAX_LINES 4 +static struct osd_state *osd; -typedef uint64_t timestamp_t; static timestamp_t now; +/*** Options ***/ + +static char *font_name = "times-64:bold"; +static char *default_color = "green"; +static char *default_outline_color = "black"; +static int default_outline_width = 2; +static int default_duration = 1000; +static int default_min_duration = 250; +static int debug_mode; +static int test_mode; +static double line_spacing = 0.2; + +static const char short_opts[] = "c:d:Df:m:o:O:s:"; + +enum long_opt { + OPT_TEST = 256, +}; + +static const struct option long_opts[] = { + { "color", required_argument, NULL, 'c' }, + { "debug", no_argument, NULL, 'D' }, + { "duration", required_argument, NULL, 'd' }, + { "font", required_argument, NULL, 'f' }, + { "min-duration", required_argument, NULL, 'm' }, + { "outline-color", required_argument, NULL, 'o' }, + { "outline-width", required_argument, NULL, 'O' }, + { "line-spacing", required_argument, NULL, 's' }, + { "test", no_argument, NULL, OPT_TEST }, // Undocumented test mode + { NULL, 0, NULL, 0 }, +}; + +static void NONRET +usage(void) +{ + fprintf(stderr, "Usage: osdd \n\n\ +Options:\n\ +-c, --color=\t\tDefault color (#rgb, #rrggbb or a name from rgb.txt)\n\ +-D, --debug\t\tDebugging mode (do not detach from the terminal)\n\ +-d, --duration=\tDefault message duration in milliseconds\n\ +-f, --font=\t\tFont to use for the OSD\n\ +-m, --min-duration=\tDefault minimum message duration in milliseconds\n\ +-o, --outline-color=\tDefault outline color\n\ +-O, --outline-width=\tDefault outline width (default=2)\n\ +-s, --line-spacing=\tSet line spacing factor (decimal fraction, default=0.2)\n\ +"); + exit(1); +} + +static void +parse_opts(int argc, char **argv) +{ + int opt; + while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0) + switch (opt) + { + case 'c': + default_color = optarg; + break; + case 'd': + default_duration = atoi(optarg); + break; + case 'D': + debug_mode = 1; + break; + case 'f': + font_name = optarg; + break; + case 'l': + line_spacing = atof(optarg); + break; + case 'm': + default_min_duration = atoi(optarg); + break; + case 'o': + default_outline_color = optarg; + break; + case 'O': + default_outline_width = atoi(optarg); + break; + case OPT_TEST: + test_mode = 1; + debug_mode = 1; + break; + default: + usage(); + } + + if (optind < argc) + usage(); +} + /*** Displaying of messages ***/ struct msg { @@ -34,13 +124,17 @@ struct msg { static void display_msg(struct msg *msg) { - msg->min_light = msg->max_light = now + 1000; + DBG("## Displaying message\n"); + msg->min_light = now + default_min_duration; + msg->max_light = now + default_duration; + char *fg_color = default_color; + char *outline_color = default_outline_color; + int outline_width = default_outline_width; char *line = msg->text; - int row = 0; while (*line) { - // The parser it destructive, but it does not harm, since we display each message only once. + // The parser it destructive, but it does not do any harm, since we display each message only once. char *nl = strchr(line, '\n'); *nl++ = 0; @@ -56,29 +150,56 @@ display_msg(struct msg *msg) key = ""; val = line; } + DBG("\t%s:%s\n", key, val); + struct osd_line *l = NULL; if (!key[0]) { - if (row < MAX_LINES) - xosd_display(osd, row++, XOSD_string, val); + l = osd_add_line(osd, OSD_TYPE_TEXT); + sprintf(l->u.text, "%.*s", OSD_MAX_LINE_LEN, val); + } + else if (!strcmp(key, "percentage") || !strcmp(key, "percent")) + { + l = osd_add_line(osd, OSD_TYPE_PERCENTAGE); + l->u.percent = atoi(val); + } + else if (!strcmp(key, "slider")) + { + l = osd_add_line(osd, OSD_TYPE_SLIDER); + l->u.percent = atoi(val); } else if (!strcmp(key, "duration")) msg->max_light = now + atoi(val); else if (!strcmp(key, "min-duration")) msg->min_light = now + atoi(val); + else if (!strcmp(key, "color")) + fg_color = val; + else if (!strcmp(key, "outline-color")) + outline_color = val; + else if (!strcmp(key, "outline-width")) + outline_width = atoi(val); + + if (l) + { + l->fg_color = fg_color; + l->outline_color = outline_color; + l->outline_width = outline_width; + } line = nl; } if (msg->min_light > msg->max_light) msg->min_light = msg->max_light; + + osd_show(osd); } static void hide_msg(struct msg *msg) { - xosd_scroll(osd, MAX_LINES); - xosd_hide(osd); + DBG("## Hiding message\n"); + osd_clear(osd); free(msg); } @@ -89,7 +210,7 @@ static struct msg *current_msg, *first_msg, *last_msg; static void enqueue_msg(unsigned char *buf, int len) { - DBG("[%.*s]\n", len, buf); + DBG("Received: [%.*s]\n", len, buf); if (!len || buf[len-1] != '\n') return; @@ -124,11 +245,26 @@ parse_input(unsigned char *buf, int len) } } +static void +do_test(void) +{ + unsigned char buf[4096]; + int len = 0; + int c; + + while ((c = read(0, buf + len, 4096 - len)) > 0) + len += c; + if (len) + enqueue_msg(buf, len); +} + /*** Main loop ***/ int -main(void) +main(int argc, char **argv) { + parse_opts(argc, argv); + setlocale(LC_CTYPE, ""); XInitThreads(); Display *dpy = XOpenDisplay(NULL); @@ -140,18 +276,30 @@ main(void) if (!pty) die("Cannot intern OSD_QUEUE atom"); - XSelectInput(dpy, win, PropertyChangeMask); - XDeleteProperty(dpy, win, pty); - XFlush(dpy); + if (!debug_mode) + { + pid_t pid = fork(); + if (pid < 0) + die("Cannot fork: %m"); + if (pid > 0) + return 0; + setsid(); + } - 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); + if (test_mode) + { + do_test(); + pty = 0; + } + else + { + XSelectInput(dpy, win, PropertyChangeMask); + XDeleteProperty(dpy, win, pty); + XFlush(dpy); + } + + osd = osd_new(dpy); + osd_set_font(osd, font_name, line_spacing); struct pollfd pfd = { .fd = ConnectionNumber(dpy), @@ -160,9 +308,7 @@ main(void) for (;;) { - struct timeval tv; - gettimeofday(&tv, NULL); - now = (timestamp_t) tv.tv_sec * 1000 + tv.tv_usec / 1000; + now = get_current_time(); timestamp_t wait_until = now - 1; if (!current_msg && first_msg) @@ -184,8 +330,10 @@ main(void) continue; } } + if (test_mode && !current_msg) + break; - DBG("Waiting for %d ms\n", (int)(wait_until - now)); + DBG("... waiting for %d ms\n", (int)(wait_until - now)); poll(&pfd, 1, wait_until - now); if (pfd.revents & POLLIN) { @@ -193,6 +341,8 @@ main(void) { XEvent ev; XNextEvent(dpy, &ev); + if (osd_handle_event(osd, &ev)) + continue; if (ev.type != PropertyNotify) continue; XPropertyEvent *p = &ev.xproperty; @@ -204,10 +354,7 @@ main(void) 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); - } + parse_input(pty_buf, pty_items); if (pty_buf) XFree(pty_buf); }