1 /*
2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; either version 2, or (at your option)
5 any later version.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17 #include <glib.h>
18 #include <gtk/gtk.h>
19 #include <unistd.h> // unlink()
20 #include <stdlib.h> // getenv()
21 #include <stdio.h> // fopen() fdopen() fprintf()
22 #include <string.h>
23 #include <fcntl.h>
24 #include "main.h"
25 #include "stock.h"
26 #include "mainwin.h"
27
28 GHashTable *hash = NULL;
29 GSList *awaiting_activation = NULL;
30 gchar *tmp_rc = NULL, *gtkrc = NULL, *font = NULL, *themename = NULL;
31
32 // dirname gets freed!
read_theme_list(gchar * dirname)33 void read_theme_list(gchar * dirname)
34 {
35 GDir *dir = g_dir_open(dirname, 0, NULL);
36 const gchar *entry;
37 gchar *rc_file;
38
39 if (dir)
40 {
41 while ((entry = g_dir_read_name(dir)))
42 {
43 if (g_file_test(entry, G_FILE_TEST_IS_DIR))
44 continue;
45
46 rc_file = g_strdup_printf("%s/%s/gtk-2.0/gtkrc", dirname, entry);
47
48 if (!g_file_test(rc_file, G_FILE_TEST_IS_REGULAR))
49 {
50 g_free(rc_file);
51 continue;
52 }
53
54 g_hash_table_insert(hash, g_strdup(entry), rc_file);
55 }
56 }
57
58 g_free(dirname);
59 }
60
populate_themelist(GHFunc func,gpointer user_data)61 void populate_themelist(GHFunc func, gpointer user_data)
62 {
63 g_hash_table_foreach(hash, func, user_data);
64 }
65
cleanup_temporary(void)66 void cleanup_temporary(void)
67 {
68 if (tmp_rc)
69 {
70 unlink(tmp_rc);
71 g_free(tmp_rc);
72 tmp_rc = NULL;
73 }
74 }
75
apply_new_look(gboolean is_preview)76 void apply_new_look(gboolean is_preview)
77 {
78 FILE *gtkrc_fh;
79 gchar *include_file;
80 gchar *default_files[2];
81 if(!themename) return;
82
83 cleanup_temporary();
84
85 gtkrc_fh = is_preview
86 ? fdopen(g_file_open_tmp("gtkrc.preview-XXXXXXXX", &tmp_rc, NULL), "w+")
87 : fopen(gtkrc, "w");
88
89 include_file = g_hash_table_lookup(hash, themename);
90
91 fprintf(gtkrc_fh,
92 "# -- THEME AUTO-WRITTEN DO NOT EDIT\n" "include \"%s\"\n\n",
93 include_file);
94
95 if (font)
96 {
97 fprintf(gtkrc_fh,
98 "style \"user-font\" {\n" "\tfont_name = \"%s\"\n" "}\n\n", font);
99 fprintf(gtkrc_fh, "widget_class \"*\" style \"user-font\"\n\n");
100 fprintf(gtkrc_fh, "gtk-font-name=\"%s\"\n\n", font);
101 }
102
103 fprintf(gtkrc_fh, "include \"%s/.gtkrc.mine\"\n\n", getenv("HOME"));
104 fprintf(gtkrc_fh, "# -- THEME AUTO-WRITTEN DO NOT EDIT\n");
105 fclose(gtkrc_fh);
106
107 default_files[0] = is_preview ? tmp_rc : gtkrc;
108 default_files[1] = NULL;
109 gtk_rc_set_default_files(default_files);
110
111 if (is_preview)
112 {
113 gtk_rc_reparse_all_for_settings(gtk_settings_get_default(), TRUE);
114 }
115 else
116 {
117 GdkEventClient event =
118 { GDK_CLIENT_EVENT, NULL, TRUE, gdk_atom_intern("_GTK_READ_RCFILES",
119 FALSE), 8 };
120 gdk_event_send_clientmessage_toall((GdkEvent *) & event);
121 }
122 }
123
await_activation(GtkWidget * w)124 void await_activation(GtkWidget* w)
125 {
126 if(themename) return;
127
128 gtk_widget_set_sensitive(w, FALSE);
129 awaiting_activation = g_slist_append(awaiting_activation, w);
130 }
131
set_font(gchar * newfont,gboolean is_preview)132 void set_font(gchar * newfont, gboolean is_preview)
133 {
134 if (font)
135 g_free(font);
136 font = newfont;
137 apply_new_look(is_preview);
138 }
139
get_font(void)140 gchar* get_font(void)
141 {
142 return font;
143 }
144
set_theme(gchar * newthemename,gboolean is_preview)145 void set_theme(gchar * newthemename, gboolean is_preview)
146 {
147 themename = newthemename;
148 apply_new_look(is_preview);
149
150 if (awaiting_activation)
151 {
152 g_slist_foreach(awaiting_activation,
153 (GFunc) gtk_widget_set_sensitive, GINT_TO_POINTER(TRUE));
154 g_slist_free(awaiting_activation);
155 awaiting_activation = NULL;
156 }
157 }
158
get_theme(void)159 gchar* get_theme(void)
160 {
161 return themename;
162 }
163
rc_skip_section(GScanner * s,GTokenType close)164 void rc_skip_section(GScanner *s, GTokenType close)
165 {
166 while(!g_scanner_eof(s)) {
167 g_scanner_get_next_token(s);
168 switch(s->token)
169 {
170 case G_TOKEN_LEFT_PAREN: rc_skip_section(s, G_TOKEN_RIGHT_PAREN); break;
171 case G_TOKEN_LEFT_CURLY: rc_skip_section(s, G_TOKEN_RIGHT_CURLY); break;
172 case G_TOKEN_LEFT_BRACE: rc_skip_section(s, G_TOKEN_RIGHT_BRACE); break;
173 default: if(s->token == close) return;
174 }
175 }
176 }
177
set_theme_if_match(gpointer key,gpointer value,gpointer path)178 void set_theme_if_match(gpointer key, gpointer value, gpointer path)
179 {
180 if(strcmp(path, value) == 0)
181 set_theme(key, TRUE);
182 }
183
parse_gtkrc(void)184 void parse_gtkrc(void)
185 {
186 GScanner *s = gtk_rc_scanner_new();
187 g_scanner_input_file(s, open(gtkrc, O_RDONLY));
188
189 g_strconcat(getenv("HOME"), "/.themes", NULL);
190 g_strconcat(gtk_rc_get_theme_dir(), "%s/gtk-2.0/gtkrc", NULL);
191
192 while(!g_scanner_eof(s)) {
193 g_scanner_get_next_token(s);
194 switch(s->token)
195 {
196 case G_TOKEN_LEFT_PAREN: rc_skip_section(s, G_TOKEN_RIGHT_PAREN); break;
197 case G_TOKEN_LEFT_CURLY: rc_skip_section(s, G_TOKEN_RIGHT_CURLY); break;
198 case G_TOKEN_LEFT_BRACE: rc_skip_section(s, G_TOKEN_RIGHT_BRACE); break;
199 case G_TOKEN_IDENTIFIER:
200 if(strcmp(s->value.v_string, "include") == 0)
201 {
202 if(g_scanner_get_next_token(s) == G_TOKEN_STRING)
203 g_hash_table_foreach(hash, set_theme_if_match, s->value.v_string);
204 }
205 else if(strcmp(s->value.v_string, "gtk-font-name") == 0)
206 {
207 if(g_scanner_get_next_token(s) == G_TOKEN_EQUAL_SIGN
208 && g_scanner_get_next_token(s) == G_TOKEN_STRING)
209 set_font(strdup(s->value.v_string), TRUE);
210 }
211 break;
212 default:
213 break;
214 }
215 }
216 g_scanner_destroy(s);
217 }
218
main(int argc,char * argv[])219 int main(int argc, char *argv[])
220 {
221 hash = g_hash_table_new(g_str_hash, g_str_equal);
222 gtkrc = g_strdup_printf("%s/.gtkrc-2.0", getenv("HOME"));
223
224 gtk_init(&argc, &argv);
225
226 init_new_stock_items();
227
228 read_theme_list(g_strconcat(getenv("HOME"), "/.themes", NULL));
229 read_theme_list(gtk_rc_get_theme_dir());
230
231 parse_gtkrc();
232
233 gtk_widget_show_all(create_mainwin());
234
235 gtk_main();
236
237 cleanup_temporary();
238
239 return 0;
240 }
241