gtkplacessidebar: implement libcloudproviders support
authorJulius Härtl <jus@bitgrid.net>
Thu, 10 Aug 2017 20:30:36 +0000 (22:30 +0200)
committerMatthias Clasen <mclasen@redhat.com>
Fri, 25 Aug 2017 20:58:21 +0000 (16:58 -0400)
Add integration of the libcloudproviders DBus API to the
GtkPlacesSidebar by showing name and sync status of the cloud providers.
The exported menu is rendered as a GtkPopover.

The sidebar will be updated if the list of cloudproviders changes e.g.
by adding or removing an account. If any cloud provider changes detailed
information like sync status only the individual sidebar row gets
updated.

Co-authored-by: Carlos Soriano <csoriano@gnome.org>
https://bugzilla.gnome.org/show_bug.cgi?id=786123

configure.ac
gtk/gtkplacessidebar.c
gtk/gtkplacessidebarprivate.h
gtk/gtksidebarrow.c
gtk/gtksidebarrowprivate.h
gtk/ui/gtksidebarrow.ui

index 4eee8712a6826b1e69eacb2be930413f6c7c6e49..480f487221455287d4506488646e28d5464893ed 100644 (file)
@@ -64,6 +64,7 @@ m4_define([wayland_protocols_required_version], [1.9])
 m4_define([mirclient_required_version], [0.22.0])
 m4_define([mircookie_required_version], [0.17.0])
 m4_define([epoxy_required_version], [1.0])
+m4_define([cloudproviders_required_version], [1.0])
 GLIB_REQUIRED_VERSION=glib_required_version
 PANGO_REQUIRED_VERSION=pango_required_version
 ATK_REQUIRED_VERSION=atk_required_version
@@ -346,6 +347,11 @@ AC_ARG_ENABLE(mir-backend,
                               [enable the Mir gdk backend])],
                              [backend_set=yes])
 
+AC_ARG_ENABLE(cloudproviders,
+              [AS_HELP_STRING([--enable-cloudproviders],
+                              [enable libcloudproviders integration])],
+                              [cloudproviders_set=yes])
+
 if test -z "$backend_set"; then
   if test "$platform_win32" = yes; then
     enable_win32_backend=yes
@@ -1341,11 +1347,26 @@ else
         LIBS="$gtk_save_LIBS"
 fi
 
+# Check for libcloudproviders
+
+CLOUDPROVIDER_PACKAGES=""
+if test "x$cloudproviders_set" = "xyes"; then
+  CLOUDPROVIDER_PACKAGES="cloudproviders >= cloudproviders_required_version"
+  if $PKG_CONFIG --exists $CLOUDPROVIDER_PACKAGES ; then
+    AC_DEFINE(HAVE_CLOUDPROVIDERS, [1],
+              [Define if libcloudproviders is available]
+              )
+  else
+    AC_MSG_ERROR([
+*** libcloudproviders not found.])
+  fi
+fi
+
 CFLAGS="$saved_cflags"
 LDFLAGS="$saved_ldflags"
 
 GDK_PACKAGES="$PANGO_PACKAGES gdk-pixbuf-2.0 >= gdk_pixbuf_required_version cairo >= cairo_required_version cairo-gobject >= cairo_required_version"
-GDK_PRIVATE_PACKAGES="$GDK_GIO_PACKAGE $X_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES $cairo_backends epoxy >= epoxy_required_version"
+GDK_PRIVATE_PACKAGES="$GDK_GIO_PACKAGE $X_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES $cairo_backends epoxy >= epoxy_required_version $CLOUDPROVIDER_PACKAGES"
 
 PKG_CHECK_MODULES(GDK_DEP, $GDK_PACKAGES $GDK_PRIVATE_PACKAGES)
 GDK_DEP_LIBS="$GDK_EXTRA_LIBS $GDK_DEP_LIBS $MATH_LIB"
index b8d59852abec81a568e71323db04d75e4db448f4..d684f6719a79cb3e9401f692b5580d778bbbffc3 100644 (file)
 #include "config.h"
 
 #include <gio/gio.h>
+#ifdef HAVE_CLOUDPROVIDERS
+#include <cloudproviders/cloudproviders.h>
+#include <cloudproviders/cloudproviderproxy.h>
+#endif
 
 #include "gtkplacessidebarprivate.h"
 #include "gtksidebarrowprivate.h"
