1 /*                                                     -*- linux-c -*-
2     Copyright (C) 2004 Tom Szilagyi
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18     $Id: skin.c 1236 2012-02-04 10:28:58Z assworth $
19 */
20 
21 #include <config.h>
22 
23 #include <dirent.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <errno.h>
29 #include <glib.h>
30 #include <glib-object.h>
31 #include <gdk/gdk.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <gtk/gtk.h>
34 
35 #include "common.h"
36 #include "utils_gui.h"
37 #include "gui_main.h"
38 #include "playlist.h"
39 #include "options.h"
40 #include "i18n.h"
41 #include "skin.h"
42 
43 
44 extern options_t options;
45 
46 extern GtkWidget * main_window;
47 
48 char * pdir;
49 
50 GtkWidget * skin_window;
51 GtkListStore * skin_store;
52 GtkTreeSelection * skin_select;
53 
54 
55 void
apply_skin_foreach(GtkWidget * window)56 apply_skin_foreach(GtkWidget * window) {
57 
58 	gtk_widget_reset_rc_styles(window);
59 	gtk_widget_queue_draw(window);
60 }
61 
62 void
apply_skin(char * path)63 apply_skin(char * path) {
64 
65 	char rcpath[MAXLEN];
66 
67 	sprintf(rcpath, "%s/rc", path);
68 	gtk_rc_parse(rcpath);
69 
70 	toplevel_window_foreach(TOP_WIN_SKIN, apply_skin_foreach);
71 
72 	main_buttons_set_content(path);
73 
74 	playlist_set_color();
75 }
76 
77 static int
filter(const struct dirent * de)78 filter(const struct dirent * de) {
79 
80 	struct stat st_file;
81 	char dirname[MAXLEN];
82 
83 
84 	if (de->d_name[0] == '.') {
85 		return 0;
86 	}
87 
88 	snprintf(dirname, MAXLEN-1, "%s/%s", pdir, de->d_name);
89 	if (stat(dirname, &st_file) == -1) {
90 		fprintf(stderr,
91 			"error %s: skin.c/filter(): stat() failed on %s [likely cause: nonexistent file]\n",
92 			strerror(errno), dirname);
93 		return 0;
94 	}
95 
96 	return S_ISDIR(st_file.st_mode);
97 }
98 
99 
100 static gint
cancel(GtkWidget * widget,gpointer data)101 cancel(GtkWidget * widget, gpointer data) {
102 
103 	gtk_widget_destroy(skin_window);
104 	return TRUE;
105 }
106 
107 static gint
apply(GtkWidget * widget,gpointer data)108 apply(GtkWidget * widget, gpointer data) {
109 
110 	GtkTreeModel * model;
111 	GtkTreeIter iter;
112 	char * str;
113 
114 	if (gtk_tree_selection_get_selected(skin_select, &model, &iter)) {
115 
116 		gtk_tree_model_get(model, &iter, 1, &str, -1);
117 		strcpy(options.skin, str);
118 		g_free(str);
119 
120 		gtk_widget_destroy(skin_window);
121 		apply_skin(options.skin);
122 	}
123 
124 	return TRUE;
125 }
126 
127 static gint
skin_window_key_pressed(GtkWidget * widget,GdkEventKey * kevent)128 skin_window_key_pressed(GtkWidget * widget, GdkEventKey * kevent) {
129 
130 	switch (kevent->keyval) {
131 
132 	case GDK_q:
133 	case GDK_Q:
134 	case GDK_Escape:
135 		cancel(NULL, NULL);
136 		return TRUE;
137 		break;
138 
139         case GDK_Return:
140 	case GDK_KP_Enter:
141 		apply(NULL, NULL);
142                 return TRUE;
143 		break;
144 	}
145 
146 	return FALSE;
147 }
148 
149 static gint
skin_list_double_click(GtkWidget * widget,GdkEventButton * event,gpointer func_data)150 skin_list_double_click(GtkWidget * widget, GdkEventButton * event, gpointer func_data) {
151 
152 	if ((event->type == GDK_2BUTTON_PRESS) && (event->button == 1)) {
153 		apply(NULL, NULL);
154 		return TRUE;
155 	}
156 
157 	return FALSE;
158 }
159 
160 
161 void
create_skin_window()162 create_skin_window() {
163 
164 	GtkWidget * vbox;
165 	GtkWidget * viewp;
166 	GtkWidget * scrolledwin;
167 
168 	GtkWidget * skin_list;
169 	GtkTreeIter iter;
170 	GtkTreeViewColumn *column;
171 	GtkCellRenderer * renderer;
172 
173 	GtkWidget * hbuttonbox;
174 	GtkWidget * apply_btn;
175 	GtkWidget * cancel_btn;
176 
177 	struct dirent ** ent;
178 	int n;
179 
180 
181 	skin_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
182 	gtk_window_set_transient_for(GTK_WINDOW(skin_window), GTK_WINDOW(main_window));
183 	gtk_widget_set_size_request(skin_window, 250, 240);
184         gtk_window_set_title(GTK_WINDOW(skin_window), _("Skin chooser"));
185 	gtk_window_set_position(GTK_WINDOW(skin_window), GTK_WIN_POS_CENTER);
186 	gtk_window_set_modal(GTK_WINDOW(skin_window), TRUE);
187         gtk_container_set_border_width(GTK_CONTAINER(skin_window), 2);
188 
189         g_signal_connect(G_OBJECT(skin_window), "key_press_event",
190 			 G_CALLBACK(skin_window_key_pressed), NULL);
191 
192 	vbox = gtk_vbox_new(FALSE, 0);
193 	gtk_container_add(GTK_CONTAINER(skin_window), vbox);
194 
195 	viewp = gtk_viewport_new(NULL, NULL);
196 	gtk_box_pack_start(GTK_BOX(vbox), viewp, TRUE, TRUE, 0);
197 
198 	scrolledwin = gtk_scrolled_window_new(NULL, NULL);
199 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
200 				       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
201 	gtk_container_add(GTK_CONTAINER(viewp), scrolledwin);
202 
203 	skin_store = gtk_list_store_new(2,
204 					G_TYPE_STRING,  /* skin name */
205 					G_TYPE_STRING); /* path */
206         skin_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(skin_store));
207 	gtk_tree_view_set_enable_search(GTK_TREE_VIEW(skin_list), FALSE);
208 
209         g_signal_connect(G_OBJECT(skin_list), "button_press_event",
210                          G_CALLBACK(skin_list_double_click), NULL);
211 
212         skin_select = gtk_tree_view_get_selection(GTK_TREE_VIEW(skin_list));
213 
214 	renderer = gtk_cell_renderer_text_new();
215 	column = gtk_tree_view_column_new_with_attributes(_("Available skins"), renderer, "text", 0, NULL);
216         gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(skin_store), 0, GTK_SORT_ASCENDING);
217 
218 	gtk_tree_view_append_column(GTK_TREE_VIEW(skin_list), column);
219 	gtk_container_add(GTK_CONTAINER(scrolledwin), skin_list);
220 
221 	/* per-user skins */
222 	pdir = options.confdir;
223 	n = scandir(options.confdir, &ent, filter, alphasort);
224 	if (n >= 0) {
225 		int c;
226 		char path[MAXLEN];
227 
228 		for (c = 0; c < n; ++c) {
229                         gtk_list_store_append(skin_store, &iter);
230                         snprintf(path, MAXLEN - 1, "%s/%s", options.confdir, ent[c]->d_name);
231                         gtk_list_store_set(skin_store, &iter, 0, ent[c]->d_name, 1, path, -1);
232 			free(ent[c]);
233 		}
234 		free(ent);
235 	}
236 
237 	/* system wide skins */
238 	pdir = AQUALUNG_SKINDIR;
239 	n = scandir(AQUALUNG_SKINDIR, &ent, filter, alphasort);
240 	if (n >= 0) {
241 		int c;
242 		char path[MAXLEN];
243 
244 		for (c = 0; c < n; ++c) {
245 			int found = 0;
246 
247 			if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(skin_store), &iter)) {
248 				int i = 0;
249 				char * str;
250 
251 				do {
252 					gtk_tree_model_get(GTK_TREE_MODEL(skin_store), &iter, 0, &str, -1);
253 					if (strcmp(str, ent[c]->d_name) == 0) {
254 						found = 1;
255 					}
256 					g_free(str);
257 
258 				} while (i++, gtk_tree_model_iter_next(GTK_TREE_MODEL(skin_store), &iter));
259 			}
260 
261 			if (!found) {
262                                 if (strncmp(ent[c]->d_name, "no_skin", MAXLEN-1)) {
263                                         gtk_list_store_append(skin_store, &iter);
264                                         snprintf(path, MAXLEN - 1, "%s/%s", AQUALUNG_SKINDIR, ent[c]->d_name);
265                                         gtk_list_store_set(skin_store, &iter, 0, ent[c]->d_name, 1, path, -1);
266                                 }
267 			}
268 			free(ent[c]);
269 		}
270 		free(ent);
271 	}
272 
273 	hbuttonbox = gtk_hbutton_box_new();
274 	gtk_box_pack_end(GTK_BOX(vbox), hbuttonbox, FALSE, TRUE, 0);
275 	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_END);
276         gtk_box_set_spacing(GTK_BOX(hbuttonbox), 8);
277         gtk_container_set_border_width(GTK_CONTAINER(hbuttonbox), 3);
278 
279         apply_btn = gtk_button_new_from_stock (GTK_STOCK_APPLY);
280 	g_signal_connect(apply_btn, "clicked", G_CALLBACK(apply), NULL);
281   	gtk_container_add(GTK_CONTAINER(hbuttonbox), apply_btn);
282 
283         cancel_btn = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
284 	g_signal_connect(cancel_btn, "clicked", G_CALLBACK(cancel), NULL);
285   	gtk_container_add(GTK_CONTAINER(hbuttonbox), cancel_btn);
286 
287 	gtk_widget_show_all(skin_window);
288 
289 	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(skin_store), &iter)) {
290 		int i = 0;
291 		char * str;
292 
293 		do {
294 			gtk_tree_model_get(GTK_TREE_MODEL(skin_store), &iter, 1, &str, -1);
295 			if (strcmp(str, options.skin) == 0) {
296 				gtk_tree_selection_select_iter(skin_select, &iter);
297 				gtk_tree_view_set_cursor(GTK_TREE_VIEW(skin_list),
298 					 gtk_tree_model_get_path(GTK_TREE_MODEL(skin_store), &iter),
299 					 NULL, FALSE);
300 			}
301 			g_free(str);
302 
303 		} while (i++, gtk_tree_model_iter_next(GTK_TREE_MODEL(skin_store), &iter));
304 	}
305 }
306 
307 // vim: shiftwidth=8:tabstop=8:softtabstop=8 :
308 
309