changeset 31950:9e9abd65b840

propagate from branch 'im.pidgin.pidgin' (head ece03c16966f58e1db43e5c20fe35a6707b468d2) to branch 'im.pidgin.pidgin.mxit' (head 524638c79d3d0540b9343247091acf620ef2c733)
author andrew.victor@mxit.com
date Thu, 31 Mar 2011 19:32:34 +0000
parents acd92b7d8511 (current diff) a9e077fb65e9 (diff)
children a769e6da0a8e
files
diffstat 9 files changed, 201 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Tue Mar 29 14:43:15 2011 +0000
+++ b/ChangeLog.API	Thu Mar 31 19:32:34 2011 +0000
@@ -5,6 +5,7 @@
 		Added:
 		* account-authorization-requested-with-message signal (Stefan Ott)
 		  (#8690)
+		* cleared-message-history signal (conversation signals)
 		* purple_account_add_buddy_with_invite
 		* purple_account_add_buddies_with_invite
 		* purple_notify_user_info_add_pair_plaintext
--- a/doc/conversation-signals.dox	Tue Mar 29 14:43:15 2011 +0000
+++ b/doc/conversation-signals.dox	Thu Mar 31 19:32:34 2011 +0000
@@ -32,6 +32,7 @@
   @signal chat-join-failed
   @signal chat-left
   @signal chat-topic-changed
+  @signal cleared-message-history
   @signal conversation-extended-menu
   @signal sent-attention
   @signal got-attention
@@ -479,6 +480,16 @@
   @since 2.1.0
  @endsignaldef
 
+ @signaldef cleared-message-history
+  @signalproto
+void (*cleared_message_history)(PurpleConversation *conv);
+  @endsignalproto
+  @signaldesc
+    Emitted when the conversation history is cleared.
+  @param conv   The conversation.
+  @since 2.8.0
+ @endsignaldef
+
  @signaldef sent-attention
   @signalproto
 void (*got_attention)(PurpleAccount *account, const char *who, 
--- a/finch/gntconv.c	Tue Mar 29 14:43:15 2011 +0000
+++ b/finch/gntconv.c	Thu Mar 31 19:32:34 2011 +0000
@@ -396,10 +396,18 @@
 }
 
 static void
+cleared_message_history_cb(PurpleConversation *conv, gpointer data)
+{
+	FinchConv *ggc = FINCH_GET_DATA(conv);
+	if (ggc)
+		gnt_text_view_clear(GNT_TEXT_VIEW(ggc->tv));
+}
+
+static void
 clear_scrollback_cb(GntMenuItem *item, gpointer ggconv)
 {
 	FinchConv *ggc = ggconv;
-	gnt_text_view_clear(GNT_TEXT_VIEW(ggc->tv));
+	purple_conversation_clear_message_history(ggc->active_conv);
 }
 
 static void
@@ -1264,8 +1272,6 @@
 clear_command_cb(PurpleConversation *conv,
                  const char *cmd, char **args, char **error, void *data)
 {
-	FinchConv *ggconv = FINCH_GET_DATA(conv);
-	gnt_text_view_clear(GNT_TEXT_VIEW(ggconv->tv));
 	purple_conversation_clear_message_history(conv);
 	return PURPLE_CMD_RET_OK;
 }
@@ -1459,6 +1465,8 @@
 					PURPLE_CALLBACK(update_buddy_typing), NULL);
 	purple_signal_connect(purple_conversations_get_handle(), "chat-left", finch_conv_get_handle(),
 					PURPLE_CALLBACK(chat_left_cb), NULL);
+	purple_signal_connect(purple_conversations_get_handle(), "cleared-message-history", finch_conv_get_handle(),
+					PURPLE_CALLBACK(cleared_message_history_cb), NULL);
 	purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", finch_conv_get_handle(),
 					PURPLE_CALLBACK(buddy_signed_on_off), NULL);
 	purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", finch_conv_get_handle(),
--- a/libpurple/conversation.c	Tue Mar 29 14:43:15 2011 +0000
+++ b/libpurple/conversation.c	Thu Mar 31 19:32:34 2011 +0000
@@ -575,6 +575,7 @@
 
 	if (ops != NULL && ops->destroy_conversation != NULL)
 		ops->destroy_conversation(conv);
+	conv->ui_data = NULL;
 
 	purple_conversation_close_logs(conv);
 