@@ -121,6 +125,9 @@ struct _GtkPlacesSidebar {
   GtkWidget *new_bookmark_row;
 
   GtkBookmarksManager     *bookmarks_manager;
+#ifdef HAVE_CLOUDPROVIDERS
+  CloudProviders *cloud_manager;
+#endif
   GVolumeMonitor    *volume_monitor;
   GtkTrashMonitor   *trash_monitor;
   GtkSettings       *gtk_settings;
@@ -150,6 +157,8 @@ struct _GtkPlacesSidebar {
   DropState drop_state;
   GtkGesture *long_press_gesture;
 
+  GList *cloud_rows;
+
   /* volume mounting - delayed open process */
   GtkPlacesOpenFlags go_to_after_mount_open_flags;
   GCancellable *cancellable;
@@ -164,6 +173,8 @@ struct _GtkPlacesSidebar {
 
   GtkPlacesOpenFlags open_flags;
 
+  GActionGroup *action_group;
+
   guint mounting               : 1;
   guint  drag_data_received    : 1;
   guint drop_occurred          : 1;
@@ -444,11 +455,17 @@ add_place (GtkPlacesSidebar            *sidebar,
            GtkPlacesSidebarPlaceType    place_type,
            GtkPlacesSidebarSectionType  section_type,
            const gchar                 *name,
-           GIcon                       *icon,
+           GIcon                       *start_icon,
+           GIcon                       *end_icon,
            const gchar                 *uri,
            GDrive                      *drive,
            GVolume                     *volume,
            GMount                      *mount,
+#ifdef HAVE_CLOUDPROVIDERS
+           CloudProviderProxy          *cloud_provider_proxy,
+#else
+           gpointer                    *cloud_provider_proxy,
+#endif
            const gint                   index,
            const gchar                 *tooltip)
 {
@@ -468,7 +485,8 @@ add_place (GtkPlacesSidebar            *sidebar,
 
   row = g_object_new (GTK_TYPE_SIDEBAR_ROW,
                       "sidebar", sidebar,
-                      "icon", icon,
+                      "start-icon", start_icon,
+                      "end-icon", end_icon,
                       "label", name,
                       "tooltip", tooltip,
                       "ejectable", show_eject_button,
@@ -479,6 +497,9 @@ add_place (GtkPlacesSidebar            *sidebar,
                       "drive", drive,
                       "volume", volume,
                       "mount", mount,
+#ifdef HAVE_CLOUDPROVIDERS
+                      "cloud-provider", cloud_provider_proxy,
+#endif
                       NULL);
 
   eject_button = gtk_sidebar_row_get_eject_button (GTK_SIDEBAR_ROW (row));
@@ -604,7 +625,7 @@ add_special_dirs (GtkPlacesSidebar *sidebar)
     {
       const gchar *path;
       GFile *root;
-      GIcon *icon;
+      GIcon *start_icon;
       gchar *name;
       gchar *mount_uri;
       gchar *tooltip;
@@ -629,18 +650,18 @@ add_special_dirs (GtkPlacesSidebar *sidebar)
       if (!name)
         name = g_file_get_basename (root);
 
-      icon = special_directory_get_gicon (index);
+      start_icon = special_directory_get_gicon (index);
       mount_uri = g_file_get_uri (root);
       tooltip = g_file_get_parse_name (root);
 
       add_place (sidebar, PLACES_XDG_DIR,
                  SECTION_COMPUTER,
-                 name, icon, mount_uri,
-                 NULL, NULL, NULL, 0,
+                 name, start_icon, NULL, mount_uri,
+                 NULL, NULL, NULL, NULL, 0,
                  tooltip);
       g_free (name);
       g_object_unref (root);
-      g_object_unref (icon);
+      g_object_unref (start_icon);
       g_free (mount_uri);
       g_free (tooltip);
 
@@ -743,11 +764,11 @@ on_app_shortcuts_query_complete (GObject      *source,
       gchar *uri;
       gchar *tooltip;
       const gchar *name;
-      GIcon *icon;
+      GIcon *start_icon;
       int pos = 0;
 
       name = g_file_info_get_display_name (info);
-      icon = g_file_info_get_symbolic_icon (info);
+      start_icon = g_file_info_get_symbolic_icon (info);
       uri = g_file_get_uri (file);
       tooltip = g_file_get_parse_name (file);
 
@@ -760,8 +781,8 @@ on_app_shortcuts_query_complete (GObject      *source,
 
       add_place (sidebar, PLACES_BUILT_IN,
                  SECTION_COMPUTER,
-                 name, icon, uri,
-                 NULL, NULL, NULL,
+                 name, start_icon, NULL, uri,
+                 NULL, NULL, NULL, NULL,
                  pos,
                  tooltip);
 
@@ -816,7 +837,7 @@ on_bookmark_query_info_complete (GObject      *source,
   gchar *bookmark_name;
   gchar *mount_uri;
   gchar *tooltip;
-  GIcon *icon;
+  GIcon *start_icon;
 
   info = g_file_query_info_finish (root, result, &error);
   if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
@@ -837,23 +858,23 @@ on_bookmark_query_info_complete (GObject      *source,
     }
 
   if (info)
-    icon = g_object_ref (g_file_info_get_symbolic_icon (info));
+    start_icon = g_object_ref (g_file_info_get_symbolic_icon (info));
   else
-    icon = g_themed_icon_new_with_default_fallbacks (clos->is_native ? ICON_NAME_FOLDER : ICON_NAME_FOLDER_NETWORK);
+    start_icon = g_themed_icon_new_with_default_fallbacks (clos->is_native ? ICON_NAME_FOLDER : ICON_NAME_FOLDER_NETWORK);
 
   mount_uri = g_file_get_uri (root);
   tooltip = g_file_get_parse_name (root);
 
   add_place (sidebar, PLACES_BOOKMARK,
              SECTION_BOOKMARKS,
-             bookmark_name, icon, mount_uri,
-             NULL, NULL, NULL, clos->index,
+             bookmark_name, start_icon, NULL, mount_uri,
+             NULL, NULL, NULL, NULL, clos->index,
              tooltip);
 
   g_free (mount_uri);
   g_free (tooltip);
   g_free (bookmark_name);
-  g_object_unref (icon);
+  g_object_unref (start_icon);
 
 out:
   g_clear_object (&info);
@@ -893,11 +914,69 @@ update_trash_icon (GtkPlacesSidebar *sidebar)
       GIcon *icon;
 
       icon = _gtk_trash_monitor_get_icon (sidebar->trash_monitor);
-      gtk_sidebar_row_set_icon (GTK_SIDEBAR_ROW (sidebar->trash_row), icon);
+      gtk_sidebar_row_set_start_icon (GTK_SIDEBAR_ROW (sidebar->trash_row), icon);
       g_object_unref (icon);
     }
 }
 
+#ifdef HAVE_CLOUDPROVIDERS
+static void
+cloud_row_update (CloudProviderProxy *cloud_provider_proxy,
+                  GtkWidget          *cloud_row)
+{
+  GIcon *end_icon;
+  gint provider_status;
+  provider_status = cloud_provider_proxy_get_status (cloud_provider_proxy);
+  switch (provider_status)
+    {
+      case CLOUD_PROVIDER_STATUS_IDLE:
+        end_icon = NULL;
+        break;
+
+      case CLOUD_PROVIDER_STATUS_SYNCING:
+        end_icon = g_themed_icon_new ("emblem-synchronizing-symbolic");
+        break;
+
+      case CLOUD_PROVIDER_STATUS_ERROR:
+        end_icon = g_themed_icon_new ("dialog-warning-symbolic");
+        break;
+
+      default:
+        return;
+    }
+
+  gtk_sidebar_row_set_end_icon (GTK_SIDEBAR_ROW (cloud_row), end_icon);
+  if (end_icon != NULL)
+    g_object_unref (end_icon);
+
+  g_object_set (cloud_row,
+                "label", cloud_provider_proxy_get_name (cloud_provider_proxy),
+                NULL);
+  g_object_set (cloud_row,
+                "tooltip", cloud_provider_proxy_get_status_details (cloud_provider_proxy),
+                NULL);
+
+}
+
+void
+cloud_row_destroy (GtkWidget *object,
+                   gpointer   user_data)
+{
+  GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
+  CloudProviderProxy *cloud_provider_proxy = NULL;
+  g_object_get (GTK_SIDEBAR_ROW (object), "cloud-provider", &cloud_provider_proxy, NULL);
+  if (cloud_provider_proxy != NULL)
+    {
+      g_signal_handlers_disconnect_matched (cloud_provider_proxy,
+                                            G_SIGNAL_MATCH_DATA,
+                                            0, 0, 0, cloud_row_update, object);
+      g_object_unref (object);
+      g_object_unref (cloud_provider_proxy);
+    }
+  sidebar->cloud_rows = g_list_remove (sidebar->cloud_rows, object);
+}
+#endif
+
 static void
 update_places (GtkPlacesSidebar *sidebar)
 {
@@ -912,11 +991,16 @@ update_places (GtkPlacesSidebar *sidebar)
   gchar *original_uri, *mount_uri, *name, *identifier;
   GtkListBoxRow *selected;
   gchar *home_uri;
-  GIcon *icon;
+  GIcon *start_icon;
+  GIcon *end_icon;
   GFile *root;
   gchar *tooltip;
   GList *network_mounts, *network_volumes;
   GIcon *new_bookmark_icon;
+#ifdef HAVE_CLOUDPROVIDERS
+  GList *cloud_provider_proxies;
+  guint provider_status;
+#endif
   GtkStyleContext *context;
 
   /* save original selection */
@@ -944,24 +1028,24 @@ update_places (GtkPlacesSidebar *sidebar)
   if (should_show_recent (sidebar))
     {
       mount_uri = "recent:///";
-      icon = g_themed_icon_new_with_default_fallbacks ("document-open-recent-symbolic");
+      start_icon = g_themed_icon_new_with_default_fallbacks ("document-open-recent-symbolic");
       add_place (sidebar, PLACES_BUILT_IN,
                  SECTION_COMPUTER,
-                 _("Recent"), icon, mount_uri,
-                 NULL, NULL, NULL, 0,
+                 _("Recent"), start_icon, NULL, mount_uri,
+                 NULL, NULL, NULL, NULL, 0,
                  _("Recent files"));
-      g_object_unref (icon);
+      g_object_unref (start_icon);
     }
 
   /* home folder */
   home_uri = get_home_directory_uri ();
-  icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_HOME);
+  start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_HOME);
   add_place (sidebar, PLACES_BUILT_IN,
              SECTION_COMPUTER,
-             _("Home"), icon, home_uri,
-             NULL, NULL, NULL, 0,
+             _("Home"), start_icon, NULL, home_uri,
+             NULL, NULL, NULL, NULL, 0,
              _("Open your personal folder"));
-  g_object_unref (icon);
+  g_object_unref (start_icon);
   g_free (home_uri);
 
   /* desktop */
@@ -970,13 +1054,13 @@ update_places (GtkPlacesSidebar *sidebar)
       mount_uri = get_desktop_directory_uri ();
       if (mount_uri)
         {
-          icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_DESKTOP);
+          start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_DESKTOP);
           add_place (sidebar, PLACES_BUILT_IN,
                      SECTION_COMPUTER,
-                     _("Desktop"), icon, mount_uri,
-                     NULL, NULL, NULL, 0,
+                     _("Desktop"), start_icon, NULL, mount_uri,
+                     NULL, NULL, NULL, NULL, 0,
                      _("Open the contents of your desktop in a folder"));
-          g_object_unref (icon);
+          g_object_unref (start_icon);
           g_free (mount_uri);
         }
     }
@@ -986,33 +1070,83 @@ update_places (GtkPlacesSidebar *sidebar)
 
   if (sidebar->show_enter_location)
     {
-      icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_NETWORK_SERVER);
+      start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_NETWORK_SERVER);
       add_place (sidebar, PLACES_ENTER_LOCATION,
                  SECTION_COMPUTER,
-                 _("Enter Location"), icon, NULL,
-                 NULL, NULL, NULL, 0,
+                 _("Enter Location"), start_icon, NULL, NULL,
+                 NULL, NULL, NULL, NULL, 0,
                  _("Manually enter a location"));
-      g_object_unref (icon);
+      g_object_unref (start_icon);
     }
 
   /* Trash */
   if (!sidebar->local_only && sidebar->show_trash)
     {
-      mount_uri = "trash:///"; /* No need to strdup */
-      icon = _gtk_trash_monitor_get_icon (sidebar->trash_monitor);
+      start_icon = _gtk_trash_monitor_get_icon (sidebar->trash_monitor);
       sidebar->trash_row = add_place (sidebar, PLACES_BUILT_IN,
                                       SECTION_COMPUTER,
-                                      _("Trash"), icon, mount_uri,
-                                      NULL, NULL, NULL, 0,
+                                      _("Trash"), start_icon, NULL, "trash:///",
+                                      NULL, NULL, NULL, NULL, 0,
                                       _("Open the trash"));
       g_object_add_weak_pointer (G_OBJECT (sidebar->trash_row),
                                  (gpointer *) &sidebar->trash_row);
-      g_object_unref (icon);
+      g_object_unref (start_icon);
     }
 
   /* Application-side shortcuts */
   add_application_shortcuts (sidebar);
 
+  /* Cloud providers */
+#ifdef HAVE_CLOUDPROVIDERS
+  cloud_provider_proxies = cloud_providers_get_providers (sidebar->cloud_manager);
+  for (l = cloud_provider_proxies; l != NULL; l = l->next)
+    {
+      start_icon = cloud_provider_proxy_get_icon (l->data);
+      name = cloud_provider_proxy_get_name (l->data);
+      provider_status = cloud_provider_proxy_get_status (l->data);
+      mount_uri = cloud_provider_proxy_get_path (l->data);
+      if (start_icon == NULL
+          || name == NULL
+          || provider_status == CLOUD_PROVIDER_STATUS_INVALID
+          || mount_uri == NULL)
+        continue;
+      mount_uri = g_strconcat ("file://", cloud_provider_proxy_get_path (l->data), NULL);
+      switch (provider_status)
+        {
+        case CLOUD_PROVIDER_STATUS_IDLE:
+          end_icon = NULL;
+          break;
+
+        case CLOUD_PROVIDER_STATUS_SYNCING:
+          end_icon = g_themed_icon_new ("emblem-synchronizing-symbolic");
+          break;
+
+        case CLOUD_PROVIDER_STATUS_ERROR:
+          end_icon = g_themed_icon_new ("dialog-warning-symbolic");
+          break;
+
+        default:
+          continue;
+        }
+
+      /* translators: %s is the name of a cloud provider for files */
+      tooltip = g_strdup_printf (_("Open %s"), name);
+
+      GtkWidget *cloud_row = NULL;
+      cloud_row = add_place (sidebar, PLACES_BUILT_IN,
+                               SECTION_CLOUD,
+                               name, start_icon, end_icon, mount_uri,
+                               NULL, NULL, NULL, l->data, 0,
+                               tooltip);
+
+      g_signal_connect (l->data, "changed", G_CALLBACK (cloud_row_update), cloud_row);
+      g_signal_connect (cloud_row, "destroy", G_CALLBACK (cloud_row_destroy), sidebar);
+      g_object_ref (cloud_row);
+      g_object_ref (l->data);
+      sidebar->cloud_rows = g_list_append (sidebar->cloud_rows, cloud_row);
+    }
+#endif
+
   /* go through all connected drives */
   drives = g_volume_monitor_get_connected_drives (sidebar->volume_monitor);
 
@@ -1046,19 +1180,19 @@ update_places (GtkPlacesSidebar *sidebar)
               if (mount != NULL)
                 {
                   /* Show mounted volume in the sidebar */
-                  icon = g_mount_get_symbolic_icon (mount);
+                  start_icon = g_mount_get_symbolic_icon (mount);
                   root = g_mount_get_default_location (mount);
                   mount_uri = g_file_get_uri (root);
                   name = g_mount_get_name (mount);
                   tooltip = g_file_get_parse_name (root);
 
                   add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                             SECTION_MOUNTS,
-                             name, icon, mount_uri,
-                             drive, volume, mount, 0, tooltip);
+                             SECTION_DEVICES,
+                             name, start_icon, NULL, mount_uri,
+                             drive, volume, mount, NULL, 0, tooltip);
                   g_object_unref (root);
                   g_object_unref (mount);
-                  g_object_unref (icon);
+                  g_object_unref (start_icon);
                   g_free (tooltip);
                   g_free (name);
                   g_free (mount_uri);
@@ -1073,15 +1207,15 @@ update_places (GtkPlacesSidebar *sidebar)
                    * cue that the user should remember to yank out the media if
                    * he just unmounted it.
                    */
-                  icon = g_volume_get_symbolic_icon (volume);
+                  start_icon = g_volume_get_symbolic_icon (volume);
                   name = g_volume_get_name (volume);
                   tooltip = g_strdup_printf (_("Mount and open “%s”"), name);
 
                   add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                             SECTION_MOUNTS,
-                             name, icon, NULL,
-                             drive, volume, NULL, 0, tooltip);
-                  g_object_unref (icon);
+                             SECTION_DEVICES,
+                             name, start_icon, NULL, NULL,
+                             drive, volume, NULL, NULL, 0, tooltip);
+                  g_object_unref (start_icon);
                   g_free (name);
                   g_free (tooltip);
                 }
