Blame gtk/gtkfilesystem.c

Packit 98cdb6
/* GTK - The GIMP Toolkit
Packit 98cdb6
 * gtkfilesystem.c: Filesystem abstraction functions.
Packit 98cdb6
 * Copyright (C) 2003, Red Hat, Inc.
Packit 98cdb6
 * Copyright (C) 2007-2008 Carlos Garnacho
Packit 98cdb6
 *
Packit 98cdb6
 * This program is free software; you can redistribute it and/or modify
Packit 98cdb6
 * it under the terms of the GNU Lesser General Public License as
Packit 98cdb6
 * published by the Free Software Foundation; either version 2 of the
Packit 98cdb6
 * License, or (at your option) any later version.
Packit 98cdb6
 *
Packit 98cdb6
 * This program is distributed in the hope that it will be useful,
Packit 98cdb6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 98cdb6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 98cdb6
 * GNU General Public License for more details.
Packit 98cdb6
 *
Packit 98cdb6
 * You should have received a copy of the GNU General Public License
Packit 98cdb6
 * along with this program; if not, write to the Free Software
Packit 98cdb6
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
Packit 98cdb6
 *
Packit 98cdb6
 * Authors: Carlos Garnacho <carlos@imendio.com>
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
#include "config.h"
Packit 98cdb6
Packit 98cdb6
#include <string.h>
Packit 98cdb6
Packit 98cdb6
#include <glib/gi18n-lib.h>
Packit 98cdb6
Packit 98cdb6
#include "gtkfilechooser.h"
Packit 98cdb6
#include "gtkfilesystem.h"
Packit 98cdb6
#include "gtkicontheme.h"
Packit 98cdb6
#include "gtkprivate.h"
Packit 98cdb6
Packit 98cdb6
#include "gtkalias.h"
Packit 98cdb6
Packit 98cdb6
/* #define DEBUG_MODE */
Packit 98cdb6
#ifdef DEBUG_MODE
Packit 98cdb6
#define DEBUG(x) g_debug (x);
Packit 98cdb6
#else
Packit 98cdb6
#define DEBUG(x)
Packit 98cdb6
#endif
Packit 98cdb6
Packit 98cdb6
#define GTK_FILE_SYSTEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_FILE_SYSTEM, GtkFileSystemPrivate))
Packit 98cdb6
#define GTK_FOLDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_FOLDER, GtkFolderPrivate))
Packit 98cdb6
#define FILES_PER_QUERY 100
Packit 98cdb6
Packit 98cdb6
/* The pointers we return for a GtkFileSystemVolume are opaque tokens; they are
Packit 98cdb6
 * really pointers to GDrive, GVolume or GMount objects.  We need an extra
Packit 98cdb6
 * token for the fake "File System" volume.  So, we'll return a pointer to
Packit 98cdb6
 * this particular string.
Packit 98cdb6
 */
