diff --git a/Makefile.am b/Makefile.am
index 3962b6152..c768d0cec 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -126,13 +126,14 @@ awesome_SOURCES = \
common/xutil.c common/xutil.h \
common/configopts.h common/configopts.c \
common/xscreen.h common/xscreen.c \
+ common/draw.c common/draw.h \
+ common/markup.c common/markup.h \
common/list.h \
structs.h \
client.c client.h \
titlebar.c titlebar.h \
placement.c placement.h \
focus.c focus.h \
- common/draw.c common/draw.h \
event.c event.h \
layout.c layout.h \
awesome.c awesome.h \
@@ -165,6 +166,7 @@ bin_PROGRAMS += awesome-message
awesome_message_SOURCES = \
common/swindow.c common/swindow.h \
common/draw.c common/draw.h \
+ common/markup.c common/markup.h \
common/util.h common/util.c \
common/version.h common/version.c \
common/configopts.h common/configopts.c \
@@ -178,6 +180,7 @@ bin_PROGRAMS += awesome-menu
awesome_menu_SOURCES = \
common/swindow.c common/swindow.h \
common/draw.c common/draw.h \
+ common/markup.c common/markup.h \
common/util.h common/util.c \
common/version.h common/version.c \
common/configopts.h common/configopts.c \
diff --git a/common/draw.c b/common/draw.c
index 26da718c4..5036ed917 100644
--- a/common/draw.c
+++ b/common/draw.c
@@ -44,6 +44,7 @@
#include "common/draw.h"
#include "common/util.h"
#include "common/xutil.h"
+#include "common/markup.h"
/** Convert text from any charset to UTF-8 using iconv
* \param iso the ISO string to convert
@@ -223,117 +224,31 @@ typedef struct
xcolor_t bg_color;
} draw_parser_data_t;
-static void
-draw_text_markup_parse_start_element(GMarkupParseContext *context __attribute__ ((unused)),
- const gchar *element_name,
- const gchar **attribute_names,
- const gchar **attribute_values,
- gpointer user_data,
- GError **error __attribute__ ((unused)))
-{
- draw_parser_data_t *p = (draw_parser_data_t *) user_data;
- char *newtext;
- int i = 0;
- ssize_t len;
-
- if(!a_strcmp(element_name, "bg"))
- {
- for(i = 0; attribute_names[i]; i++)
- if(!p->has_bg_color && !a_strcmp(attribute_names[i], "color"))
- p->has_bg_color = draw_color_new(p->connection, p->phys_screen,
- attribute_values[i], &p->bg_color);
- }
- else if(a_strcmp(element_name, "markup"))
- {
- if(!(len = asprintf(&newtext, "%s<%s ", NONULL(p->text), element_name)))
- return;
- len++; /* add \0 that asprintf does not return in len */
- for(i = 0; attribute_names[i]; i++)
- {
- len += a_strlen(attribute_names[i]) + a_strlen(attribute_values[i]) + 5;
- p_realloc(&newtext, len);
- a_strcat(newtext, len, attribute_names[i]);
- a_strcat(newtext, len, "=\"");
- a_strcat(newtext, len, attribute_values[i]);
- a_strcat(newtext, len, "\" ");
- }
- p_realloc(&newtext, ++len);
- a_strcat(newtext, len, ">");
- p_delete(&p->text);
- p->text = newtext;
- }
-}
-
-static void
-draw_text_markup_parse_end_element(GMarkupParseContext *context __attribute__ ((unused)),
- const gchar *element_name,
- gpointer user_data,
- GError **error __attribute__ ((unused)))
-{
- draw_parser_data_t *p = (draw_parser_data_t *) user_data;
- char *newtext;
-
- if(a_strcmp(element_name, "markup")
- && a_strcmp(element_name, "bg"))
- {
- asprintf(&newtext, "%s%s>", p->text, element_name);
- p_delete(&p->text);
- p->text = newtext;
- }
-}
-
-static void
-draw_text_markup_parse_text(GMarkupParseContext *context __attribute__ ((unused)),
- const gchar *text,
- gsize text_len,
- gpointer user_data,
- GError **error __attribute__ ((unused)))
-{
- draw_parser_data_t *p = (draw_parser_data_t *) user_data;
- ssize_t len, rlen;
-
- len = a_strlen(p->text);
- rlen = len + 1 + text_len;
- p_realloc(&p->text, rlen);
- if(len)
- a_strncat(p->text, rlen, text, len);
- else
- a_strncpy(p->text, rlen, text, text_len);
-}
-
static bool
draw_text_markup_expand(draw_parser_data_t *data,
const char *str, ssize_t slen)
{
- GMarkupParseContext *mkp_ctx;
- GMarkupParser parser =
- {
- /* start_element */
- draw_text_markup_parse_start_element,
- /* end_element */
- draw_text_markup_parse_end_element,
- /* text */
- draw_text_markup_parse_text,
- /* passthrough */
- NULL,
- /* error */
- NULL
- };
- GError *error = NULL;
+ const char *elements[] = { "bg", NULL};
+ markup_parser_data_t *p;
+ int i;
- mkp_ctx = g_markup_parse_context_new(&parser, 0, data, NULL);
+ p = markup_parser_data_new(elements, countof(elements));
- if(!g_markup_parse_context_parse(mkp_ctx, "", -1, &error)
- || !g_markup_parse_context_parse(mkp_ctx, str, slen, &error)
- || !g_markup_parse_context_parse(mkp_ctx, "", -1, &error)
- || !g_markup_parse_context_end_parse(mkp_ctx, &error))
- {
- warn("unable to parse text: %s\n", error->message);
- g_error_free(error);
+ if(!markup_parse(p, str, slen))
return false;
- }
- g_markup_parse_context_free(mkp_ctx);
+ /* bg */
+ if(p->attribute_values[0])
+ for(i = 0; p->attribute_values[0][i]; i++)
+ if(!strcmp(p->attribute_values[0][i], "color"))
+ data->has_bg_color = draw_color_new(data->connection, data->phys_screen,
+ p->attribute_values[0][i], &data->bg_color);
+
+ /* stole text */
+ data->text = p->text;
+ p->text = NULL;
+
+ markup_parser_data_delete(&p);
return true;
}
@@ -343,11 +258,7 @@ draw_text_markup_expand(draw_parser_data_t *data,
* \param area area to draw to
* \param align alignment
* \param padding padding to add before drawing the text
- * \param font font to use
* \param text text to draw
- * \param enable shadow
- * \param fg foreground color
- * \param bg background color
* \return area_t with width and height are set to what used
*/
void
@@ -373,8 +284,8 @@ draw_text(DrawCtx *ctx,
len = a_strlen(utf8);
else
utf8 = a_strdup(text);
-
- bzero(&parser_data, sizeof(parser_data));
+
+ p_clear(&parser_data, 1);
parser_data.connection = ctx->connection;
parser_data.phys_screen = ctx->phys_screen;
if(draw_text_markup_expand(&parser_data, utf8, len))
@@ -1014,8 +925,8 @@ draw_text_extents(xcb_connection_t *conn, int default_screen, font_t *font, cons
len = a_strlen(utf8);
else
utf8 = a_strdup(text);
-
- bzero(&parser_data, sizeof(parser_data));
+
+ p_clear(&parser_data, 1);
parser_data.connection = conn;
parser_data.phys_screen = default_screen;
if(draw_text_markup_expand(&parser_data, utf8, len))
diff --git a/common/markup.c b/common/markup.c
new file mode 100644
index 000000000..06c6786b9
--- /dev/null
+++ b/common/markup.c
@@ -0,0 +1,237 @@
+/*
+ * markup.c - markup functions
+ *
+ * Copyright © 2008 Julien Danjou
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/* asprintf */
+#define _GNU_SOURCE
+
+#include
+
+#include
+#include
+
+#include "common/markup.h"
+
+/** Callback to invoke when the opening tag of an element is seen.
+ * Here is just copies element elements we do not care about, and copies
+ * values we care.
+ * \param context the context of GMarkup
+ * \param element_name element name
+ * \param attribute_names array of attribute names
+ * \param attribute_values array of attribute values
+ * \param user_data pointer to user data, here a markup_parser_data_t pointer
+ * \param error a GError
+ */
+static void
+markup_parse_start_element(GMarkupParseContext *context __attribute__ ((unused)),
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error __attribute__ ((unused)))
+{
+ markup_parser_data_t *p = (markup_parser_data_t *) user_data;
+ char *newtext;
+ int i, j;
+ ssize_t len;
+
+ 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]);
+ }
+ return;
+ }
+
+ if(a_strcmp(element_name, "markup"))
+ {
+ if(!(len = asprintf(&newtext, "%s<%s ", NONULL(p->text), element_name)))
+ return;
+ len++; /* add \0 that asprintf does not return in len */
+ for(i = 0; attribute_names[i]; i++)
+ {
+ len += a_strlen(attribute_names[i]) + a_strlen(attribute_values[i]) + 5;
+ p_realloc(&newtext, len);
+ a_strcat(newtext, len, attribute_names[i]);
+ a_strcat(newtext, len, "=\"");
+ a_strcat(newtext, len, attribute_values[i]);
+ a_strcat(newtext, len, "\" ");
+ }
+ p_realloc(&newtext, ++len);
+ a_strcat(newtext, len, ">");
+ p_delete(&p->text);
+ p->text = newtext;
+ }
+}
+
+/** Callback to invoke when the closing tag of an element is seen. Note that
+ * this is also called for empty tags like .
+ * Here is just copies element elements we do not care about.
+ * \param context the context of GMarkup
+ * \param element_name element name
+ * \param user_data pointer to user data, here a markup_parser_data_t pointer
+ * \param error a GError
+ */
+static void
+markup_parse_end_element(GMarkupParseContext *context __attribute__ ((unused)),
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error __attribute__ ((unused)))
+{
+ markup_parser_data_t *p = (markup_parser_data_t *) user_data;
+ char *newtext;
+ int i;
+
+ for(i = 0; p->elements[i]; i++)
+ if(!a_strcmp(element_name, p->elements[i]))
+ return;
+
+ if(a_strcmp(element_name, "markup"))
+ {
+ asprintf(&newtext, "%s%s>", p->text, element_name);
+ p_delete(&p->text);
+ p->text = newtext;
+ }
+}
+
+/** Callback to invoke when some text is seen (text is always inside an
+ * element). Note that the text of an element may be spread over multiple calls
+ * of this function. If the G_MARKUP_TREAT_CDATA_AS_TEXT flag is set, this
+ * function is also called for the content of CDATA marked sections.
+ * Here it recopies blindly the text in the text attribute of user_data.
+ * \param context the context of GMarkup
+ * \param text the text
+ * \param text_len the text length
+ * \param user_data pointer to user data, here a markup_parser_data_t pointer
+ * \param error a GError
+ */
+static void
+markup_parse_text(GMarkupParseContext *context __attribute__ ((unused)),
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error __attribute__ ((unused)))
+{
+ markup_parser_data_t *p = (markup_parser_data_t *) user_data;
+ ssize_t len, rlen;
+
+ len = a_strlen(p->text);
+ rlen = len + 1 + text_len;
+ p_realloc(&p->text, rlen);
+ if(len)
+ a_strncat(p->text, rlen, text, len);
+ else
+ a_strncpy(p->text, rlen, text, text_len);
+}
+
+/** Create a markup_parser_data_t structure with elements list.
+ * \param elements an array of elements to look for, NULL terminated
+ * \param number of elements in the array (without NULL)
+ * \return a pointer to an allocated markup_parser_data_t which must be freed
+ * with markup_parser_data_delete()
+ */
+markup_parser_data_t *
+markup_parser_data_new(const char **elements, ssize_t nelem)
+{
+ markup_parser_data_t *p;
+
+ p = p_new(markup_parser_data_t, 1);
+
+ p->elements = elements;
+ p->attribute_names = p_new(char **, nelem);
+ p->attribute_values = p_new(char **, nelem);
+
+ return p;
+}
+
+/** Delete a markup_parser_data_t allocated.
+ * \param p markup_parser_data_t pointer address
+ */
+void
+markup_parser_data_delete(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)->text);
+ p_delete(p);
+}
+
+/** Parse markup defined in data on the string str.
+ * \param data a markup_parser_data_t allocated by markup_parser_data_new()
+ * \param str a string to parse markup from
+ * \param slen str length
+ * \return true if success, false otherwise
+ */
+bool
+markup_parse(markup_parser_data_t *data, const char *str, ssize_t slen)
+{
+ GMarkupParseContext *mkp_ctx;
+ GMarkupParser parser =
+ {
+ /* start_element */
+ markup_parse_start_element,
+ /* end_element */
+ markup_parse_end_element,
+ /* text */
+ markup_parse_text,
+ /* passthrough */
+ NULL,
+ /* error */
+ NULL
+ };
+ GError *error = NULL;
+
+ mkp_ctx = g_markup_parse_context_new(&parser, 0, data, NULL);
+
+ if(!g_markup_parse_context_parse(mkp_ctx, "", -1, &error)
+ || !g_markup_parse_context_parse(mkp_ctx, str, slen, &error)
+ || !g_markup_parse_context_parse(mkp_ctx, "", -1, &error)
+ || !g_markup_parse_context_end_parse(mkp_ctx, &error))
+ {
+ warn("unable to parse text: %s\n", error->message);
+ g_error_free(error);
+ return false;
+ }
+
+ g_markup_parse_context_free(mkp_ctx);
+
+ return true;
+}
+
+// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
diff --git a/common/markup.h b/common/markup.h
new file mode 100644
index 000000000..17b9dc4f2
--- /dev/null
+++ b/common/markup.h
@@ -0,0 +1,40 @@
+/*
+ * markup.h - markup header
+ *
+ * Copyright © 2008 Julien Danjou
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef AWESOME_COMMON_MARKUP_H
+#define AWESOME_COMMON_MARKUP_H
+
+#include "common/util.h"
+
+typedef struct
+{
+ char *text;
+ const char **elements;
+ char ***attribute_names;
+ char ***attribute_values;
+} markup_parser_data_t;
+
+markup_parser_data_t * markup_parser_data_new(const char **, ssize_t);
+void markup_parser_data_delete(markup_parser_data_t **);
+bool markup_parse(markup_parser_data_t *data, const char *, ssize_t);
+
+#endif
+// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80