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
24 #include "special-vars.h"
28 #include "statusbar.h"
29 #include "statusbar-config.h"
30 #include "gui-windows.h"
31 #include "gui-printtext.h"
33 void statusbar_items_init(void);
34 void statusbar_items_deinit(void);
36 GSList *statusbar_groups;
37 STATUSBAR_GROUP_REC *active_statusbar_group;
40 sbar_item_defs: char *name => char *value
41 sbar_item_funcs: char *name => STATUSBAR_FUNC func
42 sbar_signal_items: int signal_id => GSList *(SBAR_ITEM_REC *items)
43 sbar_item_signals: SBAR_ITEM_REC *item => GSList *(int *signal_ids)
44 named_sbar_items: const char *name => GSList *(SBAR_ITEM_REC *items)
46 static GHashTable *sbar_item_defs, *sbar_item_funcs;
47 static GHashTable *sbar_signal_items, *sbar_item_signals;
48 static GHashTable *named_sbar_items;
49 static int statusbar_need_recreate_items;
51 void statusbar_item_register(const char *name, const char *value,
54 gpointer hkey, hvalue;
56 statusbar_need_recreate_items = TRUE;
58 if (g_hash_table_lookup_extended(sbar_item_defs,
59 name, &hkey, &hvalue)) {
60 g_hash_table_remove(sbar_item_defs, name);
64 g_hash_table_insert(sbar_item_defs,
65 g_strdup(name), g_strdup(value));
69 if (g_hash_table_lookup(sbar_item_funcs, name) == NULL) {
70 g_hash_table_insert(sbar_item_funcs,
71 g_strdup(name), (void *) func);
76 void statusbar_item_unregister(const char *name)
80 statusbar_need_recreate_items = TRUE;
81 if (g_hash_table_lookup_extended(sbar_item_defs,
82 name, &key, &value)) {
83 g_hash_table_remove(sbar_item_defs, key);
88 if (g_hash_table_lookup_extended(sbar_item_funcs,
89 name, &key, &value)) {
90 g_hash_table_remove(sbar_item_funcs, key);
95 STATUSBAR_GROUP_REC *statusbar_group_create(const char *name)
97 STATUSBAR_GROUP_REC *rec;
99 rec = g_new0(STATUSBAR_GROUP_REC, 1);
100 rec->name = g_strdup(name);
102 statusbar_groups = g_slist_append(statusbar_groups, rec);
106 void statusbar_group_destroy(STATUSBAR_GROUP_REC *rec)
108 statusbar_groups = g_slist_remove(statusbar_groups, rec);
110 while (rec->bars != NULL)
111 statusbar_destroy(rec->bars->data);
112 while (rec->config_bars != NULL)
113 statusbar_config_destroy(rec, rec->config_bars->data);
119 STATUSBAR_GROUP_REC *statusbar_group_find(const char *name)
123 for (tmp = statusbar_groups; tmp != NULL; tmp = tmp->next) {
124 STATUSBAR_GROUP_REC *rec = tmp->data;
126 if (strcmp(rec->name, name) == 0)
133 static int sbar_item_cmp(SBAR_ITEM_REC *item1, SBAR_ITEM_REC *item2)
135 return item1->config->priority == item2->config->priority ? 0 :
136 item1->config->priority < item2->config->priority ? -1 : 1;
139 static int sbar_cmp_position(STATUSBAR_REC *bar1, STATUSBAR_REC *bar2)
141 return bar1->config->position < bar2->config->position ? -1 : 1;
144 /* Shink all items in statusbar to their minimum requested size.
145 The items list should be sorted by priority, highest first. */
146 static int statusbar_shrink_to_min(GSList *items, int size, int max_width)
150 for (tmp = items; tmp != NULL; tmp = tmp->next) {
151 SBAR_ITEM_REC *rec = tmp->data;
153 size -= (rec->max_size-rec->min_size);
154 rec->size = rec->min_size;
156 if (size <= max_width) {
157 rec->size += max_width-size;
161 if (rec->size == 0) {
162 /* min_size was 0, item removed.
163 remove the marginal too */
171 /* shink the items in statusbar, even if their size gets smaller than
172 their minimum requested size. The items list should be sorted by
173 priority, highest first. */
174 static void statusbar_shrink_forced(GSList *items, int size, int max_width)
178 for (tmp = items; tmp != NULL; tmp = tmp->next) {
179 SBAR_ITEM_REC *rec = tmp->data;
181 if (size-rec->size > max_width) {
182 /* remove the whole item */
186 /* shrink the item */
187 rec->size -= size-max_width;
193 static void statusbar_resize_items(STATUSBAR_REC *bar, int max_width)
195 GSList *tmp, *prior_sorted;
198 /* first give items their max. size */
201 for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
202 SBAR_ITEM_REC *rec = tmp->data;
204 rec->func(rec, TRUE);
205 rec->size = rec->max_size;
208 width += rec->max_size;
210 prior_sorted = g_slist_insert_sorted(prior_sorted, rec,
216 if (width > max_width) {
217 /* too big, start shrinking from items with lowest priority
218 and shrink until everything fits or until we've shrinked
220 width = statusbar_shrink_to_min(prior_sorted, width,
222 if (width > max_width) {
223 /* still need to shrink, remove the items with lowest
224 priority until everything fits to screen */
225 statusbar_shrink_forced(prior_sorted, width,
230 g_slist_free(prior_sorted);
233 #define SBAR_ITEM_REDRAW_NEEDED(_bar, _item, _xpos) \
234 (((_bar)->dirty_xpos != -1 && (_xpos) >= (_bar)->dirty_xpos) || \
235 (_item)->xpos != (_xpos) || (_item)->current_size != (_item)->size)
237 static void statusbar_calc_item_positions(STATUSBAR_REC *bar)
239 WINDOW_REC *old_active_win;
240 GSList *tmp, *right_items;
243 old_active_win = active_win;
244 if (bar->parent_window != NULL)
245 active_win = bar->parent_window->active;
247 statusbar_resize_items(bar, term_width);
249 /* left-aligned items */
251 for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
252 SBAR_ITEM_REC *rec = tmp->data;
254 if (!rec->config->right_alignment &&
255 (rec->size > 0 || rec->current_size > 0)) {
256 if (SBAR_ITEM_REDRAW_NEEDED(bar, rec, xpos)) {
257 /* redraw the item */
259 if (bar->dirty_xpos == -1 ||
260 xpos < bar->dirty_xpos) {
263 bar->dirty_xpos = xpos;
272 /* right-aligned items - first copy them to a new list backwards,
273 easier to draw them in right order */
275 for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
276 SBAR_ITEM_REC *rec = tmp->data;
278 if (rec->config->right_alignment) {
280 right_items = g_slist_prepend(right_items, rec);
281 else if (rec->current_size > 0 &&
282 (bar->dirty_xpos == -1 ||
283 rec->xpos < bar->dirty_xpos)) {
284 /* item was hidden - set the dirty position
285 to begin from the item's old xpos */
288 bar->dirty_xpos = rec->xpos;
294 for (tmp = right_items; tmp != NULL; tmp = tmp->next) {
295 SBAR_ITEM_REC *rec = tmp->data;
298 if (SBAR_ITEM_REDRAW_NEEDED(bar, rec, rxpos)) {
300 if (bar->dirty_xpos == -1 ||
301 rxpos < bar->dirty_xpos) {
304 bar->dirty_xpos = rxpos;
309 g_slist_free(right_items);
311 active_win = old_active_win;
314 void statusbar_redraw(STATUSBAR_REC *bar, int force)
316 if (statusbar_need_recreate_items)
317 return; /* don't bother yet */
325 statusbar_calc_item_positions(bar);
326 } else if (active_statusbar_group != NULL) {
327 g_slist_foreach(active_statusbar_group->bars,
328 (GFunc) statusbar_redraw,
329 GINT_TO_POINTER(force));
333 void statusbar_item_redraw(SBAR_ITEM_REC *item)
335 WINDOW_REC *old_active_win;
337 g_return_if_fail(item != NULL);
339 old_active_win = active_win;
340 if (item->bar->parent_window != NULL)
341 active_win = item->bar->parent_window->active;
343 item->func(item, TRUE);
346 item->bar->dirty = TRUE;
349 if (item->max_size != item->size) {
350 /* item wants a new size - we'll need to redraw
351 the statusbar to see if this is allowed */
352 statusbar_redraw(item->bar, FALSE);
355 active_win = old_active_win;
358 void statusbar_items_redraw(const char *name)
360 g_slist_foreach(g_hash_table_lookup(named_sbar_items, name),
361 (GFunc) statusbar_item_redraw, NULL);
364 static void statusbars_recalc_ypos(STATUSBAR_REC *bar)
366 GSList *tmp, *bar_group;
369 /* get list of statusbars with same type and placement,
370 sorted by position */
372 tmp = bar->config->type == STATUSBAR_TYPE_ROOT ? bar->group->bars :
373 bar->parent_window->statusbars;
375 for (; tmp != NULL; tmp = tmp->next) {
376 STATUSBAR_REC *rec = tmp->data;
378 if (rec->config->type == bar->config->type &&
379 rec->config->placement == bar->config->placement) {
380 bar_group = g_slist_insert_sorted(bar_group, rec,
386 if (bar_group == NULL) {
387 /* we just destroyed the last statusbar in this
388 type/placement group */
392 /* get the Y-position for the first statusbar */
393 if (bar->config->type == STATUSBAR_TYPE_ROOT) {
394 ypos = bar->config->placement == STATUSBAR_TOP ? 0 :
395 term_height - g_slist_length(bar_group);
397 ypos = bar->config->placement == STATUSBAR_TOP ?
398 bar->parent_window->first_line :
399 bar->parent_window->last_line -
400 (g_slist_length(bar_group)-1);
403 /* set the Y-positions */
404 while (bar_group != NULL) {
405 bar = bar_group->data;
407 if (bar->real_ypos != ypos) {
408 bar->real_ypos = ypos;
409 statusbar_redraw(bar, TRUE);
413 bar_group = g_slist_remove(bar_group, bar_group->data);
417 static void sig_terminal_resized(void)
421 for (tmp = active_statusbar_group->bars; tmp != NULL; tmp = tmp->next) {
422 STATUSBAR_REC *bar = tmp->data;
424 if (bar->config->type == STATUSBAR_TYPE_ROOT &&
425 bar->config->placement == STATUSBAR_BOTTOM) {
426 statusbars_recalc_ypos(bar);
432 static void mainwindow_recalc_ypos(MAIN_WINDOW_REC *window, int placement)
436 for (tmp = window->statusbars; tmp != NULL; tmp = tmp->next) {
437 STATUSBAR_REC *bar = tmp->data;
439 if (bar->config->placement == placement) {
440 statusbars_recalc_ypos(bar);
446 static void sig_mainwindow_resized(MAIN_WINDOW_REC *window)
448 mainwindow_recalc_ypos(window, STATUSBAR_TOP);
449 mainwindow_recalc_ypos(window, STATUSBAR_BOTTOM);
452 STATUSBAR_REC *statusbar_create(STATUSBAR_GROUP_REC *group,
453 STATUSBAR_CONFIG_REC *config,
454 MAIN_WINDOW_REC *parent_window)
461 g_return_val_if_fail(group != NULL, NULL);
462 g_return_val_if_fail(config != NULL, NULL);
463 g_return_val_if_fail(config->type != STATUSBAR_TYPE_WINDOW ||
464 parent_window != NULL, NULL);
466 bar = g_new0(STATUSBAR_REC, 1);
467 group->bars = g_slist_append(group->bars, bar);
471 bar->config = config;
472 bar->parent_window = parent_window;
478 signal_remove("terminal resized", (SIGNAL_FUNC) sig_terminal_resized);
479 signal_remove("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
480 signal_remove("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
482 if (config->type == STATUSBAR_TYPE_ROOT) {
483 /* top/bottom of the screen */
484 mainwindows_reserve_lines(config->placement == STATUSBAR_TOP,
485 config->placement == STATUSBAR_BOTTOM);
486 theme = current_theme;
488 /* top/bottom of the window */
489 parent_window->statusbars =
490 g_slist_append(parent_window->statusbars, bar);
491 mainwindow_set_statusbar_lines(parent_window,
492 config->placement == STATUSBAR_TOP,
493 config->placement == STATUSBAR_BOTTOM);
494 theme = parent_window != NULL && parent_window->active != NULL &&
495 parent_window->active->theme != NULL ?
496 parent_window->active->theme : current_theme;
499 signal_add("terminal resized", (SIGNAL_FUNC) sig_terminal_resized);
500 signal_add("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
501 signal_add("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
503 /* get background color from sb_background abstract */
504 name = g_strdup_printf("{sb_%s_bg}", config->name);
505 value = theme_format_expand(theme, name);
508 if (*value == '\0') {
509 /* try with the statusbar group name */
512 name = g_strdup_printf("{sb_%s_bg}", group->name);
513 value = theme_format_expand(theme, name);
516 if (*value == '\0') {
517 /* fallback to default statusbar background
518 (also provides backwards compatibility..) */
520 value = theme_format_expand(theme, "{sb_background}");
524 if (*value == '\0') {
526 value = g_strdup("%8");
528 bar->color = g_strconcat("%n", value, NULL);
531 statusbars_recalc_ypos(bar);
532 signal_emit("statusbar created", 1, bar);
534 /* create the items to statusbar */
535 for (tmp = config->items; tmp != NULL; tmp = tmp->next) {
536 SBAR_ITEM_CONFIG_REC *rec = tmp->data;
538 statusbar_item_create(bar, rec);
543 void statusbar_destroy(STATUSBAR_REC *bar)
547 g_return_if_fail(bar != NULL);
549 bar->group->bars = g_slist_remove(bar->group->bars, bar);
550 if (bar->parent_window != NULL) {
551 bar->parent_window->statusbars =
552 g_slist_remove(bar->parent_window->statusbars, bar);
555 signal_emit("statusbar destroyed", 1, bar);
557 while (bar->items != NULL)
558 statusbar_item_destroy(bar->items->data);
562 if (bar->config->type != STATUSBAR_TYPE_WINDOW ||
563 bar->parent_window != NULL)
564 statusbars_recalc_ypos(bar);
566 top = bar->config->placement == STATUSBAR_TOP;
567 if (bar->config->type == STATUSBAR_TYPE_ROOT) {
568 /* top/bottom of the screen */
569 mainwindows_reserve_lines(top ? -1 : 0, !top ? -1 : 0);
570 } else if (bar->parent_window != NULL) {
571 /* top/bottom of the window */
572 mainwindow_set_statusbar_lines(bar->parent_window,
573 top ? -1 : 0, !top ? -1 : 0);
579 void statusbar_recreate_items(STATUSBAR_REC *bar)
584 while (bar->items != NULL)
585 statusbar_item_destroy(bar->items->data);
588 for (tmp = bar->config->items; tmp != NULL; tmp = tmp->next) {
589 SBAR_ITEM_CONFIG_REC *rec = tmp->data;
591 statusbar_item_create(bar, rec);
594 statusbar_redraw(bar, TRUE);
597 void statusbars_recreate_items(void)
599 if (active_statusbar_group != NULL) {
600 g_slist_foreach(active_statusbar_group->bars,
601 (GFunc) statusbar_recreate_items, NULL);
605 STATUSBAR_REC *statusbar_find(STATUSBAR_GROUP_REC *group, const char *name,
606 MAIN_WINDOW_REC *window)
610 for (tmp = group->bars; tmp != NULL; tmp = tmp->next) {
611 STATUSBAR_REC *rec = tmp->data;
613 if (rec->parent_window == window &&
614 strcmp(rec->config->name, name) == 0)
621 static char *update_statusbar_bg(const char *str, const char *color)
626 out = g_string_new(color);
627 while (*str != '\0') {
628 if (*str == '%' && str[1] == 'n') {
629 g_string_append(out, color);
634 g_string_append_c(out, *str);
639 g_string_free(out, FALSE);
643 const char *statusbar_item_get_value(SBAR_ITEM_REC *item)
647 value = item->config->value;
649 value = g_hash_table_lookup(sbar_item_defs,
656 static char *reverse_controls(const char *str)
661 out = g_string_new(NULL);
663 while (*str != '\0') {
664 if ((unsigned char) *str < 32 ||
665 (term_type == TERM_TYPE_8BIT &&
666 (unsigned char) (*str & 0x7f) < 32)) {
668 g_string_sprintfa(out, "%%8%c%%8",
669 'A'-1 + (*str & 0x7f));
671 g_string_append_c(out, *str);
678 g_string_free(out, FALSE);
682 void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only,
683 const char *str, const char *data,
688 char *tmpstr, *tmpstr2;
692 str = statusbar_item_get_value(item);
693 if (str == NULL || *str == '\0') {
694 item->min_size = item->max_size = 0;
698 if (active_win == NULL) {
702 server = active_win->active_server;
703 wiitem = active_win->active;
706 /* expand templates */
707 tmpstr = theme_format_expand_data(current_theme, &str,
711 EXPAND_FLAG_IGNORE_REPLACES |
712 EXPAND_FLAG_IGNORE_EMPTY);
713 /* expand $variables */
714 tmpstr2 = parse_special_string(tmpstr, server, wiitem, data, NULL,
715 (escape_vars ? PARSE_FLAG_ESCAPE_VARS : 0 ));
718 /* remove color codes (not %formats) */
719 tmpstr = strip_codes(tmpstr2);
722 /* show all control chars reversed */
723 tmpstr2 = reverse_controls(tmpstr);
728 item->min_size = item->max_size = format_get_length(tmpstr);
730 if (item->size < item->min_size) {
731 /* they're forcing us smaller than minimum size.. */
732 len = format_real_length(tmpstr, item->size);
736 tmpstr2 = update_statusbar_bg(tmpstr, item->bar->color);
737 gui_printtext(item->xpos, item->bar->real_ypos, tmpstr2);
743 static void statusbar_item_default_func(SBAR_ITEM_REC *item, int get_size_only)
745 statusbar_item_default_handler(item, get_size_only, NULL, "", TRUE);
748 static void statusbar_update_item(void)
752 items = g_hash_table_lookup(sbar_signal_items,
753 GINT_TO_POINTER(signal_get_emitted_id()));
754 while (items != NULL) {
755 SBAR_ITEM_REC *item = items->data;
757 statusbar_item_redraw(item);
762 static void statusbar_update_server(SERVER_REC *server)
764 SERVER_REC *item_server;
767 items = g_hash_table_lookup(sbar_signal_items,
768 GINT_TO_POINTER(signal_get_emitted_id()));
769 while (items != NULL) {
770 SBAR_ITEM_REC *item = items->data;
772 item_server = item->bar->parent_window != NULL ?
773 item->bar->parent_window->active->active_server :
774 active_win->active_server;
776 if (item_server == server)
777 statusbar_item_redraw(item);
783 static void statusbar_update_window(WINDOW_REC *window)
785 WINDOW_REC *item_window;
788 items = g_hash_table_lookup(sbar_signal_items,
789 GINT_TO_POINTER(signal_get_emitted_id()));
790 while (items != NULL) {
791 SBAR_ITEM_REC *item = items->data;
793 item_window = item->bar->parent_window != NULL ?
794 item->bar->parent_window->active : active_win;
796 if (item_window == window)
797 statusbar_item_redraw(item);
803 static void statusbar_update_window_item(WI_ITEM_REC *wiitem)
805 WI_ITEM_REC *item_wi;
808 items = g_hash_table_lookup(sbar_signal_items,
809 GINT_TO_POINTER(signal_get_emitted_id()));
810 while (items != NULL) {
811 SBAR_ITEM_REC *item = items->data;
813 item_wi = item->bar->parent_window != NULL ?
814 item->bar->parent_window->active->active :
817 if (item_wi == wiitem)
818 statusbar_item_redraw(item);
824 static void statusbar_item_default_signals(SBAR_ITEM_REC *item)
832 value = statusbar_item_get_value(item);
836 signals = special_vars_get_signals(value);
840 for (pos = signals; *pos != -1; pos += 2) {
841 /* update signal -> item mappings */
842 signal_id = GINT_TO_POINTER(*pos);
843 list = g_hash_table_lookup(sbar_signal_items, signal_id);
846 case EXPANDO_ARG_NONE:
847 func = (SIGNAL_FUNC) statusbar_update_item;
849 case EXPANDO_ARG_SERVER:
850 func = (SIGNAL_FUNC) statusbar_update_server;
852 case EXPANDO_ARG_WINDOW:
853 func = (SIGNAL_FUNC) statusbar_update_window;
855 case EXPANDO_ARG_WINDOW_ITEM:
856 func = (SIGNAL_FUNC) statusbar_update_window_item;
863 signal_add_full_id(MODULE_NAME,
864 SIGNAL_PRIORITY_DEFAULT,
869 if (g_slist_find(list, item) == NULL)
870 list = g_slist_append(list, item);
871 g_hash_table_insert(sbar_signal_items, signal_id, list);
873 /* update item -> signal mappings */
874 list = g_hash_table_lookup(sbar_item_signals, item);
875 if (g_slist_find(list, signal_id) == NULL)
876 list = g_slist_append(list, signal_id);
877 g_hash_table_insert(sbar_item_signals, item, list);
882 SBAR_ITEM_REC *statusbar_item_create(STATUSBAR_REC *bar,
883 SBAR_ITEM_CONFIG_REC *config)
888 g_return_val_if_fail(bar != NULL, NULL);
889 g_return_val_if_fail(config != NULL, NULL);
891 rec = g_new0(SBAR_ITEM_REC, 1);
892 bar->items = g_slist_append(bar->items, rec);
895 rec->config = config;
897 rec->func = (STATUSBAR_FUNC) g_hash_table_lookup(sbar_item_funcs,
899 if (rec->func == NULL)
900 rec->func = statusbar_item_default_func;
901 statusbar_item_default_signals(rec);
903 items = g_hash_table_lookup(named_sbar_items, config->name);
904 items = g_slist_append(items, rec);
905 g_hash_table_insert(named_sbar_items, config->name, items);
911 signal_emit("statusbar item created", 1, rec);
915 static void statusbar_signal_remove(int signal_id)
917 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_item, NULL);
918 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_server, NULL);
919 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_window, NULL);
920 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_window_item, NULL);
923 static void statusbar_item_remove_signal(SBAR_ITEM_REC *item, int signal_id)
927 /* update signal -> item hash */
928 list = g_hash_table_lookup(sbar_signal_items,
929 GINT_TO_POINTER(signal_id));
930 list = g_slist_remove(list, item);
932 g_hash_table_insert(sbar_signal_items,
933 GINT_TO_POINTER(signal_id), list);
935 g_hash_table_remove(sbar_signal_items,
936 GINT_TO_POINTER(signal_id));
937 statusbar_signal_remove(signal_id);
941 void statusbar_item_destroy(SBAR_ITEM_REC *item)
945 g_return_if_fail(item != NULL);
947 item->bar->items = g_slist_remove(item->bar->items, item);
949 list = g_hash_table_lookup(named_sbar_items, item->config->name);
950 list = g_slist_remove(list, item);
952 g_hash_table_remove(named_sbar_items, item->config->name);
954 g_hash_table_insert(named_sbar_items, item->config->name, list);
956 signal_emit("statusbar item destroyed", 1, item);
958 list = g_hash_table_lookup(sbar_item_signals, item);
959 g_hash_table_remove(sbar_item_signals, item);
961 while (list != NULL) {
962 statusbar_item_remove_signal(item, GPOINTER_TO_INT(list->data));
963 list = g_slist_remove(list, list->data);
969 static void statusbar_redraw_needed_items(STATUSBAR_REC *bar)
971 WINDOW_REC *old_active_win;
975 old_active_win = active_win;
976 if (bar->parent_window != NULL)
977 active_win = bar->parent_window->active;
979 if (bar->dirty_xpos >= 0) {
980 str = g_strconcat(bar->color, "%>", NULL);
981 gui_printtext(bar->dirty_xpos, bar->real_ypos, str);
985 for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
986 SBAR_ITEM_REC *rec = tmp->data;
989 (bar->dirty_xpos != -1 &&
990 rec->xpos >= bar->dirty_xpos)) {
991 rec->current_size = rec->size;
992 rec->func(rec, FALSE);
997 active_win = old_active_win;
1000 void statusbar_redraw_dirty(void)
1004 if (statusbar_need_recreate_items) {
1005 statusbar_need_recreate_items = FALSE;
1006 statusbars_recreate_items();
1009 for (tmp = active_statusbar_group->bars; tmp != NULL; tmp = tmp->next) {
1010 STATUSBAR_REC *rec = tmp->data;
1013 statusbar_redraw_needed_items(rec);
1015 rec->dirty_xpos = -1;
1020 #define STATUSBAR_IS_VISIBLE(bar, window) \
1021 ((bar)->visible == STATUSBAR_VISIBLE_ALWAYS || \
1022 (active_mainwin == (window) && \
1023 (bar)->visible == STATUSBAR_VISIBLE_ACTIVE) || \
1024 (active_mainwin != (window) && \
1025 (bar)->visible == STATUSBAR_VISIBLE_INACTIVE))
1027 static void statusbars_remove_unvisible(MAIN_WINDOW_REC *window)
1031 for (tmp = window->statusbars; tmp != NULL; tmp = next) {
1032 STATUSBAR_REC *bar = tmp->data;
1035 if (!STATUSBAR_IS_VISIBLE(bar->config, window))
1036 statusbar_destroy(bar);
1040 static void statusbars_add_visible(MAIN_WINDOW_REC *window)
1042 STATUSBAR_GROUP_REC *group;
1046 group = active_statusbar_group;
1047 for (tmp = group->config_bars; tmp != NULL; tmp = tmp->next) {
1048 STATUSBAR_CONFIG_REC *config = tmp->data;
1050 if (config->type == STATUSBAR_TYPE_WINDOW &&
1051 STATUSBAR_IS_VISIBLE(config, window) &&
1052 statusbar_find(group, config->name, window) == NULL) {
1053 bar = statusbar_create(group, config, window);
1054 statusbar_redraw(bar, TRUE);
1059 static void sig_mainwindow_destroyed(MAIN_WINDOW_REC *window)
1061 while (window->statusbars != NULL) {
1062 STATUSBAR_REC *bar = window->statusbars->data;
1064 bar->parent_window->statusbars =
1065 g_slist_remove(bar->parent_window->statusbars, bar);
1066 bar->parent_window = NULL;
1067 statusbar_destroy(bar);
1071 static void sig_window_changed(void)
1075 for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
1076 MAIN_WINDOW_REC *rec = tmp->data;
1078 statusbars_remove_unvisible(rec);
1079 statusbars_add_visible(rec);
1083 static void sig_gui_window_created(WINDOW_REC *window)
1085 statusbars_add_visible(WINDOW_MAIN(window));
1088 static void statusbar_item_def_destroy(void *key, void *value)
1094 static void statusbar_signal_item_destroy(void *key, GSList *value)
1096 while (value != NULL) {
1097 statusbar_signal_remove(GPOINTER_TO_INT(value->data));
1098 value->data = g_slist_remove(value, value->data);
1102 static void statusbar_item_signal_destroy(void *key, GSList *value)
1104 g_slist_free(value);
1107 void statusbars_create_window_bars(void)
1109 g_slist_foreach(mainwindows, (GFunc) statusbars_add_visible, NULL);
1112 void statusbar_init(void)
1114 statusbar_need_recreate_items = FALSE;
1115 statusbar_groups = NULL;
1116 active_statusbar_group = NULL;
1117 sbar_item_defs = g_hash_table_new((GHashFunc) g_str_hash,
1118 (GCompareFunc) g_str_equal);
1119 sbar_item_funcs = g_hash_table_new((GHashFunc) g_str_hash,
1120 (GCompareFunc) g_str_equal);
1121 sbar_signal_items = g_hash_table_new((GHashFunc) g_direct_hash,
1122 (GCompareFunc) g_direct_equal);
1123 sbar_item_signals = g_hash_table_new((GHashFunc) g_direct_hash,
1124 (GCompareFunc) g_direct_equal);
1125 named_sbar_items = g_hash_table_new((GHashFunc) g_str_hash,
1126 (GCompareFunc) g_str_equal);
1128 signal_add("terminal resized", (SIGNAL_FUNC) sig_terminal_resized);
1129 signal_add("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
1130 signal_add("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
1131 signal_add("gui window created", (SIGNAL_FUNC) sig_gui_window_created);
1132 signal_add("window changed", (SIGNAL_FUNC) sig_window_changed);
1133 signal_add("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
1135 statusbar_items_init();
1136 statusbar_config_init(); /* signals need to be before this call */
1139 void statusbar_deinit(void)
1141 while (statusbar_groups != NULL)
1142 statusbar_group_destroy(statusbar_groups->data);
1144 g_hash_table_foreach(sbar_item_defs,
1145 (GHFunc) statusbar_item_def_destroy, NULL);
1146 g_hash_table_destroy(sbar_item_defs);
1148 g_hash_table_foreach(sbar_item_funcs, (GHFunc) g_free, NULL);
1149 g_hash_table_destroy(sbar_item_funcs);
1151 g_hash_table_foreach(sbar_signal_items,
1152 (GHFunc) statusbar_signal_item_destroy, NULL);
1153 g_hash_table_destroy(sbar_signal_items);
1154 g_hash_table_foreach(sbar_item_signals,
1155 (GHFunc) statusbar_item_signal_destroy, NULL);
1156 g_hash_table_destroy(sbar_item_signals);
1157 g_hash_table_destroy(named_sbar_items);
1159 signal_remove("terminal resized", (SIGNAL_FUNC) sig_terminal_resized);
1160 signal_remove("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
1161 signal_remove("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
1162 signal_remove("gui window created", (SIGNAL_FUNC) sig_gui_window_created);
1163 signal_remove("window changed", (SIGNAL_FUNC) sig_window_changed);
1164 signal_remove("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
1166 statusbar_items_deinit();
1167 statusbar_config_deinit();