* 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 * 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 "gtkconv-theme-loader.h" #include "gtkconv-theme.h" /***************************************************************************** * Conversation Theme Builder *****************************************************************************/ read_info_plist(PurpleXmlNode *plist) PurpleXmlNode *key, *value; info = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); for (key = purple_xmlnode_get_child(plist, "dict/key"); key = purple_xmlnode_get_next_twin(key)) { for (value = key->next; value && value->type != PURPLE_XMLNODE_TYPE_TAG; value = value->next) if (g_str_equal(value->name, "string")) { g_value_init(val, G_TYPE_STRING); g_value_take_string(val, purple_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 = purple_xmlnode_get_data_unescaped(value); g_value_init(val, G_TYPE_FLOAT); g_value_set_float(val, atof(temp)); } else if (g_str_equal(value->name, "integer")) { char *temp = purple_xmlnode_get_data_unescaped(value); g_value_init(val, G_TYPE_INT); g_value_set_int(val, atoi(temp)); /* NOTE: We don't support array, data, date, or dict as values, since they don't seem to be needed for styles. */ keyname = purple_xmlnode_get_data_unescaped(key); g_hash_table_insert(info, keyname, val); g_hash_table_destroy(info); pidgin_conv_loader_probe(const gchar *dir) plist_file = g_build_filename(dir, "Contents", "Info.plist", NULL); result = g_file_test(plist_file, G_FILE_TEST_IS_REGULAR); pidgin_conv_loader_build(const gchar *dir) PidginConvTheme *theme = NULL; const char *CFBundleName; const char *CFBundleIdentifier; g_return_val_if_fail(dir != NULL, NULL); /* Load Info.plist for theme information */ contents = g_build_filename(dir, "Contents", NULL); plist = purple_xmlnode_from_file(contents, "Info.plist", "Info.plist", "gtkconv-theme-loader"); purple_debug_error("gtkconv-theme-loader", "Failed to load Contents/Info.plist in %s\n", dir); info = read_info_plist(plist); purple_xmlnode_free(plist); purple_debug_error("gtkconv-theme-loader", "Failed to load Contents/Info.plist in %s\n", dir); /* 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", g_hash_table_destroy(info); 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", g_hash_table_destroy(info); 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", g_hash_table_destroy(info); 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); theme = g_object_new(PIDGIN_TYPE_CONV_THEME, /* Read list of variants */ variant_dir = g_build_filename(dir, "Contents", "Resources", "Variants", NULL); variants = g_dir_open(variant_dir, 0, NULL); const char *default_variant = NULL; /* Make sure prefs exist */ prefname = g_strdup_printf(PIDGIN_PREFS_ROOT "/conversations/themes/%s", purple_prefs_add_none(prefname); /* Try user-set variant */ prefname = g_strdup_printf(PIDGIN_PREFS_ROOT "/conversations/themes/%s/variant", if (purple_prefs_exists(prefname)) default_variant = purple_prefs_get_string(prefname); if (default_variant && *default_variant) { pidgin_conversation_theme_set_variant(theme, default_variant); 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); while ((file = g_dir_read_name(variants)) != NULL) { const char *end = g_strrstr(file, ".css"); if ((end == NULL) || (*(end + 4) != '\0')) name = g_strndup(file, end - file); pidgin_conversation_theme_add_variant(theme, name); /* Set variant with first found */ pidgin_conversation_theme_set_variant(theme, name); return PURPLE_THEME(theme); /****************************************************************************** *****************************************************************************/ 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; loader_klass->probe_directory = pidgin_conv_loader_probe; pidgin_conversation_theme_loader_get_type(void) static const GTypeInfo info = { sizeof(PidginConvThemeLoaderClass), NULL, /* base_finalize */ (GClassInitFunc)pidgin_conv_theme_loader_class_init, /* class_init */ NULL, /* class_finalize */ sizeof (PidginConvThemeLoader), NULL, /* instance_init */ type = g_type_register_static(PURPLE_TYPE_THEME_LOADER, "PidginConvThemeLoader", &info, 0);