diff pidgin/gtksmiley.c @ 22874:02eda4bd2b22

Apply the custom smiley patches from #1187, from Jorge Villaseo (Masca) and Mauro Srgio Ferreira Brasil. I have not applied the bits on MSN yet. I will have to look at it later, but I would rather someone else more familiar with the MSN code look at it first. I changed some bits of the applied patch (whitespacing, camelcasing etc.), and the bit that required a major version bump (in gtkthemes.h). There are a few more things that need to be done for this to be merged back to i.p.p.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Tue, 19 Feb 2008 19:41:56 +0000
parents
children db31bbdf355b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtksmiley.c	Tue Feb 19 19:41:56 2008 +0000
@@ -0,0 +1,562 @@
+/**
+ * @file gtksmiley.c GTK+ Smiley Manager API
+ * @ingroup pidgin
+ */
+
+/*
+ * 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 "internal.h"
+#include "pidgin.h"
+
+#include "debug.h"
+#include "notify.h"
+#include "smiley.h"
+
+#include "gtkimhtml.h"
+#include "gtksmiley.h"
+
+typedef struct
+{
+	GtkWidget *parent;
+	GtkWidget *smile;
+	GtkWidget *file_chooser;
+	gchar *filename;
+} PidginSmiley;
+
+typedef struct
+{
+	GtkWidget *window;
+
+	GtkWidget *treeview;
+	GtkListStore *model;
+} SmileyManager;
+
+enum
+{
+	ICON,
+	SHORTCUT,
+	DATA,
+	N_COL
+};
+
+static SmileyManager *smiley_manager = NULL;
+static GSList *gtk_smileys = NULL;
+
+static void
+pidgin_smiley_destroy(PidginSmiley *smiley)
+{
+	gtk_widget_destroy(smiley->parent);
+	g_free(smiley->filename);
+	g_free(smiley);
+}
+
+/******************************************************************************
+ * GtkIMHtmlSmileys stuff
+ *****************************************************************************/
+static void add_gtkimhtml_to_list(GtkIMHtmlSmiley *gtksmiley)
+{
+	gtk_smileys = g_slist_prepend(gtk_smileys, gtksmiley);
+
+	purple_debug_info("gtksmiley", "adding %s to gtk_smileys\n", gtksmiley->smile);
+}
+
+static GtkIMHtmlSmiley *smiley_purple_to_gtkimhtml(PurpleSmiley *smiley)
+{
+	GtkIMHtmlSmiley *gtksmiley;
+	gchar *filename;
+	const gchar *file;
+
+	file = purple_imgstore_get_filename(smiley->img);
+
+	filename = g_build_filename(purple_smileys_get_storing_dir(),file, NULL);
+
+	gtksmiley = g_new0(GtkIMHtmlSmiley,1);
+	gtksmiley->smile = g_strdup(smiley->shortcut);
+	gtksmiley->hidden = FALSE;
+	gtksmiley->file = filename;
+	gtksmiley->flags = GTK_IMHTML_SMILEY_CUSTOM;
+
+	return gtksmiley;
+}
+
+void pidgin_smiley_add_to_list(PurpleSmiley *smiley)
+{
+	GtkIMHtmlSmiley *gtksmiley;
+
+	gtksmiley = smiley_purple_to_gtkimhtml(smiley);
+	add_gtkimhtml_to_list(gtksmiley);
+}
+
+static void destroy_gtksmiley(GtkIMHtmlSmiley *gtksmiley)
+{
+	purple_debug_info("gtksmiley", "destroying %s\n", gtksmiley->smile);
+	g_free(gtksmiley->smile);
+	g_free(gtksmiley->file);
+	g_free(gtksmiley);
+}
+
+void pidgin_smiley_del_from_list(PurpleSmiley *smiley)
+{
+	GSList *list = NULL;
+	GtkIMHtmlSmiley *gtksmiley;
+
+	if (gtk_smileys == NULL)
+		return;
+
+	list = gtk_smileys;
+
+	for (; list; list = list->next) {
+		gtksmiley = (GtkIMHtmlSmiley*)list->data;
+
+		if (strcmp(gtksmiley->smile, smiley->shortcut))
+			continue;
+
+		destroy_gtksmiley(gtksmiley);
+		list = g_slist_delete_link(list, list);
+		break;
+	}
+
+	gtk_smileys = list;
+}
+
+void pidgin_smileys_init(void)
+{
+	GList *purple_smileys;
+	PurpleSmiley *smiley;
+
+	if (gtk_smileys != NULL)
+		return;
+
+	purple_smileys = purple_smileys_get_all();
+
+	for (; purple_smileys; purple_smileys = purple_smileys->next) {
+		smiley = (PurpleSmiley*)purple_smileys->data;
+
+		pidgin_smiley_add_to_list(smiley);
+	}
+}
+
+void pidgin_smileys_uninit(void)
+{
+	GSList *list;
+	GtkIMHtmlSmiley *gtksmiley;
+
+	list = gtk_smileys;
+
+	if (list == NULL)
+		return;
+
+	for (; list; list = g_slist_delete_link(list, list)) {
+		gtksmiley = (GtkIMHtmlSmiley*)list->data;
+		destroy_gtksmiley(gtksmiley);
+	}
+
+	gtk_smileys = NULL;
+}
+
+GSList *pidgin_smileys_get_all(void)
+{
+	return gtk_smileys;
+}
+
+/******************************************************************************
+ * Manager stuff
+ *****************************************************************************/
+
+static void refresh_list(void);
+
+/******************************************************************************
+ * The Add dialog
+ ******************************************************************************/
+
+static void do_add(GtkWidget *widget, PidginSmiley *s)
+{
+	const gchar *entry;
+	PurpleSmiley *emoticon;
+	gchar *file;
+
+	entry = gtk_entry_get_text(GTK_ENTRY(s->smile));
+
+	if (s->filename == NULL || *entry == 0) {
+		purple_notify_error(s->parent, _("Custom Smiley"),
+				_("More Data needed"), NULL);
+		return;
+	}
+
+	purple_debug_info("gtksmiley", "adding a new smiley\n");
+	file = g_path_get_basename(s->filename);
+	emoticon = purple_smiley_new_from_file(entry, s->filename, file);
+	purple_smileys_add(emoticon);
+	g_free(file);
+
+	if (gtk_smileys != NULL)
+		pidgin_smiley_add_to_list(emoticon);
+
+	if (smiley_manager != NULL)
+		refresh_list();
+
+	gtk_widget_destroy(s->parent);
+}
+
+static void do_add_select_cb(GtkWidget *widget, gint resp, PidginSmiley *s)
+{
+	switch (resp) {
+		case GTK_RESPONSE_ACCEPT:
+			do_add(widget, s);
+			break;
+		case GTK_RESPONSE_DELETE_EVENT:
+		case GTK_RESPONSE_CANCEL:
+			gtk_widget_destroy(s->parent);
+			break;
+		default:
+			purple_debug_error("gtksmiley", "no valid response\n");
+			break;
+	}
+}
+
+static void do_add_file_cb(GtkWidget *widget, gint resp, PidginSmiley *s)
+{
+	if (resp == GTK_RESPONSE_ACCEPT)
+		s->filename = gtk_file_chooser_get_filename(
+				GTK_FILE_CHOOSER(s->file_chooser));
+}
+
+void pidgin_smiley_add(GtkWidget *widget)
+{
+	GtkWidget *vbox;
+	GtkWidget *hbox;
+	GtkWidget *label;
+	GtkWidget *filech;
+	GtkWidget *window;
+
+	PidginSmiley *s = g_new0(PidginSmiley, 1);
+
+	window = gtk_dialog_new_with_buttons(_("Add Smiley"),
+			GTK_WINDOW(widget),
+			GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+			GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
+			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+			NULL);
+	s->parent = window;
+
+	gtk_container_set_border_width(GTK_CONTAINER(window), PIDGIN_HIG_BORDER);
+
+	g_signal_connect(window, "response", G_CALLBACK(do_add_select_cb), s);
+
+	/* The vbox */
+	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
+	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), vbox);
+	gtk_widget_show(vbox);
+
+	/* The hbox */
+	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
+	gtk_container_add(GTK_CONTAINER(GTK_VBOX(vbox)), hbox);
+
+	label = gtk_label_new(_("Select the file:"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show(label);
+
+	s->file_chooser = gtk_file_chooser_dialog_new(_("Custom Smiley"),
+		GTK_WINDOW(window),
+		GTK_FILE_CHOOSER_ACTION_OPEN,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+		NULL);
+
+	g_signal_connect(s->file_chooser, "response", G_CALLBACK(do_add_file_cb), s);
+
+	filech = gtk_file_chooser_button_new_with_dialog(GTK_WIDGET(s->file_chooser));
+
+	gtk_box_pack_end(GTK_BOX(hbox), filech, TRUE, TRUE, 0);
+	gtk_widget_show(filech);
+
+	gtk_widget_show(hbox);
+
+	/* info */
+	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
+	gtk_container_add(GTK_CONTAINER(GTK_VBOX(vbox)),hbox);
+
+	/* Smiley shortcut */
+	label = gtk_label_new(_("Define Smiley's shortcut"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show(label);
+
+	s->smile = gtk_entry_new();
+	gtk_entry_set_activates_default(GTK_ENTRY(s->smile), TRUE);
+	gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_WIDGET(s->smile));
+
+	g_signal_connect(s->smile, "activate", G_CALLBACK(do_add), s);
+
+	gtk_box_pack_end(GTK_BOX(hbox), s->smile, FALSE, FALSE, 0);
+	gtk_widget_show(s->smile);
+
+	gtk_widget_show(hbox);
+
+	gtk_widget_show(GTK_WIDGET(window));
+	g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(pidgin_smiley_destroy), s);
+	g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(purple_notify_close_with_handle), s);
+}
+
+/******************************************************************************
+ * Delete smiley
+ *****************************************************************************/
+static void delete_foreach(GtkTreeModel *model, GtkTreePath *path,
+		GtkTreeIter *iter, gpointer data)
+{
+	PurpleSmiley *smiley;
+	char *shortcut;
+	SmileyManager *dialog;
+
+	dialog = (SmileyManager*)data;
+
+	gtk_tree_model_get(model, iter,
+			SHORTCUT, &shortcut,
+			-1);
+
+	purple_debug_info("gtksmiley", "delete_foreach shortcut = %s\n", shortcut);
+
+	smiley = purple_smileys_find_by_shortcut(shortcut);
+
+	if(smiley == NULL)
+		purple_debug_error("gtksmiley", "%s not found\n", shortcut);
+	else {
+		pidgin_smiley_del_from_list(smiley);
+		purple_smiley_delete(smiley);
+	}
+
+	g_free(shortcut);
+}
+
+static void smiley_delete(SmileyManager *dialog)
+{
+	GtkTreeSelection *selection;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
+	gtk_tree_selection_selected_foreach(selection, delete_foreach, dialog);
+}
+/******************************************************************************
+ * The Smiley Manager
+ *****************************************************************************/
+static void add_columns(GtkWidget *treeview, SmileyManager *dialog)
+{
+	GtkCellRenderer *rend;
+	GtkTreeViewColumn *column;
+
+	/* Icon */
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_title(column, _("Smiley"));
+	gtk_tree_view_column_set_resizable(column, TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+	rend = gtk_cell_renderer_pixbuf_new();
+	gtk_tree_view_column_pack_start(column, rend, FALSE);
+	gtk_tree_view_column_add_attribute(column, rend, "pixbuf", ICON);
+
+	/* Shortcut */
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_title(column, _("Shortcut"));
+	gtk_tree_view_column_set_resizable(column, TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+	rend = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(column, rend, TRUE);
+	gtk_tree_view_column_add_attribute(column, rend, "text", SHORTCUT);
+}
+
+static void store_smiley_add(PurpleSmiley *smiley)
+{
+	GtkTreeIter iter;
+	PurpleStoredImage *img;
+	GdkPixbuf *sized_smiley = NULL;
+
+	if (smiley_manager == NULL)
+		return;
+
+	img = purple_smiley_get_stored_image(smiley);
+
+	if (img != NULL) {
+		GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
+		GdkPixbuf *smiley_image = NULL;
+
+		gdk_pixbuf_loader_write(loader, purple_imgstore_get_data(img),
+				purple_imgstore_get_size(img), NULL);
+		gdk_pixbuf_loader_close(loader, NULL);
+		smiley_image = gdk_pixbuf_loader_get_pixbuf(loader);
+
+		purple_imgstore_unref(img);
+
+		if (smiley_image != NULL)
+			sized_smiley = gdk_pixbuf_scale_simple(smiley_image,
+					22, 22, GDK_INTERP_HYPER);
+
+		g_object_unref(loader);
+	}
+
+
+	gtk_list_store_append(smiley_manager->model, &iter);
+
+	gtk_list_store_set(smiley_manager->model, &iter,
+			ICON, sized_smiley,
+			SHORTCUT, smiley->shortcut,
+			DATA, NULL,
+			-1);
+
+	if (sized_smiley != NULL)
+		g_object_unref(G_OBJECT(sized_smiley));
+}
+
+static void populate_smiley_list(SmileyManager *dialog)
+{
+	GList *list;
+	PurpleSmiley *emoticon;
+
+	gtk_list_store_clear(dialog->model);
+
+	for(list = purple_smileys_get_all(); list != NULL; list = list->next) {
+		emoticon = (PurpleSmiley*)list->data;
+
+		store_smiley_add(emoticon);
+	}
+}
+
+static void smile_selected_cb(GtkTreeSelection *sel, SmileyManager *dialog)
+{
+	gint selected;
+
+	selected = gtk_tree_selection_count_selected_rows(sel);
+
+	gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog->window),
+			GTK_RESPONSE_NO, selected > 0);
+}
+
+static GtkWidget *smiley_list_create(SmileyManager *dialog)
+{
+	GtkWidget *sw;
+	GtkWidget *treeview;
+	GtkTreeSelection *sel;
+
+	sw = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
+			GTK_POLICY_AUTOMATIC,
+			GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
+			GTK_SHADOW_NONE);
+	gtk_widget_show(sw);
+
+	/* Create the list model */
+	dialog->model = gtk_list_store_new(N_COL,
+			GDK_TYPE_PIXBUF,	/* ICON */
+			G_TYPE_STRING,		/* SHORTCUT */
+			G_TYPE_POINTER		/* DATA */
+			);
+
+	/* the actual treeview */
+	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
+	dialog->treeview = treeview;
+	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
+
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+	gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
+	gtk_container_add(GTK_CONTAINER(sw), treeview);
+
+	g_signal_connect(G_OBJECT(sel), "changed",
+			G_CALLBACK(smile_selected_cb), dialog);
+
+	gtk_widget_show(treeview);
+
+	add_columns(treeview, dialog);
+	populate_smiley_list(dialog);
+
+	return sw;
+}
+
+static void refresh_list()
+{
+	populate_smiley_list(smiley_manager);
+}
+
+static void smiley_manager_select_cb(GtkWidget *widget, gint resp, SmileyManager *dialog)
+{
+	switch (resp) {
+		case GTK_RESPONSE_YES:
+			pidgin_smiley_add(dialog->window);
+			break;
+		case GTK_RESPONSE_NO:
+			smiley_delete(dialog);
+			refresh_list();
+			break;
+		case GTK_RESPONSE_DELETE_EVENT:
+		case GTK_RESPONSE_CLOSE:
+			gtk_widget_destroy(dialog->window);
+			g_free(smiley_manager);
+			smiley_manager = NULL;
+			break;
+		default:
+			purple_debug_info("gtksmiley", "No valid selection\n");
+			break;
+	}
+}
+
+void pidgin_smiley_manager_show(void)
+{
+	SmileyManager *dialog;
+	GtkWidget *win;
+	GtkWidget *sw;
+	GtkWidget *vbox;
+
+	if (smiley_manager) {
+		gtk_window_present(GTK_WINDOW(smiley_manager->window));
+		return;
+	}
+
+	dialog = g_new0(SmileyManager, 1);
+	smiley_manager = dialog;
+
+	dialog->window = win = gtk_dialog_new_with_buttons(
+			_("Custom Smiley Manager"),
+			NULL,
+			GTK_DIALOG_DESTROY_WITH_PARENT,
+			GTK_STOCK_ADD, GTK_RESPONSE_YES,
+			GTK_STOCK_DELETE, GTK_RESPONSE_NO,
+			GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+			NULL);
+
+	gtk_window_set_default_size(GTK_WINDOW(win), 50, 400);
+	gtk_container_set_border_width(GTK_CONTAINER(win),PIDGIN_HIG_BORDER);
+
+	g_signal_connect(win, "response", G_CALLBACK(smiley_manager_select_cb),
+			dialog);
+
+	/* The vbox */
+	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
+	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(win)->vbox), vbox);
+	gtk_widget_show(vbox);
+
+	/* get the scrolled window with all stuff */
+	sw = smiley_list_create(dialog);
+	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
+	gtk_widget_show(sw);
+
+	gtk_widget_show(win);
+}
+