mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
579 lines
15 KiB
C
579 lines
15 KiB
C
/* Sessions status management */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include "elinks.h"
|
|
|
|
#include "bfu/dialog.h"
|
|
#include "cache/cache.h"
|
|
#include "config/options.h"
|
|
#include "dialogs/progress.h"
|
|
#include "dialogs/status.h"
|
|
#include "document/document.h"
|
|
#include "document/renderer.h"
|
|
#include "document/view.h"
|
|
#include "intl/libintl.h"
|
|
#include "network/connection.h"
|
|
#include "network/progress.h"
|
|
#include "network/state.h"
|
|
#include "protocol/bittorrent/dialogs.h"
|
|
#include "protocol/protocol.h"
|
|
#include "protocol/uri.h"
|
|
#include "session/download.h"
|
|
#include "session/session.h"
|
|
#include "terminal/draw.h"
|
|
#include "terminal/screen.h"
|
|
#include "terminal/tab.h"
|
|
#include "terminal/terminal.h"
|
|
#include "terminal/window.h"
|
|
#include "util/color.h"
|
|
#include "util/conv.h"
|
|
#include "util/error.h"
|
|
#include "util/memory.h"
|
|
#include "util/snprintf.h"
|
|
#include "util/string.h"
|
|
#include "viewer/text/form.h"
|
|
#include "viewer/text/link.h"
|
|
#include "viewer/text/view.h"
|
|
|
|
|
|
char *
|
|
get_download_msg(struct download *download, struct terminal *term,
|
|
int wide, int full, const char *separator)
|
|
{
|
|
if (!download_is_progressing(download)) {
|
|
/* DBG("%d -> %s", download->state, _(get_err_msg(download->state), term)); */
|
|
return stracpy(get_state_message(download->state, term));
|
|
}
|
|
|
|
#ifdef CONFIG_BITTORRENT
|
|
if (download->conn
|
|
&& download->conn->uri->protocol == PROTOCOL_BITTORRENT)
|
|
return get_bittorrent_message(download, term, wide, full, separator);
|
|
#endif
|
|
if (download->conn && download->conn->http_upload_progress)
|
|
return get_upload_progress_msg(download->conn->http_upload_progress,
|
|
term, wide, full, separator);
|
|
|
|
return get_progress_msg(download->progress, term, wide, full, separator);
|
|
}
|
|
|
|
#define show_tabs(option, tabs) (((option) > 0) && !((option) == 1 && (tabs) < 2))
|
|
|
|
void
|
|
update_status(void)
|
|
{
|
|
int show_title_bar = get_opt_bool("ui.show_title_bar", NULL);
|
|
int show_status_bar = get_opt_bool("ui.show_status_bar", NULL);
|
|
int show_tabs_bar = get_opt_int("ui.tabs.show_bar", NULL);
|
|
int show_tabs_bar_at_top = get_opt_bool("ui.tabs.top", NULL);
|
|
#ifdef CONFIG_LEDS
|
|
int show_leds = get_opt_bool("ui.leds.enable", NULL);
|
|
#endif
|
|
int set_window_title = get_opt_bool("ui.window_title", NULL);
|
|
int insert_mode = get_opt_bool("document.browse.forms.insert_mode",
|
|
NULL);
|
|
struct session *ses;
|
|
int tabs_count = 1;
|
|
struct terminal *term = NULL;
|
|
|
|
foreach (ses, sessions) {
|
|
struct session_status *status = &ses->status;
|
|
int dirty = 0;
|
|
|
|
/* Try to descrease the number of tab calculation using that
|
|
* tab sessions share the same term. */
|
|
if (ses->tab->term != term) {
|
|
term = ses->tab->term;
|
|
tabs_count = number_of_tabs(term);
|
|
}
|
|
|
|
if (status->force_show_title_bar >= 0)
|
|
show_title_bar = status->force_show_title_bar;
|
|
if (status->show_title_bar != show_title_bar) {
|
|
status->show_title_bar = show_title_bar;
|
|
dirty = 1;
|
|
}
|
|
|
|
if (status->force_show_status_bar >= 0)
|
|
show_status_bar = status->force_show_status_bar;
|
|
if (status->show_status_bar != show_status_bar) {
|
|
status->show_status_bar = show_status_bar;
|
|
dirty = 1;
|
|
}
|
|
|
|
if (show_tabs(show_tabs_bar, tabs_count) != status->show_tabs_bar) {
|
|
status->show_tabs_bar = show_tabs(show_tabs_bar, tabs_count);
|
|
dirty = 1;
|
|
}
|
|
|
|
if (status->show_tabs_bar) {
|
|
if (status->show_tabs_bar_at_top != show_tabs_bar_at_top) {
|
|
status->show_tabs_bar_at_top = show_tabs_bar_at_top;
|
|
dirty = 1;
|
|
}
|
|
}
|
|
#ifdef CONFIG_LEDS
|
|
if (status->show_leds != show_leds) {
|
|
status->show_leds = show_leds;
|
|
}
|
|
#endif
|
|
|
|
status->set_window_title = set_window_title;
|
|
|
|
/* This more belongs to the current browsing state but ... */
|
|
if (!insert_mode)
|
|
ses->insert_mode = INSERT_MODE_LESS;
|
|
else if (ses->insert_mode == INSERT_MODE_LESS)
|
|
ses->insert_mode = INSERT_MODE_OFF;
|
|
|
|
if (!dirty) continue;
|
|
|
|
/* Force the current document to be rerendered so the
|
|
* document view and document height is updated to fit
|
|
* into the new dimensions. Related to bug 87. */
|
|
render_document_frames(ses, 1);
|
|
|
|
set_screen_dirty(term->screen, 0, term->height);
|
|
}
|
|
}
|
|
|
|
static char *
|
|
get_current_link_info_and_title(struct session *ses,
|
|
struct document_view *doc_view)
|
|
{
|
|
char *link_info, *link_title, *ret = NULL;
|
|
|
|
link_info = get_current_link_info(ses, doc_view);
|
|
if (!link_info) return NULL;
|
|
|
|
link_title = get_current_link_title(doc_view);
|
|
if (link_title) {
|
|
assert(*link_title);
|
|
|
|
ret = straconcat(link_info, " - ", link_title,
|
|
(char *) NULL);
|
|
mem_free(link_info);
|
|
mem_free(link_title);
|
|
}
|
|
|
|
if (!ret) ret = link_info;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static inline void
|
|
display_status_bar(struct session *ses, struct terminal *term, int tabs_count)
|
|
{
|
|
char *msg = NULL;
|
|
unsigned int tab_info_len = 0;
|
|
struct download *download = get_current_download(ses);
|
|
struct session_status *status = &ses->status;
|
|
unsigned int text_color_node = 0;
|
|
int msglen;
|
|
struct el_box box;
|
|
|
|
#ifdef CONFIG_MARKS
|
|
if (ses->kbdprefix.mark != KP_MARK_NOTHING) {
|
|
switch (ses->kbdprefix.mark) {
|
|
case KP_MARK_NOTHING:
|
|
assert(0);
|
|
break;
|
|
|
|
case KP_MARK_SET:
|
|
msg = msg_text(term, N_("Enter a mark to set"));
|
|
break;
|
|
|
|
case KP_MARK_GOTO:
|
|
msg = msg_text(term, N_("Enter a mark"
|
|
" to which to jump"));
|
|
break;
|
|
}
|
|
} else
|
|
#endif
|
|
if (ses->kbdprefix.repeat_count) {
|
|
msg = msg_text(term, N_("Keyboard prefix: %d"),
|
|
ses->kbdprefix.repeat_count);
|
|
}
|
|
else if (ses->status.window_status) {
|
|
msg = stracpy(ses->status.window_status);
|
|
}
|
|
else if (download) {
|
|
struct document_view *doc_view = current_frame(ses);
|
|
|
|
/* Show S_INTERRUPTED message *once* but then show links
|
|
* again as usual. */
|
|
/* doc_view->vs may be NULL here in the short interval between
|
|
* ses_forward() with @loading_in_frame set, disconnecting the
|
|
* doc_view from vs, and render_document_frames(), detaching
|
|
* the doc_view. */
|
|
if (doc_view && doc_view->vs) {
|
|
static int last_current_link;
|
|
int ncl = doc_view->vs->current_link;
|
|
|
|
if (is_in_state(download->state, S_INTERRUPTED)
|
|
&& ncl != last_current_link)
|
|
download->state = connection_state(S_OK);
|
|
last_current_link = ncl;
|
|
|
|
if (is_in_state(download->state, S_OK)) {
|
|
if (get_current_link(doc_view)) {
|
|
msg = get_current_link_info_and_title(ses, doc_view);
|
|
} else if (ses->navigate_mode == NAVIGATE_CURSOR_ROUTING) {
|
|
msg = msg_text(term, N_("Cursor position: %dx%d"),
|
|
ses->tab->x + 1, ses->tab->y + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (!msg) {
|
|
int full = term->width > 130;
|
|
int wide = term->width > 80;
|
|
|
|
msg = get_download_msg(download, term, wide, full, ", ");
|
|
}
|
|
}
|
|
|
|
set_box(&box, 0, term->height - 1, term->width, 1);
|
|
draw_box_node(term, &box, ' ', 0, get_bfu_color_node(term, "status.status-bar"));
|
|
|
|
if (!status->show_tabs_bar && tabs_count > 1) {
|
|
char tab_info[8];
|
|
|
|
tab_info[tab_info_len++] = '[';
|
|
ulongcat(tab_info, &tab_info_len, term->current_tab + 1, 4, 0);
|
|
tab_info[tab_info_len++] = ']';
|
|
tab_info[tab_info_len++] = ' ';
|
|
tab_info[tab_info_len] = '\0';
|
|
|
|
text_color_node = get_bfu_color_node(term, "status.status-text");
|
|
draw_text_node(term, 0, term->height - 1, tab_info, tab_info_len,
|
|
0, text_color_node);
|
|
}
|
|
|
|
if (!msg) return;
|
|
|
|
if (!text_color_node)
|
|
text_color_node = get_bfu_color_node(term, "status.status-text");
|
|
|
|
msglen = strlen(msg);
|
|
draw_text_node(term, 0 + tab_info_len, term->height - 1,
|
|
msg, msglen, 0, text_color_node);
|
|
mem_free(msg);
|
|
|
|
if (download_is_progressing(download) && download->progress->size > 0) {
|
|
int xend = term->width - 1;
|
|
int width;
|
|
|
|
#ifdef CONFIG_LEDS
|
|
if (ses->status.show_leds)
|
|
xend -= term->leds_length;
|
|
#endif
|
|
|
|
width = int_max(0, xend - msglen - tab_info_len - 1);
|
|
if (width < 6) return;
|
|
int_upper_bound(&width, 20);
|
|
draw_progress_bar_node(download->progress, term,
|
|
xend - width, term->height - 1, width,
|
|
NULL, 0);
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
display_tab_bar(struct session *ses, struct terminal *term, int tabs_count)
|
|
{
|
|
unsigned int normal_color_node = get_bfu_color_node(term, "tabs.normal");
|
|
unsigned int selected_color_node = get_bfu_color_node(term, "tabs.selected");
|
|
unsigned int loading_color_node = get_bfu_color_node(term, "tabs.loading");
|
|
unsigned int fresh_color_node = get_bfu_color_node(term, "tabs.unvisited");
|
|
unsigned int tabsep_color_node = get_bfu_color_node(term, "tabs.separator");
|
|
struct session_status *status = &ses->status;
|
|
int tab_width = int_max(1, term->width / tabs_count);
|
|
int tab_total_width = tab_width * tabs_count;
|
|
int tab_remain_width = int_max(0, term->width - tab_total_width);
|
|
int tab_add = int_max(1, (tab_remain_width / tabs_count));
|
|
int tab_num;
|
|
struct el_box box;
|
|
|
|
if (status->show_tabs_bar_at_top) set_box(&box, 0, status->show_title_bar, term->width, 1);
|
|
else set_box(&box, 0, term->height - (status->show_status_bar ? 2 : 1), 0, 1);
|
|
|
|
for (tab_num = 0; tab_num < tabs_count; tab_num++) {
|
|
struct download *download = NULL;
|
|
unsigned int color_node = normal_color_node;
|
|
struct window *tab = get_tab_by_number(term, tab_num);
|
|
struct document_view *doc_view;
|
|
struct session *tab_ses = (struct session *)tab->data;
|
|
int actual_tab_width = tab_width - 1;
|
|
char *msg;
|
|
|
|
/* Adjust tab size to use full term width. */
|
|
if (tab_remain_width) {
|
|
actual_tab_width += tab_add;
|
|
tab_remain_width -= tab_add;
|
|
}
|
|
|
|
doc_view = tab_ses ? current_frame(tab_ses) : NULL;
|
|
|
|
if (doc_view) {
|
|
if (doc_view->document->title
|
|
&& *(doc_view->document->title))
|
|
msg = doc_view->document->title;
|
|
else
|
|
msg = _("Untitled", term);
|
|
} else {
|
|
msg = _("No document", term);
|
|
}
|
|
|
|
if (tab_num) {
|
|
draw_char_node(term, box.x, box.y, BORDER_SVLINE,
|
|
SCREEN_ATTR_FRAME, tabsep_color_node);
|
|
box.x++;
|
|
}
|
|
|
|
if (tab_num == term->current_tab) {
|
|
color_node = selected_color_node;
|
|
|
|
} else {
|
|
download = get_current_download(tab_ses);
|
|
|
|
if (download && !is_in_state(download->state, S_OK)) {
|
|
color_node = loading_color_node;
|
|
} else if (!tab_ses || !tab_ses->status.visited) {
|
|
color_node = fresh_color_node;
|
|
}
|
|
|
|
if (!download_is_progressing(download)
|
|
|| download->progress->size <= 0)
|
|
download = NULL;
|
|
}
|
|
|
|
box.width = actual_tab_width + 1;
|
|
draw_box_node(term, &box, ' ', 0, color_node);
|
|
|
|
if (download) {
|
|
draw_progress_bar_node(download->progress, term,
|
|
box.x, box.y, actual_tab_width,
|
|
msg, 0);
|
|
} else {
|
|
int msglen;
|
|
#ifdef CONFIG_UTF8
|
|
if (term->utf8_cp) {
|
|
msglen = utf8_step_forward(msg, NULL,
|
|
actual_tab_width,
|
|
UTF8_STEP_CELLS_FEWER,
|
|
NULL) - msg;
|
|
} else
|
|
#endif /* CONFIG_UTF8 */
|
|
msglen = int_min(strlen(msg), actual_tab_width);
|
|
|
|
draw_text_node(term, box.x, box.y, msg, msglen, 0, color_node);
|
|
}
|
|
|
|
tab->xpos = box.x;
|
|
tab->width = actual_tab_width;
|
|
if (tab_num == tabs_count - 1) {
|
|
/* This is the last tab, and is therefore followed
|
|
* by a space, not a separator; increment tab->width
|
|
* to count that space as part of the tab.
|
|
* -- Miciah */
|
|
tab->width++;
|
|
}
|
|
|
|
box.x += actual_tab_width;
|
|
}
|
|
}
|
|
|
|
/* Print page's title and numbering at window top. */
|
|
static inline void
|
|
display_title_bar(struct session *ses, struct terminal *term)
|
|
{
|
|
struct document_view *doc_view;
|
|
struct document *document;
|
|
struct string title;
|
|
char buf[40];
|
|
int buflen = 0;
|
|
int height;
|
|
|
|
/* Clear the old title */
|
|
if (!get_opt_bool("ui.show_menu_bar_always", NULL)) {
|
|
struct el_box box;
|
|
|
|
set_box(&box, 0, 0, term->width, 1);
|
|
draw_box_node(term, &box, ' ', 0, get_bfu_color_node(term, "title.title-bar"));
|
|
}
|
|
|
|
doc_view = current_frame(ses);
|
|
if (!doc_view || !doc_view->document) return;
|
|
|
|
if (!init_string(&title)) return;
|
|
|
|
document = doc_view->document;
|
|
|
|
/* Set up the document page info string: '(' %page '/' %pages ')' */
|
|
height = doc_view->box.height;
|
|
if (height < document->height && doc_view->vs) {
|
|
int pos = doc_view->vs->y + height;
|
|
int page = 1;
|
|
int pages = height ? (document->height + height - 1) / height : 1;
|
|
|
|
/* Check if at the end else calculate the page. */
|
|
if (pos >= document->height) {
|
|
page = pages;
|
|
} else if (height) {
|
|
page = int_min((pos - height / 2) / height + 1, pages);
|
|
}
|
|
|
|
buflen = snprintf(buf, sizeof(buf), " (%d/%d)", page, pages);
|
|
if (buflen < 0) buflen = 0;
|
|
}
|
|
|
|
if (document->title) {
|
|
int maxlen = int_max(term->width - 4 - buflen, 0);
|
|
int titlelen, titlewidth;
|
|
|
|
#ifdef CONFIG_UTF8
|
|
if (term->utf8_cp) {
|
|
titlewidth = utf8_ptr2cells(document->title, NULL);
|
|
titlewidth = int_min(titlewidth, maxlen);
|
|
|
|
titlelen = utf8_cells2bytes(document->title,
|
|
titlewidth, NULL);
|
|
} else
|
|
#endif /* CONFIG_UTF8 */
|
|
{
|
|
titlewidth = int_min(strlen(document->title), maxlen);
|
|
titlelen = titlewidth;
|
|
}
|
|
|
|
add_bytes_to_string(&title, document->title, titlelen);
|
|
|
|
if (titlewidth == maxlen)
|
|
add_bytes_to_string(&title, "...", 3);
|
|
}
|
|
|
|
if (buflen > 0)
|
|
add_bytes_to_string(&title, buf, buflen);
|
|
|
|
if (title.length) {
|
|
int x;
|
|
#ifdef CONFIG_UTF8
|
|
if (term->utf8_cp) {
|
|
x = int_max(term->width - 1
|
|
- utf8_ptr2cells(title.source,
|
|
title.source
|
|
+ title.length), 0);
|
|
} else
|
|
#endif /* CONFIG_UTF8 */
|
|
x = int_max(term->width - 1 - title.length, 0);
|
|
|
|
draw_text_node(term, x, 0, title.source, title.length, 0,
|
|
get_bfu_color_node(term, "title.title-text"));
|
|
}
|
|
|
|
done_string(&title);
|
|
}
|
|
|
|
static inline void
|
|
display_window_title(struct session *ses, struct terminal *term)
|
|
{
|
|
static struct session *last_ses;
|
|
struct session_status *status = &ses->status;
|
|
char *doc_title = NULL;
|
|
char *title;
|
|
int titlelen;
|
|
|
|
if (ses->doc_view
|
|
&& ses->doc_view->document
|
|
&& ses->doc_view->document->title
|
|
&& ses->doc_view->document->title[0])
|
|
doc_title = ses->doc_view->document->title;
|
|
|
|
title = doc_title ? straconcat(doc_title, " - ELinks",
|
|
(char *) NULL)
|
|
: stracpy("ELinks");
|
|
if (!title) return;
|
|
|
|
titlelen = strlen(title);
|
|
if ((last_ses != ses
|
|
|| !status->last_title
|
|
|| strlen(status->last_title) != titlelen
|
|
|| memcmp(status->last_title, title, titlelen))
|
|
&& set_terminal_title(term, title) >= 0) {
|
|
mem_free_set(&status->last_title, title);
|
|
last_ses = ses;
|
|
} else {
|
|
mem_free(title);
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_LEDS
|
|
static inline void
|
|
display_leds(struct session *ses, struct session_status *status)
|
|
{
|
|
if (ses->doc_view && ses->doc_view->document) {
|
|
struct cache_entry *cached = ses->doc_view->document->cached;
|
|
|
|
if (cached) {
|
|
if (cached->ssl_info)
|
|
set_led_value(status->ssl_led, 'S');
|
|
else
|
|
unset_led_value(status->ssl_led);
|
|
} else {
|
|
/* FIXME: We should do this thing better. */
|
|
set_led_value(status->ssl_led, '?');
|
|
}
|
|
}
|
|
|
|
if (ses->insert_mode == INSERT_MODE_LESS) {
|
|
set_led_value(status->insert_mode_led, 'i');
|
|
} else {
|
|
if (ses->insert_mode == INSERT_MODE_ON)
|
|
set_led_value(status->insert_mode_led, 'I');
|
|
else
|
|
unset_led_value(status->insert_mode_led);
|
|
}
|
|
|
|
draw_leds(ses);
|
|
}
|
|
#endif /* CONFIG_LEDS */
|
|
|
|
/* Print statusbar and titlebar, set terminal title. */
|
|
void
|
|
print_screen_status(struct session *ses)
|
|
{
|
|
struct terminal *term = ses->tab->term;
|
|
struct session_status *status = &ses->status;
|
|
int tabs_count = number_of_tabs(term);
|
|
int ses_tab_is_current = (ses->tab == get_current_tab(term));
|
|
|
|
if (ses_tab_is_current) {
|
|
if (status->set_window_title)
|
|
display_window_title(ses, term);
|
|
|
|
if (status->show_title_bar)
|
|
display_title_bar(ses, term);
|
|
|
|
if (status->show_status_bar)
|
|
display_status_bar(ses, term, tabs_count);
|
|
#ifdef CONFIG_LEDS
|
|
if (status->show_leds)
|
|
display_leds(ses, status);
|
|
#endif
|
|
|
|
if (!ses->status.visited)
|
|
ses->status.visited = 1;
|
|
}
|
|
|
|
if (status->show_tabs_bar) {
|
|
display_tab_bar(ses, term, tabs_count);
|
|
}
|
|
|
|
redraw_windows(REDRAW_IN_FRONT_OF_WINDOW, ses->tab);
|
|
}
|