]> Pileus Git - ~andy/gtk/blob - gtk/gtkfilesystem.c
1ab2f213aa6490bc7c820a0b990d61977beb8f6f
[~andy/gtk] / gtk / gtkfilesystem.c
1 /* GTK - The GIMP Toolkit
2  * gtkfilesystem.c: Abstract file system interfaces
3  * Copyright (C) 2003, Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include <config.h>
22 #include <gmodule.h>
23 #include "gtkfilesystem.h"
24 #include "gtkicontheme.h"
25 #include "gtkmodules.h"
26 #include "gtkalias.h"
27
28 #include <string.h>
29
30 struct _GtkFileInfo
31 {
32   GtkFileTime modification_time;
33   gint64 size;
34   gchar *display_name;
35   gchar *display_key;
36   gchar *mime_type;
37   guint is_folder : 1;
38   guint is_hidden : 1;
39 };
40
41 static void gtk_file_system_base_init (gpointer g_class);
42 static void gtk_file_folder_base_init (gpointer g_class);
43
44 GQuark
45 gtk_file_system_error_quark (void)
46 {
47   static GQuark quark = 0;
48   if (quark == 0)
49     quark = g_quark_from_static_string ("gtk-file-system-error-quark");
50   return quark;
51 }
52
53 /*****************************************
54  *             GtkFileInfo               *
55  *****************************************/
56 GType
57 gtk_file_info_get_type (void)
58 {
59   static GType our_type = 0;
60   
61   if (our_type == 0)
62     our_type = g_boxed_type_register_static ("GtkFileInfo",
63                                              (GBoxedCopyFunc) gtk_file_info_copy,
64                                              (GBoxedFreeFunc) gtk_file_info_free);
65
66   return our_type;
67 }
68
69 GtkFileInfo *
70 gtk_file_info_new  (void)
71 {
72   GtkFileInfo *info;
73   
74   info = g_new0 (GtkFileInfo, 1);
75
76   return info;
77 }
78
79 GtkFileInfo *
80 gtk_file_info_copy (GtkFileInfo *info)
81 {
82   GtkFileInfo *new_info;
83
84   g_return_val_if_fail (info != NULL, NULL);
85
86   new_info = g_memdup (info, sizeof (GtkFileInfo));
87   if (new_info->display_name)
88     new_info->display_name = g_strdup (new_info->display_name);
89   if (new_info->mime_type)
90     new_info->mime_type = g_strdup (new_info->mime_type);
91
92   return new_info;
93 }
94
95 void
96 gtk_file_info_free (GtkFileInfo *info)
97 {
98   g_return_if_fail (info != NULL);
99
100   if (info->display_name)
101     g_free (info->display_name);
102   if (info->mime_type)
103     g_free (info->mime_type);
104   if (info->display_key)
105     g_free (info->display_key);
106
107   g_free (info);
108 }
109
110 G_CONST_RETURN gchar *
111 gtk_file_info_get_display_name (const GtkFileInfo *info)
112 {
113   g_return_val_if_fail (info != NULL, NULL);
114   
115   return info->display_name;
116 }
117
118 /**
119  * gtk_file_info_get_display_key:
120  * @info: a #GtkFileInfo
121  * 
122  * Returns results of g_utf8_collate_key() on the display name
123  * for @info. This is useful when sorting a bunch of #GtkFileInfo
124  * structures since the collate key will be only computed once.
125  * 
126  * Return value: The collate key for the display name, or %NULL
127  *   if the display name hasn't been set.
128  **/
129 G_CONST_RETURN gchar *
130 gtk_file_info_get_display_key (const GtkFileInfo *info)
131 {
132   g_return_val_if_fail (info != NULL, NULL);
133
134   if (!info->display_key && info->display_name)
135     {
136       /* Since info->display_key is only a cache, we cast off the const
137        */
138       ((GtkFileInfo *)info)->display_key = g_utf8_collate_key (info->display_name, -1);
139     }
140         
141   return info->display_key;
142 }
143
144 void
145 gtk_file_info_set_display_name (GtkFileInfo *info,
146                                 const gchar *display_name)
147 {
148   g_return_if_fail (info != NULL);
149
150   if (display_name == info->display_name)
151     return;
152
153   if (info->display_name)
154     g_free (info->display_name);
155   if (info->display_key)
156     {
157       g_free (info->display_key);
158       info->display_key = NULL;
159     }
160
161   info->display_name = g_strdup (display_name);
162 }
163
164 gboolean
165 gtk_file_info_get_is_folder (const GtkFileInfo *info)
166 {
167   g_return_val_if_fail (info != NULL, FALSE);
168   
169   return info->is_folder;
170 }
171
172 void
173 gtk_file_info_set_is_folder (GtkFileInfo *info,
174                              gboolean     is_folder)
175 {
176   g_return_if_fail (info != NULL);
177
178   info->is_folder = is_folder != FALSE;
179 }
180
181 gboolean
182 gtk_file_info_get_is_hidden (const GtkFileInfo *info)
183 {
184   g_return_val_if_fail (info != NULL, FALSE);
185   
186   return info->is_hidden;
187 }
188
189 void
190 gtk_file_info_set_is_hidden (GtkFileInfo *info,
191                              gboolean     is_hidden)
192 {
193   g_return_if_fail (info != NULL);
194
195   info->is_hidden = is_hidden != FALSE;
196 }
197
198 G_CONST_RETURN gchar *
199 gtk_file_info_get_mime_type (const GtkFileInfo *info)
200 {
201   g_return_val_if_fail (info != NULL, NULL);
202   
203   return info->mime_type;
204 }
205
206 void
207 gtk_file_info_set_mime_type (GtkFileInfo *info,
208                              const gchar *mime_type)
209 {
210   g_return_if_fail (info != NULL);
211   
212   if (info->mime_type)
213     g_free (info->mime_type);
214
215   info->mime_type = g_strdup (mime_type);
216 }
217
218 GtkFileTime
219 gtk_file_info_get_modification_time (const GtkFileInfo *info)
220 {
221   g_return_val_if_fail (info != NULL, 0);
222
223   return info->modification_time;
224 }
225
226 void
227 gtk_file_info_set_modification_time (GtkFileInfo *info,
228                                      GtkFileTime  modification_time)
229 {
230   g_return_if_fail (info != NULL);
231   
232   info->modification_time = modification_time;
233 }
234
235 gint64
236 gtk_file_info_get_size (const GtkFileInfo *info)
237 {
238   g_return_val_if_fail (info != NULL, 0);
239   
240   return info->size;
241 }
242
243 void
244 gtk_file_info_set_size (GtkFileInfo *info,
245                         gint64       size)
246 {
247   g_return_if_fail (info != NULL);
248   g_return_if_fail (size >= 0);
249   
250   info->size = size;
251 }
252
253
254 /*****************************************
255  *             GtkFileSystem             *
256  *****************************************/
257 GType
258 gtk_file_system_get_type (void)
259 {
260   static GType file_system_type = 0;
261
262   if (!file_system_type)
263     {
264       static const GTypeInfo file_system_info =
265       {
266         sizeof (GtkFileSystemIface),  /* class_size */
267         gtk_file_system_base_init,    /* base_init */
268         NULL,                         /* base_finalize */
269       };
270
271       file_system_type = g_type_register_static (G_TYPE_INTERFACE,
272                                                  "GtkFileSystem",
273                                                  &file_system_info, 0);
274
275       g_type_interface_add_prerequisite (file_system_type, G_TYPE_OBJECT);
276     }
277
278   return file_system_type;
279 }
280
281 static void
282 gtk_file_system_base_init (gpointer g_class)
283 {
284   static gboolean initialized = FALSE;
285   
286   if (!initialized)
287     {
288       GType iface_type = G_TYPE_FROM_INTERFACE (g_class);
289
290       g_signal_new ("volumes-changed",
291                     iface_type,
292                     G_SIGNAL_RUN_LAST,
293                     G_STRUCT_OFFSET (GtkFileSystemIface, volumes_changed),
294                     NULL, NULL,
295                     g_cclosure_marshal_VOID__VOID,
296                     G_TYPE_NONE, 0);
297       g_signal_new ("bookmarks-changed",
298                     iface_type,
299                     G_SIGNAL_RUN_LAST,
300                     G_STRUCT_OFFSET (GtkFileSystemIface, bookmarks_changed),
301                     NULL, NULL,
302                     g_cclosure_marshal_VOID__VOID,
303                     G_TYPE_NONE, 0);
304
305       initialized = TRUE;
306     }
307 }
308
309 GSList *
310 gtk_file_system_list_volumes (GtkFileSystem  *file_system)
311 {
312   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
313
314   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->list_volumes (file_system);
315 }
316
317 GtkFileFolder *
318 gtk_file_system_get_folder (GtkFileSystem     *file_system,
319                             const GtkFilePath *path,
320                             GtkFileInfoType    types,
321                             GError           **error)
322 {
323   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
324   g_return_val_if_fail (path != NULL, NULL);
325   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
326
327   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_folder (file_system, path, types, error);
328 }
329
330 gboolean
331 gtk_file_system_create_folder(GtkFileSystem     *file_system,
332                               const GtkFilePath *path,
333                               GError           **error)
334 {
335   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
336   g_return_val_if_fail (path != NULL, FALSE);
337   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
338
339   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->create_folder (file_system, path, error);
340 }
341
342 /**
343  * gtk_file_system_get_volume_for_path:
344  * @file_system: a #GtkFileSystem
345  * @path: a #GtkFilePath
346  * 
347  * Queries the file system volume that corresponds to a specific path.
348  * There might not be a volume for all paths (consinder for instance remote
349  * shared), so this can return NULL.
350  * 
351  * Return value: the #GtkFileSystemVolume that corresponds to the specified
352  * @path, or NULL if there is no such volume. You should free this value with
353  * gtk_file_system_volume_free().
354  **/
355 GtkFileSystemVolume *
356 gtk_file_system_get_volume_for_path (GtkFileSystem     *file_system,
357                                      const GtkFilePath *path)
358 {
359   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
360   g_return_val_if_fail (path != NULL, NULL);
361
362   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_volume_for_path (file_system, path);
363 }
364
365 /**
366  * gtk_file_system_volume_free:
367  * @file_system: a #GtkFileSystem
368  * @volume: a #GtkFileSystemVolume
369  * 
370  * Frees a #GtkFileSystemVolume structure as returned by
371  * gtk_file_system_list_volumes().
372  **/
373 void
374 gtk_file_system_volume_free (GtkFileSystem       *file_system,
375                              GtkFileSystemVolume *volume)
376 {
377   g_return_if_fail (GTK_IS_FILE_SYSTEM (file_system));
378   g_return_if_fail (volume != NULL);
379
380   GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_free (file_system, volume);
381 }
382
383 /**
384  * gtk_file_system_volume_get_base_path:
385  * @file_system: a #GtkFileSystem
386  * @volume: a #GtkFileSystemVolume
387  * 
388  * Queries the base path for a volume.  For example, a CD-ROM device may yield a
389  * path of "/mnt/cdrom".
390  * 
391  * Return value: a #GtkFilePath with the base mount path of the specified
392  * @volume.
393  **/
394 GtkFilePath *
395 gtk_file_system_volume_get_base_path (GtkFileSystem       *file_system,
396                                       GtkFileSystemVolume *volume)
397 {
398   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
399   g_return_val_if_fail (volume != NULL, NULL);
400
401   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_base_path (file_system, volume);
402 }
403
404 /**
405  * gtk_file_system_volume_get_is_mounted:
406  * @file_system: a #GtkFileSystem
407  * @volume: a #GtkFileSystemVolume
408  * 
409  * Queries whether a #GtkFileSystemVolume is mounted or not.  If it is not, it
410  * can be mounted with gtk_file_system_volume_mount().
411  * 
412  * Return value: TRUE if the @volume is mounted, FALSE otherwise.
413  **/
414 gboolean
415 gtk_file_system_volume_get_is_mounted (GtkFileSystem       *file_system,
416                                        GtkFileSystemVolume *volume)
417 {
418   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
419   g_return_val_if_fail (volume != NULL, FALSE);
420
421   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_is_mounted (file_system, volume);
422 }
423
424 /**
425  * gtk_file_system_volume_mount:
426  * @file_system: a #GtkFileSystem
427  * @volume: a #GtkFileSystemVolume
428  * @error: location to store error, or %NULL
429  * 
430  * Tries to mount an unmounted volume.  This may cause the "volumes-changed"
431  * signal in the @file_system to be emitted.
432  * 
433  * Return value: TRUE if the @volume was mounted successfully, FALSE otherwise.
434  **/
435 gboolean
436 gtk_file_system_volume_mount (GtkFileSystem        *file_system, 
437                               GtkFileSystemVolume  *volume,
438                               GError              **error)
439 {
440   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
441   g_return_val_if_fail (volume != NULL, FALSE);
442   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
443
444   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_mount (file_system, volume, error);
445 }
446
447 /**
448  * gtk_file_system_volume_get_display_name:
449  * @file_system: a #GtkFileSystem
450  * @volume: a #GtkFileSystemVolume
451  * 
452  * Queries the human-readable name for a @volume.  This string can be displayed
453  * in a list of volumes that can be accessed, for example.
454  * 
455  * Return value: A string with the human-readable name for a #GtkFileSystemVolume.
456  **/
457 char *
458 gtk_file_system_volume_get_display_name (GtkFileSystem        *file_system, 
459                                          GtkFileSystemVolume  *volume)
460 {
461   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
462   g_return_val_if_fail (volume != NULL, NULL);
463
464   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_display_name (file_system, volume);
465 }
466
467 /**
468  * gtk_file_system_volume_render_icon:
469  * @file_system: a #GtkFileSystem
470  * @volume: a #GtkFileSystemVolume
471  * @widget: Reference widget to render icons.
472  * @pixel_size: Size of the icon.
473  * @error: location to store error, or %NULL
474  * 
475  * Renders an icon suitable for a file #GtkFileSystemVolume.
476  * 
477  * Return value: A #GdkPixbuf containing an icon, or NULL if the icon could not
478  * be rendered.  In the latter case, the @error value will be set as
479  * appropriate.
480  **/
481 GdkPixbuf *
482 gtk_file_system_volume_render_icon (GtkFileSystem        *file_system,
483                                     GtkFileSystemVolume  *volume,
484                                     GtkWidget            *widget,
485                                     gint                  pixel_size,
486                                     GError              **error)
487 {
488   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
489   g_return_val_if_fail (volume != NULL, NULL);
490   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
491   g_return_val_if_fail (pixel_size > 0, NULL);
492   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
493
494   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_render_icon (file_system,
495                                                                       volume,
496                                                                       widget,
497                                                                       pixel_size,
498                                                                       error);
499 }
500
501 /**
502  * gtk_file_system_get_parent:
503  * @file_system: a #GtkFileSystem
504  * @path: base path name
505  * @parent: location to store parent path name
506  * @error: location to store error, or %NULL
507  * 
508  * Gets the name of the parent folder of a path.  If the path has no parent, as when
509  * you request the parent of a file system root, then @parent will be set to %NULL.
510  * 
511  * Return value: %TRUE if the operation was successful:  @parent will be set to
512  * the name of the @path's parent, or to %NULL if @path is already a file system
513  * root.  If the operation fails, this function returns %FALSE, sets @parent to
514  * NULL, and sets the @error value if it is specified.
515  **/
516 gboolean
517 gtk_file_system_get_parent (GtkFileSystem     *file_system,
518                             const GtkFilePath *path,
519                             GtkFilePath      **parent,
520                             GError           **error)
521 {
522   gboolean result;
523   
524   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
525   g_return_val_if_fail (path != NULL, FALSE);
526   g_return_val_if_fail (parent != NULL, FALSE);
527   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
528
529   *parent = NULL;
530
531   result = GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_parent (file_system, path, parent, error);
532   g_assert (result || *parent == NULL);
533
534   return result;
535 }
536
537 GtkFilePath *
538 gtk_file_system_make_path (GtkFileSystem    *file_system,
539                           const GtkFilePath *base_path,
540                           const gchar       *display_name,
541                           GError           **error)
542 {
543   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
544   g_return_val_if_fail (base_path != NULL, NULL);
545   g_return_val_if_fail (display_name != NULL, NULL);
546   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
547
548   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->make_path (file_system, base_path, display_name, error);
549 }
550
551 /**
552  * gtk_file_system_parse:
553  * @file_system: a #GtkFileSystem
554  * @base_path: reference folder with respect to which relative
555  *            paths should be interpreted.
556  * @str: the string to parse
557  * @folder: location to store folder portion of result, or %NULL
558  * @file_part: location to store file portion of result, or %NULL
559  * @error: location to store error, or %NULL
560  * 
561  * Given a string entered by a user, parse it (possibly using
562  * heuristics) into a folder path and a UTF-8 encoded
563  * filename part. (Suitable for passing to gtk_file_system_make_path())
564  *
565  * Note that the returned filename point may point to a subfolder
566  * of the returned folder. Adding a trailing path separator is needed
567  * to enforce the interpretation as a folder name.
568  *
569  * If parsing fails because the syntax of @str is not understood,
570  * and error of type GTK_FILE_SYSTEM_ERROR_BAD_FILENAME will
571  * be set in @error and %FALSE returned.
572  *
573  * If parsing fails because a path was encountered that doesn't
574  * exist on the filesystem, then an error of type
575  * %GTK_FILE_SYSTEM_ERROR_NONEXISTENT will be set in @error
576  * and %FALSE returned. (This only applies to parsing relative paths,
577  * not to interpretation of @file_part. No check is made as
578  * to whether @file_part exists.)
579  *
580  * Return value: %TRUE if the parsing succeeds, otherwise, %FALSE.
581  **/
582 gboolean
583 gtk_file_system_parse (GtkFileSystem     *file_system,
584                        const GtkFilePath *base_path,
585                        const gchar       *str,
586                        GtkFilePath      **folder,
587                        gchar            **file_part,
588                        GError           **error)
589 {
590   GtkFilePath *tmp_folder = NULL;
591   gchar *tmp_file_part = NULL;
592   gboolean result;
593
594   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
595   g_return_val_if_fail (base_path != NULL, FALSE);
596   g_return_val_if_fail (str != NULL, FALSE);
597   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
598
599   result = GTK_FILE_SYSTEM_GET_IFACE (file_system)->parse (file_system, base_path, str,
600                                                            &tmp_folder, &tmp_file_part,
601                                                            error);
602   g_assert (result || (tmp_folder == NULL && tmp_file_part == NULL));
603
604   if (folder)
605     *folder = tmp_folder;
606   else
607     gtk_file_path_free (tmp_folder);
608
609   if (file_part)
610     *file_part = tmp_file_part;
611   else
612     g_free (tmp_file_part);
613
614   return result;
615 }
616
617
618 gchar *
619 gtk_file_system_path_to_uri (GtkFileSystem     *file_system,
620                              const GtkFilePath *path)
621 {
622   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
623   g_return_val_if_fail (path != NULL, NULL);
624   
625   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->path_to_uri (file_system, path);
626 }
627
628 gchar *
629 gtk_file_system_path_to_filename (GtkFileSystem     *file_system,
630                                   const GtkFilePath *path)
631 {
632   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
633   g_return_val_if_fail (path != NULL, NULL);
634   
635   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->path_to_filename (file_system, path);
636 }
637
638 GtkFilePath *
639 gtk_file_system_uri_to_path (GtkFileSystem *file_system,
640                              const gchar    *uri)
641 {
642   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
643   g_return_val_if_fail (uri != NULL, NULL);
644   
645   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->uri_to_path (file_system, uri);
646 }
647
648 GtkFilePath *
649 gtk_file_system_filename_to_path (GtkFileSystem *file_system,
650                                   const gchar   *filename)
651 {
652   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
653   g_return_val_if_fail (filename != NULL, NULL);
654
655   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->filename_to_path (file_system, filename);
656 }
657
658 /**
659  * gtk_file_system_path_is_local:
660  * @filesystem: a #GtkFileSystem
661  * @path: A #GtkFilePath from that filesystem
662  * 
663  * Checks whether a #GtkFilePath is local; that is whether
664  * gtk_file_system_path_to_filename would return non-%NULL.
665  * 
666  * Return value: %TRUE if the path is loca
667  **/
668 gboolean
669 gtk_file_system_path_is_local (GtkFileSystem     *file_system,
670                                const GtkFilePath *path)
671 {
672   gchar *filename;
673   gboolean result;
674     
675   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
676   g_return_val_if_fail (path != NULL, FALSE);
677
678   filename = gtk_file_system_path_to_filename (file_system, path);
679   result = filename != NULL;
680   g_free (filename);
681
682   return result;
683 }
684
685 GdkPixbuf *
686 gtk_file_system_render_icon (GtkFileSystem      *file_system,
687                              const GtkFilePath  *path,
688                              GtkWidget          *widget,
689                              gint                pixel_size,
690                              GError            **error)
691 {
692   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
693   g_return_val_if_fail (path != NULL, NULL);
694   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
695   g_return_val_if_fail (pixel_size > 0, NULL);
696
697   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->render_icon (file_system, path, widget, pixel_size, error);
698 }
699
700 /**
701  * gtk_file_system_insert_bookmark:
702  * @file_system: a #GtkFileSystem
703  * @path: path of the bookmark to add
704  * @position: index in the bookmarks list at which the @path should be inserted; use 0
705  * for the beginning, and -1 or the number of bookmarks itself for the end of the list.
706  * @error: location to store error, or %NULL
707  * 
708  * Adds a path for a folder to the user's bookmarks list.  If the operation
709  * succeeds, the "bookmarks_changed" signal will be emitted.  Bookmark paths are
710  * unique; if you try to insert a @path that already exists, the operation will
711  * fail and the @error will be set to #GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS.  To
712  * reorder the list of bookmarks, use gtk_file_system_remove_bookmark() to
713  * remove the path in question, and call gtk_file_system_insert_bookmark() with
714  * the new position for the path.
715  * 
716  * Return value: TRUE if the operation succeeds, FALSE otherwise.  In the latter case,
717  * the @error value will be set.
718  **/
719 gboolean
720 gtk_file_system_insert_bookmark (GtkFileSystem     *file_system,
721                                  const GtkFilePath *path,
722                                  gint               position,
723                                  GError           **error)
724 {
725   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
726   g_return_val_if_fail (path != NULL, FALSE);
727
728   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->insert_bookmark (file_system, path, position, error);
729 }
730
731 /**
732  * gtk_file_system_remove_bookmark:
733  * @file_system: a #GtkFileSystem
734  * @path: path of the bookmark to remove
735  * @error: location to store error, or %NULL
736  * 
737  * Removes a bookmark folder from the user's bookmarks list.  If the operation
738  * succeeds, the "bookmarks_changed" signal will be emitted.  If you try to remove
739  * a @path which does not exist in the bookmarks list, the operation will fail
740  * and the @error will be set to GTK_FILE_SYSTEM_ERROR_NONEXISTENT.
741  * 
742  * Return value: TRUE if the operation succeeds, FALSE otherwise.  In the latter
743  * case, the @error value will be set.
744  **/
745 gboolean
746 gtk_file_system_remove_bookmark (GtkFileSystem     *file_system,
747                                  const GtkFilePath *path,
748                                  GError           **error)
749 {
750   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
751   g_return_val_if_fail (path != NULL, FALSE);
752
753   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->remove_bookmark (file_system, path, error);
754 }
755
756 /**
757  * gtk_file_system_list_bookmarks:
758  * @file_system: a #GtkFileSystem
759  * 
760  * Queries the list of bookmarks in the file system.
761  * 
762  * Return value: A list of #GtkFilePath, or NULL if there are no configured
763  * bookmarks.  You should use gtk_file_paths_free() to free this list.
764  *
765  * See also: gtk_file_system_get_supports_bookmarks()
766  **/
767 GSList *
768 gtk_file_system_list_bookmarks (GtkFileSystem *file_system)
769 {
770   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
771
772   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->list_bookmarks (file_system);
773 }
774
775 /**
776  * gtk_file_system_get_bookmark_label:
777  * @file_system: a #GtkFileSystem
778  * @path: path of the bookmark 
779  *
780  * Gets the label to display for a bookmark, or %NULL.
781  *
782  * Returns: the label for the bookmark @path
783  *
784  * Since: 2.8
785  */
786 gchar *
787 gtk_file_system_get_bookmark_label (GtkFileSystem     *file_system,
788                                     const GtkFilePath *path)
789 {
790   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
791   g_return_val_if_fail (path != NULL, FALSE);
792
793   if (GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_bookmark_label)
794     return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_bookmark_label (file_system, 
795                                                                         path);
796
797   return NULL;
798 }
799
800 /**
801  * gtk_file_system_set_bookmark_label:
802  * @file_system: a #GtkFileSystem
803  * @path: path of the bookmark 
804  * @label: the label for the bookmark, or %NULL to display
805  *   the path itself
806  *
807  * Sets the label to display for a bookmark.
808  *
809  * Since: 2.8
810  */
811 void
812 gtk_file_system_set_bookmark_label (GtkFileSystem     *file_system,
813                                     const GtkFilePath *path,
814                                     const gchar       *label)
815 {
816   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
817   g_return_val_if_fail (path != NULL, FALSE);
818
819   if (GTK_FILE_SYSTEM_GET_IFACE (file_system)->set_bookmark_label)
820     GTK_FILE_SYSTEM_GET_IFACE (file_system)->set_bookmark_label (file_system, 
821                                                                  path,
822                                                                  label);
823 }
824
825 /*****************************************
826  *             GtkFileFolder             *
827  *****************************************/
828 GType
829 gtk_file_folder_get_type (void)
830 {
831   static GType file_folder_type = 0;
832
833   if (!file_folder_type)
834     {
835       static const GTypeInfo file_folder_info =
836       {
837         sizeof (GtkFileFolderIface),  /* class_size */
838         gtk_file_folder_base_init,    /* base_init */
839         NULL,                         /* base_finalize */
840       };
841
842       file_folder_type = g_type_register_static (G_TYPE_INTERFACE,
843                                                  "GtkFileFolder",
844                                                  &file_folder_info, 0);
845       
846       g_type_interface_add_prerequisite (file_folder_type, G_TYPE_OBJECT);
847     }
848
849   return file_folder_type;
850 }
851
852 static void
853 gtk_file_folder_base_init (gpointer g_class)
854 {
855   static gboolean initialized = FALSE;
856   
857   if (!initialized)
858     {
859       GType iface_type = G_TYPE_FROM_INTERFACE (g_class);
860
861       g_signal_new ("deleted",
862                     iface_type,
863                     G_SIGNAL_RUN_LAST,
864                     G_STRUCT_OFFSET (GtkFileFolderIface, deleted),
865                     NULL, NULL,
866                     g_cclosure_marshal_VOID__VOID,
867                     G_TYPE_NONE, 0);
868       g_signal_new ("files-added",
869                     iface_type,
870                     G_SIGNAL_RUN_LAST,
871                     G_STRUCT_OFFSET (GtkFileFolderIface, files_added),
872                     NULL, NULL,
873                     g_cclosure_marshal_VOID__POINTER,
874                     G_TYPE_NONE, 1,
875                     G_TYPE_POINTER);
876       g_signal_new ("files-changed",
877                     iface_type,
878                     G_SIGNAL_RUN_LAST,
879                     G_STRUCT_OFFSET (GtkFileFolderIface, files_changed),
880                     NULL, NULL,
881                     g_cclosure_marshal_VOID__POINTER,
882                     G_TYPE_NONE, 1,
883                     G_TYPE_POINTER);
884       g_signal_new ("files-removed",
885                     iface_type,
886                     G_SIGNAL_RUN_LAST,
887                     G_STRUCT_OFFSET (GtkFileFolderIface, files_removed),
888                     NULL, NULL,
889                     g_cclosure_marshal_VOID__POINTER,
890                     G_TYPE_NONE, 1,
891                     G_TYPE_POINTER);
892       g_signal_new ("finished-loading",
893                     iface_type,
894                     G_SIGNAL_RUN_LAST,
895                     G_STRUCT_OFFSET (GtkFileFolderIface, finished_loading),
896                     NULL, NULL,
897                     g_cclosure_marshal_VOID__VOID,
898                     G_TYPE_NONE, 0);
899
900       initialized = TRUE;
901     }
902 }
903
904 gboolean
905 gtk_file_folder_list_children (GtkFileFolder    *folder,
906                                GSList          **children,
907                                GError          **error)
908 {
909   gboolean result;
910   GSList *tmp_children = NULL;
911   
912   g_return_val_if_fail (GTK_IS_FILE_FOLDER (folder), FALSE);
913   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
914
915   result = GTK_FILE_FOLDER_GET_IFACE (folder)->list_children (folder, &tmp_children, error);
916   g_assert (result || tmp_children == NULL);
917
918   if (children)
919     *children = tmp_children;
920   else
921     gtk_file_paths_free (tmp_children);
922
923   return result;
924 }
925
926 GtkFileInfo *
927 gtk_file_folder_get_info (GtkFileFolder     *folder,
928                           const GtkFilePath *path,
929                           GError           **error)
930 {
931   g_return_val_if_fail (GTK_IS_FILE_FOLDER (folder), NULL);
932   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
933
934   return GTK_FILE_FOLDER_GET_IFACE (folder)->get_info (folder, path, error);
935 }
936
937 gboolean
938 gtk_file_folder_is_finished_loading (GtkFileFolder *folder)
939 {
940   g_return_val_if_fail (GTK_IS_FILE_FOLDER (folder), TRUE);
941
942   if (!GTK_FILE_FOLDER_GET_IFACE (folder)->is_finished_loading)
943     return TRUE;
944   else
945     return GTK_FILE_FOLDER_GET_IFACE (folder)->is_finished_loading (folder);
946 }
947
948
949 /*****************************************
950  *         GtkFilePath modules           *
951  *****************************************/
952
953 /* We make these real functions in case either copy or free are implemented as macros
954  */
955 static gpointer
956 gtk_file_path_real_copy (gpointer boxed)
957 {
958   return gtk_file_path_copy ((GtkFilePath *) boxed);
959 }
960
961 static void
962 gtk_file_path_real_free (gpointer boxed)
963 {
964   gtk_file_path_free (boxed);
965 }
966
967 GType
968 gtk_file_path_get_type (void)
969 {
970   static GType our_type = 0;
971   
972   if (our_type == 0)
973     our_type = g_boxed_type_register_static ("GtkFilePath",
974                                              (GBoxedCopyFunc) gtk_file_path_real_copy,
975                                              (GBoxedFreeFunc) gtk_file_path_real_free);
976
977   return our_type;
978 }
979
980
981 GSList *
982 gtk_file_paths_sort (GSList *paths)
983 {
984   return g_slist_sort (paths, (GCompareFunc)strcmp);
985 }
986
987 /**
988  * gtk_file_paths_copy:
989  * @paths: A #GSList of #GtkFilePath structures.
990  * 
991  * Copies a list of #GtkFilePath structures.
992  * 
993  * Return value: A copy of @paths.  Since the contents of the list are copied as
994  * well, you should use gtk_file_paths_free() to free the result.
995  **/
996 GSList *
997 gtk_file_paths_copy (GSList *paths)
998 {
999   GSList *head, *tail, *l;
1000
1001   head = tail = NULL;
1002
1003   for (l = paths; l; l = l->next)
1004     {
1005       GtkFilePath *path;
1006       GSList *node;
1007
1008       path = l->data;
1009       node = g_slist_alloc ();
1010
1011       if (tail)
1012         tail->next = node;
1013       else
1014         head = node;
1015
1016       node->data = gtk_file_path_copy (path);
1017       tail = node;
1018     }
1019
1020   return head;
1021 }
1022
1023 void
1024 gtk_file_paths_free (GSList *paths)
1025 {
1026   GSList *tmp_list;
1027
1028   for (tmp_list = paths; tmp_list; tmp_list = tmp_list->next)
1029     gtk_file_path_free (tmp_list->data);
1030
1031   g_slist_free (paths);
1032 }
1033
1034 /*****************************************
1035  *         GtkFileSystem modules         *
1036  *****************************************/
1037
1038 typedef struct _GtkFileSystemModule GtkFileSystemModule;
1039 typedef struct _GtkFileSystemModuleClass GtkFileSystemModuleClass;
1040
1041 struct _GtkFileSystemModule
1042 {
1043   GTypeModule parent_instance;
1044   
1045   GModule *library;
1046
1047   void            (*init)     (GTypeModule    *module);
1048   void            (*exit)     (void);
1049   GtkFileSystem * (*create)   (void);
1050
1051   gchar *path;
1052 };
1053
1054 struct _GtkFileSystemModuleClass
1055 {
1056   GTypeModuleClass parent_class;
1057 };
1058
1059 G_DEFINE_TYPE (GtkFileSystemModule, _gtk_file_system_module, G_TYPE_TYPE_MODULE);
1060 #define GTK_TYPE_FILE_SYSTEM_MODULE       (_gtk_file_system_module_get_type ())
1061 #define GTK_FILE_SYSTEM_MODULE(module)    (G_TYPE_CHECK_INSTANCE_CAST ((module), GTK_TYPE_FILE_SYSTEM_MODULE, GtkFileSystemModule))
1062
1063
1064 static GSList *loaded_file_systems;
1065
1066 static gboolean
1067 gtk_file_system_module_load (GTypeModule *module)
1068 {
1069   GtkFileSystemModule *fs_module = GTK_FILE_SYSTEM_MODULE (module);
1070   
1071   fs_module->library = g_module_open (fs_module->path, 0);
1072   if (!fs_module->library)
1073     {
1074       g_warning (g_module_error());
1075       return FALSE;
1076     }
1077   
1078   /* extract symbols from the lib */
1079   if (!g_module_symbol (fs_module->library, "fs_module_init",
1080                         (gpointer *)&fs_module->init) ||
1081       !g_module_symbol (fs_module->library, "fs_module_exit", 
1082                         (gpointer *)&fs_module->exit) ||
1083       !g_module_symbol (fs_module->library, "fs_module_create", 
1084                         (gpointer *)&fs_module->create))
1085     {
1086       g_warning (g_module_error());
1087       g_module_close (fs_module->library);
1088       
1089       return FALSE;
1090     }
1091             
1092   /* call the filesystems's init function to let it */
1093   /* setup anything it needs to set up. */
1094   fs_module->init (module);
1095
1096   return TRUE;
1097 }
1098
1099 static void
1100 gtk_file_system_module_unload (GTypeModule *module)
1101 {
1102   GtkFileSystemModule *fs_module = GTK_FILE_SYSTEM_MODULE (module);
1103   
1104   fs_module->exit();
1105
1106   g_module_close (fs_module->library);
1107   fs_module->library = NULL;
1108
1109   fs_module->init = NULL;
1110   fs_module->exit = NULL;
1111   fs_module->create = NULL;
1112 }
1113
1114 /* This only will ever be called if an error occurs during
1115  * initialization
1116  */
1117 static void
1118 gtk_file_system_module_finalize (GObject *object)
1119 {
1120   GtkFileSystemModule *module = GTK_FILE_SYSTEM_MODULE (object);
1121
1122   g_free (module->path);
1123
1124   G_OBJECT_CLASS (_gtk_file_system_module_parent_class)->finalize (object);
1125 }
1126
1127 static void
1128 _gtk_file_system_module_class_init (GtkFileSystemModuleClass *class)
1129 {
1130   GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
1131   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1132   
1133   module_class->load = gtk_file_system_module_load;
1134   module_class->unload = gtk_file_system_module_unload;
1135
1136   gobject_class->finalize = gtk_file_system_module_finalize;
1137 }
1138
1139 static void
1140 _gtk_file_system_module_init (GtkFileSystemModule *fs_module)
1141 {
1142 }
1143
1144
1145 static GtkFileSystem *
1146 _gtk_file_system_module_create (GtkFileSystemModule *fs_module)
1147 {
1148   GtkFileSystem *fs;
1149   
1150   if (g_type_module_use (G_TYPE_MODULE (fs_module)))
1151     {
1152       fs = fs_module->create ();
1153       g_type_module_unuse (G_TYPE_MODULE (fs_module));
1154       return fs;
1155     }
1156   return NULL;
1157 }
1158
1159
1160 GtkFileSystem *
1161 _gtk_file_system_create (const char *file_system_name)
1162 {
1163   GSList *l;
1164   char *module_path;
1165   GtkFileSystemModule *fs_module;
1166   GtkFileSystem *fs;
1167
1168   for (l = loaded_file_systems; l != NULL; l = l->next)
1169     {
1170       fs_module = l->data;
1171       
1172       if (strcmp (G_TYPE_MODULE (fs_module)->name, file_system_name) == 0)
1173         return _gtk_file_system_module_create (fs_module);
1174     }
1175
1176   fs = NULL;
1177   if (g_module_supported ())
1178     {
1179       module_path = _gtk_find_module (file_system_name, "filesystems");
1180
1181       if (module_path)
1182         {
1183           fs_module = g_object_new (GTK_TYPE_FILE_SYSTEM_MODULE, NULL);
1184
1185           g_type_module_set_name (G_TYPE_MODULE (fs_module), file_system_name);
1186           fs_module->path = g_strdup (module_path);
1187
1188           loaded_file_systems = g_slist_prepend (loaded_file_systems,
1189                                                  fs_module);
1190
1191           fs = _gtk_file_system_module_create (fs_module);
1192         }
1193       
1194       g_free (module_path);
1195     }
1196   
1197   return fs;
1198 }
1199
1200 #define __GTK_FILE_SYSTEM_C__
1201 #include "gtkaliasdef.c"