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);
735 /* make sure the str is big enough to fill the
736 requested size, so it won't corrupt screen */
737 len = format_get_length(tmpstr);
738 if (len < item->size) {
741 len = item->size-len;
742 fill = g_malloc(len + 1);
743 memset(fill, ' ', len); fill[len] = '\0';
745 tmpstr2 = g_strconcat(tmpstr, fill, NULL);
752 tmpstr2 = update_statusbar_bg(tmpstr, item->bar->color);
753 gui_printtext(item->xpos, item->bar->real_ypos, tmpstr2);
759 static void statusbar_item_default_func(SBAR_ITEM_REC *item, int get_size_only)
761 statusbar_item_default_handler(item, get_size_only, NULL, "", TRUE);
764 static void statusbar_update_item(void)
768 items = g_hash_table_lookup(sbar_signal_items,
769 GINT_TO_POINTER(signal_get_emitted_id()));
770 while (items != NULL) {
771 SBAR_ITEM_REC *item = items->data;
773 statusbar_item_redraw(item);
778 static void statusbar_update_server(SERVER_REC *server)
780 SERVER_REC *item_server;
783 items = g_hash_table_lookup(sbar_signal_items,
784 GINT_TO_POINTER(signal_get_emitted_id()));
785 while (items != NULL) {
786 SBAR_ITEM_REC *item = items->data;
788 item_server = item->bar->parent_window != NULL ?
789 item->bar->parent_window->active->active_server :
790 active_win->active_server;
792 if (item_server == server)
793 statusbar_item_redraw(item);
799 static void statusbar_update_window(WINDOW_REC *window)
801 WINDOW_REC *item_window;
804 items = g_hash_table_lookup(sbar_signal_items,
805 GINT_TO_POINTER(signal_get_emitted_id()));
806 while (items != NULL) {
807 SBAR_ITEM_REC *item = items->data;
809 item_window = item->bar->parent_window != NULL ?
810 item->bar->parent_window->active : active_win;
812 if (item_window == window)
813 statusbar_item_redraw(item);
819 static void statusbar_update_window_item(WI_ITEM_REC *wiitem)
821 WI_ITEM_REC *item_wi;
824 items = g_hash_table_lookup(sbar_signal_items,
825 GINT_TO_POINTER(signal_get_emitted_id()));
826 while (items != NULL) {
827 SBAR_ITEM_REC *item = items->data;
829 item_wi = item->bar->parent_window != NULL ?
830 item->bar->parent_window->active->active :
833 if (item_wi == wiitem)
834 statusbar_item_redraw(item);
840 static void statusbar_item_default_signals(SBAR_ITEM_REC *item)
848 value = statusbar_item_get_value(item);
852 signals = special_vars_get_signals(value);
856 for (pos = signals; *pos != -1; pos += 2) {
857 /* update signal -> item mappings */
858 signal_id = GINT_TO_POINTER(*pos);
859 list = g_hash_table_lookup(sbar_signal_items, signal_id);
862 case EXPANDO_ARG_NONE:
863 func = (SIGNAL_FUNC) statusbar_update_item;
865 case EXPANDO_ARG_SERVER:
866 func = (SIGNAL_FUNC) statusbar_update_server;
868 case EXPANDO_ARG_WINDOW:
869 func = (SIGNAL_FUNC) statusbar_update_window;
871 case EXPANDO_ARG_WINDOW_ITEM:
872 func = (SIGNAL_FUNC) statusbar_update_window_item;
879 signal_add_full_id(MODULE_NAME,
880 SIGNAL_PRIORITY_DEFAULT,
885 if (g_slist_find(list, item) == NULL)
886 list = g_slist_append(list, item);
887 g_hash_table_insert(sbar_signal_items, signal_id, list);
889 /* update item -> signal mappings */
890 list = g_hash_table_lookup(sbar_item_signals, item);
891 if (g_slist_find(list, signal_id) == NULL)
892 list = g_slist_append(list, signal_id);
893 g_hash_table_insert(sbar_item_signals, item, list);
898 SBAR_ITEM_REC *statusbar_item_create(STATUSBAR_REC *bar,
899 SBAR_ITEM_CONFIG_REC *config)
904 g_return_val_if_fail(bar != NULL, NULL);
905 g_return_val_if_fail(config != NULL, NULL);
907 rec = g_new0(SBAR_ITEM_REC, 1);
908 bar->items = g_slist_append(bar->items, rec);
911 rec->config = config;
913 rec->func = (STATUSBAR_FUNC) g_hash_table_lookup(sbar_item_funcs,
915 if (rec->func == NULL)
916 rec->func = statusbar_item_default_func;
917 statusbar_item_default_signals(rec);
919 items = g_hash_table_lookup(named_sbar_items, config->name);
920 items = g_slist_append(items, rec);
921 g_hash_table_insert(named_sbar_items, config->name, items);
927 signal_emit("statusbar item created", 1, rec);
931 static void statusbar_signal_remove(int signal_id)
933 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_item, NULL);
934 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_server, NULL);
935 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_window, NULL);
936 signal_remove_id(signal_id, (SIGNAL_FUNC) statusbar_update_window_item, NULL);
939 static void statusbar_item_remove_signal(SBAR_ITEM_REC *item, int signal_id)
943 /* update signal -> item hash */
944 list = g_hash_table_lookup(sbar_signal_items,
945 GINT_TO_POINTER(signal_id));
946 list = g_slist_remove(list, item);
948 g_hash_table_insert(sbar_signal_items,
949 GINT_TO_POINTER(signal_id), list);
951 g_hash_table_remove(sbar_signal_items,
952 GINT_TO_POINTER(signal_id));
953 statusbar_signal_remove(signal_id);
957 void statusbar_item_destroy(SBAR_ITEM_REC *item)
961 g_return_if_fail(item != NULL);
963 item->bar->items = g_slist_remove(item->bar->items, item);
965 list = g_hash_table_lookup(named_sbar_items, item->config->name);
966 list = g_slist_remove(list, item);
968 g_hash_table_remove(named_sbar_items, item->config->name);
970 g_hash_table_insert(named_sbar_items, item->config->name, list);
972 signal_emit("statusbar item destroyed", 1, item);
974 list = g_hash_table_lookup(sbar_item_signals, item);
975 g_hash_table_remove(sbar_item_signals, item);
977 while (list != NULL) {
978 statusbar_item_remove_signal(item, GPOINTER_TO_INT(list->data));
979 list = g_slist_remove(list, list->data);
985 static void statusbar_redraw_needed_items(STATUSBAR_REC *bar)
987 WINDOW_REC *old_active_win;
991 old_active_win = active_win;
992 if (bar->parent_window != NULL)
993 active_win = bar->parent_window->active;
995 if (bar->dirty_xpos >= 0) {
996 str = g_strconcat(bar->color, "%>", NULL);
997 gui_printtext(bar->dirty_xpos, bar->real_ypos, str);
1001 for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
1002 SBAR_ITEM_REC *rec = tmp->data;
1005 (bar->dirty_xpos != -1 &&
1006 rec->xpos >= bar->dirty_xpos)) {
1007 rec->current_size = rec->size;
1008 rec->func(rec, FALSE);
1013 active_win = old_active_win;
1016 void statusbar_redraw_dirty(void)
1020 if (statusbar_need_recreate_items) {
1021 statusbar_need_recreate_items = FALSE;
1022 statusbars_recreate_items();
1025 for (tmp = active_statusbar_group->bars; tmp != NULL; tmp = tmp->next) {
1026 STATUSBAR_REC *rec = tmp->data;
1029 statusbar_redraw_needed_items(rec);
1031 rec->dirty_xpos = -1;
1036 #define STATUSBAR_IS_VISIBLE(bar, window) \
1037 ((bar)->visible == STATUSBAR_VISIBLE_ALWAYS || \
1038 (active_mainwin == (window) && \
1039 (bar)->visible == STATUSBAR_VISIBLE_ACTIVE) || \
1040 (active_mainwin != (window) && \
1041 (bar)->visible == STATUSBAR_VISIBLE_INACTIVE))
1043 static void statusbars_remove_unvisible(MAIN_WINDOW_REC *window)
1047 for (tmp = window->statusbars; tmp != NULL; tmp = next) {
1048 STATUSBAR_REC *bar = tmp->data;
1051 if (!STATUSBAR_IS_VISIBLE(bar->config, window))
1052 statusbar_destroy(bar);
1056 static void statusbars_add_visible(MAIN_WINDOW_REC *window)
1058 STATUSBAR_GROUP_REC *group;
1062 group = active_statusbar_group;
1063 for (tmp = group->config_bars; tmp != NULL; tmp = tmp->next) {
1064 STATUSBAR_CONFIG_REC *config = tmp->data;
1066 if (config->type == STATUSBAR_TYPE_WINDOW &&
1067 STATUSBAR_IS_VISIBLE(config, window) &&
1068 statusbar_find(group, config->name, window) == NULL) {
1069 bar = statusbar_create(group, config, window);
1070 statusbar_redraw(bar, TRUE);
1075 static void sig_mainwindow_destroyed(MAIN_WINDOW_REC *window)
1077 while (window->statusbars != NULL) {
1078 STATUSBAR_REC *bar = window->statusbars->data;
1080 bar->parent_window->statusbars =
1081 g_slist_remove(bar->parent_window->statusbars, bar);
1082 bar->parent_window = NULL;
1083 statusbar_destroy(bar);
1087 static void sig_window_changed(void)
1091 for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
1092 MAIN_WINDOW_REC *rec = tmp->data;
1094 statusbars_remove_unvisible(rec);
1095 statusbars_add_visible(rec);
1099 static void sig_gui_window_created(WINDOW_REC *window)
1101 statusbars_add_visible(WINDOW_MAIN(window));
1104 static void statusbar_item_def_destroy(void *key, void *value)
1110 static void statusbar_signal_item_destroy(void *key, GSList *value)
1112 while (value != NULL) {
1113 statusbar_signal_remove(GPOINTER_TO_INT(value->data));
1114 value->data = g_slist_remove(value, value->data);
1118 static void statusbar_item_signal_destroy(void *key, GSList *value)
1120 g_slist_free(value);
1123 void statusbars_create_window_bars(void)
1125 g_slist_foreach(mainwindows, (GFunc) statusbars_add_visible, NULL);
1128 void statusbar_init(void)
1130 statusbar_need_recreate_items = FALSE;
1131 statusbar_groups = NULL;
1132 active_statusbar_group = NULL;
1133 sbar_item_defs = g_hash_table_new((GHashFunc) g_str_hash,
1134 (GCompareFunc) g_str_equal);
1135 sbar_item_funcs = g_hash_table_new((GHashFunc) g_str_hash,
1136 (GCompareFunc) g_str_equal);
1137 sbar_signal_items = g_hash_table_new((GHashFunc) g_direct_hash,
1138 (GCompareFunc) g_direct_equal);
1139 sbar_item_signals = g_hash_table_new((GHashFunc) g_direct_hash,
1140 (GCompareFunc) g_direct_equal);
1141 named_sbar_items = g_hash_table_new((GHashFunc) g_str_hash,
1142 (GCompareFunc) g_str_equal);
1144 signal_add("terminal resized", (SIGNAL_FUNC) sig_terminal_resized);
1145 signal_add("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
1146 signal_add("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
1147 signal_add("gui window created", (SIGNAL_FUNC) sig_gui_window_created);
1148 signal_add("window changed", (SIGNAL_FUNC) sig_window_changed);
1149 signal_add("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
1151 statusbar_items_init();
1152 statusbar_config_init(); /* signals need to be before this call */
1155 void statusbar_deinit(void)
1157 while (statusbar_groups != NULL)
1158 statusbar_group_destroy(statusbar_groups->data);
1160 g_hash_table_foreach(sbar_item_defs,
1161 (GHFunc) statusbar_item_def_destroy, NULL);
1162 g_hash_table_destroy(sbar_item_defs);
1164 g_hash_table_foreach(sbar_item_funcs, (GHFunc) g_free, NULL);
1165 g_hash_table_destroy(sbar_item_funcs);
1167 g_hash_table_foreach(sbar_signal_items,
1168 (GHFunc) statusbar_signal_item_destroy, NULL);
1169 g_hash_table_destroy(sbar_signal_items);
1170 g_hash_table_foreach(sbar_item_signals,
1171 (GHFunc) statusbar_item_signal_destroy, NULL);
1172 g_hash_table_destroy(sbar_item_signals);
1173 g_hash_table_destroy(named_sbar_items);
1175 signal_remove("terminal resized", (SIGNAL_FUNC) sig_terminal_resized);
1176 signal_remove("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
1177 signal_remove("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
1178 signal_remove("gui window created", (SIGNAL_FUNC) sig_gui_window_created);
1179 signal_remove("window changed", (SIGNAL_FUNC) sig_window_changed);
1180 signal_remove("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
1182 statusbar_items_deinit();
1183 statusbar_config_deinit();