pidgin/gtkconv-theme-loader.c

changeset 32710
e07993a28f20
parent 32588
b0ce9232396b
child 32958
98a8270ec6aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkconv-theme-loader.c	Mon Oct 31 01:25:36 2011 +0000
@@ -0,0 +1,280 @@
+/*
+ * PidginConvThemeLoader for Pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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  02111-1301  USA
+ */
+
+#include "pidgin.h"
+#include "gtkconv-theme-loader.h"
+#include "gtkconv-theme.h"
+
+#include "xmlnode.h"
+#include "debug.h"
+
+/*****************************************************************************
+ * Conversation Theme Builder
+ *****************************************************************************/
+
+static GHashTable *
+read_info_plist(xmlnode *plist)
+{
+	GHashTable *info;
+	xmlnode *key, *value;
+	gboolean fail = FALSE;
+
+	info = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+	for (key = xmlnode_get_child(plist, "dict/key");
+	     key;
+	     key = xmlnode_get_next_twin(key)) {
+		char *keyname;
+		GValue *val;
+
+		;
+		for (value = key->next; value && value->type != XMLNODE_TYPE_TAG; value = value->next)
+			;
+		if (!value) {
+			fail = TRUE;
+			break;
+		}
+
+		val = g_new0(GValue, 1);
+		if (g_str_equal(value->name, "string")) {
+			g_value_init(val, G_TYPE_STRING);
+			g_value_take_string(val, xmlnode_get_data_unescaped(value));
+
+		} else if (g_str_equal(value->name, "true")) {
+			g_value_init(val, G_TYPE_BOOLEAN);
+			g_value_set_boolean(val, TRUE);
+
+		} else if (g_str_equal(value->name, "false")) {
+			g_value_init(val, G_TYPE_BOOLEAN);
+			g_value_set_boolean(val, FALSE);
+
+		} else if (g_str_equal(value->name, "real")) {
+			char *temp = xmlnode_get_data_unescaped(value);
+			g_value_init(val, G_TYPE_FLOAT);
+			g_value_set_float(val, atof(temp));
+			g_free(temp);
+
+		} else if (g_str_equal(value->name, "integer")) {
+			char *temp = xmlnode_get_data_unescaped(value);
+			g_value_init(val, G_TYPE_INT);
+			g_value_set_int(val, atoi(temp));
+			g_free(temp);
+
+		} else {
+			/* NOTE: We don't support array, data, date, or dict as values,
+			   since they don't seem to be needed for styles. */
+			g_free(val);
+			fail = TRUE;
+			break;
+		}
+
+		keyname = xmlnode_get_data_unescaped(key);
+		g_hash_table_insert(info, keyname, val);
+	}
+
+	if (fail) {
+		g_hash_table_destroy(info);
+		info = NULL;
+	}
+
+	return info;
+}
+
+static PurpleTheme *
+pidgin_conv_loader_build(const gchar *dir)
+{
+	PidginConvTheme *theme = NULL;
+	char *contents;
+	xmlnode *plist;
+	GHashTable *info;
+	GValue *val;
+	int MessageViewVersion;
+	const char *CFBundleName;
+	const char *CFBundleIdentifier;
+	GDir *variants;
+	char *variant_dir;
+
+	g_return_val_if_fail(dir != NULL, NULL);
+
+	/* Load Info.plist for theme information */
+	contents = g_build_filename(dir, "Contents", NULL);
+	plist = xmlnode_from_file(contents, "Info.plist", "Info.plist", "gtkconv-theme-loader");
+	g_free(contents);
+	if (plist == NULL) {
+		purple_debug_error("gtkconv-theme-loader",
+		                   "Failed to load Contents/Info.plist in %s\n", dir);
+		return NULL;
+	}
+
+	info = read_info_plist(plist);
+	xmlnode_free(plist);
+	if (info == NULL) {
+		purple_debug_error("gtkconv-theme-loader",
+		                   "Failed to load Contents/Info.plist in %s\n", dir);
+		return NULL;
+	}
+
+	/* Check for required keys: CFBundleName */
+	val = g_hash_table_lookup(info, "CFBundleName");
+	if (!val || !G_VALUE_HOLDS_STRING(val)) {
+		purple_debug_error("gtkconv-theme-loader",
+		                   "%s/Contents/Info.plist missing required string key CFBundleName.\n",
+		                   dir);
+		g_hash_table_destroy(info);
+		return NULL;
+	}
+	CFBundleName = g_value_get_string(val);
+
+	/* Check for required keys: CFBundleIdentifier */
+	val = g_hash_table_lookup(info, "CFBundleIdentifier");
+	if (!val || !G_VALUE_HOLDS_STRING(val)) {
+		purple_debug_error("gtkconv-theme-loader",
+		                   "%s/Contents/Info.plist missing required string key CFBundleIdentifier.\n",
+		                   dir);
+		g_hash_table_destroy(info);
+		return NULL;
+	}
+	CFBundleIdentifier = g_value_get_string(val);
+
+	/* Check for required keys: MessageViewVersion */
+	val = g_hash_table_lookup(info, "MessageViewVersion");
+	if (!val || !G_VALUE_HOLDS_INT(val)) {
+		purple_debug_error("gtkconv-theme-loader",
+		                   "%s/Contents/Info.plist missing required integer key MessageViewVersion.\n",
+		                   dir);
+		g_hash_table_destroy(info);
+		return NULL;
+	}
+
+	MessageViewVersion = g_value_get_int(val);
+	if (MessageViewVersion < 3) {
+		purple_debug_error("gtkconv-theme-loader",
+		                   "%s is a legacy style (version %d) and will not be loaded.\n",
+		                   CFBundleName, MessageViewVersion);
+		g_hash_table_destroy(info);
+		return NULL;
+	}
+
+	theme = g_object_new(PIDGIN_TYPE_CONV_THEME,
+	                     "type", "conversation",
+	                     "name", CFBundleName,
+	                     "directory", dir,
+	                     "info", info, NULL);
+
+	/* Read list of variants */
+	variant_dir = g_build_filename(dir, "Contents", "Resources", "Variants", NULL);
+	variants = g_dir_open(variant_dir, 0, NULL);
+	g_free(variant_dir);
+
+	if (variants) {
+		char *prefname;
+		const char *default_variant = NULL;
+		const char *file;
+
+		/* Make sure prefs exist */
+		prefname = g_strdup_printf(PIDGIN_PREFS_ROOT "/conversations/themes/%s",
+		                           CFBundleIdentifier);
+		purple_prefs_add_none(prefname);
+		g_free(prefname);
+
+		/* Try user-set variant */
+		prefname = g_strdup_printf(PIDGIN_PREFS_ROOT "/conversations/themes/%s/variant",
+		                           CFBundleIdentifier);
+		if (purple_prefs_exists(prefname))
+			default_variant = purple_prefs_get_string(prefname);
+		g_free(prefname);
+
+		if (default_variant && *default_variant) {
+			pidgin_conversation_theme_set_variant(theme, default_variant);
+
+		} else {
+			/* Try theme default */
+			val = g_hash_table_lookup(info, "DefaultVariant");
+			if (val && G_VALUE_HOLDS_STRING(val)) {
+				default_variant = g_value_get_string(val);
+				if (default_variant && *default_variant)
+					pidgin_conversation_theme_set_variant(theme, default_variant);
+				else
+					default_variant = NULL;
+			} else
+				default_variant = NULL;
+		}
+
+		while ((file = g_dir_read_name(variants)) != NULL) {
+			const char *end = g_strrstr(file, ".css");
+			char *name;
+
+			if ((end == NULL) || (*(end + 4) != '\0'))
+				continue;
+
+			name = g_strndup(file, end - file);
+			pidgin_conversation_theme_add_variant(theme, name);
+
+			/* Set variant with first found */
+			if (!default_variant) {
+				pidgin_conversation_theme_set_variant(theme, name);
+				default_variant = name;
+			}
+		}
+
+		g_dir_close(variants);
+	}
+
+	return PURPLE_THEME(theme);
+}
+
+/******************************************************************************
+ * GObject Stuff
+ *****************************************************************************/
+
+static void
+pidgin_conv_theme_loader_class_init(PidginConvThemeLoaderClass *klass)
+{
+	PurpleThemeLoaderClass *loader_klass = PURPLE_THEME_LOADER_CLASS(klass);
+
+	loader_klass->purple_theme_loader_build = pidgin_conv_loader_build;
+}
+
+
+GType
+pidgin_conversation_theme_loader_get_type(void)
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PidginConvThemeLoaderClass),
+			NULL, /* base_init */
+			NULL, /* base_finalize */
+			(GClassInitFunc)pidgin_conv_theme_loader_class_init, /* class_init */
+			NULL, /* class_finalize */
+			NULL, /* class_data */
+			sizeof (PidginConvThemeLoader),
+			0, /* n_preallocs */
+			NULL, /* instance_init */
+			NULL, /* value table */
+		};
+		type = g_type_register_static(PURPLE_TYPE_THEME_LOADER,
+				"PidginConvThemeLoader", &info, 0);
+	}
+	return type;
+}
+

mercurial