@@ -2270,6 +2271,9 @@
 	GList *list = conv->message_history;
 	message_history_free(list);
 	conv->message_history = NULL;
+
+	purple_signal_emit(purple_conversations_get_handle(),
+			"cleared-message-history", conv);
 }
 
 GList *purple_conversation_get_message_history(PurpleConversation *conv)
@@ -2626,6 +2630,11 @@
 						 purple_value_new(PURPLE_TYPE_STRING),
 						 purple_value_new(PURPLE_TYPE_STRING));
 
+	purple_signal_register(handle, "cleared-message-history",
+	                       purple_marshal_VOID__POINTER, NULL, 1,
+	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
+	                                        PURPLE_SUBTYPE_CONVERSATION));
+
 	purple_signal_register(handle, "conversation-extended-menu",
 			     purple_marshal_VOID__POINTER_POINTER, NULL, 2,
 			     purple_value_new(PURPLE_TYPE_SUBTYPE,
--- a/pidgin/gtkaccount.c	Tue Mar 29 14:43:15 2011 +0000
+++ b/pidgin/gtkaccount.c	Thu Mar 31 19:32:34 2011 +0000
@@ -46,6 +46,7 @@
 #include "gtkutils.h"
 #include "gtkstatusbox.h"
 #include "pidginstock.h"
+#include "minidialog.h"
 
 enum
 {
@@ -2501,6 +2502,28 @@
 	ar->deny_cb(ar->data);
 }
 
+static gboolean
+get_user_info_cb(GtkWidget   *label,
+                 const gchar *uri,
+                 gpointer     data)
+{
+	struct auth_request *ar = data;
+	if (!strcmp(uri, "viewinfo")) {
+		pidgin_retrieve_user_info(purple_account_get_connection(ar->account), ar->username);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static void
+send_im_cb(PidginMiniDialog *mini_dialog,
+           GtkButton *button,
+           gpointer data)
+{
+	struct auth_request *ar = data;
+	pidgin_dialogs_im_with_user(ar->account, ar->username);
+}
+
 static void *
 pidgin_accounts_request_authorization(PurpleAccount *account,
                                       const char *remote_user,
@@ -2515,27 +2538,47 @@
 	char *buffer;
 	PurpleConnection *gc;
 	GtkWidget *alert;
+	PidginMiniDialog *dialog;
 	GdkPixbuf *prpl_icon;
 	struct auth_request *aa;
+	const char *our_name;
 	gboolean have_valid_alias = alias && *alias;
 
 	gc = purple_account_get_connection(account);
 	if (message != NULL && *message == '\0')
 		message = NULL;
 
-	buffer = g_strdup_printf(_("%s%s%s%s wants to add you (%s) to his or her buddy list%s%s"),
-				remote_user,
-				(have_valid_alias ? " ("  : ""),
-				(have_valid_alias ? alias : ""),
-				(have_valid_alias ? ")"   : ""),
-				(id != NULL
-				? id
-				: (purple_connection_get_display_name(gc) != NULL
-				? purple_connection_get_display_name(gc)
-				: purple_account_get_username(account))),
-				(message != NULL ? ": " : "."),
-				(message != NULL ? message  : ""));
-
+	our_name = (id != NULL) ? id :
+			(purple_connection_get_display_name(gc) != NULL) ? purple_connection_get_display_name(gc) :
+			purple_account_get_username(account);
+
+	if (pidgin_mini_dialog_links_supported()) {
+		char *escaped_remote_user = g_markup_escape_text(remote_user, -1);
+		char *escaped_alias = alias != NULL ? g_markup_escape_text(alias, -1) : g_strdup("");
+		char *escaped_our_name = g_markup_escape_text(our_name, -1);
+		char *escaped_message = message != NULL ? g_markup_escape_text(message, -1) : g_strdup("");
+		buffer = g_strdup_printf(_("<a href=\"viewinfo\">%s</a>%s%s%s wants to add you (%s) to his or her buddy list%s%s"),
+					escaped_remote_user,
+					(have_valid_alias ? " ("  : ""),
+					escaped_alias,
+					(have_valid_alias ? ")"   : ""),
+					escaped_our_name,
+					(have_valid_alias ? ": " : "."),
+					escaped_message);
+		g_free(escaped_remote_user);
+		g_free(escaped_alias);
+		g_free(escaped_our_name);
+		g_free(escaped_message);
+	} else {
+		buffer = g_strdup_printf(_("%s%s%s%s wants to add you (%s) to his or her buddy list%s%s"),
+					remote_user,
+					(have_valid_alias ? " ("  : ""),
+					(have_valid_alias ? alias : ""),
+					(have_valid_alias ? ")"   : ""),
+					our_name,
+					(message != NULL ? ": " : "."),
+					(message != NULL ? message  : ""));
+	}
 
 	prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
 
@@ -2550,11 +2593,19 @@
 
 	alert = pidgin_make_mini_dialog_with_custom_icon(
 		gc, prpl_icon,
-		_("Authorize buddy?"), buffer, aa,
+		_("Authorize buddy?"), NULL, aa,
 		_("Authorize"), authorize_and_add_cb,
 		_("Deny"), deny_no_add_cb,
 		NULL);
 
+	dialog = PIDGIN_MINI_DIALOG(alert);
+	if (pidgin_mini_dialog_links_supported()) {
+		pidgin_mini_dialog_enable_description_markup(dialog);
+		pidgin_mini_dialog_set_link_callback(dialog, G_CALLBACK(get_user_info_cb), aa);
+	}
+	pidgin_mini_dialog_set_description(dialog, buffer);
+	pidgin_mini_dialog_add_non_closing_button(dialog, _("Send Instant Message"), send_im_cb, aa);
+
 	g_signal_connect_swapped(G_OBJECT(alert), "destroy", G_CALLBACK(free_auth_request), aa);
 	g_signal_connect(G_OBJECT(alert), "destroy", G_CALLBACK(purple_account_request_close), NULL);
 	pidgin_blist_add_alert(alert);
--- a/pidgin/gtkblist.c	Tue Mar 29 14:43:15 2011 +0000
+++ b/pidgin/gtkblist.c	Thu Mar 31 19:32:34 2011 +0000
@@ -5134,7 +5134,7 @@
 		account);
 
 	 if(err->type == PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT)
-		pidgin_mini_dialog_add_button(PIDGIN_MINI_DIALOG(mini_dialog),
+		pidgin_mini_dialog_add_non_closing_button(PIDGIN_MINI_DIALOG(mini_dialog),
 				_("SSL FAQs"), ssl_faq_clicked_cb, NULL);
 
 	g_signal_connect_after(mini_dialog, "destroy",
--- a/pidgin/gtkconv.c	Tue Mar 29 14:43:15 2011 +0000
+++ b/pidgin/gtkconv.c	Thu Mar 31 19:32:34 2011 +0000
@@ -373,23 +373,21 @@
 	return PURPLE_CMD_RET_OK;
 }
 
-static void clear_conversation_scrollback(PurpleConversation *conv)
+static void clear_conversation_scrollback_cb(PurpleConversation *conv,
+                                             void *data)
 {
 	PidginConversation *gtkconv = NULL;
-	GList *iter;
 
 	gtkconv = PIDGIN_CONVERSATION(conv);
-
-	gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
-	for (iter = gtkconv->convs; iter; iter = iter->next)
-		purple_conversation_clear_message_history(iter->data);
+	if (gtkconv)
+		gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
 }
 
 static PurpleCmdRet
 clear_command_cb(PurpleConversation *conv,
                  const char *cmd, char **args, char **error, void *data)
 {
-	clear_conversation_scrollback(conv);
+	purple_conversation_clear_message_history(conv);
 	return PURPLE_CMD_RET_OK;
 }
 
@@ -397,7 +395,7 @@
 clearall_command_cb(PurpleConversation *conv,
                  const char *cmd, char **args, char **error, void *data)
 {
-	purple_conversation_foreach(clear_conversation_scrollback);
+	purple_conversation_foreach(purple_conversation_clear_message_history);
 	return PURPLE_CMD_RET_OK;
 }
 
@@ -1113,7 +1111,7 @@
 	PurpleConversation *conv;
 
 	conv = pidgin_conv_window_get_active_conversation(win);
-	clear_conversation_scrollback(conv);
+	purple_conversation_clear_message_history(conv);
 }
 
 static void
@@ -8042,6 +8040,8 @@
 
 	purple_signal_connect(purple_conversations_get_handle(), "received-im-msg",
 						handle, G_CALLBACK(received_im_msg_cb), NULL);
+	purple_signal_connect(purple_conversations_get_handle(), "cleared-message-history",
+	                      handle, G_CALLBACK(clear_conversation_scrollback_cb), NULL);
 
 	purple_conversations_set_ui_ops(&conversation_ui_ops);
 
--- a/pidgin/minidialog.c	Tue Mar 29 14:43:15 2011 +0000
+++ b/pidgin/minidialog.c	Thu Mar 31 19:32:34 2011 +0000
@@ -76,6 +76,7 @@
 	PROP_DESCRIPTION,
 	PROP_ICON_NAME,
 	PROP_CUSTOM_ICON,
+	PROP_ENABLE_DESCRIPTION_MARKUP,
 
 	LAST_PROPERTY
 } HazeConnectionProperties;
@@ -87,6 +88,7 @@
 	GtkLabel *title;
 	GtkLabel *desc;
 	GtkBox *buttons;
+	gboolean enable_description_markup;
 
 	guint idle_destroy_cb_id;
 } PidginMiniDialogPrivate;
@@ -138,6 +140,27 @@
 }
 
 void
+pidgin_mini_dialog_enable_description_markup(PidginMiniDialog *mini_dialog)
+{
+	g_object_set(G_OBJECT(mini_dialog), "enable-description-markup", TRUE, NULL);
+}
+
+gboolean
+pidgin_mini_dialog_links_supported()
+{
+#if GTK_CHECK_VERSION(2,18,0)
+	return TRUE;
+#else
+	return FALSE;
+#endif
+}
+
+void pidgin_mini_dialog_set_link_callback(PidginMiniDialog *mini_dialog, GCallback cb, gpointer user_data)
+{
+	g_signal_connect(PIDGIN_MINI_DIALOG_GET_PRIVATE(mini_dialog)->desc, "activate-link", cb, user_data);
+}
+
+void
 pidgin_mini_dialog_set_icon_name(PidginMiniDialog *mini_dialog,
                                  const char *icon_name)
 {
@@ -155,6 +178,7 @@
 	PidginMiniDialog *mini_dialog;
 	PidginMiniDialogCallback callback;
 	gpointer user_data;
+	gboolean close_dialog_after_click;
 };
 
 guint
@@ -178,12 +202,14 @@
 	PidginMiniDialogPrivate *priv =
 		PIDGIN_MINI_DIALOG_GET_PRIVATE(data->mini_dialog);
 
-	/* Set up the destruction callback before calling the clicked callback,
-	 * so that if the mini-dialog gets destroyed during the clicked callback
-	 * the idle_destroy_cb is correctly removed by _finalize.
-	 */
-	priv->idle_destroy_cb_id =
-		g_idle_add((GSourceFunc) idle_destroy_cb, data->mini_dialog);
+	if (data->close_dialog_after_click) {
+		/* Set up the destruction callback before calling the clicked callback,
+		 * so that if the mini-dialog gets destroyed during the clicked callback
+		 * the idle_destroy_cb is correctly removed by _finalize.
+		 */
+		priv->idle_destroy_cb_id =
+			g_idle_add((GSourceFunc) idle_destroy_cb, data->mini_dialog);
+	}
 
 	if (data->callback != NULL)
 		data->callback(data->mini_dialog, button, data->user_data);
@@ -198,11 +224,12 @@
 	g_free(data);
 }
 
