changeset 26572:f099e7f2739c

Several changes: * Use "color" for text-color consistently in the buddylist themes, instead of using "text_color" in some places and "color" in others. * Rename FontColorPair to PidginThemeFont. (I suspect we might use this later for conversation themes as well?) * Hide PidginThemeFont structure, add accessor/mutator functions. * Remove some ridiculous code duplications.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Fri, 17 Apr 2009 19:28:20 +0000
parents 74d62c5fd716
children 98c40e2a0c7f
files pidgin/gtkblist-theme-loader.c pidgin/gtkblist-theme.c pidgin/gtkblist-theme.h pidgin/gtkblist.c
diffstat 4 files changed, 274 insertions(+), 215 deletions(-) [+]
line wrap: on
line diff
--- a/pidgin/gtkblist-theme-loader.c	Fri Apr 17 16:23:02 2009 +0000
+++ b/pidgin/gtkblist-theme-loader.c	Fri Apr 17 19:28:20 2009 +0000
@@ -38,6 +38,22 @@
  * Buddy List Theme Builder
  *****************************************************************************/
 
+static PidginThemeFont *
+pidgin_theme_font_parse(xmlnode *node)
+{
+	const char *font;
+	const char *colordesc;
+	GdkColor color;
+
+	font = xmlnode_get_attrib(node, "font");
+
+	if ((colordesc = xmlnode_get_attrib(node, "color")) == NULL ||
+			!gdk_color_parse(colordesc, &color))
+		gdk_color_parse(DEFAULT_TEXT_COLOR, &color);
+
+	return pidgin_theme_font_new(font, &color);
+}
+
 static PurpleTheme *
 pidgin_blist_loader_build(const gchar *dir)
 {
@@ -46,10 +62,24 @@
 	const gchar *temp;
 	gboolean success = TRUE;
 	GdkColor bgcolor, expanded_bgcolor, collapsed_bgcolor, contact_color;
-	GdkColor color;
-	FontColorPair expanded, collapsed, contact, online, away, offline, idle, message, message_nick_said, status;
+	PidginThemeFont *expanded, *collapsed, *contact, *online, *away, *offline, *idle, *message, *message_nick_said, *status;
 	PidginBlistLayout layout;
 	PidginBlistTheme *theme;
+	int i;
+	struct {
+		const char *tag;
+		PidginThemeFont **font;
+	} lookups[] = {
+		{"contact_text", &contact},
+		{"online_text", &online},
+		{"away_text", &away},
+		{"offline_text", &offline},
+		{"idle_text", &idle},
+		{"message_text", &message},
+		{"message_nick_said_text", &message_nick_said},
+		{"status_text", &status},
+		{NULL, NULL}
+	};
 
 	/* Find the theme file */
 	g_return_val_if_fail(dir != NULL, NULL);
@@ -76,11 +106,7 @@
 	if ((success = (success && (sub_node = xmlnode_get_child(root_node, "groups")) != NULL
 		     && (sub_sub_node = xmlnode_get_child(sub_node, "expanded")) != NULL)))
 	{
-		expanded.font = xmlnode_get_attrib(sub_sub_node, "font");
-
-		if ((temp = xmlnode_get_attrib(sub_sub_node, "text_color")) != NULL && gdk_color_parse(temp, &color))
-			expanded.color = temp;
-		else expanded.color = DEFAULT_TEXT_COLOR;
+		expanded = pidgin_theme_font_parse(sub_sub_node);
 
 		if ((temp = xmlnode_get_attrib(sub_sub_node, "background")) != NULL && gdk_color_parse(temp, &expanded_bgcolor))
 			gdk_colormap_alloc_color(gdk_colormap_get_system(), &expanded_bgcolor, FALSE, TRUE);
@@ -90,11 +116,7 @@
 
 	if ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "collapsed")) != NULL)))
 	{
-		collapsed.font = xmlnode_get_attrib(sub_sub_node, "font");
-
-		if((temp = xmlnode_get_attrib(sub_sub_node, "text_color")) != NULL && gdk_color_parse(temp, &color))
-			collapsed.color = temp;
-		else collapsed.color = DEFAULT_TEXT_COLOR;
+		collapsed = pidgin_theme_font_parse(sub_sub_node);
 
 		if ((temp = xmlnode_get_attrib(sub_sub_node, "background")) != NULL && gdk_color_parse(temp, &collapsed_bgcolor))
 			gdk_colormap_alloc_color(gdk_colormap_get_system(), &collapsed_bgcolor, FALSE, TRUE);
@@ -121,60 +143,13 @@
 			memset(&contact_color, 0, sizeof(GdkColor));
 	}
 
