[nautilus/wip/gbsneto/other-locations: 1/12] operations: implement new design



commit a5dec27cac7e151bc28500d6ccd154db9bbc26fc
Author: Carlos Soriano <csoriano gnome org>
Date:   Wed Jul 1 15:53:43 2015 +0200

    operations: implement new design
    
    Now operations reside in the toolbar, in form of a button with
    a popover. In this way we avoid to have a nautilus window hanging
    around for it.
    When no nautilus window is open, the persistence handlers of nautilus
    are enough. This use a notification if the server supports it or
    a systray icon in case it doesn't.

 libnautilus-private/nautilus-file-operations.c     |   28 ++-
 libnautilus-private/nautilus-file-operations.h     |    2 +
 .../nautilus-progress-info-manager.c               |   16 ++-
 .../nautilus-progress-info-manager.h               |    3 +-
 libnautilus-private/nautilus-progress-info.c       |   46 ++++-
 libnautilus-private/nautilus-progress-info.h       |    7 +
 src/Makefile.am                                    |    4 +-
 src/nautilus-application-actions.c                 |   13 -
 src/nautilus-application.c                         |   13 +-
 src/nautilus-application.h                         |    6 -
 src/nautilus-progress-info-widget.c                |    8 +-
 src/nautilus-progress-info-widget.h                |    4 +-
 src/nautilus-progress-info-widget.xml              |   85 +++----
 ...r.c => nautilus-progress-persistence-handler.c} |  250 +++++++++-----------
 src/nautilus-progress-persistence-handler.h        |   65 +++++
 src/nautilus-progress-ui-handler.h                 |   64 -----
 src/nautilus-toolbar-ui.xml                        |   53 ++++
 src/nautilus-toolbar.c                             |  232 ++++++++++++++++++
 test/test-copy.c                                   |    2 +-
 19 files changed, 608 insertions(+), 293 deletions(-)
---
diff --git a/libnautilus-private/nautilus-file-operations.c b/libnautilus-private/nautilus-file-operations.c
index acb4c7c..7762916 100644
--- a/libnautilus-private/nautilus-file-operations.c
+++ b/libnautilus-private/nautilus-file-operations.c
@@ -1478,13 +1478,18 @@ report_delete_progress (CommonJob *job,
                                            f (_("Deleting files")));
 
        elapsed = g_timer_elapsed (job->time, NULL);