-void
-pidgin_mini_dialog_add_button(PidginMiniDialog *self,
-                              const char *text,
-                              PidginMiniDialogCallback clicked_cb,
-                              gpointer user_data)
+static void
+mini_dialog_add_button(PidginMiniDialog *self,
+                       const char *text,
+                       PidginMiniDialogCallback clicked_cb,
+                       gpointer user_data,
+                       gboolean close_dialog_after_click)
 {
 	PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
 	struct _mini_dialog_button_clicked_cb_data *callback_data
@@ -218,6 +245,7 @@
 	callback_data->mini_dialog = self;
 	callback_data->callback = clicked_cb;
 	callback_data->user_data = user_data;
+	callback_data->close_dialog_after_click = close_dialog_after_click;
 	g_signal_connect(G_OBJECT(button), "clicked",
 		(GCallback) mini_dialog_button_clicked_cb, callback_data);
 	g_signal_connect(G_OBJECT(button), "destroy",
@@ -231,6 +259,24 @@
 	gtk_widget_show_all(GTK_WIDGET(button));
 }
 
+void
+pidgin_mini_dialog_add_button(PidginMiniDialog *self,
+                              const char *text,
+                              PidginMiniDialogCallback clicked_cb,
+                              gpointer user_data)
+{
+	mini_dialog_add_button(self, text, clicked_cb, user_data, TRUE);
+}
+
+void
+pidgin_mini_dialog_add_non_closing_button(PidginMiniDialog *self,
+                                          const char *text,
+                                          PidginMiniDialogCallback clicked_cb,
+                                          gpointer user_data)
+{
+	mini_dialog_add_button(self, text, clicked_cb, user_data, FALSE);
+}
+
 static void
 pidgin_mini_dialog_get_property(GObject *object,
                                 guint property_id,
@@ -258,6 +304,9 @@
 		case PROP_CUSTOM_ICON:
 			g_value_set_object(value, gtk_image_get_pixbuf(priv->icon));
 			break;
+		case PROP_ENABLE_DESCRIPTION_MARKUP:
+			g_value_set_boolean(value, priv->enable_description_markup);
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 	}
@@ -287,7 +336,7 @@
 	PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
 	if(description)
 	{
-		char *desc_esc = g_markup_escape_text(description, -1);
+		char *desc_esc = priv->enable_description_markup ? g_strdup(description) : g_markup_escape_text(description, -1);
 		char *desc_markup = g_strdup_printf(
 			"<span size=\"smaller\">%s</span>", desc_esc);
 
@@ -333,6 +382,9 @@
 		case PROP_CUSTOM_ICON:
 			gtk_image_set_from_pixbuf(priv->icon, g_value_get_object(value));
 			break;
+		case PROP_ENABLE_DESCRIPTION_MARKUP:
+			priv->enable_description_markup = g_value_get_boolean(value);
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 	}
@@ -390,6 +442,12 @@
 		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
 		G_PARAM_READWRITE);
 	g_object_class_install_property (object_class, PROP_CUSTOM_ICON, param_spec);
