changeset 11525:b47708f46a38

[gaim-migrate @ 13773] Here's the rest of that custom smiley receiving patch, with some changes from me. I'm still not all that happy with it, but that's probably not the author's fault, and I don't have time to take it further right now. committer: Tailor Script <tailor@pidgin.im>
author Tim Ringenbach <marv@pidgin.im>
date Mon, 12 Sep 2005 13:25:41 +0000
parents 4fd0c3a663b8
children 744b70723801
files src/Makefile.am src/gtkconv.c src/gtkdialogs.h src/gtkimhtml.c src/gtkimhtml.h src/gtkimhtmltoolbar.c src/gtkmain.c src/gtkprefs.c src/gtkthemes.c src/gtkutils.c
diffstat 10 files changed, 137 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.am	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/Makefile.am	Mon Sep 12 13:25:41 2005 +0000
@@ -313,6 +313,7 @@
 	gtksourceiter.h \
 	gtkstatusbox.h \
 	gtkstock.h \
+	gtkthemes.h \
 	gtkutils.h \
 	internal.h \
 	gtkwhiteboard.h
--- a/src/gtkconv.c	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/gtkconv.c	Mon Sep 12 13:25:41 2005 +0000
@@ -60,6 +60,7 @@
 #include "gtkpounce.h"
 #include "gtkprefs.h"
 #include "gtkprivacy.h"
+#include "gtkthemes.h"
 #include "gtkutils.h"
 #include "gtkstock.h"
 
@@ -5686,23 +5687,50 @@
 	GaimGtkConversation *gtkconv;
 	GtkIMHtmlSmiley *smiley;
 	GdkPixbufLoader *loader;
-	const char *sml;
-
-	if (conv == NULL || smile == NULL) {
+	struct smiley_list *list;
+	const char *sml = NULL, *conv_sml;
+
+	if (!conv || !smile || !*smile) {
 		return FALSE;
 	}
 
-	sml = gaim_account_get_protocol_name(conv->account); /* XXX this sucks */
+	/* If smileys are off, return false */
+	if (gaim_gtkthemes_smileys_disabled())
+		return FALSE;
+
+	/* If possible add this smiley to the current theme.
+	 * The addition is only temporary: custom smilies aren't saved to disk. */
+	conv_sml = gaim_account_get_protocol_name(conv->account);
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
+
+	for (list = (struct smiley_list *)current_smiley_theme->list; list; list = list->next) {
+		if (!strcmp(list->sml, conv_sml)) {
+			sml = list->sml;
+			break;
+		}
+	}
+
 	smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile);
 
-	/* TODO: implement changing a custom smiley in the middle of a conversation */
-
 	if (smiley) {
-		return FALSE;
+
+		if (!(smiley->flags & GTK_IMHTML_SMILEY_CUSTOM)) {
+			return FALSE;
+		}
+
+		/* Close the old GdkPixbufAnimation, then create a new one for
+		 * the smiley we are about to receive */
+		g_object_unref(G_OBJECT(smiley->icon));
+
+		smiley->loader = gdk_pixbuf_loader_new();
+		smiley->icon = gdk_pixbuf_loader_get_animation(smiley->loader);
+		if (smiley->icon)
+			g_object_ref(G_OBJECT(smiley->icon));
+
+		/* A custom smiley is already associated */
+		return TRUE;
 	}
 
-
 	loader = gdk_pixbuf_loader_new();
 
 	/* this is wrong, this file ought not call g_new on GtkIMHtmlSmiley */
@@ -5712,11 +5740,13 @@
 	smiley->file   = NULL;
 	smiley->smile  = g_strdup(smile);
 	smiley->loader = loader;
+	smiley->flags  = smiley->flags | GTK_IMHTML_SMILEY_CUSTOM;
 
 	smiley->icon = gdk_pixbuf_loader_get_animation(loader);
 	if (smiley->icon)
 		g_object_ref(G_OBJECT(smiley->icon));
 