-       if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE) {
+        transfer_rate = 0;
+        remaining_time = INT_MAX;
+       if (elapsed > 0) {
+               transfer_rate = transfer_info->num_files / elapsed;
+                if (transfer_rate > 0)
+                       remaining_time = (source_info->num_files - transfer_info->num_files) / transfer_rate;
+       }
 
+       if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE) {
                nautilus_progress_info_set_details (job->progress, files_left_s);
        } else {
                char *details, *time_left_s;
-               transfer_rate = transfer_info->num_files / elapsed;
-               remaining_time = files_left / transfer_rate;
 
                /* To translators: %T will expand to a time like "2 minutes".
                 * The singular/plural form will be used depending on the remaining time (i.e. the %T 
argument).
@@ -1500,6 +1505,12 @@ report_delete_progress (CommonJob *job,
                g_free (time_left_s);
        }
 
+        if (elapsed > SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE) {
+                nautilus_progress_info_set_remaining_time (job->progress,
+                                                           remaining_time);
+                nautilus_progress_info_set_elapsed_time (job->progress,
+                                                         elapsed);
+        }
        g_free (files_left_s);
 
        if (source_info->num_files != 0) {
@@ -3039,8 +3050,11 @@ report_copy_progress (CopyMoveJob *copy_job,
        
        elapsed = g_timer_elapsed (job->time, NULL);
        transfer_rate = 0;
+        remaining_time = INT_MAX;
        if (elapsed > 0) {
                transfer_rate = transfer_info->num_bytes / elapsed;
+                if (transfer_rate > 0)
+                       remaining_time = (total_size - transfer_info->num_bytes) / transfer_rate;
        }
 
        if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE &&
@@ -3051,7 +3065,6 @@ report_copy_progress (CopyMoveJob *copy_job,
                nautilus_progress_info_take_details (job->progress, s);
        } else {
                char *s;
-               remaining_time = (total_size - transfer_info->num_bytes) / transfer_rate;
 
                /* To translators: %S will expand to a size like "2 bytes" or "3 MB", %T to a time duration 
like
                 * "2 minutes". So the whole thing will be something like "2 kb of 4 MB -- 2 hours left 
(4kb/sec)"
@@ -3067,6 +3080,13 @@ report_copy_progress (CopyMoveJob *copy_job,
                nautilus_progress_info_take_details (job->progress, s);
        }
 
+        if (elapsed > SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE) {
+                nautilus_progress_info_set_remaining_time (job->progress,
+                                                           remaining_time);
+                nautilus_progress_info_set_elapsed_time (job->progress,
+                                                         elapsed);
+        }
+
        nautilus_progress_info_set_progress (job->progress, transfer_info->num_bytes, total_size);
 }
 
diff --git a/libnautilus-private/nautilus-file-operations.h b/libnautilus-private/nautilus-file-operations.h
index e65ba7d..38b714f 100644
--- a/libnautilus-private/nautilus-file-operations.h
+++ b/libnautilus-private/nautilus-file-operations.h
@@ -28,6 +28,8 @@
 #include <gtk/gtk.h>
 #include <gio/gio.h>
 
+#define SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE 1
+
 typedef void (* NautilusCopyCallback)      (GHashTable *debuting_uris,
                                            gboolean    success,
                                            gpointer    callback_data);
diff --git a/libnautilus-private/nautilus-progress-info-manager.c 
b/libnautilus-private/nautilus-progress-info-manager.c
index 97343ee..401cd47 100644
--- a/libnautilus-private/nautilus-progress-info-manager.c
+++ b/libnautilus-private/nautilus-progress-info-manager.c
@@ -111,7 +111,7 @@ progress_info_finished_cb (NautilusProgressInfo *info,
 }
 
 NautilusProgressInfoManager *
-nautilus_progress_info_manager_new (void)
+nautilus_progress_info_manager_dup_singleton (void)
 {
        return g_object_new (NAUTILUS_TYPE_PROGRESS_INFO_MANAGER, NULL);
 }
@@ -139,3 +139,17 @@ nautilus_progress_info_manager_get_all_infos (NautilusProgressInfoManager *self)
 {
        return self->priv->progress_infos;
 }
+
+gboolean
+nautilus_progress_manager_are_all_infos_finished (NautilusProgressInfoManager *self)
+{
+        GList *l;
+
+        for (l = self->priv->progress_infos; l != NULL; l = l->next) {
+                if (!nautilus_progress_info_get_is_finished (l->data)) {
+                      return FALSE;
+                    }
+        }
+
+        return TRUE;
+}
diff --git a/libnautilus-private/nautilus-progress-info-manager.h 
b/libnautilus-private/nautilus-progress-info-manager.h
index 21c22f0..da0eda7 100644
--- a/libnautilus-private/nautilus-progress-info-manager.h
+++ b/libnautilus-private/nautilus-progress-info-manager.h
@@ -57,11 +57,12 @@ struct _NautilusProgressInfoManagerClass {
 
 GType nautilus_progress_info_manager_get_type (void);
 
-NautilusProgressInfoManager* nautilus_progress_info_manager_new (void);
+NautilusProgressInfoManager* nautilus_progress_info_manager_dup_singleton (void);
 
 void nautilus_progress_info_manager_add_new_info (NautilusProgressInfoManager *self,
                                                   NautilusProgressInfo *info);
 GList *nautilus_progress_info_manager_get_all_infos (NautilusProgressInfoManager *self);
+gboolean nautilus_progress_manager_are_all_infos_finished (NautilusProgressInfoManager *self);
 
 G_END_DECLS
 
diff --git a/libnautilus-private/nautilus-progress-info.c b/libnautilus-private/nautilus-progress-info.c
index 16b2cb2..389aaeb 100644
--- a/libnautilus-private/nautilus-progress-info.c
+++ b/libnautilus-private/nautilus-progress-info.c
@@ -50,6 +50,8 @@ struct _NautilusProgressInfo
        char *status;
        char *details;
        double progress;
+        gdouble remaining_time;
+        gdouble elapsed_time;
        gboolean activity_mode;
        gboolean started;
        gboolean finished;
@@ -162,7 +164,7 @@ nautilus_progress_info_init (NautilusProgressInfo *info)
 
        info->cancellable = g_cancellable_new ();
 
-       manager = nautilus_progress_info_manager_new ();
+       manager = nautilus_progress_info_manager_dup_singleton ();
        nautilus_progress_info_manager_add_new_info (manager, info);
        g_object_unref (manager);
 }
@@ -570,3 +572,45 @@ nautilus_progress_info_set_progress (NautilusProgressInfo *info,
        
        G_UNLOCK (progress_info);
 }
+
+void
+nautilus_progress_info_set_remaining_time (NautilusProgressInfo *info,
+                                           gdouble               time)
+{
+        G_LOCK (progress_info);
+        info->remaining_time = time;
+        G_UNLOCK (progress_info);
+}
+
+gdouble
+nautilus_progress_info_get_remaining_time (NautilusProgressInfo *info)
+{
+        gint remaining_time;
+
+        G_LOCK (progress_info);
+        remaining_time = info->remaining_time;
+        G_UNLOCK (progress_info);
+
+        return remaining_time;
+}
+
+void
+nautilus_progress_info_set_elapsed_time (NautilusProgressInfo *info,
+                                         gdouble               time)
+{
+        G_LOCK (progress_info);
+        info->elapsed_time = time;
+        G_UNLOCK (progress_info);
+}
+
+gdouble
+nautilus_progress_info_get_elapsed_time (NautilusProgressInfo *info)
+{
+        gint elapsed_time;
+
+        G_LOCK (progress_info);
+        elapsed_time = info->elapsed_time;
+        G_UNLOCK (progress_info);
+
+        return elapsed_time;
+}
diff --git a/libnautilus-private/nautilus-progress-info.h b/libnautilus-private/nautilus-progress-info.h
index edca861..0ce0ad1 100644
--- a/libnautilus-private/nautilus-progress-info.h
+++ b/libnautilus-private/nautilus-progress-info.h
@@ -78,6 +78,13 @@ void          nautilus_progress_info_set_progress    (NautilusProgressInfo *info
                                                      double                total);
 void          nautilus_progress_info_pulse_progress  (NautilusProgressInfo *info);
 
+void          nautilus_progress_info_set_remaining_time (NautilusProgressInfo *info,
+                                                         gdouble               time);
+gdouble       nautilus_progress_info_get_remaining_time (NautilusProgressInfo *info);
+void          nautilus_progress_info_set_elapsed_time (NautilusProgressInfo *info,
+                                                       gdouble               time);
+gdouble       nautilus_progress_info_get_elapsed_time (NautilusProgressInfo *info);
+
 
 
 #endif /* NAUTILUS_PROGRESS_INFO_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 72a07c3..7de649b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -189,8 +189,8 @@ nautilus_SOURCES = \
        nautilus-previewer.h                    \
        nautilus-progress-info-widget.c         \
        nautilus-progress-info-widget.h         \
-       nautilus-progress-ui-handler.c          \
-       nautilus-progress-ui-handler.h          \
+       nautilus-progress-persistence-handler.c \
+       nautilus-progress-persistence-handler.h \
        nautilus-properties-window.c            \
        nautilus-properties-window.h            \
        nautilus-query-editor.c                 \
diff --git a/src/nautilus-application-actions.c b/src/nautilus-application-actions.c
index 3caa09e..17c4b68 100644
--- a/src/nautilus-application-actions.c
+++ b/src/nautilus-application-actions.c
@@ -217,18 +217,6 @@ action_search (GSimpleAction *action,
 }
 
 static void
-action_show_file_transfers (GSimpleAction *action,
-                           GVariant *parameter,
-                           gpointer user_data)
-{
-       NautilusApplication *application = user_data;
-       NautilusProgressUIHandler *progress_handler;
-
-       progress_handler = nautilus_application_get_progress_ui_handler (application);
-       nautilus_progress_ui_handler_ensure_window (progress_handler);
-}
-
-static void
 action_show_hide_sidebar (GSimpleAction *action,
                          GVariant      *state,
                          gpointer       user_data)
@@ -261,7 +249,6 @@ static GActionEntry app_entries[] = {
        { "kill", action_kill, NULL, NULL, NULL },
        { "open-desktop", action_open_desktop, NULL, NULL, NULL },
        { "close-desktop", action_close_desktop, NULL, NULL, NULL },
-       { "show-file-transfers", action_show_file_transfers, NULL, NULL, NULL }
 };
 
 void
diff --git a/src/nautilus-application.c b/src/nautilus-application.c
index bde2330..19ce99a 100644
--- a/src/nautilus-application.c
+++ b/src/nautilus-application.c
@@ -37,6 +37,7 @@
 #include "nautilus-freedesktop-dbus.h"
 #include "nautilus-image-properties-page.h"
 #include "nautilus-previewer.h"
+#include "nautilus-progress-persistence-handler.h"
 #include "nautilus-self-check-functions.h"
 #include "nautilus-shell-search-provider.h"
 #include "nautilus-window.h"
@@ -70,7 +71,7 @@
 G_DEFINE_TYPE (NautilusApplication, nautilus_application, GTK_TYPE_APPLICATION);
 
 struct _NautilusApplicationPriv {
-       NautilusProgressUIHandler *progress_handler;
+       NautilusProgressPersistenceHandler *progress_handler;
        NautilusDBusManager *dbus_manager;
        NautilusFreedesktopDBus *fdb_manager;
 
@@ -104,13 +105,6 @@ nautilus_application_get_windows (NautilusApplication *application)
        return application->priv->windows;
 }
 
-
-NautilusProgressUIHandler *
-nautilus_application_get_progress_ui_handler (NautilusApplication *application)
-{
-       return application->priv->progress_handler;
-}
-
 NautilusBookmarkList *
 nautilus_application_get_bookmarks (NautilusApplication *application)
 {
@@ -996,7 +990,7 @@ nautilus_application_startup (GApplication *app)
        menu_provider_init_callback ();
        
        /* Initialize the UI handler singleton for file operations */
-       self->priv->progress_handler = nautilus_progress_ui_handler_new ();
+       self->priv->progress_handler = nautilus_progress_persistence_handler_new (G_OBJECT (self));
 
        /* Check the user's .nautilus directories and post warnings
         * if there are problems.
@@ -1169,6 +1163,7 @@ nautilus_application_window_removed (GtkApplication *app,
        /* if this was the last window, close the previewer */
        if (g_list_length (self->priv->windows) == 0) {
                nautilus_previewer_call_close ();
+                nautilus_progress_persistence_handler_make_persistent (self->priv->progress_handler);
        }
 }
 
