int max_lines;
int line_distance;
int line_height;
+ int line_skip;
bool visible;
};
nitems > 0)
{
DBG("stay_on_top: Gnome mode\n");
- // FIXME: check capabilities
+ // FIXME: Check capabilities
XClientMessageEvent e;
memset(&e, 0, sizeof(e));
e.type = ClientMessage;
if (!XShapeQueryExtension(osd->dpy, &event_basep, &error_basep))
die("XShape extension not supported by X server, giving up");
- osd->max_lines = 2; // FIXME
+ osd->max_lines = 4;
osd->lines = xmalloc(sizeof(struct osd_line) * osd->max_lines);
return osd;
free(osd);
}
-void osd_set_font(struct osd_state *osd, char *font_name)
+void osd_set_font(struct osd_state *osd, char *font_name, double line_spacing)
{
if (osd->font)
XftFontClose(osd->dpy, osd->font);
- DBG("Using font %s", font_name);
+ DBG("Using font %s\n", font_name);
osd->font = XftFontOpenName(osd->dpy, osd->screen, font_name);
if (!osd->font)
die("Cannot open font %s", font_name);
- DBG("Font: asc=%d desc=%d ht=%d", osd->font->ascent, osd->font->descent, osd->font->height);
+ DBG("Font: asc=%d desc=%d ht=%d\n", osd->font->ascent, osd->font->descent, osd->font->height);
osd->line_distance = osd->font->height;
osd->line_height = osd->font->ascent;
+ osd->line_skip = osd->line_distance * line_spacing;
+ DBG("Line: distance=%d height=%d skip=%d\n", osd->line_distance, osd->line_height, osd->line_skip);
}
struct osd_line *osd_add_line(struct osd_state *osd, enum osd_line_type type)
struct osd_line *l = &osd->lines[osd->num_lines++];
l->type = type;
l->fg_color = "green";
- l->outline_color = "yellow";
+ l->outline_color = "black";
l->outline_width = 0;
- // FIXME: Colors, alignment etc.
switch (l->type)
{
if (line->width > osd->win_width)
osd->win_width = line->width;
osd->win_height += line->height;
+ if (i)
+ osd->win_height += osd->line_skip;
}
- // FIXME: Check clipping
if (osd->win_width > osd->screen_width)
osd->win_width = osd->screen_width;
if (osd->win_height > osd->screen_height)
for (int i=0; i < osd->num_lines; i++)
{
struct osd_line *line = &osd->lines[i];
+ if (i)
+ y += osd->line_skip;
line->y_pos = y;
osd_justify_line(osd, i);
y += line->height;
{
case OSD_TYPE_TEXT:
{
+ int x = line->x_pos + line->outline_width;
+ int y = line->y_pos + line->outline_width + osd->line_height;
+
unsigned char *text = (unsigned char *) line->u.text;
int text_len = strlen(line->u.text);
- XftDrawStringUtf8(osd->image_draw, &fg_color, osd->font, line->x_pos + line->outline_width, line->y_pos + line->outline_width, text, text_len);
+ XftDrawStringUtf8(osd->image_draw, &fg_color, osd->font, x, y, text, text_len);
// This is slow, but unlike the method used by libxosd, the result isn't ugly.
int outline = line->outline_width;
for (int dx = -outline; dx <= outline; dx++)
for (int dy = -outline; dy <= outline; dy++)
if (dx*dx + dy*dy <= outline*outline)
- XftDrawStringUtf8(osd->mask_draw, &mask_color, osd->font, 100 + dx, 100 + dy, text, text_len);
+ XftDrawStringUtf8(osd->mask_draw, &mask_color, osd->font, x + dx, y + dy, text, text_len);
break;
}
};
osd->win = XCreateWindow(osd->dpy,
osd->root,
- 0, 0,
+ (osd->screen_width - osd->win_width) / 2, (osd->screen_height - osd->win_height) / 2,
osd->win_width, osd->win_height,
0,
osd->depth,
osd->visible = 0;
}
+void osd_clear(struct osd_state *osd)
+{
+ osd_hide(osd);
+ osd->num_lines = 0;
+}
+
bool osd_handle_event(struct osd_state *osd, XEvent *ev)
{
if (!osd->visible)
/*** Options ***/
-static int num_lines = 4; // FIXME
-static char *font_name = "-bitstream-bitstream vera sans-bold-r-normal-*-*-320-*-*-p-*-*"; // FIXME
+static char *font_name = "times-64";
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:l:m:o:";
+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' },
- { "lines", required_argument, NULL, 'l' },
{ "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 },
};
-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\
+-O, --outline-width=<n>\tDefault outline width (default=2)\n\
+-s, --line-spacing=<n>\tSet line spacing factor (decimal fraction, default=0.2)\n\
");
exit(1);
}
font_name = optarg;
break;
case 'l':
- num_lines = atoi(optarg);
- if (num_lines < 1)
- usage();
+ line_spacing = atof(optarg);
break;
case 'm':
default_min_duration = atoi(optarg);
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();
}
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;
while (*line)
else if (!strcmp(key, "slider"))
{
// FIXME
- // xsd_display(osd, row++, XOSD_slider, atoi(val));
+ // 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"))
- fg_color = val; // FIXME: Need copying!
+ fg_color = val;
else if (!strcmp(key, "outline-color"))
- outline_color = val; // FIXME: Need copying!
+ 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)
{
DBG("## Hiding message\n");
- osd_hide(osd);
- // FIXME: Reset the osd state
+ osd_clear(osd);
free(msg);
}
}
}
+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
setsid();
}
- XSelectInput(dpy, win, PropertyChangeMask);
- XDeleteProperty(dpy, win, pty);
- XFlush(dpy);
+ 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);
+ osd_set_font(osd, font_name, line_spacing);
struct pollfd pfd = {
.fd = ConnectionNumber(dpy),
continue;
}
}
+ if (test_mode && !current_msg)
+ break;
DBG("... waiting for %d ms\n", (int)(wait_until - now));
poll(&pfd, 1, wait_until - now);