changeset 25515:37af7de81430

propagate from branch 'im.pidgin.pidgin' (head 4aabd11d86454556c0ed6e7c67640fa2a2ea5d6b) to branch 'im.pidgin.pidgin.yaz' (head 8376a42bcad5e1ffeaa542cec3a258adb1b83c1a)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Wed, 20 Jun 2007 04:56:08 +0000
parents 4cc042912ac2 (diff) 90d558470507 (current diff)
children 708198aadad8
files pidgin/gtkconv.c pidgin/gtkmain.c
diffstat 28 files changed, 352 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Mon Jun 18 03:20:15 2007 +0000
+++ b/ChangeLog.API	Wed Jun 20 04:56:08 2007 +0000
@@ -71,10 +71,18 @@
 		* gtk_imhtml_animation_new
 		    Can be used for inserting an animated image into an IMHTML.
 		* pidgin_menu_position_func_helper
+		* pidgin_blist_get_name_markup, returns the buddy list markup
+		  text for a given buddy.
 
 		Changed:
 		* pidgin_append_menu_action returns the menuitem added to the menu.
 		* pidgin_separator returns the separator added to the menu.
+		* PidginConversation has struct members to handle the new info
+		  pane:
+		  	* infopane
+			* infopane_hbox
+			* infopane_model
+			* infopane_iter
 
 	Finch:
 		Added:
--- a/finch/libgnt/gntfilesel.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/finch/libgnt/gntfilesel.c	Wed Jun 20 04:56:08 2007 +0000
@@ -46,6 +46,7 @@
 static GntWindowClass *parent_class = NULL;
 static guint signals[SIGS] = { 0 };
 static void (*orig_map)(GntWidget *widget);
+static void (*orig_size_request)(GntWidget *widget);
 
 static void
 gnt_file_sel_destroy(GntWidget *widget)
@@ -552,6 +553,19 @@
 }
 
 static void
+gnt_file_sel_size_request(GntWidget *widget)
+{
+	GntFileSel *sel;
+	if (widget->priv.height > 0)
+		return;
+
+	sel = GNT_FILE_SEL(widget);
+	sel->dirs->priv.height = 16;
+	sel->files->priv.height = 16;
+	orig_size_request(widget);
+}
+
+static void
 gnt_file_sel_class_init(GntFileSelClass *klass)
 {
 	GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass);
@@ -560,6 +574,8 @@
 	kl->destroy = gnt_file_sel_destroy;
 	orig_map = kl->map;
 	kl->map = gnt_file_sel_map;
