comparison pidgin/gtkconv.c @ 20049:7af1af2b7ad3

propagate from branch 'im.pidgin.pidgin' (head 02b9fa9cd591c94c082a8ff02ea27fe33b278a0a) to branch 'im.pidgin.sadrul.conv.persistent' (head f0287adbcd60b64f6209cc00141e15d1a67a4c7f)
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Sat, 15 Sep 2007 06:26:35 +0000
parents a2b4eac83902 501c05b1e3e5
children 20c336838629
comparison
equal deleted inserted replaced
20044:4fdf9c1212e2 20049:7af1af2b7ad3
67 #include "gtkutils.h" 67 #include "gtkutils.h"
68 #include "pidginstock.h" 68 #include "pidginstock.h"
69 69
70 #include "gtknickcolors.h" 70 #include "gtknickcolors.h"
71 71
72 #define CLOSE_CONV_TIMEOUT_SECS (10 * 60)
73
72 #define AUTO_RESPONSE "&lt;AUTO-REPLY&gt; : " 74 #define AUTO_RESPONSE "&lt;AUTO-REPLY&gt; : "
73 75
74 typedef enum 76 typedef enum
75 { 77 {
76 PIDGIN_CONV_SET_TITLE = 1 << 0, 78 PIDGIN_CONV_SET_TITLE = 1 << 0,
120 } InviteBuddyInfo; 122 } InviteBuddyInfo;
121 123
122 static GtkWidget *invite_dialog = NULL; 124 static GtkWidget *invite_dialog = NULL;
123 static GtkWidget *warn_close_dialog = NULL; 125 static GtkWidget *warn_close_dialog = NULL;
124 126
125 static PidginWindow *hidden_convwin = NULL;
126 static GList *window_list = NULL; 127 static GList *window_list = NULL;
127 128
128 /* Lists of status icons at all available sizes for use as window icons */ 129 /* Lists of status icons at all available sizes for use as window icons */
129 static GList *available_list = NULL; 130 static GList *available_list = NULL;
130 static GList *away_list = NULL; 131 static GList *away_list = NULL;
158 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); 159 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win);
159 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); 160 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv);
160 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv); 161 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv);
161 static gboolean pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv); 162 static gboolean pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv);
162 static void pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv); 163 static void pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv);
164 static void hide_conv(PidginConversation *gtkconv, gboolean closetimer);
163 165
164 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y, 166 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y,
165 int width, int height); 167 int width, int height);
166 168
167 static GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) { 169 static GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) {
205 /************************************************************************** 207 /**************************************************************************
206 * Callbacks 208 * Callbacks
207 **************************************************************************/ 209 **************************************************************************/
208 210
209 static gboolean 211 static gboolean
210 close_conv_cb(GtkWidget *w, GdkEventButton *event, PidginConversation *gtkconv) 212 close_this_sucker(gpointer data)
211 { 213 {
214 PidginConversation *gtkconv = data;
212 GList *list = g_list_copy(gtkconv->convs); 215 GList *list = g_list_copy(gtkconv->convs);
213
214 g_list_foreach(list, (GFunc)purple_conversation_destroy, NULL); 216 g_list_foreach(list, (GFunc)purple_conversation_destroy, NULL);
215 g_list_free(list); 217 g_list_free(list);
218 return FALSE;
219 }
220
221 static gboolean
222 close_conv_cb(GtkWidget *w, GdkEventButton *event, PidginConversation *gtkconv)
223 {
224 /* We are going to destroy the conversations immediately only if the 'close immediately'
225 * preference is selected. Otherwise, close the conversation after a reasonable timeout
226 * (I am going to consider 10 minutes as a 'reasonable timeout' here.
227 * For chats, close immediately if the chat is not in the buddylist, or if the chat is
228 * not marked 'Persistent' */
229 PurpleConversation *conv = gtkconv->active_conv;
230 PurpleAccount *account = purple_conversation_get_account(conv);
231 const char *name = purple_conversation_get_name(conv);
232
233 switch (purple_conversation_get_type(conv)) {
234 case PURPLE_CONV_TYPE_IM:
235 {
236 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately"))
237 close_this_sucker(gtkconv);
238 else
239 hide_conv(gtkconv, TRUE);
240 break;
241 }
242 case PURPLE_CONV_TYPE_CHAT:
243 {
244 PurpleChat *chat = purple_blist_find_chat(account, name);
245 if (!chat ||
246 !purple_blist_node_get_bool(&chat->node, "gtk-persistent"))
247 close_this_sucker(gtkconv);
248 else
249 hide_conv(gtkconv, FALSE);
250 break;
251 }
252 default:
253 ;
254 }
216 255
217 return TRUE; 256 return TRUE;
218 } 257 }
219 258
220 static gboolean 259 static gboolean
1312 conv = pidgin_conv_window_get_active_conversation(win); 1351 conv = pidgin_conv_window_get_active_conversation(win);
1313 1352
1314 add_remove_cb(NULL, PIDGIN_CONVERSATION(conv)); 1353 add_remove_cb(NULL, PIDGIN_CONVERSATION(conv));
1315 } 1354 }
1316 1355
1317 #if 0 1356 static gboolean
1318 static void 1357 close_already(gpointer data)
1319 menu_hide_conv_cb(gpointer data, guint action, GtkWidget *widget) 1358 {
1320 { 1359 purple_conversation_destroy(data);
1321 PidginWindow *win = data; 1360 return FALSE;
1322 PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win); 1361 }
1323 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
1324 purple_signal_emit(pidgin_conversations_get_handle(), 1368 purple_signal_emit(pidgin_conversations_get_handle(),
1325 "conversation-hiding", gtkconv); 1369 "conversation-hiding", gtkconv);
1326 purple_conversation_set_ui_ops(conv, NULL); 1370
1327 } 1371 for (list = g_list_copy(gtkconv->convs); list; list = g_list_delete_link(list, list)) {
1328 #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 }
1329 1383
1330 static void 1384 static void
1331 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget) 1385 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget)
1332 { 1386 {
1333 PidginWindow *win = data; 1387 PidginWindow *win = data;
2338 } 2392 }
2339 2393
2340 return get_prpl_icon_list(account); 2394 return get_prpl_icon_list(account);
2341 } 2395 }
2342 2396
2343 GdkPixbuf * 2397 static GdkPixbuf *
2344 pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon) 2398 pidgin_conv_get_icon(PurpleConversation *conv, GtkWidget *parent, const char *icon_size)
2345 { 2399 {
2346 PurpleAccount *account = NULL; 2400 PurpleAccount *account = NULL;
2347 const char *name = NULL; 2401 const char *name = NULL;
2348 GdkPixbuf *status = NULL; 2402 GdkPixbuf *status = NULL;
2349 PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); 2403 PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
2350 const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL; 2404 g_return_val_if_fail(conv != NULL, NULL);
2351 g_return_val_if_fail(conv != NULL, NULL); 2405
2352 2406 account = purple_conversation_get_account(conv);
2353 account = purple_conversation_get_account(conv); 2407 name = purple_conversation_get_name(conv);
2354 name = purple_conversation_get_name(conv); 2408
2355 2409 g_return_val_if_fail(account != NULL, NULL);
2356 g_return_val_if_fail(account != NULL, NULL); 2410 g_return_val_if_fail(name != NULL, NULL);
2357 g_return_val_if_fail(name != NULL, NULL); 2411
2358 2412 /* Use the buddy icon, if possible */
2359 /* Use the buddy icon, if possible */ 2413 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
2360 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { 2414 PurpleBuddy *b = purple_find_buddy(account, name);
2361 PurpleBuddy *b = purple_find_buddy(account, name); 2415 if (b != NULL) {
2362 if (b != NULL) {
2363 PurplePresence *p = purple_buddy_get_presence(b); 2416 PurplePresence *p = purple_buddy_get_presence(b);
2364 /* I hate this hack. It fixes a bug where the pending message icon 2417 /* I hate this hack. It fixes a bug where the pending message icon
2365 * displays in the conv tab even though it shouldn't. 2418 * displays in the conv tab even though it shouldn't.
2366 * A better solution would be great. */ 2419 * A better solution would be great. */
2367 if (ops && ops->update) 2420 if (ops && ops->update)
2368 ops->update(NULL, (PurpleBlistNode*)b); 2421 ops->update(NULL, (PurpleBlistNode*)b);
2369 2422
2370 /* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */ 2423 /* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */
2371 if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY)) 2424 if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY))
2372 status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2425 status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, parent, icon_size);
2373 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_EXTENDED_AWAY)) 2426 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_EXTENDED_AWAY))
2374 status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2427 status = pidgin_create_status_icon(PURPLE_STATUS_EXTENDED_AWAY, parent, icon_size);
2375 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE)) 2428 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE))
2376 status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2429 status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, parent, icon_size);
2377 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE)) 2430 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE))
2378 status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2431 status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, parent, icon_size);
2379 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE)) 2432 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE))
2380 status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2433 status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, parent, icon_size);
2381 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE)) 2434 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE))
2382 status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, PIDGIN_CONVERSATION(conv)->icon, icon_size); 2435 status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, parent, icon_size);
2383 } 2436 }
2384 } 2437 }
2385 2438
2386 /* If they don't have a buddy icon, then use the PRPL icon */ 2439 /* If they don't have a buddy icon, then use the PRPL icon */
2387 if (status == NULL) { 2440 if (status == NULL) {
2388 GtkIconSize size = gtk_icon_size_from_name(icon_size); 2441 GtkIconSize size = gtk_icon_size_from_name(icon_size);
2389 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { 2442 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
2390 status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_PERSON, 2443 status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_PERSON,
2391 size, "GtkWidget"); 2444 size, "GtkWidget");
2392 } else { 2445 } else {
2393 status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_CHAT, 2446 status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_CHAT,
2394 size, "GtkWidget"); 2447 size, "GtkWidget");
2395 } 2448 }
2396 } 2449 }
2397 return status; 2450 return status;
2451 }
2452
2453 GdkPixbuf *
2454 pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon)
2455 {
2456 const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL;
2457 return pidgin_conv_get_icon(conv, PIDGIN_CONVERSATION(conv)->icon, icon_size);
2398 } 2458 }
2399 2459
2400 2460
2401 static void 2461 static void
2402 update_tab_icon(PurpleConversation *conv) 2462 update_tab_icon(PurpleConversation *conv)
2746 pidgin_conv_present_conversation(PurpleConversation *conv) 2806 pidgin_conv_present_conversation(PurpleConversation *conv)
2747 { 2807 {
2748 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 2808 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
2749 GdkModifierType state; 2809 GdkModifierType state;
2750 2810
2751 if(gtkconv->win==hidden_convwin) { 2811 if (gtkconv == NULL) {
2752 pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv); 2812 pidgin_conv_attach_to_conversation(conv);
2753 pidgin_conv_placement_place(gtkconv); 2813 gtkconv = PIDGIN_CONVERSATION(conv);
2754 } 2814 }
2755 2815
2756 pidgin_conv_switch_active_conversation(conv); 2816 pidgin_conv_switch_active_conversation(conv);
2757 /* Switch the tab only if the user initiated the event by pressing 2817 /* Switch the tab only if the user initiated the event by pressing
2758 * a button or hitting a key. */ 2818 * a button or hitting a key. */
2781 2841
2782 for (; l != NULL && (max_count == 0 || c < max_count); l = l->next) { 2842 for (; l != NULL && (max_count == 0 || c < max_count); l = l->next) {
2783 PurpleConversation *conv = (PurpleConversation*)l->data; 2843 PurpleConversation *conv = (PurpleConversation*)l->data;
2784 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 2844 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
2785 2845
2786 if(gtkconv == NULL || gtkconv->active_conv != conv) 2846 if (gtkconv != NULL && gtkconv->active_conv != conv)
2787 continue; 2847 continue;
2788 2848 if (gtkconv == NULL) {
2789 if (gtkconv->unseen_state >= min_state 2849 if (!hidden_only ||
2790 && (!hidden_only || 2850 !purple_conversation_get_data(conv, "unseen-count"))
2791 (hidden_only && gtkconv->win == hidden_convwin))) { 2851 continue;
2792
2793 r = g_list_prepend(r, conv); 2852 r = g_list_prepend(r, conv);
2794 c++; 2853 c++;
2854 } else {
2855 if (gtkconv->unseen_state >= min_state && !hidden_only) {
2856 r = g_list_prepend(r, conv);
2857 c++;
2858 }
2795 } 2859 }
2796 } 2860 }
2797 2861
2798 return r; 2862 return r;
2799 } 2863 }
2829 for (l = convs; l != NULL ; l = l->next) { 2893 for (l = convs; l != NULL ; l = l->next) {
2830 PurpleConversation *conv = (PurpleConversation*)l->data; 2894 PurpleConversation *conv = (PurpleConversation*)l->data;
2831 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 2895 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
2832 2896
2833 GtkWidget *icon = gtk_image_new(); 2897 GtkWidget *icon = gtk_image_new();
2834 GdkPixbuf *pbuf = pidgin_conv_get_tab_icon(conv, TRUE); 2898 GdkPixbuf *pbuf = pidgin_conv_get_icon(conv, icon, PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC);
2835 GtkWidget *item; 2899 GtkWidget *item;
2836 gchar *text = g_strdup_printf("%s (%d)", 2900 gchar *text = g_strdup_printf("%s (%d)",
2837 gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)), 2901 gtkconv ? gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)) : purple_conversation_get_name(conv),
2838 gtkconv->unseen_count); 2902 gtkconv ? gtkconv->unseen_count : GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")));
2839 2903
2840 gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pbuf); 2904 gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pbuf);
2841 g_object_unref(pbuf); 2905 g_object_unref(pbuf);
2842 2906
2843 item = gtk_image_menu_item_new_with_label(text); 2907 item = gtk_image_menu_item_new_with_label(text);
3091 GList *list; 3155 GList *list;
3092 PidginConversation *gtkconv; 3156 PidginConversation *gtkconv;
3093 PurpleConversation *conv; 3157 PurpleConversation *conv;
3094 GtkWidget *item; 3158 GtkWidget *item;
3095 3159
3096 if (win->window == NULL || win == hidden_convwin) 3160 if (win->window == NULL)
3097 return; 3161 return;
3098 3162
3099 gtkconv = pidgin_conv_window_get_active_gtkconv(win); 3163 gtkconv = pidgin_conv_window_get_active_gtkconv(win);
3100 if (gtkconv == NULL) 3164 if (gtkconv == NULL)
3101 return; 3165 return;
4940 PurpleConversationType conv_type = purple_conversation_get_type(conv); 5004 PurpleConversationType conv_type = purple_conversation_get_type(conv);
4941 GtkWidget *pane = NULL; 5005 GtkWidget *pane = NULL;
4942 GtkWidget *tab_cont; 5006 GtkWidget *tab_cont;
4943 PurpleBlistNode *convnode; 5007 PurpleBlistNode *convnode;
4944 5008
5009 if (hidden)
5010 return;
5011
4945 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))) {
4946 conv->ui_data = gtkconv; 5013 conv->ui_data = gtkconv;
4947 if (!g_list_find(gtkconv->convs, conv)) 5014 if (!g_list_find(gtkconv->convs, conv))
4948 gtkconv->convs = g_list_prepend(gtkconv->convs, conv); 5015 gtkconv->convs = g_list_prepend(gtkconv->convs, conv);
4949 pidgin_conv_switch_active_conversation(conv); 5016 pidgin_conv_switch_active_conversation(conv);
5039 5106
5040 g_signal_connect_swapped(G_OBJECT(pane), "focus", 5107 g_signal_connect_swapped(G_OBJECT(pane), "focus",
5041 G_CALLBACK(gtk_widget_grab_focus), 5108 G_CALLBACK(gtk_widget_grab_focus),
5042 gtkconv->entry); 5109 gtkconv->entry);
5043 5110
5044 if (hidden) 5111 pidgin_conv_placement_place(gtkconv);
5045 pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv);
5046 else
5047 pidgin_conv_placement_place(gtkconv);
5048 5112
5049 if (nick_colors == NULL) { 5113 if (nick_colors == NULL) {
5050 nbr_nick_colors = NUM_NICK_COLORS; 5114 nbr_nick_colors = NUM_NICK_COLORS;
5051 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]);
5052 } 5116 }
5053 } 5117 }
5054 5118
5119 #if 0
5055 static void 5120 static void
5056 pidgin_conv_new_hidden(PurpleConversation *conv) 5121 pidgin_conv_new_hidden(PurpleConversation *conv)
5057 { 5122 {
5058 private_gtkconv_new(conv, TRUE); 5123 private_gtkconv_new(conv, TRUE);
5059 } 5124 }
5125 #endif
5060 5126
5061 void 5127 void
5062 pidgin_conv_new(PurpleConversation *conv) 5128 pidgin_conv_new(PurpleConversation *conv)
5063 { 5129 {
5064 private_gtkconv_new(conv, FALSE); 5130 private_gtkconv_new(conv, FALSE);
5071 PurpleConversationUiOps *ui_ops = pidgin_conversations_get_conv_ui_ops(); 5137 PurpleConversationUiOps *ui_ops = pidgin_conversations_get_conv_ui_ops();
5072 if (conv != NULL) 5138 if (conv != NULL)
5073 return; 5139 return;
5074 5140
5075 /* create hidden conv if hide_new pref is always */ 5141 /* create hidden conv if hide_new pref is always */
5076 if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0) 5142 /* or if hide_new pref is away and account is away */
5077 { 5143 if ((strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0) ||
5078 ui_ops->create_conversation = pidgin_conv_new_hidden; 5144 (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
5079 purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender); 5145 !purple_status_is_available(purple_account_get_active_status(account)))) {
5080 ui_ops->create_conversation = pidgin_conv_new; 5146 if (!conv) {
5147 ui_ops->create_conversation = NULL;
5148 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
5149 purple_conversation_set_ui_ops(conv, NULL);
5150 ui_ops->create_conversation = pidgin_conv_new;
5151 }
5152 } else {
5153 /* new message for an IM */
5154 if (conv && conv->type == PURPLE_CONV_TYPE_IM)
5155 pidgin_conv_attach_to_conversation(conv);
5156 }
5157 }
5158
5159 static void
5160 pidgin_conv_destroy(PurpleConversation *conv)
5161 {
5162 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
5163
5164 if (!gtkconv)
5081 return; 5165 return;
5082 }
5083
5084 /* create hidden conv if hide_new pref is away and account is away */
5085 if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
5086 !purple_status_is_available(purple_account_get_active_status(account)))
5087 {
5088 ui_ops->create_conversation = pidgin_conv_new_hidden;
5089 purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
5090 ui_ops->create_conversation = pidgin_conv_new;
5091 return;
5092 }
5093 }
5094
5095 static void
5096 pidgin_conv_destroy(PurpleConversation *conv)
5097 {
5098 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
5099 5166
5100 gtkconv->convs = g_list_remove(gtkconv->convs, conv); 5167 gtkconv->convs = g_list_remove(gtkconv->convs, conv);
5101 /* Don't destroy ourselves until all our convos are gone */ 5168 /* Don't destroy ourselves until all our convos are gone */
5102 if (gtkconv->convs) { 5169 if (gtkconv->convs) {
5103 /* Make sure the destroyed conversation is not the active one */ 5170 /* Make sure the destroyed conversation is not the active one */
6567 } 6634 }
6568 6635
6569 pidgin_conv_update_fields(conv, flags); 6636 pidgin_conv_update_fields(conv, flags);
6570 } 6637 }
6571 6638
6639 static void
6640 wrote_msg_update_unseen_cb(PurpleAccount *account, const char *who, const char *message,
6641 PurpleConversation *conv, PurpleMessageFlags flag, gpointer null)
6642 {
6643 if (conv == NULL || PIDGIN_IS_PIDGIN_CONVERSATION(conv))
6644 return;
6645 if (flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) {
6646 purple_conversation_set_data(conv, "unseen-count",
6647 GINT_TO_POINTER(GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")) + 1));
6648 purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
6649 }
6650 }
6651
6572 static PurpleConversationUiOps conversation_ui_ops = 6652 static PurpleConversationUiOps conversation_ui_ops =
6573 { 6653 {
6574 pidgin_conv_new, 6654 pidgin_conv_new,
6575 pidgin_conv_destroy, /* destroy_conversation */ 6655 pidgin_conv_destroy, /* destroy_conversation */
6576 NULL, /* write_chat */ 6656 NULL, /* write_chat */
7064 7144
7065 static void 7145 static void
7066 account_status_changed_cb(PurpleAccount *account, PurpleStatus *oldstatus, 7146 account_status_changed_cb(PurpleAccount *account, PurpleStatus *oldstatus,
7067 PurpleStatus *newstatus) 7147 PurpleStatus *newstatus)
7068 { 7148 {
7149 #if 0
7069 GList *l; 7150 GList *l;
7070 PurpleConversation *conv = NULL; 7151 PurpleConversation *conv = NULL;
7071 PidginConversation *gtkconv; 7152 PidginConversation *gtkconv;
7072 7153
7073 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")!=0) 7154 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")!=0)
7074 return; 7155 return;
7075 7156
7076 if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus)) 7157 if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus))
7077 return; 7158 return;
7078 7159 #endif
7079 while ((l = hidden_convwin->gtkconvs) != NULL)
7080 {
7081 gtkconv = l->data;
7082
7083 conv = gtkconv->active_conv;
7084
7085 while(l && !purple_status_is_available(
7086 purple_account_get_active_status(
7087 purple_conversation_get_account(conv))))
7088 l = l->next;
7089 if (!l)
7090 break;
7091
7092 pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
7093 pidgin_conv_placement_place(gtkconv);
7094
7095 /* TODO: do we need to do anything for any other conversations that are in the same gtkconv here?
7096 * I'm a little concerned that not doing so will cause the "pending" indicator in the gtkblist not to be cleared. -DAA*/
7097 purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
7098 }
7099 } 7160 }
7100 7161
7101 static void 7162 static void
7102 hide_new_pref_cb(const char *name, PurplePrefType type, 7163 hide_new_pref_cb(const char *name, PurplePrefType type,
7103 gconstpointer value, gpointer data) 7164 gconstpointer value, gpointer data)
7104 { 7165 {
7105 GList *l; 7166 GList *l;
7106 PurpleConversation *conv = NULL;
7107 PidginConversation *gtkconv;
7108 gboolean when_away = FALSE; 7167 gboolean when_away = FALSE;
7109
7110 if(!hidden_convwin)
7111 return;
7112 7168
7113 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always")==0) 7169 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always")==0)
7114 return; 7170 return;
7115 7171
7116 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0) 7172 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0)
7117 when_away = TRUE; 7173 when_away = TRUE;
7118 7174
7119 while ((l = hidden_convwin->gtkconvs) != NULL) 7175 for (l = purple_get_conversations(); l; l = l->next)
7120 { 7176 {
7121 gtkconv = l->data; 7177 PurpleConversation *conv = l->data;
7122 7178 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
7123 conv = gtkconv->active_conv; 7179 if (gtkconv)
7124 7180 continue;
7125 if(when_away && !purple_status_is_available( 7181 if(when_away && !purple_status_is_available(
7126 purple_account_get_active_status( 7182 purple_account_get_active_status(
7127 purple_conversation_get_account(conv)))) 7183 purple_conversation_get_account(conv))))
7128 continue; 7184 continue;
7129 7185 pidgin_conv_attach_to_conversation(conv);
7130 pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
7131 pidgin_conv_placement_place(gtkconv);
7132 } 7186 }
7133 } 7187 }
7134 7188
7135 7189
7136 static void 7190 static void
7312 int count = 0; 7366 int count = 0;
7313 int timer = gtkconv->attach.timer; 7367 int timer = gtkconv->attach.timer;
7314 gtkconv->attach.timer = 0; 7368 gtkconv->attach.timer = 0;
7315 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ 7369 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */
7316 PurpleConvMessage *msg = gtkconv->attach.current->data; 7370 PurpleConvMessage *msg = gtkconv->attach.current->data;
7371 if (gtkconv->attach.when && gtkconv->attach.when < msg->when) {
7372 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<HR>", 0);
7373 gtkconv->attach.when = 0;
7374 }
7317 pidgin_conv_write_conv(gtkconv->active_conv, msg->who, msg->who, msg->what, msg->flags, msg->when); 7375 pidgin_conv_write_conv(gtkconv->active_conv, msg->who, msg->who, msg->what, msg->flags, msg->when);
7318 gtkconv->attach.current = gtkconv->attach.current->prev; 7376 gtkconv->attach.current = gtkconv->attach.current->prev;
7319 count++; 7377 count++;
7320 } 7378 }
7321 gtkconv->attach.timer = timer; 7379 gtkconv->attach.timer = timer;
7331 7389
7332 gboolean pidgin_conv_attach_to_conversation(PurpleConversation *conv) 7390 gboolean pidgin_conv_attach_to_conversation(PurpleConversation *conv)
7333 { 7391 {
7334 GList *list; 7392 GList *list;
7335 PidginConversation *gtkconv; 7393 PidginConversation *gtkconv;
7394 int timer;
7336 7395
7337 if (PIDGIN_IS_PIDGIN_CONVERSATION(conv)) 7396 if (PIDGIN_IS_PIDGIN_CONVERSATION(conv))
7338 return FALSE; 7397 return FALSE;
7339 7398
7399 purple_conversation_set_data(conv, "unseen-count", NULL);
7340 purple_conversation_set_ui_ops(conv, pidgin_conversations_get_conv_ui_ops()); 7400 purple_conversation_set_ui_ops(conv, pidgin_conversations_get_conv_ui_ops());
7341 private_gtkconv_new(conv, FALSE); 7401 private_gtkconv_new(conv, FALSE);
7342 gtkconv = PIDGIN_CONVERSATION(conv); 7402 gtkconv = PIDGIN_CONVERSATION(conv);
7343 7403
7344 list = purple_conversation_get_message_history(conv); 7404 list = purple_conversation_get_message_history(conv);
7345 if (list) { 7405 if (list) {
7346 list = g_list_last(list); 7406 gtkconv->attach.when = ((PurpleConvMessage*)(list->data))->when;
7347 gtkconv->attach.current = list; 7407 gtkconv->attach.current = g_list_last(list);
7348 gtkconv->attach.timer = g_idle_add(add_message_history_to_gtkconv, gtkconv); 7408 gtkconv->attach.timer = g_idle_add(add_message_history_to_gtkconv, gtkconv);
7349 } else { 7409 } else {
7350 purple_signal_emit(pidgin_conversations_get_handle(), 7410 purple_signal_emit(pidgin_conversations_get_handle(),
7351 "conversation-displayed", gtkconv); 7411 "conversation-displayed", gtkconv);
7352 } 7412 }
7353 7413
7354 if (conv->type == PURPLE_CONV_TYPE_CHAT) { 7414 if (conv->type == PURPLE_CONV_TYPE_CHAT) {
7355 pidgin_conv_update_fields(conv, PIDGIN_CONV_TOPIC); 7415 pidgin_conv_update_fields(conv, PIDGIN_CONV_TOPIC);
7356 pidgin_conv_chat_add_users(conv, PURPLE_CONV_CHAT(conv)->in_room, TRUE); 7416 pidgin_conv_chat_add_users(conv, PURPLE_CONV_CHAT(conv)->in_room, TRUE);
7357 } 7417 }
7418
7419 timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer"));
7420 if (timer)
7421 purple_timeout_remove(timer);
7358 7422
7359 return TRUE; 7423 return TRUE;
7360 } 7424 }
7361 7425
7362 void * 7426 void *
7419 7483
7420 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height", 54); 7484 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height", 54);
7421 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE); 7485 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE);
7422 7486
7423 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never"); 7487 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never");
7488 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", FALSE);
7424 7489
7425 #ifdef _WIN32 7490 #ifdef _WIN32
7426 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE); 7491 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE);
7427 #endif 7492 #endif
7428 7493
7581 7646
7582 purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", 7647 purple_signal_connect(purple_conversations_get_handle(), "received-im-msg",
7583 handle, G_CALLBACK(received_im_msg_cb), NULL); 7648 handle, G_CALLBACK(received_im_msg_cb), NULL);
7584 7649
7585 purple_conversations_set_ui_ops(&conversation_ui_ops); 7650 purple_conversations_set_ui_ops(&conversation_ui_ops);
7586
7587 hidden_convwin = pidgin_conv_window_new();
7588 window_list = g_list_remove(window_list, hidden_convwin);
7589 7651
7590 purple_signal_connect(purple_accounts_get_handle(), "account-status-changed", 7652 purple_signal_connect(purple_accounts_get_handle(), "account-status-changed",
7591 handle, PURPLE_CALLBACK(account_status_changed_cb), NULL); 7653 handle, PURPLE_CALLBACK(account_status_changed_cb), NULL);
7592 7654
7593 /* Callbacks to update a conversation */ 7655 /* Callbacks to update a conversation */
7620 purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", handle, 7682 purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", handle,
7621 PURPLE_CALLBACK(update_chat_topic), NULL); 7683 PURPLE_CALLBACK(update_chat_topic), NULL);
7622 purple_signal_connect_priority(purple_conversations_get_handle(), "conversation-updated", handle, 7684 purple_signal_connect_priority(purple_conversations_get_handle(), "conversation-updated", handle,
7623 PURPLE_CALLBACK(pidgin_conv_updated), NULL, 7685 PURPLE_CALLBACK(pidgin_conv_updated), NULL,
7624 PURPLE_SIGNAL_PRIORITY_LOWEST); 7686 PURPLE_SIGNAL_PRIORITY_LOWEST);
7687 purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg", handle,
7688 PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL);
7689 purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg", handle,
7690 PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL);
7625 } 7691 }
7626 7692
7627 void 7693 void
7628 pidgin_conversations_uninit(void) 7694 pidgin_conversations_uninit(void)
7629 { 7695 {
7630 purple_prefs_disconnect_by_handle(pidgin_conversations_get_handle()); 7696 purple_prefs_disconnect_by_handle(pidgin_conversations_get_handle());
7631 purple_signals_disconnect_by_handle(pidgin_conversations_get_handle()); 7697 purple_signals_disconnect_by_handle(pidgin_conversations_get_handle());
7632 purple_signals_unregister_by_instance(pidgin_conversations_get_handle()); 7698 purple_signals_unregister_by_instance(pidgin_conversations_get_handle());
7633 pidgin_conv_window_destroy(hidden_convwin);
7634 hidden_convwin=NULL;
7635 } 7699 }
7636 7700
7637 7701
7638 7702
7639 7703
9046 0, 0, NULL, NULL, gtkconv); 9110 0, 0, NULL, NULL, gtkconv);
9047 9111
9048 if (win->gtkconvs && win->gtkconvs->next == NULL) 9112 if (win->gtkconvs && win->gtkconvs->next == NULL)
9049 pidgin_conv_tab_pack(win, win->gtkconvs->data); 9113 pidgin_conv_tab_pack(win, win->gtkconvs->data);
9050 9114
9051 if (!win->gtkconvs && win != hidden_convwin) 9115 if (!win->gtkconvs)
9052 pidgin_conv_window_destroy(win); 9116 pidgin_conv_window_destroy(win);
9053 } 9117 }
9054 9118
9055 PidginConversation * 9119 PidginConversation *
9056 pidgin_conv_window_get_gtkconv_at_index(const PidginWindow *win, int index) 9120 pidgin_conv_window_get_gtkconv_at_index(const PidginWindow *win, int index)
9585 } 9649 }
9586 9650
9587 gboolean 9651 gboolean
9588 pidgin_conv_is_hidden(PidginConversation *gtkconv) 9652 pidgin_conv_is_hidden(PidginConversation *gtkconv)
9589 { 9653 {
9590 g_return_val_if_fail(gtkconv != NULL, FALSE); 9654 return (gtkconv == NULL);
9591
9592 return (gtkconv->win == hidden_convwin);
9593 } 9655 }
9594 9656
9595 9657
9596 /* Algorithm from http://www.w3.org/TR/AERT#color-contrast */ 9658 /* Algorithm from http://www.w3.org/TR/AERT#color-contrast */
9597 static gboolean 9659 static gboolean
9688 *color_count = i; 9750 *color_count = i;
9689 } 9751 }
9690 9752
9691 return colors; 9753 return colors;
9692 } 9754 }
9755