]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkfilesystemunix.c
Translation updated by Ivar Smolin.
[~andy/gtk] / gtk / gtkfilesystemunix.c
index 39f98a1aba28c5fb99f9a49b710093d48d8193d6..b426afe764573106e8443f006907f424e93f5a91 100644 (file)
  * 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"
@@ -68,6 +73,11 @@ struct _GtkFileSystemUnix
   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;
 };
@@ -88,7 +98,7 @@ typedef enum {
 } 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))
@@ -132,12 +142,8 @@ static const GtkFileInfoType STAT_NEEDED_MASK = (GTK_FILE_INFO_IS_FOLDER |
                                                 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);
@@ -215,10 +221,7 @@ static void     gtk_file_system_unix_set_bookmark_label (GtkFileSystem     *file
                                                         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,
@@ -251,6 +254,8 @@ static GtkFileInfo *create_file_info              (GtkFileFolderUnix *folder_uni
                                                   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);
@@ -269,43 +274,17 @@ static char *       get_parent_dir    (const char       *filename);
 /*
  * 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:
@@ -327,13 +306,12 @@ gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class)
 {
   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;
@@ -375,6 +353,100 @@ gtk_file_system_unix_init (GtkFileSystemUnix *system_unix)
     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
@@ -384,10 +456,12 @@ gtk_file_system_unix_finalize (GObject *object)
 
   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 */
@@ -434,7 +508,7 @@ enum callback_types
   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
 {
@@ -477,7 +551,7 @@ queue_get_info_callback (GtkFileSystemGetInfoCallback  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);
 }
 
 
@@ -519,7 +593,7 @@ queue_get_folder_callback (GtkFileSystemGetFolderCallback  callback,
   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);
 }
 
 
@@ -564,7 +638,7 @@ queue_create_folder_callback (GtkFileSystemCreateFolderCallback  callback,
   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);
 }
 
 
@@ -606,7 +680,7 @@ queue_volume_mount_callback (GtkFileSystemVolumeMountCallback  callback,
   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);
 }
 
 
@@ -624,17 +698,20 @@ struct callback_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;
 
@@ -660,18 +737,21 @@ execute_callbacks_idle (gpointer 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;
 
@@ -697,20 +777,26 @@ queue_callback (enum callback_types type, gpointer data)
        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;
 }
 
@@ -736,8 +822,8 @@ gtk_file_system_unix_get_info (GtkFileSystem                *file_system,
   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))
     {
@@ -768,8 +854,6 @@ load_folder (gpointer data)
   GtkFileFolderUnix *folder_unix = data;
   GSList *children;
 
-  GDK_THREADS_ENTER ();
-
   if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
     fill_in_stats (folder_unix);
 
@@ -787,8 +871,6 @@ load_folder (gpointer data)
 
   g_signal_emit_by_name (folder_unix, "finished-loading", 0);
 
-  GDK_THREADS_LEAVE ();
-
   return FALSE;
 }
 
@@ -921,8 +1003,9 @@ gtk_file_system_unix_get_folder (GtkFileSystem                  *file_system,
   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;
 }
@@ -944,8 +1027,8 @@ gtk_file_system_unix_create_folder (GtkFileSystem                     *file_syst
   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);
 
@@ -961,7 +1044,7 @@ gtk_file_system_unix_create_folder (GtkFileSystem                     *file_syst
       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));
       
@@ -1359,10 +1442,8 @@ expand_tilde (const char *filename)
   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 ();
 
@@ -1374,7 +1455,11 @@ expand_tilde (const char *filename)
       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);
 
@@ -1384,7 +1469,10 @@ expand_tilde (const char *filename)
       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
@@ -1513,17 +1601,12 @@ gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
 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";
@@ -2047,54 +2130,11 @@ gtk_file_system_unix_set_bookmark_label (GtkFileSystem     *file_system,
   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;
 }
 
@@ -2107,7 +2147,7 @@ gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface)
 }
 
 static void
-gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
+_gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
 {
 }
 
@@ -2134,7 +2174,7 @@ gtk_file_folder_unix_finalize (GObject *object)
 
   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 */
@@ -2153,8 +2193,8 @@ file_info_for_root_with_error (const char  *root_name,
       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;
     }