+	orig_size_request = kl->size_request;
+	kl->size_request = gnt_file_sel_size_request;
 
 	signals[SIG_FILE_SELECTED] = 
 		g_signal_new("file_selected",
--- a/finch/libgnt/gntmain.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/finch/libgnt/gntmain.c	Wed Jun 20 04:56:08 2007 +0000
@@ -429,10 +429,14 @@
 
 	setup_io();
 
+#ifdef NO_WIDECHAR
+	ascii_only = TRUE;
+#else
 	if (locale && (strstr(locale, "UTF") || strstr(locale, "utf")))
 		ascii_only = FALSE;
 	else
 		ascii_only = TRUE;
+#endif
 
 	initscr();
 	typeahead(-1);
--- a/finch/libgnt/gnttree.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/finch/libgnt/gnttree.c	Wed Jun 20 04:56:08 2007 +0000
@@ -303,7 +303,7 @@
 
 		notfirst = TRUE;
 
-		if (len > width - 2) {
+		if (len > width) {
 			len = width - 1;
 			cut = TRUE;
 		}
--- a/libpurple/account.h	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/account.h	Wed Jun 20 04:56:08 2007 +0000
@@ -369,7 +369,7 @@
  *                  as a NULL-terminated list of id/value pairs.
  */
 void purple_account_set_status(PurpleAccount *account, const char *status_id,
-							 gboolean active, ...);
+							 gboolean active, ...) G_GNUC_NULL_TERMINATED;
 
 
 /**
--- a/libpurple/accountopt.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/accountopt.c	Wed Jun 20 04:56:08 2007 +0000
@@ -22,6 +22,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include "internal.h"
+
 #include "accountopt.h"
 #include "util.h"
 
--- a/libpurple/cmds.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/cmds.c	Wed Jun 20 04:56:08 2007 +0000
@@ -22,6 +22,8 @@
 
 #include <string.h>
 
+#include "internal.h"
+
 #include "account.h"
 #include "util.h"
 #include "cmds.h"
--- a/libpurple/core.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/core.c	Wed Jun 20 04:56:08 2007 +0000
@@ -512,7 +512,7 @@
 
 				if ((linklen = readlink(name, buf, sizeof(buf) - 1) == -1))
 				{
-					char *name_utf8 = g_filename_to_utf8(name);
+					char *name_utf8 = g_filename_to_utf8(name, -1, NULL, NULL, NULL);
 					purple_debug_error("core", "Error reading symlink %s: %s. Please report this at http://developer.pidgin.im\n",
 					                   name_utf8, strerror(errno));
 					g_free(name_utf8);
--- a/libpurple/imgstore.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/imgstore.c	Wed Jun 20 04:56:08 2007 +0000
@@ -25,6 +25,8 @@
 */
 
 #include <glib.h>
+#include "internal.h"
+
 #include "dbus-maybe.h"
 #include "debug.h"
 #include "imgstore.h"
--- a/libpurple/internal.h	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/internal.h	Wed Jun 20 04:56:08 2007 +0000
@@ -111,6 +111,14 @@
 # include <unistd.h>
 #endif
 
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+#  define MAXPATHLEN PATH_MAX
+# else
+#  define MAXPATHLEN 1024
+# endif
+#endif
+
 #ifndef HOST_NAME_MAX
 # define HOST_NAME_MAX 255
 #endif
@@ -170,6 +178,14 @@
 #	endif
 #endif
 
+#ifndef G_GNUC_NULL_TERMINATED
+#	if     __GNUC__ >= 4
+#		define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
+#	else
+#		define G_GNUC_NULL_TERMINATED
+#	endif
+#endif
+
 /* Safer ways to work with static buffers. When using non-static
  * buffers, either use g_strdup_* functions (preferred) or use
  * g_strlcpy/g_strlcpy directly. */
--- a/libpurple/mime.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/mime.c	Wed Jun 20 04:56:08 2007 +0000
@@ -29,6 +29,8 @@
 #include <glib/glist.h>
 #include <glib/gstring.h>
 
+#include "internal.h"
+
 /* this should become "util.h" if we ever get this into purple proper */
 #include "debug.h"
 #include "mime.h"
--- a/libpurple/ntlm.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/ntlm.c	Wed Jun 20 04:56:08 2007 +0000
@@ -25,6 +25,8 @@
 
 #include <glib.h>
 #include <stdlib.h>
+#include "internal.h"
+
 #include "util.h"
 #include "ntlm.h"
 #include "cipher.h"
--- a/libpurple/prpl.h	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/prpl.h	Wed Jun 20 04:56:08 2007 +0000
@@ -378,7 +378,7 @@
  *                  beginning with the value for @a attr_id.
  */
 void purple_prpl_got_account_status(PurpleAccount *account,
-								  const char *status_id, ...);
+								  const char *status_id, ...) G_GNUC_NULL_TERMINATED;
 /**
  * Notifies Purple that a user's idle state and time have changed.
  *
@@ -418,7 +418,7 @@
  *                  beginning with the value for @a attr_id.
  */
 void purple_prpl_got_user_status(PurpleAccount *account, const char *name,
-							   const char *status_id, ...);
+							   const char *status_id, ...) G_GNUC_NULL_TERMINATED;
 
 /**
  * Notifies libpurple that a user's status has been deactivated
--- a/libpurple/request.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/request.c	Wed Jun 20 04:56:08 2007 +0000
@@ -22,6 +22,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include "internal.h"
+
 #include "notify.h"
 #include "request.h"
 #include "debug.h"
--- a/libpurple/request.h	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/request.h	Wed Jun 20 04:56:08 2007 +0000
@@ -1228,7 +1228,7 @@
 						  const char *ok_text, GCallback ok_cb,
 						  const char *cancel_text, GCallback cancel_cb,
 						  PurpleAccount *account, const char *who, PurpleConversation *conv,
-						  void *user_data, ...);
+						  void *user_data, ...) G_GNUC_NULL_TERMINATED;
 
 /**
  * Prompts the user for multiple-choice input.
--- a/libpurple/roomlist.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/roomlist.c	Wed Jun 20 04:56:08 2007 +0000
@@ -25,6 +25,8 @@
 
 #include <glib.h>
 
+#include "internal.h"
+
 #include "account.h"
 #include "connection.h"
 #include "debug.h"
--- a/libpurple/savedstatuses.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/savedstatuses.c	Wed Jun 20 04:56:08 2007 +0000
@@ -29,6 +29,7 @@
 #include "notify.h"
 #include "savedstatuses.h"
 #include "dbus-maybe.h"
+#include "request.h"
 #include "status.h"
 #include "util.h"
 #include "xmlnode.h"
@@ -110,6 +111,7 @@
 	g_return_if_fail(substatus != NULL);
 
 	g_free(substatus->message);
+	purple_request_close_with_handle(substatus);
 	PURPLE_DBUS_UNREGISTER_POINTER(substatus);
 	g_free(substatus);
 }
@@ -128,7 +130,7 @@
 		status->substatuses = g_list_remove(status->substatuses, substatus);
 		free_saved_status_sub(substatus);
 	}
-
+	purple_request_close_with_handle(status);
 	PURPLE_DBUS_UNREGISTER_POINTER(status);
 	g_free(status);
 }
@@ -569,6 +571,9 @@
 
 	schedule_save();
 
+	purple_signal_emit(purple_savedstatuses_get_handle(), "savedstatus-added",
+		status);
+
 	return status;
 }
 
@@ -584,6 +589,9 @@
 	status->title = g_strdup(title);
 
 	schedule_save();
+
+	purple_signal_emit(purple_savedstatuses_get_handle(),
+			"savedstatus-modified", status);
 }
 
 void
@@ -594,6 +602,8 @@
 	status->type = type;
 
 	schedule_save();
+	purple_signal_emit(purple_savedstatuses_get_handle(),
+			"savedstatus-modified", status);
 }
 
 void
@@ -608,6 +618,9 @@
 		status->message = g_strdup(message);
 
 	schedule_save();
+
+	purple_signal_emit(purple_savedstatuses_get_handle(),
+			"savedstatus-modified", status);
 }
 
 void
@@ -637,6 +650,8 @@
 	substatus->message = g_strdup(message);
 
 	schedule_save();
+	purple_signal_emit(purple_savedstatuses_get_handle(),
+			"savedstatus-modified", saved_status);
 }
 
 void
@@ -660,6 +675,9 @@
 			return;
 		}
 	}
+
+	purple_signal_emit(purple_savedstatuses_get_handle(),
+			"savedstatus-modified", saved_status);
 }
 
 /*
@@ -683,16 +701,12 @@
 	}
 }
 
-gboolean
-purple_savedstatus_delete(const char *title)
+void
+purple_savedstatus_delete_by_status(PurpleSavedStatus *status)
 {
-	PurpleSavedStatus *status;
 	time_t creation_time, current, idleaway;
 
-	status = purple_savedstatus_find(title);
-
-	if (status == NULL)
-		return FALSE;
+	g_return_if_fail(status != NULL);
 
 	saved_statuses = g_list_remove(saved_statuses, status);
 	creation_time = purple_savedstatus_get_creation_time(status);
@@ -713,6 +727,25 @@
 	if (idleaway == creation_time)
 		purple_prefs_set_int("/purple/savedstatus/idleaway", 0);
 
+	purple_signal_emit(purple_savedstatuses_get_handle(),
+			"savedstatus-deleted", status);
+}
+
+gboolean
+purple_savedstatus_delete(const char *title)
+{
+	PurpleSavedStatus *status;
+
+	status = purple_savedstatus_find(title);
+
+	if (status == NULL)
+		return FALSE;
+
+	if (purple_savedstatus_get_current() == status)
+		return FALSE;
+
+	purple_savedstatus_delete_by_status(status);
+
 	return TRUE;
 }
 
@@ -1171,6 +1204,21 @@
 					 purple_value_new(PURPLE_TYPE_SUBTYPE,
 									PURPLE_SUBTYPE_SAVEDSTATUS));
 
+	purple_signal_register(handle, "savedstatus-added",
+		purple_marshal_VOID__POINTER, NULL, 1,
+		purple_value_new(PURPLE_TYPE_SUBTYPE,
+			PURPLE_SUBTYPE_SAVEDSTATUS));
+
+	purple_signal_register(handle, "savedstatus-deleted",
+		purple_marshal_VOID__POINTER, NULL, 1,
+		purple_value_new(PURPLE_TYPE_SUBTYPE,
+			PURPLE_SUBTYPE_SAVEDSTATUS));
+
+	purple_signal_register(handle, "savedstatus-modified",
+		purple_marshal_VOID__POINTER, NULL, 1,
+		purple_value_new(PURPLE_TYPE_SUBTYPE,
+			PURPLE_SUBTYPE_SAVEDSTATUS));
+
 	purple_signal_connect(purple_accounts_get_handle(), "account-removed",
 			handle,
 			PURPLE_CALLBACK(purple_savedstatus_unset_all_substatuses),
--- a/libpurple/savedstatuses.h	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/savedstatuses.h	Wed Jun 20 04:56:08 2007 +0000
@@ -149,6 +149,16 @@
 gboolean purple_savedstatus_delete(const char *title);
 
 /**
+ * Delete a saved status.  This removes the saved status from the list
+ * of saved statuses, and writes the revised list to status.xml.
+ *
+ * @param saved_status the status to delete, the pointer is invalid after
+ *        the call
+ *
+ */
+void purple_savedstatus_delete_by_status(PurpleSavedStatus *saved_status);
+
+/**
  * Returns all saved statuses.
  *
  * @constreturn A list of saved statuses.
--- a/libpurple/status.h	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/status.h	Wed Jun 20 04:56:08 2007 +0000
@@ -227,7 +227,7 @@
 												gboolean independent,
 												const char *attr_id,
 												const char *attr_name,
-												PurpleValue *attr_value, ...);
+												PurpleValue *attr_value, ...) G_GNUC_NULL_TERMINATED;
 
 /**
  * Destroys a status type.
@@ -270,7 +270,7 @@
  * @param ...         Additional attribute information.
  */
 void purple_status_type_add_attrs(PurpleStatusType *status_type, const char *id,
-								const char *name, PurpleValue *value, ...);
+								const char *name, PurpleValue *value, ...) G_GNUC_NULL_TERMINATED;
 
 /**
  * Adds multiple attributes to a status type using a va_list.
--- a/libpurple/whiteboard.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/libpurple/whiteboard.c	Wed Jun 20 04:56:08 2007 +0000
@@ -23,6 +23,7 @@
 
 #include <string.h>
 
+#include "internal.h"
 #include "whiteboard.h"
 #include "prpl.h"
 
--- a/pidgin/gtkblist.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/pidgin/gtkblist.c	Wed Jun 20 04:56:08 2007 +0000
@@ -3282,7 +3282,7 @@
 	return ret;
 }
 
-static gchar *pidgin_blist_get_name_markup(PurpleBuddy *b, gboolean selected)
+gchar *pidgin_blist_get_name_markup(PurpleBuddy *b, gboolean selected)
 {
 	const char *name;
 	char *esc, *text = NULL;
--- a/pidgin/gtkblist.h	Mon Jun 18 03:20:15 2007 +0000
+++ b/pidgin/gtkblist.h	Wed Jun 20 04:56:08 2007 +0000
@@ -360,4 +360,13 @@
 void pidgin_blist_set_headline(const char *text, GdkPixbuf *pixbuf, GCallback callback, gpointer user_data,
 		GDestroyNotify destroy);
 
+/**
+ * Returns a buddy's Pango markup appropriate for setting in a GtkCellRenderer.
+ *
+ * @param buddy The buddy to return markup from
+ * @param selected  Whether this buddy is selected. If TRUE, the markup will not change the color.
+ * @return The markup for this buddy
+ */
+gchar *pidgin_blist_get_name_markup(PurpleBuddy *buddy, gboolean selected);
+
 #endif /* _PIDGINBLIST_H_ */
