* Boston, MA 02111-1307, USA.
*/
+/* #define this if you want the program to crash when a file system gets
+ * finalized while async handles are still outstanding.
+ */
+#undef HANDLE_ME_HARDER
+
#include <config.h>
#include "gtkfilesystem.h"
struct stat afs_statbuf;
struct stat net_statbuf;
+ GHashTable *handles;
+
+ guint execute_callbacks_idle_id;
+ GSList *callbacks;
+
guint have_afs : 1;
guint have_net : 1;
};
} IconType;
-#define GTK_TYPE_FILE_FOLDER_UNIX (gtk_file_folder_unix_get_type ())
+#define GTK_TYPE_FILE_FOLDER_UNIX (_gtk_file_folder_unix_get_type ())
#define GTK_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnix))
#define GTK_IS_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_UNIX))
#define GTK_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
GTK_FILE_INFO_SIZE |
GTK_FILE_INFO_ICON);
-static GObjectClass *system_parent_class;
-static GObjectClass *folder_parent_class;
-
-static void gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class);
static void gtk_file_system_unix_iface_init (GtkFileSystemIface *iface);
-static void gtk_file_system_unix_init (GtkFileSystemUnix *impl);
+static void gtk_file_system_unix_dispose (GObject *object);
static void gtk_file_system_unix_finalize (GObject *object);
static GSList * gtk_file_system_unix_list_volumes (GtkFileSystem *file_system);
const GtkFilePath *path,
const gchar *label);
-static GType gtk_file_folder_unix_get_type (void);
-static void gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class);
static void gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface);
-static void gtk_file_folder_unix_init (GtkFileFolderUnix *impl);
static void gtk_file_folder_unix_finalize (GObject *object);
static GtkFileInfo *gtk_file_folder_unix_get_info (GtkFileFolder *folder,
struct stat *statbuf,
const char *mime_type);
+static gboolean execute_callbacks (gpointer data);
+
static gboolean fill_in_names (GtkFileFolderUnix *folder_unix,
GError **error);
static void fill_in_stats (GtkFileFolderUnix *folder_unix);
/*
* GtkFileSystemUnix
*/
-GType
-gtk_file_system_unix_get_type (void)
-{
- static GType file_system_unix_type = 0;
+G_DEFINE_TYPE_WITH_CODE (GtkFileSystemUnix, gtk_file_system_unix, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_SYSTEM,
+ gtk_file_system_unix_iface_init))
- if (!file_system_unix_type)
- {
- static const GTypeInfo file_system_unix_info =
- {
- sizeof (GtkFileSystemUnixClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_file_system_unix_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkFileSystemUnix),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gtk_file_system_unix_init,
- };
-
- static const GInterfaceInfo file_system_info =
- {
- (GInterfaceInitFunc) gtk_file_system_unix_iface_init, /* interface_init */
- NULL, /* interface_finalize */
- NULL /* interface_data */
- };
-
- file_system_unix_type = g_type_register_static (G_TYPE_OBJECT,
- I_("GtkFileSystemUnix"),
- &file_system_unix_info, 0);
- g_type_add_interface_static (file_system_unix_type,
- GTK_TYPE_FILE_SYSTEM,
- &file_system_info);
- }
+/*
+ * GtkFileFolderUnix
+ */
+G_DEFINE_TYPE_WITH_CODE (GtkFileFolderUnix, _gtk_file_folder_unix, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_FOLDER,
+ gtk_file_folder_unix_iface_init))
- return file_system_unix_type;
-}
/**
* gtk_file_system_unix_new:
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
- system_parent_class = g_type_class_peek_parent (class);
-
+ gobject_class->dispose = gtk_file_system_unix_dispose;
gobject_class->finalize = gtk_file_system_unix_finalize;
}
static void
-gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
+gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
{
iface->list_volumes = gtk_file_system_unix_list_volumes;
iface->get_volume_for_path = gtk_file_system_unix_get_volume_for_path;
system_unix->have_net = TRUE;
else
system_unix->have_net = FALSE;
+
+ system_unix->handles = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ system_unix->execute_callbacks_idle_id = 0;
+ system_unix->callbacks = NULL;
+}
+
+static void
+check_handle_fn (gpointer key, gpointer value, gpointer data)
+{
+ GtkFileSystemHandle *handle;
+ int *num_live_handles;
+
+ handle = key;
+ num_live_handles = data;
+
+ (*num_live_handles)++;
+
+ g_warning ("file_system_unix=%p still has handle=%p at finalization which is %s!",
+ handle->file_system,
+ handle,
+ handle->cancelled ? "CANCELLED" : "NOT CANCELLED");
+}
+
+static void
+check_handles_at_finalization (GtkFileSystemUnix *system_unix)
+{
+ int num_live_handles;
+
+ num_live_handles = 0;
+
+ g_hash_table_foreach (system_unix->handles, check_handle_fn, &num_live_handles);
+#ifdef HANDLE_ME_HARDER
+ g_assert (num_live_handles == 0);
+#endif
+
+ g_hash_table_destroy (system_unix->handles);
+ system_unix->handles = NULL;
+}
+
+#define GTK_TYPE_FILE_SYSTEM_HANDLE_UNIX (_gtk_file_system_handle_unix_get_type ())
+
+typedef struct _GtkFileSystemHandle GtkFileSystemHandleUnix;
+typedef struct _GtkFileSystemHandleClass GtkFileSystemHandleUnixClass;
+
+G_DEFINE_TYPE (GtkFileSystemHandleUnix, _gtk_file_system_handle_unix, GTK_TYPE_FILE_SYSTEM_HANDLE)
+
+static void
+_gtk_file_system_handle_unix_init (GtkFileSystemHandleUnix *handle)
+{
+}
+
+static void
+_gtk_file_system_handle_unix_finalize (GObject *object)
+{
+ GtkFileSystemHandleUnix *handle;
+ GtkFileSystemUnix *system_unix;
+
+ handle = (GtkFileSystemHandleUnix *)object;
+
+ system_unix = GTK_FILE_SYSTEM_UNIX (GTK_FILE_SYSTEM_HANDLE (handle)->file_system);
+
+ g_assert (g_hash_table_lookup (system_unix->handles, handle) != NULL);
+ g_hash_table_remove (system_unix->handles, handle);
+
+ if (G_OBJECT_CLASS (_gtk_file_system_handle_unix_parent_class)->finalize)
+ G_OBJECT_CLASS (_gtk_file_system_handle_unix_parent_class)->finalize (object);
+}
+
+static void
+_gtk_file_system_handle_unix_class_init (GtkFileSystemHandleUnixClass *class)
+{
+ GObjectClass *gobject_class = (GObjectClass *) class;
+
+ gobject_class->finalize = _gtk_file_system_handle_unix_finalize;
+}
+
+static void
+gtk_file_system_unix_dispose (GObject *object)
+{
+ GtkFileSystemUnix *system_unix;
+
+ system_unix = GTK_FILE_SYSTEM_UNIX (object);
+
+ if (system_unix->execute_callbacks_idle_id)
+ {
+ g_source_remove (system_unix->execute_callbacks_idle_id);
+ system_unix->execute_callbacks_idle_id = 0;
+
+ /* call pending callbacks */
+ execute_callbacks (system_unix);
+ }
+
+ G_OBJECT_CLASS (gtk_file_system_unix_parent_class)->dispose (object);
}
static void
system_unix = GTK_FILE_SYSTEM_UNIX (object);
+ check_handles_at_finalization (system_unix);
+
/* FIXME: assert that the hash is empty? */
g_hash_table_destroy (system_unix->folder_hash);
- system_parent_class->finalize (object);
+ G_OBJECT_CLASS (gtk_file_system_unix_parent_class)->finalize (object);
}
/* Returns our single root volume */
CALLBACK_VOLUME_MOUNT
};
-static void queue_callback (enum callback_types type, gpointer data);
+static void queue_callback (GtkFileSystemUnix *system_unix, enum callback_types type, gpointer data);
struct get_info_callback
{
info->error = error;
info->data = data;
- queue_callback (CALLBACK_GET_INFO, info);
+ queue_callback (GTK_FILE_SYSTEM_UNIX (handle->file_system), CALLBACK_GET_INFO, info);
}
info->error = error;
info->data = data;
- queue_callback (CALLBACK_GET_FOLDER, info);
+ queue_callback (GTK_FILE_SYSTEM_UNIX (handle->file_system), CALLBACK_GET_FOLDER, info);
}
info->error = error;
info->data = data;
- queue_callback (CALLBACK_CREATE_FOLDER, info);
+ queue_callback (GTK_FILE_SYSTEM_UNIX (handle->file_system), CALLBACK_CREATE_FOLDER, info);
}
info->error = error;
info->data = data;
- queue_callback (CALLBACK_VOLUME_MOUNT, info);
+ queue_callback (GTK_FILE_SYSTEM_UNIX (handle->file_system), CALLBACK_VOLUME_MOUNT, info);
}
};
-static guint execute_callbacks_idle_id = 0;
-static GSList *callbacks = NULL;
static gboolean
-execute_callbacks_idle (gpointer data)
+execute_callbacks (gpointer data)
{
GSList *l;
+ gboolean unref_file_system = TRUE;
+ GtkFileSystemUnix *system_unix = GTK_FILE_SYSTEM_UNIX (data);
- GDK_THREADS_ENTER ();
+ if (!system_unix->execute_callbacks_idle_id)
+ unref_file_system = FALSE;
+ else
+ g_object_ref (system_unix);
- for (l = callbacks; l; l = l->next)
+ for (l = system_unix->callbacks; l; l = l->next)
{
struct callback_info *info = l->data;
g_free (info);
}
- g_slist_free (callbacks);
- callbacks = NULL;
+ g_slist_free (system_unix->callbacks);
+ system_unix->callbacks = NULL;
- execute_callbacks_idle_id = 0;
+ if (unref_file_system)
+ g_object_unref (system_unix);
- GDK_THREADS_LEAVE ();
+ system_unix->execute_callbacks_idle_id = 0;
return FALSE;
}
static void
-queue_callback (enum callback_types type, gpointer data)
+queue_callback (GtkFileSystemUnix *system_unix,
+ enum callback_types type,
+ gpointer data)
{
struct callback_info *info;
break;
}
- callbacks = g_slist_append (callbacks, info);
+ system_unix->callbacks = g_slist_append (system_unix->callbacks, info);
- if (!execute_callbacks_idle_id)
- execute_callbacks_idle_id = g_idle_add (execute_callbacks_idle, NULL);
+ if (!system_unix->execute_callbacks_idle_id)
+ system_unix->execute_callbacks_idle_id = gdk_threads_add_idle (execute_callbacks, system_unix);
}
static GtkFileSystemHandle *
create_handle (GtkFileSystem *file_system)
{
+ GtkFileSystemUnix *system_unix;
GtkFileSystemHandle *handle;
- handle = g_object_new (GTK_TYPE_FILE_SYSTEM_HANDLE, NULL);
+ system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
+
+ handle = g_object_new (GTK_TYPE_FILE_SYSTEM_HANDLE_UNIX, NULL);
handle->file_system = file_system;
+ g_assert (g_hash_table_lookup (system_unix->handles, handle) == NULL);
+ g_hash_table_insert (system_unix->handles, handle, handle);
+
return handle;
}
handle = create_handle (file_system);
filename = gtk_file_path_get_string (path);
- g_return_val_if_fail (filename != NULL, FALSE);
- g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
+ g_return_val_if_fail (filename != NULL, NULL);
+ g_return_val_if_fail (g_path_is_absolute (filename), NULL);
if (!stat_with_error (filename, &statbuf, &error))
{
GtkFileFolderUnix *folder_unix = data;
GSList *children;
- GDK_THREADS_ENTER ();
-
if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
fill_in_stats (folder_unix);
g_signal_emit_by_name (folder_unix, "finished-loading", 0);
- GDK_THREADS_LEAVE ();
-
return FALSE;
}
queue_get_folder_callback (callback, handle, GTK_FILE_FOLDER (folder_unix), NULL, data);
/* Start loading the folder contents in an idle */
- folder_unix->load_folder_id =
- g_idle_add ((GSourceFunc) load_folder, folder_unix);
+ if (!folder_unix->load_folder_id)
+ folder_unix->load_folder_id =
+ gdk_threads_add_idle ((GSourceFunc) load_folder, folder_unix);
return handle;
}
system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
filename = gtk_file_path_get_string (path);
- g_return_val_if_fail (filename != NULL, FALSE);
- g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
+ g_return_val_if_fail (filename != NULL, NULL);
+ g_return_val_if_fail (g_path_is_absolute (filename), NULL);
handle = create_handle (file_system);
g_set_error (&error,
GTK_FILE_SYSTEM_ERROR,
GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
- _("Error creating directory '%s': %s"),
+ _("Error creating folder '%s': %s"),
display_name,
g_strerror (save_errno));
notilde = filename + 1;
slash = strchr (notilde, G_DIR_SEPARATOR);
- if (!slash)
- return NULL;
- if (slash == notilde)
+ if (slash == notilde || !*notilde)
{
home = g_get_home_dir ();
char *username;
struct passwd *passwd;
- username = g_strndup (notilde, slash - notilde);
+ if (slash)
+ username = g_strndup (notilde, slash - notilde);
+ else
+ username = g_strdup (notilde);
+
passwd = getpwnam (username);
g_free (username);
home = passwd->pw_dir;
}
- return g_build_filename (home, G_DIR_SEPARATOR_S, slash + 1, NULL);
+ if (slash)
+ return g_build_filename (home, G_DIR_SEPARATOR_S, slash + 1, NULL);
+ else
+ return g_strdup (home);
}
static gboolean
static const char *
get_icon_name_for_directory (const char *path)
{
- static char *desktop_path = NULL;
-
if (!g_get_home_dir ())
return "gnome-fs-directory";
- if (!desktop_path)
- desktop_path = g_build_filename (g_get_home_dir (), "Desktop", NULL);
-
if (strcmp (g_get_home_dir (), path) == 0)
return "gnome-fs-home";
- else if (strcmp (desktop_path, path) == 0)
+ else if (strcmp (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP), path) == 0)
return "gnome-fs-desktop";
else
return "gnome-fs-directory";
g_free (uri);
}
-/*
- * GtkFileFolderUnix
- */
-static GType
-gtk_file_folder_unix_get_type (void)
-{
- static GType file_folder_unix_type = 0;
-
- if (!file_folder_unix_type)
- {
- static const GTypeInfo file_folder_unix_info =
- {
- sizeof (GtkFileFolderUnixClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_file_folder_unix_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkFileFolderUnix),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gtk_file_folder_unix_init,
- };
-
- static const GInterfaceInfo file_folder_info =
- {
- (GInterfaceInitFunc) gtk_file_folder_unix_iface_init, /* interface_init */
- NULL, /* interface_finalize */
- NULL /* interface_data */
- };
-
- file_folder_unix_type = g_type_register_static (G_TYPE_OBJECT,
- I_("GtkFileFolderUnix"),
- &file_folder_unix_info, 0);
- g_type_add_interface_static (file_folder_unix_type,
- GTK_TYPE_FILE_FOLDER,
- &file_folder_info);
- }
-
- return file_folder_unix_type;
-}
-
static void
-gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class)
+_gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
- folder_parent_class = g_type_class_peek_parent (class);
-
gobject_class->finalize = gtk_file_folder_unix_finalize;
}
}
static void
-gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
+_gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
{
}
g_free (folder_unix->filename);
- folder_parent_class->finalize (object);
+ G_OBJECT_CLASS (_gtk_file_folder_unix_parent_class)->finalize (object);
}
/* Creates a GtkFileInfo for "/" by stat()ing it */
g_set_error (error,
GTK_FILE_SYSTEM_ERROR,
GTK_FILE_SYSTEM_ERROR_FAILED,
- _("Error getting information for '/': %s"),
- g_strerror (saved_errno));
+ _("Error getting information for '%s': %s"),
+ "/", g_strerror (saved_errno));
return NULL;
}