diff -r 30f07afd658e -r 22ffec5874b4 pidgin/gtkconv.c
--- a/pidgin/gtkconv.c Fri Sep 28 17:18:13 2007 +0000
+++ b/pidgin/gtkconv.c Fri Sep 28 17:20:33 2007 +0000
@@ -70,6 +70,8 @@
#include "gtknickcolors.h"
+#define CLOSE_CONV_TIMEOUT_SECS (10 * 60)
+
#define AUTO_RESPONSE "<AUTO-REPLY> : "
typedef enum
@@ -123,7 +125,6 @@
static GtkWidget *invite_dialog = NULL;
static GtkWidget *warn_close_dialog = NULL;
-static PidginWindow *hidden_convwin = NULL;
static GList *window_list = NULL;
/* Lists of status icons at all available sizes for use as window icons */
@@ -161,6 +162,7 @@
static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv);
static gboolean pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv);
static void pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv);
+static void hide_conv(PidginConversation *gtkconv, gboolean closetimer);
static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y,
int width, int height);
@@ -208,12 +210,49 @@
**************************************************************************/
static gboolean
-close_conv_cb(GtkWidget *w, GdkEventButton *event, PidginConversation *gtkconv)
-{
+close_this_sucker(gpointer data)
+{
+ PidginConversation *gtkconv = data;
GList *list = g_list_copy(gtkconv->convs);
-
g_list_foreach(list, (GFunc)purple_conversation_destroy, NULL);
g_list_free(list);
+ return FALSE;
+}
+
+static gboolean
+close_conv_cb(GtkWidget *w, GdkEventButton *dontuse, PidginConversation *gtkconv)
+{
+ /* We are going to destroy the conversations immediately only if the 'close immediately'
+ * preference is selected. Otherwise, close the conversation after a reasonable timeout
+ * (I am going to consider 10 minutes as a 'reasonable timeout' here.
+ * For chats, close immediately if the chat is not in the buddylist, or if the chat is
+ * not marked 'Persistent' */
+ PurpleConversation *conv = gtkconv->active_conv;
+ PurpleAccount *account = purple_conversation_get_account(conv);
+ const char *name = purple_conversation_get_name(conv);
+
+ switch (purple_conversation_get_type(conv)) {
+ case PURPLE_CONV_TYPE_IM:
+ {
+ if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately"))
+ close_this_sucker(gtkconv);
+ else
+ hide_conv(gtkconv, TRUE);
+ break;
+ }
+ case PURPLE_CONV_TYPE_CHAT:
+ {
+ PurpleChat *chat = purple_blist_find_chat(account, name);
+ if (!chat ||
+ !purple_blist_node_get_bool(&chat->node, "gtk-persistent"))
+ close_this_sucker(gtkconv);
+ else
+ hide_conv(gtkconv, FALSE);
+ break;
+ }
+ default:
+ ;
+ }
return TRUE;
}
@@ -337,10 +376,13 @@
static void clear_conversation_scrollback(PurpleConversation *conv)
{
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);
}
static PurpleCmdRet
@@ -348,7 +390,6 @@
const char *cmd, char **args, char **error, void *data)
{
clear_conversation_scrollback(conv);
- purple_conversation_clear_message_history(conv);
return PURPLE_CMD_STATUS_OK;
}
@@ -1060,12 +1101,9 @@
{
PidginWindow *win = data;
PurpleConversation *conv;
- PidginConversation *gtkconv;
conv = pidgin_conv_window_get_active_conversation(win);
- gtkconv = PIDGIN_CONVERSATION(conv);
-
- gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
+ clear_conversation_scrollback(conv);
}
struct _search {
@@ -1315,18 +1353,33 @@
add_remove_cb(NULL, PIDGIN_CONVERSATION(conv));
}
-#if 0
-static void
-menu_hide_conv_cb(gpointer data, guint action, GtkWidget *widget)
-{
- PidginWindow *win = data;
- PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win);
- PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
+static gboolean
+close_already(gpointer data)
+{
+ purple_conversation_destroy(data);
+ return FALSE;
+}
+
+static void
+hide_conv(PidginConversation *gtkconv, gboolean closetimer)
+{
+ GList *list;
+
purple_signal_emit(pidgin_conversations_get_handle(),
"conversation-hiding", gtkconv);
- purple_conversation_set_ui_ops(conv, NULL);
-}
-#endif
+
+ for (list = g_list_copy(gtkconv->convs); list; list = g_list_delete_link(list, list)) {
+ PurpleConversation *conv = list->data;
+ if (closetimer) {
+ guint timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer"));
+ if (timer)
+ purple_timeout_remove(timer);
+ timer = purple_timeout_add_seconds(CLOSE_CONV_TIMEOUT_SECS, close_already, conv);
+ purple_conversation_set_data(conv, "close-timer", GINT_TO_POINTER(timer));
+ }
+ purple_conversation_set_ui_ops(conv, NULL);
+ }
+}
static void
menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget)
@@ -2343,63 +2396,69 @@
return get_prpl_icon_list(account);
}
-GdkPixbuf *
-pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon)
-{
- PurpleAccount *account = NULL;
- const char *name = NULL;
- GdkPixbuf *status = NULL;
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL;
- g_return_val_if_fail(conv != NULL, NULL);
-
- account = purple_conversation_get_account(conv);
- name = purple_conversation_get_name(conv);
-
- g_return_val_if_fail(account != NULL, NULL);
- g_return_val_if_fail(name != NULL, NULL);
-
- /* Use the buddy icon, if possible */
- if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
- PurpleBuddy *b = purple_find_buddy(account, name);
- if (b != NULL) {
+static GdkPixbuf *
+pidgin_conv_get_icon(PurpleConversation *conv, GtkWidget *parent, const char *icon_size)
+{
+ PurpleAccount *account = NULL;
+ const char *name = NULL;
+ GdkPixbuf *status = NULL;
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ g_return_val_if_fail(conv != NULL, NULL);
+
+ account = purple_conversation_get_account(conv);
+ name = purple_conversation_get_name(conv);
+
+ g_return_val_if_fail(account != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ /* Use the buddy icon, if possible */
+ if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
+ PurpleBuddy *b = purple_find_buddy(account, name);
+ if (b != NULL) {
PurplePresence *p = purple_buddy_get_presence(b);
- /* I hate this hack. It fixes a bug where the pending message icon
- * displays in the conv tab even though it shouldn't.
- * A better solution would be great. */
- if (ops && ops->update)
- ops->update(NULL, (PurpleBlistNode*)b);
+ /* I hate this hack. It fixes a bug where the pending message icon
+ * displays in the conv tab even though it shouldn't.
+ * A better solution would be great. */
+ if (ops && ops->update)
+ ops->update(NULL, (PurpleBlistNode*)b);
/* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */
if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY))
- status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size);
+ status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, parent, icon_size);
else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_EXTENDED_AWAY))
- status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size);
- else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE))
- status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, PIDGIN_CONVERSATION(conv)->icon, icon_size);
- else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE))
- status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size);
- else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE))
- status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, PIDGIN_CONVERSATION(conv)->icon, icon_size);
- else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE))
- status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size);
- }
- }
-
- /* If they don't have a buddy icon, then use the PRPL icon */
- if (status == NULL) {
+ status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, parent, icon_size);
+ else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE))
+ status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, parent, icon_size);
+ else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE))
+ status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, parent, icon_size);
+ else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE))
+ status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, parent, icon_size);
+ else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE))
+ status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, parent, icon_size);
+ }
+ }
+
+ /* If they don't have a buddy icon, then use the PRPL icon */
+ if (status == NULL) {
GtkIconSize size = gtk_icon_size_from_name(icon_size);
if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
- status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_PERSON,
- size, "GtkWidget");
+ status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_PERSON,
+ size, "GtkWidget");
} else {
- status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_CHAT,
- size, "GtkWidget");
+ status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_CHAT,
+ size, "GtkWidget");
}
}
return status;
}
+GdkPixbuf *
+pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon)
+{
+ const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL;
+ return pidgin_conv_get_icon(conv, PIDGIN_CONVERSATION(conv)->icon, icon_size);
+}
+
static void
update_tab_icon(PurpleConversation *conv)
@@ -2751,9 +2810,9 @@
PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
GdkModifierType state;
- if(gtkconv->win==hidden_convwin) {
- pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
- pidgin_conv_placement_place(gtkconv);
+ if (gtkconv == NULL) {
+ pidgin_conv_attach_to_conversation(conv);
+ gtkconv = PIDGIN_CONVERSATION(conv);
}
pidgin_conv_switch_active_conversation(conv);
@@ -2786,15 +2845,19 @@
PurpleConversation *conv = (PurpleConversation*)l->data;
PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
- if(gtkconv == NULL || gtkconv->active_conv != conv)
+ if (gtkconv != NULL && gtkconv->active_conv != conv)
continue;
-
- if (gtkconv->unseen_state >= min_state
- && (!hidden_only ||
- (hidden_only && gtkconv->win == hidden_convwin))) {
-
+ if (gtkconv == NULL) {
+ if (!hidden_only ||
+ !purple_conversation_get_data(conv, "unseen-count"))
+ continue;
r = g_list_prepend(r, conv);
c++;
+ } else {
+ if (gtkconv->unseen_state >= min_state && !hidden_only) {
+ r = g_list_prepend(r, conv);
+ c++;
+ }
}
}
@@ -2834,11 +2897,11 @@
PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
GtkWidget *icon = gtk_image_new();
- GdkPixbuf *pbuf = pidgin_conv_get_tab_icon(conv, TRUE);
+ GdkPixbuf *pbuf = pidgin_conv_get_icon(conv, icon, PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC);
GtkWidget *item;
gchar *text = g_strdup_printf("%s (%d)",
- gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)),
- gtkconv->unseen_count);
+ gtkconv ? gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)) : purple_conversation_get_name(conv),
+ gtkconv ? gtkconv->unseen_count : GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")));
gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pbuf);
g_object_unref(pbuf);
@@ -3096,7 +3159,7 @@
PurpleConversation *conv;
GtkWidget *item;
- if (win->window == NULL || win == hidden_convwin)
+ if (win->window == NULL)
return;
gtkconv = pidgin_conv_window_get_active_gtkconv(win);
@@ -3571,7 +3634,7 @@
gtk_widget_destroy(win->menu.send_to);
/* Build the Send To menu */
- win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("_Send To"));
+ win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("S_end To"));
gtk_widget_show(win->menu.send_to);
menu = gtk_menu_new();
@@ -4943,6 +5006,9 @@
GtkWidget *tab_cont;
PurpleBlistNode *convnode;
+ if (hidden)
+ return;
+
if (conv_type == PURPLE_CONV_TYPE_IM && (gtkconv = pidgin_conv_find_gtkconv(conv))) {
conv->ui_data = gtkconv;
if (!g_list_find(gtkconv->convs, conv))
@@ -5042,10 +5108,7 @@
G_CALLBACK(gtk_widget_grab_focus),
gtkconv->entry);
- if (hidden)
- pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv);
- else
- pidgin_conv_placement_place(gtkconv);
+ pidgin_conv_placement_place(gtkconv);
if (nick_colors == NULL) {
nbr_nick_colors = NUM_NICK_COLORS;
@@ -5053,11 +5116,13 @@
}
}
+#if 0
static void
pidgin_conv_new_hidden(PurpleConversation *conv)
{
private_gtkconv_new(conv, TRUE);
}
+#endif
void
pidgin_conv_new(PurpleConversation *conv)
@@ -5070,26 +5135,22 @@
PurpleConversation *conv, PurpleMessageFlags flags)
{
PurpleConversationUiOps *ui_ops = pidgin_conversations_get_conv_ui_ops();
- if (conv != NULL)
- return;
/* create hidden conv if hide_new pref is always */
- if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0)
- {
- ui_ops->create_conversation = pidgin_conv_new_hidden;
- purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
- ui_ops->create_conversation = pidgin_conv_new;
- return;
- }
-
- /* create hidden conv if hide_new pref is away and account is away */
- if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
- !purple_status_is_available(purple_account_get_active_status(account)))
- {
- ui_ops->create_conversation = pidgin_conv_new_hidden;
- purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
- ui_ops->create_conversation = pidgin_conv_new;
- return;
+ /* or if hide_new pref is away and account is away */
+ if ((strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0) ||
+ (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
+ !purple_status_is_available(purple_account_get_active_status(account)))) {
+ if (!conv) {
+ ui_ops->create_conversation = NULL;
+ conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
+ purple_conversation_set_ui_ops(conv, NULL);
+ ui_ops->create_conversation = pidgin_conv_new;
+ }
+ } else {
+ /* new message for an IM */
+ if (conv && conv->type == PURPLE_CONV_TYPE_IM)
+ pidgin_conv_attach_to_conversation(conv);
}
}
@@ -5098,6 +5159,9 @@
{
PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
+ if (!gtkconv)
+ return;
+
gtkconv->convs = g_list_remove(gtkconv->convs, conv);
/* Don't destroy ourselves until all our convos are gone */
if (gtkconv->convs) {
@@ -6575,6 +6639,19 @@
pidgin_conv_update_fields(conv, flags);
}
+static void
+wrote_msg_update_unseen_cb(PurpleAccount *account, const char *who, const char *message,
+ PurpleConversation *conv, PurpleMessageFlags flag, gpointer null)
+{
+ if (conv == NULL || PIDGIN_IS_PIDGIN_CONVERSATION(conv))
+ return;
+ if (flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) {
+ purple_conversation_set_data(conv, "unseen-count",
+ GINT_TO_POINTER(GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")) + 1));
+ purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
+ }
+}
+
static PurpleConversationUiOps conversation_ui_ops =
{
pidgin_conv_new,
@@ -7072,6 +7149,7 @@
account_status_changed_cb(PurpleAccount *account, PurpleStatus *oldstatus,
PurpleStatus *newstatus)
{
+#if 0
GList *l;
PurpleConversation *conv = NULL;
PidginConversation *gtkconv;
@@ -7081,27 +7159,7 @@
if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus))
return;
-
- while ((l = hidden_convwin->gtkconvs) != NULL)
- {
- gtkconv = l->data;
-
- conv = gtkconv->active_conv;
-
- while(l && !purple_status_is_available(
- purple_account_get_active_status(
- purple_conversation_get_account(conv))))
- l = l->next;
- if (!l)
- break;
-
- pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
- pidgin_conv_placement_place(gtkconv);
-
- /* TODO: do we need to do anything for any other conversations that are in the same gtkconv here?
- * I'm a little concerned that not doing so will cause the "pending" indicator in the gtkblist not to be cleared. -DAA*/
- purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
- }
+#endif
}
static void
@@ -7109,32 +7167,25 @@
gconstpointer value, gpointer data)
{
GList *l;
- PurpleConversation *conv = NULL;
- PidginConversation *gtkconv;
gboolean when_away = FALSE;
- if(!hidden_convwin)
- return;
-
if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always")==0)
return;
if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0)
when_away = TRUE;
- while ((l = hidden_convwin->gtkconvs) != NULL)
+ for (l = purple_get_conversations(); l; l = l->next)
{
- gtkconv = l->data;
-
- conv = gtkconv->active_conv;
-
+ PurpleConversation *conv = l->data;
+ PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
+ if (gtkconv)
+ continue;
if(when_away && !purple_status_is_available(
purple_account_get_active_status(
purple_conversation_get_account(conv))))
continue;
-
- pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
- pidgin_conv_placement_place(gtkconv);
+ pidgin_conv_attach_to_conversation(conv);
}
}
@@ -7190,6 +7241,23 @@
/* if (purple_conversation_get_account(conv) == account) */
pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON |
PIDGIN_CONV_MENU | PIDGIN_CONV_COLORIZE_TITLE);
+
+ if (PURPLE_CONNECTION_IS_CONNECTED(gc) &&
+ conv->type == PURPLE_CONV_TYPE_CHAT &&
+ conv->account == gc->account &&
+ purple_conversation_get_data(conv, "want-to-rejoin")) {
+ GHashTable *comps = NULL;
+ PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name);
+ if (chat == NULL) {
+ if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL)
+ comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, conv->name);
+ } else {
+ comps = chat->components;
+ }
+ serv_join_chat(gc, comps);
+ if (chat == NULL && comps != NULL)
+ g_hash_table_destroy(comps);
+ }
}
}
@@ -7317,9 +7385,15 @@
PidginConversation *gtkconv = data;
int count = 0;
int timer = gtkconv->attach.timer;
+ time_t when = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gtkconv->entry), "attach-start-time"));
+
gtkconv->attach.timer = 0;
while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */
PurpleConvMessage *msg = gtkconv->attach.current->data;
+ if (when && when < msg->when) {
+ gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "