Mercurial > pidgin.yaz
changeset 32566:59f433824040
Separated the MessageStyle loading code from the actual rendering code.
author | tdrhq@soc.pidgin.im |
---|---|
date | Fri, 14 Aug 2009 02:51:41 +0000 |
parents | 53735be6950a |
children | 285db86fcf99 |
files | pidgin/plugins/adiumthemes/Makefile.am pidgin/plugins/adiumthemes/message-style.c pidgin/plugins/adiumthemes/message-style.h pidgin/plugins/adiumthemes/webkit.c |
diffstat | 4 files changed, 495 insertions(+), 444 deletions(-) [+] |
line wrap: on
line diff
--- a/pidgin/plugins/adiumthemes/Makefile.am Thu Aug 13 19:58:17 2009 +0000 +++ b/pidgin/plugins/adiumthemes/Makefile.am Fri Aug 14 02:51:41 2009 +0000 @@ -12,7 +12,9 @@ webkit_LTLIBRARIES = webkit.la -webkit_la_SOURCES = webkit.c +webkit_la_SOURCES = webkit.c \ + message-style.h \ + message-style.c endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/adiumthemes/message-style.c Fri Aug 14 02:51:41 2009 +0000 @@ -0,0 +1,429 @@ +/* + * Adium Message Styles + * Copyright (C) 2009 Arnold Noronha <arnstein87@gmail.com> + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "message-style.h" + +#include <string.h> + +#include <glib.h> + +#include <debug.h> +#include <util.h> + +static GList *style_list; /**< List of PidginMessageStyles */ + +static void +glist_free_all_string (GList *list) +{ + GList *first = list; + for (; list; list = g_list_next (list)) + g_free (list->data); + g_list_free (first); +} + +static +PidginMessageStyle* pidgin_message_style_new (const char* styledir) +{ + PidginMessageStyle* ret = g_new0 (PidginMessageStyle, 1); + GList *iter; + + /* sanity check */ + for (iter = style_list; iter; iter = g_list_next (iter)) + g_assert (!g_str_equal (((PidginMessageStyle*)iter->data)->style_dir, styledir)); + + ret->ref_counter = 1; + ret->style_dir = g_strdup (styledir); + + style_list = g_list_append (style_list, ret); + return ret; +} + +/** + * deallocate any memory used for info.plist options + */ +static void +pidgin_message_style_unset_info_plist (PidginMessageStyle *style) +{ + style->message_view_version = 0; + g_free (style->cf_bundle_name); + style->cf_bundle_name = NULL; + + g_free (style->cf_bundle_identifier); + style->cf_bundle_identifier = NULL; + + g_free (style->cf_bundle_get_info_string); + style->cf_bundle_get_info_string = NULL; + + g_free (style->default_font_family); + style->default_font_family = NULL; + + style->default_font_size = 0; + style->shows_user_icons = TRUE; + style->disable_combine_consecutive = FALSE; + style->default_background_is_transparent = FALSE; + style->disable_custom_background = FALSE; + + g_free (style->default_background_color); + style->default_background_color = NULL; + + style->allow_text_colors = TRUE; + + g_free (style->image_mask); + style->image_mask = NULL; +} + + +void pidgin_message_style_unref (PidginMessageStyle *style) +{ + if (!style) return; + g_assert (style->ref_counter > 0); + + style->ref_counter--; + if (style->ref_counter) return; + + g_free (style->style_dir); + g_free (style->template_path); + + g_free (style->template_html); + g_free (style->incoming_content_html); + g_free (style->outgoing_content_html); + g_free (style->outgoing_next_content_html); + g_free (style->status_html); + g_free (style->basestyle_css); + + style_list = g_list_remove (style_list, style); + g_free (style); + + pidgin_message_style_unset_info_plist (style); +} + +void +pidgin_message_style_save_state (PidginMessageStyle *style) +{ + char *prefname = g_strdup_printf ("/plugins/gtk/adiumthemes/%s", style->cf_bundle_identifier); + char *variant = g_strdup_printf ("%s/%s", prefname, style->variant); + + purple_prefs_add_none (prefname); + purple_prefs_add_string (variant, ""); + purple_prefs_set_string (variant, style->variant); + + g_free (prefname); + g_free (variant); +} + +void +pidgin_message_style_load_state (PidginMessageStyle *style) +{ + char *prefname = g_strdup_printf ("/plugins/gtk/adiumthemes/%s", style->cf_bundle_identifier); + char *variant = g_strdup_printf ("%s/%s", prefname, style->variant); + + const char* value = purple_prefs_get_string (variant); + gboolean changed = !style->variant || !g_str_equal (style->variant, value); + + g_free (style->variant); + style->variant = g_strdup (value); + + if (changed) pidgin_message_style_read_info_plist (style, style->variant); + + g_free (prefname); + 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_message_style_read_info_plist (PidginMessageStyle *style, const char* variant) +{ + /* note that if a variant is used the option:VARIANTNAME takes precedence */ + char *contents = g_build_filename (style->style_dir, "Contents", NULL); + xmlnode *plist = xmlnode_from_file (contents, "Info.plist", "Info.plist", "webkit"), *iter; + xmlnode *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, &style->message_view_version, "integer"); + else if (g_str_equal ("CFBundleName", key)) + pr = parse_info_plist_key_value (iter, &style->cf_bundle_name, "string"); + else if (g_str_equal ("CFBundleIdentifier", key)) + pr = parse_info_plist_key_value (iter, &style->cf_bundle_identifier, "string"); + else if (g_str_equal ("CFBundleGetInfoString", key)) + pr = parse_info_plist_key_value (iter, &style->cf_bundle_get_info_string, "string"); + else if (str_for_key ("DefaultFontFamily", key, variant)) + pr = parse_info_plist_key_value (iter, &style->default_font_family, "string"); + else if (str_for_key ("DefaultFontSize", key, variant)) + pr = parse_info_plist_key_value (iter, &style->default_font_size, "integer"); + else if (str_for_key ("ShowsUserIcons", key, variant)) + pr = parse_info_plist_key_value (iter, &style->shows_user_icons, "boolean"); + else if (str_for_key ("DisableCombineConsecutive", key, variant)) + pr = parse_info_plist_key_value (iter, &style->disable_combine_consecutive, "boolean"); + else if (str_for_key ("DefaultBackgroundIsTransparent", key, variant)) + pr = parse_info_plist_key_value (iter, &style->default_background_is_transparent, "boolean"); + else if (str_for_key ("DisableCustomBackground", key, variant)) + pr = parse_info_plist_key_value (iter, &style->disable_custom_background, "boolean"); + else if (str_for_key ("DefaultBackgroundColor", key, variant)) + pr = parse_info_plist_key_value (iter, &style->default_background_color, "string"); + else if (str_for_key ("AllowTextColors", key, variant)) + pr = parse_info_plist_key_value (iter, &style->allow_text_colors, "string"); + else if (str_for_key ("ImageMask", key, variant)) + pr = parse_info_plist_key_value (iter, &style->image_mask, "string"); + + g_free (key); + if (!pr) break; /* does not make sense */ + } + + xmlnode_free (plist); +} + +PidginMessageStyle* +pidgin_message_style_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. + */ + + /* is this style already loaded? */ + GList *cur = style_list; + char *file; /* temporary variable */ + PidginMessageStyle *style = NULL; + + g_assert (styledir); + for (cur = style_list; cur; cur = g_list_next (cur)) { + style = (PidginMessageStyle*) cur->data; + if (g_str_equal (styledir, style->style_dir)) { + style->ref_counter++; + return style; + } + } + + /* else we need to load it */ + style = pidgin_message_style_new (styledir); + + /* load all other files */ + + /* The template path can either come from the theme, or can + * be stock Template.html that comes with the plugin */ + style->template_path = g_build_filename(styledir, "Contents", "Resources", "Template.html", NULL); + + if (!g_file_test(style->template_path, G_FILE_TEST_EXISTS)) { + g_free (style->template_path); + style->template_path = g_build_filename(DATADIR, "pidgin", "webkit", "Template.html", NULL); + } + + if (!g_file_get_contents(style->template_path, &style->template_html, NULL, NULL)) { + pidgin_message_style_unref (style); + purple_debug_error ("webkit", "Could not locate a Template.html\n"); + return NULL; + } + + file = g_build_filename(styledir, "Contents", "Resources", "Status.html", NULL); + if (!g_file_get_contents(file, &style->status_html, NULL, NULL)) { + purple_debug_info ("webkit", "%s could not find Resources/Status.html", styledir); + pidgin_message_style_unref (style); + g_free (file); + return NULL; + } + g_free (file); + + file = g_build_filename(styledir, "Contents", "Resources", "main.css", NULL); + if (!g_file_get_contents(file, &style->basestyle_css, NULL, NULL)) + style->basestyle_css = g_strdup (""); + g_free (file); + + file = g_build_filename(styledir, "Contents", "Resources", "Header.html", NULL); + if (!g_file_get_contents(file, &style->header_html, NULL, NULL)) + style->header_html = g_strdup (""); + g_free (file); + + file = g_build_filename(styledir, "Contents", "Resources", "Footer.html", NULL); + if (!g_file_get_contents(file, &style->footer_html, NULL, NULL)) + style->footer_html = g_strdup (""); + g_free (file); + + file = g_build_filename(styledir, "Contents", "Resources", "Incoming", "Content.html", NULL); + if (!g_file_get_contents(file, &style->incoming_content_html, NULL, NULL)) { + purple_debug_info ("webkit", "%s did not have a Incoming/Content.html\n", styledir); + pidgin_message_style_unref (style); + g_free (file); + return NULL; + } + g_free (file); + + + /* according to the spec, the following are optional files */ + file = g_build_filename(styledir, "Contents", "Resources", "Incoming", "NextContent.html", NULL); + if (!g_file_get_contents(file, &style->incoming_next_content_html, NULL, NULL)) { + style->incoming_next_content_html = g_strdup (style->incoming_content_html); + } + g_free (file); + + file = g_build_filename(styledir, "Contents", "Resources", "Outgoing", "Content.html", NULL); + if (!g_file_get_contents(file, &style->outgoing_content_html, NULL, NULL)) { + style->outgoing_content_html = g_strdup(style->incoming_content_html); + } + g_free (file); + + file = g_build_filename(styledir, "Contents", "Resources", "Outgoing", "NextContent.html", NULL); + if (!g_file_get_contents(file, &style->outgoing_next_content_html, NULL, NULL)) { + style->outgoing_next_content_html = g_strdup (style->outgoing_content_html); + } + + pidgin_message_style_load_state (style); + pidgin_message_style_read_info_plist (style, style->variant); + + /* non variant dependent Info.plist checks */ + if (style->message_view_version < 3) { + pidgin_message_style_unref (style); + return NULL; + } + + if (!style->variant) + { + GList *variants = pidgin_message_style_get_variants (style); + + if (variants) + pidgin_message_style_set_variant (style, variants->data); + + glist_free_all_string (variants); + pidgin_message_style_save_state (style); + } + + return style; +} + +void +pidgin_message_style_set_variant (PidginMessageStyle *style, const char *variant) +{ + /* I'm not going to test whether this variant is valid! */ + g_free (style->variant); + style->variant = g_strdup (variant); + + pidgin_message_style_read_info_plist (style, variant); + pidgin_message_style_save_state (style); + + /* todo, the style has "changed". Ideally, I would like to use signals at this point. */ +} + +char* pidgin_message_style_get_variant (PidginMessageStyle *style) +{ + return g_strdup (style->variant); +} + +/** + * Get a list of variants supported by the style. + */ +GList* +pidgin_message_style_get_variants (PidginMessageStyle *style) +{ + GList *ret = NULL; + GDir *variants; + const char *css_file; + char *css; + char *variant_dir; + + g_assert (style->style_dir); + variant_dir = g_build_filename(style->style_dir, "Contents", "Resources", "Variants", NULL); + + variants = g_dir_open(variant_dir, 0, NULL); + if (!variants) return NULL; + + while ((css_file = g_dir_read_name(variants)) != NULL) { + if (!g_str_has_suffix (css_file, ".css")) + continue; + + css = g_strndup (css_file, strlen (css_file) - 4); + ret = g_list_append(ret, css); + } + + g_dir_close(variants); + g_free(variant_dir); + + ret = g_list_sort (ret, (GCompareFunc)g_strcmp0); + return ret; +} + + +char* pidgin_message_style_get_css (PidginMessageStyle *style) +{ + if (!style->variant) { + return g_build_filename (style->style_dir, "Contents", "Resources", "main.css", NULL); + } else { + char *file = g_strdup_printf ("%s.css", style->variant); + char *ret = g_build_filename (style->style_dir, "Contents", "Resources", "Variants", file, NULL); + g_free (file); + return ret; + } +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/adiumthemes/message-style.h Fri Aug 14 02:51:41 2009 +0000 @@ -0,0 +1,56 @@ + +#include <glib.h> + +/* + * I'm going to allow a different style for each PidginConversation. + * This way I can do two things: 1) change the theme on the fly and not + * change existing themes, and 2) Use a different theme for IMs and + * chats. + */ +typedef struct _PidginMessageStyle { + int ref_counter; + + /* current config options */ + char *variant; /* allowed to be NULL if there are no variants */ + gboolean show_user_icons; + + + /* Info.plist keys */ + int message_view_version; + char *cf_bundle_name; + char *cf_bundle_identifier; + char *cf_bundle_get_info_string; + char *default_font_family; + int default_font_size; + gboolean shows_user_icons; + gboolean disable_combine_consecutive; + gboolean default_background_is_transparent; + gboolean disable_custom_background; + char *default_background_color; + gboolean allow_text_colors; + char *image_mask; + + /* paths */ + char *style_dir; + char *template_path; + + /* caches */ + char *template_html; + char *header_html; + char *footer_html; + char *incoming_content_html; + char *outgoing_content_html; + char *incoming_next_content_html; + char *outgoing_next_content_html; + char *status_html; + char *basestyle_css; +} PidginMessageStyle; + +PidginMessageStyle* pidgin_message_style_load (const char* styledir); +void pidgin_message_style_unref (PidginMessageStyle *style); +void pidgin_message_style_read_info_plist (PidginMessageStyle *style, const char* variant); +char* pidgin_message_style_get_variant (PidginMessageStyle *style); +GList* pidgin_message_style_get_variants (PidginMessageStyle *style); +void pidgin_message_style_set_variant (PidginMessageStyle *style, const char *variant); + +char* pidgin_message_style_get_css (PidginMessageStyle *style);
--- a/pidgin/plugins/adiumthemes/webkit.c Thu Aug 13 19:58:17 2009 +0000 +++ b/pidgin/plugins/adiumthemes/webkit.c Fri Aug 14 02:51:41 2009 +0000 @@ -50,74 +50,14 @@ #include <smileyparser.h> #include <libxml/xmlreader.h> + +#include "message-style.h" /* GObject data keys */ #define MESSAGE_STYLE_KEY "message-style" -/* - * I'm going to allow a different style for each PidginConversation. - * This way I can do two things: 1) change the theme on the fly and not - * change existing themes, and 2) Use a different theme for IMs and - * chats. - */ -typedef struct _PidginMessageStyle { - int ref_counter; - - /* current config options */ - char *variant; /* allowed to be NULL if there are no variants */ - char *bg_color; - - /* Info.plist keys */ - int message_view_version; - char *cf_bundle_name; - char *cf_bundle_identifier; - char *cf_bundle_get_info_string; - char *default_font_family; - int default_font_size; - gboolean shows_user_icons; - gboolean disable_combine_consecutive; - gboolean default_background_is_transparent; - gboolean disable_custom_background; - char *default_background_color; - gboolean allow_text_colors; - char *image_mask; - - /* paths */ - char *style_dir; - char *template_path; - - /* caches */ - char *template_html; - char *header_html; - char *footer_html; - char *incoming_content_html; - char *outgoing_content_html; - char *incoming_next_content_html; - char *outgoing_next_content_html; - char *status_html; - char *basestyle_css; -} PidginMessageStyle; - -static GList *style_list; /**< List of PidginMessageStyles */ static char *cur_style_dir = NULL; static void *handle = NULL; -static PidginMessageStyle* pidgin_message_style_new (const char* styledir); -static PidginMessageStyle* pidgin_message_style_load (const char* styledir); -static void pidgin_message_style_unref (PidginMessageStyle *style); -static void pidgin_message_style_read_info_plist (PidginMessageStyle *style, const char* variant); -static char* pidgin_message_style_get_variant (PidginMessageStyle *style); -static GList* pidgin_message_style_get_variants (PidginMessageStyle *style); -static void pidgin_message_style_set_variant (PidginMessageStyle *style, const char *variant); - -static void -glist_free_all_string (GList *list) -{ - GList *first = list; - for (; list; list = g_list_next (list)) - g_free (list->data); - g_list_free (first); -} - static inline char* get_absolute_path (const char *path) { if (g_path_is_absolute (path)) return g_strdup (path); @@ -129,393 +69,17 @@ } } -static PidginMessageStyle* pidgin_message_style_new (const char* styledir) -{ - PidginMessageStyle* ret = g_new0 (PidginMessageStyle, 1); - GList *iter; - - /* sanity check */ - for (iter = style_list; iter; iter = g_list_next (iter)) - g_assert (!g_str_equal (((PidginMessageStyle*)iter->data)->style_dir, styledir)); - - ret->ref_counter = 1; - ret->style_dir = g_strdup (styledir); - - style_list = g_list_append (style_list, ret); - return ret; -} - -/** - * deallocate any memory used for info.plist options - */ static void -pidgin_message_style_unset_info_plist (PidginMessageStyle *style) -{ - style->message_view_version = 0; - g_free (style->cf_bundle_name); - style->cf_bundle_name = NULL; - - g_free (style->cf_bundle_identifier); - style->cf_bundle_identifier = NULL; - - g_free (style->cf_bundle_get_info_string); - style->cf_bundle_get_info_string = NULL; - - g_free (style->default_font_family); - style->default_font_family = NULL; - - style->default_font_size = 0; - style->shows_user_icons = TRUE; - style->disable_combine_consecutive = FALSE; - style->default_background_is_transparent = FALSE; - style->disable_custom_background = FALSE; - - g_free (style->default_background_color); - style->default_background_color = NULL; - - style->allow_text_colors = TRUE; - - g_free (style->image_mask); - style->image_mask = NULL; -} - - -static void pidgin_message_style_unref (PidginMessageStyle *style) +glist_free_all_string (GList *list) { - if (!style) return; - g_assert (style->ref_counter > 0); - - style->ref_counter--; - if (style->ref_counter) return; - - g_free (style->style_dir); - g_free (style->template_path); - - g_free (style->template_html); - g_free (style->incoming_content_html); - g_free (style->outgoing_content_html); - g_free (style->outgoing_next_content_html); - g_free (style->status_html); - g_free (style->basestyle_css); - - style_list = g_list_remove (style_list, style); - g_free (style); - - pidgin_message_style_unset_info_plist (style); -} - -static void -pidgin_message_style_save_state (PidginMessageStyle *style) -{ - char *prefname = g_strdup_printf ("/plugins/gtk/adiumthemes/%s", style->cf_bundle_identifier); - char *variant = g_strdup_printf ("%s/%s", prefname, style->variant); - - purple_prefs_add_none (prefname); - purple_prefs_add_string (variant, ""); - purple_prefs_set_string (variant, style->variant); - - g_free (prefname); - g_free (variant); -} - -static void -pidgin_message_style_load_state (PidginMessageStyle *style) -{ - char *prefname = g_strdup_printf ("/plugins/gtk/adiumthemes/%s", style->cf_bundle_identifier); - char *variant = g_strdup_printf ("%s/%s", prefname, style->variant); - - const char* value = purple_prefs_get_string (variant); - gboolean changed = !style->variant || !g_str_equal (style->variant, value); - - g_free (style->variant); - style->variant = g_strdup (value); - - if (changed) pidgin_message_style_read_info_plist (style, style->variant); - - g_free (prefname); - g_free(variant); + GList *first = list; + for (; list; list = g_list_next (list)) + g_free (list->data); + g_list_free (first); } static void webkit_on_webview_destroy (GtkObject* obj, gpointer data); -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, BAD_CAST "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, BAD_CAST "true")) *dest = TRUE; - else if (g_str_equal (val->name, BAD_CAST "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. - */ -static void -pidgin_message_style_read_info_plist (PidginMessageStyle *style, const char* variant) -{ - /* note that if a variant is used the option:VARIANTNAME takes precedence */ - char *contents = g_build_filename (style->style_dir, "Contents", NULL); - xmlnode *plist = xmlnode_from_file (contents, "Info.plist", "Info.plist", "webkit"), *iter; - xmlnode *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, &style->message_view_version, "integer"); - else if (g_str_equal ("CFBundleName", key)) - pr = parse_info_plist_key_value (iter, &style->cf_bundle_name, "string"); - else if (g_str_equal ("CFBundleIdentifier", key)) - pr = parse_info_plist_key_value (iter, &style->cf_bundle_identifier, "string"); - else if (g_str_equal ("CFBundleGetInfoString", key)) - pr = parse_info_plist_key_value (iter, &style->cf_bundle_get_info_string, "string"); - else if (str_for_key ("DefaultFontFamily", key, variant)) - pr = parse_info_plist_key_value (iter, &style->default_font_family, "string"); - else if (str_for_key ("DefaultFontSize", key, variant)) - pr = parse_info_plist_key_value (iter, &style->default_font_size, "integer"); - else if (str_for_key ("ShowsUserIcons", key, variant)) - pr = parse_info_plist_key_value (iter, &style->shows_user_icons, "boolean"); - else if (str_for_key ("DisableCombineConsecutive", key, variant)) - pr = parse_info_plist_key_value (iter, &style->disable_combine_consecutive, "boolean"); - else if (str_for_key ("DefaultBackgroundIsTransparent", key, variant)) - pr = parse_info_plist_key_value (iter, &style->default_background_is_transparent, "boolean"); - else if (str_for_key ("DisableCustomBackground", key, variant)) - pr = parse_info_plist_key_value (iter, &style->disable_custom_background, "boolean"); - else if (str_for_key ("DefaultBackgroundColor", key, variant)) - pr = parse_info_plist_key_value (iter, &style->default_background_color, "string"); - else if (str_for_key ("AllowTextColors", key, variant)) - pr = parse_info_plist_key_value (iter, &style->allow_text_colors, "string"); - else if (str_for_key ("ImageMask", key, variant)) - pr = parse_info_plist_key_value (iter, &style->image_mask, "string"); - - g_free (key); - if (!pr) break; /* does not make sense */ - } - - xmlnode_free (plist); -} - -static PidginMessageStyle* -pidgin_message_style_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. - */ - - /* is this style already loaded? */ - GList *cur = style_list; - char *file; /* temporary variable */ - PidginMessageStyle *style = NULL; - - g_assert (styledir); - for (cur = style_list; cur; cur = g_list_next (cur)) { - style = (PidginMessageStyle*) cur->data; - if (g_str_equal (styledir, style->style_dir)) { - style->ref_counter++; - return style; - } - } - - /* else we need to load it */ - style = pidgin_message_style_new (styledir); - - /* load all other files */ - - /* The template path can either come from the theme, or can - * be stock Template.html that comes with the plugin */ - style->template_path = g_build_filename(styledir, "Contents", "Resources", "Template.html", NULL); - - if (!g_file_test(style->template_path, G_FILE_TEST_EXISTS)) { - g_free (style->template_path); - style->template_path = g_build_filename(DATADIR, "pidgin", "webkit", "Template.html", NULL); - } - - if (!g_file_get_contents(style->template_path, &style->template_html, NULL, NULL)) { - pidgin_message_style_unref (style); - purple_debug_error ("webkit", "Could not locate a Template.html\n"); - return NULL; - } - - file = g_build_filename(styledir, "Contents", "Resources", "Status.html", NULL); - if (!g_file_get_contents(file, &style->status_html, NULL, NULL)) { - purple_debug_info ("webkit", "%s could not find Resources/Status.html", styledir); - pidgin_message_style_unref (style); - g_free (file); - return NULL; - } - g_free (file); - - file = g_build_filename(styledir, "Contents", "Resources", "main.css", NULL); - if (!g_file_get_contents(file, &style->basestyle_css, NULL, NULL)) - style->basestyle_css = g_strdup (""); - g_free (file); - - file = g_build_filename(styledir, "Contents", "Resources", "Header.html", NULL); - if (!g_file_get_contents(file, &style->header_html, NULL, NULL)) - style->header_html = g_strdup (""); - g_free (file); - - file = g_build_filename(styledir, "Contents", "Resources", "Footer.html", NULL); - if (!g_file_get_contents(file, &style->footer_html, NULL, NULL)) - style->footer_html = g_strdup (""); - g_free (file); - - file = g_build_filename(styledir, "Contents", "Resources", "Incoming", "Content.html", NULL); - if (!g_file_get_contents(file, &style->incoming_content_html, NULL, NULL)) { - purple_debug_info ("webkit", "%s did not have a Incoming/Content.html\n", styledir); - pidgin_message_style_unref (style); - g_free (file); - return NULL; - } - g_free (file); - - - /* according to the spec, the following are optional files */ - file = g_build_filename(styledir, "Contents", "Resources", "Incoming", "NextContent.html", NULL); - if (!g_file_get_contents(file, &style->incoming_next_content_html, NULL, NULL)) { - style->incoming_next_content_html = g_strdup (style->incoming_content_html); - } - g_free (file); - - file = g_build_filename(styledir, "Contents", "Resources", "Outgoing", "Content.html", NULL); - if (!g_file_get_contents(file, &style->outgoing_content_html, NULL, NULL)) { - style->outgoing_content_html = g_strdup(style->incoming_content_html); - } - g_free (file); - - file = g_build_filename(styledir, "Contents", "Resources", "Outgoing", "NextContent.html", NULL); - if (!g_file_get_contents(file, &style->outgoing_next_content_html, NULL, NULL)) { - style->outgoing_next_content_html = g_strdup (style->outgoing_content_html); - } - - pidgin_message_style_load_state (style); - pidgin_message_style_read_info_plist (style, style->variant); - - /* non variant dependent Info.plist checks */ - if (style->message_view_version < 3) { - pidgin_message_style_unref (style); - return NULL; - } - - if (!style->variant) - { - GList *variants = pidgin_message_style_get_variants (style); - - if (variants) - pidgin_message_style_set_variant (style, variants->data); - - glist_free_all_string (variants); - pidgin_message_style_save_state (style); - } - - return style; -} - -static void -pidgin_message_style_set_variant (PidginMessageStyle *style, const char *variant) -{ - /* I'm not going to test whether this variant is valid! */ - g_free (style->variant); - style->variant = g_strdup (variant); - - pidgin_message_style_read_info_plist (style, variant); - pidgin_message_style_save_state (style); - - /* todo, the style has "changed". Ideally, I would like to use signals at this point. */ -} - -char* pidgin_message_style_get_variant (PidginMessageStyle *style) -{ - return g_strdup (style->variant); -} - -/** - * Get a list of variants supported by the style. - */ -static GList* -pidgin_message_style_get_variants (PidginMessageStyle *style) -{ - GList *ret = NULL; - GDir *variants; - const char *css_file; - char *css; - char *variant_dir; - - g_assert (style->style_dir); - variant_dir = g_build_filename(style->style_dir, "Contents", "Resources", "Variants", NULL); - - variants = g_dir_open(variant_dir, 0, NULL); - if (!variants) return NULL; - - while ((css_file = g_dir_read_name(variants)) != NULL) { - if (!g_str_has_suffix (css_file, ".css")) - continue; - - css = g_strndup (css_file, strlen (css_file) - 4); - ret = g_list_append(ret, css); - } - - g_dir_close(variants); - g_free(variant_dir); - - ret = g_list_sort (ret, (GCompareFunc)g_strcmp0); - return ret; -} - -static char* pidgin_message_style_get_css (PidginMessageStyle *style) -{ - if (!style->variant) { - return g_build_filename (style->style_dir, "Contents", "Resources", "main.css", NULL); - } else { - char *file = g_strdup_printf ("%s.css", style->variant); - char *ret = g_build_filename (style->style_dir, "Contents", "Resources", "Variants", file, NULL); - g_free (file); - return ret; - } -} - static void* webkit_plugin_get_handle () { if (handle) return handle;