[gtk+/multiroot-filechooser: 1/15] Add the concept of rooting the filechooser to a specific URI.



commit 272e8ee2eee35f71428cb854002fce1553ce5438
Author: Christian Hammond <chipx86 chipx86 com>
Date:   Mon Mar 22 19:03:14 2010 -0700

    Add the concept of rooting the filechooser to a specific URI.
    
    The only UI elements (shortcuts, bookmarks, special folders, etc.) that will
    show up are ones within the root URI.
    
    At this point, we have the UI filtering out the special sidebar entries
    that are not within the root URI, and we have some API calls set up for
    specifying the root URI.
    
    Future changes will limit browsing within the root URI, limit search
    results, and other such fixes.

 gtk/gtkfilechooser.c        |  159 ++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtkfilechooser.h        |    3 +
 gtk/gtkfilechooserbutton.c  |    1 +
 gtk/gtkfilechooserdefault.c |  134 ++++++++++++++++++++++++++++++------
 gtk/gtkfilechooserentry.c   |   42 +++++++++++-
 gtk/gtkfilechooserentry.h   |    3 +
 gtk/gtkfilechooserprivate.h |   11 +++
 gtk/gtkfilechooserutils.c   |    3 +
 gtk/gtkfilechooserutils.h   |    3 +-
 9 files changed, 332 insertions(+), 27 deletions(-)
---
diff --git a/gtk/gtkfilechooser.c b/gtk/gtkfilechooser.c
index 705a845..a674ac3 100644
--- a/gtk/gtkfilechooser.c
+++ b/gtk/gtkfilechooser.c
@@ -849,6 +849,25 @@ gtk_file_chooser_class_init (gpointer g_iface)
 								"will offer the user to create new folders."),
 							     TRUE,
 							     GTK_PARAM_READWRITE));
+
+  /**
+   * GtkFileChooser:root-uri:
+   *
+   * The absolute root URI that can be accessed in the file chooser.
+   * Any shortcuts (special or user-defined) or volumes not within
+   * this URI will be filtered out for this dialog.
+   *
+   * The default is an empty string or NULL, which provides the
+   * default level of access for the file chooser.
+   *
+   * Since: 2.18
+   */
+  g_object_interface_install_property (g_iface,
+				       g_param_spec_string ("root-uri",
+							     P_("Root URI"),
+							     P_("The URI, if any, to use as the root for all access in the file chooser."),
+							     NULL,
+							     GTK_PARAM_READWRITE));
 }
 
 /**
@@ -926,6 +945,9 @@ gtk_file_chooser_get_action (GtkFileChooser *chooser)
  * rather than the URI functions like
  * gtk_file_chooser_get_uri(),
  *
+ * This implies a root URI of "file://". See
+ * gtk_file_chooser_set_root_uri().
+ *
  * Since: 2.4
  **/
 void
