placessidebar: add Other Locations item
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Tue, 14 Jul 2015 17:47:42 +0000 (14:47 -0300)
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Thu, 16 Jul 2015 02:11:52 +0000 (23:11 -0300)
Places sidebar is a widget that enabled the user to select
XDG directories, bookmarks and mounted network locations,
as well as manages permanent and removable devices.

The new design that aims to look less clutered makes the
sidebar display only removable devices, as well as mounted
networks, bookmarks and XDG directories, and delegates the
management of permanent devices such as hard drive partitions
to GtkPlacesView, a newly introduced widget for this specific
purpose.

To delegate it, add an "Other Locations..." item to notify
when the permanent devices manager is required. Besides that,
don't show these fixes devices on the sidebar itself, as they
are not supposed to be handled by the sidebar anymore.

https://bugzilla.gnome.org/show_bug.cgi?id=752034

gtk/gtkplacessidebar.c
gtk/gtkplacessidebar.h
gtk/gtkplacessidebarprivate.h

index 3b20ff610636321c0537663d2f72ea05f869dc9f..1781f3973f3e2691a5d5bb2f2bb6b4b8352be53c 100644 (file)
@@ -158,6 +158,7 @@ struct _GtkPlacesSidebar {
   guint show_desktop           : 1;
   guint show_connect_to_server : 1;
   guint show_enter_location    : 1;
+  guint show_other_locations   : 1;
   guint show_trash             : 1;
   guint local_only             : 1;
 };
@@ -187,6 +188,8 @@ struct _GtkPlacesSidebarClass {
                                       GList              *source_file_list,
                                       GdkDragAction       action);
   void    (* show_enter_location)    (GtkPlacesSidebar   *sidebar);
+
+  void    (* show_other_locations)   (GtkPlacesSidebar   *sidebar);
 };
 
 enum {
@@ -198,6 +201,7 @@ enum {
   DRAG_ACTION_REQUESTED,
   DRAG_ACTION_ASK,
   DRAG_PERFORM_DROP,
+  SHOW_OTHER_LOCATIONS,
   LAST_SIGNAL
 };
 
@@ -210,6 +214,7 @@ enum {
   PROP_SHOW_ENTER_LOCATION,
   PROP_SHOW_TRASH,
   PROP_LOCAL_ONLY,
+  PROP_SHOW_OTHER_LOCATIONS,
   NUM_PROPERTIES
 };
 
@@ -221,6 +226,7 @@ enum {
 #define ICON_NAME_NETWORK  "network-workgroup-symbolic"
 #define ICON_NAME_NETWORK_SERVER "network-server-symbolic"
 #define ICON_NAME_FOLDER_NETWORK "folder-remote-symbolic"
+#define ICON_NAME_OTHER_LOCATIONS "list-add-symbolic"
 
 #define ICON_NAME_FOLDER                "folder-symbolic"
 #define ICON_NAME_FOLDER_DESKTOP  "user-desktop-symbolic"
@@ -315,6 +321,12 @@ emit_show_enter_location (GtkPlacesSidebar *sidebar)
   g_signal_emit (sidebar, places_sidebar_signals[SHOW_ENTER_LOCATION], 0);
 }
 
+static void
+emit_show_other_locations (GtkPlacesSidebar *sidebar)
+{
+  g_signal_emit (sidebar, places_sidebar_signals[SHOW_OTHER_LOCATIONS], 0);
+}
+
 static GdkDragAction
 emit_drag_action_requested (GtkPlacesSidebar *sidebar,
                             GdkDragContext   *context,
@@ -809,6 +821,36 @@ out:
   g_slice_free (BookmarkQueryClosure, clos);
 }
 
+static gboolean
+is_removable_volume (GVolume *volume)
+{
+  gboolean is_removable;
+  GDrive *drive;
+  GMount *mount;
+  gchar *id;
+
+  drive = g_volume_get_drive (volume);
+  mount = g_volume_get_mount (volume);
+  id = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS);
+
+  is_removable = g_volume_can_eject (volume);
+
+  /* NULL volume identifier only happens on removable devices */
+  is_removable |= !id;
+
+  if (drive)
+    is_removable |= g_drive_can_eject (drive);
+
+  if (mount)
+    is_removable |= (g_mount_can_eject (mount) && !g_mount_can_unmount (mount));
+
+  g_clear_object (&drive);
+  g_clear_object (&mount);
+  g_free (id);
+
+  return is_removable;
+}
+
 static void
 update_places (GtkPlacesSidebar *sidebar)
 {
@@ -945,6 +987,12 @@ update_places (GtkPlacesSidebar *sidebar)
                 }
               g_free (identifier);
 
