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