aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brendan Taylor <whateley@gmail.com>2010-12-03 15:14:42 -0700
committerGravatar Brendan Taylor <whateley@gmail.com>2010-12-03 15:14:42 -0700
commitde79ee76d7c86d032309d73ba210668466785b42 (patch)
treecf596cff5b87f6b67155318188e5f9508239540c
parenteccb7ec98fa198d076be72cd017926354d67cc70 (diff)
parent5ab073d90e3c66a53e116c78299c657a13847d5c (diff)
Merge branch 'dev/in-webkit-downloads' into experimental
Conflicts: examples/data/scripts/download.sh
-rw-r--r--README9
-rw-r--r--examples/config/config5
-rw-r--r--examples/data/plugins/downloads.py69
-rwxr-xr-xexamples/data/scripts/download.sh34
-rw-r--r--src/callbacks.c125
-rw-r--r--src/callbacks.h5
-rw-r--r--src/events.c6
-rw-r--r--src/events.h3
-rw-r--r--src/uzbl-core.c1
-rw-r--r--src/uzbl-core.h1
10 files changed, 226 insertions, 32 deletions
diff --git a/README b/README
index 22c1a99..331b040 100644
--- a/README
+++ b/README
@@ -664,8 +664,13 @@ Events have this format:
* `EVENT [uzbl_instance_name] TITLE_CHANGED title_name`: When the title of the
page (and hence maybe, the window title) changed. `title_name` is the new
title.
-* `EVENT [uzbl_instance_name] DOWNLOAD_REQUEST download_uri`: When content needs
- to be downloaded, `download_uri` is the URI to get.
+* `EVENT [uzbl_instance_name] DOWNLOAD_STARTED destination_path`: A download
+ has been started, the file will be saved to `destination_path`.
+* `EVENT [uzbl_instance_name] DOWNLOAD_PROGRESS destination_path progress`:
+ While a download is active this event notifies you of the progress.
+ `progress` is a decimal between 0 and 1.
+* `EVENT [uzbl_instance_name] DOWNLOAD_COMPLETE destination_path`: The
+ download being saved to `destination_path` is now complete.
* `EVENT [uzbl_instance_name] LINK_HOVER uri`: The mouse hovers over the link
`uri`.
* `EVENT [uzbl_instance_name] LINK_UNHOVER uri`: The mouse leaves the link
diff --git a/examples/config/config b/examples/config/config
index e282bb9..5d7073f 100644
--- a/examples/config/config
+++ b/examples/config/config
@@ -45,6 +45,7 @@ set scripts_dir = @data_home/uzbl:@prefix/share/uzbl/examples/data:scripts
set cookie_handler = talk_to_socket @cache_home/uzbl/cookie_daemon_socket
set scheme_handler = sync_spawn @scripts_dir/scheme.py
set authentication_handler = sync_spawn @scripts_dir/auth.py
+set download_handler = sync_spawn @scripts_dir/download.sh
# === Dynamic event handlers =================================================
@@ -106,7 +107,9 @@ set name_section = <span foreground="khaki">\@[\@NAME]\@</span>
set status_section = <span foreground="orange">\@status_message</span>
set selected_section = <span foreground="#606060">\@[\@SELECTED_URI]\@</span>
-set status_format = <span font_family="monospace">@mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @scroll_section @selected_section</span>
+set download_section = <span foreground="white">\@downloads</span>
+
+set status_format = <span font_family="monospace">@mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @scroll_section @selected_section @download_section</span>
set title_format_long = \@keycmd_prompt \@raw_modcmd \@raw_keycmd \@TITLE - Uzbl browser <\@NAME> \@SELECTED_URI
diff --git a/examples/data/plugins/downloads.py b/examples/data/plugins/downloads.py
new file mode 100644
index 0000000..7bf32d7
--- /dev/null
+++ b/examples/data/plugins/downloads.py
@@ -0,0 +1,69 @@
+# this plugin does a very simple display of download progress. to use it, add
+# @downloads to your status_format.
+
+import os
+ACTIVE_DOWNLOADS = {}
+
+# after a download's status has changed this is called to update the status bar
+def update_download_section(uzbl):
+ global ACTIVE_DOWNLOADS
+
+ if len(ACTIVE_DOWNLOADS):
+ # add a newline before we list downloads
+ result = '&#10;downloads:'
+ for path in ACTIVE_DOWNLOADS:
+ # add each download
+ fn = os.path.basename(path)
+ progress, = ACTIVE_DOWNLOADS[path]
+
+ dl = " %s (%d%%)" % (fn, progress * 100)
+
+ # replace entities to make sure we don't break our markup
+ # (this could be done with an @[]@ expansion in uzbl, but then we
+ # can't use the &#10; above to make a new line)
+ dl = dl.replace("&", "&amp;").replace("<", "&lt;")
+ result += dl
+ else:
+ result = ''
+
+ # and the result gets saved to an uzbl variable that can be used in
+ # status_format
+ if uzbl.config.get('downloads', '') != result:
+ uzbl.config['downloads'] = result
+
+def download_started(uzbl, destination_path):
+ # add to the list of active downloads
+ global ACTIVE_DOWNLOADS
+ ACTIVE_DOWNLOADS[destination_path] = (0.0,)
+
+ # update the progress
+ update_download_section(uzbl)
+
+def download_progress(uzbl, args):
+ # parse the arguments
+ s = args.rindex(' ')
+ destination_path = args[:s]
+ progress = float(args[s+1:])
+
+ # update the progress
+ global ACTIVE_DOWNLOADS
+ ACTIVE_DOWNLOADS[destination_path] = (progress,)
+
+ # update the status bar variable
+ update_download_section(uzbl)
+
+def download_complete(uzbl, destination_path):
+ # remove from the list of active downloads
+ global ACTIVE_DOWNLOADS
+ del ACTIVE_DOWNLOADS[destination_path]
+
+ # update the status bar variable
+ update_download_section(uzbl)
+
+# plugin init hook
+def init(uzbl):
+ connect_dict(uzbl, {
+ 'DOWNLOAD_STARTED': download_started,
+ 'DOWNLOAD_PROGRESS': download_progress,
+ 'DOWNLOAD_COMPLETE': download_complete,
+ })
diff --git a/examples/data/scripts/download.sh b/examples/data/scripts/download.sh
index b378a85..df7a571 100755
--- a/examples/data/scripts/download.sh
+++ b/examples/data/scripts/download.sh
@@ -1,26 +1,26 @@
#!/bin/sh
-# just an example of how you could handle your downloads
-# try some pattern matching on the uri to determine what we should do
+#
+# uzbl's example configuration sets this script up as its download_handler.
+# when uzbl starts a download it runs this script.
+# if the script prints a file path to stdout, uzbl will save the download to
+# that path.
+# if nothing is printed to stdout, the download will be cancelled.
shift 7
. $UZBL_UTIL_DIR/uzbl-dir.sh
-# Some sites block the default wget --user-agent..
-GET="wget --user-agent=Firefox --content-disposition --load-cookies=$UZBL_COOKIE_FILE"
+# the URL that is being downloaded
+uri=$1
-url="$1"
+# a filename suggested by the server or based on the URL
+suggested_filename=${2:-$(echo "$uri" | sed 's/\W/-/g')}
-http_proxy="$2"
-export http_proxy
+# the mimetype of the file being downloaded
+content_type=$3
-if [ -z "$url" ]; then
- echo "you must supply a url! ($url)"
- exit 1
-fi
+# the size of the downloaded file in bytes. this is not always accurate, since
+# the server might not have sent a size with its response headers.
+total_size=$4
-# only changes the dir for the $get sub process
-if echo "$url" | grep -E '.*\.torrent' >/dev/null; then
- ( cd "$UZBL_DOWNLOAD_DIR"; $GET "$url")
-else
- ( cd "$UZBL_DOWNLOAD_DIR"; $GET "$url")
-fi
+# just save the file to the default directory with the suggested name
+echo $UZBL_DOWNLOAD_DIR/$suggested_filename
diff --git a/src/callbacks.c b/src/callbacks.c
index 4f0e4ac..bcbac00 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -773,13 +773,128 @@ create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer us
return NULL;
}
+void
+download_progress_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_data) {
+ (void) pspec; (void) user_data;
+
+ gdouble progress;
+ g_object_get(download, "progress", &progress, NULL);
+
+ const gchar *dest_uri = webkit_download_get_destination_uri(download);
+ const gchar *dest_path = dest_uri + strlen("file://");
+
+ gchar *details = g_strdup_printf("%s %.2lf", dest_path, progress);
+ send_event(DOWNLOAD_PROGRESS, details, NULL);
+ g_free(details);
+}
+
+void
+download_status_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_data) {
+ (void) pspec; (void) user_data;
+
+ WebKitDownloadStatus status;
+ g_object_get(download, "status", &status, NULL);
+
+ switch(status) {
+ case WEBKIT_DOWNLOAD_STATUS_CREATED:
+ case WEBKIT_DOWNLOAD_STATUS_STARTED:
+ case WEBKIT_DOWNLOAD_STATUS_ERROR:
+ case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
+ return; /* these are irrelevant */
+ case WEBKIT_DOWNLOAD_STATUS_FINISHED:
+ {
+ const gchar *dest_uri = webkit_download_get_destination_uri(download);
+ const gchar *dest_path = dest_uri + strlen("file://");
+ send_event(DOWNLOAD_COMPLETE, dest_path, NULL);
+ }
+ }
+}
+
gboolean
-download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
- (void) web_view;
- (void) user_data;
+download_cb(WebKitWebView *web_view, WebKitDownload *download, gpointer user_data) {
+ (void) web_view; (void) user_data;
- send_event(DOWNLOAD_REQ, webkit_download_get_uri ((WebKitDownload*)download), NULL);
- return (FALSE);
+ /* get the URI being downloaded */
+ const gchar *uri = webkit_download_get_uri(download);
+
+ if (uzbl.state.verbose)
+ printf("Download requested -> %s\n", uri);
+
+ if (!uzbl.behave.download_handler) {
+ webkit_download_cancel(download);
+ return FALSE; /* reject downloads when there's no download handler */
+ }
+
+ /* get a reasonable suggestion for a filename */
+ const gchar *suggested_filename;
+ g_object_get(download, "suggested-filename", &suggested_filename, NULL);
+
+ /* get the mimetype of the download */
+ const gchar *content_type;
+ WebKitNetworkResponse *r = webkit_download_get_network_response(download);
+ /* downloads can be initiated from the context menu, in that case there is
+ no network response yet and trying to get one would crash. */
+ if(WEBKIT_IS_NETWORK_RESPONSE(r)) {
+ SoupMessage *m = webkit_network_response_get_message(r);
+ SoupMessageHeaders *h;
+ g_object_get(m, "response-headers", &h, NULL);
+ content_type = soup_message_headers_get_one(h, "Content-Type");
+ } else
+ content_type = "application/octet-stream";
+
+ /* get the filesize of the download, as given by the server.
+ (this may be inaccurate, there's nothing we can do about that.) */
+ unsigned int total_size = webkit_download_get_total_size(download);
+
+ gchar *ev = g_strdup_printf("'%s' '%s' '%s' %d", uri, suggested_filename,
+ content_type, total_size);
+ run_handler(uzbl.behave.download_handler, ev);
+ g_free(ev);
+
+ /* no response, cancel the download */
+ if(!uzbl.comm.sync_stdout) {
+ webkit_download_cancel(download);
+ return FALSE;
+ }
+
+ /* no response, cancel the download */
+ if(uzbl.comm.sync_stdout[0] == 0) {
+ webkit_download_cancel(download);
+ uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
+ return FALSE;
+ }
+
+ /* we got a response, it's the path we should download the file to */
+ gchar *destination_path = uzbl.comm.sync_stdout;
+ uzbl.comm.sync_stdout = NULL;
+
+ /* presumably people don't need newlines in their filenames. */
+ char *p = strchr(destination_path, '\n');
+ if ( p != NULL ) *p = '\0';
+
+ /* set up progress callbacks */
+ g_signal_connect(download, "notify::status", G_CALLBACK(download_status_cb), NULL);
+ g_signal_connect(download, "notify::progress", G_CALLBACK(download_progress_cb), NULL);
+
+ /* convert relative path to absolute path */
+ if(destination_path[0] != '/') {
+ gchar *rel_path = destination_path;
+ gchar *cwd = g_get_current_dir();
+ destination_path = g_strconcat(cwd, "/", destination_path, NULL);
+ g_free(cwd);
+ g_free(rel_path);
+ }
+
+ send_event(DOWNLOAD_STARTED, destination_path, NULL);
+
+ /* convert absolute path to file:// URI */
+ gchar *destination_uri = g_strconcat("file://", destination_path, NULL);
+ g_free(destination_path);
+
+ webkit_download_set_destination_uri(download, destination_uri);
+ g_free(destination_uri);
+
+ return TRUE;
}
gboolean
diff --git a/src/callbacks.h b/src/callbacks.h
index a4258f2..40fa80d 100644
--- a/src/callbacks.h
+++ b/src/callbacks.h
@@ -133,9 +133,6 @@ cmd_load_start();
WebKitWebSettings*
view_settings();
-gboolean
-download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data);
-
void
toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result);
@@ -197,7 +194,7 @@ request_starting_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitWebRes
create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data);
gboolean
-download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data);
+download_cb (WebKitWebView *web_view, WebKitDownload *download, gpointer user_data);
void
populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c);
diff --git a/src/events.c b/src/events.c
index fde731a..b02cb89 100644
--- a/src/events.c
+++ b/src/events.c
@@ -22,7 +22,6 @@ const char *event_table[LAST_EVENT] = {
"REQUEST_STARTING" ,
"KEY_PRESS" ,
"KEY_RELEASE" ,
- "DOWNLOAD_REQUEST" ,
"COMMAND_EXECUTED" ,
"LINK_HOVER" ,
"TITLE_CHANGED" ,
@@ -47,7 +46,10 @@ const char *event_table[LAST_EVENT] = {
"BUILTINS" ,
"PTR_MOVE" ,
"SCROLL_VERT" ,
- "SCROLL_HORIZ"
+ "SCROLL_HORIZ" ,
+ "DOWNLOAD_STARTED" ,
+ "DOWNLOAD_PROGRESS",
+ "DOWNLOAD_COMPLETE"
};
void
diff --git a/src/events.h b/src/events.h
index bc7960d..4b04dd2 100644
--- a/src/events.h
+++ b/src/events.h
@@ -7,7 +7,7 @@
enum event_type {
LOAD_START, LOAD_COMMIT, LOAD_FINISH, LOAD_ERROR,
REQUEST_STARTING,
- KEY_PRESS, KEY_RELEASE, DOWNLOAD_REQ, COMMAND_EXECUTED,
+ KEY_PRESS, KEY_RELEASE, COMMAND_EXECUTED,
LINK_HOVER, TITLE_CHANGED, GEOMETRY_CHANGED,
WEBINSPECTOR, NEW_WINDOW, SELECTION_CHANGED,
VARIABLE_SET, FIFO_SET, SOCKET_SET,
@@ -16,6 +16,7 @@ enum event_type {
FOCUS_LOST, FOCUS_GAINED, FILE_INCLUDED,
PLUG_CREATED, COMMAND_ERROR, BUILTINS,
PTR_MOVE, SCROLL_VERT, SCROLL_HORIZ,
+ DOWNLOAD_STARTED, DOWNLOAD_PROGRESS, DOWNLOAD_COMPLETE,
/* must be last entry */
LAST_EVENT
diff --git a/src/uzbl-core.c b/src/uzbl-core.c
index 5adc4e1..1110b02 100644
--- a/src/uzbl-core.c
+++ b/src/uzbl-core.c
@@ -93,6 +93,7 @@ const struct var_name_to_ptr_t {
{ "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_set_cookie_handler)},
{ "authentication_handler", PTR_V_STR(uzbl.behave.authentication_handler, 1, set_authentication_handler)},
{ "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)},
+ { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)},
{ "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)},
{ "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)},
{ "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)},
diff --git a/src/uzbl-core.h b/src/uzbl-core.h
index 6c926c6..b521f93 100644
--- a/src/uzbl-core.h
+++ b/src/uzbl-core.h
@@ -133,6 +133,7 @@ typedef struct {
gchar* fantasy_font_family;
gchar* cursive_font_family;
gchar* scheme_handler;
+ gchar* download_handler;
gboolean show_status;
gboolean forward_keys;
gboolean status_top;