+              if (!is_removable_volume (volume))
+                {
+                  g_object_unref (volume);
+                  continue;
+                }
+
               mount = g_volume_get_mount (volume);
               if (mount != NULL)
                 {
@@ -956,7 +1004,7 @@ update_places (GtkPlacesSidebar *sidebar)
                   tooltip = g_file_get_parse_name (root);
 
                   add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                             SECTION_DEVICES,
+                             SECTION_MOUNTS,
                              name, icon, mount_uri,
                              drive, volume, mount, 0, tooltip);
                   g_object_unref (root);
@@ -981,7 +1029,7 @@ update_places (GtkPlacesSidebar *sidebar)
                   tooltip = g_strdup_printf (_("Mount and open “%s”"), name);
 
                   add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                             SECTION_DEVICES,
+                             SECTION_MOUNTS,
                              name, icon, NULL,
                              drive, volume, NULL, 0, tooltip);
                   g_object_unref (icon);
@@ -1009,7 +1057,7 @@ update_places (GtkPlacesSidebar *sidebar)
               tooltip = g_strdup_printf (_("Mount and open “%s”"), name);
 
               add_place (sidebar, PLACES_BUILT_IN,
-                         SECTION_DEVICES,
+                         SECTION_MOUNTS,
                          name, icon, NULL,
                          drive, NULL, NULL, 0, tooltip);
               g_object_unref (icon);
@@ -1017,11 +1065,10 @@ update_places (GtkPlacesSidebar *sidebar)
               g_free (name);
             }
         }
-      g_object_unref (drive);
     }
-  g_list_free (drives);
+  g_list_free_full (drives, g_object_unref);
 
-  /* add all volumes that is not associated with a drive */
+  /* add all network volumes that is not associated with a drive */
   volumes = g_volume_monitor_get_volumes (sidebar->volume_monitor);
   for (l = volumes; l != NULL; l = l->next)
     {
@@ -1044,6 +1091,12 @@ update_places (GtkPlacesSidebar *sidebar)
         }
       g_free (identifier);
 
+      if (!is_removable_volume (volume))
+        {
+          g_object_unref (volume);
+          continue;
+        }
+
       mount = g_volume_get_mount (volume);
       if (mount != NULL)
         {
@@ -1053,7 +1106,7 @@ update_places (GtkPlacesSidebar *sidebar)
           tooltip = g_file_get_parse_name (root);
           name = g_mount_get_name (mount);
           add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                     SECTION_DEVICES,
+                     SECTION_MOUNTS,
                      name, icon, mount_uri,
                      NULL, volume, mount, 0, tooltip);
           g_object_unref (mount);
@@ -1069,7 +1122,7 @@ update_places (GtkPlacesSidebar *sidebar)
           icon = g_volume_get_symbolic_icon (volume);
           name = g_volume_get_name (volume);
           add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                     SECTION_DEVICES,
+                     SECTION_MOUNTS,
                      name, icon, NULL,
                      NULL, volume, NULL, 0, name);
           g_object_unref (icon);
@@ -1079,16 +1132,6 @@ update_places (GtkPlacesSidebar *sidebar)
     }
   g_list_free (volumes);
 
-  /* file system root */
-  mount_uri = "file:///"; /* No need to strdup */
-  icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_FILESYSTEM);
-  add_place (sidebar, PLACES_BUILT_IN,
-             SECTION_DEVICES,
-             sidebar->hostname, icon, mount_uri,
-             NULL, NULL, NULL, 0,
-             _("Open the contents of the file system"));
-  g_object_unref (icon);
-
   /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
   mounts = g_volume_monitor_get_mounts (sidebar->volume_monitor);
 
