diff --git a/client.c b/client.c index 6f1e0e70..09a70933 100644 --- a/client.c +++ b/client.c @@ -759,6 +759,17 @@ client_updatesizehints(client_t *c) return size; } +/** Markup parsing hook. + * For now only substitute + */ +static void +client_markup_on_elem(markup_parser_data_t *p, const char *elem, + const char **names, const char **values) +{ + assert (!strcmp(elem, "title")); + buffer_add_xmlescaped(&p->text, p->priv); +} + /** Parse a markup string which contains special markup sequence relative to a * client, i.e. its title, etc. * \param c The client concerned by the markup string. @@ -768,17 +779,18 @@ client_updatesizehints(client_t *c) char * client_markup_parse(client_t *c, const char *str, ssize_t len) { - const char *elements[] = { "title", NULL }; - const char *elements_sub[] = { c->name , NULL }; - markup_parser_data_t p; + static char const * const elements[] = { "title", NULL }; + markup_parser_data_t p = { + .elements = elements, + .priv = c->name, + .on_element = client_markup_on_elem, + }; char *ret; - markup_parser_data_init(&p, elements, elements_sub, countof(elements)); + markup_parser_data_init(&p); if(markup_parse(&p, str, len)) - { ret = buffer_detach(&p.text); - } else ret = a_strdup(str); diff --git a/common/draw.c b/common/draw.c index 7a18aeff..c7ee6508 100644 --- a/common/draw.c +++ b/common/draw.c @@ -216,15 +216,62 @@ typedef struct } shadow; } draw_parser_data_t; +static void +draw_markup_on_event(markup_parser_data_t *p, const char *elem, + const char **names, const char **values) +{ + draw_parser_data_t *data = p->priv; + + /* hack: markup.c validates tags so we can avoid strcmps here */ + switch (*elem) { + case 'b': /* bg */ + for (; *names; names++, values++) + { + if(!a_strcmp(*names, "color")) + data->has_bg_color = xcolor_new(data->connection, data->phys_screen, + *values, &data->bg_color); + else if(!a_strcmp(*names, "image")) + data->bg_image = draw_image_new(*values); + } + break; + + case 't': /* text */ + for (; *names; names++, values++) + { + if(!a_strcmp(*names, "align")) + data->align = draw_align_get_from_str(*values); + else if(!a_strcmp(*names, "shadow")) + xcolor_new(data->connection, data->phys_screen, *values, + &data->shadow.color); + else if(!a_strcmp(*names, "shadow_offset")) + data->shadow.offset = atoi(*values); + } + break; + + case 'm': /* margin */ + for (; *names; names++, values++) + { + if(!a_strcmp(*names, "left")) + data->margin.left = atoi(*values); + else if(!a_strcmp(*names, "right")) + data->margin.right = atoi(*values); + } + break; + } +} + static bool draw_text_markup_expand(draw_parser_data_t *data, const char *str, ssize_t slen) { - const char *elements[] = { "bg", "text", "margin", NULL }; - markup_parser_data_t p; - int i; + static char const * const elements[] = { "bg", "text", "margin", NULL }; + markup_parser_data_t p = { + .elements = elements, + .priv = data, + .on_element = &draw_markup_on_event, + }; - markup_parser_data_init(&p, elements, NULL, countof(elements)); + markup_parser_data_init(&p); if(!markup_parse(&p, str, slen)) { @@ -232,34 +279,6 @@ draw_text_markup_expand(draw_parser_data_t *data, return false; } - /* bg */ - if(p.attribute_names[0]) - for(i = 0; p.attribute_names[0][i]; i++) - if(!a_strcmp(p.attribute_names[0][i], "color")) - data->has_bg_color = xcolor_new(data->connection, data->phys_screen, - p.attribute_values[0][i], &data->bg_color); - else if(!a_strcmp(p.attribute_names[0][i], "image")) - data->bg_image = draw_image_new(p.attribute_values[0][i]); - - /* text */ - if(p.attribute_names[1]) - for(i = 0; p.attribute_names[1][i]; i++) - if(!a_strcmp(p.attribute_names[1][i], "align")) - data->align = draw_align_get_from_str(p.attribute_values[1][i]); - else if(!a_strcmp(p.attribute_names[1][i], "shadow")) - xcolor_new(data->connection, data->phys_screen, - p.attribute_values[1][i], &data->shadow.color); - else if(!a_strcmp(p.attribute_names[1][i], "shadow_offset")) - data->shadow.offset = atoi(p.attribute_values[1][i]); - - /* margin */ - if(p.attribute_names[2]) - for(i = 0; p.attribute_names[2][i]; i++) - if(!a_strcmp(p.attribute_names[2][i], "left")) - data->margin.left = atoi(p.attribute_values[2][i]); - else if(!a_strcmp(p.attribute_names[2][i], "right")) - data->margin.right = atoi(p.attribute_values[2][i]); - /* stole text */ data->text = p.text; buffer_init(&p.text); diff --git a/common/markup.c b/common/markup.c index 070ab3b6..9de51f68 100644 --- a/common/markup.c +++ b/common/markup.c @@ -47,26 +47,12 @@ markup_parse_start_element(GMarkupParseContext *context __attribute__ ((unused)) GError **error __attribute__ ((unused))) { markup_parser_data_t *p = (markup_parser_data_t *) user_data; - int i, j; + int i; for(i = 0; p->elements[i]; i++) - if(!a_strcmp(element_name, p->elements[i])) - { - for(j = 0; attribute_names[j]; j++); - p->attribute_names[i] = p_new(char *, ++j); - p->attribute_values[i] = p_new(char *, j); - - for(j = 0; attribute_names[j]; j++) - { - p->attribute_names[i][j] = a_strdup(attribute_names[j]); - p->attribute_values[i][j] = a_strdup(attribute_values[j]); - } - - if(p->elements_sub && p->elements_sub[i]) - { - buffer_add_xmlescaped(&p->text, p->elements_sub[i]); - } - + if(!a_strcmp(element_name, p->elements[i])) { + (*p->on_element)(p, element_name, attribute_names, + attribute_values); return; } @@ -134,20 +120,10 @@ markup_parse_text(GMarkupParseContext *context __attribute__ ((unused)), /** Create a markup_parser_data_t structure with elements list. * \param a pointer to an allocated markup_parser_data_t which must be wiped * with markup_parser_data_wipe() - * \param elements an array of elements to look for, NULL terminated - * \param elements_sub an optional array of values to substitude to elements, NULL - * terminated, or NULL if not needed - * \param nelem number of elements in the array (without NULL) */ -void -markup_parser_data_init(markup_parser_data_t *p, const char **elements, - const char **elements_sub, ssize_t nelem) +void markup_parser_data_init(markup_parser_data_t *p) { buffer_init(&p->text); - p->elements = elements; - p->elements_sub = elements_sub; - p->attribute_names = p_new(char **, nelem); - p->attribute_values = p_new(char **, nelem); } /** Wipe a markup_parser_data_t initialized with markup_parser_data_init. @@ -156,23 +132,6 @@ markup_parser_data_init(markup_parser_data_t *p, const char **elements, void markup_parser_data_wipe(markup_parser_data_t *p) { - int i, j; - - for(i = 0; p->elements[i]; i++) - if(p->attribute_names[i]) - { - for(j = 0; p->attribute_names[i][j]; j++) - { - p_delete(&p->attribute_names[i][j]); - p_delete(&p->attribute_values[i][j]); - } - p_delete(&p->attribute_names[i]); - p_delete(&p->attribute_values[i]); - } - - p_delete(&p->attribute_names); - p_delete(&p->attribute_values); - buffer_wipe(&p->text); } diff --git a/common/markup.h b/common/markup.h index 54a47b69..e14d30c9 100644 --- a/common/markup.h +++ b/common/markup.h @@ -24,16 +24,20 @@ #include "common/buffer.h" -typedef struct +typedef struct markup_parser_data_t markup_parser_data_t; + +typedef void (markup_on_elem_f)(markup_parser_data_t *, const char *, + const char **, const char **); + +struct markup_parser_data_t { buffer_t text; - const char **elements; - const char **elements_sub; - char ***attribute_names; - char ***attribute_values; -} markup_parser_data_t; + const char * const *elements; + markup_on_elem_f *on_element; + void *priv; +}; -void markup_parser_data_init(markup_parser_data_t *, const char **, const char **, ssize_t); +void markup_parser_data_init(markup_parser_data_t *); void markup_parser_data_wipe(markup_parser_data_t *); bool markup_parse(markup_parser_data_t *data, const char *, ssize_t); diff --git a/widgets/taglist.c b/widgets/taglist.c index 75af0e75..64df4e72 100644 --- a/widgets/taglist.c +++ b/widgets/taglist.c @@ -54,15 +54,27 @@ typedef struct } taglist_data_t; +static void +tag_markup_on_elem(markup_parser_data_t *p, const char *elem, + const char **names, const char **values) +{ + assert (!strcmp(elem, "title")); + buffer_add_xmlescaped(&p->text, p->priv); +} + + static char * tag_markup_parse(tag_t *t, const char *str, ssize_t len) { - const char *elements[] = { "title", NULL }; - const char *elements_sub[] = { t->name , NULL }; - markup_parser_data_t p; + static char const * const elements[] = { "title", NULL }; + markup_parser_data_t p = { + .elements = elements, + .on_element = &tag_markup_on_elem, + .priv = t->name, + }; char *ret; - markup_parser_data_init(&p, elements, elements_sub, countof(elements)); + markup_parser_data_init(&p); if(markup_parse(&p, str, len)) ret = buffer_detach(&p.text); diff --git a/widgets/tasklist.c b/widgets/tasklist.c index 3a27c888..3b2873c8 100644 --- a/widgets/tasklist.c +++ b/widgets/tasklist.c @@ -63,6 +63,31 @@ tasklist_isvisible(client_t *c, int screen, showclient_t show) return false; } +struct tasklist_hook_data { + draw_context_t *ctx; + area_t *area; +}; + +static void +tasklist_markup_on_elem(markup_parser_data_t *p, const char *elem, + const char **names, const char **values) +{ + struct tasklist_hook_data *data = p->priv; + draw_context_t *ctx = data->ctx; + + assert (!strcmp(elem, "bg")); + for (; *names; names++, values++) { + if(!a_strcmp(*names, "color")) + { + xcolor_t bg_color; + xcolor_new(ctx->connection, ctx->phys_screen, *values, &bg_color); + draw_rectangle(ctx, *data->area, 1.0, true, bg_color); + break; + } + } +} + + static int tasklist_draw(draw_context_t *ctx, int screen, widget_node_t *w, @@ -72,11 +97,8 @@ tasklist_draw(draw_context_t *ctx, int screen, tasklist_data_t *d = w->widget->data; area_t area; char *text; - int n = 0, i = 0, box_width = 0, icon_width = 0, box_width_rest = 0, j = 0; + int n = 0, i = 0, box_width = 0, icon_width = 0, box_width_rest = 0; netwm_icon_t *icon; - markup_parser_data_t p; - const char *elements[] = { "bg", NULL }; - xcolor_t bg_color; draw_image_t *image; if(used >= ctx->width) @@ -114,6 +136,14 @@ tasklist_draw(draw_context_t *ctx, int screen, if(d->show_icons) { + static char const * const elements[] = { "bg", NULL }; + struct tasklist_hook_data data = { .ctx = ctx, .area = &area }; + markup_parser_data_t p = { + .elements = elements, + .on_element = &tasklist_markup_on_elem, + .priv = &data, + }; + /* draw a background for icons */ area.x = w->area.x + box_width * i; area.y = w->area.y; @@ -122,15 +152,8 @@ tasklist_draw(draw_context_t *ctx, int screen, /* Actually look for the proper background color, since * otherwise the background statusbar color is used instead */ - markup_parser_data_init(&p, elements, NULL, countof(elements)); - if(markup_parse(&p, text, a_strlen(text)) && p.attribute_names[0]) - for(j = 0; p.attribute_names[0][j]; j++) - if(!a_strcmp(p.attribute_names[0][j], "color")) - { - xcolor_new(ctx->connection, ctx->phys_screen, p.attribute_values[0][j], &bg_color); - draw_rectangle(ctx, area, 1.0, true, bg_color); - break; - } + markup_parser_data_init(&p); + markup_parse(&p, text, a_strlen(text)); markup_parser_data_wipe(&p); if((image = draw_image_new(c->icon_path)))