[epiphany] downloads: Replace the downloads box with a popover



commit 3e24ba2a16ee0444e6617cd7b95355f401465a3f
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Fri Oct 2 12:09:51 2015 +0200

    downloads: Replace the downloads box with a popover
    
    Downloads are no longer associated to a particular window, they are
    globally accessed with a button in the toolbar that shows a popover with
    the list of downloads.

 lib/widgets/Makefile.am              |    2 +
 lib/widgets/ephy-download-widget.c   |  535 +++++++++++++---------------------
 lib/widgets/ephy-download-widget.h   |   14 +-
 lib/widgets/ephy-downloads-popover.c |  211 +++++++++++++
 lib/widgets/ephy-downloads-popover.h |   45 +++
 src/ephy-shell.c                     |    5 +-
 src/ephy-toolbar.c                   |   61 ++++
 src/ephy-window.c                    |  178 ++----------
 src/ephy-window.h                    |    7 +-
 src/popup-commands.c                 |    8 +-
 src/resources/epiphany.css           |   26 +--
 11 files changed, 566 insertions(+), 526 deletions(-)
---
diff --git a/lib/widgets/Makefile.am b/lib/widgets/Makefile.am
index 383432a..3b935fa 100644
--- a/lib/widgets/Makefile.am
+++ b/lib/widgets/Makefile.am
@@ -68,6 +68,8 @@ libephywidgets_la_SOURCES = \
        ephy-certificate-dialog.h               \
        ephy-certificate-popover.c              \
        ephy-certificate-popover.h              \
+       ephy-downloads-popover.h                \
+       ephy-downloads-popover.c                \
        ephy-download-widget.c                  \
        ephy-download-widget.h                  \
        ephy-location-entry.c                   \
diff --git a/lib/widgets/ephy-download-widget.c b/lib/widgets/ephy-download-widget.c
index 445a252..416d6a5 100644
--- a/lib/widgets/ephy-download-widget.c
+++ b/lib/widgets/ephy-download-widget.c
@@ -4,7 +4,7 @@
  * ephy-download.c
  * This file is part of Epiphany
  *
- * Copyright © 2011 - Igalia S.L.
+ * Copyright © 2011, 2015 - Igalia S.L.
  *
  * Epiphany is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,14 +26,14 @@
 #include "ephy-download-widget.h"
 
 #include "ephy-debug.h"
-#include "ephy-embed-shell.h"
-#include "ephy-download.h"
 #include "ephy-uri-helpers.h"
+#include "ephy-embed-shell.h"
+#include "ephy-downloads-manager.h"
 
 #include <glib/gi18n.h>
 #include <webkit2/webkit2.h>
 
-G_DEFINE_TYPE (EphyDownloadWidget, ephy_download_widget, GTK_TYPE_BOX)
+G_DEFINE_TYPE (EphyDownloadWidget, ephy_download_widget, GTK_TYPE_GRID)
 
 #define DOWNLOAD_WIDGET_PRIVATE(o) \
   (G_TYPE_INSTANCE_GET_PRIVATE ((o), EPHY_TYPE_DOWNLOAD_WIDGET, EphyDownloadWidgetPrivate))
@@ -42,16 +42,11 @@ struct _EphyDownloadWidgetPrivate
 {
   EphyDownload *download;
 
-  GtkWidget *text;
-  GtkWidget *remaining;
-  GtkWidget *button;
-  GtkWidget *menu_button;
+  GtkWidget *filename;
+  GtkWidget *status;
   GtkWidget *icon;
-  GtkWidget *open_menuitem;
-  GtkWidget *cancel_menuitem;
-  GtkWidget *show_folder_menuitem;
-
-  gboolean finished;
+  GtkWidget *progress;
+  GtkWidget *action_button;
 };
 
 enum
