pidgin/gtkconv.c

changeset 21076
bb293a21ce84
parent 20244
049b21b4470f
parent 21043
a465c6bc6d63
child 21081
09317aaf5ef9
child 21083
b2268cf761d3
equal deleted inserted replaced
20266:4529d7c0d260 21076:bb293a21ce84
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;
145 static void gray_stuff_out(PidginConversation *gtkconv); 146 static void gray_stuff_out(PidginConversation *gtkconv);
146 static GList *generate_invite_user_names(PurpleConnection *gc); 147 static GList *generate_invite_user_names(PurpleConnection *gc);
147 static void add_chat_buddy_common(PurpleConversation *conv, PurpleConvChatBuddy *cb, const char *old_name); 148 static void add_chat_buddy_common(PurpleConversation *conv, PurpleConvChatBuddy *cb, const char *old_name);
148 static gboolean tab_complete(PurpleConversation *conv); 149 static gboolean tab_complete(PurpleConversation *conv);
149 static void pidgin_conv_updated(PurpleConversation *conv, PurpleConvUpdateType type); 150 static void pidgin_conv_updated(PurpleConversation *conv, PurpleConvUpdateType type);
151 static void conv_set_unseen(PurpleConversation *gtkconv, PidginUnseenState state);
150 static void gtkconv_set_unseen(PidginConversation *gtkconv, PidginUnseenState state); 152 static void gtkconv_set_unseen(PidginConversation *gtkconv, PidginUnseenState state);
151 static void update_typing_icon(PidginConversation *gtkconv); 153 static void update_typing_icon(PidginConversation *gtkconv);
152 static const char *item_factory_translate_func (const char *path, gpointer func_data); 154 static const char *item_factory_translate_func (const char *path, gpointer func_data);
153 gboolean pidgin_conv_has_focus(PurpleConversation *conv); 155 gboolean pidgin_conv_has_focus(PurpleConversation *conv);
154 static void pidgin_conv_custom_smiley_allocated(GdkPixbufLoader *loader, gpointer user_data); 156 static void pidgin_conv_custom_smiley_allocated(GdkPixbufLoader *loader, gpointer user_data);
159 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); 161 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win);
160 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); 162 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv);
161 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv); 163 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv);
162 static gboolean pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv); 164 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); 165 static void pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv);
166 static void hide_conv(PidginConversation *gtkconv, gboolean closetimer);
164 167
165 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y, 168 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y,
166 int width, int height); 169 int width, int height);
167 170
168 static GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) { 171 static GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) {
206 /************************************************************************** 209 /**************************************************************************
207 * Callbacks 210 * Callbacks
208 **************************************************************************/ 211 **************************************************************************/
209 212
210 static gboolean 213 static gboolean
211 close_conv_cb(GtkWidget *w, GdkEventButton *event, PidginConversation *gtkconv) 214 close_this_sucker(gpointer data)
212 { 215 {
216 PidginConversation *gtkconv = data;
213 GList *list = g_list_copy(gtkconv->convs); 217 GList *list = g_list_copy(gtkconv->convs);
214
215 g_list_foreach(list, (GFunc)purple_conversation_destroy, NULL); 218 g_list_foreach(list, (GFunc)purple_conversation_destroy, NULL);
216 g_list_free(list); 219 g_list_free(list);
220 return FALSE;
221 }
222
223 static gboolean
224 close_conv_cb(GtkWidget *w, GdkEventButton *dontuse, PidginConversation *gtkconv)
225 {
226 /* We are going to destroy the conversations immediately only if the 'close immediately'
227 * preference is selected. Otherwise, close the conversation after a reasonable timeout
228 * (I am going to consider 10 minutes as a 'reasonable timeout' here.
229 * For chats, close immediately if the chat is not in the buddylist, or if the chat is
230 * not marked 'Persistent' */
231 PurpleConversation *conv = gtkconv->active_conv;
232 PurpleAccount *account = purple_conversation_get_account(conv);
233 const char *name = purple_conversation_get_name(conv);
234
235 switch (purple_conversation_get_type(conv)) {
236 case PURPLE_CONV_TYPE_IM:
237 {
238 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately"))
239 close_this_sucker(gtkconv);
240 else
241 hide_conv(gtkconv, TRUE);
242 break;
243 }
244 case PURPLE_CONV_TYPE_CHAT:
245 {
246 PurpleChat *chat = purple_blist_find_chat(account, name);
247 if (!chat ||
248 !purple_blist_node_get_bool(&chat->node, "gtk-persistent"))
249 close_this_sucker(gtkconv);
250 else
251 hide_conv(gtkconv, FALSE);
252 break;
253 }
254 default:
255 ;
256 }
217 257
218 return TRUE; 258 return TRUE;
219 } 259 }
220 260
221 static gboolean 261 static gboolean
335 } 375 }
336 376
337 static void clear_conversation_scrollback(PurpleConversation *conv) 377 static void clear_conversation_scrollback(PurpleConversation *conv)
338 { 378 {
339 PidginConversation *gtkconv = NULL; 379 PidginConversation *gtkconv = NULL;
380 GList *iter;
340 381
341 gtkconv = PIDGIN_CONVERSATION(conv); 382 gtkconv = PIDGIN_CONVERSATION(conv);
342 383
343 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml)); 384 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
385 for (iter = gtkconv->convs; iter; iter = iter->next)
386 purple_conversation_clear_message_history(iter->data);
344 } 387 }
345 388
346 static PurpleCmdRet 389 static PurpleCmdRet
347 clear_command_cb(PurpleConversation *conv, 390 clear_command_cb(PurpleConversation *conv,
348 const char *cmd, char **args, char **error, void *data) 391 const char *cmd, char **args, char **error, void *data)
349 { 392 {
350 clear_conversation_scrollback(conv); 393 clear_conversation_scrollback(conv);
351 purple_conversation_clear_message_history(conv);
352 return PURPLE_CMD_STATUS_OK; 394 return PURPLE_CMD_STATUS_OK;
353 } 395 }
354 396
355 static PurpleCmdRet 397 static PurpleCmdRet
356 clearall_command_cb(PurpleConversation *conv, 398 clearall_command_cb(PurpleConversation *conv,
1058 static void 1100 static void
1059 menu_clear_cb(gpointer data, guint action, GtkWidget *widget) 1101 menu_clear_cb(gpointer data, guint action, GtkWidget *widget)
1060 { 1102 {
1061 PidginWindow *win = data; 1103 PidginWindow *win = data;
1062 PurpleConversation *conv; 1104 PurpleConversation *conv;
1063 PidginConversation *gtkconv;
1064 1105
1065 conv = pidgin_conv_window_get_active_conversation(win); 1106 conv = pidgin_conv_window_get_active_conversation(win);
1066 gtkconv = PIDGIN_CONVERSATION(conv); 1107 clear_conversation_scrollback(conv);
1067
1068 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
1069 } 1108 }
1070 1109
1071 struct _search { 1110 struct _search {
1072 PidginWindow *gtkwin; 1111 PidginWindow *gtkwin;
1073 GtkWidget *entry; 1112 GtkWidget *entry;
1313 conv = pidgin_conv_window_get_active_conversation(win); 1352 conv = pidgin_conv_window_get_active_conversation(win);
1314 1353
1315 add_remove_cb(NULL, PIDGIN_CONVERSATION(conv)); 1354 add_remove_cb(NULL, PIDGIN_CONVERSATION(conv));
1316 } 1355 }
1317 1356
1318 #if 0 1357 static gboolean
1319 static void 1358 close_already(gpointer data)
1320 menu_hide_conv_cb(gpointer data, guint action, GtkWidget *widget) 1359 {
1321 { 1360 purple_conversation_destroy(data);
1322 PidginWindow *win = data; 1361 return FALSE;
1323 PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win); 1362 }
1324 PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win); 1363
1364 static void
1365 hide_conv(PidginConversation *gtkconv, gboolean closetimer)
1366 {
1367 GList *list;
1368
1325 purple_signal_emit(pidgin_conversations_get_handle(), 1369 purple_signal_emit(pidgin_conversations_get_handle(),
1326 "conversation-hiding", gtkconv); 1370 "conversation-hiding", gtkconv);
1327 purple_conversation_set_ui_ops(conv, NULL); 1371
1328 } 1372 for (list = g_list_copy(gtkconv->convs); list; list = g_list_delete_link(list, list)) {
1329 #endif 1373 PurpleConversation *conv = list->data;
1374 if (closetimer) {
1375 guint timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer"));
1376 if (timer)
1377 purple_timeout_remove(timer);
1378 timer = purple_timeout_add_seconds(CLOSE_CONV_TIMEOUT_SECS, close_already, conv);
1379 purple_conversation_set_data(conv, "close-timer", GINT_TO_POINTER(timer));
1380 }
1381 purple_conversation_set_ui_ops(conv, NULL);
1382 }
1383 }
1330 1384
1331 static void 1385 static void
1332 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget) 1386 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget)
1333 { 1387 {
1334 PidginWindow *win = data; 1388 PidginWindow *win = data;
2341 } 2395 }
2342 2396
2343 return get_prpl_icon_list(account); 2397 return get_prpl_icon_list(account);
2344 } 2398 }
2345 2399
2346 GdkPixbuf * 2400 static GdkPixbuf *
2347 pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon) 2401 pidgin_conv_get_icon(PurpleConversation *conv, GtkWidget *parent, const char *icon_size)
2348 { 2402 {
2349 PurpleAccount *account = NULL; 2403 PurpleAccount *account = NULL;
2350 const char *name = NULL; 2404 const char *name = NULL;
2351 GdkPixbuf *status = NULL; 2405 GdkPixbuf *status = NULL;
2352 PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); 2406 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; 2407 g_return_val_if_fail(conv != NULL, NULL);
2354 g_return_val_if_fail(conv != NULL, NULL); 2408
2355 2409 account = purple_conversation_get_account(conv);
2356 account = purple_conversation_get_account(conv); 2410 name = purple_conversation_get_name(conv);
2357 name = purple_conversation_get_name(conv); 2411
2358 2412 g_return_val_if_fail(account != NULL, NULL);
2359 g_return_val_if_fail(account != NULL, NULL); 2413 g_return_val_if_fail(name != NULL, NULL);
2360 g_return_val_if_fail(name != NULL, NULL); 2414
2361 2415 /* Use the buddy icon, if possible */
2362 /* Use the buddy icon, if possible */ 2416 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
2363 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { 2417 PurpleBuddy *b = purple_find_buddy(account, name);
2364 PurpleBuddy *b = purple_find_buddy(account, name); 2418 if (b != NULL) {
2365 if (b != NULL) {
2366 PurplePresence *p = purple_buddy_get_presence(b); 2419 PurplePresence *p = purple_buddy_get_presence(b);
2367 /* I hate this hack. It fixes a bug where the pending message icon 2420 /* I hate this hack. It fixes a bug where the pending message icon
2368 * displays in the conv tab even though it shouldn't. 2421 * displays in the conv tab even though it shouldn't.
2369 * A better solution would be great. */ 2422 * A better solution would be great. */
2370 if (ops && ops->update) 2423 if (ops && ops->update)
2371 ops->update(NULL, (PurpleBlistNode*)b); 2424 ops->update(NULL, (PurpleBlistNode*)b);
2372 2425
2373 /* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */ 2426 /* 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)) 2427 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); 2428 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)) 2429 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); 2430 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)) 2431 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); 2432 status = pidgin_create_status_icon(PURPLE_STATUS_OFFLINE, parent, icon_size);
2380 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AVAILABLE)) 2433 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); 2434 status = pidgin_create_status_icon(PURPLE_STATUS_AVAILABLE, parent, icon_size);
2382 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE)) 2435 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); 2436 status = pidgin_create_status_icon(PURPLE_STATUS_INVISIBLE, parent, icon_size);
2384 else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE)) 2437 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); 2438 status = pidgin_create_status_icon(PURPLE_STATUS_UNAVAILABLE, parent, icon_size);
2386 } 2439 }
2387 } 2440 }
2388 2441
2389 /* If they don't have a buddy icon, then use the PRPL icon */ 2442 /* If they don't have a buddy icon, then use the PRPL icon */
2390 if (status == NULL) { 2443 if (status == NULL) {
2391 GtkIconSize size = gtk_icon_size_from_name(icon_size); 2444 GtkIconSize size = gtk_icon_size_from_name(icon_size);
2392 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { 2445 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
2393 status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_PERSON, 2446 status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_PERSON,
2394 size, "GtkWidget"); 2447 size, "GtkWidget");
2395 } else { 2448 } else {
2396 status = gtk_widget_render_icon (PIDGIN_CONVERSATION(conv)->icon, PIDGIN_STOCK_STATUS_CHAT, 2449 status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_CHAT,
2397 size, "GtkWidget"); 2450 size, "GtkWidget");
2398 } 2451 }
2399 } 2452 }
2400 return status; 2453 return status;
2454 }
2455
2456 GdkPixbuf *
2457 pidgin_conv_get_tab_icon(PurpleConversation *conv, gboolean small_icon)
2458 {
2459 const char *icon_size = small_icon ? PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC : PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL;
2460 return pidgin_conv_get_icon(conv, PIDGIN_CONVERSATION(conv)->icon, icon_size);
2401 } 2461 }
2402 2462
2403 2463
2404 static void 2464 static void
2405 update_tab_icon(PurpleConversation *conv) 2465 update_tab_icon(PurpleConversation *conv)
2754 pidgin_conv_present_conversation(PurpleConversation *conv) 2814 pidgin_conv_present_conversation(PurpleConversation *conv)
2755 { 2815 {
2756 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 2816 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
2757 GdkModifierType state; 2817 GdkModifierType state;
2758 2818
2759 if(gtkconv->win==hidden_convwin) { 2819 if (gtkconv == NULL) {
2760 pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv); 2820 pidgin_conv_attach_to_conversation(conv);
2761 pidgin_conv_placement_place(gtkconv); 2821 gtkconv = PIDGIN_CONVERSATION(conv);
2762 } 2822 }
2763 2823
2764 pidgin_conv_switch_active_conversation(conv); 2824 pidgin_conv_switch_active_conversation(conv);
2765 /* Switch the tab only if the user initiated the event by pressing 2825 /* Switch the tab only if the user initiated the event by pressing
2766 * a button or hitting a key. */ 2826 * a button or hitting a key. */
2789 2849
2790 for (; l != NULL && (max_count == 0 || c < max_count); l = l->next) { 2850 for (; l != NULL && (max_count == 0 || c < max_count); l = l->next) {
2791 PurpleConversation *conv = (PurpleConversation*)l->data; 2851 PurpleConversation *conv = (PurpleConversation*)l->data;
2792 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 2852 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
2793 2853
2794 if(gtkconv == NULL || gtkconv->active_conv != conv) 2854 if (gtkconv != NULL && gtkconv->active_conv != conv)
2795 continue; 2855 continue;
2796 2856 if (gtkconv == NULL) {
2797 if (gtkconv->unseen_state >= min_state 2857 if (!purple_conversation_get_data(conv, "unseen-count") ||
2798 && (!hidden_only || 2858 !purple_conversation_get_data(conv, "unseen-state") ||
2799 (hidden_only && gtkconv->win == hidden_convwin))) { 2859 GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-state"))<min_state)
2800 2860 continue;
2801 r = g_list_prepend(r, conv); 2861 r = g_list_prepend(r, conv);
2802 c++; 2862 c++;
2863 } else {
2864 if (gtkconv->unseen_state >= min_state && !hidden_only) {
2865 r = g_list_prepend(r, conv);
2866 c++;
2867 }
2803 } 2868 }
2804 } 2869 }
2805 2870
2806 return r; 2871 return r;
2807 } 2872 }
2837 for (l = convs; l != NULL ; l = l->next) { 2902 for (l = convs; l != NULL ; l = l->next) {
2838 PurpleConversation *conv = (PurpleConversation*)l->data; 2903 PurpleConversation *conv = (PurpleConversation*)l->data;
2839 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 2904 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
2840 2905
2841 GtkWidget *icon = gtk_image_new(); 2906 GtkWidget *icon = gtk_image_new();
2842 GdkPixbuf *pbuf = pidgin_conv_get_tab_icon(conv, TRUE); 2907 GdkPixbuf *pbuf = pidgin_conv_get_icon(conv, icon, PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC);
2843 GtkWidget *item; 2908 GtkWidget *item;
2844 gchar *text = g_strdup_printf("%s (%d)", 2909 gchar *text = g_strdup_printf("%s (%d)",
2845 gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)), 2910 gtkconv ? gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)) : purple_conversation_get_name(conv),
2846 gtkconv->unseen_count); 2911 gtkconv ? gtkconv->unseen_count : GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")));
2847 2912
2848 gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pbuf); 2913 gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pbuf);
2849 g_object_unref(pbuf); 2914 g_object_unref(pbuf);
2850 2915
2851 item = gtk_image_menu_item_new_with_label(text); 2916 item = gtk_image_menu_item_new_with_label(text);
3099 GList *list; 3164 GList *list;
3100 PidginConversation *gtkconv; 3165 PidginConversation *gtkconv;
3101 PurpleConversation *conv; 3166 PurpleConversation *conv;
3102 GtkWidget *item; 3167 GtkWidget *item;
3103 3168
3104 if (win->window == NULL || win == hidden_convwin) 3169 if (win->window == NULL)
3105 return; 3170 return;
3106 3171
3107 gtkconv = pidgin_conv_window_get_active_gtkconv(win); 3172 gtkconv = pidgin_conv_window_get_active_gtkconv(win);
3108 if (gtkconv == NULL) 3173 if (gtkconv == NULL)
3109 return; 3174 return;
3575 3640
3576 if (win->menu.send_to != NULL) 3641 if (win->menu.send_to != NULL)
3577 gtk_widget_destroy(win->menu.send_to); 3642 gtk_widget_destroy(win->menu.send_to);
3578 3643
3579 /* Build the Send To menu */ 3644 /* Build the Send To menu */
3580 win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("_Send To")); 3645 win->menu.send_to = gtk_menu_item_new_with_mnemonic(_("S_end To"));
3581 gtk_widget_show(win->menu.send_to); 3646 gtk_widget_show(win->menu.send_to);
3582 3647
3583 menu = gtk_menu_new(); 3648 menu = gtk_menu_new();
3584 gtk_menu_shell_insert(GTK_MENU_SHELL(win->menu.menubar), 3649 gtk_menu_shell_insert(GTK_MENU_SHELL(win->menu.menubar),
3585 win->menu.send_to, 2); 3650 win->menu.send_to, 2);
4955 PurpleConversationType conv_type = purple_conversation_get_type(conv); 5020 PurpleConversationType conv_type = purple_conversation_get_type(conv);
4956 GtkWidget *pane = NULL; 5021 GtkWidget *pane = NULL;
4957 GtkWidget *tab_cont; 5022 GtkWidget *tab_cont;
4958 PurpleBlistNode *convnode; 5023 PurpleBlistNode *convnode;
4959 5024
5025 if (hidden)
5026 return;
5027
4960 if (conv_type == PURPLE_CONV_TYPE_IM && (gtkconv = pidgin_conv_find_gtkconv(conv))) { 5028 if (conv_type == PURPLE_CONV_TYPE_IM && (gtkconv = pidgin_conv_find_gtkconv(conv))) {
4961 conv->ui_data = gtkconv; 5029 conv->ui_data = gtkconv;
4962 if (!g_list_find(gtkconv->convs, conv)) 5030 if (!g_list_find(gtkconv->convs, conv))
4963 gtkconv->convs = g_list_prepend(gtkconv->convs, conv); 5031 gtkconv->convs = g_list_prepend(gtkconv->convs, conv);
4964 pidgin_conv_switch_active_conversation(conv); 5032 pidgin_conv_switch_active_conversation(conv);
5054 5122
5055 g_signal_connect_swapped(G_OBJECT(pane), "focus", 5123 g_signal_connect_swapped(G_OBJECT(pane), "focus",
5056 G_CALLBACK(gtk_widget_grab_focus), 5124 G_CALLBACK(gtk_widget_grab_focus),
5057 gtkconv->entry); 5125 gtkconv->entry);
5058 5126
5059 if (hidden) 5127 pidgin_conv_placement_place(gtkconv);
5060 pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv);
5061 else
5062 pidgin_conv_placement_place(gtkconv);
5063 5128
5064 if (nick_colors == NULL) { 5129 if (nick_colors == NULL) {
5065 nbr_nick_colors = NUM_NICK_COLORS; 5130 nbr_nick_colors = NUM_NICK_COLORS;
5066 nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->imhtml)->base[GTK_STATE_NORMAL]); 5131 nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->imhtml)->base[GTK_STATE_NORMAL]);
5067 } 5132 }
5068 } 5133 }
5069 5134
5135 #if 0
5070 static void 5136 static void
5071 pidgin_conv_new_hidden(PurpleConversation *conv) 5137 pidgin_conv_new_hidden(PurpleConversation *conv)
5072 { 5138 {
5073 private_gtkconv_new(conv, TRUE); 5139 private_gtkconv_new(conv, TRUE);
5074 } 5140 }
5141 #endif
5075 5142
5076 void 5143 void
5077 pidgin_conv_new(PurpleConversation *conv) 5144 pidgin_conv_new(PurpleConversation *conv)
5078 { 5145 {
5079 private_gtkconv_new(conv, FALSE); 5146 private_gtkconv_new(conv, FALSE);
5085 static void 5152 static void
5086 received_im_msg_cb(PurpleAccount *account, char *sender, char *message, 5153 received_im_msg_cb(PurpleAccount *account, char *sender, char *message,
5087 PurpleConversation *conv, PurpleMessageFlags flags) 5154 PurpleConversation *conv, PurpleMessageFlags flags)
5088 { 5155 {
5089 PurpleConversationUiOps *ui_ops = pidgin_conversations_get_conv_ui_ops(); 5156 PurpleConversationUiOps *ui_ops = pidgin_conversations_get_conv_ui_ops();
5090 if (conv != NULL) 5157
5158 /* create hidden conv if hide_new pref is always */
5159 /* or if hide_new pref is away and account is away */
5160 if ((strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0) ||
5161 (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
5162 !purple_status_is_available(purple_account_get_active_status(account)))) {
5163 if (!conv) {
5164 ui_ops->create_conversation = NULL;
5165 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
5166 purple_conversation_set_ui_ops(conv, NULL);
5167 ui_ops->create_conversation = pidgin_conv_new;
5168 } else {
5169 /* TODO: update the unseen_state data on the conv here */
5170 }
5171 } else {
5172 /* new message for an IM */
5173 if (conv && conv->type == PURPLE_CONV_TYPE_IM)
5174 pidgin_conv_attach_to_conversation(conv);
5175 }
5176 }
5177
5178 static void
5179 pidgin_conv_destroy(PurpleConversation *conv)
5180 {
5181 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
5182
5183 if (!gtkconv)
5091 return; 5184 return;
5092
5093 /* create hidden conv if hide_new pref is always */
5094 if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always") == 0)
5095 {
5096 ui_ops->create_conversation = pidgin_conv_new_hidden;
5097 purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
5098 ui_ops->create_conversation = pidgin_conv_new;
5099 return;
5100 }
5101
5102 /* create hidden conv if hide_new pref is away and account is away */
5103 if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away") == 0 &&
5104 !purple_status_is_available(purple_account_get_active_status(account)))
5105 {
5106 ui_ops->create_conversation = pidgin_conv_new_hidden;
5107 purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender);
5108 ui_ops->create_conversation = pidgin_conv_new;
5109 return;
5110 }
5111 }
5112
5113 static void
5114 pidgin_conv_destroy(PurpleConversation *conv)
5115 {
5116 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
5117 5185
5118 gtkconv->convs = g_list_remove(gtkconv->convs, conv); 5186 gtkconv->convs = g_list_remove(gtkconv->convs, conv);
5119 /* Don't destroy ourselves until all our convos are gone */ 5187 /* Don't destroy ourselves until all our convos are gone */
5120 if (gtkconv->convs) { 5188 if (gtkconv->convs) {
5121 /* Make sure the destroyed conversation is not the active one */ 5189 /* Make sure the destroyed conversation is not the active one */
6507 purple_conv_im_get_typing_state(im) == PURPLE_TYPED) { 6575 purple_conv_im_get_typing_state(im) == PURPLE_TYPED) {
6508 atk_object_set_description(accessibility_obj, _("Stopped Typing")); 6576 atk_object_set_description(accessibility_obj, _("Stopped Typing"));
6509 style = "color=\"#c4a000\""; 6577 style = "color=\"#c4a000\"";
6510 } else if (gtkconv->unseen_state == PIDGIN_UNSEEN_NICK) { 6578 } else if (gtkconv->unseen_state == PIDGIN_UNSEEN_NICK) {
6511 atk_object_set_description(accessibility_obj, _("Nick Said")); 6579 atk_object_set_description(accessibility_obj, _("Nick Said"));
6512 style = "color=\"#204a87\""; 6580 style = "color=\"#cc0000\"";
6513 } else if (gtkconv->unseen_state == PIDGIN_UNSEEN_TEXT) { 6581 } else if (gtkconv->unseen_state == PIDGIN_UNSEEN_TEXT) {
6514 atk_object_set_description(accessibility_obj, _("Unread Messages")); 6582 atk_object_set_description(accessibility_obj, _("Unread Messages"));
6515 style = "color=\"#cc0000\""; 6583 if (gtkconv->active_conv->type == PURPLE_CONV_TYPE_CHAT)
6584 style = "color=\"#204a87\"";
6585 else
6586 style = "color=\"#cc0000\"";
6516 } else if (gtkconv->unseen_state == PIDGIN_UNSEEN_EVENT) { 6587 } else if (gtkconv->unseen_state == PIDGIN_UNSEEN_EVENT) {
6517 atk_object_set_description(accessibility_obj, _("New Event")); 6588 atk_object_set_description(accessibility_obj, _("New Event"));
6518 style = "color=\"#888a85\""; 6589 style = "color=\"#888a85\"";
6519 } else { 6590 } else {
6520 style = NULL; 6591 style = NULL;
6522 6593
6523 if (gtkconv->unseen_state == PIDGIN_UNSEEN_TEXT || 6594 if (gtkconv->unseen_state == PIDGIN_UNSEEN_TEXT ||
6524 gtkconv->unseen_state == PIDGIN_UNSEEN_NICK || 6595 gtkconv->unseen_state == PIDGIN_UNSEEN_NICK ||
6525 gtkconv->unseen_state == PIDGIN_UNSEEN_EVENT) 6596 gtkconv->unseen_state == PIDGIN_UNSEEN_EVENT)
6526 bold = TRUE; 6597 bold = TRUE;
6527 6598
6528 if (style || bold) 6599 if (style || bold)
6529 { 6600 {
6530 char *html_title,*label; 6601 char *html_title,*label;
6531 6602
6532 html_title = g_markup_escape_text(title, -1); 6603 html_title = g_markup_escape_text(title, -1);
6596 { 6667 {
6597 flags = PIDGIN_CONV_MENU; 6668 flags = PIDGIN_CONV_MENU;
6598 } 6669 }
6599 6670
6600 pidgin_conv_update_fields(conv, flags); 6671 pidgin_conv_update_fields(conv, flags);
6672 }
6673
6674 static void
6675 wrote_msg_update_unseen_cb(PurpleAccount *account, const char *who, const char *message,
6676 PurpleConversation *conv, PurpleMessageFlags flags, gpointer null)
6677 {
6678 if (conv == NULL || PIDGIN_IS_PIDGIN_CONVERSATION(conv))
6679 return;
6680 if (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) {
6681 PidginUnseenState unseen = PIDGIN_UNSEEN_NONE;
6682
6683 if ((flags & PURPLE_MESSAGE_NICK) == PURPLE_MESSAGE_NICK)
6684 unseen = PIDGIN_UNSEEN_NICK;
6685 else if (((flags & PURPLE_MESSAGE_SYSTEM) == PURPLE_MESSAGE_SYSTEM) ||
6686 ((flags & PURPLE_MESSAGE_ERROR) == PURPLE_MESSAGE_ERROR))
6687 unseen = PIDGIN_UNSEEN_EVENT;
6688 else if ((flags & PURPLE_MESSAGE_NO_LOG) == PURPLE_MESSAGE_NO_LOG)
6689 unseen = PIDGIN_UNSEEN_NO_LOG;
6690 else
6691 unseen = PIDGIN_UNSEEN_TEXT;
6692
6693 conv_set_unseen(conv, unseen);
6694 purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
6695 }
6601 } 6696 }
6602 6697
6603 static PurpleConversationUiOps conversation_ui_ops = 6698 static PurpleConversationUiOps conversation_ui_ops =
6604 { 6699 {
6605 pidgin_conv_new, 6700 pidgin_conv_new,
7097 7192
7098 static void 7193 static void
7099 account_status_changed_cb(PurpleAccount *account, PurpleStatus *oldstatus, 7194 account_status_changed_cb(PurpleAccount *account, PurpleStatus *oldstatus,
7100 PurpleStatus *newstatus) 7195 PurpleStatus *newstatus)
7101 { 7196 {
7197 #if 0
7102 GList *l; 7198 GList *l;
7103 PurpleConversation *conv = NULL; 7199 PurpleConversation *conv = NULL;
7104 PidginConversation *gtkconv; 7200 PidginConversation *gtkconv;
7105 7201
7106 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")!=0) 7202 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")!=0)
7107 return; 7203 return;
7108 7204
7109 if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus)) 7205 if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus))
7110 return; 7206 return;
7111 7207 #endif
7112 while ((l = hidden_convwin->gtkconvs) != NULL)
7113 {
7114 gtkconv = l->data;
7115
7116 conv = gtkconv->active_conv;
7117
7118 while(l && !purple_status_is_available(
7119 purple_account_get_active_status(
7120 purple_conversation_get_account(conv))))
7121 l = l->next;
7122 if (!l)
7123 break;
7124
7125 pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
7126 pidgin_conv_placement_place(gtkconv);
7127
7128 /* TODO: do we need to do anything for any other conversations that are in the same gtkconv here?
7129 * I'm a little concerned that not doing so will cause the "pending" indicator in the gtkblist not to be cleared. -DAA*/
7130 purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
7131 }
7132 } 7208 }
7133 7209
7134 static void 7210 static void
7135 hide_new_pref_cb(const char *name, PurplePrefType type, 7211 hide_new_pref_cb(const char *name, PurplePrefType type,
7136 gconstpointer value, gpointer data) 7212 gconstpointer value, gpointer data)
7137 { 7213 {
7138 GList *l; 7214 GList *l;
7139 PurpleConversation *conv = NULL;
7140 PidginConversation *gtkconv;
7141 gboolean when_away = FALSE; 7215 gboolean when_away = FALSE;
7142
7143 if(!hidden_convwin)
7144 return;
7145 7216
7146 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always")==0) 7217 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "always")==0)
7147 return; 7218 return;
7148 7219
7149 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0) 7220 if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new"), "away")==0)
7150 when_away = TRUE; 7221 when_away = TRUE;
7151 7222
7152 while ((l = hidden_convwin->gtkconvs) != NULL) 7223 for (l = purple_get_conversations(); l; l = l->next)
7153 { 7224 {
7154 gtkconv = l->data; 7225 PurpleConversation *conv = l->data;
7155 7226 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
7156 conv = gtkconv->active_conv; 7227 if (gtkconv)
7157 7228 continue;
7158 if(when_away && !purple_status_is_available( 7229 if(when_away && !purple_status_is_available(
7159 purple_account_get_active_status( 7230 purple_account_get_active_status(
7160 purple_conversation_get_account(conv)))) 7231 purple_conversation_get_account(conv))))
7161 continue; 7232 continue;
7162 7233 pidgin_conv_attach_to_conversation(conv);
7163 pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
7164 pidgin_conv_placement_place(gtkconv);
7165 } 7234 }
7166 } 7235 }
7167 7236
7168 7237
7169 static void 7238 static void
7215 * one of the contacts containing the buddy corresponding to 7284 * one of the contacts containing the buddy corresponding to
7216 * a conversation. It's easier to just update them all. */ 7285 * a conversation. It's easier to just update them all. */
7217 /* if (purple_conversation_get_account(conv) == account) */ 7286 /* if (purple_conversation_get_account(conv) == account) */
7218 pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON | 7287 pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON |
7219 PIDGIN_CONV_MENU | PIDGIN_CONV_COLORIZE_TITLE); 7288 PIDGIN_CONV_MENU | PIDGIN_CONV_COLORIZE_TITLE);
7289
7290 if (PURPLE_CONNECTION_IS_CONNECTED(gc) &&
7291 conv->type == PURPLE_CONV_TYPE_CHAT &&
7292 conv->account == gc->account &&
7293 purple_conversation_get_data(conv, "want-to-rejoin")) {
7294 GHashTable *comps = NULL;
7295 PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name);
7296 if (chat == NULL) {
7297 if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL)
7298 comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, conv->name);
7299 } else {
7300 comps = chat->components;
7301 }
7302 serv_join_chat(gc, comps);
7303 if (chat == NULL && comps != NULL)
7304 g_hash_table_destroy(comps);
7305 }
7220 } 7306 }
7221 } 7307 }
7222 7308
7223 static gboolean 7309 static gboolean
7224 update_buddy_status_timeout(PurpleBuddy *buddy) 7310 update_buddy_status_timeout(PurpleBuddy *buddy)
7342 add_message_history_to_gtkconv(gpointer data) 7428 add_message_history_to_gtkconv(gpointer data)
7343 { 7429 {
7344 PidginConversation *gtkconv = data; 7430 PidginConversation *gtkconv = data;
7345 int count = 0; 7431 int count = 0;
7346 int timer = gtkconv->attach.timer; 7432 int timer = gtkconv->attach.timer;
7433 time_t when = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gtkconv->entry), "attach-start-time"));
7434
7347 gtkconv->attach.timer = 0; 7435 gtkconv->attach.timer = 0;
7348 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ 7436 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */
7349 PurpleConvMessage *msg = gtkconv->attach.current->data; 7437 PurpleConvMessage *msg = gtkconv->attach.current->data;
7438 if (when && when < msg->when) {
7439 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0);
7440 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
7441 }
7350 pidgin_conv_write_conv(gtkconv->active_conv, msg->who, msg->who, msg->what, msg->flags, msg->when); 7442 pidgin_conv_write_conv(gtkconv->active_conv, msg->who, msg->who, msg->what, msg->flags, msg->when);
7351 gtkconv->attach.current = gtkconv->attach.current->prev; 7443 gtkconv->attach.current = gtkconv->attach.current->prev;
7352 count++; 7444 count++;
7353 } 7445 }
7354 gtkconv->attach.timer = timer; 7446 gtkconv->attach.timer = timer;
7355 if (gtkconv->attach.current) 7447 if (gtkconv->attach.current)
7356 return TRUE; 7448 return TRUE;
7357 7449
7450 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
7358 purple_signal_emit(pidgin_conversations_get_handle(), 7451 purple_signal_emit(pidgin_conversations_get_handle(),
7359 "conversation-displayed", gtkconv); 7452 "conversation-displayed", gtkconv);
7360 g_source_remove(gtkconv->attach.timer); 7453 g_source_remove(gtkconv->attach.timer);
7361 gtkconv->attach.timer = 0; 7454 gtkconv->attach.timer = 0;
7362 return FALSE; 7455 return FALSE;
7364 7457
7365 gboolean pidgin_conv_attach_to_conversation(PurpleConversation *conv) 7458 gboolean pidgin_conv_attach_to_conversation(PurpleConversation *conv)
7366 { 7459 {
7367 GList *list; 7460 GList *list;
7368 PidginConversation *gtkconv; 7461 PidginConversation *gtkconv;
7462 int timer;
7369 7463
7370 if (PIDGIN_IS_PIDGIN_CONVERSATION(conv)) 7464 if (PIDGIN_IS_PIDGIN_CONVERSATION(conv))
7371 return FALSE; 7465 return FALSE;
7372 7466
7467 purple_conversation_set_data(conv, "unseen-count", NULL);
7468 purple_conversation_set_data(conv, "unseen-state", NULL);
7373 purple_conversation_set_ui_ops(conv, pidgin_conversations_get_conv_ui_ops()); 7469 purple_conversation_set_ui_ops(conv, pidgin_conversations_get_conv_ui_ops());
7374 private_gtkconv_new(conv, FALSE); 7470 private_gtkconv_new(conv, FALSE);
7375 gtkconv = PIDGIN_CONVERSATION(conv); 7471 gtkconv = PIDGIN_CONVERSATION(conv);
7376 7472
7377 list = purple_conversation_get_message_history(conv); 7473 list = purple_conversation_get_message_history(conv);
7378 if (list) { 7474 if (list) {
7379 list = g_list_last(list); 7475 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time",
7380 gtkconv->attach.current = list; 7476 GINT_TO_POINTER(((PurpleConvMessage*)(list->data))->when));
7477 gtkconv->attach.current = g_list_last(list);
7381 gtkconv->attach.timer = g_idle_add(add_message_history_to_gtkconv, gtkconv); 7478 gtkconv->attach.timer = g_idle_add(add_message_history_to_gtkconv, gtkconv);
7382 } else { 7479 } else {
7383 purple_signal_emit(pidgin_conversations_get_handle(), 7480 purple_signal_emit(pidgin_conversations_get_handle(),
7384 "conversation-displayed", gtkconv); 7481 "conversation-displayed", gtkconv);
7385 } 7482 }
7387 if (conv->type == PURPLE_CONV_TYPE_CHAT) { 7484 if (conv->type == PURPLE_CONV_TYPE_CHAT) {
7388 pidgin_conv_update_fields(conv, PIDGIN_CONV_TOPIC); 7485 pidgin_conv_update_fields(conv, PIDGIN_CONV_TOPIC);
7389 pidgin_conv_chat_add_users(conv, PURPLE_CONV_CHAT(conv)->in_room, TRUE); 7486 pidgin_conv_chat_add_users(conv, PURPLE_CONV_CHAT(conv)->in_room, TRUE);
7390 } 7487 }
7391 7488
7489 timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer"));
7490 if (timer)
7491 purple_timeout_remove(timer);
7392 return TRUE; 7492 return TRUE;
7393 } 7493 }
7394 7494
7395 void * 7495 void *
7396 pidgin_conversations_get_handle(void) 7496 pidgin_conversations_get_handle(void)
7452 7552
7453 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height", 54); 7553 purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height", 54);
7454 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE); 7554 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE);
7455 7555
7456 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never"); 7556 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never");
7557 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", FALSE);
7457 7558
7458 #ifdef _WIN32 7559 #ifdef _WIN32
7459 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE); 7560 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE);
7460 #endif 7561 #endif
7461 7562
7614 7715
7615 purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", 7716 purple_signal_connect(purple_conversations_get_handle(), "received-im-msg",
7616 handle, G_CALLBACK(received_im_msg_cb), NULL); 7717 handle, G_CALLBACK(received_im_msg_cb), NULL);
7617 7718
7618 purple_conversations_set_ui_ops(&conversation_ui_ops); 7719 purple_conversations_set_ui_ops(&conversation_ui_ops);
7619
7620 hidden_convwin = pidgin_conv_window_new();
7621 window_list = g_list_remove(window_list, hidden_convwin);
7622 7720
7623 purple_signal_connect(purple_accounts_get_handle(), "account-status-changed", 7721 purple_signal_connect(purple_accounts_get_handle(), "account-status-changed",
7624 handle, PURPLE_CALLBACK(account_status_changed_cb), NULL); 7722 handle, PURPLE_CALLBACK(account_status_changed_cb), NULL);
7625 7723
7626 /* Callbacks to update a conversation */ 7724 /* Callbacks to update a conversation */
7653 purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", handle, 7751 purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", handle,
7654 PURPLE_CALLBACK(update_chat_topic), NULL); 7752 PURPLE_CALLBACK(update_chat_topic), NULL);
7655 purple_signal_connect_priority(purple_conversations_get_handle(), "conversation-updated", handle, 7753 purple_signal_connect_priority(purple_conversations_get_handle(), "conversation-updated", handle,
7656 PURPLE_CALLBACK(pidgin_conv_updated), NULL, 7754 PURPLE_CALLBACK(pidgin_conv_updated), NULL,
7657 PURPLE_SIGNAL_PRIORITY_LOWEST); 7755 PURPLE_SIGNAL_PRIORITY_LOWEST);
7756 purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg", handle,
7757 PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL);
7758 purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg", handle,
7759 PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL);
7658 } 7760 }
7659 7761
7660 void 7762 void
7661 pidgin_conversations_uninit(void) 7763 pidgin_conversations_uninit(void)
7662 { 7764 {
7663 purple_prefs_disconnect_by_handle(pidgin_conversations_get_handle()); 7765 purple_prefs_disconnect_by_handle(pidgin_conversations_get_handle());
7664 purple_signals_disconnect_by_handle(pidgin_conversations_get_handle()); 7766 purple_signals_disconnect_by_handle(pidgin_conversations_get_handle());
7665 purple_signals_unregister_by_instance(pidgin_conversations_get_handle()); 7767 purple_signals_unregister_by_instance(pidgin_conversations_get_handle());
7666 pidgin_conv_window_destroy(hidden_convwin);
7667 hidden_convwin=NULL;
7668 } 7768 }
7669 7769
7670 7770
7671 7771
7672 7772
7833 7933
7834 return TRUE; 7934 return TRUE;
7835 } 7935 }
7836 7936
7837 static void 7937 static void
7938 conv_set_unseen(PurpleConversation *conv, PidginUnseenState state)
7939 {
7940 int unseen_count = 0;
7941 PidginUnseenState unseen_state = PIDGIN_UNSEEN_NONE;
7942
7943 if(purple_conversation_get_data(conv, "unseen-count"))
7944 unseen_count = GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count"));
7945
7946 if(purple_conversation_get_data(conv, "unseen-state"))
7947 unseen_state = GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-state"));
7948
7949 if (state == PIDGIN_UNSEEN_NONE)
7950 {
7951 unseen_count = 0;
7952 unseen_state = PIDGIN_UNSEEN_NONE;
7953 }
7954 else
7955 {
7956 if (state >= PIDGIN_UNSEEN_TEXT)
7957 unseen_count++;
7958
7959 if (state > unseen_state)
7960 unseen_state = state;
7961 }
7962
7963 purple_conversation_set_data(conv, "unseen-count", GINT_TO_POINTER(unseen_count));
7964 purple_conversation_set_data(conv, "unseen-state", GINT_TO_POINTER(unseen_state));
7965
7966 purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
7967 }
7968
7969 static void
7838 gtkconv_set_unseen(PidginConversation *gtkconv, PidginUnseenState state) 7970 gtkconv_set_unseen(PidginConversation *gtkconv, PidginUnseenState state)
7839 { 7971 {
7840 if (state == PIDGIN_UNSEEN_NONE) 7972 if (state == PIDGIN_UNSEEN_NONE)
7841 { 7973 {
7842 gtkconv->unseen_count = 0; 7974 gtkconv->unseen_count = 0;
8044 GtkWidget *menu = gtk_menu_new(), *sub; 8176 GtkWidget *menu = gtk_menu_new(), *sub;
8045 gboolean populated = populate_menu_with_options(menu, gtkconv, TRUE); 8177 gboolean populated = populate_menu_with_options(menu, gtkconv, TRUE);
8046 sub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(gtkconv->win->menu.send_to)); 8178 sub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(gtkconv->win->menu.send_to));
8047 8179
8048 if (sub && GTK_WIDGET_IS_SENSITIVE(gtkconv->win->menu.send_to)) { 8180 if (sub && GTK_WIDGET_IS_SENSITIVE(gtkconv->win->menu.send_to)) {
8049 GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("_Send To")); 8181 GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("S_end To"));
8050 if (populated) 8182 if (populated)
8051 pidgin_separator(menu); 8183 pidgin_separator(menu);
8052 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 8184 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
8053 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub); 8185 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
8054 gtk_widget_show(item); 8186 gtk_widget_show(item);
8794 8926
8795 gtk_widget_hide_all(win->window); 8927 gtk_widget_hide_all(win->window);
8796 8928
8797 if (win->gtkconvs) { 8929 if (win->gtkconvs) {
8798 while (win->gtkconvs) { 8930 while (win->gtkconvs) {
8799 GList *nextgtk = win->gtkconvs->next; 8931 gboolean last = (win->gtkconvs->next == NULL);
8800 PidginConversation *gtkconv = win->gtkconvs->data; 8932 close_conv_cb(NULL, NULL, win->gtkconvs->data);
8801 GList *nextcore = gtkconv->convs->next; 8933 if (last)
8802 PurpleConversation *conv = gtkconv->convs->data; 8934 break;
8803 purple_conversation_destroy(conv);
8804 if (!nextgtk && !nextcore)
8805 /* we'll end up invoking ourselves when we destroy our last child */
8806 /* so don't destroy ourselves right now */
8807 return;
8808 } 8935 }
8809 return; 8936 return;
8810 } 8937 }
8811 gtk_widget_destroy(win->window); 8938 gtk_widget_destroy(win->window);
8812 8939
9081 0, 0, NULL, NULL, gtkconv); 9208 0, 0, NULL, NULL, gtkconv);
9082 9209
9083 if (win->gtkconvs && win->gtkconvs->next == NULL) 9210 if (win->gtkconvs && win->gtkconvs->next == NULL)
9084 pidgin_conv_tab_pack(win, win->gtkconvs->data); 9211 pidgin_conv_tab_pack(win, win->gtkconvs->data);
9085 9212
9086 if (!win->gtkconvs && win != hidden_convwin) 9213 if (!win->gtkconvs)
9087 pidgin_conv_window_destroy(win); 9214 pidgin_conv_window_destroy(win);
9088 } 9215 }
9089 9216
9090 PidginConversation * 9217 PidginConversation *
9091 pidgin_conv_window_get_gtkconv_at_index(const PidginWindow *win, int index) 9218 pidgin_conv_window_get_gtkconv_at_index(const PidginWindow *win, int index)
9620 } 9747 }
9621 9748
9622 gboolean 9749 gboolean
9623 pidgin_conv_is_hidden(PidginConversation *gtkconv) 9750 pidgin_conv_is_hidden(PidginConversation *gtkconv)
9624 { 9751 {
9625 g_return_val_if_fail(gtkconv != NULL, FALSE); 9752 return (gtkconv == NULL);
9626
9627 return (gtkconv->win == hidden_convwin);
9628 } 9753 }
9629 9754
9630 9755
9631 /* Algorithm from http://www.w3.org/TR/AERT#color-contrast */ 9756 /* Algorithm from http://www.w3.org/TR/AERT#color-contrast */
9632 static gboolean 9757 static gboolean
9723 *color_count = i; 9848 *color_count = i;
9724 } 9849 }
9725 9850
9726 return colors; 9851 return colors;
9727 } 9852 }
9853

mercurial