pidgin/gtkconv.c

changeset 20752
22ffec5874b4
parent 20747
c7494ef1530d
equal deleted inserted replaced
20300:30f07afd658e 20752:22ffec5874b4
68 #include "gtkutils.h" 68 #include "gtkutils.h"
69 #include "pidginstock.h" 69 #include "pidginstock.h"
70 70
71 #include "gtknickcolors.h" 71 #include "gtknickcolors.h"
72 72
73 #define CLOSE_CONV_TIMEOUT_SECS (10 * 60)
74
73 #define AUTO_RESPONSE "<AUTO-REPLY> : " 75 #define AUTO_RESPONSE "<AUTO-REPLY> : "
74 76
75 typedef enum 77 typedef enum
76 { 78 {
77 PIDGIN_CONV_SET_TITLE = 1 << 0, 79 PIDGIN_CONV_SET_TITLE = 1 << 0,
121 } InviteBuddyInfo; 123 } InviteBuddyInfo;
122 124
123 static GtkWidget *invite_dialog = NULL; 125 static GtkWidget *invite_dialog = NULL;
124 static GtkWidget *warn_close_dialog = NULL; 126 static GtkWidget *warn_close_dialog = NULL;
125 127
126 static PidginWindow *hidden_convwin = NULL;
127 static GList *window_list = NULL; 128 static GList *window_list = NULL;
128 129
129 /* Lists of status icons at all available sizes for use as window icons */ 130 /* Lists of status icons at all available sizes for use as window icons */
130 static GList *available_list = NULL; 131 static GList *available_list = NULL;
131 static GList *away_list = NULL; 132 static GList *away_list = NULL;
159 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); 160 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win);
160 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); 161 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv);
161 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv); 162 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv);
162 static gboolean pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv); 163 static gboolean pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv);
163 static void pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv); 164 static void pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv);
165 static void hide_conv(PidginConversation *gtkconv, gboolean closetimer);
164 166
165 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y, 167 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y,
166 int width, int height); 168 int width, int height);
167 169
168 static GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) { 170 static GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) {
206 /************************************************************************** 208 /**************************************************************************
207 * Callbacks 209 * Callbacks
208 **************************************************************************/ 210 **************************************************************************/
209 211
210 static gboolean 212 static gboolean
211 close_conv_cb(GtkWidget *w, GdkEventButton *event, PidginConversation *gtkconv) 213 close_this_sucker(gpointer data)
212 { 214 {
215 PidginConversation *gtkconv = data;
213 GList *list = g_list_copy(gtkconv->convs); 216 GList *list = g_list_copy(gtkconv->convs);
214
215 g_list_foreach(list, (GFunc)purple_conversation_destroy, NULL); 217 g_list_foreach(list, (GFunc)purple_conversation_destroy, NULL);
216 g_list_free(list); 218 g_list_free(list);
219 return FALSE;
220 }
221
222 static gboolean
223 close_conv_cb(GtkWidget *w, GdkEventButton *dontuse, PidginConversation *gtkconv)
224 {
225 /* We are going to destroy the conversations immediately only if the 'close immediately'
226 * preference is selected. Otherwise, close the conversation after a reasonable timeout
227 * (I am going to consider 10 minutes as a 'reasonable timeout' here.
228 * For chats, close immediately if the chat is not in the buddylist, or if the chat is
229 * not marked 'Persistent' */
230 PurpleConversation *conv = gtkconv->active_conv;
231 PurpleAccount *account = purple_conversation_get_account(conv);
232 const char *name = purple_conversation_get_name(conv);
233
234 switch (purple_conversation_get_type(conv)) {
235 case PURPLE_CONV_TYPE_IM:
236 {
237 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately"))
238 close_this_sucker(gtkconv);
239 else
240 hide_conv(gtkconv, TRUE);
241 break;
242 }
243 case PURPLE_CONV_TYPE_CHAT:
244 {
245 PurpleChat *chat = purple_blist_find_chat(account, name);
246 if (!chat ||
247 !purple_blist_node_get_bool(&chat->node, "gtk-persistent"))
248 close_this_sucker(gtkconv);
249 else
250 hide_conv(gtkconv, FALSE);
251 break;
252 }
253 default:
254 ;
255 }
217 256
218 return TRUE; 257 return TRUE;
219 } 258 }
220 259
221 static gboolean 260 static gboolean
335 } 374 }
336 375
337 static void clear_conversation_scrollback(PurpleConversation *conv) 376 static void clear_conversation_scrollback(PurpleConversation *conv)
338 { 377 {
339 PidginConversation *gtkconv = NULL; 378 PidginConversation *gtkconv = NULL;
379 GList *iter;
340 380
341 gtkconv = PIDGIN_CONVERSATION(conv); 381 gtkconv = PIDGIN_CONVERSATION(conv);
342 382
343 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml)); 383 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
384 for (iter = gtkconv->convs; iter; iter = iter->next)
385 purple_conversation_clear_message_history(iter->data);
344 } 386 }
345 387
346 static PurpleCmdRet 388 static PurpleCmdRet
347 clear_command_cb(PurpleConversation *conv, 389 clear_command_cb(PurpleConversation *conv,
348 const char *cmd, char **args, char **error, void *data) 390 const char *cmd, char **args, char **error, void *data)
349 { 391 {
350 clear_conversation_scrollback(conv); 392 clear_conversation_scrollback(conv);
351 purple_conversation_clear_message_history(conv);
352 return PURPLE_CMD_STATUS_OK; 393 return PURPLE_CMD_STATUS_OK;
353 } 394 }
354 395
355 static PurpleCmdRet 396 static PurpleCmdRet
356 clearall_command_cb(PurpleConversation *conv, 397 clearall_command_cb(PurpleConversation *conv,
1058 static void 1099 static void
1059 menu_clear_cb(gpointer data, guint action, GtkWidget *widget) 1100 menu_clear_cb(gpointer data, guint action, GtkWidget *widget)
1060 { 1101 {
1061 PidginWindow *win = data; 1102 PidginWindow *win = data;
1062 PurpleConversation *conv; 1103 PurpleConversation *conv;
1063 PidginConversation *gtkconv;
1064 1104
1065 conv = pidgin_conv_window_get_active_conversation(win); 1105 conv = pidgin_conv_window_get_active_conversation(win);
1066 gtkconv = PIDGIN_CONVERSATION(conv); 1106 clear_conversation_scrollback(conv);
1067
1068 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
1069 } 1107 }
1070 1108
1071 struct _search { 1109 struct _search {
1072 PidginWindow *gtkwin; 1110 PidginWindow *gtkwin;
1073 GtkWidget *entry; 1111 GtkWidget *entry;
1313 conv = pidgin_conv_window_get_active_conversation(win); 1351 conv = pidgin_conv_window_get_active_conversation(win);
1314 1352
1315 add_remove_cb(NULL, PIDGIN_CONVERSATION(conv)); 1353 add_remove_cb(NULL, PIDGIN_CONVERSATION(conv));
1316 } 1354 }
1317 1355
1318 #if 0 1356 static gboolean
1319 static void 1357 close_already(gpointer data)
1320 menu_hide_conv_cb(gpointer data, guint action, GtkWidget *widget) 1358 {
1321 { 1359 purple_conversation_destroy(data);
1322 PidginWindow *win = data; 1360 return FALSE;
1323 PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win); 1361 }
1324 PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win); 1362
1363 static void
1364 hide_conv(PidginConversation *gtkconv, gboolean closetimer)
1365 {
1366 GList *list;
1367
1325 purple_signal_emit(pidgin_conversations_get_handle(), 1368 purple_signal_emit(pidgin_conversations_get_handle(),
1326 "conversation-hiding", gtkconv); 1369 "conversation-hiding", gtkconv);
1327 purple_conversation_set_ui_ops(conv, NULL); 1370
1328 } 1371 for (list = g_list_copy(gtkconv->convs); list; list = g_list_delete_link(list, list)) {
1329 #endif 1372 PurpleConversation *conv = list->data;
1373 if (closetimer) {
1374 guint timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer"));
1375 if (timer)
1376 purple_timeout_remove(timer);
1377 timer = purple_timeout_add_seconds(CLOSE_CONV_TIMEOUT_SECS, close_already, conv);
1378 purple_conversation_set_data(conv, "close-timer", GINT_TO_POINTER(timer));
1379 }
1380 purple_conversation_set_ui_ops(conv, NULL);
1381 }
1382 }
1330 1383
1331 static void 1384 static void
1332 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget) 1385 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget)
1333 { 1386 {
1334 PidginWindow *win = data; 1387 PidginWindow *win = data;
2341 } 2394 }
2342 2395
2343 return get_prpl_icon_list(account); 2396 return get_prpl_icon_list(account);
2344 } 2397 }
2345 2398
2346 GdkPixbuf * 2399 static GdkPixbuf *
2347 pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon) 2400 pidgin_conv_get_icon(PurpleConversation *conv, GtkWidget *parent, const char *icon_size)
2348 { 2401 {
2349 PurpleAccount *account = NULL; 2402 PurpleAccount *account = NULL;
2350 const char *name = NULL; 2403 const char *name = NULL;
2351 GdkPixbuf *status = NULL; 2404 GdkPixbuf *status = NULL;
2352 PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); 2405 PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
2353 const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL; 2406 g_return_val_if_fail(conv != NULL, NULL);
2354 g_return_val_if_fail(conv != NULL, NULL); 2407
2355 2408 account = purple_conversation_get_account(conv);
2356 account = purple_conversation_get_account(conv); 2409 name = purple_conversation_get_name(conv);
2357 name = purple_conversation_get_name(conv); 2410
2358 2411 g_return_val_if_fail(account != NULL, NULL);
2359 g_return_val_if_fail(account != NULL, NULL); 2412 g_return_val_if_fail(name != NULL, NULL);
2360 g_return_val_if_fail(name != NULL, NULL); 2413
2361 2414 /* Use the buddy icon, if possible */
2362 /* Use the buddy icon, if possible */ 2415 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
2363 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { 2416 PurpleBuddy *b = purple_find_buddy(account, name);
2364 PurpleBuddy *b = purple_find_buddy(account, name); 2417 if (b != NULL) {
2365 if (b != NULL) {
2366 PurplePresence *p = purple_buddy_get_presence(b); 2418 PurplePresence *p = purple_buddy_get_presence(b);
2367 /* I hate this hack. It fixes a bug where the pending message icon 2419 /* I hate this hack. It fixes a bug where the pending message icon
2368 * displays in the conv tab even though it shouldn't. 2420 * displays in the conv tab even though it shouldn't.
2369 * A better solution would be great. */ 2421 * A better solution would be great. */
2370 if (ops && ops->update) 2422 if (ops && ops->update)
2371 ops->update(NULL, (PurpleBlistNode*)b); 2423 ops->update(NULL, (PurpleBlistNode*)b);
2372 2424
2373 /* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */ 2425 /* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */
2374 if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY)) 2426 if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY))
2375 status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2427 status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, parent, icon_size);
2376 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_EXTENDED_AWAY)) 2428 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_EXTENDED_AWAY))
2377 status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2429 status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, parent, icon_size);
2378 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE)) 2430 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE))
2379 status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2431 status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, parent, icon_size);
2380 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE)) 2432 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE))
2381 status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2433 status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, parent, icon_size);
2382 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE)) 2434 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE))
2383 status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2435 status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, parent, icon_size);
2384 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE)) 2436 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE))
2385 status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2437 status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, parent, icon_size);
2386 } 2438 }
2387 } 2439 }
2388 2440
2389 /* If they don't have a buddy icon, then use the PRPL icon */ 2441 /* If they don't have a buddy icon, then use the PRPL icon */
2390 if (status == NULL) { 2442 if (status == NULL) {
2391 GtkIconSize size = gtk_icon_size_from_name(icon_size); 2443 GtkIconSize size = gtk_icon_size_from_name(icon_size);
2392 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { 2444 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
2393 status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_PERSON, 2445 status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_PERSON,
2394 size, "GtkWidget"); 2446 size, "GtkWidget");
2395 } else { 2447 } else {
2396 status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_CHAT, 2448 status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_CHAT,
2397 size, "GtkWidget"); 2449 size, "GtkWidget");
2398 } 2450 }
2399 } 2451 }
2400 return status; 2452 return status;
2453 }
2454
2455 GdkPixbuf *
2456 pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon)
2457 {
2458 const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL;
2459 return pidgin_conv_get_icon(conv, PIDGIN_CONVERSATION(conv)->icon, icon_size);
2401 } 2460 }
2402 2461
2403 2462
2404 static void 2463 static void
2405 update_tab_icon(PurpleConversation *conv) 2464 update_tab_icon(PurpleConversation *conv)
2749 pidgin_conv_present_conversation(PurpleConversation *conv) 2808 pidgin_conv_present_conversation(PurpleConversation *conv)
2750 { 2809 {
2751 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 2810 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
2752 GdkModifierType state; 2811 GdkModifierType state;
2753 2812
2754 if(gtkconv->win==hidden_convwin) { 2813 if (gtkconv == NULL) {
2755 pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv); 2814 pidgin_conv_attach_to_conversation(conv);
2756 pidgin_conv_placement_place(gtkconv); 2815 gtkconv = PIDGIN_CONVERSATION(conv);
2757 } 2816 }
2758 2817
2759 pidgin_conv_switch_active_conversation(conv); 2818 pidgin_conv_switch_active_conversation(conv);
2760 /* Switch the tab only if the user initiated the event by pressing 2819 /* Switch the tab only if the user initiated the event by pressing
2761 * a button or hitting a key. */ 2820 * a button or hitting a key. */
2784 2843
2785 for (; l != NULL && (max_count == 0 || c < max_count); l = l->next) { 2844 for (; l != NULL && (max_count == 0 || c < max_count); l = l->next) {
2786 PurpleConversation *conv = (PurpleConversation*)l->data; 2845 PurpleConversation *conv = (PurpleConversation*)l->data;
2787 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 2846 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
2788 2847
2789 if(gtkconv == NULL || gtkconv->active_conv != conv) 2848 if (gtkconv != NULL && gtkconv->active_conv != conv)
2790 continue; 2849 continue;
2791 2850 if (gtkconv == NULL) {
2792 if (gtkconv->unseen_state >= min_state 2851 if (!hidden_only ||
2793 && (!hidden_only || 2852 !purple_conversation_get_data(conv, "unseen-count"))
2794 (hidden_only && gtkconv->win == hidden_convwin))) { 2853 continue;
2795
2796 r = g_list_prepend(r, conv); 2854 r = g_list_prepend(r, conv);
2797 c++; 2855 c++;
2856 } else {
2857 if (gtkconv->unseen_state >= min_state && !hidden_only) {
2858 r = g_list_prepend(r, conv);
2859 c++;
2860 }
2798 } 2861 }
2799 } 2862 }
2800 2863
2801 return r; 2864 return r;
2802 } 2865 }
2832 for (l = convs; l != NULL ; l = l->next) { 2895 for (l = convs; l != NULL ; l = l->next) {
2833 PurpleConversation *conv = (PurpleConversation*)l->data; 2896 PurpleConversation *conv = (PurpleConversation*)l->data;
2834 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 2897 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
2835 2898
2836 GtkWidget *icon = gtk_image_new(); 2899 GtkWidget *icon = gtk_image_new();
2837 GdkPixbuf *pbuf = pidgin_conv_get_tab_icon(conv, TRUE); 2900 GdkPixbuf *pbuf = pidgin_conv_get_icon(conv, icon, PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC);
2838 GtkWidget *item; 2901 GtkWidget *item;
2839 gchar *text = g_strdup_printf("%s (%d)", 2902 gchar *text = g_strdup_printf("%s (%d)",
2840 gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)), 2903 gtkconv ? gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)) : purple_conversation_get_name(conv),
2841 gtkconv->unseen_count); 2904 gtkconv ? gtkconv->unseen_count : GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")));
2842 2905
2843 gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pbuf); 2906 gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pbuf);
2844 g_object_unref(pbuf); 2907 g_object_unref(pbuf);
2845 2908
2846 item = gtk_image_menu_item_new_with_label(text); 2909 item = gtk_image_menu_item_new_with_label(text);
3094 GList *list; 3157 GList *list;
3095 PidginConversation *gtkconv; 3158 PidginConversation *gtkconv;
3096 PurpleConversation *conv; 3159 PurpleConversation *conv;
3097 GtkWidget *item; 3160 GtkWidget *item;
3098 3161
3099 if (win->window == NULL || win == hidden_convwin) 3162 if (win->window == NULL)
3100 return; 3163 return;
3101 3164
3102 gtkconv = pidgin_conv_window_get_active_gtkconv(win); 3165 gtkconv = pidgin_conv_window_get_active_gtkconv(win);
3103 if (gtkconv == NULL) 3166 if (gtkconv == NULL)
3104 return; 3167 return;
3569 3632
3570 if (win->menu.send_to != NULL) 3633 if (win->menu.send_to != NULL)
3571 gtk_widget_destroy(win->menu.send_to); 3634 gtk_widget_destroy(win->menu.send_to);
3572 3635
3573 /* Build the Send To menu */ 3636 /* Build the Send To menu */
3574 win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("_Send To")); 3637 win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("S_end To"));
3575 gtk_widget_show(win->menu.send_to); 3638 gtk_widget_show(win->menu.send_to);
3576 3639
3577 menu = gtk_menu_new(); 3640 menu = gtk_menu_new();
3578 gtk_menu_shell_insert(GTK_MENU_SHELL(win->menu.menubar), 3641 gtk_menu_shell_insert(GTK_MENU_SHELL(win->menu.menubar),
3579 win->menu.send_to, 2); 3642 win->menu.send_to, 2);
4941 PurpleConversationType conv_type = purple_conversation_get_type(conv); 5004 PurpleConversationType conv_type = purple_conversation_get_type(conv);
4942 GtkWidget *pane = NULL; 5005 GtkWidget *pane = NULL;
4943 GtkWidget *tab_cont; 5006 GtkWidget *tab_cont;
4944 PurpleBlistNode *convnode; 5007 PurpleBlistNode *convnode;
4945 5008
5009 if (hidden)
5010 return;
5011
4946 if (conv_type == PURPLE_CONV_TYPE_IM && (gtkconv = pidgin_conv_find_gtkconv(conv))) { 5012 if (conv_type == PURPLE_CONV_TYPE_IM && (gtkconv = pidgin_conv_find_gtkconv(conv))) {
4947 conv->ui_data = gtkconv; 5013 conv->ui_data = gtkconv;
4948 if (!g_list_find(gtkconv->convs, conv)) 5014 if (!g_list_find(gtkconv->convs, conv))
4949 gtkconv->convs = g_list_prepend(gtkconv->convs, conv); 5015 gtkconv->convs = g_list_prepend(gtkconv->convs, conv);
4950 pidgin_conv_switch_active_conversation(conv); 5016 pidgin_conv_switch_active_conversation(conv);
5040 5106
5041 g_signal_connect_swapped(G_OBJECT(pane), "focus", 5107 g_signal_connect_swapped(G_OBJECT(pane), "focus",
5042 G_CALLBACK(gtk_widget_grab_focus), 5108 G_CALLBACK(gtk_widget_grab_focus),
5043 gtkconv->entry); 5109 gtkconv->entry);
5044 5110
5045 if (hidden) 5111 pidgin_conv_placement_place(gtkconv);
5046 pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv);
5047 else
5048 pidgin_conv_placement_place(gtkconv);
5049 5112
5050 if (nick_colors == NULL) { 5113 if (nick_colors == NULL) {
5051 nbr_nick_colors = NUM_NICK_COLORS; 5114 nbr_nick_colors = NUM_NICK_COLORS;
5052 nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->imhtml)->base[GTK_STATE_NORMAL]); 5115 nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->imhtml)->base[GTK_STATE_NORMAL]);
5053 } 5116 }
5054 } 5117 }
5055 5118
5119 #if 0
5056 static void 5120 static void
5057 pidgin_conv_new_hidden(PurpleConversation *conv) 5121 pidgin_conv_new_hidden(PurpleConversation *conv)
5058 { 5122 {
5059 private_gtkconv_new(conv, TRUE); 5123 private_gtkconv_new(conv, TRUE);
5060 } 5124 }
5125 #endif
5061 5126
5062 void 5127 void
5063 pidgin_conv_new(PurpleConversation *conv) 5128 pidgin_conv_new(PurpleConversation *conv)
5064 { 5129 {
5065 private_gtkconv_new(conv, FALSE); 5130 private_gtkconv_new(conv, FALSE);
5068 static void 5133 static void
5069 received_im_msg_cb(PurpleAccount *account, char *sender, char *message, 5134 received_im_msg_cb(PurpleAccount *account, char *sender, char *message,
5070 PurpleConversation *conv, PurpleMessageFlags flags) 5135 PurpleConversation *conv, PurpleMessageFlags flags)
5071 { 5136 {
5072 PurpleConversationUiOps *ui_ops = pidgin_conversations_get_conv_ui_ops(); 5137 PurpleConversationUiOps *ui_ops = pidgin_conversations_get_conv_ui_ops();
5073 if (conv != NULL) 5138
5139 /* create hidden conv if hide_new pref is always */
5140 /* or if hide_new pref is away and account is away */
5141 if ((strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0) ||
5142 (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
5143 !purple_status_is_available(purple_account_get_active_status(account)))) {
5144 if (!conv) {
5145 ui_ops->create_conversation = NULL;
5146 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
5147 purple_conversation_set_ui_ops(conv, NULL);
5148 ui_ops->create_conversation = pidgin_conv_new;
5149 }
5150 } else {
5151 /* new message for an IM */
5152 if (conv && conv->type == PURPLE_CONV_TYPE_IM)
5153 pidgin_conv_attach_to_conversation(conv);
5154 }
5155 }
5156
5157 static void
5158 pidgin_conv_destroy(PurpleConversation *conv)
5159 {
5160 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
5161
5162 if (!gtkconv)
5074 return; 5163 return;
5075
5076 /* create hidden conv if hide_new pref is always */
5077 if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0)
5078 {
5079 ui_ops->create_conversation = pidgin_conv_new_hidden;
5080 purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
5081 ui_ops->create_conversation = pidgin_conv_new;
5082 return;
5083 }
5084
5085 /* create hidden conv if hide_new pref is away and account is away */
5086 if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
5087 !purple_status_is_available(purple_account_get_active_status(account)))
5088 {
5089 ui_ops->create_conversation = pidgin_conv_new_hidden;
5090 purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
5091 ui_ops->create_conversation = pidgin_conv_new;
5092 return;
5093 }
5094 }
5095
5096 static void
5097 pidgin_conv_destroy(PurpleConversation *conv)
5098 {
5099 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
5100 5164
5101 gtkconv->convs = g_list_remove(gtkconv->convs, conv); 5165 gtkconv->convs = g_list_remove(gtkconv->convs, conv);
5102 /* Don't destroy ourselves until all our convos are gone */ 5166 /* Don't destroy ourselves until all our convos are gone */
5103 if (gtkconv->convs) { 5167 if (gtkconv->convs) {
5104 /* Make sure the destroyed conversation is not the active one */ 5168 /* Make sure the destroyed conversation is not the active one */
6573 } 6637 }
6574 6638
6575 pidgin_conv_update_fields(conv, flags); 6639 pidgin_conv_update_fields(conv, flags);
6576 } 6640 }
6577 6641
6642 static void
6643 wrote_msg_update_unseen_cb(PurpleAccount *account, const char *who, const char *message,
6644 PurpleConversation *conv, PurpleMessageFlags flag, gpointer null)
6645 {
6646 if (conv == NULL || PIDGIN_IS_PIDGIN_CONVERSATION(conv))
6647 return;
6648 if (flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) {
6649 purple_conversation_set_data(conv, "unseen-count",
6650 GINT_TO_POINTER(GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")) + 1));
6651 purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
6652 }
6653 }
6654
6578 static PurpleConversationUiOps conversation_ui_ops = 6655 static PurpleConversationUiOps conversation_ui_ops =
6579 { 6656 {
6580 pidgin_conv_new, 6657 pidgin_conv_new,
6581 pidgin_conv_destroy, /* destroy_conversation */ 6658 pidgin_conv_destroy, /* destroy_conversation */
6582 NULL, /* write_chat */ 6659 NULL, /* write_chat */
7070 7147
7071 static void 7148 static void
7072 account_status_changed_cb(PurpleAccount *account, PurpleStatus *oldstatus, 7149 account_status_changed_cb(PurpleAccount *account, PurpleStatus *oldstatus,
7073 PurpleStatus *newstatus) 7150 PurpleStatus *newstatus)
7074 { 7151 {
7152 #if 0
7075 GList *l; 7153 GList *l;
7076 PurpleConversation *conv = NULL; 7154 PurpleConversation *conv = NULL;
7077 PidginConversation *gtkconv; 7155 PidginConversation *gtkconv;
7078 7156
7079 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")!=0) 7157 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")!=0)
7080 return; 7158 return;
7081 7159
7082 if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus)) 7160 if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus))
7083 return; 7161 return;
7084 7162 #endif
7085 while ((l = hidden_convwin->gtkconvs) != NULL)
7086 {
7087 gtkconv = l->data;
7088
7089 conv = gtkconv->active_conv;
7090
7091 while(l && !purple_status_is_available(
7092 purple_account_get_active_status(
7093 purple_conversation_get_account(conv))))
7094 l = l->next;
7095 if (!l)
7096 break;
7097
7098 pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
7099 pidgin_conv_placement_place(gtkconv);
7100
7101 /* TODO: do we need to do anything for any other conversations that are in the same gtkconv here?
7102 * I'm a little concerned that not doing so will cause the "pending" indicator in the gtkblist not to be cleared. -DAA*/
7103 purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
7104 }
7105 } 7163 }
7106 7164
7107 static void 7165 static void
7108 hide_new_pref_cb(const char *name, PurplePrefType type, 7166 hide_new_pref_cb(const char *name, PurplePrefType type,
7109 gconstpointer value, gpointer data) 7167 gconstpointer value, gpointer data)
7110 { 7168 {
7111 GList *l; 7169 GList *l;
7112 PurpleConversation *conv = NULL;
7113 PidginConversation *gtkconv;
7114 gboolean when_away = FALSE; 7170 gboolean when_away = FALSE;
7115
7116 if(!hidden_convwin)
7117 return;
7118 7171
7119 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always")==0) 7172 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always")==0)
7120 return; 7173 return;
7121 7174
7122 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0) 7175 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0)
7123 when_away = TRUE; 7176 when_away = TRUE;
7124 7177
7125 while ((l = hidden_convwin->gtkconvs) != NULL) 7178 for (l = purple_get_conversations(); l; l = l->next)
7126 { 7179 {
7127 gtkconv = l->data; 7180 PurpleConversation *conv = l->data;
7128 7181 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
7129 conv = gtkconv->active_conv; 7182 if (gtkconv)
7130 7183 continue;
7131 if(when_away && !purple_status_is_available( 7184 if(when_away && !purple_status_is_available(
7132 purple_account_get_active_status( 7185 purple_account_get_active_status(
7133 purple_conversation_get_account(conv)))) 7186 purple_conversation_get_account(conv))))
7134 continue; 7187 continue;
7135 7188 pidgin_conv_attach_to_conversation(conv);
7136 pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
7137 pidgin_conv_placement_place(gtkconv);
7138 } 7189 }
7139 } 7190 }
7140 7191
7141 7192
7142 static void 7193 static void
7188 * one of the contacts containing the buddy corresponding to 7239 * one of the contacts containing the buddy corresponding to
7189 * a conversation. It's easier to just update them all. */ 7240 * a conversation. It's easier to just update them all. */
7190 /* if (purple_conversation_get_account(conv) == account) */ 7241 /* if (purple_conversation_get_account(conv) == account) */
7191 pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON | 7242 pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON |
7192 PIDGIN_CONV_MENU | PIDGIN_CONV_COLORIZE_TITLE); 7243 PIDGIN_CONV_MENU | PIDGIN_CONV_COLORIZE_TITLE);
7244
7245 if (PURPLE_CONNECTION_IS_CONNECTED(gc) &&
7246 conv->type == PURPLE_CONV_TYPE_CHAT &&
7247 conv->account == gc->account &&
7248 purple_conversation_get_data(conv, "want-to-rejoin")) {
7249 GHashTable *comps = NULL;
7250 PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name);
7251 if (chat == NULL) {
7252 if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL)
7253 comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, conv->name);
7254 } else {
7255 comps = chat->components;
7256 }
7257 serv_join_chat(gc, comps);
7258 if (chat == NULL && comps != NULL)
7259 g_hash_table_destroy(comps);
7260 }
7193 } 7261 }
7194 } 7262 }
7195 7263
7196 static gboolean 7264 static gboolean
7197 update_buddy_status_timeout(PurpleBuddy *buddy) 7265 update_buddy_status_timeout(PurpleBuddy *buddy)
7315 add_message_history_to_gtkconv(gpointer data) 7383 add_message_history_to_gtkconv(gpointer data)
7316 { 7384 {
7317 PidginConversation *gtkconv = data; 7385 PidginConversation *gtkconv = data;
7318 int count = 0; 7386 int count = 0;
7319 int timer = gtkconv->attach.timer; 7387 int timer = gtkconv->attach.timer;
7388 time_t when = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gtkconv->entry), "attach-start-time"));
7389
7320 gtkconv->attach.timer = 0; 7390 gtkconv->attach.timer = 0;
7321 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ 7391 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */
7322 PurpleConvMessage *msg = gtkconv->attach.current->data; 7392 PurpleConvMessage *msg = gtkconv->attach.current->data;
7393 if (when && when < msg->when) {
7394 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0);
7395 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
7396 }
7323 pidgin_conv_write_conv(gtkconv->active_conv, msg->who, msg->who, msg->what, msg->flags, msg->when); 7397 pidgin_conv_write_conv(gtkconv->active_conv, msg->who, msg->who, msg->what, msg->flags, msg->when);
7324 gtkconv->attach.current = gtkconv->attach.current->prev; 7398 gtkconv->attach.current = gtkconv->attach.current->prev;
7325 count++; 7399 count++;
7326 } 7400 }
7327 gtkconv->attach.timer = timer; 7401 gtkconv->attach.timer = timer;
7328 if (gtkconv->attach.current) 7402 if (gtkconv->attach.current)
7329 return TRUE; 7403 return TRUE;
7330 7404
7405 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
7331 purple_signal_emit(pidgin_conversations_get_handle(), 7406 purple_signal_emit(pidgin_conversations_get_handle(),
7332 "conversation-displayed", gtkconv); 7407 "conversation-displayed", gtkconv);
7333 g_source_remove(gtkconv->attach.timer); 7408 g_source_remove(gtkconv->attach.timer);
7334 gtkconv->attach.timer = 0; 7409 gtkconv->attach.timer = 0;
7335 return FALSE; 7410 return FALSE;
7337 7412
7338 gboolean pidgin_conv_attach_to_conversation(PurpleConversation *conv) 7413 gboolean pidgin_conv_attach_to_conversation(PurpleConversation *conv)
7339 { 7414 {
7340 GList *list; 7415 GList *list;
7341 PidginConversation *gtkconv; 7416 PidginConversation *gtkconv;
7417 int timer;
7342 7418
7343 if (PIDGIN_IS_PIDGIN_CONVERSATION(conv)) 7419 if (PIDGIN_IS_PIDGIN_CONVERSATION(conv))
7344 return FALSE; 7420 return FALSE;
7345 7421
7422 purple_conversation_set_data(conv, "unseen-count", NULL);
7346 purple_conversation_set_ui_ops(conv, pidgin_conversations_get_conv_ui_ops()); 7423 purple_conversation_set_ui_ops(conv, pidgin_conversations_get_conv_ui_ops());
7347 private_gtkconv_new(conv, FALSE); 7424 private_gtkconv_new(conv, FALSE);
7348 gtkconv = PIDGIN_CONVERSATION(conv); 7425 gtkconv = PIDGIN_CONVERSATION(conv);
7349 7426
7350 list = purple_conversation_get_message_history(conv); 7427 list = purple_conversation_get_message_history(conv);
7351 if (list) { 7428 if (list) {
7352 list = g_list_last(list); 7429 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time",
7353 gtkconv->attach.current = list; 7430 GINT_TO_POINTER(((PurpleConvMessage*)(list->data))->when));
7431 gtkconv->attach.current = g_list_last(list);
7354 gtkconv->attach.timer = g_idle_add(add_message_history_to_gtkconv, gtkconv); 7432 gtkconv->attach.timer = g_idle_add(add_message_history_to_gtkconv, gtkconv);
7355 } else { 7433 } else {
7356 purple_signal_emit(pidgin_conversations_get_handle(), 7434 purple_signal_emit(pidgin_conversations_get_handle(),
7357 "conversation-displayed", gtkconv); 7435 "conversation-displayed", gtkconv);
7358 } 7436 }
7360 if (conv->type == PURPLE_CONV_TYPE_CHAT) { 7438 if (conv->type == PURPLE_CONV_TYPE_CHAT) {
7361 pidgin_conv_update_fields(conv, PIDGIN_CONV_TOPIC); 7439 pidgin_conv_update_fields(conv, PIDGIN_CONV_TOPIC);
7362 pidgin_conv_chat_add_users(conv, PURPLE_CONV_CHAT(conv)->in_room, TRUE); 7440 pidgin_conv_chat_add_users(conv, PURPLE_CONV_CHAT(conv)->in_room, TRUE);
7363 } 7441 }
7364 7442
7443 timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer"));
7444 if (timer)
7445 purple_timeout_remove(timer);
7365 return TRUE; 7446 return TRUE;
7366 } 7447 }
7367 7448
7368 void * 7449 void *
7369 pidgin_conversations_get_handle(void) 7450 pidgin_conversations_get_handle(void)
7425 7506
7426 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height", 54); 7507 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height", 54);
7427 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE); 7508 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE);
7428 7509
7429 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never"); 7510 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never");
7511 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", FALSE);
7430 7512
7431 #ifdef _WIN32 7513 #ifdef _WIN32
7432 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE); 7514 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE);
7433 #endif 7515 #endif
7434 7516
7587 7669
7588 purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", 7670 purple_signal_connect(purple_conversations_get_handle(), "received-im-msg",
7589 handle, G_CALLBACK(received_im_msg_cb), NULL); 7671 handle, G_CALLBACK(received_im_msg_cb), NULL);
7590 7672
7591 purple_conversations_set_ui_ops(&conversation_ui_ops); 7673 purple_conversations_set_ui_ops(&conversation_ui_ops);
7592
7593 hidden_convwin = pidgin_conv_window_new();
7594 window_list = g_list_remove(window_list, hidden_convwin);
7595 7674
7596 purple_signal_connect(purple_accounts_get_handle(), "account-status-changed", 7675 purple_signal_connect(purple_accounts_get_handle(), "account-status-changed",
7597 handle, PURPLE_CALLBACK(account_status_changed_cb), NULL); 7676 handle, PURPLE_CALLBACK(account_status_changed_cb), NULL);
7598 7677
7599 /* Callbacks to update a conversation */ 7678 /* Callbacks to update a conversation */
7626 purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", handle, 7705 purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", handle,
7627 PURPLE_CALLBACK(update_chat_topic), NULL); 7706 PURPLE_CALLBACK(update_chat_topic), NULL);
7628 purple_signal_connect_priority(purple_conversations_get_handle(), "conversation-updated", handle, 7707 purple_signal_connect_priority(purple_conversations_get_handle(), "conversation-updated", handle,
7629 PURPLE_CALLBACK(pidgin_conv_updated), NULL, 7708 PURPLE_CALLBACK(pidgin_conv_updated), NULL,
7630 PURPLE_SIGNAL_PRIORITY_LOWEST); 7709 PURPLE_SIGNAL_PRIORITY_LOWEST);
7710 purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg", handle,
7711 PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL);
7712 purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg", handle,
7713 PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL);
7631 } 7714 }
7632 7715
7633 void 7716 void
7634 pidgin_conversations_uninit(void) 7717 pidgin_conversations_uninit(void)
7635 { 7718 {
7636 purple_prefs_disconnect_by_handle(pidgin_conversations_get_handle()); 7719 purple_prefs_disconnect_by_handle(pidgin_conversations_get_handle());
7637 purple_signals_disconnect_by_handle(pidgin_conversations_get_handle()); 7720 purple_signals_disconnect_by_handle(pidgin_conversations_get_handle());
7638 purple_signals_unregister_by_instance(pidgin_conversations_get_handle()); 7721 purple_signals_unregister_by_instance(pidgin_conversations_get_handle());
7639 pidgin_conv_window_destroy(hidden_convwin);
7640 hidden_convwin=NULL;
7641 } 7722 }
7642 7723
7643 7724
7644 7725
7645 7726
8017 GtkWidget *menu = gtk_menu_new(), *sub; 8098 GtkWidget *menu = gtk_menu_new(), *sub;
8018 gboolean populated = populate_menu_with_options(menu, gtkconv, TRUE); 8099 gboolean populated = populate_menu_with_options(menu, gtkconv, TRUE);
8019 sub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(gtkconv->win->menu.send_to)); 8100 sub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(gtkconv->win->menu.send_to));
8020 8101
8021 if (sub && GTK_WIDGET_IS_SENSITIVE(gtkconv->win->menu.send_to)) { 8102 if (sub && GTK_WIDGET_IS_SENSITIVE(gtkconv->win->menu.send_to)) {
8022 GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("_Send To")); 8103 GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("S_end To"));
8023 if (populated) 8104 if (populated)
8024 pidgin_separator(menu); 8105 pidgin_separator(menu);
8025 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 8106 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
8026 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub); 8107 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
8027 gtk_widget_show(item); 8108 gtk_widget_show(item);
8767 8848
8768 gtk_widget_hide_all(win->window); 8849 gtk_widget_hide_all(win->window);
8769 8850
8770 if (win->gtkconvs) { 8851 if (win->gtkconvs) {
8771 while (win->gtkconvs) { 8852 while (win->gtkconvs) {
8772 GList *nextgtk = win->gtkconvs->next; 8853 gboolean last = (win->gtkconvs->next == NULL);
8773 PidginConversation *gtkconv = win->gtkconvs->data; 8854 close_conv_cb(NULL, NULL, win->gtkconvs->data);
8774 GList *nextcore = gtkconv->convs->next; 8855 if (last)
8775 PurpleConversation *conv = gtkconv->convs->data; 8856 break;
8776 purple_conversation_destroy(conv);
8777 if (!nextgtk && !nextcore)
8778 /* we'll end up invoking ourselves when we destroy our last child */
8779 /* so don't destroy ourselves right now */
8780 return;
8781 } 8857 }
8782 return; 8858 return;
8783 } 8859 }
8784 gtk_widget_destroy(win->window); 8860 gtk_widget_destroy(win->window);
8785 8861
9052 0, 0, NULL, NULL, gtkconv); 9128 0, 0, NULL, NULL, gtkconv);
9053 9129
9054 if (win->gtkconvs && win->gtkconvs->next == NULL) 9130 if (win->gtkconvs && win->gtkconvs->next == NULL)
9055 pidgin_conv_tab_pack(win, win->gtkconvs->data); 9131 pidgin_conv_tab_pack(win, win->gtkconvs->data);
9056 9132
9057 if (!win->gtkconvs && win != hidden_convwin) 9133 if (!win->gtkconvs)
9058 pidgin_conv_window_destroy(win); 9134 pidgin_conv_window_destroy(win);
9059 } 9135 }
9060 9136
9061 PidginConversation * 9137 PidginConversation *
9062 pidgin_conv_window_get_gtkconv_at_index(const PidginWindow *win, int index) 9138 pidgin_conv_window_get_gtkconv_at_index(const PidginWindow *win, int index)
9591 } 9667 }
9592 9668
9593 gboolean 9669 gboolean
9594 pidgin_conv_is_hidden(PidginConversation *gtkconv) 9670 pidgin_conv_is_hidden(PidginConversation *gtkconv)
9595 { 9671 {
9596 g_return_val_if_fail(gtkconv != NULL, FALSE); 9672 return (gtkconv == NULL);
9597
9598 return (gtkconv->win == hidden_convwin);
9599 } 9673 }
9600 9674
9601 9675
9602 /* Algorithm from http://www.w3.org/TR/AERT#color-contrast */ 9676 /* Algorithm from http://www.w3.org/TR/AERT#color-contrast */
9603 static gboolean 9677 static gboolean
9694 *color_count = i; 9768 *color_count = i;
9695 } 9769 }
9696 9770
9697 return colors; 9771 return colors;
9698 } 9772 }
9773

mercurial