Initial commit of the HEAD branch of the ELinks CVS repository, as of
[elinks/images.git] / src / bfu / leds.c
blob7d1c9b10b5f83ef30cd2edb9f04d41f0d021644b
1 /* These cute LightEmittingDiode-like indicators. */
2 /* $Id: leds.c,v 1.88 2005/08/25 15:08:00 zas Exp $ */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #ifdef HAVE_SYS_TIME_H
12 #include <sys/time.h>
13 #endif
14 #ifdef HAVE_TIME_H
15 #include <time.h>
16 #endif
18 #include "elinks.h"
20 #include "bfu/leds.h"
21 #include "config/options.h"
22 #include "intl/gettext/libintl.h"
23 #include "main/module.h"
24 #include "main/timer.h"
25 #include "session/session.h"
26 #include "terminal/draw.h"
27 #include "terminal/terminal.h"
28 #include "terminal/window.h"
29 #include "util/color.h"
30 #include "util/error.h"
31 #include "util/time.h"
32 #include "viewer/timer.h"
34 #define LEDS_REFRESH_DELAY ((milliseconds_T) 100)
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 - unused */
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 *);
62 enum led_option {
63 LEDS_CLOCK_TREE,
64 LEDS_CLOCK_ENABLE,
65 LEDS_CLOCK_FORMAT,
66 LEDS_CLOCK_ALIAS,
68 LEDS_PANEL_TREE,
69 LEDS_PANEL_ENABLE,
71 LEDS_OPTIONS,
74 static struct option_info led_options[] = {
75 INIT_OPT_TREE("ui", N_("Clock"),
76 "clock", 0, N_("Digital clock in the status bar.")),
78 INIT_OPT_BOOL("ui.clock", N_("Enable"),
79 "enable", 0, 0,
80 N_("Whether to display a digital clock in the status bar.")),
82 INIT_OPT_STRING("ui.clock", N_("Format"),
83 "format", 0, "[%H:%M]",
84 N_("Format string for the digital clock. See the strftime(3)\n"
85 "manpage for details.")),
87 /* Compatibility alias. Added: 2004-04-22, 0.9.CVS. */
88 INIT_OPT_ALIAS("ui.timer", "clock", 0, "ui.clock"),
91 INIT_OPT_TREE("ui", N_("LEDs"),
92 "leds", 0,
93 N_("LEDs (visual indicators) options.")),
95 INIT_OPT_BOOL("ui.leds", N_("Enable"),
96 "enable", 0, 1,
97 N_("Enable LEDs.\n"
98 "These visual indicators will inform you about various states.")),
100 NULL_OPTION_INFO,
103 #define get_opt_leds(which) led_options[(which)].option.value
104 #define get_leds_clock_enable() get_opt_leds(LEDS_CLOCK_ENABLE).number
105 #define get_leds_clock_format() get_opt_leds(LEDS_CLOCK_FORMAT).string
106 #define get_leds_panel_enable() get_opt_leds(LEDS_PANEL_ENABLE).number
108 void
109 init_leds(struct module *module)
111 timer_duration_backup = 0;
113 /* We can't setup timer here, because we may not manage to startup in
114 * 100ms and we will get to problems when we will call draw_leds() on
115 * uninitialized terminal. So, we will wait for draw_leds(). */
118 void
119 done_leds(struct module *module)
121 kill_timer(&redraw_timer);
124 void
125 set_led_value(struct led *led, unsigned char value)
127 if (value != led->value__) {
128 led->value__ = value;
129 led->value_changed__ = 1;
133 void
134 unset_led_value(struct led *led)
136 set_led_value(led, '-');
140 void
141 init_led_panel(struct led_panel *leds)
143 int i;
145 for (i = 0; i < LEDS_COUNT; i++) {
146 leds->leds[i].used__ = 0;
147 unset_led_value(&leds->leds[i]);
151 static int
152 draw_timer(struct terminal *term, int xpos, int ypos, struct color_pair *color)
154 unsigned char s[64];
155 int i, length;
157 snprintf(s, sizeof(s), "[%d]", get_timer_duration());
158 length = strlen(s);
160 for (i = length - 1; i >= 0; i--)
161 draw_char(term, xpos - (length - i), ypos, s[i], 0, color);
163 return length;
166 #ifdef HAVE_STRFTIME
167 static int
168 draw_clock(struct terminal *term, int xpos, int ypos, struct color_pair *color)
170 unsigned char s[64];
171 time_t curtime = time(NULL);
172 struct tm *loctime = localtime(&curtime);
173 int i, length;
175 length = strftime(s, sizeof(s), get_leds_clock_format(), loctime);
176 s[length] = '\0';
177 for (i = length - 1; i >= 0; i--)
178 draw_char(term, xpos - (length - i), ypos, s[i], 0, color);
180 return length;
182 #endif
184 void
185 draw_leds(struct session *ses)
187 struct terminal *term = ses->tab->term;
188 struct color_pair *led_color = NULL;
189 int i;
190 int xpos = term->width - LEDS_COUNT - 3;
191 int ypos = term->height - 1;
193 term->leds_length = 0;
195 /* This should be done elsewhere, but this is very nice place where we
196 * could do that easily. */
197 if (get_opt_int("ui.timer.enable") == 2) {
198 led_color = get_bfu_color(term, "status.status-text");
199 if (!led_color) goto end;
201 term->leds_length += draw_timer(term, xpos, ypos, led_color);
204 if (!get_leds_panel_enable()) return;
206 if (!led_color) {
207 led_color = get_bfu_color(term, "status.status-text");
208 if (!led_color) goto end;
211 #ifdef HAVE_STRFTIME
212 if (get_leds_clock_enable()) {
213 term->leds_length += draw_clock(term, xpos - term->leds_length, ypos, led_color);
215 #endif
217 /* We must shift the whole thing by one char to left, because we don't
218 * draft the char in the right-down corner :(. */
220 draw_char(term, xpos, ypos, '[', 0, led_color);
222 for (i = 0; i < LEDS_COUNT; i++) {
223 struct led *led = &ses->status.leds.leds[i];
225 draw_char(term, xpos + i + 1, ypos, led->value__, 0, led_color);
226 led->value_changed__ = 0;
229 draw_char(term, xpos + LEDS_COUNT + 1, ypos, ']', 0, led_color);
231 term->leds_length += LEDS_COUNT + 2;
233 end:
234 /* Redraw each 100ms. */
235 if (!drawing && redraw_timer == TIMER_ID_UNDEF)
236 install_timer(&redraw_timer, LEDS_REFRESH_DELAY, redraw_leds, NULL);
239 /* Determine if leds redrawing is necessary. Returns non-zero if so. */
240 static int
241 sync_leds(struct session *ses)
243 int i;
244 int timer_duration;
246 #ifdef HAVE_STRFTIME
247 /* Check if clock was enabled and update if needed. */
248 if (get_leds_clock_enable()) {
249 /* We _always_ update when clock is enabled
250 * Not perfect. --Zas */
251 return 1;
253 #endif
255 for (i = 0; i < LEDS_COUNT; i++) {
256 struct led *led = &ses->status.leds.leds[i];
258 if (led->value_changed__)
259 return 1;
262 /* Check if timer was updated. */
263 timer_duration = get_timer_duration();
264 if (timer_duration_backup != timer_duration) {
265 timer_duration_backup = timer_duration;
266 return 1;
269 return 0;
272 static void
273 redraw_leds(void *xxx)
275 struct session *ses;
277 if (!get_leds_panel_enable()
278 && get_opt_int("ui.timer.enable") != 2) {
279 redraw_timer = TIMER_ID_UNDEF;
280 return;
283 install_timer(&redraw_timer, LEDS_REFRESH_DELAY, redraw_leds, NULL);
285 if (drawing) return;
286 drawing = 1;
288 foreach (ses, sessions) {
289 if (!sync_leds(ses))
290 continue;
291 redraw_terminal(ses->tab->term);
292 draw_leds(ses);
294 drawing = 0;
297 void
298 menu_leds_info(struct terminal *term, void *xxx, void *xxxx)
300 /* If LEDs ever get more dynamic we might have to change this, but it
301 * should do for now. --jonas */
302 info_box(term, MSGBOX_FREE_TEXT | MSGBOX_SCROLLABLE,
303 N_("LED indicators"), ALIGN_LEFT,
304 msg_text(term, N_("What the different LEDs indicate:\n"
305 "\n"
306 "[SIJP--]\n"
307 " |||||`- Unused\n"
308 " ||||`-- Unused\n"
309 " |||`--- A JavaScript pop-up window was blocked\n"
310 " ||`---- A JavaScript error has occured\n"
311 " |`----- The state of insert mode for text-input form-fields\n"
312 " | 'i' means modeless, 'I' means insert mode is on\n"
313 " `------ Whether an SSL connection was used\n"
314 "\n"
315 "'-' generally indicates that the LED is off.")));
319 struct led *
320 register_led(struct session *ses, int number)
322 struct led *led;
324 if (number >= LEDS_COUNT || number < 0)
325 return NULL;
327 led = &ses->status.leds.leds[number];
328 if (led->used__)
329 return NULL;
331 led->used__ = 1;
333 return led;
336 void
337 unregister_led(struct led *led)
339 assertm(led->used__, "Attempted to unregister unused led!");
340 led->used__ = 0;
341 unset_led_value(led);
344 struct module leds_module = struct_module(
345 /* name: */ N_("LED indicators"),
346 /* options: */ led_options,
347 /* events: */ NULL,
348 /* submodules: */ NULL,
349 /* data: */ NULL,
350 /* init: */ init_leds,
351 /* done: */ done_leds