--- a/pidgin/gtkconv.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/pidgin/gtkconv.c	Wed Jun 20 04:56:08 2007 +0000
@@ -82,6 +82,12 @@
 	PIDGIN_CONV_COLORIZE_TITLE		= 1 << 6
 }PidginConvFields;
 
+enum {
+	ICON_COLUMN,
+	TEXT_COLUMN,
+	NUM_COLUMNS
+} PidginInfopaneColumns;
+
 #define	PIDGIN_CONV_ALL	((1 << 7) - 1)
 
 #define SEND_COLOR "#204a87"
@@ -2354,6 +2360,9 @@
 	gtk_image_set_from_pixbuf(GTK_IMAGE(gtkconv->icon), status);
 	gtk_image_set_from_pixbuf(GTK_IMAGE(gtkconv->menu_icon), status);
 
+	gtk_list_store_set(gtkconv->infopane_model, &(gtkconv->infopane_iter),
+			ICON_COLUMN, status, -1);
+
 	if (status != NULL)
 		g_object_unref(status);
 
@@ -2413,11 +2422,7 @@
 			PURPLE_ICON_SCALE_DISPLAY, &scale_width, &scale_height);
 
 	/* this code is ugly, and scares me */
-	scale = gdk_pixbuf_scale_simple(buf,
-		MAX(gdk_pixbuf_get_width(buf) * scale_width /
-		    gdk_pixbuf_animation_get_width(gtkconv->u.im->anim), 1),
-		MAX(gdk_pixbuf_get_height(buf) * scale_height /
-		    gdk_pixbuf_animation_get_height(gtkconv->u.im->anim), 1),
+	scale = gdk_pixbuf_scale_simple(buf, 32, 32,
 		GDK_INTERP_BILINEAR);
 
 	gtk_image_set_from_pixbuf(GTK_IMAGE(gtkconv->u.im->icon), scale);
@@ -4407,6 +4412,8 @@
 setup_common_pane(PidginConversation *gtkconv)
 {
 	GtkWidget *paned, *vbox, *frame, *imhtml_sw;
+	GtkCellRenderer *rend;
+	GtkTreePath *path;
 	PurpleConversation *conv = gtkconv->active_conv;
 	gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT);
 	GtkPolicyType imhtml_sw_hscroll;
@@ -4419,6 +4426,35 @@
 	gtk_paned_pack1(GTK_PANED(paned), vbox, TRUE, TRUE);
 	gtk_widget_show(vbox);
 
+	/* Setup the info pane */
+	gtkconv->infopane_hbox = gtk_hbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), gtkconv->infopane_hbox, FALSE, FALSE, 0);
+	gtk_widget_show(gtkconv->infopane_hbox);
+
+	gtkconv->infopane = gtk_cell_view_new();
+	gtkconv->infopane_model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+	gtk_cell_view_set_model(GTK_CELL_VIEW(gtkconv->infopane), gtkconv->infopane_model);
+	gtk_list_store_append(gtkconv->infopane_model, &(gtkconv->infopane_iter));
+	gtk_box_pack_start(GTK_BOX(gtkconv->infopane_hbox), gtkconv->infopane, TRUE, TRUE, 0);
+        path = gtk_tree_path_new_from_string("0");
+        gtk_cell_view_set_displayed_row(GTK_CELL_VIEW(gtkconv->infopane), path);
+	gtk_widget_set_size_request(gtkconv->infopane, -1, 32);
+	gtk_widget_show(gtkconv->infopane);
+
+	rend = gtk_cell_renderer_pixbuf_new();
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkconv->infopane), rend, FALSE);
+	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkconv->infopane), rend, "pixbuf", ICON_COLUMN, NULL);
+        g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL);
+
+	rend = gtk_cell_renderer_text_new();
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkconv->infopane), rend, TRUE);
+	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkconv->infopane), rend, "markup", TEXT_COLUMN, NULL);
+        g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL);
+
+#if GTK_CHECK_VERSION(2, 6, 0)
+	g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+#endif
+
 	/* Setup the gtkimhtml widget */
 	frame = pidgin_create_imhtml(FALSE, &gtkconv->imhtml, NULL, &imhtml_sw);
 	if (chat) {
@@ -6151,6 +6187,8 @@
 		char *title, *title_tmp;
 		PurpleConvIm *im = NULL;
 		PurpleAccount *account = purple_conversation_get_account(conv);
+		PurpleBuddy *buddy; 
+		char *markup;
 		AtkObject *accessibility_obj;
 		gboolean ellipsis = FALSE;
 		/* I think this is a little longer than it needs to be but I'm lazy. */
@@ -6167,6 +6205,17 @@
 		else
 			title = g_strdup(purple_conversation_get_title(conv));
 
+		buddy = purple_find_buddy(account, conv->name);
+		if (buddy)
+			markup = pidgin_blist_get_name_markup(buddy, FALSE);
+		else
+			markup = title;
+		gtk_list_store_set(gtkconv->infopane_model, &(gtkconv->infopane_iter),
+				TEXT_COLUMN, markup, -1);
+	
+		if (title != markup)
+			g_free(markup);
+
 		*style = '\0';
 
 		if (!GTK_WIDGET_REALIZED(gtkconv->tab_label))
@@ -6338,7 +6387,6 @@
 	GdkPixbuf *buf;
 
 	GtkWidget *event;
-	GtkWidget *frame;
 	GdkPixbuf *scale;
 	int scale_width, scale_height;
 
@@ -6447,24 +6495,13 @@
 			start_anim(NULL, gtkconv);
 	}
 