diff --git a/src/nautilus-application.h b/src/nautilus-application.h
index 3dd4af5..cc53e51 100644
--- a/src/nautilus-application.h
+++ b/src/nautilus-application.h
@@ -27,7 +27,6 @@
 #include <gtk/gtk.h>
 
 #include "nautilus-bookmark-list.h"
-#include "nautilus-progress-ui-handler.h"
 #include "nautilus-window.h"
 
 #define NAUTILUS_DESKTOP_ICON_VIEW_IID "OAFIID:Nautilus_File_Manager_Desktop_Canvas_View"
@@ -79,9 +78,4 @@ NautilusBookmarkList *
 void nautilus_application_edit_bookmarks (NautilusApplication *application,
                                          NautilusWindow      *window);
 
-GtkWidget * nautilus_application_connect_server (NautilusApplication *application,
-                                                NautilusWindow      *window);
-
-NautilusProgressUIHandler * nautilus_application_get_progress_ui_handler (NautilusApplication *application);
-
 #endif /* __NAUTILUS_APPLICATION_H__ */
diff --git a/src/nautilus-progress-info-widget.c b/src/nautilus-progress-info-widget.c
index 86b34fd..7834676 100644
--- a/src/nautilus-progress-info-widget.c
+++ b/src/nautilus-progress-info-widget.c
@@ -42,7 +42,7 @@ enum {
 static GParamSpec *properties[NUM_PROPERTIES] = { NULL };
 
 G_DEFINE_TYPE_WITH_PRIVATE (NautilusProgressInfoWidget, nautilus_progress_info_widget,
-                            GTK_TYPE_BOX);
+                            GTK_TYPE_GRID);
 
 static void
 info_finished (NautilusProgressInfoWidget *self)