@@ -939,10 +961,13 @@ gtk_file_chooser_set_local_only (GtkFileChooser *chooser,
 
 /**
  * gtk_file_chooser_get_local_only:
- * @chooser: a #GtkFileChoosre
+ * @chooser: a #GtkFileChooser
  * 
  * Gets whether only local files can be selected in the
  * file selector. See gtk_file_chooser_set_local_only()
+ *
+ * This is %TRUE when the root URI of the file chooser is
+ * "file://". See gtk_file_chooser_get_root_uri().
  * 
  * Return value: %TRUE if only local files can be selected.
  *
@@ -961,6 +986,66 @@ gtk_file_chooser_get_local_only (GtkFileChooser *chooser)
 }
 
 /**
+ * gtk_file_chooser_set_root_uri:
+ * @chooser: a #GtkFileChooser
+ * @root_uri: The root URI, or %NULL to allow access to everything.
+ *
+ * Sets the URI that will be the root of the file chooser. The file
+ * chooser will not display or allow access to files outside of this URI.
+ *
+ * If this is set to %NULL, then the file chooser will have access to all
+ * local and remote volumes and files.
+ *
+ * This is useful when needing to restrict the file chooser to a particular
+ * directory and its subdirectories, to a particular storage device, or to a
+ * remote server.
+ *
+ * See gtk_file_chooser_get_root_uri()
+ *
+ * Since: 2.18
+ **/
+void
+gtk_file_chooser_set_root_uri (GtkFileChooser *chooser,
+			       const gchar    *root_uri)
+{
+  g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
+
+  g_object_set (chooser, "root-uri", root_uri, NULL);
+}
+
+/**
+ * gtk_file_chooser_get_root_uri:
+ * @chooser: a #GtkFileChooser
+ *
+ * Gets the URI that is the root of the file chooser. The file chooser
+ * will not display or allow access to files outside of this URI.
+ *
+ * If this is %NULL, then the file chooser has access to all local and
+ * remote volumes and files.
+ *
+ * This is useful when needing to restrict the file chooser to a particular
+ * directory and its subdirectories, to a particular storage device, or to a
+ * remote server.
+ *
+ * See gtk_file_chooser_set_root_uri()
+ *
+ * Return value: The root URI, or %NULL.
+ *
+ * Since: 2.18
+ **/
+const gchar *
+gtk_file_chooser_get_root_uri (GtkFileChooser *chooser)
+{
+  const gchar *root_uri;
+
+  g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
+
+  g_object_get (chooser, "root-uri", &root_uri, NULL);
+
+  return root_uri;
+}
+
+/**
  * gtk_file_chooser_set_select_multiple:
  * @chooser: a #GtkFileChooser
  * @select_multiple: %TRUE if multiple files can be selected.
@@ -2761,5 +2846,77 @@ gtk_file_chooser_list_shortcut_folders (GtkFileChooser *chooser)
 
 #endif
 
+gboolean
+_gtk_file_chooser_uri_has_prefix (const char *uri,
+                                  const char *prefix)
+{
+  int uri_len;
+  int prefix_len;
+  gboolean result;
+  char *new_prefix = NULL;
+
+  g_return_val_if_fail (uri != NULL, FALSE);
+  g_return_val_if_fail (prefix != NULL, FALSE);
+
+  uri_len = strlen (uri);
+  prefix_len = strlen (prefix);
+
+  if (prefix[prefix_len - 1] != '/')
+    {
+      new_prefix = g_strdup_printf ("%s/", prefix);
+      prefix = new_prefix;
+      prefix_len++;
+    }
+
+  if (prefix_len == uri_len + 1)
+    {
+      /*
+       * Special case. The prefix URI may contain a trailing slash while the
+       * URI we're comparing against may not (or vice-versa), despite the
+       * URIs being equal.
+       */
+      result = !strncmp (prefix, uri, uri_len);
+    }
+  else
+    result = (uri_len >= prefix_len && g_str_has_prefix (uri, prefix));
+
+  g_free (new_prefix);
+
+  return result;
+}
+
+gboolean
+_gtk_file_chooser_is_uri_in_root (GtkFileChooser *chooser,
+                                  const char     *uri)
+{
+  const char *root_uri;
+
+  g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), FALSE);
+  g_return_val_if_fail (uri != NULL, FALSE);
+
+  root_uri = gtk_file_chooser_get_root_uri (chooser);
+
+  return root_uri == NULL || _gtk_file_chooser_uri_has_prefix (uri, root_uri);
+}
+
+gboolean
+_gtk_file_chooser_is_file_in_root (GtkFileChooser *chooser,
+                                   GFile          *file)
+{
+  char *uri;
+  gboolean result;
+
+  g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), FALSE);
+  g_return_val_if_fail (file != NULL, FALSE);
+
+  uri = g_file_get_uri (file);
+  result = _gtk_file_chooser_is_uri_in_root (chooser, uri);
+  g_free (uri);
+
+  return result;
+}
+
 #define __GTK_FILE_CHOOSER_C__
 #include "gtkaliasdef.c"