+
 	gtk_imhtml_associate_smiley(GTK_IMHTML(gtkconv->imhtml), sml, smiley);
 
 	return TRUE;
@@ -5752,6 +5782,11 @@
 	GtkIMHtmlSmiley *smiley;
 	GdkPixbufLoader *loader;
 	const char *sml;
+	GtkWidget *icon = NULL;
+	GtkTextChildAnchor *anchor = NULL;
+	GtkTextIter end;
+	GtkIMHtml *imhtml;
+	GSList *current = NULL;
 
 	g_return_if_fail(conv  != NULL);
 	g_return_if_fail(smile != NULL);
@@ -5768,6 +5803,36 @@
 	if (!loader)
 		return;
 
+	smiley->icon = gdk_pixbuf_loader_get_animation(loader);
+	if (smiley->icon)
+		g_object_ref(G_OBJECT(smiley->icon));
+
+	for (current = smiley->anchors; current != NULL; current = g_slist_next(current)) {
+
+		icon = gtk_image_new_from_animation(smiley->icon);
+		gtk_widget_show(icon);
+
+		if (icon) {
+			anchor = GTK_TEXT_CHILD_ANCHOR(current->data);
+
+			g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", g_strdup(gaim_unescape_html(smile)), g_free);
+			g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smile), g_free);
+
+			gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(gtkconv->imhtml), icon, anchor);
+		}
+
+	}
+
+	g_slist_free(smiley->anchors);
+	smiley->anchors = NULL;
+
+	/* Scroll to the end of the widget in case the smiley height was big... */
+	/* FIXME: need to test this actually works, previous dealings with scrolling
+	 * makes me question it */
+	imhtml = GTK_IMHTML(gtkconv->imhtml);
+	gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(imhtml->text_buffer), &end);
+	gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(gtkconv->imhtml), &end, 0, TRUE, 0, 0);
+
 	gaim_debug_info("gtkconv", "About to close the smiley pixbuf\n");
 
 	gdk_pixbuf_loader_close(loader, NULL);
@@ -5803,7 +5868,7 @@
 
 		g_timeout_add(0, (GSourceFunc)update_send_as_selection, win);
 
-		smiley_themeize(gtkconv->imhtml);
+		gaim_gtkthemes_smiley_themeize(gtkconv->imhtml);
 
 		update_tab_icon(conv);
 	}
--- a/src/gtkdialogs.h	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/gtkdialogs.h	Mon Sep 12 13:25:41 2005 +0000
@@ -67,31 +67,12 @@
 	GaimMessageFlags flags;
 };
 
-struct smiley_theme {
-	char *path;
-	char *name;
-	char *desc;
-	char *icon;
-	char *author;
-
-	struct smiley_list *list;
-};
-
 /* Globals in gtkmain.c */
 extern int docklet_count;
 
-/* Globals in gtkthemes.c */
-extern struct smiley_theme *current_smiley_theme;
-extern GSList *smiley_themes;
-
 /* Functions in session.c */
 extern void session_init(gchar *, gchar *, gchar *);
 extern void session_end();
 
-/* Functions in gtkthemes.c */
-extern void smiley_themeize(GtkWidget *);
-extern void smiley_theme_probe();
-extern void load_smiley_theme(const char *file, gboolean load);
-extern GSList *get_proto_smileys(const char *id);
 
 #endif /* _GAIM_GTKDIALOGS_H_ */
--- a/src/gtkimhtml.c	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/gtkimhtml.c	Mon Sep 12 13:25:41 2005 +0000
@@ -4311,6 +4311,7 @@
 	GtkWidget *icon = NULL;
 	GtkTextChildAnchor *anchor;
 	char *unescaped = gaim_unescape_html(smiley);
+	GtkIMHtmlSmiley *imhtml_smiley = gtk_imhtml_smiley_get(imhtml, sml, unescaped);
 
 	if (imhtml->format_functions & GTK_IMHTML_SMILEY) {
 		annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped);