@@ -1180,26 +1223,6 @@ update_places (GtkPlacesSidebar *sidebar)
   /* network */
   if (!sidebar->local_only)
     {
-      mount_uri = "network:///";
-      icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_NETWORK);
-      add_place (sidebar, PLACES_BUILT_IN,
-                 SECTION_NETWORK,
-                 _("Browse Network"), icon, mount_uri,
-                 NULL, NULL, NULL, 0,
-                 _("Browse the contents of the network"));
-      g_object_unref (icon);
-
-      if (sidebar->show_connect_to_server)
-        {
-          icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_NETWORK_SERVER);
-          add_place (sidebar, PLACES_CONNECT_TO_SERVER,
-                     SECTION_NETWORK,
-                     _("Connect to Server"), icon, NULL,
-                     NULL, NULL, NULL, 0,
-                     _("Connect to a network server address"));
-          g_object_unref (icon);
-        }
-
       network_volumes = g_list_reverse (network_volumes);
       for (l = network_volumes; l != NULL; l = l->next)
         {
@@ -1218,13 +1241,24 @@ update_places (GtkPlacesSidebar *sidebar)
               tooltip = g_strdup_printf (_("Mount and open “%s”"), name);
 
               add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                         SECTION_NETWORK,
+                         SECTION_MOUNTS,
                          name, icon, NULL,
                          NULL, volume, NULL, 0, tooltip);
               g_object_unref (icon);
               g_free (name);
               g_free (tooltip);
             }
+
+          if (sidebar->show_connect_to_server)
+            {
+              icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_NETWORK_SERVER);
+              add_place (sidebar, PLACES_CONNECT_TO_SERVER,
+                         SECTION_MOUNTS,
+                         _("Connect to Server"), icon, NULL,
+                         NULL, NULL, NULL, 0,
+                         _("Connect to a network server address"));
+              g_object_unref (icon);
+            }
         }
 
       network_mounts = g_list_reverse (network_mounts);
@@ -1237,7 +1271,7 @@ update_places (GtkPlacesSidebar *sidebar)
           name = g_mount_get_name (mount);
           tooltip = g_file_get_parse_name (root);
           add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                     SECTION_NETWORK,
+                     SECTION_MOUNTS,
                      name, icon, mount_uri,
                      NULL, NULL, mount, 0, tooltip);
           g_object_unref (root);
@@ -1251,6 +1285,19 @@ update_places (GtkPlacesSidebar *sidebar)
   g_list_free_full (network_volumes, g_object_unref);
   g_list_free_full (network_mounts, g_object_unref);
 
+  /* Other locations */
+  if (sidebar->show_other_locations)
+    {
+      icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_OTHER_LOCATIONS);
+
+      add_place (sidebar, PLACES_OTHER_LOCATIONS,
+                 SECTION_OTHER_LOCATIONS,
+                 _("Other Locations"), icon, NULL,
+                 NULL, NULL, NULL, 0, _("Show other locations"));
+
+      g_object_unref (icon);
+    }
+
   gtk_widget_show_all (GTK_WIDGET (sidebar));
   /* We want this hidden by default, but need to do it after the show_all call */
   gtk_sidebar_row_hide (GTK_SIDEBAR_ROW (sidebar->new_bookmark_row), TRUE);
@@ -2222,7 +2269,9 @@ open_row (GtkSidebarRow      *row,
                 "volume", &volume,
                 NULL);
 
-  if (uri != NULL)
+  if (place_type == PLACES_OTHER_LOCATIONS)
+    emit_show_other_locations (sidebar);
+  else if (uri != NULL)
     open_uri (sidebar, uri, open_flags);
   else if (place_type == PLACES_CONNECT_TO_SERVER)
     emit_show_connect_to_server (sidebar);
