[epiphany/downloads: 3/5] ephy-download: add the new EphyDownload object



commit 7e4fc26b5336ef1f0d1c5820a997b702a51428c7
Author: Diego Escalante Urrelo <descalante igalia com>
Date:   Tue Jan 18 11:10:11 2011 -0500

    ephy-download: add the new EphyDownload object
    
    EphyDownload is a wrapper object around WebKitDownload that handles common
    behavior in downloads: auto-destination, default action for the MIME type.
    
    It can be used to wrap a WebKitDownload coming from a WebKitView or to download
    a url: ephy_download_new_for_uri and ephy_download_new_for_download are
    provided.
    
    Its lifetime is not automagic like EphyEmbedPersist, so you have to unref it
    when you no longer need it.
    
    This new object replaces EphyEmbedPersist and enables us to use a single
    codepath for downloads in all Epiphany.
    
    Bug #618443

 data/glade/epiphany.ui     |   80 ----
 embed/Makefile.am          |    6 +-
 embed/downloader-view.c    | 1022 --------------------------------------------
 embed/downloader-view.h    |   84 ----
 embed/ephy-download.c      |  960 +++++++++++++++++++++++++++++++++++++++++
 embed/ephy-download.h      |  115 +++++
 embed/ephy-embed-persist.c |  911 ---------------------------------------
 embed/ephy-embed-persist.h |  132 ------
 embed/ephy-embed-shell.c   |  144 ++++---
 embed/ephy-embed-shell.h   |   16 +-
 embed/ephy-embed.c         |  478 +--------------------
 lib/ephy-marshal.list      |    1 +
 po/POTFILES.in             |    3 +-
 src/Makefile.am            |    4 +-
 src/ephy-session.c         |   21 +-
 src/ephy-shell.c           |    1 -
 src/ephy-window.c          |    1 -
 src/epiphany.h.in          |    1 +
 src/popup-commands.c       |  162 ++++----
 src/window-commands.c      |    1 -
 tests/Makefile.am          |    6 +-
 tests/ephy-download.c      |  207 +++++++++
 tests/ephy-embed-persist.c |  315 --------------
 23 files changed, 1491 insertions(+), 3180 deletions(-)
---
diff --git a/data/glade/epiphany.ui b/data/glade/epiphany.ui
index f8023a2..08c67b4 100644
--- a/data/glade/epiphany.ui
+++ b/data/glade/epiphany.ui
@@ -454,84 +454,4 @@
       <action-widget response="-11">encoding_help_button</action-widget>
     </action-widgets>
   </object>
-  <object class="GtkDialog" id="download_manager_dialog">
-    <property name="border_width">5</property>
-    <property name="title" translatable="yes">Downloads</property>
-    <property name="role">epiphany-download-manager</property>
-    <property name="default_width">440</property>
-    <property name="default_height">260</property>
-    <property name="type_hint">normal</property>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox31">
-        <property name="visible">True</property>
-        <property name="orientation">vertical</property>
-        <property name="spacing">2</property>
-        <child>
-          <object class="GtkScrolledWindow" id="scrolledwindow1134">
-            <property name="height_request">100</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="border_width">5</property>
-            <property name="hscrollbar_policy">automatic</property>
-            <property name="vscrollbar_policy">automatic</property>
-            <property name="shadow_type">in</property>
-            <child>
-              <object class="GtkTreeView" id="clist">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area31">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="pause_button">
-                <property name="label">DYNAMIC</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_underline">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="abort_button">
-                <property name="label">gtk-stop</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <action-widgets>
-      <action-widget response="1">pause_button</action-widget>
-      <action-widget response="2">abort_button</action-widget>
-    </action-widgets>
-  </object>
 </interface>
diff --git a/embed/Makefile.am b/embed/Makefile.am
index 5138043..d517fb4 100644
--- a/embed/Makefile.am
+++ b/embed/Makefile.am
@@ -8,7 +8,6 @@ header_DATA = \
 	$(INST_H_FILES)
 
 NOINST_H_FILES = \
-	downloader-view.h		\
 	ephy-embed-dialog.h		\
 	ephy-encodings.h		\
 	ephy-favicon-cache.h
@@ -16,10 +15,10 @@ NOINST_H_FILES = \
 INST_H_FILES = \
 	ephy-adblock.h			\
 	ephy-adblock-manager.h		\
+	ephy-download.h			\
 	ephy-embed.h			\
 	ephy-embed-container.h          \
 	ephy-embed-event.h		\
-	ephy-embed-persist.h		\
 	ephy-embed-prefs.h		\
 	ephy-embed-single.h		\
 	ephy-embed-shell.h		\
@@ -36,12 +35,11 @@ BUILT_SOURCES = \
 libephyembed_la_SOURCES = \
 	ephy-adblock.c			\
 	ephy-adblock-manager.c		\
-	downloader-view.c		\
+	ephy-download.c			\
 	ephy-embed.c			\
 	ephy-embed-container.c          \
 	ephy-embed-dialog.c		\
 	ephy-embed-event.c		\
-	ephy-embed-persist.c		\
 	ephy-embed-single.c		\
 	ephy-embed-shell.c		\
 	ephy-embed-utils.c              \