+
+// vim: et sw=2 cinoptions=(0,t0,f1s,n-1s,{1s,>2s,^-1s
diff --git a/gtk/gtkfilechooser.h b/gtk/gtkfilechooser.h
index 21ba7ee..9ac4058 100644
--- a/gtk/gtkfilechooser.h
+++ b/gtk/gtkfilechooser.h
@@ -123,6 +123,9 @@ GtkFileChooserAction gtk_file_chooser_get_action          (GtkFileChooser
 void                 gtk_file_chooser_set_local_only      (GtkFileChooser       *chooser,
 							   gboolean              local_only);
 gboolean             gtk_file_chooser_get_local_only      (GtkFileChooser       *chooser);
+void                 gtk_file_chooser_set_root_uri        (GtkFileChooser       *chooser,
+							   const gchar          *root_uri);
+const gchar         *gtk_file_chooser_get_root_uri        (GtkFileChooser       *chooser);
 void                 gtk_file_chooser_set_select_multiple (GtkFileChooser       *chooser,
 							   gboolean              select_multiple);
 gboolean             gtk_file_chooser_get_select_multiple (GtkFileChooser       *chooser);
diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c
index 771597a..c09af62 100644
--- a/gtk/gtkfilechooserbutton.c
+++ b/gtk/gtkfilechooserbutton.c
@@ -815,6 +815,7 @@ gtk_file_chooser_button_set_property (GObject      *object,
       break;
 
     case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
+    case GTK_FILE_CHOOSER_PROP_ROOT_URI:
       g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value);
       fs_volumes_changed_cb (priv->fs, button);
       fs_bookmarks_changed_cb (priv->fs, button);
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index 3f634d3..71553b2 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -231,6 +231,9 @@ enum {
 static gboolean
 search_is_possible (GtkFileChooserDefault *impl)
 {
+  if (impl->root_uri != NULL && !g_str_has_prefix (impl->root_uri, "file:"))
+    return FALSE;
+
   if (impl->search_engine == NULL)
     impl->search_engine = _gtk_search_engine_new ();
   
@@ -711,6 +714,7 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
   access ("MARK: *** CREATE FILE CHOOSER", F_OK);
 #endif
   impl->local_only = TRUE;
+  impl->root_uri = NULL;
   impl->preview_widget_active = TRUE;
   impl->use_preview_label = TRUE;
   impl->select_multiple = FALSE;
@@ -1819,8 +1823,15 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
     }
 
   home = g_file_new_for_path (home_path);
-  shortcuts_insert_file (impl, -1, SHORTCUT_TYPE_FILE, NULL, home, NULL, FALSE, SHORTCUTS_HOME);
-  impl->has_home = TRUE;
+
+  if (_gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl), home))
+    {
+      shortcuts_insert_file (impl, -1, SHORTCUT_TYPE_FILE, NULL, home,
+                             NULL, FALSE, SHORTCUTS_HOME);
+      impl->has_home = TRUE;
+    }
+  else
+    impl->has_home = FALSE;
 
   g_object_unref (home);
 
@@ -1847,8 +1858,15 @@ shortcuts_append_desktop (GtkFileChooserDefault *impl)
     }
 
   file = g_file_new_for_path (name);