-	pidgin_buddy_icon_get_scale_size(buf, &prpl_info->icon_spec,
-			PURPLE_ICON_SCALE_DISPLAY, &scale_width, &scale_height);
-	scale = gdk_pixbuf_scale_simple(buf,
-				MAX(gdk_pixbuf_get_width(buf) * scale_width /
-				    gdk_pixbuf_animation_get_width(gtkconv->u.im->anim), 1),
-				MAX(gdk_pixbuf_get_height(buf) * scale_height /
-				    gdk_pixbuf_animation_get_height(gtkconv->u.im->anim), 1),
+	scale = gdk_pixbuf_scale_simple(buf, 32, 32,
 				GDK_INTERP_BILINEAR);
 
 	gtkconv->u.im->icon_container = gtk_vbox_new(FALSE, 0);
 
-	frame = gtk_frame_new(NULL);
-	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
-	gtk_box_pack_start(GTK_BOX(gtkconv->u.im->icon_container), frame,
-					   FALSE, FALSE, 0);
-
 	event = gtk_event_box_new();
-	gtk_container_add(GTK_CONTAINER(frame), event);
+	gtk_container_add(GTK_CONTAINER(gtkconv->u.im->icon_container), event);
 	g_signal_connect(G_OBJECT(event), "button-press-event",
 					 G_CALLBACK(icon_menu), gtkconv);
 	gtk_widget_show(event);
@@ -6472,19 +6509,16 @@
 	gtkconv->u.im->icon = gtk_image_new_from_pixbuf(scale);
 	gtkconv->auto_resize = TRUE;
 	/* Reset the size request to allow the buddy icon to resize */
-	gtk_widget_set_size_request(gtkconv->lower_hbox, -1, -1);
 	g_idle_add(reset_auto_resize_cb, gtkconv);
-	gtk_widget_set_size_request(gtkconv->u.im->icon, scale_width, scale_height);
 	gtk_container_add(GTK_CONTAINER(event), gtkconv->u.im->icon);
 	gtk_widget_show(gtkconv->u.im->icon);
 
 	g_object_unref(G_OBJECT(scale));
 
-	gtk_box_pack_start(GTK_BOX(gtkconv->lower_hbox),
+	gtk_box_pack_start(GTK_BOX(gtkconv->infopane_hbox),
 			   gtkconv->u.im->icon_container, FALSE, FALSE, 0);
 
 	gtk_widget_show(gtkconv->u.im->icon_container);
-	gtk_widget_show(frame);
 
 	/* The buddy icon code needs badly to be fixed. */
 	if(pidgin_conv_window_is_active_conversation(conv))
@@ -8479,7 +8513,7 @@
 	gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont, !tabs_side && !angle, TRUE, GTK_PACK_START);
 
 	/* show the widgets */
-	gtk_widget_show(gtkconv->icon);
+/* XXX	gtk_widget_show(gtkconv->icon); */
 	gtk_widget_show(gtkconv->tab_label);
 	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/close_on_tabs"))
 		gtk_widget_show(gtkconv->close);
--- a/pidgin/gtkconv.h	Mon Jun 18 03:20:15 2007 +0000
+++ b/pidgin/gtkconv.h	Wed Jun 20 04:56:08 2007 +0000
@@ -158,6 +158,10 @@
 	} u;
 
 	time_t newday;
