comparison pidgin/gtkprefs.c @ 27666:a08e84032814

merge of '2348ff22f0ff3453774b8b25b36238465580c609' and 'e76f11543c2a4aa05bdf584f087cbe3439029661'
author Paul Aurich <paul@darkrain42.org>
date Sun, 12 Jul 2009 05:43:38 +0000
parents 5b07c7253ba4
children 85fa979b08c2 da33da2e1a1e
comparison
equal deleted inserted replaced
27186:048bcf41deef 27666:a08e84032814
26 */ 26 */
27 #include "internal.h" 27 #include "internal.h"
28 #include "pidgin.h" 28 #include "pidgin.h"
29 29
30 #include "debug.h" 30 #include "debug.h"
31 #include "nat-pmp.h"
31 #include "notify.h" 32 #include "notify.h"
32 #include "prefs.h" 33 #include "prefs.h"
33 #include "proxy.h" 34 #include "proxy.h"
34 #include "prpl.h" 35 #include "prpl.h"
35 #include "request.h" 36 #include "request.h"
36 #include "savedstatuses.h" 37 #include "savedstatuses.h"
37 #include "sound.h" 38 #include "sound.h"
38 #include "sound-theme.h" 39 #include "sound-theme.h"
40 #include "stun.h"
39 #include "theme-manager.h" 41 #include "theme-manager.h"
42 #include "upnp.h"
40 #include "util.h" 43 #include "util.h"
41 #include "network.h" 44 #include "network.h"
42 45
43 #include "gtkblist.h" 46 #include "gtkblist.h"
44 #include "gtkconv.h" 47 #include "gtkconv.h"
59 #define PROXYUSER 2 62 #define PROXYUSER 2
60 #define PROXYPASS 3 63 #define PROXYPASS 3
61 64
62 #define PREFS_OPTIMAL_ICON_SIZE 32 65 #define PREFS_OPTIMAL_ICON_SIZE 32
63 66
67 struct theme_info {
68 gchar *type;
69 gchar *extension;
70 gchar *original_name;
71 };
72
64 static int sound_row_sel = 0; 73 static int sound_row_sel = 0;
65 static GtkWidget *prefsnotebook; 74 static GtkWidget *prefsnotebook;
66 75
67 static GtkWidget *sound_entry = NULL; 76 static GtkWidget *sound_entry = NULL;
68 static GtkListStore *smiley_theme_store = NULL; 77 static GtkListStore *smiley_theme_store = NULL;
72 static GtkWidget *prefs = NULL; 81 static GtkWidget *prefs = NULL;
73 static GtkWidget *debugbutton = NULL; 82 static GtkWidget *debugbutton = NULL;
74 static int notebook_page = 0; 83 static int notebook_page = 0;
75 static GtkTreeRowReference *previous_smiley_row = NULL; 84 static GtkTreeRowReference *previous_smiley_row = NULL;
76 85
77 static gboolean prefs_themes_unsorted = TRUE;
78 static GtkListStore *prefs_sound_themes; 86 static GtkListStore *prefs_sound_themes;
79 static GtkListStore *prefs_blist_themes; 87 static GtkListStore *prefs_blist_themes;
80 static GtkListStore *prefs_status_icon_themes; 88 static GtkListStore *prefs_status_icon_themes;
81 89
90 static GtkWidget *prefs_sound_themes_combo_box;
91 static GtkWidget *prefs_blist_themes_combo_box;
92 static GtkWidget *prefs_status_themes_combo_box;
82 93
83 /* 94 /*
84 * PROTOTYPES 95 * PROTOTYPES
85 */ 96 */
86 static void delete_prefs(GtkWidget *, void *); 97 static void delete_prefs(GtkWidget *, void *);
104 GtkObject *adjust; 115 GtkObject *adjust;
105 int val; 116 int val;
106 117
107 val = purple_prefs_get_int(key); 118 val = purple_prefs_get_int(key);
108 119
109 adjust = gtk_adjustment_new(val, min, max, 1, 1, 1); 120 adjust = gtk_adjustment_new(val, min, max, 1, 1, 0);
110 spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0); 121 spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
111 g_object_set_data(G_OBJECT(spin), "val", (char *)key); 122 g_object_set_data(G_OBJECT(spin), "val", (char *)key);
112 if (max < 10000) 123 if (max < 10000)
113 gtk_widget_set_size_request(spin, 50, -1); 124 gtk_widget_set_size_request(spin, 50, -1);
114 else 125 else
119 130
120 return pidgin_add_widget_to_vbox(GTK_BOX(box), title, sg, spin, FALSE, NULL); 131 return pidgin_add_widget_to_vbox(GTK_BOX(box), title, sg, spin, FALSE, NULL);
121 } 132 }
122 133
123 static void 134 static void
124 entry_set(GtkEntry *entry, gpointer data) { 135 entry_set(GtkEntry *entry, gpointer data)
136 {
125 const char *key = (const char*)data; 137 const char *key = (const char*)data;
126 138
127 purple_prefs_set_string(key, gtk_entry_get_text(entry)); 139 purple_prefs_set_string(key, gtk_entry_get_text(entry));
128 } 140 }
129 141
331 gtk_tree_row_reference_free(previous_smiley_row); 343 gtk_tree_row_reference_free(previous_smiley_row);
332 previous_smiley_row = NULL; 344 previous_smiley_row = NULL;
333 345
334 } 346 }
335 347
336 static void smiley_sel(GtkTreeSelection *sel, GtkTreeModel *model) { 348 static void
349 smiley_sel(GtkTreeSelection *sel, GtkTreeModel *model)
350 {
337 GtkTreeIter iter; 351 GtkTreeIter iter;
338 const char *themename; 352 const char *themename;
339 char *description; 353 char *description;
340 GValue val; 354 GValue val;
341 GtkTreePath *path, *oldpath; 355 GtkTreePath *path, *oldpath;
382 gtk_tree_row_reference_free(previous_smiley_row); 396 gtk_tree_row_reference_free(previous_smiley_row);
383 previous_smiley_row = gtk_tree_row_reference_new(model, path); 397 previous_smiley_row = gtk_tree_row_reference_new(model, path);
384 gtk_tree_path_free(path); 398 gtk_tree_path_free(path);
385 } 399 }
386 400
387 static GtkTreeRowReference *theme_refresh_theme_list(void) 401 static GtkTreeRowReference *
402 theme_refresh_theme_list(void)
388 { 403 {
389 GdkPixbuf *pixbuf; 404 GdkPixbuf *pixbuf;
390 GSList *themes; 405 GSList *themes;
391 GtkTreeIter iter; 406 GtkTreeIter iter;
392 GtkTreeRowReference *row_ref = NULL; 407 GtkTreeRowReference *row_ref = NULL;
440 } 455 }
441 456
442 return row_ref; 457 return row_ref;
443 } 458 }
444 459
445 static void theme_install_theme(char *path, char *extn) { 460 /* Rebuild the markup for the sound theme selection for "(Custom)" themes */
461 static void
462 pref_sound_generate_markup(void)
463 {
464 gboolean print_custom, customized;
465 const gchar *name, *author, *description, *current_theme;
466 gchar *markup;
467 PurpleSoundTheme *theme;
468 GtkTreeIter iter;
469
470 customized = pidgin_sound_is_customized();
471 current_theme = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme");
472
473 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs_sound_themes), &iter)) {
474 do {
475 gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &iter, 2, &name, -1);
476
477 print_custom = customized && g_str_equal(current_theme, name);
478
479 if (!name || *name == '\0')
480 markup = g_strdup_printf("<b>(Default)</b>%s%s - None\n<span foreground='dim grey'>The default Pidgin sound theme</span>",
481 print_custom ? " " : "", print_custom ? "(Custom)" : "");
482 else {
483 theme = PURPLE_SOUND_THEME(purple_theme_manager_find_theme(name, "sound"));
484 author = purple_theme_get_author(PURPLE_THEME(theme));
485 description = purple_theme_get_description(PURPLE_THEME(theme));
486
487 markup = g_strdup_printf("<b>%s</b>%s%s%s%s\n<span foreground='dim grey'>%s</span>",
488 name, print_custom ? " " : "", print_custom ? "(Custom)" : "",
489 author != NULL ? " - " : "", author != NULL ? author : "", description != NULL ? description : "");
490 }
491
492 gtk_list_store_set(prefs_sound_themes, &iter, 1, markup, -1);
493
494 g_free(markup);
495
496 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(prefs_sound_themes), &iter));
497 }
498 }
499
500 /* adds the themes to the theme list from the manager so they can be displayed in prefs */
501 static void
502 prefs_themes_sort(PurpleTheme *theme)
503 {
504 GdkPixbuf *pixbuf = NULL;
505 GtkTreeIter iter;
506 gchar *image_full = NULL, *markup;
507 const gchar *name, *author, *description;
508
509 if (PURPLE_IS_SOUND_THEME(theme)){
510
511 image_full = purple_theme_get_image_full(theme);
512 if (image_full != NULL){
513 pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
514 g_free(image_full);
515 } else pixbuf = NULL;
516
517 gtk_list_store_append(prefs_sound_themes, &iter);
518 gtk_list_store_set(prefs_sound_themes, &iter, 0, pixbuf, 2, purple_theme_get_name(theme), -1);
519
520 if (pixbuf != NULL)
521 g_object_unref(G_OBJECT(pixbuf));
522
523 } else if (PIDGIN_IS_BLIST_THEME(theme) || PIDGIN_IS_STATUS_ICON_THEME(theme)){
524 GtkListStore *store;
525
526 if (PIDGIN_IS_BLIST_THEME(theme))
527 store = prefs_blist_themes;
528 else store = prefs_status_icon_themes;
529
530 image_full = purple_theme_get_image_full(theme);
531 if (image_full != NULL){
532 pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
533 g_free(image_full);
534 } else pixbuf = NULL;
535
536 name = purple_theme_get_name(theme);
537 author = purple_theme_get_author(theme);
538 description = purple_theme_get_description(theme);
539
540 markup = g_strdup_printf("<b>%s</b>%s%s\n<span foreground='dim grey'>%s</span>", name, author != NULL ? " - " : "",
541 author != NULL ? author : "", description != NULL ? description : "");
542
543 gtk_list_store_append(store, &iter);
544 gtk_list_store_set(store, &iter, 0, pixbuf, 1, markup, 2, name, -1);
545
546 g_free(markup);
547 if (pixbuf != NULL)
548 g_object_unref(G_OBJECT(pixbuf));
549 }
550 }
551
552 static void
553 prefs_set_active_theme_combo(GtkWidget *combo_box, GtkListStore *store, const gchar *current_theme)
554 {
555 GtkTreeIter iter;
556 gchar *theme = NULL;
557 gboolean unset = TRUE;
558
559 if (current_theme && *current_theme && gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
560 do {
561 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &theme, -1);
562
563 if (g_str_equal(current_theme, theme)) {
564 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter);
565 unset = FALSE;
566 }
567
568 g_free(theme);
569 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
570 }
571
572 if (unset)
573 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0);
574 }
575
576 static void
577 prefs_themes_refresh(void)
578 {
579 GdkPixbuf *pixbuf = NULL;
580 gchar *filename;
581 GtkTreeIter iter;
582
583 /* refresh the list of themes in the manager */
584 purple_theme_manager_refresh();
585
586 filename = g_build_filename(DATADIR, "icons", "hicolor", "32x32", "apps", "pidgin.png", NULL);
587 pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
588 g_free(filename);
589
590 /* sound themes */
591 gtk_list_store_clear(prefs_sound_themes);
592 gtk_list_store_append(prefs_sound_themes, &iter);
593 gtk_list_store_set(prefs_sound_themes, &iter, 0, pixbuf, 2, "", -1);
594
595 /* blist themes */
596 gtk_list_store_clear(prefs_blist_themes);
597 gtk_list_store_append(prefs_blist_themes, &iter);
598 gtk_list_store_set(prefs_blist_themes, &iter, 0, pixbuf, 1,
599 "<b>(Default)</b> - None\n<span color='dim grey'>"
600 "The default Pidgin buddy list theme</span>", 2, "", -1);
601
602 /* status icon themes */
603 gtk_list_store_clear(prefs_status_icon_themes);
604 gtk_list_store_append(prefs_status_icon_themes, &iter);
605 gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1,
606 "<b>(Default)</b> - None\n<span color='dim grey'>"
607 "The default Pidgin status icon theme</span>", 2, "", -1);
608 g_object_unref(G_OBJECT(pixbuf));
609
610 purple_theme_manager_for_each_theme(prefs_themes_sort);
611 pref_sound_generate_markup();
612
613 /* set active */
614 prefs_set_active_theme_combo(prefs_sound_themes_combo_box, prefs_sound_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme"));
615 prefs_set_active_theme_combo(prefs_blist_themes_combo_box, prefs_blist_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"));
616 prefs_set_active_theme_combo(prefs_status_themes_combo_box, prefs_status_icon_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"));
617 }
618
619 /* init all the theme variables so that the themes can be sorted later and used by pref pages */
620 static void
621 prefs_themes_init(void)
622 {
623 prefs_sound_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
624
625 prefs_blist_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
626
627 prefs_status_icon_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
628 }
629
630 static PurpleTheme *
631 prefs_theme_find_theme(const gchar *path, const gchar *type)
632 {
633 PurpleTheme *theme = purple_theme_manager_load_theme(path, type);
634 GDir *dir = g_dir_open(path, 0, NULL);
635 const gchar *next;
636
637 while (!PURPLE_IS_THEME(theme) && (next = g_dir_read_name(dir))) {
638 gchar *next_path = g_build_filename(path, next, NULL);
639
640 if (g_file_test(next_path, G_FILE_TEST_IS_DIR))
641 theme = prefs_theme_find_theme(next_path, type);
642
643 g_free(next_path);
644 }
645
646 g_dir_close(dir);
647
648 return theme;
649 }
650
651 /* Eww. Seriously ewww. But thanks, grim! This is taken from guifications2 */
652 static gboolean
653 purple_theme_file_copy(const gchar *source, const gchar *destination)
654 {
655 FILE *src, *dest;
656 gint chr = EOF;
657
658 if(!(src = g_fopen(source, "rb")))
659 return FALSE;
660 if(!(dest = g_fopen(destination, "wb"))) {
661 fclose(src);
662 return FALSE;
663 }
664
665 while((chr = fgetc(src)) != EOF) {
666 fputc(chr, dest);
667 }
668
669 fclose(dest);
670 fclose(src);
671
672 return TRUE;
673 }
674
675 /* installs a theme, info is freed by function */
676 static void
677 theme_install_theme(char *path, struct theme_info *info)
678 {
446 #ifndef _WIN32 679 #ifndef _WIN32
447 gchar *command; 680 gchar *command;
448 #endif 681 #endif
449 gchar *destdir; 682 gchar *destdir, *tail, *type, *original_name;
450 gchar *tail;
451 GtkTreeRowReference *theme_rowref; 683 GtkTreeRowReference *theme_rowref;
684 gboolean is_smiley_theme, is_archive;
685 PurpleTheme *theme = NULL;
686
687 if (info == NULL)
688 return;
689
690 original_name = info->original_name;
691 type = info->type;
692
693 /* check the extension */
694 tail = info->extension ? info->extension : g_strdup(strrchr(path, '.'));
695
696 if (!tail) {
697 g_free(type);
698 g_free(original_name);
699 g_free(info);
700 return;
701 } else g_free(info);
702
703 is_archive = !g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz");
704
705 g_free(tail);
452 706
453 /* Just to be safe */ 707 /* Just to be safe */
454 g_strchomp(path); 708 g_strchomp(path);
455 709
456 /* I dont know what you are, get out of here */ 710 if ((is_smiley_theme = g_str_equal(type, "smiley")))
457 if (extn != NULL) 711 destdir = g_build_filename(purple_user_dir(), "smileys", NULL);
458 tail = extn; 712 else destdir = g_build_filename(purple_user_dir(), "themes", "temp", NULL);
459 else if ((tail = strrchr(path, '.')) == NULL)
460 return;
461
462 destdir = g_strconcat(purple_user_dir(), G_DIR_SEPARATOR_S "smileys", NULL);
463 713
464 /* We'll check this just to make sure. This also lets us do something different on 714 /* We'll check this just to make sure. This also lets us do something different on
465 * other platforms, if need be */ 715 * other platforms, if need be */
466 if (!g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz")) { 716 if (is_archive) {
467 #ifndef _WIN32 717 #ifndef _WIN32
468 gchar *path_escaped = g_shell_quote(path); 718 gchar *path_escaped = g_shell_quote(path);
469 gchar *destdir_escaped = g_shell_quote(destdir); 719 gchar *destdir_escaped = g_shell_quote(destdir);
720
721 if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
722 purple_build_dir(destdir, S_IRUSR | S_IWUSR | S_IXUSR);
723
470 command = g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped, destdir_escaped); 724 command = g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped, destdir_escaped);
471 g_free(path_escaped); 725 g_free(path_escaped);
472 g_free(destdir_escaped); 726 g_free(destdir_escaped);
727
728 /* Fire! */
729 if (system(command)) {
730 purple_notify_error(NULL, NULL, _("Theme failed to unpack."), NULL);
731 g_free(command);
732 g_free(destdir);
733 g_free(type);
734 g_free(original_name);
735 return;
736 }
473 #else 737 #else
474 if(!winpidgin_gz_untar(path, destdir)) { 738 if(!winpidgin_gz_untar(path, destdir)) {
475 g_free(destdir); 739 g_free(destdir);
740 g_free(type);
741 g_free(original_name);
476 return; 742 return;
477 } 743 }
478 #endif 744 #endif
479 } 745 }
480 else { 746
481 g_free(destdir); 747 if (is_smiley_theme) {
482 return; 748 /* just extract the folder to the smiley directory */
483 } 749 theme_rowref = theme_refresh_theme_list();
484 750
485 #ifndef _WIN32 751 if (theme_rowref != NULL) {
486 /* Fire! */ 752 GtkTreePath *tp = gtk_tree_row_reference_get_path(theme_rowref);
487 if (system(command)) 753
488 { 754 if (tp)
489 purple_notify_error(NULL, NULL, _("Smiley theme failed to unpack."), NULL); 755 gtk_tree_selection_select_path(smiley_theme_sel, tp);
490 } 756
491 757 gtk_tree_row_reference_free(theme_rowref);
492 g_free(command); 758 }
493 #endif 759
760 } else if (is_archive) {
761 theme = prefs_theme_find_theme(destdir, type);
762
763 if (PURPLE_IS_THEME(theme)) {
764 /* create the location for the theme */
765 gchar *theme_dest = g_build_filename(purple_user_dir(), "themes",
766 purple_theme_get_name(theme),
767 "purple", type, NULL);
768
769 if (!g_file_test(theme_dest, G_FILE_TEST_IS_DIR))
770 purple_build_dir(theme_dest, S_IRUSR | S_IWUSR | S_IXUSR);
771
772 g_free(theme_dest);
773 theme_dest = g_build_filename(purple_user_dir(), "themes",
774 purple_theme_get_name(theme),
775 "purple", type, NULL);
776
777 /* move the entire directory to new location */
778 g_rename(purple_theme_get_dir(theme), theme_dest);
779
780 g_free(theme_dest);
781 g_remove(destdir);
782 g_object_unref(theme);
783
784 prefs_themes_refresh();
785
786 } else {
787 /* something was wrong with the theme archive */
788 g_unlink(destdir);
789 purple_notify_error(NULL, NULL, _("Theme failed to load."), NULL);
790 }
791
792 } else { /* just a single file so copy it to a new temp directory and attempt to load it*/
793 gchar *temp_path, *temp_file;
794
795 temp_path = g_build_filename(purple_user_dir(), "themes", "temp", "sub_folder", NULL);
796
797 if (original_name != NULL) {
798 /* name was changed from the original (probably a dnd) change it back before loading */
799 temp_file = g_build_filename(temp_path, original_name, NULL);
800
801 } else {
802 gchar *source_name = g_path_get_basename(path);
803 temp_file = g_build_filename(temp_path, source_name, NULL);
804 g_free(source_name);
805 }
806
807 if (!g_file_test(temp_path, G_FILE_TEST_IS_DIR))
808 purple_build_dir(temp_path, S_IRUSR | S_IWUSR | S_IXUSR);
809
810 if (purple_theme_file_copy(path, temp_file)) {
811 /* find the theme, could be in subfolder */
812 theme = prefs_theme_find_theme(temp_path, type);
813
814 if (PURPLE_IS_THEME(theme)) {
815 gchar *theme_dest = g_build_filename(purple_user_dir(), "themes",
816 purple_theme_get_name(theme),
817 "purple", type, NULL);
818
819 if(!g_file_test(theme_dest, G_FILE_TEST_IS_DIR))
820 purple_build_dir(theme_dest, S_IRUSR | S_IWUSR | S_IXUSR);
821
822 g_rename(purple_theme_get_dir(theme), theme_dest);
823
824 g_free(theme_dest);
825 g_object_unref(theme);
826
827 prefs_themes_refresh();
828 } else {
829 g_remove(temp_path);
830 purple_notify_error(NULL, NULL, _("Theme failed to load."), NULL);
831 }
832 } else {
833 purple_notify_error(NULL, NULL, _("Theme failed to copy."), NULL);
834 }
835
836 g_free(temp_file);
837 g_free(temp_path);
838 }
839
840 g_free(type);
841 g_free(original_name);
494 g_free(destdir); 842 g_free(destdir);
495
496 theme_rowref = theme_refresh_theme_list();
497 if (theme_rowref != NULL) {
498 GtkTreePath *tp = gtk_tree_row_reference_get_path(theme_rowref);
499
500 if (tp)
501 gtk_tree_selection_select_path(smiley_theme_sel, tp);
502 gtk_tree_row_reference_free(theme_rowref);
503 }
504 } 843 }
505 844
506 static void 845 static void
507 theme_got_url(PurpleUtilFetchUrlData *url_data, gpointer user_data, 846 theme_got_url(PurpleUtilFetchUrlData *url_data, gpointer user_data,
508 const gchar *themedata, size_t len, const gchar *error_message) 847 const gchar *themedata, size_t len, const gchar *error_message)
531 g_free(path); 870 g_free(path);
532 } 871 }
533 872
534 static void 873 static void
535 theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, 874 theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y,
536 GtkSelectionData *sd, guint info, guint t, gpointer data) 875 GtkSelectionData *sd, guint info, guint t, gpointer user_data)
537 { 876 {
538 gchar *name = (gchar *)sd->data; 877 gchar *name = g_strchomp((gchar *)sd->data);
539 878
540 if ((sd->length >= 0) && (sd->format == 8)) { 879 if ((sd->length >= 0) && (sd->format == 8)) {
541 /* Well, it looks like the drag event was cool. 880 /* Well, it looks like the drag event was cool.
542 * Let's do something with it */ 881 * Let's do something with it */
882 gchar *temp;
883 struct theme_info *info = g_new0(struct theme_info, 1);
884 info->type = g_strdup((gchar *)user_data);
885 info->extension = g_strdup(g_strrstr(name,"."));
886 temp = g_strrstr(name, "/");
887 info->original_name = temp ? g_strdup(++temp) : NULL;
543 888
544 if (!g_ascii_strncasecmp(name, "file://", 7)) { 889 if (!g_ascii_strncasecmp(name, "file://", 7)) {
545 GError *converr = NULL; 890 GError *converr = NULL;
546 gchar *tmp; 891 gchar *tmp;
547 /* It looks like we're dealing with a local file. Let's 892 /* It looks like we're dealing with a local file. Let's
550 purple_debug(PURPLE_DEBUG_ERROR, "theme dnd", "%s\n", 895 purple_debug(PURPLE_DEBUG_ERROR, "theme dnd", "%s\n",
551 (converr ? converr->message : 896 (converr ? converr->message :
552 "g_filename_from_uri error")); 897 "g_filename_from_uri error"));
553 return; 898 return;
554 } 899 }
555 theme_install_theme(tmp, NULL); 900 theme_install_theme(tmp, info);
556 g_free(tmp); 901 g_free(tmp);
557 } else if (!g_ascii_strncasecmp(name, "http://", 7)) { 902 } else if (!g_ascii_strncasecmp(name, "http://", 7)) {
558 /* Oo, a web drag and drop. This is where things 903 /* Oo, a web drag and drop. This is where things
559 * will start to get interesting */ 904 * will start to get interesting */
560 purple_util_fetch_url(name, TRUE, NULL, FALSE, theme_got_url, ".tgz"); 905 purple_util_fetch_url(name, TRUE, NULL, FALSE, theme_got_url, info);
561 } else if (!g_ascii_strncasecmp(name, "https://", 8)) { 906 } else if (!g_ascii_strncasecmp(name, "https://", 8)) {
562 /* purple_util_fetch_url() doesn't support HTTPS, but we want users 907 /* purple_util_fetch_url() doesn't support HTTPS, but we want users
563 * to be able to drag and drop links from the SF trackers, so 908 * to be able to drag and drop links from the SF trackers, so
564 * we'll try it as an HTTP URL. */ 909 * we'll try it as an HTTP URL. */
565 char *tmp = g_strdup(name + 1); 910 char *tmp = g_strdup(name + 1);
566 tmp[0] = 'h'; 911 tmp[0] = 'h';
567 tmp[1] = 't'; 912 tmp[1] = 't';
568 tmp[2] = 't'; 913 tmp[2] = 't';
569 tmp[3] = 'p'; 914 tmp[3] = 'p';
570 purple_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, ".tgz"); 915
916 purple_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, info);
571 g_free(tmp); 917 g_free(tmp);
572 } 918 }
573 919
574 gtk_drag_finish(dc, TRUE, FALSE, t); 920 gtk_drag_finish(dc, TRUE, FALSE, t);
575 } 921 }
576 922
577 gtk_drag_finish(dc, FALSE, FALSE, t); 923 gtk_drag_finish(dc, FALSE, FALSE, t);
578 } 924 }
579 925
580 /* Rebuild the markup for the sound theme selection for "(Custom)" themes */
581 static void
582 pref_sound_generate_markup()
583 {
584 gboolean print_custom, customized;
585 const gchar *name, *author, *description, *current_theme;
586 gchar *markup;
587 PurpleSoundTheme *theme;
588 GtkTreeIter iter;
589
590 customized = pidgin_sound_is_customized();
591 current_theme = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme");
592
593 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs_sound_themes), &iter)) {
594 do {
595 gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &iter, 2, &name, -1);
596
597 print_custom = customized && g_str_equal(current_theme, name);
598
599 if (g_str_equal(name, ""))
600 markup = g_strdup_printf("<b>(Default)</b>%s%s - None\n<span foreground='dim grey'>The default Pidgin sound theme</span>",
601 print_custom ? " " : "", print_custom ? "(Custom)" : "");
602 else {
603 theme = PURPLE_SOUND_THEME(purple_theme_manager_find_theme(name, "sound"));
604 author = purple_theme_get_author(PURPLE_THEME(theme));
605 description = purple_theme_get_description(PURPLE_THEME(theme));
606
607 markup = g_strdup_printf("<b>%s</b>%s%s%s%s\n<span foreground='dim grey'>%s</span>",
608 name, print_custom ? " " : "", print_custom ? "(Custom)" : "",
609 author != NULL ? " - " : "", author != NULL ? author : "", description != NULL ? description : "");
610 }
611
612 gtk_list_store_set(prefs_sound_themes, &iter, 1, markup, -1);
613
614 g_free(markup);
615
616 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(prefs_sound_themes), &iter));
617 }
618 }
619
620 /* adds the themes to the theme list from the manager so they can be sisplayed in prefs */
621 static void
622 prefs_themes_sort(PurpleTheme *theme)
623 {
624 GdkPixbuf *pixbuf = NULL;
625 GtkTreeIter iter;
626 gchar *image_full = NULL, *markup;
627 const gchar *name, *author, *description;
628
629 if (PURPLE_IS_SOUND_THEME(theme)){
630
631 image_full = purple_theme_get_image_full(theme);
632 if (image_full != NULL){
633 pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
634 g_free(image_full);
635 } else pixbuf = NULL;
636
637 gtk_list_store_append(prefs_sound_themes, &iter);
638 gtk_list_store_set(prefs_sound_themes, &iter, 0, pixbuf, 2, purple_theme_get_name(theme), -1);
639
640 if (pixbuf != NULL)
641 g_object_unref(G_OBJECT(pixbuf));
642
643 } else if (PIDGIN_IS_BLIST_THEME(theme) || PIDGIN_IS_STATUS_ICON_THEME(theme)){
644 GtkListStore *store;
645
646 if (PIDGIN_IS_BLIST_THEME(theme))
647 store = prefs_blist_themes;
648 else store = prefs_status_icon_themes;
649
650 image_full = purple_theme_get_image_full(theme);
651 if (image_full != NULL){
652 pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
653 g_free(image_full);
654 } else pixbuf = NULL;
655
656 name = purple_theme_get_name(theme);
657 author = purple_theme_get_author(theme);
658 description = purple_theme_get_description(theme);
659
660 markup = g_strdup_printf("<b>%s</b>%s%s\n<span foreground='dim grey'>%s</span>", name, author != NULL ? " - " : "",
661 author != NULL ? author : "", description != NULL ? description : "");
662
663 gtk_list_store_append(store, &iter);
664 gtk_list_store_set(store, &iter, 0, pixbuf, 1, markup, 2, name, -1);
665
666 g_free(markup);
667 if (pixbuf != NULL)
668 g_object_unref(G_OBJECT(pixbuf));
669 }
670
671 }
672
673 /* init all the theme variables so that the themes can be sorted later and used by pref pages */
674 static void
675 prefs_themes_init()
676 {
677 GdkPixbuf *pixbuf = NULL;
678 gchar *filename;
679 GtkTreeIter iter;
680
681 filename = g_build_filename(DATADIR, "icons", "hicolor", "32x32", "apps", "pidgin.png", NULL);
682 pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
683 g_free(filename);
684
685 /* sound themes */
686 prefs_sound_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
687
688 gtk_list_store_append(prefs_sound_themes, &iter);
689 gtk_list_store_set(prefs_sound_themes, &iter, 0, pixbuf, 2, "", -1);
690
691 /* blist themes */
692 prefs_blist_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
693
694 gtk_list_store_append(prefs_blist_themes, &iter);
695 gtk_list_store_set(prefs_blist_themes, &iter, 0, pixbuf, 1, "<b>(Default)</b> - None\n<span color='dim grey'>"
696 "The default Pidgin buddy list theme</span>", 2, "", -1);
697
698 /* status icon themes */
699 prefs_status_icon_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
700
701 gtk_list_store_append(prefs_status_icon_themes, &iter);
702 gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1, "<b>(Default)</b> - None\n<span color='dim grey'>"
703 "The default Pidgin status icon theme</span>", 2, "", -1);
704
705 g_object_unref(G_OBJECT(pixbuf));
706 }
707
708 /* builds a theme combo box from a list store with colums: icon preview, markup, theme name */ 926 /* builds a theme combo box from a list store with colums: icon preview, markup, theme name */
709 static GtkWidget * 927 static GtkWidget *
710 prefs_build_theme_combo_box(GtkListStore *store, const gchar *current_theme) 928 prefs_build_theme_combo_box(GtkListStore *store, const gchar *current_theme, gchar *type)
711 { 929 {
930 GtkCellRenderer *cell_rend;
712 GtkWidget *combo_box; 931 GtkWidget *combo_box;
713 GtkCellRenderer *cell_rend; 932 GtkTargetEntry te[3] = {{"text/plain", 0, 0},{"text/uri-list", 0, 1},{"STRING", 0, 2}};
714 GtkTreeIter iter;
715 gchar *theme = NULL;
716 gboolean unset = TRUE;
717 933
718 g_return_val_if_fail(store != NULL && current_theme != NULL, NULL); 934 g_return_val_if_fail(store != NULL && current_theme != NULL, NULL);
719 935
720 combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); 936 combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
721 937
729 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell_rend, "markup", 1, NULL); 945 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell_rend, "markup", 1, NULL);
730 /*#if GTK_CHECK_VERSION(2,6,0) 946 /*#if GTK_CHECK_VERSION(2,6,0)
731 g_object_set(cell_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL); 947 g_object_set(cell_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
732 #endif*/ 948 #endif*/
733 949
734 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { 950 gtk_drag_dest_set(combo_box, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te,
735 do { 951 sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE);
736 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &theme, -1); 952
737 953 g_signal_connect(G_OBJECT(combo_box), "drag_data_received", G_CALLBACK(theme_dnd_recv), type);
738 if (g_str_equal(current_theme, theme)) {
739 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter);
740 unset = FALSE;
741 }
742
743 g_free(theme);
744 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
745 }
746
747 if (unset)
748 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0);
749 954
750 return combo_box; 955 return combo_box;
751 } 956 }
752 957
753 /* sets the current sound theme */ 958 /* sets the current sound theme */
755 prefs_set_sound_theme_cb(GtkComboBox *combo_box, gpointer user_data) 960 prefs_set_sound_theme_cb(GtkComboBox *combo_box, gpointer user_data)
756 { 961 {
757 gint i; 962 gint i;
758 gchar *pref; 963 gchar *pref;
759 gchar *new_theme; 964 gchar *new_theme;
760 gboolean success;
761 GtkTreeIter new_iter; 965 GtkTreeIter new_iter;
762 966
763 success = gtk_combo_box_get_active_iter(combo_box, &new_iter); 967 if(gtk_combo_box_get_active_iter(combo_box, &new_iter)) {
764 g_return_if_fail(success); 968
765 969 gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &new_iter, 2, &new_theme, -1);
766 gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &new_iter, 2, &new_theme, -1); 970
767 971 purple_prefs_set_string(PIDGIN_PREFS_ROOT "/sound/theme", new_theme);
768 purple_prefs_set_string(PIDGIN_PREFS_ROOT "/sound/theme", new_theme); 972
769 973 /* New theme removes all customization */
770 /* New theme removes all customization */ 974 for(i=0; i < PURPLE_NUM_SOUNDS; i++){
771 for(i=0; i < PURPLE_NUM_SOUNDS; i++){ 975 pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
772 pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s", 976 pidgin_sound_get_event_option(i));
773 pidgin_sound_get_event_option(i)); 977 purple_prefs_set_path(pref, "");
774 purple_prefs_set_path(pref, ""); 978 g_free(pref);
775 g_free(pref); 979 }
776 } 980
777 981 /* gets rid of the "(Custom)" from the last selection */
778 /* gets rid of the "(Custom)" from the last selection */ 982 pref_sound_generate_markup();
779 pref_sound_generate_markup(); 983
780 984 gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)"));
781 gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)")); 985
782 986 g_free(new_theme);
783 g_free(new_theme); 987 }
784 } 988 }
989
785 990
786 /* Does same as normal sort, except "none" is sorted first */ 991 /* Does same as normal sort, except "none" is sorted first */
787 static gint pidgin_sort_smileys (GtkTreeModel *model, 992 static gint pidgin_sort_smileys (GtkTreeModel *model,
788 GtkTreeIter *a, 993 GtkTreeIter *a,
789 GtkTreeIter *b, 994 GtkTreeIter *b,
819 } 1024 }
820 1025
821 static void 1026 static void
822 request_theme_file_name_cb(gpointer data, char *theme_file_name) 1027 request_theme_file_name_cb(gpointer data, char *theme_file_name)
823 { 1028 {
824 theme_install_theme(theme_file_name, NULL) ; 1029 struct theme_info *info = g_new0(struct theme_info, 1);
825 } 1030 info->type = g_strdup("smiley");
826 1031 info->extension = NULL;
827 static void 1032 info->original_name = NULL;
828 add_theme_button_clicked_cb(GtkWidget *widget, gpointer null) 1033
829 { 1034 theme_install_theme(theme_file_name, info);
830 purple_request_file(NULL, _("Install Theme"), NULL, FALSE, (GCallback)request_theme_file_name_cb, NULL, NULL, NULL, NULL, NULL) ; 1035
1036 g_free(info);
1037 }
1038
1039 static void
1040 add_theme_button_clicked_cb(GtkWidget *widget, gpointer user_data)
1041 {
1042 purple_request_file(NULL, _("Install Theme"), NULL, FALSE, (GCallback)request_theme_file_name_cb, NULL, NULL, NULL, NULL, NULL);
831 } 1043 }
832 1044
833 static void 1045 static void
834 remove_theme_button_clicked_cb(GtkWidget *button, GtkTreeView *tv) 1046 remove_theme_button_clicked_cb(GtkWidget *button, GtkTreeView *tv)
835 { 1047 {
901 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(smiley_theme_store)); 1113 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(smiley_theme_store));
902 1114
903 gtk_drag_dest_set(view, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te, 1115 gtk_drag_dest_set(view, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te,
904 sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE); 1116 sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE);
905 1117
906 g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(theme_dnd_recv), smiley_theme_store); 1118 g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(theme_dnd_recv), "smiley");
907 1119
908 rend = gtk_cell_renderer_pixbuf_new(); 1120 rend = gtk_cell_renderer_pixbuf_new();
909 smiley_theme_sel = sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); 1121 smiley_theme_sel = sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
910 1122
911 /* Custom sort so "none" theme is at top of list */ 1123 /* Custom sort so "none" theme is at top of list */
1161 1373
1162 /* sets the current buddy list theme */ 1374 /* sets the current buddy list theme */
1163 static void 1375 static void
1164 prefs_set_blist_theme_cb(GtkComboBox *combo_box, gpointer user_data) 1376 prefs_set_blist_theme_cb(GtkComboBox *combo_box, gpointer user_data)
1165 { 1377 {
1166 PidginBlistTheme *theme = NULL; 1378 PidginBlistTheme *theme = NULL;
1167 GtkTreeIter iter; 1379 GtkTreeIter iter;
1168 gchar *name = NULL; 1380 gchar *name = NULL;
1169 1381
1170 g_return_if_fail(gtk_combo_box_get_active_iter(combo_box, &iter)); 1382 if(gtk_combo_box_get_active_iter(combo_box, &iter)) {
1171 gtk_tree_model_get(GTK_TREE_MODEL(prefs_blist_themes), &iter, 2, &name, -1); 1383
1172 1384 gtk_tree_model_get(GTK_TREE_MODEL(prefs_blist_themes), &iter, 2, &name, -1);
1173 if (name && *name) 1385
1174 theme = PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(name, "blist")); 1386 if(!name || !g_str_equal(name, ""))
1175 g_free(name); 1387 theme = PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(name, "blist"));
1176 1388
1177 pidgin_blist_set_theme(theme); 1389 g_free(name);
1390
1391 pidgin_blist_set_theme(theme);
1392 }
1178 } 1393 }
1179 1394
1180 /* sets the current icon theme */ 1395 /* sets the current icon theme */
1181 static void 1396 static void
1182 prefs_set_status_icon_theme_cb(GtkComboBox *combo_box, gpointer user_data) 1397 prefs_set_status_icon_theme_cb(GtkComboBox *combo_box, gpointer user_data)
1183 { 1398 {
1184 PidginStatusIconTheme *theme; 1399 PidginStatusIconTheme *theme = NULL;
1185 GtkTreeIter iter; 1400 GtkTreeIter iter;
1186 gchar *name = NULL; 1401 gchar *name = NULL;
1187 1402
1188 g_return_if_fail(gtk_combo_box_get_active_iter(combo_box, &iter)); 1403 if(gtk_combo_box_get_active_iter(combo_box, &iter)) {
1189 gtk_tree_model_get(GTK_TREE_MODEL(prefs_status_icon_themes), &iter, 2, &name, -1); 1404
1190 1405 gtk_tree_model_get(GTK_TREE_MODEL(prefs_status_icon_themes), &iter, 2, &name, -1);
1191 theme = PIDGIN_STATUS_ICON_THEME(purple_theme_manager_find_theme(name, "status-icon")); 1406
1192 g_free(name); 1407 if(!name || !g_str_equal(name, ""))
1193 1408 theme = PIDGIN_STATUS_ICON_THEME(purple_theme_manager_find_theme(name, "status-icon"));
1194 pidgin_stock_load_status_icon_theme(theme); 1409
1410 g_free(name);
1411
1412 pidgin_stock_load_status_icon_theme(theme);
1413 }
1195 } 1414 }
1196 1415
1197 static GtkWidget * 1416 static GtkWidget *
1198 interface_page(void) 1417 interface_page(void)
1199 { 1418 {
1200 GtkWidget *ret; 1419 GtkWidget *ret;
1201 GtkWidget *vbox; 1420 GtkWidget *vbox;
1202 GtkWidget *vbox2; 1421 GtkWidget *vbox2;
1203 GtkWidget *label; 1422 GtkWidget *label;
1204 GtkWidget *combo_box;
1205 GtkSizeGroup *sg; 1423 GtkSizeGroup *sg;
1206 GList *names = NULL; 1424 GList *names = NULL;
1207 1425
1208 ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE); 1426 ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
1209 gtk_container_set_border_width(GTK_CONTAINER(ret), PIDGIN_HIG_BORDER); 1427 gtk_container_set_border_width(GTK_CONTAINER(ret), PIDGIN_HIG_BORDER);
1211 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); 1429 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1212 1430
1213 /* Buddy List Themes */ 1431 /* Buddy List Themes */
1214 vbox = pidgin_make_frame(ret, _("Buddy List Theme")); 1432 vbox = pidgin_make_frame(ret, _("Buddy List Theme"));
1215 1433
1216 combo_box = prefs_build_theme_combo_box(prefs_blist_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme")); 1434 prefs_blist_themes_combo_box = prefs_build_theme_combo_box(prefs_blist_themes,
1217 gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0); 1435 purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"),
1218 g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_blist_theme_cb, NULL); 1436 "blist");
1437
1438 gtk_box_pack_start(GTK_BOX (vbox), prefs_blist_themes_combo_box, FALSE, FALSE, 0);
1439 g_signal_connect(G_OBJECT(prefs_blist_themes_combo_box), "changed", (GCallback)prefs_set_blist_theme_cb, NULL);
1219 1440
1220 /* Status Icon Themes */ 1441 /* Status Icon Themes */
1221 combo_box = prefs_build_theme_combo_box(prefs_status_icon_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme")); 1442 prefs_status_themes_combo_box = prefs_build_theme_combo_box(prefs_status_icon_themes,
1222 gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0); 1443 purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"),
1223 g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_status_icon_theme_cb, NULL); 1444 "icon");
1445
1446 gtk_box_pack_start(GTK_BOX (vbox), prefs_status_themes_combo_box, FALSE, FALSE, 0);
1447 g_signal_connect(G_OBJECT(prefs_status_themes_combo_box), "changed", (GCallback)prefs_set_status_icon_theme_cb, NULL);
1224 1448
1225 /* System Tray */ 1449 /* System Tray */
1226 vbox = pidgin_make_frame(ret, _("System Tray Icon")); 1450 vbox = pidgin_make_frame(ret, _("System Tray Icon"));
1227 label = pidgin_prefs_dropdown(vbox, _("_Show system tray icon:"), PURPLE_PREF_STRING, 1451 label = pidgin_prefs_dropdown(vbox, _("_Show system tray icon:"), PURPLE_PREF_STRING,
1228 PIDGIN_PREFS_ROOT "/docklet/show", 1452 PIDGIN_PREFS_ROOT "/docklet/show",
1229 _("Always"), "always", 1453 _("Always"), "always",
1230 _("On unread messages"), "pending", 1454 _("On unread messages"), "pending",
1231 _("Never"), "never", 1455 _("Never"), "never",
1232 NULL); 1456 NULL);
1233 gtk_size_group_add_widget(sg, label); 1457 gtk_size_group_add_widget(sg, label);
1234 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); 1458 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1235 1459
1236 vbox = pidgin_make_frame(ret, _("Conversation Window Hiding")); 1460 vbox = pidgin_make_frame(ret, _("Conversation Window"));
1237 label = pidgin_prefs_dropdown(vbox, _("_Hide new IM conversations:"), 1461 label = pidgin_prefs_dropdown(vbox, _("_Hide new IM conversations:"),
1238 PURPLE_PREF_STRING, PIDGIN_PREFS_ROOT "/conversations/im/hide_new", 1462 PURPLE_PREF_STRING, PIDGIN_PREFS_ROOT "/conversations/im/hide_new",
1239 _("Never"), "never", 1463 _("Never"), "never",
1240 _("When away"), "away", 1464 _("When away"), "away",
1241 _("Always"), "always", 1465 _("Always"), "always",
1242 NULL); 1466 NULL);
1243 gtk_size_group_add_widget(sg, label); 1467 gtk_size_group_add_widget(sg, label);
1244 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); 1468 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1245 1469
1470 #ifdef _WIN32
1471 pidgin_prefs_checkbox(_("Minimi_ze new conversation windows"), PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", vbox);
1472 #endif
1246 1473
1247 /* All the tab options! */ 1474 /* All the tab options! */
1248 vbox = pidgin_make_frame(ret, _("Tabs")); 1475 vbox = pidgin_make_frame(ret, _("Tabs"));
1249 1476
1250 pidgin_prefs_checkbox(_("Show IMs and chats in _tabbed windows"), 1477 pidgin_prefs_checkbox(_("Show IMs and chats in _tabbed windows"),
1257 vbox2 = gtk_vbox_new(FALSE, 9); 1484 vbox2 = gtk_vbox_new(FALSE, 9);
1258 gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0); 1485 gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0);
1259 purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/conversations/tabs", 1486 purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/conversations/tabs",
1260 conversation_usetabs_cb, vbox2); 1487 conversation_usetabs_cb, vbox2);
1261 if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/tabs")) 1488 if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/tabs"))
1262 gtk_widget_set_sensitive(vbox2, FALSE); 1489 gtk_widget_set_sensitive(vbox2, FALSE);
1263 1490
1264 pidgin_prefs_checkbox(_("Show close b_utton on tabs"), 1491 pidgin_prefs_checkbox(_("Show close b_utton on tabs"),
1265 PIDGIN_PREFS_ROOT "/conversations/close_on_tabs", vbox2); 1492 PIDGIN_PREFS_ROOT "/conversations/close_on_tabs", vbox2);
1266 1493
1267 label = pidgin_prefs_dropdown(vbox2, _("_Placement:"), PURPLE_PREF_INT, 1494 label = pidgin_prefs_dropdown(vbox2, _("_Placement:"), PURPLE_PREF_INT,
1274 _("Left Vertical"), GTK_POS_LEFT|8, 1501 _("Left Vertical"), GTK_POS_LEFT|8,
1275 _("Right Vertical"), GTK_POS_RIGHT|8, 1502 _("Right Vertical"), GTK_POS_RIGHT|8,
1276 #endif 1503 #endif
1277 NULL); 1504 NULL);
1278 gtk_size_group_add_widget(sg, label); 1505 gtk_size_group_add_widget(sg, label);
1279 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); 1506 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1280 1507
1281 names = pidgin_conv_placement_get_options(); 1508 names = pidgin_conv_placement_get_options();
1282 label = pidgin_prefs_dropdown_from_list(vbox2, _("N_ew conversations:"), 1509 label = pidgin_prefs_dropdown_from_list(vbox2, _("N_ew conversations:"),
1283 PURPLE_PREF_STRING, PIDGIN_PREFS_ROOT "/conversations/placement", names); 1510 PURPLE_PREF_STRING, PIDGIN_PREFS_ROOT "/conversations/placement", names);
1284 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); 1511 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1285 1512
1286 gtk_size_group_add_widget(sg, label); 1513 gtk_size_group_add_widget(sg, label);
1287 1514
1288 g_list_free(names); 1515 g_list_free(names);
1289 1516
1290
1291 keyboard_shortcuts(ret); 1517 keyboard_shortcuts(ret);
1292
1293 1518
1294 gtk_widget_show_all(ret); 1519 gtk_widget_show_all(ret);
1295 g_object_unref(sg); 1520 g_object_unref(sg);
1296 return ret; 1521 return ret;
1297 } 1522 }
1351 1576
1352 pidgin_prefs_checkbox(_("Use smooth-scrolling"), PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling", vbox); 1577 pidgin_prefs_checkbox(_("Use smooth-scrolling"), PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling", vbox);
1353 1578
1354 #ifdef _WIN32 1579 #ifdef _WIN32
1355 pidgin_prefs_checkbox(_("F_lash window when IMs are received"), PIDGIN_PREFS_ROOT "/win32/blink_im", vbox); 1580 pidgin_prefs_checkbox(_("F_lash window when IMs are received"), PIDGIN_PREFS_ROOT "/win32/blink_im", vbox);
1356
1357 pidgin_prefs_checkbox(_("Minimi_ze new conversation windows"), PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", vbox);
1358 #endif 1581 #endif
1359 1582
1360 pidgin_prefs_labeled_spin_button(vbox, 1583 pidgin_prefs_labeled_spin_button(vbox,
1361 _("Minimum input area height in lines:"), 1584 _("Minimum input area height in lines:"),
1362 PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines", 1585 PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines",
1363 1, 8, NULL); 1586 1, 8, NULL);
1364
1365 1587
1366 #if GTK_CHECK_VERSION(2,4,0) 1588 #if GTK_CHECK_VERSION(2,4,0)
1367 vbox = pidgin_make_frame(ret, _("Font")); 1589 vbox = pidgin_make_frame(ret, _("Font"));
1368 if (purple_running_gnome()) 1590 if (purple_running_gnome())
1369 fontpref = pidgin_prefs_checkbox(_("Use document font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox); 1591 fontpref = pidgin_prefs_checkbox(_("Use document font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox);
1370 else 1592 else
1371 fontpref = pidgin_prefs_checkbox(_("Use font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox); 1593 fontpref = pidgin_prefs_checkbox(_("Use font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox);
1372 1594
1373 font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font"); 1595 font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font");
1374 font_button = gtk_font_button_new_with_font(font_name ? font_name : NULL); 1596 if ((font_name == NULL) || (*font_name == '\0')) {
1597 font_button = gtk_font_button_new();
1598 } else {
1599 font_button = gtk_font_button_new_with_font(font_name);
1600 }
1375 1601
1376 gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE); 1602 gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE);
1377 hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Conversation _font:"), NULL, font_button, FALSE, NULL); 1603 hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Conversation _font:"), NULL, font_button, FALSE, NULL);
1378 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font")) 1604 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font"))
1379 gtk_widget_set_sensitive(hbox, FALSE); 1605 gtk_widget_set_sensitive(hbox, FALSE);
1415 gtk_widget_show(ret); 1641 gtk_widget_show(ret);
1416 1642
1417 return ret; 1643 return ret;
1418 } 1644 }
1419 1645
1420 static void network_ip_changed(GtkEntry *entry, gpointer data) 1646 static void
1421 { 1647 network_ip_changed(GtkEntry *entry, gpointer data)
1422 /* 1648 {
1423 * TODO: It would be nice if we could validate this and show a 1649 const gchar *text = gtk_entry_get_text(entry);
1424 * red background in the box when the IP address is invalid 1650 GdkColor color;
1425 * and a green background when the IP address is valid. 1651
1426 */ 1652 if (text && *text) {
1427 purple_network_set_public_ip(gtk_entry_get_text(entry)); 1653 if (purple_ip_address_is_valid(text)) {
1428 } 1654 color.red = 0xAFFF;
1429 1655 color.green = 0xFFFF;
1430 static gboolean network_stun_server_changed_cb(GtkWidget *widget, 1656 color.blue = 0xAFFF;
1431 GdkEventFocus *event, gpointer data) 1657
1658 purple_network_set_public_ip(text);
1659 } else {
1660 color.red = 0xFFFF;
1661 color.green = 0xAFFF;
1662 color.blue = 0xAFFF;
1663 }
1664
1665 gtk_widget_modify_base(GTK_WIDGET(entry), GTK_STATE_NORMAL, &color);
1666
1667 } else {
1668 purple_network_set_public_ip("");
1669 gtk_widget_modify_base(GTK_WIDGET(entry), GTK_STATE_NORMAL, NULL);
1670 }
1671 }
1672
1673 static gboolean
1674 network_stun_server_changed_cb(GtkWidget *widget,
1675 GdkEventFocus *event, gpointer data)
1432 { 1676 {
1433 GtkEntry *entry = GTK_ENTRY(widget); 1677 GtkEntry *entry = GTK_ENTRY(widget);
1434 purple_prefs_set_string("/purple/network/stun_server", 1678 purple_prefs_set_string("/purple/network/stun_server",
1435 gtk_entry_get_text(entry)); 1679 gtk_entry_get_text(entry));
1436 purple_network_set_stun_server(gtk_entry_get_text(entry)); 1680 purple_network_set_stun_server(gtk_entry_get_text(entry));
1437 1681
1438 return FALSE; 1682 return FALSE;
1439 } 1683 }
1440 1684
1441 static gboolean network_turn_server_changed_cb(GtkWidget *widget, 1685 static gboolean
1442 GdkEventFocus *event, gpointer data) 1686 network_turn_server_changed_cb(GtkWidget *widget,
1687 GdkEventFocus *event, gpointer data)
1443 { 1688 {
1444 GtkEntry *entry = GTK_ENTRY(widget); 1689 GtkEntry *entry = GTK_ENTRY(widget);
1445 purple_prefs_set_string("/purple/network/turn_server", 1690 purple_prefs_set_string("/purple/network/turn_server",
1446 gtk_entry_get_text(entry)); 1691 gtk_entry_get_text(entry));
1447 purple_network_set_turn_server(gtk_entry_get_text(entry)); 1692 purple_network_set_turn_server(gtk_entry_get_text(entry));
1448 1693
1449 return FALSE; 1694 return FALSE;
1450 } 1695 }
1451 1696
1452 static void 1697 static void
1453 proxy_changed_cb(const char *name, PurplePrefType type, 1698 proxy_changed_cb(const char *name, PurplePrefType type,
1460 gtk_widget_show_all(frame); 1705 gtk_widget_show_all(frame);
1461 else 1706 else
1462 gtk_widget_hide(frame); 1707 gtk_widget_hide(frame);
1463 } 1708 }
1464 1709
1465 static void proxy_print_option(GtkEntry *entry, int entrynum) 1710 static void
1711 proxy_print_option(GtkEntry *entry, int entrynum)
1466 { 1712 {
1467 if (entrynum == PROXYHOST) 1713 if (entrynum == PROXYHOST)
1468 purple_prefs_set_string("/purple/proxy/host", gtk_entry_get_text(entry)); 1714 purple_prefs_set_string("/purple/proxy/host", gtk_entry_get_text(entry));
1469 else if (entrynum == PROXYPORT) 1715 else if (entrynum == PROXYPORT)
1470 purple_prefs_set_int("/purple/proxy/port", atoi(gtk_entry_get_text(entry))); 1716 purple_prefs_set_int("/purple/proxy/port", atoi(gtk_entry_get_text(entry)));
1506 GtkWidget *table, *label, *auto_ip_checkbox, *ports_checkbox, *spin_button; 1752 GtkWidget *table, *label, *auto_ip_checkbox, *ports_checkbox, *spin_button;
1507 GtkWidget *proxy_warning = NULL, *browser_warning = NULL; 1753 GtkWidget *proxy_warning = NULL, *browser_warning = NULL;
1508 GtkWidget *proxy_button = NULL, *browser_button = NULL; 1754 GtkWidget *proxy_button = NULL, *browser_button = NULL;
1509 GtkSizeGroup *sg; 1755 GtkSizeGroup *sg;
1510 PurpleProxyInfo *proxy_info = NULL; 1756 PurpleProxyInfo *proxy_info = NULL;
1757 const char *ip;
1758 PurpleStunNatDiscovery *stun;
1759 char *auto_ip_text;
1511 1760
1512 ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE); 1761 ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
1513 gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER); 1762 gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
1514 1763
1515 vbox = pidgin_make_frame (ret, _("IP Address")); 1764 vbox = pidgin_make_frame (ret, _("IP Address"));
1536 gtk_label_set_markup(GTK_LABEL(label), 1785 gtk_label_set_markup(GTK_LABEL(label),
1537 _("<span style=\"italic\">Example: stunserver.org</span>")); 1786 _("<span style=\"italic\">Example: stunserver.org</span>"));
1538 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); 1787 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1539 gtk_container_add(GTK_CONTAINER(hbox), label); 1788 gtk_container_add(GTK_CONTAINER(hbox), label);
1540 1789
1541 auto_ip_checkbox = pidgin_prefs_checkbox(_("_Autodetect IP address"), 1790 /* purple_network_get_my_ip will return the IP that was set by the user with
1542 "/purple/network/auto_ip", vbox); 1791 purple_network_set_public_ip, so make a lookup for the auto-detected IP
1792 ourselves. */
1793
1794 /* Check if STUN discovery was already done */
1795 stun = purple_stun_discover(NULL);
1796 if ((stun != NULL) && (stun->status == PURPLE_STUN_STATUS_DISCOVERED)) {
1797 ip = stun->publicip;
1798 } else {
1799 /* Attempt to get the IP from a NAT device using UPnP */
1800 ip = purple_upnp_get_public_ip();
1801 if (ip == NULL) {
1802 /* Attempt to get the IP from a NAT device using NAT-PMP */
1803 ip = purple_pmp_get_public_ip();
1804 if (ip == NULL) {
1805 /* Just fetch the IP of the local system */
1806 ip = purple_network_get_local_system_ip(-1);
1807 }
1808 }
1809 }
1810
1811 auto_ip_text = g_strdup_printf(_("Use _automatically detected IP address: %s"), ip);
1812 auto_ip_checkbox = pidgin_prefs_checkbox(auto_ip_text, "/purple/network/auto_ip", vbox);
1813 g_free(auto_ip_text);
1543 1814
1544 table = gtk_table_new(2, 2, FALSE); 1815 table = gtk_table_new(2, 2, FALSE);
1545 gtk_container_set_border_width(GTK_CONTAINER(table), 0); 1816 gtk_container_set_border_width(GTK_CONTAINER(table), 0);
1546 gtk_table_set_col_spacings(GTK_TABLE(table), 5); 1817 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1547 gtk_table_set_row_spacings(GTK_TABLE(table), 10); 1818 gtk_table_set_row_spacings(GTK_TABLE(table), 10);
1556 gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry); 1827 gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
1557 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0); 1828 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
1558 g_signal_connect(G_OBJECT(entry), "changed", 1829 g_signal_connect(G_OBJECT(entry), "changed",
1559 G_CALLBACK(network_ip_changed), NULL); 1830 G_CALLBACK(network_ip_changed), NULL);
1560 1831
1561 /* 1832 gtk_entry_set_text(GTK_ENTRY(entry), purple_network_get_public_ip());
1562 * TODO: This could be better by showing the autodeteced 1833
1563 * IP separately from the user-specified IP. 1834 pidgin_set_accessible_label(entry, label);
1564 */
1565 if (purple_network_get_my_ip(-1) != NULL)
1566 gtk_entry_set_text(GTK_ENTRY(entry),
1567 purple_network_get_my_ip(-1));
1568
1569 pidgin_set_accessible_label (entry, label);
1570
1571 1835
1572 if (purple_prefs_get_bool("/purple/network/auto_ip")) { 1836 if (purple_prefs_get_bool("/purple/network/auto_ip")) {
1573 gtk_widget_set_sensitive(GTK_WIDGET(table), FALSE); 1837 gtk_widget_set_sensitive(GTK_WIDGET(table), FALSE);
1574 } 1838 }
1575 1839
1617 hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), "_TURN server:", 1881 hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), "_TURN server:",
1618 sg, entry, TRUE, NULL); 1882 sg, entry, TRUE, NULL);
1619 1883
1620 pidgin_prefs_labeled_spin_button(hbox, _("_Port:"), 1884 pidgin_prefs_labeled_spin_button(hbox, _("_Port:"),
1621 "/purple/network/turn_port", 0, 65535, NULL); 1885 "/purple/network/turn_port", 0, 65535, NULL);
1622 hbox = pidgin_prefs_labeled_entry(vbox, "_Username:", 1886 hbox = pidgin_prefs_labeled_entry(vbox, "_Username:",
1623 "/purple/network/turn_username", sg); 1887 "/purple/network/turn_username", sg);
1624 pidgin_prefs_labeled_password(hbox, "_Password:", 1888 pidgin_prefs_labeled_password(hbox, "_Password:",
1625 "/purple/network/turn_password", NULL); 1889 "/purple/network/turn_password", NULL);
1626 1890
1627 if (purple_running_gnome()) { 1891 if (purple_running_gnome()) {
1799 2063
1800 return ret; 2064 return ret;
1801 } 2065 }
1802 2066
1803 #ifndef _WIN32 2067 #ifndef _WIN32
1804 static gboolean manual_browser_set(GtkWidget *entry, GdkEventFocus *event, gpointer data) { 2068 static gboolean
2069 manual_browser_set(GtkWidget *entry, GdkEventFocus *event, gpointer data)
2070 {
1805 const char *program = gtk_entry_get_text(GTK_ENTRY(entry)); 2071 const char *program = gtk_entry_get_text(GTK_ENTRY(entry));
1806 2072
1807 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/browsers/command", program); 2073 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/browsers/command", program);
1808 2074
1809 /* carry on normally */ 2075 /* carry on normally */
1810 return FALSE; 2076 return FALSE;
1811 } 2077 }
1812 2078
1813 static GList *get_available_browsers(void) 2079 static GList *
2080 get_available_browsers(void)
1814 { 2081 {
1815 struct browser { 2082 struct browser {
1816 char *name; 2083 char *name;
1817 char *command; 2084 char *command;
1818 }; 2085 };
1975 2242
1976 return ret; 2243 return ret;
1977 } 2244 }
1978 2245
1979 #ifndef _WIN32 2246 #ifndef _WIN32
1980 static gint sound_cmd_yeah(GtkEntry *entry, gpointer d) 2247 static gint
2248 sound_cmd_yeah(GtkEntry *entry, gpointer d)
1981 { 2249 {
1982 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/sound/command", 2250 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/sound/command",
1983 gtk_entry_get_text(GTK_ENTRY(entry))); 2251 gtk_entry_get_text(GTK_ENTRY(entry)));
1984 return TRUE; 2252 return TRUE;
1985 } 2253 }
2107 gtk_entry_set_text(GTK_ENTRY(sound_entry), filename); 2375 gtk_entry_set_text(GTK_ENTRY(sound_entry), filename);
2108 2376
2109 pref_sound_generate_markup(); 2377 pref_sound_generate_markup();
2110 } 2378 }
2111 2379
2112 static void select_sound(GtkWidget *button, gpointer being_NULL_is_fun) 2380 static void
2381 select_sound(GtkWidget *button, gpointer being_NULL_is_fun)
2113 { 2382 {
2114 gchar *pref; 2383 gchar *pref;
2115 const char *filename; 2384 const char *filename;
2116 2385
2117 pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s", 2386 pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
2127 NULL, NULL, NULL, 2396 NULL, NULL, NULL,
2128 GINT_TO_POINTER(sound_row_sel)); 2397 GINT_TO_POINTER(sound_row_sel));
2129 } 2398 }
2130 2399
2131 #ifdef USE_GSTREAMER 2400 #ifdef USE_GSTREAMER
2132 static gchar* prefs_sound_volume_format(GtkScale *scale, gdouble val) 2401 static gchar *
2402 prefs_sound_volume_format(GtkScale *scale, gdouble val)
2133 { 2403 {
2134 if(val < 15) { 2404 if(val < 15) {
2135 return g_strdup_printf(_("Quietest")); 2405 return g_strdup_printf(_("Quietest"));
2136 } else if(val < 30) { 2406 } else if(val < 30) {
2137 return g_strdup_printf(_("Quieter")); 2407 return g_strdup_printf(_("Quieter"));
2146 } else { 2416 } else {
2147 return g_strdup_printf(_("Loudest")); 2417 return g_strdup_printf(_("Loudest"));
2148 } 2418 }
2149 } 2419 }
2150 2420
2151 static void prefs_sound_volume_changed(GtkRange *range) 2421 static void
2422 prefs_sound_volume_changed(GtkRange *range)
2152 { 2423 {
2153 int val = (int)gtk_range_get_value(GTK_RANGE(range)); 2424 int val = (int)gtk_range_get_value(GTK_RANGE(range));
2154 purple_prefs_set_int(PIDGIN_PREFS_ROOT "/sound/volume", val); 2425 purple_prefs_set_int(PIDGIN_PREFS_ROOT "/sound/volume", val);
2155 } 2426 }
2156 #endif 2427 #endif
2157 2428
2158 static void prefs_sound_sel(GtkTreeSelection *sel, GtkTreeModel *model) { 2429 static void
2430 prefs_sound_sel(GtkTreeSelection *sel, GtkTreeModel *model)
2431 {
2159 GtkTreeIter iter; 2432 GtkTreeIter iter;
2160 GValue val; 2433 GValue val;
2161 const char *file; 2434 const char *file;
2162 char *pref; 2435 char *pref;
2163 2436
2200 2473
2201 static GtkWidget * 2474 static GtkWidget *
2202 sound_page(void) 2475 sound_page(void)
2203 { 2476 {
2204 GtkWidget *ret; 2477 GtkWidget *ret;
2205 GtkWidget *vbox, *sw, *button, *combo_box; 2478 GtkWidget *vbox, *sw, *button;
2206 GtkSizeGroup *sg; 2479 GtkSizeGroup *sg;
2207 GtkTreeIter iter; 2480 GtkTreeIter iter;
2208 GtkWidget *event_view; 2481 GtkWidget *event_view;
2209 GtkListStore *event_store; 2482 GtkListStore *event_store;
2210 GtkCellRenderer *rend; 2483 GtkCellRenderer *rend;
2306 TRUE, 0, GTK_PACK_START); 2579 TRUE, 0, GTK_PACK_START);
2307 gtk_box_set_child_packing(GTK_BOX(vbox->parent->parent->parent), 2580 gtk_box_set_child_packing(GTK_BOX(vbox->parent->parent->parent),
2308 vbox->parent->parent, TRUE, TRUE, 0, GTK_PACK_START); 2581 vbox->parent->parent, TRUE, TRUE, 0, GTK_PACK_START);
2309 2582
2310 /* SOUND THEMES */ 2583 /* SOUND THEMES */
2311 combo_box = prefs_build_theme_combo_box(prefs_sound_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme")); 2584 prefs_sound_themes_combo_box = prefs_build_theme_combo_box(prefs_sound_themes,
2312 pref_sound_generate_markup(); 2585 purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme"),
2313 gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0); 2586 "sound");
2314 2587
2315 g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_sound_theme_cb, NULL); 2588
2589 gtk_box_pack_start(GTK_BOX (vbox), prefs_sound_themes_combo_box, FALSE, FALSE, 0);
2590
2591 g_signal_connect(G_OBJECT(prefs_sound_themes_combo_box), "changed", (GCallback)prefs_set_sound_theme_cb, NULL);
2316 2592
2317 /* SOUND SELECTION */ 2593 /* SOUND SELECTION */
2318 sw = gtk_scrolled_window_new(NULL,NULL); 2594 sw = gtk_scrolled_window_new(NULL,NULL);
2319 gtk_widget_set_size_request(sw, -1, 100); 2595 gtk_widget_set_size_request(sw, -1, 100);
2320 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); 2596 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2503 2779
2504 return ret; 2780 return ret;
2505 } 2781 }
2506 2782
2507 static int 2783 static int
2508 prefs_notebook_add_page(const char *text, 2784 prefs_notebook_add_page(const char *text, GtkWidget *page, int ind)
2509 GtkWidget *page, 2785 {
2510 int ind) {
2511
2512 #if GTK_CHECK_VERSION(2,4,0) 2786 #if GTK_CHECK_VERSION(2,4,0)
2513 return gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text)); 2787 return gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text));
2514 #else 2788 #else
2515 gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text)); 2789 gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text));
2516 return gtk_notebook_page_num(GTK_NOTEBOOK(prefsnotebook), page); 2790 return gtk_notebook_page_num(GTK_NOTEBOOK(prefsnotebook), page);
2517 #endif 2791 #endif
2518 } 2792 }
2519 2793
2520 static void prefs_notebook_init(void) { 2794 static void
2795 prefs_notebook_init(void)
2796 {
2521 prefs_notebook_add_page(_("Interface"), interface_page(), notebook_page++); 2797 prefs_notebook_add_page(_("Interface"), interface_page(), notebook_page++);
2522 prefs_notebook_add_page(_("Conversations"), conv_page(), notebook_page++); 2798 prefs_notebook_add_page(_("Conversations"), conv_page(), notebook_page++);
2523 prefs_notebook_add_page(_("Smiley Themes"), theme_page(), notebook_page++); 2799 prefs_notebook_add_page(_("Smiley Themes"), theme_page(), notebook_page++);
2524 prefs_notebook_add_page(_("Sounds"), sound_page(), notebook_page++); 2800 prefs_notebook_add_page(_("Sounds"), sound_page(), notebook_page++);
2525 prefs_notebook_add_page(_("Network"), network_page(), notebook_page++); 2801 prefs_notebook_add_page(_("Network"), network_page(), notebook_page++);
2532 #endif 2808 #endif
2533 prefs_notebook_add_page(_("Logging"), logging_page(), notebook_page++); 2809 prefs_notebook_add_page(_("Logging"), logging_page(), notebook_page++);
2534 prefs_notebook_add_page(_("Status / Idle"), away_page(), notebook_page++); 2810 prefs_notebook_add_page(_("Status / Idle"), away_page(), notebook_page++);
2535 } 2811 }
2536 2812
2537 void pidgin_prefs_show(void) 2813 void
2814 pidgin_prefs_show(void)
2538 { 2815 {
2539 GtkWidget *vbox; 2816 GtkWidget *vbox;
2540 GtkWidget *notebook; 2817 GtkWidget *notebook;
2541 GtkWidget *button; 2818 GtkWidget *button;
2542 2819
2543 if (prefs) { 2820 if (prefs) {
2544 gtk_window_present(GTK_WINDOW(prefs)); 2821 gtk_window_present(GTK_WINDOW(prefs));
2545 return; 2822 return;
2546 } 2823 }
2547 2824
2548 /* Refresh the list of themes before showing the preferences window */
2549 purple_theme_manager_refresh();
2550
2551 /* add everything in the theme manager before the window is loaded */
2552 if (prefs_themes_unsorted) {
2553 purple_theme_manager_for_each_theme(prefs_themes_sort);
2554 prefs_themes_unsorted = FALSE;
2555 }
2556 /* copy the preferences to tmp values... 2825 /* copy the preferences to tmp values...
2557 * I liked "take affect immediately" Oh well :-( */ 2826 * I liked "take affect immediately" Oh well :-( */
2558 /* (that should have been "effect," right?) */ 2827 /* (that should have been "effect," right?) */
2559 2828
2560 /* Back to instant-apply! I win! BU-HAHAHA! */ 2829 /* Back to instant-apply! I win! BU-HAHAHA! */
2574 button = pidgin_dialog_add_button(GTK_DIALOG(prefs), GTK_STOCK_CLOSE, NULL, NULL); 2843 button = pidgin_dialog_add_button(GTK_DIALOG(prefs), GTK_STOCK_CLOSE, NULL, NULL);
2575 g_signal_connect_swapped(G_OBJECT(button), "clicked", 2844 g_signal_connect_swapped(G_OBJECT(button), "clicked",
2576 G_CALLBACK(gtk_widget_destroy), prefs); 2845 G_CALLBACK(gtk_widget_destroy), prefs);
2577 2846
2578 prefs_notebook_init(); 2847 prefs_notebook_init();
2848
2849 /* Refresh the list of themes before showing the preferences window */
2850 prefs_themes_refresh();
2579 2851
2580 /* Show everything. */ 2852 /* Show everything. */
2581 gtk_widget_show(prefs); 2853 gtk_widget_show(prefs);
2582 } 2854 }
2583 2855
2659 smiley_theme_pref_cb, NULL); 2931 smiley_theme_pref_cb, NULL);
2660 2932
2661 pidgin_prefs_update_old(); 2933 pidgin_prefs_update_old();
2662 } 2934 }
2663 2935
2664 void pidgin_prefs_update_old() 2936 void
2937 pidgin_prefs_update_old(void)
2665 { 2938 {
2666 const char *str; 2939 const char *str;
2667 2940
2668 purple_prefs_rename("/gaim/gtk", PIDGIN_PREFS_ROOT); 2941 purple_prefs_rename("/gaim/gtk", PIDGIN_PREFS_ROOT);
2669 2942