@@ -3859,13 +3908,19 @@ gtk_places_sidebar_set_property (GObject      *obj,
       break;
 
     case PROP_SHOW_CONNECT_TO_SERVER:
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
       gtk_places_sidebar_set_show_connect_to_server (sidebar, g_value_get_boolean (value));
+G_GNUC_END_IGNORE_DEPRECATIONS
       break;
 
     case PROP_SHOW_ENTER_LOCATION:
       gtk_places_sidebar_set_show_enter_location (sidebar, g_value_get_boolean (value));
       break;
 
+    case PROP_SHOW_OTHER_LOCATIONS:
+      gtk_places_sidebar_set_show_other_locations (sidebar, g_value_get_boolean (value));
+      break;
+
     case PROP_SHOW_TRASH:
       gtk_places_sidebar_set_show_trash (sidebar, g_value_get_boolean (value));
       break;
@@ -3907,13 +3962,19 @@ gtk_places_sidebar_get_property (GObject    *obj,
       break;
 
     case PROP_SHOW_CONNECT_TO_SERVER:
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
       g_value_set_boolean (value, gtk_places_sidebar_get_show_connect_to_server (sidebar));
+G_GNUC_END_IGNORE_DEPRECATIONS
       break;
 
     case PROP_SHOW_ENTER_LOCATION:
       g_value_set_boolean (value, gtk_places_sidebar_get_show_enter_location (sidebar));
       break;
 
+    case PROP_SHOW_OTHER_LOCATIONS:
+      g_value_set_boolean (value, gtk_places_sidebar_get_show_other_locations (sidebar));
+      break;
+
     case PROP_SHOW_TRASH:
       g_value_set_boolean (value, gtk_places_sidebar_get_show_trash (sidebar));
       break;
@@ -4110,7 +4171,8 @@ gtk_places_sidebar_class_init (GtkPlacesSidebarClass *class)
    * a URL like "sftp://ftp.example.com".  It is up to the application to create
    * the corresponding mount by using, for example, g_file_mount_enclosing_volume().
    *
-   * Since: 3.10
+   * Deprecated: 3.18: use #GtkPlacesSidebar::show-other-locations property to
+   * connect to network servers.
    */
   places_sidebar_signals [SHOW_CONNECT_TO_SERVER] =
           g_signal_new (I_("show-connect-to-server"),
@@ -4228,6 +4290,29 @@ gtk_places_sidebar_class_init (GtkPlacesSidebarClass *class)
                         G_TYPE_POINTER, /* GList of GFile */
                         G_TYPE_INT);
 
+  /**
+   * GtkPlacesSidebar::show-other-locations:
+   * @sidebar: the object which received the signal.
+   *
+   * The places sidebar emits this signal when it needs the calling
+   * application to present a way to show other locations e.g. drives
+   * and network access points.
+   * For example, the application may bring up a page showing persistent
+   * volumes and discovered network addresses. #GtkPlacesView is the
+   * prime example of how to handle them.
+   *
+   * Since: 3.18
+   */
+  places_sidebar_signals [SHOW_OTHER_LOCATIONS] =
+          g_signal_new (I_("show-other-locations"),
+                        G_OBJECT_CLASS_TYPE (gobject_class),
+                        G_SIGNAL_RUN_FIRST,
+                        G_STRUCT_OFFSET (GtkPlacesSidebarClass, show_other_locations),
+                        NULL, NULL,
+                        _gtk_marshal_VOID__VOID,
+                        G_TYPE_NONE, 0);
+
+
   properties[PROP_LOCATION] =
           g_param_spec_object ("location",
                                P_("Location to Select"),
@@ -4258,7 +4343,7 @@ gtk_places_sidebar_class_init (GtkPlacesSidebarClass *class)
                                 P_("Show 'Connect to Server'"),
                                 P_("Whether the sidebar includes a builtin shortcut to a 'Connect to server' dialog"),
                                 FALSE,
-                                G_PARAM_READWRITE);
+                                G_PARAM_READWRITE | G_PARAM_DEPRECATED);
   properties[PROP_SHOW_ENTER_LOCATION] =
           g_param_spec_boolean ("show-enter-location",
                                 P_("Show 'Enter Location'"),
@@ -4277,6 +4362,12 @@ gtk_places_sidebar_class_init (GtkPlacesSidebarClass *class)
                                 P_("Whether the sidebar includes a builtin shortcut to  the Trash location"),
                                 TRUE,
                                 G_PARAM_READWRITE);
+  properties[PROP_SHOW_OTHER_LOCATIONS] =
+          g_param_spec_boolean ("show-other-locations",
+                                P_("Show 'Other locations'"),
+                                P_("Whether the sidebar includes an item to show external locations"),
+                                FALSE,
+                                G_PARAM_READWRITE);
 
   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
 }
