pidgin/gtkblist.c

changeset 40385
c3e9a7d14e6f
parent 40383
dbc5c2d601ab
child 40392
924a47d2652d
equal deleted inserted replaced
40384:8f6c0247f9f2 40385:c3e9a7d14e6f
58 #include "pidgin/pidginactiongroup.h" 58 #include "pidgin/pidginactiongroup.h"
59 #include "pidgin/pidginbuddylistmenu.h" 59 #include "pidgin/pidginbuddylistmenu.h"
60 #include "pidgin/pidgindebug.h" 60 #include "pidgin/pidgindebug.h"
61 #include "pidgin/pidgingdkpixbuf.h" 61 #include "pidgin/pidgingdkpixbuf.h"
62 #include "pidgin/pidginlog.h" 62 #include "pidgin/pidginlog.h"
63 #include "pidgin/pidginmooddialog.h"
63 #include "pidgin/pidginplugininfo.h" 64 #include "pidgin/pidginplugininfo.h"
64 #include "pidgin/pidgintooltip.h" 65 #include "pidgin/pidgintooltip.h"
65 #include "pidginmenutray.h" 66 #include "pidginmenutray.h"
66 67
67 #include <gdk/gdkkeysyms.h> 68 #include <gdk/gdkkeysyms.h>
3247 gtkblist->mouseover_contact = NULL; 3248 gtkblist->mouseover_contact = NULL;
3248 } 3249 }
3249 return FALSE; 3250 return FALSE;
3250 } 3251 }
3251 3252
3252 static char *get_mood_icon_path(const char *mood)
3253 {
3254 char *path;
3255
3256 if (purple_strequal(mood, "busy")) {
3257 path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons",
3258 "hicolor", "16x16", "status", "user-busy.png", NULL);
3259 } else if (purple_strequal(mood, "hiptop")) {
3260 path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons",
3261 "hicolor", "16x16", "emblems", "emblem-hiptop.png",
3262 NULL);
3263 } else {
3264 char *filename = g_strdup_printf("%s.png", mood);
3265 path = g_build_filename(PURPLE_DATADIR, "pixmaps", "pidgin",
3266 "emotes", "small", filename, NULL);
3267 g_free(filename);
3268 }
3269 return path;
3270 }
3271
3272 static void
3273 update_status_with_mood(PurpleAccount *account, const gchar *mood,
3274 const gchar *text)
3275 {
3276 if (mood && *mood) {
3277 if (text) {
3278 purple_account_set_status(account, "mood", TRUE,
3279 PURPLE_MOOD_NAME, mood,
3280 PURPLE_MOOD_COMMENT, text,
3281 NULL);
3282 } else {
3283 purple_account_set_status(account, "mood", TRUE,
3284 PURPLE_MOOD_NAME, mood,
3285 NULL);
3286 }
3287 } else {
3288 purple_account_set_status(account, "mood", FALSE, NULL);
3289 }
3290 }
3291
3292 static void
3293 edit_mood_cb(PurpleConnection *gc, PurpleRequestFields *fields)
3294 {
3295 PurpleRequestField *mood_field;
3296 GList *l;
3297
3298 mood_field = purple_request_fields_get_field(fields, "mood");
3299 l = purple_request_field_list_get_selected(mood_field);
3300
3301 if (l) {
3302 const char *mood = purple_request_field_list_get_data(mood_field, l->data);
3303
3304 if (gc) {
3305 const char *text;
3306 PurpleAccount *account = purple_connection_get_account(gc);
3307
3308 if (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_SUPPORT_MOOD_MESSAGES) {
3309 PurpleRequestField *text_field;
3310 text_field = purple_request_fields_get_field(fields, "text");
3311 text = purple_request_field_string_get_value(text_field);
3312 } else {
3313 text = NULL;
3314 }
3315
3316 update_status_with_mood(account, mood, text);
3317 } else {
3318 GList *accounts = purple_accounts_get_all_active();
3319
3320 for (; accounts ; accounts = g_list_delete_link(accounts, accounts)) {
3321 PurpleAccount *account = (PurpleAccount *) accounts->data;
3322 PurpleConnection *gc = purple_account_get_connection(account);
3323
3324 if (gc && (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_SUPPORT_MOODS)) {
3325 update_status_with_mood(account, mood, NULL);
3326 }
3327 }
3328 }
3329 }
3330 }
3331
3332 static void
3333 global_moods_for_each(gpointer key, gpointer value, gpointer user_data)
3334 {
3335 GList **out_moods = (GList **) user_data;
3336 PurpleMood *mood = (PurpleMood *) value;
3337
3338 *out_moods = g_list_append(*out_moods, mood);
3339 }
3340
3341 static PurpleMood *
3342 get_global_moods(void)
3343 {
3344 GHashTable *global_moods =
3345 g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
3346 GHashTable *mood_counts =
3347 g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
3348 GList *accounts = purple_accounts_get_all_active();
3349 PurpleMood *result = NULL;
3350 GList *out_moods = NULL;
3351 int i = 0;
3352 int num_accounts = 0;
3353
3354 for (; accounts ; accounts = g_list_delete_link(accounts, accounts)) {
3355 PurpleAccount *account = (PurpleAccount *) accounts->data;
3356 if (purple_account_is_connected(account)) {
3357 PurpleConnection *gc = purple_account_get_connection(account);
3358
3359 if (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_SUPPORT_MOODS) {
3360 PurpleProtocol *protocol = purple_connection_get_protocol(gc);
3361 PurpleMood *mood = NULL;
3362
3363 for (mood = purple_protocol_client_iface_get_moods(protocol, account) ;
3364 mood->mood != NULL ; mood++) {
3365 int mood_count =
3366 GPOINTER_TO_INT(g_hash_table_lookup(mood_counts, mood->mood));
3367
3368 if (!g_hash_table_lookup(global_moods, mood->mood)) {
3369 g_hash_table_insert(global_moods, (gpointer)mood->mood, mood);
3370 }
3371 g_hash_table_insert(mood_counts, (gpointer)mood->mood,
3372 GINT_TO_POINTER(mood_count + 1));
3373 }
3374
3375 num_accounts++;
3376 }
3377 }
3378 }
3379
3380 g_hash_table_foreach(global_moods, global_moods_for_each, &out_moods);
3381 result = g_new0(PurpleMood, g_hash_table_size(global_moods) + 1);
3382
3383 while (out_moods) {
3384 PurpleMood *mood = (PurpleMood *) out_moods->data;
3385 int in_num_accounts =
3386 GPOINTER_TO_INT(g_hash_table_lookup(mood_counts, mood->mood));
3387
3388 if (in_num_accounts == num_accounts) {
3389 /* mood is present in all accounts supporting moods */
3390 result[i].mood = mood->mood;
3391 result[i].description = mood->description;
3392 i++;
3393 }
3394 out_moods = g_list_delete_link(out_moods, out_moods);
3395 }
3396
3397 g_hash_table_destroy(global_moods);
3398 g_hash_table_destroy(mood_counts);
3399
3400 return result;
3401 }
3402
3403 /* get current set mood for all mood-supporting accounts, or NULL if not set
3404 or not set to the same on all */
3405 static const gchar *
3406 get_global_mood_status(void)
3407 {
3408 GList *accounts = purple_accounts_get_all_active();
3409 const gchar *found_mood = NULL;
3410
3411 for (; accounts ; accounts = g_list_delete_link(accounts, accounts)) {
3412 PurpleAccount *account = (PurpleAccount *) accounts->data;
3413
3414 if (purple_account_is_connected(account) &&
3415 (purple_connection_get_flags(purple_account_get_connection(account)) &
3416 PURPLE_CONNECTION_FLAG_SUPPORT_MOODS)) {
3417 PurplePresence *presence = purple_account_get_presence(account);
3418 PurpleStatus *status = purple_presence_get_status(presence, "mood");
3419 const gchar *curr_mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
3420
3421 if (found_mood != NULL && !purple_strequal(curr_mood, found_mood)) {
3422 /* found a different mood */
3423 found_mood = NULL;
3424 break;
3425 } else {
3426 found_mood = curr_mood;
3427 }
3428 }
3429 }
3430
3431 return found_mood;
3432 }
3433
3434 static void
3435 set_mood_cb(GtkWidget *widget, PurpleAccount *account)
3436 {
3437 const char *current_mood;
3438 PurpleRequestFields *fields;
3439 PurpleRequestFieldGroup *g;
3440 PurpleRequestField *f;
3441 PurpleConnection *gc = NULL;
3442 PurpleProtocol *protocol = NULL;
3443 PurpleMood *mood;
3444 PurpleMood *global_moods = NULL;
3445
3446 if (account) {
3447 PurplePresence *presence = purple_account_get_presence(account);
3448 PurpleStatus *status = purple_presence_get_status(presence, "mood");
3449 gc = purple_account_get_connection(account);
3450 g_return_if_fail(purple_connection_get_protocol(gc) != NULL);
3451 protocol = purple_connection_get_protocol(gc);
3452 current_mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
3453 } else {
3454 current_mood = get_global_mood_status();
3455 }
3456
3457 fields = purple_request_fields_new();
3458 g = purple_request_field_group_new(NULL);
3459 f = purple_request_field_list_new("mood", _("Please select your mood from the list"));
3460
3461 purple_request_field_list_add_icon(f, _("None"), NULL, "");
3462 if (current_mood == NULL)
3463 purple_request_field_list_add_selected(f, _("None"));
3464
3465 /* TODO: rlaager wants this sorted. */
3466 /* TODO: darkrain wants it sorted post-translation */
3467 if (account && PURPLE_PROTOCOL_IMPLEMENTS(protocol, CLIENT, get_moods)) {
3468 mood = purple_protocol_client_iface_get_moods(protocol, account);
3469 } else {
3470 mood = global_moods = get_global_moods();
3471 }
3472 for ( ; mood->mood != NULL ; mood++) {
3473 char *path;
3474
3475 if (mood->description == NULL) {
3476 continue;
3477 }
3478
3479 path = get_mood_icon_path(mood->mood);
3480 purple_request_field_list_add_icon(f, _(mood->description),
3481 path, (gpointer)mood->mood);
3482 g_free(path);
3483
3484 if (current_mood && purple_strequal(current_mood, mood->mood))
3485 purple_request_field_list_add_selected(f, _(mood->description));
3486 }
3487 purple_request_field_group_add_field(g, f);
3488
3489 purple_request_fields_add_group(fields, g);
3490
3491 /* if the connection allows setting a mood message */
3492 if (gc && (purple_connection_get_flags(gc) & PURPLE_CONNECTION_FLAG_SUPPORT_MOOD_MESSAGES)) {
3493 g = purple_request_field_group_new(NULL);
3494 f = purple_request_field_string_new("text",
3495 _("Message (optional)"), NULL, FALSE);
3496 purple_request_field_group_add_field(g, f);
3497 purple_request_fields_add_group(fields, g);
3498 }
3499
3500 purple_request_fields(gc, _("Edit User Mood"), _("Edit User Mood"),
3501 NULL, fields,
3502 _("OK"), G_CALLBACK(edit_mood_cb),
3503 _("Cancel"), NULL,
3504 purple_request_cpar_from_connection(gc), gc);
3505
3506 g_free(global_moods);
3507 }
3508
3509 static void
3510 set_mood_show(void)
3511 {
3512 set_mood_cb(NULL, NULL);
3513 }
3514
3515 /***************************************************
3516 * Crap *
3517 ***************************************************/
3518 static const GtkActionEntry blist_menu_entries[] = {
3519 /* Tools */
3520 { "ToolsMenu", NULL, N_("_Tools"), NULL, NULL, NULL },
3521 { "SetMood", NULL, N_("Set _Mood"), "<control>D", NULL, set_mood_show },
3522 };
3523
3524 static const char *blist_menu =
3525 "<ui>"
3526 "<menubar name='BList'>"
3527 "<menu action='ToolsMenu'>"
3528 "<menuitem action='SetMood'/>"
3529 "</menu>"
3530 "</menubar>"
3531 "</ui>";
3532
3533 /********************************************************* 3253 /*********************************************************
3534 * Private Utility functions * 3254 * Private Utility functions *
3535 *********************************************************/ 3255 *********************************************************/
3536 3256
3537 static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full) 3257 static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full)
3926 name = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); 3646 name = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
3927 3647
3928 if (!(name && *name)) 3648 if (!(name && *name))
3929 return NULL; 3649 return NULL;
3930 3650
3931 path = get_mood_icon_path(name); 3651 path = pidgin_mood_get_icon_path(name);
3932 } else { 3652 } else {
3933 filename = g_strdup_printf("emblem-%s.png", name); 3653 filename = g_strdup_printf("emblem-%s.png", name);
3934 path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons", 3654 path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons",
3935 "hicolor", "16x16", "emblems", filename, NULL); 3655 "hicolor", "16x16", "emblems", filename, NULL);
3936 g_free(filename); 3656 g_free(filename);
5427 { 5147 {
5428 PidginBuddyListPrivate *priv; 5148 PidginBuddyListPrivate *priv;
5429 void *handle; 5149 void *handle;
5430 GSimpleActionGroup *actions; 5150 GSimpleActionGroup *actions;
5431 GtkTreeViewColumn *column; 5151 GtkTreeViewColumn *column;
5432 GtkWidget *menu;
5433 GtkWidget *sep; 5152 GtkWidget *sep;
5434 GtkWidget *infobar; 5153 GtkWidget *infobar;
5435 GtkWidget *content_area; 5154 GtkWidget *content_area;
5436 GtkWidget *label; 5155 GtkWidget *label;
5437 GtkWidget *close; 5156 GtkWidget *close;
5438 gchar *text; 5157 gchar *text;
5439 const char *theme_name; 5158 const char *theme_name;
5440 GtkActionGroup *action_group;
5441 GError *error;
5442 GtkAccelGroup *accel_group;
5443 GtkTreeSelection *selection; 5159 GtkTreeSelection *selection;
5444 GtkTargetEntry dte[] = {{"PURPLE_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW}, 5160 GtkTargetEntry dte[] = {{"PURPLE_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW},
5445 {"application/x-im-contact", 0, DRAG_BUDDY}, 5161 {"application/x-im-contact", 0, DRAG_BUDDY},
5446 {"text/x-vcard", 0, DRAG_VCARD }, 5162 {"text/x-vcard", 0, DRAG_VCARD },
5447 {"text/uri-list", 0, DRAG_URI}, 5163 {"text/uri-list", 0, DRAG_URI},
5494 /******************************* Menu bar *************************************/ 5210 /******************************* Menu bar *************************************/
5495 actions = pidgin_action_group_new(); 5211 actions = pidgin_action_group_new();
5496 gtk_widget_insert_action_group(gtkblist->window, "blist", 5212 gtk_widget_insert_action_group(gtkblist->window, "blist",
5497 G_ACTION_GROUP(actions)); 5213 G_ACTION_GROUP(actions));
5498 5214
5499 action_group = gtk_action_group_new("BListActions");
5500 gtk_action_group_set_translation_domain(action_group, PACKAGE);
5501 gtk_action_group_add_actions(action_group,
5502 blist_menu_entries,
5503 G_N_ELEMENTS(blist_menu_entries),
5504 GTK_WINDOW(gtkblist->window));
5505
5506 gtkblist->ui = gtk_ui_manager_new();
5507 gtk_ui_manager_insert_action_group(gtkblist->ui, action_group, 0);
5508
5509 accel_group = gtk_ui_manager_get_accel_group(gtkblist->ui);
5510 gtk_window_add_accel_group(GTK_WINDOW(gtkblist->window), accel_group);
5511 pidgin_load_accels();
5512 g_signal_connect(G_OBJECT(accel_group), "accel-changed", G_CALLBACK(pidgin_save_accels_cb), NULL);
5513
5514 error = NULL;
5515 if (!gtk_ui_manager_add_ui_from_string(gtkblist->ui, blist_menu, -1, &error))
5516 {
5517 g_message("building menus failed: %s", error->message);
5518 g_error_free(error);
5519 exit(EXIT_FAILURE);
5520 }
5521
5522 menu = gtk_ui_manager_get_widget(gtkblist->ui, "/BList");
5523 gtk_widget_show(menu);
5524 gtk_box_pack_start(GTK_BOX(gtkblist->main_vbox), menu, FALSE, FALSE, 0);
5525
5526 gtkblist->menu = pidgin_buddy_list_menu_new(); 5215 gtkblist->menu = pidgin_buddy_list_menu_new();
5527 gtk_box_pack_start(GTK_BOX(gtkblist->main_vbox), gtkblist->menu, FALSE, 5216 gtk_box_pack_start(GTK_BOX(gtkblist->main_vbox), gtkblist->menu, FALSE,
5528 FALSE, 0); 5217 FALSE, 0);
5529 5218
5530 gtkblist->menutray = pidgin_buddy_list_menu_get_menu_tray(gtkblist->menu); 5219 gtkblist->menutray = pidgin_buddy_list_menu_get_menu_tray(PIDGIN_BUDDY_LIST_MENU(gtkblist->menu));
5531 5220
5532 /****************************** Notebook *************************************/ 5221 /****************************** Notebook *************************************/
5533 gtkblist->notebook = gtk_notebook_new(); 5222 gtkblist->notebook = gtk_notebook_new();
5534 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkblist->notebook), FALSE); 5223 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkblist->notebook), FALSE);
5535 gtk_notebook_set_show_border(GTK_NOTEBOOK(gtkblist->notebook), FALSE); 5224 gtk_notebook_set_show_border(GTK_NOTEBOOK(gtkblist->notebook), FALSE);
7212 gtkblist->drag_timeout = 0; 6901 gtkblist->drag_timeout = 0;
7213 } 6902 }
7214 6903
7215 gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL; 6904 gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL;
7216 g_clear_object(&gtkblist->treemodel); 6905 g_clear_object(&gtkblist->treemodel);
7217 g_object_unref(G_OBJECT(gtkblist->ui));
7218 g_object_unref(G_OBJECT(gtkblist->empty_avatar)); 6906 g_object_unref(G_OBJECT(gtkblist->empty_avatar));
7219 6907
7220 g_clear_object(&priv->current_theme); 6908 g_clear_object(&priv->current_theme);
7221 if (priv->select_notebook_page_timeout) { 6909 if (priv->select_notebook_page_timeout) {
7222 g_source_remove(priv->select_notebook_page_timeout); 6910 g_source_remove(priv->select_notebook_page_timeout);
7570 { 7258 {
7571 GtkWidget *sort_item = NULL; 7259 GtkWidget *sort_item = NULL;
7572 GMenu *menu = NULL; 7260 GMenu *menu = NULL;
7573 GList *l; 7261 GList *l;
7574 7262
7575 if ((gtkblist == NULL) || (gtkblist->ui == NULL)) 7263 if(gtkblist == NULL)
7576 return; 7264 return;
7577 7265
7578 /* create the gmenu */ 7266 /* create the gmenu */
7579 menu = g_menu_new(); 7267 menu = g_menu_new();
7580 7268

mercurial