pidgin/gtkblist.c

changeset 40392
924a47d2652d
parent 40360
e21f3bbcc2a5
parent 40385
c3e9a7d14e6f
child 40443
025772e2b454
equal deleted inserted replaced
40362:1edaee25f763 40392:924a47d2652d
29 #include "gtkcellrendererexpander.h" 29 #include "gtkcellrendererexpander.h"
30 #include "gtkconv.h" 30 #include "gtkconv.h"
31 #include "gtkdialogs.h" 31 #include "gtkdialogs.h"
32 #include "gtkxfer.h" 32 #include "gtkxfer.h"
33 #include "gtkpounce.h" 33 #include "gtkpounce.h"
34 #include "gtkprefs.h"
35 #include "gtkprivacy.h" 34 #include "gtkprivacy.h"
36 #include "gtkroomlist.h" 35 #include "gtkroomlist.h"
37 #include "gtkstatusbox.h" 36 #include "gtkstatusbox.h"
38 #include "gtkscrollbook.h" 37 #include "gtkscrollbook.h"
39 #include "gtksmiley-manager.h"
40 #include "gtkstyle.h" 38 #include "gtkstyle.h"
41 #include "gtkblist-theme.h" 39 #include "gtkblist-theme.h"
42 #include "gtkblist-theme-loader.h" 40 #include "gtkblist-theme-loader.h"
43 #include "gtkutils.h" 41 #include "gtkutils.h"
44 #include "pidgin/minidialog.h" 42 #include "pidgin/minidialog.h"
45 #include "pidgin/pidginabout.h"
46 #include "pidgin/pidginaccountchooser.h" 43 #include "pidgin/pidginaccountchooser.h"
44 #include "pidgin/pidginactiongroup.h"
45 #include "pidgin/pidginbuddylistmenu.h"
47 #include "pidgin/pidgindebug.h" 46 #include "pidgin/pidgindebug.h"
48 #include "pidgin/pidgingdkpixbuf.h" 47 #include "pidgin/pidgingdkpixbuf.h"
49 #include "pidgin/pidginlog.h" 48 #include "pidgin/pidginlog.h"
49 #include "pidgin/pidginmooddialog.h"
50 #include "pidgin/pidginplugininfo.h" 50 #include "pidgin/pidginplugininfo.h"
51 #include "pidgin/pidginpluginsdialog.h"
52 #include "pidgin/pidgintooltip.h" 51 #include "pidgin/pidgintooltip.h"
53 #include "pidginmenutray.h" 52 #include "pidginmenutray.h"
54 #include "pidginstock.h" 53 #include "pidginstock.h"
55 54
56 #include <gdk/gdkkeysyms.h> 55 #include <gdk/gdkkeysyms.h>
124 123
125 #define PIDGIN_WINDOW_MAXIMIZED(x) \ 124 #define PIDGIN_WINDOW_MAXIMIZED(x) \
126 (gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(x))) & \ 125 (gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(x))) & \
127 GDK_WINDOW_STATE_MAXIMIZED) 126 GDK_WINDOW_STATE_MAXIMIZED)
128 127
129 static GtkWidget *accountmenu = NULL;
130
131 static guint visibility_manager_count = 0; 128 static guint visibility_manager_count = 0;
132 static GdkVisibilityState gtk_blist_visibility = GDK_VISIBILITY_UNOBSCURED; 129 static GdkVisibilityState gtk_blist_visibility = GDK_VISIBILITY_UNOBSCURED;
133 static gboolean gtk_blist_focused = FALSE; 130 static gboolean gtk_blist_focused = FALSE;
134 static gboolean editing_blist = FALSE; 131 static gboolean editing_blist = FALSE;
135 132
138 static void sort_method_none(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter); 135 static void sort_method_none(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
139 136
140 static void sort_method_alphabetical(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter); 137 static void sort_method_alphabetical(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
141 static void sort_method_status(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter); 138 static void sort_method_status(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
142 static void sort_method_log_activity(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter); 139 static void sort_method_log_activity(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
143 static guint sort_merge_id;
144 static GtkActionGroup *sort_action_group = NULL;
145 140
146 static PidginBuddyList *gtkblist = NULL; 141 static PidginBuddyList *gtkblist = NULL;
147 142
148 static GList *groups_tree(void); 143 static GList *groups_tree(void);
149 static gboolean pidgin_blist_refresh_timer(PurpleBuddyList *list); 144 static gboolean pidgin_blist_refresh_timer(PurpleBuddyList *list);
775 pidgin_blist_update(purple_blist_get_default(), 770 pidgin_blist_update(purple_blist_get_default(),
776 bnode); 771 bnode);
777 } 772 }
778 } 773 }
779 } 774 }
780 }
781
782 static void gtk_blist_show_systemlog_cb(void)
783 {
784 pidgin_syslog_show();
785 }
786
787 static void gtk_blist_show_onlinehelp_cb(void)
788 {
789 purple_notify_uri(NULL, PURPLE_WEBSITE "documentation");
790 } 775 }
791 776
792 static void 777 static void
793 do_join_chat(PidginChatData *data) 778 do_join_chat(PidginChatData *data)
794 { 779 {
2004 1989
2005 /* Shift+F10 draws a context menu */ 1990 /* Shift+F10 draws a context menu */
2006 handled = pidgin_blist_show_context_menu(tv, node, NULL); 1991 handled = pidgin_blist_show_context_menu(tv, node, NULL);
2007 1992
2008 return handled; 1993 return handled;
2009 }
2010
2011 static void gtk_blist_show_xfer_dialog_cb(GtkAction *item, gpointer data)
2012 {
2013 pidgin_xfer_dialog_show(NULL);
2014 }
2015
2016 static void pidgin_blist_buddy_details_cb(GtkToggleAction *item, gpointer data)
2017 {
2018 pidgin_set_cursor(gtkblist->window, GDK_WATCH);
2019
2020 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons",
2021 gtk_toggle_action_get_active(item));
2022
2023 pidgin_clear_cursor(gtkblist->window);
2024 }
2025
2026 static void pidgin_blist_show_idle_time_cb(GtkToggleAction *item, gpointer data)
2027 {
2028 pidgin_set_cursor(gtkblist->window, GDK_WATCH);
2029
2030 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time",
2031 gtk_toggle_action_get_active(item));
2032
2033 pidgin_clear_cursor(gtkblist->window);
2034 }
2035
2036 static void pidgin_blist_show_protocol_icons_cb(GtkToggleAction *item, gpointer data)
2037 {
2038 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons",
2039 gtk_toggle_action_get_active(item));
2040 }
2041
2042 static void pidgin_blist_show_empty_groups_cb(GtkToggleAction *item, gpointer data)
2043 {
2044 pidgin_set_cursor(gtkblist->window, GDK_WATCH);
2045
2046 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_empty_groups",
2047 gtk_toggle_action_get_active(item));
2048
2049 pidgin_clear_cursor(gtkblist->window);
2050 }
2051
2052 static void pidgin_blist_edit_mode_cb(GtkToggleAction *checkitem, gpointer data)
2053 {
2054 pidgin_set_cursor(gtkblist->window, GDK_WATCH);
2055
2056 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies",
2057 gtk_toggle_action_get_active(checkitem));
2058
2059 pidgin_clear_cursor(gtkblist->window);
2060 }
2061
2062 static void pidgin_blist_mute_sounds_cb(GtkToggleAction *item, gpointer data)
2063 {
2064 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute",
2065 gtk_toggle_action_get_active(item));
2066 }
2067
2068
2069 static void
2070 pidgin_blist_mute_pref_cb(const char *name, PurplePrefType type,
2071 gconstpointer value, gpointer data)
2072 {
2073 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui,
2074 "/BList/ToolsMenu/MuteSounds")), (gboolean)GPOINTER_TO_INT(value));
2075 }
2076
2077 static void
2078 pidgin_blist_sound_method_pref_cb(const char *name, PurplePrefType type,
2079 gconstpointer value, gpointer data)
2080 {
2081 gboolean sensitive = TRUE;
2082
2083 if(purple_strequal(value, "none"))
2084 sensitive = FALSE;
2085
2086 gtk_action_set_sensitive(gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/MuteSounds"), sensitive);
2087 } 1994 }
2088 1995
2089 static void 1996 static void
2090 add_buddies_from_vcard(const char *protocol_id, PurpleGroup *group, GList *list, 1997 add_buddies_from_vcard(const char *protocol_id, PurpleGroup *group, GList *list,
2091 const char *alias) 1998 const char *alias)
3328 gtkblist->mouseover_contact = NULL; 3235 gtkblist->mouseover_contact = NULL;
3329 } 3236 }
3330 return FALSE; 3237 return FALSE;
3331 } 3238 }
3332 3239
3333 static void
3334 toggle_debug(void)
3335 {
3336 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/debug/enabled",
3337 !purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/enabled"));
3338 }
3339
3340 static char *get_mood_icon_path(const char *mood)
3341 {
3342 char *path;
3343
3344 if (purple_strequal(mood, "busy")) {
3345 path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons",
3346 "hicolor", "16x16", "status", "user-busy.png", NULL);
3347 } else if (purple_strequal(mood, "hiptop")) {
3348 path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons",
3349 "hicolor", "16x16", "emblems", "emblem-hiptop.png",
3350 NULL);
3351 } else {
3352 char *filename = g_strdup_printf("%s.png", mood);
3353 path = g_build_filename(PURPLE_DATADIR, "pixmaps", "pidgin",
3354 "emotes", "small", filename, NULL);
3355 g_free(filename);
3356 }
3357 return path;
3358 }
3359
3360 static void
3361 update_status_with_mood(PurpleAccount *account, const gchar *mood,
3362 const gchar *text)
3363 {
3364 if (mood && *mood) {
3365 if (text) {
3366 purple_account_set_status(account, "mood", TRUE,
3367 PURPLE_MOOD_NAME, mood,
3368 PURPLE_MOOD_COMMENT, text,
3369 NULL);
3370 } else {
3371 purple_account_set_status(account, "mood", TRUE,
3372 PURPLE_MOOD_NAME, mood,
3373 NULL);
3374 }
3375 } else {
3376 purple_account_set_status(account, "mood", FALSE, NULL);
3377 }
3378 }
3379
3380 static void
3381 edit_mood_cb(PurpleConnection *gc, PurpleRequestFields *fields)
3382 {
3383 PurpleRequestField *mood_field;
3384 GList *l;
3385
3386 mood_field = purple_request_fields_get_field(fields, "mood");
3387 l = purple_request_field_list_get_selected(mood_field);
3388
3389 if (l) {
3390 const char *mood = purple_request_field_list_get_data(mood_field, l->data);
3391
3392 if (gc) {
3393 const char *text;
3394 PurpleAccount *account = purple_connection_get_account(gc);
3395
3396 if (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_SUPPORT_MOOD_MESSAGES) {
3397 PurpleRequestField *text_field;
3398 text_field = purple_request_fields_get_field(fields, "text");
3399 text = purple_request_field_string_get_value(text_field);
3400 } else {
3401 text = NULL;
3402 }
3403
3404 update_status_with_mood(account, mood, text);
3405 } else {
3406 GList *accounts = purple_accounts_get_all_active();
3407
3408 for (; accounts ; accounts = g_list_delete_link(accounts, accounts)) {
3409 PurpleAccount *account = (PurpleAccount *) accounts->data;
3410 PurpleConnection *gc = purple_account_get_connection(account);
3411
3412 if (gc && (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_SUPPORT_MOODS)) {
3413 update_status_with_mood(account, mood, NULL);
3414 }
3415 }
3416 }
3417 }
3418 }
3419
3420 static void
3421 global_moods_for_each(gpointer key, gpointer value, gpointer user_data)
3422 {
3423 GList **out_moods = (GList **) user_data;
3424 PurpleMood *mood = (PurpleMood *) value;
3425
3426 *out_moods = g_list_append(*out_moods, mood);
3427 }
3428
3429 static PurpleMood *
3430 get_global_moods(void)
3431 {
3432 GHashTable *global_moods =
3433 g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
3434 GHashTable *mood_counts =
3435 g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
3436 GList *accounts = purple_accounts_get_all_active();
3437 PurpleMood *result = NULL;
3438 GList *out_moods = NULL;
3439 int i = 0;
3440 int num_accounts = 0;
3441
3442 for (; accounts ; accounts = g_list_delete_link(accounts, accounts)) {
3443 PurpleAccount *account = (PurpleAccount *) accounts->data;
3444 if (purple_account_is_connected(account)) {
3445 PurpleConnection *gc = purple_account_get_connection(account);
3446
3447 if (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_SUPPORT_MOODS) {
3448 PurpleProtocol *protocol = purple_connection_get_protocol(gc);
3449 PurpleMood *mood = NULL;
3450
3451 for (mood = purple_protocol_client_iface_get_moods(protocol, account) ;
3452 mood->mood != NULL ; mood++) {
3453 int mood_count =
3454 GPOINTER_TO_INT(g_hash_table_lookup(mood_counts, mood->mood));
3455
3456 if (!g_hash_table_lookup(global_moods, mood->mood)) {
3457 g_hash_table_insert(global_moods, (gpointer)mood->mood, mood);
3458 }
3459 g_hash_table_insert(mood_counts, (gpointer)mood->mood,
3460 GINT_TO_POINTER(mood_count + 1));
3461 }
3462
3463 num_accounts++;
3464 }
3465 }
3466 }
3467
3468 g_hash_table_foreach(global_moods, global_moods_for_each, &out_moods);
3469 result = g_new0(PurpleMood, g_hash_table_size(global_moods) + 1);
3470
3471 while (out_moods) {
3472 PurpleMood *mood = (PurpleMood *) out_moods->data;
3473 int in_num_accounts =
3474 GPOINTER_TO_INT(g_hash_table_lookup(mood_counts, mood->mood));
3475
3476 if (in_num_accounts == num_accounts) {
3477 /* mood is present in all accounts supporting moods */
3478 result[i].mood = mood->mood;
3479 result[i].description = mood->description;
3480 i++;
3481 }
3482 out_moods = g_list_delete_link(out_moods, out_moods);
3483 }
3484
3485 g_hash_table_destroy(global_moods);
3486 g_hash_table_destroy(mood_counts);
3487
3488 return result;
3489 }
3490
3491 /* get current set mood for all mood-supporting accounts, or NULL if not set
3492 or not set to the same on all */
3493 static const gchar *
3494 get_global_mood_status(void)
3495 {
3496 GList *accounts = purple_accounts_get_all_active();
3497 const gchar *found_mood = NULL;
3498
3499 for (; accounts ; accounts = g_list_delete_link(accounts, accounts)) {
3500 PurpleAccount *account = (PurpleAccount *) accounts->data;
3501
3502 if (purple_account_is_connected(account) &&
3503 (purple_connection_get_flags(purple_account_get_connection(account)) &
3504 PURPLE_CONNECTION_FLAG_SUPPORT_MOODS)) {
3505 PurplePresence *presence = purple_account_get_presence(account);
3506 PurpleStatus *status = purple_presence_get_status(presence, "mood");
3507 const gchar *curr_mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
3508
3509 if (found_mood != NULL && !purple_strequal(curr_mood, found_mood)) {
3510 /* found a different mood */
3511 found_mood = NULL;
3512 break;
3513 } else {
3514 found_mood = curr_mood;
3515 }
3516 }
3517 }
3518
3519 return found_mood;
3520 }
3521
3522 static void
3523 set_mood_cb(GtkWidget *widget, PurpleAccount *account)
3524 {
3525 const char *current_mood;
3526 PurpleRequestFields *fields;
3527 PurpleRequestFieldGroup *g;
3528 PurpleRequestField *f;
3529 PurpleConnection *gc = NULL;
3530 PurpleProtocol *protocol = NULL;
3531 PurpleMood *mood;
3532 PurpleMood *global_moods = NULL;
3533
3534 if (account) {
3535 PurplePresence *presence = purple_account_get_presence(account);
3536 PurpleStatus *status = purple_presence_get_status(presence, "mood");
3537 gc = purple_account_get_connection(account);
3538 g_return_if_fail(purple_connection_get_protocol(gc) != NULL);
3539 protocol = purple_connection_get_protocol(gc);
3540 current_mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
3541 } else {
3542 current_mood = get_global_mood_status();
3543 }
3544
3545 fields = purple_request_fields_new();
3546 g = purple_request_field_group_new(NULL);
3547 f = purple_request_field_list_new("mood", _("Please select your mood from the list"));
3548
3549 purple_request_field_list_add_icon(f, _("None"), NULL, "");
3550 if (current_mood == NULL)
3551 purple_request_field_list_add_selected(f, _("None"));
3552
3553 /* TODO: rlaager wants this sorted. */
3554 /* TODO: darkrain wants it sorted post-translation */
3555 if (account && PURPLE_PROTOCOL_IMPLEMENTS(protocol, CLIENT, get_moods)) {
3556 mood = purple_protocol_client_iface_get_moods(protocol, account);
3557 } else {
3558 mood = global_moods = get_global_moods();
3559 }
3560 for ( ; mood->mood != NULL ; mood++) {
3561 char *path;
3562
3563 if (mood->description == NULL) {
3564 continue;
3565 }
3566
3567 path = get_mood_icon_path(mood->mood);
3568 purple_request_field_list_add_icon(f, _(mood->description),
3569 path, (gpointer)mood->mood);
3570 g_free(path);
3571
3572 if (current_mood && purple_strequal(current_mood, mood->mood))
3573 purple_request_field_list_add_selected(f, _(mood->description));
3574 }
3575 purple_request_field_group_add_field(g, f);
3576
3577 purple_request_fields_add_group(fields, g);
3578
3579 /* if the connection allows setting a mood message */
3580 if (gc && (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_SUPPORT_MOOD_MESSAGES)) {
3581 g = purple_request_field_group_new(NULL);
3582 f = purple_request_field_string_new("text",
3583 _("Message (optional)"), NULL, FALSE);
3584 purple_request_field_group_add_field(g, f);
3585 purple_request_fields_add_group(fields, g);
3586 }
3587
3588 purple_request_fields(gc, _("Edit User Mood"), _("Edit User Mood"),
3589 NULL, fields,
3590 _("OK"), G_CALLBACK(edit_mood_cb),
3591 _("Cancel"), NULL,
3592 purple_request_cpar_from_connection(gc), gc);
3593
3594 g_free(global_moods);
3595 }
3596
3597 static void
3598 set_mood_show(void)
3599 {
3600 set_mood_cb(NULL, NULL);
3601 }
3602
3603 /***************************************************
3604 * Crap *
3605 ***************************************************/
3606 static void
3607 pidgin_blist_plugins_dialog_cb(GtkAction *action, GtkWidget *window) {
3608 GtkWidget *dialog = pidgin_plugins_dialog_new();
3609
3610 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window));
3611
3612 gtk_widget_show_all(dialog);
3613 }
3614
3615 static void
3616 _pidgin_about_cb(GtkAction *action, GtkWidget *window) {
3617 GtkWidget *about = pidgin_about_dialog_new();
3618
3619 gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(window));
3620
3621 gtk_widget_show_all(about);
3622 }
3623
3624 /* TODO: fill out tooltips... */
3625 static const GtkActionEntry blist_menu_entries[] = {
3626 /* NOTE: Do not set any accelerator to Control+O. It is mapped by
3627 gtk_blist_key_press_cb to "Get User Info" on the selected buddy. */
3628 /* Buddies menu */
3629 { "BuddiesMenu", NULL, N_("_Buddies"), NULL, NULL, NULL },
3630 { "NewInstantMessage", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, N_("New Instant _Message..."), "<control>M", NULL, pidgin_dialogs_im },
3631 { "JoinAChat", PIDGIN_STOCK_CHAT, N_("Join a _Chat..."), "<control>C", NULL, pidgin_blist_joinchat_show },
3632 { "GetUserInfo", PIDGIN_STOCK_TOOLBAR_USER_INFO, N_("Get User _Info..."), "<control>I", NULL, pidgin_dialogs_info },
3633 { "ViewUserLog", NULL, N_("View User _Log..."), "<control>L", NULL, pidgin_dialogs_log },
3634 { "ShowMenu", NULL, N_("Sh_ow"), NULL, NULL, NULL },
3635 { "SortMenu", NULL, N_("_Sort Buddies"), NULL, NULL, NULL },
3636 { "AddBuddy", GTK_STOCK_ADD, N_("_Add Buddy..."), "<control>B", NULL, pidgin_blist_add_buddy_cb },
3637 { "AddChat", GTK_STOCK_ADD, N_("Add C_hat..."), NULL, NULL, pidgin_blist_add_chat_cb },
3638 { "AddGroup", GTK_STOCK_ADD, N_("Add _Group..."), NULL, NULL, purple_blist_request_add_group },
3639 { "Quit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", NULL, purple_core_quit },
3640
3641 /* Accounts menu */
3642 { "AccountsMenu", NULL, N_("_Accounts"), NULL, NULL, NULL },
3643 { "ManageAccounts", NULL, N_("Manage Accounts"), "<control>A", NULL, pidgin_accounts_window_show },
3644
3645 /* Tools */
3646 { "ToolsMenu", NULL, N_("_Tools"), NULL, NULL, NULL },
3647 { "BuddyPounces", NULL, N_("Buddy _Pounces"), NULL, NULL, pidgin_pounces_manager_show },
3648 { "CustomSmileys", PIDGIN_STOCK_TOOLBAR_SMILEY, N_("Custom Smile_ys"), "<control>Y", NULL, pidgin_smiley_manager_show },
3649 { "Plugins", PIDGIN_STOCK_TOOLBAR_PLUGINS, N_("Plu_gins"), "<control>U", NULL, pidgin_blist_plugins_dialog_cb },
3650 { "Preferences", GTK_STOCK_PREFERENCES, N_("Pr_eferences"), "<control>P", NULL, pidgin_prefs_show },
3651 { "Privacy", NULL, N_("Pr_ivacy"), NULL, NULL, pidgin_privacy_dialog_show },
3652 { "SetMood", NULL, N_("Set _Mood"), "<control>D", NULL, set_mood_show },
3653 { "FileTransfers", PIDGIN_STOCK_TOOLBAR_TRANSFER, N_("_File Transfers"), "<control>T", NULL, G_CALLBACK(gtk_blist_show_xfer_dialog_cb) },
3654 { "RoomList", NULL, N_("R_oom List"), NULL, NULL, pidgin_roomlist_dialog_show },
3655 { "SystemLog", NULL, N_("System _Log"), NULL, NULL, gtk_blist_show_systemlog_cb },
3656
3657 /* Help */
3658 { "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
3659 { "OnlineHelp", GTK_STOCK_HELP, N_("Online _Help"), "F1", NULL, gtk_blist_show_onlinehelp_cb },
3660 { "DebugWindow", NULL, N_("_Debug Window"), NULL, NULL, toggle_debug },
3661 { "About", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, G_CALLBACK(_pidgin_about_cb) },
3662 };
3663
3664 /* Toggle items */
3665 static const GtkToggleActionEntry blist_menu_toggle_entries[] = {
3666 /* Buddies->Show menu */
3667 { "ShowOffline", NULL, N_("_Offline Buddies"), NULL, NULL, G_CALLBACK(pidgin_blist_edit_mode_cb), FALSE },
3668 { "ShowEmptyGroups", NULL, N_("_Empty Groups"), NULL, NULL, G_CALLBACK(pidgin_blist_show_empty_groups_cb), FALSE },
3669 { "ShowBuddyDetails", NULL, N_("Buddy _Details"), NULL, NULL, G_CALLBACK(pidgin_blist_buddy_details_cb), FALSE },
3670 { "ShowIdleTimes", NULL, N_("Idle _Times"), NULL, NULL, G_CALLBACK(pidgin_blist_show_idle_time_cb), FALSE },
3671 { "ShowProtocolIcons", NULL, N_("_Protocol Icons"), NULL, NULL, G_CALLBACK(pidgin_blist_show_protocol_icons_cb), FALSE },
3672
3673 /* Tools menu */
3674 { "MuteSounds", NULL, N_("Mute _Sounds"), NULL, NULL, G_CALLBACK(pidgin_blist_mute_sounds_cb), FALSE },
3675 };
3676
3677 static const char *blist_menu =
3678 "<ui>"
3679 "<menubar name='BList'>"
3680 "<menu action='BuddiesMenu'>"
3681 "<menuitem action='NewInstantMessage'/>"
3682 "<menuitem action='JoinAChat'/>"
3683 "<menuitem action='GetUserInfo'/>"
3684 "<menuitem action='ViewUserLog'/>"
3685 "<separator/>"
3686 "<menu action='ShowMenu'>"
3687 "<menuitem action='ShowOffline'/>"
3688 "<menuitem action='ShowEmptyGroups'/>"
3689 "<menuitem action='ShowBuddyDetails'/>"
3690 "<menuitem action='ShowIdleTimes'/>"
3691 "<menuitem action='ShowProtocolIcons'/>"
3692 "</menu>"
3693 "<menu action='SortMenu'/>"
3694 "<separator/>"
3695 "<menuitem action='AddBuddy'/>"
3696 "<menuitem action='AddChat'/>"
3697 "<menuitem action='AddGroup'/>"
3698 "<separator/>"
3699 "<menuitem action='Quit'/>"
3700 "</menu>"
3701 "<menu action='AccountsMenu'>"
3702 "<menuitem action='ManageAccounts'/>"
3703 "</menu>"
3704 "<menu action='ToolsMenu'>"
3705 "<menuitem action='BuddyPounces'/>"
3706 "<menuitem action='CustomSmileys'/>"
3707 "<menuitem action='Plugins'/>"
3708 "<menuitem action='Preferences'/>"
3709 "<menuitem action='Privacy'/>"
3710 "<menuitem action='SetMood'/>"
3711 "<separator/>"
3712 "<menuitem action='FileTransfers'/>"
3713 "<menuitem action='RoomList'/>"
3714 "<menuitem action='SystemLog'/>"
3715 "<separator/>"
3716 "<menuitem action='MuteSounds'/>"
3717 "<placeholder name='PluginActions'/>"
3718 "</menu>"
3719 "<menu action='HelpMenu'>"
3720 "<menuitem action='OnlineHelp'/>"
3721 "<separator/>"
3722 "<menuitem action='DebugWindow'/>"
3723 "<separator/>"
3724 "<menuitem action='About'/>"
3725 "</menu>"
3726 "</menubar>"
3727 "</ui>";
3728
3729 /********************************************************* 3240 /*********************************************************
3730 * Private Utility functions * 3241 * Private Utility functions *
3731 *********************************************************/ 3242 *********************************************************/
3732 3243
3733 static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full) 3244 static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full)
4122 name = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); 3633 name = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
4123 3634
4124 if (!(name && *name)) 3635 if (!(name && *name))
4125 return NULL; 3636 return NULL;
4126 3637
4127 path = get_mood_icon_path(name); 3638 path = pidgin_mood_get_icon_path(name);
4128 } else { 3639 } else {
4129 filename = g_strdup_printf("emblem-%s.png", name); 3640 filename = g_strdup_printf("emblem-%s.png", name);
4130 path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons", 3641 path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons",
4131 "hicolor", "16x16", "emblems", filename, NULL); 3642 "hicolor", "16x16", "emblems", filename, NULL);
4132 g_free(filename); 3643 g_free(filename);
4521 } 4032 }
4522 gtk_tree_row_reference_free(gtknode->row); 4033 gtk_tree_row_reference_free(gtknode->row);
4523 gtknode->row = NULL; 4034 gtknode->row = NULL;
4524 } 4035 }
4525 4036
4526 static const char *require_connection[] =
4527 {
4528 "/BList/BuddiesMenu/NewInstantMessage",
4529 "/BList/BuddiesMenu/JoinAChat",
4530 "/BList/BuddiesMenu/GetUserInfo",
4531 "/BList/BuddiesMenu/AddBuddy",
4532 "/BList/BuddiesMenu/AddChat",
4533 "/BList/BuddiesMenu/AddGroup",
4534 "/BList/ToolsMenu/Privacy",
4535 };
4536
4537 static const int require_connection_size = sizeof(require_connection)
4538 / sizeof(*require_connection);
4539
4540 /*
4541 * Rebuild dynamic menus and make menu items sensitive/insensitive
4542 * where appropriate.
4543 */
4544 static void
4545 update_menu_bar(PidginBuddyList *gtkblist)
4546 {
4547 GtkAction *action;
4548 gboolean sensitive;
4549 int i;
4550
4551 g_return_if_fail(gtkblist != NULL);
4552
4553 pidgin_blist_update_accounts_menu();
4554
4555 sensitive = (purple_connections_get_all() != NULL);
4556
4557 for (i = 0; i < require_connection_size; i++)
4558 {
4559 action = gtk_ui_manager_get_action(gtkblist->ui, require_connection[i]);
4560 gtk_action_set_sensitive(action, sensitive);
4561 }
4562
4563 action = gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/JoinAChat");
4564 gtk_action_set_sensitive(action, pidgin_blist_joinchat_is_showable());
4565
4566 action = gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/AddChat");
4567 gtk_action_set_sensitive(action, pidgin_blist_joinchat_is_showable());
4568
4569 action = gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/RoomList");
4570 gtk_action_set_sensitive(action, pidgin_roomlist_is_showable());
4571 }
4572
4573 static void
4574 sign_on_off_cb(PurpleConnection *gc, PurpleBuddyList *blist)
4575 {
4576 PidginBuddyList *gtkblist = PIDGIN_BUDDY_LIST(blist);
4577
4578 update_menu_bar(gtkblist);
4579 }
4580
4581 static void
4582 plugin_changed_cb(PurplePlugin *p, gpointer data)
4583 {
4584 pidgin_blist_update_plugin_actions();
4585 }
4586
4587 static void 4037 static void
4588 unseen_conv_menu(GdkEvent *event) 4038 unseen_conv_menu(GdkEvent *event)
4589 { 4039 {
4590 static GtkWidget *menu = NULL; 4040 static GtkWidget *menu = NULL;
4591 GList *convs = NULL; 4041 GList *convs = NULL;
4927 { 4377 {
4928 if (!gtkblist) 4378 if (!gtkblist)
4929 return; 4379 return;
4930 4380
4931 pidgin_blist_select_notebook_page(gtkblist); 4381 pidgin_blist_select_notebook_page(gtkblist);
4932 update_menu_bar(gtkblist);
4933 }
4934
4935 static void
4936 account_actions_changed(PurpleAccount *account, gpointer data)
4937 {
4938 pidgin_blist_update_accounts_menu();
4939 } 4382 }
4940 4383
4941 static void 4384 static void
4942 account_status_changed(PurpleAccount *account, PurpleStatus *old, 4385 account_status_changed(PurpleAccount *account, PurpleStatus *old,
4943 PurpleStatus *new, PidginBuddyList *gtkblist) 4386 PurpleStatus *new, PidginBuddyList *gtkblist)
5689 5132
5690 static void pidgin_blist_show(PurpleBuddyList *list) 5133 static void pidgin_blist_show(PurpleBuddyList *list)
5691 { 5134 {
5692 PidginBuddyListPrivate *priv; 5135 PidginBuddyListPrivate *priv;
5693 void *handle; 5136 void *handle;
5137 GSimpleActionGroup *actions;
5694 GtkTreeViewColumn *column; 5138 GtkTreeViewColumn *column;
5695 GtkWidget *menu;
5696 GtkWidget *sep; 5139 GtkWidget *sep;
5697 GtkWidget *infobar; 5140 GtkWidget *infobar;
5698 GtkWidget *content_area; 5141 GtkWidget *content_area;
5699 GtkWidget *label; 5142 GtkWidget *label;
5700 GtkWidget *close; 5143 GtkWidget *close;
5701 gchar *text; 5144 gchar *text;
5702 const char *theme_name; 5145 const char *theme_name;
5703 GtkActionGroup *action_group;
5704 GError *error;
5705 GtkAccelGroup *accel_group;
5706 GtkTreeSelection *selection; 5146 GtkTreeSelection *selection;
5707 GtkTargetEntry dte[] = {{"PURPLE_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW}, 5147 GtkTargetEntry dte[] = {{"PURPLE_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW},
5708 {"application/x-im-contact", 0, DRAG_BUDDY}, 5148 {"application/x-im-contact", 0, DRAG_BUDDY},
5709 {"text/x-vcard", 0, DRAG_VCARD }, 5149 {"text/x-vcard", 0, DRAG_VCARD },
5710 {"text/uri-list", 0, DRAG_URI}, 5150 {"text/uri-list", 0, DRAG_URI},
5753 g_signal_connect(G_OBJECT(gtkblist->window), "window_state_event", G_CALLBACK(gtk_blist_window_state_cb), NULL); 5193 g_signal_connect(G_OBJECT(gtkblist->window), "window_state_event", G_CALLBACK(gtk_blist_window_state_cb), NULL);
5754 g_signal_connect(G_OBJECT(gtkblist->window), "key_press_event", G_CALLBACK(gtk_blist_window_key_press_cb), gtkblist); 5194 g_signal_connect(G_OBJECT(gtkblist->window), "key_press_event", G_CALLBACK(gtk_blist_window_key_press_cb), gtkblist);
5755 gtk_widget_add_events(gtkblist->window, GDK_VISIBILITY_NOTIFY_MASK); 5195 gtk_widget_add_events(gtkblist->window, GDK_VISIBILITY_NOTIFY_MASK);
5756 5196
5757 /******************************* Menu bar *************************************/ 5197 /******************************* Menu bar *************************************/
5758 action_group = gtk_action_group_new("BListActions"); 5198 actions = pidgin_action_group_new();
5759 gtk_action_group_set_translation_domain(action_group, PACKAGE); 5199 gtk_widget_insert_action_group(gtkblist->window, "blist",
5760 gtk_action_group_add_actions(action_group, 5200 G_ACTION_GROUP(actions));
5761 blist_menu_entries, 5201
5762 G_N_ELEMENTS(blist_menu_entries), 5202 gtkblist->menu = pidgin_buddy_list_menu_new();
5763 GTK_WINDOW(gtkblist->window)); 5203 gtk_box_pack_start(GTK_BOX(gtkblist->main_vbox), gtkblist->menu, FALSE,
5764 gtk_action_group_add_toggle_actions(action_group, 5204 FALSE, 0);
5765 blist_menu_toggle_entries, 5205
5766 G_N_ELEMENTS(blist_menu_toggle_entries), 5206 gtkblist->menutray = pidgin_buddy_list_menu_get_menu_tray(PIDGIN_BUDDY_LIST_MENU(gtkblist->menu));
5767 GTK_WINDOW(gtkblist->window));
5768
5769 gtkblist->ui = gtk_ui_manager_new();
5770 gtk_ui_manager_insert_action_group(gtkblist->ui, action_group, 0);
5771
5772 accel_group = gtk_ui_manager_get_accel_group(gtkblist->ui);
5773 gtk_window_add_accel_group(GTK_WINDOW(gtkblist->window), accel_group);
5774 pidgin_load_accels();
5775 g_signal_connect(G_OBJECT(accel_group), "accel-changed", G_CALLBACK(pidgin_save_accels_cb), NULL);
5776
5777 error = NULL;
5778 if (!gtk_ui_manager_add_ui_from_string(gtkblist->ui, blist_menu, -1, &error))
5779 {
5780 g_message("building menus failed: %s", error->message);
5781 g_error_free(error);
5782 exit(EXIT_FAILURE);
5783 }
5784
5785 menu = gtk_ui_manager_get_widget(gtkblist->ui, "/BList");
5786 gtkblist->menutray = pidgin_menu_tray_new();
5787 gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtkblist->menutray);
5788 gtk_widget_show(gtkblist->menutray);
5789 gtk_widget_show(menu);
5790 gtk_box_pack_start(GTK_BOX(gtkblist->main_vbox), menu, FALSE, FALSE, 0);
5791
5792 menu = gtk_ui_manager_get_widget(gtkblist->ui, "/BList/AccountsMenu");
5793 accountmenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu));
5794 5207
5795 /****************************** Notebook *************************************/ 5208 /****************************** Notebook *************************************/
5796 gtkblist->notebook = gtk_notebook_new(); 5209 gtkblist->notebook = gtk_notebook_new();
5797 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkblist->notebook), FALSE); 5210 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkblist->notebook), FALSE);
5798 gtk_notebook_set_show_border(GTK_NOTEBOOK(gtkblist->notebook), FALSE); 5211 gtk_notebook_set_show_border(GTK_NOTEBOOK(gtkblist->notebook), FALSE);
5957 gtkblist->statusbox = pidgin_status_box_new(); 5370 gtkblist->statusbox = pidgin_status_box_new();
5958 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->statusbox, FALSE, TRUE, 0); 5371 gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->statusbox, FALSE, TRUE, 0);
5959 gtk_widget_set_name(gtkblist->statusbox, "pidgin_blist_statusbox"); 5372 gtk_widget_set_name(gtkblist->statusbox, "pidgin_blist_statusbox");
5960 gtk_widget_show(gtkblist->statusbox); 5373 gtk_widget_show(gtkblist->statusbox);
5961 5374
5962 /* set the Show Offline Buddies option. must be done
5963 * after the treeview or faceprint gets mad. -Robot101
5964 */
5965 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowOffline")),
5966 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies"));
5967
5968 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowEmptyGroups")),
5969 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_empty_groups"));
5970
5971 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/MuteSounds")),
5972 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/sound/mute"));
5973
5974 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowBuddyDetails")),
5975 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"));
5976
5977 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowIdleTimes")),
5978 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time"));
5979
5980 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowProtocolIcons")),
5981 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"));
5982
5983 if(purple_strequal(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"), "none"))
5984 gtk_action_set_sensitive(gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/MuteSounds"), FALSE);
5985
5986 /* Update some dynamic things */ 5375 /* Update some dynamic things */
5987 update_menu_bar(gtkblist);
5988 pidgin_blist_update_plugin_actions();
5989 pidgin_blist_update_sort_methods(); 5376 pidgin_blist_update_sort_methods();
5990 5377
5991 /* OK... let's show this bad boy. */ 5378 /* OK... let's show this bad boy. */
5992 pidgin_blist_refresh(list); 5379 pidgin_blist_refresh(list);
5993 pidgin_blist_restore_window_state(); 5380 pidgin_blist_restore_window_state();
6013 _prefs_change_redo_list, NULL); 5400 _prefs_change_redo_list, NULL);
6014 5401
6015 /* sorting */ 5402 /* sorting */
6016 purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/blist/sort_type", 5403 purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/blist/sort_type",
6017 _prefs_change_sort_method, NULL); 5404 _prefs_change_sort_method, NULL);
6018
6019 /* menus */
6020 purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/sound/mute",
6021 pidgin_blist_mute_pref_cb, NULL);
6022 purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/sound/method",
6023 pidgin_blist_sound_method_pref_cb, NULL);
6024 5405
6025 /* Setup some purple signal handlers. */ 5406 /* Setup some purple signal handlers. */
6026 5407
6027 handle = purple_accounts_get_handle(); 5408 handle = purple_accounts_get_handle();
6028 purple_signal_connect(handle, "account-enabled", gtkblist, 5409 purple_signal_connect(handle, "account-enabled", gtkblist,
6035 PURPLE_CALLBACK(account_status_changed), 5416 PURPLE_CALLBACK(account_status_changed),
6036 gtkblist); 5417 gtkblist);
6037 purple_signal_connect(handle, "account-error-changed", gtkblist, 5418 purple_signal_connect(handle, "account-error-changed", gtkblist,
6038 PURPLE_CALLBACK(update_account_error_state), 5419 PURPLE_CALLBACK(update_account_error_state),
6039 gtkblist); 5420 gtkblist);
6040 purple_signal_connect(handle, "account-actions-changed", gtkblist,
6041 PURPLE_CALLBACK(account_actions_changed), NULL);
6042 5421
6043 handle = pidgin_accounts_get_handle(); 5422 handle = pidgin_accounts_get_handle();
6044 purple_signal_connect(handle, "account-modified", gtkblist, 5423 purple_signal_connect(handle, "account-modified", gtkblist,
6045 PURPLE_CALLBACK(account_modified), gtkblist); 5424 PURPLE_CALLBACK(account_modified), gtkblist);
6046
6047 handle = purple_connections_get_handle();
6048 purple_signal_connect(handle, "signed-on", gtkblist,
6049 PURPLE_CALLBACK(sign_on_off_cb), list);
6050 purple_signal_connect(handle, "signed-off", gtkblist,
6051 PURPLE_CALLBACK(sign_on_off_cb), list);
6052
6053 handle = purple_plugins_get_handle();
6054 purple_signal_connect(handle, "plugin-load", gtkblist,
6055 PURPLE_CALLBACK(plugin_changed_cb), NULL);
6056 purple_signal_connect(handle, "plugin-unload", gtkblist,
6057 PURPLE_CALLBACK(plugin_changed_cb), NULL);
6058 5425
6059 handle = purple_conversations_get_handle(); 5426 handle = purple_conversations_get_handle();
6060 purple_signal_connect(handle, "conversation-updated", gtkblist, 5427 purple_signal_connect(handle, "conversation-updated", gtkblist,
6061 PURPLE_CALLBACK(conversation_updated_cb), 5428 PURPLE_CALLBACK(conversation_updated_cb),
6062 gtkblist); 5429 gtkblist);
7482 g_hash_table_destroy(cached_emblems); 6849 g_hash_table_destroy(cached_emblems);
7483 6850
7484 purple_signals_unregister_by_instance(pidgin_blist_get_handle()); 6851 purple_signals_unregister_by_instance(pidgin_blist_get_handle());
7485 purple_signals_disconnect_by_handle(pidgin_blist_get_handle()); 6852 purple_signals_disconnect_by_handle(pidgin_blist_get_handle());
7486 6853
7487 accountmenu = NULL;
7488 gtkblist = NULL; 6854 gtkblist = NULL;
7489 } 6855 }
7490 6856
7491 /************************************************************************** 6857 /**************************************************************************
7492 * GTK Buddy list GObject code 6858 * GTK Buddy list GObject code
7522 gtkblist->drag_timeout = 0; 6888 gtkblist->drag_timeout = 0;
7523 } 6889 }
7524 6890
7525 gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL; 6891 gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL;
7526 g_clear_object(&gtkblist->treemodel); 6892 g_clear_object(&gtkblist->treemodel);
7527 g_object_unref(G_OBJECT(gtkblist->ui));
7528 g_object_unref(G_OBJECT(gtkblist->empty_avatar)); 6893 g_object_unref(G_OBJECT(gtkblist->empty_avatar));
7529 6894
7530 g_clear_object(&priv->current_theme); 6895 g_clear_object(&priv->current_theme);
7531 if (priv->select_notebook_page_timeout) { 6896 if (priv->select_notebook_page_timeout) {
7532 g_source_remove(priv->select_notebook_page_timeout); 6897 g_source_remove(priv->select_notebook_page_timeout);
7873 gtk_tree_store_append(gtkblist->treemodel, iter, &groupiter); 7238 gtk_tree_store_append(gtkblist->treemodel, iter, &groupiter);
7874 return; 7239 return;
7875 } 7240 }
7876 } 7241 }
7877 7242
7878 static void
7879 plugin_act(GSimpleAction *action, GVariant *param, PurplePluginAction *pam)
7880 {
7881 if (pam && pam->callback)
7882 pam->callback(pam);
7883 }
7884
7885 static GtkWidget *
7886 build_plugin_actions(GActionMap *action_map, const gchar *parent,
7887 PurplePlugin *plugin)
7888 {
7889 GMenu *menu = NULL;
7890 GMenu *section = NULL;
7891 PurplePluginActionsCb actions_cb;
7892 PurplePluginAction *action = NULL;
7893 GList *actions, *l;
7894 char *name;
7895 int count = 0;
7896 GtkWidget *ret;
7897
7898 actions_cb =
7899 purple_plugin_info_get_actions_cb(purple_plugin_get_info(plugin));
7900
7901 actions = actions_cb(plugin);
7902
7903 if (actions == NULL) {
7904 return NULL;
7905 }
7906
7907 menu = g_menu_new();
7908
7909 for (l = actions; l != NULL; l = l->next) {
7910 GAction *menuaction;
7911
7912 action = (PurplePluginAction *)l->data;
7913
7914 if (action == NULL) {
7915 if (section != NULL) {
7916 /* Close and append section if any */
7917 g_menu_append_section(menu, NULL,
7918 G_MENU_MODEL(section));
7919 g_clear_object(&section);
7920 }
7921
7922 continue;
7923 }
7924
7925 action->plugin = plugin;
7926
7927 name = g_strdup_printf("plugin.%s-action-%d", parent, count++);
7928 /* +7 to skip "plugin." prefix */
7929 menuaction = G_ACTION(g_simple_action_new(name + 7, NULL));
7930 g_signal_connect_data(G_OBJECT(menuaction), "activate",
7931 G_CALLBACK(plugin_act), action,
7932 (GClosureNotify)purple_plugin_action_free, 0);
7933 g_action_map_add_action(action_map, menuaction);
7934 g_object_unref(menuaction);
7935
7936 if (section == NULL) {
7937 section = g_menu_new();
7938 }
7939
7940 g_menu_append(section, action->label, name);
7941 g_free(name);
7942 }
7943
7944 if (section != NULL) {
7945 /* Close and append final section if any */
7946 g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
7947 g_clear_object(&section);
7948 }
7949
7950 g_list_free(actions);
7951
7952 ret = gtk_menu_new_from_model(G_MENU_MODEL(menu));
7953 g_object_unref(menu);
7954 return ret;
7955 }
7956
7957
7958 static void
7959 modify_account_cb(GtkWidget *widget, gpointer data)
7960 {
7961 pidgin_account_dialog_show(PIDGIN_MODIFY_ACCOUNT_DIALOG, data);
7962 }
7963
7964 static void
7965 enable_account_cb(GtkCheckMenuItem *widget, gpointer data)
7966 {
7967 PurpleAccount *account = data;
7968 const PurpleSavedStatus *saved_status;
7969
7970 saved_status = purple_savedstatus_get_current();
7971 purple_savedstatus_activate_for_account(saved_status, account);
7972
7973 purple_account_set_enabled(account, PIDGIN_UI, TRUE);
7974 }
7975
7976 static void
7977 disable_account_cb(GtkCheckMenuItem *widget, gpointer data)
7978 {
7979 PurpleAccount *account = data;
7980
7981 purple_account_set_enabled(account, PIDGIN_UI, FALSE);
7982 }
7983
7984 static void
7985 protocol_act(GtkWidget *obj, PurpleProtocolAction *pam)
7986 {
7987 if (pam && pam->callback)
7988 pam->callback(pam);
7989 }
7990
7991 void
7992 pidgin_blist_update_accounts_menu(void)
7993 {
7994 GtkWidget *menuitem, *submenu;
7995 GtkAccelGroup *accel_group;
7996 GList *l, *accounts;
7997 gboolean disabled_accounts = FALSE;
7998 gboolean enabled_accounts = FALSE;
7999
8000 if (accountmenu == NULL)
8001 return;
8002
8003 /* Clear the old Accounts menu */
8004 for (l = gtk_container_get_children(GTK_CONTAINER(accountmenu)); l; l = g_list_delete_link(l, l)) {
8005 menuitem = l->data;
8006
8007 if (menuitem != gtk_ui_manager_get_widget(gtkblist->ui, "/BList/AccountsMenu/ManageAccounts"))
8008 gtk_widget_destroy(menuitem);
8009 }
8010
8011 accel_group = gtk_menu_get_accel_group(GTK_MENU(accountmenu));
8012
8013 for (accounts = purple_accounts_get_all(); accounts; accounts = accounts->next) {
8014 char *buf = NULL;
8015 GtkWidget *image = NULL;
8016 PurpleAccount *account = NULL;
8017 GdkPixbuf *pixbuf = NULL;
8018
8019 account = accounts->data;
8020
8021 if (!purple_account_get_enabled(account, PIDGIN_UI)) {
8022 if (!disabled_accounts) {
8023 menuitem = gtk_menu_item_new_with_label(_("Enable Account"));
8024 gtk_menu_shell_append(GTK_MENU_SHELL(accountmenu), menuitem);
8025
8026 submenu = gtk_menu_new();
8027 gtk_menu_set_accel_group(GTK_MENU(submenu), accel_group);
8028 gtk_menu_set_accel_path(GTK_MENU(submenu), "<Actions>/BListActions/EnableAccount");
8029 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
8030
8031 disabled_accounts = TRUE;
8032 }
8033
8034 buf = g_strconcat(purple_account_get_username(account), " (",
8035 purple_account_get_protocol_name(account), ")", NULL);
8036 menuitem = gtk_image_menu_item_new_with_label(buf);
8037 g_free(buf);
8038
8039 pixbuf = pidgin_create_protocol_icon(account, PIDGIN_PROTOCOL_ICON_SMALL);
8040 if (pixbuf != NULL) {
8041 if (!purple_account_is_connected(account))
8042 gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE);
8043 image = gtk_image_new_from_pixbuf(pixbuf);
8044 g_object_unref(G_OBJECT(pixbuf));
8045 gtk_widget_show(image);
8046 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
8047 }
8048
8049 g_signal_connect(G_OBJECT(menuitem), "activate",
8050 G_CALLBACK(enable_account_cb), account);
8051 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
8052
8053 } else {
8054 enabled_accounts = TRUE;
8055 }
8056 }
8057
8058 if (!enabled_accounts) {
8059 gtk_widget_show_all(accountmenu);
8060 return;
8061 }
8062
8063 pidgin_separator(accountmenu);
8064
8065 for (accounts = purple_accounts_get_all(); accounts; accounts = accounts->next) {
8066 char *buf = NULL;
8067 char *accel_path_buf = NULL;
8068 GtkWidget *image = NULL;
8069 PurpleConnection *gc = NULL;
8070 PurpleAccount *account = NULL;
8071 GdkPixbuf *pixbuf = NULL;
8072 PurpleProtocol *protocol;
8073
8074 account = accounts->data;
8075
8076 if (!purple_account_get_enabled(account, PIDGIN_UI))
8077 continue;
8078
8079 buf = g_strconcat(purple_account_get_username(account), " (",
8080 purple_account_get_protocol_name(account), ")", NULL);
8081 menuitem = gtk_image_menu_item_new_with_label(buf);
8082 accel_path_buf = g_strconcat("<Actions>/AccountActions/", buf, NULL);
8083 g_free(buf);
8084
8085 pixbuf = pidgin_create_protocol_icon(account, PIDGIN_PROTOCOL_ICON_SMALL);
8086 if (pixbuf != NULL) {
8087 if (!purple_account_is_connected(account))
8088 gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf,
8089 0.0, FALSE);
8090 image = gtk_image_new_from_pixbuf(pixbuf);
8091 g_object_unref(G_OBJECT(pixbuf));
8092 gtk_widget_show(image);
8093 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
8094 }
8095
8096 gtk_menu_shell_append(GTK_MENU_SHELL(accountmenu), menuitem);
8097
8098 submenu = gtk_menu_new();
8099 gtk_menu_set_accel_group(GTK_MENU(submenu), accel_group);
8100 gtk_menu_set_accel_path(GTK_MENU(submenu), accel_path_buf);
8101 g_free(accel_path_buf);
8102 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
8103
8104 menuitem = gtk_menu_item_new_with_mnemonic(_("_Edit Account"));
8105 g_signal_connect(G_OBJECT(menuitem), "activate",
8106 G_CALLBACK(modify_account_cb), account);
8107 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
8108
8109 pidgin_separator(submenu);
8110
8111 gc = purple_account_get_connection(account);
8112 protocol = gc && PURPLE_CONNECTION_IS_CONNECTED(gc) ?
8113 purple_connection_get_protocol(gc) : NULL;
8114
8115 if (protocol &&
8116 (PURPLE_PROTOCOL_IMPLEMENTS(protocol, CLIENT, get_moods) ||
8117 PURPLE_PROTOCOL_IMPLEMENTS(protocol, CLIENT, get_actions))) {
8118 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, CLIENT, get_moods) &&
8119 (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_SUPPORT_MOODS)) {
8120
8121 if (purple_account_get_status(account, "mood")) {
8122 menuitem = gtk_menu_item_new_with_mnemonic(_("Set _Mood..."));
8123 g_signal_connect(G_OBJECT(menuitem), "activate",
8124 G_CALLBACK(set_mood_cb), account);
8125 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
8126 }
8127 }
8128
8129 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, CLIENT, get_actions)) {
8130 GtkWidget *menuitem;
8131 PurpleProtocolAction *action = NULL;
8132 GList *actions, *l;
8133
8134 actions = purple_protocol_client_iface_get_actions(protocol, gc);
8135
8136 for (l = actions; l != NULL; l = l->next)
8137 {
8138 if (l->data)
8139 {
8140 action = (PurpleProtocolAction *) l->data;
8141 action->connection = gc;
8142
8143 menuitem = gtk_menu_item_new_with_label(action->label);
8144 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
8145
8146 g_signal_connect(G_OBJECT(menuitem), "activate",
8147 G_CALLBACK(protocol_act), action);
8148 g_object_set_data_full(G_OBJECT(menuitem), "protocol_action",
8149 action,
8150 (GDestroyNotify)purple_protocol_action_free);
8151 gtk_widget_show(menuitem);
8152 }
8153 else
8154 pidgin_separator(submenu);
8155 }
8156
8157 g_list_free(actions);
8158 }
8159 } else {
8160 menuitem = gtk_menu_item_new_with_label(_("No actions available"));
8161 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
8162 gtk_widget_set_sensitive(menuitem, FALSE);
8163 }
8164
8165 pidgin_separator(submenu);
8166
8167 menuitem = gtk_menu_item_new_with_mnemonic(_("_Disable"));
8168 g_signal_connect(G_OBJECT(menuitem), "activate",
8169 G_CALLBACK(disable_account_cb), account);
8170 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
8171 }
8172
8173 gtk_widget_show_all(accountmenu);
8174 }
8175
8176 static GSList *plugin_menu_items;
8177
8178 void
8179 pidgin_blist_update_plugin_actions(void)
8180 {
8181 GtkWidget *toolsmenu;
8182 GSimpleActionGroup *action_group;
8183 PurplePlugin *plugin = NULL;
8184 PurplePluginInfo *info;
8185 GList *l;
8186
8187 int count = 0;
8188
8189 if ((gtkblist == NULL) || (gtkblist->ui == NULL))
8190 return;
8191
8192 /* Clear the old menu */
8193 g_slist_free_full(plugin_menu_items,
8194 (GDestroyNotify)gtk_widget_destroy);
8195 plugin_menu_items = NULL;
8196
8197 toolsmenu = gtk_ui_manager_get_widget(gtkblist->ui,
8198 "/BList/ToolsMenu");
8199 toolsmenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(toolsmenu));
8200
8201 action_group = g_simple_action_group_new();
8202
8203 /* Add a submenu for each plugin with custom actions */
8204 for (l = purple_plugins_get_loaded(); l; l = l->next) {
8205 char *name;
8206 GtkWidget *submenu;
8207 GtkWidget *menuitem;
8208
8209 plugin = (PurplePlugin *)l->data;
8210 info = purple_plugin_get_info(plugin);
8211
8212 if (!purple_plugin_info_get_actions_cb(info))
8213 continue;
8214
8215 name = g_strdup_printf("plugin%d", count);
8216 submenu = build_plugin_actions(G_ACTION_MAP(action_group),
8217 name, plugin);
8218 g_free(name);
8219
8220 if (submenu == NULL) {
8221 continue;
8222 }
8223
8224 menuitem = gtk_menu_item_new_with_mnemonic(
8225 _(gplugin_plugin_info_get_name(
8226 GPLUGIN_PLUGIN_INFO(info))));
8227 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
8228 gtk_widget_show(menuitem);
8229 plugin_menu_items = g_slist_prepend(plugin_menu_items,
8230 menuitem);
8231 gtk_menu_shell_append(GTK_MENU_SHELL(toolsmenu), menuitem);
8232
8233 count++;
8234 }
8235
8236 /* Replaces existing "plugin" group if any */
8237 gtk_widget_insert_action_group(toolsmenu, "plugin",
8238 G_ACTION_GROUP(action_group));
8239 g_object_unref(action_group);
8240 }
8241
8242 static void
8243 sortmethod_act(GtkRadioAction *action, GtkRadioAction *current, char *id)
8244 {
8245 if (action == current)
8246 {
8247 pidgin_set_cursor(gtkblist->window, GDK_WATCH);
8248 /* This is redundant. I think. */
8249 /* pidgin_blist_sort_method_set(id); */
8250 purple_prefs_set_string(PIDGIN_PREFS_ROOT "/blist/sort_type", id);
8251
8252 pidgin_clear_cursor(gtkblist->window);
8253 }
8254 }
8255
8256 void 7243 void
8257 pidgin_blist_update_sort_methods(void) 7244 pidgin_blist_update_sort_methods(void)
8258 { 7245 {
8259 PidginBlistSortMethod *method = NULL; 7246 GtkWidget *sort_item = NULL;
7247 GMenu *menu = NULL;
8260 GList *l; 7248 GList *l;
8261 GSList *sl = NULL; 7249
8262 const char *m = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/sort_type"); 7250 if(gtkblist == NULL)
8263
8264 GtkRadioAction *action;
8265 GString *ui_string;
8266
8267 if ((gtkblist == NULL) || (gtkblist->ui == NULL))
8268 return; 7251 return;
8269 7252
8270 /* Clear the old menu */ 7253 /* create the gmenu */
8271 if (sort_action_group) { 7254 menu = g_menu_new();
8272 gtk_ui_manager_remove_ui(gtkblist->ui, sort_merge_id); 7255
8273 gtk_ui_manager_remove_action_group(gtkblist->ui, sort_action_group); 7256 /* walk through the sort methods and update all the things */
8274 g_object_unref(G_OBJECT(sort_action_group));
8275 }
8276
8277 sort_action_group = gtk_action_group_new("SortMethods");
8278 gtk_action_group_set_translation_domain(sort_action_group, PACKAGE);
8279
8280 ui_string = g_string_new("<ui><menubar name='BList'>"
8281 "<menu action='BuddiesMenu'><menu action='SortMenu'>");
8282
8283 for (l = pidgin_blist_sort_methods; l; l = l->next) { 7257 for (l = pidgin_blist_sort_methods; l; l = l->next) {
7258 PidginBlistSortMethod *method = NULL;
7259 GMenuItem *item = NULL;
7260 gchar *action = NULL;
7261
8284 method = (PidginBlistSortMethod *)l->data; 7262 method = (PidginBlistSortMethod *)l->data;
8285 7263
8286 g_string_append_printf(ui_string, "<menuitem action='%s'/>", method->id); 7264 action = g_action_print_detailed_name("blist.sort-method",
8287 action = gtk_radio_action_new(method->id, 7265 g_variant_new_string(method->id));
8288 method->name, 7266 item = g_menu_item_new(method->name, action);
8289 NULL, 7267 g_free(action);
8290 NULL, 7268
8291 0); 7269 g_menu_append_item(menu, item);
8292 gtk_action_group_add_action_with_accel(sort_action_group, GTK_ACTION(action), NULL); 7270 }
8293 7271
8294 gtk_radio_action_set_group(action, sl); 7272 /* replace the old submenu with a new one */
8295 sl = gtk_radio_action_get_group(action); 7273 sort_item = pidgin_buddy_list_menu_get_sort_item(PIDGIN_BUDDY_LIST_MENU(gtkblist->menu));
8296 7274 gtk_menu_item_set_submenu(GTK_MENU_ITEM(sort_item),
8297 if (purple_strequal(m, method->id)) 7275 gtk_menu_new_from_model(G_MENU_MODEL(menu)));
8298 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE); 7276 g_object_unref(G_OBJECT(menu));
8299 else 7277 }
8300 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), FALSE);
8301
8302 g_signal_connect(G_OBJECT(action), "changed",
8303 G_CALLBACK(sortmethod_act), method->id);
8304 }
8305
8306 g_string_append(ui_string, "</menu></menu></menubar></ui>");
8307 gtk_ui_manager_insert_action_group(gtkblist->ui, sort_action_group, 1);
8308 sort_merge_id = gtk_ui_manager_add_ui_from_string(gtkblist->ui, ui_string->str, -1, NULL);
8309
8310 g_string_free(ui_string, TRUE);
8311 }
8312

mercurial