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