@@ -63,12 +58,13 @@ enum
 static GIcon *
 get_gicon_from_download (EphyDownload *ephy_download)
 {
-  char *content_type = NULL;
+  char *content_type;
   GIcon *gicon;
 
+  /* FIXME: this might do sync IO during downloads */
   content_type = ephy_download_get_content_type (ephy_download);
 
-  if (content_type != NULL) {
+  if (content_type) {
     gicon = g_content_type_get_icon (content_type);
     g_free (content_type);
   } else {
@@ -140,24 +136,15 @@ duration_to_string (guint seconds)
 }
 
 static gdouble
-get_remaining_time (WebKitDownload *download)
+get_remaining_time (guint64 content_length,
+                    guint64 received_length,
+                    gdouble elapsed_time)
 {
-  gint64 total, cur;
-  gdouble elapsed_time;
   gdouble remaining_time;
   gdouble per_byte_time;
-  WebKitURIResponse *response;
-
-  response = webkit_download_get_response (download);
-  total = webkit_uri_response_get_content_length (response);
-  cur = webkit_download_get_received_data_length (download);
-  elapsed_time = webkit_download_get_elapsed_time (download);
 
-  if (cur <= 0)
-    return -1.0;
-
-  per_byte_time = elapsed_time / cur;
-  remaining_time = per_byte_time * (total - cur);
+  per_byte_time = elapsed_time / received_length;
+  remaining_time = per_byte_time * (content_length - received_length);
 
   return remaining_time;
 }
@@ -168,9 +155,6 @@ download_clicked_cb (GtkButton *button,
 {
   EphyDownload *download;
 
-  if (!widget->priv->finished)
-    return;
-
   download = widget->priv->download;
   if (ephy_download_do_download_action (download, EPHY_DOWNLOAD_ACTION_AUTO))
     gtk_widget_destroy (GTK_WIDGET (widget));
@@ -185,7 +169,7 @@ update_download_icon (EphyDownloadWidget *widget)
   gtk_image_get_gicon (GTK_IMAGE (widget->priv->icon), &old_icon, NULL);
   if (!g_icon_equal (new_icon, old_icon)) {
     gtk_image_set_from_gicon (GTK_IMAGE (widget->priv->icon), new_icon,
-                              GTK_ICON_SIZE_LARGE_TOOLBAR);
+                              GTK_ICON_SIZE_DIALOG);
   }
   g_object_unref (new_icon);
 }
@@ -194,10 +178,15 @@ static void
 update_download_destination (EphyDownloadWidget *widget)
 {
   char *dest;
+  char *markup;
 
   dest = get_destination_basename_from_download (widget->priv->download);
-  gtk_label_set_text (GTK_LABEL (widget->priv->text), dest);
+  if (!dest)
+    return;
+  markup = g_markup_printf_escaped ("<b>%s</b>", dest);
   g_free (dest);
+  gtk_label_set_markup (GTK_LABEL (widget->priv->filename), markup);
+  g_free (markup);
 }
 
 static void
@@ -207,9 +196,17 @@ update_download_label_and_tooltip (EphyDownloadWidget *widget,
   WebKitDownload *download;
   char *remaining_tooltip;
   char *destination;
+  char *markup;
   const char *dest;
 
+  markup = g_markup_printf_escaped ("<span size='small'>%s</span>", download_label);
+  gtk_label_set_markup (GTK_LABEL (widget->priv->status), markup);
+  g_free (markup);
+
   download = ephy_download_get_webkit_download (widget->priv->download);
+  if (!download)
+    return;
+
   dest = webkit_download_get_destination (download);
   if (dest == NULL)
     return;
@@ -219,54 +216,56 @@ update_download_label_and_tooltip (EphyDownloadWidget *widget,
   remaining_tooltip = g_markup_printf_escaped ("%s\n%s", destination, download_label);
   g_free (destination);
 
-  gtk_label_set_text (GTK_LABEL (widget->priv->remaining), download_label);
   gtk_widget_set_tooltip_text (GTK_WIDGET (widget), remaining_tooltip);
   g_free (remaining_tooltip);
 }
 
-static gboolean
-download_content_length_is_known (WebKitDownload *download)
-{
-  WebKitURIResponse *response;
-
-  response = webkit_download_get_response (download);
-  return webkit_uri_response_get_content_length (response);
-}
-
 static void
-widget_progress_cb (WebKitDownload *download,
-                    GParamSpec *pspec,
-                    EphyDownloadWidget *widget)
+download_progress_cb (WebKitDownload *download,
+                      GParamSpec *pspec,
+                      EphyDownloadWidget *widget)
 {
-  int progress;
+  gdouble progress;
+  int percentage;
+  WebKitURIResponse *response;
+  guint64 content_length;
+  guint64 received_length;
   char *download_label = NULL;
 
   if (!webkit_download_get_destination (download))
     return;
 
-  progress = webkit_download_get_estimated_progress (download) * 100;
-
-  if (progress % 10 == 0)
+  progress = webkit_download_get_estimated_progress (download);
+  percentage = progress * 100;
+  if (percentage % 10 == 0)
     update_download_icon (widget);
 
-  if (download_content_length_is_known (download)) {
-    gdouble time;
+  response = webkit_download_get_response (download);
+  content_length = webkit_uri_response_get_content_length (response);
+  received_length = webkit_download_get_received_data_length (download);
 
-    time = get_remaining_time (download);
-    if (time > 0) {
+  if (content_length > 0 && received_length > 0) {
+      gdouble time;
       char *remaining;
+      char *received;
+      char *total;
 
+      received = g_format_size (received_length);
+      total = g_format_size (content_length);
+
+      time = get_remaining_time (content_length, received_length,
+                                 webkit_download_get_elapsed_time (download));
       remaining = duration_to_string ((guint)time);
-      download_label = g_strdup_printf ("%d%% (%s)", progress, remaining);
+      download_label = g_strdup_printf ("%s / %s — %s", received, total, remaining);
+      g_free (received);
+      g_free (total);
       g_free (remaining);
-    }
-  } else {
-    gint64 current_size;
 
-    /* Unknown content length, show received bytes instead. */
-    current_size = webkit_download_get_received_data_length (download);
-    if (current_size > 0)
-      download_label = g_format_size (current_size);
+      gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (widget->priv->progress),
+                                     progress);
+  } else if (received_length > 0) {
+    download_label = g_format_size (received_length);
+    gtk_progress_bar_pulse (GTK_PROGRESS_BAR (widget->priv->progress));
   }
 
   if (download_label) {
@@ -276,197 +275,67 @@ widget_progress_cb (WebKitDownload *download,
 }
 
 static void
-update_popup_menu (EphyDownloadWidget *widget)
-{
-  gtk_widget_set_sensitive (widget->priv->cancel_menuitem, !widget->priv->finished);
-  gtk_widget_set_visible (widget->priv->cancel_menuitem, !widget->priv->finished);
-  gtk_widget_set_sensitive (widget->priv->open_menuitem, widget->priv->finished);
-  gtk_widget_set_sensitive (widget->priv->show_folder_menuitem, widget->priv->finished);
-}
-
-static void
-widget_attention_needed (EphyDownloadWidget *widget)
+download_finished_cb (EphyDownload *download,
+                      EphyDownloadWidget *widget)
 {
-  gtk_style_context_add_class (gtk_widget_get_style_context (widget->priv->button), "needs-attention");
-}
-
-static void
-widget_attention_unneeded (EphyDownloadWidget *widget)
-{
-  gtk_style_context_remove_class (gtk_widget_get_style_context (widget->priv->button), "needs-attention");
-}
-
-static void
-widget_finished_cb (WebKitDownload *download,
-                    EphyDownloadWidget *widget)
-{
-  widget->priv->finished = TRUE;
-  update_popup_menu (widget);
+  gtk_widget_hide (widget->priv->progress);
   update_download_label_and_tooltip (widget, _("Finished"));
-  widget_attention_needed (widget);
+  gtk_image_set_from_icon_name (GTK_IMAGE (gtk_button_get_image (GTK_BUTTON (widget->priv->action_button))),
+                                "folder-open-symbolic",
+                                GTK_ICON_SIZE_MENU);
 }
 
 static void
-widget_failed_cb (WebKitDownload *download,
-                  GError *error,
-                  EphyDownloadWidget *widget)
+download_failed_cb (EphyDownload *download,
+                    GError *error,
+                    EphyDownloadWidget *widget)
 {
   char *error_msg;
 
-  g_signal_handlers_disconnect_by_func (download, widget_finished_cb, widget);
-  g_signal_handlers_disconnect_by_func (download, widget_progress_cb, widget);
+  g_signal_handlers_disconnect_by_func (download, download_progress_cb, widget);
+
+  gtk_widget_hide (widget->priv->progress);
 
-  widget->priv->finished = TRUE;
-  update_popup_menu (widget);
   error_msg = g_strdup_printf (_("Error downloading: %s"), error->message);
-  gtk_label_set_text (GTK_LABEL (widget->priv->remaining), error_msg);
-  gtk_widget_set_tooltip_text (GTK_WIDGET (widget), error_msg);
+  update_download_label_and_tooltip (widget, error_msg);
   g_free (error_msg);
-
-  widget_attention_needed (widget);
-}
-
-static void
-open_activate_cb (GtkMenuItem *item, EphyDownloadWidget *widget)
-{
-  if (ephy_download_do_download_action (widget->priv->download,
-                                        EPHY_DOWNLOAD_ACTION_OPEN))
-    gtk_widget_destroy (GTK_WIDGET (widget));
-}
-static void
-folder_activate_cb (GtkMenuItem *item, EphyDownloadWidget *widget)
-{
-  if (ephy_download_do_download_action (widget->priv->download,
-                                        EPHY_DOWNLOAD_ACTION_BROWSE_TO))
-    gtk_widget_destroy (GTK_WIDGET (widget));
-}
-static void
-cancel_activate_cb (GtkMenuItem *item, EphyDownloadWidget *widget)
-{
-  ephy_download_cancel (widget->priv->download);
-  gtk_widget_destroy (GTK_WIDGET (widget));
-}
-
-static void
-add_popup_menu (EphyDownloadWidget *widget)
-{
-  GtkWidget *item;
-  GtkWidget *menu;
-  char *basename, *name;
-  WebKitDownload *download;
-  const char *dest;
-
-  download = ephy_download_get_webkit_download (widget->priv->download);
-  dest = webkit_download_get_destination (download);
-  if (dest == NULL)
-    return;
-
-  basename = g_filename_display_basename (dest);
-  name = ephy_uri_safe_unescape (basename);
-
-  menu = gtk_menu_new ();
-  gtk_widget_set_halign (menu, GTK_ALIGN_END);
-
-  item = gtk_menu_item_new_with_label (name);
-  gtk_widget_set_sensitive (item, FALSE);
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  g_free (basename);
-  g_free (name);
-
-  widget->priv->cancel_menuitem = item = gtk_menu_item_new_with_label (_("Cancel"));
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  g_signal_connect (item, "activate",
-                    G_CALLBACK (cancel_activate_cb), widget);
-
-  item = gtk_separator_menu_item_new ();
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-
-  widget->priv->open_menuitem = item = gtk_menu_item_new_with_label (_("Open"));
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  g_signal_connect (item, "activate",
-                    G_CALLBACK (open_activate_cb), widget);
-
-  widget->priv->show_folder_menuitem = item = gtk_menu_item_new_with_label (_("Show in folder"));
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  g_signal_connect (item, "activate",
-                    G_CALLBACK (folder_activate_cb), widget);
-
-  update_popup_menu (widget);
-
-  gtk_widget_show_all (menu);
-
-  gtk_menu_button_set_popup (GTK_MENU_BUTTON (widget->priv->menu_button), menu);
-}
-
-static void
-widget_destination_changed_cb (WebKitDownload *download,
-                               GParamSpec *pspec,
-                               EphyDownloadWidget *widget)
-{
-  update_download_destination (widget);
-  add_popup_menu (widget);
+  gtk_image_set_from_icon_name (GTK_IMAGE (gtk_button_get_image (GTK_BUTTON (widget->priv->action_button))),
+                                "list-remove-symbolic",
+                                GTK_ICON_SIZE_MENU);
 }
 
 static void
-disconnect_download (EphyDownloadWidget *widget)
+widget_action_button_clicked_cb (EphyDownloadWidget *widget)
 {
-  WebKitDownload *download;
+  if (ephy_download_is_active (widget->priv->download)) {
+    WebKitDownload *download;
 
-  download = ephy_download_get_webkit_download (widget->priv->download);
-
-  g_signal_handlers_disconnect_by_func (download, widget_progress_cb, widget);
-  g_signal_handlers_disconnect_by_func (download, widget_destination_changed_cb, widget);
-  g_signal_handlers_disconnect_by_func (download, widget_finished_cb, widget);
-  g_signal_handlers_disconnect_by_func (download, widget_failed_cb, widget);
+    download = ephy_download_get_webkit_download (widget->priv->download);
+    g_signal_handlers_disconnect_matched (download, G_SIGNAL_MATCH_DATA, 0, 0,
+                                          NULL, NULL, widget);
+    g_signal_handlers_disconnect_matched (widget->priv->download, G_SIGNAL_MATCH_DATA, 0, 0,
+                                          NULL, NULL, widget);
+    update_download_label_and_tooltip (widget, _("Cancelling…"));
+    gtk_widget_set_sensitive (widget->priv->action_button, FALSE);
 
-  ephy_download_set_widget (widget->priv->download, NULL);
-}
+    ephy_download_cancel (widget->priv->download);
+  } else if (ephy_download_failed (widget->priv->download, NULL)) {
+    EphyDownloadsManager *manager;
 
-static void
-connect_download (EphyDownloadWidget *widget)
-{
-  WebKitDownload *download;
-
-  download = ephy_download_get_webkit_download (widget->priv->download);
-
-  g_signal_connect (download, "notify::estimated-progress",
-                    G_CALLBACK (widget_progress_cb), widget);
-  g_signal_connect (download, "notify::destination",
-                    G_CALLBACK (widget_destination_changed_cb), widget);
-  g_signal_connect (download, "finished",
-                    G_CALLBACK (widget_finished_cb), widget);
-  g_signal_connect (download, "failed",
-                    G_CALLBACK (widget_failed_cb), widget);
-
-  ephy_download_set_widget (widget->priv->download, GTK_WIDGET (widget));
+    manager = ephy_embed_shell_get_downloads_manager (ephy_embed_shell_get_default ());
+    ephy_downloads_manager_remove_download (manager, widget->priv->download);
+  } else {
+    ephy_download_do_download_action (widget->priv->download,
+                                      EPHY_DOWNLOAD_ACTION_BROWSE_TO);
+  }
 }
 
 static void
-ephy_download_widget_set_download (EphyDownloadWidget *widget,
-                                   EphyDownload       *download)
+download_destination_changed_cb (WebKitDownload *download,
+                                 GParamSpec *pspec,
+                                 EphyDownloadWidget *widget)
 {
-  g_return_if_fail (EPHY_IS_DOWNLOAD_WIDGET (widget));
-
-  if (widget->priv->download == download)
-    return;
-
-  if (widget->priv->download != NULL) {
-    disconnect_download (widget);
-    g_object_unref (widget->priv->download);
-  }
-
-  widget->priv->download = NULL;
-
-  if (download != NULL) {
-    widget->priv->download = g_object_ref (download);
-    connect_download (widget);
-  }
-
-  update_download_icon (widget);
   update_download_destination (widget);
-  add_popup_menu (widget);
-
-  g_object_notify (G_OBJECT (widget), "download");
 }
 
 static void
@@ -500,7 +369,7 @@ ephy_download_widget_set_property (GObject      *object,
 
   switch (property_id) {
     case PROP_DOWNLOAD:
-      ephy_download_widget_set_download (widget, g_value_get_object (value));
+      widget->priv->download = g_value_dup_object (value);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -518,7 +387,13 @@ ephy_download_widget_dispose (GObject *object)
   widget = EPHY_DOWNLOAD_WIDGET (object);
 
   if (widget->priv->download != NULL) {
-    disconnect_download (widget);
+    WebKitDownload *download = ephy_download_get_webkit_download (widget->priv->download);
+
+    g_signal_handlers_disconnect_matched (download, G_SIGNAL_MATCH_DATA, 0, 0,
+                                          NULL, NULL, widget);
+    g_signal_handlers_disconnect_matched (widget->priv->download, G_SIGNAL_MATCH_DATA, 0, 0,
+                                          NULL, NULL, widget);
+    ephy_download_set_widget (widget->priv->download, NULL);
     g_object_unref (widget->priv->download);
     widget->priv->download = NULL;
   }
@@ -527,12 +402,106 @@ ephy_download_widget_dispose (GObject *object)
 }
 
 static void
+ephy_download_widget_constructed (GObject *object)
+{
+  EphyDownloadWidget *widget = EPHY_DOWNLOAD_WIDGET (object);
+  EphyDownloadWidgetPrivate *priv = widget->priv;
+  GtkWidget *title;
+  WebKitDownload *download;
+  const char *action_icon_name = NULL;
+  GError *error = NULL;
+
+  G_OBJECT_CLASS (ephy_download_widget_parent_class)->constructed (object);
+
+  gtk_widget_set_margin_start (GTK_WIDGET (widget), 5);
+  gtk_widget_set_margin_end (GTK_WIDGET (widget), 5);
+
+  priv->icon = gtk_image_new ();
+  gtk_widget_set_margin_end (priv->icon, 10);
+  update_download_icon (widget);
+  gtk_grid_attach (GTK_GRID (widget), priv->icon, 0, 0, 1, 3);
+  gtk_widget_show (priv->icon);
+
+  priv->filename = gtk_label_new (NULL);
+  gtk_widget_set_valign (priv->filename, GTK_ALIGN_CENTER);
+  gtk_widget_set_margin_bottom (priv->filename, 6);
+  gtk_label_set_xalign (GTK_LABEL (priv->filename), 0);
+  gtk_label_set_max_width_chars (GTK_LABEL (priv->filename), 30);
+  gtk_label_set_ellipsize (GTK_LABEL (priv->filename), PANGO_ELLIPSIZE_END);
+  update_download_destination (widget);
+  gtk_grid_attach (GTK_GRID (widget), priv->filename, 1, 0, 1, 1);
+  gtk_widget_show (priv->filename);
+
+  priv->progress = gtk_progress_bar_new ();
+  gtk_widget_set_valign (priv->progress, GTK_ALIGN_CENTER);
+  gtk_widget_set_margin_start (priv->progress, 2);
+  gtk_widget_set_margin_bottom (priv->progress, 4);
+  gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (priv->progress), 0.05);
+  gtk_grid_attach (GTK_GRID (widget), priv->progress, 1, 1, 1, 1);
+  if (ephy_download_is_active (priv->download))
+          gtk_widget_show (priv->progress);
+
+  priv->status = gtk_label_new (NULL);
+  gtk_widget_set_valign (priv->status, GTK_ALIGN_CENTER);
+  gtk_label_set_xalign (GTK_LABEL (priv->status), 0);
+  g_object_set (priv->status, "width-request", 260, NULL);
+  gtk_label_set_max_width_chars (GTK_LABEL (priv->status), 30);
+  gtk_label_set_ellipsize (GTK_LABEL (priv->status), PANGO_ELLIPSIZE_END);
+  if (ephy_download_failed (priv->download, &error)) {
+          char *error_msg;
+
+          error_msg = g_strdup_printf (_("Error downloading: %s"), error->message);
+          update_download_label_and_tooltip (widget, error_msg);
+          g_free (error_msg);
+  } else if (ephy_download_succeeded (priv->download)) {
+          update_download_label_and_tooltip (widget, _("Finished"));
+  } else {
+          update_download_label_and_tooltip (widget, _("Starting…"));
+  }
+  gtk_grid_attach (GTK_GRID (widget), priv->status, 1, 2, 1, 1);
+  gtk_widget_show (priv->status);
+
+  if (ephy_download_succeeded (priv->download))
+    action_icon_name = "folder-open-symbolic";
+  else if (ephy_download_failed (priv->download, NULL))
+    action_icon_name = "list-remove-symbolic";
+  else
+    action_icon_name = "window-close-symbolic";
+  priv->action_button = gtk_button_new_from_icon_name (action_icon_name, GTK_ICON_SIZE_MENU);
+  g_signal_connect_swapped (priv->action_button, "clicked",
+                            G_CALLBACK (widget_action_button_clicked_cb),
+                            widget);
+  gtk_widget_set_valign (priv->action_button, GTK_ALIGN_CENTER);
+  gtk_widget_set_margin_start (priv->action_button, 10);
+  gtk_style_context_add_class (gtk_widget_get_style_context (priv->action_button),
+                               "download-circular-button");
+  gtk_grid_attach (GTK_GRID (widget), priv->action_button, 3, 0, 1, 3);
+  gtk_widget_show (priv->action_button);
+
+  download = ephy_download_get_webkit_download (priv->download);
+  g_signal_connect (download, "notify::estimated-progress",
+                    G_CALLBACK (download_progress_cb),
+                    widget);
+  g_signal_connect (download, "notify::destination",
+                    G_CALLBACK (download_destination_changed_cb),
+                    widget);
+  g_signal_connect (priv->download, "completed",
+                    G_CALLBACK (download_finished_cb),
+                    widget);
+  g_signal_connect (priv->download, "error",
+                    G_CALLBACK (download_failed_cb),
+                    widget);
+  ephy_download_set_widget (priv->download, GTK_WIDGET (widget));
+}
+
+static void
 ephy_download_widget_class_init (EphyDownloadWidgetClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   g_type_class_add_private (klass, sizeof (EphyDownloadWidgetPrivate));
 
+  object_class->constructed = ephy_download_widget_constructed;
   object_class->get_property = ephy_download_widget_get_property;
   object_class->set_property = ephy_download_widget_set_property;
   object_class->dispose = ephy_download_widget_dispose;
@@ -555,90 +524,9 @@ ephy_download_widget_class_init (EphyDownloadWidgetClass *klass)
 }
 
 static void
-smallify_label (GtkLabel *label)
-{
-        PangoAttrList *attrs;
-        attrs = pango_attr_list_new ();
-        pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL));
-        gtk_label_set_attributes (label, attrs);
-        pango_attr_list_unref (attrs);
-}
-
-static void
-create_widget (EphyDownloadWidget *widget)
-{
-
-  GtkWidget *grid;
-  GtkWidget *icon;
-  GtkWidget *text;
-  GtkWidget *button;
-  GtkWidget *menu_button;
-  GtkWidget *remain;
-
-  grid = gtk_grid_new ();
-  gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
-
-  button = gtk_button_new ();
-  menu_button = gtk_menu_button_new ();
-  gtk_menu_button_set_direction (GTK_MENU_BUTTON (menu_button), GTK_ARROW_UP);
-
-  icon = gtk_image_new ();
-
-  text = gtk_label_new (NULL);
-  smallify_label (GTK_LABEL (text));
-  gtk_misc_set_alignment (GTK_MISC (text), 0, 0.5);
-  gtk_label_set_ellipsize (GTK_LABEL (text), PANGO_ELLIPSIZE_END);
-  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_LABEL (text)), "filename");
-
-  remain = gtk_label_new (_("Starting…"));
-  smallify_label (GTK_LABEL (remain));
-  gtk_misc_set_alignment (GTK_MISC (remain), 0, 0.5);
-  gtk_label_set_ellipsize (GTK_LABEL (remain), PANGO_ELLIPSIZE_END);
-
-  gtk_grid_attach (GTK_GRID (grid), icon, 0, 0, 1, 2);
-  gtk_grid_attach (GTK_GRID (grid), text, 1, 0, 1, 1);
-  gtk_grid_attach (GTK_GRID (grid), remain, 1, 1, 1, 1);
-
-  widget->priv->text = text;
-  widget->priv->icon = icon;
-  widget->priv->button = button;
-  widget->priv->remaining = remain;
-  widget->priv->menu_button = menu_button;
-
-  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_HALF);
-
-  gtk_container_add (GTK_CONTAINER (button), grid);
-
-  gtk_box_pack_start (GTK_BOX (widget), button, FALSE, FALSE, 0);
-  gtk_box_pack_end (GTK_BOX (widget), menu_button, FALSE, FALSE, 0);
-
-  g_signal_connect (button, "clicked",
-                    G_CALLBACK (download_clicked_cb), widget);
-  g_signal_connect_swapped (menu_button, "clicked",
-                            G_CALLBACK (widget_attention_unneeded), widget);
-
-  gtk_widget_show_all (button);
-  gtk_widget_show_all (menu_button);
-
-}
-
-static void
-ephy_download_widget_init (EphyDownloadWidget *self)
+ephy_download_widget_init (EphyDownloadWidget *widget)
 {
-  GtkStyleContext *context;
-
-  self->priv = DOWNLOAD_WIDGET_PRIVATE (self);
-
-  create_widget (self);
-
-  gtk_orientable_set_orientation (GTK_ORIENTABLE (self),
-                                  GTK_ORIENTATION_HORIZONTAL);
-  context = gtk_widget_get_style_context (GTK_WIDGET (self));
-  gtk_style_context_add_class (context, GTK_STYLE_CLASS_LINKED);
-
-  g_object_set (self,
-                "margin", 2,
-                NULL);
+  widget->priv = DOWNLOAD_WIDGET_PRIVATE (widget);
 }
 
 /**
@@ -657,21 +545,6 @@ ephy_download_widget_get_download (EphyDownloadWidget *widget)
 }
 
 /**
- * ephy_download_widget_download_is_finished:
- * @widget: an #EphyDownloadWidget
- *
- * Whether the download finished
- *
- * Returns: %TRUE if download operation finished or %FALSE otherwise
- **/
-gboolean
-ephy_download_widget_download_is_finished (EphyDownloadWidget *widget)
-{
-  g_return_val_if_fail (EPHY_IS_DOWNLOAD_WIDGET (widget), FALSE);
-  return widget->priv->finished;
-}
-
-/**
  * ephy_download_widget_new:
  * @ephy_download: the #EphyDownload that @widget is wrapping
  *
diff --git a/lib/widgets/ephy-download-widget.h b/lib/widgets/ephy-download-widget.h
index cbdab20..a0bc4cc 100644
--- a/lib/widgets/ephy-download-widget.h
+++ b/lib/widgets/ephy-download-widget.h
@@ -4,7 +4,7 @@
  * ephy-download.c
  * This file is part of Epiphany
  *
- * Copyright © 2011 - Igalia S.L.
+ * Copyright © 2011, 2015 - Igalia S.L.
  *
  * Epiphany is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -47,23 +47,21 @@ typedef struct _EphyDownloadWidgetPrivate EphyDownloadWidgetPrivate;
 
 struct _EphyDownloadWidget
 {
-  GtkBox parent;
+  GtkGrid parent;
 
   EphyDownloadWidgetPrivate *priv;
 };
 
 struct _EphyDownloadWidgetClass
 {
-  GtkBoxClass parent_class;
+  GtkGridClass parent_class;
 };
 
-GType          ephy_download_widget_get_type             (void) G_GNUC_CONST;
+GType          ephy_download_widget_get_type     (void) G_GNUC_CONST;
 
-GtkWidget     *ephy_download_widget_new                  (EphyDownload *ephy_download);
+GtkWidget     *ephy_download_widget_new          (EphyDownload *ephy_download);
 
-EphyDownload  *ephy_download_widget_get_download         (EphyDownloadWidget *widget);
-
-gboolean       ephy_download_widget_download_is_finished (EphyDownloadWidget *widget);
+EphyDownload  *ephy_download_widget_get_download (EphyDownloadWidget *widget);
 
 G_END_DECLS
 
diff --git a/lib/widgets/ephy-downloads-popover.c b/lib/widgets/ephy-downloads-popover.c
new file mode 100644
index 0000000..59f693a
--- /dev/null
+++ b/lib/widgets/ephy-downloads-popover.c
@@ -0,0 +1,211 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2015 Igalia S.L.
+ *
+ *  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, 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/>.
+ *
+ */
+
+#include "config.h"
+#include "ephy-downloads-popover.h"
+
+#include "ephy-downloads-manager.h"
+#include "ephy-download-widget.h"
+#include "ephy-embed-shell.h"
+
+#include <glib/gi18n.h>
+
+struct _EphyDownloadsPopover
+{
+  GtkPopover parent;
+
+  GtkWidget *downloads_box;
+};
+
+struct _EphyDownloadsPopoverClass
+{
+  GtkPopoverClass parent_class;
+};
+
+G_DEFINE_TYPE (EphyDownloadsPopover, ephy_downloads_popover, GTK_TYPE_POPOVER)
+
+#define DOWNLOADS_BOX_MIN_SIZE 270
+
+static void
+download_box_row_activated_cb (EphyDownloadsPopover *popover,
+                               GtkListBoxRow        *row)
+{
+  EphyDownloadWidget *widget;
+  EphyDownload *download;
+
+  widget = EPHY_DOWNLOAD_WIDGET (gtk_bin_get_child (GTK_BIN (row)));
+  download = ephy_download_widget_get_download (widget);
+  if (!ephy_download_succeeded (download))
+    return;
+
+  ephy_download_do_download_action (download, EPHY_DOWNLOAD_ACTION_OPEN);
+}
+
+static void
+download_added_cb (EphyDownloadsPopover *popover,
+                   EphyDownload         *download)
+{
+  GtkWidget *widget;
+
+  widget = ephy_download_widget_new (download);
+  gtk_list_box_prepend (GTK_LIST_BOX (popover->downloads_box), widget);
+  gtk_widget_show (widget);
+}
+
+static void
+download_removed_cb (EphyDownloadsPopover *popover,
+                     EphyDownload         *download)
+{
+  GList *children, *l;
+
+  children = gtk_container_get_children (GTK_CONTAINER (popover->downloads_box));
+  for (l = children; l; l = g_list_next (l)) {
+    GtkWidget *widget;
+
+    if (!GTK_IS_LIST_BOX_ROW (l->data))
+      continue;
+
+    widget = gtk_bin_get_child (GTK_BIN (l->data));
+    if (!EPHY_IS_DOWNLOAD_WIDGET (widget))
+      continue;
+
+    if (ephy_download_widget_get_download (EPHY_DOWNLOAD_WIDGET (widget)) == download) {
+      gtk_widget_destroy (widget);
+      break;
+    }
+  }
+  g_list_free (children);
+}
+
+static void
+clear_button_clicked_cb (EphyDownloadsPopover *popover)
+{
+  GList *children, *l;
+  EphyDownloadsManager *manager;
+
+  manager = ephy_embed_shell_get_downloads_manager (ephy_embed_shell_get_default ());
+  g_signal_handlers_block_by_func (manager, download_removed_cb, popover);
+
+  children = gtk_container_get_children (GTK_CONTAINER (popover->downloads_box));
+  for (l = children; l; l = g_list_next (l)) {
+    GtkWidget *widget;
+    EphyDownload *download;
+
+    if (!GTK_IS_LIST_BOX_ROW (l->data))
+      continue;
+
+    widget = gtk_bin_get_child (GTK_BIN (l->data));
+    if (!EPHY_IS_DOWNLOAD_WIDGET (widget))
+      continue;
+
+    download = ephy_download_widget_get_download (EPHY_DOWNLOAD_WIDGET (widget));
+    if (!ephy_download_is_active (download)) {
+      ephy_downloads_manager_remove_download (manager, download);
+      gtk_widget_destroy (widget);
+    }
+  }
+  g_list_free (children);
+
+  g_signal_handlers_unblock_by_func (manager, download_removed_cb, popover);
+}
+
+static void
+ephy_downloads_popover_class_init (EphyDownloadsPopoverClass *klass)
+{
+}
+
+static void
+ephy_downloads_popover_init (EphyDownloadsPopover *popover)
+{
+  GtkWidget *scrolled_window;
+  GtkWidget *title, *clear_button;
+  GtkWidget *vbox, *hbox;
+  GList *downloads, *l;
+  char *markup;
+  EphyDownloadsManager *manager;
+
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  gtk_widget_set_valign (hbox, GTK_ALIGN_CENTER);
+  gtk_widget_set_margin_top (hbox, 6);
+  gtk_widget_set_margin_end (hbox, 6);
+
+  title = gtk_label_new (NULL);
+  markup = g_strdup_printf ("<b>%s</b>", _("Downloads"));
+  gtk_label_set_markup (GTK_LABEL (title), markup);
+  g_free (markup);
+  gtk_style_context_add_class (gtk_widget_get_style_context (title), GTK_STYLE_CLASS_TITLE);
+  gtk_box_pack_start (GTK_BOX (hbox), title, TRUE, TRUE, 0);
+  gtk_widget_show (title);
+
+  clear_button = gtk_button_new_with_label (_("Clear"));
+  g_signal_connect_swapped (clear_button, "clicked",
+                            G_CALLBACK (clear_button_clicked_cb),
+                            popover);
+  gtk_box_pack_end (GTK_BOX (hbox), clear_button, FALSE, FALSE, 0);
+  gtk_widget_show (clear_button);
+
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+                                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (scrolled_window),
+                                              DOWNLOADS_BOX_MIN_SIZE);
+
+  popover->downloads_box = gtk_list_box_new ();
+  g_signal_connect_swapped (popover->downloads_box, "row-activated",
+                            G_CALLBACK (download_box_row_activated_cb),
+                            popover);
+  gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (popover->downloads_box), FALSE);
+  g_object_set (popover->downloads_box, "margin", 12, NULL);
+  gtk_container_add (GTK_CONTAINER (scrolled_window), popover->downloads_box);
+  gtk_widget_show (popover->downloads_box);
+
+  manager = ephy_embed_shell_get_downloads_manager (ephy_embed_shell_get_default ());
+  downloads = ephy_downloads_manager_get_downloads (manager);
+  for (l = downloads; l != NULL; l = g_list_next (l)) {
+    EphyDownload *download = (EphyDownload *)l->data;
+    GtkWidget *widget;
+
+    widget = ephy_download_widget_new (download);
+    gtk_list_box_prepend (GTK_LIST_BOX (popover->downloads_box), widget);
+    gtk_widget_show (widget);
+  }
+
+  g_signal_connect_object (manager, "download-added",
+                           G_CALLBACK (download_added_cb),
+                           popover, G_CONNECT_SWAPPED);
+  g_signal_connect_object (manager, "download-removed",
+                           G_CALLBACK (download_removed_cb),
+                           popover, G_CONNECT_SWAPPED);
+
+  gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, FALSE, FALSE, 0);
+  gtk_widget_show (scrolled_window);
+
+  gtk_container_add (GTK_CONTAINER (popover), vbox);
+  gtk_widget_show (vbox);
+}
+
+GtkWidget *ephy_downloads_popover_new (GtkWidget *relative_to)
+{
+  return GTK_WIDGET (g_object_new (EPHY_TYPE_DOWNLOADS_POPOVER, "relative-to", relative_to, NULL));
+}
diff --git a/lib/widgets/ephy-downloads-popover.h b/lib/widgets/ephy-downloads-popover.h
new file mode 100644
index 0000000..587888d
--- /dev/null
+++ b/lib/widgets/ephy-downloads-popover.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2015 Igalia S.L.
+ *
+ *  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, 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/>.
+ *
+ */
+
+#ifndef EPHY_DOWNLOADS_POPOVER_H
+#define EPHY_DOWNLOADS_POPOVER_H
+
+#include <gtk/gtk.h>
+
+#include "ephy-download.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_DOWNLOADS_POPOVER            (ephy_downloads_popover_get_type())
+#define EPHY_DOWNLOADS_POPOVER(object)         (G_TYPE_CHECK_INSTANCE_CAST((object), 
EPHY_TYPE_DOWNLOADS_POPOVER, EphyDownloadsPopover))
+#define EPHY_IS_DOWNLOADS_POPOVER(object)      (G_TYPE_CHECK_INSTANCE_TYPE((object), 
EPHY_TYPE_DOWNLOADS_POPOVER))
+#define EPHY_DOWNLOADS_POPOVER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), 
EPHY_TYPE_DOWNLOADS_POPOVER, EphyDownloadsPopoverClass))
+#define EPHY_IS_DOWNLOADS_POPOVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), 
EPHY_TYPE_DOWNLOADS_POPOVER))
+#define EPHY_DOWNLOADS_POPOVER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), 
EPHY_TYPE_DOWNLOADS_POPOVER, EphyDownloadsPopoverClass))
+
+typedef struct _EphyDownloadsPopover        EphyDownloadsPopover;
+typedef struct _EphyDownloadsPopoverClass   EphyDownloadsPopoverClass;
+
+GType      ephy_downloads_popover_get_type (void);
+
+GtkWidget *ephy_downloads_popover_new      (GtkWidget *relative_to);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index 1a093de..28f2df7 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -26,7 +26,7 @@
 #include "ephy-bookmarks-editor.h"
 #include "ephy-bookmarks-import.h"
 #include "ephy-debug.h"
