Fix error creation and warning
[claws.git] / src / prefs_themes.c
blob5e0147ec867ce165d2d9635cd8e3db73dc793b90
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2022 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 if (IS_SYSTEM_THEME(theme_str)) {
504 alert_title = g_strdup_printf(_("Remove system theme '%s'"), tmp);
505 } else {
506 alert_title = g_strdup_printf(_("Remove theme '%s'"), tmp);
508 g_free(tmp);
510 val = alertpanel(alert_title,
511 _("Are you sure you want to remove this theme?"),
512 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL, ALERTFOCUS_FIRST);
513 g_free(alert_title);
515 if (G_ALERTALTERNATE == val) {
516 gchar *status = NULL;
518 prefs_themes_foreach_file(theme_str, prefs_themes_file_remove, &status);
519 if (0 != rmdir(theme_str)) {
520 if (status != NULL) {
521 alertpanel_error(_("File %s failed\nwhile removing theme."), status);
522 g_free(status);
524 else
525 alertpanel_error(_("Removing theme directory failed."));
527 else {
528 alertpanel_notice(_("Theme removed successfully"));
529 /* update interface back to first theme */
530 prefs_themes_get_themes_and_names(tdata);
531 prefs_themes_set_themes_menu(GTK_COMBO_BOX(tdata->page->op_menu), tdata);
532 prefs_themes_display_global_stats(tdata);
533 tdata->displayed = (gchar *)((g_list_first(tdata->themes))->data);
534 prefs_themes_get_theme_info(tdata);
539 static void prefs_themes_btn_install_clicked_cb(GtkWidget *widget, gpointer data)
541 gchar *filename, *source;
542 gchar *themeinfo, *themename;
543 gchar *alert_title = NULL;
544 CopyInfo *cinfo;
545 AlertValue val = 0;
546 ThemesData *tdata = prefs_themes_data;
548 filename = filesel_select_file_open_folder(_("Select theme folder"), NULL);
549 if (filename == NULL)
550 return;
552 if (filename[strlen(filename) - 1] != G_DIR_SEPARATOR)
553 filename = g_strconcat(filename, G_DIR_SEPARATOR_S, NULL);
554 else
555 filename = g_strdup(filename);
557 cinfo = g_new0(CopyInfo, 1);
558 source = g_path_get_dirname(filename);
559 themename = g_path_get_basename(source);
560 debug_print("Installing '%s' theme from %s\n", themename, filename);
562 themeinfo = g_strconcat(source, G_DIR_SEPARATOR_S, THEMEINFO_FILE, NULL);
563 alert_title = g_strdup_printf(_("Install theme '%s'"), themename);
564 if (file_exist(themeinfo, FALSE) == FALSE) {
565 val = alertpanel(alert_title,
566 _("This folder doesn't seem to be a theme"
567 "folder.\nInstall anyway?"),
568 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL, ALERTFOCUS_FIRST);
569 if (G_ALERTALTERNATE != val) {
570 g_free(alert_title);
571 goto end_inst;
575 val = alertpanel(alert_title,
576 _("Do you want to install theme for all users?"),
577 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL, ALERTFOCUS_FIRST);
578 g_free(alert_title);
579 switch (val) {
580 case G_ALERTALTERNATE:
581 cinfo->dest = stock_pixmap_get_system_theme_dir_for_theme(
582 themename);
583 break;
584 case G_ALERTDEFAULT:
585 break;
586 default:
587 goto end_inst;
590 if (cinfo->dest == NULL) {
591 cinfo->dest = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
592 PIXMAP_THEME_DIR, G_DIR_SEPARATOR_S,
593 themename, NULL);
595 if (TRUE == is_dir_exist(cinfo->dest)) {
596 AlertValue val = alertpanel_full(_("Theme exists"),
597 _("A theme with the same name is\n"
598 "already installed in this location.\n\n"
599 "Do you want to replace it?"),
600 NULL, _("_Cancel"), NULL, _("Overwrite"), NULL, NULL,
601 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_WARNING);
602 if (val == G_ALERTALTERNATE) {
603 if (remove_dir_recursive(cinfo->dest) < 0) {
604 alertpanel_error(_("Couldn't delete the old theme in %s."),
605 cinfo->dest);
606 goto end_inst;
608 } else {
609 goto end_inst;
612 if (0 != make_dir_hier(cinfo->dest)) {
613 alertpanel_error(_("Couldn't create destination directory %s."),
614 cinfo->dest);
615 goto end_inst;
617 prefs_themes_foreach_file(source, prefs_themes_file_install, cinfo);
618 if (cinfo->status == NULL) {
619 GList *insted;
621 /* update interface to show newly installed theme */
622 prefs_themes_get_themes_and_names(tdata);
623 insted = g_list_find_custom(tdata->themes,
624 (gpointer)(cinfo->dest),
625 (GCompareFunc)g_strcmp0);
626 if (NULL != insted) {
627 alertpanel_notice(_("Theme installed successfully."));
628 tdata->displayed = (gchar *)(insted->data);
629 prefs_themes_set_themes_menu(GTK_COMBO_BOX(tdata->page->op_menu), tdata);
630 prefs_themes_display_global_stats(tdata);
631 prefs_themes_get_theme_info(tdata);
633 else
634 alertpanel_error(_("Failed installing theme"));
636 else
637 alertpanel_error(_("File %s failed\nwhile installing theme."), cinfo->status);
638 end_inst:
639 g_free(cinfo->dest);
640 g_free(filename);
641 g_free(source);
642 g_free(themeinfo);
643 g_free(cinfo);
644 g_free(themename);
647 static gboolean prefs_themes_viewall_key_pressed(GtkWidget *keywidget, GdkEventKey *event, GtkWidget **widget)
649 if (event && event->keyval == GDK_KEY_Escape) {
650 prefs_themes_viewall_close_btn_clicked(NULL, widget);
653 return FALSE;
656 static void prefs_themes_viewall_close_btn_clicked(GtkWidget *widget, gpointer data)
658 GtkWidget **window = (GtkWidget **) data;
660 cm_return_if_fail(window != NULL);
661 cm_return_if_fail(*window != NULL);
663 gtk_widget_destroy(*window);
664 *window = NULL;
667 #define ICONS_PER_ROW 19
669 static void prefs_themes_btn_viewall_clicked_cb(GtkWidget *widget, gpointer data)
671 static GtkWidget *viewall_win = NULL;
673 ThemesData *tdata = prefs_themes_data;
674 GtkWidget *vbox;
675 GtkWidget *hbox;
676 GtkWidget *icons[N_STOCK_PIXMAPS];
677 GdkPixbuf *pixbufs[N_STOCK_PIXMAPS];
678 GtkWidget *separator;
679 GtkWidget *confirm_area;
680 GtkWidget *close_btn;
681 gchar *save_prefs_path;
682 gint i;
684 viewall_win = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "prefs_themes_view_all");
685 gtk_container_set_border_width(GTK_CONTAINER(viewall_win), 5);
686 gtk_window_set_title(GTK_WINDOW(viewall_win), _("View all theme icons"));
687 gtk_window_set_position(GTK_WINDOW(viewall_win), GTK_WIN_POS_CENTER);
689 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
690 gtk_widget_show(vbox);
691 gtk_container_add(GTK_CONTAINER(viewall_win), vbox);
693 save_prefs_path = prefs_common.pixmap_theme_path;
694 prefs_common.pixmap_theme_path = tdata->displayed;
695 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
696 gtk_widget_show(hbox);
697 for (i = 0; i < N_STOCK_PIXMAPS; ++i) {
698 icons[i] = gtk_image_new();
699 gtk_widget_show (icons[i]);
700 stock_pixbuf_gdk(i, &(pixbufs[i]));
701 gtk_image_set_from_pixbuf(GTK_IMAGE(icons[i]), pixbufs[i]);
702 gtk_box_pack_start(GTK_BOX(hbox), icons[i], TRUE, TRUE, 5);
703 if ((i + 1) % ICONS_PER_ROW == 0) {
704 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 5);
705 if (i + 1 < N_STOCK_PIXMAPS) {
706 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
707 gtk_widget_show(hbox);
711 prefs_common.pixmap_theme_path = save_prefs_path;
713 separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
714 gtk_widget_show(separator);
715 gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, FALSE, 0);
717 gtkut_stock_button_set_create(&confirm_area,
718 &close_btn, "window-close", _("_Close"),
719 NULL, NULL, NULL, NULL, NULL, NULL);
720 gtk_box_pack_start(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 5);
721 gtk_widget_show(confirm_area);
722 gtk_widget_grab_default(close_btn);
723 gtk_widget_grab_focus(close_btn);
725 g_signal_connect(G_OBJECT(close_btn), "clicked",
726 G_CALLBACK(prefs_themes_viewall_close_btn_clicked),
727 &viewall_win);
728 g_signal_connect(G_OBJECT(viewall_win), "key_press_event",
729 G_CALLBACK(prefs_themes_viewall_key_pressed),
730 &viewall_win);
732 manage_window_set_transient(GTK_WINDOW(viewall_win));
733 gtk_window_set_modal(GTK_WINDOW(viewall_win), TRUE);
734 gtk_widget_show(viewall_win);
737 static void prefs_themes_menu_item_activated_cb(GtkWidget *widget, gpointer data)
739 ThemesData *tdata = prefs_themes_data;
740 gchar *path;
741 GtkTreeModel *model;
742 GtkTreeIter iter;
744 cm_return_if_fail(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter));
746 model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
747 gtk_tree_model_get(model, &iter, 1, &path, -1);
749 tdata->displayed = path;
750 prefs_themes_get_theme_info(tdata);
753 #ifdef HAVE_SVG
754 #define MM_INCH 0.0393700787402
755 static gdouble prefs_themes_compute_ppi(GdkScreen *screen)
757 GdkRectangle workarea = {0};
758 GdkMonitor *monitor = gdk_display_get_primary_monitor(gdk_display_get_default());
760 gdk_monitor_get_workarea(monitor, &workarea);
761 gdouble wp = workarea.width;
762 gdouble hp = workarea.height;
763 gdouble wi = gdk_monitor_get_width_mm(monitor);
764 gdouble hi = gdk_monitor_get_height_mm(monitor);
765 gdouble dp, di;
767 debug_print("screen is %f x %f pixels, %f x %f mm\n", wp, hp, wi, hi);
769 /* https://en.wikipedia.org/wiki/Pixel_density */
770 wi *= MM_INCH;
771 hi *= MM_INCH;
772 dp = sqrt(wp * wp + hp * hp);
773 di = sqrt(wi * wi + hi * hi);
775 return (di != 0.0)? dp / di: 0.0;
778 static gdouble prefs_themes_get_adjusted_ppi(void)
780 gdouble ppi, cppi;
781 GdkScreen * screen = gdk_screen_get_default();
783 if (screen == NULL) { /* oops! */
784 g_warning("unable to get default GDK screen");
785 return MIN_PPI;
788 ppi = gdk_screen_get_resolution(screen);
789 cppi = prefs_themes_compute_ppi(screen);
790 debug_print("returned PPI: %f / computed PPI: %f\n", ppi, cppi);
792 gdk_screen_get_resolution doesn't seem to work well when running
793 on a remote display and returns the value of the local display.
794 height/width functions do this better, so we can compute a PPI
795 from them and take the highest value.
797 return MAX(ppi, cppi);
800 static void prefs_themes_checkbtn_enable_scaling_toggled_cb (GtkWidget *widget, gpointer data)
802 ThemesPage *page = (ThemesPage *) data;
803 gboolean enabled = gtk_toggle_button_get_active(
804 GTK_TOGGLE_BUTTON (widget));
805 gboolean automatic = gtk_toggle_button_get_active(
806 GTK_TOGGLE_BUTTON (page->checkbtn_scaling_auto));
808 gtk_widget_set_sensitive(page->checkbtn_scaling_auto, enabled);
809 gtk_widget_set_sensitive(page->spinbtn_scaling_ppi, enabled && !automatic);
810 gtk_widget_set_sensitive(page->label_scaling_ppi, enabled && !automatic);
813 static void prefs_themes_checkbtn_scaling_auto_toggled_cb(GtkWidget *widget, gpointer data)
815 ThemesPage *page = (ThemesPage *) data;
816 gboolean automatic = gtk_toggle_button_get_active(
817 GTK_TOGGLE_BUTTON (widget));
819 gtk_widget_set_sensitive(page->spinbtn_scaling_ppi, !automatic);
820 gtk_widget_set_sensitive(page->label_scaling_ppi, !automatic);
822 if (automatic) /* update PPI value */
823 gtk_spin_button_set_value(
824 GTK_SPIN_BUTTON (page->spinbtn_scaling_ppi),
825 prefs_themes_get_adjusted_ppi());
827 #endif
829 static void prefs_themes_update_buttons(const ThemesData *tdata)
831 ThemesPage *theme = tdata->page;
832 gboolean can_rem, can_use;
834 can_use = !IS_CURRENT_THEME(tdata->displayed);
835 can_rem = can_use && !IS_INTERNAL_THEME(tdata->displayed);
837 if (theme->btn_remove != NULL)
838 gtk_widget_set_sensitive(theme->btn_remove, can_rem);
841 /* placeholders may already be utf8 (i18n) */
842 #define SET_LABEL_TEXT_UTF8(label, text) \
844 gchar *tmpstr; \
846 if (!g_utf8_validate(text, -1, NULL)) \
847 tmpstr = conv_codeset_strdup(text, \
848 conv_get_locale_charset_str(), CS_UTF_8); \
849 else \
850 tmpstr = g_strdup(text); \
852 gtk_label_set_text(GTK_LABEL(label), tmpstr); \
853 gtk_label_set_selectable(GTK_LABEL(label), TRUE); \
854 g_free(tmpstr); \
856 static void prefs_themes_display_theme_info(ThemesData *tdata, const ThemeInfo *info)
858 ThemesPage *theme = tdata->page;
859 gchar *save_prefs_path;
860 gint i;
862 SET_LABEL_TEXT_UTF8(theme->name, info->name);
863 SET_LABEL_TEXT_UTF8(theme->author, info->author);
864 SET_LABEL_TEXT_UTF8(theme->url, info->url);
865 SET_LABEL_TEXT_UTF8(theme->status, info->status);
867 save_prefs_path = prefs_common.pixmap_theme_path;
868 prefs_common.pixmap_theme_path = tdata->displayed;
869 for (i = 0; i < PREVIEW_ICONS; ++i) {
870 stock_pixbuf_gdk(prefs_themes_icons[i], &(theme->pixbufs[i]));
871 gtk_image_set_from_pixbuf(GTK_IMAGE(theme->icons[i]),
872 theme->pixbufs[i]);
874 prefs_common.pixmap_theme_path = save_prefs_path;
876 prefs_themes_update_buttons(tdata);
878 #undef SET_LABEL_TEXT_UTF8
880 static void prefs_themes_display_global_stats(const ThemesData *tdata)
882 ThemesPage *theme = tdata->page;
883 GList *tnames = tdata->names;
884 gchar *gstats;
885 gint sys = 0;
886 gint usr = 0;
887 gint all = 0;
889 while (tnames != NULL) {
890 ThemeName *tname = (ThemeName *)(tnames->data);
891 gchar *tpath = (gchar *)(tname->item->data);
893 if (IS_SYSTEM_THEME(tpath))
894 ++sys;
895 else if (!IS_INTERNAL_THEME(tpath))
896 ++usr;
897 ++all;
898 tnames = g_list_next(tnames);
901 gstats = g_strdup_printf(_("%d themes available (%d user, %d system, 1 internal)"),
902 all, usr, sys);
903 gtk_label_set_text(GTK_LABEL(theme->global), gstats);
904 gtk_label_set_justify (GTK_LABEL (theme->global), GTK_JUSTIFY_LEFT);
905 gtkut_widget_set_small_font_size (theme->global);
906 g_free(gstats);
909 #define INFOFILE_LINE_LEN 80
911 #define FGETS_INFOFILE_LINE() \
912 line[0] = '\0'; \
913 if (claws_fgets(line, INFOFILE_LINE_LEN, finfo) != NULL && (len = strlen(line)) > 0) { \
914 if (line[len - 1] == '\n') line[len - 1] = '\0'; \
916 else { \
917 g_strlcpy(line, _("Unknown"),sizeof(line)); \
920 static void prefs_themes_get_theme_info(ThemesData *tdata)
922 FILE *finfo;
923 gchar *sinfo;
924 gchar *path;
925 gchar line[INFOFILE_LINE_LEN];
926 gint len;
927 ThemeInfo *info;
928 ThemesPage *theme = tdata->page;
930 cm_return_if_fail(theme != NULL);
931 path = tdata->displayed;
932 cm_return_if_fail(path != NULL);
934 debug_print("Getting theme info for %s\n", path);
936 info = g_new0(ThemeInfo, 1);
938 if (IS_INTERNAL_THEME(path)) {
939 info->name = g_strdup(_("Default internal theme"));
940 info->author = g_strdup(_("The Claws Mail Team"));
941 info->url = g_strdup(HOMEPAGE_URI);
942 info->status = g_strdup_printf(_("Internal theme has %d icons"), N_STOCK_PIXMAPS);
944 else {
945 sinfo = g_strconcat(path, G_DIR_SEPARATOR_S, THEMEINFO_FILE, NULL);
946 finfo = claws_fopen(sinfo, "r");
947 if (finfo == NULL) {
948 info->name = g_strdup(_("No info file available for this theme"));
949 info->author = g_strdup(_("Unknown"));
950 info->url = g_strdup(_("Unknown"));
952 else {
953 FGETS_INFOFILE_LINE()
954 info->name = g_strdup(line);
955 FGETS_INFOFILE_LINE()
956 info->author = g_strdup(line);
957 FGETS_INFOFILE_LINE()
958 info->url = g_strdup(line);
960 claws_fclose(finfo);
962 g_free(sinfo);
964 info->status = prefs_themes_get_theme_stats(path);
965 if (info->status == NULL) {
966 info->status = g_strdup(_("Error: couldn't get theme status"));
970 prefs_themes_display_theme_info(tdata, info);
972 g_free(info->name);
973 g_free(info->author);
974 g_free(info->url);
975 g_free(info->status);
977 g_free(info);
980 #undef FGETS_INFOFILE_LINE
982 static gchar *prefs_themes_get_theme_stats(const gchar *dirname)
984 gchar *stats;
985 DirInfo *dinfo;
986 gint i;
988 dinfo = g_new0(DirInfo, 1);
989 dinfo->supported = stock_pixmap_theme_extensions();
990 for (i = 0; (dinfo->supported)[i] != NULL; ++i);
991 dinfo->length = g_malloc(i * sizeof(gint));
992 for (i = 0; (dinfo->supported)[i] != NULL; ++i) {
993 (dinfo->length)[i] = strlen((dinfo->supported)[i]);
995 prefs_themes_foreach_file(dirname, prefs_themes_file_stats, dinfo);
996 stats = g_strdup_printf(_("%d files (%d icons), size: %s"),
997 dinfo->files, dinfo->pixms,
998 to_human_readable((goffset)dinfo->bytes));
999 g_free(dinfo->length);
1000 g_free(dinfo);
1001 return stats;
1004 static void prefs_themes_create_widget(PrefsPage *page, GtkWindow *window, gpointer data)
1006 ThemesPage *prefs_themes = (ThemesPage *)page;
1007 ThemesData *tdata = prefs_themes_data;
1009 GtkWidget *vbox1;
1010 GtkWidget *frame1;
1011 GtkWidget *vbox2;
1012 GtkWidget *hbox3;
1013 GtkWidget *menu_themes;
1014 GtkWidget *btn_install;
1015 GtkWidget *btn_more;
1016 GtkWidget *label_global_status;
1017 GtkWidget *frame_info;
1018 GtkWidget *table1;
1019 GtkWidget *label1;
1020 GtkWidget *label2;
1021 GtkWidget *label3;
1022 GtkWidget *label_name;
1023 GtkWidget *label_author;
1024 GtkWidget *label_url;
1025 GtkWidget *label4;
1026 GtkWidget *label_status;
1027 GtkWidget *frame_preview;
1028 GtkWidget *hbox1;
1029 GtkWidget *icon_1;
1030 GtkWidget *icon_2;
1031 GtkWidget *icon_3;
1032 GtkWidget *icon_4;
1033 GtkWidget *icon_5;
1034 GtkWidget *icon_6;
1035 GtkWidget *icon_7;
1036 GtkWidget *btn_viewall;
1037 GtkWidget *frame_buttons;
1038 GtkWidget *hbuttonbox1;
1039 GtkWidget *btn_remove;
1040 GtkCellRenderer *renderer;
1041 #ifdef HAVE_SVG
1042 GtkWidget *frame_scaling;
1043 GtkWidget *checkbtn_enable_alpha;
1044 GtkWidget *checkbtn_enable_scaling;
1045 GtkWidget *checkbtn_scaling_auto;
1046 GtkWidget *label_scaling_ppi;
1047 GtkWidget *spinbtn_scaling_ppi;
1048 GtkAdjustment *spinbtn_scaling_ppi_adj;
1049 #endif
1051 vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, VSPACING);
1052 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5);
1053 gtk_widget_show (vbox1);
1055 vbox2 = gtkut_get_options_frame(vbox1, &frame1, _("Selector"));
1057 hbox3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
1058 gtk_widget_show (hbox3);
1059 gtk_box_pack_start (GTK_BOX (vbox2), hbox3, FALSE, FALSE, 0);
1060 // gtk_container_set_border_width (GTK_CONTAINER (hbox3), 5);
1062 menu_themes = gtk_combo_box_new();
1063 gtk_widget_show (menu_themes);
1064 gtk_box_pack_start (GTK_BOX (hbox3), menu_themes, FALSE, FALSE, 0);
1066 btn_install = gtk_button_new_with_label (_("Install new..."));
1067 gtk_widget_show (btn_install);
1068 gtk_box_pack_start (GTK_BOX (hbox3), btn_install, FALSE, FALSE, 0);
1069 gtk_widget_set_can_default (btn_install, TRUE);
1071 btn_more = gtk_link_button_new_with_label(THEMES_URI, _("Get more..."));
1072 gtk_widget_show (btn_more);
1073 gtk_box_pack_start (GTK_BOX (hbox3), btn_more, FALSE, FALSE, 0);
1075 label_global_status = gtk_label_new ("");
1076 gtk_widget_show (label_global_status);
1077 gtk_box_pack_start (GTK_BOX (vbox2), label_global_status, FALSE, FALSE, 0);
1078 gtk_label_set_justify (GTK_LABEL (label_global_status), GTK_JUSTIFY_LEFT);
1079 gtk_label_set_xalign (GTK_LABEL (label_global_status), 0.0);
1080 gtk_widget_set_margin_start(GTK_WIDGET(label_global_status), 1);
1081 gtk_widget_set_margin_end(GTK_WIDGET(label_global_status), 0);
1083 PACK_FRAME(vbox1, frame_info, _("Information"));
1085 table1 = gtk_grid_new();
1086 gtk_widget_show (table1);
1087 gtk_container_add (GTK_CONTAINER (frame_info), table1);
1088 gtk_container_set_border_width (GTK_CONTAINER (table1), 5);
1089 gtk_grid_set_row_spacing(GTK_GRID(table1), 4);
1090 gtk_grid_set_column_spacing(GTK_GRID(table1), 8);
1092 label1 = gtk_label_new (_("Name"));
1093 gtk_widget_show (label1);
1094 gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_LEFT);
1095 gtk_label_set_xalign (GTK_LABEL (label1), 1.0);
1096 gtk_grid_attach(GTK_GRID(table1), label1, 0, 0, 1, 1);
1098 label2 = gtk_label_new (_("Author"));
1099 gtk_widget_show (label2);
1100 gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT);
1101 gtk_label_set_xalign (GTK_LABEL (label2), 1.0);
1102 gtk_grid_attach(GTK_GRID(table1), label2, 0, 1, 1, 1);
1104 label3 = gtk_label_new (_("URL"));
1105 gtk_widget_show (label3);
1106 gtk_label_set_xalign (GTK_LABEL (label3), 1.0);
1107 gtk_grid_attach(GTK_GRID(table1), label3, 0, 2, 1, 1);
1109 label_name = gtk_label_new ("");
1110 gtk_widget_show (label_name);
1111 gtk_label_set_xalign (GTK_LABEL (label_name), 0.0);
1112 gtk_grid_attach(GTK_GRID(table1), label_name, 1, 0, 1, 1);
1113 gtk_widget_set_hexpand(label_name, TRUE);
1114 gtk_widget_set_halign(label_name, GTK_ALIGN_FILL);
1116 label_author = gtk_label_new ("");
1117 gtk_widget_show (label_author);
1118 gtk_label_set_xalign (GTK_LABEL (label_author), 0.0);
1119 gtk_grid_attach(GTK_GRID(table1), label_author, 1, 1, 1, 1);
1120 gtk_widget_set_hexpand(label_author, TRUE);
1121 gtk_widget_set_halign(label_author, GTK_ALIGN_FILL);
1123 label_url = gtk_label_new ("");
1124 gtk_widget_show (label_url);
1125 gtk_label_set_xalign (GTK_LABEL (label_url), 0.0);
1126 gtk_grid_attach(GTK_GRID(table1), label_url, 1, 2, 1, 1);
1127 gtk_widget_set_hexpand(label_url, TRUE);
1128 gtk_widget_set_halign(label_url, GTK_ALIGN_FILL);
1130 label4 = gtk_label_new (_("Status"));
1131 gtk_widget_show (label4);
1132 gtk_label_set_xalign (GTK_LABEL (label4), 1.0);
1133 gtk_grid_attach(GTK_GRID(table1), label4, 0, 3, 1, 1);
1135 label_status = gtk_label_new ("");
1136 gtk_widget_show (label_status);
1137 gtk_label_set_xalign (GTK_LABEL (label_status), 0.0);
1138 gtk_grid_attach(GTK_GRID(table1), label_status, 1, 3, 1, 1);
1139 gtk_widget_set_hexpand(label_status, TRUE);
1140 gtk_widget_set_halign(label_status, GTK_ALIGN_FILL);
1142 PACK_FRAME(vbox1, frame_preview, _("Preview"));
1144 hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1145 gtk_widget_show (hbox1);
1146 gtk_container_add (GTK_CONTAINER (frame_preview), hbox1);
1147 gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5);
1149 icon_1 = gtk_image_new();
1150 gtk_widget_show (icon_1);
1151 gtk_box_pack_start (GTK_BOX (hbox1), icon_1, TRUE, TRUE, 2);
1152 gtk_widget_set_margin_start(GTK_WIDGET(icon_1), 0);
1153 gtk_widget_set_margin_end(GTK_WIDGET(icon_1), 5);
1155 icon_2 = gtk_image_new();
1156 gtk_widget_show (icon_2);
1157 gtk_box_pack_start (GTK_BOX (hbox1), icon_2, TRUE, TRUE, 2);
1158 gtk_widget_set_margin_start(GTK_WIDGET(icon_2), 0);
1159 gtk_widget_set_margin_end(GTK_WIDGET(icon_2), 5);
1161 icon_3 = gtk_image_new();
1162 gtk_widget_show (icon_3);
1163 gtk_box_pack_start (GTK_BOX (hbox1), icon_3, TRUE, TRUE, 2);
1164 gtk_widget_set_margin_start(GTK_WIDGET(icon_3), 0);
1165 gtk_widget_set_margin_end(GTK_WIDGET(icon_3), 5);
1167 icon_4 = gtk_image_new();
1168 gtk_widget_show (icon_4);
1169 gtk_box_pack_start (GTK_BOX (hbox1), icon_4, TRUE, TRUE, 2);
1170 gtk_widget_set_margin_start(GTK_WIDGET(icon_4), 0);
1171 gtk_widget_set_margin_end(GTK_WIDGET(icon_4), 5);
1173 icon_5 = gtk_image_new();
1174 gtk_widget_show (icon_5);
1175 gtk_box_pack_start (GTK_BOX (hbox1), icon_5, TRUE, TRUE, 2);
1176 gtk_widget_set_margin_start(GTK_WIDGET(icon_5), 0);
1177 gtk_widget_set_margin_end(GTK_WIDGET(icon_5), 5);
1179 icon_6 = gtk_image_new();
1180 gtk_widget_show (icon_6);
1181 gtk_box_pack_start (GTK_BOX (hbox1), icon_6, TRUE, TRUE, 2);
1182 gtk_widget_set_margin_start(GTK_WIDGET(icon_6), 0);
1183 gtk_widget_set_margin_end(GTK_WIDGET(icon_6), 5);
1185 icon_7 = gtk_image_new();
1186 gtk_widget_show (icon_7);
1187 gtk_box_pack_start (GTK_BOX (hbox1), icon_7, TRUE, TRUE, 2);
1188 gtk_widget_set_margin_start(GTK_WIDGET(icon_7), 0);
1189 gtk_widget_set_margin_end(GTK_WIDGET(icon_7), 5);
1191 PACK_FRAME(vbox1, frame_buttons, _("Actions"));
1193 hbuttonbox1 = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
1194 gtk_widget_show (hbuttonbox1);
1195 gtk_container_add (GTK_CONTAINER (frame_buttons), hbuttonbox1);
1196 gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 8);
1197 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_START);
1198 gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 5);
1200 btn_remove = gtkut_stock_button("list-remove", _("_Remove"));
1201 gtk_widget_show (btn_remove);
1202 gtk_container_add (GTK_CONTAINER (hbuttonbox1), btn_remove);
1203 gtk_widget_set_can_default (btn_remove, TRUE);
1205 btn_viewall = gtk_button_new_with_label(_("View all"));
1206 gtk_widget_show (btn_viewall);
1207 gtk_box_pack_start (GTK_BOX (hbuttonbox1), btn_viewall, FALSE, FALSE, 5);
1209 #ifdef HAVE_SVG
1210 PACK_FRAME(vbox1, frame_scaling, _("SVG rendering"));
1212 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, VSPACING);
1213 gtk_widget_show (vbox2);
1214 gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5);
1215 gtk_container_add (GTK_CONTAINER (frame_scaling), vbox2);
1217 PACK_CHECK_BUTTON(vbox2, checkbtn_enable_alpha, _("Enable alpha channel"));
1218 PACK_CHECK_BUTTON(vbox2, checkbtn_enable_scaling, _("Force scaling"));
1219 PACK_CHECK_BUTTON(vbox2, checkbtn_scaling_auto, _("Automatic"));
1221 hbox3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
1222 gtk_widget_show (hbox3);
1224 label_scaling_ppi = gtk_label_new (_("Pixels per inch (PPI)"));
1225 gtk_widget_show (label_scaling_ppi);
1226 gtk_box_pack_start (GTK_BOX (hbox3), label_scaling_ppi,
1227 FALSE, FALSE, 5);
1229 spinbtn_scaling_ppi_adj = GTK_ADJUSTMENT(
1230 gtk_adjustment_new (MIN_PPI, MIN_PPI, MAX_PPI, 1, 10, 0));
1231 spinbtn_scaling_ppi = gtk_spin_button_new(
1232 spinbtn_scaling_ppi_adj, 1.0, 0);
1233 gtk_widget_show (spinbtn_scaling_ppi);
1234 gtk_box_pack_start (GTK_BOX (hbox3), spinbtn_scaling_ppi,
1235 FALSE, FALSE, 5);
1237 gtk_box_pack_start (GTK_BOX (vbox2), hbox3, FALSE, FALSE, 0);
1239 /* initialize widget values */
1240 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (checkbtn_enable_alpha),
1241 prefs_common.enable_alpha_svg);
1242 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (checkbtn_enable_scaling),
1243 prefs_common.enable_pixmap_scaling);
1244 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (checkbtn_scaling_auto),
1245 prefs_common.pixmap_scaling_auto);
1246 gtk_spin_button_set_value(GTK_SPIN_BUTTON (spinbtn_scaling_ppi),
1247 prefs_common.pixmap_scaling_ppi);
1249 /* sensitivity */
1250 gtk_widget_set_sensitive(checkbtn_scaling_auto,
1251 prefs_common.enable_pixmap_scaling);
1252 gtk_widget_set_sensitive(spinbtn_scaling_ppi,
1253 prefs_common.enable_pixmap_scaling
1254 && !prefs_common.pixmap_scaling_auto);
1255 gtk_widget_set_sensitive(label_scaling_ppi,
1256 prefs_common.enable_pixmap_scaling
1257 && !prefs_common.pixmap_scaling_auto);
1259 /* signals */
1260 g_signal_connect(G_OBJECT(checkbtn_enable_scaling), "toggled",
1261 G_CALLBACK(prefs_themes_checkbtn_enable_scaling_toggled_cb),
1262 prefs_themes);
1263 g_signal_connect(G_OBJECT(checkbtn_scaling_auto), "toggled",
1264 G_CALLBACK(prefs_themes_checkbtn_scaling_auto_toggled_cb),
1265 prefs_themes);
1266 #endif
1268 g_signal_connect(G_OBJECT(btn_remove), "clicked",
1269 G_CALLBACK(prefs_themes_btn_remove_clicked_cb),
1270 NULL);
1271 g_signal_connect(G_OBJECT(btn_install), "clicked",
1272 G_CALLBACK(prefs_themes_btn_install_clicked_cb),
1273 NULL);
1274 g_signal_connect(G_OBJECT(btn_viewall), "clicked",
1275 G_CALLBACK(prefs_themes_btn_viewall_clicked_cb),
1276 NULL);
1278 prefs_themes->window = GTK_WIDGET(window);
1280 prefs_themes->name = label_name;
1281 prefs_themes->author = label_author;
1282 prefs_themes->url = label_url;
1283 prefs_themes->status = label_status;
1284 prefs_themes->global = label_global_status;
1286 prefs_themes->icons[0] = icon_1;
1287 prefs_themes->icons[1] = icon_2;
1288 prefs_themes->icons[2] = icon_3;
1289 prefs_themes->icons[3] = icon_4;
1290 prefs_themes->icons[4] = icon_5;
1291 prefs_themes->icons[5] = icon_6;
1292 prefs_themes->icons[6] = icon_7;
1294 prefs_themes->btn_remove = btn_remove;
1295 prefs_themes->btn_install = btn_install;
1296 prefs_themes->btn_more = btn_more;
1298 prefs_themes->op_menu = menu_themes;
1300 #ifdef HAVE_SVG
1301 prefs_themes->checkbtn_enable_alpha = checkbtn_enable_alpha;
1302 prefs_themes->checkbtn_enable_scaling = checkbtn_enable_scaling;
1303 prefs_themes->checkbtn_scaling_auto = checkbtn_scaling_auto;
1304 prefs_themes->label_scaling_ppi = label_scaling_ppi;
1305 prefs_themes->spinbtn_scaling_ppi = spinbtn_scaling_ppi;
1306 #endif
1308 prefs_themes->page.widget = vbox1;
1310 prefs_themes_set_themes_menu(GTK_COMBO_BOX(menu_themes), tdata);
1311 renderer = gtk_cell_renderer_text_new();
1312 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(menu_themes), renderer, TRUE);
1313 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(menu_themes), renderer,
1314 "text", 0, NULL);
1316 prefs_themes_get_theme_info(tdata);
1317 prefs_themes_display_global_stats(tdata);
1320 static void prefs_themes_destroy_widget(PrefsPage *page)
1322 /* ThemesPage *theme = (ThemesPage *)page; */
1325 static void prefs_themes_save(PrefsPage *page)
1327 ThemesData *tdata = prefs_themes_data;
1328 gchar *theme_str = tdata->displayed;
1329 #ifdef HAVE_SVG
1330 ThemesPage *tpage = (ThemesPage *) page;
1331 gboolean alpha = prefs_common.enable_alpha_svg;
1332 gboolean scaling = prefs_common.enable_pixmap_scaling;
1333 gboolean scaling_auto = prefs_common.pixmap_scaling_auto;
1334 gint scaling_ppi = prefs_common.pixmap_scaling_ppi;
1336 prefs_common.enable_alpha_svg = gtk_toggle_button_get_active(
1337 GTK_TOGGLE_BUTTON (tpage->checkbtn_enable_alpha));
1338 prefs_common.enable_pixmap_scaling = gtk_toggle_button_get_active(
1339 GTK_TOGGLE_BUTTON (tpage->checkbtn_enable_scaling));
1340 prefs_common.pixmap_scaling_auto = gtk_toggle_button_get_active(
1341 GTK_TOGGLE_BUTTON (tpage->checkbtn_scaling_auto));
1342 prefs_common.pixmap_scaling_ppi = gtk_spin_button_get_value_as_int (
1343 GTK_SPIN_BUTTON (tpage->spinbtn_scaling_ppi));
1344 #endif
1346 if (!IS_CURRENT_THEME(theme_str)) {
1347 debug_print("Changing theme to %s\n", theme_str);
1348 g_free(prefs_common.pixmap_theme_path);
1350 prefs_common.pixmap_theme_path = g_strdup(theme_str);
1352 main_window_reflect_prefs_all_real(TRUE);
1353 compose_reflect_prefs_pixmap_theme();
1354 addrcompl_reflect_prefs_pixmap_theme();
1356 prefs_themes_update_buttons(tdata);
1358 #ifdef HAVE_SVG
1359 else if (scaling != prefs_common.enable_pixmap_scaling
1360 || alpha != prefs_common.enable_alpha_svg
1361 || (scaling_auto != prefs_common.pixmap_scaling_auto
1362 && scaling_ppi != prefs_common.pixmap_scaling_ppi)) {
1363 /* same theme, different scaling options */
1364 debug_print("Updating theme scaling\n");
1365 stock_pixmap_invalidate_all_icons();
1366 main_window_reflect_prefs_all_real(TRUE);
1367 compose_reflect_prefs_pixmap_theme();
1368 addrcompl_reflect_prefs_pixmap_theme();
1370 #endif