+
+	param_spec = g_param_spec_boolean("enable-description-markup", "enable-description-markup",
+		"Use GMarkup in the description text", FALSE,
+		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+		G_PARAM_READWRITE);
+	g_object_class_install_property (object_class, PROP_ENABLE_DESCRIPTION_MARKUP, param_spec);
 }
 
 /* 16 is the width of the icon, due to PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL */
--- a/pidgin/minidialog.h	Tue Mar 29 14:43:15 2011 +0000
+++ b/pidgin/minidialog.h	Thu Mar 31 19:32:34 2011 +0000
@@ -139,6 +139,23 @@
 void pidgin_mini_dialog_set_description(PidginMiniDialog *mini_dialog,
 	const char *description);
 
+/** Enable GMarkup elements in the mini-dialog's description.
+ *  @param mini_dialog a mini-dialog
+ */
+void pidgin_mini_dialog_enable_description_markup(PidginMiniDialog *mini_dialog);
+
+/** Mini-dialogs support hyperlinks in their description
+ *  (you should first call pidgin_mini_dialog_enable_description_markup() on a given
+ *  dialog to enable them). */
+gboolean pidgin_mini_dialog_links_supported(void);
+
+/** Sets a callback which gets invoked when a hyperlink in the dialog's description is clicked on.
+ *  @param mini_dialog a mini-dialog
+ *  @param cb the callback to invoke
+ *  @param user_data the user data to pass to the callback
+ */
+void pidgin_mini_dialog_set_link_callback(PidginMiniDialog *mini_dialog, GCallback cb, gpointer user_data);
+
 /** Shortcut for setting a mini-dialog's icon via GObject properties.
  *  @param mini_dialog a mini-dialog
  *  @param icon_name   the Gtk stock ID of an icon, or @c NULL for no icon.
@@ -166,6 +183,13 @@
 	const char *text, PidginMiniDialogCallback clicked_cb,
 	gpointer user_data);
 
+/** Equivalent to pidgin_mini_dialog_add_button(), the only difference
+ *  is that the mini-dialog won't be closed after the button is clicked.
+ */
+void pidgin_mini_dialog_add_non_closing_button(PidginMiniDialog *mini_dialog,
+	const char *text, PidginMiniDialogCallback clicked_cb,
+	gpointer user_data);
+
 /** Gets the number of widgets packed into PidginMiniDialog.contents.
  *  @param mini_dialog a mini-dialog
  *  @return the number of widgets in @a mini_dialog->contents.