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