Tue, 01 Apr 2014 03:46:16 +0200
Smileys: implement and use new parser, only themes for now
--- a/libpurple/Makefile.am Tue Apr 01 02:11:17 2014 +0200 +++ b/libpurple/Makefile.am Tue Apr 01 03:46:16 2014 +0200 @@ -102,6 +102,7 @@ server.c \ signals.c \ smiley-list.c \ + smiley-parser.c \ smiley-theme.c \ smiley.c \ dnsquery.c \ @@ -179,6 +180,7 @@ server.h \ signals.h \ smiley-list.h \ + smiley-parser.h \ smiley-theme.h \ smiley.h \ dnsquery.h \
--- a/libpurple/smiley-list.c Tue Apr 01 02:11:17 2014 +0200 +++ b/libpurple/smiley-list.c Tue Apr 01 03:46:16 2014 +0200 @@ -41,9 +41,6 @@ PROP_LAST }; -static GObjectClass *parent_class; -static GParamSpec *properties[PROP_LAST]; - static void _list_append2(GList **head_p, GList **tail_p, gpointer data) { @@ -84,6 +81,12 @@ * API implementation ******************************************************************************/ +PurpleSmileyList * +purple_smiley_list_new(void) +{ + return g_object_new(PURPLE_TYPE_SMILEY_LIST, NULL); +} + gboolean purple_smiley_list_add(PurpleSmileyList *list, PurpleSmiley *smiley) { @@ -138,6 +141,16 @@ g_object_unref(smiley); } +PurpleTrie * +purple_smiley_list_get_trie(PurpleSmileyList *list) +{ + PurpleSmileyListPrivate *priv = PURPLE_SMILEY_LIST_GET_PRIVATE(list); + + g_return_val_if_fail(priv != NULL, NULL); + + return priv->trie; +} + /******************************************************************************* * Object stuff @@ -211,15 +224,11 @@ { GObjectClass *gobj_class = G_OBJECT_CLASS(klass); - parent_class = g_type_class_peek_parent(klass); - g_type_class_add_private(klass, sizeof(PurpleSmileyListPrivate)); gobj_class->get_property = purple_smiley_list_get_property; gobj_class->set_property = purple_smiley_list_set_property; gobj_class->finalize = purple_smiley_list_finalize; - - g_object_class_install_properties(gobj_class, PROP_LAST, properties); } GType
--- a/libpurple/smiley-list.h Tue Apr 01 02:11:17 2014 +0200 +++ b/libpurple/smiley-list.h Tue Apr 01 03:46:16 2014 +0200 @@ -25,6 +25,7 @@ #include <glib-object.h> #include "smiley.h" +#include "trie.h" typedef struct _PurpleSmileyList PurpleSmileyList; typedef struct _PurpleSmileyListClass PurpleSmileyListClass; @@ -68,12 +69,18 @@ GType purple_smiley_list_get_type(void); +PurpleSmileyList * +purple_smiley_list_new(void); + gboolean purple_smiley_list_add(PurpleSmileyList *list, PurpleSmiley *smiley); void purple_smiley_list_remove(PurpleSmileyList *list, PurpleSmiley *smiley); +PurpleTrie * +purple_smiley_list_get_trie(PurpleSmileyList *list); + G_END_DECLS #endif /* _PURPLE_SMILEY_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/smiley-parser.c Tue Apr 01 03:46:16 2014 +0200 @@ -0,0 +1,67 @@ +/* purple + * + * Purple 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 "smiley-parser.h" + +#include "smiley-theme.h" + +static gboolean purple_smiley_parse_cb(GString *out, const gchar *word, + gpointer _smiley, gpointer _unused) +{ + PurpleSmiley *smiley = _smiley; + + g_string_append_printf(out, "<img alt=\"%s\" src=\"%s\" />", + word, purple_smiley_get_path(smiley)); + + return TRUE; +} + +gchar * +purple_smiley_parse(const gchar *message, gpointer ui_data) +{ + PurpleSmileyTheme *theme; + PurpleSmileyList *theme_smileys; + PurpleTrie *theme_trie; + + if (message == NULL || message[0] == '\0') { + purple_debug_info("tomo", "no msg"); + return g_strdup(message); + } + + theme = purple_smiley_theme_get_current(); + if (theme == NULL) { + purple_debug_info("tomo", "no theme"); + return g_strdup(message); + } + + theme_smileys = purple_smiley_theme_get_smileys(theme, ui_data); + if (theme_smileys == NULL) { + purple_debug_info("tomo", "no smileys"); + return g_strdup(message); + } + + theme_trie = purple_smiley_list_get_trie(theme_smileys); + g_return_val_if_fail(theme_trie != NULL, g_strdup(message)); + + /* TODO: don't replace text within tags, ie. <span style=":)"> */ + return purple_trie_replace(theme_trie, message, + purple_smiley_parse_cb, NULL); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/smiley-parser.h Tue Apr 01 03:46:16 2014 +0200 @@ -0,0 +1,30 @@ +/* purple + * + * Purple 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 + */ + +#ifndef _PURPLE_SMILEY_PARSER_H_ +#define _PURPLE_SMILEY_PARSER_H_ + +#include "purple.h" + +gchar * +purple_smiley_parse(const gchar *message, gpointer ui_data); + +#endif /* _PURPLE_SMILEY_PARSER_H_ */
--- a/libpurple/smiley-theme.c Tue Apr 01 02:11:17 2014 +0200 +++ b/libpurple/smiley-theme.c Tue Apr 01 03:46:16 2014 +0200 @@ -43,6 +43,8 @@ void purple_smiley_theme_set_current(PurpleSmileyTheme *theme) { + PurpleSmileyThemeClass *klass; + g_return_if_fail(theme == NULL || PURPLE_IS_SMILEY_THEME(theme)); if (theme) @@ -50,6 +52,13 @@ if (current) g_object_unref(current); current = theme; + + if (!theme) + return; + klass = PURPLE_SMILEY_THEME_GET_CLASS(theme); + g_return_if_fail(klass != NULL); + if (klass->activate) + klass->activate(theme); } PurpleSmileyTheme *
--- a/libpurple/smiley-theme.h Tue Apr 01 02:11:17 2014 +0200 +++ b/libpurple/smiley-theme.h Tue Apr 01 03:46:16 2014 +0200 @@ -55,6 +55,7 @@ PurpleSmileyList * (*get_smileys)(PurpleSmileyTheme *theme, gpointer ui_data); + void (*activate)(PurpleSmileyTheme *theme); void (*purple_reserved1)(void); void (*purple_reserved2)(void);
--- a/libpurple/smiley.c Tue Apr 01 02:11:17 2014 +0200 +++ b/libpurple/smiley.c Tue Apr 01 03:46:16 2014 +0200 @@ -138,6 +138,12 @@ case PROP_SHORTCUT: g_value_set_string(value, priv->shortcut); break; + case PROP_IS_READY: + g_value_set_boolean(value, priv->is_ready); + break; + case PROP_PATH: + g_value_set_string(value, priv->path); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, par_id, pspec); break; @@ -156,6 +162,13 @@ g_free(priv->shortcut); priv->shortcut = g_strdup(g_value_get_string(value)); break; + case PROP_IS_READY: + priv->is_ready = g_value_get_boolean(value); + break; + case PROP_PATH: + g_free(priv->path); + priv->path = g_strdup(g_value_get_string(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, par_id, pspec); break;
--- a/pidgin/gtkconv.c Tue Apr 01 02:11:17 2014 +0200 +++ b/pidgin/gtkconv.c Tue Apr 01 03:46:16 2014 +0200 @@ -41,6 +41,7 @@ #include "notify.h" #include "prpl.h" #include "request.h" +#include "smiley-parser.h" #include "theme-loader.h" #include "theme-manager.h" #include "util.h" @@ -6710,7 +6711,8 @@ gtkconv->last_flags = flags; gtkconv->last_conversed = conv; - smileyed = pidgin_smiley_parse_markup(displaying, purple_account_get_protocol_id(account)); + smileyed = purple_smiley_parse(displaying, + (gpointer)purple_account_get_protocol_name(account)); msg = replace_message_tokens(message_html, conv, name, alias, smileyed, flags, mtime); escape = pidgin_webview_quote_js_string(msg ? msg : ""); script = g_strdup_printf("%s(%s)", func, escape);
--- a/pidgin/gtksmiley-theme.c Tue Apr 01 02:11:17 2014 +0200 +++ b/pidgin/gtksmiley-theme.c Tue Apr 01 03:46:16 2014 +0200 @@ -47,6 +47,8 @@ gchar *author; GdkPixbuf *icon_pixbuf; + + GHashTable *smiley_lists_map; } PidginSmileyThemePrivate; static GObjectClass *parent_class; @@ -111,18 +113,21 @@ } static PidginSmileyThemeIndex * -pidgin_smiley_theme_index_parse(const gchar *index_path, gboolean load_contents) +pidgin_smiley_theme_index_parse(const gchar *theme_path, gboolean load_contents) { PidginSmileyThemeIndex *index; PidginSmileyThemeIndexProtocol *proto = NULL; + gchar *index_path; FILE *file; int line_no = 0; gboolean inv_frm = FALSE; + index_path = g_build_filename(theme_path, "theme", NULL); file = g_fopen(index_path, "r"); if (!file) { purple_debug_error("gtksmiley-theme", "Failed to open index file %s", index_path); + g_free(index_path); return NULL; } @@ -253,6 +258,7 @@ index = NULL; } + g_free(index_path); return index; } @@ -267,7 +273,6 @@ PidginSmileyThemePrivate *priv; PidginSmileyThemeIndex *index; GList *it; - gchar *index_path; /* it's not super-efficient, but we don't expect huge amount of * installed themes */ @@ -280,16 +285,12 @@ return; } - index_path = g_build_filename(theme_path, "theme", NULL); - theme = g_object_new(PIDGIN_TYPE_SMILEY_THEME, NULL); priv = PIDGIN_SMILEY_THEME_GET_PRIVATE(theme); priv->path = g_strdup(theme_path); - index = pidgin_smiley_theme_index_parse(index_path, FALSE); - - g_free(index_path); + index = pidgin_smiley_theme_index_parse(theme_path, FALSE); if (!index->name || index->name[0] == '\0') { purple_debug_warning("gtksmiley-theme", @@ -425,16 +426,85 @@ return priv->author; } +static void +pidgin_smiley_theme_activate_impl(PurpleSmileyTheme *theme) +{ + PidginSmileyThemePrivate *priv = PIDGIN_SMILEY_THEME_GET_PRIVATE(theme); + PidginSmileyThemeIndex *index; + GHashTable *smap; + GList *it, *it2, *it3; + + g_return_if_fail(priv != NULL); + + if (priv->smiley_lists_map) + return; + + priv->smiley_lists_map = smap = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, g_object_unref); + + index = pidgin_smiley_theme_index_parse(priv->path, TRUE); + + for (it = index->protocols; it; it = g_list_next(it)) { + PidginSmileyThemeIndexProtocol *proto_idx = it->data; + PurpleSmileyList *proto_smileys; + + proto_smileys = g_hash_table_lookup(smap, proto_idx->name); + if (!proto_smileys) { + proto_smileys = purple_smiley_list_new(); + g_hash_table_insert(smap, + g_strdup(proto_idx->name), proto_smileys); + } + + for (it2 = proto_idx->smileys; it2; it2 = g_list_next(it2)) { + PidginSmileyThemeIndexSmiley *smiley_idx = it2->data; + gchar *smiley_path; + + smiley_path = g_build_filename( + priv->path, smiley_idx->file, NULL); + if (!g_file_test(smiley_path, G_FILE_TEST_EXISTS)) { + purple_debug_warning("gtksmiley-theme", + "Smiley %s is missing", smiley_path); + continue; + } + + for (it3 = smiley_idx->shortcuts; it3; + it3 = g_list_next(it3)) + { + PurpleSmiley *smiley; + gchar *shortcut = it3->data; + + smiley = purple_smiley_new( + shortcut, smiley_path); + purple_smiley_list_add(proto_smileys, smiley); + g_object_unref(smiley); + } + } + } + + pidgin_smiley_theme_index_free(index); +} + static PurpleSmileyList * pidgin_smiley_theme_get_smileys_impl(PurpleSmileyTheme *theme, gpointer ui_data) { - return NULL; + PidginSmileyThemePrivate *priv = PIDGIN_SMILEY_THEME_GET_PRIVATE(theme); + PurpleSmileyList *smileys; + + pidgin_smiley_theme_activate_impl(theme); + + smileys = g_hash_table_lookup(priv->smiley_lists_map, ui_data); + if (smileys != NULL) + return smileys; + + return g_hash_table_lookup(priv->smiley_lists_map, "default"); } void pidgin_smiley_theme_init(void) { + GList *it; const gchar *user_smileys_dir; + const gchar *theme_name; probe_dirs = g_new0(gchar*, 3); probe_dirs[0] = g_build_filename( @@ -445,7 +515,18 @@ if (!g_file_test(user_smileys_dir, G_FILE_TEST_IS_DIR)) g_mkdir(user_smileys_dir, S_IRUSR | S_IWUSR | S_IXUSR); - /* TODO: load configured theme */ + /* setting theme by name (copy-paste from gtkprefs) */ + pidgin_smiley_theme_probe(); + theme_name = purple_prefs_get_string( + PIDGIN_PREFS_ROOT "/smileys/theme"); + for (it = smiley_themes; it; it = g_list_next(it)) { + PidginSmileyTheme *theme = it->data; + + if (g_strcmp0(pidgin_smiley_theme_get_name(theme), theme_name)) + continue; + + purple_smiley_theme_set_current(PURPLE_SMILEY_THEME(theme)); + } } void @@ -478,6 +559,8 @@ g_free(priv->author); if (priv->icon_pixbuf) g_object_unref(priv->icon_pixbuf); + if (priv->smiley_lists_map) + g_hash_table_destroy(priv->smiley_lists_map); G_OBJECT_CLASS(parent_class)->finalize(obj); } @@ -495,6 +578,7 @@ gobj_class->finalize = pidgin_smiley_theme_finalize; pst_class->get_smileys = pidgin_smiley_theme_get_smileys_impl; + pst_class->activate = pidgin_smiley_theme_activate_impl; } GType