-#include "ephy-download.h"
+#include "ephy-downloads-manager.h"
 #include "ephy-embed-container.h"
 #include "ephy-embed-utils.h"
 #include "ephy-file-helpers.h"
@@ -294,7 +294,8 @@ download_started_cb (WebKitWebContext *web_context,
     window = gtk_application_get_active_window (GTK_APPLICATION (shell));
 
   ephy_download = ephy_download_new (download, window);
-  ephy_window_add_download (EPHY_WINDOW (window), ephy_download);
+  ephy_downloads_manager_add_download (ephy_embed_shell_get_downloads_manager (EPHY_EMBED_SHELL (shell)),
+                                       ephy_download);
   g_object_unref (ephy_download);
 }
 
diff --git a/src/ephy-toolbar.c b/src/ephy-toolbar.c
index 12f877b..c5c9337 100644
--- a/src/ephy-toolbar.c
+++ b/src/ephy-toolbar.c
@@ -25,6 +25,7 @@
 #include "ephy-location-entry.h"
 #include "ephy-middle-clickable-button.h"
 #include "ephy-private.h"
+#include "ephy-downloads-popover.h"
 
 G_DEFINE_TYPE (EphyToolbar, ephy_toolbar, GTK_TYPE_HEADER_BAR)
 
@@ -45,9 +46,37 @@ struct _EphyToolbarPrivate {
   GtkWidget *navigation_box;
   GtkWidget *page_menu_button;
   GtkWidget *new_tab_button;
+  GtkWidget *downloads_revealer;
+  GtkWidget *downloads_button;
+  GtkWidget *downloads_popover;
 };
 
 static void