+	GtkWidget *infopane_hbox;
+	GtkWidget *infopane;
+	GtkTreeModel *infopane_model;
+	GtkTreeIter infopane_iter;
 };
 
 /*@}*/
--- a/pidgin/gtkmain.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/pidgin/gtkmain.c	Wed Jun 20 04:56:08 2007 +0000
@@ -498,7 +498,7 @@
 			"no fault of your own.\n\n"
 			"If you can reproduce the crash, please notify the developers\n"
 			"by reporting a bug at:\n"
-			"%snewticket/\n\n"
+			"%ssimpleticket/\n\n"
 			"Please make sure to specify what you were doing at the time\n"
 			"and post the backtrace from the core file.  If you do not know\n"
 			"how to get the backtrace, please read the instructions at\n"
--- a/pidgin/gtksavedstatuses.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/pidgin/gtksavedstatuses.c	Wed Jun 20 04:56:08 2007 +0000
@@ -285,9 +285,11 @@
 
 	for (l = sel_titles; l != NULL; l = l->next) {
 		title = l->data;
-		if (status_window_find_savedstatus(&iter, title))
-			gtk_list_store_remove(status_window->model, &iter);
-		purple_savedstatus_delete(title);
+		if (purple_savedstatus_find(title) != purple_savedstatus_get_current()) {
+			if (status_window_find_savedstatus(&iter, title))
+				gtk_list_store_remove(status_window->model, &iter);
+			purple_savedstatus_delete(title);
+		}
 		g_free(title);
 	}
 	g_list_free(sel_titles);