-	if ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "contact_text")) != NULL))) {
-		contact.font = xmlnode_get_attrib(sub_sub_node, "font");
-		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
-			contact.color = temp;
-		else contact.color = DEFAULT_TEXT_COLOR;
-	}
-
-	if ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "online_text")) != NULL))) {
-		online.font = xmlnode_get_attrib(sub_sub_node, "font");
-		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
-			online.color = temp;
-		else online.color = DEFAULT_TEXT_COLOR;
-	}
-
-	if ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "away_text")) != NULL))) {
-		away.font = xmlnode_get_attrib(sub_sub_node, "font");
-		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
-			away.color = temp;
-		else away.color = DEFAULT_TEXT_COLOR;
-	}
-
-	if ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "offline_text")) != NULL))) {
-		offline.font = xmlnode_get_attrib(sub_sub_node, "font");
-		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
-			offline.color = temp;
-		else offline.color = DEFAULT_TEXT_COLOR;
-	}
-
-	if ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "idle_text")) != NULL))) {
-		idle.font = xmlnode_get_attrib(sub_sub_node, "font");
-		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
-			idle.color = temp;
-		else idle.color = DEFAULT_TEXT_COLOR;
-	}
-
-	if ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "message_text")) != NULL))) {
-		message.font = xmlnode_get_attrib(sub_sub_node, "font");
-		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
-			message.color = temp;
-		else message.color = DEFAULT_TEXT_COLOR;
-	}
-
-	if ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "message_nick_said_text")) != NULL))) {
-		message_nick_said.font = xmlnode_get_attrib(sub_sub_node, "font");
-		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
-			message_nick_said.color = temp;
-		else message_nick_said.color = DEFAULT_TEXT_COLOR;
-	}
-
-	if ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "status_text")) != NULL))) {
-		status.font = xmlnode_get_attrib(sub_sub_node, "font");
-		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
-			status.color = temp;
-		else status.color = DEFAULT_TEXT_COLOR;
+	for (i = 0; success && lookups[i].tag; i++) {
+		if ((success = (sub_node != NULL &&
+						(sub_sub_node = xmlnode_get_child(sub_node, lookups[i].tag)) != NULL))) {
+			*(lookups[i].font) = pidgin_theme_font_parse(sub_sub_node);
+		} else {
+			*(lookups[i].font) = NULL;
+		}
 	}
 
 	/* name is required for theme manager */
@@ -191,19 +166,24 @@
 			"background-color", &bgcolor,
 			"layout", &layout,
 			"expanded-color", &expanded_bgcolor,
-			"expanded-text", &expanded,
+			"expanded-text", expanded,
 			"collapsed-color", &collapsed_bgcolor,
-			"collapsed-text", &collapsed,
+			"collapsed-text", collapsed,
 			"contact-color", &contact_color,
-			"contact", &contact,
-			"online", &online,
-			"away", &away,
-			"offline", &offline,
-			"idle", &idle,
-			"message", &message,
-			"message_nick_said", &message_nick_said,
-			"status", &status, NULL);
+			"contact", contact,
+			"online", online,
+			"away", away,
+			"offline", offline,
+			"idle", idle,
+			"message", message,
+			"message_nick_said", message_nick_said,
+			"status", status, NULL);
 