+download_added_cb (EphyDownloadsManager *manager,
+                   EphyDownload *download,
+                   EphyToolbar *toolbar)
+{
+  EphyToolbarPrivate *priv = toolbar->priv;
+
+  if (!priv->downloads_popover) {
+    priv->downloads_popover = ephy_downloads_popover_new (priv->downloads_button);
+    gtk_menu_button_set_popover (GTK_MENU_BUTTON (priv->downloads_button),
+                                 priv->downloads_popover);
+  }
+
+  gtk_revealer_set_reveal_child (GTK_REVEALER (priv->downloads_revealer), TRUE);
+}
+
+static void
+download_removed_cb (EphyDownloadsManager *manager,
+                     EphyDownload *download,
+                     EphyToolbar *toolbar)
+{
+  if (!ephy_downloads_manager_get_downloads (manager))
+    gtk_revealer_set_reveal_child (GTK_REVEALER (toolbar->priv->downloads_revealer), FALSE);
+}
+
+static void
 ephy_toolbar_set_property (GObject *object,
                            guint property_id,
                            const GValue *value,
@@ -103,6 +132,7 @@ ephy_toolbar_constructed (GObject *object)
   GtkAction *action;
   GtkUIManager *manager;
   GtkWidget *toolbar, *box, *button, *menu;
+  EphyDownloadsManager *downloads_manager;
 
   G_OBJECT_CLASS (ephy_toolbar_parent_class)->constructed (object);
 
@@ -190,6 +220,37 @@ ephy_toolbar_constructed (GObject *object)
   gtk_widget_set_halign (menu, GTK_ALIGN_END);
   gtk_menu_button_set_popup (GTK_MENU_BUTTON (button), menu);
   gtk_header_bar_pack_end (GTK_HEADER_BAR (toolbar), button);
+
+  /* Downloads */
+  downloads_manager = ephy_embed_shell_get_downloads_manager (ephy_embed_shell_get_default ());
+
+  priv->downloads_revealer = gtk_revealer_new ();
+  gtk_revealer_set_transition_type (GTK_REVEALER (priv->downloads_revealer), 
GTK_REVEALER_TRANSITION_TYPE_CROSSFADE);
+  gtk_revealer_set_reveal_child (GTK_REVEALER (priv->downloads_revealer),
+                                 ephy_downloads_manager_get_downloads (downloads_manager) != NULL);
+
+  priv->downloads_button = gtk_menu_button_new ();
+  gtk_button_set_image (GTK_BUTTON (priv->downloads_button),
+                        gtk_image_new_from_icon_name ("folder-download-symbolic", GTK_ICON_SIZE_BUTTON));
+  gtk_widget_set_valign (priv->downloads_button, GTK_ALIGN_CENTER);
+  gtk_container_add (GTK_CONTAINER (priv->downloads_revealer), priv->downloads_button);
+  gtk_widget_show (priv->downloads_button);
+
+  if (ephy_downloads_manager_get_downloads (downloads_manager)) {
+    priv->downloads_popover = ephy_downloads_popover_new (priv->downloads_button);
+    gtk_menu_button_set_popover (GTK_MENU_BUTTON (priv->downloads_button),
+                                 priv->downloads_popover);
+  }
+
+  g_signal_connect_object (downloads_manager, "download-added",
+                           G_CALLBACK (download_added_cb),
+                           object, 0);
+  g_signal_connect_object (downloads_manager, "download-removed",
+                           G_CALLBACK (download_removed_cb),
+                           object, 0);
+
+  gtk_header_bar_pack_end (GTK_HEADER_BAR (toolbar), priv->downloads_revealer);
+  gtk_widget_show (priv->downloads_revealer);
 }
 
 static void