@@ -93,6 +93,9 @@ nautilus_progress_info_widget_dispose (GObject *obj)
 {
        NautilusProgressInfoWidget *self = NAUTILUS_PROGRESS_INFO_WIDGET (obj);
 
+        if (self->priv->info != NULL) {
+                g_signal_handlers_disconnect_by_data (self->priv->info, self);
+        }
        g_clear_object (&self->priv->info);
 
        G_OBJECT_CLASS (nautilus_progress_info_widget_parent_class)->dispose (obj);
@@ -185,8 +188,5 @@ nautilus_progress_info_widget_new (NautilusProgressInfo *info)
 {
        return g_object_new (NAUTILUS_TYPE_PROGRESS_INFO_WIDGET,
                             "info", info,
-                            "orientation", GTK_ORIENTATION_VERTICAL,
-                            "homogeneous", FALSE,
-                            "spacing", 5,
                             NULL);
 }
diff --git a/src/nautilus-progress-info-widget.h b/src/nautilus-progress-info-widget.h
index 5bb40c9..f1c99c0 100644
--- a/src/nautilus-progress-info-widget.h
+++ b/src/nautilus-progress-info-widget.h
@@ -44,14 +44,14 @@
 typedef struct _NautilusProgressInfoWidgetPrivate NautilusProgressInfoWidgetPrivate;
 
 typedef struct {
-       GtkBox parent;
+       GtkGrid parent;
 
        /* private */
        NautilusProgressInfoWidgetPrivate *priv;
 } NautilusProgressInfoWidget;
 
 typedef struct {
-       GtkBoxClass parent_class;
+       GtkGridClass parent_class;
 } NautilusProgressInfoWidgetClass;
 
 GType nautilus_progress_info_widget_get_type (void);
diff --git a/src/nautilus-progress-info-widget.xml b/src/nautilus-progress-info-widget.xml
index e4a9802..3eace47 100644
--- a/src/nautilus-progress-info-widget.xml
+++ b/src/nautilus-progress-info-widget.xml
@@ -1,67 +1,59 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <template class="NautilusProgressInfoWidget" parent="GtkBox">
+  <template class="NautilusProgressInfoWidget" parent="GtkGrid">
     <property name="visible">True</property>
-    <property name="margin">5</property>
-    <property name="orientation">vertical</property>
+    <property name="margin-start">5</property>
+    <property name="margin-end">5</property>
     <child>
       <object class="GtkLabel" id="status">
         <property name="label">status</property>
         <property name="visible">True</property>
         <property name="xalign">0</property>
-        <property name="width-request">400</property>
-        <property name="wrap">True</property>
-        <property name="wrap-mode">word-char</property>
+        <property name="width-request">300</property>
+        <property name="max-width-chars">30</property>
+        <property name="ellipsize">middle</property>
+        <property name="margin-bottom">6</property>
       </object>
       <packing>
-        <property name="expand">False</property>
-        <property name="fill">True</property>
-        <property name="position">0</property>
+        <property name="top-attach">0</property>
+        <property name="left-attach">0</property>
       </packing>
     </child>
     <child>
-      <object class="GtkBox" id="box2">
+      <object class="GtkProgressBar" id="progress_bar">
         <property name="visible">True</property>
+        <property name="valign">center</property>
+        <property name="pulse-step">0.05</property>
+        <property name="margin_start">2</property>
+        <property name="margin-bottom">4</property>
+      </object>
+      <packing>
+        <property name="top-attach">1</property>
+        <property name="left-attach">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="cancel">
+        <property name="visible">True</property>
+        <property name="receives_default">True</property>
+        <property name="margin_start">20</property>
+        <property name="valign">center</property>
+        <style>
+          <class name="image-button"/>
+          <class name="nautilus-circular-button"/>
+        </style>
         <child>
-          <object class="GtkProgressBar" id="progress_bar">
-            <property name="visible">True</property>
-            <property name="valign">center</property>
-            <property name="pulse-step">0.05</property>
-          </object>
-          <packing>
-            <property name="expand">True</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkButton" id="cancel">
+          <object class="GtkImage" id="cancel_icon">
             <property name="visible">True</property>
-            <property name="receives_default">True</property>
-            <property name="margin_start">20</property>
-            <style>
-              <class name="image-button"/>
-              <class name="nautilus-circular-button"/>
-            </style>
-            <child>
-              <object class="GtkImage" id="cancel_icon">
-                <property name="visible">True</property>
-                <property name="icon-name">window-close-symbolic</property>
-                <property name="icon-size">1</property>
-              </object>
-            </child>
+            <property name="icon-name">window-close-symbolic</property>
+            <property name="icon-size">1</property>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
         </child>
       </object>
       <packing>
-        <property name="expand">False</property>
-        <property name="fill">True</property>
-        <property name="position">1</property>
+        <property name="height">3</property>
+        <property name="top-attach">0</property>
+        <property name="left-attach">1</property>
       </packing>
     </child>
     <child>
@@ -78,9 +70,8 @@
         </style>
       </object>
       <packing>
-        <property name="expand">False</property>
-        <property name="fill">True</property>
-        <property name="position">2</property>
+        <property name="top-attach">2</property>
+        <property name="left-attach">0</property>
       </packing>
     </child>
   </template>
diff --git a/src/nautilus-progress-ui-handler.c b/src/nautilus-progress-persistence-handler.c
similarity index 60%
rename from src/nautilus-progress-ui-handler.c
rename to src/nautilus-progress-persistence-handler.c
index 21722df..10e9fc4 100644
--- a/src/nautilus-progress-ui-handler.c
+++ b/src/nautilus-progress-persistence-handler.c
@@ -1,8 +1,8 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 /*
- * nautilus-progress-ui-handler.c: file operation progress user interface.
+ * nautilus-progress-persistence-handler.c: file operation progress systray icon and notification handler.
  *
- * Copyright (C) 2007, 2011 Red Hat, Inc.
+ * Copyright (C) 2007, 2011, 2015 Red Hat, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -19,12 +19,13 @@
  *
  * Authors: Alexander Larsson <alexl redhat com>
  *          Cosimo Cecchi <cosimoc redhat com>
+ *          Carlos Soriano <csoriano gnome com>
  *
  */
 
 #include <config.h>
 
-#include "nautilus-progress-ui-handler.h"
+#include "nautilus-progress-persistence-handler.h"
 
 #include "nautilus-application.h"
 #include "nautilus-progress-info-widget.h"
@@ -34,17 +35,16 @@
 #include <libnautilus-private/nautilus-progress-info.h>
 #include <libnautilus-private/nautilus-progress-info-manager.h>
 
-struct _NautilusProgressUIHandlerPriv {
+struct _NautilusProgressPersistenceHandlerPriv {
        NautilusProgressInfoManager *manager;
 
-       GtkWidget *progress_dialog;
-       GtkWidget *content_area;
+        NautilusApplication *app;
        guint active_infos;
 
        GtkStatusIcon *status_icon;
 };
 
-G_DEFINE_TYPE (NautilusProgressUIHandler, nautilus_progress_ui_handler, G_TYPE_OBJECT);
+G_DEFINE_TYPE (NautilusProgressPersistenceHandler, nautilus_progress_persistence_handler, G_TYPE_OBJECT);
 
 /* Our policy for showing progress notification is the following:
  * - file operations that end within two seconds do not get notified in any way
@@ -66,15 +66,41 @@ G_DEFINE_TYPE (NautilusProgressUIHandler, nautilus_progress_ui_handler, G_TYPE_O
 static gboolean server_has_persistence (void);
 
 static void
-status_icon_activate_cb (GtkStatusIcon *icon,
-                        NautilusProgressUIHandler *self)
-{      
+show_file_transfers (NautilusProgressPersistenceHandler *self)
+{
+        GFile *home;
+
+        home = g_file_new_for_path (g_get_home_dir ());
+        nautilus_application_open_location (self->priv->app, home, NULL, NULL);
+
+        g_object_unref (home);
+}
+
+static void
+action_show_file_transfers (GSimpleAction *action,
+                           GVariant *parameter,
+                           gpointer user_data)
+{
+        NautilusProgressPersistenceHandler *self;
+
+        self = NAUTILUS_PROGRESS_PERSISTENCE_HANDLER (user_data);
+        show_file_transfers (self);
+}
+
+static GActionEntry progress_persistence_entries[] = {
+       { "show-file-transfers", action_show_file_transfers, NULL, NULL, NULL }
+};
+
+static void
+status_icon_activate_cb (GtkStatusIcon                      *icon,
+                         NautilusProgressPersistenceHandler *self)
+{
        gtk_status_icon_set_visible (icon, FALSE);
-       gtk_window_present (GTK_WINDOW (self->priv->progress_dialog));
+        show_file_transfers (self);
 }
 
 static void
-progress_ui_handler_ensure_status_icon (NautilusProgressUIHandler *self)
+progress_persistence_handler_ensure_status_icon (NautilusProgressPersistenceHandler *self)
 {
        GIcon *icon;
        GtkStatusIcon *status_icon;
@@ -96,7 +122,7 @@ progress_ui_handler_ensure_status_icon (NautilusProgressUIHandler *self)
 }
 
 static void
-progress_ui_handler_update_notification (NautilusProgressUIHandler *self)
+progress_persistence_handler_update_notification (NautilusProgressPersistenceHandler *self)
 {
         GNotification *notification;
        gchar *body;
@@ -120,11 +146,11 @@ progress_ui_handler_update_notification (NautilusProgressUIHandler *self)
 }
 
 static void
-progress_ui_handler_update_status_icon (NautilusProgressUIHandler *self)
+progress_persistence_handler_update_status_icon (NautilusProgressPersistenceHandler *self)
 {
        gchar *tooltip;
 
-       progress_ui_handler_ensure_status_icon (self);
+       progress_persistence_handler_ensure_status_icon (self);
 
        tooltip = g_strdup_printf (ngettext ("%'d file operation active",
                                             "%'d file operations active",
@@ -136,81 +162,34 @@ progress_ui_handler_update_status_icon (NautilusProgressUIHandler *self)
        gtk_status_icon_set_visible (self->priv->status_icon, TRUE);
 }
 
-static gboolean
-progress_window_delete_event (GtkWidget *widget,
-                             GdkEvent *event,
-                             NautilusProgressUIHandler *self)
-{
-       gtk_widget_hide (widget);
-
-       if (server_has_persistence ()) {
-               progress_ui_handler_update_notification (self);
-       } else {
-               progress_ui_handler_update_status_icon (self);
-       }
-
-       return TRUE;
-}
-
-static void
-progress_ui_handler_ensure_window (NautilusProgressUIHandler *self)
+void
+nautilus_progress_persistence_handler_make_persistent (NautilusProgressPersistenceHandler *self)
 {
-       GtkWidget *progress_dialog;
-       
-       if (self->priv->progress_dialog != NULL) {
-               return;
-       }
-       
-       progress_dialog = g_object_new (GTK_TYPE_DIALOG, "use-header-bar", TRUE, NULL);
-       self->priv->progress_dialog = progress_dialog;
-       gtk_window_set_resizable (GTK_WINDOW (progress_dialog),
-                                 FALSE);
-       gtk_container_set_border_width (GTK_CONTAINER (progress_dialog), 10);
- 
-       gtk_window_set_title (GTK_WINDOW (progress_dialog),
-                             _("File Operations"));
-       gtk_window_set_wmclass (GTK_WINDOW (progress_dialog),
-                               "file_progress", "Nautilus");
-       gtk_window_set_position (GTK_WINDOW (progress_dialog),
-                                GTK_WIN_POS_CENTER);
-       gtk_window_set_icon_name (GTK_WINDOW (progress_dialog),
-                               "system-file-manager");
-
-       self->priv->content_area = gtk_dialog_get_content_area (GTK_DIALOG (self->priv->progress_dialog));
-
-       g_signal_connect (progress_dialog,
-                         "delete-event",
-                         (GCallback) progress_window_delete_event, self);
+        GList *windows;
+
+        windows = nautilus_application_get_windows (self->priv->app);
+        if (self->priv->active_infos > 0 &&
+            g_list_length (windows) == 0) {
+               if (server_has_persistence ()) {
+                       progress_persistence_handler_update_notification (self);
+               } else {
+                       progress_persistence_handler_update_status_icon (self);
+               }
+        }
 }
 
 static void
-progress_ui_handler_update_notification_or_status (NautilusProgressUIHandler *self)
+progress_persistence_handler_update_notification_or_status (NautilusProgressPersistenceHandler *self)
 {
        if (server_has_persistence ()) {
-               progress_ui_handler_update_notification (self);
+               progress_persistence_handler_update_notification (self);
        } else {
-               progress_ui_handler_update_status_icon (self);
+               progress_persistence_handler_update_status_icon (self);
        }
 }
 
 static void
-progress_ui_handler_add_to_window (NautilusProgressUIHandler *self,
-                                  NautilusProgressInfo *info)
-{
-       GtkWidget *progress;
-
-       progress = nautilus_progress_info_widget_new (info);
-       progress_ui_handler_ensure_window (self);
-
-       gtk_box_pack_start (GTK_BOX (self->priv->content_area),
-                           progress,
-                           FALSE, FALSE, 6);
-
-       gtk_widget_show (progress);
-}
-
-static void
-progress_ui_handler_show_complete_notification (NautilusProgressUIHandler *self)
+progress_persistence_handler_show_complete_notification (NautilusProgressPersistenceHandler *self)
 {
        GNotification *complete_notification;
 
@@ -230,7 +209,7 @@ progress_ui_handler_show_complete_notification (NautilusProgressUIHandler *self)
 }
 
 static void
-progress_ui_handler_hide_notification_or_status (NautilusProgressUIHandler *self)
+progress_persistence_handler_hide_notification_or_status (NautilusProgressPersistenceHandler *self)
 {
        if (self->priv->status_icon != NULL) {
                gtk_status_icon_set_visible (self->priv->status_icon, FALSE);
@@ -241,50 +220,44 @@ progress_ui_handler_hide_notification_or_status (NautilusProgressUIHandler *self
 }
 
 static void
-progress_info_finished_cb (NautilusProgressInfo *info,
-                          NautilusProgressUIHandler *self)
+progress_info_finished_cb (NautilusProgressInfo               *info,
+                           NautilusProgressPersistenceHandler *self)
 {
+        GList *windows;
+
        self->priv->active_infos--;
 
-       if (self->priv->active_infos > 0) {
-               if (!gtk_widget_get_visible (self->priv->progress_dialog)) {
-                       progress_ui_handler_update_notification_or_status (self);
-               }
-       } else {
-               if (gtk_widget_get_visible (self->priv->progress_dialog)) {
-                       gtk_widget_hide (self->priv->progress_dialog);
-               } else {
-                       progress_ui_handler_hide_notification_or_status (self);
-                       progress_ui_handler_show_complete_notification (self);
-               }
-       }
+        windows = nautilus_application_get_windows (self->priv->app);
+        if (self->priv->active_infos > 0) {
+               if (g_list_length (windows) == 0) {
+                       progress_persistence_handler_update_notification_or_status (self);
+               }
+        } else if (g_list_length (windows)  == 0) {
+               progress_persistence_handler_hide_notification_or_status (self);
+               progress_persistence_handler_show_complete_notification (self);
+        }
+
 }
 
 static void
-handle_new_progress_info (NautilusProgressUIHandler *self,
-                         NautilusProgressInfo *info)
+handle_new_progress_info (NautilusProgressPersistenceHandler *self,
+                          NautilusProgressInfo               *info)
 {
+        GList *windows;
        g_signal_connect (info, "finished",
                          G_CALLBACK (progress_info_finished_cb), self);
 
        self->priv->active_infos++;
+        windows = nautilus_application_get_windows (self->priv->app);
 
-       if (self->priv->active_infos == 1) {
-               /* this is the only active operation, present the window */
-               progress_ui_handler_add_to_window (self, info);
-               gtk_window_present (GTK_WINDOW (self->priv->progress_dialog));
-       } else {
-               if (gtk_widget_get_visible (self->priv->progress_dialog)) {
-                       progress_ui_handler_add_to_window (self, info);
-               } else {
-                       progress_ui_handler_update_notification_or_status (self);
-               }
-       }
+       if (g_list_length (windows) == 0) {
+               progress_persistence_handler_update_notification_or_status (self);
+        }
 }
 
 typedef struct {
        NautilusProgressInfo *info;
-       NautilusProgressUIHandler *self;
+       NautilusProgressPersistenceHandler *self;
 } TimeoutData;
 
 static void