+	for (i = 0; lookups[i].tag; i++) {
+		if (*lookups[i].font) {
+			pidgin_theme_font_free(*lookups[i].font);
+		}
+	}
 	xmlnode_free(root_node);
 	g_free(data);
 
--- a/pidgin/gtkblist-theme.c	Fri Apr 17 16:23:02 2009 +0000
+++ b/pidgin/gtkblist-theme.c	Fri Apr 17 19:28:20 2009 +0000
@@ -21,6 +21,7 @@
  */
 
 #include "gtkblist-theme.h"
+#include <string.h>
 
 #define PIDGIN_BLIST_THEME_GET_PRIVATE(Gobject) \
 	((PidginBlistThemePrivate *) ((PIDGIN_BLIST_THEME(Gobject))->priv))
@@ -37,27 +38,34 @@
 
 	/* groups */
 	GdkColor *expanded_color;
-	FontColorPair *expanded;
+	PidginThemeFont *expanded;
 
 	GdkColor *collapsed_color;
-	FontColorPair *collapsed;
+	PidginThemeFont *collapsed;
 
 	/* buddy */
 	GdkColor *contact_color;
 
-	FontColorPair *contact;
+	PidginThemeFont *contact;
 
-	FontColorPair *online;
-	FontColorPair *away;
-	FontColorPair *offline;
-	FontColorPair *idle;
-	FontColorPair *message;
-	FontColorPair *message_nick_said;
+	PidginThemeFont *online;
+	PidginThemeFont *away;
+	PidginThemeFont *offline;
+	PidginThemeFont *idle;
+	PidginThemeFont *message;
+	PidginThemeFont *message_nick_said;
 
-	FontColorPair *status;
+	PidginThemeFont *status;
 
 } PidginBlistThemePrivate;
 
+struct _PidginThemeFont
+{
+	gchar *font;
+	gchar color[10];
+	GdkColor *gdkcolor;
+};
+
 /******************************************************************************
  * Globals
  *****************************************************************************/
@@ -92,23 +100,78 @@
  * Helpers
  *****************************************************************************/
 
+PidginThemeFont *
+pidgin_theme_font_new(const char *face, GdkColor *color)
+{
+	PidginThemeFont *font = g_new0(PidginThemeFont, 1);
+	font->font = g_strdup(face);
+	pidgin_theme_font_set_color(font, color);
+	return font;
+}
+
 void
-free_font_and_color(FontColorPair *pair)
+pidgin_theme_font_free(PidginThemeFont *pair)
 {
 	if (pair != NULL) {
-		g_free((gchar *)pair->font);
-		g_free((gchar *)pair->color);
+		g_free(pair->font);
+		if (pair->gdkcolor)
+			gdk_color_free(pair->gdkcolor);
 		g_free(pair);
 	}
 }
 
