Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
00001 /* 00002 * folder-add.c 00003 * Copyright 2009-2011 John Lindgren 00004 * 00005 * This file is part of Audacious. 00006 * 00007 * Audacious is free software: you can redistribute it and/or modify it under 00008 * the terms of the GNU General Public License as published by the Free Software 00009 * Foundation, version 2 or version 3 of the License. 00010 * 00011 * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY 00012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 00013 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License along with 00016 * Audacious. If not, see <http://www.gnu.org/licenses/>. 00017 * 00018 * The Audacious team does not consider modular code linking to Audacious or 00019 * using our public API to be a derived work. 00020 */ 00021 00022 #include <dirent.h> 00023 #include <stdio.h> 00024 #include <string.h> 00025 #include <sys/stat.h> 00026 00027 #include <gtk/gtk.h> 00028 00029 #include <libaudcore/audstrings.h> 00030 00031 #include "audconfig.h" 00032 #include "config.h" 00033 #include "glib-compat.h" 00034 #include "i18n.h" 00035 #include "misc.h" 00036 #include "playback.h" 00037 #include "playlist.h" 00038 00039 typedef struct { 00040 gchar * filename; 00041 PluginHandle * decoder; 00042 } AddFile; 00043 00044 typedef struct { 00045 gint playlist_id, at; 00046 GQueue folders; // (gchar *) 00047 gboolean play; 00048 } AddGroup; 00049 00050 static GQueue add_queue = G_QUEUE_INIT; // (AddGroup *) 00051 static gint add_source = 0; 00052 static GtkWidget * add_window = NULL, * add_progress_path, * add_progress_count; 00053 00054 static void show_progress (const gchar * path, gint count) 00055 { 00056 if (add_window == NULL) 00057 { 00058 GtkWidget * vbox; 00059 00060 add_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 00061 gtk_window_set_type_hint (GTK_WINDOW(add_window), 00062 GDK_WINDOW_TYPE_HINT_DIALOG); 00063 gtk_window_set_title (GTK_WINDOW(add_window), _("Searching ...")); 00064 gtk_window_set_resizable (GTK_WINDOW(add_window), FALSE); 00065 gtk_container_set_border_width (GTK_CONTAINER(add_window), 6); 00066 00067 vbox = gtk_vbox_new (FALSE, 6); 00068 gtk_container_add (GTK_CONTAINER(add_window), vbox); 00069 00070 add_progress_path = gtk_label_new (""); 00071 gtk_widget_set_size_request (add_progress_path, 320, -1); 00072 gtk_label_set_ellipsize (GTK_LABEL(add_progress_path), 00073 PANGO_ELLIPSIZE_MIDDLE); 00074 gtk_box_pack_start (GTK_BOX(vbox), add_progress_path, FALSE, FALSE, 0); 00075 00076 add_progress_count = gtk_label_new (""); 00077 gtk_widget_set_size_request (add_progress_count, 320, -1); 00078 gtk_box_pack_start (GTK_BOX(vbox), add_progress_count, FALSE, FALSE, 0); 00079 00080 gtk_widget_show_all (add_window); 00081 00082 g_signal_connect (G_OBJECT(add_window), "destroy", 00083 G_CALLBACK(gtk_widget_destroyed), & add_window); 00084 } 00085 00086 gtk_label_set_text (GTK_LABEL(add_progress_path), path); 00087 00088 gchar scratch[128]; 00089 snprintf (scratch, sizeof scratch, dngettext (PACKAGE, "%d file found", 00090 "%d files found", count), count); 00091 gtk_label_set_text (GTK_LABEL(add_progress_count), scratch); 00092 } 00093 00094 static void show_done (void) 00095 { 00096 gtk_widget_destroy (add_window); 00097 } 00098 00099 static gint sort_cb (const AddFile * a, const AddFile * b) 00100 { 00101 return string_compare_encoded (a->filename, b->filename); 00102 } 00103 00104 static gboolean add_cb (void * unused) 00105 { 00106 static GList * stack = NULL; // (gchar *) and (DIR *) alternately 00107 static GList * big_list = NULL, * little_list = NULL; // (AddFile *) 00108 00109 if (! stack) 00110 { 00111 AddGroup * group = g_queue_peek_head (& add_queue); 00112 g_return_val_if_fail (group, FALSE); 00113 gchar * folder = g_queue_pop_head (& group->folders); 00114 g_return_val_if_fail (folder, FALSE); 00115 stack = g_list_prepend (NULL, folder); 00116 } 00117 00118 show_progress (stack->data, g_list_length (big_list) + g_list_length 00119 (little_list)); 00120 00121 for (gint count = 0; count < 30; count ++) 00122 { 00123 struct stat info; 00124 00125 /* top of stack is (gchar *) */ 00126 00127 if (! stat (stack->data, & info)) 00128 { 00129 if (S_ISREG (info.st_mode)) 00130 { 00131 gchar * filename = filename_to_uri (stack->data); 00132 PluginHandle * decoder = (filename == NULL) ? NULL : 00133 file_find_decoder (filename, TRUE); 00134 00135 if (decoder) 00136 { 00137 AddFile * file = g_slice_new (AddFile); 00138 file->filename = filename; 00139 file->decoder = decoder; 00140 little_list = g_list_prepend (little_list, file); 00141 } 00142 else 00143 g_free (filename); 00144 } 00145 else if (S_ISDIR (info.st_mode)) 00146 { 00147 DIR * folder = opendir (stack->data); 00148 00149 if (folder) 00150 { 00151 stack = g_list_prepend (stack, folder); 00152 goto READ; 00153 } 00154 } 00155 } 00156 00157 g_free (stack->data); 00158 stack = g_list_delete_link (stack, stack); 00159 00160 READ: 00161 if (! stack) 00162 break; 00163 00164 /* top of stack is (DIR *) */ 00165 00166 struct dirent * entry = readdir (stack->data); 00167 00168 if (entry) 00169 { 00170 if (entry->d_name[0] == '.') 00171 goto READ; 00172 00173 stack = g_list_prepend (stack, g_strdup_printf ("%s" 00174 G_DIR_SEPARATOR_S "%s", (gchar *) stack->next->data, entry->d_name)); 00175 } 00176 else 00177 { 00178 closedir (stack->data); 00179 stack = g_list_delete_link (stack, stack); 00180 g_free (stack->data); 00181 stack = g_list_delete_link (stack, stack); 00182 goto READ; 00183 } 00184 } 00185 00186 if (stack) 00187 return TRUE; /* not done yet */ 00188 00189 AddGroup * group = g_queue_peek_head (& add_queue); 00190 g_return_val_if_fail (group, FALSE); 00191 00192 little_list = g_list_sort (little_list, (GCompareFunc) sort_cb); 00193 big_list = g_list_concat (big_list, little_list); 00194 little_list = NULL; 00195 00196 if (! g_queue_is_empty (& group->folders)) 00197 return TRUE; /* not done yet */ 00198 00199 gint playlist = playlist_by_unique_id (group->playlist_id); 00200 00201 if (playlist < 0) /* ouch! playlist deleted */ 00202 { 00203 for (GList * node = big_list; node; node = node->next) 00204 { 00205 AddFile * file = node->data; 00206 g_free (file->filename); 00207 g_slice_free (AddFile, file); 00208 } 00209 00210 g_list_free (big_list); 00211 big_list = NULL; 00212 goto ADDED; 00213 } 00214 00215 struct index * filenames = index_new (); 00216 struct index * decoders = index_new (); 00217 00218 for (GList * node = big_list; node; node = node->next) 00219 { 00220 AddFile * file = node->data; 00221 index_append (filenames, file->filename); 00222 index_append (decoders, file->decoder); 00223 g_slice_free (AddFile, file); 00224 } 00225 00226 g_list_free (big_list); 00227 big_list = NULL; 00228 00229 gint count = playlist_entry_count (playlist); 00230 if (group->at < 0 || group->at > count) 00231 group->at = count; 00232 00233 playlist_entry_insert_batch_with_decoders (playlist, group->at, 00234 filenames, decoders, NULL); 00235 00236 if (group->play && playlist_entry_count (playlist) > count) 00237 { 00238 playlist_set_playing (playlist); 00239 if (! cfg.shuffle) 00240 playlist_set_position (playlist, group->at); 00241 playback_play (0, FALSE); 00242 } 00243 00244 ADDED: 00245 g_slice_free (AddGroup, group); 00246 g_queue_pop_head (& add_queue); 00247 00248 if (! g_queue_is_empty (& add_queue)) 00249 return TRUE; /* not done yet */ 00250 00251 show_done (); 00252 add_source = 0; 00253 return FALSE; 00254 } 00255 00256 void playlist_insert_folder (gint playlist, gint at, const gchar * folder, 00257 gboolean play) 00258 { 00259 gint playlist_id = playlist_get_unique_id (playlist); 00260 g_return_if_fail (playlist_id >= 0); 00261 00262 gchar * unix_name = uri_to_filename (folder); 00263 g_return_if_fail (unix_name); 00264 00265 if (unix_name[strlen (unix_name) - 1] == '/') 00266 unix_name[strlen (unix_name) - 1] = 0; 00267 00268 AddGroup * group = NULL; 00269 00270 for (GList * node = g_queue_peek_head_link (& add_queue); node; node = 00271 node->next) 00272 { 00273 AddGroup * test = node->data; 00274 if (test->playlist_id == playlist_id && test->at == at) 00275 { 00276 group = test; 00277 break; 00278 } 00279 } 00280 00281 if (! group) 00282 { 00283 group = g_slice_new (AddGroup); 00284 group->playlist_id = playlist_id; 00285 group->at = at; 00286 g_queue_init (& group->folders); 00287 group->play = FALSE; 00288 g_queue_push_tail (& add_queue, group); 00289 } 00290 00291 g_queue_push_tail (& group->folders, unix_name); 00292 group->play |= play; 00293 00294 if (! add_source) 00295 add_source = g_idle_add (add_cb, NULL); 00296 }