@@ -297,8 +270,8 @@ timeout_data_free (TimeoutData *data)
 }
 
 static TimeoutData *
-timeout_data_new (NautilusProgressUIHandler *self,
-                 NautilusProgressInfo *info)
+timeout_data_new (NautilusProgressPersistenceHandler *self,
+                  NautilusProgressInfo               *info)
 {
        TimeoutData *retval;
 
@@ -313,7 +286,7 @@ static gboolean
 new_op_started_timeout (TimeoutData *data)
 {
        NautilusProgressInfo *info = data->info;
-       NautilusProgressUIHandler *self = data->self;
+       NautilusProgressPersistenceHandler *self = data->self;
 
        if (nautilus_progress_info_get_is_paused (info)) {
                return TRUE;
@@ -329,16 +302,16 @@ new_op_started_timeout (TimeoutData *data)
 }
 
 static void
-release_application (NautilusProgressInfo *info,
-                    NautilusProgressUIHandler *self)
+release_application (NautilusProgressInfo               *info,
+                     NautilusProgressPersistenceHandler *self)
 {
        /* release the GApplication hold we acquired */
        g_application_release (g_application_get_default ());
 }
 
 static void
-progress_info_started_cb (NautilusProgressInfo *info,
-                         NautilusProgressUIHandler *self)
+progress_info_started_cb (NautilusProgressInfo               *info,
+                          NautilusProgressPersistenceHandler *self)
 {
        TimeoutData *data;
 
@@ -357,22 +330,22 @@ progress_info_started_cb (NautilusProgressInfo *info,
 }
 
 static void
-new_progress_info_cb (NautilusProgressInfoManager *manager,
-                     NautilusProgressInfo *info,
-                     NautilusProgressUIHandler *self)
+new_progress_info_cb (NautilusProgressInfoManager        *manager,
+                      NautilusProgressInfo               *info,
+                      NautilusProgressPersistenceHandler *self)
 {
        g_signal_connect (info, "started",
                          G_CALLBACK (progress_info_started_cb), self);
 }
 
 static void
-nautilus_progress_ui_handler_dispose (GObject *obj)
+nautilus_progress_persistence_handler_dispose (GObject *obj)
 {
-       NautilusProgressUIHandler *self = NAUTILUS_PROGRESS_UI_HANDLER (obj);
+       NautilusProgressPersistenceHandler *self = NAUTILUS_PROGRESS_PERSISTENCE_HANDLER (obj);
 
        g_clear_object (&self->priv->manager);
 
-       G_OBJECT_CLASS (nautilus_progress_ui_handler_parent_class)->dispose (obj);
+       G_OBJECT_CLASS (nautilus_progress_persistence_handler_parent_class)->dispose (obj);
 }
 
 static gboolean
@@ -416,36 +389,37 @@ server_has_persistence (void)
 }
 
 static void
-nautilus_progress_ui_handler_init (NautilusProgressUIHandler *self)
+nautilus_progress_persistence_handler_init (NautilusProgressPersistenceHandler *self)
 {
-       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NAUTILUS_TYPE_PROGRESS_UI_HANDLER,
-                                                 NautilusProgressUIHandlerPriv);
+       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER,
+                                                 NautilusProgressPersistenceHandlerPriv);
 
-       self->priv->manager = nautilus_progress_info_manager_new ();
+       self->priv->manager = nautilus_progress_info_manager_dup_singleton ();
        g_signal_connect (self->priv->manager, "new-progress-info",
                          G_CALLBACK (new_progress_info_cb), self);
 }
 
 static void
