| 136 static const char *item_factory_translate_func (const char *path, gpointer func_data); |
138 static const char *item_factory_translate_func (const char *path, gpointer func_data); |
| 137 static gboolean get_iter_from_node(PurpleBlistNode *node, GtkTreeIter *iter); |
139 static gboolean get_iter_from_node(PurpleBlistNode *node, GtkTreeIter *iter); |
| 138 static void redo_buddy_list(PurpleBuddyList *list, gboolean remove, gboolean rerender); |
140 static void redo_buddy_list(PurpleBuddyList *list, gboolean remove, gboolean rerender); |
| 139 static void pidgin_blist_collapse_contact_cb(GtkWidget *w, PurpleBlistNode *node); |
141 static void pidgin_blist_collapse_contact_cb(GtkWidget *w, PurpleBlistNode *node); |
| 140 static char *pidgin_get_group_title(PurpleBlistNode *gnode, gboolean expanded); |
142 static char *pidgin_get_group_title(PurpleBlistNode *gnode, gboolean expanded); |
| 141 |
143 static void pidgin_blist_expand_contact_cb(GtkWidget *w, PurpleBlistNode *node); |
| 142 struct _pidgin_blist_node { |
144 |
| |
145 typedef enum { |
| |
146 PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE = 1 << 0, /* Whether there's pending message in a conversation */ |
| |
147 } PidginBlistNodeFlags; |
| |
148 |
| |
149 typedef struct _pidgin_blist_node { |
| 143 GtkTreeRowReference *row; |
150 GtkTreeRowReference *row; |
| 144 gboolean contact_expanded; |
151 gboolean contact_expanded; |
| 145 gboolean recent_signonoff; |
152 gboolean recent_signonoff; |
| 146 gint recent_signonoff_timer; |
153 gint recent_signonoff_timer; |
| 147 }; |
154 struct { |
| |
155 PurpleConversation *conv; |
| |
156 time_t last_message; /* timestamp for last displayed message */ |
| |
157 PidginBlistNodeFlags flags; |
| |
158 } conv; |
| |
159 } PidginBlistNode; |
| 148 |
160 |
| 149 static char dim_grey_string[8] = ""; |
161 static char dim_grey_string[8] = ""; |
| 150 static char *dim_grey() |
162 static char *dim_grey() |
| 151 { |
163 { |
| 152 if (!gtkblist) |
164 if (!gtkblist) |
| 304 static void gtk_blist_menu_send_file_cb(GtkWidget *w, PurpleBuddy *b) |
316 static void gtk_blist_menu_send_file_cb(GtkWidget *w, PurpleBuddy *b) |
| 305 { |
317 { |
| 306 serv_send_file(b->account->gc, b->name, NULL); |
318 serv_send_file(b->account->gc, b->name, NULL); |
| 307 } |
319 } |
| 308 |
320 |
| |
321 static void gtk_blist_menu_move_to_cb(GtkWidget *w, PurpleBlistNode *node) |
| |
322 { |
| |
323 PurpleGroup *group = g_object_get_data(G_OBJECT(w), "groupnode"); |
| |
324 purple_blist_add_contact((PurpleContact *)node, group, NULL); |
| |
325 |
| |
326 } |
| |
327 |
| 309 static void gtk_blist_menu_autojoin_cb(GtkWidget *w, PurpleChat *chat) |
328 static void gtk_blist_menu_autojoin_cb(GtkWidget *w, PurpleChat *chat) |
| 310 { |
329 { |
| 311 purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-autojoin", |
330 purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-autojoin", |
| 312 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))); |
331 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))); |
| |
332 } |
| |
333 |
| |
334 static void gtk_blist_menu_persistent_cb(GtkWidget *w, PurpleChat *chat) |
| |
335 { |
| |
336 purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-persistent", |
| |
337 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))); |
| |
338 } |
| |
339 |
| |
340 static PurpleConversation * |
| |
341 find_conversation_with_buddy(PurpleBuddy *buddy) |
| |
342 { |
| |
343 PidginBlistNode *ui = buddy->node.ui_data; |
| |
344 if (ui) |
| |
345 return ui->conv.conv; |
| |
346 return purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, |
| |
347 purple_buddy_get_name(buddy), |
| |
348 purple_buddy_get_account(buddy)); |
| 313 } |
349 } |
| 314 |
350 |
| 315 static void gtk_blist_join_chat(PurpleChat *chat) |
351 static void gtk_blist_join_chat(PurpleChat *chat) |
| 316 { |
352 { |
| 317 PurpleConversation *conv; |
353 PurpleConversation *conv; |
| 393 } |
429 } |
| 394 editing_blist = TRUE; |
430 editing_blist = TRUE; |
| 395 } |
431 } |
| 396 #endif |
432 #endif |
| 397 |
433 |
| |
434 static void |
| |
435 gtk_blist_do_personize(GList *merges) |
| |
436 { |
| |
437 PurpleBlistNode *contact = NULL; |
| |
438 int max = 0; |
| |
439 GList *tmp; |
| |
440 |
| |
441 /* First, we find the contact to merge the rest of the buddies into. |
| |
442 * This will be the contact with the most buddies in it; ties are broken |
| |
443 * by which contact is higher in the list |
| |
444 */ |
| |
445 for (tmp = merges; tmp; tmp = tmp->next) { |
| |
446 PurpleBlistNode *node = tmp->data; |
| |
447 PurpleBlistNode *b; |
| |
448 int i = 0; |
| |
449 |
| |
450 if (node->type == PURPLE_BLIST_BUDDY_NODE) |
| |
451 node = node->parent; |
| |
452 |
| |
453 if (node->type != PURPLE_BLIST_CONTACT_NODE) |
| |
454 continue; |
| |
455 |
| |
456 |
| |
457 for (b = node->child; b; b = b->next) |
| |
458 i++; |
| |
459 if (i > max) { |
| |
460 contact = node; |
| |
461 max = i; |
| |
462 } |
| |
463 } |
| |
464 |
| |
465 if (contact == NULL) |
| |
466 return; |
| |
467 |
| |
468 /* Merge all those buddies into this contact */ |
| |
469 for (tmp = merges; tmp; tmp = tmp->next) { |
| |
470 PurpleBlistNode *node = tmp->data; |
| |
471 if (node->type == PURPLE_BLIST_BUDDY_NODE) |
| |
472 node = node->parent; |
| |
473 |
| |
474 if (node == contact) |
| |
475 continue; |
| |
476 |
| |
477 purple_blist_merge_contact((PurpleContact *)node, contact); |
| |
478 } |
| |
479 |
| |
480 /* And show the expanded contact, so the people know what's going on */ |
| |
481 pidgin_blist_expand_contact_cb(NULL, contact); |
| |
482 g_list_free(merges); |
| |
483 } |
| |
484 |
| |
485 static void |
| |
486 gtk_blist_auto_personize(PurpleBlistNode *group, const char *alias) |
| |
487 { |
| |
488 PurpleBlistNode *contact; |
| |
489 PurpleBlistNode *buddy; |
| |
490 GList *merges = NULL; |
| |
491 int i = 0; |
| |
492 char *a = g_utf8_casefold(alias, -1); |
| |
493 |
| |
494 for (contact = group->child; contact; contact = contact->next) { |
| |
495 char *node_alias; |
| |
496 if (contact->type != PURPLE_BLIST_CONTACT_NODE) |
| |
497 continue; |
| |
498 |
| |
499 node_alias = g_utf8_casefold(purple_contact_get_alias((PurpleContact *)contact), -1); |
| |
500 if (node_alias && !g_utf8_collate(node_alias, a)) { |
| |
501 merges = g_list_append(merges, contact); |
| |
502 i++; |
| |
503 g_free(node_alias); |
| |
504 continue; |
| |
505 } |
| |
506 g_free(node_alias); |
| |
507 |
| |
508 for (buddy = contact->child; buddy; buddy = buddy->next) { |
| |
509 if (buddy->type != PURPLE_BLIST_BUDDY_NODE) |
| |
510 continue; |
| |
511 |
| |
512 node_alias = g_utf8_casefold(purple_buddy_get_alias((PurpleBuddy *)buddy), -1); |
| |
513 if (node_alias && !g_utf8_collate(node_alias, a)) { |
| |
514 merges = g_list_append(merges, buddy); |
| |
515 i++; |
| |
516 } |
| |
517 g_free(node_alias); |
| |
518 } |
| |
519 } |
| |
520 g_free(a); |
| |
521 |
| |
522 if (i > 1) |
| |
523 { |
| |
524 char *msg = g_strdup_printf(ngettext("You have %d contact named %s. Would you like to merge them?", "You currently have %d contacts named %s. Would you like to merge them?", i), i, alias); |
| |
525 purple_request_action(NULL, NULL, msg, _("Merging these contacts will cause them to share a single entry on the buddy list and use a single conversation window. " |
| |
526 "You can separate them again by choosing 'Expand' from the contact's context menu"), 0, NULL, NULL, NULL, |
| |
527 merges, 2, _("_Merge"), PURPLE_CALLBACK(gtk_blist_do_personize), _("_Cancel"), PURPLE_CALLBACK(g_list_free)); |
| |
528 g_free(msg); |
| |
529 } else |
| |
530 g_list_free(merges); |
| |
531 } |
| |
532 |
| 398 static void gtk_blist_renderer_edited_cb(GtkCellRendererText *text_rend, char *arg1, |
533 static void gtk_blist_renderer_edited_cb(GtkCellRendererText *text_rend, char *arg1, |
| 399 char *arg2, PurpleBuddyList *list) |
534 char *arg2, PurpleBuddyList *list) |
| 400 { |
535 { |
| 401 GtkTreeIter iter; |
536 GtkTreeIter iter; |
| 402 GtkTreePath *path; |
537 GtkTreePath *path; |
| 419 case PURPLE_BLIST_CONTACT_NODE: |
554 case PURPLE_BLIST_CONTACT_NODE: |
| 420 { |
555 { |
| 421 PurpleContact *contact = (PurpleContact *)node; |
556 PurpleContact *contact = (PurpleContact *)node; |
| 422 struct _pidgin_blist_node *gtknode = (struct _pidgin_blist_node *)node->ui_data; |
557 struct _pidgin_blist_node *gtknode = (struct _pidgin_blist_node *)node->ui_data; |
| 423 |
558 |
| 424 if (contact->alias || gtknode->contact_expanded) |
559 if (contact->alias || gtknode->contact_expanded) { |
| 425 purple_blist_alias_contact(contact, arg2); |
560 purple_blist_alias_contact(contact, arg2); |
| 426 else |
561 gtk_blist_auto_personize(node->parent, arg2); |
| 427 { |
562 } else { |
| 428 PurpleBuddy *buddy = purple_contact_get_priority_buddy(contact); |
563 PurpleBuddy *buddy = purple_contact_get_priority_buddy(contact); |
| 429 purple_blist_alias_buddy(buddy, arg2); |
564 purple_blist_alias_buddy(buddy, arg2); |
| 430 serv_alias_buddy(buddy); |
565 serv_alias_buddy(buddy); |
| |
566 gtk_blist_auto_personize(node->parent, arg2); |
| 431 } |
567 } |
| 432 } |
568 } |
| 433 break; |
569 break; |
| 434 |
570 |
| 435 case PURPLE_BLIST_BUDDY_NODE: |
571 case PURPLE_BLIST_BUDDY_NODE: |
| 436 purple_blist_alias_buddy((PurpleBuddy*)node, arg2); |
572 purple_blist_alias_buddy((PurpleBuddy*)node, arg2); |
| 437 serv_alias_buddy((PurpleBuddy *)node); |
573 serv_alias_buddy((PurpleBuddy *)node); |
| |
574 gtk_blist_auto_personize(node->parent->parent, arg2); |
| 438 break; |
575 break; |
| 439 case PURPLE_BLIST_GROUP_NODE: |
576 case PURPLE_BLIST_GROUP_NODE: |
| 440 dest = purple_find_group(arg2); |
577 dest = purple_find_group(arg2); |
| 441 if (dest != NULL && strcmp(arg2, ((PurpleGroup*) node)->name)) { |
578 if (dest != NULL && strcmp(arg2, ((PurpleGroup*) node)->name)) { |
| 442 pidgin_dialogs_merge_groups((PurpleGroup*) node, arg2); |
579 pidgin_dialogs_merge_groups((PurpleGroup*) node, arg2); |
| 1117 pidgin_append_menu_action(menu, act, node); |
1274 pidgin_append_menu_action(menu, act, node); |
| 1118 } |
1275 } |
| 1119 g_list_free(ll); |
1276 g_list_free(ll); |
| 1120 } |
1277 } |
| 1121 |
1278 |
| |
1279 |
| |
1280 |
| |
1281 static void |
| |
1282 pidgin_append_blist_node_move_to_menu(GtkWidget *menu, PurpleBlistNode *node) |
| |
1283 { |
| |
1284 GtkWidget *submenu; |
| |
1285 GtkWidget *menuitem; |
| |
1286 PurpleBlistNode *group; |
| |
1287 |
| |
1288 menuitem = gtk_menu_item_new_with_label(_("Move to")); |
| |
1289 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); |
| |
1290 gtk_widget_show(menuitem); |
| |
1291 |
| |
1292 submenu = gtk_menu_new(); |
| |
1293 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); |
| |
1294 |
| |
1295 for (group = purple_blist_get_root(); group; group = group->next) { |
| |
1296 if (group->type != PURPLE_BLIST_GROUP_NODE) |
| |
1297 continue; |
| |
1298 if (group == node->parent) |
| |
1299 continue; |
| |
1300 menuitem = pidgin_new_item_from_stock(submenu, purple_group_get_name((PurpleGroup *)group), NULL, |
| |
1301 G_CALLBACK(gtk_blist_menu_move_to_cb), node, 0, 0, NULL); |
| |
1302 g_object_set_data(G_OBJECT(menuitem), "groupnode", group); |
| |
1303 } |
| |
1304 gtk_widget_show_all(submenu); |
| |
1305 } |
| |
1306 |
| 1122 void |
1307 void |
| 1123 pidgin_blist_make_buddy_menu(GtkWidget *menu, PurpleBuddy *buddy, gboolean sub) { |
1308 pidgin_blist_make_buddy_menu(GtkWidget *menu, PurpleBuddy *buddy, gboolean sub) { |
| 1124 PurplePluginProtocolInfo *prpl_info; |
1309 PurplePluginProtocolInfo *prpl_info; |
| 1125 PurpleContact *contact; |
1310 PurpleContact *contact; |
| |
1311 PurpleBlistNode *node; |
| 1126 gboolean contact_expanded = FALSE; |
1312 gboolean contact_expanded = FALSE; |
| |
1313 gboolean show_offline = FALSE; |
| 1127 |
1314 |
| 1128 g_return_if_fail(menu); |
1315 g_return_if_fail(menu); |
| 1129 g_return_if_fail(buddy); |
1316 g_return_if_fail(buddy); |
| 1130 |
1317 |
| 1131 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl); |
1318 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl); |
| |
1319 |
| |
1320 node = (PurpleBlistNode*)buddy; |
| 1132 |
1321 |
| 1133 contact = purple_buddy_get_contact(buddy); |
1322 contact = purple_buddy_get_contact(buddy); |
| 1134 if (contact) { |
1323 if (contact) { |
| 1135 contact_expanded = ((struct _pidgin_blist_node *)(((PurpleBlistNode*)contact)->ui_data))->contact_expanded; |
1324 contact_expanded = ((struct _pidgin_blist_node *)(((PurpleBlistNode*)contact)->ui_data))->contact_expanded; |
| 1136 } |
1325 } |
| 1143 G_CALLBACK(gtk_blist_menu_im_cb), buddy, 0, 0, NULL); |
1332 G_CALLBACK(gtk_blist_menu_im_cb), buddy, 0, 0, NULL); |
| 1144 if (prpl_info && prpl_info->send_file) { |
1333 if (prpl_info && prpl_info->send_file) { |
| 1145 if (!prpl_info->can_receive_file || |
1334 if (!prpl_info->can_receive_file || |
| 1146 prpl_info->can_receive_file(buddy->account->gc, buddy->name)) |
1335 prpl_info->can_receive_file(buddy->account->gc, buddy->name)) |
| 1147 { |
1336 { |
| 1148 pidgin_new_item_from_stock(menu, _("_Send File"), |
1337 pidgin_new_item_from_stock(menu, _("_Send File..."), |
| 1149 PIDGIN_STOCK_TOOLBAR_SEND_FILE, |
1338 PIDGIN_STOCK_TOOLBAR_SEND_FILE, |
| 1150 G_CALLBACK(gtk_blist_menu_send_file_cb), |
1339 G_CALLBACK(gtk_blist_menu_send_file_cb), |
| 1151 buddy, 0, 0, NULL); |
1340 buddy, 0, 0, NULL); |
| 1152 } |
1341 } |
| 1153 } |
1342 } |
| 1154 |
1343 |
| 1155 pidgin_new_item_from_stock(menu, _("Add Buddy _Pounce"), NULL, |
1344 pidgin_new_item_from_stock(menu, _("Add Buddy _Pounce..."), NULL, |
| 1156 G_CALLBACK(gtk_blist_menu_bp_cb), buddy, 0, 0, NULL); |
1345 G_CALLBACK(gtk_blist_menu_bp_cb), buddy, 0, 0, NULL); |
| 1157 |
1346 |
| 1158 if (((PurpleBlistNode*)buddy)->parent && ((PurpleBlistNode*)buddy)->parent->child->next && |
1347 if (node->parent && node->parent->child->next && |
| 1159 !sub && !contact_expanded) { |
1348 !sub && !contact_expanded) { |
| 1160 pidgin_new_item_from_stock(menu, _("View _Log"), NULL, |
1349 pidgin_new_item_from_stock(menu, _("View _Log"), NULL, |
| 1161 G_CALLBACK(gtk_blist_menu_showlog_cb), |
1350 G_CALLBACK(gtk_blist_menu_showlog_cb), |
| 1162 contact, 0, 0, NULL); |
1351 contact, 0, 0, NULL); |
| 1163 } else if (!sub) { |
1352 } else if (!sub) { |
| 1164 pidgin_new_item_from_stock(menu, _("View _Log"), NULL, |
1353 pidgin_new_item_from_stock(menu, _("View _Log"), NULL, |
| 1165 G_CALLBACK(gtk_blist_menu_showlog_cb), buddy, 0, 0, NULL); |
1354 G_CALLBACK(gtk_blist_menu_showlog_cb), buddy, 0, 0, NULL); |
| 1166 } |
1355 } |
| 1167 |
1356 |
| 1168 |
1357 if (!(purple_blist_node_get_flags(node) & PURPLE_BLIST_NODE_FLAG_NO_SAVE)) { |
| 1169 pidgin_append_blist_node_proto_menu(menu, buddy->account->gc, |
1358 show_offline = purple_blist_node_get_bool(node, "show_offline"); |
| 1170 (PurpleBlistNode *)buddy); |
1359 pidgin_new_item_from_stock(menu, show_offline ? _("Hide when offline") : _("Show when offline"), |
| 1171 pidgin_append_blist_node_extended_menu(menu, (PurpleBlistNode *)buddy); |
1360 NULL, G_CALLBACK(gtk_blist_menu_showoffline_cb), node, 0, 0, NULL); |
| 1172 |
1361 } |
| 1173 if (((PurpleBlistNode*)buddy)->parent && ((PurpleBlistNode*)buddy)->parent->child->next && |
1362 |
| |
1363 pidgin_append_blist_node_proto_menu(menu, buddy->account->gc, node); |
| |
1364 pidgin_append_blist_node_extended_menu(menu, node); |
| |
1365 |
| |
1366 if (!contact_expanded) |
| |
1367 pidgin_append_blist_node_move_to_menu(menu, (PurpleBlistNode *)contact); |
| |
1368 |
| |
1369 if (node->parent && node->parent->child->next && |
| 1174 !sub && !contact_expanded) { |
1370 !sub && !contact_expanded) { |
| 1175 pidgin_separator(menu); |
1371 pidgin_separator(menu); |
| 1176 pidgin_append_blist_node_privacy_menu(menu, (PurpleBlistNode *)buddy); |
1372 pidgin_append_blist_node_privacy_menu(menu, node); |
| 1177 pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS, |
1373 pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS, |
| 1178 G_CALLBACK(gtk_blist_menu_alias_cb), |
1374 G_CALLBACK(gtk_blist_menu_alias_cb), |
| 1179 contact, 0, 0, NULL); |
1375 contact, 0, 0, NULL); |
| 1180 pidgin_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE, |
1376 pidgin_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE, |
| 1181 G_CALLBACK(pidgin_blist_remove_cb), |
1377 G_CALLBACK(pidgin_blist_remove_cb), |
| 1182 contact, 0, 0, NULL); |
1378 contact, 0, 0, NULL); |
| 1183 } else if (!sub || contact_expanded) { |
1379 } else if (!sub || contact_expanded) { |
| 1184 pidgin_separator(menu); |
1380 pidgin_separator(menu); |
| 1185 pidgin_append_blist_node_privacy_menu(menu, (PurpleBlistNode *)buddy); |
1381 pidgin_append_blist_node_privacy_menu(menu, node); |
| 1186 pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS, |
1382 pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS, |
| 1187 G_CALLBACK(gtk_blist_menu_alias_cb), buddy, 0, 0, NULL); |
1383 G_CALLBACK(gtk_blist_menu_alias_cb), buddy, 0, 0, NULL); |
| 1188 pidgin_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE, |
1384 pidgin_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE, |
| 1189 G_CALLBACK(pidgin_blist_remove_cb), buddy, |
1385 G_CALLBACK(pidgin_blist_remove_cb), buddy, |
| 1190 0, 0, NULL); |
1386 0, 0, NULL); |
| 1233 { |
1429 { |
| 1234 GtkWidget *menu; |
1430 GtkWidget *menu; |
| 1235 GtkWidget *item; |
1431 GtkWidget *item; |
| 1236 |
1432 |
| 1237 menu = gtk_menu_new(); |
1433 menu = gtk_menu_new(); |
| 1238 item = pidgin_new_item_from_stock(menu, _("Add a _Buddy"), GTK_STOCK_ADD, |
1434 item = pidgin_new_item_from_stock(menu, _("Add _Buddy..."), GTK_STOCK_ADD, |
| 1239 G_CALLBACK(pidgin_blist_add_buddy_cb), node, 0, 0, NULL); |
1435 G_CALLBACK(pidgin_blist_add_buddy_cb), node, 0, 0, NULL); |
| 1240 gtk_widget_set_sensitive(item, purple_connections_get_all() != NULL); |
1436 gtk_widget_set_sensitive(item, purple_connections_get_all() != NULL); |
| 1241 item = pidgin_new_item_from_stock(menu, _("Add a C_hat"), GTK_STOCK_ADD, |
1437 item = pidgin_new_item_from_stock(menu, _("Add C_hat..."), GTK_STOCK_ADD, |
| 1242 G_CALLBACK(pidgin_blist_add_chat_cb), node, 0, 0, NULL); |
1438 G_CALLBACK(pidgin_blist_add_chat_cb), node, 0, 0, NULL); |
| 1243 gtk_widget_set_sensitive(item, pidgin_blist_joinchat_is_showable()); |
1439 gtk_widget_set_sensitive(item, pidgin_blist_joinchat_is_showable()); |
| 1244 pidgin_new_item_from_stock(menu, _("_Delete Group"), GTK_STOCK_REMOVE, |
1440 pidgin_new_item_from_stock(menu, _("_Delete Group"), GTK_STOCK_REMOVE, |
| 1245 G_CALLBACK(pidgin_blist_remove_cb), node, 0, 0, NULL); |
1441 G_CALLBACK(pidgin_blist_remove_cb), node, 0, 0, NULL); |
| 1246 pidgin_new_item_from_stock(menu, _("_Rename"), NULL, |
1442 pidgin_new_item_from_stock(menu, _("_Rename"), NULL, |
| 1254 |
1450 |
| 1255 static GtkWidget * |
1451 static GtkWidget * |
| 1256 create_chat_menu(PurpleBlistNode *node, PurpleChat *c) |
1452 create_chat_menu(PurpleBlistNode *node, PurpleChat *c) |
| 1257 { |
1453 { |
| 1258 GtkWidget *menu; |
1454 GtkWidget *menu; |
| 1259 gboolean autojoin; |
1455 gboolean autojoin, persistent; |
| 1260 |
1456 |
| 1261 menu = gtk_menu_new(); |
1457 menu = gtk_menu_new(); |
| 1262 autojoin = (purple_blist_node_get_bool(node, "gtk-autojoin") || |
1458 autojoin = (purple_blist_node_get_bool(node, "gtk-autojoin") || |
| 1263 (purple_blist_node_get_string(node, "gtk-autojoin") != NULL)); |
1459 (purple_blist_node_get_string(node, "gtk-autojoin") != NULL)); |
| |
1460 persistent = purple_blist_node_get_bool(node, "gtk-persistent"); |
| 1264 |
1461 |
| 1265 pidgin_new_item_from_stock(menu, _("_Join"), PIDGIN_STOCK_CHAT, |
1462 pidgin_new_item_from_stock(menu, _("_Join"), PIDGIN_STOCK_CHAT, |
| 1266 G_CALLBACK(gtk_blist_menu_join_cb), node, 0, 0, NULL); |
1463 G_CALLBACK(gtk_blist_menu_join_cb), node, 0, 0, NULL); |
| 1267 pidgin_new_check_item(menu, _("Auto-Join"), |
1464 pidgin_new_check_item(menu, _("Auto-Join"), |
| 1268 G_CALLBACK(gtk_blist_menu_autojoin_cb), node, autojoin); |
1465 G_CALLBACK(gtk_blist_menu_autojoin_cb), node, autojoin); |
| |
1466 pidgin_new_check_item(menu, _("Persistent"), |
| |
1467 G_CALLBACK(gtk_blist_menu_persistent_cb), node, persistent); |
| 1269 pidgin_new_item_from_stock(menu, _("View _Log"), NULL, |
1468 pidgin_new_item_from_stock(menu, _("View _Log"), NULL, |
| 1270 G_CALLBACK(gtk_blist_menu_showlog_cb), node, 0, 0, NULL); |
1469 G_CALLBACK(gtk_blist_menu_showlog_cb), node, 0, 0, NULL); |
| 1271 |
1470 |
| 1272 pidgin_append_blist_node_proto_menu(menu, c->account->gc, node); |
1471 pidgin_append_blist_node_proto_menu(menu, c->account->gc, node); |
| 1273 pidgin_append_blist_node_extended_menu(menu, node); |
1472 pidgin_append_blist_node_extended_menu(menu, node); |
| 2886 { "/Buddies/sep3", NULL, NULL, 0, "<Separator>", NULL }, |
3084 { "/Buddies/sep3", NULL, NULL, 0, "<Separator>", NULL }, |
| 2887 { N_("/Buddies/_Quit"), "<CTL>Q", purple_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT }, |
3085 { N_("/Buddies/_Quit"), "<CTL>Q", purple_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT }, |
| 2888 |
3086 |
| 2889 /* Accounts menu */ |
3087 /* Accounts menu */ |
| 2890 { N_("/_Accounts"), NULL, NULL, 0, "<Branch>", NULL }, |
3088 { N_("/_Accounts"), NULL, NULL, 0, "<Branch>", NULL }, |
| 2891 { N_("/Accounts/Add\\/Edit"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL }, |
3089 { N_("/Accounts/Manage"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL }, |
| 2892 |
3090 |
| 2893 /* Tools */ |
3091 /* Tools */ |
| 2894 { N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL }, |
3092 { N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL }, |
| 2895 { N_("/Tools/Buddy _Pounces"), NULL, pidgin_pounces_manager_show, 0, "<Item>", NULL }, |
3093 { N_("/Tools/Buddy _Pounces"), NULL, pidgin_pounces_manager_show, 0, "<Item>", NULL }, |
| 2896 { N_("/Tools/_Certificates"), NULL, pidgin_certmgr_show, 0, "<Item>", NULL }, |
3094 { N_("/Tools/_Certificates"), NULL, pidgin_certmgr_show, 0, "<Item>", NULL }, |
| 3725 if (gtkblist->menutrayicon) { |
3929 if (gtkblist->menutrayicon) { |
| 3726 gtk_widget_destroy(gtkblist->menutrayicon); |
3930 gtk_widget_destroy(gtkblist->menutrayicon); |
| 3727 gtkblist->menutrayicon = NULL; |
3931 gtkblist->menutrayicon = NULL; |
| 3728 } |
3932 } |
| 3729 |
3933 |
| 3730 convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_IM, PIDGIN_UNSEEN_TEXT, TRUE, 0); |
3934 convs = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_ANY, PIDGIN_UNSEEN_TEXT, TRUE, 0); |
| 3731 if (convs) { |
3935 if (convs) { |
| 3732 GtkWidget *img = NULL; |
3936 GtkWidget *img = NULL; |
| 3733 GString *tooltip_text = NULL; |
3937 GString *tooltip_text = NULL; |
| 3734 |
3938 |
| 3735 tooltip_text = g_string_new(""); |
3939 tooltip_text = g_string_new(""); |
| 3736 l = convs; |
3940 l = convs; |
| 3737 while (l != NULL) { |
3941 while (l != NULL) { |
| 3738 if (PIDGIN_IS_PIDGIN_CONVERSATION(l->data)) { |
3942 int count = GPOINTER_TO_INT(purple_conversation_get_data(l->data, "unseen-count")); |
| 3739 PidginConversation *gtkconv = PIDGIN_CONVERSATION((PurpleConversation *)l->data); |
3943 g_string_append_printf(tooltip_text, |
| 3740 |
3944 ngettext("%d unread message from %s\n", "%d unread messages from %s\n", count), |
| 3741 g_string_append_printf(tooltip_text, |
3945 count, purple_conversation_get_name(l->data)); |
| 3742 ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count), |
|
| 3743 gtkconv->unseen_count, |
|
| 3744 gtk_label_get_text(GTK_LABEL(gtkconv->tab_label))); |
|
| 3745 } |
|
| 3746 l = l->next; |
3946 l = l->next; |
| 3747 } |
3947 } |
| 3748 if(tooltip_text->len > 0) { |
3948 if(tooltip_text->len > 0) { |
| 3749 /* get rid of the last newline */ |
3949 /* get rid of the last newline */ |
| 3750 g_string_truncate(tooltip_text, tooltip_text->len -1); |
3950 g_string_truncate(tooltip_text, tooltip_text->len -1); |
| 3766 |
3966 |
| 3767 static void |
3967 static void |
| 3768 conversation_deleting_cb(PurpleConversation *conv, PidginBuddyList *gtkblist) |
3968 conversation_deleting_cb(PurpleConversation *conv, PidginBuddyList *gtkblist) |
| 3769 { |
3969 { |
| 3770 conversation_updated_cb(conv, PURPLE_CONV_UPDATE_UNSEEN, gtkblist); |
3970 conversation_updated_cb(conv, PURPLE_CONV_UPDATE_UNSEEN, gtkblist); |
| |
3971 } |
| |
3972 |
| |
3973 static void |
| |
3974 conversation_deleted_update_ui_cb(PurpleConversation *conv, struct _pidgin_blist_node *ui) |
| |
3975 { |
| |
3976 if (ui->conv.conv != conv) |
| |
3977 return; |
| |
3978 ui->conv.conv = NULL; |
| |
3979 ui->conv.flags = 0; |
| |
3980 ui->conv.last_message = 0; |
| |
3981 } |
| |
3982 |
| |
3983 static void |
| |
3984 written_msg_update_ui_cb(PurpleAccount *account, const char *who, const char *message, |
| |
3985 PurpleConversation *conv, PurpleMessageFlags flag, PurpleBlistNode *node) |
| |
3986 { |
| |
3987 PidginBlistNode *ui = node->ui_data; |
| |
3988 if (ui->conv.conv != conv || PIDGIN_CONVERSATION(conv) || |
| |
3989 !(flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV))) |
| |
3990 return; |
| |
3991 ui->conv.flags |= PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE; |
| |
3992 ui->conv.last_message = time(NULL); /* XXX: for lack of better data */ |
| |
3993 pidgin_blist_update(purple_get_blist(), node); |
| |
3994 } |
| |
3995 |
| |
3996 static void |
| |
3997 displayed_msg_update_ui_cb(PurpleAccount *account, const char *who, const char *message, |
| |
3998 PurpleConversation *conv, PurpleMessageFlags flag, PurpleBlistNode *node) |
| |
3999 { |
| |
4000 PidginBlistNode *ui = node->ui_data; |
| |
4001 if (ui->conv.conv != conv) |
| |
4002 return; |
| |
4003 ui->conv.flags &= ~PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE; |
| |
4004 pidgin_blist_update(purple_get_blist(), node); |
| |
4005 } |
| |
4006 |
| |
4007 static void |
| |
4008 conversation_created_cb(PurpleConversation *conv, PidginBuddyList *gtkblist) |
| |
4009 { |
| |
4010 switch (conv->type) { |
| |
4011 case PURPLE_CONV_TYPE_IM: |
| |
4012 { |
| |
4013 GSList *buddies = purple_find_buddies(conv->account, conv->name); |
| |
4014 while (buddies) { |
| |
4015 PurpleBlistNode *buddy = buddies->data; |
| |
4016 struct _pidgin_blist_node *ui = buddy->ui_data; |
| |
4017 buddies = g_slist_delete_link(buddies, buddies); |
| |
4018 if (!ui) |
| |
4019 continue; |
| |
4020 ui->conv.conv = conv; |
| |
4021 ui->conv.flags = 0; |
| |
4022 ui->conv.last_message = 0; |
| |
4023 purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation", |
| |
4024 ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui); |
| |
4025 purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg", |
| |
4026 ui, PURPLE_CALLBACK(written_msg_update_ui_cb), buddy); |
| |
4027 purple_signal_connect(pidgin_conversations_get_handle(), "displayed-im-msg", |
| |
4028 ui, PURPLE_CALLBACK(displayed_msg_update_ui_cb), buddy); |
| |
4029 } |
| |
4030 } |
| |
4031 case PURPLE_CONV_TYPE_CHAT: |
| |
4032 { |
| |
4033 PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name); |
| |
4034 struct _pidgin_blist_node *ui; |
| |
4035 if (!chat) |
| |
4036 break; |
| |
4037 ui = chat->node.ui_data; |
| |
4038 if (!ui) |
| |
4039 break; |
| |
4040 ui->conv.conv = conv; |
| |
4041 ui->conv.flags = 0; |
| |
4042 ui->conv.last_message = 0; |
| |
4043 purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation", |
| |
4044 ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui); |
| |
4045 purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg", |
| |
4046 ui, PURPLE_CALLBACK(written_msg_update_ui_cb), chat); |
| |
4047 purple_signal_connect(pidgin_conversations_get_handle(), "displayed-chat-msg", |
| |
4048 ui, PURPLE_CALLBACK(displayed_msg_update_ui_cb), chat); |
| |
4049 } |
| |
4050 default: |
| |
4051 break; |
| |
4052 } |
| 3771 } |
4053 } |
| 3772 |
4054 |
| 3773 /********************************************************************************** |
4055 /********************************************************************************** |
| 3774 * Public API Functions * |
4056 * Public API Functions * |
| 3775 **********************************************************************************/ |
4057 **********************************************************************************/ |
| 4951 gtk_tree_store_set(gtkblist->treemodel, &iter, |
5237 gtk_tree_store_set(gtkblist->treemodel, &iter, |
| 4952 STATUS_ICON_VISIBLE_COLUMN, FALSE, |
5238 STATUS_ICON_VISIBLE_COLUMN, FALSE, |
| 4953 STATUS_ICON_COLUMN, NULL, |
5239 STATUS_ICON_COLUMN, NULL, |
| 4954 NAME_COLUMN, title, |
5240 NAME_COLUMN, title, |
| 4955 NODE_COLUMN, gnode, |
5241 NODE_COLUMN, gnode, |
| 4956 BGCOLOR_COLUMN, &bgcolor, |
5242 /* BGCOLOR_COLUMN, &bgcolor, */ |
| 4957 GROUP_EXPANDER_COLUMN, TRUE, |
5243 GROUP_EXPANDER_COLUMN, TRUE, |
| 4958 GROUP_EXPANDER_VISIBLE_COLUMN, TRUE, |
5244 GROUP_EXPANDER_VISIBLE_COLUMN, TRUE, |
| 4959 CONTACT_EXPANDER_VISIBLE_COLUMN, FALSE, |
5245 CONTACT_EXPANDER_VISIBLE_COLUMN, FALSE, |
| 4960 BUDDY_ICON_VISIBLE_COLUMN, FALSE, |
5246 BUDDY_ICON_VISIBLE_COLUMN, FALSE, |
| 4961 IDLE_VISIBLE_COLUMN, FALSE, |
5247 IDLE_VISIBLE_COLUMN, FALSE, |
| 5525 gtk_table_set_col_spacings(GTK_TABLE(table), 5); |
5814 gtk_table_set_col_spacings(GTK_TABLE(table), 5); |
| 5526 gtk_container_set_border_width(GTK_CONTAINER(table), 0); |
5815 gtk_container_set_border_width(GTK_CONTAINER(table), 0); |
| 5527 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); |
5816 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); |
| 5528 |
5817 |
| 5529 /* Set up stuff for the account box */ |
5818 /* Set up stuff for the account box */ |
| 5530 label = gtk_label_new_with_mnemonic(_("_Account:")); |
5819 label = gtk_label_new_with_mnemonic(_("A_ccount:")); |
| 5531 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
5820 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
| 5532 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); |
5821 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); |
| 5533 |
5822 |
| 5534 data->account_box = pidgin_account_option_menu_new(account, FALSE, |
5823 data->account_box = pidgin_account_option_menu_new(account, FALSE, |
| 5535 G_CALLBACK(add_buddy_select_account_cb), NULL, data); |
5824 G_CALLBACK(add_buddy_select_account_cb), NULL, data); |
| 5936 |
6231 |
| 5937 data->group_combo = pidgin_text_combo_box_entry_new(group ? group->name : NULL, groups_tree()); |
6232 data->group_combo = pidgin_text_combo_box_entry_new(group ? group->name : NULL, groups_tree()); |
| 5938 gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_BIN(data->group_combo)->child); |
6233 gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_BIN(data->group_combo)->child); |
| 5939 pidgin_set_accessible_label (data->group_combo, label); |
6234 pidgin_set_accessible_label (data->group_combo, label); |
| 5940 gtk_box_pack_end(GTK_BOX(rowbox), data->group_combo, TRUE, TRUE, 0); |
6235 gtk_box_pack_end(GTK_BOX(rowbox), data->group_combo, TRUE, TRUE, 0); |
| |
6236 |
| |
6237 data->autojoin = gtk_check_button_new_with_mnemonic(_("Autojoin when account becomes online.")); |
| |
6238 data->persistent = gtk_check_button_new_with_mnemonic(_("Hide chat when the window is closed.")); |
| |
6239 gtk_box_pack_start(GTK_BOX(vbox), data->autojoin, FALSE, FALSE, 0); |
| |
6240 gtk_box_pack_start(GTK_BOX(vbox), data->persistent, FALSE, FALSE, 0); |
| 5941 |
6241 |
| 5942 g_signal_connect(G_OBJECT(data->window), "response", |
6242 g_signal_connect(G_OBJECT(data->window), "response", |
| 5943 G_CALLBACK(add_chat_resp_cb), data); |
6243 G_CALLBACK(add_chat_resp_cb), data); |
| 5944 |
6244 |
| 5945 gtk_widget_show_all(data->window); |
6245 gtk_widget_show_all(data->window); |