2 statusbar-items.c : irssi
4 Copyright (C) 1999-2001 Timo Sirainen
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "special-vars.h"
27 #include "window-items.h"
30 #include "statusbar.h"
31 #include "gui-printtext.h"
33 /* how often to redraw lagging time (seconds) */
34 #define LAG_REFRESH_TIME 10
36 /* how often to check for new mail (seconds) */
37 #define MAIL_REFRESH_TIME 60
39 /* If we haven't been able to check lag for this long, "(??)" is added after
41 #define MAX_LAG_UNKNOWN_TIME 30
43 static STATUSBAR_REC *mainbar;
44 static MAIN_WINDOW_REC *mainbar_window;
45 static int use_colors;
48 static SBAR_ITEM_REC *clock_item;
49 static int clock_timetag;
50 static time_t clock_last;
53 static SBAR_ITEM_REC *nick_item;
56 static SBAR_ITEM_REC *window_item;
59 static SBAR_ITEM_REC *activity_item;
60 static GList *activity_list;
63 static SBAR_ITEM_REC *more_item;
66 static SBAR_ITEM_REC *lag_item;
67 static int lag_timetag, lag_min_show;
68 static time_t lag_last_draw;
71 static SBAR_ITEM_REC *mail_item;
72 static int mail_timetag, mail_last_count;
73 static time_t mail_last_mtime = -1;
74 static off_t mail_last_size = -1;
77 static SBAR_ITEM_REC *topic_item;
78 static STATUSBAR_REC *topic_bar;
80 static void item_default(SBAR_ITEM_REC *item, int get_size_only,
81 const char *str, const char *data)
85 char *tmpstr, *tmpstr2;
88 if (active_win == NULL) {
92 server = active_win->active_server;
93 wiitem = active_win->active;
96 /* expand $variables */
97 tmpstr = parse_special_string(str, server, wiitem, data, NULL,
98 PARSE_FLAG_ESCAPE_VARS);
100 /* expand templates */
102 tmpstr2 = theme_format_expand_data(current_theme, &str,
103 'n', '0' + item->bar->color,
106 EXPAND_FLAG_IGNORE_REPLACES |
107 EXPAND_FLAG_IGNORE_EMPTY);
110 /* remove color codes */
111 tmpstr = strip_codes(tmpstr2);
115 item->min_size = item->max_size = format_get_length(tmpstr);
117 if (item->size < item->min_size) {
118 /* they're forcing us smaller than minimum size.. */
119 len = format_real_length(tmpstr, item->size);
123 tmpstr2 = g_strconcat(item->bar->color_string, tmpstr, NULL);
124 gui_printtext(item->xpos, item->bar->ypos, tmpstr2);
131 static void statusbar_clock(SBAR_ITEM_REC *item, int get_size_only)
133 item_default(item, get_size_only, "{sb $Z}", "");
136 /* check if we need to redraw clock.. */
137 static int statusbar_clock_timeout(void)
143 tm = localtime(&clock_last);
149 if (tm->tm_min != min) {
150 /* minute changed, redraw! */
152 statusbar_item_redraw(clock_item);
158 static void statusbar_nick(SBAR_ITEM_REC *item, int get_size_only)
160 item_default(item, get_size_only,
161 "{sb $P$N{sbmode $usermode}{sbaway $A}}", "");
164 static void sig_statusbar_nick_redraw(void)
166 statusbar_item_redraw(nick_item);
170 static void statusbar_window(SBAR_ITEM_REC *item, int get_size_only)
172 if (active_win->active != NULL) {
173 item_default(item, get_size_only,
174 "{sb $winref:$T{sbmode $M}}", "");
176 item_default(item, get_size_only,
177 "{sb $winref{sbservertag $tag}}", "");
181 static void sig_statusbar_window_redraw(void)
183 statusbar_item_redraw(window_item);
186 static void sig_statusbar_window_redraw_window(WINDOW_REC *window)
188 if (is_window_visible(window))
189 statusbar_item_redraw(window_item);
192 static void sig_statusbar_window_redraw_window_item(WI_ITEM_REC *item)
196 window = window_item_window(item);
197 if (window->active == item && is_window_visible(window))
198 statusbar_item_redraw(window_item);
201 static char *get_activity_list(int normal, int hilight)
208 str = g_string_new(NULL);
210 for (tmp = activity_list; tmp != NULL; tmp = tmp->next) {
211 WINDOW_REC *window = tmp->data;
213 is_det = window->data_level >= DATA_LEVEL_HILIGHT;
214 if ((!is_det && !normal) || (is_det && !hilight))
217 g_string_append(str, "%c");
219 g_string_append_c(str, ',');
221 switch (window->data_level) {
222 case DATA_LEVEL_NONE:
223 case DATA_LEVEL_TEXT:
226 g_string_append(str, "%W");
229 g_string_append(str, window->hilight_color == NULL ?
230 "%M" : window->hilight_color);
233 g_string_sprintfa(str, "%d", window->refnum);
235 /* make sure the background is returned to default */
236 g_string_append(str, "%n");
239 ret = str->len == 0 ? NULL : str->str;
240 g_string_free(str, ret == NULL);
244 /* redraw activity, FIXME: if we didn't get enough size, this gets buggy.
245 At least "Det:" isn't printed properly. also we should rearrange the
246 act list so that the highest priority items comes first. */
247 static void statusbar_activity(SBAR_ITEM_REC *item, int get_size_only)
249 char *actlist, *detlist, *data;
252 actlist = get_activity_list(TRUE, TRUE);
255 actlist = get_activity_list(TRUE, FALSE);
256 detlist = get_activity_list(FALSE, TRUE);
259 if (actlist == NULL && detlist == NULL) {
261 item->min_size = item->max_size = 0;
265 data = g_strconcat("{sbact ", actlist != NULL ? actlist : "",
266 " ", detlist != NULL ? detlist : "", "}", NULL);
267 item_default(item, get_size_only, data, "");
270 g_free_not_null(actlist);
271 g_free_not_null(detlist);
274 static void sig_statusbar_activity_hilight(WINDOW_REC *window, gpointer oldlevel)
279 g_return_if_fail(window != NULL);
281 if (settings_get_bool("actlist_moves")) {
282 /* Move the window to the first in the activity list */
283 if (g_list_find(activity_list, window) != NULL)
284 activity_list = g_list_remove(activity_list, window);
285 if (window->data_level != 0)
286 activity_list = g_list_prepend(activity_list, window);
287 statusbar_item_redraw(activity_item);
291 if (g_list_find(activity_list, window) != NULL) {
292 /* already in activity list */
293 if (window->data_level == 0) {
294 /* remove from activity list */
295 activity_list = g_list_remove(activity_list, window);
296 statusbar_item_redraw(activity_item);
297 } else if (window->data_level != GPOINTER_TO_INT(oldlevel) ||
298 window->hilight_color != 0) {
299 /* different level as last time (or maybe different
300 hilight color?), just redraw it. */
301 statusbar_item_redraw(activity_item);
306 if (window->data_level == 0)
309 /* add window to activity list .. */
311 for (tmp = activity_list; tmp != NULL; tmp = tmp->next, inspos++) {
312 WINDOW_REC *rec = tmp->data;
314 if (window->refnum < rec->refnum) {
316 g_list_insert(activity_list, window, inspos);
321 activity_list = g_list_append(activity_list, window);
323 statusbar_item_redraw(activity_item);
326 static void sig_statusbar_activity_window_destroyed(WINDOW_REC *window)
328 g_return_if_fail(window != NULL);
330 if (g_list_find(activity_list, window) != NULL)
331 activity_list = g_list_remove(activity_list, window);
332 statusbar_item_redraw(activity_item);
335 static void sig_statusbar_activity_updated(void)
337 statusbar_item_redraw(activity_item);
340 /* redraw -- more -- */
341 static void statusbar_more(SBAR_ITEM_REC *item, int get_size_only)
343 item_default(item, get_size_only, "{sbmore}", "");
346 static void sig_statusbar_more_check_remove(WINDOW_REC *window)
348 g_return_if_fail(window != NULL);
350 if (!is_window_visible(window))
353 if (more_item != NULL && WINDOW_GUI(window)->view->bottom) {
354 statusbar_item_remove(more_item);
359 static void sig_statusbar_more_check(WINDOW_REC *window)
361 if (window == NULL || !is_window_visible(window))
364 if (!WINDOW_GUI(window)->view->bottom) {
365 if (more_item == NULL) {
366 more_item = statusbar_item_create(mainbar, SBAR_PRIORITY_LOW, FALSE, statusbar_more);
367 statusbar_redraw(mainbar);
369 } else if (more_item != NULL) {
370 statusbar_item_remove(more_item);
375 static void statusbar_lag(SBAR_ITEM_REC *item, int get_size_only)
382 server = active_win == NULL ? NULL : active_win->active_server;
383 if (server == NULL || server->lag_last_check == 0) {
384 /* No lag information */
386 item->min_size = item->max_size = 0;
391 str = g_string_new(NULL);
393 /* FIXME: ugly ugly.. */
394 if (server->lag_sent == 0 || now-server->lag_sent < 5) {
395 lag_unknown = now-server->lag_last_check >
396 MAX_LAG_UNKNOWN_TIME+settings_get_int("lag_check_time");
398 if (lag_min_show < 0 || (server->lag < lag_min_show && !lag_unknown)) {
399 /* small lag, don't display */
401 g_string_sprintfa(str, "%d.%02d", server->lag/1000,
402 (server->lag % 1000)/10);
404 g_string_append(str, " (??)");
407 /* big lag, still waiting .. */
408 g_string_sprintfa(str, "%ld (??)",
409 (long) (now-server->lag_sent));
412 item_default(item, get_size_only, "{sblag $0-}", str->str);
414 g_string_free(str, TRUE);
417 static void sig_statusbar_lag_redraw(void)
419 statusbar_item_redraw(lag_item);
422 static int statusbar_lag_timeout(void)
424 /* refresh statusbar every 10 seconds */
425 if (time(NULL)-lag_last_draw < LAG_REFRESH_TIME)
428 statusbar_item_redraw(lag_item);
432 /* FIXME: this isn't very good.. it handles only mbox mailboxes.
433 this whole mail feature should really be in it's own module with lots
434 of other mail formats supported and people who don't want to use it
435 wouldn't need to.. */
436 static int get_mail_count(void)
440 char str[512], *fname;
443 fname = g_getenv("MAIL");
444 if (fname == NULL) return 0;
446 if (stat(fname, &statbuf) != 0) {
447 mail_last_mtime = -1;
453 if (statbuf.st_mtime == mail_last_mtime &&
454 statbuf.st_size == mail_last_size)
455 return mail_last_count;
456 mail_last_mtime = statbuf.st_mtime;
457 mail_last_size = statbuf.st_size;
459 f = fopen(fname, "r");
466 while (fgets(str, sizeof(str), f) != NULL) {
467 if (strncmp(str, "From ", 5) == 0)
469 if (strncmp(str, "Subject: ", 9) == 0 &&
470 strstr(str, "FOLDER INTERNAL DATA")) {
471 /* don't count these. */
477 mail_last_count = count;
481 static void statusbar_mail(SBAR_ITEM_REC *item, int get_size_only)
483 char countstr[MAX_INT_STRLEN];
486 mail_count = settings_get_bool("mail_counter") ? get_mail_count() : 0;
488 if (mail_count <= 0) {
490 item->min_size = item->max_size = 0;
494 ltoa(countstr, mail_count);
495 item_default(item, get_size_only, "{sbmail $0-}", countstr);
498 static int statusbar_mail_timeout(void)
500 statusbar_item_redraw(mail_item);
504 static void statusbar_topic(SBAR_ITEM_REC *item, int get_size_only)
506 item_default(item, get_size_only, "$topic", "");
509 static void sig_statusbar_topic_redraw(void)
511 if (topic_item != NULL) statusbar_item_redraw(topic_item);
514 static void sig_sidebars_redraw(void)
518 for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
519 MAIN_WINDOW_REC *rec = tmp->data;
521 if (rec->statusbar_window_item != NULL)
522 statusbar_item_redraw(rec->statusbar_window_item);
526 static void topicbar_create(void)
528 if (topic_bar != NULL)
531 topic_bar = statusbar_create(STATUSBAR_POS_UP, 0);
532 topic_item = statusbar_item_create(topic_bar, SBAR_PRIORITY_NORMAL, FALSE, statusbar_topic);
533 topic_item->max_size = TRUE;
534 statusbar_redraw(topic_bar);
536 signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
537 signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
538 signal_add("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
539 signal_add("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
542 static void topicbar_destroy(void)
544 if (topic_bar == NULL)
547 statusbar_destroy(topic_bar);
551 signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
552 signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
553 signal_remove("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
554 signal_remove("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw);
557 static void mainbar_remove_items(void)
559 statusbar_item_remove(clock_item);
560 statusbar_item_remove(nick_item);
561 statusbar_item_remove(window_item);
562 statusbar_item_remove(mail_item);
563 statusbar_item_remove(lag_item);
564 statusbar_item_remove(activity_item);
567 static void mainbar_add_items(MAIN_WINDOW_REC *window)
569 mainbar = window->statusbar;
570 mainbar_window = window;
572 clock_item = statusbar_item_create(mainbar, SBAR_PRIORITY_HIGH, FALSE, statusbar_clock);
573 nick_item = statusbar_item_create(mainbar, SBAR_PRIORITY_NORMAL, FALSE, statusbar_nick);
574 window_item = statusbar_item_create(mainbar, SBAR_PRIORITY_NORMAL, FALSE, statusbar_window);
575 mail_item = statusbar_item_create(mainbar, SBAR_PRIORITY_LOW, FALSE, statusbar_mail);
576 lag_item = statusbar_item_create(mainbar, SBAR_PRIORITY_LOW, FALSE, statusbar_lag);
577 activity_item = statusbar_item_create(mainbar, SBAR_PRIORITY_HIGH, FALSE, statusbar_activity);
580 static void sidebar_add_items(MAIN_WINDOW_REC *window)
582 window->statusbar_window_item =
583 statusbar_item_create(window->statusbar, SBAR_PRIORITY_NORMAL, FALSE, statusbar_window);
586 static void sidebar_remove_items(MAIN_WINDOW_REC *window)
588 if (window->statusbar_window_item != NULL) {
589 statusbar_item_remove(window->statusbar_window_item);
590 window->statusbar_window_item = NULL;
594 static void sig_mainwindow_created(MAIN_WINDOW_REC *window)
597 statusbar_create(STATUSBAR_POS_MIDDLE,
598 window->first_line+window->height);
599 ((STATUSBAR_REC *) window->statusbar)->window = window;
600 sidebar_add_items(window);
603 static void sig_mainwindow_destroyed(MAIN_WINDOW_REC *window)
605 if (window == mainbar_window) {
607 mainbar_window = NULL;
610 if (window->statusbar != NULL)
611 statusbar_destroy(window->statusbar);
614 static void sig_main_statusbar_changed(WINDOW_REC *window)
616 MAIN_WINDOW_REC *parent;
621 parent = WINDOW_GUI(window)->parent;
622 if (mainbar == parent->statusbar)
625 if (mainbar != NULL) {
626 mainbar_remove_items();
627 sidebar_add_items(mainbar_window);
629 sidebar_remove_items(parent);
630 mainbar_add_items(parent);
633 static void read_settings(void)
635 use_colors = settings_get_bool("colors") && has_colors();
636 if (settings_get_bool("topicbar"))
641 lag_min_show = settings_get_int("lag_min_show")*10;
642 statusbar_redraw(NULL);
645 void statusbar_items_init(void)
649 settings_add_int("misc", "lag_min_show", 100);
650 settings_add_bool("lookandfeel", "topicbar", TRUE);
651 settings_add_bool("lookandfeel", "actlist_moves", FALSE);
652 settings_add_bool("misc", "mail_counter", TRUE);
655 clock_timetag = g_timeout_add(1000, (GSourceFunc) statusbar_clock_timeout, NULL);
658 signal_add("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
659 signal_add("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
660 signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
661 signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
662 signal_add("nick mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
663 signal_add("user mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
664 signal_add("server nick changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
665 signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
666 signal_add("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
669 signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_window_redraw);
670 signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_window_redraw_window);
671 signal_add("channel mode changed", (SIGNAL_FUNC) sig_statusbar_window_redraw_window_item);
672 signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_window_redraw_window);
673 signal_add("window refnum changed", (SIGNAL_FUNC) sig_statusbar_window_redraw_window);
676 activity_list = NULL;
677 signal_add("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight);
678 signal_add("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed);
679 signal_add("window refnum changed", (SIGNAL_FUNC) sig_statusbar_activity_updated);
683 signal_add("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove);
684 signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_more_check);
685 signal_add("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check);
688 lag_timetag = g_timeout_add(1000*LAG_REFRESH_TIME, (GSourceFunc) statusbar_lag_timeout, NULL);
689 signal_add("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
690 signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
693 mail_timetag = g_timeout_add(1000*MAIL_REFRESH_TIME, (GSourceFunc) statusbar_mail_timeout, NULL);
696 topic_item = NULL; topic_bar = NULL;
697 signal_add("setup changed", (SIGNAL_FUNC) read_settings);
700 statusbar_redraw(NULL);
703 signal_add("mainwindow created", (SIGNAL_FUNC) sig_mainwindow_created);
704 signal_add("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
705 signal_add("window changed", (SIGNAL_FUNC) sig_main_statusbar_changed);
706 signal_add("window refnum changed", (SIGNAL_FUNC) sig_sidebars_redraw);
708 /* add statusbars to existing windows */
709 for (tmp = mainwindows; tmp != NULL; tmp = tmp->next)
710 sig_mainwindow_created(tmp->data);
711 sig_main_statusbar_changed(active_win);
714 void statusbar_items_deinit(void)
717 g_source_remove(clock_timetag);
720 signal_remove("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
721 signal_remove("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
722 signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
723 signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
724 signal_remove("nick mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
725 signal_remove("user mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
726 signal_remove("server nick changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
727 signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
728 signal_remove("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw);
731 signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_window_redraw);
732 signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_window_redraw_window);
733 signal_remove("channel mode changed", (SIGNAL_FUNC) sig_statusbar_window_redraw_window_item);
734 signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_window_redraw_window);
735 signal_remove("window refnum changed", (SIGNAL_FUNC) sig_statusbar_window_redraw_window);
738 signal_remove("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight);
739 signal_remove("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed);
740 signal_remove("window refnum changed", (SIGNAL_FUNC) sig_statusbar_activity_updated);
741 g_list_free(activity_list);
744 signal_remove("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove);
745 signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_more_check);
746 signal_remove("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check);
749 g_source_remove(lag_timetag);
750 signal_remove("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
751 signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw);
754 g_source_remove(mail_timetag);
758 signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
761 signal_remove("mainwindow created", (SIGNAL_FUNC) sig_mainwindow_created);
762 signal_remove("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
763 signal_remove("window changed", (SIGNAL_FUNC) sig_main_statusbar_changed);
764 signal_remove("window refnum changed", (SIGNAL_FUNC) sig_sidebars_redraw);