-nautilus_progress_ui_handler_class_init (NautilusProgressUIHandlerClass *klass)
+nautilus_progress_persistence_handler_class_init (NautilusProgressPersistenceHandlerClass *klass)
 {
        GObjectClass *oclass;
 
        oclass = G_OBJECT_CLASS (klass);
-       oclass->dispose = nautilus_progress_ui_handler_dispose;
-       
-       g_type_class_add_private (klass, sizeof (NautilusProgressUIHandlerPriv));
-}
+       oclass->dispose = nautilus_progress_persistence_handler_dispose;
 
-NautilusProgressUIHandler *
-nautilus_progress_ui_handler_new (void)
-{
-       return g_object_new (NAUTILUS_TYPE_PROGRESS_UI_HANDLER, NULL);
+       g_type_class_add_private (klass, sizeof (NautilusProgressPersistenceHandlerPriv));
 }
 
-void
-nautilus_progress_ui_handler_ensure_window (NautilusProgressUIHandler *self)
+NautilusProgressPersistenceHandler *
+nautilus_progress_persistence_handler_new (GObject *app)
 {
-       if (self->priv->active_infos > 0)
-               gtk_window_present (GTK_WINDOW (self->priv->progress_dialog));
+        NautilusProgressPersistenceHandler *self;
+
+        self = g_object_new (NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER, NULL);
+        self->priv->app = NAUTILUS_APPLICATION (app);
+
+        g_action_map_add_action_entries (G_ACTION_MAP (self->priv->app),
+                                         progress_persistence_entries, G_N_ELEMENTS 
(progress_persistence_entries),
+                                         self);
+       return self;
 }
diff --git a/src/nautilus-progress-persistence-handler.h b/src/nautilus-progress-persistence-handler.h
new file mode 100644
index 0000000..924255c
--- /dev/null
+++ b/src/nautilus-progress-persistence-handler.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * nautilus-progress-persistence-handler.h: file operation progress systray icon or notification handler.
+ *
+ * Copyright (C) 2007, 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Alexander Larsson <alexl redhat com>
+ *          Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#ifndef __NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_H__
+#define __NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER nautilus_progress_persistence_handler_get_type()
+#define NAUTILUS_PROGRESS_PERSISTENCE_HANDLER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER, 
NautilusProgressPersistenceHandler))
+#define NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER, 
NautilusProgressPersistenceHandlerClass))
+#define NAUTILUS_IS_PROGRESS_PERSISTENCE_HANDLER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER))
+#define NAUTILUS_IS_PROGRESS_PERSISTENCE_HANDLER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER))
+#define NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER, 
NautilusProgressPersistenceHandlerClass))
+
+typedef struct _NautilusProgressPersistenceHandlerPriv NautilusProgressPersistenceHandlerPriv;
+
+typedef struct {
+  GObject parent;
+
+  /* private */
+  NautilusProgressPersistenceHandlerPriv *priv;
+} NautilusProgressPersistenceHandler;
+
+typedef struct {
+  GObjectClass parent_class;
+} NautilusProgressPersistenceHandlerClass;
+
+GType nautilus_progress_persistence_handler_get_type (void);
+
+/* @app is actually a NautilusApplication, but we need to avoid circular dependencies */
+NautilusProgressPersistenceHandler * nautilus_progress_persistence_handler_new (GObject *app);
+void nautilus_progress_persistence_handler_make_persistent (NautilusProgressPersistenceHandler *self);
+
+G_END_DECLS
+
+#endif /* __NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_H__ */
diff --git a/src/nautilus-toolbar-ui.xml b/src/nautilus-toolbar-ui.xml
index bf371b0..42051b2 100644
--- a/src/nautilus-toolbar-ui.xml
+++ b/src/nautilus-toolbar-ui.xml
@@ -141,5 +141,58 @@
         <property name="pack-type">end</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkRevealer" id="operations_revealer">
