Mercurial > audlegacy
comparison libaudacious/dirbrowser.c @ 2046:456c74b6880a trunk
[svn] - bleah, put dirbrowser back
author | nenolod |
---|---|
date | Mon, 04 Dec 2006 01:39:52 -0800 |
parents | |
children | 2618fcfb3bcf |
comparison
equal
deleted
inserted
replaced
2045:04961c9a5242 | 2046:456c74b6880a |
---|---|
1 /* XMMS - Cross-platform multimedia player | |
2 * Copyright (C) 1998-2002 Peter Alm, Mikael Alm, Olle Hallnas, | |
3 * Thomas Nilsson and 4Front Technologies | |
4 * Copyright (C) 1999-2002 Haavard Kvaalen | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
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 | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 */ | |
20 | |
21 #ifdef HAVE_CONFIG_H | |
22 # include "config.h" | |
23 #endif | |
24 | |
25 #define GETTEXT_PACKAGE PACKAGE | |
26 | |
27 #include <glib.h> | |
28 #include <glib/gi18n-lib.h> | |
29 #include <gtk/gtk.h> | |
30 #include <stdio.h> | |
31 #include <string.h> | |
32 | |
33 #include <unistd.h> | |
34 #include <dirent.h> | |
35 #include <sys/types.h> | |
36 #include <sys/stat.h> | |
37 | |
38 | |
39 /* XPM */ | |
40 static gchar *folder[] = { | |
41 "16 16 16 1", | |
42 " c None", | |
43 ". c #f4f7e4", | |
44 "X c #dee4b5", | |
45 "o c #e1e7b9", | |
46 "O c #c6cba4", | |
47 "+ c #dce2b8", | |
48 "@ c #e9e9ec", | |
49 "# c #d3d8ae", | |
50 "$ c #d8daca", | |
51 "% c #b2b2b5", | |
52 "& c #767862", | |
53 "* c #e3e6c3", | |
54 "= c #1b1b1a", | |
55 "- c #939684", | |
56 "; c #555555", | |
57 ": c #000000", | |
58 " ", | |
59 " ", | |
60 " :::: ", | |
61 " :.@@O: ", | |
62 ":-&&&&&::::: ", | |
63 ":.@@@@@*$O#O= ", | |
64 ":@*+XXXX+##O: ", | |
65 ":.*#oooXXXXX: ", | |
66 ":@+XoXXXXXX#: ", | |
67 ":@*ooXXXXXX#: ", | |
68 ":@**XXXXXXX#: ", | |
69 ":@*XXXXXXXX%: ", | |
70 ":$.*OOOOOO%-: ", | |
71 " ;::::::::::: ", | |
72 " ", | |
73 " " | |
74 }; | |
75 | |
76 /* Icon by Jakub Steiner <jimmac@ximian.com> */ | |
77 | |
78 /* XPM */ | |
79 static gchar *ofolder[] = { | |
80 "16 16 16 1", | |
81 " c None", | |
82 ". c #a9ad93", | |
83 "X c #60634d", | |
84 "o c #dee4b5", | |
85 "O c #9ca085", | |
86 "+ c #0c0d04", | |
87 "@ c #2f2f31", | |
88 "# c #3b3d2c", | |
89 "$ c #c8cda2", | |
90 "% c #e6e6e9", | |
91 "& c #b3b5a5", | |
92 "* c #80826d", | |
93 "= c #292a1c", | |
94 "- c #fefef6", | |
95 "; c #8f937b", | |
96 ": c #000000", | |
97 " ", | |
98 " ", | |
99 " :::: ", | |
100 " :-%%&: ", | |
101 ":-;;;OX::::: ", | |
102 ":-;;;;O;O;&.: ", | |
103 ":-*X##@@@@@=#: ", | |
104 ":%*+-%%ooooooO: ", | |
105 ":%X;%ooooooo.*: ", | |
106 ":.+-%oooooooO: ", | |
107 ":*O-oooooooo*: ", | |
108 ":O-oooooooo.: ", | |
109 ":*-%$$$$$$OX: ", | |
110 " ::::::::::: ", | |
111 " ", | |
112 " " | |
113 }; | |
114 | |
115 #define NODE_SPACING 4 | |
116 | |
117 typedef void (*db_handler_t) (char *); | |
118 | |
119 static GdkPixmap *folder_pixmap = NULL, *ofolder_pixmap; | |
120 static GdkBitmap *folder_mask, *ofolder_mask; | |
121 | |
122 struct dirnode { | |
123 guint scanned:1; | |
124 gchar *path; | |
125 }; | |
126 | |
127 static gboolean | |
128 check_for_subdir(gchar * path) | |
129 { | |
130 DIR *dir; | |
131 struct dirent *dirent; | |
132 struct stat statbuf; | |
133 gchar *npath; | |
134 | |
135 if ((dir = opendir(path)) != NULL) { | |
136 while ((dirent = readdir(dir)) != NULL) { | |
137 if (dirent->d_name[0] == '.') | |
138 continue; | |
139 | |
140 npath = g_strconcat(path, dirent->d_name, NULL); | |
141 if (stat(npath, &statbuf) != -1 && S_ISDIR(statbuf.st_mode)) { | |
142 g_free(npath); | |
143 closedir(dir); | |
144 return TRUE; | |
145 } | |
146 g_free(npath); | |
147 } | |
148 closedir(dir); | |
149 } | |
150 return FALSE; | |
151 } | |
152 | |
153 static void | |
154 destroy_cb(gpointer data) | |
155 { | |
156 struct dirnode *node = data; | |
157 | |
158 g_free(node->path); | |
159 g_free(node); | |
160 } | |
161 | |
162 static void | |
163 add_dir(GtkCTree * tree, GtkCTreeNode * pnode, gchar * parent, gchar * dir) | |
164 { | |
165 struct stat statbuf; | |
166 gchar *path; | |
167 | |
168 /* Don't show hidden dirs, nor . and .. */ | |
169 if (dir[0] == '.') | |
170 return; | |
171 | |
172 path = g_strconcat(parent, dir, NULL); | |
173 if (stat(path, &statbuf) != -1 && S_ISDIR(statbuf.st_mode)) { | |
174 gboolean has_subdir; | |
175 gchar *text = ""; | |
176 GtkCTreeNode *node; | |
177 struct dirnode *dirnode = g_new0(struct dirnode, 1); | |
178 dirnode->path = g_strconcat(path, "/", NULL); | |
179 has_subdir = check_for_subdir(dirnode->path); | |
180 node = gtk_ctree_insert_node(tree, pnode, NULL, &dir, | |
181 NODE_SPACING, folder_pixmap, | |
182 folder_mask, ofolder_pixmap, | |
183 ofolder_mask, !has_subdir, FALSE); | |
184 gtk_ctree_node_set_row_data_full(tree, node, dirnode, destroy_cb); | |
185 if (has_subdir) | |
186 gtk_ctree_insert_node(tree, node, NULL, &text, | |
187 NODE_SPACING, NULL, NULL, | |
188 NULL, NULL, FALSE, FALSE); | |
189 } | |
190 g_free(path); | |
191 } | |
192 | |
193 static void | |
194 expand_cb(GtkWidget * widget, GtkCTreeNode * parent_node) | |
195 { | |
196 struct dirent *dirent; | |
197 GtkCTree *tree = GTK_CTREE(widget); | |
198 struct dirnode *parent_dirnode; | |
199 | |
200 parent_dirnode = gtk_ctree_node_get_row_data(tree, parent_node); | |
201 if (!parent_dirnode->scanned) { | |
202 DIR *dir; | |
203 | |
204 gtk_clist_freeze(GTK_CLIST(widget)); | |
205 gtk_ctree_remove_node(tree, GTK_CTREE_ROW(parent_node)->children); | |
206 if ((dir = opendir(parent_dirnode->path)) != NULL) { | |
207 while ((dirent = readdir(dir)) != NULL) { | |
208 add_dir(tree, parent_node, | |
209 parent_dirnode->path, dirent->d_name); | |
210 } | |
211 closedir(dir); | |
212 gtk_ctree_sort_node(tree, parent_node); | |
213 } | |
214 gtk_clist_thaw(GTK_CLIST(widget)); | |
215 parent_dirnode->scanned = TRUE; | |
216 } | |
217 } | |
218 | |
219 static void | |
220 select_row_cb(GtkWidget * widget, gint row, gint column, | |
221 GdkEventButton * bevent, gpointer data) | |
222 { | |
223 struct dirnode *dirnode; | |
224 GtkCTreeNode *node; | |
225 db_handler_t handler; | |
226 | |
227 if (bevent && bevent->type == GDK_2BUTTON_PRESS) { | |
228 node = gtk_ctree_node_nth(GTK_CTREE(widget), row); | |
229 dirnode = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node); | |
230 handler = (db_handler_t) gtk_object_get_user_data(GTK_OBJECT(widget)); | |
231 if (handler) | |
232 handler(dirnode->path); | |
233 } | |
234 } | |
235 | |
236 static void | |
237 show_cb(GtkWidget * widget, gpointer data) | |
238 { | |
239 GtkCTree *tree = GTK_CTREE(data); | |
240 GtkCTreeNode *node = gtk_object_get_data(GTK_OBJECT(tree), | |
241 "selected_node"); | |
242 | |
243 if (node) | |
244 gtk_ctree_node_moveto(tree, node, -1, 0.6, 0); | |
245 } | |
246 | |
247 static void | |
248 ok_clicked(GtkWidget * widget, GtkWidget * tree) | |
249 { | |
250 GtkCTreeNode *node; | |
251 struct dirnode *dirnode; | |
252 GList *list_node; | |
253 GtkWidget *window; | |
254 db_handler_t handler; | |
255 | |
256 window = gtk_object_get_user_data(GTK_OBJECT(widget)); | |
257 gtk_widget_hide(window); | |
258 list_node = GTK_CLIST(tree)->selection; | |
259 while (list_node) { | |
260 node = list_node->data; | |
261 dirnode = gtk_ctree_node_get_row_data(GTK_CTREE(tree), node); | |
262 handler = (db_handler_t) gtk_object_get_user_data(GTK_OBJECT(tree)); | |
263 if (handler) | |
264 handler(dirnode->path); | |
265 list_node = g_list_next(list_node); | |
266 } | |
267 gtk_widget_destroy(window); | |
268 | |
269 } | |
270 | |
271 GtkWidget * | |
272 xmms_create_dir_browser(gchar * title, gchar * current_path, | |
273 GtkSelectionMode mode, void (*handler) (gchar *)) | |
274 { | |
275 GtkWidget *window, *scroll_win, *tree, *vbox, *bbox, *ok, *cancel, *sep; | |
276 gchar *root_text = "/", *text = ""; | |
277 GtkCTreeNode *root_node, *node, *selected_node = NULL; | |
278 GtkCTree *ctree; | |
279 struct dirnode *dirnode; | |
280 | |
281 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
282 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | |
283 gtk_window_set_title(GTK_WINDOW(window), title); | |
284 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG); | |
285 gtk_container_border_width(GTK_CONTAINER(window), 10); | |
286 | |
287 vbox = gtk_vbox_new(FALSE, 10); | |
288 gtk_container_add(GTK_CONTAINER(window), vbox); | |
289 | |
290 scroll_win = gtk_scrolled_window_new(NULL, NULL); | |
291 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win), | |
292 GTK_POLICY_AUTOMATIC, | |
293 GTK_POLICY_AUTOMATIC); | |
294 gtk_widget_set_usize(scroll_win, 450, 400); | |
295 gtk_box_pack_start(GTK_BOX(vbox), scroll_win, TRUE, TRUE, 0); | |
296 gtk_widget_show(scroll_win); | |
297 | |
298 gtk_widget_realize(window); | |
299 if (!folder_pixmap) { | |
300 folder_pixmap = gdk_pixmap_create_from_xpm_d(window->window, | |
301 &folder_mask, | |
302 NULL, folder); | |
303 ofolder_pixmap = gdk_pixmap_create_from_xpm_d(window->window, | |
304 &ofolder_mask, | |
305 NULL, ofolder); | |
306 } | |
307 | |
308 tree = gtk_ctree_new(1, 0); | |
309 ctree = GTK_CTREE(tree); | |
310 gtk_clist_set_column_auto_resize(GTK_CLIST(tree), 0, TRUE); | |
311 gtk_clist_set_selection_mode(GTK_CLIST(tree), mode); | |
312 gtk_ctree_set_line_style(ctree, GTK_CTREE_LINES_DOTTED); | |
313 g_signal_connect(G_OBJECT(tree), "tree_expand", | |
314 G_CALLBACK(expand_cb), NULL); | |
315 g_signal_connect(G_OBJECT(tree), "select_row", | |
316 G_CALLBACK(select_row_cb), NULL); | |
317 g_signal_connect(G_OBJECT(window), "show", G_CALLBACK(show_cb), tree); | |
318 gtk_container_add(GTK_CONTAINER(scroll_win), tree); | |
319 gtk_object_set_user_data(GTK_OBJECT(tree), (void *) handler); | |
320 | |
321 root_node = gtk_ctree_insert_node(ctree, NULL, NULL, | |
322 &root_text, NODE_SPACING, | |
323 folder_pixmap, folder_mask, | |
324 ofolder_pixmap, ofolder_mask, | |
325 FALSE, FALSE); | |
326 dirnode = g_new0(struct dirnode, 1); | |
327 dirnode->path = g_strdup(G_DIR_SEPARATOR_S); | |
328 gtk_ctree_node_set_row_data_full(ctree, root_node, dirnode, destroy_cb); | |
329 node = gtk_ctree_insert_node(ctree, root_node, NULL, | |
330 &text, 4, NULL, NULL, NULL, | |
331 NULL, TRUE, TRUE); | |
332 gtk_ctree_expand(ctree, root_node); | |
333 gtk_widget_show(tree); | |
334 | |
335 sep = gtk_hseparator_new(); | |
336 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); | |
337 gtk_widget_show(sep); | |
338 | |
339 bbox = gtk_hbutton_box_new(); | |
340 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); | |
341 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); | |
342 | |
343 ok = gtk_button_new_from_stock(GTK_STOCK_OK); | |
344 gtk_object_set_user_data(GTK_OBJECT(ok), window); | |
345 GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); | |
346 gtk_window_set_default(GTK_WINDOW(window), ok); | |
347 gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); | |
348 g_signal_connect(G_OBJECT(ok), "clicked", G_CALLBACK(ok_clicked), tree); | |
349 gtk_widget_show(ok); | |
350 | |
351 cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); | |
352 GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); | |
353 gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); | |
354 g_signal_connect_swapped(G_OBJECT(cancel), "clicked", | |
355 G_CALLBACK(gtk_widget_destroy), | |
356 GTK_OBJECT(window)); | |
357 gtk_widget_show(cancel); | |
358 | |
359 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); | |
360 gtk_widget_show(bbox); | |
361 gtk_widget_show(vbox); | |
362 | |
363 if (current_path && *current_path) { | |
364 gchar **dir; | |
365 gint i; | |
366 | |
367 dir = g_strsplit(current_path, G_DIR_SEPARATOR_S, 0); | |
368 node = root_node; | |
369 for (i = 0; dir[i] != NULL; i++) { | |
370 if (dir[i][0] == '\0') | |
371 continue; | |
372 | |
373 for (node = GTK_CTREE_ROW(node)->children; node != NULL; | |
374 node = GTK_CTREE_ROW(node)->sibling) { | |
375 gchar *tmp; | |
376 if (gtk_ctree_node_get_pixtext(ctree, node, 0, | |
377 &tmp, NULL, NULL, NULL)) | |
378 if (!strcmp(dir[i], tmp)) | |
379 break; | |
380 } | |
381 if (!node) | |
382 break; | |
383 if (!GTK_CTREE_ROW(node)->is_leaf && dir[i + 1]) | |
384 gtk_ctree_expand(ctree, node); | |
385 else { | |
386 selected_node = node; | |
387 break; | |
388 } | |
389 } | |
390 g_strfreev(dir); | |
391 } | |
392 | |
393 if (!selected_node) | |
394 selected_node = root_node; | |
395 | |
396 gtk_ctree_select(ctree, selected_node); | |
397 gtk_object_set_data(GTK_OBJECT(tree), "selected_node", selected_node); | |
398 | |
399 return window; | |
400 } |