Mercurial > pidgin.yaz
changeset 32766:ea2b621fd3ba
Goodbye Adium themes plugin. I never really liked you anyway.
PS, someone write our default theme for us...
author | Elliott Sales de Andrade <qulogic@pidgin.im> |
---|---|
date | Tue, 18 Oct 2011 04:47:58 +0000 |
parents | 8fb1124b2794 |
children | 2ec94166be43 |
files | configure.ac pidgin/plugins/Makefile.am pidgin/plugins/adiumthemes/Makefile.am pidgin/plugins/adiumthemes/message-style.c pidgin/plugins/adiumthemes/message-style.h pidgin/plugins/adiumthemes/webkit.c |
diffstat | 6 files changed, 2 insertions(+), 1402 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.ac Tue Oct 18 04:17:47 2011 +0000 +++ b/configure.ac Tue Oct 18 04:47:58 2011 +0000 @@ -2496,7 +2496,6 @@ pidgin/pixmaps/emotes/none/Makefile pidgin/pixmaps/emotes/small/16/Makefile pidgin/plugins/Makefile - pidgin/plugins/adiumthemes/Makefile pidgin/plugins/cap/Makefile pidgin/plugins/disco/Makefile pidgin/plugins/gestures/Makefile
--- a/pidgin/plugins/Makefile.am Tue Oct 18 04:17:47 2011 +0000 +++ b/pidgin/plugins/Makefile.am Tue Oct 18 04:47:58 2011 +0000 @@ -1,4 +1,4 @@ -DIST_SUBDIRS = adiumthemes cap disco gestures gevolution musicmessaging perl ticker +DIST_SUBDIRS = cap disco gestures gevolution musicmessaging perl ticker if BUILD_GEVOLUTION GEVOLUTION_DIR = gevolution @@ -27,8 +27,7 @@ $(MUSICMESSAGING_DIR) \ $(PERL_DIR) \ disco \ - ticker \ - adiumthemes + ticker plugindir = $(libdir)/pidgin
--- a/pidgin/plugins/adiumthemes/Makefile.am Tue Oct 18 04:17:47 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ - -adiumtemplatedir = $(datadir)/pidgin/webkit -adiumtemplate_DATA = Template.html - -adiumdir = $(libdir)/pidgin - -adium_la_LDFLAGS = -module -avoid-version - -EXTRA_DIST = $(webkittemplate_DATA) - -if PLUGINS - -adium_LTLIBRARIES = adium.la - -adium_la_SOURCES = webkit.c \ - message-style.h \ - message-style.c - -endif - -adium_la_LIBADD = $(GTK_LIBS) $(WEBKIT_LIBS) - -AM_CPPFLAGS = \ - -DDATADIR=\"$(datadir)\" \ - -I$(top_srcdir)/libpurple \ - -I$(top_builddir)/libpurple \ - -I$(top_srcdir)/pidgin \ - $(DEBUG_CFLAGS) \ - $(GTK_CFLAGS) \ - $(WEBKIT_CFLAGS)
--- a/pidgin/plugins/adiumthemes/message-style.c Tue Oct 18 04:17:47 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,429 +0,0 @@ -/* 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 "message-style.h" - -#include <string.h> - -#include <glib.h> - -#include <debug.h> -#include <util.h> - -static void -glist_free_all_string(GList *list) -{ - for (; list; list = g_list_delete_link(list, list)) - g_free(list->data); -} - -static PidginMessageStyle * -pidgin_message_style_new(const char *styledir) -{ - PidginMessageStyle *ret = g_new0(PidginMessageStyle, 1); - - ret->ref_counter = 1; - ret->style_dir = g_strdup(styledir); - - return ret; -} - -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->cf_bundle_name); - g_free(style->cf_bundle_identifier); - g_free(style->cf_bundle_get_info_string); - g_free(style->default_font_family); - g_free(style->default_background_color); - g_free(style->image_mask); - g_free(style->default_variant); - - 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); - - g_free(style); -} - -void -pidgin_message_style_save_state(const PidginMessageStyle *style) -{ - char *prefname = g_strdup_printf("/plugins/gtk/adiumthemes/%s", style->cf_bundle_identifier); - char *variant = g_strdup_printf("%s/variant", prefname); - - purple_debug_info("webkit", "saving state with variant %s\n", 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/variant", prefname); - - 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, "integer"); - else if (str_for_key("ImageMask", key, variant)) - pr = parse_info_plist_key_value(iter, &style->image_mask, "string"); - - if (!pr) - purple_debug_warning("webkit", "Failed to parse key %s\n", key); - g_free(key); - } - - 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. - */ - char *file; - PidginMessageStyle *style = NULL; - - 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)) { - purple_debug_error("webkit", "Could not locate a Template.html (%s)\n", style->template_path); - pidgin_message_style_unref(style); - 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_read_info_plist(style, NULL); - pidgin_message_style_load_state(style); - - /* non variant dependent Info.plist checks */ - if (style->message_view_version < 3) { - purple_debug_info("webkit", "%s is a legacy style (version %d) and will not be loaded\n", style->cf_bundle_name, style->message_view_version); - 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); - } - - return style; -} - -PidginMessageStyle * -pidgin_message_style_copy(const PidginMessageStyle *style) -{ - PidginMessageStyle *ret = pidgin_message_style_new(style->style_dir); - - ret->variant = g_strdup(style->variant); - ret->message_view_version = style->message_view_version; - ret->cf_bundle_name = g_strdup(style->cf_bundle_name); - ret->cf_bundle_identifier = g_strdup(style->cf_bundle_identifier); - ret->cf_bundle_get_info_string = g_strdup(style->cf_bundle_get_info_string); - ret->default_font_family = g_strdup(style->default_font_family); - ret->default_font_size = style->default_font_size; - ret->shows_user_icons = style->shows_user_icons; - ret->disable_combine_consecutive = style->disable_combine_consecutive; - ret->default_background_is_transparent = style->default_background_is_transparent; - ret->disable_custom_background = style->disable_custom_background; - ret->default_background_color = g_strdup(style->default_background_color); - ret->allow_text_colors = style->allow_text_colors; - ret->image_mask = g_strdup(style->image_mask); - ret->default_variant = g_strdup(style->default_variant); - - ret->template_path = g_strdup(style->template_path); - ret->template_html = g_strdup(style->template_html); - ret->header_html = g_strdup(style->header_html); - ret->footer_html = g_strdup(style->footer_html); - ret->incoming_content_html = g_strdup(style->incoming_content_html); - ret->outgoing_content_html = g_strdup(style->outgoing_content_html); - ret->incoming_next_content_html = g_strdup(style->incoming_next_content_html); - ret->outgoing_next_content_html = g_strdup(style->outgoing_next_content_html); - ret->status_html = g_strdup(style->status_html); - ret->basestyle_css = g_strdup(style->basestyle_css); - return ret; -} - -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); - - /* 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; - } -} -
--- a/pidgin/plugins/adiumthemes/message-style.h Tue Oct 18 04:17:47 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* 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 <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 */ - - /* Info.plist keys that change with Variant */ - - /* Static 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; - char *default_variant; - - /* 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); -PidginMessageStyle *pidgin_message_style_copy(const PidginMessageStyle *style); -void pidgin_message_style_save_state(const PidginMessageStyle *style); -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 Tue Oct 18 04:17:47 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,858 +0,0 @@ -/* 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 - * - */ - -#define PLUGIN_ID "gtk-webview-adium-ims" -#define PLUGIN_NAME "webview-adium-ims" - -/* - * A lot of this was originally written by Sean Egan, but I think I've - * rewrote enough to replace the author for now. - */ -#define PLUGIN_AUTHOR "Arnold Noronha <arnstein87@gmail.com>" -#define PURPLE_PLUGINS "Hell yeah" - -/* System headers */ -#include <string.h> -#include <gdk/gdk.h> -#include <gtk/gtk.h> - -#include <webkit/webkit.h> - -/* Purple headers */ -#include <conversation.h> -#include <debug.h> -#include <internal.h> -#include <notify.h> -#include <util.h> -#include <version.h> - -/* Pidgin headers */ -#include <gtkconv.h> -#include <gtkplugin.h> -#include <gtkwebview.h> -#include <smileyparser.h> - -#include <libxml/xmlreader.h> - -#include "message-style.h" -/* GObject data keys */ -#define MESSAGE_STYLE_KEY "message-style" - -static char *cur_style_dir = NULL; -static void *handle = NULL; - -static inline char * -get_absolute_path(const char *path) -{ - if (g_path_is_absolute(path)) - return g_strdup(path); - else { - char *cwd, *ret; - cwd = g_get_current_dir(); - ret = g_build_filename(cwd, path, NULL); - g_free(cwd); - return ret; - } -} - -static void webkit_on_webview_destroy(GtkObject* obj, gpointer data); - -static void * -webkit_plugin_get_handle(void) -{ - if (handle) - return handle; - else - return (handle = g_malloc(1)); -} - -static void -webkit_plugin_free_handle(void) -{ - purple_signals_disconnect_by_handle(handle); - g_free(handle); -} - -static char * -replace_message_tokens( - const char *text, - PurpleConversation *conv, - const char *name, - const char *alias, - const char *message, - PurpleMessageFlags flags, - time_t mtime) -{ - PurpleAccount *account = purple_conversation_get_account(conv); - GString *str = g_string_new(NULL); - const char *cur = text; - const char *prev = cur; - - while ((cur = strchr(cur, '%'))) { - const char *replace = NULL; - char *fin = NULL; - - if (!strncmp(cur, "%message%", strlen("%message%"))) { - replace = message; - } else if (!strncmp(cur, "%messageClasses%", strlen("%messageClasses%"))) { - replace = flags & PURPLE_MESSAGE_SEND ? "outgoing" : - flags & PURPLE_MESSAGE_RECV ? "incoming" : "event"; - } else if (!strncmp(cur, "%time", strlen("%time"))) { - char *format = NULL; - if (*(cur + strlen("%time")) == '{') { - const char *start = cur + strlen("%time") + 1; - char *end = strstr(start, "}%"); - if (!end) /* Invalid string */ - continue; - format = g_strndup(start, end - start); - fin = end + 1; - } - replace = purple_utf8_strftime(format ? format : "%X", NULL); - g_free(format); - } else if (!strncmp(cur, "%userIconPath%", strlen("%userIconPath%"))) { - if (flags & PURPLE_MESSAGE_SEND) { - if (purple_account_get_bool(account, "use-global-buddyicon", TRUE)) { - replace = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon"); - } else { - PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account); - replace = purple_imgstore_get_filename(img); - } - if (replace == NULL || !g_file_test(replace, G_FILE_TEST_EXISTS)) { - replace = g_build_filename("Outgoing", "buddy_icon.png", NULL); - } - } else if (flags & PURPLE_MESSAGE_RECV) { - PurpleBuddyIcon *icon = purple_conv_im_get_icon(PURPLE_CONV_IM(conv)); - replace = purple_buddy_icon_get_full_path(icon); - if (replace == NULL || !g_file_test(replace, G_FILE_TEST_EXISTS)) { - replace = g_build_filename("Incoming", "buddy_icon.png", NULL); - } - } - - } else if (!strncmp(cur, "%senderScreenName%", strlen("%senderScreenName%"))) { - replace = name; - } else if (!strncmp(cur, "%sender%", strlen("%sender%"))) { - replace = alias; - } else if (!strncmp(cur, "%service%", strlen("%service%"))) { - replace = purple_account_get_protocol_name(account); - } else { - cur++; - continue; - } - - /* Here we have a replacement to make */ - g_string_append_len(str, prev, cur - prev); - g_string_append(str, replace); - - /* And update the pointers */ - if (fin) { - prev = cur = fin + 1; - } else { - prev = cur = strchr(cur + 1, '%') + 1; - } - - } - - /* And wrap it up */ - g_string_append(str, prev); - return g_string_free(str, FALSE); -} - -static char * -replace_header_tokens(char *text, PurpleConversation *conv) -{ - PurpleAccount *account = purple_conversation_get_account(conv); - GString *str = g_string_new(NULL); - char *cur = text; - char *prev = cur; - - if (text == NULL) - return NULL; - - while ((cur = strchr(cur, '%'))) { - const char *replace = NULL; - char *fin = NULL; - - if (!strncmp(cur, "%chatName%", strlen("%chatName%"))) { - replace = purple_conversation_get_name(conv); - } else if (!strncmp(cur, "%sourceName%", strlen("%sourceName%"))) { - replace = purple_account_get_alias(account); - if (replace == NULL) - replace = purple_account_get_username(account); - } else if (!strncmp(cur, "%destinationName%", strlen("%destinationName%"))) { - PurpleBuddy *buddy = purple_find_buddy(account, purple_conversation_get_name(conv)); - if (buddy) { - replace = purple_buddy_get_alias(buddy); - } else { - replace = purple_conversation_get_name(conv); - } - } else if (!strncmp(cur, "%incomingIconPath%", strlen("%incomingIconPath%"))) { - PurpleBuddyIcon *icon = purple_conv_im_get_icon(PURPLE_CONV_IM(conv)); - replace = purple_buddy_icon_get_full_path(icon); - } else if (!strncmp(cur, "%outgoingIconPath%", strlen("%outgoingIconPath%"))) { - } else if (!strncmp(cur, "%timeOpened", strlen("%timeOpened"))) { - char *format = NULL; - if (*(cur + strlen("%timeOpened")) == '{') { - char *start = cur + strlen("%timeOpened") + 1; - char *end = strstr(start, "}%"); - if (!end) /* Invalid string */ - continue; - format = g_strndup(start, end - start); - fin = end + 1; - } - replace = purple_utf8_strftime(format ? format : "%X", NULL); - g_free(format); - } else { - continue; - } - - /* Here we have a replacement to make */ - g_string_append_len(str, prev, cur - prev); - g_string_append(str, replace); - - /* And update the pointers */ - if (fin) { - prev = cur = fin + 1; - } else { - prev = cur = strchr(cur + 1, '%') + 1; - } - } - - /* And wrap it up */ - g_string_append(str, prev); - return g_string_free(str, FALSE); -} - -static char * -replace_template_tokens(PidginMessageStyle *style, char *text, char *header, char *footer) -{ - GString *str = g_string_new(NULL); - - char **ms = g_strsplit(text, "%@", 6); - char *base = NULL; - char *csspath = pidgin_message_style_get_css(style); - if (ms[0] == NULL || ms[1] == NULL || ms[2] == NULL || ms[3] == NULL || ms[4] == NULL || ms[5] == NULL) { - g_strfreev(ms); - g_string_free(str, TRUE); - return NULL; - } - - g_string_append(str, ms[0]); - g_string_append(str, "file://"); - base = g_build_filename(style->style_dir, "Contents", "Resources", "Template.html", NULL); - g_string_append(str, base); - g_free(base); - - g_string_append(str, ms[1]); - - g_string_append(str, style->basestyle_css); - - g_string_append(str, ms[2]); - - g_string_append(str, "file://"); - g_string_append(str, csspath); - - g_string_append(str, ms[3]); - if (header) - g_string_append(str, header); - g_string_append(str, ms[4]); - if (footer) - g_string_append(str, footer); - g_string_append(str, ms[5]); - - g_strfreev(ms); - g_free(csspath); - return g_string_free(str, FALSE); -} - -static GtkWidget * -get_webkit(PurpleConversation *conv) -{ - PidginConversation *gtkconv; - gtkconv = PIDGIN_CONVERSATION(conv); - if (!gtkconv) - return NULL; - else - return gtkconv->webview; -} - -static void -set_theme_webkit_settings(WebKitWebView *webview, PidginMessageStyle *style) -{ - WebKitWebSettings *settings; - - g_object_get(G_OBJECT(webview), "settings", &settings, NULL); - if (style->default_font_family) - g_object_set(G_OBJECT(settings), "default-font-family", style->default_font_family, NULL); - - if (style->default_font_size) - g_object_set(G_OBJECT(settings), "default-font-size", GINT_TO_POINTER(style->default_font_size), NULL); - - /* this does not work :( */ - webkit_web_view_set_transparent(webview, style->default_background_is_transparent); -} - -/* - * The style specification says that if the conversation is a group - * chat then the <div id="Chat"> element will be given a class - * 'groupchat'. I can't add another '%@' in Template.html because - * that breaks style-specific Template.html's. I have to either use libxml - * or conveniently play with WebKit's javascript engine. The javascript - * engine should work, but it's not an identical behavior. - */ -static void -webkit_set_groupchat(GtkWebView *webview) -{ - gtk_webview_safe_execute_script(webview, "document.getElementById('Chat').className = 'groupchat'"); -} - - -/** - * Called when either a new PurpleConversation is created - * or when a PidginConversation changes its active PurpleConversation - * This will not change the theme if the theme is already set. - * (This is to prevent accidental theme changes if a new - * PurpleConversation gets added. - * - * FIXME: it's not at all clear to me as to how - * Adium themes handle the case when the PurpleConversation - * changes. - */ -static void -init_theme_for_webkit(PurpleConversation *conv, char *style_dir) -{ - GtkWidget *webkit = PIDGIN_CONVERSATION(conv)->webview; - char *header, *footer; - char *template; - - char* basedir; - char* baseuri; - PidginMessageStyle *style, *oldStyle; - PidginMessageStyle *copy; - - oldStyle = g_object_get_data(G_OBJECT(webkit), MESSAGE_STYLE_KEY); - if (oldStyle) - return; - - purple_debug_info("webkit", "loading %s\n", style_dir); - style = pidgin_message_style_load(style_dir); - g_assert(style); - g_assert(style->template_html); /* debugging test? */ - - basedir = g_build_filename(style->style_dir, "Contents", "Resources", "Template.html", NULL); - baseuri = g_strdup_printf("file://%s", basedir); - header = replace_header_tokens(style->header_html, conv); - g_assert(style); - footer = replace_header_tokens(style->footer_html, conv); - template = replace_template_tokens(style, style->template_html, header, footer); - - g_assert(template); - - purple_debug_info("webkit", "template: %s\n", template); - - set_theme_webkit_settings(WEBKIT_WEB_VIEW(webkit), style); - webkit_web_view_load_string(WEBKIT_WEB_VIEW(webkit), template, "text/html", "UTF-8", baseuri); - - copy = pidgin_message_style_copy(style); - g_object_set_data(G_OBJECT(webkit), MESSAGE_STYLE_KEY, copy); - - pidgin_message_style_unref(style); - /* I need to unref this style when the webkit object destroys */ - g_signal_connect(G_OBJECT(webkit), "destroy", G_CALLBACK(webkit_on_webview_destroy), copy); - - if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) - webkit_set_groupchat(GTK_WEBVIEW(webkit)); - g_free(basedir); - g_free(baseuri); - g_free(header); - g_free(footer); - g_free(template); -} - - -/* restore the non theme version of the conversation window */ -static void -finalize_theme_for_webkit(PurpleConversation *conv) -{ - GtkWidget *webview = PIDGIN_CONVERSATION(conv)->webview; - PidginMessageStyle *style = g_object_get_data(G_OBJECT(webview), MESSAGE_STYLE_KEY); - - webkit_web_view_load_string(WEBKIT_WEB_VIEW(webview), "", "text/html", "UTF-8", ""); - - g_object_set_data(G_OBJECT(webview), MESSAGE_STYLE_KEY, NULL); - pidgin_message_style_unref(style); -} - -static void -webkit_on_webview_destroy(GtkObject *object, gpointer data) -{ - pidgin_message_style_unref((PidginMessageStyle *)data); - g_object_set_data(G_OBJECT(object), MESSAGE_STYLE_KEY, NULL); -} - -static gboolean -webkit_on_displaying_im_msg(PurpleAccount *account, - const char* name, - char **pmessage, - PurpleConversation *conv, - PurpleMessageFlags flags, - gpointer data) -{ - GtkWidget *webkit; - char *message = *pmessage; - const char *alias = name; /* FIXME: signal doesn't give me alias */ - char *stripped; - char *message_html; - char *msg; - char *escape; - char *script; - char *func = "appendMessage"; - char *smileyed; - time_t mtime = time(NULL); /* FIXME: this should come from the write_conv calback, but the signal doesn't pass this to me */ - - PurpleMessageFlags old_flags = GPOINTER_TO_INT(purple_conversation_get_data(conv, "webkit-lastflags")); - PidginMessageStyle *style; - - webkit = get_webkit(conv); - stripped = g_strdup(message); - - style = g_object_get_data(G_OBJECT(webkit), MESSAGE_STYLE_KEY); - g_assert(style); - - if (flags & PURPLE_MESSAGE_SEND && old_flags & PURPLE_MESSAGE_SEND) { - message_html = style->outgoing_next_content_html; - func = "appendNextMessage"; - } else if (flags & PURPLE_MESSAGE_SEND) { - message_html = style->outgoing_content_html; - } else if (flags & PURPLE_MESSAGE_RECV && old_flags & PURPLE_MESSAGE_RECV) { - message_html = style->incoming_next_content_html; - func = "appendNextMessage"; - } else if (flags & PURPLE_MESSAGE_RECV) { - message_html = style->incoming_content_html; - } else { - message_html = style->status_html; - } - purple_conversation_set_data(conv, "webkit-lastflags", GINT_TO_POINTER(flags)); - - smileyed = smiley_parse_markup(stripped, purple_account_get_protocol_id(purple_conversation_get_account(conv))); - msg = replace_message_tokens(message_html, conv, name, alias, smileyed, flags, mtime); - escape = gtk_webview_quote_js_string(msg); - script = g_strdup_printf("%s(%s)", func, escape); - - purple_debug_info("webkit", "JS: %s\n", script); - gtk_webview_safe_execute_script(GTK_WEBVIEW(webkit), script); - - g_free(script); - g_free(smileyed); - g_free(msg); - g_free(stripped); - g_free(escape); - - return TRUE; /* GtkConv should not handle this IM */ -} - -static gboolean -webkit_on_displaying_chat_msg(PurpleAccount *account, - const char *who, - char **message, - PurpleConversation *conv, - PurpleMessageFlags flags, - gpointer userdata) -{ - /* handle exactly like an IM message for now */ - return webkit_on_displaying_im_msg(account, who, message, conv, flags, NULL); -} - -static void -webkit_on_conversation_displayed(PidginConversation *gtkconv, gpointer data) -{ - init_theme_for_webkit(gtkconv->active_conv, cur_style_dir); -} - -static void -webkit_on_conversation_switched(PurpleConversation *conv, gpointer data) -{ - init_theme_for_webkit(conv, cur_style_dir); -} - -static void -webkit_on_conversation_hiding(PidginConversation *gtkconv, gpointer data) -{ - /* - * I'm not sure if I need to do anything here, but let's keep - * this anyway. - */ -} - -static GList * -get_dir_dir_list(const char *dirname) -{ - GList *ret = NULL; - GDir *dir = g_dir_open(dirname, 0, NULL); - const char* subdir; - - if (!dir) return NULL; - while ((subdir = g_dir_read_name(dir))) { - ret = g_list_append(ret, g_build_filename(dirname, subdir, NULL)); - } - - g_dir_close(dir); - return ret; -} - -/** - * Get me a list of all the available themes specified by their - * directories. I don't guarrantee that these are valid themes, just - * that they are in the directories for themes. - */ -static GList * -get_style_directory_list(void) -{ - char *user_dir, *user_style_dir, *global_style_dir; - GList *list1, *list2; - - user_dir = get_absolute_path(purple_user_dir()); - - user_style_dir = g_build_filename(user_dir, "styles", NULL); - global_style_dir = g_build_filename(DATADIR, "pidgin", "styles", NULL); - - list1 = get_dir_dir_list(user_style_dir); - list2 = get_dir_dir_list(global_style_dir); - - g_free(global_style_dir); - g_free(user_style_dir); - g_free(user_dir); - - return g_list_concat(list1, list2); -} - -/** - * use heuristics or previous user options to figure out what - * theme to use as default in this Pidgin instance. - */ -static void -style_set_default(void) -{ - GList *styles = get_style_directory_list(), *iter; - const char *stylepath = purple_prefs_get_string("/plugins/gtk/adiumthemes/stylepath"); - g_assert(cur_style_dir == NULL); - - if (stylepath && *stylepath) - styles = g_list_prepend(styles, g_strdup(stylepath)); - - /* pick any one that works. Note that we have first preference - * for the one in the userdir */ - for (iter = styles; iter; iter = g_list_next(iter)) { - PidginMessageStyle *style = pidgin_message_style_load(iter->data); - if (style) { - cur_style_dir = (char *)g_strdup(iter->data); - pidgin_message_style_unref(style); - break; - } - purple_debug_info("webkit", "Style %s is invalid\n", (char *)iter->data); - } - - for (iter = styles; iter; iter = g_list_next(iter)) - g_free(iter->data); - g_list_free(styles); -} - -static gboolean -plugin_load(PurplePlugin *plugin) -{ - style_set_default(); - if (!cur_style_dir) - return FALSE; /* couldn't find a style */ - - purple_signal_connect(pidgin_conversations_get_handle(), - "displaying-im-msg", - webkit_plugin_get_handle(), - PURPLE_CALLBACK(webkit_on_displaying_im_msg), - NULL); - - purple_signal_connect(pidgin_conversations_get_handle(), - "displaying-chat-msg", - webkit_plugin_get_handle(), - PURPLE_CALLBACK(webkit_on_displaying_chat_msg), - NULL); - - purple_signal_connect(pidgin_conversations_get_handle(), - "conversation-displayed", - webkit_plugin_get_handle(), - PURPLE_CALLBACK(webkit_on_conversation_displayed), - NULL); - - purple_signal_connect(pidgin_conversations_get_handle(), - "conversation-switched", - webkit_plugin_get_handle(), - PURPLE_CALLBACK(webkit_on_conversation_switched), - NULL); - - purple_signal_connect(pidgin_conversations_get_handle(), - "conversation-hiding", - webkit_plugin_get_handle(), - PURPLE_CALLBACK(webkit_on_conversation_hiding), - NULL); - - /* finally update each of the existing conversation windows */ - { - GList *list = purple_get_conversations(); - for (;list; list = g_list_next(list)) - init_theme_for_webkit(list->data, cur_style_dir); - - } - return TRUE; -} - -static gboolean -plugin_unload(PurplePlugin *plugin) -{ - GList *list; - - webkit_plugin_free_handle(); - cur_style_dir = NULL; - list = purple_get_conversations(); - while (list) { - finalize_theme_for_webkit(list->data); - list = g_list_next(list); - } - - return TRUE; -} - -/* - * UI config code - */ - -static void -style_changed(GtkWidget *combobox, gpointer null) -{ - char *name = gtk_combo_box_get_active_text(GTK_COMBO_BOX(combobox)); - GtkWidget *dialog; - GList *styles = get_style_directory_list(), *iter; - - /* find the full path for this name, I wish I could store this info in the combobox itself. :( */ - for (iter = styles; iter; iter = g_list_next(iter)) { - char *basename = g_path_get_basename(iter->data); - if (g_str_equal(basename, name)) { - g_free(basename); - break; - } - g_free(basename); - } - - g_assert(iter); - g_free(name); - g_free(cur_style_dir); - cur_style_dir = g_strdup(iter->data);; - purple_prefs_set_string("/plugins/gtk/adiumthemes/stylepath", cur_style_dir); - - /* inform the user that existing conversations haven't changed */ - dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "The style for existing conversations have not been changed. Please close and re-open the conversation for the changes to take effect."); - g_assert(dialog); - gtk_widget_show(dialog); - g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); -} - -static GtkWidget * -get_style_config_frame(void) -{ - GtkWidget *combobox = gtk_combo_box_new_text(); - GList *styles = get_style_directory_list(), *iter; - int index = 0, selected = 0; - - for (iter = styles; iter; iter = g_list_next(iter)) { - PidginMessageStyle *style = pidgin_message_style_load(iter->data); - - if (style) { - char *text = g_path_get_basename(iter->data); - gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), text); - g_free(text); - - if (g_str_equal(iter->data, cur_style_dir)) - selected = index; - index++; - pidgin_message_style_unref(style); - } - } - gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), selected); - g_signal_connect_after(G_OBJECT(combobox), "changed", G_CALLBACK(style_changed), NULL); - return combobox; -} - -static void -variant_update_conversation(PurpleConversation *conv) -{ - PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); - WebKitWebView *webview = WEBKIT_WEB_VIEW(gtkconv->webview); - PidginMessageStyle *style = (PidginMessageStyle *)g_object_get_data(G_OBJECT(webview), MESSAGE_STYLE_KEY); - char *script; - - g_assert(style); - - script = g_strdup_printf("setStylesheet(\"mainStyle\",\"%s\")", pidgin_message_style_get_css(style)); - gtk_webview_safe_execute_script(GTK_WEBVIEW(webview), script); - - set_theme_webkit_settings(WEBKIT_WEB_VIEW(gtkconv->webview), style); - g_free(script); -} - -static void -variant_changed(GtkWidget* combobox, gpointer null) -{ - char *name; - GList *list; - PidginMessageStyle *style = pidgin_message_style_load(cur_style_dir); - - g_assert(style); - name = gtk_combo_box_get_active_text(GTK_COMBO_BOX(combobox)); - pidgin_message_style_set_variant(style, name); - pidgin_message_style_save_state(style); - - /* update conversations */ - list = purple_get_conversations(); - while (list) { - variant_update_conversation(list->data); - list = g_list_next(list); - } - - g_free(name); - pidgin_message_style_unref(style); -} - -static GtkWidget * -get_variant_config_frame() -{ - PidginMessageStyle *style = pidgin_message_style_load(cur_style_dir); - GList *variants = pidgin_message_style_get_variants(style), *iter; - char *cur_variant = pidgin_message_style_get_variant(style); - GtkWidget *combobox = gtk_combo_box_new_text(); - int def = -1, index = 0; - - pidgin_message_style_unref(style); - - for (iter = variants; iter; iter = g_list_next(iter)) { - gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), iter->data); - - if (g_str_equal(cur_variant, iter->data)) - def = index; - index ++; - - } - - gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), def); - g_signal_connect(G_OBJECT(combobox), "changed", G_CALLBACK(variant_changed), NULL); - - return combobox; -} - -static void -style_changed_reset_variants(GtkWidget* combobox, gpointer table) -{ - /* I hate to do this, I swear. But I don't know how to cleanly clean an existing combobox */ - GtkWidget* variants = g_object_get_data(G_OBJECT(table), "variants-cbox"); - gtk_widget_destroy(variants); - variants = get_variant_config_frame(); - gtk_table_attach_defaults(GTK_TABLE(table), variants, 1, 2, 1, 2); - gtk_widget_show_all(GTK_WIDGET(table)); - - g_object_set_data(G_OBJECT(table), "variants-cbox", variants); -} - -static GtkWidget* -get_config_frame(PurplePlugin* plugin) -{ - GtkWidget *table = gtk_table_new(2, 2, FALSE); - GtkWidget *style_config = get_style_config_frame(); - GtkWidget *variant_config = get_variant_config_frame(); - - gtk_table_attach_defaults(GTK_TABLE(table), gtk_label_new("Message Style"), 0, 1, 0, 1); - gtk_table_attach_defaults(GTK_TABLE(table), style_config, 1, 2, 0, 1); - gtk_table_attach_defaults(GTK_TABLE(table), gtk_label_new("Style Variant"), 0, 1, 1, 2); - gtk_table_attach_defaults(GTK_TABLE(table), variant_config, 1, 2, 1, 2); - - g_object_set_data(G_OBJECT(table), "variants-cbox", variant_config); - /* to clarify, this is a second signal connected on style config */ - g_signal_connect_after(G_OBJECT(style_config), "changed", G_CALLBACK(style_changed_reset_variants), table); - - return table; -} - -PidginPluginUiInfo ui_info = -{ - get_config_frame, - 0, /* page_num (Reserved) */ - - /* padding */ - NULL, - NULL, - NULL, - NULL -}; - - -static PurplePluginInfo info = -{ - PURPLE_PLUGIN_MAGIC, /* Magic */ - PURPLE_MAJOR_VERSION, /* Purple Major Version */ - PURPLE_MINOR_VERSION, /* Purple Minor Version */ - PURPLE_PLUGIN_STANDARD, /* plugin type */ - PIDGIN_PLUGIN_TYPE, /* ui requirement */ - 0, /* flags */ - NULL, /* dependencies */ - PURPLE_PRIORITY_DEFAULT, /* priority */ - - PLUGIN_ID, /* plugin id */ - NULL, /* name */ - "0.1", /* version */ - NULL, /* summary */ - NULL, /* description */ - PLUGIN_AUTHOR, /* author */ - "http://pidgin.im", /* website */ - - plugin_load, /* load */ - plugin_unload, /* unload */ - NULL, /* destroy */ - - &ui_info, /* ui_info */ - NULL, /* extra_info */ - NULL, /* prefs_info */ - NULL, /* actions */ - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - NULL, /* reserved 3 */ - NULL /* reserved 4 */ -}; - -static void -init_plugin(PurplePlugin *plugin) { - info.name = "Adium IMs"; - info.summary = "Adium-like IMs with Pidgin"; - info.description = "You can chat in Pidgin using Adium's WebKit view."; - - purple_prefs_add_none("/plugins"); - purple_prefs_add_none("/plugins/gtk"); - purple_prefs_add_none("/plugins/gtk/adiumthemes"); - purple_prefs_add_string("/plugins/gtk/adiumthemes/stylepath", ""); -} - -PURPLE_INIT_PLUGIN(webkit, init_plugin, info) -