#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <inttypes.h>
+#include <unistd.h>
#include <poll.h>
-#include <sys/time.h>
+#include <getopt.h>
#include <xosd.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
-#define DEBUG
-#include "util.h"
+#undef DEBUG
+#include "osd.h"
static xosd *osd;
-#define MAX_LINES 4
-typedef uint64_t timestamp_t;
static timestamp_t now;
+/*** Options ***/
+
+static int num_lines = 4;
+static char *font_name = "-bitstream-bitstream vera sans-bold-r-normal-*-*-320-*-*-p-*-*";
+static char *default_color = "green";
+static char *default_outline_color = "black";
+static int default_duration = 1000;
+static int default_min_duration = 250;
+static int debug_mode;
+
+static const char short_opts[] = "c:d:Df:l:m:o:";
+
+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' },
+ { "lines", required_argument, NULL, 'l' },
+ { "min-duration", required_argument, NULL, 'm' },
+ { "outline-color", required_argument, NULL, 'o' },
+ { NULL, 0, NULL, 0 },
+};
+
+static void NONRET
+usage(void)
+{
+ fprintf(stderr, "Usage: osdd <options>\n\n\
+Options:\n\
+-c, --color=<c>\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=<ms>\tDefault message duration in milliseconds\n\
+-f, --font=<f>\t\tFont to use for the OSD\n\
+-l, --lines=<n>\t\tNumber of lines of the OSD\n\
+-m, --min-duration=<ms>\tDefault minimum message duration in milliseconds\n\
+-o, --outline-color=<c>\tDefault outline color\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':
+ num_lines = atoi(optarg);
+ if (num_lines < 1)
+ usage();
+ break;
+ case 'm':
+ default_min_duration = atoi(optarg);
+ break;
+ case 'o':
+ default_outline_color = optarg;
+ break;
+ default:
+ usage();
+ }
+
+ if (optind < argc)
+ usage();
+}
+
/*** Displaying of messages ***/
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;
+ xosd_set_colour(osd, default_color);
+ xosd_set_outline_colour(osd, default_outline_color);
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;
key = "";
val = line;
}
+ DBG("\t%s:%s\n", key, val);
if (!key[0])
{
- if (row < MAX_LINES)
+ if (row < num_lines)
xosd_display(osd, row++, XOSD_string, val);
}
+ else if (!strcmp(key, "percentage") || !strcmp(key, "percent"))
+ {
+ if (row < num_lines)
+ xosd_display(osd, row++, XOSD_percentage, atoi(val));
+ }
+ else if (!strcmp(key, "slider"))
+ {
+ if (row < num_lines)
+ xosd_display(osd, row++, XOSD_slider, 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"))
+ xosd_set_colour(osd, val);
+ else if (!strcmp(key, "outline-color"))
+ xosd_set_outline_colour(osd, val);
+ else
+ xosd_display(osd, (row < num_lines ? row++ : num_lines-1), XOSD_string, "PARSE ERROR");
line = nl;
}
static void
hide_msg(struct msg *msg)
{
- xosd_scroll(osd, MAX_LINES);
+ DBG("## Hiding message\n");
+ for (int i=0; i<num_lines; i++)
+ xosd_display(osd, i, XOSD_string, "");
xosd_hide(osd);
free(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;
/*** Main loop ***/
int
-main(void)
+main(int argc, char **argv)
{
+ parse_opts(argc, argv);
XInitThreads();
Display *dpy = XOpenDisplay(NULL);
if (!pty)
die("Cannot intern OSD_QUEUE atom");
+ if (!debug_mode)
+ {
+ pid_t pid = fork();
+ if (pid < 0)
+ die("Cannot fork: %m");
+ if (pid > 0)
+ return 0;
+ setsid();
+ }
+
XSelectInput(dpy, win, PropertyChangeMask);
XDeleteProperty(dpy, win, pty);
XFlush(dpy);
- osd = xosd_create(4);
+ osd = xosd_create(num_lines);
if (!osd)
die("Cannot initialize OSD");
- xosd_set_font(osd, "-bitstream-bitstream vera sans-bold-r-normal-*-*-320-*-*-p-*-*");
+ xosd_set_font(osd, font_name);
xosd_set_outline_offset(osd, 2);
- xosd_set_outline_colour(osd, "black");
xosd_set_pos(osd, XOSD_middle);
xosd_set_align(osd, XOSD_center);
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)
}
}
- 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)
{
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);
}