aboutsummaryrefslogtreecommitdiffstats
path: root/embed/ephy-download.c
diff options
context:
space:
mode:
authorDiego Escalante Urrelo <descalante@igalia.com>2011-01-19 00:10:11 +0800
committerDiego Escalante Urrelo <descalante@igalia.com>2011-03-08 04:34:52 +0800
commitb9f9bf1a0763492f8bf41b8856bbd1149c5871a9 (patch)
tree92ad55101bff9eabcbc17afdba4a398ce4c4b709 /embed/ephy-download.c
parent7f7826a163f31bb662247ac4486dca0d01df35f6 (diff)
downloadgsoc2013-epiphany-b9f9bf1a0763492f8bf41b8856bbd1149c5871a9.tar
gsoc2013-epiphany-b9f9bf1a0763492f8bf41b8856bbd1149c5871a9.tar.gz
gsoc2013-epiphany-b9f9bf1a0763492f8bf41b8856bbd1149c5871a9.tar.bz2
gsoc2013-epiphany-b9f9bf1a0763492f8bf41b8856bbd1149c5871a9.tar.lz
gsoc2013-epiphany-b9f9bf1a0763492f8bf41b8856bbd1149c5871a9.tar.xz
gsoc2013-epiphany-b9f9bf1a0763492f8bf41b8856bbd1149c5871a9.tar.zst
gsoc2013-epiphany-b9f9bf1a0763492f8bf41b8856bbd1149c5871a9.zip
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
Diffstat (limited to 'embed/ephy-download.c')
-rw-r--r--embed/ephy-download.c965
1 files changed, 965 insertions, 0 deletions
diff --git a/embed/ephy-download.c b/embed/ephy-download.c
new file mode 100644
index 000000000..3a7d2d1ff
--- /dev/null
+++ b/embed/ephy-download.c
@@ -0,0 +1,965 @@
+/* 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);
+
+ download->priv->window = NULL;
+
+ 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);
+
+ download->priv->widget = NULL;
+
+ 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);
+}