summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2004-06-27 23:24:11 +0000
committerJames Bursa <james@netsurf-browser.org>2004-06-27 23:24:11 +0000
commita1d73ecd110f6cc252f6146672802f87cc45723d (patch)
treeb7cf1aaa3ca066b9d4281fed890e82c470733fc2
parent79a10e41a4be1a718df36e54036cd1666f967fef (diff)
downloadnetsurf-a1d73ecd110f6cc252f6146672802f87cc45723d.tar.gz
netsurf-a1d73ecd110f6cc252f6146672802f87cc45723d.tar.bz2
[project @ 2004-06-27 23:24:11 by bursa]
Rewritten download window. Now downloads direct to file. New download window gui. svn path=/import/netsurf/; revision=1020
-rw-r--r--!NetSurf/Resources/en/Messages5
-rw-r--r--!NetSurf/Resources/en/Templates,fecbin6410 -> 6489 bytes
-rw-r--r--!NetSurf/Resources/fr/Messages5
-rw-r--r--!NetSurf/Resources/fr/Templates,fecbin6516 -> 6568 bytes
-rw-r--r--content/fetch.c15
-rw-r--r--content/fetch.h4
-rw-r--r--desktop/browser.c91
-rw-r--r--desktop/gui.h13
-rw-r--r--riscos/download.c727
-rw-r--r--riscos/gui.c26
-rw-r--r--riscos/gui.h89
-rw-r--r--utils/utils.c7
12 files changed, 743 insertions, 239 deletions
diff --git a/!NetSurf/Resources/en/Messages b/!NetSurf/Resources/en/Messages
index ba67c2dcb..0dab38037 100644
--- a/!NetSurf/Resources/en/Messages
+++ b/!NetSurf/Resources/en/Messages
@@ -65,7 +65,10 @@ HelpAbout:About NetSurf
Themes:Themes
# Download window
-Downloaded:Download complete, %s
+Download:%s of %s %s/s %s remaining
+DownloadU:%s of unknown %s/s %s total
+Downloaded:%s complete average %s/s %s total
+Unwritten:Writing data to file failed.
# Forms
Form_Submit:Submit
diff --git a/!NetSurf/Resources/en/Templates,fec b/!NetSurf/Resources/en/Templates,fec
index afad82c15..798cc0475 100644
--- a/!NetSurf/Resources/en/Templates,fec
+++ b/!NetSurf/Resources/en/Templates,fec
Binary files differ
diff --git a/!NetSurf/Resources/fr/Messages b/!NetSurf/Resources/fr/Messages
index 941d74c13..7b5a6798e 100644
--- a/!NetSurf/Resources/fr/Messages
+++ b/!NetSurf/Resources/fr/Messages
@@ -65,7 +65,10 @@ HelpAbout: propos de NetSurf
Themes:Thmes
# Download window
-Downloaded:Tlchargement termin, %s
+Download:%s of %s %s/s %s remaining
+DownloadU:%s of unknown %s/s %s total
+Downloaded:%s complete average %s/s %s total
+Unwritten:Writing data to file failed.
# Forms
Form_Submit:Soumettre
diff --git a/!NetSurf/Resources/fr/Templates,fec b/!NetSurf/Resources/fr/Templates,fec
index 1f2934814..e2e6efeff 100644
--- a/!NetSurf/Resources/fr/Templates,fec
+++ b/!NetSurf/Resources/fr/Templates,fec
Binary files differ
diff --git a/content/fetch.c b/content/fetch.c
index 5e27add95..184d78bcb 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -825,6 +825,21 @@ bool fetch_can_fetch(const char *url)
/**
+ * Change the callback function for a fetch.
+ */
+
+void fetch_change_callback(struct fetch *fetch,
+ void (*callback)(fetch_msg msg, void *p, const char *data,
+ unsigned long size),
+ void *p)
+{
+ assert(fetch);
+ fetch->callback = callback;
+ fetch->p = p;
+}
+
+
+/**
* testing framework
*/
diff --git a/content/fetch.h b/content/fetch.h
index df2fd65c6..59767d255 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -53,5 +53,9 @@ void fetch_quit(void);
const char *fetch_filetype(const char *unix_path);
char *fetch_mimetype(const char *ro_path);
bool fetch_can_fetch(const char *url);
+void fetch_change_callback(struct fetch *fetch,
+ void (*callback)(fetch_msg msg, void *p, const char *data,
+ unsigned long size),
+ void *p);
#endif
diff --git a/desktop/browser.c b/desktop/browser.c
index 2e9b2cf56..46a7b8443 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -39,8 +39,7 @@
static void browser_window_callback(content_msg msg, struct content *c,
void *p1, void *p2, union content_msg_data data);
-static void browser_window_convert_to_download(struct browser_window *bw,
- content_msg msg);
+static void browser_window_convert_to_download(struct browser_window *bw);
static void browser_window_start_throbber(struct browser_window *bw);
static void browser_window_stop_throbber(struct browser_window *bw);
static void browser_window_update(struct browser_window *bw,
@@ -48,8 +47,8 @@ static void browser_window_update(struct browser_window *bw,
static void browser_window_set_status(struct browser_window *bw,
const char *text);
static void browser_window_set_pointer(gui_pointer_shape shape);
-static void download_window_callback(content_msg msg, struct content *c,
- void *p1, void *p2, union content_msg_data data);
+static void download_window_callback(fetch_msg msg, void *p, const char *data,
+ unsigned long size);
static void browser_window_text_selection(struct browser_window* bw,
unsigned long click_x, unsigned long click_y, int click_type);
@@ -194,13 +193,12 @@ void browser_window_callback(content_msg msg, struct content *c,
struct browser_window *bw = p1;
char status[40];
- if (c->type == CONTENT_OTHER) {
- browser_window_convert_to_download(bw, msg);
- return;
- }
-
switch (msg) {
case CONTENT_MSG_LOADING:
+ assert(bw->loading_content == c);
+
+ if (c->type == CONTENT_OTHER)
+ browser_window_convert_to_download(bw);
break;
case CONTENT_MSG_READY:
@@ -294,21 +292,32 @@ void browser_window_callback(content_msg msg, struct content *c,
* Transfer the loading_content to a new download window.
*/
-void browser_window_convert_to_download(struct browser_window *bw,
- content_msg msg)
+void browser_window_convert_to_download(struct browser_window *bw)
{
- gui_window *download_window;
+ struct gui_download_window *download_window;
struct content *c = bw->loading_content;
- union content_msg_data data;
+ struct fetch *fetch;
+
assert(c);
- /* create download window and add content to it */
- download_window = gui_create_download_window(c);
- content_add_user(c, download_window_callback, download_window, 0);
+ fetch = c->fetch;
- if (msg == CONTENT_MSG_DONE)
- download_window_callback(CONTENT_MSG_DONE, c, download_window,
- 0, data);
+ if (fetch) {
+ /* create download window */
+ download_window = gui_download_window_create(c->url,
+ c->mime_type, fetch, c->total_size);
+
+ if (download_window) {
+ /* extract fetch from content */
+ c->fetch = 0;
+ c->fresh = false;
+ fetch_change_callback(fetch, download_window_callback,
+ download_window);
+ }
+ } else {
+ /* must already be a download window for this fetch */
+ /** \todo open it at top of stack */
+ }
/* remove content from browser window */
bw->loading_content = 0;
@@ -466,50 +475,38 @@ void browser_window_destroy(struct browser_window *bw)
/**
- * Callback for fetchcache() for download window fetches.
+ * Callback for fetch for download window fetches.
*/
-void download_window_callback(content_msg msg, struct content *c,
- void *p1, void *p2, union content_msg_data data)
+void download_window_callback(fetch_msg msg, void *p, const char *data,
+ unsigned long size)
{
- gui_window *download_window = p1;
+ struct gui_download_window *download_window = p;
switch (msg) {
- case CONTENT_MSG_STATUS:
- gui_download_window_update_status(download_window);
+ case FETCH_DATA:
+ gui_download_window_data(download_window, data, size);
break;
- case CONTENT_MSG_DONE:
+ case FETCH_FINISHED:
gui_download_window_done(download_window);
break;
- case CONTENT_MSG_ERROR:
- gui_download_window_error(download_window, data.error);
- break;
-
- case CONTENT_MSG_READY:
+ case FETCH_ERROR:
+ gui_download_window_error(download_window, data);
break;
- case CONTENT_MSG_LOADING:
- case CONTENT_MSG_REDIRECT:
- /* not possible at this point, handled in
- browser_window_callback() */
+ case FETCH_TYPE:
+ case FETCH_REDIRECT:
+ case FETCH_AUTH:
+ default:
+ /* not possible */
assert(0);
break;
-
- case CONTENT_MSG_REFORMAT:
- break;
-
- case CONTENT_MSG_REDRAW:
- break;
-
-#ifdef WITH_AUTH
- case CONTENT_MSG_AUTH:
- break;
-#endif
- }
+ }
}
+
void clear_radio_gadgets(struct browser_window *bw, struct box *box,
struct form_control *group)
{
diff --git a/desktop/gui.h b/desktop/gui.h
index 4bf69c6aa..553962ae9 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -14,6 +14,7 @@
#define _NETSURF_DESKTOP_GUI_H_
struct gui_window;
+struct gui_download_window;
typedef struct gui_window gui_window;
typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET,
GUI_POINTER_MENU, GUI_POINTER_UD, GUI_POINTER_LR,
@@ -26,7 +27,6 @@ typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET,
gui_window *gui_create_browser_window(struct browser_window *bw,
struct browser_window *clone);
-gui_window *gui_create_download_window(struct content *content);
void gui_window_destroy(gui_window* g);
void gui_window_redraw(gui_window* g, unsigned long x0, unsigned long y0,
unsigned long x1, unsigned long y1);
@@ -40,9 +40,14 @@ void gui_window_set_pointer(gui_pointer_shape shape);
void gui_window_set_title(gui_window* g, char* title);
void gui_window_set_url(gui_window *g, char *url);
-void gui_download_window_update_status(gui_window *g);
-void gui_download_window_done(gui_window *g);
-void gui_download_window_error(gui_window *g, const char *error);
+struct gui_download_window *gui_download_window_create(const char *url,
+ const char *mime_type, struct fetch *fetch,
+ unsigned int total_size);
+void gui_download_window_data(struct gui_download_window *dw, const char *data,
+ unsigned int size);
+void gui_download_window_error(struct gui_download_window *dw,
+ const char *error_msg);
+void gui_download_window_done(struct gui_download_window *dw);
void gui_init(int argc, char** argv);
void gui_window_clone_options(struct browser_window *new_bw, struct browser_window *old_bw);
diff --git a/riscos/download.c b/riscos/download.c
index 03d96b9d1..e1599fc46 100644
--- a/riscos/download.c
+++ b/riscos/download.c
@@ -6,10 +6,26 @@
* Copyright 2003 Rob Jackson <jacko@xms.ms>
*/
+/** \file
+ * Download windows (RISC OS implementation).
+ *
+ * This file implements the interface given by desktop/gui.h for download
+ * windows. Each download window has an associated fetch. Downloads start by
+ * writing received data to a temporary file. At some point the user chooses
+ * a destination (by drag & drop), and the temporary file is then moved to the
+ * destination and the download continues until complete.
+ */
+
#include <assert.h>
#include <string.h>
+#include <sys/time.h>
+#include <time.h>
#include "oslib/mimemap.h"
+#include "oslib/osargs.h"
#include "oslib/osfile.h"
+#include "oslib/osfind.h"
+#include "oslib/osfscontrol.h"
+#include "oslib/osgbpb.h"
#include "oslib/wimp.h"
#include "oslib/wimpspriteop.h"
#include "netsurf/content/fetch.h"
@@ -21,8 +37,57 @@
#include "netsurf/utils/utils.h"
+/** Data for a download window. */
+struct gui_download_window {
+ /** Associated fetch, or 0 if the fetch has completed or aborted. */
+ struct fetch *fetch;
+ unsigned int received; /**< Amount of data received so far. */
+ unsigned int total_size; /**< Size of resource, or 0 if unknown. */
+
+ wimp_w window; /**< RISC OS window handle. */
+ bits file_type; /**< RISC OS file type. */
+
+ char url[256]; /**< Buffer for URL icon. */
+ char sprite_name[20]; /**< Buffer for sprite icon. */
+ char path[256]; /**< Buffer for pathname icon. */
+ char status[256]; /**< Buffer for status icon. */
+
+ /** User has chosen the destination, and it is being written. */
+ bool saved;
+ bool error; /**< Error occurred, aborted. */
+ /** RISC OS file handle, of temporary file when !saved, and of
+ * destination when saved. */
+ os_fw file;
+
+ struct timeval start_time; /**< Time download started. */
+ struct timeval last_time; /**< Time status was last updated. */
+ unsigned int last_received; /**< Value of received at last_time. */
+
+ struct gui_download_window *prev; /**< Previous in linked list. */
+ struct gui_download_window *next; /**< Next in linked list. */
+};
+
+
+/** List of all download windows. */
+static struct gui_download_window *download_window_list = 0;
+/** Download window with current save operation. */
+static struct gui_download_window *download_window_current = 0;
+
+/** Template for a download window. */
static wimp_window *download_template;
+/** Width of progress bar at 100%. */
+static int download_progress_width;
+/** Coordinates of progress bar. */
+static int download_progress_x0;
+static int download_progress_y0;
+static int download_progress_y1;
+
+
+static void ro_gui_download_update_status(struct gui_download_window *dw);
+static void ro_gui_download_update_status_wrapper(void *p);
+static void ro_gui_download_window_destroy_wrapper(void *p);
+
/**
* Load the download window template.
@@ -31,164 +96,427 @@ static wimp_window *download_template;
void ro_gui_download_init(void)
{
download_template = ro_gui_dialog_load_template("download");
+ download_progress_width =
+ download_template->icons[ICON_DOWNLOAD_STATUS].extent.x1 -
+ download_template->icons[ICON_DOWNLOAD_STATUS].extent.x0;
+ download_progress_x0 =
+ download_template->icons[ICON_DOWNLOAD_PROGRESS].extent.x0;
+ download_progress_y0 =
+ download_template->icons[ICON_DOWNLOAD_PROGRESS].extent.y0;
+ download_progress_y1 =
+ download_template->icons[ICON_DOWNLOAD_PROGRESS].extent.y1;
}
/**
* Create and open a download progress window.
+ *
+ * \param url URL of download
+ * \param mime_type MIME type sent by server
+ * \param fetch fetch structure
+ * \param total_size size of resource, or 0 if unknown
+ * \return a new gui_download_window structure, or 0 on error and error
+ * reported
*/
-gui_window *gui_create_download_window(struct content *content)
+struct gui_download_window *gui_download_window_create(const char *url,
+ const char *mime_type, struct fetch *fetch,
+ unsigned int total_size)
{
char *nice;
- gui_window *g = xcalloc(1, sizeof(gui_window));
- os_error *e;
+ char temp_name[40];
+ struct gui_download_window *dw;
+ os_error *error;
- assert(content->type == CONTENT_OTHER);
+ dw = malloc(sizeof *dw);
+ if (!dw) {
+ warn_user("NoMemory", 0);
+ return 0;
+ }
- g->type = GUI_DOWNLOAD_WINDOW;
- g->data.download.content = content;
+ dw->fetch = fetch;
+ dw->saved = false;
+ dw->error = false;
+ dw->received = 0;
+ dw->total_size = total_size;
+ strncpy(dw->url, url, sizeof dw->url);
+ dw->url[sizeof dw->url - 1] = 0;
+ dw->status[0] = 0;
+ gettimeofday(&dw->start_time, 0);
+ dw->last_time = dw->start_time;
+ dw->last_received = 0;
/* convert MIME type to RISC OS file type */
- e = xmimemaptranslate_mime_type_to_filetype(content->mime_type,
- &(g->data.download.file_type));
- if (e)
- g->data.download.file_type = 0xffd;
+ error = xmimemaptranslate_mime_type_to_filetype(mime_type,
+ &(dw->file_type));
+ if (error) {
+ LOG(("xmimemaptranslate_mime_type_to_filetype: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("MiscError", error->errmess);
+ dw->file_type = 0xffd;
+ }
+
+ /* open temporary output file */
+ snprintf(temp_name, sizeof temp_name, "<Wimp$ScrapDir>.ns%x",
+ (unsigned int) dw);
+ error = xosfind_openoutw(osfind_NO_PATH | osfind_ERROR_IF_DIR,
+ temp_name, 0, &dw->file);
+ if (error) {
+ LOG(("xosfind_openoutw: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ free(dw);
+ return 0;
+ }
/* fill in download window icons */
download_template->icons[ICON_DOWNLOAD_URL].data.indirected_text.text =
- content->url;
+ dw->url;
download_template->icons[ICON_DOWNLOAD_URL].data.indirected_text.size =
- strlen(content->url) + 1;
- strncpy(g->status, content->status_message, 256);
- download_template->icons[ICON_DOWNLOAD_STATUS].data.indirected_text.text =
- g->status;
- download_template->icons[ICON_DOWNLOAD_STATUS].data.indirected_text.size =
- 256;
- sprintf(g->data.download.sprite_name, "file_%.3x",
- g->data.download.file_type);
- e = xwimpspriteop_select_sprite(g->data.download.sprite_name, 0);
- if (e)
- strcpy(g->data.download.sprite_name, "file_xxx");
+ sizeof dw->url;
+
+ download_template->icons[ICON_DOWNLOAD_STATUS].data.indirected_text.
+ text = dw->status;
+ download_template->icons[ICON_DOWNLOAD_STATUS].data.indirected_text.
+ size = sizeof dw->status;
+
+ sprintf(dw->sprite_name, "file_%.3x", dw->file_type);
+ error = xwimpspriteop_select_sprite(dw->sprite_name, 0);
+ if (error) {
+ if (error->errnum != error_SPRITE_OP_DOESNT_EXIST) {
+ LOG(("xwimpspriteop_select_sprite: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("MiscError", error->errmess);
+ }
+ strcpy(dw->sprite_name, "file_xxx");
+ }
download_template->icons[ICON_DOWNLOAD_ICON].data.indirected_sprite.id =
- (osspriteop_id) g->data.download.sprite_name;
- strcpy(g->data.download.path, messages_get("SaveObject"));
- if ((nice = url_nice(content->url))) {
- strcpy(g->data.download.path, nice);
+ (osspriteop_id) dw->sprite_name;
+
+ strcpy(dw->path, messages_get("SaveObject"));
+ if ((nice = url_nice(url))) {
+ strcpy(dw->path, nice);
free(nice);
}
download_template->icons[ICON_DOWNLOAD_PATH].data.indirected_text.text =
- g->data.download.path;
+ dw->path;
download_template->icons[ICON_DOWNLOAD_PATH].data.indirected_text.size =
- 256;
+ sizeof dw->path;
+
+ download_template->icons[ICON_DOWNLOAD_DESTINATION].data.
+ indirected_text.text = dw->path;
+ download_template->icons[ICON_DOWNLOAD_DESTINATION].data.
+ indirected_text.size = sizeof dw->path;
+
+ download_template->icons[ICON_DOWNLOAD_DESTINATION].flags |=
+ wimp_ICON_DELETED;
/* create and open the download window */
- g->window = wimp_create_window(download_template);
- ro_gui_dialog_open(g->window);
+ error = xwimp_create_window(download_template, &dw->window);
+ if (error) {
+ LOG(("xwimp_create_window: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ free(dw);
+ return 0;
+ }
+
+ dw->prev = 0;
+ dw->next = download_window_list;
+ download_window_list = dw;
+
+ ro_gui_download_update_status(dw);
+
+ ro_gui_dialog_open(dw->window);
- g->data.download.download_status = download_INCOMPLETE;
+ return dw;
+}
+
+
+/**
+ * Handle received download data.
+ *
+ * \param dw download window
+ * \param data pointer to block of data received
+ * \param size size of data
+ */
+
+void gui_download_window_data(struct gui_download_window *dw, const char *data,
+ unsigned int size)
+{
+ int unwritten;
+ os_error *error;
+
+ error = xosgbpb_writew(dw->file, data, size, &unwritten);
+ if (error) {
+ LOG(("xosgbpb_writew: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ fetch_abort(dw->fetch);
+ gui_download_window_error(dw, error->errmess);
+ return;
+ }
+ if (unwritten) {
+ LOG(("xosgbpb_writew: unwritten %i", unwritten));
+ warn_user("SaveError", messages_get("Unwritten"));
+ fetch_abort(dw->fetch);
+ gui_download_window_error(dw, messages_get("Unwritten"));
+ return;
+ }
+
+ dw->received += size;
+}
+
+
+/**
+ * Update the status text and progress bar.
+ *
+ * \param dw download window
+ */
+
+void ro_gui_download_update_status(struct gui_download_window *dw)
+{
+ char *received;
+ char *total_size;
+ char *speed;
+ char time[20] = "?";
+ float f = 0;
+ struct timeval t;
+ float dt;
+ unsigned int left;
+ float rate;
+ os_error *error;
+
+ gettimeofday(&t, 0);
+ dt = (t.tv_sec + 0.000001 * t.tv_usec) - (dw->last_time.tv_sec +
+ 0.000001 * dw->last_time.tv_usec);
+ if (dt == 0)
+ dt = 0.001;
+
+ total_size = human_friendly_bytesize(dw->total_size);
+
+ if (dw->fetch) {
+ rate = (dw->received - dw->last_received) / dt;
+ received = human_friendly_bytesize(dw->received);
+ speed = human_friendly_bytesize(rate);
+ if (dw->total_size) {
+ if (rate) {
+ left = (dw->total_size - dw->received) / rate;
+ sprintf(time, "%u:%.2u", left / 60, left % 60);
+ }
+ snprintf(dw->status, sizeof dw->status,
+ messages_get("Download"),
+ received, total_size, speed, time);
+ } else {
+ left = t.tv_sec - dw->start_time.tv_sec;
+ sprintf(time, "%u:%.2u", left / 60, left % 60);
+ snprintf(dw->status, sizeof dw->status,
+ messages_get("DownloadU"),
+ received, speed, time);
+ }
+ } else {
+ left = dw->last_time.tv_sec - dw->start_time.tv_sec;
+ rate = (float) dw->received / (float) left;
+ sprintf(time, "%u:%.2u", left / 60, left % 60);
+ speed = human_friendly_bytesize(rate);
+ snprintf(dw->status, sizeof dw->status,
+ messages_get("Downloaded"),
+ total_size, speed, time);
+ }
+
+ dw->last_time = t;
+ dw->last_received = dw->received;
+
+ if (dw->total_size)
+ f = (float) dw->received /
+ (float) dw->total_size;
+ error = xwimp_resize_icon(dw->window, ICON_DOWNLOAD_PROGRESS,
+ download_progress_x0,
+ download_progress_y0,
+ download_progress_x0 + download_progress_width * f,
+ download_progress_y1);
+ if (error) {
+ LOG(("xwimp_resize_icon: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_STATUS, 0, 0);
+ if (error) {
+ LOG(("xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
- g->next = window_list;
- window_list = g;
- return g;
+ if (dw->fetch)
+ schedule(100, ro_gui_download_update_status_wrapper, dw);
+ else
+ schedule_remove(ro_gui_download_update_status_wrapper, dw);
}
/**
- * Refresh the status icon in the download window.
+ * Wrapper for ro_gui_download_update_status(), suitable for schedule().
*/
-void gui_download_window_update_status(gui_window *g)
+void ro_gui_download_update_status_wrapper(void *p)
{
- strncpy(g->status, g->data.download.content->status_message, 256);
- wimp_set_icon_state(g->window,
- ICON_DOWNLOAD_STATUS, 0, 0);
+ ro_gui_download_update_status((struct gui_download_window *) p);
}
/**
* Handle failed downloads.
+ *
+ * \param dw download window
+ * \param error_msg error message
*/
-void gui_download_window_error(gui_window *g, const char *error)
+void gui_download_window_error(struct gui_download_window *dw,
+ const char *error_msg)
{
- g->data.download.content = 0;
+ os_error *error;
+
+ dw->fetch = 0;
+ dw->error = true;
+
+ schedule_remove(ro_gui_download_update_status_wrapper, dw);
/* place error message in status icon in red */
- strncpy(g->status, error, 256);
- wimp_set_icon_state(g->window,
+ strncpy(dw->status, error_msg, sizeof dw->status);
+ error = xwimp_set_icon_state(dw->window,
ICON_DOWNLOAD_STATUS,
wimp_COLOUR_RED << wimp_ICON_FG_COLOUR_SHIFT,
wimp_ICON_FG_COLOUR);
+ if (error) {
+ LOG(("xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
- /* grey out file and pathname icons */
- wimp_set_icon_state(g->window,
- ICON_DOWNLOAD_ICON, wimp_ICON_SHADED, 0);
- wimp_set_icon_state(g->window,
- ICON_DOWNLOAD_PATH, wimp_ICON_SHADED, 0);
-
- g->data.download.download_status = download_ERROR;
+ /* grey out pathname icon */
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_PATH,
+ wimp_ICON_SHADED, 0);
+ if (error) {
+ LOG(("xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
}
/**
* Handle completed downloads.
+ *
+ * \param dw download window
*/
-void gui_download_window_done(gui_window *g)
+void gui_download_window_done(struct gui_download_window *dw)
{
- snprintf(g->status, 256, messages_get("Downloaded"),
- human_friendly_bytesize(g->data.download.content->source_size));
- wimp_set_icon_state(g->window,
- ICON_DOWNLOAD_STATUS, 0, 0);
-
- // clear shaded path and icon icons
- wimp_set_icon_state(g->window,
- ICON_DOWNLOAD_ICON, 0, wimp_ICON_SHADED);
- wimp_set_icon_state(g->window,
- ICON_DOWNLOAD_PATH, 0, wimp_ICON_SHADED);
-
- g->data.download.download_status = download_COMPLETE;
+ os_error *error;
+
+ dw->fetch = 0;
+ ro_gui_download_update_status(dw);
+
+ error = xosfind_closew(dw->file);
+ if (error) {
+ LOG(("xosfind_closew: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ }
+ dw->file = 0;
+
+ if (dw->saved) {
+ error = xosfile_set_type(dw->path,
+ dw->file_type);
+ if (error) {
+ LOG(("xosfile_set_type: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ }
+
+ schedule(200, ro_gui_download_window_destroy_wrapper, dw);
+ }
}
/**
- * Handle clicks in a download window.
+ * Convert a RISC OS window handle to a gui_download_window.
+ *
+ * \param w RISC OS window handle
+ * \return pointer to a structure if found, 0 otherwise
*/
-void ro_download_window_click(struct gui_window *g, wimp_pointer *pointer)
+struct gui_download_window * ro_gui_download_window_lookup(wimp_w w)
{
- switch (pointer->i) {
- case ICON_DOWNLOAD_ABORT:
- if (g->data.download.download_status ==
- download_INCOMPLETE)
- fetch_abort(g->data.download.content->fetch);
-
- ro_download_window_close(g);
- break;
-
- case ICON_DOWNLOAD_ICON:
- if (g->data.download.download_status ==
- download_COMPLETE) {
- gui_current_drag_type = GUI_DRAG_DOWNLOAD_SAVE;
- current_gui = g;
- ro_gui_drag_icon(pointer);
+ struct gui_download_window *dw;
+ for (dw = download_window_list; dw; dw = dw->next)
+ if (dw->window == w)
+ return dw;
+ return 0;
+}
+
+
+/**
+ * Handle Mouse_Click events in a download window.
+ *
+ * \param dw download window
+ * \param pointer block returned by Wimp_Poll
+ */
+
+void ro_gui_download_window_click(struct gui_download_window *dw,
+ wimp_pointer *pointer)
+{
+ char command[256] = "Filer_OpenDir ";
+ char *dot;
+ os_error *error;
+
+ if (pointer->i == ICON_DOWNLOAD_ICON && !dw->error &&
+ !dw->saved) {
+ gui_current_drag_type = GUI_DRAG_DOWNLOAD_SAVE;
+ download_window_current = dw;
+ ro_gui_drag_icon(pointer);
+
+ } else if (pointer->i == ICON_DOWNLOAD_DESTINATION) {
+ strncpy(command + 14, dw->path, 242);
+ command[255] = 0;
+ dot = strrchr(command, '.');
+ if (dot) {
+ *dot = 0;
+ error = xos_cli(command);
+ if (error) {
+ LOG(("xos_cli: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("MiscError", error->errmess);
}
- break;
+ }
}
}
/**
* Handle User_Drag_Box event for a drag from a download window.
+ *
+ * \param drag block returned by Wimp_Poll
*/
-void ro_download_drag_end(wimp_dragged *drag)
+void ro_gui_download_drag_end(wimp_dragged *drag)
{
wimp_pointer pointer;
wimp_message message;
+ struct gui_download_window *dw = download_window_current;
+ os_error *error;
- wimp_get_pointer_info(&pointer);
+ if (dw->saved || dw->error)
+ return;
+
+ error = xwimp_get_pointer_info(&pointer);
+ if (error) {
+ LOG(("xwimp_get_pointer_info: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ return;
+ }
message.your_ref = 0;
message.action = message_DATA_SAVE;
@@ -196,71 +524,230 @@ void ro_download_drag_end(wimp_dragged *drag)
message.data.data_xfer.i = pointer.i;
message.data.data_xfer.pos.x = pointer.pos.x;
message.data.data_xfer.pos.y = pointer.pos.y;
- message.data.data_xfer.est_size = (int)
- current_gui->data.download.content->source_size;
- message.data.data_xfer.file_type = current_gui->data.download.file_type;
- strncpy(message.data.data_xfer.file_name,
- current_gui->data.download.path, 212);
+ message.data.data_xfer.est_size = dw->total_size ? dw->total_size :
+ dw->received;
+ message.data.data_xfer.file_type = dw->file_type;
+ strncpy(message.data.data_xfer.file_name, dw->path, 212);
message.size = 44 + ((strlen(message.data.data_xfer.file_name) + 4) &
(~3u));
- wimp_send_message_to_window(wimp_USER_MESSAGE, &message,
- pointer.w, pointer.i);
+ error = xwimp_send_message_to_window(wimp_USER_MESSAGE, &message,
+ pointer.w, pointer.i, 0);
+ if (error) {
+ LOG(("xwimp_send_message_to_window: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
}
/**
* Handle Message_DataSaveAck for a drag from a download window.
+ *
+ * \param message block returned by Wimp_Poll
*/
-void ro_download_datasave_ack(wimp_message *message)
+void ro_gui_download_datasave_ack(wimp_message *message)
{
- char *data;
- char *data_end;
+ char temp_name[40];
+ char *file_name;
+ struct gui_download_window *dw = download_window_current;
os_error *error;
- assert(current_gui->data.download.download_status == download_COMPLETE);
+ if (dw->saved || dw->error)
+ return;
- data = current_gui->data.download.content->source_data;
- data_end = data + current_gui->data.download.content->source_size;
+ file_name = message->data.data_xfer.file_name;
+ snprintf(temp_name, sizeof temp_name, "<Wimp$ScrapDir>.ns%x",
+ (unsigned int) dw);
+
+ /* close temporary file */
+ if (dw->file) {
+ error = xosfind_closew(dw->file);
+ dw->file = 0;
+ if (error) {
+ LOG(("xosfind_closew: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ if (dw->fetch)
+ fetch_abort(dw->fetch);
+ gui_download_window_error(dw, error->errmess);
+ return;
+ }
+ }
- error = xosfile_save_stamped(message->data.data_xfer.file_name,
- current_gui->data.download.file_type,
- data, data_end);
- if (error) {
- LOG(("0x%x: %s\n", error->errnum, error->errmess));
+ /* move or copy temporary file to destination file */
+ error = xosfscontrol_rename(temp_name, file_name);
+ if (error && error->errnum == error_BAD_RENAME) {
+ /* rename failed: copy with delete */
+ error = xosfscontrol_copy(temp_name, file_name,
+ osfscontrol_COPY_FORCE |
+ osfscontrol_COPY_DELETE |
+ osfscontrol_COPY_LOOK,
+ 0, 0, 0, 0, 0);
+ if (error) {
+ LOG(("xosfscontrol_copy: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ if (dw->fetch)
+ fetch_abort(dw->fetch);
+ gui_download_window_error(dw, error->errmess);
+ return;
+ }
+ } else if (error) {
+ LOG(("xosfscontrol_rename: 0x%x: %s",
+ error->errnum, error->errmess));
warn_user("SaveError", error->errmess);
+ if (dw->fetch)
+ fetch_abort(dw->fetch);
+ gui_download_window_error(dw, error->errmess);
return;
}
+ if (dw->fetch) {
+ /* open new destination file if still fetching */
+ error = xosfile_write(file_name, 0xdeaddead, 0xdeaddead,
+ fileswitch_ATTR_OWNER_READ |
+ fileswitch_ATTR_OWNER_WRITE);
+ if (error) {
+ LOG(("xosfile_write: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ }
+
+ error = xosfind_openupw(osfind_NO_PATH | osfind_ERROR_IF_DIR,
+ file_name, 0, &dw->file);
+ if (error) {
+ LOG(("xosfind_openupw: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ if (dw->fetch)
+ fetch_abort(dw->fetch);
+ gui_download_window_error(dw, error->errmess);
+ return;
+ }
+
+ error = xosargs_set_ptrw(dw->file, dw->received);
+ if (error) {
+ LOG(("xosargs_set_ptrw: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ if (dw->fetch)
+ fetch_abort(dw->fetch);
+ gui_download_window_error(dw, error->errmess);
+ return;
+ }
+
+ } else {
+ /* otherwise just set the file type */
+ error = xosfile_set_type(file_name,
+ dw->file_type);
+ if (error) {
+ LOG(("xosfile_set_type: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ }
+ }
+
+ dw->saved = true;
+ strncpy(dw->path, file_name, sizeof dw->path);
+
+ /* hide writeable path icon and show destination icon */
+ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_PATH,
+ wimp_ICON_DELETED, wimp_ICON_DELETED);
+ if (error) {
+ LOG(("xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+ error = xwimp_set_icon_state(dw->window,
+ ICON_DOWNLOAD_DESTINATION, 0, wimp_ICON_DELETED);
+ if (error) {
+ LOG(("xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+
/* Ack successful save with message_DATA_LOAD */
message->action = message_DATA_LOAD;
message->your_ref = message->my_ref;
- wimp_send_message_to_window(wimp_USER_MESSAGE, message, message->data.data_xfer.w, message->data.data_xfer.i);
+ error = xwimp_send_message_to_window(wimp_USER_MESSAGE, message,
+ message->data.data_xfer.w,
+ message->data.data_xfer.i, 0);
+ if (error) {
+ LOG(("xwimp_set_icon_state: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
- ro_download_window_close(current_gui);
+ if (!dw->fetch)
+ schedule(200, ro_gui_download_window_destroy_wrapper, dw);
}
-struct gui_window * ro_lookup_download_window_from_w(wimp_w window)
+/**
+ * Close a download window and free any related resources.
+ *
+ * \param dw download window
+ */
+
+void ro_gui_download_window_destroy(struct gui_download_window *dw)
{
- gui_window* g;
- for (g = window_list; g != NULL; g = g->next)
- {
- if (g->type == GUI_DOWNLOAD_WINDOW)
- {
- if (g->window == window)
- {
- return g;
- }
- }
- }
- return NULL;
+ char temp_name[40];
+ os_error *error;
+
+ schedule_remove(ro_gui_download_update_status_wrapper, dw);
+
+ /* remove from list */
+ if (dw->prev)
+ dw->prev->next = dw->next;
+ else
+ download_window_list = dw->next;
+ if (dw->next)
+ dw->next->prev = dw->prev;
+
+ /* delete window */
+ error = xwimp_delete_window(dw->window);
+ if (error) {
+ LOG(("xwimp_delete_window: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+
+ /* close download file */
+ if (dw->file) {
+ error = xosfind_closew(dw->file);
+ if (error) {
+ LOG(("xosfind_closew: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ }
+ }
+
+ /* delete temporary file */
+ if (!dw->saved) {
+ snprintf(temp_name, sizeof temp_name, "<Wimp$ScrapDir>.ns%x",
+ (unsigned int) dw);
+ error = xosfile_delete(temp_name, 0, 0, 0, 0, 0);
+ if (error) {
+ LOG(("xosfile_delete: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ }
+ }
+
+ if (dw->fetch)
+ fetch_abort(dw->fetch);
+
+ free(dw);
}
-void ro_download_window_close(struct gui_window *g)
-{
- // free contexts etc???
- wimp_close_window(g->window);
+/**
+ * Wrapper for ro_gui_download_window_destroy(), suitable for schedule().
+ */
+
+void ro_gui_download_window_destroy_wrapper(void *p)
+{
+ ro_gui_download_window_destroy((struct gui_download_window *) p);
}
diff --git a/riscos/gui.c b/riscos/gui.c
index 7ce5a3f89..b60f52ab6 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -660,17 +660,15 @@ void ro_gui_open_window_request(wimp_open *open)
void ro_gui_close_window_request(wimp_close *close)
{
gui_window *g;
+ struct gui_download_window *dw;
- if (close->w == dialog_debug) {
+ if (close->w == dialog_debug)
ro_gui_debugwin_close();
- return;
- }
-
- g = ro_lookup_gui_from_w(close->w);
-
- if (g) {
+ else if ((g = ro_gui_window_lookup(close->w)))
browser_window_destroy(g->data.browser.bw);
- } else
+ else if ((dw = ro_gui_download_window_lookup(close->w)))
+ ro_gui_download_window_destroy(dw);
+ else
ro_gui_dialog_close(close->w);
}
@@ -682,6 +680,7 @@ void ro_gui_close_window_request(wimp_close *close)
void ro_gui_mouse_click(wimp_pointer *pointer)
{
gui_window *g = ro_gui_window_lookup(pointer->w);
+ struct gui_download_window *dw;
if (pointer->w == wimp_ICON_BAR)
ro_gui_icon_bar_click(pointer);
@@ -695,8 +694,8 @@ void ro_gui_mouse_click(wimp_pointer *pointer)
else if (g && g->type == GUI_BROWSER_WINDOW &&
g->data.browser.toolbar->status_handle == pointer->w)
ro_gui_status_click(g, pointer);
- else if (g && g->type == GUI_DOWNLOAD_WINDOW)
- ro_download_window_click(g, pointer);
+ else if ((dw = ro_gui_download_window_lookup(pointer->w)))
+ ro_gui_download_window_click(dw, pointer);
else if (pointer->w == dialog_saveas)
ro_gui_save_click(pointer);
else
@@ -739,7 +738,7 @@ void ro_gui_drag_end(wimp_dragged *drag)
break;
case GUI_DRAG_DOWNLOAD_SAVE:
- ro_download_drag_end(drag);
+ ro_gui_download_drag_end(drag);
break;
case GUI_DRAG_SAVE:
@@ -774,9 +773,6 @@ void ro_gui_keypress(wimp_key *key)
handled = ro_gui_window_keypress(g, key->c,
(bool) (g->data.browser.toolbar->toolbar_handle == key->w));
break;
-
- case GUI_DOWNLOAD_WINDOW:
- break;
}
if (!handled)
@@ -1140,7 +1136,7 @@ void ro_msg_datasave_ack(wimp_message *message)
{
switch (gui_current_drag_type) {
case GUI_DRAG_DOWNLOAD_SAVE:
- ro_download_datasave_ack(message);
+ ro_gui_download_datasave_ack(message);
break;
case GUI_DRAG_SAVE:
diff --git a/riscos/gui.h b/riscos/gui.h
index d8e07e79f..38fae3396 100644
--- a/riscos/gui.h
+++ b/riscos/gui.h
@@ -37,7 +37,7 @@ extern gui_window *current_gui;
extern gui_window *ro_gui_current_redraw_gui;
extern osspriteop_area *gui_pointers;
-typedef enum { GUI_BROWSER_WINDOW, GUI_DOWNLOAD_WINDOW } gui_window_type;
+typedef enum { GUI_BROWSER_WINDOW } gui_window_type;
typedef enum { GUI_SAVE_SOURCE, GUI_SAVE_DRAW, GUI_SAVE_TEXT,
GUI_SAVE_COMPLETE,
GUI_SAVE_OBJECT_ORIG, GUI_SAVE_OBJECT_NATIVE,
@@ -48,44 +48,33 @@ typedef enum { GUI_DRAG_SELECTION, GUI_DRAG_DOWNLOAD_SAVE,
GUI_DRAG_SAVE, GUI_DRAG_STATUS_RESIZE } gui_drag_type;
extern gui_drag_type gui_current_drag_type;
-struct gui_window
-{
- gui_window_type type;
-
- wimp_w window;
-
- union {
- struct {
- struct toolbar *toolbar;
- int toolbar_width;
- struct browser_window* bw;
- bool reformat_pending;
- int old_width;
- int old_height;
- } browser;
- struct {
- struct content *content;
- bits file_type;
- char sprite_name[20];
- char path[256];
- enum {
- download_COMPLETE,
- download_INCOMPLETE,
- download_ERROR
- } download_status;
- } download;
- } data;
-
- char status[256];
- char title[256];
- char url[256];
- gui_window* next;
-
- int throbber;
- char throb_buf[12];
- float throbtime;
-
- enum { drag_NONE, drag_UNKNOWN, drag_BROWSER_TEXT_SELECTION } drag_status;
+struct gui_window {
+ gui_window_type type;
+
+ wimp_w window;
+
+ union {
+ struct {
+ struct toolbar *toolbar;
+ int toolbar_width;
+ struct browser_window* bw;
+ bool reformat_pending;
+ int old_width;
+ int old_height;
+ } browser;
+ } data;
+
+ char status[256];
+ char title[256];
+ char url[256];
+ gui_window *next;
+
+ int throbber;
+ char throb_buf[12];
+ float throbtime;
+
+ enum { drag_NONE, drag_UNKNOWN, drag_BROWSER_TEXT_SELECTION }
+ drag_status;
/* Options
*/
@@ -132,11 +121,12 @@ void ro_gui_redraw_config_th_pane(wimp_draw *redraw);
/* in download.c */
void ro_gui_download_init(void);
-void ro_download_window_close(struct gui_window *g);
-struct gui_window * ro_lookup_download_window_from_w(wimp_w window);
-void ro_download_window_click(struct gui_window *g, wimp_pointer *pointer);
-void ro_download_drag_end(wimp_dragged *drag);
-void ro_download_datasave_ack(wimp_message *message);
+struct gui_download_window * ro_gui_download_window_lookup(wimp_w w);
+void ro_gui_download_window_click(struct gui_download_window *dw,
+ wimp_pointer *pointer);
+void ro_gui_download_drag_end(wimp_dragged *drag);
+void ro_gui_download_datasave_ack(wimp_message *message);
+void ro_gui_download_window_destroy(struct gui_download_window *dw);
/* in mouseactions.c */
void ro_gui_mouse_action(gui_window* g);
@@ -253,11 +243,12 @@ void ro_gui_debugwin_redraw(wimp_draw *redraw);
#define ICON_CONFIG_TH_GET 2
#define ICON_CONFIG_TH_MANAGE 3
-#define ICON_DOWNLOAD_URL 0
-#define ICON_DOWNLOAD_STATUS 1
-#define ICON_DOWNLOAD_ICON 2
-#define ICON_DOWNLOAD_PATH 3
-#define ICON_DOWNLOAD_ABORT 4
+#define ICON_DOWNLOAD_ICON 0
+#define ICON_DOWNLOAD_URL 1
+#define ICON_DOWNLOAD_PATH 2
+#define ICON_DOWNLOAD_DESTINATION 3
+#define ICON_DOWNLOAD_PROGRESS 5
+#define ICON_DOWNLOAD_STATUS 6
#define ICON_401LOGIN_LOGIN 0
#define ICON_401LOGIN_CANCEL 1
diff --git a/utils/utils.c b/utils/utils.c
index 92f064bc4..ca33051cf 100644
--- a/utils/utils.c
+++ b/utils/utils.c
@@ -308,7 +308,7 @@ void clean_cookiejar(void) {
/**
* Does a simple conversion which assumes the user speaks English. The buffer
- * returned is one of two static ones so may change each time this call is
+ * returned is one of three static ones so may change each time this call is
* made. Don't store the buffer for later use. It's done this way for
* convenience and to fight possible memory leaks, it is not necessarily pretty.
**/
@@ -316,12 +316,15 @@ void clean_cookiejar(void) {
char *human_friendly_bytesize(unsigned long bsize) {
static char buffer1[BYTESIZE_BUFFER_SIZE];
static char buffer2[BYTESIZE_BUFFER_SIZE];
- static char *curbuffer = buffer2;
+ static char buffer3[BYTESIZE_BUFFER_SIZE];
+ static char *curbuffer = buffer3;
float bytesize = (float)bsize;
if (curbuffer == buffer1)
curbuffer = buffer2;
+ else if (curbuffer == buffer2)
+ curbuffer = buffer3;
else
curbuffer = buffer1;