fix bug 4773, 'remove obsolescent AC_C_CONST'
[claws.git] / src / prefs_themes.c
blob93eae1e4f03b077ecba883042c6aeb727f90a1c9
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2023 the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include "defs.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #ifdef HAVE_SVG
30 #include <math.h>
31 #endif
33 #include <glib.h>
34 #include <glib/gi18n.h>
35 #include <gtk/gtk.h>
37 #include "utils.h"
38 #include "codeconv.h"
39 #include "prefs_common.h"
40 #include "prefs_gtk.h"
42 #include "gtk/gtkutils.h"
43 #include "gtk/prefswindow.h"
44 #include "gtk/filesel.h"
45 #include "gtk/manage_window.h"
47 #include "stock_pixmap.h"
48 #include "mainwindow.h"
49 #include "compose.h"
50 #include "alertpanel.h"
51 #include "addr_compl.h"
52 #include "file-utils.h"
54 #define IS_CURRENT_THEME(path) (strcmp(prefs_common.pixmap_theme_path, path) == 0)
55 #define IS_INTERNAL_THEME(path) (strcmp(DEFAULT_PIXMAP_THEME, path) == 0)
56 #define IS_SYSTEM_THEME(path) (prefs_themes_is_system_theme(path))
58 #define PREVIEW_ICONS 7
60 typedef struct _ThemesPage
62 PrefsPage page;
64 GtkWidget *window; /* do not modify */
66 GtkWidget *op_menu;
67 GtkWidget *btn_install;
68 GtkWidget *btn_more;
69 GtkWidget *global;
71 GtkWidget *name;
72 GtkWidget *author;
73 GtkWidget *url;
74 GtkWidget *status;
76 GtkWidget *icons[PREVIEW_ICONS];
78 GtkWidget *btn_remove;
80 GdkPixbuf *pixbufs[PREVIEW_ICONS];
82 #ifdef HAVE_SVG
83 GtkWidget *checkbtn_enable_alpha;
84 GtkWidget *checkbtn_enable_scaling;
85 GtkWidget *checkbtn_scaling_auto;
86 GtkWidget *label_scaling_ppi;
87 GtkWidget *spinbtn_scaling_ppi;
88 #endif
89 } ThemesPage;
91 typedef struct _ThemeInfo
93 gchar *name;
94 gchar *author;
95 gchar *url;
96 gchar *status;
97 } ThemeInfo;
99 typedef struct _ThemeName
101 gchar *name;
102 GList *item;
103 } ThemeName;
105 typedef struct _ThemesData
107 GList *themes;
108 GList *names;
109 gchar *displayed;
110 ThemesPage *page;
111 } ThemesData;
113 typedef void (*FileFunc) (const gchar *filename, gpointer data);
115 typedef struct _DirInfo {
116 gint bytes;
117 gint files;
118 gint pixms;
119 /* extensions info */
120 const char **supported;
121 gint *length;
122 } DirInfo;
124 typedef struct _CopyInfo {
125 gchar *dest;
126 gchar *status;
127 } CopyInfo;
129 static ThemesData *prefs_themes_data;
131 StockPixmap prefs_themes_icons[PREVIEW_ICONS] = {
132 STOCK_PIXMAP_DIR_CLOSE,
133 STOCK_PIXMAP_MAIL_SEND,
134 STOCK_PIXMAP_MAIL_RECEIVE,
135 STOCK_PIXMAP_MAIL_ATTACH,
136 STOCK_PIXMAP_BOOK,
137 STOCK_PIXMAP_MIME_TEXT_PLAIN,
138 STOCK_PIXMAP_REPLIED
143 static void prefs_themes_btn_remove_clicked_cb (GtkWidget *widget, gpointer data);
144 static void prefs_themes_btn_install_clicked_cb (GtkWidget *widget, gpointer data);
145 static void prefs_themes_btn_viewall_clicked_cb (GtkWidget *widget, gpointer data);
146 static void prefs_themes_viewall_close_btn_clicked (GtkWidget *widget, gpointer data);
147 static gboolean prefs_themes_viewall_key_pressed (GtkWidget *keywidget, GdkEventKey *event, GtkWidget **widget);
148 static void prefs_themes_menu_item_activated_cb (GtkWidget *widget, gpointer data);
149 #ifdef HAVE_SVG
150 static gdouble prefs_themes_compute_ppi(GdkScreen *screen);
151 static gdouble prefs_themes_get_adjusted_ppi(void);
152 static void prefs_themes_checkbtn_enable_scaling_toggled_cb (GtkWidget *widget, gpointer data);
153 static void prefs_themes_checkbtn_scaling_auto_toggled_cb (GtkWidget *widget, gpointer data);
154 #endif
156 static void prefs_themes_update_buttons (const ThemesData *tdata);
157 static void prefs_themes_display_global_stats (const ThemesData *tdata);
158 static void prefs_themes_get_theme_info (ThemesData *tdata);
159 static void prefs_themes_display_theme_info (ThemesData *tdata, const ThemeInfo *info);
160 static void prefs_themes_get_themes_and_names (ThemesData *tdata);
161 static int prefs_themes_cmp_name(gconstpointer a, gconstpointer b);
162 static void prefs_themes_free_names (ThemesData *tdata);
164 static void prefs_themes_set_themes_menu (GtkComboBox *combo, const ThemesData *tdata);
166 static gchar *prefs_themes_get_theme_stats (const gchar *dirname);
167 static gboolean prefs_themes_is_system_theme (const gchar *dirname);
169 static void prefs_themes_create_widget (PrefsPage *page, GtkWindow *window, gpointer data);
170 static void prefs_themes_destroy_widget (PrefsPage *page);
171 static void prefs_themes_save (PrefsPage *page);
173 static void prefs_themes_foreach_file (const gchar *dirname, const FileFunc func, gpointer data);
174 static void prefs_themes_file_stats (const gchar *filename, gpointer data);
175 static void prefs_themes_file_remove (const gchar *filename, gpointer data);
176 static void prefs_themes_file_install (const gchar *filename, gpointer data);
180 static void prefs_themes_file_stats(const gchar *filename, gpointer data)
182 #ifdef G_OS_WIN32
183 GFile *f;
184 GFileInfo *fi;
185 GError *error = NULL;
186 #else
187 GStatBuf s;
188 #endif
189 goffset size;
190 DirInfo *di = (DirInfo *)data;
191 gint len;
192 gint i;
194 #ifdef G_OS_WIN32
195 f = g_file_new_for_path(filename);
196 fi = g_file_query_info(f, "standard::size,standard::type",
197 G_FILE_QUERY_INFO_NONE, NULL, &error);
198 if (error != NULL) {
199 g_warning(error->message);
200 g_error_free(error);
201 g_object_unref(f);
202 return;
204 if (g_file_info_get_file_type(fi) != G_FILE_TYPE_REGULAR) {
205 g_object_unref(fi);
206 g_object_unref(f);
207 return;
209 size = g_file_info_get_size(fi);
210 g_object_unref(fi);
211 g_object_unref(f);
212 #else
213 if ((i = g_stat(filename, &s)) != 0) {
214 debug_print("g_stat on '%s' failed: %d\n", filename, i);
215 return;
217 if (!S_ISREG(s.st_mode)) {
218 return;
220 size = s.st_size;
221 #endif
223 di->bytes += size;
224 di->files++;
225 len = strlen(filename);
226 for (i = 0; (di->supported)[i] != NULL; ++i) {
227 gint curlen = (di->length)[i];
228 if (len <= curlen)
229 continue;
230 const gchar *extension = filename + (len - curlen);
231 if (!strcmp(extension, (di->supported)[i])) {
232 di->pixms++;
233 break;
238 static void prefs_themes_file_remove(const gchar *filename, gpointer data)
240 gchar **status = (gchar **)data;
241 gchar *base;
243 if ((*status) != NULL)
244 return;
246 base = g_path_get_basename(filename);
247 if (TRUE == is_dir_exist(filename)) {
248 if (strcmp(base, ".") != 0 && strcmp(base, "..") != 0)
249 g_warning("prefs_themes_file_remove(): subdir in theme dir skipped: '%s'",
250 base);
252 else if (0 != claws_unlink(filename)) {
253 (*status) = g_strdup(filename);
255 g_free(base);
258 static void prefs_themes_file_install(const gchar *filename, gpointer data)
260 CopyInfo *ci = (CopyInfo *)data;
261 gchar *base;
263 if (ci->status != NULL)
264 return;
266 base = g_path_get_basename(filename);
267 if (TRUE == is_dir_exist(filename)) {
268 if (strcmp(base, ".") != 0 && strcmp(base, "..") !=0 )
269 g_warning("prefs_themes_file_install(): subdir in theme dir skipped: '%s'",
270 base);
272 else {
273 gchar *fulldest;
275 fulldest = g_strconcat(ci->dest, G_DIR_SEPARATOR_S, base, NULL);
277 if (0 != copy_file(filename, fulldest, FALSE)) {
278 ci->status = g_strdup(filename);
280 g_free(fulldest);
282 g_free(base);
285 static void prefs_themes_foreach_file(const gchar *dirname, const FileFunc func, gpointer data)
287 const gchar *entry;
288 gchar *fullentry;
289 GDir *dp;
290 GError *error = NULL;
292 cm_return_if_fail(dirname != NULL);
293 cm_return_if_fail(func != NULL);
295 if ((dp = g_dir_open(dirname, 0, &error)) == NULL) {
296 debug_print("couldn't open dir '%s': %s (%d)\n", dirname,
297 error->message, error->code);
298 g_error_free(error);
299 return;
302 while ((entry = g_dir_read_name(dp)) != NULL) {
304 fullentry = g_strconcat(dirname, G_DIR_SEPARATOR_S, entry, NULL);
306 (*func)(fullentry, data);
308 g_free(fullentry);
310 g_dir_close(dp);
313 static gboolean prefs_themes_is_system_theme(const gchar *dirname)
315 gint len;
316 gchar *system_theme_dir;
317 gboolean is_sys = FALSE;
319 cm_return_val_if_fail(dirname != NULL, FALSE);
321 system_theme_dir = stock_pixmap_get_system_theme_dir_for_theme(NULL);
322 len = strlen(system_theme_dir);
323 if (strlen(dirname) > len && 0 == strncmp(dirname, system_theme_dir, len))
324 is_sys = TRUE;
326 g_free(system_theme_dir);
328 return is_sys;
331 static void prefs_themes_set_themes_menu(GtkComboBox *combo, const ThemesData *tdata)
333 GtkListStore *store;
334 GtkTreeIter iter;
335 GList *themes = tdata->names;
336 gint i = 0, active = 0;
337 GList *sorted_list = NULL;
339 cm_return_if_fail(combo != NULL);
341 /* sort theme data list by data name */
342 while (themes != NULL) {
343 ThemeName *tname = (ThemeName *)(themes->data);
345 sorted_list = g_list_insert_sorted(sorted_list, (gpointer)(tname),
346 (GCompareFunc)prefs_themes_cmp_name);
348 themes = g_list_next(themes);
351 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
353 /* feed gtk_menu w/ sorted themes names */
354 themes = sorted_list;
355 while (themes != NULL) {
356 ThemeName *tname = (ThemeName *)(themes->data);
357 gchar *tpath = (gchar *)(tname->item->data);
359 gtk_list_store_append(store, &iter);
360 gtk_list_store_set(store, &iter,
361 0, tname->name,
362 1, tname->item->data, -1);
364 if (tdata->displayed != NULL && !g_strcmp0(tdata->displayed,tpath))
365 active = i;
366 ++i;
368 themes = g_list_next(themes);
371 g_list_free(sorted_list);
373 g_signal_connect(G_OBJECT(combo), "changed",
374 G_CALLBACK(prefs_themes_menu_item_activated_cb),
375 NULL);
377 gtk_combo_box_set_model(combo, GTK_TREE_MODEL(store));
378 gtk_combo_box_set_active(combo, active);
381 static int prefs_themes_cmp_name(gconstpointer a_p, gconstpointer b_p)
383 /* compare two ThemeData structures by their name attribute */
384 return g_strcmp0((gchar *)(((ThemeName*)a_p)->name),
385 (gchar *)(((ThemeName*)b_p)->name));
388 static void prefs_themes_get_themes_and_names(ThemesData *tdata)
390 GList *tpaths;
392 cm_return_if_fail(tdata != NULL);
394 stock_pixmap_themes_list_free(tdata->themes);
395 prefs_themes_free_names(tdata);
397 tdata->themes = stock_pixmap_themes_list_new();
399 tpaths = tdata->themes;
400 while (tpaths != NULL) {
401 ThemeName *name = g_new0(ThemeName, 1);
402 gchar *sname = g_path_get_basename((const gchar *)(tpaths->data));
404 if (IS_INTERNAL_THEME(sname))
405 name->name = g_strdup(_("Default internal theme"));
406 else
407 name->name = g_strdup(sname);
408 name->item = tpaths;
410 tdata->names = g_list_append(tdata->names, name);
411 if (!g_strcmp0(tpaths->data, prefs_common.pixmap_theme_path)) {
412 tdata->displayed = (gchar *)tpaths->data;
414 tpaths = g_list_next(tpaths);
415 g_free(sname);
419 void prefs_themes_init(void)
421 ThemesData *tdata;
422 ThemesPage *page;
423 GList *tpaths;
424 static gchar *path[3];
426 path[0] = _("Display");
427 path[1] = _("Themes");
428 path[2] = NULL;
430 debug_print("Creating preferences for themes...\n");
432 tdata = g_new0(ThemesData, 1);
433 prefs_themes_data = tdata;
435 prefs_themes_get_themes_and_names(tdata);
437 page = g_new0(ThemesPage, 1);
439 page->page.path = path;
440 page->page.create_widget = prefs_themes_create_widget;
441 page->page.destroy_widget = prefs_themes_destroy_widget;
442 page->page.save_page = prefs_themes_save;
443 page->page.weight = 130.0;
444 prefs_gtk_register_page((PrefsPage *) page);
446 tdata->page = page;
448 tpaths = g_list_first(tdata->themes);
449 if (tdata->displayed == NULL)
450 tdata->displayed = (gchar *)(tpaths->data);
451 #ifdef HAVE_SVG
452 if (prefs_common.pixmap_scaling_auto)
453 prefs_common.pixmap_scaling_ppi = prefs_themes_get_adjusted_ppi();
454 #endif
457 static void prefs_themes_free_names(ThemesData *tdata)
459 GList *names;
461 cm_return_if_fail(tdata != NULL);
463 if (tdata->names == NULL)
464 return;
466 names = tdata->names;
467 while (names != NULL) {
468 ThemeName *tn = (ThemeName *)(names->data);
470 tn->item = NULL;
471 g_free(tn->name);
472 g_free(tn);
474 names = g_list_next(names);
476 g_list_free(tdata->names);
477 tdata->names = NULL;
480 void prefs_themes_done(void)
482 ThemesData *tdata = prefs_themes_data;
484 debug_print("Finished preferences for themes.\n");
486 stock_pixmap_themes_list_free(tdata->themes);
487 prefs_themes_free_names(tdata);
488 g_free(tdata->page);
489 g_free(tdata);
492 static void prefs_themes_btn_remove_clicked_cb(GtkWidget *widget, gpointer data)
494 ThemesData *tdata = prefs_themes_data;
495 gchar *theme_str;
496 gchar *alert_title = NULL;
497 AlertValue val = 0;
498 gchar *tmp = NULL;
500 theme_str = tdata->displayed;
502 tmp = g_path_get_basename(theme_str);
503 alert_title = g_strdup_printf(_("Remove theme '%s'"), tmp);
504 g_free(tmp);
506 val = alertpanel(alert_title,
507 _("Are you sure you want to remove this theme?"),
508 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL, ALERTFOCUS_FIRST);
509 g_free(alert_title);
511 if (G_ALERTALTERNATE == val) {
512 gchar *status = NULL;
514 prefs_themes_foreach_file(theme_str, prefs_themes_file_remove, &status);
515 if (0 != rmdir(theme_str)) {
516 if (status != NULL) {
517 alertpanel_error(_("File %s failed\nwhile removing theme."), status);
518 g_free(status);
520 else
521 alertpanel_error(_("Removing theme directory failed."));
523 else {
524 alertpanel_notice(_("Theme removed successfully"));
525 /* update interface back to first theme */
526 prefs_themes_get_themes_and_names(tdata);
527 prefs_themes_set_themes_menu(GTK_COMBO_BOX(tdata->page->op_menu), tdata);
528 prefs_themes_display_global_stats(tdata);
529 tdata->displayed = (gchar *)((g_list_first(tdata->themes))->data);
530 prefs_themes_get_theme_info(tdata);
535 static void prefs_themes_btn_install_clicked_cb(GtkWidget *widget, gpointer data)
537 gchar *filename, *source;
538 gchar *themeinfo, *themename;
539 gchar *alert_title = NULL;
540 CopyInfo *cinfo;
541 AlertValue val = 0;
542 ThemesData *tdata = prefs_themes_data;
544 filename = filesel_select_file_open_folder(_("Select theme folder"), NULL);
545 if (filename == NULL)
546 return;
548 if (filename[strlen(filename) - 1] != G_DIR_SEPARATOR)
549 filename = g_strconcat(filename, G_DIR_SEPARATOR_S, NULL);
550 else
551 filename = g_strdup(filename);
553 cinfo = g_new0(CopyInfo, 1);
554 source = g_path_get_dirname(filename);
555 themename = g_path_get_basename(source);
556 debug_print("Installing '%s' theme from %s\n", themename, filename);
558 themeinfo = g_strconcat(source, G_DIR_SEPARATOR_S, THEMEINFO_FILE, NULL);
559 alert_title = g_strdup_printf(_("Install theme '%s'"), themename);
560 if (file_exist(themeinfo, FALSE) == FALSE) {
561 val = alertpanel(alert_title,
562 _("This folder doesn't seem to be a theme"
563 "folder.\nInstall anyway?"),
564 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL, ALERTFOCUS_FIRST);
565 if (G_ALERTALTERNATE != val)
566 goto end_inst;
569 cinfo->dest = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
570 PIXMAP_THEME_DIR, G_DIR_SEPARATOR_S,
571 themename, NULL);
572 if (TRUE == is_dir_exist(cinfo->dest)) {
573 AlertValue val = alertpanel_full(_("Theme exists"),
574 _("A theme with the same name is\n"
575 "already installed in this location.\n\n"
576 "Do you want to replace it?"),
577 NULL, _("_Cancel"), NULL, _("Overwrite"), NULL, NULL,
578 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_WARNING);
579 if (val == G_ALERTALTERNATE) {
580 if (remove_dir_recursive(cinfo->dest) < 0) {
581 alertpanel_error(_("Couldn't delete the old theme in %s."),
582 cinfo->dest);
583 goto end_inst;
585 } else {
586 goto end_inst;
589 if (0 != make_dir_hier(cinfo->dest)) {
590 alertpanel_error(_("Couldn't create destination directory %s."),
591 cinfo->dest);
592 goto end_inst;
594 prefs_themes_foreach_file(source, prefs_themes_file_install, cinfo);
595 if (cinfo->status == NULL) {
596 GList *insted;
598 /* update interface to show newly installed theme */
599 prefs_themes_get_themes_and_names(tdata);
600 insted = g_list_find_custom(tdata->themes,
601 (gpointer)(cinfo->dest),
602 (GCompareFunc)g_strcmp0);
603 if (NULL != insted) {
604 alertpanel_notice(_("Theme installed successfully."));
605 tdata->displayed = (gchar *)(insted->data);
606 prefs_themes_set_themes_menu(GTK_COMBO_BOX(tdata->page->op_menu), tdata);
607 prefs_themes_display_global_stats(tdata);
608 prefs_themes_get_theme_info(tdata);
610 else
611 alertpanel_error(_("Failed installing theme"));
613 else
614 alertpanel_error(_("File %s failed\nwhile installing theme."), cinfo->status);
615 end_inst:
616 g_free(cinfo->dest);
617 g_free(filename);
618 g_free(source);
619 g_free(themeinfo);
620 g_free(cinfo);
621 g_free(themename);
622 g_free(alert_title);
625 static gboolean prefs_themes_viewall_key_pressed(GtkWidget *keywidget, GdkEventKey *event, GtkWidget **widget)
627 if (event && event->keyval == GDK_KEY_Escape) {
628 prefs_themes_viewall_close_btn_clicked(NULL, widget);
631 return FALSE;
634 static void prefs_themes_viewall_close_btn_clicked(GtkWidget *widget, gpointer data)
636 GtkWidget **window = (GtkWidget **) data;
638 cm_return_if_fail(window != NULL);
639 cm_return_if_fail(*window != NULL);
641 gtk_widget_destroy(*window);
642 *window = NULL;
645 #define ICONS_PER_ROW 19
647 static void prefs_themes_btn_viewall_clicked_cb(GtkWidget *widget, gpointer data)
649 static GtkWidget *viewall_win = NULL;
651 ThemesData *tdata = prefs_themes_data;
652 GtkWidget *vbox;
653 GtkWidget *hbox;
654 GtkWidget *icons[N_STOCK_PIXMAPS];
655 GdkPixbuf *pixbufs[N_STOCK_PIXMAPS];
656 GtkWidget *separator;
657 GtkWidget *confirm_area;
658 GtkWidget *close_btn;
659 gchar *save_prefs_path;
660 gint i;
662 viewall_win = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "prefs_themes_view_all");
663 gtk_container_set_border_width(GTK_CONTAINER(viewall_win), 5);
664 gtk_window_set_title(GTK_WINDOW(viewall_win), _("View all theme icons"));
665 gtk_window_set_position(GTK_WINDOW(viewall_win), GTK_WIN_POS_CENTER);
667 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
668 gtk_widget_show(vbox);
669 gtk_container_add(GTK_CONTAINER(viewall_win), vbox);
671 save_prefs_path = prefs_common.pixmap_theme_path;
672 prefs_common.pixmap_theme_path = tdata->displayed;
673 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
674 gtk_widget_show(hbox);
675 for (i = 0; i < N_STOCK_PIXMAPS; ++i) {
676 icons[i] = gtk_image_new();
677 gtk_widget_show (icons[i]);
678 stock_pixbuf_gdk(i, &(pixbufs[i]));
679 gtk_image_set_from_pixbuf(GTK_IMAGE(icons[i]), pixbufs[i]);
680 gtk_box_pack_start(GTK_BOX(hbox), icons[i], TRUE, TRUE, 5);
681 if ((i + 1) % ICONS_PER_ROW == 0) {
682 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 5);
683 if (i + 1 < N_STOCK_PIXMAPS) {
684 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
685 gtk_widget_show(hbox);
689 prefs_common.pixmap_theme_path = save_prefs_path;
691 separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
692 gtk_widget_show(separator);
693 gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, FALSE, 0);
695 gtkut_stock_button_set_create(&confirm_area,
696 &close_btn, "window-close", _("_Close"),
697 NULL, NULL, NULL, NULL, NULL, NULL);
698 gtk_box_pack_start(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 5);
699 gtk_widget_show(confirm_area);
700 gtk_widget_grab_default(close_btn);
701 gtk_widget_grab_focus(close_btn);
703 g_signal_connect(G_OBJECT(close_btn), "clicked",
704 G_CALLBACK(prefs_themes_viewall_close_btn_clicked),
705 &viewall_win);
706 g_signal_connect(G_OBJECT(viewall_win), "key_press_event",
707 G_CALLBACK(prefs_themes_viewall_key_pressed),
708 &viewall_win);
710 manage_window_set_transient(GTK_WINDOW(viewall_win));
711 gtk_window_set_modal(GTK_WINDOW(viewall_win), TRUE);
712 gtk_widget_show(viewall_win);
715 static void prefs_themes_menu_item_activated_cb(GtkWidget *widget, gpointer data)
717 ThemesData *tdata = prefs_themes_data;
718 gchar *path;
719 GtkTreeModel *model;
720 GtkTreeIter iter;
722 cm_return_if_fail(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter));
724 model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
725 gtk_tree_model_get(model, &iter, 1, &path, -1);
727 tdata->displayed = path;
728 prefs_themes_get_theme_info(tdata);
731 #ifdef HAVE_SVG
732 #define MM_INCH 0.0393700787402
733 static gdouble prefs_themes_compute_ppi(GdkScreen *screen)
735 GdkRectangle workarea = {0};
736 GdkMonitor *monitor = gdk_display_get_primary_monitor(gdk_display_get_default());
738 gdk_monitor_get_workarea(monitor, &workarea);
739 gdouble wp = workarea.width;
740 gdouble hp = workarea.height;
741 gdouble wi = gdk_monitor_get_width_mm(monitor);
742 gdouble hi = gdk_monitor_get_height_mm(monitor);
743 gdouble dp, di;
745 debug_print("screen is %f x %f pixels, %f x %f mm\n", wp, hp, wi, hi);
747 /* https://en.wikipedia.org/wiki/Pixel_density */
748 wi *= MM_INCH;
749 hi *= MM_INCH;
750 dp = sqrt(wp * wp + hp * hp);
751 di = sqrt(wi * wi + hi * hi);
753 return (di != 0.0)? dp / di: 0.0;
756 static gdouble prefs_themes_get_adjusted_ppi(void)
758 gdouble ppi, cppi;
759 GdkScreen * screen = gdk_screen_get_default();
761 if (screen == NULL) { /* oops! */
762 g_warning("unable to get default GDK screen");
763 return MIN_PPI;
766 ppi = gdk_screen_get_resolution(screen);
767 cppi = prefs_themes_compute_ppi(screen);
768 debug_print("returned PPI: %f / computed PPI: %f\n", ppi, cppi);
770 gdk_screen_get_resolution doesn't seem to work well when running
771 on a remote display and returns the value of the local display.
772 height/width functions do this better, so we can compute a PPI
773 from them and take the highest value.
775 return MAX(ppi, cppi);
778 static void prefs_themes_checkbtn_enable_scaling_toggled_cb (GtkWidget *widget, gpointer data)
780 ThemesPage *page = (ThemesPage *) data;
781 gboolean enabled = gtk_toggle_button_get_active(
782 GTK_TOGGLE_BUTTON (widget));
783 gboolean automatic = gtk_toggle_button_get_active(
784 GTK_TOGGLE_BUTTON (page->checkbtn_scaling_auto));
786 gtk_widget_set_sensitive(page->checkbtn_scaling_auto, enabled);
787 gtk_widget_set_sensitive(page->spinbtn_scaling_ppi, enabled && !automatic);
788 gtk_widget_set_sensitive(page->label_scaling_ppi, enabled && !automatic);
791 static void prefs_themes_checkbtn_scaling_auto_toggled_cb(GtkWidget *widget, gpointer data)
793 ThemesPage *page = (ThemesPage *) data;
794 gboolean automatic = gtk_toggle_button_get_active(
795 GTK_TOGGLE_BUTTON (widget));
797 gtk_widget_set_sensitive(page->spinbtn_scaling_ppi, !automatic);
798 gtk_widget_set_sensitive(page->label_scaling_ppi, !automatic);
800 if (automatic) /* update PPI value */
801 gtk_spin_button_set_value(
802 GTK_SPIN_BUTTON (page->spinbtn_scaling_ppi),
803 prefs_themes_get_adjusted_ppi());
805 #endif
807 static void prefs_themes_update_buttons(const ThemesData *tdata)
809 ThemesPage *theme = tdata->page;
810 gboolean can_rem;
812 can_rem = !IS_CURRENT_THEME(tdata->displayed) &&
813 !IS_INTERNAL_THEME(tdata->displayed) &&
814 !IS_SYSTEM_THEME(tdata->displayed);
816 if (theme->btn_remove != NULL)
817 gtk_widget_set_sensitive(theme->btn_remove, can_rem);
820 /* placeholders may already be utf8 (i18n) */
821 #define SET_LABEL_TEXT_UTF8(label, text) \
823 gchar *tmpstr; \
825 if (!g_utf8_validate(text, -1, NULL)) \
826 tmpstr = conv_codeset_strdup(text, \
827 conv_get_locale_charset_str(), CS_UTF_8); \
828 else \
829 tmpstr = g_strdup(text); \
831 gtk_label_set_text(GTK_LABEL(label), tmpstr); \
832 gtk_label_set_selectable(GTK_LABEL(label), TRUE); \
833 g_free(tmpstr); \
835 static void prefs_themes_display_theme_info(ThemesData *tdata, const ThemeInfo *info)
837 ThemesPage *theme = tdata->page;
838 gchar *save_prefs_path;
839 gint i;
841 SET_LABEL_TEXT_UTF8(theme->name, info->name);
842 SET_LABEL_TEXT_UTF8(theme->author, info->author);
843 SET_LABEL_TEXT_UTF8(theme->url, info->url);
844 SET_LABEL_TEXT_UTF8(theme->status, info->status);
846 save_prefs_path = prefs_common.pixmap_theme_path;
847 prefs_common.pixmap_theme_path = tdata->displayed;
848 for (i = 0; i < PREVIEW_ICONS; ++i) {
849 stock_pixbuf_gdk(prefs_themes_icons[i], &(theme->pixbufs[i]));
850 gtk_image_set_from_pixbuf(GTK_IMAGE(theme->icons[i]),
851 theme->pixbufs[i]);
853 prefs_common.pixmap_theme_path = save_prefs_path;
855 prefs_themes_update_buttons(tdata);
857 #undef SET_LABEL_TEXT_UTF8
859 static void prefs_themes_display_global_stats(const ThemesData *tdata)
861 ThemesPage *theme = tdata->page;
862 GList *tnames = tdata->names;
863 gchar *gstats;
864 gint sys = 0;
865 gint usr = 0;
866 gint all = 0;
868 while (tnames != NULL) {
869 ThemeName *tname = (ThemeName *)(tnames->data);
870 gchar *tpath = (gchar *)(tname->item->data);
872 if (IS_SYSTEM_THEME(tpath))
873 ++sys;
874 else if (!IS_INTERNAL_THEME(tpath))
875 ++usr;
876 ++all;
877 tnames = g_list_next(tnames);
880 gstats = g_strdup_printf(_("%d themes available (%d user, %d system, 1 internal)"),
881 all, usr, sys);
882 gtk_label_set_text(GTK_LABEL(theme->global), gstats);
883 gtk_label_set_justify (GTK_LABEL (theme->global), GTK_JUSTIFY_LEFT);
884 gtkut_widget_set_small_font_size (theme->global);
885 g_free(gstats);
888 #define INFOFILE_LINE_LEN 80
890 #define FGETS_INFOFILE_LINE() \
891 line[0] = '\0'; \
892 if (claws_fgets(line, INFOFILE_LINE_LEN, finfo) != NULL && (len = strlen(line)) > 0) { \
893 if (line[len - 1] == '\n') line[len - 1] = '\0'; \
895 else { \
896 g_strlcpy(line, _("Unknown"),sizeof(line)); \
899 static void prefs_themes_get_theme_info(ThemesData *tdata)
901 FILE *finfo;
902 gchar *sinfo;
903 gchar *path;
904 gchar line[INFOFILE_LINE_LEN];
905 gint len;
906 ThemeInfo *info;
907 ThemesPage *theme = tdata->page;
909 cm_return_if_fail(theme != NULL);
910 path = tdata->displayed;
911 cm_return_if_fail(path != NULL);
913 debug_print("Getting theme info for %s\n", path);
915 info = g_new0(ThemeInfo, 1);
917 if (IS_INTERNAL_THEME(path)) {
918 info->name = g_strdup(_("Default internal theme"));
919 info->author = g_strdup(_("The Claws Mail Team"));
920 info->url = g_strdup(HOMEPAGE_URI);
921 info->status = g_strdup_printf(_("Internal theme has %d icons"), N_STOCK_PIXMAPS);
923 else {
924 sinfo = g_strconcat(path, G_DIR_SEPARATOR_S, THEMEINFO_FILE, NULL);
925 finfo = claws_fopen(sinfo, "r");
926 if (finfo == NULL) {
927 info->name = g_strdup(_("No info file available for this theme"));
928 info->author = g_strdup(_("Unknown"));
929 info->url = g_strdup(_("Unknown"));
931 else {
932 FGETS_INFOFILE_LINE()
933 info->name = g_strdup(line);
934 FGETS_INFOFILE_LINE()
935 info->author = g_strdup(line);
936 FGETS_INFOFILE_LINE()
937 info->url = g_strdup(line);
939 claws_fclose(finfo);
941 g_free(sinfo);
943 info->status = prefs_themes_get_theme_stats(path);
944 if (info->status == NULL) {
945 info->status = g_strdup(_("Error: couldn't get theme status"));
949 prefs_themes_display_theme_info(tdata, info);
951 g_free(info->name);
952 g_free(info->author);
953 g_free(info->url);
954 g_free(info->status);
956 g_free(info);
959 #undef FGETS_INFOFILE_LINE
961 static gchar *prefs_themes_get_theme_stats(const gchar *dirname)
963 gchar *stats;
964 DirInfo *dinfo;
965 gint i;
967 dinfo = g_new0(DirInfo, 1);
968 dinfo->supported = stock_pixmap_theme_extensions();
969 for (i = 0; (dinfo->supported)[i] != NULL; ++i);
970 dinfo->length = g_malloc(i * sizeof(gint));
971 for (i = 0; (dinfo->supported)[i] != NULL; ++i) {
972 (dinfo->length)[i] = strlen((dinfo->supported)[i]);
974 prefs_themes_foreach_file(dirname, prefs_themes_file_stats, dinfo);
975 stats = g_strdup_printf(_("%d files (%d icons), size: %s"),
976 dinfo->files, dinfo->pixms,
977 to_human_readable((goffset)dinfo->bytes));
978 g_free(dinfo->length);
979 g_free(dinfo);
980 return stats;
983 static void prefs_themes_create_widget(PrefsPage *page, GtkWindow *window, gpointer data)
985 ThemesPage *prefs_themes = (ThemesPage *)page;
986 ThemesData *tdata = prefs_themes_data;
988 GtkWidget *vbox1;
989 GtkWidget *frame1;
990 GtkWidget *vbox2;
991 GtkWidget *hbox3;
992 GtkWidget *menu_themes;
993 GtkWidget *btn_install;
994 GtkWidget *btn_more;
995 GtkWidget *label_global_status;
996 GtkWidget *frame_info;
997 GtkWidget *table1;
998 GtkWidget *label1;
999 GtkWidget *label2;
1000 GtkWidget *label3;
1001 GtkWidget *label_name;
1002 GtkWidget *label_author;
1003 GtkWidget *label_url;
1004 GtkWidget *label4;
1005 GtkWidget *label_status;
1006 GtkWidget *frame_preview;
1007 GtkWidget *hbox1;
1008 GtkWidget *icon_1;
1009 GtkWidget *icon_2;
1010 GtkWidget *icon_3;
1011 GtkWidget *icon_4;
1012 GtkWidget *icon_5;
1013 GtkWidget *icon_6;
1014 GtkWidget *icon_7;
1015 GtkWidget *btn_viewall;
1016 GtkWidget *frame_buttons;
1017 GtkWidget *hbuttonbox1;
1018 GtkWidget *btn_remove;
1019 GtkCellRenderer *renderer;
1020 #ifdef HAVE_SVG
1021 GtkWidget *frame_scaling;
1022 GtkWidget *checkbtn_enable_alpha;
1023 GtkWidget *checkbtn_enable_scaling;
1024 GtkWidget *checkbtn_scaling_auto;
1025 GtkWidget *label_scaling_ppi;
1026 GtkWidget *spinbtn_scaling_ppi;
1027 GtkAdjustment *spinbtn_scaling_ppi_adj;
1028 #endif
1030 vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, VSPACING);
1031 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5);
1032 gtk_widget_show (vbox1);
1034 vbox2 = gtkut_get_options_frame(vbox1, &frame1, _("Selector"));
1036 hbox3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
1037 gtk_widget_show (hbox3);
1038 gtk_box_pack_start (GTK_BOX (vbox2), hbox3, FALSE, FALSE, 0);
1039 // gtk_container_set_border_width (GTK_CONTAINER (hbox3), 5);
1041 menu_themes = gtk_combo_box_new();
1042 gtk_widget_show (menu_themes);
1043 gtk_box_pack_start (GTK_BOX (hbox3), menu_themes, FALSE, FALSE, 0);
1045 btn_install = gtk_button_new_with_label (_("Install new..."));
1046 gtk_widget_show (btn_install);
1047 gtk_box_pack_start (GTK_BOX (hbox3), btn_install, FALSE, FALSE, 0);
1048 gtk_widget_set_can_default (btn_install, TRUE);
1050 btn_more = gtk_link_button_new_with_label(THEMES_URI, _("Get more..."));
1051 gtk_widget_show (btn_more);
1052 gtk_box_pack_start (GTK_BOX (hbox3), btn_more, FALSE, FALSE, 0);
1054 label_global_status = gtk_label_new ("");
1055 gtk_widget_show (label_global_status);
1056 gtk_box_pack_start (GTK_BOX (vbox2), label_global_status, FALSE, FALSE, 0);
1057 gtk_label_set_justify (GTK_LABEL (label_global_status), GTK_JUSTIFY_LEFT);
1058 gtk_label_set_xalign (GTK_LABEL (label_global_status), 0.0);
1059 gtk_widget_set_margin_start(GTK_WIDGET(label_global_status), 1);
1060 gtk_widget_set_margin_end(GTK_WIDGET(label_global_status), 0);
1062 PACK_FRAME(vbox1, frame_info, _("Information"));
1064 table1 = gtk_grid_new();
1065 gtk_widget_show (table1);
1066 gtk_container_add (GTK_CONTAINER (frame_info), table1);
1067 gtk_container_set_border_width (GTK_CONTAINER (table1), 5);
1068 gtk_grid_set_row_spacing(GTK_GRID(table1), 4);
1069 gtk_grid_set_column_spacing(GTK_GRID(table1), 8);
1071 label1 = gtk_label_new (_("Name"));
1072 gtk_widget_show (label1);
1073 gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_LEFT);
1074 gtk_label_set_xalign (GTK_LABEL (label1), 1.0);
1075 gtk_grid_attach(GTK_GRID(table1), label1, 0, 0, 1, 1);
1077 label2 = gtk_label_new (_("Author"));
1078 gtk_widget_show (label2);
1079 gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT);
1080 gtk_label_set_xalign (GTK_LABEL (label2), 1.0);
1081 gtk_grid_attach(GTK_GRID(table1), label2, 0, 1, 1, 1);
1083 label3 = gtk_label_new (_("URL"));
1084 gtk_widget_show (label3);
1085 gtk_label_set_xalign (GTK_LABEL (label3), 1.0);
1086 gtk_grid_attach(GTK_GRID(table1), label3, 0, 2, 1, 1);
1088 label_name = gtk_label_new ("");
1089 gtk_widget_show (label_name);
1090 gtk_label_set_xalign (GTK_LABEL (label_name), 0.0);
1091 gtk_grid_attach(GTK_GRID(table1), label_name, 1, 0, 1, 1);
1092 gtk_widget_set_hexpand(label_name, TRUE);
1093 gtk_widget_set_halign(label_name, GTK_ALIGN_FILL);
1095 label_author = gtk_label_new ("");
1096 gtk_widget_show (label_author);
1097 gtk_label_set_xalign (GTK_LABEL (label_author), 0.0);
1098 gtk_grid_attach(GTK_GRID(table1), label_author, 1, 1, 1, 1);
1099 gtk_widget_set_hexpand(label_author, TRUE);
1100 gtk_widget_set_halign(label_author, GTK_ALIGN_FILL);
1102 label_url = gtk_label_new ("");
1103 gtk_widget_show (label_url);
1104 gtk_label_set_xalign (GTK_LABEL (label_url), 0.0);
1105 gtk_grid_attach(GTK_GRID(table1), label_url, 1, 2, 1, 1);
1106 gtk_widget_set_hexpand(label_url, TRUE);
1107 gtk_widget_set_halign(label_url, GTK_ALIGN_FILL);
1109 label4 = gtk_label_new (_("Status"));
1110 gtk_widget_show (label4);
1111 gtk_label_set_xalign (GTK_LABEL (label4), 1.0);
1112 gtk_grid_attach(GTK_GRID(table1), label4, 0, 3, 1, 1);
1114 label_status = gtk_label_new ("");
1115 gtk_widget_show (label_status);
1116 gtk_label_set_xalign (GTK_LABEL (label_status), 0.0);
1117 gtk_grid_attach(GTK_GRID(table1), label_status, 1, 3, 1, 1);
1118 gtk_widget_set_hexpand(label_status, TRUE);
1119 gtk_widget_set_halign(label_status, GTK_ALIGN_FILL);
1121 PACK_FRAME(vbox1, frame_preview, _("Preview"));
1123 hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1124 gtk_widget_show (hbox1);
1125 gtk_container_add (GTK_CONTAINER (frame_preview), hbox1);
1126 gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5);
1128 icon_1 = gtk_image_new();
1129 gtk_widget_show (icon_1);
1130 gtk_box_pack_start (GTK_BOX (hbox1), icon_1, TRUE, TRUE, 2);
1131 gtk_widget_set_margin_start(GTK_WIDGET(icon_1), 0);
1132 gtk_widget_set_margin_end(GTK_WIDGET(icon_1), 5);
1134 icon_2 = gtk_image_new();
1135 gtk_widget_show (icon_2);
1136 gtk_box_pack_start (GTK_BOX (hbox1), icon_2, TRUE, TRUE, 2);
1137 gtk_widget_set_margin_start(GTK_WIDGET(icon_2), 0);
1138 gtk_widget_set_margin_end(GTK_WIDGET(icon_2), 5);
1140 icon_3 = gtk_image_new();
1141 gtk_widget_show (icon_3);
1142 gtk_box_pack_start (GTK_BOX (hbox1), icon_3, TRUE, TRUE, 2);
1143 gtk_widget_set_margin_start(GTK_WIDGET(icon_3), 0);
1144 gtk_widget_set_margin_end(GTK_WIDGET(icon_3), 5);
1146 icon_4 = gtk_image_new();
1147 gtk_widget_show (icon_4);
1148 gtk_box_pack_start (GTK_BOX (hbox1), icon_4, TRUE, TRUE, 2);
1149 gtk_widget_set_margin_start(GTK_WIDGET(icon_4), 0);
1150 gtk_widget_set_margin_end(GTK_WIDGET(icon_4), 5);
1152 icon_5 = gtk_image_new();
1153 gtk_widget_show (icon_5);
1154 gtk_box_pack_start (GTK_BOX (hbox1), icon_5, TRUE, TRUE, 2);
1155 gtk_widget_set_margin_start(GTK_WIDGET(icon_5), 0);
1156 gtk_widget_set_margin_end(GTK_WIDGET(icon_5), 5);
1158 icon_6 = gtk_image_new();
1159 gtk_widget_show (icon_6);
1160 gtk_box_pack_start (GTK_BOX (hbox1), icon_6, TRUE, TRUE, 2);
1161 gtk_widget_set_margin_start(GTK_WIDGET(icon_6), 0);
1162 gtk_widget_set_margin_end(GTK_WIDGET(icon_6), 5);
1164 icon_7 = gtk_image_new();
1165 gtk_widget_show (icon_7);
1166 gtk_box_pack_start (GTK_BOX (hbox1), icon_7, TRUE, TRUE, 2);
1167 gtk_widget_set_margin_start(GTK_WIDGET(icon_7), 0);
1168 gtk_widget_set_margin_end(GTK_WIDGET(icon_7), 5);
1170 PACK_FRAME(vbox1, frame_buttons, _("Actions"));
1172 hbuttonbox1 = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
1173 gtk_widget_show (hbuttonbox1);
1174 gtk_container_add (GTK_CONTAINER (frame_buttons), hbuttonbox1);
1175 gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 8);
1176 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_START);
1177 gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 5);
1179 btn_remove = gtkut_stock_button("list-remove", _("_Remove"));
1180 gtk_widget_show (btn_remove);
1181 gtk_container_add (GTK_CONTAINER (hbuttonbox1), btn_remove);
1182 gtk_widget_set_can_default (btn_remove, TRUE);
1184 btn_viewall = gtk_button_new_with_label(_("View all"));
1185 gtk_widget_show (btn_viewall);
1186 gtk_box_pack_start (GTK_BOX (hbuttonbox1), btn_viewall, FALSE, FALSE, 5);
1188 #ifdef HAVE_SVG
1189 PACK_FRAME(vbox1, frame_scaling, _("SVG rendering"));
1191 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, VSPACING);
1192 gtk_widget_show (vbox2);
1193 gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5);
1194 gtk_container_add (GTK_CONTAINER (frame_scaling), vbox2);
1196 PACK_CHECK_BUTTON(vbox2, checkbtn_enable_alpha, _("Enable alpha channel"));
1197 PACK_CHECK_BUTTON(vbox2, checkbtn_enable_scaling, _("Force scaling"));
1198 PACK_CHECK_BUTTON(vbox2, checkbtn_scaling_auto, _("Automatic"));
1200 hbox3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
1201 gtk_widget_show (hbox3);
1203 label_scaling_ppi = gtk_label_new (_("Pixels per inch (PPI)"));
1204 gtk_widget_show (label_scaling_ppi);
1205 gtk_box_pack_start (GTK_BOX (hbox3), label_scaling_ppi,
1206 FALSE, FALSE, 5);
1208 spinbtn_scaling_ppi_adj = GTK_ADJUSTMENT(
1209 gtk_adjustment_new (MIN_PPI, MIN_PPI, MAX_PPI, 1, 10, 0));
1210 spinbtn_scaling_ppi = gtk_spin_button_new(
1211 spinbtn_scaling_ppi_adj, 1.0, 0);
1212 gtk_widget_show (spinbtn_scaling_ppi);
1213 gtk_box_pack_start (GTK_BOX (hbox3), spinbtn_scaling_ppi,
1214 FALSE, FALSE, 5);
1216 gtk_box_pack_start (GTK_BOX (vbox2), hbox3, FALSE, FALSE, 0);
1218 /* initialize widget values */
1219 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (checkbtn_enable_alpha),
1220 prefs_common.enable_alpha_svg);
1221 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (checkbtn_enable_scaling),
1222 prefs_common.enable_pixmap_scaling);
1223 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (checkbtn_scaling_auto),
1224 prefs_common.pixmap_scaling_auto);
1225 gtk_spin_button_set_value(GTK_SPIN_BUTTON (spinbtn_scaling_ppi),
1226 prefs_common.pixmap_scaling_ppi);
1228 /* sensitivity */
1229 gtk_widget_set_sensitive(checkbtn_scaling_auto,
1230 prefs_common.enable_pixmap_scaling);
1231 gtk_widget_set_sensitive(spinbtn_scaling_ppi,
1232 prefs_common.enable_pixmap_scaling
1233 && !prefs_common.pixmap_scaling_auto);
1234 gtk_widget_set_sensitive(label_scaling_ppi,
1235 prefs_common.enable_pixmap_scaling
1236 && !prefs_common.pixmap_scaling_auto);
1238 /* signals */
1239 g_signal_connect(G_OBJECT(checkbtn_enable_scaling), "toggled",
1240 G_CALLBACK(prefs_themes_checkbtn_enable_scaling_toggled_cb),
1241 prefs_themes);
1242 g_signal_connect(G_OBJECT(checkbtn_scaling_auto), "toggled",
1243 G_CALLBACK(prefs_themes_checkbtn_scaling_auto_toggled_cb),
1244 prefs_themes);
1245 #endif
1247 g_signal_connect(G_OBJECT(btn_remove), "clicked",
1248 G_CALLBACK(prefs_themes_btn_remove_clicked_cb),
1249 NULL);
1250 g_signal_connect(G_OBJECT(btn_install), "clicked",
1251 G_CALLBACK(prefs_themes_btn_install_clicked_cb),
1252 NULL);
1253 g_signal_connect(G_OBJECT(btn_viewall), "clicked",
1254 G_CALLBACK(prefs_themes_btn_viewall_clicked_cb),
1255 NULL);
1257 prefs_themes->window = GTK_WIDGET(window);
1259 prefs_themes->name = label_name;
1260 prefs_themes->author = label_author;
1261 prefs_themes->url = label_url;
1262 prefs_themes->status = label_status;
1263 prefs_themes->global = label_global_status;
1265 prefs_themes->icons[0] = icon_1;
1266 prefs_themes->icons[1] = icon_2;
1267 prefs_themes->icons[2] = icon_3;
1268 prefs_themes->icons[3] = icon_4;
1269 prefs_themes->icons[4] = icon_5;
1270 prefs_themes->icons[5] = icon_6;
1271 prefs_themes->icons[6] = icon_7;
1273 prefs_themes->btn_remove = btn_remove;
1274 prefs_themes->btn_install = btn_install;
1275 prefs_themes->btn_more = btn_more;
1277 prefs_themes->op_menu = menu_themes;
1279 #ifdef HAVE_SVG
1280 prefs_themes->checkbtn_enable_alpha = checkbtn_enable_alpha;
1281 prefs_themes->checkbtn_enable_scaling = checkbtn_enable_scaling;
1282 prefs_themes->checkbtn_scaling_auto = checkbtn_scaling_auto;
1283 prefs_themes->label_scaling_ppi = label_scaling_ppi;
1284 prefs_themes->spinbtn_scaling_ppi = spinbtn_scaling_ppi;
1285 #endif
1287 prefs_themes->page.widget = vbox1;
1289 prefs_themes_set_themes_menu(GTK_COMBO_BOX(menu_themes), tdata);
1290 renderer = gtk_cell_renderer_text_new();
1291 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(menu_themes), renderer, TRUE);
1292 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(menu_themes), renderer,
1293 "text", 0, NULL);
1295 prefs_themes_get_theme_info(tdata);
1296 prefs_themes_display_global_stats(tdata);
1299 static void prefs_themes_destroy_widget(PrefsPage *page)
1301 /* ThemesPage *theme = (ThemesPage *)page; */
1304 static void prefs_themes_save(PrefsPage *page)
1306 ThemesData *tdata = prefs_themes_data;
1307 gchar *theme_str = tdata->displayed;
1308 #ifdef HAVE_SVG
1309 ThemesPage *tpage = (ThemesPage *) page;
1310 gboolean alpha = prefs_common.enable_alpha_svg;
1311 gboolean scaling = prefs_common.enable_pixmap_scaling;
1312 gboolean scaling_auto = prefs_common.pixmap_scaling_auto;
1313 gint scaling_ppi = prefs_common.pixmap_scaling_ppi;
1315 prefs_common.enable_alpha_svg = gtk_toggle_button_get_active(
1316 GTK_TOGGLE_BUTTON (tpage->checkbtn_enable_alpha));
1317 prefs_common.enable_pixmap_scaling = gtk_toggle_button_get_active(
1318 GTK_TOGGLE_BUTTON (tpage->checkbtn_enable_scaling));
1319 prefs_common.pixmap_scaling_auto = gtk_toggle_button_get_active(
1320 GTK_TOGGLE_BUTTON (tpage->checkbtn_scaling_auto));
1321 prefs_common.pixmap_scaling_ppi = gtk_spin_button_get_value_as_int (
1322 GTK_SPIN_BUTTON (tpage->spinbtn_scaling_ppi));
1323 #endif
1325 if (!IS_CURRENT_THEME(theme_str)) {
1326 debug_print("Changing theme to %s\n", theme_str);
1327 g_free(prefs_common.pixmap_theme_path);
1329 prefs_common.pixmap_theme_path = g_strdup(theme_str);
1331 main_window_reflect_prefs_all_real(TRUE);
1332 compose_reflect_prefs_pixmap_theme();
1333 addrcompl_reflect_prefs_pixmap_theme();
1335 prefs_themes_update_buttons(tdata);
1337 #ifdef HAVE_SVG
1338 else if (scaling != prefs_common.enable_pixmap_scaling
1339 || alpha != prefs_common.enable_alpha_svg
1340 || (scaling_auto != prefs_common.pixmap_scaling_auto
1341 && scaling_ppi != prefs_common.pixmap_scaling_ppi)) {
1342 /* same theme, different scaling options */
1343 debug_print("Updating theme scaling\n");
1344 main_window_reflect_prefs_all_real(FALSE);
1345 compose_reflect_prefs_pixmap_theme();
1346 addrcompl_reflect_prefs_pixmap_theme();
1348 #endif