Implement UI for icon and cursor themes.
[lxde/lxappearance.git] / src / icon-theme.c
1 /*
2 * icon-theme.c
3 *
4 * Copyright 2010 PCMan <pcman.tw@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "icon-theme.h"
23 #include "lxappearance2.h"
24 #include <string.h>
25
26 gint icon_theme_cmp_name(IconTheme* t, const char* name)
27 {
28 return strcmp(t->name, name);
29 }
30
31 gint icon_theme_cmp_disp_name(IconTheme* t1, IconTheme* t2)
32 {
33 return g_utf8_collate(t1->disp_name, t2->disp_name);
34 }
35
36 static void icon_theme_free(IconTheme* theme)
37 {
38 g_free(theme->comment);
39 g_free(theme->name);
40 if(theme->disp_name != theme->name)
41 g_free(theme->disp_name);
42 g_slice_free(IconTheme, theme);
43 }
44
45 static void load_icon_themes_from_dir(const char* theme_dir, GKeyFile* kf)
46 {
47 GDir* dir = g_dir_open(theme_dir, 0, NULL);
48 if(dir)
49 {
50 const char* name;
51 while(name = g_dir_read_name(dir))
52 {
53 /* skip "default" */
54 if(G_UNLIKELY(strcmp(name, "default") == 0))
55 continue;
56 /* test if we already have this in list */
57 if(!g_slist_find_custom(app.icon_themes, name, (GCompareFunc)icon_theme_cmp_name))
58 {
59 IconTheme* theme = g_slice_new0(IconTheme);
60 char* index_theme;
61 char* cursor_subdir;
62
63 theme->name = g_strdup(name);
64 index_theme = g_build_filename(theme_dir, name, "index.theme", NULL);
65 if(g_key_file_load_from_file(kf, index_theme, 0, NULL))
66 {
67 /* skip hidden ones */
68 if(!g_key_file_get_boolean(kf, "Icon Theme", "Hidden", NULL))
69 {
70 theme->disp_name = g_key_file_get_locale_string(kf, "Icon Theme", "Name", NULL, NULL);
71 /* test if this is a icon theme or it's a cursor theme */
72 theme->comment = g_key_file_get_locale_string(kf, "Icon Theme", "Comment", NULL, NULL);
73
74 /* icon theme must have this key, so it has icons if it has this key */
75 theme->has_icon = g_key_file_has_key(kf, "Icon Theme", "Directories", NULL);
76 }
77 }
78 else
79 theme->disp_name = theme->name;
80 g_free(index_theme);
81
82 cursor_subdir = g_build_filename(theme_dir, name, "cursors", NULL);
83 /* it contains a cursor theme */
84 if(g_file_test(cursor_subdir, G_FILE_TEST_IS_DIR))
85 theme->has_cursor = TRUE;
86 g_free(cursor_subdir);
87
88 if(theme->has_icon || theme->has_cursor)
89 app.icon_themes = g_slist_prepend(app.icon_themes, theme);
90 else /* this dir contains no icon or cursor theme, drop it. */
91 icon_theme_free(theme);
92 }
93 }
94 g_dir_close(dir);
95 }
96 }
97
98 static void load_icon_themes()
99 {
100 const char* const *dirs = g_get_system_data_dirs();
101 const char* const *pdir;
102 char* dir_path;
103 GKeyFile* kf = g_key_file_new();
104
105 dir_path = g_build_filename(g_get_home_dir(), ".icons", NULL);
106 load_icon_themes_from_dir(dir_path, kf);
107 g_free(dir_path);
108
109 dir_path = g_build_filename(g_get_user_data_dir(), "icons", NULL);
110 load_icon_themes_from_dir(dir_path, kf);
111 g_free(dir_path);
112
113 for(pdir = dirs; *pdir; ++pdir)
114 {
115 dir_path = g_build_filename(*pdir, "icons", NULL);
116 load_icon_themes_from_dir(dir_path, kf);
117 g_free(dir_path);
118 }
119 g_key_file_free(kf);
120
121 app.icon_themes = g_slist_sort(app.icon_themes, (GCompareFunc)icon_theme_cmp_disp_name);
122 }
123
124 static void icon_sizes_init(GtkBuilder* b)
125 {
126 const char* names[] = {
127 "gtk-menu",
128 "gtk-button",
129 "gtk-small-toolbar",
130 "gtk-large-toolbar",
131 "gtk-dnd",
132 "gtk-dialog"
133 };
134 char* sizes_str;
135 g_object_get(gtk_settings_get_default(), "gtk-icon-sizes", &sizes_str);
136 g_debug("%s", sizes_str);
137 }
138
139 void icon_theme_init(GtkBuilder* b)
140 {
141 GSList* l;
142 GtkTreeIter it;
143 GtkTreeIter icon_theme_sel_it = {0};
144 GtkTreeIter cursor_theme_sel_it = {0};
145 GtkTreeSelection* sel;
146
147 app.icon_theme_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
148 app.cursor_theme_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
149 app.icon_theme_view = GTK_WIDGET(gtk_builder_get_object(b, "icon_theme_view"));
150 app.cursor_theme_view = GTK_WIDGET(gtk_builder_get_object(b, "cursor_theme_view"));
151
152 /* load icon themes */
153 load_icon_themes();
154
155 for(l = app.icon_themes; l; l=l->next)
156 {
157 IconTheme* theme = (IconTheme*)l->data;
158
159 if(theme->has_icon)
160 {
161 gtk_list_store_insert_with_values(app.icon_theme_store, &it, -1, 0, theme->disp_name, 1, theme, -1);
162 if(!icon_theme_sel_it.user_data)
163 {
164 if(strcmp(theme->name, app.icon_theme) == 0)
165 icon_theme_sel_it = it;
166 }
167 }
168
169 if(theme->has_cursor)
170 {
171 gtk_list_store_insert_with_values(app.cursor_theme_store, &it, -1, 0, theme->disp_name, 1, theme, -1);
172 if(!cursor_theme_sel_it.user_data)
173 {
174 if(g_strcmp0(theme->name, app.cursor_theme) == 0)
175 cursor_theme_sel_it = it;
176 }
177 }
178 }
179
180 /* select the currently used theme from the list */
181 gtk_tree_view_set_model(app.icon_theme_view, GTK_TREE_MODEL(app.icon_theme_store));
182 sel = gtk_tree_view_get_selection(app.icon_theme_view);
183 if(icon_theme_sel_it.user_data)
184 gtk_tree_selection_select_iter(sel, &icon_theme_sel_it);
185
186 gtk_tree_view_set_model(app.cursor_theme_view, GTK_TREE_MODEL(app.cursor_theme_store));
187 sel = gtk_tree_view_get_selection(app.cursor_theme_view);
188 if(cursor_theme_sel_it.user_data)
189 gtk_tree_selection_select_iter(sel, &cursor_theme_sel_it);
190
191 /* load "gtk-icon-sizes" */
192 icon_sizes_init(b);
193 }