diff --git a/src/ephy-window.c b/src/ephy-window.c
index 9bca864..4c2cde6 100644
--- a/src/ephy-window.c
+++ b/src/ephy-window.c
@@ -28,7 +28,6 @@
 #include "ephy-certificate-popover.h"
 #include "ephy-combined-stop-reload-action.h"
 #include "ephy-debug.h"
-#include "ephy-download-widget.h"
 #include "ephy-embed-container.h"
 #include "ephy-embed-prefs.h"
 #include "ephy-embed-shell.h"
@@ -196,9 +195,6 @@ static const GtkToggleActionEntry ephy_menu_toggle_entries [] =
 {
        /* View actions. */
 
-       { "ViewDownloadsBar", NULL, N_("_Downloads Bar"), NULL, NULL,
-         NULL, FALSE },
-
        { "ViewFullscreen", NULL, N_("_Fullscreen"), "F11", NULL,
          G_CALLBACK (window_cmd_view_fullscreen), FALSE },
        { "ViewPopupWindows", NULL, N_("Popup _Windows"), NULL, NULL,
@@ -368,7 +364,6 @@ struct _EphyWindowPrivate
        EphyEmbedEvent *context_event;
        WebKitHitTestResult *hit_test_result;
        guint idle_worker;
-       GtkWidget *downloads_box;
 
        EphyLocationController *location_controller;
 
@@ -488,9 +483,9 @@ confirm_close_with_downloads (EphyWindow *window)
        int response;
 
        dialog = construct_confirm_close_dialog (window,
-                       _("There are ongoing downloads in this window"),
-                       _("If you close this window, the downloads will be cancelled"),
-                       _("Close window and cancel downloads"));
+                       _("There are ongoing downloads"),
+                       _("If you quit, the downloads will be cancelled"),
+                       _("Quit and cancel downloads"));
        response = gtk_dialog_run (GTK_DIALOG (dialog));
 
        gtk_widget_destroy (dialog);
@@ -676,18 +671,15 @@ static void
 sync_chromes_visibility (EphyWindow *window)
 {
        EphyWindowPrivate *priv = window->priv;
-       gboolean show_tabsbar, show_downloads_box;
+       gboolean show_tabsbar;
 
        if (priv->closing)
                return;
 
        show_tabsbar = (priv->chrome & EPHY_WINDOW_CHROME_TABSBAR);
-       show_downloads_box = (priv->chrome & EPHY_WINDOW_CHROME_DOWNLOADS_BOX);
 
        ephy_notebook_set_tabs_allowed (EPHY_NOTEBOOK (priv->notebook),
                                        show_tabsbar && !(priv->is_popup || priv->fullscreen_mode));
-       gtk_widget_set_visible (priv->downloads_box,
-                               show_downloads_box && !priv->fullscreen_mode);
 }
 
 static void
@@ -869,30 +861,6 @@ ephy_window_key_press_event (GtkWidget *widget,
 }
 
 static gboolean
-window_has_ongoing_downloads (EphyWindow *window)
-{
-       GList *l, *downloads;
-       gboolean downloading = FALSE;
-
-       downloads = gtk_container_get_children (GTK_CONTAINER (window->priv->downloads_box));
-
-       for (l = downloads; l != NULL; l = l->next)
-       {
-               if (EPHY_IS_DOWNLOAD_WIDGET (l->data) != TRUE)
-                       continue;
-
-               if (!ephy_download_widget_download_is_finished (EPHY_DOWNLOAD_WIDGET (l->data)))
-               {
-                       downloading = TRUE;
-                       break;
-               }
-       }
-       g_list_free (downloads);
-
-       return downloading;
-}
-
-static gboolean
 ephy_window_delete_event (GtkWidget *widget,
                          GdkEventAny *event)
 {
@@ -2003,7 +1971,8 @@ save_target_uri (EphyWindow *window,
 
                        download = ephy_download_new_for_uri (location, GTK_WINDOW (window));
                        ephy_download_set_action (download, EPHY_DOWNLOAD_ACTION_OPEN);
-                       ephy_window_add_download (window, download);
+                       ephy_downloads_manager_add_download (ephy_embed_shell_get_downloads_manager 
(EPHY_EMBED_SHELL (ephy_shell_get_default ())),
+                                                            download);
                        g_object_unref (download);
                }
 
@@ -2825,10 +2794,15 @@ notebook_page_close_request_cb (EphyNotebook *notebook,
                {
                        return;
                }
-               if (window_has_ongoing_downloads (window) &&
-                   !confirm_close_with_downloads (window))
+
+               /* Last window, check ongoing downloads before closing the tab */
+               if (ephy_shell_get_n_windows (ephy_shell_get_default ()) == 1)
                {
-                       return;
+                       EphyDownloadsManager *manager = ephy_embed_shell_get_downloads_manager 
(EPHY_EMBED_SHELL (ephy_shell_get_default ()));
+
+                       if (ephy_downloads_manager_has_active_downloads (manager) &&
+                           !confirm_close_with_downloads (window))
+                               return;
                }
        }
 
@@ -2937,103 +2911,6 @@ setup_notebook (EphyWindow *window)
 }
 
 static void
-ephy_window_set_downloads_box_visibility (EphyWindow *window,
-                                         gboolean show)
-{
-       EphyWindowChrome chrome = window->priv->chrome;
-
-       if (show)
-               chrome |= EPHY_WINDOW_CHROME_DOWNLOADS_BOX;
-       else
-               chrome &= ~EPHY_WINDOW_CHROME_DOWNLOADS_BOX;
-
-       ephy_window_set_chrome (window, chrome);
-}
-
-void
-ephy_window_add_download (EphyWindow *window,
-                         EphyDownload *download)
-{
-       GtkWidget *widget;
-
-       widget = ephy_download_widget_new (download);
-       gtk_box_pack_start (GTK_BOX (window->priv->downloads_box),
-                           widget, FALSE, FALSE, 0);
-       gtk_widget_show (widget);
-       ephy_window_set_downloads_box_visibility (window, TRUE);
-}
-
-static void
-downloads_removed_cb (GtkContainer *container,
-                     GtkWidget *widget,
-                     gpointer data)
-{
-       EphyWindow *window = EPHY_WINDOW (data);
-       GList *children = NULL;
-
-       children = gtk_container_get_children (container);
-       if (g_list_length (children) == 1)
-               ephy_window_set_downloads_box_visibility (window, FALSE);
-
-       g_list_free (children);
-}
-
-static void
-downloads_close_cb (GtkButton *button, EphyWindow *window)
-{
-       GList *l, *downloads;
-
-       downloads = gtk_container_get_children (GTK_CONTAINER (window->priv->downloads_box));
-
-       for (l = downloads; l != NULL; l = l->next)
-       {
-               if (EPHY_IS_DOWNLOAD_WIDGET (l->data) != TRUE)
-                       continue;
-
-               if (ephy_download_widget_download_is_finished (EPHY_DOWNLOAD_WIDGET (l->data)))
-               {
-                       gtk_widget_destroy (GTK_WIDGET (l->data));
-               }
-       }
-       g_list_free (downloads);
-
-       ephy_window_set_downloads_box_visibility (window, FALSE);
-}
-
-static GtkWidget *
-setup_downloads_box (EphyWindow *window)
-{
-       GtkWidget *widget;
-       GtkWidget *close_button;
-       GtkWidget *image;
-
-       widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
-       close_button = gtk_button_new ();
-       gtk_container_set_border_width (GTK_CONTAINER (close_button), 6);
-       gtk_widget_set_valign (close_button, GTK_ALIGN_CENTER);
-       gtk_style_context_add_class (gtk_widget_get_style_context (close_button), "image-button");
-       gtk_style_context_add_class (gtk_widget_get_style_context (close_button), "close");
-       gtk_style_context_add_class (gtk_widget_get_style_context (widget), "download-box");
-
-       gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
-
-       image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_MENU);
-       g_object_set (image, "use-fallback", TRUE, NULL);
-
-       gtk_container_add (GTK_CONTAINER (close_button), image);
-       gtk_box_pack_end (GTK_BOX (widget), close_button, FALSE, FALSE, 4);
-
-       g_signal_connect (close_button, "clicked",
-                         G_CALLBACK (downloads_close_cb), window);
-       g_signal_connect (widget, "remove",
-                         G_CALLBACK (downloads_removed_cb), window);
-
-       gtk_widget_show_all (close_button);
-
-       return widget;
-}
-
-static void
 ephy_window_dispose (GObject *object)
 {
        EphyWindow *window = EPHY_WINDOW (object);
@@ -3491,16 +3368,6 @@ ephy_window_constructor (GType type,
                            TRUE, TRUE, 0);
        gtk_widget_show (GTK_WIDGET (priv->notebook));
 
-       priv->downloads_box = setup_downloads_box (window);
-       gtk_box_pack_start (GTK_BOX (priv->main_vbox),
-                           GTK_WIDGET (priv->downloads_box), FALSE, FALSE, 0);
-       action = gtk_action_group_get_action (window->priv->action_group,
-                                             "ViewDownloadsBar");
-
-       g_object_bind_property (action, "active",
-                               priv->downloads_box, "visible",
-                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-
        /* Attach the CSS provider to the window. */
        css_provider = gtk_css_provider_new ();
        _gtk_css_provider_load_from_resource (css_provider,
@@ -4084,15 +3951,18 @@ ephy_window_close (EphyWindow *window)
                return FALSE;
        }
 
-       if (window_has_ongoing_downloads (window) && confirm_close_with_downloads (window) == FALSE)
-       {
-               /* stop window close */
-               return FALSE;
-       }
-
-       /* If this is the last window, save its state in the session. */
+       /* If this is the last window, check ongoing downloads and save its state in the session. */
        if (ephy_shell_get_n_windows (ephy_shell_get_default ()) == 1)
        {
+               EphyDownloadsManager *manager = ephy_embed_shell_get_downloads_manager (EPHY_EMBED_SHELL 
(ephy_shell_get_default ()));
+
+               if (ephy_downloads_manager_has_active_downloads (manager) &&
+                   !confirm_close_with_downloads (window))
+               {
+                       /* stop window close */
+                       return FALSE;
+               }
+
                ephy_session_close (ephy_shell_get_session (ephy_shell_get_default ()));
        }
 
diff --git a/src/ephy-window.h b/src/ephy-window.h
index 4d4e3c8..2b09311 100644
--- a/src/ephy-window.h
+++ b/src/ephy-window.h
@@ -24,7 +24,6 @@
 #ifndef EPHY_WINDOW_H
 #define EPHY_WINDOW_H
 
-#include "ephy-download.h"
 #include "ephy-web-view.h"
 
 #include <gtk/gtk.h>
@@ -43,8 +42,7 @@ typedef enum
         EPHY_WINDOW_CHROME_TOOLBAR       = 1 << 0,
         EPHY_WINDOW_CHROME_MENU          = 1 << 1,
         EPHY_WINDOW_CHROME_LOCATION      = 1 << 2,
-        EPHY_WINDOW_CHROME_DOWNLOADS_BOX = 1 << 3,
-        EPHY_WINDOW_CHROME_TABSBAR       = 1 << 4,
+        EPHY_WINDOW_CHROME_TABSBAR       = 1 << 3,
         EPHY_WINDOW_CHROME_DEFAULT       = (EPHY_WINDOW_CHROME_TOOLBAR | EPHY_WINDOW_CHROME_MENU | 
EPHY_WINDOW_CHROME_LOCATION | EPHY_WINDOW_CHROME_TABSBAR)
 } EphyWindowChrome;
 
@@ -84,9 +82,6 @@ const char       *ephy_window_get_location        (EphyWindow *window);
 
 gboolean          ephy_window_close               (EphyWindow *window);
 
-void              ephy_window_add_download        (EphyWindow *window,
-                                                   EphyDownload *download);
-
 EphyWindowChrome  ephy_window_get_chrome          (EphyWindow *window);
 
 gboolean      ephy_window_is_on_current_workspace (EphyWindow *window);
diff --git a/src/popup-commands.c b/src/popup-commands.c
index ab6538a..d4541d4 100644
--- a/src/popup-commands.c
+++ b/src/popup-commands.c
@@ -22,7 +22,7 @@
 #include "popup-commands.h"
 
 #include "ephy-bookmarks-ui.h"
-#include "ephy-download.h"
+#include "ephy-downloads-manager.h"
 #include "ephy-embed-container.h"
 #include "ephy-embed-utils.h"
 #include "ephy-file-chooser.h"
@@ -183,7 +183,8 @@ filename_suggested_cb (EphyDownload *download,
                webkit_download = ephy_download_get_webkit_download (download);
                webkit_download_set_allow_overwrite (webkit_download, TRUE);
 
-               ephy_window_add_download (window, download);
+               ephy_downloads_manager_add_download (ephy_embed_shell_get_downloads_manager 
(ephy_embed_shell_get_default ()),
+                                                    download);
        }
        else
        {
@@ -280,7 +281,8 @@ popup_cmd_set_image_as_background (GtkAction *action,
 
        ephy_download_set_destination_uri (download, dest_uri);
        ephy_download_set_action (download, EPHY_DOWNLOAD_ACTION_DO_NOTHING);
-       ephy_window_add_download (window, download);
+       ephy_downloads_manager_add_download (ephy_embed_shell_get_downloads_manager 
(ephy_embed_shell_get_default ()),
+                                            download);
        g_object_unref (download);
 
        g_signal_connect (download, "completed",
diff --git a/src/resources/epiphany.css b/src/resources/epiphany.css
index 7c513d8..53cefdd 100644
--- a/src/resources/epiphany.css
+++ b/src/resources/epiphany.css
@@ -23,28 +23,10 @@
     background-color: @theme_unfocused_base_color;
     border-color: @unfocused_borders; }
 
-.download-box {
-  border-style: solid none none;
-  border-width: 1px;
-  border-color: @borders; }
-  .download-box:backdrop {
-    border-color: @unfocused_borders; }
-
-.download-box .button .filename:dir(ltr) {
-  padding-right: 6px; }
-.download-box .button .filename:dir(rtl) {
-  padding-left: 6px; }
-
-.download-box .button.needs-attention .filename {
-  animation: needs_attention 150ms ease-in;
-  background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(#4a90d9), 
to(transparent)), -gtk-gradient(radial, center center, 0, center center, 0.5, to(rgba(255, 255, 255, 
0.76923)), to(transparent));
-  background-size: 6px 6px, 6px 6px;
-  background-repeat: no-repeat;
-  background-position: right 3px, right 4px; }
-  .download-box .button.needs-attention .filename:dir(rtl) {
-    background-position: left 3px, left 4px; }
-  .download-box .button.needs-attention .filename:backdrop {
-    background-size: 6px 6px, 0 0; }
+.download-circular-button {
+  border-radius: 20px;
+  outline-radius: 20px;
+}
 
 .incognito-mode.titlebar {
   background-image: linear-gradient(to bottom, #d7dce2, #cbd2d9);


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