@@ -302,6 +304,7 @@
 	GList *sel_paths, *l, *sel_titles = NULL;
 	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model);
 	char *title;
+	gpointer handle;
 
 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
 #if GTK_CHECK_VERSION(2,2,0)
@@ -324,13 +327,16 @@
 	}
 	g_list_free(sel_paths);
 
-	if (g_list_length(sel_titles) == 1)
+	if (g_list_length(sel_titles) == 1) {
 		title = g_strdup_printf(_("Are you sure you want to delete %s?"),
 				(const gchar *)sel_titles->data);
-	else
+		handle = purple_savedstatus_find(sel_titles->data);
+	} else {
 		title = g_strdup(_("Are you sure you want to delete the selected saved statuses?"));
+		handle = dialog;
+	}
 
-	purple_request_action(dialog, NULL, title, NULL, 0,
+	purple_request_action(handle, NULL, title, NULL, 0,
 		 NULL, NULL, NULL,
 		 sel_titles, 2,
 		_("Delete"), status_window_delete_confirm_cb,
@@ -349,17 +355,39 @@
 status_selected_cb(GtkTreeSelection *sel, gpointer user_data)
 {
 	StatusWindow *dialog = user_data;
-	int num_selected = 0;
+	GList *sel_paths, *tmp;
+	gboolean can_use = TRUE, can_delete = TRUE;
+	int num_selected;
+	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model);
 
 #if GTK_CHECK_VERSION(2,2,0)
-	num_selected = gtk_tree_selection_count_selected_rows(sel);
+	sel_paths = gtk_tree_selection_get_selected_rows(sel, NULL);
 #else
-	gtk_tree_selection_selected_foreach(sel, count_selected_helper, &num_selected);
+	gtk_tree_selection_selected_foreach(sel, list_selected_helper, &sel_paths);
 #endif
 
-	gtk_widget_set_sensitive(dialog->use_button, (num_selected == 1));
+	for (tmp = sel_paths, num_selected = 0; tmp; tmp = tmp->next, num_selected++) {
+		GtkTreeIter iter;
+		char *title;
+
+		if (gtk_tree_model_get_iter(model, &iter, tmp->data)) {
+			gtk_tree_model_get(model, &iter,
+					STATUS_WINDOW_COLUMN_TITLE, &title, -1);
+			if (purple_savedstatus_find(title) == purple_savedstatus_get_current()) {
+				can_use = can_delete = FALSE;
+			}
+
+			g_free(title);
+		}
+
+		gtk_tree_path_free(tmp->data);
+	}
+
+	gtk_widget_set_sensitive(dialog->use_button, (num_selected == 1) && can_use);
 	gtk_widget_set_sensitive(dialog->modify_button, (num_selected > 0));
-	gtk_widget_set_sensitive(dialog->delete_button, (num_selected > 0));
+	gtk_widget_set_sensitive(dialog->delete_button, can_delete);
+
+    g_list_free(sel_paths);
 }
 
 static void
@@ -421,6 +449,12 @@
 	status_window_modify_cb(NULL, dialog);
 }
 
