2417
|
1 /* Audacious - Cross-platform multimedia player
|
|
2 * Copyright (C) 2005-2007 Audacious development team
|
|
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; under version 2 of the License.
|
|
7 *
|
|
8 * This program is distributed in the hope that it will be useful,
|
|
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11 * GNU General Public License for more details.
|
|
12 *
|
|
13 * You should have received a copy of the GNU General Public License
|
|
14 * along with this program; if not, write to the Free Software
|
|
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
16 */
|
|
17
|
|
18 #include "ui_fileopener.h"
|
|
19
|
|
20 #include <glib/gi18n.h>
|
|
21 #include <string.h>
|
|
22
|
|
23 #include "input.h"
|
|
24 #include "main.h"
|
|
25 #include "playback.h"
|
|
26 #include "strings.h"
|
|
27 #include "ui_playlist.h"
|
|
28
|
|
29 static void
|
|
30 filebrowser_add_files(GtkFileChooser * browser,
|
|
31 GSList * files)
|
|
32 {
|
|
33 GSList *cur;
|
|
34 gchar *ptr;
|
|
35 guint ctr = 0;
|
|
36 Playlist *playlist = playlist_get_active();
|
|
37
|
|
38 if (GTK_IS_WIDGET(mainwin_jtf))
|
|
39 gtk_widget_set_sensitive(mainwin_jtf, FALSE);
|
|
40
|
|
41 for (cur = files; cur; cur = g_slist_next(cur)) {
|
|
42
|
|
43 if (g_file_test(cur->data,G_FILE_TEST_IS_DIR)) {
|
|
44 playlist_add_dir(playlist, (const gchar *) cur->data);
|
|
45 } else {
|
|
46 playlist_add(playlist, (const gchar *) cur->data);
|
|
47 }
|
|
48
|
|
49 if (++ctr == 20) {
|
|
50 playlistwin_update_list(playlist);
|
|
51 ctr = 0;
|
|
52 while (gtk_events_pending() ) gtk_main_iteration();
|
|
53 }
|
|
54 }
|
|
55
|
|
56 playlistwin_update_list(playlist);
|
|
57
|
|
58 if (GTK_IS_WIDGET(mainwin_jtf))
|
|
59 gtk_widget_set_sensitive(mainwin_jtf, TRUE);
|
|
60
|
|
61 ptr = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(browser));
|
|
62
|
|
63 g_free(cfg.filesel_path);
|
|
64 cfg.filesel_path = ptr;
|
|
65 }
|
|
66
|
|
67 static void
|
|
68 action_button_cb(GtkWidget *widget, gpointer data)
|
|
69 {
|
|
70 GtkWidget *window = g_object_get_data(data, "window");
|
|
71 GtkWidget *chooser = g_object_get_data(data, "chooser");
|
|
72 GtkWidget *toggle = g_object_get_data(data, "toggle-button");
|
|
73 cfg.close_dialog_open =
|
|
74 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle));
|
|
75
|
|
76 gboolean play_button =
|
|
77 GPOINTER_TO_INT(g_object_get_data(data, "play-button"));
|
|
78
|
|
79
|
|
80 GSList *files;
|
|
81 files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(chooser));
|
|
82 if (!files) return;
|
|
83
|
|
84 if (play_button)
|
|
85 playlist_clear(playlist_get_active());
|
|
86
|
|
87 filebrowser_add_files(GTK_FILE_CHOOSER(chooser), files);
|
|
88 g_slist_foreach(files, (GFunc) g_free, NULL);
|
|
89 g_slist_free(files);
|
|
90
|
|
91 if (play_button)
|
|
92 playback_initiate();
|
|
93
|
|
94
|
|
95 if (cfg.close_dialog_open)
|
|
96 gtk_widget_destroy(window);
|
|
97 }
|
|
98
|
|
99
|
|
100 static void
|
|
101 close_button_cb(GtkWidget *widget, gpointer data)
|
|
102 {
|
|
103 gtk_widget_destroy(GTK_WIDGET(data));
|
|
104 }
|
|
105
|
|
106 void
|
|
107 util_run_filebrowser_gtk2style(gboolean play_button)
|
|
108 {
|
|
109 GtkWidget *window;
|
|
110 GtkWidget *vbox, *hbox, *bbox;
|
|
111 GtkWidget *chooser;
|
|
112 GtkWidget *action_button, *close_button;
|
|
113 GtkWidget *toggle;
|
|
114
|
|
115 gchar *window_title = play_button ? _("Open Files") : _("Add Files");
|
|
116 gchar *toggle_text = play_button ?
|
|
117 _("Close dialog on Open") : _("Close dialog on Add");
|
|
118 gpointer action_stock = play_button ? GTK_STOCK_OPEN : GTK_STOCK_ADD;
|
|
119
|
|
120 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
121 gtk_window_set_title(GTK_WINDOW(window), window_title);
|
|
122 gtk_window_set_default_size(GTK_WINDOW(window), 700, 450);
|
|
123 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
|
|
124
|
|
125 vbox = gtk_vbox_new(FALSE, 0);
|
|
126 gtk_container_add(GTK_CONTAINER(window), vbox);
|
|
127
|
|
128 chooser = gtk_file_chooser_widget_new(GTK_FILE_CHOOSER_ACTION_OPEN);
|
|
129 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chooser), TRUE);
|
|
130 if (cfg.filesel_path)
|
|
131 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser),
|
|
132 cfg.filesel_path);
|
|
133 gtk_box_pack_start(GTK_BOX(vbox), chooser, TRUE, TRUE, 5);
|
|
134
|
|
135 hbox = gtk_hbox_new(TRUE, 0);
|
|
136 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
|
137
|
|
138 toggle = gtk_check_button_new_with_label(toggle_text);
|
|
139 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle),
|
|
140 cfg.close_dialog_open ? TRUE : FALSE);
|
|
141 gtk_box_pack_start(GTK_BOX(hbox), toggle, TRUE, TRUE, 5);
|
|
142
|
|
143 bbox = gtk_hbutton_box_new();
|
|
144 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
|
|
145 gtk_box_pack_end(GTK_BOX(hbox), bbox, TRUE, TRUE, 5);
|
|
146
|
|
147 close_button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
|
|
148 action_button = gtk_button_new_from_stock(action_stock);
|
|
149 gtk_container_add(GTK_CONTAINER(bbox), close_button);
|
|
150 gtk_container_add(GTK_CONTAINER(bbox), action_button);
|
|
151
|
|
152 // this storage object holds several other objects which are used in the
|
|
153 // callback functions
|
|
154 gpointer storage = g_object_new(G_TYPE_OBJECT, NULL);
|
|
155 g_object_set_data(storage, "window", window);
|
|
156 g_object_set_data(storage, "chooser", chooser);
|
|
157 g_object_set_data(storage, "toggle-button", toggle);
|
|
158 g_object_set_data(storage, "play-button", GINT_TO_POINTER(play_button));
|
|
159
|
|
160 g_signal_connect(chooser, "file-activated",
|
|
161 G_CALLBACK(action_button_cb), storage);
|
|
162 g_signal_connect(action_button, "clicked",
|
|
163 G_CALLBACK(action_button_cb), storage);
|
|
164 g_signal_connect(close_button, "clicked",
|
|
165 G_CALLBACK(close_button_cb), window);
|
|
166 g_signal_connect(window, "destroy",
|
|
167 G_CALLBACK(gtk_widget_destroyed), &window);
|
|
168
|
|
169 gtk_widget_show_all(window);
|
|
170 }
|
|
171
|
|
172 /*
|
|
173 * Derived from Beep Media Player 0.9.6.1.
|
|
174 * Which is (C) 2003 - 2006 Milosz Derezynski &c
|
|
175 *
|
|
176 * Although I changed it quite a bit. -nenolod
|
|
177 */
|
|
178 static void filebrowser_changed_classic(GtkFileSelection * filesel)
|
|
179 {
|
|
180 GList *list;
|
|
181 GList *node;
|
|
182 char *filename = (char *)
|
|
183 gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel));
|
|
184 GtkListStore *store;
|
|
185 GtkTreeIter iter;
|
|
186
|
|
187 if ((list = input_scan_dir(filename)) != NULL)
|
|
188 {
|
|
189 /*
|
|
190 * We enter a directory that has been "hijacked" by an
|
|
191 * input-plugin. This is used by the CDDA plugin
|
|
192 */
|
|
193 store =
|
|
194 GTK_LIST_STORE(gtk_tree_view_get_model
|
|
195 (GTK_TREE_VIEW(filesel->file_list)));
|
|
196 gtk_list_store_clear(store);
|
|
197
|
|
198 node = list;
|
|
199 while (node) {
|
|
200 gtk_list_store_append(store, &iter);
|
|
201 gtk_list_store_set(store, &iter, 0, node->data, -1);
|
|
202 g_free(node->data);
|
|
203 node = g_list_next(node);
|
|
204 }
|
|
205
|
|
206 g_list_free(list);
|
|
207 }
|
|
208 }
|
|
209
|
|
210 static void filebrowser_entry_changed_classic(GtkEditable * entry, gpointer data)
|
|
211 {
|
|
212 filebrowser_changed_classic(GTK_FILE_SELECTION(data));
|
|
213 }
|
|
214
|
|
215
|
|
216 static gboolean
|
|
217 util_filebrowser_is_dir_classic(GtkFileSelection * filesel)
|
|
218 {
|
|
219 char *text;
|
|
220 struct stat buf;
|
|
221 gboolean retv = FALSE;
|
|
222
|
|
223 text = g_strdup(gtk_file_selection_get_filename(filesel));
|
|
224
|
|
225 if (stat(text, &buf) == 0 && S_ISDIR(buf.st_mode)) {
|
|
226 /* Selected directory */
|
|
227 int len = strlen(text);
|
|
228 if (len > 3 && !strcmp(text + len - 4, "/../")) {
|
|
229 if (len == 4)
|
|
230 /* At the root already */
|
|
231 *(text + len - 3) = '\0';
|
|
232 else {
|
|
233 char *ptr;
|
|
234 *(text + len - 4) = '\0';
|
|
235 ptr = strrchr(text, '/');
|
|
236 *(ptr + 1) = '\0';
|
|
237 }
|
|
238 } else if (len > 2 && !strcmp(text + len - 3, "/./"))
|
|
239 *(text + len - 2) = '\0';
|
|
240 gtk_file_selection_set_filename(filesel, text);
|
|
241 retv = TRUE;
|
|
242 }
|
|
243 g_free(text);
|
|
244 return retv;
|
|
245 }
|
|
246
|
|
247 static void filebrowser_add_files_classic(gchar ** files,
|
|
248 GtkFileSelection * filesel)
|
|
249 {
|
|
250 int ctr = 0;
|
|
251 char *ptr;
|
|
252 Playlist *playlist = playlist_get_active();
|
|
253
|
|
254 if (GTK_IS_WIDGET(mainwin_jtf))
|
|
255 gtk_widget_set_sensitive(mainwin_jtf, FALSE);
|
|
256
|
|
257 while (files[ctr] != NULL) {
|
|
258 playlist_add(playlist, files[ctr++]);
|
|
259 }
|
|
260 playlistwin_update_list(playlist);
|
|
261
|
|
262 if (GTK_IS_WIDGET(mainwin_jtf))
|
|
263 gtk_widget_set_sensitive(mainwin_jtf, TRUE);
|
|
264
|
|
265 gtk_label_get(GTK_LABEL(GTK_BIN(filesel->history_pulldown)->child),
|
|
266 &ptr);
|
|
267
|
|
268 /* This will give an extra slash if the current dir is the root. */
|
|
269 cfg.filesel_path = g_strconcat(ptr, "/", NULL);
|
|
270 }
|
|
271
|
|
272 static void filebrowser_ok_classic(GtkWidget * w, GtkWidget * filesel)
|
|
273 {
|
|
274 gchar **files;
|
|
275
|
|
276 if (util_filebrowser_is_dir_classic(GTK_FILE_SELECTION(filesel)))
|
|
277 return;
|
|
278 files = gtk_file_selection_get_selections(GTK_FILE_SELECTION(filesel));
|
|
279 filebrowser_add_files_classic(files, GTK_FILE_SELECTION(filesel));
|
|
280 gtk_widget_destroy(filesel);
|
|
281 }
|
|
282
|
|
283 static void filebrowser_play_classic(GtkWidget * w, GtkWidget * filesel)
|
|
284 {
|
|
285 gchar **files;
|
|
286
|
|
287 if (util_filebrowser_is_dir_classic
|
|
288 (GTK_FILE_SELECTION(GTK_FILE_SELECTION(filesel))))
|
|
289 return;
|
|
290 playlist_clear(playlist_get_active());
|
|
291 files = gtk_file_selection_get_selections(GTK_FILE_SELECTION(filesel));
|
|
292 filebrowser_add_files_classic(files, GTK_FILE_SELECTION(filesel));
|
|
293 gtk_widget_destroy(filesel);
|
|
294 playback_initiate();
|
|
295 }
|
|
296
|
|
297 static void filebrowser_add_selected_files_classic(GtkWidget * w, gpointer data)
|
|
298 {
|
|
299 gchar **files;
|
|
300
|
|
301 GtkFileSelection *filesel = GTK_FILE_SELECTION(data);
|
|
302 files = gtk_file_selection_get_selections(filesel);
|
|
303
|
|
304 filebrowser_add_files_classic(files, filesel);
|
|
305 gtk_tree_selection_unselect_all(gtk_tree_view_get_selection
|
|
306 (GTK_TREE_VIEW(filesel->file_list)));
|
|
307
|
|
308 gtk_entry_set_text(GTK_ENTRY(filesel->selection_entry), "");
|
|
309 }
|
|
310
|
|
311 static void filebrowser_add_all_files_classic(GtkWidget * w, gpointer data)
|
|
312 {
|
|
313 gchar **files;
|
|
314 GtkFileSelection *filesel;
|
|
315
|
|
316 filesel = data;
|
|
317 gtk_tree_selection_select_all(gtk_tree_view_get_selection
|
|
318 (GTK_TREE_VIEW(filesel->file_list)));
|
|
319 files = gtk_file_selection_get_selections(filesel);
|
|
320 filebrowser_add_files_classic(files, filesel);
|
|
321 gtk_tree_selection_unselect_all(gtk_tree_view_get_selection
|
|
322 (GTK_TREE_VIEW(filesel->file_list)));
|
|
323 gtk_entry_set_text(GTK_ENTRY(filesel->selection_entry), "");
|
|
324 }
|
|
325
|
|
326 void
|
|
327 util_run_filebrowser_classic(gboolean play_button)
|
|
328 {
|
|
329 static GtkWidget *dialog;
|
|
330 GtkWidget *button_add_selected, *button_add_all, *button_close,
|
|
331 *button_add;
|
|
332 char *title;
|
|
333
|
|
334 if (dialog != NULL) {
|
|
335 gtk_window_present(GTK_WINDOW(dialog));
|
|
336 return;
|
|
337 }
|
|
338
|
|
339 if (play_button)
|
|
340 title = _("Play files");
|
|
341 else
|
|
342 title = _("Load files");
|
|
343
|
|
344 dialog = gtk_file_selection_new(title);
|
|
345
|
|
346 gtk_file_selection_set_select_multiple
|
|
347 (GTK_FILE_SELECTION(dialog), TRUE);
|
|
348
|
|
349 if (cfg.filesel_path)
|
|
350 gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog),
|
|
351 cfg.filesel_path);
|
|
352
|
|
353 gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(dialog));
|
|
354 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
|
|
355
|
|
356 gtk_widget_hide(GTK_FILE_SELECTION(dialog)->ok_button);
|
|
357 gtk_widget_destroy(GTK_FILE_SELECTION(dialog)->cancel_button);
|
|
358
|
|
359 /*
|
|
360 * The mnemonics are quite unorthodox, but that should guarantee they're unique in any locale
|
|
361 * plus kinda easy to use
|
|
362 */
|
|
363 button_add_selected =
|
|
364 gtk_dialog_add_button(GTK_DIALOG(dialog), "Add selected",
|
|
365 GTK_RESPONSE_NONE);
|
|
366 gtk_button_set_use_underline(GTK_BUTTON(button_add_selected), TRUE);
|
|
367 g_signal_connect(G_OBJECT(button_add_selected), "clicked",
|
|
368 G_CALLBACK(filebrowser_add_selected_files_classic), dialog);
|
|
369
|
|
370 button_add_all =
|
|
371 gtk_dialog_add_button(GTK_DIALOG(dialog), "Add all",
|
|
372 GTK_RESPONSE_NONE);
|
|
373 gtk_button_set_use_underline(GTK_BUTTON(button_add_all), TRUE);
|
|
374 g_signal_connect(G_OBJECT(button_add_all), "clicked",
|
|
375 G_CALLBACK(filebrowser_add_all_files_classic), dialog);
|
|
376
|
|
377 if (play_button) {
|
|
378 button_add =
|
|
379 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_MEDIA_PLAY,
|
|
380 GTK_RESPONSE_NONE);
|
|
381 gtk_button_set_use_stock(GTK_BUTTON(button_add), TRUE);
|
|
382 g_signal_connect(G_OBJECT(button_add), "clicked",
|
|
383 G_CALLBACK(filebrowser_play_classic), dialog);
|
|
384 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(dialog)->ok_button),
|
|
385 "clicked", G_CALLBACK(filebrowser_play_classic), dialog);
|
|
386 } else {
|
|
387 button_add =
|
|
388 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_ADD,
|
|
389 GTK_RESPONSE_NONE);
|
|
390 gtk_button_set_use_stock(GTK_BUTTON(button_add), TRUE);
|
|
391 g_signal_connect(G_OBJECT(button_add), "clicked",
|
|
392 G_CALLBACK(filebrowser_ok_classic), dialog);
|
|
393 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(dialog)->ok_button),
|
|
394 "clicked", G_CALLBACK(filebrowser_ok_classic), dialog);
|
|
395 }
|
|
396
|
|
397 button_close =
|
|
398 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CLOSE,
|
|
399 GTK_RESPONSE_NONE);
|
|
400 gtk_button_set_use_stock(GTK_BUTTON(button_close), TRUE);
|
|
401 g_signal_connect_swapped(G_OBJECT(button_close), "clicked",
|
|
402 G_CALLBACK(gtk_widget_destroy),
|
|
403 G_OBJECT(dialog));
|
|
404
|
|
405 gtk_widget_set_size_request(dialog, 600, 450);
|
|
406 gtk_widget_realize(dialog);
|
|
407
|
|
408 g_signal_connect(G_OBJECT
|
|
409 (GTK_FILE_SELECTION(dialog)->history_pulldown),
|
|
410 "changed", G_CALLBACK(filebrowser_entry_changed_classic),
|
|
411 dialog);
|
|
412
|
|
413 g_signal_connect(G_OBJECT(dialog), "destroy",
|
|
414 G_CALLBACK(gtk_widget_destroyed), &dialog);
|
|
415
|
|
416 filebrowser_changed_classic(GTK_FILE_SELECTION(dialog));
|
|
417
|
|
418 gtk_widget_show(dialog);
|
|
419 }
|
|
420
|
|
421 /*
|
|
422 * util_run_filebrowser(gboolean play_button)
|
|
423 *
|
|
424 * Inputs:
|
|
425 * - whether or not a play button should be used
|
|
426 *
|
|
427 * Outputs:
|
|
428 * - none
|
|
429 *
|
|
430 * Side Effects:
|
|
431 * - either a GTK1 or a GTK2 fileselector is launched
|
|
432 */
|
|
433 void
|
|
434 run_filebrowser(gboolean play_button)
|
|
435 {
|
|
436 if (!cfg.use_xmms_style_fileselector)
|
|
437 util_run_filebrowser_gtk2style(play_button);
|
|
438 else
|
|
439 util_run_filebrowser_classic(play_button);
|
|
440 }
|