@@ -1101,15 +1235,15 @@ update_places (GtkPlacesSidebar *sidebar)
                * work.. but it's also for human beings who like to turn off media detection
                * in the OS to save battery juice.
                */
-              icon = g_drive_get_symbolic_icon (drive);
+              start_icon = g_drive_get_symbolic_icon (drive);
               name = g_drive_get_name (drive);
               tooltip = g_strdup_printf (_("Mount and open “%s”"), name);
 
               add_place (sidebar, PLACES_BUILT_IN,
-                         SECTION_MOUNTS,
-                         name, icon, NULL,
-                         drive, NULL, NULL, 0, tooltip);
-              g_object_unref (icon);
+                         SECTION_DEVICES,
+                         name, start_icon, NULL, NULL,
+                         drive, NULL, NULL, NULL, 0, tooltip);
+              g_object_unref (start_icon);
               g_free (tooltip);
               g_free (name);
             }
@@ -1149,18 +1283,19 @@ update_places (GtkPlacesSidebar *sidebar)
       mount = g_volume_get_mount (volume);
       if (mount != NULL)
         {
-          icon = g_mount_get_symbolic_icon (mount);
+          char *mount_uri;
+          start_icon = g_mount_get_symbolic_icon (mount);
           root = g_mount_get_default_location (mount);
           mount_uri = g_file_get_uri (root);
           tooltip = g_file_get_parse_name (root);
           name = g_mount_get_name (mount);
           add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                     SECTION_MOUNTS,
-                     name, icon, mount_uri,
-                     NULL, volume, mount, 0, tooltip);
+                     SECTION_DEVICES,
+                     name, start_icon, NULL, mount_uri,
+                     NULL, volume, mount, NULL, 0, tooltip);
           g_object_unref (mount);
           g_object_unref (root);