Packit 98cdb6
static const gchar *root_volume_token = N_("File System");
Packit 98cdb6
#define IS_ROOT_VOLUME(volume) ((gpointer) (volume) == (gpointer) root_volume_token)
Packit 98cdb6
Packit 98cdb6
enum {
Packit 98cdb6
  PROP_0,
Packit 98cdb6
  PROP_FILE,
Packit 98cdb6
  PROP_ENUMERATOR,
Packit 98cdb6
  PROP_ATTRIBUTES
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
enum {
Packit 98cdb6
  BOOKMARKS_CHANGED,
Packit 98cdb6
  VOLUMES_CHANGED,
Packit 98cdb6
  FS_LAST_SIGNAL
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
enum {
Packit 98cdb6
  FILES_ADDED,
Packit 98cdb6
  FILES_REMOVED,
Packit 98cdb6
  FILES_CHANGED,
Packit 98cdb6
  FINISHED_LOADING,
Packit 98cdb6
  DELETED,
Packit 98cdb6
  FOLDER_LAST_SIGNAL
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
static guint fs_signals [FS_LAST_SIGNAL] = { 0, };
Packit 98cdb6
static guint folder_signals [FOLDER_LAST_SIGNAL] = { 0, };
Packit 98cdb6
Packit 98cdb6
typedef struct GtkFileSystemPrivate GtkFileSystemPrivate;
Packit 98cdb6
typedef struct GtkFolderPrivate GtkFolderPrivate;
Packit 98cdb6
typedef struct AsyncFuncData AsyncFuncData;
Packit 98cdb6
Packit 98cdb6
struct GtkFileSystemPrivate
Packit 98cdb6
{
Packit 98cdb6
  GVolumeMonitor *volume_monitor;
Packit 98cdb6
Packit 98cdb6
  /* This list contains elements that can be
Packit 98cdb6
   * of type GDrive, GVolume and GMount
Packit 98cdb6
   */
Packit 98cdb6
  GSList *volumes;
Packit 98cdb6
Packit 98cdb6
  /* This list contains GtkFileSystemBookmark structs */
Packit 98cdb6
  GSList *bookmarks;
Packit 98cdb6
  GFile *bookmarks_file;
Packit 98cdb6
Packit 98cdb6
  GFileMonitor *bookmarks_monitor;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
struct GtkFolderPrivate
Packit 98cdb6
{
Packit 98cdb6
  GFile *folder_file;
Packit 98cdb6
  GHashTable *children;
Packit 98cdb6
  GFileMonitor *directory_monitor;
Packit 98cdb6
  GFileEnumerator *enumerator;
Packit 98cdb6
  GCancellable *cancellable;
Packit 98cdb6
  gchar *attributes;
Packit 98cdb6
Packit 98cdb6
  guint finished_loading : 1;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
struct AsyncFuncData
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystem *file_system;
Packit 98cdb6
  GFile *file;
Packit 98cdb6
  GCancellable *cancellable;
Packit 98cdb6
  gchar *attributes;
Packit 98cdb6
Packit 98cdb6
  gpointer callback;
Packit 98cdb6
  gpointer data;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
struct GtkFileSystemBookmark
Packit 98cdb6
{
Packit 98cdb6
  GFile *file;
Packit 98cdb6
  gchar *label;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
G_DEFINE_TYPE (GtkFileSystem, _gtk_file_system, G_TYPE_OBJECT)
Packit 98cdb6
Packit 98cdb6
G_DEFINE_TYPE (GtkFolder, _gtk_folder, G_TYPE_OBJECT)
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
static void gtk_folder_set_finished_loading (GtkFolder *folder,
Packit 98cdb6
					     gboolean   finished_loading);
Packit 98cdb6
static void gtk_folder_add_file             (GtkFolder *folder,
Packit 98cdb6
					     GFile     *file,
Packit 98cdb6
					     GFileInfo *info);
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
/* GtkFileSystemBookmark methods */
Packit 98cdb6
void
Packit 98cdb6
_gtk_file_system_bookmark_free (GtkFileSystemBookmark *bookmark)
Packit 98cdb6
{
Packit 98cdb6
  g_object_unref (bookmark->file);
Packit 98cdb6
  g_free (bookmark->label);
Packit 98cdb6
  g_slice_free (GtkFileSystemBookmark, bookmark);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/* GtkFileSystem methods */
Packit 98cdb6
static void
Packit 98cdb6
volumes_changed (GVolumeMonitor *volume_monitor,
Packit 98cdb6
		 gpointer        volume,
Packit 98cdb6
		 gpointer        user_data)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystem *file_system;
Packit 98cdb6
Packit 98cdb6
  gdk_threads_enter ();
Packit 98cdb6
Packit 98cdb6
  file_system = GTK_FILE_SYSTEM (user_data);
Packit 98cdb6
  g_signal_emit (file_system, fs_signals[VOLUMES_CHANGED], 0, volume);
Packit 98cdb6
  gdk_threads_leave ();
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
gtk_file_system_dispose (GObject *object)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("dispose");
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (object);
Packit 98cdb6
Packit 98cdb6
  if (priv->volumes)
Packit 98cdb6
    {
Packit 98cdb6
      g_slist_foreach (priv->volumes, (GFunc) g_object_unref, NULL);
Packit 98cdb6
      g_slist_free (priv->volumes);
Packit 98cdb6
      priv->volumes = NULL;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (priv->volume_monitor)
Packit 98cdb6
    {
Packit 98cdb6
      g_signal_handlers_disconnect_by_func (priv->volume_monitor, volumes_changed, object);
Packit 98cdb6
      g_object_unref (priv->volume_monitor);
Packit 98cdb6
      priv->volume_monitor = NULL;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  G_OBJECT_CLASS (_gtk_file_system_parent_class)->dispose (object);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
gtk_file_system_finalize (GObject *object)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("finalize");
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (object);
Packit 98cdb6
Packit 98cdb6
  if (priv->bookmarks_monitor)
Packit 98cdb6
    g_object_unref (priv->bookmarks_monitor);
Packit 98cdb6
Packit 98cdb6
  if (priv->bookmarks)
Packit 98cdb6
    {
Packit 98cdb6
      g_slist_foreach (priv->bookmarks, (GFunc) _gtk_file_system_bookmark_free, NULL);
Packit 98cdb6
      g_slist_free (priv->bookmarks);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (priv->bookmarks_file)
Packit 98cdb6
    g_object_unref (priv->bookmarks_file);
Packit 98cdb6
Packit 98cdb6
  G_OBJECT_CLASS (_gtk_file_system_parent_class)->finalize (object);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
_gtk_file_system_class_init (GtkFileSystemClass *class)
Packit 98cdb6
{
Packit 98cdb6
  GObjectClass *object_class = G_OBJECT_CLASS (class);
Packit 98cdb6
Packit 98cdb6
  object_class->dispose = gtk_file_system_dispose;
Packit 98cdb6
  object_class->finalize = gtk_file_system_finalize;
Packit 98cdb6
Packit 98cdb6
  fs_signals[BOOKMARKS_CHANGED] =
Packit 98cdb6
    g_signal_new ("bookmarks-changed",
Packit 98cdb6
		  G_TYPE_FROM_CLASS (object_class),
Packit 98cdb6
		  G_SIGNAL_RUN_LAST,
Packit 98cdb6
		  G_STRUCT_OFFSET (GtkFileSystemClass, bookmarks_changed),
Packit 98cdb6
		  NULL, NULL,
Packit 98cdb6
		  g_cclosure_marshal_VOID__VOID,
Packit 98cdb6
		  G_TYPE_NONE, 0);
Packit 98cdb6
Packit 98cdb6
  fs_signals[VOLUMES_CHANGED] =
Packit 98cdb6
    g_signal_new ("volumes-changed",
Packit 98cdb6
		  G_TYPE_FROM_CLASS (object_class),
Packit 98cdb6
		  G_SIGNAL_RUN_LAST,
Packit 98cdb6
		  G_STRUCT_OFFSET (GtkFileSystemClass, volumes_changed),
Packit 98cdb6
		  NULL, NULL,
Packit 98cdb6
		  g_cclosure_marshal_VOID__VOID,
Packit 98cdb6
		  G_TYPE_NONE, 0);
Packit 98cdb6
Packit 98cdb6
  g_type_class_add_private (object_class, sizeof (GtkFileSystemPrivate));
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static GFile *
Packit 98cdb6
get_legacy_bookmarks_file (void)
Packit 98cdb6
{
Packit 98cdb6
  GFile *file;
Packit 98cdb6
  gchar *filename;
Packit 98cdb6
Packit 98cdb6
  filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
Packit 98cdb6
  file = g_file_new_for_path (filename);
Packit 98cdb6
  g_free (filename);
Packit 98cdb6
Packit 98cdb6
  return file;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static GFile *
Packit 98cdb6
get_bookmarks_file (void)
Packit 98cdb6
{
Packit 98cdb6
  GFile *file;
Packit 98cdb6
  gchar *filename;
Packit 98cdb6
Packit 98cdb6
  filename = g_build_filename (g_get_user_config_dir (), "gtk-3.0", "bookmarks", NULL);
Packit 98cdb6
  file = g_file_new_for_path (filename);
Packit 98cdb6
  g_free (filename);
Packit 98cdb6
Packit 98cdb6
  return file;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static GSList *
Packit 98cdb6
read_bookmarks (GFile *file)
Packit 98cdb6
{
Packit 98cdb6
  gchar *contents;
Packit 98cdb6
  gchar **lines, *space;
Packit 98cdb6
  GSList *bookmarks = NULL;
Packit 98cdb6
  gint i;
Packit 98cdb6
Packit 98cdb6
  if (!g_file_load_contents (file, NULL, &contents,
Packit 98cdb6
			     NULL, NULL, NULL))
Packit 98cdb6
    return NULL;
Packit 98cdb6
Packit 98cdb6
  lines = g_strsplit (contents, "\n", -1);
Packit 98cdb6
Packit 98cdb6
  for (i = 0; lines[i]; i++)
Packit 98cdb6
    {
Packit 98cdb6
      GtkFileSystemBookmark *bookmark;
Packit 98cdb6
Packit 98cdb6
      if (!*lines[i])
Packit 98cdb6
	continue;
Packit 98cdb6
Packit 98cdb6
      if (!g_utf8_validate (lines[i], -1, NULL))
Packit 98cdb6
	continue;
Packit 98cdb6
Packit 98cdb6
      bookmark = g_slice_new0 (GtkFileSystemBookmark);
Packit 98cdb6
Packit 98cdb6
      if ((space = strchr (lines[i], ' ')) != NULL)
Packit 98cdb6
	{
Packit 98cdb6
	  space[0] = '\0';
Packit 98cdb6
	  bookmark->label = g_strdup (space + 1);
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      bookmark->file = g_file_new_for_uri (lines[i]);
Packit 98cdb6
      bookmarks = g_slist_prepend (bookmarks, bookmark);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  bookmarks = g_slist_reverse (bookmarks);
Packit 98cdb6
  g_strfreev (lines);
Packit 98cdb6
  g_free (contents);
Packit 98cdb6
Packit 98cdb6
  return bookmarks;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
save_bookmarks (GFile  *bookmarks_file,
Packit 98cdb6
		GSList *bookmarks)
Packit 98cdb6
{
Packit 98cdb6
  GError *error = NULL;
Packit 98cdb6
  GString *contents;
Packit 98cdb6
  GSList *l;
Packit 98cdb6
  GFile *parent_file;
Packit 98cdb6
  gchar *path;
Packit 98cdb6
Packit 98cdb6
  contents = g_string_new ("");
Packit 98cdb6
Packit 98cdb6
  for (l = bookmarks; l; l = l->next)
Packit 98cdb6
    {
Packit 98cdb6
      GtkFileSystemBookmark *bookmark = l->data;
Packit 98cdb6
      gchar *uri;
Packit 98cdb6
Packit 98cdb6
      uri = g_file_get_uri (bookmark->file);
Packit 98cdb6
      if (!uri)
Packit 98cdb6
	continue;
Packit 98cdb6
Packit 98cdb6
      g_string_append (contents, uri);
Packit 98cdb6
Packit 98cdb6
      if (bookmark->label)
Packit 98cdb6
	g_string_append_printf (contents, " %s", bookmark->label);
Packit 98cdb6
Packit 98cdb6
      g_string_append_c (contents, '\n');
Packit 98cdb6
      g_free (uri);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  parent_file = g_file_get_parent (bookmarks_file);
Packit 98cdb6
  path = g_file_get_path (parent_file);
Packit 98cdb6
  if (g_mkdir_with_parents (path, 0700) == 0)
Packit 98cdb6
    {
Packit 98cdb6
      if (!g_file_replace_contents (bookmarks_file,
Packit 98cdb6
                                    contents->str,
Packit 98cdb6
                                    strlen (contents->str),
Packit 98cdb6
                                    NULL, FALSE, 0, NULL,
Packit 98cdb6
                                    NULL, &error))
Packit 98cdb6
        {
Packit 98cdb6
          g_critical ("%s", error->message);
Packit 98cdb6
          g_error_free (error);
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
  g_free (path);
Packit 98cdb6
  g_object_unref (parent_file);
Packit 98cdb6
  g_string_free (contents, TRUE);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
bookmarks_file_changed (GFileMonitor      *monitor,
Packit 98cdb6
			GFile             *file,
Packit 98cdb6
			GFile             *other_file,
Packit 98cdb6
			GFileMonitorEvent  event,
Packit 98cdb6
			gpointer           data)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (data);
Packit 98cdb6
Packit 98cdb6
  switch (event)
Packit 98cdb6
    {
Packit 98cdb6
    case G_FILE_MONITOR_EVENT_CHANGED:
Packit 98cdb6
    case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
Packit 98cdb6
    case G_FILE_MONITOR_EVENT_CREATED:
Packit 98cdb6
    case G_FILE_MONITOR_EVENT_DELETED:
Packit 98cdb6
      g_slist_foreach (priv->bookmarks, (GFunc) _gtk_file_system_bookmark_free, NULL);
Packit 98cdb6
      g_slist_free (priv->bookmarks);
Packit 98cdb6
Packit 98cdb6
      priv->bookmarks = read_bookmarks (file);
Packit 98cdb6
Packit 98cdb6
      gdk_threads_enter ();
Packit 98cdb6
      g_signal_emit (data, fs_signals[BOOKMARKS_CHANGED], 0);
Packit 98cdb6
      gdk_threads_leave ();
Packit 98cdb6
      break;
Packit 98cdb6
    default:
Packit 98cdb6
      /* ignore at the moment */
Packit 98cdb6
      break;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static gboolean
Packit 98cdb6
mount_referenced_by_volume_activation_root (GList *volumes, GMount *mount)
Packit 98cdb6
{
Packit 98cdb6
  GList *l;
Packit 98cdb6
  GFile *mount_root;
Packit 98cdb6
  gboolean ret;
Packit 98cdb6
Packit 98cdb6
  ret = FALSE;
Packit 98cdb6
Packit 98cdb6
  mount_root = g_mount_get_root (mount);
Packit 98cdb6
Packit 98cdb6
  for (l = volumes; l != NULL; l = l->next)
Packit 98cdb6
    {
Packit 98cdb6
      GVolume *volume = G_VOLUME (l->data);
Packit 98cdb6
      GFile *volume_activation_root;
Packit 98cdb6
Packit 98cdb6
      volume_activation_root = g_volume_get_activation_root (volume);
Packit 98cdb6
      if (volume_activation_root != NULL)
Packit 98cdb6
        {
Packit 98cdb6
          if (g_file_has_prefix (volume_activation_root, mount_root))
Packit 98cdb6
            {
Packit 98cdb6
              ret = TRUE;
Packit 98cdb6
              g_object_unref (volume_activation_root);
Packit 98cdb6
              break;
Packit 98cdb6
            }
Packit 98cdb6
          g_object_unref (volume_activation_root);
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  g_object_unref (mount_root);
Packit 98cdb6
  return ret;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
get_volumes_list (GtkFileSystem *file_system)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
  GList *l, *ll;
Packit 98cdb6
  GList *drives;
Packit 98cdb6
  GList *volumes;
Packit 98cdb6
  GList *mounts;
Packit 98cdb6
  GDrive *drive;
Packit 98cdb6
  GVolume *volume;
Packit 98cdb6
  GMount *mount;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
Packit 98cdb6
Packit 98cdb6
  if (priv->volumes)
Packit 98cdb6
    {
Packit 98cdb6
      g_slist_foreach (priv->volumes, (GFunc) g_object_unref, NULL);
Packit 98cdb6
      g_slist_free (priv->volumes);
Packit 98cdb6
      priv->volumes = NULL;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  /* first go through all connected drives */
Packit 98cdb6
  drives = g_volume_monitor_get_connected_drives (priv->volume_monitor);
Packit 98cdb6
Packit 98cdb6
  for (l = drives; l != NULL; l = l->next)
Packit 98cdb6
    {
Packit 98cdb6
      drive = l->data;
Packit 98cdb6
      volumes = g_drive_get_volumes (drive);
Packit 98cdb6
Packit 98cdb6
      if (volumes)
Packit 98cdb6
        {
Packit 98cdb6
          for (ll = volumes; ll != NULL; ll = ll->next)
Packit 98cdb6
            {
Packit 98cdb6
              volume = ll->data;
Packit 98cdb6
              mount = g_volume_get_mount (volume);
Packit 98cdb6
Packit 98cdb6
              if (mount)
Packit 98cdb6
                {
Packit 98cdb6
                  /* Show mounted volume */
Packit 98cdb6
                  priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (mount));
Packit 98cdb6
                  g_object_unref (mount);
Packit 98cdb6
                }
Packit 98cdb6
              else
Packit 98cdb6
                {
Packit 98cdb6
                  /* Do show the unmounted volumes in the sidebar;
Packit 98cdb6
                   * this is so the user can mount it (in case automounting
Packit 98cdb6
                   * is off).
Packit 98cdb6
                   *
Packit 98cdb6
                   * Also, even if automounting is enabled, this gives a visual
Packit 98cdb6
                   * cue that the user should remember to yank out the media if
Packit 98cdb6
                   * he just unmounted it.
Packit 98cdb6
                   */
Packit 98cdb6
                  priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (volume));
Packit 98cdb6
                }
Packit 98cdb6
Packit 98cdb6
	      g_object_unref (volume);
Packit 98cdb6
            }
Packit 98cdb6
  
Packit 98cdb6
           g_list_free (volumes);
Packit 98cdb6
        }
Packit 98cdb6
      else if (g_drive_is_media_removable (drive) && !g_drive_is_media_check_automatic (drive))
Packit 98cdb6
	{
Packit 98cdb6
	  /* If the drive has no mountable volumes and we cannot detect media change.. we
Packit 98cdb6
	   * display the drive in the sidebar so the user can manually poll the drive by
Packit 98cdb6
	   * right clicking and selecting "Rescan..."
Packit 98cdb6
	   *
Packit 98cdb6
	   * This is mainly for drives like floppies where media detection doesn't
Packit 98cdb6
	   * work.. but it's also for human beings who like to turn off media detection
Packit 98cdb6
	   * in the OS to save battery juice.
Packit 98cdb6
	   */
Packit 98cdb6
Packit 98cdb6
	  priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (drive));
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      g_object_unref (drive);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  g_list_free (drives);
Packit 98cdb6
Packit 98cdb6
  /* add all volumes that is not associated with a drive */
Packit 98cdb6
  volumes = g_volume_monitor_get_volumes (priv->volume_monitor);
Packit 98cdb6
Packit 98cdb6
  for (l = volumes; l != NULL; l = l->next)
Packit 98cdb6
    {
Packit 98cdb6
      volume = l->data;
Packit 98cdb6
      drive = g_volume_get_drive (volume);
Packit 98cdb6
Packit 98cdb6
      if (drive)
Packit 98cdb6
        {
Packit 98cdb6
          g_object_unref (drive);
Packit 98cdb6
          continue;
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
      mount = g_volume_get_mount (volume);
Packit 98cdb6
Packit 98cdb6
      if (mount)
Packit 98cdb6
        {
Packit 98cdb6
          /* show this mount */
Packit 98cdb6
          priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (mount));
Packit 98cdb6
          g_object_unref (mount);
Packit 98cdb6
        }
Packit 98cdb6
      else
Packit 98cdb6
        {
Packit 98cdb6
          /* see comment above in why we add an icon for a volume */
Packit 98cdb6
          priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (volume));
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
      g_object_unref (volume);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
Packit 98cdb6
  mounts = g_volume_monitor_get_mounts (priv->volume_monitor);
Packit 98cdb6
Packit 98cdb6
  for (l = mounts; l != NULL; l = l->next)
Packit 98cdb6
    {
Packit 98cdb6
      mount = l->data;
Packit 98cdb6
      volume = g_mount_get_volume (mount);
Packit 98cdb6
Packit 98cdb6
      if (volume)
Packit 98cdb6
        {
Packit 98cdb6
          g_object_unref (volume);
Packit 98cdb6
          continue;
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
      /* if there's exists one or more volumes with an activation root inside the mount,
Packit 98cdb6
       * don't display the mount
Packit 98cdb6
       */
Packit 98cdb6
      if (mount_referenced_by_volume_activation_root (volumes, mount))
Packit 98cdb6
        {
Packit 98cdb6
          g_object_unref (mount);
Packit 98cdb6
          continue;
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
      /* show this mount */
Packit 98cdb6
      priv->volumes = g_slist_prepend (priv->volumes, g_object_ref (mount));
Packit 98cdb6
      g_object_unref (mount);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  g_list_free (volumes);
Packit 98cdb6
Packit 98cdb6
  g_list_free (mounts);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
_gtk_file_system_init (GtkFileSystem *file_system)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
  GFile *bookmarks_file;
Packit 98cdb6
  GError *error = NULL;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("init");
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
Packit 98cdb6
Packit 98cdb6
  /* Volumes */
Packit 98cdb6
  priv->volume_monitor = g_volume_monitor_get ();
Packit 98cdb6
Packit 98cdb6
  g_signal_connect (priv->volume_monitor, "mount-added",
Packit 98cdb6
		    G_CALLBACK (volumes_changed), file_system);
Packit 98cdb6
  g_signal_connect (priv->volume_monitor, "mount-removed",
Packit 98cdb6
		    G_CALLBACK (volumes_changed), file_system);
Packit 98cdb6
  g_signal_connect (priv->volume_monitor, "mount-changed",
Packit 98cdb6
		    G_CALLBACK (volumes_changed), file_system);
Packit 98cdb6
  g_signal_connect (priv->volume_monitor, "volume-added",
Packit 98cdb6
		    G_CALLBACK (volumes_changed), file_system);
Packit 98cdb6
  g_signal_connect (priv->volume_monitor, "volume-removed",
Packit 98cdb6
		    G_CALLBACK (volumes_changed), file_system);
Packit 98cdb6
  g_signal_connect (priv->volume_monitor, "volume-changed",
Packit 98cdb6
		    G_CALLBACK (volumes_changed), file_system);
Packit 98cdb6
  g_signal_connect (priv->volume_monitor, "drive-connected",
Packit 98cdb6
		    G_CALLBACK (volumes_changed), file_system);
Packit 98cdb6
  g_signal_connect (priv->volume_monitor, "drive-disconnected",
Packit 98cdb6
		    G_CALLBACK (volumes_changed), file_system);
Packit 98cdb6
  g_signal_connect (priv->volume_monitor, "drive-changed",
Packit 98cdb6
		    G_CALLBACK (volumes_changed), file_system);
Packit 98cdb6
Packit 98cdb6
  /* Bookmarks */
Packit 98cdb6
  bookmarks_file = get_bookmarks_file ();
Packit 98cdb6
  priv->bookmarks = read_bookmarks (bookmarks_file);
Packit 98cdb6
  if (!priv->bookmarks)
Packit 98cdb6
    {
Packit 98cdb6
      /* Use the legacy file instead */
Packit 98cdb6
      g_object_unref (bookmarks_file);
Packit 98cdb6
      bookmarks_file = get_legacy_bookmarks_file ();
Packit 98cdb6
      priv->bookmarks = read_bookmarks (bookmarks_file);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  priv->bookmarks_monitor = g_file_monitor_file (bookmarks_file,
Packit 98cdb6
						 G_FILE_MONITOR_NONE,
Packit 98cdb6
						 NULL, &error);
Packit 98cdb6
  if (error)
Packit 98cdb6
    {
Packit 98cdb6
      g_warning ("%s", error->message);
Packit 98cdb6
      g_error_free (error);
Packit 98cdb6
    }
Packit 98cdb6
  else
Packit 98cdb6
    g_signal_connect (priv->bookmarks_monitor, "changed",
Packit 98cdb6
		      G_CALLBACK (bookmarks_file_changed), file_system);
Packit 98cdb6
Packit 98cdb6
  priv->bookmarks_file = g_object_ref (bookmarks_file);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/* GtkFileSystem public methods */
Packit 98cdb6
GtkFileSystem *
Packit 98cdb6
_gtk_file_system_new (void)
Packit 98cdb6
{
Packit 98cdb6
  return g_object_new (GTK_TYPE_FILE_SYSTEM, NULL);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GSList *
Packit 98cdb6
_gtk_file_system_list_volumes (GtkFileSystem *file_system)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
  GSList *list;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("list_volumes");
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
Packit 98cdb6
  get_volumes_list (GTK_FILE_SYSTEM (file_system));
Packit 98cdb6
Packit 98cdb6
  list = g_slist_copy (priv->volumes);
Packit 98cdb6
Packit 98cdb6
#ifndef G_OS_WIN32
Packit 98cdb6
  /* Prepend root volume */
Packit 98cdb6
  list = g_slist_prepend (list, (gpointer) root_volume_token);
Packit 98cdb6
#endif
Packit 98cdb6
Packit 98cdb6
  return list;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GSList *
Packit 98cdb6
_gtk_file_system_list_bookmarks (GtkFileSystem *file_system)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
  GSList *bookmarks, *files = NULL;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("list_bookmarks");
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
Packit 98cdb6
  bookmarks = priv->bookmarks;
Packit 98cdb6
Packit 98cdb6
  while (bookmarks)
Packit 98cdb6
    {
Packit 98cdb6
      GtkFileSystemBookmark *bookmark;
Packit 98cdb6
Packit 98cdb6
      bookmark = bookmarks->data;
Packit 98cdb6
      bookmarks = bookmarks->next;
Packit 98cdb6
Packit 98cdb6
      files = g_slist_prepend (files, g_object_ref (bookmark->file));
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return g_slist_reverse (files);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
free_async_data (AsyncFuncData *async_data)
Packit 98cdb6
{
Packit 98cdb6
  g_object_unref (async_data->file_system);
Packit 98cdb6
  g_object_unref (async_data->file);
Packit 98cdb6
  g_object_unref (async_data->cancellable);
Packit 98cdb6
Packit 98cdb6
  g_free (async_data->attributes);
Packit 98cdb6
  g_free (async_data);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
query_info_callback (GObject      *source_object,
Packit 98cdb6
		     GAsyncResult *result,
Packit 98cdb6
		     gpointer      user_data)
Packit 98cdb6
{
Packit 98cdb6
  AsyncFuncData *async_data;
Packit 98cdb6
  GError *error = NULL;
Packit 98cdb6
  GFileInfo *file_info;
Packit 98cdb6
  GFile *file;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("query_info_callback");
Packit 98cdb6
Packit 98cdb6
  file = G_FILE (source_object);
Packit 98cdb6
  async_data = (AsyncFuncData *) user_data;
Packit 98cdb6
  file_info = g_file_query_info_finish (file, result, &error);
Packit 98cdb6
Packit 98cdb6
  if (async_data->callback)
Packit 98cdb6
    {
Packit 98cdb6
      gdk_threads_enter ();
Packit 98cdb6
      ((GtkFileSystemGetInfoCallback) async_data->callback) (async_data->cancellable,
Packit 98cdb6
							     file_info, error, async_data->data);
Packit 98cdb6
      gdk_threads_leave ();
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (file_info)
Packit 98cdb6
    g_object_unref (file_info);
Packit 98cdb6
Packit 98cdb6
  if (error)
Packit 98cdb6
    g_error_free (error);
Packit 98cdb6
Packit 98cdb6
  free_async_data (async_data);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GCancellable *
Packit 98cdb6
_gtk_file_system_get_info (GtkFileSystem                *file_system,
Packit 98cdb6
			   GFile                        *file,
Packit 98cdb6
			   const gchar                  *attributes,
Packit 98cdb6
			   GtkFileSystemGetInfoCallback  callback,
Packit 98cdb6
			   gpointer                      data)
Packit 98cdb6
{
Packit 98cdb6
  GCancellable *cancellable;
Packit 98cdb6
  AsyncFuncData *async_data;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
Packit 98cdb6
  g_return_val_if_fail (G_IS_FILE (file), NULL);
Packit 98cdb6
Packit 98cdb6
  cancellable = g_cancellable_new ();
Packit 98cdb6
Packit 98cdb6
  async_data = g_new0 (AsyncFuncData, 1);
Packit 98cdb6
  async_data->file_system = g_object_ref (file_system);
Packit 98cdb6
  async_data->file = g_object_ref (file);
Packit 98cdb6
  async_data->cancellable = g_object_ref (cancellable);
Packit 98cdb6
Packit 98cdb6
  async_data->callback = callback;
Packit 98cdb6
  async_data->data = data;
Packit 98cdb6
Packit 98cdb6
  g_file_query_info_async (file,
Packit 98cdb6
			   attributes,
Packit 98cdb6
			   G_FILE_QUERY_INFO_NONE,
Packit 98cdb6
			   G_PRIORITY_DEFAULT,
Packit 98cdb6
			   cancellable,
Packit 98cdb6
			   query_info_callback,
Packit 98cdb6
			   async_data);
Packit 98cdb6
Packit 98cdb6
  return cancellable;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
drive_poll_for_media_cb (GObject      *source_object,
Packit 98cdb6
                         GAsyncResult *result,
Packit 98cdb6
                         gpointer      user_data)
Packit 98cdb6
{
Packit 98cdb6
  AsyncFuncData *async_data;
Packit 98cdb6
  GError *error = NULL;
Packit 98cdb6
Packit 98cdb6
  g_drive_poll_for_media_finish (G_DRIVE (source_object), result, &error);
Packit 98cdb6
  async_data = (AsyncFuncData *) user_data;
Packit 98cdb6
Packit 98cdb6
  gdk_threads_enter ();
Packit 98cdb6
  ((GtkFileSystemVolumeMountCallback) async_data->callback) (async_data->cancellable,
Packit 98cdb6
							     (GtkFileSystemVolume *) source_object,
Packit 98cdb6
							     error, async_data->data);
Packit 98cdb6
  gdk_threads_leave ();
Packit 98cdb6
Packit 98cdb6
  if (error)
Packit 98cdb6
    g_error_free (error);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
volume_mount_cb (GObject      *source_object,
Packit 98cdb6
		 GAsyncResult *result,
Packit 98cdb6
		 gpointer      user_data)
Packit 98cdb6
{
Packit 98cdb6
  AsyncFuncData *async_data;
Packit 98cdb6
  GError *error = NULL;
Packit 98cdb6
Packit 98cdb6
  g_volume_mount_finish (G_VOLUME (source_object), result, &error);
Packit 98cdb6
  async_data = (AsyncFuncData *) user_data;
Packit 98cdb6
Packit 98cdb6
  gdk_threads_enter ();
Packit 98cdb6
  ((GtkFileSystemVolumeMountCallback) async_data->callback) (async_data->cancellable,
Packit 98cdb6
							     (GtkFileSystemVolume *) source_object,
Packit 98cdb6
							     error, async_data->data);
Packit 98cdb6
  gdk_threads_leave ();
Packit 98cdb6
Packit 98cdb6
  if (error)
Packit 98cdb6
    g_error_free (error);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GCancellable *
Packit 98cdb6
_gtk_file_system_mount_volume (GtkFileSystem                    *file_system,
Packit 98cdb6
			       GtkFileSystemVolume              *volume,
Packit 98cdb6
			       GMountOperation                  *mount_operation,
Packit 98cdb6
			       GtkFileSystemVolumeMountCallback  callback,
Packit 98cdb6
			       gpointer                          data)
Packit 98cdb6
{
Packit 98cdb6
  GCancellable *cancellable;
Packit 98cdb6
  AsyncFuncData *async_data;
Packit 98cdb6
  gboolean handled = FALSE;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("volume_mount");
Packit 98cdb6
Packit 98cdb6
  cancellable = g_cancellable_new ();
Packit 98cdb6
Packit 98cdb6
  async_data = g_new0 (AsyncFuncData, 1);
Packit 98cdb6
  async_data->file_system = g_object_ref (file_system);
Packit 98cdb6
  async_data->cancellable = g_object_ref (cancellable);
Packit 98cdb6
Packit 98cdb6
  async_data->callback = callback;
Packit 98cdb6
  async_data->data = data;
Packit 98cdb6
Packit 98cdb6
  if (G_IS_DRIVE (volume))
Packit 98cdb6
    {
Packit 98cdb6
      /* this path happens for drives that are not polled by the OS and where the last media
Packit 98cdb6
       * check indicated that no media was available. So the thing to do here is to
Packit 98cdb6
       * invoke poll_for_media() on the drive
Packit 98cdb6
       */
Packit 98cdb6
      g_drive_poll_for_media (G_DRIVE (volume), cancellable, drive_poll_for_media_cb, async_data);
Packit 98cdb6
      handled = TRUE;
Packit 98cdb6
    }
Packit 98cdb6
  else if (G_IS_VOLUME (volume))
Packit 98cdb6
    {
Packit 98cdb6
      g_volume_mount (G_VOLUME (volume), G_MOUNT_MOUNT_NONE, mount_operation, cancellable, volume_mount_cb, async_data);
Packit 98cdb6
      handled = TRUE;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (!handled)
Packit 98cdb6
    free_async_data (async_data);
Packit 98cdb6
Packit 98cdb6
  return cancellable;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
enclosing_volume_mount_cb (GObject      *source_object,
Packit 98cdb6
			   GAsyncResult *result,
Packit 98cdb6
			   gpointer      user_data)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemVolume *volume;
Packit 98cdb6
  AsyncFuncData *async_data;
Packit 98cdb6
  GError *error = NULL;
Packit 98cdb6
Packit 98cdb6
  async_data = (AsyncFuncData *) user_data;
Packit 98cdb6
  g_file_mount_enclosing_volume_finish (G_FILE (source_object), result, &error);
Packit 98cdb6
  volume = _gtk_file_system_get_volume_for_file (async_data->file_system, G_FILE (source_object));
Packit 98cdb6
Packit 98cdb6
  /* Silently drop G_IO_ERROR_ALREADY_MOUNTED error for gvfs backends without visible mounts. */
Packit 98cdb6
  /* Better than doing query_info with additional I/O every time. */
Packit 98cdb6
  if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_ALREADY_MOUNTED))
Packit 98cdb6
    g_clear_error (&error);
Packit 98cdb6
Packit 98cdb6
  gdk_threads_enter ();
Packit 98cdb6
  ((GtkFileSystemVolumeMountCallback) async_data->callback) (async_data->cancellable, volume,
Packit 98cdb6
							     error, async_data->data);
Packit 98cdb6
  gdk_threads_leave ();
Packit 98cdb6
Packit 98cdb6
  if (error)
Packit 98cdb6
    g_error_free (error);
Packit 98cdb6
Packit 98cdb6
  _gtk_file_system_volume_unref (volume);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GCancellable *
Packit 98cdb6
_gtk_file_system_mount_enclosing_volume (GtkFileSystem                     *file_system,
Packit 98cdb6
					 GFile                             *file,
Packit 98cdb6
					 GMountOperation                   *mount_operation,
Packit 98cdb6
					 GtkFileSystemVolumeMountCallback   callback,
Packit 98cdb6
					 gpointer                           data)
Packit 98cdb6
{
Packit 98cdb6
  GCancellable *cancellable;
Packit 98cdb6
  AsyncFuncData *async_data;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
Packit 98cdb6
  g_return_val_if_fail (G_IS_FILE (file), NULL);
Packit 98cdb6
Packit 98cdb6
  DEBUG ("mount_enclosing_volume");
Packit 98cdb6
Packit 98cdb6
  cancellable = g_cancellable_new ();
Packit 98cdb6
Packit 98cdb6
  async_data = g_new0 (AsyncFuncData, 1);
Packit 98cdb6
  async_data->file_system = g_object_ref (file_system);
Packit 98cdb6
  async_data->file = g_object_ref (file);
Packit 98cdb6
  async_data->cancellable = g_object_ref (cancellable);
Packit 98cdb6
Packit 98cdb6
  async_data->callback = callback;
Packit 98cdb6
  async_data->data = data;
Packit 98cdb6
Packit 98cdb6
  g_file_mount_enclosing_volume (file,
Packit 98cdb6
				 G_MOUNT_MOUNT_NONE,
Packit 98cdb6
				 mount_operation,
Packit 98cdb6
				 cancellable,
Packit 98cdb6
				 enclosing_volume_mount_cb,
Packit 98cdb6
				 async_data);
Packit 98cdb6
  return cancellable;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
gboolean
Packit 98cdb6
_gtk_file_system_insert_bookmark (GtkFileSystem  *file_system,
Packit 98cdb6
				  GFile          *file,
Packit 98cdb6
				  gint            position,
Packit 98cdb6
				  GError        **error)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
  GSList *bookmarks;
Packit 98cdb6
  GtkFileSystemBookmark *bookmark;
Packit 98cdb6
  gboolean result = TRUE;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
Packit 98cdb6
  bookmarks = priv->bookmarks;
Packit 98cdb6
Packit 98cdb6
  while (bookmarks)
Packit 98cdb6
    {
Packit 98cdb6
      bookmark = bookmarks->data;
Packit 98cdb6
      bookmarks = bookmarks->next;
Packit 98cdb6
Packit 98cdb6
      if (g_file_equal (bookmark->file, file))
Packit 98cdb6
	{
Packit 98cdb6
	  /* File is already in bookmarks */
Packit 98cdb6
	  result = FALSE;
Packit 98cdb6
	  break;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (!result)
Packit 98cdb6
    {
Packit 98cdb6
      gchar *uri = g_file_get_uri (file);
Packit 98cdb6
Packit 98cdb6
      g_set_error (error,
Packit 98cdb6
		   GTK_FILE_CHOOSER_ERROR,
Packit 98cdb6
		   GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
Packit 98cdb6
		   "%s already exists in the bookmarks list",
Packit 98cdb6
		   uri);
Packit 98cdb6
Packit 98cdb6
      g_free (uri);
Packit 98cdb6
Packit 98cdb6
      return FALSE;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  bookmark = g_slice_new0 (GtkFileSystemBookmark);
Packit 98cdb6
  bookmark->file = g_object_ref (file);
Packit 98cdb6
Packit 98cdb6
  priv->bookmarks = g_slist_insert (priv->bookmarks, bookmark, position);
Packit 98cdb6
  save_bookmarks (priv->bookmarks_file, priv->bookmarks);
Packit 98cdb6
Packit 98cdb6
  g_signal_emit (file_system, fs_signals[BOOKMARKS_CHANGED], 0);
Packit 98cdb6
Packit 98cdb6
  return TRUE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
gboolean
Packit 98cdb6
_gtk_file_system_remove_bookmark (GtkFileSystem  *file_system,
Packit 98cdb6
				  GFile          *file,
Packit 98cdb6
				  GError        **error)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
  GtkFileSystemBookmark *bookmark;
Packit 98cdb6
  GSList *bookmarks;
Packit 98cdb6
  gboolean result = FALSE;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
Packit 98cdb6
Packit 98cdb6
  if (!priv->bookmarks)
Packit 98cdb6
    return FALSE;
Packit 98cdb6
Packit 98cdb6
  bookmarks = priv->bookmarks;
Packit 98cdb6
Packit 98cdb6
  while (bookmarks)
Packit 98cdb6
    {
Packit 98cdb6
      bookmark = bookmarks->data;
Packit 98cdb6
Packit 98cdb6
      if (g_file_equal (bookmark->file, file))
Packit 98cdb6
	{
Packit 98cdb6
	  result = TRUE;
Packit 98cdb6
	  priv->bookmarks = g_slist_remove_link (priv->bookmarks, bookmarks);
Packit 98cdb6
	  _gtk_file_system_bookmark_free (bookmark);
Packit 98cdb6
	  g_slist_free_1 (bookmarks);
Packit 98cdb6
	  break;
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      bookmarks = bookmarks->next;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (!result)
Packit 98cdb6
    {
Packit 98cdb6
      gchar *uri = g_file_get_uri (file);
Packit 98cdb6
Packit 98cdb6
      g_set_error (error,
Packit 98cdb6
		   GTK_FILE_CHOOSER_ERROR,
Packit 98cdb6
		   GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
Packit 98cdb6
		   "%s does not exist in the bookmarks list",
Packit 98cdb6
		   uri);
Packit 98cdb6
Packit 98cdb6
      g_free (uri);
Packit 98cdb6
Packit 98cdb6
      return FALSE;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  save_bookmarks (priv->bookmarks_file, priv->bookmarks);
Packit 98cdb6
Packit 98cdb6
  g_signal_emit (file_system, fs_signals[BOOKMARKS_CHANGED], 0);
Packit 98cdb6
Packit 98cdb6
  return TRUE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
gchar *
Packit 98cdb6
_gtk_file_system_get_bookmark_label (GtkFileSystem *file_system,
Packit 98cdb6
				     GFile         *file)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
  GSList *bookmarks;
Packit 98cdb6
  gchar *label = NULL;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("get_bookmark_label");
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
Packit 98cdb6
  bookmarks = priv->bookmarks;
Packit 98cdb6
Packit 98cdb6
  while (bookmarks)
Packit 98cdb6
    {
Packit 98cdb6
      GtkFileSystemBookmark *bookmark;
Packit 98cdb6
Packit 98cdb6
      bookmark = bookmarks->data;
Packit 98cdb6
      bookmarks = bookmarks->next;
Packit 98cdb6
Packit 98cdb6
      if (g_file_equal (file, bookmark->file))
Packit 98cdb6
	{
Packit 98cdb6
	  label = g_strdup (bookmark->label);
Packit 98cdb6
	  break;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return label;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
void
Packit 98cdb6
_gtk_file_system_set_bookmark_label (GtkFileSystem *file_system,
Packit 98cdb6
				     GFile         *file,
Packit 98cdb6
				     const gchar   *label)
Packit 98cdb6
{
Packit 98cdb6
  GtkFileSystemPrivate *priv;
Packit 98cdb6
  gboolean changed = FALSE;
Packit 98cdb6
  GSList *bookmarks;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("set_bookmark_label");
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FILE_SYSTEM_GET_PRIVATE (file_system);
Packit 98cdb6
  bookmarks = priv->bookmarks;
Packit 98cdb6
Packit 98cdb6
  while (bookmarks)
Packit 98cdb6
    {
Packit 98cdb6
      GtkFileSystemBookmark *bookmark;
Packit 98cdb6
Packit 98cdb6
      bookmark = bookmarks->data;
Packit 98cdb6
      bookmarks = bookmarks->next;
Packit 98cdb6
Packit 98cdb6
      if (g_file_equal (file, bookmark->file))
Packit 98cdb6
	{
Packit 98cdb6
          g_free (bookmark->label);
Packit 98cdb6
	  bookmark->label = g_strdup (label);
Packit 98cdb6
	  changed = TRUE;
Packit 98cdb6
	  break;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  save_bookmarks (priv->bookmarks_file, priv->bookmarks);
Packit 98cdb6
Packit 98cdb6
  if (changed)
Packit 98cdb6
    g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GtkFileSystemVolume *
Packit 98cdb6
_gtk_file_system_get_volume_for_file (GtkFileSystem *file_system,
Packit 98cdb6
				      GFile         *file)
Packit 98cdb6
{
Packit 98cdb6
  GMount *mount;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("get_volume_for_file");
Packit 98cdb6
Packit 98cdb6
  mount = g_file_find_enclosing_mount (file, NULL, NULL);
Packit 98cdb6
Packit 98cdb6
  if (!mount && g_file_is_native (file))
Packit 98cdb6
    return (GtkFileSystemVolume *) root_volume_token;
Packit 98cdb6
Packit 98cdb6
  return (GtkFileSystemVolume *) mount;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/* GtkFolder methods */
Packit 98cdb6
static void
Packit 98cdb6
gtk_folder_set_property (GObject      *object,
Packit 98cdb6
			 guint         prop_id,
Packit 98cdb6
			 const GValue *value,
Packit 98cdb6
			 GParamSpec   *pspec)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (object);
Packit 98cdb6
Packit 98cdb6
  switch (prop_id)
Packit 98cdb6
    {
Packit 98cdb6
    case PROP_FILE:
Packit 98cdb6
      priv->folder_file = g_value_dup_object (value);
Packit 98cdb6
      break;
Packit 98cdb6
    case PROP_ENUMERATOR:
Packit 98cdb6
      priv->enumerator = g_value_dup_object (value);
Packit 98cdb6
      break;
Packit 98cdb6
    case PROP_ATTRIBUTES:
Packit 98cdb6
      priv->attributes = g_value_dup_string (value);
Packit 98cdb6
      break;
Packit 98cdb6
    default:
Packit 98cdb6
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 98cdb6
      break;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
gtk_folder_get_property (GObject    *object,
Packit 98cdb6
			 guint       prop_id,
Packit 98cdb6
			 GValue     *value,
Packit 98cdb6
			 GParamSpec *pspec)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (object);
Packit 98cdb6
Packit 98cdb6
  switch (prop_id)
Packit 98cdb6
    {
Packit 98cdb6
    case PROP_FILE:
Packit 98cdb6
      g_value_set_object (value, priv->folder_file);
Packit 98cdb6
      break;
Packit 98cdb6
    case PROP_ENUMERATOR:
Packit 98cdb6
      g_value_set_object (value, priv->enumerator);
Packit 98cdb6
      break;
Packit 98cdb6
    case PROP_ATTRIBUTES:
Packit 98cdb6
      g_value_set_string (value, priv->attributes);
Packit 98cdb6
      break;
Packit 98cdb6
    default:
Packit 98cdb6
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 98cdb6
      break;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
query_created_file_info_callback (GObject      *source_object,
Packit 98cdb6
				  GAsyncResult *result,
Packit 98cdb6
				  gpointer      user_data)
Packit 98cdb6
{
Packit 98cdb6
  GFile *file = G_FILE (source_object);
Packit 98cdb6
  GError *error = NULL;
Packit 98cdb6
  GFileInfo *info;
Packit 98cdb6
  GtkFolder *folder;
Packit 98cdb6
  GSList *files;
Packit 98cdb6
Packit 98cdb6
  info = g_file_query_info_finish (file, result, &error);
Packit 98cdb6
Packit 98cdb6
  if (error)
Packit 98cdb6
    {
Packit 98cdb6
      g_error_free (error);
Packit 98cdb6
      return;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  gdk_threads_enter ();
Packit 98cdb6
Packit 98cdb6
  folder = GTK_FOLDER (user_data);
Packit 98cdb6
  gtk_folder_add_file (folder, file, info);
Packit 98cdb6
Packit 98cdb6
  files = g_slist_prepend (NULL, file);
Packit 98cdb6
  g_signal_emit (folder, folder_signals[FILES_ADDED], 0, files);
Packit 98cdb6
  g_slist_free (files);
Packit 98cdb6
Packit 98cdb6
  g_object_unref (info);
Packit 98cdb6
  gdk_threads_leave ();
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
directory_monitor_changed (GFileMonitor      *monitor,
Packit 98cdb6
			   GFile             *file,
Packit 98cdb6
			   GFile             *other_file,
Packit 98cdb6
			   GFileMonitorEvent  event,
Packit 98cdb6
			   gpointer           data)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
  GtkFolder *folder;
Packit 98cdb6
  GSList *files;
Packit 98cdb6
Packit 98cdb6
  folder = GTK_FOLDER (data);
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (folder);
Packit 98cdb6
  files = g_slist_prepend (NULL, file);
Packit 98cdb6
Packit 98cdb6
  gdk_threads_enter ();
Packit 98cdb6
Packit 98cdb6
  switch (event)
Packit 98cdb6
    {
Packit 98cdb6
    case G_FILE_MONITOR_EVENT_CREATED:
Packit 98cdb6
      g_file_query_info_async (file,
Packit 98cdb6
			       priv->attributes,
Packit 98cdb6
			       G_FILE_QUERY_INFO_NONE,
Packit 98cdb6
			       G_PRIORITY_DEFAULT,
Packit 98cdb6
			       priv->cancellable,
Packit 98cdb6
			       query_created_file_info_callback,
Packit 98cdb6
			       folder);
Packit 98cdb6
      break;
Packit 98cdb6
    case G_FILE_MONITOR_EVENT_DELETED:
Packit 98cdb6
      if (g_file_equal (file, priv->folder_file))
Packit 98cdb6
	g_signal_emit (folder, folder_signals[DELETED], 0);
Packit 98cdb6
      else
Packit 98cdb6
	g_signal_emit (folder, folder_signals[FILES_REMOVED], 0, files);
Packit 98cdb6
      break;
Packit 98cdb6
    default:
Packit 98cdb6
      break;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  gdk_threads_leave ();
Packit 98cdb6
Packit 98cdb6
  g_slist_free (files);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
enumerator_files_callback (GObject      *source_object,
Packit 98cdb6
			   GAsyncResult *result,
Packit 98cdb6
			   gpointer      user_data)
Packit 98cdb6
{
Packit 98cdb6
  GFileEnumerator *enumerator;
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
  GtkFolder *folder;
Packit 98cdb6
  GError *error = NULL;
Packit 98cdb6
  GSList *files = NULL;
Packit 98cdb6
  GList *file_infos, *f;
Packit 98cdb6
Packit 98cdb6
  enumerator = G_FILE_ENUMERATOR (source_object);
Packit 98cdb6
  file_infos = g_file_enumerator_next_files_finish (enumerator, result, &error);
Packit 98cdb6
Packit 98cdb6
  if (error)
Packit 98cdb6
    {
Packit 98cdb6
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
Packit 98cdb6
        g_warning ("%s", error->message);
Packit 98cdb6
Packit 98cdb6
      g_error_free (error);
Packit 98cdb6
      return;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  folder = GTK_FOLDER (user_data);
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (folder);
Packit 98cdb6
Packit 98cdb6
  if (!file_infos)
Packit 98cdb6
    {
Packit 98cdb6
      g_file_enumerator_close_async (enumerator,
Packit 98cdb6
				     G_PRIORITY_DEFAULT,
Packit 98cdb6
				     NULL, NULL, NULL);
Packit 98cdb6
Packit 98cdb6
      gtk_folder_set_finished_loading (folder, TRUE);
Packit 98cdb6
      return;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  g_file_enumerator_next_files_async (enumerator, FILES_PER_QUERY,
Packit 98cdb6
				      G_PRIORITY_DEFAULT,
Packit 98cdb6
				      priv->cancellable,
Packit 98cdb6
				      enumerator_files_callback,
Packit 98cdb6
				      folder);
Packit 98cdb6
Packit 98cdb6
  for (f = file_infos; f; f = f->next)
Packit 98cdb6
    {
Packit 98cdb6
      GFileInfo *info;
Packit 98cdb6
      GFile *child_file;
Packit 98cdb6
Packit 98cdb6
      info = f->data;
Packit 98cdb6
      child_file = g_file_get_child (priv->folder_file, g_file_info_get_name (info));
Packit 98cdb6
      gtk_folder_add_file (folder, child_file, info);
Packit 98cdb6
      files = g_slist_prepend (files, child_file);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  gdk_threads_enter ();
Packit 98cdb6
  g_signal_emit (folder, folder_signals[FILES_ADDED], 0, files);
Packit 98cdb6
  gdk_threads_leave ();
Packit 98cdb6
Packit 98cdb6
  g_list_foreach (file_infos, (GFunc) g_object_unref, NULL);
Packit 98cdb6
  g_list_free (file_infos);
Packit 98cdb6
Packit 98cdb6
  g_slist_foreach (files, (GFunc) g_object_unref, NULL);
Packit 98cdb6
  g_slist_free (files);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
gtk_folder_constructed (GObject *object)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
  GError *error = NULL;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (object);
Packit 98cdb6
  priv->directory_monitor = g_file_monitor_directory (priv->folder_file, G_FILE_MONITOR_NONE, NULL, &error);
Packit 98cdb6
Packit 98cdb6
  if (error)
Packit 98cdb6
    {
Packit 98cdb6
      g_warning ("%s", error->message);
Packit 98cdb6
      g_error_free (error);
Packit 98cdb6
    }
Packit 98cdb6
  else
Packit 98cdb6
    g_signal_connect (priv->directory_monitor, "changed",
Packit 98cdb6
		      G_CALLBACK (directory_monitor_changed), object);
Packit 98cdb6
Packit 98cdb6
  g_file_enumerator_next_files_async (priv->enumerator,
Packit 98cdb6
				      FILES_PER_QUERY,
Packit 98cdb6
				      G_PRIORITY_DEFAULT,
Packit 98cdb6
				      priv->cancellable,
Packit 98cdb6
				      enumerator_files_callback,
Packit 98cdb6
				      object);
Packit 98cdb6
  /* This isn't needed anymore */
Packit 98cdb6
  g_object_unref (priv->enumerator);
Packit 98cdb6
  priv->enumerator = NULL;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
gtk_folder_finalize (GObject *object)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (object);
Packit 98cdb6
Packit 98cdb6
  g_hash_table_unref (priv->children);
Packit 98cdb6
Packit 98cdb6
  if (priv->folder_file)
Packit 98cdb6
    g_object_unref (priv->folder_file);
Packit 98cdb6
Packit 98cdb6
  if (priv->directory_monitor)
Packit 98cdb6
    g_object_unref (priv->directory_monitor);
Packit 98cdb6
Packit 98cdb6
  g_cancellable_cancel (priv->cancellable);
Packit 98cdb6
  g_object_unref (priv->cancellable);
Packit 98cdb6
  g_free (priv->attributes);
Packit 98cdb6
Packit 98cdb6
  G_OBJECT_CLASS (_gtk_folder_parent_class)->finalize (object);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
_gtk_folder_class_init (GtkFolderClass *class)
Packit 98cdb6
{
Packit 98cdb6
  GObjectClass *object_class = G_OBJECT_CLASS (class);
Packit 98cdb6
Packit 98cdb6
  object_class->set_property = gtk_folder_set_property;
Packit 98cdb6
  object_class->get_property = gtk_folder_get_property;
Packit 98cdb6
  object_class->constructed = gtk_folder_constructed;
Packit 98cdb6
  object_class->finalize = gtk_folder_finalize;
Packit 98cdb6
Packit 98cdb6
  g_object_class_install_property (object_class,
Packit 98cdb6
				   PROP_FILE,
Packit 98cdb6
				   g_param_spec_object ("file",
Packit 98cdb6
							"File",
Packit 98cdb6
							"GFile for the folder",
Packit 98cdb6
							G_TYPE_FILE,
Packit 98cdb6
							GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit 98cdb6
  g_object_class_install_property (object_class,
Packit 98cdb6
				   PROP_ENUMERATOR,
Packit 98cdb6
				   g_param_spec_object ("enumerator",
Packit 98cdb6
							"Enumerator",
Packit 98cdb6
							"GFileEnumerator to list files",
Packit 98cdb6
							G_TYPE_FILE_ENUMERATOR,
Packit 98cdb6
							GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit 98cdb6
  g_object_class_install_property (object_class,
Packit 98cdb6
				   PROP_ATTRIBUTES,
Packit 98cdb6
				   g_param_spec_string ("attributes",
Packit 98cdb6
							"Attributes",
Packit 98cdb6
							"Attributes to query for",
Packit 98cdb6
							NULL,
Packit 98cdb6
							GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit 98cdb6
  folder_signals[FILES_ADDED] =
Packit 98cdb6
    g_signal_new ("files-added",
Packit 98cdb6
		  G_TYPE_FROM_CLASS (object_class),
Packit 98cdb6
		  G_SIGNAL_RUN_LAST,
Packit 98cdb6
		  G_STRUCT_OFFSET (GtkFolderClass, files_added),
Packit 98cdb6
		  NULL, NULL,
Packit 98cdb6
		  g_cclosure_marshal_VOID__POINTER,
Packit 98cdb6
		  G_TYPE_NONE, 1, G_TYPE_POINTER);
Packit 98cdb6
  folder_signals[FILES_REMOVED] =
Packit 98cdb6
    g_signal_new ("files-removed",
Packit 98cdb6
		  G_TYPE_FROM_CLASS (object_class),
Packit 98cdb6
		  G_SIGNAL_RUN_LAST,
Packit 98cdb6
		  G_STRUCT_OFFSET (GtkFolderClass, files_removed),
Packit 98cdb6
		  NULL, NULL,
Packit 98cdb6
		  g_cclosure_marshal_VOID__POINTER,
Packit 98cdb6
		  G_TYPE_NONE, 1, G_TYPE_POINTER);
Packit 98cdb6
  folder_signals[FILES_CHANGED] =
Packit 98cdb6
    g_signal_new ("files-changed",
Packit 98cdb6
		  G_TYPE_FROM_CLASS (object_class),
Packit 98cdb6
		  G_SIGNAL_RUN_LAST,
Packit 98cdb6
		  G_STRUCT_OFFSET (GtkFolderClass, files_changed),
Packit 98cdb6
		  NULL, NULL,
Packit 98cdb6
		  g_cclosure_marshal_VOID__POINTER,
Packit 98cdb6
		  G_TYPE_NONE, 1, G_TYPE_POINTER);
Packit 98cdb6
  folder_signals[FINISHED_LOADING] =
Packit 98cdb6
    g_signal_new ("finished-loading",
Packit 98cdb6
		  G_TYPE_FROM_CLASS (object_class),
Packit 98cdb6
		  G_SIGNAL_RUN_LAST,
Packit 98cdb6
		  G_STRUCT_OFFSET (GtkFolderClass, finished_loading),
Packit 98cdb6
		  NULL, NULL,
Packit 98cdb6
		  g_cclosure_marshal_VOID__VOID,
Packit 98cdb6
		  G_TYPE_NONE, 0);
Packit 98cdb6
  folder_signals[DELETED] =
Packit 98cdb6
    g_signal_new ("deleted",
Packit 98cdb6
		  G_TYPE_FROM_CLASS (object_class),
Packit 98cdb6
		  G_SIGNAL_RUN_LAST,
Packit 98cdb6
		  G_STRUCT_OFFSET (GtkFolderClass, deleted),
Packit 98cdb6
		  NULL, NULL,
Packit 98cdb6
		  g_cclosure_marshal_VOID__VOID,
Packit 98cdb6
		  G_TYPE_NONE, 0);
Packit 98cdb6
Packit 98cdb6
  g_type_class_add_private (object_class, sizeof (GtkFolderPrivate));
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
_gtk_folder_init (GtkFolder *folder)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (folder);
Packit 98cdb6
Packit 98cdb6
  priv->children = g_hash_table_new_full (g_file_hash,
Packit 98cdb6
					  (GEqualFunc) g_file_equal,
Packit 98cdb6
					  (GDestroyNotify) g_object_unref,
Packit 98cdb6
					  (GDestroyNotify) g_object_unref);
Packit 98cdb6
  priv->cancellable = g_cancellable_new ();
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
gtk_folder_set_finished_loading (GtkFolder *folder,
Packit 98cdb6
				 gboolean   finished_loading)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (folder);
Packit 98cdb6
  priv->finished_loading = (finished_loading == TRUE);
Packit 98cdb6
Packit 98cdb6
  gdk_threads_enter ();
Packit 98cdb6
  g_signal_emit (folder, folder_signals[FINISHED_LOADING], 0);
Packit 98cdb6
  gdk_threads_leave ();
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
gtk_folder_add_file (GtkFolder *folder,
Packit 98cdb6
		     GFile     *file,
Packit 98cdb6
		     GFileInfo *info)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (folder);
Packit 98cdb6
Packit 98cdb6
  g_hash_table_insert (priv->children,
Packit 98cdb6
		       g_object_ref (file),
Packit 98cdb6
		       g_object_ref (info));
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GSList *
Packit 98cdb6
_gtk_folder_list_children (GtkFolder *folder)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
  GList *files, *elem;
Packit 98cdb6
  GSList *children = NULL;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (folder);
Packit 98cdb6
  files = g_hash_table_get_keys (priv->children);
Packit 98cdb6
  children = NULL;
Packit 98cdb6
Packit 98cdb6
  for (elem = files; elem; elem = elem->next)
Packit 98cdb6
    children = g_slist_prepend (children, g_object_ref (elem->data));
Packit 98cdb6
Packit 98cdb6
  g_list_free (files);
Packit 98cdb6
Packit 98cdb6
  return children;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GFileInfo *
Packit 98cdb6
_gtk_folder_get_info (GtkFolder  *folder,
Packit 98cdb6
		      GFile      *file)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
  GFileInfo *info;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (folder);
Packit 98cdb6
  info = g_hash_table_lookup (priv->children, file);
Packit 98cdb6
Packit 98cdb6
  if (!info)
Packit 98cdb6
    return NULL;
Packit 98cdb6
Packit 98cdb6
  return g_object_ref (info);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
gboolean
Packit 98cdb6
_gtk_folder_is_finished_loading (GtkFolder *folder)
Packit 98cdb6
{
Packit 98cdb6
  GtkFolderPrivate *priv;
Packit 98cdb6
Packit 98cdb6
  priv = GTK_FOLDER_GET_PRIVATE (folder);
Packit 98cdb6
Packit 98cdb6
  return priv->finished_loading;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/* GtkFileSystemVolume public methods */
Packit 98cdb6
gchar *
Packit 98cdb6
_gtk_file_system_volume_get_display_name (GtkFileSystemVolume *volume)
Packit 98cdb6
{
Packit 98cdb6
  DEBUG ("volume_get_display_name");
Packit 98cdb6
Packit 98cdb6
  if (IS_ROOT_VOLUME (volume))
Packit 98cdb6
    return g_strdup (_(root_volume_token));
Packit 98cdb6
  if (G_IS_DRIVE (volume))
Packit 98cdb6
    return g_drive_get_name (G_DRIVE (volume));
Packit 98cdb6
  else if (G_IS_MOUNT (volume))
Packit 98cdb6
    return g_mount_get_name (G_MOUNT (volume));
Packit 98cdb6
  else if (G_IS_VOLUME (volume))
Packit 98cdb6
    return g_volume_get_name (G_VOLUME (volume));
Packit 98cdb6
Packit 98cdb6
  return NULL;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
gboolean
Packit 98cdb6
_gtk_file_system_volume_is_mounted (GtkFileSystemVolume *volume)
Packit 98cdb6
{
Packit 98cdb6
  gboolean mounted;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("volume_is_mounted");
Packit 98cdb6
Packit 98cdb6
  if (IS_ROOT_VOLUME (volume))
Packit 98cdb6
    return TRUE;
Packit 98cdb6
Packit 98cdb6
  mounted = FALSE;
Packit 98cdb6
Packit 98cdb6
  if (G_IS_MOUNT (volume))
Packit 98cdb6
    mounted = TRUE;
Packit 98cdb6
  else if (G_IS_VOLUME (volume))
Packit 98cdb6
    {
Packit 98cdb6
      GMount *mount;
Packit 98cdb6
Packit 98cdb6
      mount = g_volume_get_mount (G_VOLUME (volume));
Packit 98cdb6
Packit 98cdb6
      if (mount)
Packit 98cdb6
        {
Packit 98cdb6
          mounted = TRUE;
Packit 98cdb6
          g_object_unref (mount);
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return mounted;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GFile *
Packit 98cdb6
_gtk_file_system_volume_get_root (GtkFileSystemVolume *volume)
Packit 98cdb6
{
Packit 98cdb6
  GFile *file = NULL;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("volume_get_base");
Packit 98cdb6
Packit 98cdb6
  if (IS_ROOT_VOLUME (volume))
Packit 98cdb6
    return g_file_new_for_uri ("file:///");
Packit 98cdb6
Packit 98cdb6
  if (G_IS_MOUNT (volume))
Packit 98cdb6
    file = g_mount_get_root (G_MOUNT (volume));
Packit 98cdb6
  else if (G_IS_VOLUME (volume))
Packit 98cdb6
    {
Packit 98cdb6
      GMount *mount;
Packit 98cdb6
Packit 98cdb6
      mount = g_volume_get_mount (G_VOLUME (volume));
Packit 98cdb6
Packit 98cdb6
      if (mount)
Packit 98cdb6
	{
Packit 98cdb6
	  file = g_mount_get_root (mount);
Packit 98cdb6
	  g_object_unref (mount);
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return file;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static GdkPixbuf *
Packit 98cdb6
get_pixbuf_from_gicon (GIcon      *icon,
Packit 98cdb6
		       GtkWidget  *widget,
Packit 98cdb6
		       gint        icon_size,
Packit 98cdb6
		       GError    **error)
Packit 98cdb6
{
Packit 98cdb6
  GdkScreen *screen;
Packit 98cdb6
  GtkIconTheme *icon_theme;
Packit 98cdb6
  GtkIconInfo *icon_info;
Packit 98cdb6
  GdkPixbuf *pixbuf;
Packit 98cdb6
Packit 98cdb6
  screen = gtk_widget_get_screen (GTK_WIDGET (widget));
Packit 98cdb6
  icon_theme = gtk_icon_theme_get_for_screen (screen);
Packit 98cdb6
Packit 98cdb6
  icon_info = gtk_icon_theme_lookup_by_gicon (icon_theme,
Packit 98cdb6
					      icon,
Packit 98cdb6
					      icon_size,
Packit 98cdb6
					      GTK_ICON_LOOKUP_USE_BUILTIN);
Packit 98cdb6
Packit 98cdb6
  if (!icon_info)
Packit 98cdb6
    return NULL;
Packit 98cdb6
Packit 98cdb6
  pixbuf = gtk_icon_info_load_icon (icon_info, error);
Packit 98cdb6
  gtk_icon_info_free (icon_info);
Packit 98cdb6
Packit 98cdb6
  return pixbuf;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GdkPixbuf *
Packit 98cdb6
_gtk_file_system_volume_render_icon (GtkFileSystemVolume  *volume,
Packit 98cdb6
				     GtkWidget            *widget,
Packit 98cdb6
				     gint                  icon_size,
Packit 98cdb6
				     GError              **error)
Packit 98cdb6
{
Packit 98cdb6
  GIcon *icon = NULL;
Packit 98cdb6
  GdkPixbuf *pixbuf;
Packit 98cdb6
Packit 98cdb6
  DEBUG ("volume_get_icon_name");
Packit 98cdb6
Packit 98cdb6
  if (IS_ROOT_VOLUME (volume))
Packit 98cdb6
    icon = g_themed_icon_new ("drive-harddisk");
Packit 98cdb6
  else if (G_IS_DRIVE (volume))
Packit 98cdb6
    icon = g_drive_get_icon (G_DRIVE (volume));
Packit 98cdb6
  else if (G_IS_VOLUME (volume))
Packit 98cdb6
    icon = g_volume_get_icon (G_VOLUME (volume));
Packit 98cdb6
  else if (G_IS_MOUNT (volume))
Packit 98cdb6
    icon = g_mount_get_icon (G_MOUNT (volume));
Packit 98cdb6
Packit 98cdb6
  if (!icon)
Packit 98cdb6
    return NULL;
Packit 98cdb6
Packit 98cdb6
  pixbuf = get_pixbuf_from_gicon (icon, widget, icon_size, error);
Packit 98cdb6
Packit 98cdb6
  g_object_unref (icon);
Packit 98cdb6
Packit 98cdb6
  return pixbuf;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GtkFileSystemVolume *
Packit 98cdb6
_gtk_file_system_volume_ref (GtkFileSystemVolume *volume)
Packit 98cdb6
{
Packit 98cdb6
  if (IS_ROOT_VOLUME (volume))
Packit 98cdb6
    return volume;
Packit 98cdb6
Packit 98cdb6
  if (G_IS_MOUNT (volume)  ||
Packit 98cdb6
      G_IS_VOLUME (volume) ||
Packit 98cdb6
      G_IS_DRIVE (volume))
Packit 98cdb6
    g_object_ref (volume);
Packit 98cdb6
Packit 98cdb6
  return volume;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
void
Packit 98cdb6
_gtk_file_system_volume_unref (GtkFileSystemVolume *volume)
Packit 98cdb6
{
Packit 98cdb6
  /* Root volume doesn't need to be freed */
Packit 98cdb6
  if (IS_ROOT_VOLUME (volume))
Packit 98cdb6
    return;
Packit 98cdb6
Packit 98cdb6
  if (G_IS_MOUNT (volume)  ||
Packit 98cdb6
      G_IS_VOLUME (volume) ||
Packit 98cdb6
      G_IS_DRIVE (volume))
Packit 98cdb6
    g_object_unref (volume);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/* GFileInfo helper functions */
Packit 98cdb6
GdkPixbuf *
Packit 98cdb6
_gtk_file_info_render_icon (GFileInfo *info,
Packit 98cdb6
			   GtkWidget *widget,
Packit 98cdb6
			   gint       icon_size)
Packit 98cdb6
{
Packit 98cdb6
  GIcon *icon;
Packit 98cdb6
  GdkPixbuf *pixbuf = NULL;
Packit 98cdb6
  const gchar *thumbnail_path;
Packit 98cdb6
Packit 98cdb6
  thumbnail_path = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
Packit 98cdb6
Packit 98cdb6
  if (thumbnail_path)
Packit 98cdb6
    pixbuf = gdk_pixbuf_new_from_file_at_size (thumbnail_path,
Packit 98cdb6
					       icon_size, icon_size,
Packit 98cdb6
					       NULL);
Packit 98cdb6
Packit 98cdb6
  if (!pixbuf)
Packit 98cdb6
    {
Packit 98cdb6
      icon = g_file_info_get_icon (info);
Packit 98cdb6
Packit 98cdb6
      if (icon)
Packit 98cdb6
	pixbuf = get_pixbuf_from_gicon (icon, widget, icon_size, NULL);
Packit 98cdb6
Packit 98cdb6
      if (!pixbuf)
Packit 98cdb6
	{
Packit 98cdb6
	   /* Use general fallback for all files without icon */
Packit 98cdb6
	  icon = g_themed_icon_new ("text-x-generic");
Packit 98cdb6
	  pixbuf = get_pixbuf_from_gicon (icon, widget, icon_size, NULL);
Packit 98cdb6
	  g_object_unref (icon);
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return pixbuf;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
gboolean
Packit 98cdb6
_gtk_file_info_consider_as_directory (GFileInfo *info)
Packit 98cdb6
{
Packit 98cdb6
  GFileType type = g_file_info_get_file_type (info);
Packit 98cdb6
  
Packit 98cdb6
  return (type == G_FILE_TYPE_DIRECTORY ||
Packit 98cdb6
          type == G_FILE_TYPE_MOUNTABLE ||
Packit 98cdb6
          type == G_FILE_TYPE_SHORTCUT);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
gboolean
Packit 98cdb6
_gtk_file_has_native_path (GFile *file)
Packit 98cdb6
{
Packit 98cdb6
  char *local_file_path;
Packit 98cdb6
  gboolean has_native_path;
Packit 98cdb6
Packit 98cdb6
  /* Don't use g_file_is_native(), as we want to support FUSE paths if available */
Packit 98cdb6
  local_file_path = g_file_get_path (file);
Packit 98cdb6
  has_native_path = (local_file_path != NULL);
Packit 98cdb6
  g_free (local_file_path);
Packit 98cdb6
Packit 98cdb6
  return has_native_path;
Packit 98cdb6
}