diff options
Diffstat (limited to 'libempathy-gtk/empathy-theme-adium.c')
-rw-r--r-- | libempathy-gtk/empathy-theme-adium.c | 659 |
1 files changed, 401 insertions, 258 deletions
diff --git a/libempathy-gtk/empathy-theme-adium.c b/libempathy-gtk/empathy-theme-adium.c index 2ab3383b3..06410c528 100644 --- a/libempathy-gtk/empathy-theme-adium.c +++ b/libempathy-gtk/empathy-theme-adium.c @@ -22,7 +22,7 @@ #include "config.h" #include <string.h> -#include <glib/gi18n.h> +#include <glib/gi18n-lib.h> #include <webkit/webkit.h> #include <telepathy-glib/dbus.h> @@ -59,11 +59,13 @@ typedef struct { gint64 last_timestamp; gboolean last_is_backlog; guint pages_loading; - GList *message_queue; + /* Queue of GValue* containing an EmpathyMessage or string */ + GQueue message_queue; GtkWidget *inspector_window; GSettings *gsettings_chat; gboolean has_focus; gboolean has_unread_message; + gboolean allow_scrolling; } EmpathyThemeAdiumPriv; struct _EmpathyAdiumData { @@ -73,26 +75,27 @@ struct _EmpathyAdiumData { gchar *default_avatar_filename; gchar *default_incoming_avatar_filename; gchar *default_outgoing_avatar_filename; - gchar *template_html; - gchar *in_content_html; - gsize in_content_len; - gchar *in_context_html; - gsize in_context_len; - gchar *in_nextcontent_html; - gsize in_nextcontent_len; - gchar *in_nextcontext_html; - gsize in_nextcontext_len; - gchar *out_content_html; - gsize out_content_len; - gchar *out_context_html; - gsize out_context_len; - gchar *out_nextcontent_html; - gsize out_nextcontent_len; - gchar *out_nextcontext_html; - gsize out_nextcontext_len; - gchar *status_html; - gsize status_len; GHashTable *info; + guint version; + gboolean custom_template; + + /* HTML bits */ + const gchar *template_html; + const gchar *content_html; + const gchar *in_content_html; + const gchar *in_context_html; + const gchar *in_nextcontent_html; + const gchar *in_nextcontext_html; + const gchar *out_content_html; + const gchar *out_context_html; + const gchar *out_nextcontent_html; + const gchar *out_nextcontext_html; + const gchar *status_html; + + /* Above html strings are pointers to strings stored in this array. + * We do this because of fallbacks, some htmls could be pointing the + * same string. */ + GPtrArray *strings_to_free; }; static void theme_adium_iface_init (EmpathyChatViewIface *iface); @@ -191,6 +194,36 @@ theme_adium_open_address_cb (GtkMenuItem *menuitem, g_free (uri); } +/* Replace each %@ in format with string passed in args */ +static gchar * +string_with_format (const gchar *format, + const gchar *first_string, + ...) +{ + va_list args; + const gchar *str; + GString *result; + + va_start (args, first_string); + result = g_string_sized_new (strlen (format)); + for (str = first_string; str != NULL; str = va_arg (args, const gchar *)) { + const gchar *next; + + next = strstr (format, "%@"); + if (next == NULL) { + break; + } + + g_string_append_len (result, format, next - format); + g_string_append (result, str); + format = next + 2; + } + g_string_append (result, format); + va_end (args); + + return g_string_free (result, FALSE); +} + static void theme_adium_match_newline (const gchar *text, gssize len, @@ -283,7 +316,7 @@ theme_adium_parse_body (EmpathyThemeAdium *self, static void escape_and_append_len (GString *string, const gchar *str, gint len) { - while (*str != '\0' && len != 0) { + while (str != NULL && *str != '\0' && len != 0) { switch (*str) { case '\\': /* \ becomes \\ */ @@ -345,10 +378,36 @@ theme_adium_match_with_format (const gchar **str, return TRUE; } +/* List of colors used by %senderColor%. Copied from + * adium/Frameworks/AIUtilities\ Framework/Source/AIColorAdditions.m + */ +static gchar *colors[] = { + "aqua", "aquamarine", "blue", "blueviolet", "brown", "burlywood", "cadetblue", + "chartreuse", "chocolate", "coral", "cornflowerblue", "crimson", "cyan", + "darkblue", "darkcyan", "darkgoldenrod", "darkgreen", "darkgrey", "darkkhaki", + "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", + "darksalmon", "darkseagreen", "darkslateblue", "darkslategrey", + "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgrey", + "dodgerblue", "firebrick", "forestgreen", "fuchsia", "gold", "goldenrod", + "green", "greenyellow", "grey", "hotpink", "indianred", "indigo", "lawngreen", + "lightblue", "lightcoral", + "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", + "lightskyblue", "lightslategrey", "lightsteelblue", "lime", "limegreen", + "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", + "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", + "mediumturquoise", "mediumvioletred", "midnightblue", "navy", "olive", + "olivedrab", "orange", "orangered", "orchid", "palegreen", "paleturquoise", + "palevioletred", "peru", "pink", "plum", "powderblue", "purple", "red", + "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", + "sienna", "silver", "skyblue", "slateblue", "slategrey", "springgreen", + "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", + "yellowgreen", +}; + static void theme_adium_append_html (EmpathyThemeAdium *theme, const gchar *func, - const gchar *html, gsize len, + const gchar *html, const gchar *message, const gchar *avatar_filename, const gchar *name, @@ -363,10 +422,10 @@ theme_adium_append_html (EmpathyThemeAdium *theme, gchar *script; /* Make some search-and-replace in the html code */ - string = g_string_sized_new (len + strlen (message)); + string = g_string_sized_new (strlen (html) + strlen (message)); g_string_append_printf (string, "%s(\"", func); for (cur = html; *cur != '\0'; cur++) { - const gchar *replace = ""; + const gchar *replace = NULL; gchar *dup_replace = NULL; gchar *format = NULL; @@ -380,11 +439,15 @@ theme_adium_append_html (EmpathyThemeAdium *theme, } else if (theme_adium_match (&cur, "%sender%")) { replace = name; } else if (theme_adium_match (&cur, "%senderColor%")) { - /* FIXME: A color derived from the user's name. If a - * colon separated list of HTML colors is at + /* A color derived from the user's name. + * FIXME: If a colon separated list of HTML colors is at * Incoming/SenderColors.txt it will be used instead of * the default colors. */ + if (contact_id != NULL) { + guint hash = g_str_hash (contact_id); + replace = colors[hash % G_N_ELEMENTS (colors)]; + } } else if (theme_adium_match (&cur, "%senderStatusIcon%")) { /* FIXME: The path to the status icon of the sender * (available, away, etc...) @@ -493,13 +556,10 @@ theme_adium_append_event_escaped (EmpathyChatView *view, EmpathyThemeAdium *theme = EMPATHY_THEME_ADIUM (view); EmpathyThemeAdiumPriv *priv = GET_PRIV (theme); - if (priv->data->status_html) { - theme_adium_append_html (theme, "appendMessage", - priv->data->status_html, - priv->data->status_len, - escaped, NULL, NULL, NULL, NULL, - "event", empathy_time_get_current (), FALSE); - } + theme_adium_append_html (theme, "appendMessage", + priv->data->status_html, escaped, NULL, NULL, NULL, + NULL, "event", + empathy_time_get_current (), FALSE); /* There is no last contact */ if (priv->last_contact) { @@ -511,11 +571,17 @@ theme_adium_append_event_escaped (EmpathyChatView *view, static void theme_adium_remove_focus_marks (EmpathyThemeAdium *theme) { + EmpathyThemeAdiumPriv *priv = GET_PRIV (theme); WebKitDOMDocument *dom; WebKitDOMNodeList *nodes; guint i; GError *error = NULL; + if (!priv->has_unread_message) + return; + + priv->has_unread_message = FALSE; + dom = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (theme)); if (dom == NULL) { return; @@ -580,17 +646,18 @@ theme_adium_append_message (EmpathyChatView *view, EmpathyAvatar *avatar; const gchar *avatar_filename = NULL; gint64 timestamp; - gchar *html = NULL; - gsize len = 0; + const gchar *html = NULL; const gchar *func; const gchar *service_name; GString *message_classes = NULL; gboolean is_backlog; gboolean consecutive; + gboolean action; if (priv->pages_loading != 0) { - priv->message_queue = g_list_prepend (priv->message_queue, - g_object_ref (msg)); + GValue *value = tp_g_value_slice_new (EMPATHY_TYPE_MESSAGE); + g_value_set_object (value, msg); + g_queue_push_tail (&priv->message_queue, value); return; } @@ -606,17 +673,21 @@ theme_adium_append_message (EmpathyChatView *view, body_escaped = theme_adium_parse_body (theme, body); name = empathy_contact_get_alias (sender); contact_id = empathy_contact_get_id (sender); + action = (empathy_message_get_tptype (msg) == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION); - /* If this is a /me, append an event */ - if (empathy_message_get_tptype (msg) == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION) { + /* If this is a /me probably */ + if (action) { gchar *str; - str = g_strdup_printf ("%s %s", name, body_escaped); - theme_adium_append_event_escaped (view, str); - - g_free (str); + if (priv->data->version >= 4 || !priv->data->custom_template) { + str = g_strdup_printf ("<span class='actionMessageUserName'>%s</span>" + "<span class='actionMessageBody'>%s</span>", + name, body_escaped); + } else { + str = g_strdup_printf ("*%s*", body_escaped); + } g_free (body_escaped); - return; + body_escaped = str; } /* Get the avatar filename, or a fallback */ @@ -656,10 +727,6 @@ theme_adium_append_message (EmpathyChatView *view, message_classes = g_string_new ("message"); if (!priv->has_focus && !is_backlog) { if (!priv->has_unread_message) { - /* This is the first message we receive since we lost - * focus; remove previous unread marks. */ - theme_adium_remove_focus_marks (theme); - g_string_append (message_classes, " firstFocus"); priv->has_unread_message = TRUE; } @@ -676,95 +743,56 @@ theme_adium_append_message (EmpathyChatView *view, } else { g_string_append (message_classes, " incoming"); } + if (empathy_message_should_highlight (msg)) { + g_string_append (message_classes, " mention"); + } + if (empathy_message_get_tptype (msg) == TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY) { + g_string_append (message_classes, " autoreply"); + } + if (action) { + g_string_append (message_classes, " action"); + } /* FIXME: other classes: - * autoreply - the message is an automatic response, generally due to an - * away status - * mention - the incoming message (in groupchat) matches your username - * or one of the mention keywords specified in Adium's - * advanced prefs. * status - the message is a status change * event - the message is a notification of something happening * (for example, encryption being turned on) - * %status% - See %status% in theme_adium_append_html() + * %status% - See %status% in theme_adium_append_html () */ /* Define javascript function to use */ if (consecutive) { - func = "appendNextMessage"; + func = priv->allow_scrolling ? "appendNextMessage" : "appendNextMessageNoScroll"; } else { - func = "appendMessage"; + func = priv->allow_scrolling ? "appendMessage" : "appendMessageNoScroll"; } - /* Outgoing */ if (empathy_contact_is_user (sender)) { - if (consecutive) { - if (is_backlog) { - html = priv->data->out_nextcontext_html; - len = priv->data->out_nextcontext_len; - } - - /* Not backlog, or fallback if NextContext.html - * is missing */ - if (html == NULL) { - html = priv->data->out_nextcontent_html; - len = priv->data->out_nextcontent_len; - } - } - - /* Not consecutive, or fallback if NextContext.html and/or - * NextContent.html are missing */ - if (html == NULL) { - if (is_backlog) { - html = priv->data->out_context_html; - len = priv->data->out_context_len; - } - - if (html == NULL) { - html = priv->data->out_content_html; - len = priv->data->out_content_len; - } - } - } - - /* Incoming, or fallback if outgoing files are missing */ - if (html == NULL) { - if (consecutive) { - if (is_backlog) { - html = priv->data->in_nextcontext_html; - len = priv->data->in_nextcontext_len; - } - - /* Note backlog, or fallback if NextContext.html - * is missing */ - if (html == NULL) { - html = priv->data->in_nextcontent_html; - len = priv->data->in_nextcontent_len; - } + /* out */ + if (is_backlog) { + /* context */ + html = consecutive ? priv->data->out_nextcontext_html : priv->data->out_context_html; + } else { + /* content */ + html = consecutive ? priv->data->out_nextcontent_html : priv->data->out_content_html; } - /* Not consecutive, or fallback if NextContext.html and/or - * NextContent.html are missing */ - if (html == NULL) { - if (is_backlog) { - html = priv->data->in_context_html; - len = priv->data->in_context_len; - } - - if (html == NULL) { - html = priv->data->in_content_html; - len = priv->data->in_content_len; - } + /* remove all the unread marks when we are sending a message */ + theme_adium_remove_focus_marks (theme); + } else { + /* in */ + if (is_backlog) { + /* context */ + html = consecutive ? priv->data->in_nextcontext_html : priv->data->in_context_html; + } else { + /* content */ + html = consecutive ? priv->data->in_nextcontent_html : priv->data->in_content_html; } } - if (html != NULL) { - theme_adium_append_html (theme, func, html, len, body_escaped, - avatar_filename, name, contact_id, - service_name, message_classes->str, - timestamp, is_backlog); - } else { - DEBUG ("Couldn't find HTML file for this message"); - } + theme_adium_append_html (theme, func, html, body_escaped, + avatar_filename, name, contact_id, + service_name, message_classes->str, + timestamp, is_backlog); /* Keep the sender of the last displayed message */ if (priv->last_contact) { @@ -782,8 +810,15 @@ static void theme_adium_append_event (EmpathyChatView *view, const gchar *str) { + EmpathyThemeAdiumPriv *priv = GET_PRIV (view); gchar *str_escaped; + if (priv->pages_loading != 0) { + g_queue_push_tail (&priv->message_queue, + tp_g_value_slice_new_string (str)); + return; + } + str_escaped = g_markup_escape_text (str, -1); theme_adium_append_event_escaped (view, str_escaped); g_free (str_escaped); @@ -793,14 +828,18 @@ static void theme_adium_scroll (EmpathyChatView *view, gboolean allow_scrolling) { - /* FIXME: Is it possible? I guess we need a js function, but I don't - * see any... */ + EmpathyThemeAdiumPriv *priv = GET_PRIV (view); + + priv->allow_scrolling = allow_scrolling; + if (allow_scrolling) { + empathy_chat_view_scroll_down (view); + } } static void theme_adium_scroll_down (EmpathyChatView *view) { - webkit_web_view_execute_script (WEBKIT_WEB_VIEW (view), "scrollToBottom()"); + webkit_web_view_execute_script (WEBKIT_WEB_VIEW (view), "alignChat(true);"); } static gboolean @@ -891,11 +930,12 @@ static void theme_adium_focus_toggled (EmpathyChatView *view, gboolean has_focus) { + EmpathyThemeAdium *self = (EmpathyThemeAdium *) view; EmpathyThemeAdiumPriv *priv = GET_PRIV (view); priv->has_focus = has_focus; - if (priv->has_focus) { - priv->has_unread_message = FALSE; + if (!priv->has_focus) { + theme_adium_remove_focus_marks (self); } } @@ -1028,6 +1068,7 @@ theme_adium_load_finished_cb (WebKitWebView *view, { EmpathyThemeAdiumPriv *priv = GET_PRIV (view); EmpathyChatView *chat_view = EMPATHY_CHAT_VIEW (view); + GList *l; DEBUG ("Page loaded"); priv->pages_loading--; @@ -1036,14 +1077,20 @@ theme_adium_load_finished_cb (WebKitWebView *view, return; /* Display queued messages */ - priv->message_queue = g_list_reverse (priv->message_queue); - while (priv->message_queue) { - EmpathyMessage *message = priv->message_queue->data; + for (l = priv->message_queue.head; l != NULL; l = l->next) { + GValue *value = l->data; + + if (G_VALUE_HOLDS_OBJECT (value)) { + theme_adium_append_message (chat_view, + g_value_get_object (value)); + } else { + theme_adium_append_event (chat_view, + g_value_get_string (value)); + } - theme_adium_append_message (chat_view, message); - priv->message_queue = g_list_remove (priv->message_queue, message); - g_object_unref (message); + tp_g_value_slice_free (value); } + g_queue_clear (&priv->message_queue); } static void @@ -1319,6 +1366,8 @@ empathy_theme_adium_init (EmpathyThemeAdium *theme) theme->priv = priv; + g_queue_init (&priv->message_queue); + priv->allow_scrolling = TRUE; priv->smiley_manager = empathy_smiley_manager_dup_singleton (); g_signal_connect (theme, "load-finished", @@ -1359,18 +1408,24 @@ empathy_adium_path_is_valid (const gchar *path) ret = g_file_test (file, G_FILE_TEST_EXISTS); g_free (file); - if (ret == FALSE) - return ret; + if (!ret) + return FALSE; /* We ship a default Template.html as fallback if there is any problem * with the one inside the theme. The only other required file is - * Content.html for incoming messages (outgoing fallback to use - * incoming). */ - file = g_build_filename (path, "Contents", "Resources", "Incoming", - "Content.html", NULL); + * Content.html OR Incoming/Content.html*/ + file = g_build_filename (path, "Contents", "Resources", "Content.html", + NULL); ret = g_file_test (file, G_FILE_TEST_EXISTS); g_free (file); + if (!ret) { + file = g_build_filename (path, "Contents", "Resources", "Incoming", + "Content.html", NULL); + ret = g_file_test (file, G_FILE_TEST_EXISTS); + g_free (file); + } + return ret; } @@ -1400,6 +1455,108 @@ empathy_adium_info_new (const gchar *path) return info; } +static guint +adium_info_get_version (GHashTable *info) +{ + return tp_asv_get_int32 (info, "MessageViewVersion", NULL); +} + +static const gchar * +adium_info_get_no_variant_name (GHashTable *info) +{ + const gchar *name = tp_asv_get_string (info, "DisplayNameForNoVariant"); + return name ? name : _("Normal"); +} + +static const gchar * +adium_info_get_default_or_first_variant (GHashTable *info) +{ + const gchar *name; + GPtrArray *variants; + + name = empathy_adium_info_get_default_variant (info); + if (name != NULL) { + return name; + } + + variants = empathy_adium_info_get_available_variants (info); + g_assert (variants->len > 0); + return g_ptr_array_index (variants, 0); +} + +static gchar * +adium_info_dup_path_for_variant (GHashTable *info, + const gchar *variant) +{ + guint version = adium_info_get_version (info); + const gchar *no_variant = adium_info_get_no_variant_name (info); + + if (version <= 2 && !tp_strdiff (variant, no_variant)) { + return g_strdup ("main.css"); + } + + return g_strdup_printf ("Variants/%s.css", variant); + +} + +const gchar * +empathy_adium_info_get_default_variant (GHashTable *info) +{ + if (adium_info_get_version (info) <= 2) { + return adium_info_get_no_variant_name (info); + } + + return tp_asv_get_string (info, "DefaultVariant"); +} + +GPtrArray * +empathy_adium_info_get_available_variants (GHashTable *info) +{ + GPtrArray *variants; + const gchar *path; + gchar *dirpath; + GDir *dir; + + variants = tp_asv_get_boxed (info, "AvailableVariants", G_TYPE_PTR_ARRAY); + if (variants != NULL) { + return variants; + } + + variants = g_ptr_array_new_with_free_func (g_free); + tp_asv_take_boxed (info, g_strdup ("AvailableVariants"), + G_TYPE_PTR_ARRAY, variants); + + path = tp_asv_get_string (info, "path"); + dirpath = g_build_filename (path, "Contents", "Resources", "Variants", NULL); + dir = g_dir_open (dirpath, 0, NULL); + if (dir != NULL) { + const gchar *name; + + for (name = g_dir_read_name (dir); + name != NULL; + name = g_dir_read_name (dir)) { + gchar *display_name; + + if (!g_str_has_suffix (name, ".css")) { + continue; + } + + display_name = g_strdup (name); + strstr (display_name, ".css")[0] = '\0'; + g_ptr_array_add (variants, display_name); + } + g_dir_close (dir); + } + g_free (dirpath); + + if (adium_info_get_version (info) <= 2) { + g_ptr_array_add (variants, + g_strdup (adium_info_get_no_variant_name (info))); + } + + return variants; +} + GType empathy_adium_data_get_type (void) { @@ -1419,16 +1576,10 @@ EmpathyAdiumData * empathy_adium_data_new_with_info (const gchar *path, GHashTable *info) { EmpathyAdiumData *data; - gchar *file; gchar *template_html = NULL; - gsize template_len; gchar *footer_html = NULL; - gsize footer_len; - GString *string; - gchar **strv = NULL; - gchar *css_path; - guint len = 0; - guint i = 0; + gchar *variant_path; + gchar *tmp; g_return_val_if_fail (empathy_adium_path_is_valid (path), NULL); @@ -1438,121 +1589,121 @@ empathy_adium_data_new_with_info (const gchar *path, GHashTable *info) data->basedir = g_strconcat (path, G_DIR_SEPARATOR_S "Contents" G_DIR_SEPARATOR_S "Resources" G_DIR_SEPARATOR_S, NULL); data->info = g_hash_table_ref (info); + data->version = adium_info_get_version (info); + data->strings_to_free = g_ptr_array_new_with_free_func (g_free); + + DEBUG ("Loading theme at %s", path); + +#define LOAD(path, var) \ + tmp = g_build_filename (data->basedir, path, NULL); \ + g_file_get_contents (tmp, &var, NULL, NULL); \ + g_free (tmp); \ + +#define LOAD_CONST(path, var) \ + { \ + gchar *content; \ + LOAD (path, content); \ + if (content != NULL) { \ + g_ptr_array_add (data->strings_to_free, content); \ + } \ + var = content; \ + } /* Load html files */ - file = g_build_filename (data->basedir, "Incoming", "Content.html", NULL); - g_file_get_contents (file, &data->in_content_html, &data->in_content_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Incoming", "NextContent.html", NULL); - g_file_get_contents (file, &data->in_nextcontent_html, &data->in_nextcontent_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Incoming", "Context.html", NULL); - g_file_get_contents (file, &data->in_context_html, &data->in_context_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Incoming", "NextContext.html", NULL); - g_file_get_contents (file, &data->in_nextcontext_html, &data->in_nextcontext_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Outgoing", "Content.html", NULL); - g_file_get_contents (file, &data->out_content_html, &data->out_content_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Outgoing", "NextContent.html", NULL); - g_file_get_contents (file, &data->out_nextcontent_html, &data->out_nextcontent_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Outgoing", "Context.html", NULL); - g_file_get_contents (file, &data->out_context_html, &data->out_context_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Outgoing", "NextContext.html", NULL); - g_file_get_contents (file, &data->out_nextcontext_html, &data->out_nextcontext_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Status.html", NULL); - g_file_get_contents (file, &data->status_html, &data->status_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Footer.html", NULL); - g_file_get_contents (file, &footer_html, &footer_len, NULL); - g_free (file); - - file = g_build_filename (data->basedir, "Incoming", "buddy_icon.png", NULL); - if (g_file_test (file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { - data->default_incoming_avatar_filename = file; - } else { - g_free (file); + LOAD_CONST ("Content.html", data->content_html); + LOAD_CONST ("Incoming/Content.html", data->in_content_html); + LOAD_CONST ("Incoming/NextContent.html", data->in_nextcontent_html); + LOAD_CONST ("Incoming/Context.html", data->in_context_html); + LOAD_CONST ("Incoming/NextContext.html", data->in_nextcontext_html); + LOAD_CONST ("Outgoing/Content.html", data->out_content_html); + LOAD_CONST ("Outgoing/NextContent.html", data->out_nextcontent_html); + LOAD_CONST ("Outgoing/Context.html", data->out_context_html); + LOAD_CONST ("Outgoing/NextContext.html", data->out_nextcontext_html); + LOAD_CONST ("Status.html", data->status_html); + LOAD ("Template.html", template_html); + LOAD ("Footer.html", footer_html); + +#undef LOAD_CONST +#undef LOAD + + /* HTML fallbacks: If we have at least content OR in_content, then + * everything else gets a fallback */ + +#define FALLBACK(html, fallback) \ + if (html == NULL) { \ + html = fallback; \ } - file = g_build_filename (data->basedir, "Outgoing", "buddy_icon.png", NULL); - if (g_file_test (file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { - data->default_outgoing_avatar_filename = file; - } else { - g_free (file); + /* in_nextcontent -> in_content -> content */ + FALLBACK (data->in_content_html, data->content_html); + FALLBACK (data->in_nextcontent_html, data->in_content_html); + + /* context -> content */ + FALLBACK (data->in_context_html, data->in_content_html); + FALLBACK (data->in_nextcontext_html, data->in_nextcontent_html); + FALLBACK (data->out_context_html, data->out_content_html); + FALLBACK (data->out_nextcontext_html, data->out_nextcontent_html); + + /* out -> in */ + FALLBACK (data->out_content_html, data->in_content_html); + FALLBACK (data->out_nextcontent_html, data->in_nextcontent_html); + FALLBACK (data->out_context_html, data->in_context_html); + FALLBACK (data->out_nextcontext_html, data->in_nextcontext_html); + + /* status -> in_content */ + FALLBACK (data->status_html, data->in_content_html); + +#undef FALLBACK + + /* template -> empathy's template */ + data->custom_template = (template_html != NULL); + if (template_html == NULL) { + tmp = empathy_file_lookup ("Template.html", "data"); + g_file_get_contents (tmp, &template_html, NULL, NULL); + g_free (tmp); } - css_path = g_build_filename (data->basedir, "main.css", NULL); - - /* There is 2 formats for Template.html: The old one has 4 parameters, - * the new one has 5 parameters. */ - file = g_build_filename (data->basedir, "Template.html", NULL); - if (g_file_get_contents (file, &template_html, &template_len, NULL)) { - strv = g_strsplit (template_html, "%@", -1); - len = g_strv_length (strv); + /* Default avatar */ + tmp = g_build_filename (data->basedir, "Incoming", "buddy_icon.png", NULL); + if (g_file_test (tmp, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { + data->default_incoming_avatar_filename = tmp; + } else { + g_free (tmp); } - g_free (file); - - if (len != 5 && len != 6) { - /* Either the theme has no template or it don't have the good - * number of parameters. Fallback to use our own template. */ - g_free (template_html); - g_strfreev (strv); - - file = empathy_file_lookup ("Template.html", "data"); - g_file_get_contents (file, &template_html, &template_len, NULL); - g_free (file); - strv = g_strsplit (template_html, "%@", -1); - len = g_strv_length (strv); + tmp = g_build_filename (data->basedir, "Outgoing", "buddy_icon.png", NULL); + if (g_file_test (tmp, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { + data->default_outgoing_avatar_filename = tmp; + } else { + g_free (tmp); } - /* Replace %@ with the needed information in the template html. */ - string = g_string_sized_new (template_len); - g_string_append (string, strv[i++]); - g_string_append (string, data->basedir); - g_string_append (string, strv[i++]); - if (len == 6) { - const gchar *variant; - - /* We include main.css by default */ - g_string_append_printf (string, "@import url(\"%s\");", css_path); - g_string_append (string, strv[i++]); - variant = tp_asv_get_string (data->info, "DefaultVariant"); - if (variant) { - g_string_append (string, "Variants/"); - g_string_append (string, variant); - g_string_append (string, ".css"); - } + variant_path = adium_info_dup_path_for_variant (info, + adium_info_get_default_or_first_variant (info)); + + /* Old custom templates had only 4 parameters. + * New templates have 5 parameters */ + if (data->version <= 2 && data->custom_template) { + tmp = string_with_format (template_html, + data->basedir, + variant_path, + "", /* The header */ + footer_html ? footer_html : "", + NULL); } else { - /* FIXME: We should set main.css OR the variant css */ - g_string_append (string, css_path); + tmp = string_with_format (template_html, + data->basedir, + data->version <= 2 ? "" : "@import url( \"main.css\" );", + variant_path, + "", /* The header */ + footer_html ? footer_html : "", + NULL); } - g_string_append (string, strv[i++]); - g_string_append (string, ""); /* We don't want header */ - g_string_append (string, strv[i++]); - /* FIXME: We should replace adium %macros% in footer */ - if (footer_html) { - g_string_append (string, footer_html); - } - g_string_append (string, strv[i++]); - data->template_html = g_string_free (string, FALSE); + g_ptr_array_add (data->strings_to_free, tmp); + data->template_html = tmp; - g_free (footer_html); g_free (template_html); - g_free (css_path); - g_strfreev (strv); + g_free (footer_html); + g_free (variant_path); return data; } @@ -1588,20 +1739,12 @@ empathy_adium_data_unref (EmpathyAdiumData *data) if (g_atomic_int_dec_and_test (&data->ref_count)) { g_free (data->path); g_free (data->basedir); - g_free (data->template_html); - g_free (data->in_content_html); - g_free (data->in_nextcontent_html); - g_free (data->in_context_html); - g_free (data->in_nextcontext_html); - g_free (data->out_content_html); - g_free (data->out_nextcontent_html); - g_free (data->out_context_html); - g_free (data->out_nextcontext_html); g_free (data->default_avatar_filename); g_free (data->default_incoming_avatar_filename); g_free (data->default_outgoing_avatar_filename); - g_free (data->status_html); g_hash_table_unref (data->info); + g_ptr_array_unref (data->strings_to_free); + g_slice_free (EmpathyAdiumData, data); } } |