-          g_object_unref (icon);
+          g_object_unref (start_icon);
           g_free (name);
           g_free (tooltip);
           g_free (mount_uri);
@@ -1168,13 +1303,13 @@ update_places (GtkPlacesSidebar *sidebar)
       else
         {
           /* see comment above in why we add an icon for an unmounted mountable volume */
-          icon = g_volume_get_symbolic_icon (volume);
+          start_icon = g_volume_get_symbolic_icon (volume);
           name = g_volume_get_name (volume);
           add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                     SECTION_MOUNTS,
-                     name, icon, NULL,
-                     NULL, volume, NULL, 0, name);
-          g_object_unref (icon);
+                     SECTION_DEVICES,
+                     name, start_icon, NULL, NULL,
+                     NULL, volume, NULL, NULL, 0, name);
+          g_object_unref (start_icon);
           g_free (name);
         }
       g_object_unref (volume);
@@ -1185,13 +1320,13 @@ update_places (GtkPlacesSidebar *sidebar)
   if (!sidebar->show_other_locations)
     {
       mount_uri = "file:///"; /* No need to strdup */
-      icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_FILESYSTEM);
+      start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_FILESYSTEM);
       add_place (sidebar, PLACES_BUILT_IN,
-                 SECTION_MOUNTS,
-                 sidebar->hostname, icon, mount_uri,
-                 NULL, NULL, NULL, 0,
+                 SECTION_DEVICES,
+                 sidebar->hostname, start_icon, NULL, mount_uri,
+                 NULL, NULL, NULL, NULL, 0,
                  _("Open the contents of the file system"));
