1 /* These cute LightEmittingDiode-like indicators. */
10 #ifdef HAVE_SYS_TIME_H
20 #include "config/options.h"
21 #include "document/document.h"
22 #include "document/view.h"
23 #include "intl/gettext/libintl.h"
24 #include "main/module.h"
25 #include "main/timer.h"
26 #include "session/session.h"
27 #include "terminal/draw.h"
28 #include "terminal/tab.h"
29 #include "terminal/terminal.h"
30 #include "terminal/window.h"
31 #include "util/color.h"
32 #include "util/error.h"
33 #include "util/time.h"
34 #include "viewer/timer.h"
36 /* Current leds allocation:
37 * 0 - SSL connection indicator
38 * 1 - Insert-mode indicator
39 * 2 - JavaScript Error indicator
40 * 3 - JavaScript pop-up blocking indicator
41 * 4 - unused, reserved for Lua
42 * 5 - download in progress */
44 /* XXX: Currently, the leds toggling is quite hackish, some more work should go
45 * to it (ie. some led hooks called in sync_leds() to light the leds
46 * dynamically. --pasky */
48 /* Always reset led to '-' when not used anymore. */
50 /* If we would do real protection, we would do this as array of pointers. This
51 * way someone can just get any struct led and add/subscribe appropriate struct
52 * led for his control; however, I bet on programmers' responsibility rather,
53 * and hope that everyone will abide the "rules". */
55 static int timer_duration_backup
= 0;
57 static timer_id_T redraw_timer
= TIMER_ID_UNDEF
;
58 static int drawing
= 0;
60 static void redraw_leds(void *);
76 static union option_info led_options
[] = {
77 INIT_OPT_TREE("ui", N_("Clock"),
78 "clock", 0, N_("Digital clock in the status bar.")),
80 INIT_OPT_BOOL("ui.clock", N_("Enable"),
82 N_("Whether to display a digital clock in the status bar.")),
84 INIT_OPT_STRING("ui.clock", N_("Format"),
85 "format", 0, "[%H:%M]",
86 N_("Format string for the digital clock. See the strftime(3) "
87 "manpage for details.")),
90 /* Compatibility alias. Added: 2004-04-22, 0.9.CVS. */
91 INIT_OPT_ALIAS("ui.timer", "clock", 0, "ui.clock"),
93 INIT_OPT_BOOL("ui", N_("Show IP"),
95 N_("Whether to display IP of the document in the status bar.")),
98 INIT_OPT_TREE("ui", N_("LEDs"),
100 N_("LEDs (visual indicators) options.")),
102 INIT_OPT_BOOL("ui.leds", N_("Enable"),
104 N_("Enable LEDs. These visual indicators will inform you "
105 "about various states.")),
110 #define get_opt_leds(which) led_options[(which)].option.value
111 #define get_leds_clock_enable() get_opt_leds(LEDS_CLOCK_ENABLE).number
112 #define get_leds_clock_format() get_opt_leds(LEDS_CLOCK_FORMAT).string
113 #define get_leds_panel_enable() get_opt_leds(LEDS_PANEL_ENABLE).number
114 #define get_leds_show_ip_enable() get_opt_leds(LEDS_SHOW_IP_ENABLE).number
117 init_leds(struct module
*module
)
119 timer_duration_backup
= 0;
121 /* We can't setup timer here, because we may not manage to startup in
122 * 100ms and we will get to problems when we will call draw_leds() on
123 * uninitialized terminal. So, we will wait for draw_leds(). */
127 done_leds(struct module
*module
)
129 kill_timer(&redraw_timer
);
133 set_led_value(struct led
*led
, unsigned char value
)
135 if (value
!= led
->value__
) {
136 led
->value__
= value
;
137 led
->value_changed__
= 1;
142 get_led_value(struct led
*led
)
148 unset_led_value(struct led
*led
)
150 set_led_value(led
, '-');
155 init_led_panel(struct led_panel
*leds
)
159 for (i
= 0; i
< LEDS_COUNT
; i
++) {
160 leds
->leds
[i
].used__
= 0;
161 unset_led_value(&leds
->leds
[i
]);
166 draw_timer(struct terminal
*term
, int xpos
, int ypos
, struct color_pair
*color
)
171 snprintf(s
, sizeof(s
), "[%d]", get_timer_duration());
174 for (i
= length
- 1; i
>= 0; i
--)
175 draw_char(term
, xpos
- (length
- i
), ypos
, s
[i
], 0, color
);
181 draw_show_ip(struct session
*ses
, int xpos
, int ypos
, struct color_pair
*color
)
184 if (ses
->doc_view
&& ses
->doc_view
->document
&& ses
->doc_view
->document
->ip
) {
185 struct terminal
*term
= ses
->tab
->term
;
186 unsigned char *s
= ses
->doc_view
->document
->ip
;
187 int length
= strlen(s
);
190 for (i
= length
- 1; i
>= 0; i
--)
191 draw_char(term
, xpos
- (length
- i
), ypos
, s
[i
], 0, color
);
201 draw_clock(struct terminal
*term
, int xpos
, int ypos
, struct color_pair
*color
)
204 time_t curtime
= time(NULL
);
205 struct tm
*loctime
= localtime(&curtime
);
208 length
= strftime(s
, sizeof(s
), get_leds_clock_format(), loctime
);
210 for (i
= length
- 1; i
>= 0; i
--)
211 draw_char(term
, xpos
- (length
- i
), ypos
, s
[i
], 0, color
);
217 static milliseconds_T
218 compute_redraw_interval(void)
220 if (are_there_downloads())
223 /* TODO: Check whether the time format includes seconds. If not,
224 * return milliseconds to next minute. */
226 if (get_leds_clock_enable())
233 draw_leds(struct session
*ses
)
235 struct terminal
*term
= ses
->tab
->term
;
236 struct color_pair
*led_color
= NULL
;
238 int xpos
= term
->width
- LEDS_COUNT
- 3;
239 int ypos
= term
->height
- 1;
241 term
->leds_length
= 0;
243 /* This should be done elsewhere, but this is very nice place where we
244 * could do that easily. */
245 if (get_opt_int("ui.timer.enable", NULL
) == 2) {
246 led_color
= get_bfu_color(term
, "status.status-text");
247 if (!led_color
) goto end
;
249 term
->leds_length
+= draw_timer(term
, xpos
, ypos
, led_color
);
252 if (!get_leds_panel_enable()) return;
255 led_color
= get_bfu_color(term
, "status.status-text");
256 if (!led_color
) goto end
;
260 if (get_leds_clock_enable()) {
261 term
->leds_length
+= draw_clock(term
, xpos
- term
->leds_length
, ypos
, led_color
);
265 if (get_leds_show_ip_enable()) {
266 struct color_pair
*color
= get_bfu_color(term
, "status.showip-text");
268 if (color
) term
->leds_length
+= draw_show_ip(ses
, xpos
- term
->leds_length
, ypos
, color
);
271 /* We must shift the whole thing by one char to left, because we don't
272 * draft the char in the right-down corner :(. */
274 draw_char(term
, xpos
, ypos
, '[', 0, led_color
);
276 for (i
= 0; i
< LEDS_COUNT
; i
++) {
277 struct led
*led
= &ses
->status
.leds
.leds
[i
];
279 draw_char(term
, xpos
+ i
+ 1, ypos
, led
->value__
, 0, led_color
);
280 led
->value_changed__
= 0;
283 draw_char(term
, xpos
+ LEDS_COUNT
+ 1, ypos
, ']', 0, led_color
);
285 term
->leds_length
+= LEDS_COUNT
+ 2;
288 /* Redraw each 100ms. */
289 if (!drawing
&& redraw_timer
== TIMER_ID_UNDEF
) {
290 milliseconds_T delay
= compute_redraw_interval();
293 install_timer(&redraw_timer
, delay
, redraw_leds
, NULL
);
297 /* Determine if leds redrawing is necessary. Returns non-zero if so. */
299 sync_leds(struct session
*ses
)
305 /* Check if clock was enabled and update if needed. */
306 if (get_leds_clock_enable()) {
307 /* We _always_ update when clock is enabled
308 * Not perfect. --Zas */
313 for (i
= 0; i
< LEDS_COUNT
; i
++) {
314 struct led
*led
= &ses
->status
.leds
.leds
[i
];
316 if (led
->value_changed__
)
320 /* Check if timer was updated. */
321 timer_duration
= get_timer_duration();
322 if (timer_duration_backup
!= timer_duration
) {
323 timer_duration_backup
= timer_duration
;
331 update_download_led(struct session
*ses
)
333 struct session_status
*status
= &ses
->status
;
335 if (are_there_downloads()) {
336 unsigned char led
= get_led_value(status
->download_led
);
339 case '-' : led
= '\\'; break;
340 case '\\': led
= '|'; break;
341 case '|' : led
= '/'; break;
345 set_led_value(status
->download_led
, led
);
347 unset_led_value(status
->download_led
);
351 /* Timer callback for @redraw_timer. As explained in @install_timer,
352 * this function must erase the expired timer ID from all variables. */
354 redraw_leds(void *xxx
)
356 struct terminal
*term
;
357 milliseconds_T delay
;
359 redraw_timer
= TIMER_ID_UNDEF
;
361 if (!get_leds_panel_enable()
362 && get_opt_int("ui.timer.enable", NULL
) != 2) {
366 delay
= compute_redraw_interval();
368 install_timer(&redraw_timer
, delay
, redraw_leds
, NULL
);
373 foreach (term
, terminals
) {
377 if (list_empty(term
->windows
)) continue;
379 win
= get_current_tab(term
);
383 update_download_led(ses
);
386 redraw_terminal(term
);
393 menu_leds_info(struct terminal
*term
, void *xxx
, void *xxxx
)
395 /* If LEDs ever get more dynamic we might have to change this, but it
396 * should do for now. --jonas */
397 info_box(term
, MSGBOX_FREE_TEXT
| MSGBOX_SCROLLABLE
,
398 N_("LED indicators"), ALIGN_LEFT
,
399 msg_text(term
, N_("What the different LEDs indicate:\n"
402 " |||||`- Download in progress\n"
404 " |||`--- A JavaScript pop-up window was blocked\n"
405 " ||`---- A JavaScript error has occurred\n"
406 " |`----- The state of insert mode for text-input form-fields\n"
407 " | 'i' means modeless, 'I' means insert mode is on\n"
408 " `------ Whether an SSL connection was used\n"
410 "'-' generally indicates that the LED is off.")));
415 register_led(struct session
*ses
, int number
)
419 if (number
>= LEDS_COUNT
|| number
< 0)
422 led
= &ses
->status
.leds
.leds
[number
];
432 unregister_led(struct led
*led
)
434 assertm(led
->used__
, "Attempted to unregister unused led!");
436 unset_led_value(led
);
439 struct module leds_module
= struct_module(
440 /* name: */ N_("LED indicators"),
441 /* options: */ led_options
,
443 /* submodules: */ NULL
,
445 /* init: */ init_leds
,
446 /* done: */ done_leds