diff --git a/embed/ephy-download.c b/embed/ephy-download.c
new file mode 100644
index 0000000..1ee6f55
--- /dev/null
+++ b/embed/ephy-download.c
@@ -0,0 +1,960 @@
+/* vim: set sw=2 ts=2 sts=2 et: */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * ephy-download.c
+ * This file is part of Epiphany
+ *
+ * Copyright © 2011 - 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Epiphany 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 Epiphany; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+
+#include "ephy-debug.h"
+#include "ephy-download.h"
+#include "ephy-embed.h"
+#include "ephy-embed-shell.h"
+#include "ephy-embed-type-builtins.h"
+#include "ephy-file-helpers.h"
+#include "ephy-marshal.h"
+#include "ephy-prefs.h"
+#include "ephy-settings.h"
+
+#include <errno.h>
+#include <glib/gi18n.h>
+#include <string.h>
+#include <webkit/webkit.h>
+
+G_DEFINE_TYPE (EphyDownload, ephy_download, G_TYPE_OBJECT)
+
+#define EPHY_DOWNLOAD_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), EPHY_TYPE_DOWNLOAD, EphyDownloadPrivate))
+
+struct _EphyDownloadPrivate
+{
+  WebKitDownload *download;
+
+  char *destination;
+  char *source;
+
+  EphyDownloadActionType action;
+  guint32 start_time;
+
+  GtkWidget *window;
+  GtkWidget *widget;
+};
+
+enum
+{
+  PROP_0,
+  PROP_DOWNLOAD,
+  PROP_DESTINATION,
+  PROP_SOURCE,
+  PROP_ACTION,
+  PROP_START_TIME,
+  PROP_WINDOW,
+  PROP_WIDGET
+};
+
+static void
+ephy_download_get_property (GObject    *object,
+                            guint       property_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  EphyDownload *download;
+  EphyDownloadPrivate *priv;
+
+  download = EPHY_DOWNLOAD (object);
+  priv = download->priv;
+
+  switch (property_id) {
+    case PROP_WIDGET:
+      g_value_set_object (value, priv->widget);
+      break;
+    case PROP_WINDOW:
+      g_value_set_object (value, priv->window);
+      break;
+    case PROP_DOWNLOAD:
+      g_value_set_object (value, ephy_download_get_webkit_download (download));
+      break;
+    case PROP_DESTINATION:
+      g_value_set_string (value, ephy_download_get_destination_uri (download));
+      break;
+    case PROP_SOURCE:
+      g_value_set_string (value, ephy_download_get_source_uri (download));
+      break;
+    case PROP_ACTION:
+      g_value_set_enum (value, ephy_download_get_action (download));
+      break;
+    case PROP_START_TIME:
+      g_value_set_uint (value, ephy_download_get_start_time (download));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+ephy_download_set_property (GObject      *object,
+                            guint         property_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  EphyDownload *download;
+  download = EPHY_DOWNLOAD (object);
+
+  switch (property_id) {
+    case PROP_DESTINATION:
+      ephy_download_set_destination_uri (download, g_value_get_string (value));
+      break;
+    case PROP_ACTION:
+      ephy_download_set_action (download, g_value_get_enum (value));
+      break;
+    case PROP_WINDOW:
+      ephy_download_set_window (download, g_value_get_object (value));
+      break;
+    case PROP_WIDGET:
+      ephy_download_set_widget (download, g_value_get_object (value));
+      break;
+    case PROP_DOWNLOAD:
+    case PROP_SOURCE:
+    case PROP_START_TIME:
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static EphyDownloadActionType
+decide_action_from_mime (EphyDownload *ephy_download)
+{
+  WebKitNetworkResponse *response;
+  SoupMessage *message;
+  char *mime_description = NULL;
+  GAppInfo *helper_app = NULL;
+  EphyMimePermission mime_permission = EPHY_MIME_PERMISSION_SAFE;
+  EphyDownloadActionType action;
+  WebKitDownload *download;
+
+  download = ephy_download_get_webkit_download (ephy_download);
+
+  response = webkit_download_get_network_response (download);
+  message = webkit_network_response_get_message (response);
+
+  if (message) {
+    const char *content_type = soup_message_headers_get_content_type (message->response_headers, NULL);
+
+    if (content_type) {
+      mime_description = g_content_type_get_description (content_type);
+      helper_app = g_app_info_get_default_for_type (content_type, FALSE);
+      mime_permission = ephy_file_check_mime (content_type);
+
+      if (helper_app)
+        action = EPHY_DOWNLOAD_ACTION_OPEN;
+     }
+  }
+
+  if (mime_description == NULL) {
+    mime_description = g_strdup (C_("file type", "Unknown"));
+    action = EPHY_DOWNLOAD_ACTION_BROWSE_TO;
+  }
+
+  /* Sometimes downloads can have a mime_description but a NULL helper_app
+   * in that case action is never changed so DOWNLOAD_ACTION_DOWNLOAD remains
+   * as action value. This is the same response value as Save as...
+   * button, which is wrong for the Download button.
+   */
+  if (helper_app == NULL)
+    action = EPHY_DOWNLOAD_ACTION_BROWSE_TO;
+
+  return action;
+}
+
+/* From the old embed/mozilla/MozDownload.cpp */
+static const char*
+file_is_compressed (const char *filename)
+{
+  int i;
+  static const char * const compression[] = {".gz", ".bz2", ".Z", ".lz", NULL};
+
+  for (i = 0; compression[i] != NULL; i++) {
+    if (g_str_has_suffix (filename, compression[i]))
+      return compression[i];
+  }
+
+  return NULL;
+}
+
+static const char*
+parse_extension (const char *filename)
+{
+  const char *compression;
+  const char *last_separator;
+
+  compression = file_is_compressed (filename);
+
+  /* if the file is compressed we might have a double extension */
+  if (compression != NULL) {
+    int i;
+    static const char * const extensions[] = {"tar", "ps", "xcf", "dvi", "txt", "text", NULL};
+
+    for (i = 0; extensions[i] != NULL; i++) {
+      char *suffix;
+      suffix = g_strdup_printf (".%s%s", extensions[i], compression);
+
+      if (g_str_has_suffix (filename, suffix)) {
+        char *p;
+
+        p = g_strrstr (filename, suffix);
+        g_free (suffix);
+
+        return p;
+      }
+
+      g_free (suffix);
+    }
+  }
+
+  /* no compression, just look for the last dot in the filename */
+  last_separator = strrchr (filename, G_DIR_SEPARATOR);
+  return strrchr ((last_separator) ? last_separator : filename, '.');
+}
+
+static char *
+define_destination_uri (EphyDownload *download)
+{
+  char *dest_dir;
+  char *dest_name;
+  char *destination_filename;
+  char *destination_uri;
+  const char *suggested_filename;
+
+  suggested_filename = webkit_download_get_suggested_filename (download->priv->download);
+  dest_dir = ephy_file_get_downloads_dir ();
+
+  /* Make sure the download directory exists */
+  if (g_mkdir_with_parents (dest_dir, 0700) == -1) {
+    g_critical ("Could not create downloads directory \"%s\": %s",
+                dest_dir, strerror (errno));
+    g_free (dest_dir);
+    return NULL;
+  }
+
+  if (suggested_filename != NULL) {
+    dest_name = g_strdup (suggested_filename);
+  } else {
+    dest_name = ephy_file_tmp_filename ("ephy-download-XXXXXX", NULL);
+  }
+
+  destination_filename = g_build_filename (dest_dir, dest_name, NULL);
+  g_free (dest_dir);
+  g_free (dest_name);
+
+  /* Append (n) as needed. */
+  if (g_file_test (destination_filename, G_FILE_TEST_EXISTS)) {
+    int i = 1;
+    const char *dot_pos;
+    gssize position;
+    char *serial = NULL;
+    GString *tmp_filename;
+
+    dot_pos = parse_extension (destination_filename);
+    if (dot_pos)
+      position = dot_pos - destination_filename;
+    else
+      position = strlen (destination_filename);
+
+    tmp_filename = g_string_new (NULL);
+
+    do {
+      serial = g_strdup_printf ("(%d)", i++);
+
+      g_string_assign (tmp_filename, destination_filename);
+      g_string_insert (tmp_filename, position, serial);
+
+      g_free (serial);
+    } while (g_file_test (tmp_filename->str, G_FILE_TEST_EXISTS));
+
+    destination_filename = g_strdup (tmp_filename->str);
+    g_string_free (tmp_filename, TRUE);
+  }
+
+  destination_uri = g_filename_to_uri (destination_filename, NULL, NULL);
+  g_free (destination_filename);
+
+  g_assert (destination_uri);
+
+  return destination_uri;
+}
+
+/**
+ * ephy_download_set_destination_uri:
+ * @download: an #EphyDownload
+ * @destination: URI where to save @download
+ *
+ * Sets the destination URI of @download. It must be a proper URI, with a
+ * scheme like file:/// or similar.
+ **/
+void
+ephy_download_set_destination_uri (EphyDownload *download, const char *destination)
+{
+  EphyDownloadPrivate *priv;
+  char *scheme;
+
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+  g_return_if_fail (destination != NULL);
+
+  priv = download->priv;
+
+  scheme = g_uri_parse_scheme (destination);
+  g_return_if_fail (scheme != NULL);
+  g_free (scheme);
+
+  priv->destination = g_strdup (destination);
+
+  webkit_download_set_destination_uri (priv->download, priv->destination);
+  g_object_notify (G_OBJECT (download), "destination");
+}
+
+/**
+ * ephy_download_set_auto_destination:
+ * @download: an #EphyDownload
+ *
+ * Tells @download to automatically determine a destination for itself.
+ **/
+void
+ephy_download_set_auto_destination (EphyDownload *download)
+{
+  char *dest;
+
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  dest = define_destination_uri (download);
+  ephy_download_set_destination_uri (download, dest);
+
+  g_free (dest);
+}
+
+/**
+ * ephy_download_set_action:
+ * @download: an #EphyDownload
+ * @action: #EphyDownloadActionType to execute
+ *
+ * Sets the @action to be executed when ephy_download_do_download_action () is
+ * called on @download or on finish when "Automatically download and open
+ * files" is set.
+ **/
+void
+ephy_download_set_action (EphyDownload *download,
+                          EphyDownloadActionType action)
+{
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  download->priv->action = action;
+  g_object_notify (G_OBJECT (download), "action");
+}
+
+/**
+ * ephy_download_set_window:
+ * @download: an #EphyDownload
+ * @window: #GtkWidget that produced @download
+ *
+ * Sets @window to be @download's parent, this means that @download will be
+ * shown on @window's #EphyWindow (where it is contained).
+ **/
+void
+ephy_download_set_window (EphyDownload *download,
+                          GtkWidget *window)
+{
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  if (download->priv->window != NULL)
+    g_object_unref (download->priv->window);
+
+  if (window != NULL) {
+    download->priv->window = g_object_ref (window);
+    g_object_notify (G_OBJECT (download), "window");
+  }
+}
+
+/**
+ * ephy_download_set_widget:
+ * @download: an #EphyDownload
+ * @widget: a #GtkWidget
+ *
+ * Sets @widget to be associated with @download as its UI.
+ **/
+void
+ephy_download_set_widget (EphyDownload *download,
+                          GtkWidget *widget)
+{
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  if (download->priv->widget != NULL)
+    g_object_unref (download->priv->widget);
+
+  if (widget != NULL) {
+    download->priv->widget = g_object_ref (widget);
+    g_object_notify (G_OBJECT (download), "widget");
+  }
+}
+
+/**
+ * ephy_download_get_widget:
+ * @download: an #EphyDownload
+ *
+ * Gets the #GtkWidget associated to this download.
+ *
+ * Returns: (transfer none): a #GtkWidget.
+ **/
+GtkWidget *
+ephy_download_get_widget (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->widget;
+}
+
+/**
+ * ephy_download_get_webkit_download:
+ * @download: an #EphyDownload
+ *
+ * Gets the #WebKitDownload being wrapped by @download.
+ *
+ * Returns: (transfer none): a #WebKitDownload.
+ **/
+WebKitDownload *
+ephy_download_get_webkit_download (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->download;
+}
+
+/**
+ * ephy_download_get_window:
+ * @download: an #EphyDownload
+ *
+ * Gets the window set as the parent of @download, this can be NULL if no
+ * specific window generated this download.
+ *
+ * Returns: (transfer none): a #GtkWidget
+ **/
+GtkWidget *
+ephy_download_get_window (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->window;
+}
+
+/**
+ * ephy_download_get_destination_uri:
+ * @download: an #EphyDownload
+ *
+ * Gets the destination URI where the download is being saved.
+ *
+ * Returns: (transfer none): destination URI.
+ **/
+const char *
+ephy_download_get_destination_uri (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->destination;
+}
+
+/**
+ * ephy_download_get_source_uri:
+ * @download: an #EphyDownload
+ *
+ * Gets the source URI that this download is/will download.
+ *
+ * Returns: source URI.
+ **/
+const char *
+ephy_download_get_source_uri (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), NULL);
+
+  return download->priv->source;
+}
+
+/**
+ * ephy_download_get_action:
+ * @download: an #EphyDownload
+ *
+ * Gets the #EphyDownloadActionType that this download will execute when
+ * ephy_download_do_download_action () is called on it. This action is
+ * performed automatically is "Automatically download and open files" is
+ * enabled.
+ *
+ * Returns: the #EphyDownloadActionType to be executed
+ **/
+EphyDownloadActionType
+ephy_download_get_action (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), EPHY_DOWNLOAD_ACTION_NONE);
+
+  return download->priv->action;
+}
+
+/**
+ * ephy_download_get_start_time:
+ * @download: an #EphyDownload
+ *
+ * Gets the time (returned by gtk_get_current_event_time ()) when @download was
+ * started with ephy_download_start (). Defaults to 0.
+ *
+ * Returns: the time when @download was started.
+ **/
+guint32
+ephy_download_get_start_time (EphyDownload *download)
+{
+  g_return_val_if_fail (EPHY_IS_DOWNLOAD (download), 0);
+
+  return download->priv->start_time;
+}
+
+/**
+ * ephy_download_start:
+ * @download: an #EphyDownload
+ *
+ * Starts the wrapped #WebKitDownload.
+ **/
+void
+ephy_download_start (EphyDownload *download)
+{
+  EphyDownloadPrivate *priv;
+
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  priv = download->priv;
+  priv->start_time = gtk_get_current_event_time ();
+
+  if (priv->destination == NULL)
+    ephy_download_set_auto_destination (download);
+
+  webkit_download_start (priv->download);
+}
+
+/**
+ * ephy_download_cancel:
+ * @download: an #EphyDownload
+ *
+ * Cancels the wrapped #WebKitDownload.
+ **/
+void
+ephy_download_cancel (EphyDownload *download)
+{
+  g_return_if_fail (EPHY_IS_DOWNLOAD (download));
+
+  webkit_download_cancel (download->priv->download);
+}
+
+/**
+ * ephy_download_do_download_action:
+ * @download: an #EphyDownload
+ * @action: one of #EphyDownloadActionType
+ *
+ * Executes the given @action for @download, this can be any of
+ * #EphyDownloadActionType, including #EPHY_DOWNLOAD_ACTION_AUTO which decides
+ * the default action from the mime type of @download.
+ *
+ * Returns: %TRUE if the action was executed succesfully.
+ *
+ **/
+gboolean
+ephy_download_do_download_action (EphyDownload *download,
+                                  EphyDownloadActionType action)
+{
+    GFile *destination;
+    const char *destination_uri;
+    EphyDownloadPrivate *priv;
+    gboolean ret = FALSE;
+
+    priv = download->priv;
+
+    destination_uri = webkit_download_get_destination_uri (priv->download);
+    destination = g_file_new_for_uri (destination_uri);
+
+    switch ((action ? action : priv->action)) {
+      case EPHY_DOWNLOAD_ACTION_AUTO:
+        LOG ("ephy_download_do_download_action: auto");
+        ret = ephy_download_do_download_action (download, decide_action_from_mime (download));
+        break;
+      case EPHY_DOWNLOAD_ACTION_BROWSE_TO:
+        LOG ("ephy_download_do_download_action: browse_to");
+        ret = ephy_file_browse_to (destination, priv->start_time);
+        break;
+      case EPHY_DOWNLOAD_ACTION_OPEN:
+        LOG ("ephy_download_do_download_action: open");
+        ret = ephy_file_launch_handler (NULL, destination, priv->start_time);
+        break;
+      case EPHY_DOWNLOAD_ACTION_NONE:
+        LOG ("ephy_download_do_download_action: none");
+        ret = TRUE;
+        break;
+      default:
+        LOG ("ephy_download_do_download_action: unhandled action");
+        ret = FALSE;
+        break;
+    }
+    g_object_unref (destination);
+
+    return ret;
+}
+
+static void
+ephy_download_dispose (GObject *object)
+{
+  EphyDownload *download = EPHY_DOWNLOAD (object);
+  EphyDownloadPrivate *priv;
+
+  LOG ("EphyDownload disposed %p", object);
+
+  priv = download->priv;
+
+  if (priv->download) {
+    g_object_unref (priv->download);
+    priv->download = NULL;
+  }
+
+  if (priv->window) {
+    g_object_unref (priv->window);
+    priv->window = NULL;
+  }
+
+  if (priv->widget) {
+    g_object_unref (priv->widget);
+    priv->widget = NULL;
+  }
+
+  ephy_embed_shell_remove_download (embed_shell, download);
+
+  G_OBJECT_CLASS (ephy_download_parent_class)->dispose (object);
+}
+
+static void
+ephy_download_finalize (GObject *object)
+{
+  EphyDownload *download = EPHY_DOWNLOAD (object);
+  EphyDownloadPrivate *priv;
+
+  priv = download->priv;
+
+  g_free (priv->destination);
+  g_free (priv->source);
+
+  LOG ("EphyDownload finalised %p", object);
+
+  G_OBJECT_CLASS (ephy_download_parent_class)->finalize (object);
+}
+
+static void
+ephy_download_class_init (EphyDownloadClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (EphyDownloadPrivate));
+
+  object_class->get_property = ephy_download_get_property;
+  object_class->set_property = ephy_download_set_property;
+  object_class->dispose = ephy_download_dispose;
+  object_class->finalize = ephy_download_finalize;
+
+  /**
+   * EphyDownload::download:
+   *
+   * Internal WebKitDownload.
+   */
+  g_object_class_install_property (object_class, PROP_DOWNLOAD,
+                                   g_param_spec_object ("download",
+                                                        "Internal WebKitDownload",
+                                                        "The WebKitDownload used internally by EphyDownload",
+                                                        WEBKIT_TYPE_DOWNLOAD,
+                                                        G_PARAM_READABLE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::destination:
+   *
+   * The destination URI where to store the download.
+   */
+  g_object_class_install_property (object_class, PROP_DESTINATION,
+                                   g_param_spec_string ("destination",
+                                                        "Destination",
+                                                        "Destination file URI",
+                                                        NULL,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+  /**
+   * EphyDownload::source:
+   *
+   * Download's origin URI
+   */
+  g_object_class_install_property (object_class, PROP_SOURCE,
+                                   g_param_spec_string ("source",
+                                                        "Source",
+                                                        "Source URI",
+                                                        NULL,
+                                                        G_PARAM_READABLE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::action:
+   *
+   * Action to take when the download finishes and "Automatically download and
+   * open files" is enabled, or when ephy_download_do_download_action () is
+   * called.
+   */
+  g_object_class_install_property (object_class, PROP_ACTION,
+                                   g_param_spec_enum ("action",
+                                                      "Download action",
+                                                      "Action to take when download finishes",
+                                                      EPHY_TYPE_DOWNLOAD_ACTION_TYPE,
+                                                      EPHY_DOWNLOAD_ACTION_NONE,
+                                                      G_PARAM_READABLE |
+                                                      G_PARAM_STATIC_NAME |
+                                                      G_PARAM_STATIC_NICK |
+                                                      G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::start-time:
+   *
+   * User time when the download started, useful for launching applications
+   * aware of focus stealing.
+   */
+  g_object_class_install_property (object_class, PROP_START_TIME,
+                                   g_param_spec_uint ("start-time",
+                                                      "Event start time",
+                                                      "Time for focus-stealing prevention.",
+                                                      0, G_MAXUINT32, 0,
+                                                      G_PARAM_READABLE |
+                                                      G_PARAM_STATIC_NAME |
+                                                      G_PARAM_STATIC_NICK |
+                                                      G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::window:
+   *
+   * Window that produced the download, the download will be shown in its
+   * parent window.
+   */
+  g_object_class_install_property (object_class, PROP_WINDOW,
+                                   g_param_spec_object ("window",
+                                                        "A GtkWindow",
+                                                        "Window that produced this download.",
+                                                        GTK_TYPE_WIDGET,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::widget:
+   *
+   * An EphyDownloadWidget -or any other GtkWidget- that is representing this
+   * EphyDownload to the user.
+   */
+  g_object_class_install_property (object_class, PROP_WIDGET,
+                                   g_param_spec_object ("widget",
+                                                        "A GtkWidget",
+                                                        "GtkWidget showing this download.",
+                                                        GTK_TYPE_WIDGET,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_BLURB));
+
+  /**
+   * EphyDownload::completed:
+   *
+   * The ::completed signal is emitted when @download has finished downloading.
+   **/
+  g_signal_new ("completed",
+                G_OBJECT_CLASS_TYPE (object_class),
+                G_SIGNAL_RUN_LAST,
+                G_STRUCT_OFFSET (EphyDownloadClass, completed),
+                NULL, NULL,
+                g_cclosure_marshal_VOID__VOID,
+                G_TYPE_NONE,
+                0);
+  /**
+   * EphyDownload::error:
+   *
+   * The ::error signal wraps the @download ::error signal.
+   **/
+  g_signal_new ("error",
+                G_OBJECT_CLASS_TYPE (object_class),
+                G_SIGNAL_RUN_LAST,
+                G_STRUCT_OFFSET (EphyDownloadClass, error),
+                NULL, NULL,
+                ephy_marshal_BOOLEAN__INT_INT_STRING,
+                G_TYPE_NONE,
+                0);
+}
+
+static void
+ephy_download_init (EphyDownload *download)
+{
+  download->priv = EPHY_DOWNLOAD_GET_PRIVATE (download);
+
+  LOG ("EphyDownload initialising %p", download);
+
+  download->priv->download = NULL;
+  download->priv->destination = NULL;
+
+  download->priv->action = EPHY_DOWNLOAD_ACTION_NONE;
+
+  download->priv->start_time = 0;
+
+  download->priv->window = NULL;
+  download->priv->widget = NULL;
+}
+
+static void
+download_status_changed_cb (GObject *object,
+                            GParamSpec *pspec,
+                            EphyDownload *download)
+{
+  WebKitDownloadStatus status;
+  EphyDownloadPrivate *priv;
+
+  priv = download->priv;
+
+  status = webkit_download_get_status (priv->download);
+
+  if (status == WEBKIT_DOWNLOAD_STATUS_FINISHED) {
+    g_signal_emit_by_name (download, "completed");
+
+    if (g_settings_get_boolean (EPHY_SETTINGS_MAIN, EPHY_PREFS_AUTO_DOWNLOADS)) {
+      ephy_download_do_download_action (download, EPHY_DOWNLOAD_ACTION_AUTO);
+    } else {
+      ephy_download_do_download_action (download, EPHY_DOWNLOAD_ACTION_NONE);
+    }
+
+    ephy_embed_shell_remove_download (embed_shell, download);
+  } else if (status == WEBKIT_DOWNLOAD_STATUS_CANCELLED ||
+             status == WEBKIT_DOWNLOAD_STATUS_ERROR) {
+  } else if (status == WEBKIT_DOWNLOAD_STATUS_STARTED) {
+    ephy_embed_shell_add_download (embed_shell, download);
+  }
+}
+
+static gboolean
+download_error_cb (WebKitDownload *download,
+                   gint error_code,
+                   gint error_detail,
+                   char *reason,
+                   gpointer user_data)
+{
+  EphyDownload *ephy_download;
+  gboolean ret = FALSE;
+
+  ephy_download = EPHY_DOWNLOAD (user_data);
+
+  LOG ("error (%d - %d)! %s", error_code, error_detail, reason);
+  g_signal_emit_by_name (ephy_download, "error",
+                         error_code, error_detail, reason, &ret);
+
+  return ret;
+}
+
+/**
+ * ephy_download_new:
+ *
+ * Creates a new #EphyDownload. You can use ephy_download_new_for_download and
+ * ephy_download_new_for_uri as convenience functions to create #EphyDownload
+ * objects.
+ *
+ * Returns: an #EphyDownload.
+ **/
+EphyDownload *
+ephy_download_new (void)
+{
+  return g_object_new (EPHY_TYPE_DOWNLOAD, NULL);
+}
+
+static EphyDownload *
+_ephy_download_new (WebKitDownload *webkit_download, const char *uri)
+{
+  EphyDownload *ephy_download;
+  ephy_download = ephy_download_new ();
+
+  if (webkit_download == NULL) {
+    WebKitNetworkRequest *request;
+
+    request = webkit_network_request_new (uri);
+    webkit_download = webkit_download_new (request);
+
+    g_return_val_if_fail (webkit_download != NULL, NULL);
+    g_object_unref (request);
+  }
+
+  g_signal_connect (webkit_download, "notify::status",
+                    G_CALLBACK (download_status_changed_cb),
+                    ephy_download);
+  g_signal_connect (webkit_download, "error",
+                    G_CALLBACK (download_error_cb),
+                    ephy_download);
+
+  ephy_download->priv->download = g_object_ref (webkit_download);
+  ephy_download->priv->source = g_strdup (webkit_download_get_uri (webkit_download));
+
+  return ephy_download;
+}
+
+/**
+ * ephy_download_new_for_download:
+ * @download: a #WebKitDownload to wrap
+ *
+ * Wraps @download in an #EphyDownload.
+ *
+ * Returns: an #EphyDownload.
+ **/
+EphyDownload *
+ephy_download_new_for_download (WebKitDownload *download)
+{
+  g_return_val_if_fail (WEBKIT_IS_DOWNLOAD (download), NULL);
+
+  return _ephy_download_new (download, NULL);
+}
+
+/**
+ * ephy_download_new_for_uri:
+ * @uri: a source URI from where to download
+ *
+ * Creates an #EphyDownload to download @uri.
+ *
+ * Returns: an #EphyDownload.
+ **/
+EphyDownload *
+ephy_download_new_for_uri (const char *uri)
+{
+  g_return_val_if_fail (uri != NULL, NULL);
+
+  return _ephy_download_new (NULL, uri);
+}
diff --git a/embed/ephy-download.h b/embed/ephy-download.h
new file mode 100644
index 0000000..8c84bbe
--- /dev/null
+++ b/embed/ephy-download.h
@@ -0,0 +1,115 @@
+/* vim: set sw=2 ts=2 sts=2 et: */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * ephy-download.h
+ * This file is part of Epiphany
+ *
+ * Copyright © 2011 - 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Epiphany 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 Epiphany; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#if !defined (__EPHY_EPIPHANY_H_INSIDE__) && !defined (EPIPHANY_COMPILATION)
+#error "Only <epiphany/epiphany.h> can be included directly."
+#endif
+
+#ifndef _EPHY_DOWNLOAD_H
+#define _EPHY_DOWNLOAD_H
+
+#include <glib-object.h>
+#include <webkit/webkit.h>
+
+#include "ephy-embed.h"
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_DOWNLOAD              ephy_download_get_type()
+#define EPHY_DOWNLOAD(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_DOWNLOAD, EphyDownload))
+#define EPHY_DOWNLOAD_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_DOWNLOAD, EphyDownloadClass))
+#define EPHY_IS_DOWNLOAD(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_DOWNLOAD))
+#define EPHY_IS_DOWNLOAD_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_TYPE_DOWNLOAD))
+#define EPHY_DOWNLOAD_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_TYPE_DOWNLOAD, EphyDownloadClass))
+
+typedef struct _EphyDownload EphyDownload;
+typedef struct _EphyDownloadClass EphyDownloadClass;
+typedef struct _EphyDownloadPrivate EphyDownloadPrivate;
+
+struct _EphyDownload
+{
+  GObject parent;
+
+  EphyDownloadPrivate *priv;
+};
+
+struct _EphyDownloadClass
+{
+  GObjectClass parent_class;
+
+  void (* completed)  (EphyDownload *download);
+  void (* error)      (EphyDownload *download,
+                       gint error_code,
+                       gint error_detail,
+                       char *reason);
+};
+
+typedef enum
+{
+  EPHY_DOWNLOAD_ACTION_NONE,
+  EPHY_DOWNLOAD_ACTION_AUTO,
+  EPHY_DOWNLOAD_ACTION_BROWSE_TO,
+  EPHY_DOWNLOAD_ACTION_OPEN
+} EphyDownloadActionType;
+
+GType         ephy_download_get_type              (void) G_GNUC_CONST;
+
+EphyDownload *ephy_download_new                   (void);
+EphyDownload *ephy_download_new_for_uri           (const char *uri);
+EphyDownload *ephy_download_new_for_download      (WebKitDownload *download);
+
+
+void          ephy_download_start                 (EphyDownload *download);
+void          ephy_download_pause                 (EphyDownload *download);
+void          ephy_download_cancel                (EphyDownload *download);
+
+void          ephy_download_set_auto_destination  (EphyDownload *download);
+void          ephy_download_set_destination_uri   (EphyDownload *download,
+                                                   const char *destination);
+
+WebKitDownload *ephy_download_get_webkit_download (EphyDownload *download);
+
+const char   *ephy_download_get_destination_uri   (EphyDownload *download);
+const char   *ephy_download_get_source_uri        (EphyDownload *download);
+
+
+guint32       ephy_download_get_start_time        (EphyDownload *download);
+
+GtkWidget    *ephy_download_get_window            (EphyDownload *download);
+void          ephy_download_set_window            (EphyDownload *download,
+                                                   GtkWidget *window);
+
+EphyDownloadActionType ephy_download_get_action   (EphyDownload *download);
+void          ephy_download_set_action            (EphyDownload *download,
+                                                   EphyDownloadActionType action);
+gboolean      ephy_download_do_download_action    (EphyDownload *download,
+                                                   EphyDownloadActionType action);
+
+GtkWidget    *ephy_download_get_widget            (EphyDownload *download);
+void          ephy_download_set_widget            (EphyDownload *download,
+                                                   GtkWidget *widget);
+
+G_END_DECLS
+
+#endif /* _EPHY_DOWNLOAD_H */
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index 3fcf7ee..a0d77cd 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -25,9 +25,9 @@
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
 
-#include "downloader-view.h"
 #include "ephy-adblock-manager.h"
 #include "ephy-debug.h"
+#include "ephy-download.h"
 #include "ephy-embed-shell.h"
 #include "ephy-embed-single.h"
 #include "ephy-encodings.h"
@@ -50,7 +50,7 @@
 struct _EphyEmbedShellPrivate
 {
 	EphyHistory *global_history;
-	DownloaderView *downloader_view;
+	GList *downloads;
 	EphyFaviconCache *favicon_cache;
 	EphyEmbedSingle *embed_single;
 	EphyEncodings *encodings;
@@ -63,6 +63,8 @@ struct _EphyEmbedShellPrivate
 
 enum
 {
+	DOWNLOAD_ADDED,
+	DOWNLOAD_REMOVED,
 	PREPARE_CLOSE,
 	QUIT,
 	LAST_SIGNAL
@@ -83,17 +85,6 @@ ephy_embed_shell_dispose (GObject *object)
 	EphyEmbedShell *shell = EPHY_EMBED_SHELL (object);
 	EphyEmbedShellPrivate *priv = shell->priv;
 
-	if (priv->downloader_view != NULL)
-	{
-		DownloaderView **downloader_view = &priv->downloader_view;
-		LOG ("Unref downloader");
-		g_object_remove_weak_pointer
-			(G_OBJECT (priv->downloader_view),
-			 (gpointer *) downloader_view);
-		g_object_unref (priv->downloader_view);
-		priv->downloader_view = NULL;
-	}
-
 	if (priv->favicon_cache != NULL)
 	{
 		LOG ("Unref favicon cache");
@@ -128,6 +119,14 @@ ephy_embed_shell_finalize (GObject *object)
 {
 	EphyEmbedShell *shell = EPHY_EMBED_SHELL (object);
 
+	if (shell->priv->downloads != NULL)
+	{
+		LOG ("Destroying downloads list");
+		g_list_foreach (shell->priv->downloads, (GFunc) g_object_unref, NULL);
+		g_list_free (shell->priv->downloads);
+		shell->priv->downloads = NULL;
+	}
+
 	if (shell->priv->global_history)
 	{
 		LOG ("Unref history");
@@ -190,44 +189,6 @@ ephy_embed_shell_get_global_history (EphyEmbedShell *shell)
 	return G_OBJECT (shell->priv->global_history);
 }
 
-/**
- * ephy_embed_shell_get_downloader_view:
- * @shell: the #EphyEmbedShell
- *
- * Return value: (transfer none):
- **/
-GObject *
-ephy_embed_shell_get_downloader_view (EphyEmbedShell *shell)
-{
-	g_return_val_if_fail (EPHY_IS_EMBED_SHELL (shell), NULL);
-
-	if (shell->priv->downloader_view == NULL)
-	{
-		DownloaderView **downloader_view;
-		shell->priv->downloader_view = downloader_view_new ();
-		downloader_view = &shell->priv->downloader_view;
-		g_object_add_weak_pointer
-			(G_OBJECT(shell->priv->downloader_view),
-			 (gpointer *) downloader_view);
-	}
-
-	return G_OBJECT (shell->priv->downloader_view);
-}
-
-/**
- * ephy_embed_shell_get_downloader_view_nocreate:
- * @shell: the #EphyEmbedShell
- *
- * Return value: (transfer none):
- **/
-GObject *
-ephy_embed_shell_get_downloader_view_nocreate (EphyEmbedShell *shell)
-{
-	g_return_val_if_fail (EPHY_IS_EMBED_SHELL (shell), NULL);
-
-	return (GObject *) shell->priv->downloader_view;
-}
-
 static GObject *
 impl_get_embed_single (EphyEmbedShell *shell)
 {
@@ -319,6 +280,8 @@ ephy_embed_shell_init (EphyEmbedShell *shell)
 	/* globally accessible singleton */
 	g_assert (embed_shell == NULL);
 	embed_shell = shell;
+
+	shell->priv->downloads = NULL;
 }
 
 static void
@@ -332,6 +295,40 @@ ephy_embed_shell_class_init (EphyEmbedShellClass *klass)
 	klass->get_embed_single = impl_get_embed_single;
 
 /**
+ * EphyEmbed::download-added:
+ * @shell: the #EphyEmbedShell
+ * @download: the #EphyDownload added
+ *
+ * Emitted when a #EphyDownload has been added to the global watch list of
+ * @shell, via ephy_embed_shell_add_download.
+ **/
+	signals[DOWNLOAD_ADDED] =
+		g_signal_new ("download-added",
+			      EPHY_TYPE_EMBED_SHELL,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EphyEmbedShellClass, download_added),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE, 1, EPHY_TYPE_DOWNLOAD);
+
+/**
+ * EphyEmbed::download-removed:
+ * @shell: the #EphyEmbedShell
+ * @download: the #EphyDownload being removed
+ *
+ * Emitted when a #EphyDownload has been removed from the global watch list of
+ * @shell, via ephy_embed_shell_remove_download.
+ **/
+	signals[DOWNLOAD_REMOVED] =
+		g_signal_new ("download-removed",
+			      EPHY_TYPE_EMBED_SHELL,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EphyEmbedShellClass, download_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE, 1, EPHY_TYPE_DOWNLOAD);
+
+/**
  * EphyEmbed::prepare-close:
  * @shell: the #EphyEmbedShell
  * 
@@ -563,6 +560,51 @@ ephy_embed_shell_get_print_settings (EphyEmbedShell *shell)
 	return priv->print_settings;
 }
 
+/**
+ * ephy_embed_shell_get_downloads:
+ * @shell: the #EphyEmbedShell
+ *
+ * Gets the global #GList object listing active downloads.
+ *
+ * Returns: (transfer none): a #GList object
+ **/
+GList *
+ephy_embed_shell_get_downloads (EphyEmbedShell *shell)
+{
+	EphyEmbedShellPrivate *priv;
+
+	g_return_val_if_fail (EPHY_IS_EMBED_SHELL (shell), NULL);
+	priv = shell->priv;
+
+	return priv->downloads;
+}
+
+void
+ephy_embed_shell_add_download (EphyEmbedShell *shell, EphyDownload *download)
+{
+	EphyEmbedShellPrivate *priv;
+
+	g_return_if_fail (EPHY_IS_EMBED_SHELL (shell));
+
+	priv = shell->priv;
+	priv->downloads = g_list_prepend (priv->downloads, download);
+
+	g_signal_emit_by_name (shell, "download-added", download, NULL);
+}
+
+void
+ephy_embed_shell_remove_download (EphyEmbedShell *shell, EphyDownload *download)
+{
+	EphyEmbedShellPrivate *priv;
+
+	g_return_if_fail (EPHY_IS_EMBED_SHELL (shell));
+
+	priv = shell->priv;
+	priv->downloads = g_list_remove (priv->downloads, download);
+
+	g_signal_emit_by_name (shell, "download-removed", download, NULL);
+}
+
 
 static void
 object_notify_cb (EphyEmbedShell *shell, GObject *object)
diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h
index c58df97..00087fa 100644
--- a/embed/ephy-embed-shell.h
+++ b/embed/ephy-embed-shell.h
@@ -28,6 +28,8 @@
 #include <glib-object.h>
 #include <gtk/gtk.h>
 
+#include "ephy-download.h"
+
 G_BEGIN_DECLS
 
 #define EPHY_TYPE_EMBED_SHELL		(ephy_embed_shell_get_type ())
@@ -55,6 +57,9 @@ struct _EphyEmbedShellClass
 {
 	GObjectClass parent_class;
 
+	void	  (* download_added)	(EphyEmbedShell *shell, EphyDownload *download);
+	void	  (* download_removed)	(EphyEmbedShell *shell, EphyDownload *download);
+
 	void	  (* prepare_close)	(EphyEmbedShell *shell);
 
 	/*< private >*/
@@ -69,10 +74,6 @@ GObject		  *ephy_embed_shell_get_favicon_cache	(EphyEmbedShell *shell);
 
 GObject		  *ephy_embed_shell_get_global_history	(EphyEmbedShell *shell);
 
-GObject		  *ephy_embed_shell_get_downloader_view	(EphyEmbedShell *shell);
-
-GObject		  *ephy_embed_shell_get_downloader_view_nocreate	(EphyEmbedShell *shell);
-
 GObject		  *ephy_embed_shell_get_encodings	(EphyEmbedShell *shell);
 
 GObject		  *ephy_embed_shell_get_embed_single	(EphyEmbedShell *shell);
@@ -91,6 +92,13 @@ void		   ephy_embed_shell_set_print_settings	(EphyEmbedShell *shell,
 		
 GtkPrintSettings  *ephy_embed_shell_get_print_settings	(EphyEmbedShell *shell);
 
+GList		  *ephy_embed_shell_get_downloads	(EphyEmbedShell *shell);
+
+void		   ephy_embed_shell_add_download	(EphyEmbedShell *shell,
+							 EphyDownload *download);
+void		   ephy_embed_shell_remove_download	(EphyEmbedShell *shell,
+							 EphyDownload *download);
+
 /* Private API */
 void	       _ephy_embed_shell_track_object		(EphyEmbedShell *shell,
 							 GObject        *object);
diff --git a/embed/ephy-embed.c b/embed/ephy-embed.c
index ebd34d1..6f008f5 100644
--- a/embed/ephy-embed.c
+++ b/embed/ephy-embed.c
@@ -25,14 +25,13 @@
 
 #include "config.h"
 
-#include "downloader-view.h"
 #include "ephy-adblock-manager.h"
 #include "ephy-debug.h"
+#include "ephy-download.h"
 #include "ephy-embed.h"
 #include "ephy-embed-event.h"
 #include "ephy-embed-shell.h"
 #include "ephy-embed-single.h"
-#include "ephy-embed-persist.h"
 #include "ephy-embed-prefs.h"
 #include "ephy-embed-utils.h"
 #include "ephy-file-chooser.h"
@@ -359,458 +358,14 @@ ephy_embed_inspect_close_cb (WebKitWebInspector *inspector,
   return TRUE;
 }
 
-static void
-download_requested_dialog_response_cb (GtkDialog *dialog,
-                                       int response_id,
-                                       WebKitDownload *download)
-{
-  if (response_id == GTK_RESPONSE_ACCEPT) {
-    DownloaderView *dview;
-    char *uri;
-
-    uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
-    g_object_set_data (G_OBJECT (download), "user-destination-uri", uri);
-
-    dview = EPHY_DOWNLOADER_VIEW (ephy_embed_shell_get_downloader_view (embed_shell));
-    downloader_view_add_download (dview, download);
-  } else {
-    webkit_download_cancel (download);
-    ephy_file_delete_uri (webkit_download_get_destination_uri (download));
-  }
-
-  gtk_widget_destroy (GTK_WIDGET (dialog));
-  /* User provided us with a destination or cancelled, unfreeze. */
-  g_object_thaw_notify (G_OBJECT (download));
-  g_object_unref (download);
-}
-
-static void
-request_destination_uri (WebKitWebView *web_view,
-                         WebKitDownload *download)
-{
-  EphyFileChooser *dialog;
-  GtkWidget *window;
-  const char *suggested_filename;
-
-  suggested_filename = webkit_download_get_suggested_filename (download);
-
-  /*
-   * Try to get the toplevel window related to the WebView that caused
-   * the download, and use NULL otherwise; we don't want to pass the
-   * WebView or other widget as a parent window.
-   */
-  window = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
-  if (!gtk_widget_is_toplevel (window))
-    window = NULL;
-
-  dialog = ephy_file_chooser_new (_("Save"),
-                                  window,
-                                  GTK_FILE_CHOOSER_ACTION_SAVE,
-                                  EPHY_PREFS_STATE_SAVE_DIR,
-                                  EPHY_FILE_FILTER_ALL_SUPPORTED);
-  gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
-  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), suggested_filename);
-
-  g_signal_connect (dialog, "response",
-                    G_CALLBACK (download_requested_dialog_response_cb), download);
-
-  gtk_widget_show_all (GTK_WIDGET (dialog));
-}
-
-/* From the old embed/mozilla/MozDownload.cpp */
-static const char*
-file_is_compressed (const char *filename)
-{
-  int i;
-  static const char * const compression[] = {".gz", ".bz2", ".Z", ".lz", NULL};
-
-  for (i = 0; compression[i] != NULL; i++) {
-    if (g_str_has_suffix (filename, compression[i]))
-      return compression[i];
-  }
-
-  return NULL;
-}
-
-static const char*
-parse_extension (const char *filename)
-{
-  const char *compression;
-  const char *last_separator;
-
-  compression = file_is_compressed (filename);
-
-  /* if the file is compressed we might have a double extension */
-  if (compression != NULL) {
-    int i;
-    static const char * const extensions[] = {"tar", "ps", "xcf", "dvi", "txt", "text", NULL};
-
-    for (i = 0; extensions[i] != NULL; i++) {
-      char *suffix;
-      suffix = g_strdup_printf (".%s%s", extensions[i], compression);
-
-      if (g_str_has_suffix (filename, suffix)) {
-        char *p;
-
-        p = g_strrstr (filename, suffix);
-        g_free (suffix);
-
-        return p;
-      }
-
-      g_free (suffix);
-    }
-  }
-
-  /* no compression, just look for the last dot in the filename */
-  last_separator = strrchr (filename, G_DIR_SEPARATOR);
-  return strrchr ((last_separator) ? last_separator : filename, '.');
-}
-
-static gboolean
-define_destination_uri (WebKitDownload *download,
-                        gboolean temporary)
-{
-  char *tmp_dir;
-  char *destination_filename;
-  char *destination_uri;
-  const char *suggested_filename;
-
-  suggested_filename = webkit_download_get_suggested_filename (download);
-
-  /* If we are not doing an automatic download, use a temporary file
-   * to start the download while we ask the user for the location to
-   * where the file must go.
-   */
-  if (temporary)
-    tmp_dir = g_build_filename (ephy_dot_dir (), "downloads", NULL);
-  else
-    tmp_dir = ephy_file_get_downloads_dir ();
-
-  /* Make sure the download directory exists */
-  if (g_mkdir_with_parents (tmp_dir, 0700) == -1) {
-    g_critical ("Could not create downloads directory \"%s\": %s",
-                tmp_dir, strerror (errno));
-    g_free (tmp_dir);
-    return FALSE;
-  }
-
-  destination_filename = g_build_filename (tmp_dir, suggested_filename, NULL);
-
-  if (g_file_test (destination_filename, G_FILE_TEST_EXISTS)) {
-    int i = 1;
-    const char *dot_pos;
-    gssize position;
-    char *serial = NULL;
-    GString *tmp_filename;
-
-    dot_pos = parse_extension (destination_filename);
-    if (dot_pos)
-      position = dot_pos - destination_filename;
-    else
-      position = strlen (destination_filename);
-
-    tmp_filename = g_string_new (NULL);
-
-    do {
-      serial = g_strdup_printf ("(%d)", i++);
-
-      g_string_assign (tmp_filename, destination_filename);
-      g_string_insert (tmp_filename, position, serial);
-
-      g_free (serial);
-    } while (g_file_test (tmp_filename->str, G_FILE_TEST_EXISTS));
-
-    destination_filename = g_strdup (tmp_filename->str);
-    g_string_free (tmp_filename, TRUE);
-  }
-
-  destination_uri = g_strconcat ("file://", destination_filename, NULL);
-
-  LOG ("define_destination_uri: Downloading to %s", destination_filename);
-
-  webkit_download_set_destination_uri (download, destination_uri);
-
-  g_free (tmp_dir);
-  g_free (destination_filename);
-  g_free (destination_uri);
-
-  return TRUE;
-}
-
-static gboolean
-perform_auto_download (WebKitDownload *download)
-{
-  DownloaderView *dview;
-
-  if (!define_destination_uri (download, FALSE)) {
-    webkit_download_cancel (download);
-    ephy_file_delete_uri (webkit_download_get_destination_uri (download));
-    return FALSE;
-  }
-
-  dview = EPHY_DOWNLOADER_VIEW (ephy_embed_shell_get_downloader_view (embed_shell));
-
-  g_object_set_data (G_OBJECT(download), "download-action", GINT_TO_POINTER(DOWNLOAD_ACTION_OPEN));
-  downloader_view_add_download (dview, download);
-
-  return TRUE;
-}
-
 void
 ephy_embed_auto_download_url (EphyEmbed *embed, const char *url)
 {
-  WebKitNetworkRequest *request;
-  WebKitDownload *download;
-
-  request = webkit_network_request_new (url);
-  download = webkit_download_new (request);
-  g_object_unref (request);
-
-  if (perform_auto_download (download))
-    webkit_download_start (download);
-}
-
-static void
-confirm_action_response_cb (GtkWidget *dialog,
-                            int response,
-                            WebKitDownload *download)
-{
-  WebKitWebView *web_view = g_object_get_data (G_OBJECT(dialog), "webkit-view");
-  DownloaderView *dview;
-
-  gtk_widget_destroy (dialog);
-
-  if (response > 0) {
-    switch (response) {
-    case DOWNLOAD_ACTION_OPEN:
-      g_object_set_data (G_OBJECT (download), "download-action",
-                         GINT_TO_POINTER (DOWNLOAD_ACTION_OPEN));
-      break;
-    case DOWNLOAD_ACTION_DOWNLOAD:
-    case DOWNLOAD_ACTION_OPEN_LOCATION:
-      g_object_set_data (G_OBJECT (download), "download-action",
-                         GINT_TO_POINTER (DOWNLOAD_ACTION_OPEN_LOCATION));
-      break;
-    }
-
-    if (response == DOWNLOAD_ACTION_DOWNLOAD) {
-      /* balanced in download_requested_dialog_response_cb */
-      g_object_ref (download);
-      request_destination_uri (web_view, download);
-    } else {
-      if (!define_destination_uri (download, FALSE)) {
-        goto cleanup;
-      }
-      dview = EPHY_DOWNLOADER_VIEW (ephy_embed_shell_get_downloader_view (embed_shell));
-      downloader_view_add_download (dview, download);
-      /* User selected "Open", he won't be providing a destination, unfreeze. */
-      g_object_thaw_notify (G_OBJECT (download));
-    }
-    g_object_unref (download);
-    return;
-  }
+  EphyDownload *download;
 
-cleanup:
-  webkit_download_cancel (download);
-  ephy_file_delete_uri (webkit_download_get_destination_uri (download));
-  g_object_unref (download);
-}
-
-static void
-confirm_action_from_mime (WebKitWebView *web_view,
-                          WebKitDownload *download,
-                          DownloadAction action)
-{
-  GtkWidget *parent_window;
-  GtkWidget *dialog;
-  const char *action_label;
-  char *mime_description;
-  EphyMimePermission mime_permission;
-  GAppInfo *helper_app;
-  const char *suggested_filename;
-  int default_response;
-  WebKitNetworkResponse *response;
-  SoupMessage *message;
-  GtkMessageType mtype;
-  char *title;
-  char *secondary;
-
-  parent_window = gtk_widget_get_toplevel (GTK_WIDGET(web_view));
-  if (!gtk_widget_is_toplevel (parent_window))
-    parent_window = NULL;
-
-  helper_app = NULL;
-  mime_description = NULL;
-  mime_permission = EPHY_MIME_PERMISSION_SAFE;
-
-  response = webkit_download_get_network_response (download);
-  message = webkit_network_response_get_message (response);
-
-  if (message) {
-    const char *content_type = soup_message_headers_get_content_type (message->response_headers, NULL);
-
-    if (content_type) {
-      mime_description = g_content_type_get_description (content_type);
-      helper_app = g_app_info_get_default_for_type (content_type, FALSE);
-      mime_permission = ephy_file_check_mime (content_type);
-
-      if (helper_app)
-        action = DOWNLOAD_ACTION_OPEN;
-    }
-  }
-
-  if (mime_description == NULL) {
-    mime_description = g_strdup (C_("file type", "Unknown"));
-    action = DOWNLOAD_ACTION_OPEN_LOCATION;
-  }
-
-  /* Sometimes downloads can have a mime_description but a NULL helper_app
-   * in that case action is never changed so DOWNLOAD_ACTION_DOWNLOAD remains
-   * as action value. This is the same response value as Save as...
-   * button, which is wrong for the Download button.
-   */
-  if (helper_app == NULL)
-    action = DOWNLOAD_ACTION_OPEN_LOCATION;
-
-  action_label = (action == DOWNLOAD_ACTION_OPEN) ? GTK_STOCK_OPEN : STOCK_DOWNLOAD;
-  suggested_filename = webkit_download_get_suggested_filename (download);
-
-  if (mime_permission != EPHY_MIME_PERMISSION_SAFE && helper_app) {
-    title = _("Download this potentially unsafe file?");
-    mtype = GTK_MESSAGE_WARNING;
-    /* translators: First %s is the file type description, second %s is the
-     * file name */
-    secondary = g_strdup_printf (_("File Type: â??%sâ??.\n\nIt is unsafe to open "
-                                   "â??%sâ?? as it could potentially damage your "
-                                   "documents or invade your privacy. "
-                                   "You can download it instead."),
-                                 mime_description, suggested_filename);
-
-    action_label = STOCK_DOWNLOAD;
-  } else if (action == DOWNLOAD_ACTION_OPEN && helper_app) {
-    title = _("Open this file?");
-    mtype = GTK_MESSAGE_QUESTION;
-    /* translators: First %s is the file type description, second %s is the
-     * file name, third %s is the application used to open the file */
-    secondary = g_strdup_printf (_("File Type: â??%sâ??.\n\nYou can open â??%sâ?? "
-                                   "using â??%sâ?? or save it."),
-                                 mime_description, suggested_filename,
-                                 g_app_info_get_name (helper_app));
-  } else  {
-    title = _("Download this file?");
-    mtype = GTK_MESSAGE_QUESTION;
-    /* translators: First %s is the file type description, second %s is the
-     * file name */
-    secondary = g_strdup_printf (_("File Type: â??%sâ??.\n\nYou have no "
-                                   "application able to open â??%sâ??. "
-                                   "You can download it instead."),
-                                 mime_description, suggested_filename);
-  }
-
-  dialog = gtk_message_dialog_new (GTK_WINDOW (parent_window),
-                                   GTK_DIALOG_DESTROY_WITH_PARENT,
-                                   mtype, GTK_BUTTONS_NONE,
-                                   title);
-  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
-                                            secondary, NULL);
-
-  g_free (mime_description);
-
-  gtk_dialog_add_button (GTK_DIALOG (dialog),
-                         GTK_STOCK_SAVE_AS, DOWNLOAD_ACTION_DOWNLOAD);
-  gtk_dialog_add_button (GTK_DIALOG (dialog),
-                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
-  gtk_dialog_add_button (GTK_DIALOG (dialog),
-                         action_label, action);
-
-  gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
-
-  default_response = (action == DOWNLOAD_ACTION_NONE) ?
-                     (int) GTK_RESPONSE_CANCEL : (int) action;
-
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), default_response);
-
-  g_object_set_data (G_OBJECT (dialog), "webkit-view", web_view);
-  g_signal_connect (dialog, "response",
-                    G_CALLBACK (confirm_action_response_cb),
-                    download);
-
-  gtk_window_present (GTK_WINDOW (dialog));
-}
-
-static void
-download_status_changed_cb (GObject *object,
-                            GParamSpec *pspec,
-                            EphyEmbed *embed)
-{
-  WebKitDownload *download = WEBKIT_DOWNLOAD (object);
-
-  if (webkit_download_get_status (download) == WEBKIT_DOWNLOAD_STATUS_FINISHED)
-  {
-    GFile *destination;
-    GFile *temp;
-    char *destination_uri;
-    const char *temp_uri;
-
-    temp_uri = webkit_download_get_destination_uri (download);
-    destination_uri = g_object_get_data (G_OBJECT (download),
-                                         "user-destination-uri");
-
-    LOG ("download_status_changed_cb: finished, moving temp file %s to %s",
-         temp_uri, destination_uri);
-
-    /* No user-destination-uri is set, hence this is an auto download and we
-     * have nothing else to do. */
-    if (destination_uri == NULL) return;
-
-    temp = g_file_new_for_uri (temp_uri);
-    destination = g_file_new_for_uri (destination_uri);
-
-    ephy_file_switch_temp_file (destination, temp);
-
-    g_object_unref (destination);
-    g_object_unref (temp);
-  }
-  else if (webkit_download_get_status (download) == WEBKIT_DOWNLOAD_STATUS_STARTED)
-  {
-    /* Prevent this callback from being called before the user has selected a
-     * destination. It is freed either here or in
-     * download_requested_dialog_response_cb(). Both situations are mutually
-     * exclusive.
-     *
-     * This freeze is removed either here below, in
-     * download_requested_dialog_response_cb() or confirm_action_response_cb().
-     */
-    g_object_freeze_notify (G_OBJECT (download));
-
-    if (g_settings_get_boolean (EPHY_SETTINGS_MAIN,
-                                EPHY_PREFS_AUTO_DOWNLOADS)) {
-      perform_auto_download (download);
-      /* User won't select a destination, unfreeze. */
-      g_object_thaw_notify (G_OBJECT (download));
-      return;
-    }
-
-    /* Balanced in confirm_action_response_cb. */
-    g_object_ref (download);
-
-    confirm_action_from_mime (EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed),
-                              download, DOWNLOAD_ACTION_DOWNLOAD);
-  }
-}
-
-static gboolean
-download_error_cb (WebKitDownload *download,
-                   gint error_code,
-                   gint error_detail,
-                   const gchar *reason,
-                   EphyEmbed *embed)
-{
-  /* FIXME: handle download errors and notify the user. */
-  LOG ("download_error_cb: Error (%d:%d): %s", error_code, error_detail, reason);
-
-  return FALSE;
+  download = ephy_download_new_for_uri (url);
+  ephy_download_set_auto_destination (download);
+  ephy_download_set_action (download, EPHY_DOWNLOAD_ACTION_OPEN);
 }
 
 static gboolean
@@ -818,26 +373,19 @@ download_requested_cb (WebKitWebView *web_view,
                        WebKitDownload *download,
                        EphyEmbed *embed)
 {
+  EphyDownload *ed;
+  GtkWidget *window;
+
   /* Is download locked down? */
   if (g_settings_get_boolean (EPHY_SETTINGS_LOCKDOWN,
                               EPHY_PREFS_LOCKDOWN_SAVE_TO_DISK))
     return FALSE;
 
-  /* Wait for the request to be sent in all cases, so that we have a
-   * response which may contain a suggested filename */
-  g_signal_connect (download, "notify::status",
-                    G_CALLBACK (download_status_changed_cb),
-                    embed);
-  g_signal_connect (download, "error",
-                    G_CALLBACK (download_error_cb),
-                    embed);
+  window = gtk_widget_get_toplevel (GTK_WIDGET (embed));
 
-  /* If we are not performing an auto-download, we will ask the user
-   * where they want the file to go to; we will start downloading to a
-   * temporary location while the user decides.
-   */
-  if (!define_destination_uri (download, TRUE))
-    return FALSE;
+  ed = ephy_download_new_for_download (download);
+  ephy_download_set_window (ed, window);
+  ephy_download_set_auto_destination (ed);
 
   return TRUE;
 }
diff --git a/lib/ephy-marshal.list b/lib/ephy-marshal.list
index c3f1865..babe824 100644
--- a/lib/ephy-marshal.list
+++ b/lib/ephy-marshal.list
@@ -1,5 +1,6 @@
 BOOLEAN:BOXED
 BOOLEAN:ENUM,STRING,STRING,STRING
+BOOLEAN:INT,INT,STRING
 BOOLEAN:OBJECT
 BOOLEAN:STRING
 BOOLEAN:STRING,BOOLEAN,BOOLEAN
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4e297e6..300c809 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -10,9 +10,8 @@ data/org.gnome.epiphany.gschema.xml.in
 [type: gettext/glade] data/glade/form-signing-dialog.ui
 [type: gettext/glade] data/glade/prefs-dialog.ui
 [type: gettext/glade] data/glade/print.ui
-embed/downloader-view.c
+embed/ephy-download.c
 embed/ephy-embed.c
-embed/ephy-embed-persist.c
 embed/ephy-embed-shell.c
 embed/ephy-embed-single.c
 embed/ephy-embed-utils.c
diff --git a/src/Makefile.am b/src/Makefile.am
index ad6bf9e..dd9a0e1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -264,10 +264,10 @@ MAINTAINERCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
 
 if HAVE_INTROSPECTION
 EPHY_GIR_H_FILES = \
+	$(top_srcdir)/embed/ephy-download.h \
 	$(top_srcdir)/embed/ephy-embed.h \
 	$(top_srcdir)/embed/ephy-embed-container.h \
 	$(top_srcdir)/embed/ephy-embed-event.h \
-	$(top_srcdir)/embed/ephy-embed-persist.h \
 	$(top_srcdir)/embed/ephy-embed-shell.h \
 	$(top_srcdir)/embed/ephy-embed-single.h \
 	$(top_srcdir)/embed/ephy-favicon-cache.h \
@@ -294,10 +294,10 @@ EPHY_GIR_H_FILES = \
 	$(NULL)
 
 EPHY_GIR_C_FILES = \
+	$(top_srcdir)/embed/ephy-download.c \
 	$(top_srcdir)/embed/ephy-embed.c \
 	$(top_srcdir)/embed/ephy-embed-container.c \
 	$(top_srcdir)/embed/ephy-embed-event.c \
-	$(top_srcdir)/embed/ephy-embed-persist.c \
 	$(top_srcdir)/embed/ephy-embed-shell.c \
 	$(top_srcdir)/embed/ephy-embed-single.c \
 	$(top_srcdir)/embed/ephy-favicon-cache.c \
diff --git a/src/ephy-session.c b/src/ephy-session.c
index cee9e49..65ca3d2 100644
--- a/src/ephy-session.c
+++ b/src/ephy-session.c
@@ -167,7 +167,6 @@ confirm_shutdown_dialog_weak_ref_cb (InteractData *data,
 	EphySessionPrivate *priv = data->session->priv;
 	EggSMClient *sm_client = data->sm_client;
 	EphyShell *shell;
-	GObject *dv;
 	gboolean will_quit;
 
 	LOG ("confirm_shutdown_dialog_weak_ref_cb response %d", data->response);
@@ -180,14 +179,6 @@ confirm_shutdown_dialog_weak_ref_cb (InteractData *data,
 		g_object_weak_unref (G_OBJECT (shell),
 				     (GWeakNotify) confirm_shutdown_dialog_accept_cb,
 				     data);
-
-		dv = ephy_embed_shell_get_downloader_view_nocreate (ephy_embed_shell_get_default ());
-		if (dv != NULL)
-		{
-			g_object_weak_unref (dv,
-					     (GWeakNotify) confirm_shutdown_dialog_accept_cb,
-					     data);
-		}
 	}
 
 	if (data->timeout_id != 0)
@@ -208,15 +199,16 @@ client_quit_requested_cb (EggSMClient *sm_client,
 			  EphySession *session)
 {
 	EphySessionPrivate *priv = session->priv;
-	GObject *dv;
 	GtkWidget *dialog, *box;
 	InteractData *data;
+	GList *downloads;
 
 	/* If we're shutting down, check if there are downloads
 	 * remaining, since they can't be restarted.
 	 */
-	if (ephy_shell_get_default () == NULL ||
-	    (dv = ephy_embed_shell_get_downloader_view_nocreate (ephy_embed_shell_get_default ())) == NULL)
+
+	downloads = ephy_embed_shell_get_downloads (embed_shell);
+	if (ephy_shell_get_default () == NULL || g_list_length (downloads) == 0)
 	{
 		egg_sm_client_will_quit (sm_client, TRUE);
 		return;
@@ -271,11 +263,6 @@ client_quit_requested_cb (EggSMClient *sm_client,
 			   (GWeakNotify) confirm_shutdown_dialog_accept_cb,
 			   data);
 
-	/* When the download finishes, un-veto the shutdown */
-	g_object_weak_ref (dv,
-			   (GWeakNotify) confirm_shutdown_dialog_accept_cb,
-			   data);
-
 	g_signal_connect (dialog, "response",
 			  G_CALLBACK (confirm_shutdown_dialog_response_cb), data);
 	g_object_weak_ref (G_OBJECT (dialog),
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index f15ceda..6fddf9d 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -48,7 +48,6 @@
 #include "ephy-extensions-manager.h"
 #include "ephy-session.h"
 #include "ephy-lockdown.h"
-#include "downloader-view.h"
 #include "egg-toolbars-model.h"
 #include "ephy-toolbars-model.h"
 #include "ephy-toolbar.h"
diff --git a/src/ephy-window.c b/src/ephy-window.c
index 98eb1c4..b251fb0 100644
--- a/src/ephy-window.c
+++ b/src/ephy-window.c
@@ -52,7 +52,6 @@
 #include "ephy-fullscreen-popup.h"
 #include "ephy-action-helper.h"
 #include "ephy-find-toolbar.h"
-#include "ephy-embed-persist.h"
 #include "ephy-location-entry.h"
 #include "ephy-web-view.h"
 
diff --git a/src/epiphany.h.in b/src/epiphany.h.in
index a722c55..8664c15 100644
--- a/src/epiphany.h.in
+++ b/src/epiphany.h.in
@@ -38,6 +38,7 @@
 #include <epiphany/ephy-bookmarks.h>
 #include <epiphany/ephy-bookmarks-type-builtins.h>
 #include <epiphany/ephy-dialog.h>
+#include <epiphany/ephy-download.h>
 #include <epiphany/ephy-embed-container.h>
 #include <epiphany/ephy-embed-event.h>
 #include <epiphany/ephy-embed.h>
diff --git a/src/popup-commands.c b/src/popup-commands.c
index 1bbce9d..0bec4fb 100644
--- a/src/popup-commands.c
+++ b/src/popup-commands.c
@@ -21,12 +21,13 @@
 #include "config.h"
 
 #include "popup-commands.h"
+#include "ephy-download.h"
 #include "ephy-shell.h"
 #include "ephy-embed-container.h"
-#include "ephy-embed-persist.h"
 #include "ephy-embed-utils.h"
 #include "ephy-prefs.h"
 #include "ephy-file-helpers.h"
+#include "ephy-file-chooser.h"
 #include "ephy-bookmarks-ui.h"
 #include "ephy-web-view.h"
 
@@ -179,28 +180,25 @@ popup_cmd_copy_link_address (GtkAction *action,
 }
 
 static void
-save_property_url_completed_cb (EphyEmbedPersist *persist)
+response_cb (GtkDialog *dialog,
+	     int response_id,
+	     EphyDownload *download)
 {
-	if (!(ephy_embed_persist_get_flags (persist) & 
-				EPHY_EMBED_PERSIST_ASK_DESTINATION))
+	if (response_id == GTK_RESPONSE_ACCEPT)
 	{
-		const char *dest;
-		GFile *dest_file;
-		guint32 user_time;
+		char *uri;
 
-		user_time = ephy_embed_persist_get_user_time (persist);
-		dest = ephy_embed_persist_get_dest (persist);
-
-		g_return_if_fail (dest != NULL);
-
-		dest_file = g_file_new_for_path (dest);
-		
-		g_return_if_fail (dest_file != NULL);
-		/* If save location is the desktop, nautilus will not open */
-		ephy_file_browse_to (dest_file, user_time);
-		
-		g_object_unref (dest_file);
+		uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+		ephy_download_set_destination_uri (download, uri);
+		ephy_download_start (download);
+		g_free (uri);
+	}
+	else
+	{
+		ephy_download_cancel (download);
 	}
+
+	gtk_widget_destroy (GTK_WIDGET (dialog));
 }
 
 static void
@@ -213,38 +211,44 @@ save_property_url (GtkAction *action,
 	EphyEmbedEvent *event;
 	const char *location;
 	GValue value = { 0, };
-	EphyEmbedPersist *persist;
-	EphyEmbed *embed;
+	EphyDownload *download;
 
 	event = ephy_window_get_context_event (window);
 	g_return_if_fail (event != NULL);
 
-	embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
-	g_return_if_fail (embed != NULL);
-
 	ephy_embed_event_get_property (event, property, &value);
 	location = g_value_get_string (&value);
 
-	persist = EPHY_EMBED_PERSIST
-		(g_object_new (EPHY_TYPE_EMBED_PERSIST, NULL));
-
-	ephy_embed_persist_set_fc_title (persist, title);
-	ephy_embed_persist_set_fc_parent (persist, GTK_WINDOW (window));
-	ephy_embed_persist_set_flags
-		(persist, EPHY_EMBED_PERSIST_FROM_CACHE |
-			  (ask_dest ? EPHY_EMBED_PERSIST_ASK_DESTINATION : 0));
-	ephy_embed_persist_set_persist_key
-		(persist, EPHY_PREFS_STATE_SAVE_DIR);
-	ephy_embed_persist_set_source (persist, location);
-	ephy_embed_persist_set_embed (persist, embed);
-
-	g_signal_connect (persist, "completed",
-			  G_CALLBACK (save_property_url_completed_cb), NULL);
-
-	ephy_embed_persist_save (persist);
-
-	g_object_unref (G_OBJECT (persist));
+	download = ephy_download_new_for_uri (location);
+	ephy_download_set_window (download, GTK_WIDGET (window));
 	g_value_unset (&value);
+
+	if (ask_dest)
+	{
+		EphyFileChooser *dialog;
+		char *base;
+
+		base = g_path_get_basename (location);
+		dialog = ephy_file_chooser_new (title, GTK_WIDGET (window),
+						GTK_FILE_CHOOSER_ACTION_SAVE,
+						EPHY_PREFS_STATE_SAVE_DIR,
+						EPHY_FILE_FILTER_ALL);
+
+		gtk_file_chooser_set_do_overwrite_confirmation
+				(GTK_FILE_CHOOSER (dialog), TRUE);
+		gtk_file_chooser_set_current_name
+				(GTK_FILE_CHOOSER (dialog), base);
+		g_signal_connect (dialog, "response",
+				  G_CALLBACK (response_cb), download);
+		gtk_widget_show (GTK_WIDGET (dialog));
+
+		g_free (base);
+	}
+	else
+	{
+		ephy_download_set_auto_destination (download);
+		ephy_download_start (download);
+	}
 }
 
 void
@@ -293,15 +297,15 @@ popup_cmd_save_image_as (GtkAction *action,
 #define GNOME_APPEARANCE_PROPERTIES  "gnome-appearance-properties.desktop"
 
 static void
-background_download_completed (EphyEmbedPersist *persist,
+background_download_completed (EphyDownload *download,
 			       GtkWidget *window)
 {
-	const char *bg;
+	char *bg;
 	guint32 user_time;
 
-	user_time = ephy_embed_persist_get_user_time (persist);
+	user_time = ephy_download_get_start_time (download);
 
-	bg = ephy_embed_persist_get_dest (persist);
+	bg = g_filename_from_uri (ephy_download_get_destination_uri (download), NULL, NULL);
 
 	/* open the Appearance Properties capplet on the Background tab */
 	if (!ephy_file_launch_desktop_file (GNOME_APPEARANCE_PROPERTIES, bg, user_time, window))
@@ -315,8 +319,7 @@ background_download_completed (EphyEmbedPersist *persist,
 			ephy_file_launch_desktop_file ("gnome-background.desktop", bg, user_time, window);
 		}
 	}
-
-	g_object_unref (persist);
+	g_free (bg);
 }
 
 void
@@ -325,43 +328,36 @@ popup_cmd_set_image_as_background (GtkAction *action,
 {
 	EphyEmbedEvent *event;
 	const char *location;
-	char *dest, *base, *base_converted;
+	char *dest_uri, *dest, *base, *base_converted;
 	GValue value = { 0, };
-	EphyEmbedPersist *persist;
-	EphyEmbed *embed;
+	EphyDownload *download;
 
 	event = ephy_window_get_context_event (window);
 	g_return_if_fail (event != NULL);
 
-	embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
-	g_return_if_fail (embed != NULL);
-
 	ephy_embed_event_get_property (event, "image-uri", &value);
 	location = g_value_get_string (&value);
 
-	persist = EPHY_EMBED_PERSIST
-		(g_object_new (EPHY_TYPE_EMBED_PERSIST, NULL));
+	download = ephy_download_new_for_uri (location);
+	ephy_download_set_window (download, GTK_WIDGET (window));
 
 	base = g_path_get_basename (location);
 	base_converted = g_filename_from_utf8 (base, -1, NULL, NULL, NULL);
 	dest = g_build_filename (ephy_dot_dir (), base_converted, NULL);
+	dest_uri = g_filename_to_uri (dest, NULL, NULL);
 
-	ephy_embed_persist_set_dest (persist, dest);
-	ephy_embed_persist_set_flags (persist, EPHY_EMBED_PERSIST_NO_VIEW |
-				     	       EPHY_EMBED_PERSIST_FROM_CACHE);
-	ephy_embed_persist_set_source (persist, location);
+	ephy_download_set_destination_uri (download, dest_uri);
 
-	g_signal_connect (persist, "completed",
-			  G_CALLBACK (background_download_completed),
-			  window);
+	g_signal_connect (download, "completed",
+			  G_CALLBACK (background_download_completed), window);
 
-	ephy_embed_persist_save (persist);
-	g_object_unref (persist);
+	ephy_download_start (download);
 
 	g_value_unset (&value);
-	g_free (dest);
 	g_free (base);
 	g_free (base_converted);
+	g_free (dest);
+	g_free (dest_uri);
 }
 
 void
@@ -425,19 +421,19 @@ image_open_uri (GFile *file,
 }
 
 static void
-save_source_completed_cb (EphyEmbedPersist *persist)
+save_source_completed_cb (EphyDownload *download)
 {
 	const char *dest;
 	const char *source;
 	guint32 user_time;
 	GFile *file;
 
-	user_time = ephy_embed_persist_get_user_time (persist);
-	dest = ephy_embed_persist_get_dest (persist);
-	source = ephy_embed_persist_get_source (persist);
+	user_time = ephy_download_get_start_time (download);
+	dest = ephy_download_get_destination_uri (download);
+	source = ephy_download_get_source_uri (download);
 	g_return_if_fail (dest != NULL);
 	
-	file = g_file_new_for_path (dest);
+	file = g_file_new_for_uri (dest);
 
 	image_open_uri (file, source, user_time);
 	g_object_unref (file);
@@ -446,9 +442,9 @@ save_source_completed_cb (EphyEmbedPersist *persist)
 static void
 save_temp_source (const char *address)
 {
-	EphyEmbedPersist *persist;
+	EphyDownload *download;
 	const char *static_temp_dir;
-	char *base, *tmp_name, *tmp_path, *dest;
+	char *base, *tmp_name, *tmp_path, *dest, *dest_uri;
 
 	if (address == NULL) return;
 
@@ -467,21 +463,17 @@ save_temp_source (const char *address)
 
 	if (dest == NULL) return;
 
-	persist = EPHY_EMBED_PERSIST
-		(g_object_new (EPHY_TYPE_EMBED_PERSIST, NULL));
-
-	ephy_embed_persist_set_source (persist, address);
-	ephy_embed_persist_set_dest (persist, dest);
-	ephy_embed_persist_set_flags (persist, EPHY_EMBED_PERSIST_FROM_CACHE |
-			 		       EPHY_EMBED_PERSIST_NO_VIEW);
+	dest_uri = g_filename_to_uri (dest, NULL, NULL);
+	download = ephy_download_new_for_uri (address);
+	ephy_download_set_destination_uri (download, dest_uri);
 
-	g_signal_connect (persist, "completed",
+	g_signal_connect (download, "completed",
 			  G_CALLBACK (save_source_completed_cb), NULL);
 
-	ephy_embed_persist_save (persist);
-	g_object_unref (persist);
+	ephy_download_start (download);
 
 	g_free (dest);
+	g_free (dest_uri);
 }
 
 void
diff --git a/src/window-commands.c b/src/window-commands.c
index ff3647c..6b70b09 100644
--- a/src/window-commands.c
+++ b/src/window-commands.c
@@ -27,7 +27,6 @@
 #include "ephy-embed-single.h"
 #include "ephy-embed-utils.h"
 #include "ephy-shell.h"
-#include "ephy-embed-persist.h"
 #include "ephy-debug.h"
 #include "window-commands.h"
 #include "ephy-prefs.h"
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8cba757..bb538d8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,5 +1,5 @@
 noinst_PROGRAMS = \
-	test-ephy-embed-persist \
+	test-ephy-download \
 	test-ephy-embed-single \
 	test-ephy-location-entry \
 	test-ephy-search-entry \
@@ -33,8 +33,8 @@ LDADD += \
 	$(SEED_LIBS)
 endif
 
-test_ephy_embed_persist_SOURCES = \
-	ephy-embed-persist.c
+test_ephy_download_SOURCES = \
+	ephy-download.c
 
 test_ephy_embed_single_SOURCES = \
 	ephy-embed-single.c
diff --git a/tests/ephy-download.c b/tests/ephy-download.c
new file mode 100644
index 0000000..14fe81a
--- /dev/null
+++ b/tests/ephy-download.c
@@ -0,0 +1,207 @@
+/* vim: set sw=2 ts=2 sts=2 et: */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * ephy-download.c
+ * This file is part of Epiphany
+ *
+ * Copyright © 2011 - 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Epiphany 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 Epiphany; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+#include "ephy-debug.h"
+#include "ephy-download.h"
+#include "ephy-embed-prefs.h"
+#include "ephy-file-helpers.h"
+#include "ephy-shell.h"
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#define HTML_STRING "testing-embed-persist"
+SoupURI *base_uri;
+
+static char *
+get_uri_for_path (const char *path)
+{
+  SoupURI *uri;
+  char *uri_string;
+
+  uri = soup_uri_new_with_base (base_uri, path);
+  uri_string = soup_uri_to_string (uri, FALSE);
+  soup_uri_free (uri);
+
+  return uri_string;
+}
+
+static void
+server_callback (SoupServer *server,
+                 SoupMessage *msg,
+                 const char *path,
+                 GHashTable *query,
+                 SoupClientContext *context,
+                 gpointer data)
+{
+  soup_message_set_status (msg, SOUP_STATUS_OK);
+
+  if (g_str_equal (path, "/cancelled"))
+    soup_message_set_status (msg, SOUP_STATUS_CANT_CONNECT);
+
+  soup_message_body_append (msg->response_body, SOUP_MEMORY_STATIC,
+                            HTML_STRING, strlen (HTML_STRING));
+
+  soup_message_body_complete (msg->response_body);
+}
+
+typedef struct {
+  GMainLoop *loop;
+  EphyDownload *download;
+  char *destination;
+  char *source;
+} Fixture;
+
+static void
+fixture_setup (Fixture *fixture, gconstpointer data)
+{
+  char *tmp_filename;
+  char *dest_file;
+
+  tmp_filename = ephy_file_tmp_filename ("ephy-download-XXXXXX", NULL);
+  dest_file = g_build_filename (ephy_file_tmp_dir (), tmp_filename, NULL);
+
+  fixture->source = get_uri_for_path ("/default");
+  fixture->download = ephy_download_new_for_uri (fixture->source);
+  fixture->destination = g_filename_to_uri (dest_file, NULL, NULL);
+  fixture->loop = g_main_loop_new (NULL, TRUE);
+
+  ephy_download_set_destination_uri (fixture->download, fixture->destination);
+
+  g_free (tmp_filename);
+  g_free (dest_file);
+}
+
+static void
+fixture_teardown (Fixture *fixture, gconstpointer data)
+{
+  g_free (fixture->destination);
+  g_free (fixture->source);
+
+  g_object_unref (fixture->download);
+
+  g_main_loop_unref (fixture->loop);
+}
+
+static gboolean
+test_file_was_downloaded (EphyDownload *download)
+{
+  char *filename;
+  gboolean ret;
+
+  filename = g_filename_from_uri (ephy_download_get_destination_uri (download),
+                                  NULL, NULL);
+
+  ret = g_file_test (filename, G_FILE_TEST_EXISTS);
+  g_free (filename);
+
+  return ret;
+}
+
+static void
+completed_cb (EphyDownload *download,
+              Fixture *fixture)
+{
+  g_assert (test_file_was_downloaded (download));
+  g_main_loop_quit (fixture->loop);
+}
+
+static void
+test_ephy_download_new (Fixture *fixture, gconstpointer data)
+{
+  g_assert (EPHY_IS_DOWNLOAD (fixture->download));
+}
+
+static void
+test_ephy_download_new_for_uri (Fixture *fixture, gconstpointer data)
+{
+  EphyDownload *download;
+
+  download = ephy_download_new_for_uri (fixture->source);
+
+  g_assert (EPHY_IS_DOWNLOAD (download));
+
+  g_assert_cmpstr (fixture->source, ==, ephy_download_get_source_uri (download));
+
+  g_signal_connect (G_OBJECT (download), "completed",
+                    G_CALLBACK (completed_cb), fixture);
+
+  g_main_loop_run (fixture->loop);
+}
+
+static void
+test_ephy_download_start (Fixture *fixture, gconstpointer data)
+{
+  g_signal_connect (G_OBJECT (fixture->download), "completed",
+                    G_CALLBACK (completed_cb), fixture);
+
+  g_main_loop_run (fixture->loop);
+}
+
+int
+main (int argc, char *argv[])
+{
+  int ret;
+  SoupServer *server;
+
+  gtk_test_init (&argc, &argv);
+  g_thread_init (NULL);
+
+  ephy_debug_init ();
+  ephy_embed_prefs_init ();
+  _ephy_shell_create_instance ();
+
+  if (!ephy_file_helpers_init (NULL, TRUE, FALSE, NULL)) {
+    g_debug ("Something wrong happened with ephy_file_helpers_init()");
+    return -1;
+  }
+
+  server = soup_server_new (SOUP_SERVER_PORT, 0, NULL);
+  soup_server_run_async (server);
+
+  base_uri = soup_uri_new ("http://127.0.0.1/";);
+  soup_uri_set_port (base_uri, soup_server_get_port (server));
+
+  soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
+
+  g_test_add ("/embed/ephy-download/new",
+              Fixture, NULL, fixture_setup,
+              test_ephy_download_new, fixture_teardown);
+  g_test_add ("/embed/ephy-download/new_for_uri",
+              Fixture, NULL, fixture_setup,
+              test_ephy_download_new_for_uri, fixture_teardown);
+  g_test_add ("/embed/ephy-download/start",
+              Fixture, NULL, fixture_setup,
+              test_ephy_download_start, fixture_teardown);
+
+  ret = g_test_run ();
+
+  g_object_unref (ephy_shell);
+  ephy_file_helpers_shutdown ();
+
+  return ret;
+}



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