+static void
+saved_status_updated_cb(PurpleSavedStatus *status, StatusWindow *sw)
+{
+	populate_saved_status_list(sw);
+}
+
 static GtkWidget *
 create_saved_status_list(StatusWindow *dialog)
 {
@@ -529,6 +563,13 @@
 	return FALSE;
 }
 
+static void
+current_status_changed(PurpleSavedStatus *old, PurpleSavedStatus *new_status,
+		StatusWindow *dialog)
+{
+	status_selected_cb(gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)), dialog);
+}
+
 void
 pidgin_status_window_show(void)
 {
@@ -615,6 +656,20 @@
 	g_signal_connect(G_OBJECT(button), "clicked",
 					 G_CALLBACK(status_window_close_cb), dialog);
 
+	purple_signal_connect(purple_savedstatuses_get_handle(),
+			"savedstatus-changed", dialog,
+			PURPLE_CALLBACK(current_status_changed), dialog);
+
+	purple_signal_connect(purple_savedstatuses_get_handle(),
+			"savedstatus-added", dialog,
+			PURPLE_CALLBACK(saved_status_updated_cb), dialog);
+	purple_signal_connect(purple_savedstatuses_get_handle(),
+			"savedstatus-deleted", dialog,
+			PURPLE_CALLBACK(saved_status_updated_cb), dialog);
+	purple_signal_connect(purple_savedstatuses_get_handle(),
+			"savedstatus-modified", dialog,
+			PURPLE_CALLBACK(saved_status_updated_cb), dialog);
+
 	gtk_widget_show_all(win);
 }
 
@@ -804,8 +859,10 @@
 	gtk_widget_destroy(dialog->window);
 	g_free(dialog->original_title);
 
+/*
 	if (status_window != NULL)
 	  add_status_to_saved_status_list(status_window->model, saved_status);
+*/
 
 	/* If they clicked on "Save & Use" or "Use," then activate the status */
 	if (button != dialog->save_button)
--- a/pidgin/gtkstatusbox.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/pidgin/gtkstatusbox.c	Wed Jun 20 04:56:08 2007 +0000
@@ -47,6 +47,7 @@
 #include "internal.h"
 #include "imgstore.h"
 #include "network.h"
+#include "request.h"
 #include "savedstatuses.h"
 #include "status.h"
 #include "debug.h"
@@ -1223,6 +1224,12 @@
 }
 
 static void
+saved_status_updated_cb(PurpleSavedStatus *status, PidginStatusBox *status_box)
+{
+	pidgin_status_box_regenerate(status_box);
+}
+
+static void
 spellcheck_prefs_cb(const char *name, PurplePrefType type,
 					gconstpointer value, gpointer data)
 {
@@ -1514,6 +1521,56 @@
 	pidgin_status_box_changed(status_box);
 }
 