+        <property name="visible">True</property>
+        <property name="transition-type">GTK_REVEALER_TRANSITION_TYPE_CROSSFADE</property>
+        <child>
+          <object class="GtkMenuButton" id="operations_button">
+            <property name="visible">False</property>
+            <property name="popover">operations_popover</property>
+            <style>
+              <class name="button"/>
+            </style>
+            <child>
+              <object class="GtkDrawingArea" id="operations_icon">
+                <property name="visible">True</property>
+                <property name="height-request">16</property>
+                <property name="width-request">16</property>
+                <property name="valign">GTK_ALIGN_CENTER</property>
+                <property name="halign">GTK_ALIGN_CENTER</property>
+                <signal name="draw" handler="on_operations_icon_draw" object="NautilusToolbar" swapped="no"/>
+              </object>
+            </child>
+            <child internal-child="accessible">
+              <object class="AtkObject">
+                <property name="accessible-name" translatable="yes">Operations in progress</property>
+                <property name="accessible-description" translatable="yes">Open operations in 
progress</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="pack-type">end</property>
+      </packing>
+    </child>
   </template>
+  <object class="GtkPopover" id="operations_popover">
+    <property name="modal">false</property>
+    <property name="relative-to">operations_button</property>
+    <child>
+      <object class="GtkScrolledWindow">
+        <property name="visible">True</property>
+        <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+        <property name="min-content-height">270</property>
+        <child>
+          <object class="GtkBox" id="operations_container">
+            <property name="orientation">vertical</property>
+            <property name="visible">True</property>
+            <property name="margin">12</property>
+            <property name="spacing">10</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
 </interface>
diff --git a/src/nautilus-toolbar.c b/src/nautilus-toolbar.c
index 79697a7..c083e13 100644
--- a/src/nautilus-toolbar.c
+++ b/src/nautilus-toolbar.c
@@ -29,13 +29,18 @@
 #include "nautilus-location-entry.h"
 #include "nautilus-pathbar.h"
 #include "nautilus-window.h"
+#include "nautilus-progress-info-widget.h"
 
 #include <libnautilus-private/nautilus-global-preferences.h>
 #include <libnautilus-private/nautilus-ui-utilities.h>
+#include <libnautilus-private/nautilus-progress-info-manager.h>
+#include <libnautilus-private/nautilus-file-operations.h>
 
 #include <glib/gi18n.h>
 #include <math.h>
 
