pidgin: 016f0a7e: Move conversation theme loading into the...
qulogic at pidgin.im
qulogic at pidgin.im
Sun Sep 18 05:15:47 EDT 2011
----------------------------------------------------------------------
Revision: 016f0a7edfb704950358fcccbf5098f0c6f7dac6
Parent: 9357e9662715ddabf111c8ea5a9e548f17c2234e
Author: qulogic at pidgin.im
Date: 09/18/11 04:59:12
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/016f0a7edfb704950358fcccbf5098f0c6f7dac6
Changelog:
Move conversation theme loading into the PidginConvThemeLoader GObject
Changes against parent 9357e9662715ddabf111c8ea5a9e548f17c2234e
patched pidgin/gtkconv-theme-loader.c
patched pidgin/gtkconv-theme.c
patched pidgin/gtkconv-theme.h
-------------- next part --------------
============================================================
--- pidgin/gtkconv-theme-loader.c be6287b7e8fd1d84ec2ccd7e6ec72517c84ca490
+++ pidgin/gtkconv-theme-loader.c e4c5562affd867fca8e4b810f4d94121ed3d3772
@@ -30,14 +30,144 @@
* 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;
- /* Find the theme file */
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", "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", "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) {
+ purple_debug_error("gtkconv-theme", "%s/Contents/Info.plist missing required 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) {
+ purple_debug_error("gtkconv-theme", "%s/Contents/Info.plist missing required 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) {
+ purple_debug_error("gtkconv-theme", "%s/Contents/Info.plist missing required 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", "%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);
+
return PURPLE_THEME(theme);
}
============================================================
--- pidgin/gtkconv-theme.c dd790df2c5a57bca7ae88dc5bb9277d78c5a8b9a
+++ pidgin/gtkconv-theme.c c1b6a3b261bef83f354b41e3d7735a6701ef4d3b
@@ -48,7 +48,8 @@ typedef struct {
/* current config options */
char *variant; /* allowed to be NULL if there are no variants */
- /* Info.plist keys that change with Variant */
+ /* Info.plist keys/values */
+ GHashTable *info;
/* Static Info.plist keys */
int message_view_version;
@@ -88,10 +89,51 @@ static GObjectClass *parent_class = NULL
static GObjectClass *parent_class = NULL;
/******************************************************************************
+ * Enums
+ *****************************************************************************/
+
+enum {
+ PROP_ZERO = 0,
+ PROP_INFO,
+};
+
+/******************************************************************************
* GObject Stuff
*****************************************************************************/
static void
+pidgin_conv_theme_get_property(GObject *obj, guint param_id, GValue *value,
+ GParamSpec *psec)
+{
+ PidginConvTheme *theme = PIDGIN_CONV_THEME(obj);
+
+ switch (param_id) {
+ case PROP_INFO:
+ g_value_set_boxed(value, (gpointer)pidgin_conversation_theme_get_info(theme));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
+ break;
+ }
+}
+
+static void
+pidgin_conv_theme_set_property(GObject *obj, guint param_id, const GValue *value,
+ GParamSpec *psec)
+{
+ PidginConvTheme *theme = PIDGIN_CONV_THEME(obj);
+
+ switch (param_id) {
+ case PROP_INFO:
+ pidgin_conversation_theme_set_info(theme, g_value_get_boxed(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
+ break;
+ }
+}
+
+static void
pidgin_conv_theme_init(GTypeInstance *instance,
gpointer klass)
{
@@ -124,6 +166,9 @@ pidgin_conv_theme_finalize(GObject *obj)
g_free(priv->status_html);
g_free(priv->basestyle_css);
+ if (priv->info)
+ g_hash_table_destroy(priv->info);
+
parent_class->finalize(obj);
}
@@ -131,10 +176,23 @@ pidgin_conv_theme_class_init(PidginConvT
pidgin_conv_theme_class_init(PidginConvThemeClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+ GParamSpec *pspec;
parent_class = g_type_class_peek_parent(klass);
+ g_type_class_add_private(klass, sizeof(PidginConvThemePrivate));
+
+ obj_class->get_property = pidgin_conv_theme_get_property;
+ obj_class->set_property = pidgin_conv_theme_set_property;
obj_class->finalize = pidgin_conv_theme_finalize;
+
+ /* INFO */
+ pspec = g_param_spec_boxed("info", "Info",
+ "The information about this theme",
+ G_TYPE_HASH_TABLE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(obj_class, PROP_INFO, pspec);
+
}
GType
@@ -155,7 +213,7 @@ pidgin_conversation_theme_get_type(void)
NULL, /* value table */
};
type = g_type_register_static(PURPLE_TYPE_THEME,
- "PidginConvTheme", &info, G_TYPE_FLAG_ABSTRACT);
+ "PidginConvTheme", &info, 0);
}
return type;
}
@@ -164,18 +222,6 @@ pidgin_conversation_theme_get_type(void)
* Helper Functions
*****************************************************************************/
-static PidginConvTheme *
-pidgin_conversation_theme_new(const char *styledir)
-{
- PidginConvTheme *ret = g_object_new(PIDGIN_TYPE_CONV_THEME, NULL);
- PidginConvThemePrivate *priv;
-
- priv = PIDGIN_CONV_THEME_GET_PRIVATE(ret);
- priv->style_dir = g_strdup(styledir);
-
- return ret;
-}
-
static const char *
get_template_html(PidginConvThemePrivate *priv)
{
@@ -485,7 +531,27 @@ webkit_on_webview_destroy(GtkObject *obj
* Public API functions
*****************************************************************************/
+const GHashTable *
+pidgin_conversation_theme_get_info(const PidginConvTheme *theme)
+{
+ PidginConvThemePrivate *priv;
+ priv = PIDGIN_CONV_THEME_GET_PRIVATE(theme);
+ return priv->info;
+}
+
void
+pidgin_conversation_theme_set_info(PidginConvTheme *theme, GHashTable *info)
+{
+ PidginConvThemePrivate *priv;
+ priv = PIDGIN_CONV_THEME_GET_PRIVATE(theme);
+
+ if (priv->info)
+ g_hash_table_destroy(priv->info);
+
+ priv->info = info;
+}
+
+void
pidgin_conversation_theme_save_state(const PidginConvTheme *theme)
{
PidginConvThemePrivate *priv;
@@ -533,172 +599,14 @@ pidgin_conversation_theme_load_state(Pid
g_free(variant);
}
-
-static gboolean
-parse_info_plist_key_value(xmlnode *key, gpointer destination, const char *expected)
-{
- xmlnode *val = key->next;
-
- for (; val && val->type != XMLNODE_TYPE_TAG; val = val->next)
- ;
- if (!val)
- return FALSE;
-
- if (expected == NULL || g_str_equal(expected, "string")) {
- char **dest = (char **)destination;
- if (!g_str_equal(val->name, "string"))
- return FALSE;
- if (*dest)
- g_free(*dest);
- *dest = xmlnode_get_data_unescaped(val);
- } else if (g_str_equal(expected, "integer")) {
- int *dest = (int *)destination;
- char *value = xmlnode_get_data_unescaped(val);
-
- if (!g_str_equal(val->name, "integer"))
- return FALSE;
- *dest = atoi(value);
- g_free(value);
- } else if (g_str_equal(expected, "boolean")) {
- gboolean *dest = (gboolean *)destination;
- if (g_str_equal(val->name, "true"))
- *dest = TRUE;
- else if (g_str_equal(val->name, "false"))
- *dest = FALSE;
- else
- return FALSE;
- } else return FALSE;
-
- return TRUE;
-}
-
-static gboolean
-str_for_key(const char *key, const char *found, const char *variant)
-{
- if (g_str_equal(key, found))
- return TRUE;
- if (!variant)
- return FALSE;
- return (g_str_has_prefix(found, key)
- && g_str_has_suffix(found, variant)
- && strlen(found) == strlen(key) + strlen(variant) + 1);
-}
-
-/**
- * Info.plist should be re-read every time the variant changes, this is because
- * the keys that take precedence depend on the value of the current variant.
- */
-void
-pidgin_conversation_theme_read_info_plist(PidginConvTheme *theme, const char *variant)
-{
- PidginConvThemePrivate *priv;
- char *contents;
- xmlnode *plist, *iter;
- xmlnode *dict;
-
- priv = PIDGIN_CONV_THEME_GET_PRIVATE(theme);
-
- /* note that if a variant is used the option:VARIANTNAME takes precedence */
- contents = g_build_filename(priv->style_dir, "Contents", NULL);
- plist = xmlnode_from_file(contents, "Info.plist", "Info.plist", "webkit");
- dict = xmlnode_get_child(plist, "dict");
-
- g_assert (dict);
- for (iter = xmlnode_get_child(dict, "key"); iter; iter = xmlnode_get_next_twin(iter)) {
- char* key = xmlnode_get_data_unescaped(iter);
- gboolean pr = TRUE;
-
- if (g_str_equal("MessageViewVersion", key))
- pr = parse_info_plist_key_value(iter, &priv->message_view_version, "integer");
- else if (g_str_equal("CFBundleName", key))
- pr = parse_info_plist_key_value(iter, &priv->cf_bundle_name, "string");
- else if (g_str_equal("CFBundleIdentifier", key))
- pr = parse_info_plist_key_value(iter, &priv->cf_bundle_identifier, "string");
- else if (g_str_equal("CFBundleGetInfoString", key))
- pr = parse_info_plist_key_value(iter, &priv->cf_bundle_get_info_string, "string");
- else if (str_for_key("DefaultFontFamily", key, variant))
- pr = parse_info_plist_key_value(iter, &priv->default_font_family, "string");
- else if (str_for_key("DefaultFontSize", key, variant))
- pr = parse_info_plist_key_value(iter, &priv->default_font_size, "integer");
- else if (str_for_key("ShowsUserIcons", key, variant))
- pr = parse_info_plist_key_value(iter, &priv->shows_user_icons, "boolean");
- else if (str_for_key("DisableCombineConsecutive", key, variant))
- pr = parse_info_plist_key_value(iter, &priv->disable_combine_consecutive, "boolean");
- else if (str_for_key("DefaultBackgroundIsTransparent", key, variant))
- pr = parse_info_plist_key_value(iter, &priv->default_background_is_transparent, "boolean");
- else if (str_for_key("DisableCustomBackground", key, variant))
- pr = parse_info_plist_key_value(iter, &priv->disable_custom_background, "boolean");
- else if (str_for_key("DefaultBackgroundColor", key, variant))
- pr = parse_info_plist_key_value(iter, &priv->default_background_color, "string");
- else if (str_for_key("AllowTextColors", key, variant))
- pr = parse_info_plist_key_value(iter, &priv->allow_text_colors, "integer");
- else if (str_for_key("ImageMask", key, variant))
- pr = parse_info_plist_key_value(iter, &priv->image_mask, "string");
-
- if (!pr)
- purple_debug_warning("webkit", "Failed to parse key %s\n", key);
- g_free(key);
- }
-
- xmlnode_free(plist);
-}
-
PidginConvTheme *
-pidgin_conversation_theme_load(const char *styledir)
-{
- /*
- * the loading process described:
- *
- * First we load all the style .html files, etc.
- * The we load any config options that have been stored for
- * this variant.
- * Then we load the Info.plist, for the currently decided variant.
- * At this point, if we find that variants exist, yet
- * we don't have a variant selected, we choose DefaultVariant
- * and if that does not exist, we choose the first one in the
- * directory.
- */
- PidginConvTheme *theme = NULL;
- PidginConvThemePrivate *priv;
-
- theme = pidgin_conversation_theme_new(styledir);
-
- priv = PIDGIN_CONV_THEME_GET_PRIVATE(theme);
-
- /* load all other files */
-
- pidgin_conversation_theme_read_info_plist(theme, NULL);
- pidgin_conversation_theme_load_state(theme);
-
- /* non variant dependent Info.plist checks */
- if (priv->message_view_version < 3) {
- purple_debug_info("webkit", "%s is a legacy style (version %d) and will not be loaded\n", priv->cf_bundle_name, priv->message_view_version);
- g_object_unref(G_OBJECT(theme));
- return NULL;
- }
-
- if (!priv->variant)
- {
- GList *variants = pidgin_conversation_theme_get_variants(theme);
-
- if (variants)
- pidgin_conversation_theme_set_variant(theme, variants->data);
-
- for (; variants; variants = g_list_delete_link(variants, variants))
- g_free(variants->data);
- }
-
- return theme;
-}
-
-PidginConvTheme *
pidgin_conversation_theme_copy(const PidginConvTheme *theme)
{
PidginConvTheme *ret;
PidginConvThemePrivate *old, *new;
old = PIDGIN_CONV_THEME_GET_PRIVATE(theme);
- ret = pidgin_conversation_theme_new(old->style_dir);
+ ret = g_object_new(PIDGIN_TYPE_CONV_THEME, "directory", old->style_dir, NULL);
new = PIDGIN_CONV_THEME_GET_PRIVATE(ret);
new->variant = g_strdup(old->variant);
@@ -741,8 +649,6 @@ pidgin_conversation_theme_set_variant(Pi
g_free(priv->variant);
priv->variant = g_strdup(variant);
- pidgin_conversation_theme_read_info_plist(theme, variant);
-
/* todo, the style has "changed". Ideally, I would like to use signals at this point. */
}
============================================================
--- pidgin/gtkconv-theme.h 7998d68bfba2b9884ff90b6cea7610c621a4db62
+++ pidgin/gtkconv-theme.h f26e1079460ab031aaf7d4d5a68a0c44cd2a267a
@@ -69,6 +69,9 @@ GType pidgin_conversation_theme_get_type
*/
GType pidgin_conversation_theme_get_type(void);
+const GHashTable *pidgin_conversation_theme_get_info(const PidginConvTheme *theme);
+void pidgin_conversation_theme_set_info(PidginConvTheme *theme, GHashTable *info);
+
PidginConvTheme *pidgin_conversation_theme_load(const char *styledir);
PidginConvTheme *pidgin_conversation_theme_copy(const PidginConvTheme *theme);
void pidgin_conversation_theme_save_state(const PidginConvTheme *theme);
More information about the Commits
mailing list