+static void tree_view_delete_current_selection_cb(gpointer data)
+{
+	PurpleSavedStatus *saved;
+
+	saved = purple_savedstatus_find_by_creation_time(GPOINTER_TO_INT(data));
+	g_return_if_fail(saved != NULL);
+
+	if (purple_savedstatus_get_current() != saved)
+		purple_savedstatus_delete_by_status(saved);
+}
+
+static void
+tree_view_delete_current_selection(PidginStatusBox *status_box, GtkTreePath *path)
+{
+	GtkTreeIter iter;
+	gpointer data;
+	PurpleSavedStatus *saved;
+	gchar *msg;
+
+	if (status_box->active_row) {
+		/* don't delete active status */
+		if (gtk_tree_path_compare(path, gtk_tree_row_reference_get_path(status_box->active_row)) == 0)
+			return;
+	}
+
+	if (!gtk_tree_model_get_iter (GTK_TREE_MODEL(status_box->dropdown_store), &iter, path))
+		return;
+
+	gtk_tree_model_get(GTK_TREE_MODEL(status_box->dropdown_store), &iter,
+			   DATA_COLUMN, &data,
+			   -1);
+
+	saved = purple_savedstatus_find_by_creation_time(GPOINTER_TO_INT(data));
+	g_return_if_fail(saved != NULL);
+	if (saved == purple_savedstatus_get_current())
+		return;
+
+	msg = g_strdup_printf(_("Are you sure you want to delete %s?"), purple_savedstatus_get_title(saved));
+
+	purple_request_action(saved, NULL, msg, NULL, 0,
+		NULL, NULL, NULL,
+		data, 2,
+		_("Delete"), tree_view_delete_current_selection_cb,
+		_("Cancel"), NULL);
+
+	g_free(msg);
+
+	pidgin_status_box_popdown(status_box);
+}
+
 static gboolean
 treeview_button_release_cb(GtkWidget *widget, GdkEventButton *event, PidginStatusBox *status_box)
 {
@@ -1561,18 +1618,25 @@
 		if (event->keyval == GDK_Escape) {
 			pidgin_status_box_popdown(box);
 			return TRUE;
-		} else if (event->keyval == GDK_Return) {
+		} else {
 			GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(box->tree_view));
 			GtkTreeIter iter;
 			GtkTreePath *path;
 
 			if (gtk_tree_selection_get_selected(sel, NULL, &iter)) {
+				gboolean ret = TRUE;
 				path = gtk_tree_model_get_path(GTK_TREE_MODEL(box->dropdown_store), &iter);
-				treeview_activate_current_selection(box, path);
+				if (event->keyval == GDK_Return) {
+					treeview_activate_current_selection(box, path);
+				} else if (event->keyval == GDK_Delete) {
+					tree_view_delete_current_selection(box, path);
+				} else
+					ret = FALSE;
+
 				gtk_tree_path_free (path);
-				return TRUE;
+				return ret;
 			}
-		}
+		} 
 	}
 	return FALSE;
 }
@@ -1742,6 +1806,15 @@
 						status_box,
 						PURPLE_CALLBACK(current_savedstatus_changed_cb),
 						status_box);
+	purple_signal_connect(purple_savedstatuses_get_handle(),
+			"savedstatus-added", status_box,
+			PURPLE_CALLBACK(saved_status_updated_cb), status_box);
+	purple_signal_connect(purple_savedstatuses_get_handle(),
+			"savedstatus-deleted", status_box,
+			PURPLE_CALLBACK(saved_status_updated_cb), status_box);
+	purple_signal_connect(purple_savedstatuses_get_handle(),
+			"savedstatus-modified", status_box,
+			PURPLE_CALLBACK(saved_status_updated_cb), status_box);
 	purple_signal_connect(purple_accounts_get_handle(), "account-enabled", status_box,
 						PURPLE_CALLBACK(account_enabled_cb),
 						status_box);
--- a/pidgin/pidginstock.c	Mon Jun 18 03:20:15 2007 +0000
+++ b/pidgin/pidginstock.c	Wed Jun 20 04:56:08 2007 +0000
@@ -105,7 +105,7 @@
 	{ PIDGIN_STOCK_STATUS_AWAY, 	   "status", "away.png",	TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_AWAY_I },
 	{ PIDGIN_STOCK_STATUS_BUSY, 	"status", "busy.png", 		TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_BUSY_I },
 	{ PIDGIN_STOCK_STATUS_CHAT, 	"status", "chat.png",		TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
-	{ PIDGIN_STOCK_STATUS_INVISIBLE,"status", "invisible.png",	TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
+	{ PIDGIN_STOCK_STATUS_INVISIBLE,"status", "invisible.png",	TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL },
 	{ PIDGIN_STOCK_STATUS_XA, 	"status", "extended-away.png",	TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, PIDGIN_STOCK_STATUS_XA_I },
 	{ PIDGIN_STOCK_STATUS_LOGIN, 	"status", "log-in.png",		TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL },
 	{ PIDGIN_STOCK_STATUS_LOGOUT, 	"status", "log-out.png",	TRUE, TRUE, TRUE, TRUE, FALSE, FALSE , NULL },