Finish color scheme support.
[lxde/lxappearance.git] / src / color-scheme.c
CommitLineData
15c155a6
HJYP
1// color-scheme.c
2//
3// Copyright 2010 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
4//
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 2 of the License, or
8// (at your option) any later version.
9//
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.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18// MA 02110-1301, USA.
19
20#include "lxappearance2.h"
21#include "color-scheme.h"
22#include <string.h>
23
c92e9c11
HJYP
24static GRegex* gtkrc_include_reg = NULL;
25static GRegex* gtkrc_color_scheme_reg = NULL;
26
71ce58a7
HJYP
27/* http://live.gnome.org/GnomeArt/Tutorials/GtkThemes/SymbolicColors/#Default_colors_in_GNOME */
28static const char* gnome_color_names[] = {
29 "fg_color", /* The base for the foreground colors. */
30 "bg_color", /* Color to generate the background colors from. */
31 "base_color", /* The base color. */
32 "text_color", /* The text color in input widgets. */
33 "selected_bg_color", /* Color for the background of selected text. */
34 "selected_fg_color", /* Color of selected text. */
35 "tooltip_bg_color", /* Background color of tooltips. */
36 "tooltip_fg_color", /* Text color for text in tooltips. */
37};
38
c92e9c11 39char* color_scheme_hash_to_str(GHashTable* hash)
71ce58a7
HJYP
40{
41 GHashTableIter it;
42 char* key, *val;
43 GString* ret = g_string_sized_new(100);
44 g_hash_table_iter_init (&it, hash);
45 while(g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&val))
46 g_string_append_printf(ret, "%s:%s\n", key, val);
47 return g_string_free(ret, FALSE);
48}
49
c92e9c11
HJYP
50void color_scheme_str_to_hash(GHashTable* hash, const char* color_str)
51{
52 /* g_debug("color_str: %s", color_str); */
53 /* split color scheme string into key/value pairs */
54 char** pairs = g_strsplit_set(color_str, "\n;", -1);
55 char** pair;
56 for(pair = pairs; *pair; ++pair)
57 {
58 char* name = strtok(*pair, ": \t");
59 /* g_debug("color_name = %s", name); */
60 if(name)
61 {
62 char* val = strtok(NULL, " \t");
63 if(val)
64 g_hash_table_replace(hash, g_strdup(name), g_strdup(val));
65 }
66 }
67 g_strfreev(pairs);
68}
69
71ce58a7
HJYP
70static void on_color_set(GtkColorButton* btn, const char* color_name)
71{
72 GdkColor clr;
73 char* color_str;
74 gtk_color_button_get_color(btn, &clr);
75 color_str = gdk_color_to_string(&clr);
76
77 g_hash_table_replace(app.color_scheme_hash, g_strdup(color_name), color_str);
78 g_free(app.color_scheme);
c92e9c11 79 app.color_scheme = color_scheme_hash_to_str(app.color_scheme_hash);
71ce58a7
HJYP
80
81 g_object_set(gtk_settings_get_default(), "gtk-color-scheme", app.color_scheme, NULL);
82
83 lxappearance_changed();
84}
85
c92e9c11 86static void update_color_buttons()
71ce58a7 87{
c92e9c11
HJYP
88 int i;
89 /* set the color to buttons */
90 GHashTable* hash;
71ce58a7 91
c92e9c11
HJYP
92 /* if custom color scheme is not used, use the default one. */
93 if(app.color_scheme)
94 hash = app.color_scheme_hash;
95 else
96 hash = app.default_color_scheme_hash;
71ce58a7 97
c92e9c11
HJYP
98 for(i = 0; i < 8; ++i)
99 {
100 GtkWidget* btn = app.color_btns[i];
101 const char* color_name = gnome_color_names[i];
102 const char* color_str = (const char*)g_hash_table_lookup(app.color_scheme_hash, color_name);
103 /* g_debug("%s ='%s'", gnome_color_names[i], color_str); */
104 if(color_str)
105 {
106 GdkColor clr;
107 if(gdk_color_parse(color_str, &clr))
108 {
109 /* prevent invoking color-set handlers here. */
110 g_signal_handlers_block_by_func(btn, on_color_set, color_name);
111 gtk_color_button_set_color(GTK_COLOR_BUTTON(btn), &clr);
112 g_signal_handlers_unblock_by_func(btn, on_color_set, color_name);
113 }
114 gtk_widget_set_sensitive(btn, TRUE);
115 }
116 else
117 gtk_widget_set_sensitive(btn, FALSE);
118 }
119}
120
121static void hash_table_copy(GHashTable* dest, GHashTable* src)
122{
123 GHashTableIter it;
124 char* key, *val;
125 g_hash_table_remove_all(dest);
126 g_hash_table_iter_init(&it, src);
127 while(g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&val))
128 g_hash_table_insert(dest, g_strdup(key), g_strdup(val));
129}
130
131static void on_custom_color_toggled(GtkToggleButton* btn, gpointer user_data)
132{
133 g_free(app.color_scheme);
134 if(gtk_toggle_button_get_active(btn)) /* use customized color scheme. */
135 {
136 gtk_widget_set_sensitive(app.color_table, TRUE);
137 /* copy default colors to custom color hash table */
138 hash_table_copy(app.color_scheme_hash, app.default_color_scheme_hash);
139 app.color_scheme = color_scheme_hash_to_str(app.color_scheme_hash);
140 g_object_set(gtk_settings_get_default(), "gtk-color-scheme", app.color_scheme, NULL);
141 }
142 else /* use default colors provided by the theme. */
143 {
144 char* color_scheme_str;
145 gtk_widget_set_sensitive(app.color_table, FALSE);
146 /* restore default colors */
147 app.color_scheme = NULL;
148 g_hash_table_remove_all(app.color_scheme_hash);
149 if(app.default_color_scheme_hash)
150 color_scheme_str = color_scheme_hash_to_str(app.default_color_scheme_hash);
151 else
152 color_scheme_str = g_strdup("");
153 g_object_set(gtk_settings_get_default(), "gtk-color-scheme", color_scheme_str, NULL);
154 g_free(color_scheme_str);
155 }
156 update_color_buttons();
71ce58a7
HJYP
157
158 lxappearance_changed();
159}
160
161void color_scheme_init(GtkBuilder* b)
15c155a6 162{
71ce58a7 163 int i;
c92e9c11
HJYP
164 /* regular expressions used to parse gtkrc files */
165 gtkrc_include_reg = g_regex_new(
166 "[\\s]*include[\\s]+(\"([^\"]+)\"|'([^']+)')",
167 G_REGEX_MULTILINE|G_REGEX_OPTIMIZE, 0, NULL);
71ce58a7 168
c92e9c11
HJYP
169 gtkrc_color_scheme_reg = g_regex_new(
170 "[\\s]*(gtk-color-scheme|gtk_color_scheme)[\\s]*=[\\s]*(\"([^\"]+)\"|'([^']+)')",
171 G_REGEX_MULTILINE|G_REGEX_OPTIMIZE, 0, NULL);
71ce58a7 172
c92e9c11
HJYP
173 app.color_table = GTK_WIDGET(gtk_builder_get_object(b, "color_table"));
174 app.custom_colors = GTK_WIDGET(gtk_builder_get_object(b, "custom_colors"));
175 app.no_custom_colors = GTK_WIDGET(gtk_builder_get_object(b, "no_custom_colors"));
176
177 /* toggle the check box if we have custom color scheme */
178 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(app.custom_colors), app.color_scheme != NULL);
179 g_signal_connect(app.custom_colors, "toggled", G_CALLBACK(on_custom_color_toggled), NULL);
180
181 /* hash table of the default color scheme of currently selected theme. */
182 app.default_color_scheme_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
71ce58a7
HJYP
183
184 for(i = 0; i < 8; ++i)
185 app.color_btns[i] = GTK_WIDGET(gtk_builder_get_object(b, gnome_color_names[i]));;
186
c92e9c11 187 /* update color scheme page for currently selected gtk theme. */
15c155a6 188 color_scheme_update();
71ce58a7
HJYP
189
190 for(i = 0; i < 8; ++i)
191 g_signal_connect(app.color_btns[i], "color-set", G_CALLBACK(on_color_set), gnome_color_names[i]);
15c155a6
HJYP
192}
193
c92e9c11
HJYP
194/* return FALSE when the gtkrc file does not exists. */
195gboolean gtkrc_file_get_color_scheme(const char* gtkrc_file, GHashTable* hash)
15c155a6
HJYP
196{
197 char* content;
c92e9c11 198 /* g_debug("check: %s", gtkrc_file); */
15c155a6
HJYP
199 if(g_file_get_contents(gtkrc_file, &content, NULL, NULL))
200 {
c92e9c11
HJYP
201 GMatchInfo* match_info;
202
203 /* find gtkrc files included in this file. */
204 g_regex_match(gtkrc_include_reg, content, 0, &match_info);
205 while(g_match_info_matches (match_info))
206 {
207 gchar* include = g_match_info_fetch(match_info, 2);
208 /* try to load color schemes in every included gtkrc file. */
209 if(!g_path_is_absolute(include)) /* make a full path when needed. */
210 {
211 char* dirname = g_path_get_dirname(gtkrc_file);
212 char* file = g_build_filename(dirname, include, NULL);
213 g_free(dirname);
214 g_free(include);
215 include = file;
216 }
217 gtkrc_file_get_color_scheme(include, hash);
218 g_free(include);
219 g_match_info_next(match_info, NULL);
220 }
221
222 /* try to extract gtk-color-scheme from the gtkrc file. */
223 g_regex_match(gtkrc_color_scheme_reg, content, 0, &match_info);
224 while(g_match_info_matches (match_info))
225 {
226 char *color_scheme_str = g_match_info_fetch(match_info, 3);
227 /* need to unescape the string to replace "\\n" with "\n" */
228 char* unescaped = g_strcompress(color_scheme_str);
229 g_free (color_scheme_str);
230 color_scheme_str_to_hash(hash, unescaped);
231 g_free(unescaped);
232 g_match_info_next(match_info, NULL);
233 }
234 g_match_info_free(match_info);
15c155a6
HJYP
235 g_free(content);
236 }
71ce58a7
HJYP
237 else
238 return FALSE;
d023f0a4 239 return TRUE;
15c155a6
HJYP
240}
241
c92e9c11
HJYP
242/* update the color scheme page for currently selected gtk theme.
243 * called when currently selected gtk theme gets changed. */
15c155a6
HJYP
244void color_scheme_update()
245{
c92e9c11
HJYP
246 /* the current gtk theme gets changed.
247 * reload the default color scheme of current theme. */
248 g_hash_table_remove_all(app.default_color_scheme_hash);
249
15c155a6
HJYP
250 if(app.widget_theme)
251 {
252 gboolean file_found;
253 char* gtkrc = g_build_filename(g_get_home_dir(), ".themes", app.widget_theme, "gtk-2.0/gtkrc", NULL);
c92e9c11
HJYP
254 /* if the theme is found in user-custom theme dir */
255 file_found = gtkrc_file_get_color_scheme(gtkrc, app.default_color_scheme_hash);
15c155a6
HJYP
256 g_free(gtkrc);
257
258 if(!file_found)
259 {
c92e9c11 260 /* if the theme is found in system-wide theme dir */
15c155a6 261 gtkrc = g_build_filename(gtk_rc_get_theme_dir(), app.widget_theme, "gtk-2.0/gtkrc", NULL);
c92e9c11 262 gtkrc_file_get_color_scheme(gtkrc, app.default_color_scheme_hash);
15c155a6
HJYP
263 g_free(gtkrc);
264 }
c92e9c11 265 app.color_scheme_supported = (g_hash_table_size(app.default_color_scheme_hash) > 0);
15c155a6 266 }
c92e9c11
HJYP
267 else
268 app.color_scheme_supported = FALSE;
15c155a6 269
c92e9c11 270 if(app.color_scheme_supported)
15c155a6 271 {
c92e9c11
HJYP
272 gtk_widget_set_sensitive(app.custom_colors, TRUE);
273 gtk_widget_set_sensitive(app.color_table, app.color_scheme != NULL);
274 gtk_widget_hide(app.no_custom_colors);
15c155a6
HJYP
275 }
276 else
277 {
c92e9c11
HJYP
278 gtk_widget_set_sensitive(app.color_table, FALSE);
279 gtk_widget_set_sensitive(app.custom_colors, FALSE);
280 gtk_widget_show(app.no_custom_colors);
15c155a6 281 }
c92e9c11
HJYP
282 /* set the color to buttons */
283 update_color_buttons();
15c155a6
HJYP
284}
285