1
/* Sessions status managment */
2
/* $Id: status.c,v 1.48 2004/01/06 06:28:15 witekfl Exp $ */
13
#include "bfu/msgbox.h"
14
#include "bfu/style.h"
15
#include "config/options.h"
16
#include "cache/cache.h"
17
#include "dialogs/download.h"
18
#include "dialogs/status.h"
19
#include "document/document.h"
20
#include "document/renderer.h"
21
#include "document/view.h"
22
#include "intl/gettext/libintl.h"
23
#include "sched/connection.h"
24
#include "sched/error.h"
25
#include "sched/session.h"
26
#include "terminal/draw.h"
27
#include "terminal/screen.h"
28
#include "terminal/tab.h"
29
#include "terminal/terminal.h"
30
#include "terminal/window.h"
31
#include "util/color.h"
32
#include "util/conv.h"
33
#include "util/error.h"
34
#include "util/memory.h"
35
#include "util/snprintf.h"
36
#include "util/string.h"
37
#include "viewer/text/form.h"
38
#include "viewer/text/link.h"
39
#include "viewer/text/view.h"
42
#define average_speed(progress) \
43
((longlong) (progress)->loaded * 10 / ((progress)->elapsed / 100))
45
#define current_speed(progress) \
46
((progress)->cur_loaded / (CURRENT_SPD_SEC * SPD_DISP_TIME / 1000))
48
#define estimated_time(progress) \
49
(((progress)->size - (progress)->pos) \
50
/ ((longlong) (progress)->loaded * 10 / ((progress)->elapsed / 100)) \
54
get_stat_msg(struct download *stat, struct terminal *term,
55
int wide, int full, unsigned char *separator)
58
int newlines = separator[strlen(separator) - 1] == '\n';
60
if (!download_is_progressing(stat)) {
61
/* DBG("%d -> %s", stat->state, _(get_err_msg(stat->state), term)); */
62
return stracpy(get_err_msg(stat->state, term));
65
if (!init_string(&msg)) return NULL;
67
/* FIXME: The following is a PITA from the l10n standpoint. A *big*
68
* one, _("of")-like pearls are a nightmare. Format strings need to
69
* be introduced to this fuggy corner of code as well. --pasky */
71
add_to_string(&msg, _("Received", term));
72
add_char_to_string(&msg, ' ');
73
add_xnum_to_string(&msg, stat->prg->pos);
74
if (stat->prg->size >= 0) {
75
add_char_to_string(&msg, ' ');
76
add_to_string(&msg, _("of", term));
77
add_char_to_string(&msg, ' ');
78
add_xnum_to_string(&msg, stat->prg->size);
81
add_to_string(&msg, separator);
83
if (wide && stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) {
85
_(full ? (newlines ? N_("Average speed")
86
: N_("average speed"))
90
add_to_string(&msg, _(newlines ? N_("Speed") : N_("speed"),
94
add_char_to_string(&msg, ' ');
95
add_xnum_to_string(&msg, average_speed(stat->prg));
96
add_to_string(&msg, "/s");
98
if (wide && stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) {
99
add_to_string(&msg, ", ");
101
_(full ? N_("current speed") : N_("cur"), term));
102
add_char_to_string(&msg, ' '),
103
add_xnum_to_string(&msg, current_speed(stat->prg));
104
add_to_string(&msg, "/s");
108
/* Do the following only if there is room */
110
add_to_string(&msg, separator);
112
add_to_string(&msg, _(full ? (newlines ? N_("Elapsed time")
113
: N_("elapsed time"))
116
add_char_to_string(&msg, ' ');
117
add_time_to_string(&msg, stat->prg->elapsed);
120
if (stat->prg->size >= 0 && stat->prg->loaded > 0) {
121
if (wide) add_to_string(&msg, ", ");
122
add_to_string(&msg, _(full ? N_("estimated time")
125
add_char_to_string(&msg, ' ');
126
add_time_to_string(&msg, estimated_time(stat->prg));
133
#define show_tabs(option, tabs) (((option) > 0) && !((option) == 1 && (tabs) < 2))
138
int show_title_bar = get_opt_int("ui.show_title_bar");
139
int show_status_bar = get_opt_int("ui.show_status_bar");
140
int show_tabs_bar = get_opt_int("ui.tabs.show_bar");
142
int show_leds = get_opt_int("ui.leds.enable");
144
int set_window_title = get_opt_bool("ui.window_title");
147
struct terminal *term = NULL;
149
foreach (ses, sessions) {
150
struct session_status *status = &ses->status;
153
/* Try to descrease the number of tab calculation using that
154
* tab sessions share the same term. */
155
if (ses->tab->term != term) {
156
term = ses->tab->term;
157
tabs = number_of_tabs(term);
160
if (status->show_title_bar != show_title_bar) {
161
status->show_title_bar = show_title_bar;
165
if (status->show_status_bar != show_status_bar) {
166
status->show_status_bar = show_status_bar;
170
if (show_tabs(show_tabs_bar, tabs) != status->show_tabs_bar) {
171
status->show_tabs_bar = show_tabs(show_tabs_bar, tabs);
172
/* Force the current document to be rerendered so the
173
* document view and document height is updated to fit
174
* into the new dimensions. Related to bug 87. */
175
render_document_frames(ses);
179
if (status->show_leds != show_leds) {
180
status->show_leds = show_leds;
185
status->set_window_title = set_window_title;
187
if (!dirty) continue;
189
set_screen_dirty(term->screen, 0, term->height);
194
display_status_bar(struct session *ses, struct terminal *term, int tabs_count)
196
static int last_current_link;
197
unsigned char *msg = NULL;
198
unsigned int tab_info_len = 0;
199
struct download *stat = get_current_download(ses);
200
struct session_status *status = &ses->status;
201
struct color_pair *text_color = NULL;
204
if (ses->kbdprefix.typeahead) {
205
unsigned char *uri = print_current_link(ses);
206
struct string msgstr;
208
if (!init_string(&msgstr)) return;
210
string_concat(&msgstr, _("Typeahead", term), ": ",
211
ses->kbdprefix.typeahead, NULL);
212
set_cursor(term, msgstr.length, term->height - 1, 0);
213
string_concat(&msgstr, " [", empty_string_or_(uri), "]", NULL);
215
if (uri) mem_free(uri);
219
/* Show S_INTERRUPTED message *once* but then show links
221
if (current_frame(ses)) {
222
int ncl = current_frame(ses)->vs->current_link;
224
if (stat->state == S_INTERRUPTED
225
&& ncl != last_current_link)
227
last_current_link = ncl;
229
if (stat->state == S_OK)
230
msg = print_current_link(ses);
234
int full = term->width > 130;
235
int wide = term->width > 80;
237
msg = get_stat_msg(stat, term, wide, full, ", ");
241
draw_area(term, 0, term->height - 1, term->width, 1, ' ', 0,
242
get_bfu_color(term, "status.status-bar"));
244
if (!status->show_tabs_bar && tabs_count > 1) {
245
unsigned char tab_info[8];
247
tab_info[tab_info_len++] = '[';
248
ulongcat(tab_info, &tab_info_len, term->current_tab + 1, 4, 0);
249
tab_info[tab_info_len++] = ']';
250
tab_info[tab_info_len++] = ' ';
251
tab_info[tab_info_len] = '\0';
253
text_color = get_bfu_color(term, "status.status-text");
254
draw_text(term, 0, term->height - 1, tab_info, tab_info_len,
261
text_color = get_bfu_color(term, "status.status-text");
263
msglen = strlen(msg);
264
draw_text(term, 0 + tab_info_len, term->height - 1,
265
msg, msglen, 0, text_color);
268
if (download_is_progressing(stat) && stat->prg->size > 0) {
269
int xend = term->width - 1;
273
if (ses->status.show_leds)
274
xend -= LEDS_COUNT + 2;
277
if (xend - msglen < 6) return;
278
width = int_min(20, xend - msglen - 1);
280
download_progress_bar(term, xend - width, term->height - 1,
282
stat->prg->pos, stat->prg->size);
287
display_tab_bar(struct session *ses, struct terminal *term, int tabs_count)
289
struct color_pair *normal_color = get_bfu_color(term, "tabs.normal");
290
struct color_pair *selected_color = get_bfu_color(term, "tabs.selected");
291
struct color_pair *loading_color = get_bfu_color(term, "tabs.loading");
292
struct color_pair *fresh_color = get_bfu_color(term, "tabs.unvisited");
293
struct color_pair *tabsep_color = get_bfu_color(term, "tabs.separator");
294
struct session_status *status = &ses->status;
295
int tab_width = int_max(1, term->width / tabs_count);
296
int tab_total_width = tab_width * tabs_count;
297
int tab_remain_width = int_max(0, term->width - tab_total_width);
298
int tab_add = int_max(1, (tab_remain_width / tabs_count));
300
int ypos = term->height - (status->show_status_bar ? 2 : 1);
303
for (tab_num = 0; tab_num < tabs_count; tab_num++) {
304
struct download *stat = NULL;
305
struct color_pair *color = normal_color;
306
struct window *tab = get_tab_by_number(term, tab_num);
307
struct document_view *doc_view;
308
struct session *tab_ses = tab->data;
309
int actual_tab_width = tab_width;
312
/* Adjust tab size to use full term width. */
313
if (tab_remain_width) {
314
actual_tab_width += tab_add;
315
tab_remain_width -= tab_add;
318
doc_view = tab_ses ? current_frame(tab_ses) : NULL;
321
if (doc_view->document->title
322
&& *(doc_view->document->title))
323
msg = doc_view->document->title;
325
msg = _("Untitled", term);
327
msg = _("No document", term);
331
draw_char(term, xpos, ypos, BORDER_SVLINE,
332
SCREEN_ATTR_FRAME, tabsep_color);
336
if (tab_num == term->current_tab) {
337
color = selected_color;
340
stat = get_current_download(tab->data);
342
if (stat && stat->state != S_OK) {
343
color = loading_color;
344
/* Set incomplete download to unvisited */
345
if (tab_ses && tab_ses->status.visited)
346
tab_ses->status.visited = 0;
348
} else if (!tab_ses || !tab_ses->status.visited) {
352
if (!download_is_progressing(stat)
353
|| stat->prg->size <= 0)
357
draw_area(term, xpos, ypos, actual_tab_width, 1, ' ', 0, color);
360
download_progress_bar(term, xpos, ypos,
361
actual_tab_width - 1, msg, NULL,
362
stat->prg->pos, stat->prg->size);
364
int msglen = int_min(strlen(msg), actual_tab_width - 1);
366
draw_text(term, xpos, ypos, msg, msglen, 0, color);
370
tab->width = actual_tab_width;
371
xpos += actual_tab_width - 1;
375
/* Print page's title and numbering at window top. */
377
display_title_bar(struct session *ses, struct terminal *term)
379
struct document_view *doc_view;
380
struct document *document;
382
unsigned char buf[80];
385
/* Clear the old title */
386
draw_area(term, 0, 0, term->width, 1, ' ', 0,
387
get_bfu_color(term, "title.title-bar"));
389
doc_view = current_frame(ses);
390
if (!doc_view || !doc_view->document) return;
392
if (!init_string(&title)) return;
394
document = doc_view->document;
396
/* Set up the document page info string: '(' %page '/' %pages ')' */
397
if (doc_view->height < document->height) {
398
int pos = doc_view->vs->y + doc_view->height;
400
int pages = doc_view->height
401
? (document->height + doc_view->height - 1) / doc_view->height
404
/* Check if at the end else calculate the page. */
405
if (pos >= document->height) {
407
} else if (doc_view->height) {
408
page = int_min((pos - doc_view->height / 2) / doc_view->height + 1,
412
buflen = snprintf(buf, sizeof(buf), " (%d/%d)", page, pages);
413
if (buflen < 0) buflen = 0;
416
if (document->title) {
417
int maxlen = int_max(term->width - 4 - buflen, 0);
418
int titlelen = int_min(strlen(document->title), maxlen);
420
add_bytes_to_string(&title, document->title, titlelen);
422
if (titlelen == maxlen)
423
add_bytes_to_string(&title, "...", 3);
427
add_bytes_to_string(&title, buf, buflen);
430
int x = int_max(term->width - 1 - title.length, 0);
432
draw_text(term, x, 0, title.source, title.length, 0,
433
get_bfu_color(term, "title.title-text"));
440
display_window_title(struct session *ses, struct terminal *term)
442
static struct session *last_ses;
443
struct session_status *status = &ses->status;
444
unsigned char *doc_title = NULL;
445
unsigned char *title;
449
&& ses->doc_view->document
450
&& ses->doc_view->document->title
451
&& ses->doc_view->document->title[0])
452
doc_title = ses->doc_view->document->title;
454
title = straconcat("ELinks",
455
doc_title ? " - " : NULL,
460
titlelen = strlen(title);
462
|| !status->last_title
463
|| strlen(status->last_title) != titlelen
464
|| memcmp(status->last_title, title, titlelen)) {
465
if (status->last_title) mem_free(status->last_title);
466
status->last_title = title;
467
set_terminal_title(term, title);
476
display_leds(struct session *ses, struct session_status *status)
478
if (ses->doc_view && ses->doc_view->document
479
&& ses->doc_view->document->url) {
480
struct cache_entry *cache_entry =
481
find_in_cache(ses->doc_view->document->url);
484
status->ssl_led->value = (cache_entry->ssl_info)
487
/* FIXME: We should do this thing better. */
488
status->ssl_led->value = '?';
494
#endif /* CONFIG_LEDS */
496
/* Print statusbar and titlebar, set terminal title. */
498
print_screen_status(struct session *ses)
500
struct terminal *term = ses->tab->term;
501
struct session_status *status = &ses->status;
502
int tabs_count = number_of_tabs(term);
503
int ses_tab_is_current = (ses->tab == get_current_tab(term));
505
if (ses_tab_is_current) {
506
if (status->set_window_title)
507
display_window_title(ses, term);
509
if (status->show_title_bar)
510
display_title_bar(ses, term);
512
if (status->show_status_bar)
513
display_status_bar(ses, term, tabs_count);
515
if (status->show_leds)
516
display_leds(ses, status);
519
if (!ses->status.visited)
520
ses->status.visited = 1;
523
if (status->show_tabs_bar) {
524
display_tab_bar(ses, term, tabs_count);
527
redraw_from_window(ses->tab);