-  shortcuts_insert_file (impl, -1, SHORTCUT_TYPE_FILE, NULL, file, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
-  impl->has_desktop = TRUE;
+
+  if (_gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl), file))
+    {
+      shortcuts_insert_file (impl, -1, SHORTCUT_TYPE_FILE, NULL,
+                             file, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
+      impl->has_desktop = TRUE;
+    }
+  else
+    impl->has_desktop = FALSE;
 
   /* We do not actually pop up an error dialog if there is no desktop directory
    * because some people may really not want to have one.
@@ -1882,6 +1900,9 @@ shortcuts_append_bookmarks (GtkFileChooserDefault *impl,
       if (impl->local_only && !g_file_is_native (file))
 	continue;
 
+      if (!_gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl), file))
+        continue;
+
       if (shortcut_find_position (impl, file) != -1)
         continue;
 
@@ -1993,6 +2014,7 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
   for (l = list; l; l = l->next)
     {
       GtkFileSystemVolume *volume;
+      gboolean skip = FALSE;
 
       volume = l->data;
 
@@ -2001,19 +2023,29 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
 	  if (_gtk_file_system_volume_is_mounted (volume))
 	    {
 	      GFile *base_file;
-              gboolean base_is_native = TRUE;
 
 	      base_file = _gtk_file_system_volume_get_root (volume);
               if (base_file != NULL)
                 {
-                  base_is_native = g_file_is_native (base_file);
+                  skip = !g_file_is_native (base_file);
                   g_object_unref (base_file);
                 }
-
-              if (!base_is_native)
-                continue;
 	    }
 	}
+      else if (impl->root_uri != NULL)
+        {
+          GFile *base_file = _gtk_file_system_volume_get_root (volume);
+
+          if (base_file != NULL)
+            {
+              skip = !_gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl),
+                                                         base_file);
+              g_object_unref (base_file);
+            }
+        }
+
+      if (skip)
+        continue;
 
       shortcuts_insert_file (impl, start_row + n, SHORTCUT_TYPE_VOLUME, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
       n++;
@@ -2262,22 +2294,22 @@ shortcuts_model_create (GtkFileChooserDefault *impl)
 					      G_TYPE_POINTER);  /* GCancellable */
 
   if (search_is_possible (impl))
-    {
-      shortcuts_append_search (impl);
-    }
+	{
+	  shortcuts_append_search (impl);
+	}
 
   if (impl->recent_manager)
-    {
-      shortcuts_append_recent (impl);
-      shortcuts_insert_separator (impl, SHORTCUTS_RECENT_SEPARATOR);
-    }
-  
+	{
+	  shortcuts_append_recent (impl);
+	  shortcuts_insert_separator (impl, SHORTCUTS_RECENT_SEPARATOR);
+	}
+
   if (impl->file_system)
-    {
-      shortcuts_append_home (impl);
-      shortcuts_append_desktop (impl);
+	{
+	  shortcuts_append_home (impl);
+	  shortcuts_append_desktop (impl);
       shortcuts_add_volumes (impl);
-    }
+	}
 
   impl->shortcuts_pane_filter_model = shortcuts_pane_model_filter_new (impl,
 							               GTK_TREE_MODEL (impl->shortcuts_model),
@@ -4804,6 +4836,7 @@ save_widgets_create (GtkFileChooserDefault *impl)
   _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
 					   impl->file_system);
   _gtk_file_chooser_entry_set_local_only (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->local_only);
+  _gtk_file_chooser_entry_set_root_uri (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->root_uri);
   gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45);
   gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
   gtk_table_attach (GTK_TABLE (table), impl->location_entry,
@@ -5281,6 +5314,46 @@ set_local_only (GtkFileChooserDefault *impl,
 }
 
 static void
+set_root_uri (GtkFileChooserDefault *impl,
+              const gchar           *root_uri)
+{
+  if (root_uri == NULL || *root_uri == '\0')
+    root_uri = NULL;
+
+  if (g_strcmp0 (root_uri, impl->root_uri))
+    {
+      g_free (impl->root_uri);
+      impl->root_uri = (root_uri == NULL ? NULL : g_strdup (root_uri));
+
+      if (impl->location_entry)
+        {
+          _gtk_file_chooser_entry_set_root_uri (
+            GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+            impl->root_uri);
+        }
+
+      if (impl->shortcuts_model && impl->file_system)
+        {
+          /* Update all the sidebar entries to filter the root URI. */
+          shortcuts_add_volumes (impl);
+          shortcuts_add_bookmarks (impl);
+        }
+
+      if (impl->current_folder &&
+          _gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl),
+                                             impl->current_folder))
+        {
+          /*
+           * If we are pointing to a folder outside of the root URI, set the
+           * folder to the root URI.
+           */
+          gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (impl),
+                                                   impl->root_uri);
+        }
+    }
+}
+
+static void
 volumes_bookmarks_changed_cb (GtkFileSystem         *file_system,
 			      GtkFileChooserDefault *impl)
 {
@@ -5524,6 +5597,10 @@ gtk_file_chooser_default_set_property (GObject      *object,
       }
       break;
 
+    case GTK_FILE_CHOOSER_PROP_ROOT_URI:
+      set_root_uri (impl, g_value_get_string (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -5584,6 +5661,10 @@ gtk_file_chooser_default_get_property (GObject    *object,
       g_value_set_boolean (value, impl->create_folders);
       break;
 
+    case GTK_FILE_CHOOSER_PROP_ROOT_URI:
+      g_value_set_string (value, impl->root_uri);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -5618,6 +5699,9 @@ gtk_file_chooser_default_dispose (GObject *object)
       impl->extra_widget = NULL;
     }
 
+  g_free (impl->root_uri);
+  impl->root_uri = NULL;
+
   pending_select_files_free (impl);
 
   /* cancel all pending operations */
@@ -7066,7 +7150,9 @@ update_current_folder_get_info_cb (GCancellable *cancellable,
       parent_file = g_file_get_parent (data->file);
 
       /* get parent path and try to change the folder to that */
-      if (parent_file)
+      if (parent_file &&
+          _gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl),
+                                             parent_file))
         {
 	  g_object_unref (data->file);
 	  data->file = parent_file;
@@ -8766,7 +8852,8 @@ search_add_hit (GtkFileChooserDefault *impl,
   if (!file)
     return;
 
-  if (!g_file_is_native (file))
+  if (!g_file_is_native (file) ||
+      !_gtk_file_chooser_is_file_in_root (GTK_FILE_CHOOSER (impl), file))
     {
       g_object_unref (file);
       return;
@@ -10350,3 +10437,4 @@ shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
   return GTK_TREE_MODEL (model);
 }
 
+// vim: et sw=2 cinoptions=(0,t0,f1s,n-1s,{1s,>2s,^-1s
diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c
index 0977040..bf39236 100644
--- a/gtk/gtkfilechooserentry.c
+++ b/gtk/gtkfilechooserentry.c
@@ -26,6 +26,7 @@
 #include "gtkcellrenderertext.h"
 #include "gtkentry.h"
 #include "gtkfilechooserentry.h"
+#include "gtkfilechooserprivate.h"
 #include "gtklabel.h"
 #include "gtkmain.h"
 #include "gtkwindow.h"
@@ -66,6 +67,7 @@ struct _GtkFileChooserEntry
   GtkFileChooserAction action;
 
   GtkFileSystem *file_system;
+  char *root_uri;
   GFile *base_folder;
   GFile *current_folder_file;
   gchar *file_part;
@@ -206,6 +208,7 @@ _gtk_file_chooser_entry_init (GtkFileChooserEntry *chooser_entry)
   GtkCellRenderer *cell;
 
   chooser_entry->local_only = TRUE;
+  chooser_entry->root_uri = NULL;
 
   g_object_set (chooser_entry, "truncate-multiline", TRUE, NULL);
 
@@ -294,6 +297,9 @@ gtk_file_chooser_entry_dispose (GObject *object)
   discard_current_folder (chooser_entry);
   discard_loading_and_current_folder_file (chooser_entry);
 
+  g_free (chooser_entry->root_uri);
+  chooser_entry->root_uri = NULL;
+
   if (chooser_entry->start_autocompletion_idle_id != 0)
     {
       g_source_remove (chooser_entry->start_autocompletion_idle_id);
@@ -446,6 +452,19 @@ beep (GtkFileChooserEntry *chooser_entry)
   gtk_widget_error_bell (GTK_WIDGET (chooser_entry));
 }
 
+static gboolean
+is_file_in_root (GtkFileChooserEntry *chooser_entry,
+                 GFile               *file)
+{
+  char *uri = g_file_get_uri (file);
+  gboolean result = chooser_entry->root_uri == NULL ||
+                    _gtk_file_chooser_uri_has_prefix (uri,
+                                                      chooser_entry->root_uri);
+  g_free (uri);
+
+  return result;
+}
+
 /* This function will append a directory separator to paths to
  * display_name iff the path associated with it is a directory.
  * maybe_append_separator_to_file will g_free the display_name and
@@ -1464,8 +1483,11 @@ start_loading_current_folder (GtkFileChooserEntry *chooser_entry)
   g_assert (chooser_entry->current_folder == NULL);
   g_assert (chooser_entry->load_folder_cancellable == NULL);
 
-  if (chooser_entry->local_only
-      && !g_file_is_native (chooser_entry->current_folder_file))
+  if ((chooser_entry->local_only
+       && !g_file_is_native (chooser_entry->current_folder_file)) ||
+      (chooser_entry->root_uri != NULL
+       && !is_file_in_root (chooser_entry,
+                            chooser_entry->current_folder_file)))
     {
       g_object_unref (chooser_entry->current_folder_file);
       chooser_entry->current_folder_file = NULL;
@@ -2001,3 +2023,19 @@ _gtk_file_chooser_entry_get_local_only (GtkFileChooserEntry *chooser_entry)
 {
   return chooser_entry->local_only;
 }
+
+void
+_gtk_file_chooser_entry_set_root_uri (GtkFileChooserEntry *chooser_entry,
+                                      const char          *root_uri)
+{
+  g_free (chooser_entry->root_uri);
+
+  chooser_entry->root_uri = (root_uri == NULL ? NULL : g_strdup(root_uri));
+  clear_completions (chooser_entry);
+}
+
+const char *
+_gtk_file_chooser_entry_get_root_uri (GtkFileChooserEntry *chooser_entry)
+{
+  return chooser_entry->root_uri;
+}
diff --git a/gtk/gtkfilechooserentry.h b/gtk/gtkfilechooserentry.h
index a9c9f83..38e4ebb 100644
--- a/gtk/gtkfilechooserentry.h
+++ b/gtk/gtkfilechooserentry.h
@@ -51,6 +51,9 @@ void               _gtk_file_chooser_entry_select_filename    (GtkFileChooserEnt
 void               _gtk_file_chooser_entry_set_local_only     (GtkFileChooserEntry *chooser_entry,
                                                                gboolean             local_only);
 gboolean           _gtk_file_chooser_entry_get_local_only     (GtkFileChooserEntry *chooser_entry);
+void               _gtk_file_chooser_entry_set_root_uri     (GtkFileChooserEntry *chooser_entry,
+                                                             const char          *root_uri);
+const char        *_gtk_file_chooser_entry_get_root_uri     (GtkFileChooserEntry *chooser_entry);
 
 G_END_DECLS
 
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index 9f02b42..377a1b2 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -104,6 +104,16 @@ gboolean       _gtk_file_chooser_remove_shortcut_folder  (GtkFileChooser    *cho
 							  GError           **error);
 GSList *       _gtk_file_chooser_list_shortcut_folder_files (GtkFileChooser *chooser);
 
+GSList *       _gtk_file_chooser_list_shortcut_folder_files (GtkFileChooser *chooser);
+
+gboolean       _gtk_file_chooser_is_uri_in_root (GtkFileChooser *chooser,
+                                                 const char     *uri);
+gboolean       _gtk_file_chooser_is_file_in_root (GtkFileChooser *chooser,
+                                                  GFile          *file);
+
+gboolean       _gtk_file_chooser_uri_has_prefix (const char *uri,
+                                                 const char *prefix);
+
 /* GtkFileChooserDialog private */
 
 struct _GtkFileChooserDialogPrivate
@@ -160,6 +170,7 @@ struct _GtkFileChooserDefault
   GtkFileChooserAction action;
 
   GtkFileSystem *file_system;
+  char *root_uri;
 
   /* Save mode widgets */
   GtkWidget *save_widgets;
diff --git a/gtk/gtkfilechooserutils.c b/gtk/gtkfilechooserutils.c
index 69c71d1..8a881bf 100644
--- a/gtk/gtkfilechooserutils.c
+++ b/gtk/gtkfilechooserutils.c
@@ -120,6 +120,9 @@ _gtk_file_chooser_install_properties (GObjectClass *klass)
   g_object_class_override_property (klass,
 				    GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
 				    "create-folders");
+  g_object_class_override_property (klass,
+				    GTK_FILE_CHOOSER_PROP_ROOT_URI,
+				    "root-uri");
 }
 
 /**
diff --git a/gtk/gtkfilechooserutils.h b/gtk/gtkfilechooserutils.h
index a590ccc..53d6e83 100644
--- a/gtk/gtkfilechooserutils.h
+++ b/gtk/gtkfilechooserutils.h
@@ -42,7 +42,8 @@ typedef enum {
   GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN,
   GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION,
   GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
-  GTK_FILE_CHOOSER_PROP_LAST                   = GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS
+  GTK_FILE_CHOOSER_PROP_ROOT_URI,
+  GTK_FILE_CHOOSER_PROP_LAST                   = GTK_FILE_CHOOSER_PROP_ROOT_URI
 } GtkFileChooserProp;
 
 void _gtk_file_chooser_install_properties (GObjectClass *klass);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]