1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  GThumb
5  *
6  *  Copyright (C) 2008-2009 Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 #include <string.h>
24 #include <glib/gi18n.h>
25 #include <glib.h>
26 #include <gtk/gtk.h>
27 #include "gth-file-data.h"
28 #include "glib-utils.h"
29 #include "gth-file-source.h"
30 #include "gth-main.h"
31 
32 
33 struct _GthFileSourcePrivate {
34 	GList        *schemes;
35 	gboolean      active;
36 	GList        *queue;
37 	GCancellable *cancellable;
38 };
39 
40 
41 G_DEFINE_TYPE_WITH_CODE (GthFileSource,
42 			 gth_file_source,
43 			 G_TYPE_OBJECT,
44 			 G_ADD_PRIVATE (GthFileSource))
45 
46 
47 /* -- queue -- */
48 
49 
50 typedef enum {
51 	FILE_SOURCE_OP_WRITE_METADATA,
52 	FILE_SOURCE_OP_READ_METADATA,
53 	FILE_SOURCE_OP_LIST,
54 	FILE_SOURCE_OP_FOR_EACH_CHILD,
55 	FILE_SOURCE_OP_READ_ATTRIBUTES,
56 	FILE_SOURCE_OP_RENAME,
57 	FILE_SOURCE_OP_COPY,
58 	FILE_SOURCE_OP_REORDER,
59 	FILE_SOURCE_OP_REMOVE,
60 	FILE_SOURCE_OP_DELETED_FROM_DISK,
61 	FILE_SOURCE_OP_GET_FREE_SPACE
62 } FileSourceOp;
63 
64 
65 typedef struct {
66 	GFile      *folder;
67 	const char *attributes;
68 	ListReady   func;
69 	gpointer    data;
70 } ListData;
71 
72 
73 typedef struct {
74 	GList      *files;
75 	const char *attributes;
76 	ListReady   func;
77 	gpointer    data;
78 } ReadAttributesData;
79 
80 
81 typedef struct {
82 	GFile         *file;
83 	char          *edit_name;
84 	ReadyCallback  callback;
85 	gpointer       data;
86 } RenameData;
87 
88 
89 typedef struct {
90 	GthFileData      *destination;
91 	GList            *file_list;
92 	gboolean          move;
93 	int               destination_position;
94 	ProgressCallback  progress_callback;
95 	DialogCallback    dialog_callback;
96 	ReadyCallback     ready_callback;
97 	gpointer          data;
98 } CopyData;
99 
100 
101 typedef struct {
102 	GthFileData   *destination;
103 	GList         *visible_files;
104 	GList         *files_to_move;
105 	int            dest_pos;
106 	ReadyCallback  ready_callback;
107 	gpointer       data;
108 } ReorderData;
109 
110 
111 typedef struct {
112 	GthFileData   *file_data;
113 	char          *attributes;
114 	ReadyCallback  ready_callback;
115 	gpointer       data;
116 } WriteMetadataData;
117 
118 
119 typedef struct {
120 	GthFileData   *file_data;
121 	char          *attributes;
122 	ReadyCallback  ready_callback;
123 	gpointer       data;
124 } ReadMetadataData;
125 
126 
127 typedef struct {
128 	GFile                *parent;
129 	gboolean              recursive;
130 	const char           *attributes;
131 	StartDirCallback      dir_func;
132 	ForEachChildCallback  child_func;
133 	ReadyCallback         ready_func;
134 	gpointer              data;
135 } ForEachChildData;
136 
137 
138 typedef struct {
139 	GthFileData *location;
140 	GList       *file_list;
141 	gboolean     permanently;
142 	GtkWindow   *parent;
143 } RemoveData;
144 
145 
146 typedef struct {
147 	GthFileData *location;
148 	GList       *file_list;
149 } DeletedFromDiskData;
150 
151 
152 typedef struct {
153 	GFile              *location;
154 	SpaceReadyCallback  callback;
155 	gpointer            data;
156 } GetFreeSpaceData;
157 
158 
159 typedef struct {
160 	GthFileSource *file_source;
161 	FileSourceOp   op;
162 	union {
163 		ListData            list;
164 		ForEachChildData    fec;
165 		ReadAttributesData  read_attributes;
166 		RenameData          rename;
167 		CopyData            copy;
168 		ReorderData         reorder;
169 		WriteMetadataData   write_metadata;
170 		ReadMetadataData    read_metadata;
171 		RemoveData          remove;
172 		DeletedFromDiskData deleted_from_disk;
173 		GetFreeSpaceData    get_free_space;
174 	} data;
175 } FileSourceAsyncOp;
176 
177 
178 static void
file_source_async_op_free(FileSourceAsyncOp * async_op)179 file_source_async_op_free (FileSourceAsyncOp *async_op)
180 {
181 	switch (async_op->op) {
182 	case FILE_SOURCE_OP_WRITE_METADATA:
183 		g_free (async_op->data.write_metadata.attributes);
184 		g_object_unref (async_op->data.write_metadata.file_data);
185 		break;
186 	case FILE_SOURCE_OP_READ_METADATA:
187 		g_free (async_op->data.write_metadata.attributes);
188 		g_object_unref (async_op->data.read_metadata.file_data);
189 		break;
190 	case FILE_SOURCE_OP_LIST:
191 		g_object_unref (async_op->data.list.folder);
192 		break;
193 	case FILE_SOURCE_OP_FOR_EACH_CHILD:
194 		g_object_unref (async_op->data.fec.parent);
195 		break;
196 	case FILE_SOURCE_OP_READ_ATTRIBUTES:
197 		_g_object_list_unref (async_op->data.read_attributes.files);
198 		break;
199 	case FILE_SOURCE_OP_RENAME:
200 		g_object_unref (async_op->data.rename.file);
201 		g_free (async_op->data.rename.edit_name);
202 		break;
203 	case FILE_SOURCE_OP_COPY:
204 		g_object_unref (async_op->data.copy.destination);
205 		_g_object_list_unref (async_op->data.copy.file_list);
206 		break;
207 	case FILE_SOURCE_OP_REORDER:
208 		g_object_unref (async_op->data.copy.destination);
209 		_g_object_list_unref (async_op->data.copy.file_list);
210 		break;
211 	case FILE_SOURCE_OP_REMOVE:
212 		_g_object_unref (async_op->data.remove.location);
213 		_g_object_list_unref (async_op->data.remove.file_list);
214 		break;
215 	case FILE_SOURCE_OP_DELETED_FROM_DISK:
216 		_g_object_unref (async_op->data.deleted_from_disk.location);
217 		_g_object_list_unref (async_op->data.deleted_from_disk.file_list);
218 		break;
219 	case FILE_SOURCE_OP_GET_FREE_SPACE:
220 		_g_object_unref (async_op->data.get_free_space.location);
221 		break;
222 	}
223 
224 	g_free (async_op);
225 }
226 
227 
228 static void
gth_file_source_queue_write_metadata(GthFileSource * file_source,GthFileData * file_data,const char * attributes,ReadyCallback callback,gpointer data)229 gth_file_source_queue_write_metadata (GthFileSource *file_source,
230 			              GthFileData   *file_data,
231 			              const char    *attributes,
232 			              ReadyCallback  callback,
233 			              gpointer       data)
234 {
235 	FileSourceAsyncOp *async_op;
236 
237 	async_op = g_new0 (FileSourceAsyncOp, 1);
238 	async_op->file_source = file_source;
239 	async_op->op = FILE_SOURCE_OP_WRITE_METADATA;
240 	async_op->data.write_metadata.file_data = g_object_ref (file_data);
241 	async_op->data.write_metadata.attributes = g_strdup (attributes);
242 	async_op->data.write_metadata.ready_callback = callback;
243 	async_op->data.write_metadata.data = data;
244 
245 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
246 }
247 
248 
249 static void
gth_file_source_queue_read_metadata(GthFileSource * file_source,GthFileData * file_data,const char * attributes,ReadyCallback callback,gpointer data)250 gth_file_source_queue_read_metadata (GthFileSource *file_source,
251 			             GthFileData   *file_data,
252 			             const char    *attributes,
253 			             ReadyCallback  callback,
254 			             gpointer       data)
255 {
256 	FileSourceAsyncOp *async_op;
257 
258 	async_op = g_new0 (FileSourceAsyncOp, 1);
259 	async_op->file_source = file_source;
260 	async_op->op = FILE_SOURCE_OP_READ_METADATA;
261 	async_op->data.read_metadata.file_data = g_object_ref (file_data);
262 	async_op->data.write_metadata.attributes = g_strdup (attributes);
263 	async_op->data.read_metadata.ready_callback = callback;
264 	async_op->data.read_metadata.data = data;
265 
266 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
267 }
268 
269 
270 static void
gth_file_source_queue_list(GthFileSource * file_source,GFile * folder,const char * attributes,ListReady func,gpointer data)271 gth_file_source_queue_list (GthFileSource *file_source,
272 			    GFile         *folder,
273 			    const char    *attributes,
274 			    ListReady      func,
275 			    gpointer       data)
276 {
277 	FileSourceAsyncOp *async_op;
278 
279 	async_op = g_new0 (FileSourceAsyncOp, 1);
280 	async_op->file_source = file_source;
281 	async_op->op = FILE_SOURCE_OP_LIST;
282 	async_op->data.list.folder = g_file_dup (folder);
283 	async_op->data.list.attributes = attributes;
284 	async_op->data.list.func = func;
285 	async_op->data.list.data = data;
286 
287 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
288 }
289 
290 
291 static void
gth_file_source_queue_for_each_child(GthFileSource * file_source,GFile * parent,gboolean recursive,const char * attributes,StartDirCallback dir_func,ForEachChildCallback child_func,ReadyCallback ready_func,gpointer data)292 gth_file_source_queue_for_each_child (GthFileSource        *file_source,
293 				      GFile                *parent,
294 				      gboolean              recursive,
295 				      const char           *attributes,
296 				      StartDirCallback      dir_func,
297 				      ForEachChildCallback  child_func,
298 				      ReadyCallback         ready_func,
299 				      gpointer              data)
300 {
301 	FileSourceAsyncOp *async_op;
302 
303 	async_op = g_new0 (FileSourceAsyncOp, 1);
304 	async_op->file_source = file_source;
305 	async_op->op = FILE_SOURCE_OP_FOR_EACH_CHILD;
306 	async_op->data.fec.parent = g_file_dup (parent);
307 	async_op->data.fec.recursive = recursive;
308 	async_op->data.fec.attributes = attributes;
309 	async_op->data.fec.dir_func = dir_func;
310 	async_op->data.fec.child_func = child_func;
311 	async_op->data.fec.ready_func = ready_func;
312 	async_op->data.fec.data = data;
313 
314 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
315 }
316 
317 
318 static void
gth_file_source_queue_read_attributes(GthFileSource * file_source,GList * files,const char * attributes,ListReady func,gpointer data)319 gth_file_source_queue_read_attributes (GthFileSource *file_source,
320 				       GList         *files,
321 				       const char    *attributes,
322 				       ListReady      func,
323 				       gpointer       data)
324 {
325 	FileSourceAsyncOp *async_op;
326 
327 	async_op = g_new0 (FileSourceAsyncOp, 1);
328 	async_op->file_source = file_source;
329 	async_op->op = FILE_SOURCE_OP_READ_ATTRIBUTES;
330 	async_op->data.read_attributes.files = _g_object_list_ref (files);
331 	async_op->data.read_attributes.attributes = attributes;
332 	async_op->data.read_attributes.func = func;
333 	async_op->data.read_attributes.data = data;
334 
335 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
336 }
337 
338 
339 static void
gth_file_source_queue_rename(GthFileSource * file_source,GFile * file,const char * edit_name,ReadyCallback callback,gpointer data)340 gth_file_source_queue_rename (GthFileSource *file_source,
341 			      GFile         *file,
342 			      const char    *edit_name,
343 			      ReadyCallback  callback,
344 			      gpointer       data)
345 {
346 	FileSourceAsyncOp *async_op;
347 
348 	async_op = g_new0 (FileSourceAsyncOp, 1);
349 	async_op->file_source = file_source;
350 	async_op->op = FILE_SOURCE_OP_RENAME;
351 	async_op->data.rename.file = g_file_dup (file);
352 	async_op->data.rename.edit_name = g_strdup (edit_name);
353 	async_op->data.rename.callback = callback;
354 	async_op->data.rename.data = data;
355 
356 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
357 }
358 
359 
360 static void
gth_file_source_queue_copy(GthFileSource * file_source,GthFileData * destination,GList * file_list,gboolean move,int destination_position,ProgressCallback progress_callback,DialogCallback dialog_callback,ReadyCallback ready_callback,gpointer data)361 gth_file_source_queue_copy (GthFileSource    *file_source,
362 			    GthFileData      *destination,
363 			    GList            *file_list,
364 			    gboolean          move,
365 			    int               destination_position,
366 			    ProgressCallback  progress_callback,
367 			    DialogCallback    dialog_callback,
368 			    ReadyCallback     ready_callback,
369 			    gpointer          data)
370 {
371 	FileSourceAsyncOp *async_op;
372 
373 	async_op = g_new0 (FileSourceAsyncOp, 1);
374 	async_op->file_source = file_source;
375 	async_op->op = FILE_SOURCE_OP_COPY;
376 	async_op->data.copy.destination = gth_file_data_dup (destination);
377 	async_op->data.copy.file_list = _g_file_list_dup (file_list);
378 	async_op->data.copy.move = move;
379 	async_op->data.copy.destination_position = destination_position;
380 	async_op->data.copy.progress_callback = progress_callback;
381 	async_op->data.copy.dialog_callback = dialog_callback;
382 	async_op->data.copy.ready_callback = ready_callback;
383 	async_op->data.copy.data = data;
384 
385 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
386 }
387 
388 
389 static void
gth_file_source_queue_reorder(GthFileSource * file_source,GthFileData * destination,GList * visible_files,GList * files_to_move,int dest_pos,ReadyCallback ready_callback,gpointer data)390 gth_file_source_queue_reorder (GthFileSource    *file_source,
391 			       GthFileData      *destination,
392 			       GList            *visible_files, /* GFile list */
393 			       GList            *files_to_move, /* GFile list */
394 			       int               dest_pos,
395 			       ReadyCallback     ready_callback,
396 			       gpointer          data)
397 {
398 	FileSourceAsyncOp *async_op;
399 
400 	async_op = g_new0 (FileSourceAsyncOp, 1);
401 	async_op->file_source = file_source;
402 	async_op->op = FILE_SOURCE_OP_REORDER;
403 	async_op->data.reorder.destination = gth_file_data_dup (destination);
404 	async_op->data.reorder.visible_files = _g_file_list_dup (visible_files);
405 	async_op->data.reorder.files_to_move = _g_file_list_dup (files_to_move);
406 	async_op->data.reorder.dest_pos = dest_pos;
407 	async_op->data.reorder.ready_callback = ready_callback;
408 	async_op->data.reorder.data = data;
409 
410 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
411 }
412 
413 
414 static void
gth_file_source_queue_remove(GthFileSource * file_source,GthFileData * location,GList * file_list,gboolean permanently,GtkWindow * parent)415 gth_file_source_queue_remove (GthFileSource *file_source,
416 			      GthFileData   *location,
417 			      GList         *file_list,
418 			      gboolean       permanently,
419 			      GtkWindow     *parent)
420 {
421 	FileSourceAsyncOp *async_op;
422 
423 	async_op = g_new0 (FileSourceAsyncOp, 1);
424 	async_op->file_source = file_source;
425 	async_op->op = FILE_SOURCE_OP_REMOVE;
426 	async_op->data.remove.location = gth_file_data_dup (location);
427 	async_op->data.remove.file_list = gth_file_data_list_dup (file_list);
428 	async_op->data.remove.permanently = permanently;
429 	async_op->data.remove.parent = parent;
430 
431 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
432 }
433 
434 
435 static void
gth_file_source_queue_deleted_from_disk(GthFileSource * file_source,GthFileData * location,GList * file_list)436 gth_file_source_queue_deleted_from_disk (GthFileSource *file_source,
437 					 GthFileData   *location,
438 					 GList         *file_list)
439 {
440 	FileSourceAsyncOp *async_op;
441 
442 	async_op = g_new0 (FileSourceAsyncOp, 1);
443 	async_op->file_source = file_source;
444 	async_op->op = FILE_SOURCE_OP_DELETED_FROM_DISK;
445 	async_op->data.deleted_from_disk.location = gth_file_data_dup (location);
446 	async_op->data.deleted_from_disk.file_list = _g_file_list_dup (file_list);
447 
448 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
449 }
450 
451 
452 static void
gth_file_source_queue_get_free_space(GthFileSource * file_source,GFile * location,SpaceReadyCallback callback,gpointer data)453 gth_file_source_queue_get_free_space (GthFileSource      *file_source,
454 				      GFile              *location,
455 				      SpaceReadyCallback  callback,
456 				      gpointer            data)
457 {
458 	FileSourceAsyncOp *async_op;
459 
460 	async_op = g_new0 (FileSourceAsyncOp, 1);
461 	async_op->file_source = file_source;
462 	async_op->op = FILE_SOURCE_OP_GET_FREE_SPACE;
463 	async_op->data.get_free_space.location = g_file_dup (location);
464 	async_op->data.get_free_space.callback = callback;
465 	async_op->data.get_free_space.data = data;
466 
467 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
468 }
469 
470 
471 static void
gth_file_source_exec_next_in_queue(GthFileSource * file_source)472 gth_file_source_exec_next_in_queue (GthFileSource *file_source)
473 {
474 	GList             *head;
475 	FileSourceAsyncOp *async_op;
476 
477 	if (file_source->priv->queue == NULL)
478 		return;
479 
480 	g_cancellable_reset (file_source->priv->cancellable);
481 
482 	head = file_source->priv->queue;
483 	file_source->priv->queue = g_list_remove_link (file_source->priv->queue, head);
484 
485 	async_op = head->data;
486 	switch (async_op->op) {
487 	case FILE_SOURCE_OP_WRITE_METADATA:
488 		gth_file_source_write_metadata (file_source,
489 					        async_op->data.write_metadata.file_data,
490 					        async_op->data.write_metadata.attributes,
491 					        async_op->data.write_metadata.ready_callback,
492 					        async_op->data.write_metadata.data);
493 		break;
494 	case FILE_SOURCE_OP_READ_METADATA:
495 		gth_file_source_read_metadata (file_source,
496 					       async_op->data.read_metadata.file_data,
497 					       async_op->data.write_metadata.attributes,
498 					       async_op->data.read_metadata.ready_callback,
499 					       async_op->data.read_metadata.data);
500 		break;
501 	case FILE_SOURCE_OP_LIST:
502 		gth_file_source_list (file_source,
503 				      async_op->data.list.folder,
504 				      async_op->data.list.attributes,
505 				      async_op->data.list.func,
506 				      async_op->data.list.data);
507 		break;
508 	case FILE_SOURCE_OP_FOR_EACH_CHILD:
509 		gth_file_source_for_each_child (file_source,
510 						async_op->data.fec.parent,
511 						async_op->data.fec.recursive,
512 						async_op->data.fec.attributes,
513 						async_op->data.fec.dir_func,
514 						async_op->data.fec.child_func,
515 						async_op->data.fec.ready_func,
516 						async_op->data.fec.data);
517 		break;
518 	case FILE_SOURCE_OP_READ_ATTRIBUTES:
519 		gth_file_source_read_attributes (file_source,
520 						 async_op->data.read_attributes.files,
521 						 async_op->data.read_attributes.attributes,
522 						 async_op->data.read_attributes.func,
523 						 async_op->data.read_attributes.data);
524 		break;
525 	case FILE_SOURCE_OP_RENAME:
526 		gth_file_source_rename (file_source,
527 					async_op->data.rename.file,
528 					async_op->data.rename.edit_name,
529 					async_op->data.rename.callback,
530 					async_op->data.rename.data);
531 		break;
532 	case FILE_SOURCE_OP_COPY:
533 		gth_file_source_copy (file_source,
534 				      async_op->data.copy.destination,
535 				      async_op->data.copy.file_list,
536 				      async_op->data.copy.move,
537 				      async_op->data.copy.destination_position,
538 				      async_op->data.copy.progress_callback,
539 				      async_op->data.copy.dialog_callback,
540 				      async_op->data.copy.ready_callback,
541 				      async_op->data.copy.data);
542 		break;
543 	case FILE_SOURCE_OP_REORDER:
544 		gth_file_source_reorder (file_source,
545 					 async_op->data.reorder.destination,
546 					 async_op->data.reorder.visible_files,
547 					 async_op->data.reorder.files_to_move,
548 					 async_op->data.reorder.dest_pos,
549 				         async_op->data.reorder.ready_callback,
550 					 async_op->data.reorder.data);
551 		break;
552 	case FILE_SOURCE_OP_REMOVE:
553 		gth_file_source_remove (file_source,
554 					async_op->data.remove.location,
555 					async_op->data.remove.file_list,
556 					async_op->data.remove.permanently,
557 					async_op->data.remove.parent);
558 		break;
559 
560 	case FILE_SOURCE_OP_DELETED_FROM_DISK:
561 		gth_file_source_queue_deleted_from_disk (file_source,
562 							 async_op->data.deleted_from_disk.location,
563 							 async_op->data.deleted_from_disk.file_list);
564 		break;
565 
566 	case FILE_SOURCE_OP_GET_FREE_SPACE:
567 		gth_file_source_get_free_space (file_source,
568 						async_op->data.get_free_space.location,
569 						async_op->data.get_free_space.callback,
570 						async_op->data.get_free_space.data);
571 		break;
572 	}
573 
574 	file_source_async_op_free (async_op);
575 	g_list_free (head);
576 }
577 
578 
579 static void
gth_file_source_clear_queue(GthFileSource * file_source)580 gth_file_source_clear_queue (GthFileSource  *file_source)
581 {
582 	g_list_foreach (file_source->priv->queue, (GFunc) file_source_async_op_free, NULL);
583 	g_list_free (file_source->priv->queue);
584 	file_source->priv->queue = NULL;
585 }
586 
587 
588 /* -- */
589 
590 
591 static GList *
base_get_entry_points(GthFileSource * file_source)592 base_get_entry_points (GthFileSource  *file_source)
593 {
594 	return NULL;
595 }
596 
597 
598 static GList *
base_get_current_list(GthFileSource * file_source,GFile * file)599 base_get_current_list (GthFileSource  *file_source,
600 		       GFile          *file)
601 {
602 	GList *list = NULL;
603 	GFile *parent;
604 
605 	if (file == NULL)
606 		return NULL;
607 
608 	parent = g_file_dup (file);
609 	while (parent != NULL) {
610 		GFile *tmp;
611 
612 		list = g_list_prepend (list, g_object_ref (parent));
613 		tmp = g_file_get_parent (parent);
614 		g_object_unref (parent);
615 		parent = tmp;
616 	}
617 
618 	return g_list_reverse (list);
619 }
620 
621 
622 static GFile *
base_to_gio_file(GthFileSource * file_source,GFile * file)623 base_to_gio_file (GthFileSource *file_source,
624 		  GFile         *file)
625 {
626 	return g_file_dup (file);
627 }
628 
629 
630 static GFileInfo *
base_get_file_info(GthFileSource * file_source,GFile * file,const char * attributes)631 base_get_file_info (GthFileSource *file_source,
632 		    GFile         *file,
633 		    const char    *attributes)
634 {
635 	return NULL;
636 }
637 
638 
639 static GthFileData *
base_get_file_data(GthFileSource * file_source,GFile * file,GFileInfo * info)640 base_get_file_data (GthFileSource  *file_source,
641 		    GFile          *file,
642 		    GFileInfo      *info)
643 {
644 	return gth_file_data_new (file, info);
645 }
646 
647 
648 static void
base_write_metadata(GthFileSource * file_source,GthFileData * file_data,const char * attributes,ReadyCallback callback,gpointer data)649 base_write_metadata (GthFileSource *file_source,
650 		     GthFileData   *file_data,
651 		     const char    *attributes,
652 		     ReadyCallback  callback,
653 		     gpointer       data)
654 {
655 	object_ready_with_error (file_source, callback, data, NULL);
656 }
657 
658 
659 typedef struct {
660 	GFile              *location;
661 	GthFileSource      *file_source;
662 	SpaceReadyCallback  callback;
663 	gpointer            data;
664 } BaseFreeSpaceData;
665 
666 
667 static void
get_free_space_ready_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)668 get_free_space_ready_cb (GObject      *source_object,
669 			 GAsyncResult *res,
670 			 gpointer      user_data)
671 {
672 	BaseFreeSpaceData *free_space_data = user_data;
673 	GFileInfo         *info;
674 	GError            *error = NULL;
675 	guint64            total_size = 0;
676 	guint64            free_space = 0;
677 
678 	info = g_file_query_filesystem_info_finish (free_space_data->location, res, &error);
679 	if (info != NULL) {
680 		total_size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE);
681 		free_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
682 		g_object_unref (info);
683 	}
684 
685 	free_space_data->callback (free_space_data->file_source,
686 				   total_size,
687 				   free_space,
688 				   error,
689 				   free_space_data->data);
690 
691 	if (error != NULL)
692 		g_error_free (error);
693 	g_object_unref (free_space_data->location);
694 	g_free (free_space_data);
695 }
696 
697 
698 static void
base_get_free_space(GthFileSource * file_source,GFile * location,SpaceReadyCallback callback,gpointer data)699 base_get_free_space (GthFileSource        *file_source,
700 		     GFile                *location,
701 		     SpaceReadyCallback    callback,
702 		     gpointer              data)
703 {
704 	BaseFreeSpaceData *free_space_data;
705 
706 	free_space_data = g_new0 (BaseFreeSpaceData, 1);
707 	free_space_data->location = g_object_ref (location);
708 	free_space_data->file_source = file_source;
709 	free_space_data->callback = callback;
710 	free_space_data->data = data;
711 	g_file_query_filesystem_info_async (location,
712 					    G_FILE_ATTRIBUTE_FILESYSTEM_SIZE "," G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
713 					    G_PRIORITY_DEFAULT,
714 					    file_source->priv->cancellable,
715 					    get_free_space_ready_cb,
716 					    free_space_data);
717 }
718 
719 
720 /* -- base_read_metadata -- */
721 
722 
723 typedef struct {
724 	GthFileSource *file_source;
725 	GthFileData   *file_data;
726 	ReadyCallback  callback;
727 	gpointer       data;
728 } ReadMetadataOpData;
729 
730 
731 static void
read_metadata_free(ReadMetadataOpData * read_metadata)732 read_metadata_free (ReadMetadataOpData *read_metadata)
733 {
734 	g_object_unref (read_metadata->file_source);
735 	g_object_unref (read_metadata->file_data);
736 	g_free (read_metadata);
737 }
738 
739 
740 static void
read_metadata_info_ready_cb(GList * files,GError * error,gpointer user_data)741 read_metadata_info_ready_cb (GList    *files,
742 			     GError   *error,
743 			     gpointer  user_data)
744 {
745 	ReadMetadataOpData *read_metadata = user_data;
746 	GthFileData        *result;
747 
748 	if (error != NULL) {
749 		read_metadata->callback (G_OBJECT (read_metadata->file_source), error, read_metadata->data);
750 		read_metadata_free (read_metadata);
751 		return;
752 	}
753 
754 	result = files->data;
755 	g_file_info_copy_into (result->info, read_metadata->file_data->info);
756 	read_metadata->callback (G_OBJECT (read_metadata->file_source), NULL, read_metadata->data);
757 
758 	read_metadata_free (read_metadata);
759 }
760 
761 
762 static void
base_read_metadata(GthFileSource * file_source,GthFileData * file_data,const char * attributes,ReadyCallback callback,gpointer data)763 base_read_metadata (GthFileSource *file_source,
764 		    GthFileData   *file_data,
765 		    const char    *attributes,
766 		    ReadyCallback  callback,
767 		    gpointer       data)
768 {
769 	ReadMetadataOpData *read_metadata;
770 	GList              *files;
771 
772 	read_metadata = g_new0 (ReadMetadataOpData, 1);
773 	read_metadata->file_source = g_object_ref (file_source);
774 	read_metadata->file_data = g_object_ref (file_data);
775 	read_metadata->callback = callback;
776 	read_metadata->data = data;
777 
778 	files = g_list_prepend (NULL, file_data->file);
779 	_g_query_all_metadata_async (files,
780 				     GTH_LIST_DEFAULT,
781 				     attributes,
782 				     file_source->priv->cancellable,
783 				     read_metadata_info_ready_cb,
784 				     read_metadata);
785 
786 	g_list_free (files);
787 }
788 
789 
790 static void
base_rename(GthFileSource * file_source,GFile * file,const char * edit_name,ReadyCallback callback,gpointer data)791 base_rename (GthFileSource *file_source,
792 	     GFile         *file,
793 	     const char    *edit_name,
794 	     ReadyCallback  callback,
795 	     gpointer       data)
796 {
797 	GFile  *parent;
798 	GFile  *new_file;
799 	GFile  *source;
800 	GFile  *destination;
801 	GError *error = NULL;
802 
803 	parent = g_file_get_parent (file);
804 	new_file = g_file_get_child_for_display_name (parent, edit_name, &error);
805 	if (new_file == NULL) {
806 		object_ready_with_error (file_source, callback, data, error);
807 		return;
808 	}
809 
810 	source = gth_file_source_to_gio_file (file_source, file);
811 	destination = gth_file_source_to_gio_file (file_source, new_file);
812 
813 	if (g_file_move (source,
814 			 destination,
815 			 0,
816 			 gth_file_source_get_cancellable (file_source),
817 			 NULL,
818 			 NULL,
819 			 &error))
820 	{
821 		GthMonitor *monitor;
822 
823 		monitor = gth_main_get_default_monitor ();
824 		gth_monitor_file_renamed (monitor, file, new_file);
825 	}
826 	object_ready_with_error (file_source, callback, data, error);
827 
828 	g_object_unref (destination);
829 	g_object_unref (source);
830 }
831 
832 
833 static gboolean
base_can_cut(GthFileSource * file_source)834 base_can_cut (GthFileSource *file_source)
835 {
836 	return FALSE;
837 }
838 
839 
840 static void
base_monitor_entry_points(GthFileSource * file_source)841 base_monitor_entry_points (GthFileSource *file_source)
842 {
843 	/* void */
844 }
845 
846 
847 static void
base_monitor_directory(GthFileSource * file_source,GFile * file,gboolean activate)848 base_monitor_directory (GthFileSource  *file_source,
849 			GFile          *file,
850 			gboolean        activate)
851 {
852 	/* void */
853 }
854 
855 
856 static gboolean
base_is_reorderable(GthFileSource * file_source)857 base_is_reorderable (GthFileSource *file_source)
858 {
859 	return FALSE;
860 }
861 
862 
863 static void
base_reorder(GthFileSource * file_source,GthFileData * destination,GList * visible_files,GList * files_to_move,int dest_pos,ReadyCallback callback,gpointer data)864 base_reorder (GthFileSource *file_source,
865 	      GthFileData   *destination,
866 	      GList         *visible_files, /* GFile list */
867 	      GList         *files_to_move, /* GFile list */
868 	      int            dest_pos,
869 	      ReadyCallback  callback,
870 	      gpointer       data)
871 {
872 	/* void */
873 }
874 
875 
876 static void
base_remove(GthFileSource * file_source,GthFileData * location,GList * file_list,gboolean permanently,GtkWindow * parent)877 base_remove (GthFileSource *file_source,
878 	     GthFileData   *location,
879 	     GList         *file_list, /* GFile list */
880 	     gboolean       permanently,
881 	     GtkWindow     *parent)
882 {
883 	/* void */
884 }
885 
886 
887 static void
base_deleted_from_disk(GthFileSource * file_source,GthFileData * location,GList * file_list)888 base_deleted_from_disk (GthFileSource *file_source,
889 			GthFileData   *location,
890 			GList         *file_list /* GFile list */)
891 {
892 	/* void */
893 }
894 
895 
896 static gboolean
base_shows_extra_widget(GthFileSource * file_source)897 base_shows_extra_widget (GthFileSource *file_source)
898 {
899 	return FALSE;
900 }
901 
902 
903 static GdkDragAction
base_get_drop_actions(GthFileSource * file_source,GFile * destination,GFile * file)904 base_get_drop_actions (GthFileSource *file_source,
905 		       GFile         *destination,
906 		       GFile         *file)
907 {
908 	return 0; /* no action supported by default. */
909 }
910 
911 
912 static void
gth_file_source_finalize(GObject * object)913 gth_file_source_finalize (GObject *object)
914 {
915 	GthFileSource *file_source = GTH_FILE_SOURCE (object);
916 
917 	gth_file_source_clear_queue (file_source);
918 	_g_string_list_free (file_source->priv->schemes);
919 	_g_object_unref (file_source->priv->cancellable);
920 
921 	G_OBJECT_CLASS (gth_file_source_parent_class)->finalize (object);
922 }
923 
924 
925 static void
gth_file_source_class_init(GthFileSourceClass * class)926 gth_file_source_class_init (GthFileSourceClass *class)
927 {
928 	GObjectClass *object_class;
929 
930 	object_class = (GObjectClass*) class;
931 	object_class->finalize = gth_file_source_finalize;
932 
933 	class->get_entry_points = base_get_entry_points;
934 	class->get_current_list = base_get_current_list;
935 	class->to_gio_file = base_to_gio_file;
936 	class->get_file_info = base_get_file_info;
937 	class->get_file_data = base_get_file_data;
938 	class->write_metadata = base_write_metadata;
939 	class->read_metadata = base_read_metadata;
940 	class->rename = base_rename;
941 	class->can_cut = base_can_cut;
942 	class->monitor_entry_points = base_monitor_entry_points;
943 	class->monitor_directory = base_monitor_directory;
944 	class->is_reorderable = base_is_reorderable;
945 	class->reorder = base_reorder;
946 	class->remove = base_remove;
947 	class->deleted_from_disk = base_deleted_from_disk;
948 	class->get_free_space = base_get_free_space;
949 	class->shows_extra_widget = base_shows_extra_widget;
950 	class->get_drop_actions = base_get_drop_actions;
951 }
952 
953 
954 static void
gth_file_source_init(GthFileSource * file_source)955 gth_file_source_init (GthFileSource *file_source)
956 {
957 	file_source->priv = gth_file_source_get_instance_private (file_source);
958 	file_source->priv->schemes = NULL;
959 	file_source->priv->active = FALSE;
960 	file_source->priv->queue = NULL;
961 	file_source->priv->cancellable = g_cancellable_new ();
962 }
963 
964 
965 void
gth_file_source_add_scheme(GthFileSource * file_source,const char * scheme)966 gth_file_source_add_scheme (GthFileSource  *file_source,
967 			    const char     *scheme)
968 {
969 	file_source->priv->schemes = g_list_prepend (file_source->priv->schemes, g_strdup (scheme));
970 }
971 
972 
973 gboolean
gth_file_source_supports_scheme(GthFileSource * file_source,const char * uri)974 gth_file_source_supports_scheme (GthFileSource *file_source,
975 				 const char    *uri)
976 {
977 	GList *scan;
978 
979 	for (scan = file_source->priv->schemes; scan; scan = scan->next) {
980 		const char *scheme = scan->data;
981 
982 		if (g_str_has_prefix (uri, scheme))
983 			return TRUE;
984 	}
985 
986 	return FALSE;
987 }
988 
989 
990 void
gth_file_source_set_active(GthFileSource * file_source,gboolean active)991 gth_file_source_set_active (GthFileSource *file_source,
992 			    gboolean       active)
993 {
994 	file_source->priv->active = active;
995 	if (! active)
996 		gth_file_source_exec_next_in_queue (file_source);
997 }
998 
999 
1000 void
gth_file_source_set_cancellable(GthFileSource * file_source,GCancellable * cancellable)1001 gth_file_source_set_cancellable (GthFileSource *file_source,
1002 				 GCancellable  *cancellable)
1003 {
1004 	_g_object_unref (file_source->priv->cancellable);
1005 	file_source->priv->cancellable = NULL;
1006 	if (cancellable != NULL)
1007 		file_source->priv->cancellable = g_object_ref (cancellable);
1008 }
1009 
1010 
1011 GList *
gth_file_source_get_entry_points(GthFileSource * file_source)1012 gth_file_source_get_entry_points (GthFileSource *file_source)
1013 {
1014 	return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->get_entry_points (file_source);
1015 }
1016 
1017 
1018 GList *
gth_file_source_get_current_list(GthFileSource * file_source,GFile * file)1019 gth_file_source_get_current_list (GthFileSource *file_source,
1020 				  GFile         *file)
1021 {
1022 	return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->get_current_list (file_source, file);
1023 }
1024 
1025 
1026 GFile *
gth_file_source_to_gio_file(GthFileSource * file_source,GFile * file)1027 gth_file_source_to_gio_file (GthFileSource *file_source,
1028 			     GFile         *file)
1029 {
1030 	return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->to_gio_file (file_source, file);
1031 }
1032 
1033 
1034 GList *
gth_file_source_to_gio_file_list(GthFileSource * file_source,GList * files)1035 gth_file_source_to_gio_file_list (GthFileSource *file_source,
1036 				  GList         *files)
1037 {
1038 	GList *gio_files = NULL;
1039 	GList *scan;
1040 
1041 	for (scan = files; scan; scan = scan->next)
1042 		gio_files = g_list_prepend (gio_files, gth_file_source_to_gio_file (file_source, (GFile *) scan->data));
1043 
1044 	return g_list_reverse (gio_files);
1045 }
1046 
1047 
1048 GFileInfo *
gth_file_source_get_file_info(GthFileSource * file_source,GFile * file,const char * attributes)1049 gth_file_source_get_file_info (GthFileSource *file_source,
1050 			       GFile         *file,
1051 			       const char    *attributes)
1052 {
1053 	return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->get_file_info (file_source, file, attributes);
1054 }
1055 
1056 
1057 GthFileData *
gth_file_source_get_file_data(GthFileSource * file_source,GFile * file,GFileInfo * info)1058 gth_file_source_get_file_data (GthFileSource *file_source,
1059 			       GFile         *file,
1060 			       GFileInfo     *info)
1061 {
1062 	return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->get_file_data (file_source, file, info);
1063 }
1064 
1065 
1066 gboolean
gth_file_source_is_active(GthFileSource * file_source)1067 gth_file_source_is_active (GthFileSource *file_source)
1068 {
1069 	return file_source->priv->active;
1070 }
1071 
1072 
1073 GCancellable *
gth_file_source_get_cancellable(GthFileSource * file_source)1074 gth_file_source_get_cancellable (GthFileSource *file_source)
1075 {
1076 	return file_source->priv->cancellable;
1077 }
1078 
1079 
1080 void
gth_file_source_cancel(GthFileSource * file_source)1081 gth_file_source_cancel (GthFileSource *file_source)
1082 {
1083 	gth_file_source_clear_queue (file_source);
1084 	g_cancellable_cancel (file_source->priv->cancellable);
1085 }
1086 
1087 
1088 void
gth_file_source_write_metadata(GthFileSource * file_source,GthFileData * file_data,const char * attributes,ReadyCallback callback,gpointer data)1089 gth_file_source_write_metadata (GthFileSource *file_source,
1090 				GthFileData   *file_data,
1091 				const char    *attributes,
1092 				ReadyCallback  callback,
1093 				gpointer       data)
1094 {
1095 	if (gth_file_source_is_active (file_source)) {
1096 		gth_file_source_queue_write_metadata (file_source, file_data, attributes, callback, data);
1097 		return;
1098 	}
1099 	g_cancellable_reset (file_source->priv->cancellable);
1100 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->write_metadata (file_source, file_data, attributes, callback, data);
1101 }
1102 
1103 
1104 void
gth_file_source_read_metadata(GthFileSource * file_source,GthFileData * file_data,const char * attributes,ReadyCallback callback,gpointer data)1105 gth_file_source_read_metadata (GthFileSource *file_source,
1106 			       GthFileData   *file_data,
1107 			       const char    *attributes,
1108 			       ReadyCallback  callback,
1109 			       gpointer       data)
1110 {
1111 	if (gth_file_source_is_active (file_source)) {
1112 		gth_file_source_queue_read_metadata (file_source, file_data, attributes, callback, data);
1113 		return;
1114 	}
1115 	g_cancellable_reset (file_source->priv->cancellable);
1116 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->read_metadata (file_source, file_data, attributes, callback, data);
1117 }
1118 
1119 
1120 /* -- gth_file_source_list -- */
1121 
1122 
1123 typedef struct {
1124 	GthFileSource *file_source;
1125 	ListReady      ready_func;
1126 	gpointer       user_data;
1127 	GList         *files;
1128 } ListOpData;
1129 
1130 
1131 static void
list__done_func(GObject * source,GError * error,gpointer user_data)1132 list__done_func (GObject  *source,
1133 		 GError   *error,
1134 		 gpointer  user_data)
1135 {
1136 	ListOpData *data = user_data;
1137 
1138 	data->files = g_list_reverse (data->files);
1139 	data->ready_func (data->file_source, data->files, error, data->user_data);
1140 
1141 	_g_object_list_unref (data->files);
1142 	g_object_unref (data->file_source);
1143 	g_free (data);
1144 }
1145 
1146 
1147 static void
list__for_each_file_func(GFile * file,GFileInfo * info,gpointer user_data)1148 list__for_each_file_func (GFile     *file,
1149 			  GFileInfo *info,
1150 			  gpointer   user_data)
1151 {
1152 	ListOpData *data = user_data;
1153 
1154 	switch (g_file_info_get_file_type (info)) {
1155 	case G_FILE_TYPE_REGULAR:
1156 	case G_FILE_TYPE_DIRECTORY:
1157 		data->files = g_list_prepend (data->files, gth_file_data_new (file, info));
1158 		break;
1159 	default:
1160 		break;
1161 	}
1162 }
1163 
1164 
1165 static DirOp
list__start_dir_func(GFile * directory,GFileInfo * info,GError ** error,gpointer user_data)1166 list__start_dir_func (GFile       *directory,
1167 		      GFileInfo   *info,
1168 		      GError     **error,
1169 		      gpointer     user_data)
1170 {
1171 	return DIR_OP_CONTINUE;
1172 }
1173 
1174 
1175 void
gth_file_source_list(GthFileSource * file_source,GFile * folder,const char * attributes,ListReady func,gpointer user_data)1176 gth_file_source_list (GthFileSource *file_source,
1177 		      GFile         *folder,
1178 		      const char    *attributes,
1179 		      ListReady      func,
1180 		      gpointer       user_data)
1181 {
1182 	ListOpData *data;
1183 
1184 	if (gth_file_source_is_active (file_source)) {
1185 		gth_file_source_queue_list (file_source, folder, attributes, func, user_data);
1186 		return;
1187 	}
1188 
1189 	g_cancellable_reset (file_source->priv->cancellable);
1190 
1191 	data = g_new0 (ListOpData, 1);
1192 	data->file_source = g_object_ref (file_source);
1193 	data->ready_func = func;
1194 	data->user_data = user_data;
1195 
1196 	gth_file_source_for_each_child (file_source,
1197 				        folder,
1198 				        FALSE,
1199 				        attributes,
1200 				        list__start_dir_func,
1201 				        list__for_each_file_func,
1202 				        list__done_func,
1203 				        data);
1204 }
1205 
1206 
1207 void
gth_file_source_for_each_child(GthFileSource * file_source,GFile * parent,gboolean recursive,const char * attributes,StartDirCallback dir_func,ForEachChildCallback child_func,ReadyCallback ready_func,gpointer data)1208 gth_file_source_for_each_child (GthFileSource        *file_source,
1209 				GFile                *parent,
1210 				gboolean              recursive,
1211 				const char           *attributes,
1212 				StartDirCallback      dir_func,
1213 				ForEachChildCallback  child_func,
1214 				ReadyCallback         ready_func,
1215 				gpointer              data)
1216 {
1217 	if (gth_file_source_is_active (file_source)) {
1218 		gth_file_source_queue_for_each_child (file_source, parent, recursive, attributes, dir_func, child_func, ready_func, data);
1219 		return;
1220 	}
1221 	g_cancellable_reset (file_source->priv->cancellable);
1222 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->for_each_child (file_source, parent, recursive, attributes, dir_func, child_func, ready_func, data);
1223 }
1224 
1225 
1226 /* -- gth_file_source_read_attributes -- */
1227 
1228 
1229 typedef struct {
1230 	GthFileSource *file_source;
1231 	ListReady      ready_func;
1232 	gpointer       ready_data;
1233 } ReadAttributesOpData;
1234 
1235 
1236 
1237 static void
read_attributes_op_data_free(ReadAttributesOpData * data)1238 read_attributes_op_data_free (ReadAttributesOpData *data)
1239 {
1240 	g_object_unref (data->file_source);
1241 	g_free (data);
1242 }
1243 
1244 
1245 static void
metadata_ready_cb(GList * files,GError * error,gpointer user_data)1246 metadata_ready_cb (GList    *files,
1247 	           GError   *error,
1248 	           gpointer  user_data)
1249 {
1250 	ReadAttributesOpData *data = user_data;
1251 	GList                *scan;
1252 	GList                *result_files;
1253 
1254 	gth_file_source_set_active (data->file_source, FALSE);
1255 
1256 	result_files = NULL;
1257 	for (scan = files; scan; scan = scan->next) {
1258 		GthFileData *file_data = scan->data;
1259 		result_files = g_list_prepend (result_files, gth_file_source_get_file_data (data->file_source, file_data->file, file_data->info));
1260 	}
1261 	result_files = g_list_reverse (result_files);
1262 
1263 	data->ready_func (data->file_source,
1264 			  result_files,
1265 			  error,
1266 			  data->ready_data);
1267 
1268 	_g_object_list_unref (result_files);
1269 	read_attributes_op_data_free (data);
1270 }
1271 
1272 
1273 void
gth_file_source_read_attributes(GthFileSource * file_source,GList * files,const char * attributes,ListReady func,gpointer user_data)1274 gth_file_source_read_attributes (GthFileSource  *file_source,
1275 				 GList          *files,
1276 				 const char     *attributes,
1277 				 ListReady       func,
1278 				 gpointer        user_data)
1279 {
1280 	ReadAttributesOpData *data;
1281 	GList                *gio_files;
1282 
1283 	if (gth_file_source_is_active (file_source)) {
1284 		gth_file_source_queue_read_attributes (file_source, files, attributes, func, user_data);
1285 		return;
1286 	}
1287 
1288 	g_cancellable_reset (file_source->priv->cancellable);
1289 
1290 	data = g_new0 (ReadAttributesOpData, 1);
1291 	data->file_source = g_object_ref (file_source);
1292 	data->ready_func = func;
1293 	data->ready_data = user_data;
1294 
1295 	gio_files = gth_file_source_to_gio_file_list (file_source, files);
1296 	_g_query_all_metadata_async (gio_files,
1297 				     GTH_LIST_DEFAULT,
1298 				     attributes,
1299 				     file_source->priv->cancellable,
1300 				     metadata_ready_cb,
1301 				     data);
1302 
1303 	_g_object_list_unref (gio_files);
1304 }
1305 
1306 
1307 void
gth_file_source_rename(GthFileSource * file_source,GFile * file,const char * edit_name,ReadyCallback ready_callback,gpointer data)1308 gth_file_source_rename (GthFileSource  *file_source,
1309 			GFile          *file,
1310 			const char     *edit_name,
1311 			ReadyCallback   ready_callback,
1312 			gpointer        data)
1313 {
1314 	if (gth_file_source_is_active (file_source)) {
1315 		gth_file_source_queue_rename (file_source, file, edit_name, ready_callback, data);
1316 		return;
1317 	}
1318 	g_cancellable_reset (file_source->priv->cancellable);
1319 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->rename (file_source, file, edit_name, ready_callback, data);
1320 }
1321 
1322 
1323 void
gth_file_source_copy(GthFileSource * file_source,GthFileData * destination,GList * file_list,gboolean move,int destination_position,ProgressCallback progress_callback,DialogCallback dialog_callback,ReadyCallback ready_callback,gpointer data)1324 gth_file_source_copy (GthFileSource    *file_source,
1325 		      GthFileData      *destination,
1326 		      GList            *file_list, /* GFile * list */
1327 		      gboolean          move,
1328 		      int               destination_position,
1329 		      ProgressCallback  progress_callback,
1330 		      DialogCallback    dialog_callback,
1331 		      ReadyCallback     ready_callback,
1332 		      gpointer          data)
1333 {
1334 	if (gth_file_source_is_active (file_source)) {
1335 		gth_file_source_queue_copy (file_source, destination, file_list, move, destination_position, progress_callback, dialog_callback, ready_callback, data);
1336 		return;
1337 	}
1338 	g_cancellable_reset (file_source->priv->cancellable);
1339 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->copy (file_source, destination, file_list, move, destination_position, progress_callback, dialog_callback, ready_callback, data);
1340 }
1341 
1342 
1343 gboolean
gth_file_source_can_cut(GthFileSource * file_source)1344 gth_file_source_can_cut (GthFileSource *file_source)
1345 {
1346 	return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->can_cut (file_source);
1347 }
1348 
1349 
1350 void
gth_file_source_monitor_entry_points(GthFileSource * file_source)1351 gth_file_source_monitor_entry_points (GthFileSource *file_source)
1352 {
1353 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->monitor_entry_points (file_source);
1354 }
1355 
1356 
1357 void
gth_file_source_monitor_directory(GthFileSource * file_source,GFile * file,gboolean activate)1358 gth_file_source_monitor_directory (GthFileSource *file_source,
1359 				   GFile         *file,
1360 				   gboolean       activate)
1361 {
1362 	g_return_if_fail (file != NULL);
1363 
1364 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->monitor_directory (file_source, file, activate);
1365 }
1366 
1367 
1368 gboolean
gth_file_source_is_reorderable(GthFileSource * file_source)1369 gth_file_source_is_reorderable (GthFileSource *file_source)
1370 {
1371 	return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->is_reorderable (file_source);
1372 }
1373 
1374 
1375 void
gth_file_source_reorder(GthFileSource * file_source,GthFileData * destination,GList * visible_files,GList * files_to_move,int dest_pos,ReadyCallback callback,gpointer data)1376 gth_file_source_reorder (GthFileSource *file_source,
1377 			 GthFileData   *destination,
1378 		         GList         *visible_files, /* GFile list */
1379 		         GList         *files_to_move, /* GFile list */
1380 		         int            dest_pos,
1381 		         ReadyCallback  callback,
1382 		         gpointer       data)
1383 {
1384 	if (gth_file_source_is_active (file_source)) {
1385 		gth_file_source_queue_reorder (file_source, destination, visible_files, files_to_move, dest_pos, callback, data);
1386 		return;
1387 	}
1388 	g_cancellable_reset (file_source->priv->cancellable);
1389 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->reorder (file_source, destination, visible_files, files_to_move, dest_pos, callback, data);
1390 }
1391 
1392 
1393 void
gth_file_source_remove(GthFileSource * file_source,GthFileData * location,GList * file_list,gboolean permanently,GtkWindow * parent)1394 gth_file_source_remove (GthFileSource *file_source,
1395 			GthFileData   *location,
1396 		        GList         *file_list, /* GthFileData list */
1397 		        gboolean       permanently,
1398 		        GtkWindow     *parent)
1399 {
1400 	if (gth_file_source_is_active (file_source)) {
1401 		gth_file_source_queue_remove (file_source, location, file_list, permanently, parent);
1402 		return;
1403 	}
1404 	g_cancellable_reset (file_source->priv->cancellable);
1405 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->remove (file_source, location, file_list, permanently, parent);
1406 }
1407 
1408 
1409 void
gth_file_source_deleted_from_disk(GthFileSource * file_source,GthFileData * location,GList * file_list)1410 gth_file_source_deleted_from_disk (GthFileSource *file_source,
1411 				   GthFileData   *location,
1412 				   GList         *file_list /* GFile list */)
1413 {
1414 	if (gth_file_source_is_active (file_source)) {
1415 		gth_file_source_queue_deleted_from_disk (file_source, location, file_list);
1416 		return;
1417 	}
1418 	g_cancellable_reset (file_source->priv->cancellable);
1419 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->deleted_from_disk (file_source, location, file_list);
1420 }
1421 
1422 
1423 void
gth_file_source_get_free_space(GthFileSource * file_source,GFile * location,SpaceReadyCallback callback,gpointer data)1424 gth_file_source_get_free_space (GthFileSource      *file_source,
1425 				GFile              *location,
1426 				SpaceReadyCallback  callback,
1427 				gpointer            data)
1428 {
1429 	g_return_if_fail (location != NULL);
1430 	g_return_if_fail (callback != NULL);
1431 
1432 	if (gth_file_source_is_active (file_source)) {
1433 		gth_file_source_queue_get_free_space (file_source, location, callback, data);
1434 		return;
1435 	}
1436 	g_cancellable_reset (file_source->priv->cancellable);
1437 	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->get_free_space (file_source, location, callback, data);
1438 }
1439 
1440 
1441 gboolean
gth_file_source_shows_extra_widget(GthFileSource * file_source)1442 gth_file_source_shows_extra_widget (GthFileSource *file_source)
1443 {
1444 	return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->shows_extra_widget (file_source);
1445 }
1446 
1447 
1448 GdkDragAction
gth_file_source_get_drop_actions(GthFileSource * file_source,GFile * destination,GFile * file)1449 gth_file_source_get_drop_actions (GthFileSource *file_source,
1450 				  GFile         *destination,
1451 				  GFile         *file)
1452 {
1453 	return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->get_drop_actions (file_source, destination, file);
1454 }
1455