@@ -4345,6 +4346,9 @@
 
 		gtk_widget_show(icon);
 		gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor);
+	} else if (imhtml_smiley != NULL && (imhtml->format_functions & GTK_IMHTML_SMILEY)) {
+		anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
+		imhtml_smiley->anchors = g_slist_append(imhtml_smiley->anchors, anchor);
 	} else {
 		gtk_text_buffer_insert(imhtml->text_buffer, iter, smiley, -1);
 	}
--- a/src/gtkimhtml.h	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/gtkimhtml.h	Mon Sep 12 13:25:41 2005 +0000
@@ -72,6 +72,10 @@
 	GTK_IMHTML_ALL =       -1
 } GtkIMHtmlButtons;
 
+typedef enum {
+	GTK_IMHTML_SMILEY_CUSTOM =	1 << 0
+} GtkIMHtmlSmileyFlags;
+
 struct _GtkIMHtml {
 	GtkTextView text_view;
 	GtkTextBuffer *text_buffer;
@@ -155,6 +159,8 @@
 	GdkPixbufAnimation *icon;
 	gboolean hidden;
 	GdkPixbufLoader *loader;
+	GSList *anchors;
+	GtkIMHtmlSmileyFlags flags; 
 };
 
 struct _GtkIMHtmlScalable {
--- a/src/gtkimhtmltoolbar.c	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/gtkimhtmltoolbar.c	Mon Sep 12 13:25:41 2005 +0000
@@ -34,6 +34,7 @@
 
 #include "gtkdialogs.h"
 #include "gtkimhtmltoolbar.h"
+#include "gtkthemes.h"
 #include "gtkutils.h"
 
 static GtkHBoxClass *parent_class = NULL;
@@ -652,9 +653,9 @@
 	}
 
 	if (toolbar->sml)
-		smileys = get_proto_smileys(toolbar->sml);
+		smileys = gaim_gtkthemes_get_proto_smileys(toolbar->sml);
 	else
-		smileys = get_proto_smileys(NULL);
+		smileys = gaim_gtkthemes_get_proto_smileys(NULL);
 
 	while(smileys) {
 		GtkIMHtmlSmiley *smiley = smileys->data;
--- a/src/gtkmain.c	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/gtkmain.c	Mon Sep 12 13:25:41 2005 +0000
@@ -57,6 +57,7 @@
 #include "gtkroomlist.h"
 #include "gtksavedstatuses.h"
 #include "gtksound.h"
+#include "gtkthemes.h"
 #include "gtkutils.h"
 #include "gtkstock.h"
 #include "gtkwhiteboard.h"
@@ -215,13 +216,7 @@
 	char *icon_path;
 #endif
 
-	if (current_smiley_theme == NULL) {
-		smiley_theme_probe();
-		if (smiley_themes != NULL) {
-			struct smiley_theme *smile = smiley_themes->data;
-			load_smiley_theme(smile->path, TRUE);
-		}
-	}
+	gaim_gtkthemes_init();
 
 	gaim_gtk_blist_setup_sort_methods();
 
--- a/src/gtkprefs.c	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/gtkprefs.c	Mon Sep 12 13:25:41 2005 +0000
@@ -46,6 +46,7 @@
 #include "gtkpluginpref.h"
 #include "gtkprefs.h"
 #include "gtksound.h"
+#include "gtkthemes.h"
 #include "gtkutils.h"
 #include "gtkstock.h"
 
@@ -478,12 +479,11 @@
 	int ind = 0;
 
 
-	smiley_theme_probe();
-
-	if (!smiley_themes)
+	gaim_gtkthemes_smiley_theme_probe();
+
+	if (!(themes = smiley_themes))
 		return NULL;
 
-	themes = smiley_themes;
 
 	gtk_list_store_clear(smiley_theme_store);
 
@@ -702,7 +702,7 @@
 
 	view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(smiley_theme_store));
 