-      g_object_unref (icon);
+      g_object_unref (start_icon);
     }
 
   /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
@@ -1221,17 +1356,17 @@ update_places (GtkPlacesSidebar *sidebar)
           continue;
         }
 
-      icon = g_mount_get_symbolic_icon (mount);
+      start_icon = g_mount_get_symbolic_icon (mount);
       mount_uri = g_file_get_uri (root);
       name = g_mount_get_name (mount);
       tooltip = g_file_get_parse_name (root);
       add_place (sidebar, PLACES_MOUNTED_VOLUME,
                  SECTION_COMPUTER,
-                 name, icon, mount_uri,
-                 NULL, NULL, mount, 0, tooltip);
+                 name, start_icon, NULL, mount_uri,
+                 NULL, NULL, mount, NULL, 0, tooltip);
       g_object_unref (root);
       g_object_unref (mount);
-      g_object_unref (icon);
+      g_object_unref (start_icon);
       g_free (name);
       g_free (mount_uri);
       g_free (tooltip);
@@ -1274,8 +1409,8 @@ update_places (GtkPlacesSidebar *sidebar)
   new_bookmark_icon = g_themed_icon_new ("bookmark-new-symbolic");
   sidebar->new_bookmark_row = add_place (sidebar, PLACES_DROP_FEEDBACK,
                                          SECTION_BOOKMARKS,
-                                         _("New bookmark"), new_bookmark_icon, NULL,
-                                         NULL, NULL, NULL, 0,
+                                         _("New bookmark"), new_bookmark_icon, NULL, NULL,
+                                         NULL, NULL, NULL, NULL, 0,
                                          _("Add a new bookmark"));
   context = gtk_widget_get_style_context (sidebar->new_bookmark_row);
   gtk_style_context_add_class (context, "sidebar-new-bookmark-row");
@@ -1286,14 +1421,22 @@ update_places (GtkPlacesSidebar *sidebar)
     {
       if (sidebar->show_connect_to_server)
         {
-          icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_NETWORK_SERVER);
+          start_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 Server"), start_icon, NULL,
+                     NULL, NULL, NULL, NULL, NULL, 0,
                      _("Connect to a network server address"));
-          g_object_unref (icon);
+          g_object_unref (start_icon);
         }
+      mount_uri = "network:///";
+      start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_NETWORK);
+      add_place (sidebar, PLACES_BUILT_IN,
+                 SECTION_NETWORK,
+                 _("Browse Network"), start_icon, NULL, mount_uri,
+                 NULL, NULL, NULL, NULL, 0,
+                 _("Browse the contents of the network"));
+      g_object_unref (start_icon);
 
       network_volumes = g_list_reverse (network_volumes);
       for (l = network_volumes; l != NULL; l = l->next)
@@ -1308,15 +1451,15 @@ update_places (GtkPlacesSidebar *sidebar)
             }
           else
             {
-              icon = g_volume_get_symbolic_icon (volume);
+              start_icon = g_volume_get_symbolic_icon (volume);
               name = g_volume_get_name (volume);
               tooltip = g_strdup_printf (_("Mount and open “%s”"), name);
 
               add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                         SECTION_MOUNTS,
-                         name, icon, NULL,
-                         NULL, volume, NULL, 0, tooltip);
-              g_object_unref (icon);
+                         SECTION_NETWORK,
+                         name, start_icon, NULL, NULL,
+                         NULL, volume, NULL, NULL, 0, tooltip);
+              g_object_unref (start_icon);
               g_free (name);
               g_free (tooltip);
             }
@@ -1327,16 +1470,16 @@ update_places (GtkPlacesSidebar *sidebar)
         {
           mount = l->data;
           root = g_mount_get_default_location (mount);
-          icon = g_mount_get_symbolic_icon (mount);
+          start_icon = g_mount_get_symbolic_icon (mount);
           mount_uri = g_file_get_uri (root);
           name = g_mount_get_name (mount);
           tooltip = g_file_get_parse_name (root);
           add_place (sidebar, PLACES_MOUNTED_VOLUME,
-                     SECTION_MOUNTS,
-                     name, icon, mount_uri,
-                     NULL, NULL, mount, 0, tooltip);
+                     SECTION_NETWORK,
+                     name, start_icon, NULL, mount_uri,
+                     NULL, NULL, mount, NULL, 0, tooltip);
           g_object_unref (root);
-          g_object_unref (icon);
+          g_object_unref (start_icon);
           g_free (name);
           g_free (mount_uri);
           g_free (tooltip);
@@ -1349,14 +1492,14 @@ update_places (GtkPlacesSidebar *sidebar)
   /* Other locations */
   if (sidebar->show_other_locations)
     {
-      icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_OTHER_LOCATIONS);
+      start_icon = g_themed_icon_new_with_default_fallbacks (ICON_NAME_OTHER_LOCATIONS);
 
       add_place (sidebar, PLACES_OTHER_LOCATIONS,
                  SECTION_OTHER_LOCATIONS,
-                 _("Other Locations"), icon, "other-locations:///",
-                 NULL, NULL, NULL, 0, _("Show other locations"));
+                 _("Other Locations"), start_icon, NULL, "other-locations:///",
+                 NULL, NULL, NULL, NULL, 0, _("Show other locations"));
 
-      g_object_unref (icon);
+      g_object_unref (start_icon);
     }
 
   gtk_widget_show_all (GTK_WIDGET (sidebar));
@@ -3391,6 +3534,53 @@ on_row_popover_destroy (GtkWidget        *row_popover,
     sidebar->popover = NULL;
 }
 
