pidgin/prefs/pidginprefs.c

changeset 41154
862153de4f30
parent 41144
910bdda75c74
child 41188
c29d5bd28346
equal deleted inserted replaced
41153:5f034a5261c3 41154:862153de4f30
36 36
37 #include "gtkblist.h" 37 #include "gtkblist.h"
38 #include "gtkconv.h" 38 #include "gtkconv.h"
39 #include "gtkdialogs.h" 39 #include "gtkdialogs.h"
40 #include "gtksavedstatuses.h" 40 #include "gtksavedstatuses.h"
41 #include "gtkstatus-icon-theme.h"
42 #include "gtkutils.h" 41 #include "gtkutils.h"
43 #include "pidgincore.h" 42 #include "pidgincore.h"
44 #include "pidgindebug.h" 43 #include "pidgindebug.h"
45 #include "pidgingdkpixbuf.h" 44 #include "pidgingdkpixbuf.h"
46 #include "pidginprefs.h" 45 #include "pidginprefs.h"
47 #include "pidginstock.h"
48 #ifdef USE_VV 46 #ifdef USE_VV
49 #include <gst/video/videooverlay.h> 47 #include <gst/video/videooverlay.h>
50 #ifdef GDK_WINDOWING_WIN32 48 #ifdef GDK_WINDOWING_WIN32
51 #include <gdk/gdkwin32.h> 49 #include <gdk/gdkwin32.h>
52 #endif 50 #endif
61 59
62 #define PREFS_OPTIMAL_ICON_SIZE 32 60 #define PREFS_OPTIMAL_ICON_SIZE 32
63 61
64 /* 25MB */ 62 /* 25MB */
65 #define PREFS_MAX_DOWNLOADED_THEME_SIZE 26214400 63 #define PREFS_MAX_DOWNLOADED_THEME_SIZE 26214400
66
67 struct theme_info {
68 gchar *type;
69 gchar *extension;
70 gchar *original_name;
71 };
72 64
73 typedef struct _PidginPrefCombo PidginPrefCombo; 65 typedef struct _PidginPrefCombo PidginPrefCombo;
74 66
75 typedef void (*PidginPrefsBindDropdownCallback)(GtkComboBox *combo_box, 67 typedef void (*PidginPrefsBindDropdownCallback)(GtkComboBox *combo_box,
76 PidginPrefCombo *combo); 68 PidginPrefCombo *combo);
174 GtkWidget *startup_current_status; 166 GtkWidget *startup_current_status;
175 GtkWidget *startup_hbox; 167 GtkWidget *startup_hbox;
176 GtkWidget *startup_label; 168 GtkWidget *startup_label;
177 } away; 169 } away;
178 170
179 /* Themes page */
180 struct {
181 SoupSession *session;
182 GtkWidget *status;
183 } theme;
184
185 #ifdef USE_VV 171 #ifdef USE_VV
186 /* Voice/Video page */ 172 /* Voice/Video page */
187 struct { 173 struct {
188 struct { 174 struct {
189 PidginPrefCombo input; 175 PidginPrefCombo input;
207 #endif 193 #endif
208 }; 194 };
209 195
210 /* Main dialog */ 196 /* Main dialog */
211 static PidginPrefsWindow *prefs = NULL; 197 static PidginPrefsWindow *prefs = NULL;
212
213 /* Themes page */
214 static GtkWidget *prefs_status_themes_combo_box;
215
216 /* These exist outside the lifetime of the prefs dialog */
217 static GtkListStore *prefs_status_icon_themes;
218 198
219 /* 199 /*
220 * PROTOTYPES 200 * PROTOTYPES
221 */ 201 */
222 G_DEFINE_TYPE(PidginPrefsWindow, pidgin_prefs_window, GTK_TYPE_DIALOG); 202 G_DEFINE_TYPE(PidginPrefsWindow, pidgin_prefs_window, GTK_TYPE_DIALOG);
795 /* Close any request dialogs */ 775 /* Close any request dialogs */
796 purple_request_close_with_handle(prefs); 776 purple_request_close_with_handle(prefs);
797 777
798 purple_notify_close_with_handle(prefs); 778 purple_notify_close_with_handle(prefs);
799 779
800 g_clear_object(&prefs->theme.session);
801
802 /* Unregister callbacks. */ 780 /* Unregister callbacks. */
803 purple_prefs_disconnect_by_handle(prefs); 781 purple_prefs_disconnect_by_handle(prefs);
804 782
805 /* NULL-ify globals */
806 prefs_status_themes_combo_box = NULL;
807
808 g_free(prefs->proxy.gnome_program_path); 783 g_free(prefs->proxy.gnome_program_path);
809 prefs = NULL; 784 prefs = NULL;
810 }
811
812 static gchar *
813 get_theme_markup(const char *name, gboolean custom, const char *author,
814 const char *description)
815 {
816
817 return g_strdup_printf("<b>%s</b>%s%s%s%s\n<span foreground='dim grey'>%s</span>",
818 name, custom ? " " : "", custom ? _("(Custom)") : "",
819 author != NULL ? " - " : "", author != NULL ? author : "",
820 description != NULL ? description : "");
821 }
822
823 /* adds the themes to the theme list from the manager so they can be displayed in prefs */
824 static void
825 prefs_themes_sort(PurpleTheme *theme)
826 {
827 GdkPixbuf *pixbuf = NULL;
828 GtkTreeIter iter;
829 gchar *image_full = NULL, *markup;
830 const gchar *name, *author, *description;
831
832 if (PIDGIN_IS_STATUS_ICON_THEME(theme)){
833 GtkListStore *store;
834
835 store = prefs_status_icon_themes;
836
837 image_full = purple_theme_get_image_full(theme);
838 if (image_full != NULL){
839 pixbuf = pidgin_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE);
840 g_free(image_full);
841 } else
842 pixbuf = NULL;
843
844 name = purple_theme_get_name(theme);
845 author = purple_theme_get_author(theme);
846 description = purple_theme_get_description(theme);
847
848 markup = get_theme_markup(name, FALSE, author, description);
849
850 gtk_list_store_append(store, &iter);
851 gtk_list_store_set(store, &iter, 0, pixbuf, 1, markup, 2, name, -1);
852
853 g_free(markup);
854 if (pixbuf != NULL)
855 g_object_unref(G_OBJECT(pixbuf));
856
857 }
858 }
859
860 static void
861 prefs_set_active_theme_combo(GtkWidget *combo_box, GtkListStore *store, const gchar *current_theme)
862 {
863 GtkTreeIter iter;
864 gchar *theme = NULL;
865 gboolean unset = TRUE;
866
867 if (current_theme && *current_theme && gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
868 do {
869 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &theme, -1);
870
871 if (purple_strequal(current_theme, theme)) {
872 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter);
873 unset = FALSE;
874 }
875
876 g_free(theme);
877 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
878 }
879
880 if (unset)
881 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0);
882 }
883
884 static void
885 prefs_themes_refresh(void)
886 {
887 GdkPixbuf *pixbuf = NULL;
888 gchar *tmp;
889 GtkTreeIter iter;
890
891 /* refresh the list of themes in the manager */
892 purple_theme_manager_refresh();
893
894 tmp = g_build_filename(PURPLE_DATADIR, "icons", "hicolor", "32x32",
895 "apps", "im.pidgin.Pidgin3.png", NULL);
896 pixbuf = pidgin_pixbuf_new_from_file_at_scale(tmp, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE);
897 g_free(tmp);
898
899 /* status icon themes */
900 gtk_list_store_clear(prefs_status_icon_themes);
901 gtk_list_store_append(prefs_status_icon_themes, &iter);
902 tmp = get_theme_markup(_("Default"), FALSE, _("Penguin Pimps"),
903 _("The default Pidgin status icon theme"));
904 gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1, tmp, 2, "", -1);
905 g_free(tmp);
906 if (pixbuf)
907 g_object_unref(G_OBJECT(pixbuf));
908
909 purple_theme_manager_for_each_theme(prefs_themes_sort);
910
911 /* set active */
912 prefs_set_active_theme_combo(prefs_status_themes_combo_box, prefs_status_icon_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"));
913 }
914
915 /* init all the theme variables so that the themes can be sorted later and used by pref pages */
916 static void
917 prefs_themes_init(void)
918 {
919 prefs_status_icon_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
920 }
921
922 /*
923 * prefs_theme_find_theme:
924 * @path: A directory containing a theme. The theme could be at the
925 * top level of this directory or in any subdirectory thereof.
926 * @type: The type of theme to load. The loader for this theme type
927 * will be used and this loader will determine what constitutes a
928 * "theme."
929 *
930 * Attempt to load the given directory as a theme. If we are unable to
931 * open the path as a theme then we recurse into path and attempt to
932 * load each subdirectory that we encounter.
933 *
934 * Returns: A new reference to a #PurpleTheme.
935 */
936 static PurpleTheme *
937 prefs_theme_find_theme(const gchar *path, const gchar *type)
938 {
939 PurpleTheme *theme = purple_theme_manager_load_theme(path, type);
940 GDir *dir = g_dir_open(path, 0, NULL);
941 const gchar *next;
942
943 while (!PURPLE_IS_THEME(theme) && (next = g_dir_read_name(dir))) {
944 gchar *next_path = g_build_filename(path, next, NULL);
945
946 if (g_file_test(next_path, G_FILE_TEST_IS_DIR))
947 theme = prefs_theme_find_theme(next_path, type);
948
949 g_free(next_path);
950 }
951
952 g_dir_close(dir);
953
954 return theme;
955 }
956
957 /* Eww. Seriously ewww. But thanks, grim! This is taken from guifications2 */
958 static gboolean
959 purple_theme_file_copy(const gchar *source, const gchar *destination)
960 {
961 FILE *src, *dest;
962 gint chr = EOF;
963
964 if(!(src = g_fopen(source, "rb")))
965 return FALSE;
966 if(!(dest = g_fopen(destination, "wb"))) {
967 fclose(src);
968 return FALSE;
969 }
970
971 while((chr = fgetc(src)) != EOF) {
972 fputc(chr, dest);
973 }
974
975 fclose(dest);
976 fclose(src);
977
978 return TRUE;
979 }
980
981 static void
982 free_theme_info(struct theme_info *info)
983 {
984 if (info != NULL) {
985 g_free(info->type);
986 g_free(info->extension);
987 g_free(info->original_name);
988 g_free(info);
989 }
990 }
991
992 /* installs a theme, info is freed by function */
993 static void
994 theme_install_theme(char *path, struct theme_info *info)
995 {
996 gchar *destdir;
997 const char *tail;
998 gboolean is_archive;
999 PurpleTheme *theme = NULL;
1000
1001 if (info == NULL)
1002 return;
1003
1004 /* check the extension */
1005 tail = info->extension ? info->extension : strrchr(path, '.');
1006
1007 if (!tail) {
1008 free_theme_info(info);
1009 return;
1010 }
1011
1012 is_archive = !g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz");
1013
1014 /* Just to be safe */
1015 g_strchomp(path);
1016
1017 destdir = g_build_filename(purple_data_dir(), "themes", "temp", NULL);
1018
1019 /* We'll check this just to make sure. This also lets us do something different on
1020 * other platforms, if need be */
1021 if (is_archive) {
1022 #ifndef _WIN32
1023 gchar *path_escaped = g_shell_quote(path);
1024 gchar *destdir_escaped = g_shell_quote(destdir);
1025 gchar *command;
1026
1027 if (!g_file_test(destdir, G_FILE_TEST_IS_DIR)) {
1028 g_mkdir_with_parents(destdir, S_IRUSR | S_IWUSR | S_IXUSR);
1029 }
1030
1031 command = g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped, destdir_escaped);
1032 g_free(path_escaped);
1033 g_free(destdir_escaped);
1034
1035 /* Fire! */
1036 if (system(command)) {
1037 purple_notify_error(NULL, NULL, _("Theme failed to unpack."), NULL, NULL);
1038 g_free(command);
1039 g_free(destdir);
1040 free_theme_info(info);
1041 return;
1042 }
1043 g_free(command);
1044 #else
1045 if (!winpidgin_gz_untar(path, destdir)) {
1046 purple_notify_error(NULL, NULL, _("Theme failed to unpack."), NULL, NULL);
1047 g_free(destdir);
1048 free_theme_info(info);
1049 return;
1050 }
1051 #endif
1052 }
1053
1054 if (is_archive) {
1055 theme = prefs_theme_find_theme(destdir, info->type);
1056
1057 if (PURPLE_IS_THEME(theme)) {
1058 /* create the location for the theme */
1059 gchar *theme_dest = g_build_filename(purple_data_dir(), "themes",
1060 purple_theme_get_name(theme),
1061 "purple", info->type, NULL);
1062
1063 if (!g_file_test(theme_dest, G_FILE_TEST_IS_DIR)) {
1064 g_mkdir_with_parents(theme_dest, S_IRUSR | S_IWUSR | S_IXUSR);
1065 }
1066
1067 g_free(theme_dest);
1068 theme_dest = g_build_filename(purple_data_dir(), "themes",
1069 purple_theme_get_name(theme),
1070 "purple", info->type, NULL);
1071
1072 /* move the entire directory to new location */
1073 if (g_rename(purple_theme_get_dir(theme), theme_dest)) {
1074 purple_debug_error("gtkprefs", "Error renaming %s to %s: "
1075 "%s\n", purple_theme_get_dir(theme), theme_dest,
1076 g_strerror(errno));
1077 }
1078
1079 g_free(theme_dest);
1080 if (g_remove(destdir) != 0) {
1081 purple_debug_error("gtkprefs",
1082 "couldn't remove temp (dest) path\n");
1083 }
1084 g_object_unref(theme);
1085
1086 prefs_themes_refresh();
1087
1088 } else {
1089 /* something was wrong with the theme archive */
1090 g_unlink(destdir);
1091 purple_notify_error(NULL, NULL, _("Theme failed to load."), NULL, NULL);
1092 }
1093
1094 } else { /* just a single file so copy it to a new temp directory and attempt to load it*/
1095 gchar *temp_path, *temp_file;
1096
1097 temp_path = g_build_filename(purple_data_dir(), "themes", "temp",
1098 "sub_folder", NULL);
1099
1100 if (info->original_name != NULL) {
1101 /* name was changed from the original (probably a dnd) change it back before loading */
1102 temp_file = g_build_filename(temp_path, info->original_name, NULL);
1103
1104 } else {
1105 gchar *source_name = g_path_get_basename(path);
1106 temp_file = g_build_filename(temp_path, source_name, NULL);
1107 g_free(source_name);
1108 }
1109
1110 if (!g_file_test(temp_path, G_FILE_TEST_IS_DIR)) {
1111 g_mkdir_with_parents(temp_path, S_IRUSR | S_IWUSR | S_IXUSR);
1112 }
1113
1114 if (purple_theme_file_copy(path, temp_file)) {
1115 /* find the theme, could be in subfolder */
1116 theme = prefs_theme_find_theme(temp_path, info->type);
1117
1118 if (PURPLE_IS_THEME(theme)) {
1119 gchar *theme_dest =
1120 g_build_filename(purple_data_dir(), "themes",
1121 purple_theme_get_name(theme), "purple",
1122 info->type, NULL);
1123
1124 if(!g_file_test(theme_dest, G_FILE_TEST_IS_DIR)) {
1125 g_mkdir_with_parents(theme_dest, S_IRUSR | S_IWUSR | S_IXUSR);
1126 }
1127
1128 if (g_rename(purple_theme_get_dir(theme), theme_dest)) {
1129 purple_debug_error("gtkprefs", "Error renaming %s to %s: "
1130 "%s\n", purple_theme_get_dir(theme), theme_dest,
1131 g_strerror(errno));
1132 }
1133
1134 g_free(theme_dest);
1135 g_object_unref(theme);
1136
1137 prefs_themes_refresh();
1138 } else {
1139 if (g_remove(temp_path) != 0) {
1140 purple_debug_error("gtkprefs",
1141 "couldn't remove temp path");
1142 }
1143 purple_notify_error(NULL, NULL, _("Theme failed to load."), NULL, NULL);
1144 }
1145 } else {
1146 purple_notify_error(NULL, NULL, _("Theme failed to copy."), NULL, NULL);
1147 }
1148
1149 g_free(temp_file);
1150 g_free(temp_path);
1151 }
1152
1153 g_free(destdir);
1154 free_theme_info(info);
1155 }
1156
1157 static void
1158 theme_got_url(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg,
1159 gpointer _info)
1160 {
1161 struct theme_info *info = _info;
1162 FILE *f;
1163 gchar *path;
1164 size_t wc;
1165
1166 if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
1167 free_theme_info(info);
1168 return;
1169 }
1170
1171 f = purple_mkstemp(&path, TRUE);
1172 wc = fwrite(msg->response_body->data, msg->response_body->length, 1, f);
1173 if (wc != 1) {
1174 purple_debug_warning("theme_got_url", "Unable to write theme data.\n");
1175 fclose(f);
1176 g_unlink(path);
1177 g_free(path);
1178 free_theme_info(info);
1179 return;
1180 }
1181 fclose(f);
1182
1183 theme_install_theme(path, info);
1184
1185 g_unlink(path);
1186 g_free(path);
1187 }
1188
1189 static void
1190 theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y,
1191 GtkSelectionData *sd, guint info, guint t, gpointer user_data)
1192 {
1193 gchar *name = g_strchomp((gchar *)gtk_selection_data_get_data(sd));
1194
1195 if ((gtk_selection_data_get_length(sd) >= 0)
1196 && (gtk_selection_data_get_format(sd) == 8)) {
1197 /* Well, it looks like the drag event was cool.
1198 * Let's do something with it */
1199 gchar *temp;
1200 struct theme_info *info = g_new0(struct theme_info, 1);
1201 info->type = g_strdup((gchar *)user_data);
1202 info->extension = g_strdup(g_strrstr(name,"."));
1203 temp = g_strrstr(name, "/");
1204 info->original_name = temp ? g_strdup(++temp) : NULL;
1205
1206 if (!g_ascii_strncasecmp(name, "file://", 7)) {
1207 GError *converr = NULL;
1208 gchar *tmp;
1209 /* It looks like we're dealing with a local file. Let's
1210 * just untar it in the right place */
1211 if(!(tmp = g_filename_from_uri(name, NULL, &converr))) {
1212 purple_debug_error("theme dnd", "%s",
1213 converr ? converr->message :
1214 "g_filename_from_uri error");
1215 free_theme_info(info);
1216 return;
1217 }
1218 theme_install_theme(tmp, info);
1219 g_free(tmp);
1220 } else if (!g_ascii_strncasecmp(name, "http://", 7) ||
1221 !g_ascii_strncasecmp(name, "https://", 8)) {
1222 /* Oo, a web drag and drop. This is where things
1223 * will start to get interesting */
1224 SoupMessage *msg;
1225
1226 if (prefs->theme.session == NULL) {
1227 prefs->theme.session = soup_session_new();
1228 }
1229
1230 soup_session_abort(prefs->theme.session);
1231
1232 msg = soup_message_new("GET", name);
1233 // purple_http_request_set_max_len(msg, PREFS_MAX_DOWNLOADED_THEME_SIZE);
1234 soup_session_queue_message(prefs->theme.session, msg, theme_got_url,
1235 info);
1236 } else
1237 free_theme_info(info);
1238
1239 gtk_drag_finish(dc, TRUE, FALSE, t);
1240 }
1241
1242 gtk_drag_finish(dc, FALSE, FALSE, t);
1243 }
1244
1245 /* builds a theme combo box from a list store with columns: icon preview, markup, theme name */
1246 static void
1247 prefs_build_theme_combo_box(GtkWidget *combo_box, GtkListStore *store,
1248 const char *current_theme, const char *type)
1249 {
1250 GtkTargetEntry te[3] = {
1251 {"text/plain", 0, 0},
1252 {"text/uri-list", 0, 1},
1253 {"STRING", 0, 2}
1254 };
1255
1256 g_return_if_fail(store != NULL && current_theme != NULL);
1257
1258 gtk_combo_box_set_model(GTK_COMBO_BOX(combo_box),
1259 GTK_TREE_MODEL(store));
1260
1261 gtk_drag_dest_set(combo_box, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te,
1262 sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE);
1263
1264 g_signal_connect(G_OBJECT(combo_box), "drag_data_received", G_CALLBACK(theme_dnd_recv), (gpointer) type);
1265 }
1266
1267 /* sets the current icon theme */
1268 static void
1269 prefs_set_status_icon_theme_cb(GtkComboBox *combo_box, gpointer user_data)
1270 {
1271 PidginStatusIconTheme *theme = NULL;
1272 GtkTreeIter iter;
1273 gchar *name = NULL;
1274
1275 if(gtk_combo_box_get_active_iter(combo_box, &iter)) {
1276
1277 gtk_tree_model_get(GTK_TREE_MODEL(prefs_status_icon_themes), &iter, 2, &name, -1);
1278
1279 if(!name || *name)
1280 theme = PIDGIN_STATUS_ICON_THEME(purple_theme_manager_find_theme(name, "status-icon"));
1281
1282 g_free(name);
1283
1284 pidgin_stock_load_status_icon_theme(theme);
1285 pidgin_blist_refresh(purple_blist_get_default());
1286 }
1287 }
1288
1289 static void
1290 bind_theme_page(PidginPrefsWindow *win)
1291 {
1292 /* Status Icon Themes */
1293 prefs_build_theme_combo_box(win->theme.status, prefs_status_icon_themes,
1294 PIDGIN_PREFS_ROOT "/status/icon-theme",
1295 "icon");
1296 prefs_status_themes_combo_box = win->theme.status;
1297 } 785 }
1298 786
1299 static void 787 static void
1300 formatting_toggle_cb(TalkatuActionGroup *ag, GAction *action, const gchar *name, gpointer data) 788 formatting_toggle_cb(TalkatuActionGroup *ag, GAction *action, const gchar *name, gpointer data)
1301 { 789 {
2268 bind_interface_page(win); 1756 bind_interface_page(win);
2269 bind_conv_page(win); 1757 bind_conv_page(win);
2270 bind_network_page(win); 1758 bind_network_page(win);
2271 bind_proxy_page(win); 1759 bind_proxy_page(win);
2272 bind_away_page(win); 1760 bind_away_page(win);
2273 bind_theme_page(win);
2274 #ifdef USE_VV 1761 #ifdef USE_VV
2275 vv = vv_page(win); 1762 vv = vv_page(win);
2276 gtk_container_add_with_properties(GTK_CONTAINER(stack), vv, "name", 1763 gtk_container_add_with_properties(GTK_CONTAINER(stack), vv, "name",
2277 "vv", "title", _("Voice/Video"), 1764 "vv", "title", _("Voice/Video"),
2278 NULL); 1765 NULL);
2450 away.startup_current_status); 1937 away.startup_current_status);
2451 gtk_widget_class_bind_template_child( 1938 gtk_widget_class_bind_template_child(
2452 widget_class, PidginPrefsWindow, away.startup_hbox); 1939 widget_class, PidginPrefsWindow, away.startup_hbox);
2453 gtk_widget_class_bind_template_child( 1940 gtk_widget_class_bind_template_child(
2454 widget_class, PidginPrefsWindow, away.startup_label); 1941 widget_class, PidginPrefsWindow, away.startup_label);
2455
2456 /* Themes page */
2457 gtk_widget_class_bind_template_child(
2458 widget_class, PidginPrefsWindow, theme.status);
2459 gtk_widget_class_bind_template_callback(widget_class,
2460 prefs_set_status_icon_theme_cb);
2461 } 1942 }
2462 1943
2463 static void 1944 static void
2464 pidgin_prefs_window_init(PidginPrefsWindow *win) 1945 pidgin_prefs_window_init(PidginPrefsWindow *win)
2465 { 1946 {
2471 1952
2472 /* Create the window */ 1953 /* Create the window */
2473 gtk_widget_init_template(GTK_WIDGET(win)); 1954 gtk_widget_init_template(GTK_WIDGET(win));
2474 1955
2475 prefs_stack_init(win); 1956 prefs_stack_init(win);
2476
2477 /* Refresh the list of themes before showing the preferences window */
2478 prefs_themes_refresh();
2479 } 1957 }
2480 1958
2481 void 1959 void
2482 pidgin_prefs_show(void) 1960 pidgin_prefs_show(void)
2483 { 1961 {
2502 /* File locations */ 1980 /* File locations */
2503 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/filelocations"); 1981 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/filelocations");
2504 purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder", ""); 1982 purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder", "");
2505 purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder", ""); 1983 purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder", "");
2506 purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", ""); 1984 purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", "");
2507
2508 /* Themes */
2509 prefs_themes_init();
2510 1985
2511 #ifdef USE_VV 1986 #ifdef USE_VV
2512 /* Voice/Video */ 1987 /* Voice/Video */
2513 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/vvconfig"); 1988 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/vvconfig");
2514 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/vvconfig/audio"); 1989 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/vvconfig/audio");

mercurial