From e48fc13fafa06d9a3e817ad9b11c453198dc73fb Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Tue, 22 Oct 2013 22:54:41 +0200 Subject: [PATCH] New display code is able to show text messages Sliders and percentages are not implemented yet. Line spacing and outline widths are configurable. Undocumented test mode has been added. --- display.c | 36 ++++++++++++++++++-------- display.h | 4 ++- osdd.c | 76 ++++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 87 insertions(+), 29 deletions(-) diff --git a/display.c b/display.c index 1294db7..d2decdc 100644 --- a/display.c +++ b/display.c @@ -53,6 +53,7 @@ struct osd_state { int max_lines; int line_distance; int line_height; + int line_skip; bool visible; }; @@ -71,7 +72,7 @@ stay_on_top(struct osd_state *osd) 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; @@ -129,7 +130,7 @@ struct osd_state *osd_new(Display *dpy) 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; @@ -146,19 +147,21 @@ void osd_free(struct osd_state *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) @@ -172,9 +175,8 @@ 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) { @@ -228,9 +230,10 @@ static void osd_prepare(struct osd_state *osd) 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) @@ -241,6 +244,8 @@ static void osd_prepare(struct osd_state *osd) 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; @@ -266,16 +271,19 @@ static void osd_draw_line(struct osd_state *osd, int i) { 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; } @@ -299,7 +307,7 @@ void osd_show(struct osd_state *osd) }; 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, @@ -362,6 +370,12 @@ void osd_hide(struct osd_state *osd) 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) diff --git a/display.h b/display.h index fba43df..48ffb0b 100644 --- a/display.h +++ b/display.h @@ -26,6 +26,7 @@ struct osd_line { char text[OSD_MAX_LINE_LEN]; // in UTF-8 } u; + // Used internally int width; int height; int x_pos; @@ -34,8 +35,9 @@ struct osd_line { struct osd_state *osd_new(Display *dpy); void osd_free(struct osd_state *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); struct osd_line *osd_add_line(struct osd_state *osd, enum osd_line_type type); void osd_show(struct osd_state *osd); void osd_hide(struct osd_state *osd); +void osd_clear(struct osd_state *osd); bool osd_handle_event(struct osd_state *osd, XEvent *ev); diff --git a/osdd.c b/osdd.c index 8626cbd..2bfb8c3 100644 --- a/osdd.c +++ b/osdd.c @@ -25,24 +25,32 @@ static timestamp_t now; /*** 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 }, }; @@ -55,9 +63,10 @@ Options:\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\ --l, --lines=\t\tNumber of lines of 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); } @@ -82,9 +91,7 @@ parse_opts(int argc, char **argv) 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); @@ -92,6 +99,13 @@ parse_opts(int argc, char **argv) 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(); } @@ -116,6 +130,7 @@ display_msg(struct msg *msg) 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) @@ -152,21 +167,24 @@ display_msg(struct msg *msg) 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; @@ -174,14 +192,15 @@ display_msg(struct msg *msg) 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); } @@ -227,6 +246,19 @@ 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 @@ -255,12 +287,20 @@ main(int argc, char **argv) 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), @@ -291,6 +331,8 @@ main(int argc, char **argv) continue; } } + if (test_mode && !current_msg) + break; DBG("... waiting for %d ms\n", (int)(wait_until - now)); poll(&pfd, 1, wait_until - now); -- 2.39.2