+#define OPERATION_MINIMUM_TIME 5 //s
+
 typedef enum {
        NAUTILUS_NAVIGATION_DIRECTION_NONE,
        NAUTILUS_NAVIGATION_DIRECTION_BACK,
@@ -53,10 +58,16 @@ struct _NautilusToolbarPrivate {
        gboolean show_location_entry;
 
        guint popup_timeout_id;
+        guint start_operations_timeout_id;
 
+       GtkWidget *operations_button;
        GtkWidget *view_button;
        GtkWidget *action_button;
 
+        GtkWidget *operations_popover;
+        GtkWidget *operations_container;
+        GtkWidget *operations_revealer;
+        GtkWidget *operations_icon;
        GtkWidget *view_menu_widget;
        GtkWidget *sort_menu;
        GtkWidget *sort_modification_date;
@@ -72,6 +83,8 @@ struct _NautilusToolbarPrivate {
 
        GtkWidget *forward_button;
        GtkWidget *back_button;
+
+        NautilusProgressInfoManager *progress_manager;
 };
 
 enum {
@@ -420,6 +433,209 @@ view_menu_popover_closed (GtkPopover *popover,
        nautilus_view_grab_focus (view);
 }
 
+static gboolean
+should_hide_operations_button (NautilusToolbar *self)
+{
+        GList *progress_infos;
+        GList *l;
+
+        progress_infos = nautilus_progress_info_manager_get_all_infos (self->priv->progress_manager);
+
+        for (l = progress_infos; l != NULL; l = l->next) {
+                if (nautilus_progress_info_get_elapsed_time (l->data) +
+                    nautilus_progress_info_get_remaining_time (l->data) > OPERATION_MINIMUM_TIME) {
+                        return FALSE;
+                }
+        }
+
+        return TRUE;
+}
+
+static void
+on_progress_info_progress_changed (NautilusProgressInfo *info,
+                                   NautilusToolbar      *self)
+{
+        /* Update the pie chart progress */
+        gtk_widget_queue_draw (self->priv->operations_icon);
+}
+
+static void
+on_progress_info_finished (NautilusProgressInfo *info,
+                           NautilusToolbar      *self)
+{
+        /* Update the pie chart progress */
+        gtk_widget_queue_draw (self->priv->operations_icon);
+
+        if (should_hide_operations_button (self)) {
+                gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->operations_revealer),
+                                               FALSE);
+        }
+}
+
+static void
+disconnect_progress_infos (NautilusToolbar *self)
+{
+        GList *progress_infos;
+        GList *l;
+
+        progress_infos = nautilus_progress_info_manager_get_all_infos (self->priv->progress_manager);
+        for (l = progress_infos; l != NULL; l = l->next) {
+                g_signal_handlers_disconnect_by_data (l->data, self);
+        }
+}
+
+static void
+update_operations (NautilusToolbar *self)
+{
+        GList *progress_infos;
+        GList *l;
+        GtkWidget *progress;
+        guint total_remaining_time = 0;
+
+        gtk_container_foreach (GTK_CONTAINER (self->priv->operations_container),
+                               (GtkCallback) gtk_widget_destroy,
+                               NULL);
+
+        disconnect_progress_infos (self);
+
+        progress_infos = nautilus_progress_info_manager_get_all_infos (self->priv->progress_manager);
+        for (l = progress_infos; l != NULL; l = l->next) {
+                if (nautilus_progress_info_get_elapsed_time (l->data) +
+                    nautilus_progress_info_get_remaining_time (l->data) > OPERATION_MINIMUM_TIME) {
+                        total_remaining_time = nautilus_progress_info_get_remaining_time (l->data);
+
+                       g_signal_connect (l->data, "finished",
+                                         G_CALLBACK (on_progress_info_finished), self);
+                       g_signal_connect (l->data, "progress-changed",
+                                         G_CALLBACK (on_progress_info_progress_changed), self);
+                        progress = nautilus_progress_info_widget_new (l->data);
+                        gtk_box_pack_start (GTK_BOX (self->priv->operations_container),
+                                            progress,
+                                            FALSE, FALSE, 0);
+                }
+        }
+
+        /* Either we are already showing the button, so keep showing it until the user
+         * toggle it to hide the operations popover, or, if we want now to show it,
+         * we have to have at least one operation that its total stimated time
+         * is longer than OPERATION_MINIMUM_TIME seconds, or if we failed to get
+         * a correct stimated time and it's around OPERATION_MINIMUM_TIME,
+         * showing the button for just for a moment because now we realized the
+         * estimated time is longer than a OPERATION_MINIMUM_TIME is odd, so show
+         * it only if the remaining time is bigger than again OPERATION_MINIMUM_TIME.
+         */
+        if (total_remaining_time > OPERATION_MINIMUM_TIME ||
+            gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->operations_button))) {
+                gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->operations_revealer),
+                                               TRUE);
+                gtk_widget_queue_draw (self->priv->operations_icon);
+        }
+}
+
+static gboolean
+on_progress_info_started_timeout (NautilusToolbar *self)
+{
+        update_operations (self);
+
+        /* In case we didn't show the operations button because the operation total
+         * time stimation is not good enough, update again to make sure we don't miss
+         * a long time operation because of that */
+        if (!nautilus_progress_manager_are_all_infos_finished (self->priv->progress_manager)) {
+                return G_SOURCE_CONTINUE;
+        } else {
+                self->priv->start_operations_timeout_id = 0;
+                return G_SOURCE_REMOVE;
+        }
+}
+
+static void
+schedule_operations_start (NautilusToolbar *self)
+{
+        if (self->priv->start_operations_timeout_id == 0) {
+                /* Timeout is a little more than what we require for a stimated operation
+                 * total time, to make sure the stimated total time is correct */
+                self->priv->start_operations_timeout_id =
+                        g_timeout_add (SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE * 1000 + 500,
+                                       (GSourceFunc) on_progress_info_started_timeout,
+                                       self);
+        }
+}
+
+static void
+unschedule_operations_start (NautilusToolbar *self)
+{
+        if (self->priv->start_operations_timeout_id != 0) {
+                g_source_remove (self->priv->start_operations_timeout_id);
+                self->priv->start_operations_timeout_id = 0;
+        }
+}
+
+static void
+on_progress_info_started (NautilusProgressInfo *info,
+                          NautilusToolbar      *self)
+{
+        g_signal_handlers_disconnect_by_data (info, self);
+        schedule_operations_start (self);
+}
+
+static void
+on_new_progress_info (NautilusProgressInfoManager *manager,
+                      NautilusProgressInfo        *info,
+                      NautilusToolbar             *self)
+{
+        g_signal_connect (info, "started",
+                          G_CALLBACK (on_progress_info_started), self);
+}
+
+static void
+on_operations_icon_draw (GtkWidget       *widget,
+                         cairo_t         *cr,
+                         NautilusToolbar *self)
+{
+        gfloat elapsed_progress = 0;
+        gint remaining_progress = 0;
+        gint total_progress;
+        gdouble ratio;
+        GList *progress_infos;
+        GList *l;
+        guint width;
+        guint height;
+        GdkRGBA background = {.red = 0, .green = 0, .blue = 0, .alpha = 0.2 };
+        GdkRGBA foreground = {.red = 0, .green = 0, .blue = 0, .alpha = 0.7 };
+
+        progress_infos = nautilus_progress_info_manager_get_all_infos (self->priv->progress_manager);
+        for (l = progress_infos; l != NULL; l = l->next) {
+                remaining_progress += nautilus_progress_info_get_remaining_time (l->data);
+                elapsed_progress += nautilus_progress_info_get_elapsed_time (l->data);
+        }
+
+        total_progress = remaining_progress + elapsed_progress;
+
+        if (total_progress > 0)
+                ratio = MAX (0.05, elapsed_progress / total_progress);
+        else
+                ratio = 0.05;
+
+
+        width = gtk_widget_get_allocated_width (widget);
+        height = gtk_widget_get_allocated_height (widget);
+
+        gdk_cairo_set_source_rgba(cr, &background);
+        cairo_arc (cr,
+                   width / 2.0, height / 2.0,
+                   MIN (width, height) / 2.0,
+                   0, 2 *G_PI);
+        cairo_fill (cr);
+        cairo_move_to (cr, width / 2.0, height / 2.0);
+        gdk_cairo_set_source_rgba (cr, &foreground);
+        cairo_arc (cr,
+                   width / 2.0, height / 2.0,
+                   MIN (width, height) / 2.0,
+                   -G_PI / 2.0, ratio * 2 * G_PI - G_PI / 2.0);
+
+        cairo_fill (cr);
+}
+
 static void
 nautilus_toolbar_init (NautilusToolbar *self)
 {
@@ -462,6 +678,11 @@ nautilus_toolbar_init (NautilusToolbar *self)
                                        G_MENU_MODEL (self->priv->action_menu));
        g_object_unref (builder);
 
+        self->priv->progress_manager = nautilus_progress_info_manager_dup_singleton ();
+       g_signal_connect (self->priv->progress_manager, "new-progress-info",
+                         G_CALLBACK (on_new_progress_info), self);
+        update_operations (self);
+
        g_object_set_data (G_OBJECT (self->priv->back_button), "nav-direction",
                           GUINT_TO_POINTER (NAUTILUS_NAVIGATION_DIRECTION_BACK));
        g_object_set_data (G_OBJECT (self->priv->forward_button), "nav-direction",
@@ -527,7 +748,12 @@ nautilus_toolbar_dispose (GObject *obj)
 
        g_signal_handlers_disconnect_by_func (nautilus_preferences,
                                              toolbar_update_appearance, self);
+        disconnect_progress_infos (self);
        unschedule_menu_popup_timeout (self);
+        unschedule_operations_start (self);
+
+        g_signal_handlers_disconnect_by_data (self->priv->progress_manager, self);
+        g_clear_object (&self->priv->progress_manager);
 
        G_OBJECT_CLASS (nautilus_toolbar_parent_class)->dispose (obj);
 }
@@ -563,12 +789,18 @@ nautilus_toolbar_class_init (NautilusToolbarClass *klass)
        gtk_widget_class_set_template_from_resource (widget_class,
                                                     "/org/gnome/nautilus/nautilus-toolbar-ui.xml");
 
+       gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, operations_button);
+       gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, operations_icon);
+       gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, operations_container);
+       gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, operations_revealer);
        gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, view_button);
        gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, action_button);
        gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, path_bar_container);
        gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, 
location_entry_container);
        gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, back_button);
        gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, forward_button);
+
+        gtk_widget_class_bind_template_callback (widget_class, on_operations_icon_draw);
 }
 
 void
diff --git a/test/test-copy.c b/test/test-copy.c
index be8e7c4..d9c491e 100644
--- a/test/test-copy.c
+++ b/test/test-copy.c
@@ -69,7 +69,7 @@ main (int argc, char* argv[])
        
        gtk_widget_show (window);
 
-        manager = nautilus_progress_info_manager_new ();
+        manager = nautilus_progress_info_manager_dup_singleton ();
 
        nautilus_file_operations_copy (sources,
                                       NULL /* GArray *relative_item_points */,


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