mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
bug 1054: Don't abort downloads when closing a terminal.
Except if they have external handlers. When ELinks receives an event from a terminal, move that terminal to the beginning of the global "terminals" list, so that the terminals are always sorted according to the time of the most recent use. Note, this affects the numbering of bookmark folders in session snapshots. Add get_default_terminal(), which returns the most recently used terminal that is still open. Use that in various places that previously used terminals.prev or terminals.next. Four functions fetch the size of the terminal for User-Agent headers, and get_default_terminal() is not really right, but neither was the original code; add TODO comments in those functions. When the user chooses "Background and Notify", associate the download with the terminal where the dialog box is. So any later messages will then appear in that terminal, if it is still open. However, don't change the terminal if the download has an external handler. When a download gets some data, don't immediately check the associated terminal. Instead, wait for the download to end. Then, if the terminal of the download has been closed, use get_default_terminal() instead. If there is no default terminal either, just skip any message boxes.
This commit is contained in:
parent
9c17d8e805
commit
84e19d0e4e
6
NEWS
6
NEWS
@ -33,6 +33,12 @@ Miscellaneous:
|
||||
cached response even if you have modified a file between requests,
|
||||
and that ELinks can send inconsistent data if you modify a file
|
||||
while it is being uploaded.
|
||||
* bug 1054: Don't abort downloads when closing the terminal from which
|
||||
they were started. When such a download ends, display the message
|
||||
in the most recently used terminal. If the user chooses
|
||||
``Background and Notify'' via the download manager in some terminal,
|
||||
reassociate the download with that terminal. These changes do not
|
||||
apply to downloads to external handlers.
|
||||
* Really retry forever when connection.retries = 0.
|
||||
* enhancement: Session-specific options. Any options changed with
|
||||
toggle-* actions no longer affect other tabs or other terminals.
|
||||
|
@ -61,6 +61,15 @@ dlg_set_notify(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
||||
struct file_download *file_download = dlg_data->dlg->udata;
|
||||
|
||||
file_download->notify = 1;
|
||||
/* The user of this terminal wants to be notified about the
|
||||
* download. Make this also the terminal where the
|
||||
* notification appears. However, keep the original terminal
|
||||
* for external handlers, because the handler may have been
|
||||
* chosen based on the environment variables (usually TERM or
|
||||
* DISPLAY) of the ELinks process in that terminal. */
|
||||
if (!file_download->external_handler)
|
||||
file_download->term = dlg_data->win->term;
|
||||
|
||||
#if CONFIG_BITTORRENT
|
||||
if (file_download->uri->protocol == PROTOCOL_BITTORRENT)
|
||||
set_bittorrent_notify_on_completion(&file_download->download,
|
||||
|
@ -96,10 +96,12 @@ navigator_get(struct SEE_interpreter *interp, struct SEE_object *o,
|
||||
if (*optstr && strcmp(optstr, " ")) {
|
||||
unsigned char *ustr, ts[64] = "";
|
||||
static unsigned char custr[256];
|
||||
/* TODO: Somehow get the terminal in which the
|
||||
* document is actually being displayed. */
|
||||
struct terminal *term = get_default_terminal();
|
||||
|
||||
if (!list_empty(terminals)) {
|
||||
if (term) {
|
||||
unsigned int tslen = 0;
|
||||
struct terminal *term = terminals.prev;
|
||||
|
||||
ulongcat(ts, &tslen, term->width, 3, 0);
|
||||
ts[tslen++] = 'x';
|
||||
|
@ -119,10 +119,12 @@ navigator_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
if (*optstr && strcmp(optstr, " ")) {
|
||||
unsigned char *ustr, ts[64] = "";
|
||||
static unsigned char custr[256];
|
||||
/* TODO: Somehow get the terminal in which the
|
||||
* document is actually being displayed. */
|
||||
struct terminal *term = get_default_terminal();
|
||||
|
||||
if (!list_empty(terminals)) {
|
||||
if (term) {
|
||||
unsigned int tslen = 0;
|
||||
struct terminal *term = terminals.prev;
|
||||
|
||||
ulongcat(ts, &tslen, term->width, 3, 0);
|
||||
ts[tslen++] = 'x';
|
||||
|
@ -182,10 +182,12 @@ set_vars(struct connection *conn, unsigned char *script)
|
||||
str = get_opt_str("protocol.http.user_agent", NULL);
|
||||
if (*str && strcmp(str, " ")) {
|
||||
unsigned char *ustr, ts[64] = "";
|
||||
/* TODO: Somehow get the terminal in which the
|
||||
* document will actually be displayed. */
|
||||
struct terminal *term = get_default_terminal();
|
||||
|
||||
if (!list_empty(terminals)) {
|
||||
if (term) {
|
||||
unsigned int tslen = 0;
|
||||
struct terminal *term = terminals.prev;
|
||||
|
||||
ulongcat(ts, &tslen, term->width, 3, 0);
|
||||
ts[tslen++] = 'x';
|
||||
|
@ -761,12 +761,14 @@ http_send_header(struct socket *socket)
|
||||
optstr = get_opt_str("protocol.http.user_agent", NULL);
|
||||
if (*optstr && strcmp(optstr, " ")) {
|
||||
unsigned char *ustr, ts[64] = "";
|
||||
/* TODO: Somehow get the terminal in which the
|
||||
* document will actually be displayed. */
|
||||
struct terminal *term = get_default_terminal();
|
||||
|
||||
add_to_string(&header, "User-Agent: ");
|
||||
|
||||
if (!list_empty(terminals)) {
|
||||
if (term) {
|
||||
unsigned int tslen = 0;
|
||||
struct terminal *term = terminals.prev;
|
||||
|
||||
ulongcat(ts, &tslen, term->width, 3, 0);
|
||||
ts[tslen++] = 'x';
|
||||
|
@ -113,6 +113,7 @@ static VALUE
|
||||
erb_module_message(VALUE self, VALUE str)
|
||||
{
|
||||
unsigned char *message, *line_end;
|
||||
struct terminal *term;
|
||||
|
||||
str = rb_obj_as_string(str);
|
||||
message = memacpy(RSTRING(str)->ptr, RSTRING(str)->len);
|
||||
@ -121,13 +122,14 @@ erb_module_message(VALUE self, VALUE str)
|
||||
line_end = strchr(message, '\n');
|
||||
if (line_end) *line_end = '\0';
|
||||
|
||||
if (list_empty(terminals)) {
|
||||
term = get_default_terminal();
|
||||
if (!term) {
|
||||
usrerror("[Ruby] %s", message);
|
||||
mem_free(message);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
info_box(terminals.next, MSGBOX_NO_TEXT_INTL | MSGBOX_FREE_TEXT,
|
||||
info_box(term, MSGBOX_NO_TEXT_INTL | MSGBOX_FREE_TEXT,
|
||||
N_("Ruby Message"), ALIGN_LEFT, message);
|
||||
|
||||
return Qnil;
|
||||
@ -144,6 +146,7 @@ erb_stdout_p(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
int i;
|
||||
struct string string;
|
||||
struct terminal *term;
|
||||
|
||||
if (!init_string(&string))
|
||||
return Qnil;
|
||||
@ -174,13 +177,14 @@ erb_stdout_p(int argc, VALUE *argv, VALUE self)
|
||||
add_bytes_to_string(&string, ptr, len);
|
||||
}
|
||||
|
||||
if (list_empty(terminals)) {
|
||||
term = get_default_terminal();
|
||||
if (!term) {
|
||||
usrerror("[Ruby] %s", string.source);
|
||||
done_string(&string);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
info_box(terminals.next, MSGBOX_NO_TEXT_INTL | MSGBOX_FREE_TEXT,
|
||||
info_box(term, MSGBOX_NO_TEXT_INTL | MSGBOX_FREE_TEXT,
|
||||
N_("Ruby Message"), ALIGN_LEFT, string.source);
|
||||
|
||||
return Qnil;
|
||||
|
@ -40,15 +40,14 @@ report_scripting_error(struct module *module, struct session *ses,
|
||||
struct string string;
|
||||
|
||||
if (!ses) {
|
||||
if (list_empty(terminals)) {
|
||||
term = get_default_terminal();
|
||||
if (term == NULL) {
|
||||
usrerror(gettext("[%s error] %s"),
|
||||
gettext(module->name), msg);
|
||||
sleep(3);
|
||||
return;
|
||||
}
|
||||
|
||||
term = terminals.next;
|
||||
|
||||
} else {
|
||||
term = ses->tab->term;
|
||||
}
|
||||
|
@ -332,35 +332,46 @@ download_data_store(struct download *download, struct file_download *file_downlo
|
||||
assert_terminal_ptr_not_dangling(term);
|
||||
if_assert_failed term = file_download->term = NULL;
|
||||
|
||||
if (!term) {
|
||||
/* No term here, so no beep. --Zas */
|
||||
abort_download(file_download);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_in_progress_state(download->state)) {
|
||||
if (file_download->dlg_data)
|
||||
redraw_dialog(file_download->dlg_data, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the original terminal of the download has been closed,
|
||||
* display any messages in the default terminal instead. */
|
||||
if (term == NULL)
|
||||
term = get_default_terminal(); /* may be NULL too */
|
||||
|
||||
if (!is_in_state(download->state, S_OK)) {
|
||||
unsigned char *url = get_uri_string(file_download->uri, URI_PUBLIC);
|
||||
struct connection_state state = download->state;
|
||||
|
||||
/* abort_download_and_beep allows term==NULL. */
|
||||
abort_download_and_beep(file_download, term);
|
||||
|
||||
if (!url) return;
|
||||
|
||||
info_box(term, MSGBOX_FREE_TEXT,
|
||||
N_("Download error"), ALIGN_CENTER,
|
||||
msg_text(term, N_("Error downloading %s:\n\n%s"),
|
||||
url, get_state_message(state, term)));
|
||||
if (term) {
|
||||
info_box(term, MSGBOX_FREE_TEXT,
|
||||
N_("Download error"), ALIGN_CENTER,
|
||||
msg_text(term, N_("Error downloading %s:\n\n%s"),
|
||||
url, get_state_message(state, term)));
|
||||
}
|
||||
mem_free(url);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_download->external_handler) {
|
||||
if (term == NULL) {
|
||||
/* There is no terminal in which to run the handler.
|
||||
* Abort the download. file_download->delete should
|
||||
* be 1 here so that the following call also deletes
|
||||
* the temporary file. */
|
||||
abort_download(file_download);
|
||||
return;
|
||||
}
|
||||
|
||||
prealloc_truncate(file_download->handle, file_download->seek);
|
||||
close(file_download->handle);
|
||||
file_download->handle = -1;
|
||||
@ -372,7 +383,7 @@ download_data_store(struct download *download, struct file_download *file_downlo
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_download->notify) {
|
||||
if (file_download->notify && term) {
|
||||
unsigned char *url = get_uri_string(file_download->uri, URI_PUBLIC);
|
||||
|
||||
/* This is apparently a little racy. Deleting the box item will
|
||||
@ -399,6 +410,7 @@ download_data_store(struct download *download, struct file_download *file_downlo
|
||||
utime(file_download->file, &foo);
|
||||
}
|
||||
|
||||
/* abort_download_and_beep allows term==NULL. */
|
||||
abort_download_and_beep(file_download, term);
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,17 @@ struct file_download {
|
||||
unsigned char *file;
|
||||
unsigned char *external_handler;
|
||||
struct session *ses;
|
||||
|
||||
/** The terminal in which message boxes about the download
|
||||
* should be displayed. If this terminal is closed, then
|
||||
* detach_downloads_from_terminal() changes the pointer to
|
||||
* NULL, and get_default_terminal() will be used if a
|
||||
* terminal is needed later. However, if the download has
|
||||
* an external handler, then detach_downloads_from_terminal()
|
||||
* aborts it right away; external handlers always run in the
|
||||
* original terminal, if anywhere. */
|
||||
struct terminal *term;
|
||||
|
||||
time_t remotetime;
|
||||
off_t seek;
|
||||
int handle;
|
||||
|
@ -468,6 +468,9 @@ in_term(struct terminal *term)
|
||||
ssize_t r;
|
||||
unsigned char *iq;
|
||||
|
||||
/* Mark this as the most recently used terminal. */
|
||||
move_to_top_of_list(terminals, term);
|
||||
|
||||
if (!interlink
|
||||
|| !interlink->qfreespace
|
||||
|| interlink->qfreespace - interlink->qlen > ALLOC_GR) {
|
||||
|
@ -68,6 +68,19 @@ cls_redraw_all_terminals(void)
|
||||
redraw_terminal_cls(term);
|
||||
}
|
||||
|
||||
/** Get the terminal in which message boxes should be displayed, if
|
||||
* there is no specific reason to use some other terminal. This
|
||||
* returns NULL if all terminals have been closed. (ELinks keeps
|
||||
* running anyway if ui.sessions.keep_session_active is true.) */
|
||||
struct terminal *
|
||||
get_default_terminal(void)
|
||||
{
|
||||
if (list_empty(terminals))
|
||||
return NULL;
|
||||
else
|
||||
return terminals.next;
|
||||
}
|
||||
|
||||
struct terminal *
|
||||
init_term(int fdin, int fdout)
|
||||
{
|
||||
@ -96,6 +109,8 @@ init_term(int fdin, int fdout)
|
||||
term->spec = get_opt_rec(config_options, name);
|
||||
object_lock(term->spec);
|
||||
|
||||
/* It's a new terminal, so assume the user is using it right now,
|
||||
* and sort it to the front of the list. */
|
||||
add_to_list(terminals, term);
|
||||
|
||||
set_handlers(fdin, (select_handler_T) in_term, NULL,
|
||||
|
@ -164,7 +164,10 @@ struct terminal {
|
||||
#define do_not_ignore_next_mouse_event(term) \
|
||||
memset(&(term)->prev_mouse_event, 0, sizeof((term)->prev_mouse_event))
|
||||
|
||||
/** We keep track about all the terminals in this list. */
|
||||
/** We keep track about all the terminals in this list.
|
||||
* The list is sorted so that terminals.next is the terminal
|
||||
* from which ELinks most recently got an event. But please
|
||||
* call get_default_terminal() for that. */
|
||||
extern LIST_OF(struct terminal) terminals;
|
||||
|
||||
|
||||
@ -175,6 +178,7 @@ void destroy_terminal(struct terminal *);
|
||||
void redraw_terminal(struct terminal *term);
|
||||
void redraw_terminal_cls(struct terminal *term);
|
||||
void cls_redraw_all_terminals(void);
|
||||
struct terminal *get_default_terminal(void);
|
||||
|
||||
void redraw_all_terminals(void);
|
||||
void destroy_all_terminals(void);
|
||||
|
Loading…
Reference in New Issue
Block a user