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 != NULL ?
703 active_win->active_server : active_win->connect_server;
704 wiitem = active_win->active;
707 /* expand templates */
708 tmpstr = theme_format_expand_data(current_theme, &str,
712 EXPAND_FLAG_IGNORE_REPLACES |
713 EXPAND_FLAG_IGNORE_EMPTY);
714 /* expand $variables */
715 tmpstr2 = parse_special_string(tmpstr, server, wiitem, data, NULL,
716 (escape_vars ? PARSE_FLAG_ESCAPE_VARS : 0 ));
719 /* remove color codes (not %formats) */
720 tmpstr = strip_codes(tmpstr2);
723 /* show all control chars reversed */
724 tmpstr2 = reverse_controls(tmpstr);
729 item->min_size = item->max_size = format_get_length(tmpstr);
731 if (item->size < item->min_size) {
732 /* they're forcing us smaller than minimum size.. */
733 len = format_real_length(tmpstr, item->size);
736 /* make sure the str is big enough to fill the
737 requested size, so it won't corrupt screen */
738 len = format_get_length(tmpstr);
739 if (len < item->size) {
742 len = item->size-len;
743 fill = g_malloc(len + 1);
744 memset(fill, ' ', len); fill[len] = '\0';
746 tmpstr2 = g_strconcat(tmpstr, fill, NULL);
753 tmpstr2 = update_statusbar_bg(tmpstr, item->bar->color);
754 gui_printtext(item->xpos, item->bar->real_ypos, tmpstr2);
760 static void statusbar_item_default_func(SBAR_ITEM_REC *item, int get_size_only)
762 statusbar_item_default_handler(item, get_size_only, NULL, "", TRUE);
765 static void statusbar_update_item(void)
769 items = g_hash_table_lookup(sbar_signal_items,
770 GINT_TO_POINTER(signal_get_emitted_id()));
771 while (items != NULL) {
772 SBAR_ITEM_REC *item = items->data;
774 statusbar_item_redraw(item);
779 static void statusbar_update_server(SERVER_REC *server)
781 SERVER_REC *item_server;
784 items = g_hash_table_lookup(sbar_signal_items,
785 GINT_TO_POINTER(signal_get_emitted_id()));
786 while (items != NULL) {
787 SBAR_ITEM_REC *item = items->data;
789 item_server = item->bar->parent_window != NULL ?
790 item->bar->parent_window->active->active_server :
791 active_win->active_server;
793 if (item_server == server)
794 statusbar_item_redraw(item);
800 static void statusbar_update_window(WINDOW_REC *window)
802 WINDOW_REC *item_window;
805 items = g_hash_table_lookup(sbar_signal_items,
806 GINT_TO_POINTER(signal_get_emitted_id()));
807 while (items != NULL) {
808 SBAR_ITEM_REC *item = items->data;
810 item_window = item->bar->parent_window != NULL ?
811 item->bar->parent_window->active : active_win;
813 if (item_window == window)
814 statusbar_item_redraw(item);
820 static void statusbar_update_window_item(WI_ITEM_REC *wiitem)
822 WI_ITEM_REC *item_wi;
825 items = g_hash_table_lookup(sbar_signal_items,
826 GINT_TO_POINTER(signal_get_emitted_id()));
827 while (items != NULL) {
828 SBAR_ITEM_REC *item = items->data;
830 item_wi = item->bar->parent_window != NULL ?
831 item->bar->parent_window->active->active :
834 if (item_wi == wiitem)
835 statusbar_item_redraw(item);
841 static void statusbar_item_default_signals(SBAR_ITEM_REC *item)
849 value = statusbar_item_get_value(item);
853 signals = special_vars_get_signals(value);
857 for (pos = signals; *pos != -1; pos += 2) {
858 /* update signal -> item mappings */
859 signal_id = GINT_TO_POINTER(*pos);
860 list = g_hash_table_lookup(sbar_signal_items, signal_id);
863 case EXPANDO_ARG_NONE:
864 func = (SIGNAL_FUNC) statusbar_update_item;
866 case EXPANDO_ARG_SERVER:
867 func = (SIGNAL_FUNC) statusbar_update_server;
869 case EXPANDO_ARG_WINDOW:
870 func = (SIGNAL_FUNC) statusbar_update_window;
872 case EXPANDO_ARG_WINDOW_ITEM:
873 func = (SIGNAL_FUNC) statusbar_update_window_item;
880 signal_add_full_id(MODULE_NAME,
881 SIGNAL_PRIORITY_DEFAULT,
886 if (g_slist_find(list, item) == NULL)
887 list = g_slist_append(list, item);
888 g_hash_table_insert(sbar_signal_items, signal_id, list);
890 /* update item -> signal mappings */
891 list = g_hash_table_lookup(sbar_item_signals, item);
892 if (g_slist_find(list, signal_id) == NULL)
893 list = g_slist_append(list, signal_id);
894 g_hash_table_insert(sbar_item_signals, item, list);
899 SBAR_ITEM_REC *statusbar_item_create(STATUSBAR_REC *bar,
900 SBAR_ITEM_CONFIG_REC *config)
905 g_return_val_if_fail(bar != NULL, NULL);
906 g_return_val_if_fail(config != NULL, NULL);
908 rec = g_new0(SBAR_ITEM_REC, 1);
909 bar->items = g_slist_append(bar->items, rec);
912 rec->config = config;
914 rec->func = (STATUSBAR_FUNC) g_hash_table_lookup(sbar_item_funcs,
916 if (rec->func == NULL)
917 rec->func = statusbar_item_default_func;
918 statusbar_item_default_signals(rec);
920 items = g_hash_table_lookup(named_sbar_items, config->name);
921 items = g_slist_append(items, rec);
922 g_hash_table_insert(named_sbar_items, config->name, items);
928 signal_emit("statusbar item created", 1, rec);
932 static void statusbar_signal_remove(int signal_id)
934 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_item, NULL);
935 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_server, NULL);
936 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_window, NULL);
937 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_window_item, NULL);
940 static void statusbar_item_remove_signal(SBAR_ITEM_REC *item, int signal_id)
944 /* update signal -> item hash */
945 list = g_hash_table_lookup(sbar_signal_items,
946 GINT_TO_POINTER(signal_id));
947 list = g_slist_remove(list, item);
949 g_hash_table_insert(sbar_signal_items,
950 GINT_TO_POINTER(signal_id), list);
952 g_hash_table_remove(sbar_signal_items,
953 GINT_TO_POINTER(signal_id));
954 statusbar_signal_remove(signal_id);
958 void statusbar_item_destroy(SBAR_ITEM_REC *item)
962 g_return_if_fail(item != NULL);
964 item->bar->items = g_slist_remove(item->bar->items, item);
966 list = g_hash_table_lookup(named_sbar_items, item->config->name);
967 list = g_slist_remove(list, item);
969 g_hash_table_remove(named_sbar_items, item->config->name);
971 g_hash_table_insert(named_sbar_items, item->config->name, list);
973 signal_emit("statusbar item destroyed", 1, item);
975 list = g_hash_table_lookup(sbar_item_signals, item);
976 g_hash_table_remove(sbar_item_signals, item);
978 while (list != NULL) {
979 statusbar_item_remove_signal(item, GPOINTER_TO_INT(list->data));
980 list = g_slist_remove(list, list->data);
986 static void statusbar_redraw_needed_items(STATUSBAR_REC *bar)
988 WINDOW_REC *old_active_win;
992 old_active_win = active_win;
993 if (bar->parent_window != NULL)
994 active_win = bar->parent_window->active;
996 if (bar->dirty_xpos >= 0) {
997 str = g_strconcat(bar->color, "%>", NULL);
998 gui_printtext(bar->dirty_xpos, bar->real_ypos, str);
1002 for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
1003 SBAR_ITEM_REC *rec = tmp->data;
1006 (bar->dirty_xpos != -1 &&
1007 rec->xpos >= bar->dirty_xpos)) {
1008 rec->current_size = rec->size;
1009 rec->func(rec, FALSE);
1014 active_win = old_active_win;
1017 void statusbar_redraw_dirty(void)
1021 if (statusbar_need_recreate_items) {
1022 statusbar_need_recreate_items = FALSE;
1023 statusbars_recreate_items();
1026 for (tmp = active_statusbar_group->bars; tmp != NULL; tmp = tmp->next) {
1027 STATUSBAR_REC *rec = tmp->data;
1030 statusbar_redraw_needed_items(rec);
1032 rec->dirty_xpos = -1;
1037 #define STATUSBAR_IS_VISIBLE(bar, window) \
1038 ((bar)->visible == STATUSBAR_VISIBLE_ALWAYS || \
1039 (active_mainwin == (window) && \
1040 (bar)->visible == STATUSBAR_VISIBLE_ACTIVE) || \
1041 (active_mainwin != (window) && \
1042 (bar)->visible == STATUSBAR_VISIBLE_INACTIVE))
1044 static void statusbars_remove_unvisible(MAIN_WINDOW_REC *window)
1048 for (tmp = window->statusbars; tmp != NULL; tmp = next) {
1049 STATUSBAR_REC *bar = tmp->data;
1052 if (!STATUSBAR_IS_VISIBLE(bar->config, window))
1053 statusbar_destroy(bar);
1057 static void statusbars_add_visible(MAIN_WINDOW_REC *window)
1059 STATUSBAR_GROUP_REC *group;
1063 group = active_statusbar_group;
1064 for (tmp = group->config_bars; tmp != NULL; tmp = tmp->next) {
1065 STATUSBAR_CONFIG_REC *config = tmp->data;
1067 if (config->type == STATUSBAR_TYPE_WINDOW &&
1068 STATUSBAR_IS_VISIBLE(config, window) &&
1069 statusbar_find(group, config->name, window) == NULL) {
1070 bar = statusbar_create(group, config, window);
1071 statusbar_redraw(bar, TRUE);
1076 static void sig_mainwindow_destroyed(MAIN_WINDOW_REC *window)
1078 while (window->statusbars != NULL) {
1079 STATUSBAR_REC *bar = window->statusbars->data;
1081 bar->parent_window->statusbars =
1082 g_slist_remove(bar->parent_window->statusbars, bar);
1083 bar->parent_window = NULL;
1084 statusbar_destroy(bar);
1088 static void sig_window_changed(void)
1092 for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
1093 MAIN_WINDOW_REC *rec = tmp->data;
1095 statusbars_remove_unvisible(rec);
1096 statusbars_add_visible(rec);
1100 static void sig_gui_window_created(WINDOW_REC *window)
1102 statusbars_add_visible(WINDOW_MAIN(window));
1105 static void statusbar_item_def_destroy(void *key, void *value)
1111 static void statusbar_signal_item_destroy(void *key, GSList *value)
1113 while (value != NULL) {
1114 statusbar_signal_remove(GPOINTER_TO_INT(value->data));
1115 value->data = g_slist_remove(value, value->data);
1119 static void statusbar_item_signal_destroy(void *key, GSList *value)
1121 g_slist_free(value);
1124 void statusbars_create_window_bars(void)
1126 g_slist_foreach(mainwindows, (GFunc) statusbars_add_visible, NULL);
1129 void statusbar_init(void)
1131 statusbar_need_recreate_items = FALSE;
1132 statusbar_groups = NULL;
1133 active_statusbar_group = NULL;
1134 sbar_item_defs = g_hash_table_new((GHashFunc) g_str_hash,
1135 (GCompareFunc) g_str_equal);
1136 sbar_item_funcs = g_hash_table_new((GHashFunc) g_str_hash,
1137 (GCompareFunc) g_str_equal);
1138 sbar_signal_items = g_hash_table_new((GHashFunc) g_direct_hash,
1139 (GCompareFunc) g_direct_equal);
1140 sbar_item_signals = g_hash_table_new((GHashFunc) g_direct_hash,
1141 (GCompareFunc) g_direct_equal);
1142 named_sbar_items = g_hash_table_new((GHashFunc) g_str_hash,
1143 (GCompareFunc) g_str_equal);
1145 signal_add("terminal resized", (SIGNAL_FUNC) sig_terminal_resized);
1146 signal_add("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
1147 signal_add("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
1148 signal_add("gui window created", (SIGNAL_FUNC) sig_gui_window_created);
1149 signal_add("window changed", (SIGNAL_FUNC) sig_window_changed);
1150 signal_add("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
1152 statusbar_items_init();
1153 statusbar_config_init(); /* signals need to be before this call */
1156 void statusbar_deinit(void)
1158 while (statusbar_groups != NULL)
1159 statusbar_group_destroy(statusbar_groups->data);
1161 g_hash_table_foreach(sbar_item_defs,
1162 (GHFunc) statusbar_item_def_destroy, NULL);
1163 g_hash_table_destroy(sbar_item_defs);
1165 g_hash_table_foreach(sbar_item_funcs, (GHFunc) g_free, NULL);
1166 g_hash_table_destroy(sbar_item_funcs);
1168 g_hash_table_foreach(sbar_signal_items,
1169 (GHFunc) statusbar_signal_item_destroy, NULL);
1170 g_hash_table_destroy(sbar_signal_items);
1171 g_hash_table_foreach(sbar_item_signals,
1172 (GHFunc) statusbar_item_signal_destroy, NULL);
1173 g_hash_table_destroy(sbar_item_signals);
1174 g_hash_table_destroy(named_sbar_items);
1176 signal_remove("terminal resized", (SIGNAL_FUNC) sig_terminal_resized);
1177 signal_remove("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
1178 signal_remove("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
1179 signal_remove("gui window created", (SIGNAL_FUNC) sig_gui_window_created);
1180 signal_remove("window changed", (SIGNAL_FUNC) sig_window_changed);
1181 signal_remove("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
1183 statusbar_items_deinit();
1184 statusbar_config_deinit();