-static FontColorPair *
-copy_font_and_color(const FontColorPair *pair)
+static PidginThemeFont *
+copy_font_and_color(const PidginThemeFont *pair)
+{
+	PidginThemeFont *copy = g_new0(PidginThemeFont, 1);
+	copy->font  = g_strdup(pair->font);
+	strncpy(copy->color, pair->color, sizeof(copy->color) - 1);
+	copy->gdkcolor = gdk_color_copy(pair->gdkcolor);
+	return copy;
+}
+
+void
+pidgin_theme_font_set_font_face(PidginThemeFont *font, const gchar *face)
+{
+	g_return_if_fail(font);
+	g_return_if_fail(face);
+
+	g_free(font->font);
+	font->font = g_strdup(face);
+}
+
+void
+pidgin_theme_font_set_color(PidginThemeFont *font, const GdkColor *color)
 {
-	FontColorPair *copy = g_new0(FontColorPair, 1);
-	copy->font  = g_strdup(pair->font);
-	copy->color = g_strdup(pair->color);
-	return copy;
+	g_return_if_fail(font);
+	g_return_if_fail(color);
+
+	if (font->gdkcolor)
+		gdk_color_free(font->gdkcolor);
+	font->gdkcolor = gdk_color_copy(color);
+	g_snprintf(font->color, sizeof(font->color),
+			"#%02x%02x%02x", color->red >> 8, color->green >> 8, color->blue >> 8);
+}
+
+const gchar *
+pidgin_theme_font_get_font_face(PidginThemeFont *font)
+{
+	g_return_val_if_fail(font, NULL);
+	return font->font;
+}
+
+const GdkColor *
+pidgin_theme_font_get_color(PidginThemeFont *font)
+{
+	g_return_val_if_fail(font, NULL);
+	return font->gdkcolor;
+}
+
+const gchar *
+pidgin_theme_font_get_color_describe(PidginThemeFont *font)
+{
+	g_return_val_if_fail(font, NULL);
+	return font->color;
 }
 
 /******************************************************************************
@@ -257,20 +320,20 @@
 
 	/* Group */
 	gdk_color_free(priv->expanded_color);
-	free_font_and_color(priv->expanded);
+	pidgin_theme_font_free(priv->expanded);
 	gdk_color_free(priv->collapsed_color);
-	free_font_and_color(priv->collapsed);
+	pidgin_theme_font_free(priv->collapsed);
 
 	/* Buddy */
 	gdk_color_free(priv->contact_color);
-	free_font_and_color(priv->contact);
-	free_font_and_color(priv->online);
-	free_font_and_color(priv->away);
-	free_font_and_color(priv->offline);
-	free_font_and_color(priv->idle);
-	free_font_and_color(priv->message);
-	free_font_and_color(priv->message_nick_said);
-	free_font_and_color(priv->status);
+	pidgin_theme_font_free(priv->contact);
+	pidgin_theme_font_free(priv->online);
+	pidgin_theme_font_free(priv->away);
+	pidgin_theme_font_free(priv->offline);
+	pidgin_theme_font_free(priv->idle);
+	pidgin_theme_font_free(priv->message);
+	pidgin_theme_font_free(priv->message_nick_said);
+	pidgin_theme_font_free(priv->status);
 
 	g_free(priv);
 
@@ -447,7 +510,7 @@
 	return priv->expanded_color;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_expanded_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -471,7 +534,7 @@
 	return priv->collapsed_color;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_collapsed_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -495,7 +558,7 @@
 	return priv->contact_color;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_contact_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -507,7 +570,7 @@
 	return priv->contact;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_online_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -519,7 +582,7 @@
 	return priv->online;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_away_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -531,7 +594,7 @@
 	return priv->away;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_offline_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -543,7 +606,7 @@
 	return priv->offline;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_idle_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -555,7 +618,7 @@
 	return priv->idle;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_unread_message_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -567,7 +630,7 @@
 	return priv->message;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_unread_message_nick_said_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -579,7 +642,7 @@
 	return priv->message_nick_said;
 }
 
-FontColorPair *
+PidginThemeFont *
 pidgin_blist_theme_get_status_text_info(PidginBlistTheme *theme)
 {
 	PidginBlistThemePrivate *priv;
@@ -644,7 +707,7 @@
 }
 
 void
-pidgin_blist_theme_set_expanded_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_expanded_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -652,7 +715,7 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->expanded);
+	pidgin_theme_font_free(priv->expanded);
 	priv->expanded = copy_font_and_color(pair);
 }
 
@@ -670,7 +733,7 @@
 }
 
 void
-pidgin_blist_theme_set_collapsed_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_collapsed_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -678,7 +741,7 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->collapsed);
+	pidgin_theme_font_free(priv->collapsed);
 	priv->collapsed = copy_font_and_color(pair);
 }
 