+#ifdef HAVE_CLOUDPROVIDERS
+static void
+build_popup_menu_using_gmenu (GtkSidebarRow *row)
+{
+  CloudProviderProxy *cloud_provider_proxy;
+  GtkPlacesSidebar *sidebar;
+  GMenuModel *cloud_provider_menu;
+  GActionGroup *cloud_provider_action_group;
+
+  g_object_get (row,
+                "sidebar", &sidebar,
+                "cloud-provider", &cloud_provider_proxy,
+                NULL);
+
+  /* Cloud provider */
+  if (cloud_provider_proxy)
+    {
+      GMenu *menu = g_menu_new ();
+      GMenuItem *item;
+      item = g_menu_item_new ("_Open", "row.open");
+      g_menu_item_set_action_and_target_value (item, "row.open", g_variant_new_int32(GTK_PLACES_OPEN_NORMAL));
+      g_menu_append_item (menu, item);
+      item = g_menu_item_new ("Open in new tab", "row.open-other");
+      g_menu_item_set_action_and_target_value (item, "row.open-other", g_variant_new_int32(GTK_PLACES_OPEN_NEW_TAB));
+      g_menu_append_item (menu, item);
+      item = g_menu_item_new ("Open in new window", "row.open-other");
+      g_menu_item_set_action_and_target_value (item, "row.open-other", g_variant_new_int32(GTK_PLACES_OPEN_NEW_WINDOW));
+      g_menu_append_item (menu, item);
+      cloud_provider_menu = cloud_provider_proxy_get_menu_model (cloud_provider_proxy);
+      g_menu_append_section (menu, NULL, cloud_provider_menu);
+      cloud_provider_action_group = cloud_provider_proxy_get_action_group (cloud_provider_proxy);
+      gtk_widget_insert_action_group (GTK_WIDGET (sidebar),
+                                      "cloudprovider",
+                                      G_ACTION_GROUP (cloud_provider_action_group));
+      add_actions (sidebar);
+      if (sidebar->popover)
+        gtk_widget_destroy (sidebar->popover);
+
+      sidebar->popover = gtk_popover_new_from_model (GTK_WIDGET (sidebar),
+                                                     G_MENU_MODEL (menu));
+      g_signal_connect (sidebar->popover, "destroy", G_CALLBACK (on_row_popover_destroy), sidebar);
+      g_object_unref (sidebar);
+      g_object_unref (cloud_provider_proxy);
+    }
+}
+#endif
+
 /* Constructs the popover for the sidebar row if needed */
 static void
 create_row_popover (GtkPlacesSidebar *sidebar,
@@ -3399,6 +3589,17 @@ create_row_popover (GtkPlacesSidebar *sidebar,
   PopoverData data;
   GtkWidget *box;
 
+#ifdef HAVE_CLOUDPROVIDERS
+  CloudProviderProxy *cloud_provider_proxy;
+
+  g_object_get (row, "cloud-provider", &cloud_provider_proxy, NULL);
+
+  if (cloud_provider_proxy) {
+    build_popup_menu_using_gmenu (row);
+    return;
+  }
+#endif
+
   sidebar->popover = gtk_popover_new (GTK_WIDGET (sidebar));
   /* Clean sidebar pointer when its destroyed, most of the times due to its
    * relative_to associated row being destroyed */
@@ -3895,6 +4096,17 @@ gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
   g_object_get (sidebar->gtk_settings, "gtk-shell-shows-desktop", &show_desktop, NULL);
   sidebar->show_desktop = show_desktop;
 
+  /* Cloud providers */
+#ifdef HAVE_CLOUDPROVIDERS
+  sidebar->cloud_rows = NULL;
+  sidebar->cloud_manager = cloud_providers_dup_singleton ();
+  g_signal_connect_swapped (sidebar->cloud_manager,
+                            "owners-changed",
+                            G_CALLBACK (update_places),
+                            sidebar);
+  cloud_providers_update (sidebar->cloud_manager);
+#endif
+
   /* populate the sidebar */
   update_places (sidebar);
 
index 73a636cdb3fc33069126403df3bd0684e4af07db..30ec2c1081477d0bf02fdb012997b0f74a89bb10 100644 (file)
@@ -31,6 +31,9 @@ typedef enum {
   SECTION_INVALID,
   SECTION_COMPUTER,
   SECTION_MOUNTS,
+  SECTION_CLOUD,
+  SECTION_DEVICES,
+  SECTION_NETWORK,
   SECTION_BOOKMARKS,
   SECTION_OTHER_LOCATIONS,
   N_SECTIONS
index f8e25b44ab33d96318c1d3540996a2ceec1305d6..d5cd89235395be9b6aacf11d700e2ef80017b9a2 100644 (file)
 #include "gtkstylecontext.h"
 #include "gtkrevealer.h"
 #include "gtkselection.h"
+#ifdef HAVE_CLOUDPROVIDERS
+#include <cloudproviders/cloudproviderproxy.h>
+#endif
 
 struct _GtkSidebarRow
 {
   GtkListBoxRow parent_instance;
-  GIcon *icon;
-  GtkWidget *icon_widget;
+  GIcon *start_icon;
+  GIcon *end_icon;
+  GtkWidget *start_icon_widget;
+  GtkWidget *end_icon_widget;
   gchar *label;
   gchar *tooltip;
   GtkWidget *label_widget;
@@ -44,6 +49,7 @@ struct _GtkSidebarRow
   GDrive *drive;
   GVolume *volume;
   GMount *mount;
+  GObject *cloud_provider;
   gboolean placeholder;
   GtkPlacesSidebar *sidebar;
   GtkWidget *event_box;
@@ -55,7 +61,8 @@ G_DEFINE_TYPE (GtkSidebarRow, gtk_sidebar_row, GTK_TYPE_LIST_BOX_ROW)
 enum
 {
   PROP_0,
-  PROP_ICON,
+  PROP_START_ICON,
+  PROP_END_ICON,
   PROP_LABEL,
   PROP_TOOLTIP,
   PROP_EJECTABLE,
@@ -67,6 +74,7 @@ enum
   PROP_DRIVE,
   PROP_VOLUME,
   PROP_MOUNT,
+  PROP_CLOUD_PROVIDER,
   PROP_PLACEHOLDER,
   LAST_PROP
 };
@@ -87,8 +95,12 @@ gtk_sidebar_row_get_property (GObject    *object,
       g_value_set_object (value, self->sidebar);
       break;
 
-    case PROP_ICON:
-      g_value_set_object (value, self->icon);
+    case PROP_START_ICON:
+      g_value_set_object (value, self->start_icon);
+      break;
+
+    case PROP_END_ICON:
+      g_value_set_object (value, self->end_icon);
       break;
 
     case PROP_LABEL:
@@ -131,6 +143,10 @@ gtk_sidebar_row_get_property (GObject    *object,
       g_value_set_object (value, self->mount);
       break;
 
+    case PROP_CLOUD_PROVIDER:
+      g_value_set_object (value, self->cloud_provider);
+      break;
+
     case PROP_PLACEHOLDER:
       g_value_set_boolean (value, self->placeholder);
       break;
@@ -155,9 +171,43 @@ gtk_sidebar_row_set_property (GObject      *object,
       self->sidebar = g_value_get_object (value);
       break;
 
-    case PROP_ICON:
-      gtk_sidebar_row_set_icon (self, g_value_get_object (value));
-      break;
+    case PROP_START_ICON:
+      {
+        g_clear_object (&self->start_icon);
+        object = g_value_get_object (value);
+        if (object != NULL)
+          {
+            self->start_icon = g_object_ref (object);
+            gtk_image_set_from_gicon (GTK_IMAGE (self->start_icon_widget),
+                                      self->start_icon,
+                                      GTK_ICON_SIZE_MENU);
+          }
+        else
+          {
+            gtk_image_clear (GTK_IMAGE (self->start_icon_widget));
+          }
+        break;
+      }
+
+    case PROP_END_ICON:
+      {
+        g_clear_object (&self->end_icon);
+        object = g_value_get_object (value);
+        if (object != NULL)
+          {
+            self->end_icon = g_object_ref (object);
+            gtk_image_set_from_gicon (GTK_IMAGE (self->end_icon_widget),
+                                      self->end_icon,
+                                      GTK_ICON_SIZE_MENU);
+            gtk_widget_show (self->end_icon_widget);
+          }
+        else
+          {
+            gtk_image_clear (GTK_IMAGE (self->end_icon_widget));
+            gtk_widget_hide (self->end_icon_widget);
+          }
+        break;
+      }
 
     case PROP_LABEL:
       g_free (self->label);
@@ -213,33 +263,48 @@ gtk_sidebar_row_set_property (GObject      *object,
       g_set_object (&self->mount, g_value_get_object (value));
       break;
 
+    case PROP_CLOUD_PROVIDER:
+      {
+#ifdef HAVE_CLOUDPROVIDERS
+        gpointer *object;
+        object = g_value_get_object (value);
+        if (IS_CLOUD_PROVIDER_PROXY(object))
+          self->cloud_provider = g_object_ref (object);
+#endif
+        break;
+      }
+
     case PROP_PLACEHOLDER:
-      self->placeholder = g_value_get_boolean (value);
-      if (self->placeholder)
-        {
-          g_clear_object (&self->icon);
-          g_free (self->label);
-          self->label = NULL;
-          g_free (self->tooltip);
-          self->tooltip = NULL;
-          gtk_widget_set_tooltip_text (GTK_WIDGET (self), NULL);
-          self->ejectable = FALSE;
-          self->section_type = SECTION_BOOKMARKS;
-          self->place_type = PLACES_BOOKMARK_PLACEHOLDER;
-          g_free (self->uri);
-          self->uri = NULL;
-          g_clear_object (&self->drive);
-          g_clear_object (&self->volume);
-          g_clear_object (&self->mount);
-
-          gtk_container_foreach (GTK_CONTAINER (self),
-                                 (GtkCallback) gtk_widget_destroy,
-                                 NULL);
-
-          context = gtk_widget_get_style_context (GTK_WIDGET (self));
-          gtk_style_context_add_class (context, "sidebar-placeholder-row");
-        }
-      break;
+      {
+        self->placeholder = g_value_get_boolean (value);
+        if (self->placeholder)
+          {
+            g_clear_object (&self->start_icon);
+            g_clear_object (&self->end_icon);
+            g_free (self->label);
+            self->label = NULL;
+            g_free (self->tooltip);
+            self->tooltip = NULL;
+            gtk_widget_set_tooltip_text (GTK_WIDGET (self), NULL);
+            self->ejectable = FALSE;
+            self->section_type = SECTION_BOOKMARKS;
+            self->place_type = PLACES_BOOKMARK_PLACEHOLDER;
+            g_free (self->uri);
+            self->uri = NULL;
+            g_clear_object (&self->drive);
+            g_clear_object (&self->volume);
+            g_clear_object (&self->mount);
+
+            gtk_container_foreach (GTK_CONTAINER (self),
+                                   (GtkCallback) gtk_widget_destroy,
+                                   NULL);
+
+            context = gtk_widget_get_style_context (GTK_WIDGET (self));
+            gtk_style_context_add_class (context, "sidebar-placeholder-row");
+          }
+
+        break;
+      }
 
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -281,21 +346,41 @@ gtk_sidebar_row_hide (GtkSidebarRow *self,
 }
 
 void
-gtk_sidebar_row_set_icon (GtkSidebarRow *self,
-                          GIcon         *icon)
+gtk_sidebar_row_set_start_icon (GtkSidebarRow *self,
+                                GIcon         *icon)
+{
+  g_return_if_fail (GTK_IS_SIDEBAR_ROW (self));
+
+  if (self->start_icon != icon)
+    {
+      g_set_object (&self->start_icon, icon);
+      if (self->start_icon != NULL)
+        gtk_image_set_from_gicon (GTK_IMAGE (self->start_icon_widget), self->start_icon,
+                                  GTK_ICON_SIZE_MENU);
+      else
+        gtk_image_clear (GTK_IMAGE (self->start_icon_widget));
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_START_ICON]);
+    }
+}
+
+void
+gtk_sidebar_row_set_end_icon (GtkSidebarRow *self,
+                              GIcon         *icon)
 {
   g_return_if_fail (GTK_IS_SIDEBAR_ROW (self));
 
-  if (self->icon != icon)
+  if (self->end_icon != icon)
     {
-      g_set_object (&self->icon, icon);
-      if (self->icon != NULL)
-        gtk_image_set_from_gicon (GTK_IMAGE (self->icon_widget), self->icon,
+      g_set_object (&self->end_icon, icon);
+      if (self->end_icon != NULL)
+        gtk_image_set_from_gicon (GTK_IMAGE (self->end_icon_widget), self->end_icon,
                                   GTK_ICON_SIZE_MENU);
       else
-        gtk_image_clear (GTK_IMAGE (self->icon_widget));
+        if (self->end_icon_widget != NULL)
+          gtk_image_clear (GTK_IMAGE (self->end_icon_widget));
 
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON]);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_END_ICON]);
     }
 }
 
@@ -304,7 +389,8 @@ gtk_sidebar_row_finalize (GObject *object)
 {
   GtkSidebarRow *self = GTK_SIDEBAR_ROW (object);
 
-  g_clear_object (&self->icon);
+  g_clear_object (&self->start_icon);
+  g_clear_object (&self->end_icon);
   g_free (self->label);
   self->label = NULL;
   g_free (self->tooltip);
@@ -343,10 +429,18 @@ gtk_sidebar_row_class_init (GtkSidebarRowClass *klass)
                           G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS));
 
-  properties [PROP_ICON] =
-    g_param_spec_object ("icon",
-                         "icon",
-                         "The place icon.",
+  properties [PROP_START_ICON] =
+    g_param_spec_object ("start-icon",
+                         "start-icon",
+                         "The start icon.",
+                         G_TYPE_ICON,
+                         (G_PARAM_READWRITE |
+                          G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_END_ICON] =
+    g_param_spec_object ("end-icon",
+                         "end-icon",
+                         "The end icon.",
                          G_TYPE_ICON,
                          (G_PARAM_READWRITE |
                           G_PARAM_STATIC_STRINGS));
@@ -437,6 +531,14 @@ gtk_sidebar_row_class_init (GtkSidebarRowClass *klass)
                           G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_CLOUD_PROVIDER] =
+    g_param_spec_object ("cloud-provider",
+                         "CloudProviderProxy",
+                         "CloudProviderProxy",
+                         G_TYPE_OBJECT,
+                         (G_PARAM_READWRITE |
+                          G_PARAM_STATIC_STRINGS));
+
   properties [PROP_PLACEHOLDER] =
     g_param_spec_boolean ("placeholder",
                           "Placeholder",
@@ -451,7 +553,8 @@ gtk_sidebar_row_class_init (GtkSidebarRowClass *klass)
   gtk_widget_class_set_template_from_resource (widget_class,
                                                "/org/gtk/libgtk/ui/gtksidebarrow.ui");
 
-  gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, icon_widget);
+  gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, start_icon_widget);
+  gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, end_icon_widget);
   gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, label_widget);
   gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, eject_button);
   gtk_widget_class_bind_template_child (widget_class, GtkSidebarRow, event_box);