@@ -4606,7 +4697,7 @@ gtk_places_sidebar_set_show_connect_to_server (GtkPlacesSidebar *sidebar,
  *
  * Returns: %TRUE if the sidebar will display a “Connect to Server” item.
  *
- * Since: 3.10
+ * Deprecated: 3.18: use gtk_places_sidebar_get_show_other_locations() instead.
  */
 gboolean
 gtk_places_sidebar_get_show_connect_to_server (GtkPlacesSidebar *sidebar)
@@ -4625,7 +4716,7 @@ gtk_places_sidebar_get_show_connect_to_server (GtkPlacesSidebar *sidebar)
  * An application may want to turn this on if it implements a way for the user to connect
  * to network servers directly.
  *
- * Since: 3.14
+ * Deprecated: 3.18: use gtk_places_sidebar_set_show_other_locations() instead.
  */
 void
 gtk_places_sidebar_set_show_enter_location (GtkPlacesSidebar *sidebar,
@@ -4660,6 +4751,52 @@ gtk_places_sidebar_get_show_enter_location (GtkPlacesSidebar *sidebar)
   return sidebar->show_enter_location;
 }
 
+/**
+ * gtk_places_sidebar_set_show_other_locations:
+ * @sidebar: a places sidebar
+ * @show_other_locations: whether to show an item for the Other Locations view
+ *
+ * Sets whether the @sidebar should show an item for the application to show an Other Locations
+ * view; this is off by default.
+ * An application may want to turn this on if it implements a way for the user to see and interact
+ * with drives and network servers directly. #GtkPlacesView is the reference implementation for
+ * it.
+ *
+ * Since: 3.18
+ */
+void
+gtk_places_sidebar_set_show_other_locations (GtkPlacesSidebar *sidebar,
+                                             gboolean          show_other_locations)
+{
+  g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar));
+
+  show_other_locations = !!show_other_locations;
+  if (sidebar->show_other_locations != show_other_locations)
+    {
+      sidebar->show_other_locations = show_other_locations;
+      update_places (sidebar);
+      g_object_notify_by_pspec (G_OBJECT (sidebar), properties[PROP_SHOW_OTHER_LOCATIONS]);
+    }
+  }
+
+/**
+ * gtk_places_sidebar_get_show_other_locations:
+ * @sidebar: a places sidebar
+ *
+ * Returns the value previously set with gtk_places_sidebar_set_show_other_locations()
+ *
+ * Returns: %TRUE if the sidebar will display an “Other Locations” item.
+ *
+ * Since: 3.18
+ */
+gboolean
+gtk_places_sidebar_get_show_other_locations (GtkPlacesSidebar *sidebar)
+{
+  g_return_val_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar), FALSE);
+
+  return sidebar->show_other_locations;
+}
+
 /**
  * gtk_places_sidebar_set_show_trash:
  * @sidebar: a places sidebar
index a40c8c8909c64e03e35782f0db057af5f8b21861..aa5cb1d44bd7853b7d8f2d106d0e518393d3b763 100644 (file)
@@ -107,9 +107,9 @@ GDK_AVAILABLE_IN_3_10
 void               gtk_places_sidebar_set_show_desktop           (GtkPlacesSidebar   *sidebar,
                                                                   gboolean            show_desktop);
 
-GDK_AVAILABLE_IN_3_10
+GDK_DEPRECATED_IN_3_18
 gboolean           gtk_places_sidebar_get_show_connect_to_server (GtkPlacesSidebar   *sidebar);
-GDK_AVAILABLE_IN_3_10
+GDK_DEPRECATED_IN_3_18
 void               gtk_places_sidebar_set_show_connect_to_server (GtkPlacesSidebar   *sidebar,
                                                                   gboolean            show_connect_to_server);
 GDK_AVAILABLE_IN_3_14
@@ -147,6 +147,12 @@ GDK_AVAILABLE_IN_3_18
 void               gtk_places_sidebar_set_show_trash             (GtkPlacesSidebar   *sidebar,
                                                                   gboolean            show_trash);
 
+GDK_AVAILABLE_IN_3_18
+void                 gtk_places_sidebar_set_show_other_locations (GtkPlacesSidebar   *sidebar,
+                                                                  gboolean            show_other_locations);
+GDK_AVAILABLE_IN_3_18
+gboolean             gtk_places_sidebar_get_show_other_locations (GtkPlacesSidebar   *sidebar);
+
 G_END_DECLS
 
 #endif /* __GTK_PLACES_SIDEBAR_H__ */
index 520141f41875a93728a4060a736e013b177c3f7e..34850cc83805249b473fb80cc9946df702f5bc99 100644 (file)
@@ -30,9 +30,9 @@ G_BEGIN_DECLS
 typedef enum {
   SECTION_INVALID,
   SECTION_COMPUTER,
-  SECTION_DEVICES,
-  SECTION_NETWORK,
+  SECTION_MOUNTS,
   SECTION_BOOKMARKS,
+  SECTION_OTHER_LOCATIONS,
   N_SECTIONS
 } GtkPlacesSidebarSectionType;
 
@@ -47,6 +47,7 @@ typedef enum {
   PLACES_ENTER_LOCATION,
   PLACES_DROP_FEEDBACK,
   PLACES_BOOKMARK_PLACEHOLDER,
+  PLACES_OTHER_LOCATIONS,
   N_PLACES
 } GtkPlacesSidebarPlaceType;