/pidgin/main: 2bf06f291ff7: Add some smiley stuff to a GtkWebView.
Elliott Sales de Andrade
qulogic at pidgin.im
Tue Aug 14 04:03:26 EDT 2012
Changeset: 2bf06f291ff7feb6a383656b53bc9cba248ab694
Author: Elliott Sales de Andrade <qulogic at pidgin.im>
Date: 2012-08-13 18:25 -0400
Branch: default
URL: http://hg.pidgin.im/pidgin/main/rev/2bf06f291ff7
Description:
Add some smiley stuff to a GtkWebView.
This isn't used to parse anything yet, but just copies the API and
internal structures from the GtkIMHtml. As such, some stuff may or
may not be unnecessary.
diffstat:
pidgin/gtkwebview.c | 510 ++++++++++++++++++++++++++++++++++++++++++++++++++++
pidgin/gtkwebview.h | 94 +++++++++
2 files changed, 604 insertions(+), 0 deletions(-)
diffs (truncated from 661 to 300 lines):
diff --git a/pidgin/gtkwebview.c b/pidgin/gtkwebview.c
--- a/pidgin/gtkwebview.c
+++ b/pidgin/gtkwebview.c
@@ -75,6 +75,26 @@ typedef struct {
gboolean (*context_menu)(GtkWebView *webview, WebKitDOMHTMLAnchorElement *link, GtkWidget *menu);
} GtkWebViewProtocol;
+struct _GtkWebViewSmiley {
+ gchar *smile;
+ gchar *file;
+ GdkPixbufAnimation *icon;
+ gboolean hidden;
+ GdkPixbufLoader *loader;
+ GSList *anchors;
+ GtkWebViewSmileyFlags flags;
+ GtkWebView *webview;
+ gpointer data;
+ gsize datasize;
+};
+
+typedef struct _GtkSmileyTree GtkSmileyTree;
+struct _GtkSmileyTree {
+ GString *values;
+ GtkSmileyTree **children;
+ GtkWebViewSmiley *image;
+};
+
typedef struct _GtkWebViewPriv {
/* Processing queues */
gboolean is_loading;
@@ -94,6 +114,10 @@ typedef struct _GtkWebViewPriv {
gboolean block_changed:1;
} edit;
+ /* Smileys */
+ char *protocol_name;
+ GHashTable *smiley_data;
+ GtkSmileyTree *default_smilies;
} GtkWebViewPriv;
/******************************************************************************
@@ -103,6 +127,484 @@ typedef struct _GtkWebViewPriv {
static WebKitWebViewClass *parent_class = NULL;
/******************************************************************************
+ * Smileys
+ *****************************************************************************/
+
+const char *
+gtk_webview_get_protocol_name(GtkWebView *webview)
+{
+ GtkWebViewPriv *priv;
+
+ g_return_val_if_fail(webview != NULL, NULL);
+
+ priv = GTK_WEBVIEW_GET_PRIVATE(webview);
+ return priv->protocol_name;
+}
+
+void
+gtk_webview_set_protocol_name(GtkWebView *webview, const char *protocol_name)
+{
+ GtkWebViewPriv *priv;
+
+ g_return_if_fail(webview != NULL);
+
+ priv = GTK_WEBVIEW_GET_PRIVATE(webview);
+ priv->protocol_name = g_strdup(protocol_name);
+}
+
+static GtkSmileyTree *
+gtk_smiley_tree_new(void)
+{
+ return g_new0(GtkSmileyTree, 1);
+}
+
+static void
+gtk_smiley_tree_insert(GtkSmileyTree *tree, GtkWebViewSmiley *smiley)
+{
+ GtkSmileyTree *t = tree;
+ const char *x = smiley->smile;
+
+ if (!(*x))
+ return;
+
+ do {
+ char *pos;
+ gsize index;
+
+ if (!t->values)
+ t->values = g_string_new("");
+
+ pos = strchr(t->values->str, *x);
+ if (!pos) {
+ t->values = g_string_append_c(t->values, *x);
+ index = t->values->len - 1;
+ t->children = g_realloc(t->children, t->values->len * sizeof(GtkSmileyTree *));
+ t->children[index] = g_new0(GtkSmileyTree, 1);
+ } else
+ index = pos - t->values->str;
+
+ t = t->children[index];
+
+ x++;
+ } while (*x);
+
+ t->image = smiley;
+}
+
+static void
+gtk_smiley_tree_destroy(GtkSmileyTree *tree)
+{
+ GSList *list = g_slist_prepend(NULL, tree);
+
+ while (list) {
+ GtkSmileyTree *t = list->data;
+ gsize i;
+ list = g_slist_delete_link(list, list);
+ if (t && t->values) {
+ for (i = 0; i < t->values->len; i++)
+ list = g_slist_prepend(list, t->children[i]);
+ g_string_free(t->values, TRUE);
+ g_free(t->children);
+ }
+
+ g_free(t);
+ }
+}
+
+static void
+gtk_smiley_tree_remove(GtkSmileyTree *tree, GtkWebViewSmiley *smiley)
+{
+ GtkSmileyTree *t = tree;
+ const gchar *x = smiley->smile;
+ int len = 0;
+
+ while (*x) {
+ char *pos;
+
+ if (!t->values)
+ return;
+
+ pos = strchr(t->values->str, *x);
+ if (pos)
+ t = t->children[pos - t->values->str];
+ else
+ return;
+
+ x++; len++;
+ }
+
+ t->image = NULL;
+}
+
+static int
+gtk_smiley_tree_lookup(GtkSmileyTree *tree, const char *text)
+{
+ GtkSmileyTree *t = tree;
+ const char *x = text;
+ int len = 0;
+ const char *amp;
+ int alen;
+
+ while (*x) {
+ char *pos;
+
+ if (!t->values)
+ break;
+
+ if (*x == '&' && (amp = purple_markup_unescape_entity(x, &alen))) {
+ gboolean matched = TRUE;
+ /* Make sure all chars of the unescaped value match */
+ while (*(amp + 1)) {
+ pos = strchr(t->values->str, *amp);
+ if (pos)
+ t = t->children[pos - t->values->str];
+ else {
+ matched = FALSE;
+ break;
+ }
+ amp++;
+ }
+ if (!matched)
+ break;
+
+ pos = strchr(t->values->str, *amp);
+ }
+ else if (*x == '<') /* Because we're all WYSIWYG now, a '<' char should
+ * only appear as the start of a tag. Perhaps a
+ * safer (but costlier) check would be to call
+ * gtk_imhtml_is_tag on it */
+ break;
+ else {
+ alen = 1;
+ pos = strchr(t->values->str, *x);
+ }
+
+ if (pos)
+ t = t->children[pos - t->values->str];
+ else
+ break;
+
+ x += alen;
+ len += alen;
+ }
+
+ if (t->image)
+ return len;
+
+ return 0;
+}
+
+static void
+gtk_webview_disassociate_smiley_foreach(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ GtkSmileyTree *tree = (GtkSmileyTree *)value;
+ GtkWebViewSmiley *smiley = (GtkWebViewSmiley *)user_data;
+ gtk_smiley_tree_remove(tree, smiley);
+}
+
+static void
+gtk_webview_disconnect_smiley(GtkWebView *webview, GtkWebViewSmiley *smiley)
+{
+ smiley->webview = NULL;
+ g_signal_handlers_disconnect_matched(webview, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, smiley);
+}
+
+static void
+gtk_webview_disassociate_smiley(GtkWebViewSmiley *smiley)
+{
+ if (smiley->webview) {
+ GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(smiley->webview);
+ gtk_smiley_tree_remove(priv->default_smilies, smiley);
+ g_hash_table_foreach(priv->smiley_data,
+ gtk_webview_disassociate_smiley_foreach, smiley);
+ g_signal_handlers_disconnect_matched(smiley->webview,
+ G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+ NULL, smiley);
+ smiley->webview = NULL;
+ }
+}
+
+void
+gtk_webview_associate_smiley(GtkWebView *webview, const char *sml,
+ GtkWebViewSmiley *smiley)
+{
+ GtkSmileyTree *tree;
+ GtkWebViewPriv *priv;
+
+ g_return_if_fail(webview != NULL);
+ g_return_if_fail(GTK_IS_WEBVIEW(webview));
+
+ priv = GTK_WEBVIEW_GET_PRIVATE(webview);
+
+ if (sml == NULL)
+ tree = priv->default_smilies;
+ else if (!(tree = g_hash_table_lookup(priv->smiley_data, sml))) {
+ tree = gtk_smiley_tree_new();
+ g_hash_table_insert(priv->smiley_data, g_strdup(sml), tree);
+ }
+
+ /* need to disconnect old webview, if there is one */
+ if (smiley->webview) {
+ g_signal_handlers_disconnect_matched(smiley->webview,
+ G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+ NULL, smiley);
+ }
+
+ smiley->webview = webview;
+
+ gtk_smiley_tree_insert(tree, smiley);
+
+ /* connect destroy signal for the webview */
+ g_signal_connect(webview, "destroy",
+ G_CALLBACK(gtk_webview_disconnect_smiley), smiley);
+}
+
+static gboolean
+gtk_webview_is_smiley(GtkWebViewPriv *priv, const char *sml, const char *text,
+ int *len)
+{
+ GtkSmileyTree *tree;
+
+ if (!sml)
+ sml = priv->protocol_name;
+
+ if (!sml || !(tree = g_hash_table_lookup(priv->smiley_data, sml)))
+ tree = priv->default_smilies;
+
+ if (tree == NULL)
+ return FALSE;
+
+ *len = gtk_smiley_tree_lookup(tree, text);
+ return (*len > 0);
+}
+
+static GtkWebViewSmiley *
+gtk_webview_smiley_get_from_tree(GtkSmileyTree *t, const char *text)
More information about the Commits
mailing list