@@ -461,13 +564,13 @@ gtk_sidebar_row_class_init (GtkSidebarRowClass *klass)
   gtk_widget_class_set_css_name (widget_class, "row");
 }
 
-
 GtkSidebarRow*
 gtk_sidebar_row_clone (GtkSidebarRow *self)
 {
  return g_object_new (GTK_TYPE_SIDEBAR_ROW,
                       "sidebar", self->sidebar,
-                      "icon", self->icon,
+                      "start-icon", self->start_icon,
+                      "end-icon", self->end_icon,
                       "label", self->label,
                       "tooltip", self->tooltip,
                       "ejectable", self->ejectable,
@@ -478,16 +581,17 @@ gtk_sidebar_row_clone (GtkSidebarRow *self)
                       "drive", self->drive,
                       "volume", self->volume,
                       "mount", self->mount,
+                      "cloud-provider", self->cloud_provider,
                       NULL);
 }
 
-GtkWidget *
+GtkWidget*
 gtk_sidebar_row_get_eject_button (GtkSidebarRow *self)
 {
   return self->eject_button;
 }
 
-GtkWidget *
+GtkWidget*
 gtk_sidebar_row_get_event_box (GtkSidebarRow *self)
 {
   return self->event_box;
index d13dc6d830ce59a7cd7784e6025afac837966a3a..5b53a4b145311b3231039b139cae49e7756c26ed 100644 (file)
@@ -50,7 +50,9 @@ void           gtk_sidebar_row_reveal (GtkSidebarRow *self);
 
 GtkWidget     *gtk_sidebar_row_get_eject_button (GtkSidebarRow *self);
 GtkWidget     *gtk_sidebar_row_get_event_box    (GtkSidebarRow *self);
-void           gtk_sidebar_row_set_icon         (GtkSidebarRow *self,
+void           gtk_sidebar_row_set_start_icon   (GtkSidebarRow *self,
+                                                 GIcon         *icon);
+void           gtk_sidebar_row_set_end_icon     (GtkSidebarRow *self,
                                                  GIcon         *icon);
 
 G_END_DECLS
index 05d10ee06af13cbe54edbc2f6f04676638f9f706..4cbcd9001c62e4cd4f70468f5442f32d25ed5845 100644 (file)
@@ -22,8 +22,8 @@
               <object class="GtkBox">
                 <property name="visible">1</property>
                 <child>
-                  <object class="GtkImage" id="icon_widget">
-                    <property name="visible">1</property>
+                  <object class="GtkImage" id="start_icon_widget">
+                    <property name="visible">True</property>
                     <style>
                       <class name="sidebar-icon"/>
                     </style>
                     </style>
                   </object>
                 </child>
+                <child>
+                  <object class="GtkImage" id="end_icon_widget">
+                    <property name="visible">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="halign">end</property>
+                    <property name="valign">center</property>
+                    <style>
+                      <class name="sidebar-icon"/>
+                    </style>
+                  </object>
+                </child>
                 <child>
                   <object class="GtkButton" id="eject_button">
                     <property name="visible">1</property>
       </object>
     </child>
   </template>
+  <!-- We need it to not make the row smaller when the eject button is hidden -->
+  <object class="GtkSizeGroup">
+    <property name="mode">vertical</property>
+    <widgets>
+      <widget name="eject_button"/>
+      <widget name="label_widget"/>
+      <widget name="start_icon_widget"/>
+      <widget name="end_icon_widget"/>
+    </widgets>
+  </object>
 </interface>