-	gtk_drag_dest_set(view, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te, 
+	gtk_drag_dest_set(view, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te,
 					sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE);
 
 	g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(theme_dnd_recv), smiley_theme_store);
@@ -1832,7 +1832,7 @@
 
 static GtkWidget *plugin_description=NULL, *plugin_details=NULL;
 
-static void prefs_plugin_sel (GtkTreeSelection *sel, GtkTreeModel *model) 
+static void prefs_plugin_sel (GtkTreeSelection *sel, GtkTreeModel *model)
 {
 	gchar *buf, *pname, *perr, *pdesc, *pauth, *pweb;
 	GtkTreeIter  iter;
@@ -1845,11 +1845,11 @@
 	plug = g_value_get_pointer(&val);
 
 	pname = g_markup_escape_text(_(plug->info->name), -1);
-	pdesc = (plug->info->description) ? 
+	pdesc = (plug->info->description) ?
 			g_markup_escape_text(_(plug->info->description), -1) : NULL;
 	pauth = (plug->info->author) ?
 			g_markup_escape_text(_(plug->info->author), -1) : NULL;
-	pweb = (plug->info->homepage) ? 
+	pweb = (plug->info->homepage) ?
 		   g_markup_escape_text(_(plug->info->homepage), -1) : NULL;
 
 	if (plug->error != NULL) {
@@ -2229,7 +2229,7 @@
 					 gpointer data)
 {
 	if (!strcmp(name, "/gaim/gtk/smileys/theme"))
-		load_smiley_theme((const char *)value, TRUE);
+		gaim_gtkthemes_load_smiley_theme((const char *)value, TRUE);
 }
 
 void
--- a/src/gtkthemes.c	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/gtkthemes.c	Mon Sep 12 13:25:41 2005 +0000
@@ -4,7 +4,7 @@
  * Gaim 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
@@ -31,22 +31,25 @@
 #include "gtkconv.h"
 #include "gtkdialogs.h"
 #include "gtkimhtml.h"
-
-struct smiley_list {
-	char *sml;
-	GSList *smileys;
-	struct smiley_list *next;
-};
+#include "gtkthemes.h"
 
 GSList *smiley_themes = NULL;
 struct smiley_theme *current_smiley_theme;
 
-void smiley_themeize(GtkWidget *imhtml)
+gboolean gaim_gtkthemes_smileys_disabled()
+{
+	if (!current_smiley_theme)
+		return 1;
+
+	return strcmp(current_smiley_theme->name, "none") == 0;
+}
+
+void gaim_gtkthemes_smiley_themeize(GtkWidget *imhtml)
 {
 	struct smiley_list *list;
 	if (!current_smiley_theme)
 		return;
-	
+
 	gtk_imhtml_remove_smileys(GTK_IMHTML(imhtml));
 	list = current_smiley_theme->list;
 	while (list) {
@@ -60,7 +63,7 @@
 	}
 }
 
-void load_smiley_theme(const char *file, gboolean load)
+void gaim_gtkthemes_load_smiley_theme(const char *file, gboolean load)
 {
 	FILE *f = g_fopen(file, "r");
 	char buf[256];
@@ -196,8 +199,8 @@
 			GaimConversation *conv = cnv->data;
 
 			if (GAIM_IS_GTK_CONVERSATION(conv)) {
-				smiley_themeize(GAIM_GTK_CONVERSATION(conv)->imhtml);
-				smiley_themeize(GAIM_GTK_CONVERSATION(conv)->entry);
+				gaim_gtkthemes_smiley_themeize(GAIM_GTK_CONVERSATION(conv)->imhtml);
+				gaim_gtkthemes_smiley_themeize(GAIM_GTK_CONVERSATION(conv)->entry);
 			}
 		}
 	}
@@ -206,7 +209,7 @@
 	fclose(f);
 }
 