@@ -696,7 +759,7 @@
 }
 
 void
-pidgin_blist_theme_set_contact_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_contact_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -704,12 +767,12 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->contact);
+	pidgin_theme_font_free(priv->contact);
 	priv->contact = copy_font_and_color(pair);
 }
 
 void
-pidgin_blist_theme_set_online_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_online_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -717,12 +780,12 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->online);
+	pidgin_theme_font_free(priv->online);
 	priv->online = copy_font_and_color(pair);
 }
 
 void
-pidgin_blist_theme_set_away_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_away_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -730,12 +793,12 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->away);
+	pidgin_theme_font_free(priv->away);
 	priv->away = copy_font_and_color(pair);
 }
 
 void
-pidgin_blist_theme_set_offline_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_offline_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -743,12 +806,12 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->offline);
+	pidgin_theme_font_free(priv->offline);
 	priv->offline = copy_font_and_color(pair);
 }
 
 void
-pidgin_blist_theme_set_idle_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_idle_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -756,12 +819,12 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->idle);
+	pidgin_theme_font_free(priv->idle);
 	priv->idle = copy_font_and_color(pair);
 }
 
 void
-pidgin_blist_theme_set_unread_message_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_unread_message_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -769,12 +832,12 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->message);
+	pidgin_theme_font_free(priv->message);
 	priv->message = copy_font_and_color(pair);
 }
 
 void
-pidgin_blist_theme_set_unread_message_nick_said_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_unread_message_nick_said_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -782,12 +845,12 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->message_nick_said);
+	pidgin_theme_font_free(priv->message_nick_said);
 	priv->message_nick_said = copy_font_and_color(pair);
 }
 
 void
-pidgin_blist_theme_set_status_text_info(PidginBlistTheme *theme, const FontColorPair *pair)
+pidgin_blist_theme_set_status_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair)
 {
 	PidginBlistThemePrivate *priv;
 
@@ -795,6 +858,6 @@
 
 	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
 
-	free_font_and_color(priv->status);
+	pidgin_theme_font_free(priv->status);
 	priv->status = copy_font_and_color(pair);
 }
--- a/pidgin/gtkblist-theme.h	Fri Apr 17 16:23:02 2009 +0000
+++ b/pidgin/gtkblist-theme.h	Fri Apr 17 19:28:20 2009 +0000
@@ -59,12 +59,15 @@
 	PurpleThemeClass parent_class;
 };
 
+#if 0
 typedef struct
 {
 	const gchar *font;
 	const gchar *color;
 
-} FontColorPair;
+} PidginThemeFont;
+#endif
+typedef struct _PidginThemeFont PidginThemeFont;
 
 typedef struct
 {
@@ -78,13 +81,27 @@
 } PidginBlistLayout;
 
 /**************************************************************************/
-/** @name FontColorPair API                                               */
+/** @name PidginThemeFont API                                               */
 /**************************************************************************/
 
+PidginThemeFont * pidgin_theme_font_new(const char *face, GdkColor *color);
+
 /**
  * Frees a font and color pair
+ *
+ * @param font The theme font
  */
-void free_font_and_color(FontColorPair *pair);
+void pidgin_theme_font_free(PidginThemeFont *font);
+
+void pidgin_theme_font_set_font_face(PidginThemeFont *font, const gchar *face);
+
+void pidgin_theme_font_set_color(PidginThemeFont *font, const GdkColor *color);
+
+const gchar * pidgin_theme_font_get_font_face(PidginThemeFont *font);
+
+const GdkColor * pidgin_theme_font_get_color(PidginThemeFont *font);
+
+const gchar * pidgin_theme_font_get_color_describe(PidginThemeFont *font);
 
 /**************************************************************************/
 /** @name Purple Buddy List Theme API                                     */
