1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 /* GTK - The GIMP Toolkit
4 * gtkfilesystemunix.c: Default implementation of GtkFileSystem for UNIX-like systems
5 * Copyright (C) 2003, Red Hat, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
27 #include "beaglequery.h"
29 #include "gtkfilesystembeagle.h"
30 #define GTK_FILE_SYSTEM_ENABLE_UNSUPPORTED
31 #include "gtk/gtkfilesystem.h"
32 #include "gtk/gtkicontheme.h"
33 #include "gtk/gtkdialog.h"
34 #include "gtk/gtkstock.h"
35 #include "gtk/gtkbox.h"
36 #include "gtk/gtkhbox.h"
37 #include "gtk/gtklabel.h"
38 #include "gtk/gtkentry.h"
42 #define XDG_PREFIX _beagle_xdg
48 #include <sys/types.h>
54 #define SEARCH_MAGIC ":search:"
56 #define BOOKMARKS_FILENAME ".gtk-bookmarks"
57 #define BOOKMARKS_TMP_FILENAME ".gtk-bookmarks-XXXXXX"
59 #define FOLDER_CACHE_LIFETIME 2 /* seconds */
61 typedef struct _GtkFileSystemUnixClass GtkFileSystemUnixClass
;
63 #define GTK_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
64 #define GTK_IS_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_UNIX))
65 #define GTK_FILE_SYSTEM_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
67 struct _GtkFileSystemUnixClass
69 GObjectClass parent_class
;
72 struct _GtkFileSystemUnix
74 GObject parent_instance
;
76 GHashTable
*folder_hash
;
79 /* Icon type, supplemented by MIME type
84 ICON_REGULAR
, /* Use mime type for icon */
86 ICON_BROKEN_SYMBOLIC_LINK
,
87 ICON_CHARACTER_DEVICE
,
95 #define GTK_TYPE_FILE_FOLDER_UNIX (gtk_file_folder_unix_get_type ())
96 #define GTK_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnix))
97 #define GTK_IS_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_UNIX))
98 #define GTK_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
99 #define GTK_IS_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FOLDER_UNIX))
100 #define GTK_FILE_FOLDER_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
102 typedef struct _GtkFileFolderUnix GtkFileFolderUnix
;
103 typedef struct _GtkFileFolderUnixClass GtkFileFolderUnixClass
;
105 struct _GtkFileFolderUnixClass
107 GObjectClass parent_class
;
110 static time_t search_string_time
= 0;
111 static gchar
*search_string
= NULL
;
113 struct _GtkFileFolderUnix
115 GObject parent_instance
;
117 gboolean search_magic
;
118 BeagleQueryResult
*query_result
;
120 GtkFileSystemUnix
*system_unix
;
121 GtkFileInfoType types
;
123 GHashTable
*stat_info
;
124 unsigned int have_stat
: 1;
125 unsigned int have_mime_type
: 1;
129 struct stat_info_entry
{
135 static const GtkFileInfoType STAT_NEEDED_MASK
= (GTK_FILE_INFO_IS_FOLDER
|
136 GTK_FILE_INFO_IS_HIDDEN
|
137 GTK_FILE_INFO_MODIFICATION_TIME
|
140 static GObjectClass
*system_parent_class
;
141 static GObjectClass
*folder_parent_class
;
143 static void gtk_file_system_unix_class_init (GtkFileSystemUnixClass
*class);
144 static void gtk_file_system_unix_iface_init (GtkFileSystemIface
*iface
);
145 static void gtk_file_system_unix_init (GtkFileSystemUnix
*impl
);
146 static void gtk_file_system_unix_finalize (GObject
*object
);
148 static GSList
* gtk_file_system_unix_list_volumes (GtkFileSystem
*file_system
);
149 static GtkFileSystemVolume
*gtk_file_system_unix_get_volume_for_path (GtkFileSystem
*file_system
,
150 const GtkFilePath
*path
);
152 static GtkFileFolder
*gtk_file_system_unix_get_folder (GtkFileSystem
*file_system
,
153 const GtkFilePath
*path
,
154 GtkFileInfoType types
,
156 static gboolean
gtk_file_system_unix_create_folder (GtkFileSystem
*file_system
,
157 const GtkFilePath
*path
,
160 static void gtk_file_system_unix_volume_free (GtkFileSystem
*file_system
,
161 GtkFileSystemVolume
*volume
);
162 static GtkFilePath
*gtk_file_system_unix_volume_get_base_path (GtkFileSystem
*file_system
,
163 GtkFileSystemVolume
*volume
);
164 static gboolean
gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem
*file_system
,
165 GtkFileSystemVolume
*volume
);
166 static gboolean
gtk_file_system_unix_volume_mount (GtkFileSystem
*file_system
,
167 GtkFileSystemVolume
*volume
,
169 static gchar
* gtk_file_system_unix_volume_get_display_name (GtkFileSystem
*file_system
,
170 GtkFileSystemVolume
*volume
);
171 static GdkPixbuf
* gtk_file_system_unix_volume_render_icon (GtkFileSystem
*file_system
,
172 GtkFileSystemVolume
*volume
,
177 static gboolean
gtk_file_system_unix_get_parent (GtkFileSystem
*file_system
,
178 const GtkFilePath
*path
,
179 GtkFilePath
**parent
,
181 static GtkFilePath
* gtk_file_system_unix_make_path (GtkFileSystem
*file_system
,
182 const GtkFilePath
*base_path
,
183 const gchar
*display_name
,
185 static gboolean
gtk_file_system_unix_parse (GtkFileSystem
*file_system
,
186 const GtkFilePath
*base_path
,
188 GtkFilePath
**folder
,
192 static gchar
* gtk_file_system_unix_path_to_uri (GtkFileSystem
*file_system
,
193 const GtkFilePath
*path
);
194 static gchar
* gtk_file_system_unix_path_to_filename (GtkFileSystem
*file_system
,
195 const GtkFilePath
*path
);
196 static GtkFilePath
*gtk_file_system_unix_uri_to_path (GtkFileSystem
*file_system
,
198 static GtkFilePath
*gtk_file_system_unix_filename_to_path (GtkFileSystem
*file_system
,
199 const gchar
*filename
);
201 static GdkPixbuf
*gtk_file_system_unix_render_icon (GtkFileSystem
*file_system
,
202 const GtkFilePath
*path
,
207 static gboolean
gtk_file_system_unix_insert_bookmark (GtkFileSystem
*file_system
,
208 const GtkFilePath
*path
,
211 static gboolean
gtk_file_system_unix_remove_bookmark (GtkFileSystem
*file_system
,
212 const GtkFilePath
*path
,
214 static GSList
* gtk_file_system_unix_list_bookmarks (GtkFileSystem
*file_system
);
216 static GType
gtk_file_folder_unix_get_type (void);
217 static void gtk_file_folder_unix_class_init (GtkFileFolderUnixClass
*class);
218 static void gtk_file_folder_unix_iface_init (GtkFileFolderIface
*iface
);
219 static void gtk_file_folder_unix_init (GtkFileFolderUnix
*impl
);
220 static void gtk_file_folder_unix_finalize (GObject
*object
);
222 static GtkFileInfo
*gtk_file_folder_unix_get_info (GtkFileFolder
*folder
,
223 const GtkFilePath
*path
,
225 static gboolean
gtk_file_folder_unix_list_children (GtkFileFolder
*folder
,
229 static gboolean
gtk_file_folder_unix_is_finished_loading (GtkFileFolder
*folder
);
231 static GtkFilePath
*filename_to_path (const gchar
*filename
);
233 static gboolean
filename_is_root (const char *filename
);
235 static gboolean
fill_in_names (GtkFileFolderUnix
*folder_unix
, GError
**error
);
236 static gboolean
fill_in_stats (GtkFileFolderUnix
*folder_unix
, GError
**error
);
237 static gboolean
fill_in_mime_type (GtkFileFolderUnix
*folder_unix
, GError
**error
);
239 static char * get_parent_dir (const char *filename
);
244 static GType file_system_beagle_type
= 0;
247 gtk_file_system_beagle_get_type (void)
249 return file_system_beagle_type
;
253 gtk_file_system_beagle_register_type (GTypeModule
*module
)
256 if (!file_system_beagle_type
)
258 static const GTypeInfo file_system_beagle_info
=
260 sizeof (GtkFileSystemUnixClass
),
261 NULL
, /* base_init */
262 NULL
, /* base_finalize */
263 (GClassInitFunc
) gtk_file_system_unix_class_init
,
264 NULL
, /* class_finalize */
265 NULL
, /* class_data */
266 sizeof (GtkFileSystemUnix
),
268 (GInstanceInitFunc
) gtk_file_system_unix_init
,
271 static const GInterfaceInfo file_system_info
=
273 (GInterfaceInitFunc
) gtk_file_system_unix_iface_init
, /* interface_init */
274 NULL
, /* interface_finalize */
275 NULL
/* interface_data */
278 file_system_beagle_type
= g_type_module_register_type (module
,
280 "GtkFileSystemBeagle",
281 &file_system_beagle_info
, 0);
282 g_type_module_add_interface (module
,
283 file_system_beagle_type
,
284 GTK_TYPE_FILE_SYSTEM
,
292 * gtk_file_system_unix_new:
294 * Creates a new #GtkFileSystemUnix object. #GtkFileSystemUnix
295 * implements the #GtkFileSystem interface with direct access to
296 * the filesystem using Unix/Linux API calls
298 * Return value: the new #GtkFileSystemUnix object
301 gtk_file_system_beagle_new (void)
303 return g_object_new (GTK_TYPE_FILE_SYSTEM_UNIX
, NULL
);
307 gtk_file_system_unix_class_init (GtkFileSystemUnixClass
*class)
309 GObjectClass
*gobject_class
= G_OBJECT_CLASS (class);
311 system_parent_class
= g_type_class_peek_parent (class);
313 gobject_class
->finalize
= gtk_file_system_unix_finalize
;
317 gtk_file_system_unix_iface_init (GtkFileSystemIface
*iface
)
319 iface
->list_volumes
= gtk_file_system_unix_list_volumes
;
320 iface
->get_volume_for_path
= gtk_file_system_unix_get_volume_for_path
;
321 iface
->get_folder
= gtk_file_system_unix_get_folder
;
322 iface
->create_folder
= gtk_file_system_unix_create_folder
;
323 iface
->volume_free
= gtk_file_system_unix_volume_free
;
324 iface
->volume_get_base_path
= gtk_file_system_unix_volume_get_base_path
;
325 iface
->volume_get_is_mounted
= gtk_file_system_unix_volume_get_is_mounted
;
326 iface
->volume_mount
= gtk_file_system_unix_volume_mount
;
327 iface
->volume_get_display_name
= gtk_file_system_unix_volume_get_display_name
;
328 iface
->volume_render_icon
= gtk_file_system_unix_volume_render_icon
;
329 iface
->get_parent
= gtk_file_system_unix_get_parent
;
330 iface
->make_path
= gtk_file_system_unix_make_path
;
331 iface
->parse
= gtk_file_system_unix_parse
;
332 iface
->path_to_uri
= gtk_file_system_unix_path_to_uri
;
333 iface
->path_to_filename
= gtk_file_system_unix_path_to_filename
;
334 iface
->uri_to_path
= gtk_file_system_unix_uri_to_path
;
335 iface
->filename_to_path
= gtk_file_system_unix_filename_to_path
;
336 iface
->render_icon
= gtk_file_system_unix_render_icon
;
337 iface
->insert_bookmark
= gtk_file_system_unix_insert_bookmark
;
338 iface
->remove_bookmark
= gtk_file_system_unix_remove_bookmark
;
339 iface
->list_bookmarks
= gtk_file_system_unix_list_bookmarks
;
343 gtk_file_system_unix_init (GtkFileSystemUnix
*system_unix
)
345 system_unix
->folder_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
349 gtk_file_system_unix_finalize (GObject
*object
)
351 GtkFileSystemUnix
*system_unix
;
353 system_unix
= GTK_FILE_SYSTEM_UNIX (object
);
355 /* FIXME: assert that the hash is empty? */
356 g_hash_table_destroy (system_unix
->folder_hash
);
358 system_parent_class
->finalize (object
);
361 /* Returns our single root volume */
362 static GtkFileSystemVolume
*
363 get_root_volume (void)
365 return (GtkFileSystemVolume
*) gtk_file_path_new_dup ("/");
368 static GtkFileSystemVolume
*
369 get_search_volume (void)
371 return (GtkFileSystemVolume
*) gtk_file_path_new_dup (SEARCH_MAGIC
);
375 is_search_volume (GtkFileSystemVolume
*volume
)
377 return ! strcmp (gtk_file_path_get_string ((GtkFilePath
*) volume
), SEARCH_MAGIC
);
381 is_search_path (const GtkFilePath
*path
)
383 return ! strncmp (gtk_file_path_get_string (path
), SEARCH_MAGIC
, strlen (SEARCH_MAGIC
));
387 gtk_file_system_unix_list_volumes (GtkFileSystem
*file_system
)
389 GSList
*foo
= g_slist_append (NULL
, get_root_volume ());
390 foo
= g_slist_append (foo
, get_search_volume ());
394 static GtkFileSystemVolume
*
395 gtk_file_system_unix_get_volume_for_path (GtkFileSystem
*file_system
,
396 const GtkFilePath
*path
)
398 if (is_search_path (path
))
399 return get_search_volume ();
401 return get_root_volume ();
405 remove_trailing_slash (const char *filename
)
409 len
= strlen (filename
);
411 if (len
> 1 && filename
[len
- 1] == '/')
412 return g_strndup (filename
, len
- 1);
414 return g_memdup (filename
, len
+ 1);
418 get_search_string (void)
420 gchar
*results
= NULL
;
428 const char *accept_stock
;
430 dialog
= gtk_dialog_new_with_buttons ("Search",
432 GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT
| GTK_DIALOG_NO_SEPARATOR
,
433 //GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
434 GTK_STOCK_OK
, GTK_RESPONSE_ACCEPT
,
436 gtk_window_set_default_size (GTK_WINDOW (dialog
), 300, -1);
437 gtk_container_set_border_width (GTK_CONTAINER (dialog
), 5);
438 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog
)->vbox
), 2);
439 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_ACCEPT
);
441 hbox
= gtk_hbox_new (FALSE
, 12);
442 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog
)->vbox
), hbox
, FALSE
, FALSE
, 0);
443 gtk_container_set_border_width (GTK_CONTAINER (hbox
), 5);
445 label
= gtk_label_new_with_mnemonic (_("Search For:"));
446 gtk_box_pack_start (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
448 entry
= gtk_entry_new ();
449 gtk_entry_set_activates_default (GTK_ENTRY (entry
), TRUE
);
450 gtk_box_pack_start (GTK_BOX (hbox
), entry
, TRUE
, TRUE
, 0);
451 gtk_label_set_mnemonic_widget (GTK_LABEL (label
), entry
);
455 gtk_widget_show_all (dialog
);
459 gtk_dialog_run (GTK_DIALOG (dialog
));
461 results
= g_strdup (gtk_entry_get_text (GTK_ENTRY (entry
)));
463 gtk_widget_destroy (dialog
);
468 static GtkFileFolder
*
469 gtk_file_system_unix_get_folder (GtkFileSystem
*file_system
,
470 const GtkFilePath
*path
,
471 GtkFileInfoType types
,
474 GtkFileSystemUnix
*system_unix
;
475 GtkFileFolderUnix
*folder_unix
;
476 const char *filename
;
478 time_t now
= time (NULL
);
480 g_print ("Get folder [%s]\n", gtk_file_path_get_string (path
));
482 system_unix
= GTK_FILE_SYSTEM_UNIX (file_system
);
484 if (is_search_path (path
))
488 if (search_string
== NULL
|| difftime (now
, search_string_time
) > 2) {
489 g_free (search_string
);
490 search_string
= get_search_string ();
491 time (&search_string_time
);
494 folder_unix
= g_object_new (GTK_TYPE_FILE_FOLDER_UNIX
, NULL
);
495 folder_unix
->search_magic
= TRUE
;
496 return GTK_FILE_FOLDER (folder_unix
);
499 filename
= gtk_file_path_get_string (path
);
500 g_return_val_if_fail (filename
!= NULL
, NULL
);
501 g_return_val_if_fail (g_path_is_absolute (filename
), NULL
);
503 filename_copy
= remove_trailing_slash (filename
);
504 folder_unix
= g_hash_table_lookup (system_unix
->folder_hash
, filename_copy
);
508 g_free (filename_copy
);
509 if (now
- folder_unix
->asof
>= FOLDER_CACHE_LIFETIME
&&
510 folder_unix
->stat_info
)
513 g_print ("Cleaning out cached directory %s\n", filename
);
515 g_hash_table_destroy (folder_unix
->stat_info
);
516 folder_unix
->stat_info
= NULL
;
517 folder_unix
->have_mime_type
= FALSE
;
518 folder_unix
->have_stat
= FALSE
;
521 g_object_ref (folder_unix
);
522 folder_unix
->types
|= types
;
523 types
= folder_unix
->types
;
527 if (!g_file_test (filename
, G_FILE_TEST_IS_DIR
))
529 int save_errno
= errno
;
530 gchar
*filename_utf8
= g_filename_to_utf8 (filename
, -1, NULL
, NULL
, NULL
);
532 /* If g_file_test() returned FALSE but not due to an error, it means
533 * that the filename is not a directory.
538 GTK_FILE_SYSTEM_ERROR
,
539 GTK_FILE_SYSTEM_ERROR_NOT_FOLDER
,
541 filename_utf8
? filename_utf8
: "???",
542 g_strerror (ENOTDIR
));
545 GTK_FILE_SYSTEM_ERROR
,
546 GTK_FILE_SYSTEM_ERROR_NONEXISTENT
,
547 _("error getting information for '%s': %s"),
548 filename_utf8
? filename_utf8
: "???",
549 g_strerror (save_errno
));
551 g_free (filename_utf8
);
552 g_free (filename_copy
);
556 folder_unix
= g_object_new (GTK_TYPE_FILE_FOLDER_UNIX
, NULL
);
557 folder_unix
->system_unix
= system_unix
;
558 folder_unix
->filename
= filename_copy
;
559 folder_unix
->types
= types
;
560 folder_unix
->stat_info
= NULL
;
561 folder_unix
->asof
= now
;
562 folder_unix
->have_mime_type
= FALSE
;
563 folder_unix
->have_stat
= FALSE
;
565 g_hash_table_insert (system_unix
->folder_hash
,
566 folder_unix
->filename
,
570 if ((types
& STAT_NEEDED_MASK
) && !fill_in_stats (folder_unix
, error
))
572 g_object_unref (folder_unix
);
575 if ((types
& GTK_FILE_INFO_MIME_TYPE
) && !fill_in_mime_type (folder_unix
, error
))
577 g_object_unref (folder_unix
);
581 return GTK_FILE_FOLDER (folder_unix
);
585 gtk_file_system_unix_create_folder (GtkFileSystem
*file_system
,
586 const GtkFilePath
*path
,
589 GtkFileSystemUnix
*system_unix
;
590 const char *filename
;
594 system_unix
= GTK_FILE_SYSTEM_UNIX (file_system
);
596 filename
= gtk_file_path_get_string (path
);
597 g_return_val_if_fail (filename
!= NULL
, FALSE
);
598 g_return_val_if_fail (g_path_is_absolute (filename
), FALSE
);
600 tmp
= remove_trailing_slash (filename
);
601 result
= mkdir (tmp
, 0777) == 0;
606 int save_errno
= errno
;
607 gchar
*filename_utf8
= g_filename_to_utf8 (filename
, -1, NULL
, NULL
, NULL
);
609 GTK_FILE_SYSTEM_ERROR
,
610 GTK_FILE_SYSTEM_ERROR_NONEXISTENT
,
611 _("error creating directory '%s': %s"),
612 filename_utf8
? filename_utf8
: "???",
613 g_strerror (save_errno
));
614 g_free (filename_utf8
);
618 if (filename_is_root (filename
))
619 return TRUE
; /* hmmm, but with no notification */
621 parent
= get_parent_dir (filename
);
624 GtkFileFolderUnix
*folder_unix
;
626 folder_unix
= g_hash_table_lookup (system_unix
->folder_hash
, parent
);
629 GtkFileInfoType types
;
630 GtkFilePath
*parent_path
;
632 GtkFileFolder
*folder
;
634 /* This is sort of a hack. We re-get the folder, to ensure that the
635 * newly-created directory gets read into the folder's info hash table.
638 types
= folder_unix
->types
;
640 parent_path
= gtk_file_path_new_dup (parent
);
641 folder
= gtk_file_system_get_folder (file_system
, parent_path
, types
, NULL
);
642 gtk_file_path_free (parent_path
);
646 paths
= g_slist_append (NULL
, (GtkFilePath
*) path
);
647 g_signal_emit_by_name (folder
, "files-added", paths
);
648 g_slist_free (paths
);
649 g_object_unref (folder
);
660 gtk_file_system_unix_volume_free (GtkFileSystem
*file_system
,
661 GtkFileSystemVolume
*volume
)
665 path
= (GtkFilePath
*) volume
;
666 gtk_file_path_free (path
);
670 gtk_file_system_unix_volume_get_base_path (GtkFileSystem
*file_system
,
671 GtkFileSystemVolume
*volume
)
673 if (is_search_volume (volume
)) {
674 /* Yet another ugly hack: by having the magic search volume
675 return a differently-named folder every time, it forces the
676 path-navigation button in the chooser to be refreshed
677 if you conduct multiple searches from inside of one chooser. */
678 static int magic_counter
= 0;
679 char *path
= g_strdup_printf ("%s:%d", SEARCH_MAGIC
, magic_counter
);
681 return gtk_file_path_new_steal (path
);
683 return gtk_file_path_new_dup ("/");
688 gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem
*file_system
,
689 GtkFileSystemVolume
*volume
)
695 gtk_file_system_unix_volume_mount (GtkFileSystem
*file_system
,
696 GtkFileSystemVolume
*volume
,
700 GTK_FILE_SYSTEM_ERROR
,
701 GTK_FILE_SYSTEM_ERROR_FAILED
,
702 _("This file system does not support mounting"));
707 gtk_file_system_unix_volume_get_display_name (GtkFileSystem
*file_system
,
708 GtkFileSystemVolume
*volume
)
711 if (is_search_volume (volume
))
712 return g_strdup (_("Search"));
714 return g_strdup (_("Filesystem")); /* Same as Nautilus */
718 get_icon_type_from_stat (struct stat
*statp
)
720 if (S_ISBLK (statp
->st_mode
))
721 return ICON_BLOCK_DEVICE
;
722 else if (S_ISLNK (statp
->st_mode
))
723 return ICON_BROKEN_SYMBOLIC_LINK
; /* See get_icon_type */
724 else if (S_ISCHR (statp
->st_mode
))
725 return ICON_CHARACTER_DEVICE
;
726 else if (S_ISDIR (statp
->st_mode
))
727 return ICON_DIRECTORY
;
728 else if (S_ISFIFO (statp
->st_mode
))
730 else if (S_ISSOCK (statp
->st_mode
))
737 get_icon_type (const char *filename
,
742 /* If stat fails, try to fall back to lstat to catch broken links
744 if (stat (filename
, &statbuf
) != 0)
746 if (errno
!= ENOENT
|| lstat (filename
, &statbuf
) != 0)
748 int save_errno
= errno
;
749 gchar
*filename_utf8
= g_filename_to_utf8 (filename
, -1, NULL
, NULL
, NULL
);
751 GTK_FILE_SYSTEM_ERROR
,
752 GTK_FILE_SYSTEM_ERROR_NONEXISTENT
,
753 _("error getting information for '%s': %s"),
754 filename_utf8
? filename_utf8
: "???",
755 g_strerror (save_errno
));
756 g_free (filename_utf8
);
762 return get_icon_type_from_stat (&statbuf
);
772 icon_cache_element_free (IconCacheElement
*element
)
775 g_object_unref (element
->pixbuf
);
780 icon_theme_changed (GtkIconTheme
*icon_theme
)
784 /* Difference from the initial creation is that we don't
785 * reconnect the signal
787 cache
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
788 (GDestroyNotify
)g_free
,
789 (GDestroyNotify
)icon_cache_element_free
);
790 g_object_set_data_full (G_OBJECT (icon_theme
), "gtk-file-icon-cache",
791 cache
, (GDestroyNotify
)g_hash_table_destroy
);
795 get_cached_icon (GtkWidget
*widget
,
799 GtkIconTheme
*icon_theme
= gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget
));
800 GHashTable
*cache
= g_object_get_data (G_OBJECT (icon_theme
), "gtk-file-icon-cache");
801 IconCacheElement
*element
;
805 cache
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
806 (GDestroyNotify
)g_free
,
807 (GDestroyNotify
)icon_cache_element_free
);
809 g_object_set_data_full (G_OBJECT (icon_theme
), "gtk-file-icon-cache",
810 cache
, (GDestroyNotify
)g_hash_table_destroy
);
811 g_signal_connect (icon_theme
, "changed",
812 G_CALLBACK (icon_theme_changed
), NULL
);
815 element
= g_hash_table_lookup (cache
, name
);
818 element
= g_new0 (IconCacheElement
, 1);
819 g_hash_table_insert (cache
, g_strdup (name
), element
);
822 if (element
->size
!= pixel_size
)
825 g_object_unref (element
->pixbuf
);
826 element
->size
= pixel_size
;
827 element
->pixbuf
= gtk_icon_theme_load_icon (icon_theme
, name
,
828 pixel_size
, 0, NULL
);
831 return element
->pixbuf
? g_object_ref (element
->pixbuf
) : NULL
;
835 gtk_file_system_unix_volume_render_icon (GtkFileSystem
*file_system
,
836 GtkFileSystemVolume
*volume
,
841 /* FIXME: set the GError if we can't load the icon */
842 if (is_search_volume (volume
))
843 return get_cached_icon (widget
, "gtk-find", pixel_size
);
845 return get_cached_icon (widget
, "gnome-fs-blockdev", pixel_size
);
849 get_parent_dir (const char *filename
)
853 len
= strlen (filename
);
855 /* Ignore trailing slashes */
856 if (len
> 1 && filename
[len
- 1] == '/')
860 tmp
= g_strndup (filename
, len
- 1);
862 parent
= g_path_get_dirname (tmp
);
868 return g_path_get_dirname (filename
);
872 gtk_file_system_unix_get_parent (GtkFileSystem
*file_system
,
873 const GtkFilePath
*path
,
874 GtkFilePath
**parent
,
877 const char *filename
;
879 if (is_search_path (path
))
885 filename
= gtk_file_path_get_string (path
);
886 g_return_val_if_fail (filename
!= NULL
, FALSE
);
887 g_return_val_if_fail (g_path_is_absolute (filename
), FALSE
);
889 if (filename_is_root (filename
))
895 gchar
*parent_filename
= get_parent_dir (filename
);
896 *parent
= filename_to_path (parent_filename
);
897 g_free (parent_filename
);
904 gtk_file_system_unix_make_path (GtkFileSystem
*file_system
,
905 const GtkFilePath
*base_path
,
906 const gchar
*display_name
,
909 const char *base_filename
;
911 gchar
*full_filename
;
912 GError
*tmp_error
= NULL
;
915 base_filename
= gtk_file_path_get_string (base_path
);
916 g_return_val_if_fail (base_filename
!= NULL
, NULL
);
917 g_return_val_if_fail (g_path_is_absolute (base_filename
), NULL
);
919 if (strchr (display_name
, G_DIR_SEPARATOR
))
922 GTK_FILE_SYSTEM_ERROR
,
923 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME
,
924 _("The name \"%s\" is not valid because it contains the character \"%s\". "
925 "Please use a different name."),
931 filename
= g_filename_from_utf8 (display_name
, -1, NULL
, NULL
, &tmp_error
);
935 GTK_FILE_SYSTEM_ERROR
,
936 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME
,
940 g_error_free (tmp_error
);
945 full_filename
= g_build_filename (base_filename
, filename
, NULL
);
946 result
= filename_to_path (full_filename
);
948 g_free (full_filename
);
953 /* If this was a publically exported function, it should return
954 * a dup'ed result, but we make it modify-in-place for efficiency
955 * here, and because it works for us.
958 canonicalize_filename (gchar
*filename
)
961 gboolean last_was_slash
= FALSE
;
968 if (*p
== G_DIR_SEPARATOR
)
971 *q
++ = G_DIR_SEPARATOR
;
973 last_was_slash
= TRUE
;
977 if (last_was_slash
&& *p
== '.')
979 if (*(p
+ 1) == G_DIR_SEPARATOR
||
982 if (*(p
+ 1) == '\0')
987 else if (*(p
+ 1) == '.' &&
988 (*(p
+ 2) == G_DIR_SEPARATOR
||
991 if (q
> filename
+ 1)
994 while (q
> filename
+ 1 &&
995 *(q
- 1) != G_DIR_SEPARATOR
)
999 if (*(p
+ 2) == '\0')
1007 last_was_slash
= FALSE
;
1013 last_was_slash
= FALSE
;
1020 if (q
> filename
+ 1 && *(q
- 1) == G_DIR_SEPARATOR
)
1026 /* Takes a user-typed filename and expands a tilde at the beginning of the string */
1028 expand_tilde (const char *filename
)
1030 const char *notilde
;
1034 if (filename
[0] != '~')
1035 return g_strdup (filename
);
1037 notilde
= filename
+ 1;
1039 slash
= strchr (notilde
, G_DIR_SEPARATOR
);
1043 if (slash
== notilde
)
1045 home
= g_get_home_dir ();
1048 return g_strdup (filename
);
1053 struct passwd
*passwd
;
1055 username
= g_strndup (notilde
, slash
- notilde
);
1056 passwd
= getpwnam (username
);
1060 return g_strdup (filename
);
1062 home
= passwd
->pw_dir
;
1065 return g_build_filename (home
, G_DIR_SEPARATOR_S
, slash
+ 1, NULL
);
1069 gtk_file_system_unix_parse (GtkFileSystem
*file_system
,
1070 const GtkFilePath
*base_path
,
1072 GtkFilePath
**folder
,
1076 const char *base_filename
;
1079 gboolean result
= FALSE
;
1081 base_filename
= gtk_file_path_get_string (base_path
);
1082 g_return_val_if_fail (base_filename
!= NULL
, FALSE
);
1083 g_return_val_if_fail (g_path_is_absolute (base_filename
), FALSE
);
1085 filename
= expand_tilde (str
);
1089 GTK_FILE_SYSTEM_ERROR
,
1090 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME
,
1091 "%s", ""); /* nothing for now, as we are string-frozen */
1095 last_slash
= strrchr (filename
, G_DIR_SEPARATOR
);
1098 *folder
= gtk_file_path_copy (base_path
);
1099 *file_part
= g_strdup (filename
);
1106 GError
*tmp_error
= NULL
;
1108 if (last_slash
== filename
)
1109 folder_part
= g_strdup ("/");
1111 folder_part
= g_filename_from_utf8 (filename
, last_slash
- filename
,
1112 NULL
, NULL
, &tmp_error
);
1117 GTK_FILE_SYSTEM_ERROR
,
1118 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME
,
1120 tmp_error
->message
);
1121 g_error_free (tmp_error
);
1125 if (folder_part
[0] == G_DIR_SEPARATOR
)
1126 folder_path
= folder_part
;
1129 folder_path
= g_build_filename (base_filename
, folder_part
, NULL
);
1130 g_free (folder_part
);
1133 canonicalize_filename (folder_path
);
1135 *folder
= filename_to_path (folder_path
);
1136 *file_part
= g_strdup (last_slash
+ 1);
1138 g_free (folder_path
);
1150 gtk_file_system_unix_path_to_uri (GtkFileSystem
*file_system
,
1151 const GtkFilePath
*path
)
1153 return g_filename_to_uri (gtk_file_path_get_string (path
), NULL
, NULL
);
1157 gtk_file_system_unix_path_to_filename (GtkFileSystem
*file_system
,
1158 const GtkFilePath
*path
)
1160 return g_strdup (gtk_file_path_get_string (path
));
1163 static GtkFilePath
*
1164 gtk_file_system_unix_uri_to_path (GtkFileSystem
*file_system
,
1168 gchar
*filename
= g_filename_from_uri (uri
, NULL
, NULL
);
1172 path
= filename_to_path (filename
);
1181 static GtkFilePath
*
1182 gtk_file_system_unix_filename_to_path (GtkFileSystem
*file_system
,
1183 const gchar
*filename
)
1185 return filename_to_path (filename
);
1189 get_icon_for_directory (const char *path
)
1191 static char *desktop_path
= NULL
;
1193 if (!g_get_home_dir ())
1194 return "gnome-fs-directory";
1197 desktop_path
= g_build_filename (g_get_home_dir (), "Desktop", NULL
);
1199 if (strcmp (g_get_home_dir (), path
) == 0)
1200 return "gnome-fs-home";
1201 else if (strcmp (desktop_path
, path
) == 0)
1202 return "gnome-fs-desktop";
1204 return "gnome-fs-directory";
1208 gtk_file_system_unix_render_icon (GtkFileSystem
*file_system
,
1209 const GtkFilePath
*path
,
1214 const char *filename
;
1216 const char *mime_type
= NULL
;
1218 GtkFileSystemUnix
*system_unix
;
1219 GtkFileFolderUnix
*folder_unix
;
1221 system_unix
= GTK_FILE_SYSTEM_UNIX (file_system
);
1222 filename
= gtk_file_path_get_string (path
);
1223 dirname
= g_path_get_dirname (filename
);
1224 folder_unix
= g_hash_table_lookup (system_unix
->folder_hash
, dirname
);
1230 struct stat_info_entry
*entry
;
1232 if (!fill_in_stats (folder_unix
, error
))
1235 basename
= g_path_get_basename (filename
);
1236 entry
= g_hash_table_lookup (folder_unix
->stat_info
, basename
);
1240 if (entry
->icon_type
== ICON_UNDECIDED
)
1241 entry
->icon_type
= get_icon_type_from_stat (&entry
->statbuf
);
1242 icon_type
= entry
->icon_type
;
1243 if (icon_type
== ICON_REGULAR
)
1245 (void)fill_in_mime_type (folder_unix
, NULL
);
1246 mime_type
= entry
->mime_type
;
1250 icon_type
= ICON_NONE
;
1255 g_print ("No folder open for %s\n", filename
);
1258 icon_type
= get_icon_type (filename
, error
);
1259 if (icon_type
== ICON_REGULAR
)
1260 mime_type
= xdg_mime_get_mime_type_for_file (filename
);
1264 /* FIXME: this function should not return NULL without setting the GError; we
1265 * should perhaps provide a "never fails" generic stock icon for when all else
1269 if (icon_type
== ICON_NONE
)
1272 if (icon_type
!= ICON_REGULAR
)
1278 case ICON_BLOCK_DEVICE
:
1279 name
= "gnome-fs-blockdev";
1281 case ICON_BROKEN_SYMBOLIC_LINK
:
1282 name
= "gnome-fs-symlink";
1284 case ICON_CHARACTER_DEVICE
:
1285 name
= "gnome-fs-chardev";
1287 case ICON_DIRECTORY
:
1288 name
= get_icon_for_directory (filename
);
1290 case ICON_EXECUTABLE
:
1291 name
="gnome-fs-executable";
1294 name
= "gnome-fs-fifo";
1297 name
= "gnome-fs-socket";
1300 g_assert_not_reached ();
1304 return get_cached_icon (widget
, name
, pixel_size
);
1309 const char *separator
;
1313 separator
= strchr (mime_type
, '/');
1317 icon_name
= g_string_new ("gnome-mime-");
1318 g_string_append_len (icon_name
, mime_type
, separator
- mime_type
);
1319 g_string_append_c (icon_name
, '-');
1320 g_string_append (icon_name
, separator
+ 1);
1321 pixbuf
= get_cached_icon (widget
, icon_name
->str
, pixel_size
);
1322 g_string_free (icon_name
, TRUE
);
1326 icon_name
= g_string_new ("gnome-mime-");
1327 g_string_append_len (icon_name
, mime_type
, separator
- mime_type
);
1328 pixbuf
= get_cached_icon (widget
, icon_name
->str
, pixel_size
);
1329 g_string_free (icon_name
, TRUE
);
1334 return get_cached_icon (widget
, "gnome-fs-regular", pixel_size
);
1338 bookmark_list_free (GSList
*list
)
1342 for (l
= list
; l
; l
= l
->next
)
1345 g_slist_free (list
);
1348 /* Returns whether a URI is a local file:// */
1350 is_local_uri (const char *uri
)
1356 /* This is rather crude, but hey */
1357 filename
= g_filename_from_uri (uri
, &hostname
, NULL
);
1359 result
= (filename
&& !hostname
);
1368 bookmark_get_filename (gboolean tmp_file
)
1372 filename
= g_build_filename (g_get_home_dir (),
1373 tmp_file
? BOOKMARKS_TMP_FILENAME
: BOOKMARKS_FILENAME
,
1375 g_assert (filename
!= NULL
);
1380 bookmark_list_read (GSList
**bookmarks
, GError
**error
)
1384 gboolean result
= FALSE
;
1386 filename
= bookmark_get_filename (FALSE
);
1389 if (g_file_get_contents (filename
, &contents
, NULL
, error
))
1391 gchar
**lines
= g_strsplit (contents
, "\n", -1);
1395 table
= g_hash_table_new (g_str_hash
, g_str_equal
);
1397 for (i
= 0; lines
[i
]; i
++)
1399 if (lines
[i
][0] && !g_hash_table_lookup (table
, lines
[i
]))
1401 *bookmarks
= g_slist_prepend (*bookmarks
, g_strdup (lines
[i
]));
1402 g_hash_table_insert (table
, lines
[i
], lines
[i
]);
1407 g_hash_table_destroy (table
);
1410 *bookmarks
= g_slist_reverse (*bookmarks
);
1420 bookmark_list_write (GSList
*bookmarks
, GError
**error
)
1424 gboolean result
= TRUE
;
1429 /* First, write a temporary file */
1431 tmp_filename
= bookmark_get_filename (TRUE
);
1432 filename
= bookmark_get_filename (FALSE
);
1434 fd
= g_mkstemp (tmp_filename
);
1437 saved_errno
= errno
;
1441 if ((file
= fdopen (fd
, "w")) != NULL
)
1445 for (l
= bookmarks
; l
; l
= l
->next
)
1446 if (fputs (l
->data
, file
) == EOF
1447 || fputs ("\n", file
) == EOF
)
1449 saved_errno
= errno
;
1453 if (fclose (file
) == EOF
)
1455 saved_errno
= errno
;
1459 if (rename (tmp_filename
, filename
) == -1)
1461 saved_errno
= errno
;
1470 saved_errno
= errno
;
1472 /* fdopen() failed, so we can't do much error checking here anyway */
1479 GTK_FILE_SYSTEM_ERROR
,
1480 GTK_FILE_SYSTEM_ERROR_FAILED
,
1481 _("Bookmark saving failed (%s)"),
1482 g_strerror (saved_errno
));
1486 unlink (tmp_filename
); /* again, not much error checking we can do here */
1491 g_free (tmp_filename
);
1497 gtk_file_system_unix_insert_bookmark (GtkFileSystem
*file_system
,
1498 const GtkFilePath
*path
,
1510 if (!bookmark_list_read (&bookmarks
, &err
) && err
->code
!= G_FILE_ERROR_NOENT
)
1512 g_propagate_error (error
, err
);
1516 num_bookmarks
= g_slist_length (bookmarks
);
1517 g_return_val_if_fail (position
>= -1 && position
<= num_bookmarks
, FALSE
);
1521 uri
= gtk_file_system_unix_path_to_uri (file_system
, path
);
1523 for (l
= bookmarks
; l
; l
= l
->next
)
1525 const char *bookmark
;
1528 if (strcmp (bookmark
, uri
) == 0)
1531 GTK_FILE_SYSTEM_ERROR
,
1532 GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS
,
1533 "%s already exists in the bookmarks list",
1539 bookmarks
= g_slist_insert (bookmarks
, g_strdup (uri
), position
);
1540 if (bookmark_list_write (bookmarks
, error
))
1543 g_signal_emit_by_name (file_system
, "bookmarks-changed", 0);
1549 bookmark_list_free (bookmarks
);
1555 gtk_file_system_unix_remove_bookmark (GtkFileSystem
*file_system
,
1556 const GtkFilePath
*path
,
1564 if (!bookmark_list_read (&bookmarks
, error
))
1569 uri
= gtk_file_system_path_to_uri (file_system
, path
);
1571 for (l
= bookmarks
; l
; l
= l
->next
)
1573 const char *bookmark
;
1576 if (strcmp (bookmark
, uri
) == 0)
1579 bookmarks
= g_slist_remove_link (bookmarks
, l
);
1582 if (bookmark_list_write (bookmarks
, error
))
1585 g_signal_emit_by_name (file_system
, "bookmarks-changed", 0);
1593 GTK_FILE_SYSTEM_ERROR
,
1594 GTK_FILE_SYSTEM_ERROR_NONEXISTENT
,
1595 "%s does not exist in the bookmarks list",
1601 bookmark_list_free (bookmarks
);
1607 gtk_file_system_unix_list_bookmarks (GtkFileSystem
*file_system
)
1613 if (!bookmark_list_read (&bookmarks
, NULL
))
1618 for (l
= bookmarks
; l
; l
= l
->next
)
1624 if (is_local_uri (name
))
1625 result
= g_slist_prepend (result
, gtk_file_system_unix_uri_to_path (file_system
, name
));
1628 bookmark_list_free (bookmarks
);
1630 result
= g_slist_reverse (result
);
1637 static GType file_folder_unix_type
= 0;
1640 gtk_file_folder_unix_get_type (void)
1642 return file_folder_unix_type
;
1646 gtk_file_folder_unix_register_type (GTypeModule
*module
)
1648 if (!file_folder_unix_type
)
1650 static const GTypeInfo file_folder_unix_info
=
1652 sizeof (GtkFileFolderUnixClass
),
1653 NULL
, /* base_init */
1654 NULL
, /* base_finalize */
1655 (GClassInitFunc
) gtk_file_folder_unix_class_init
,
1656 NULL
, /* class_finalize */
1657 NULL
, /* class_data */
1658 sizeof (GtkFileFolderUnix
),
1659 0, /* n_preallocs */
1660 (GInstanceInitFunc
) gtk_file_folder_unix_init
,
1663 static const GInterfaceInfo file_folder_info
=
1665 (GInterfaceInitFunc
) gtk_file_folder_unix_iface_init
, /* interface_init */
1666 NULL
, /* interface_finalize */
1667 NULL
/* interface_data */
1670 file_folder_unix_type
= g_type_module_register_type (module
,
1672 "GtkFileFolderBeagle",
1673 &file_folder_unix_info
, 0);
1674 g_type_module_add_interface (module
,
1675 file_folder_unix_type
,
1676 GTK_TYPE_FILE_FOLDER
,
1680 return file_folder_unix_type
;
1684 gtk_file_folder_unix_class_init (GtkFileFolderUnixClass
*class)
1686 GObjectClass
*gobject_class
= G_OBJECT_CLASS (class);
1688 folder_parent_class
= g_type_class_peek_parent (class);
1690 gobject_class
->finalize
= gtk_file_folder_unix_finalize
;
1694 gtk_file_folder_unix_iface_init (GtkFileFolderIface
*iface
)
1696 iface
->get_info
= gtk_file_folder_unix_get_info
;
1697 iface
->list_children
= gtk_file_folder_unix_list_children
;
1698 /*iface->is_finished_loading = gtk_file_folder_unix_is_finished_loading;*/
1702 gtk_file_folder_unix_init (GtkFileFolderUnix
*impl
)
1707 gtk_file_folder_unix_finalize (GObject
*object
)
1709 GtkFileFolderUnix
*folder_unix
= GTK_FILE_FOLDER_UNIX (object
);
1711 if (folder_unix
->search_magic
)
1713 beagle_query_result_free (folder_unix
->query_result
);
1714 folder_parent_class
->finalize (object
);
1718 g_hash_table_remove (folder_unix
->system_unix
->folder_hash
, folder_unix
->filename
);
1720 if (folder_unix
->stat_info
)
1723 g_print ("Releasing information for directory %s\n", folder_unix
->filename
);
1725 g_hash_table_destroy (folder_unix
->stat_info
);
1728 g_free (folder_unix
->filename
);
1730 folder_parent_class
->finalize (object
);
1733 static GtkFileInfo
*
1734 gtk_file_folder_unix_get_info (GtkFileFolder
*folder
,
1735 const GtkFilePath
*path
,
1738 GtkFileFolderUnix
*folder_unix
= GTK_FILE_FOLDER_UNIX (folder
);
1740 gchar
*dirname
, *basename
;
1741 const char *filename
;
1742 struct stat_info_entry
*entry
;
1743 gboolean file_must_exist
;
1744 GtkFileInfoType types
;
1746 if (folder_unix
->search_magic
)
1751 info
= gtk_file_info_new ();
1752 str
= g_strdup_printf ("Search Results: %s", search_string
);
1753 gtk_file_info_set_display_name (info
, str
);
1755 gtk_file_info_set_is_folder (info
, TRUE
);
1756 gtk_file_info_set_is_hidden (info
, FALSE
);
1757 gtk_file_info_set_mime_type (info
, "x-directory/normal");
1760 const char *filename
= gtk_file_path_get_string (path
);
1761 char *uri
= g_strconcat ("file://", filename
, NULL
);
1762 BeagleHit
*hit
= beagle_query_result_get_by_uri (folder_unix
->query_result
, uri
);
1763 info
= gtk_file_info_new ();
1764 gtk_file_info_set_display_name (info
, filename
); /* skip over file:// */
1765 gtk_file_info_set_is_hidden (info
, FALSE
);
1766 gtk_file_info_set_is_folder (info
, FALSE
);
1767 gtk_file_info_set_mime_type (info
, beagle_hit_get_mime_type (hit
));
1768 gtk_file_info_set_modification_time (info
, beagle_hit_get_timestamp (hit
));
1778 g_return_val_if_fail (filename_is_root (folder_unix
->filename
), NULL
);
1780 if (stat (folder_unix
->filename
, &buf
) != 0)
1783 info
= gtk_file_info_new ();
1784 gtk_file_info_set_display_name (info
, "/");
1785 gtk_file_info_set_is_folder (info
, TRUE
);
1786 gtk_file_info_set_is_hidden (info
, FALSE
);
1787 gtk_file_info_set_mime_type (info
, "x-directory/normal");
1788 gtk_file_info_set_modification_time (info
, buf
.st_mtime
);
1789 gtk_file_info_set_size (info
, buf
.st_size
);
1794 filename
= gtk_file_path_get_string (path
);
1795 g_return_val_if_fail (filename
!= NULL
, NULL
);
1796 g_return_val_if_fail (g_path_is_absolute (filename
), NULL
);
1798 if (! folder_unix
->search_magic
) {
1799 dirname
= get_parent_dir (filename
);
1800 g_return_val_if_fail (strcmp (dirname
, folder_unix
->filename
) == 0, NULL
);
1804 basename
= g_path_get_basename (filename
);
1805 types
= folder_unix
->types
;
1806 file_must_exist
= (types
& ~GTK_FILE_INFO_DISPLAY_NAME
) != 0;
1807 entry
= file_must_exist
1808 ? g_hash_table_lookup (folder_unix
->stat_info
, basename
)
1810 /* basename freed later. */
1812 if (!file_must_exist
|| entry
)
1814 info
= gtk_file_info_new ();
1818 gchar
*filename_utf8
= g_filename_to_utf8 (filename
, -1, NULL
, NULL
, NULL
);
1820 GTK_FILE_SYSTEM_ERROR
,
1821 GTK_FILE_SYSTEM_ERROR_NONEXISTENT
,
1822 _("error getting information for '%s'"),
1823 filename_utf8
? filename_utf8
: "???");
1824 g_free (filename_utf8
);
1829 if (types
& GTK_FILE_INFO_DISPLAY_NAME
)
1831 gchar
*display_name
= g_filename_to_utf8 (basename
, -1, NULL
, NULL
, NULL
);
1833 display_name
= g_strescape (basename
, NULL
);
1835 gtk_file_info_set_display_name (info
, display_name
);
1837 g_free (display_name
);
1840 if (types
& GTK_FILE_INFO_IS_HIDDEN
)
1841 gtk_file_info_set_is_hidden (info
, basename
[0] == '.');
1843 if (types
& GTK_FILE_INFO_IS_FOLDER
)
1844 gtk_file_info_set_is_folder (info
, S_ISDIR (entry
->statbuf
.st_mode
));
1846 if (types
& GTK_FILE_INFO_MIME_TYPE
)
1847 gtk_file_info_set_mime_type (info
, entry
->mime_type
);
1849 if (types
& GTK_FILE_INFO_MODIFICATION_TIME
)
1850 gtk_file_info_set_modification_time (info
, entry
->statbuf
.st_mtime
);
1852 if (types
& GTK_FILE_INFO_SIZE
)
1853 gtk_file_info_set_size (info
, (gint64
)entry
->statbuf
.st_size
);
1862 cb_list_children (gpointer key
, gpointer value
, gpointer user_data
)
1864 GSList
**children
= user_data
;
1865 *children
= g_slist_prepend (*children
, key
);
1869 beagle_query_result_list_children (BeagleQueryResult
*bqr
, GSList
**children
)
1873 for (all
= beagle_query_result_get_all (bqr
); all
!= NULL
; all
= all
->next
) {
1874 BeagleHit
*hit
= all
->data
;
1876 /* Filter out non-file:// Uris */
1877 if (! strncmp (beagle_hit_get_uri (hit
), "file://", 7)) {
1878 *children
= g_slist_prepend (*children
, filename_to_path (beagle_hit_get_uri (hit
) + 7));
1884 gtk_file_folder_unix_list_children (GtkFileFolder
*folder
,
1888 GtkFileFolderUnix
*folder_unix
= GTK_FILE_FOLDER_UNIX (folder
);
1891 g_print ("List Children\n");
1893 if (folder_unix
->search_magic
)
1895 if (search_string
!= NULL
) {
1896 folder_unix
->query_result
= beagle_query (search_string
);
1897 time (&search_string_time
);
1900 beagle_query_result_list_children (folder_unix
->query_result
, children
);
1904 if (!fill_in_names (folder_unix
, error
))
1909 /* Get the list of basenames. */
1910 g_hash_table_foreach (folder_unix
->stat_info
, cb_list_children
, children
);
1912 /* Turn basenames into GFilePaths. */
1913 for (l
= *children
; l
; l
= l
->next
)
1915 const char *basename
= l
->data
;
1916 char *fullname
= g_build_filename (folder_unix
->filename
, basename
, NULL
);
1917 l
->data
= filename_to_path (fullname
);
1924 gtk_file_folder_unix_is_finished_loading (GtkFileFolder
*folder
)
1926 /* Since we don't do asynchronous loads, we are always finished loading */
1931 free_stat_info_entry (struct stat_info_entry
*entry
)
1933 g_free (entry
->mime_type
);
1938 fill_in_names (GtkFileFolderUnix
*folder_unix
, GError
**error
)
1942 if (folder_unix
->stat_info
)
1946 g_print ("Reading directory %s\n", folder_unix
->filename
);
1949 folder_unix
->stat_info
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
1950 (GDestroyNotify
)g_free
,
1951 (GDestroyNotify
)free_stat_info_entry
);
1952 dir
= g_dir_open (folder_unix
->filename
, 0, error
);
1955 int save_errno
= errno
;
1956 gchar
*filename_utf8
= g_filename_to_utf8 (folder_unix
->filename
, -1, NULL
, NULL
, NULL
);
1958 GTK_FILE_SYSTEM_ERROR
,
1959 GTK_FILE_SYSTEM_ERROR_NONEXISTENT
,
1960 _("error getting information for '%s': %s"),
1961 filename_utf8
? filename_utf8
: "???",
1962 g_strerror (save_errno
));
1963 g_free (filename_utf8
);
1969 const gchar
*basename
= g_dir_read_name (dir
);
1973 g_hash_table_insert (folder_unix
->stat_info
,
1974 g_strdup (basename
),
1975 g_new0 (struct stat_info_entry
, 1));
1980 folder_unix
->asof
= time (NULL
);
1985 cb_fill_in_stats (gpointer key
, gpointer value
, gpointer user_data
)
1987 const char *basename
= key
;
1988 struct stat_info_entry
*entry
= value
;
1989 GtkFileFolderUnix
*folder_unix
= user_data
;
1990 char *fullname
= g_build_filename (folder_unix
->filename
, basename
, NULL
);
1993 if (stat (fullname
, &entry
->statbuf
) == -1 &&
1994 (errno
!= ENOENT
|| lstat (fullname
, &entry
->statbuf
) == -1))
1995 result
= TRUE
; /* Couldn't stat -- remove from hash. */
2005 fill_in_stats (GtkFileFolderUnix
*folder_unix
, GError
**error
)
2007 if (folder_unix
->have_stat
)
2010 if (!fill_in_names (folder_unix
, error
))
2014 g_print ("Stating directory %s\n", folder_unix
->filename
);
2016 g_hash_table_foreach_remove (folder_unix
->stat_info
,
2020 folder_unix
->have_stat
= TRUE
;
2026 cb_fill_in_mime_type (gpointer key
, gpointer value
, gpointer user_data
)
2028 const char *basename
= key
;
2029 struct stat_info_entry
*entry
= value
;
2030 GtkFileFolderUnix
*folder_unix
= user_data
;
2031 char *fullname
= g_build_filename (folder_unix
->filename
, basename
, NULL
);
2033 /* FIXME: Should not need to re-stat. */
2034 const char *mime_type
= xdg_mime_get_mime_type_for_file (fullname
);
2035 entry
->mime_type
= g_strdup (mime_type
);
2038 /* FIXME: free on NULL? */
2043 fill_in_mime_type (GtkFileFolderUnix
*folder_unix
, GError
**error
)
2045 if (folder_unix
->have_mime_type
)
2049 g_print ("Getting mime types for directory %s\n", folder_unix
->filename
);
2051 g_hash_table_foreach_remove (folder_unix
->stat_info
,
2052 cb_fill_in_mime_type
,
2055 folder_unix
->have_mime_type
= TRUE
;
2059 static GtkFilePath
*
2060 filename_to_path (const char *filename
)
2064 tmp
= remove_trailing_slash (filename
);
2065 return gtk_file_path_new_steal (tmp
);
2069 filename_is_root (const char *filename
)
2071 const gchar
*after_root
;
2073 after_root
= g_path_skip_root (filename
);
2075 return (after_root
!= NULL
&& *after_root
== '\0');
2079 fs_module_init(GTypeModule
*module
)
2081 gtk_file_folder_unix_register_type (module
);
2082 gtk_file_system_beagle_register_type (module
);
2086 fs_module_exit (void)
2091 fs_module_create (void)
2093 return gtk_file_system_beagle_new ();