-void smiley_theme_probe()
+void gaim_gtkthemes_smiley_theme_probe()
 {
 	GDir *dir;
 	const gchar *file;
@@ -227,7 +230,7 @@
 				 * We set the second argument to FALSE so that it doesn't load
 				 * the theme yet.
 				 */
-				load_smiley_theme(path, FALSE);
+				gaim_gtkthemes_load_smiley_theme(path, FALSE);
 				g_free(path);
 			}
 			g_dir_close(dir);
@@ -238,7 +241,7 @@
 	}
 }
 
-GSList *get_proto_smileys(const char *id) {
+GSList *gaim_gtkthemes_get_proto_smileys(const char *id) {
 	GaimPlugin *proto;
 	struct smiley_list *list, *def;
 
@@ -263,3 +266,14 @@
 
 	return list ? list->smileys : def->smileys;
 }
+
+void gaim_gtkthemes_init()
+{
+	if (current_smiley_theme == NULL) {
+		gaim_gtkthemes_smiley_theme_probe();
+		if (smiley_themes != NULL) {
+			struct smiley_theme *smile = smiley_themes->data;
+			gaim_gtkthemes_load_smiley_theme(smile->path, TRUE);
+		}
+	}
+}
--- a/src/gtkutils.c	Mon Sep 12 06:50:29 2005 +0000
+++ b/src/gtkutils.c	Mon Sep 12 13:25:41 2005 +0000
@@ -57,6 +57,7 @@
 #include "gtkdialogs.h"
 #include "gtkimhtml.h"
 #include "gtkimhtmltoolbar.h"
+#include "gtkthemes.h"
 #include "gtkutils.h"
 
 static guint accels_save_timer = 0;
@@ -93,7 +94,7 @@
 	g_signal_connect(G_OBJECT(imhtml), "url_clicked",
 					 G_CALLBACK(url_clicked_cb), NULL);
 
-	smiley_themeize(imhtml);
+	gaim_gtkthemes_smiley_themeize(imhtml);
 
 	gtk_imhtml_set_funcs(GTK_IMHTML(imhtml), &gtkimhtml_cbs);
 }
@@ -241,7 +242,7 @@
 	gtk_label_set_pattern(GTK_LABEL(label), "_");
 	gtk_container_add(GTK_CONTAINER(menuitem), label);
 	gtk_widget_show(label);
-/* FIXME: Go back and fix this 
+/* FIXME: Go back and fix this
 	gtk_widget_add_accelerator(menuitem, "activate", accel, str[0],
 				   GDK_MOD1_MASK, GTK_ACCEL_LOCKED);
 */
@@ -1206,17 +1207,17 @@
 	monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
 
 	push_in = FALSE;
-  
+
 	/*
 	 * The placement of popup menus horizontally works like this (with
 	 * RTL in parentheses)
 	 *
 	 * - If there is enough room to the right (left) of the mouse cursor,
 	 *   position the menu there.
-	 * 
-	 * - Otherwise, if if there is enough room to the left (right) of the 
+	 *
+	 * - Otherwise, if if there is enough room to the left (right) of the
 	 *   mouse cursor, position the menu there.
-	 * 
+	 *
 	 * - Otherwise if the menu is smaller than the monitor, position it
 	 *   on the side of the mouse cursor that has the most space available
 	 *
@@ -1236,7 +1237,7 @@
 	/* position horizontally */
 
 	/* the amount of space we need to position the menu. Note the
-	 * menu is offset "xthickness" pixels 
+	 * menu is offset "xthickness" pixels
 	 */
 	needed_width = requisition.width - xthickness;
 
@@ -1300,7 +1301,7 @@
 			*y = *y - ythickness;
 		else
 			*y = *y + ythickness - requisition.height + 1;
- 
+
 		*y = CLAMP (*y, monitor.y,
 			   monitor.y + monitor.height - requisition.height);
 	}