@@ -143,7 +160,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_expanded_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_expanded_text_info(PidginBlistTheme *theme);
 
 /**
  * Returns the background color to be used with collapsed groups.
@@ -161,7 +178,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_collapsed_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_collapsed_text_info(PidginBlistTheme *theme);
 
 /**
  * Returns the colors to be used for contacts and chats.
@@ -179,7 +196,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_contact_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_contact_text_info(PidginBlistTheme *theme);
 
 /**
  * Returns the text font and color to be used for online buddies.
@@ -188,7 +205,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_online_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_online_text_info(PidginBlistTheme *theme);
 
 /**
  * Returns the text font and color to be used for away and idle buddies.
@@ -197,7 +214,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_away_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_away_text_info(PidginBlistTheme *theme);
 
 /**
  * Returns the text font and color to be used for offline buddies.
@@ -206,7 +223,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_offline_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_offline_text_info(PidginBlistTheme *theme);
 
 /**
  * Returns the text font and color to be used for idle buddies.
@@ -215,7 +232,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_idle_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_idle_text_info(PidginBlistTheme *theme);
 
 /**
  * Returns the text font and color to be used for buddies with unread messages.
@@ -224,7 +241,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_unread_message_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_unread_message_text_info(PidginBlistTheme *theme);
 
 /**
  * Returns the text font and color to be used for chats with unread messages
@@ -234,7 +251,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_unread_message_nick_said_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_unread_message_nick_said_text_info(PidginBlistTheme *theme);
 
 /**
  * Returns the text font and color to be used for a buddy's status message.
@@ -243,7 +260,7 @@
  *
  * @returns A font and color pair.
  */
- FontColorPair *pidgin_blist_theme_get_status_text_info(PidginBlistTheme *theme);
+ PidginThemeFont *pidgin_blist_theme_get_status_text_info(PidginBlistTheme *theme);
 
 /* Set Methods */
 
@@ -285,7 +302,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_expanded_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_expanded_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 /**
  * Sets the background color to be used for collapsed groups.
@@ -301,7 +318,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_collapsed_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_collapsed_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 /**
  * Sets the background color to be used for contacts and chats.
@@ -317,7 +334,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_contact_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_contact_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 /**
  * Sets the text color and font to be used for online buddies.
@@ -325,7 +342,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_online_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_online_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 /**
  * Sets the text color and font to be used for away and idle buddies.
@@ -333,7 +350,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_away_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_away_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 /**
  * Sets the text color and font to be used for offline buddies.
@@ -341,7 +358,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_offline_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_offline_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 /**
  * Sets the text color and font to be used for idle buddies.
@@ -349,7 +366,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_idle_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_idle_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 /**
  * Sets the text color and font to be used for buddies with unread messages.
@@ -357,7 +374,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_unread_message_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_unread_message_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 /**
  * Sets the text color and font to be used for a chat with unread messages
@@ -366,7 +383,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_unread_message_nick_said_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_unread_message_nick_said_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 /**
  * Sets the text color and font to be used for buddy status messages.
@@ -374,7 +391,7 @@
  * @param theme  The PidginBlist theme.
  * @param pair The new text font at color pair.
  */
-void pidgin_blist_theme_set_status_text_info(PidginBlistTheme *theme, const FontColorPair *pair);
+void pidgin_blist_theme_set_status_text_info(PidginBlistTheme *theme, const PidginThemeFont *pair);
 
 G_END_DECLS
 #endif /* PIDGIN_BLIST_THEME_H */
--- a/pidgin/gtkblist.c	Fri Apr 17 16:23:02 2009 +0000
+++ b/pidgin/gtkblist.c	Fri Apr 17 19:28:20 2009 +0000
@@ -3902,6 +3902,24 @@
 	return ret;
 }
 
