Mercurial > audlegacy
annotate src/audacious/ui_skinselector.c @ 4412:180996fcf12a
bmp_config_* -> aud_config_*
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 31 Mar 2008 06:36:41 +0300 |
parents | 331bfc72ef66 |
children | de33c83aa06f |
rev | line source |
---|---|
2313 | 1 /* BMP - Cross-platform multimedia player |
2 * Copyright (C) 2003-2004 BMP development team. | |
3 * | |
4 * Based on XMMS: | |
5 * Copyright (C) 1998-2003 XMMS development team. | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
3121
3b6d316f8b09
GPL3 relicensing.
William Pitcock <nenolod@atheme-project.org>
parents:
3027
diff
changeset
|
9 * the Free Software Foundation; under version 3 of the License. |
2313 | 10 * |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
3121
3b6d316f8b09
GPL3 relicensing.
William Pitcock <nenolod@atheme-project.org>
parents:
3027
diff
changeset
|
17 * along with this program. If not, see <http://www.gnu.org/licenses>. |
3123
f1c756f39e6c
Invoke "Plugins are not derived work" clause provided by GPL3.
William Pitcock <nenolod@atheme-project.org>
parents:
3121
diff
changeset
|
18 * |
f1c756f39e6c
Invoke "Plugins are not derived work" clause provided by GPL3.
William Pitcock <nenolod@atheme-project.org>
parents:
3121
diff
changeset
|
19 * The Audacious team does not consider modular code linking to |
f1c756f39e6c
Invoke "Plugins are not derived work" clause provided by GPL3.
William Pitcock <nenolod@atheme-project.org>
parents:
3121
diff
changeset
|
20 * Audacious or using our public API to be a derived work. |
2313 | 21 */ |
22 | |
23 #ifdef HAVE_CONFIG_H | |
24 # include "config.h" | |
25 #endif | |
26 | |
27 #include "ui_skinselector.h" | |
28 | |
29 #include <glib.h> | |
30 #include <glib/gi18n.h> | |
31 #include <gtk/gtk.h> | |
32 | |
33 #include "platform/smartinclude.h" | |
34 | |
35 #include <stdlib.h> | |
36 #include <string.h> | |
37 | |
38 #include "main.h" | |
3251 | 39 #include "skin.h" |
2313 | 40 #include "util.h" |
41 | |
42 #define EXTENSION_TARGETS 7 | |
43 | |
44 static gchar *ext_targets[EXTENSION_TARGETS] = { "bmp", "xpm", "png", "svg", | |
45 "gif", "jpg", "jpeg" }; | |
46 | |
47 #define THUMBNAIL_WIDTH 90 | |
48 #define THUMBNAIL_HEIGHT 40 | |
49 | |
50 | |
51 enum SkinViewCols { | |
52 SKIN_VIEW_COL_PREVIEW, | |
53 SKIN_VIEW_COL_FORMATTEDNAME, | |
54 SKIN_VIEW_COL_NAME, | |
55 SKIN_VIEW_N_COLS | |
56 }; | |
57 | |
58 | |
59 GList *skinlist = NULL; | |
60 | |
61 | |
62 | |
63 static gchar * | |
64 get_thumbnail_filename(const gchar * path) | |
65 { | |
66 gchar *basename, *pngname, *thumbname; | |
67 | |
68 g_return_val_if_fail(path != NULL, NULL); | |
69 | |
70 basename = g_path_get_basename(path); | |
71 pngname = g_strconcat(basename, ".png", NULL); | |
72 | |
73 thumbname = g_build_filename(bmp_paths[BMP_PATH_SKIN_THUMB_DIR], | |
74 pngname, NULL); | |
75 | |
76 g_free(basename); | |
77 g_free(pngname); | |
78 | |
79 return thumbname; | |
80 } | |
81 | |
82 | |
83 static GdkPixbuf * | |
84 skin_get_preview(const gchar * path) | |
85 { | |
86 GdkPixbuf *preview = NULL; | |
87 gchar *dec_path, *preview_path; | |
88 gboolean is_archive = FALSE; | |
89 gint i = 0; | |
90 gchar buf[60]; /* gives us lots of room */ | |
91 | |
92 if (file_is_archive(path)) | |
93 { | |
94 if (!(dec_path = archive_decompress(path))) | |
95 return NULL; | |
96 | |
97 is_archive = TRUE; | |
98 } | |
99 else | |
100 { | |
101 dec_path = g_strdup(path); | |
102 } | |
103 | |
104 for (i = 0; i < EXTENSION_TARGETS; i++) | |
105 { | |
106 sprintf(buf, "main.%s", ext_targets[i]); | |
107 | |
3027
16bd351fa0b9
Fix skinbrowser preview generation.
William Pitcock <nenolod@atheme-project.org>
parents:
2317
diff
changeset
|
108 if ((preview_path = find_path_recursively(dec_path, buf)) != NULL) |
2313 | 109 break; |
110 } | |
111 | |
112 if (preview_path) | |
113 { | |
114 preview = gdk_pixbuf_new_from_file(preview_path, NULL); | |
115 g_free(preview_path); | |
116 } | |
117 | |
118 if (is_archive) | |
119 del_directory(dec_path); | |
120 | |
121 g_free(dec_path); | |
122 | |
123 return preview; | |
124 } | |
125 | |
126 | |
127 static GdkPixbuf * | |
128 skin_get_thumbnail(const gchar * path) | |
129 { | |
130 GdkPixbuf *scaled = NULL; | |
131 GdkPixbuf *preview; | |
132 gchar *thumbname; | |
133 | |
134 g_return_val_if_fail(path != NULL, NULL); | |
135 | |
2317
49d285f6008b
[svn] Full support for XDG basedir added. The old config doesn't get automatically converted yet.
js
parents:
2313
diff
changeset
|
136 if (g_str_has_suffix(path, "thumbs")) |
2313 | 137 return NULL; |
138 | |
139 thumbname = get_thumbnail_filename(path); | |
140 | |
141 if (g_file_test(thumbname, G_FILE_TEST_EXISTS)) { | |
142 scaled = gdk_pixbuf_new_from_file(thumbname, NULL); | |
143 g_free(thumbname); | |
144 return scaled; | |
145 } | |
146 | |
147 if (!(preview = skin_get_preview(path))) { | |
148 g_free(thumbname); | |
149 return NULL; | |
150 } | |
151 | |
152 scaled = gdk_pixbuf_scale_simple(preview, | |
153 THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, | |
154 GDK_INTERP_BILINEAR); | |
155 g_object_unref(preview); | |
156 | |
157 gdk_pixbuf_save(scaled, thumbname, "png", NULL, NULL); | |
158 g_free(thumbname); | |
159 | |
160 return scaled; | |
161 } | |
162 | |
163 static void | |
164 skinlist_add(const gchar * filename) | |
165 { | |
166 SkinNode *node; | |
167 gchar *basename; | |
168 | |
169 g_return_if_fail(filename != NULL); | |
170 | |
3514
331bfc72ef66
Convert some things to use GSlice.
William Pitcock <nenolod@atheme.org>
parents:
3421
diff
changeset
|
171 node = g_slice_new0(SkinNode); |
2313 | 172 node->path = g_strdup(filename); |
173 | |
174 basename = g_path_get_basename(filename); | |
175 | |
176 if (file_is_archive(filename)) { | |
177 node->name = archive_basename(basename); | |
178 node->desc = _("Archived Winamp 2.x skin"); | |
179 g_free(basename); | |
180 } | |
181 else { | |
182 node->name = basename; | |
183 node->desc = _("Unarchived Winamp 2.x skin"); | |
184 } | |
185 | |
186 skinlist = g_list_prepend(skinlist, node); | |
187 } | |
188 | |
189 static gboolean | |
190 scan_skindir_func(const gchar * path, const gchar * basename, gpointer data) | |
191 { | |
192 if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) { | |
193 if (file_is_archive(path)) { | |
194 skinlist_add(path); | |
195 } | |
196 } | |
197 else if (g_file_test(path, G_FILE_TEST_IS_DIR)) { | |
198 skinlist_add(path); | |
199 } | |
200 | |
201 return FALSE; | |
202 } | |
203 | |
204 static void | |
205 scan_skindir(const gchar * path) | |
206 { | |
207 GError *error = NULL; | |
208 | |
209 g_return_if_fail(path != NULL); | |
210 | |
211 if (path[0] == '.') | |
212 return; | |
213 | |
214 if (!dir_foreach(path, scan_skindir_func, NULL, &error)) { | |
215 g_warning("Failed to open directory (%s): %s", path, error->message); | |
216 g_error_free(error); | |
217 return; | |
218 } | |
219 } | |
220 | |
221 static gint | |
222 skinlist_compare_func(gconstpointer a, gconstpointer b) | |
223 { | |
224 g_return_val_if_fail(a != NULL && SKIN_NODE(a)->name != NULL, 1); | |
225 g_return_val_if_fail(b != NULL && SKIN_NODE(b)->name != NULL, 1); | |
226 return strcasecmp(SKIN_NODE(a)->name, SKIN_NODE(b)->name); | |
227 } | |
228 | |
229 static void | |
230 skin_free_func(gpointer data) | |
231 { | |
232 g_return_if_fail(data != NULL); | |
233 g_free(SKIN_NODE(data)->name); | |
234 g_free(SKIN_NODE(data)->path); | |
3514
331bfc72ef66
Convert some things to use GSlice.
William Pitcock <nenolod@atheme.org>
parents:
3421
diff
changeset
|
235 g_slice_free(SkinNode, data); |
2313 | 236 } |
237 | |
238 | |
239 static void | |
240 skinlist_clear(void) | |
241 { | |
242 if (!skinlist) | |
243 return; | |
244 | |
245 g_list_foreach(skinlist, (GFunc) skin_free_func, NULL); | |
246 g_list_free(skinlist); | |
247 skinlist = NULL; | |
248 } | |
249 | |
250 void | |
251 skinlist_update(void) | |
252 { | |
253 gchar *skinsdir; | |
254 | |
255 skinlist_clear(); | |
256 | |
257 scan_skindir(bmp_paths[BMP_PATH_USER_SKIN_DIR]); | |
2317
49d285f6008b
[svn] Full support for XDG basedir added. The old config doesn't get automatically converted yet.
js
parents:
2313
diff
changeset
|
258 scan_skindir(DATA_DIR G_DIR_SEPARATOR_S "Skins"); |
2313 | 259 |
260 skinsdir = getenv("SKINSDIR"); | |
261 if (skinsdir) { | |
262 gchar **dir_list = g_strsplit(skinsdir, ":", 0); | |
263 gchar **dir; | |
264 | |
265 for (dir = dir_list; *dir; dir++) | |
266 scan_skindir(*dir); | |
267 g_strfreev(dir_list); | |
268 } | |
269 | |
270 skinlist = g_list_sort(skinlist, skinlist_compare_func); | |
271 | |
272 g_assert(skinlist != NULL); | |
273 } | |
274 | |
275 void | |
276 skin_view_update(GtkTreeView * treeview, GtkWidget * refresh_button) | |
277 { | |
278 GtkTreeSelection *selection = NULL; | |
279 GtkListStore *store; | |
280 GtkTreeIter iter, iter_current_skin; | |
281 gboolean have_current_skin = FALSE; | |
282 GtkTreePath *path; | |
283 | |
284 GdkPixbuf *thumbnail; | |
285 gchar *formattedname; | |
286 gchar *name; | |
287 GList *entry; | |
288 | |
289 gtk_widget_set_sensitive(GTK_WIDGET(treeview), FALSE); | |
290 gtk_widget_set_sensitive(GTK_WIDGET(refresh_button), FALSE); | |
291 | |
292 store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview)); | |
293 | |
294 gtk_list_store_clear(store); | |
295 | |
296 skinlist_update(); | |
297 | |
298 for (entry = skinlist; entry; entry = g_list_next(entry)) { | |
299 thumbnail = skin_get_thumbnail(SKIN_NODE(entry->data)->path); | |
300 | |
301 formattedname = g_strdup_printf("<big><b>%s</b></big>\n<i>%s</i>", | |
302 SKIN_NODE(entry->data)->name, SKIN_NODE(entry->data)->desc); | |
303 name = SKIN_NODE(entry->data)->name; | |
304 | |
305 gtk_list_store_append(store, &iter); | |
306 gtk_list_store_set(store, &iter, | |
307 SKIN_VIEW_COL_PREVIEW, thumbnail, | |
308 SKIN_VIEW_COL_FORMATTEDNAME, formattedname, | |
309 SKIN_VIEW_COL_NAME, name, -1); | |
310 if (thumbnail) | |
311 g_object_unref(thumbnail); | |
312 g_free(formattedname); | |
313 | |
314 if (g_strstr_len(bmp_active_skin->path, | |
315 strlen(bmp_active_skin->path), name) ) { | |
316 iter_current_skin = iter; | |
317 have_current_skin = TRUE; | |
318 } | |
319 } | |
320 | |
321 if (have_current_skin) { | |
322 selection = gtk_tree_view_get_selection(treeview); | |
323 gtk_tree_selection_select_iter(selection, &iter_current_skin); | |
324 | |
325 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), | |
326 &iter_current_skin); | |
327 gtk_tree_view_scroll_to_cell(treeview, path, NULL, TRUE, 0.5, 0.5); | |
328 gtk_tree_path_free(path); | |
329 } | |
330 | |
331 gtk_widget_set_sensitive(GTK_WIDGET(treeview), TRUE); | |
332 gtk_widget_set_sensitive(GTK_WIDGET(refresh_button), TRUE); | |
333 } | |
334 | |
335 | |
336 static void | |
337 skin_view_on_cursor_changed(GtkTreeView * treeview, | |
338 gpointer data) | |
339 { | |
340 GtkTreeModel *model; | |
341 GtkTreeSelection *selection; | |
342 GtkTreeIter iter; | |
343 | |
344 GList *node; | |
345 gchar *name; | |
346 gchar *comp = NULL; | |
347 | |
348 selection = gtk_tree_view_get_selection(treeview); | |
349 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) | |
350 return; | |
351 | |
352 gtk_tree_model_get(model, &iter, SKIN_VIEW_COL_NAME, &name, -1); | |
353 | |
354 for (node = skinlist; node; node = g_list_next(node)) { | |
355 comp = SKIN_NODE(node->data)->path; | |
356 if (g_strrstr(comp, name)) | |
357 break; | |
358 } | |
359 | |
360 g_free(name); | |
361 | |
362 bmp_active_skin_load(comp); | |
363 } | |
364 | |
365 | |
366 void | |
367 skin_view_realize(GtkTreeView * treeview) | |
368 { | |
369 GtkListStore *store; | |
370 GtkTreeViewColumn *column; | |
371 GtkCellRenderer *renderer; | |
372 GtkTreeSelection *selection; | |
373 | |
374 gtk_widget_show_all(GTK_WIDGET(treeview)); | |
375 | |
376 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); | |
377 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); | |
378 | |
379 store = gtk_list_store_new(SKIN_VIEW_N_COLS, GDK_TYPE_PIXBUF, | |
380 G_TYPE_STRING , G_TYPE_STRING); | |
381 gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store)); | |
382 | |
383 column = gtk_tree_view_column_new(); | |
384 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); | |
385 gtk_tree_view_column_set_spacing(column, 16); | |
386 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), | |
387 GTK_TREE_VIEW_COLUMN(column)); | |
388 | |
389 renderer = gtk_cell_renderer_pixbuf_new(); | |
390 gtk_tree_view_column_pack_start(column, renderer, FALSE); | |
391 gtk_tree_view_column_set_attributes(column, renderer, "pixbuf", | |
392 SKIN_VIEW_COL_PREVIEW, NULL); | |
393 | |
394 renderer = gtk_cell_renderer_text_new(); | |
395 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
396 gtk_tree_view_column_set_attributes(column, renderer, "markup", | |
397 SKIN_VIEW_COL_FORMATTEDNAME, NULL); | |
398 | |
399 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); | |
400 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); | |
401 | |
402 g_signal_connect(treeview, "cursor-changed", | |
403 G_CALLBACK(skin_view_on_cursor_changed), NULL); | |
404 } |