1 /* Sessions status management */
11 #include "bfu/dialog.h"
12 #include "cache/cache.h"
13 #include "config/options.h"
14 #include "dialogs/progress.h"
15 #include "dialogs/status.h"
16 #include "document/document.h"
17 #include "document/renderer.h"
18 #include "document/view.h"
19 #include "intl/gettext/libintl.h"
20 #include "network/connection.h"
21 #include "network/progress.h"
22 #include "network/state.h"
23 #include "protocol/bittorrent/dialogs.h"
24 #include "protocol/protocol.h"
25 #include "protocol/uri.h"
26 #include "session/download.h"
27 #include "session/session.h"
28 #include "terminal/draw.h"
29 #include "terminal/screen.h"
30 #include "terminal/tab.h"
31 #include "terminal/terminal.h"
32 #include "terminal/window.h"
33 #include "util/color.h"
34 #include "util/conv.h"
35 #include "util/error.h"
36 #include "util/memory.h"
37 #include "util/snprintf.h"
38 #include "util/string.h"
39 #include "viewer/text/form.h"
40 #include "viewer/text/link.h"
41 #include "viewer/text/view.h"
45 get_download_msg(struct download
*download
, struct terminal
*term
,
46 int wide
, int full
, unsigned char *separator
)
48 if (!download_is_progressing(download
)) {
49 /* DBG("%d -> %s", download->state, _(get_err_msg(download->state), term)); */
50 return stracpy(get_state_message(download
->state
, term
));
53 #ifdef CONFIG_BITTORRENT
55 && download
->conn
->uri
->protocol
== PROTOCOL_BITTORRENT
)
56 return get_bittorrent_message(download
, term
, wide
, full
, separator
);
58 if (download
->conn
&& download
->conn
->upload_progress
)
59 return get_upload_progress_msg(download
->conn
->upload_progress
,
60 term
, wide
, full
, separator
);
62 return get_progress_msg(download
->progress
, term
, wide
, full
, separator
);
65 #define show_tabs(option, tabs) (((option) > 0) && !((option) == 1 && (tabs) < 2))
70 int show_title_bar
= get_opt_bool("ui.show_title_bar", NULL
);
71 int show_status_bar
= get_opt_bool("ui.show_status_bar", NULL
);
72 int show_tabs_bar
= get_opt_int("ui.tabs.show_bar", NULL
);
73 int show_tabs_bar_at_top
= get_opt_bool("ui.tabs.top", NULL
);
75 int show_leds
= get_opt_bool("ui.leds.enable", NULL
);
77 int set_window_title
= get_opt_bool("ui.window_title", NULL
);
78 int insert_mode
= get_opt_bool("document.browse.forms.insert_mode",
82 struct terminal
*term
= NULL
;
84 foreach (ses
, sessions
) {
85 struct session_status
*status
= &ses
->status
;
88 /* Try to descrease the number of tab calculation using that
89 * tab sessions share the same term. */
90 if (ses
->tab
->term
!= term
) {
91 term
= ses
->tab
->term
;
92 tabs_count
= number_of_tabs(term
);
95 if (status
->force_show_title_bar
>= 0)
96 show_title_bar
= status
->force_show_title_bar
;
97 if (status
->show_title_bar
!= show_title_bar
) {
98 status
->show_title_bar
= show_title_bar
;
102 if (status
->force_show_status_bar
>= 0)
103 show_status_bar
= status
->force_show_status_bar
;
104 if (status
->show_status_bar
!= show_status_bar
) {
105 status
->show_status_bar
= show_status_bar
;
109 if (show_tabs(show_tabs_bar
, tabs_count
) != status
->show_tabs_bar
) {
110 status
->show_tabs_bar
= show_tabs(show_tabs_bar
, tabs_count
);
114 if (status
->show_tabs_bar
) {
115 if (status
->show_tabs_bar_at_top
!= show_tabs_bar_at_top
) {
116 status
->show_tabs_bar_at_top
= show_tabs_bar_at_top
;
121 if (status
->show_leds
!= show_leds
) {
122 status
->show_leds
= show_leds
;
126 status
->set_window_title
= set_window_title
;
128 /* This more belongs to the current browsing state but ... */
130 ses
->insert_mode
= INSERT_MODE_LESS
;
131 else if (ses
->insert_mode
== INSERT_MODE_LESS
)
132 ses
->insert_mode
= INSERT_MODE_OFF
;
134 if (!dirty
) continue;
136 /* Force the current document to be rerendered so the
137 * document view and document height is updated to fit
138 * into the new dimensions. Related to bug 87. */
139 render_document_frames(ses
, 1);
141 set_screen_dirty(term
->screen
, 0, term
->height
);
145 static unsigned char *
146 get_current_link_info_and_title(struct session
*ses
,
147 struct document_view
*doc_view
)
149 unsigned char *link_info
, *link_title
, *ret
= NULL
;
151 link_info
= get_current_link_info(ses
, doc_view
);
152 if (!link_info
) return NULL
;
154 link_title
= get_current_link_title(doc_view
);
158 ret
= straconcat(link_info
, " - ", link_title
,
159 (unsigned char *) NULL
);
161 mem_free(link_title
);
164 if (!ret
) ret
= link_info
;
170 display_status_bar(struct session
*ses
, struct terminal
*term
, int tabs_count
)
172 unsigned char *msg
= NULL
;
173 unsigned int tab_info_len
= 0;
174 struct download
*download
= get_current_download(ses
);
175 struct session_status
*status
= &ses
->status
;
176 struct color_pair
*text_color
= NULL
;
181 if (ses
->kbdprefix
.mark
!= KP_MARK_NOTHING
) {
182 switch (ses
->kbdprefix
.mark
) {
183 case KP_MARK_NOTHING
:
188 msg
= msg_text(term
, N_("Enter a mark to set"));
192 msg
= msg_text(term
, N_("Enter a mark"
193 " to which to jump"));
198 if (ses
->kbdprefix
.repeat_count
) {
199 msg
= msg_text(term
, N_("Keyboard prefix: %d"),
200 ses
->kbdprefix
.repeat_count
);
202 #ifdef CONFIG_ECMASCRIPT
203 else if (ses
->status
.window_status
) {
204 msg
= stracpy(ses
->status
.window_status
);
208 struct document_view
*doc_view
= current_frame(ses
);
210 /* Show S_INTERRUPTED message *once* but then show links
212 /* doc_view->vs may be NULL here in the short interval between
213 * ses_forward() with @loading_in_frame set, disconnecting the
214 * doc_view from vs, and render_document_frames(), detaching
216 if (doc_view
&& doc_view
->vs
) {
217 static int last_current_link
;
218 int ncl
= doc_view
->vs
->current_link
;
220 if (download
->state
== S_INTERRUPTED
221 && ncl
!= last_current_link
)
222 download
->state
= S_OK
;
223 last_current_link
= ncl
;
225 if (download
->state
== S_OK
) {
226 if (get_current_link(doc_view
)) {
227 msg
= get_current_link_info_and_title(ses
, doc_view
);
228 } else if (ses
->navigate_mode
== NAVIGATE_CURSOR_ROUTING
) {
229 msg
= msg_text(term
, N_("Cursor position: %dx%d"),
230 ses
->tab
->x
+ 1, ses
->tab
->y
+ 1);
237 int full
= term
->width
> 130;
238 int wide
= term
->width
> 80;
240 msg
= get_download_msg(download
, term
, wide
, full
, ", ");
244 set_box(&box
, 0, term
->height
- 1, term
->width
, 1);
245 draw_box(term
, &box
, ' ', 0, get_bfu_color(term
, "status.status-bar"));
247 if (!status
->show_tabs_bar
&& tabs_count
> 1) {
248 unsigned char tab_info
[8];
250 tab_info
[tab_info_len
++] = '[';
251 ulongcat(tab_info
, &tab_info_len
, term
->current_tab
+ 1, 4, 0);
252 tab_info
[tab_info_len
++] = ']';
253 tab_info
[tab_info_len
++] = ' ';
254 tab_info
[tab_info_len
] = '\0';
256 text_color
= get_bfu_color(term
, "status.status-text");
257 draw_text(term
, 0, term
->height
- 1, tab_info
, tab_info_len
,
264 text_color
= get_bfu_color(term
, "status.status-text");
266 msglen
= strlen(msg
);
267 draw_text(term
, 0 + tab_info_len
, term
->height
- 1,
268 msg
, msglen
, 0, text_color
);
271 if (download_is_progressing(download
) && download
->progress
->size
> 0) {
272 int xend
= term
->width
- 1;
276 if (ses
->status
.show_leds
)
277 xend
-= term
->leds_length
;
280 width
= int_max(0, xend
- msglen
- tab_info_len
- 1);
281 if (width
< 6) return;
282 int_upper_bound(&width
, 20);
283 draw_progress_bar(download
->progress
, term
,
284 xend
- width
, term
->height
- 1, width
,
290 display_tab_bar(struct session
*ses
, struct terminal
*term
, int tabs_count
)
292 struct color_pair
*normal_color
= get_bfu_color(term
, "tabs.normal");
293 struct color_pair
*selected_color
= get_bfu_color(term
, "tabs.selected");
294 struct color_pair
*loading_color
= get_bfu_color(term
, "tabs.loading");
295 struct color_pair
*fresh_color
= get_bfu_color(term
, "tabs.unvisited");
296 struct color_pair
*tabsep_color
= get_bfu_color(term
, "tabs.separator");
297 struct session_status
*status
= &ses
->status
;
298 int tab_width
= int_max(1, term
->width
/ tabs_count
);
299 int tab_total_width
= tab_width
* tabs_count
;
300 int tab_remain_width
= int_max(0, term
->width
- tab_total_width
);
301 int tab_add
= int_max(1, (tab_remain_width
/ tabs_count
));
305 if (status
->show_tabs_bar_at_top
) set_box(&box
, 0, status
->show_title_bar
, term
->width
, 1);
306 else set_box(&box
, 0, term
->height
- (status
->show_status_bar
? 2 : 1), 0, 1);
308 for (tab_num
= 0; tab_num
< tabs_count
; tab_num
++) {
309 struct download
*download
= NULL
;
310 struct color_pair
*color
= normal_color
;
311 struct window
*tab
= get_tab_by_number(term
, tab_num
);
312 struct document_view
*doc_view
;
313 struct session
*tab_ses
= tab
->data
;
314 int actual_tab_width
= tab_width
- 1;
317 /* Adjust tab size to use full term width. */
318 if (tab_remain_width
) {
319 actual_tab_width
+= tab_add
;
320 tab_remain_width
-= tab_add
;
323 doc_view
= tab_ses
? current_frame(tab_ses
) : NULL
;
326 if (doc_view
->document
->title
327 && *(doc_view
->document
->title
))
328 msg
= doc_view
->document
->title
;
330 msg
= _("Untitled", term
);
332 msg
= _("No document", term
);
336 draw_char(term
, box
.x
, box
.y
, BORDER_SVLINE
,
337 SCREEN_ATTR_FRAME
, tabsep_color
);
341 if (tab_num
== term
->current_tab
) {
342 color
= selected_color
;
345 download
= get_current_download(tab_ses
);
347 if (download
&& download
->state
!= S_OK
) {
348 color
= loading_color
;
349 } else if (!tab_ses
|| !tab_ses
->status
.visited
) {
353 if (!download_is_progressing(download
)
354 || download
->progress
->size
<= 0)
358 box
.width
= actual_tab_width
+ 1;
359 draw_box(term
, &box
, ' ', 0, color
);
362 draw_progress_bar(download
->progress
, term
,
363 box
.x
, box
.y
, actual_tab_width
,
366 int msglen
= int_min(strlen(msg
), actual_tab_width
);
368 draw_text(term
, box
.x
, box
.y
, msg
, msglen
, 0, color
);
372 tab
->width
= actual_tab_width
;
373 if (tab_num
== tabs_count
- 1) {
374 /* This is the last tab, and is therefore followed
375 * by a space, not a separator; increment tab->width
376 * to count that space as part of the tab.
381 box
.x
+= actual_tab_width
;
385 /* Print page's title and numbering at window top. */
387 display_title_bar(struct session
*ses
, struct terminal
*term
)
389 struct document_view
*doc_view
;
390 struct document
*document
;
392 unsigned char buf
[40];
396 /* Clear the old title */
397 if (!get_opt_bool("ui.show_menu_bar_always", NULL
)) {
400 set_box(&box
, 0, 0, term
->width
, 1);
401 draw_box(term
, &box
, ' ', 0, get_bfu_color(term
, "title.title-bar"));
404 doc_view
= current_frame(ses
);
405 if (!doc_view
|| !doc_view
->document
) return;
407 if (!init_string(&title
)) return;
409 document
= doc_view
->document
;
411 /* Set up the document page info string: '(' %page '/' %pages ')' */
412 height
= doc_view
->box
.height
;
413 if (height
< document
->height
&& doc_view
->vs
) {
414 int pos
= doc_view
->vs
->y
+ height
;
416 int pages
= height
? (document
->height
+ height
- 1) / height
: 1;
418 /* Check if at the end else calculate the page. */
419 if (pos
>= document
->height
) {
422 page
= int_min((pos
- height
/ 2) / height
+ 1, pages
);
425 buflen
= snprintf(buf
, sizeof(buf
), " (%d/%d)", page
, pages
);
426 if (buflen
< 0) buflen
= 0;
429 if (document
->title
) {
430 int maxlen
= int_max(term
->width
- 4 - buflen
, 0);
431 int titlelen
, titlewidth
;
435 titlewidth
= utf8_ptr2cells(document
->title
, NULL
);
436 titlewidth
= int_min(titlewidth
, maxlen
);
438 titlelen
= utf8_cells2bytes(document
->title
,
441 #endif /* CONFIG_UTF8 */
443 titlewidth
= int_min(strlen(document
->title
), maxlen
);
444 titlelen
= titlewidth
;
447 add_bytes_to_string(&title
, document
->title
, titlelen
);
449 if (titlewidth
== maxlen
)
450 add_bytes_to_string(&title
, "...", 3);
454 add_bytes_to_string(&title
, buf
, buflen
);
460 x
= int_max(term
->width
- 1
461 - utf8_ptr2cells(title
.source
,
465 #endif /* CONFIG_UTF8 */
466 x
= int_max(term
->width
- 1 - title
.length
, 0);
468 draw_text(term
, x
, 0, title
.source
, title
.length
, 0,
469 get_bfu_color(term
, "title.title-text"));
476 display_window_title(struct session
*ses
, struct terminal
*term
)
478 static struct session
*last_ses
;
479 struct session_status
*status
= &ses
->status
;
480 unsigned char *doc_title
= NULL
;
481 unsigned char *title
;
485 && ses
->doc_view
->document
486 && ses
->doc_view
->document
->title
487 && ses
->doc_view
->document
->title
[0])
488 doc_title
= ses
->doc_view
->document
->title
;
490 title
= doc_title
? straconcat(doc_title
, " - ELinks",
491 (unsigned char *) NULL
)
495 titlelen
= strlen(title
);
497 || !status
->last_title
498 || strlen(status
->last_title
) != titlelen
499 || memcmp(status
->last_title
, title
, titlelen
)) {
500 mem_free_set(&status
->last_title
, title
);
501 set_terminal_title(term
, title
);
510 display_leds(struct session
*ses
, struct session_status
*status
)
512 if (ses
->doc_view
&& ses
->doc_view
->document
) {
513 struct cache_entry
*cached
= ses
->doc_view
->document
->cached
;
516 if (cached
->ssl_info
)
517 set_led_value(status
->ssl_led
, 'S');
519 unset_led_value(status
->ssl_led
);
521 /* FIXME: We should do this thing better. */
522 set_led_value(status
->ssl_led
, '?');
526 if (ses
->insert_mode
== INSERT_MODE_LESS
) {
527 set_led_value(status
->insert_mode_led
, 'i');
529 if (ses
->insert_mode
== INSERT_MODE_ON
)
530 set_led_value(status
->insert_mode_led
, 'I');
532 unset_led_value(status
->insert_mode_led
);
537 #endif /* CONFIG_LEDS */
539 /* Print statusbar and titlebar, set terminal title. */
541 print_screen_status(struct session
*ses
)
543 struct terminal
*term
= ses
->tab
->term
;
544 struct session_status
*status
= &ses
->status
;
545 int tabs_count
= number_of_tabs(term
);
546 int ses_tab_is_current
= (ses
->tab
== get_current_tab(term
));
548 if (ses_tab_is_current
) {
549 if (status
->set_window_title
)
550 display_window_title(ses
, term
);
552 if (status
->show_title_bar
)
553 display_title_bar(ses
, term
);
555 if (status
->show_status_bar
)
556 display_status_bar(ses
, term
, tabs_count
);
558 if (status
->show_leds
)
559 display_leds(ses
, status
);
562 if (!ses
->status
.visited
)
563 ses
->status
.visited
= 1;
566 if (status
->show_tabs_bar
) {
567 display_tab_bar(ses
, term
, tabs_count
);
570 redraw_from_window(ses
->tab
);