+static const char *
+theme_font_get_color_default(PidginThemeFont *font, const char *def)
+{
+	const char *ret;
+	if (!font || !(ret = pidgin_theme_font_get_color_describe(font)))
+		ret = def;
+	return ret;
+}
+
+static const char *
+theme_font_get_face_default(PidginThemeFont *font, const char *def)
+{
+	const char *ret;
+	if (!font || !(ret = pidgin_theme_font_get_font_face(font)))
+		ret = def;
+	return ret;
+}
+
 gchar *
 pidgin_blist_get_name_markup(PurpleBuddy *b, gboolean selected, gboolean aliased)
 {
@@ -3916,7 +3934,7 @@
 	PurpleConversation *conv = find_conversation_with_buddy(b);
 	gboolean hidden_conv = FALSE;
 	gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
-	FontColorPair *pair = NULL;
+	PidginThemeFont *statusfont = NULL, *namefont = NULL;
 	PidginBlistTheme *theme;
 
 	if (conv != NULL) {
@@ -4034,46 +4052,29 @@
 
 	/* choose the colors of the text */
 	theme = pidgin_blist_get_theme();
-
-	if (purple_presence_is_idle(presence)) {
-		if (theme)
-			pair = pidgin_blist_theme_get_idle_text_info(theme);
-		status_color = name_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
-		status_font = name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
-
-	} else if (!purple_presence_is_online(presence)) {
-		if (theme)
-			pair = pidgin_blist_theme_get_offline_text_info(theme);
-		name_color = (pair != NULL && pair->color != NULL) ? pair->color : NULL;
-		name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
-
-		if (theme)
-			pair = pidgin_blist_theme_get_status_text_info(theme);
-		status_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
-		status_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
-
-	} else if (purple_presence_is_available(presence)) {
-		if (theme)
-			pair = pidgin_blist_theme_get_online_text_info(theme);
-		name_color = (pair != NULL && pair->color != NULL) ? pair->color : NULL;
-		name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
-
-		if (theme)
-			pair = pidgin_blist_theme_get_status_text_info(theme);
-		status_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
-		status_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
-
-	} else {
-		if (theme)
-			pair = pidgin_blist_theme_get_away_text_info(theme);
-		name_color = (pair != NULL && pair->color != NULL) ? pair->color : NULL;
-		name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
-
-		if (theme)
-			pair = pidgin_blist_theme_get_status_text_info(theme);
-		status_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
-		status_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
-	}
+	name_color = NULL;
+
+	if (theme) {
+		if (purple_presence_is_idle(presence)) {
+			namefont = statusfont = pidgin_blist_theme_get_idle_text_info(theme);
+			name_color = "dim grey";
+		} else if (!purple_presence_is_online(presence)) {
+			namefont = pidgin_blist_theme_get_offline_text_info(theme);
+			statusfont = pidgin_blist_theme_get_status_text_info(theme);
+		} else if (purple_presence_is_available(presence)) {
+			namefont = pidgin_blist_theme_get_online_text_info(theme);
+			statusfont = pidgin_blist_theme_get_status_text_info(theme);
+		} else {
+			namefont = pidgin_blist_theme_get_away_text_info(theme);
+			statusfont = pidgin_blist_theme_get_status_text_info(theme);
+		}
+	}
+
+	name_color = theme_font_get_color_default(namefont, name_color);
+	name_font = theme_font_get_face_default(namefont, "");
+
+	status_color = theme_font_get_color_default(statusfont, "dim grey");
+	status_font = theme_font_get_face_default(statusfont, "");
 
 	if (aliased && selected) {
 		if (theme) {
@@ -6196,7 +6197,7 @@
 	char *mark, *esc;
 	PurpleBlistNode *selected_node = NULL;
 	GtkTreeIter iter;
-	FontColorPair *pair;
+	PidginThemeFont *pair;
 	gchar const *text_color, *text_font;
 	PidginBlistTheme *theme;
 
@@ -6223,8 +6224,8 @@
 		pair = pidgin_blist_theme_get_collapsed_text_info(theme);
 
 
-	text_color = (selected || pair == NULL || pair->color == NULL) ? NULL : pair->color;
-	text_font = (pair == NULL || pair->font == NULL) ? "" : pair->font;
+	text_color = selected ? NULL : theme_font_get_color_default(pair, NULL);
+	text_font = theme_font_get_face_default(pair, "");
 
 	esc = g_markup_escape_text(group->name, -1);
 	if (text_color) {
@@ -6282,7 +6283,7 @@
 
 		if (idle_secs > 0)
 		{
-			FontColorPair *pair = NULL;
+			PidginThemeFont *pair = NULL;
 			const gchar *textcolor;
 			time_t t;
 			int ihrs, imin;
@@ -6291,18 +6292,18 @@
 			ihrs = (t - idle_secs) / 3600;
 			imin = ((t - idle_secs) / 60) % 60;
 
-			if (!selected && theme != NULL && (pair = pidgin_blist_theme_get_idle_text_info(theme)) != NULL && pair->color != NULL)
-				textcolor = pair->color;
+			if (!selected && theme != NULL && (pair = pidgin_blist_theme_get_idle_text_info(theme)) != NULL)
+				textcolor = pidgin_theme_font_get_color_describe(pair);
 			else
 				textcolor = NULL;
 
 			if (textcolor) {
 				idle = g_strdup_printf("<span color='%s' font_desc='%s'>%d:%02d</span>",
-					textcolor, (pair == NULL || pair->font == NULL) ? "" : pair->font, 
+					textcolor, theme_font_get_face_default(pair, ""),
 					ihrs, imin);
 			} else {
 				idle = g_strdup_printf("<span font_desc='%s'>%d:%02d</span>",
-					(pair == NULL || pair->font == NULL) ? "" : pair->font, 
+					theme_font_get_face_default(pair, ""), 
 					ihrs, imin);
 			}
 		}
@@ -6387,7 +6388,7 @@
 			const gchar *fg_color, *font;
 			GdkColor *color = NULL;
 			PidginBlistTheme *theme = pidgin_blist_get_theme();
-			FontColorPair *pair;
+			PidginThemeFont *pair;
 			gboolean selected = (gtkblist->selected_node == cnode);
 
 			mark = g_markup_escape_text(purple_contact_get_alias(contact), -1);
@@ -6400,8 +6401,8 @@
 				color = pidgin_blist_theme_get_contact_color(theme);
 			}
 
-			font = (pair == NULL || pair->font == NULL) ? "" : pair->font;
-			fg_color = (selected || pair == NULL || pair->color == NULL) ? NULL : pair->color;
+			font = theme_font_get_face_default(pair, "");
+			fg_color = selected ? NULL : theme_font_get_color_default(pair, NULL);
 
 			if (fg_color) {
 				tmp = g_strdup_printf("<span font_desc='%s' color='%s'>%s</span>",
@@ -6498,7 +6499,7 @@
 		PurpleConversation *conv;
 		gboolean hidden = FALSE;
 		GdkColor *bgcolor = NULL;
-		FontColorPair *pair;
+		PidginThemeFont *pair;
 		PidginBlistTheme *theme;
 		gboolean selected = (gtkblist->selected_node == node);
 		gboolean nick_said = FALSE;
@@ -6536,12 +6537,10 @@
 		else pair = pidgin_blist_theme_get_online_text_info(theme);
 
 
-		font = (pair == NULL || pair->font == NULL) ? "" : pair->font;
-		if (selected || pair == NULL || pair->color == NULL)
+		font = theme_font_get_face_default(pair, "");
+		if (selected || !(color = theme_font_get_color_default(pair, NULL)))
 			/* nick_said color is the same as gtkconv:tab-label-attention */
 			color = (nick_said ? "#006aff" : NULL);
-		else
-			color = pair->color;
 
 		if (color) {
 			tmp = g_strdup_printf("<span font_desc='%s' color='%s' weight='%s'>%s</span>",