diff options
Diffstat (limited to 'src/fe-text')
-rw-r--r-- | src/fe-text/gui-printtext.c | 43 | ||||
-rw-r--r-- | src/fe-text/gui-printtext.h | 1 | ||||
-rw-r--r-- | src/fe-text/gui-readline.c | 41 | ||||
-rw-r--r-- | src/fe-text/gui-windows.c | 18 | ||||
-rw-r--r-- | src/fe-text/irssi.c | 52 | ||||
-rw-r--r-- | src/fe-text/mainwindows-layout.c | 169 | ||||
-rw-r--r-- | src/fe-text/mainwindows.c | 1148 | ||||
-rw-r--r-- | src/fe-text/mainwindows.h | 22 | ||||
-rw-r--r-- | src/fe-text/module-formats.c | 26 | ||||
-rw-r--r-- | src/fe-text/module-formats.h | 7 | ||||
-rw-r--r-- | src/fe-text/statusbar-items.c | 23 | ||||
-rw-r--r-- | src/fe-text/statusbar.c | 72 | ||||
-rw-r--r-- | src/fe-text/statusbar.h | 6 | ||||
-rw-r--r-- | src/fe-text/term-terminfo.c | 110 | ||||
-rw-r--r-- | src/fe-text/term.h | 4 | ||||
-rw-r--r-- | src/fe-text/textbuffer-commands.c | 21 | ||||
-rw-r--r-- | src/fe-text/textbuffer-view.c | 188 | ||||
-rw-r--r-- | src/fe-text/textbuffer-view.h | 36 | ||||
-rw-r--r-- | src/fe-text/textbuffer.c | 1 | ||||
-rw-r--r-- | src/fe-text/textbuffer.h | 2 |
20 files changed, 1605 insertions, 385 deletions
diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c index a07451fa..c52f9ced 100644 --- a/src/fe-text/gui-printtext.c +++ b/src/fe-text/gui-printtext.c @@ -24,6 +24,7 @@ #include "formats.h" #include "printtext.h" +#include "themes.h" #include "term.h" #include "gui-printtext.h" @@ -138,6 +139,39 @@ void gui_printtext_after(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str) gui_printtext_after_time(dest, prev, str, 0); } +void gui_printtext_window_border(int x, int y) +{ + char *v0, *v1; + int len; + if (current_theme != NULL) { + v1 = theme_format_expand(current_theme, "{window_border} "); + len = format_real_length(v1, 1); + v1[len] = '\0'; + } + else { + v1 = g_strdup(" "); + } + + if (*v1 == '\0') { + g_free(v1); + v1 = g_strdup(" "); + } + + if (clrtoeol_info->color != NULL) { + char *color = g_strdup(clrtoeol_info->color); + len = format_real_length(color, 0); + color[len] = '\0'; + v0 = g_strconcat(color, v1, NULL); + g_free(color); + g_free(v1); + } else { + v0 = v1; + } + + gui_printtext(x, y, v0); + g_free(v0); +} + static void remove_old_lines(TEXT_BUFFER_VIEW_REC *view) { LINE_REC *line; @@ -236,8 +270,13 @@ static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor, term_set_color2(root_window, attr, fg, bg); term_move(root_window, next_xpos, next_ypos); - if (flags & GUI_PRINT_FLAG_CLRTOEOL) - term_clrtoeol(root_window); + if (flags & GUI_PRINT_FLAG_CLRTOEOL) { + if (clrtoeol_info->window != NULL) { + term_window_clrtoeol_abs(clrtoeol_info->window, next_ypos); + } else { + term_clrtoeol(root_window); + } + } next_xpos += term_addstr(root_window, str); return; } diff --git a/src/fe-text/gui-printtext.h b/src/fe-text/gui-printtext.h index d2671497..64595bbe 100644 --- a/src/fe-text/gui-printtext.h +++ b/src/fe-text/gui-printtext.h @@ -20,5 +20,6 @@ void gui_printtext(int xpos, int ypos, const char *str); void gui_printtext_internal(int xpos, int ypos, const char *str); void gui_printtext_after(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str); void gui_printtext_after_time(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str, time_t time); +void gui_printtext_window_border(int xpos, int ypos); #endif diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c index 3688f15e..b3a78396 100644 --- a/src/fe-text/gui-readline.c +++ b/src/fe-text/gui-readline.c @@ -530,6 +530,39 @@ static void key_forward_history(void) g_free(line); } +static void key_backward_global_history(void) +{ + const char *text; + char *line; + + line = gui_entry_get_text(active_entry); + text = command_global_history_prev(active_win, line); + gui_entry_set_text(active_entry, text); + g_free(line); +} + +static void key_forward_global_history(void) +{ + const char *text; + char *line; + + line = gui_entry_get_text(active_entry); + text = command_global_history_next(active_win, line); + gui_entry_set_text(active_entry, text); + g_free(line); +} + +static void key_erase_history_entry(void) +{ + const char *text; + char *line; + + line = gui_entry_get_text(active_entry); + text = command_history_delete_current(active_win, line); + gui_entry_set_text(active_entry, text); + g_free(line); +} + static void key_beginning_of_line(void) { gui_entry_set_pos(active_entry, 0); @@ -1176,6 +1209,8 @@ void gui_readline_init(void) key_bind("key", NULL, "meta2-5C", "cright", (SIGNAL_FUNC) key_combo); key_bind("key", NULL, "meta2-1;5D", "cleft", (SIGNAL_FUNC) key_combo); key_bind("key", NULL, "meta2-1;5C", "cright", (SIGNAL_FUNC) key_combo); + key_bind("key", NULL, "meta2-1;5A", "cup", (SIGNAL_FUNC) key_combo); + key_bind("key", NULL, "meta2-1;5B", "cdown", (SIGNAL_FUNC) key_combo); key_bind("key", NULL, "meta2-1;3A", "mup", (SIGNAL_FUNC) key_combo); key_bind("key", NULL, "meta2-1;3B", "mdown", (SIGNAL_FUNC) key_combo); @@ -1217,6 +1252,9 @@ void gui_readline_init(void) /* history */ key_bind("backward_history", "Go back one line in the history", "up", NULL, (SIGNAL_FUNC) key_backward_history); key_bind("forward_history", "Go forward one line in the history", "down", NULL, (SIGNAL_FUNC) key_forward_history); + key_bind("backward_global_history", "Go back one line in the global history", "cup", NULL, (SIGNAL_FUNC) key_backward_global_history); + key_bind("forward_global_history", "Go forward one line in the global history", "cdown", NULL, (SIGNAL_FUNC) key_forward_global_history); + key_bind("erase_history_entry", "Erase the currently active entry from the history", NULL, NULL, (SIGNAL_FUNC) key_erase_history_entry); /* line editing */ key_bind("backspace", "Delete the previous character", "backspace", NULL, (SIGNAL_FUNC) key_backspace); @@ -1310,6 +1348,9 @@ void gui_readline_deinit(void) key_unbind("backward_history", (SIGNAL_FUNC) key_backward_history); key_unbind("forward_history", (SIGNAL_FUNC) key_forward_history); + key_unbind("backward_global_history", (SIGNAL_FUNC) key_backward_global_history); + key_unbind("forward_global_history", (SIGNAL_FUNC) key_forward_global_history); + key_unbind("erase_history_entry", (SIGNAL_FUNC) key_erase_history_entry); key_unbind("backspace", (SIGNAL_FUNC) key_backspace); key_unbind("delete_character", (SIGNAL_FUNC) key_delete_character); diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c index c63c495c..3efb9803 100644 --- a/src/fe-text/gui-windows.c +++ b/src/fe-text/gui-windows.c @@ -23,6 +23,7 @@ #include "misc.h" #include "settings.h" #include "special-vars.h" +#include "levels.h" #include "term.h" #include "gui-entry.h" @@ -50,6 +51,7 @@ static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window, !settings_get_bool("indent_always"), get_default_indent_func()); textbuffer_view_set_break_wide(gui->view, settings_get_bool("break_wide")); + textbuffer_view_set_hidden_level(gui->view, MSGLEVEL_HIDDEN); if (parent->active == window) textbuffer_view_set_window(gui->view, parent->screen_win); return gui; @@ -73,17 +75,18 @@ static void gui_window_created(WINDOW_REC *window, void *automatic) g_return_if_fail(window != NULL); - new_parent = window_create_override == 0 || - window_create_override == 2 || + new_parent = window_create_override == MAIN_WINDOW_TYPE_DEFAULT || + window_create_override == MAIN_WINDOW_TYPE_SPLIT || + window_create_override == MAIN_WINDOW_TYPE_RSPLIT || active_win == NULL || WINDOW_GUI(active_win) == NULL; - parent = !new_parent ? WINDOW_MAIN(active_win) : mainwindow_create(); + parent = !new_parent ? WINDOW_MAIN(active_win) : mainwindow_create(window_create_override == MAIN_WINDOW_TYPE_RSPLIT); if (parent == NULL) { /* not enough space for new window, but we really can't abort creation of the window anymore, so create hidden window instead. */ parent = WINDOW_MAIN(active_win); } - window_create_override = -1; + window_create_override = MAIN_WINDOW_TYPE_NONE; if (parent->active == NULL) parent->active = window; window->gui_data = gui_window_init(window, parent); @@ -204,6 +207,8 @@ void gui_windows_reset_settings(void) WINDOW_REC *rec = tmp->data; GUI_WINDOW_REC *gui = WINDOW_GUI(rec); + textbuffer_view_set_hidden_level(gui->view, MSGLEVEL_HIDDEN); + textbuffer_view_set_break_wide(gui->view, settings_get_bool("break_wide")); textbuffer_view_set_default_indent(gui->view, @@ -281,13 +286,14 @@ static void read_settings(void) void gui_windows_init(void) { - settings_add_bool("lookandfeel", "autostick_split_windows", TRUE); + settings_add_bool("lookandfeel", "autostick_split_windows", FALSE); + settings_add_bool("lookandfeel", "autounstick_windows", TRUE); settings_add_int("lookandfeel", "indent", 10); settings_add_bool("lookandfeel", "indent_always", FALSE); settings_add_bool("lookandfeel", "break_wide", FALSE); settings_add_bool("lookandfeel", "scroll", TRUE); - window_create_override = -1; + window_create_override = MAIN_WINDOW_TYPE_NONE; read_settings(); signal_add("gui window create override", (SIGNAL_FUNC) sig_window_create_override); diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c index b5df47c9..0288e4f1 100644 --- a/src/fe-text/irssi.c +++ b/src/fe-text/irssi.c @@ -31,6 +31,7 @@ #include "printtext.h" #include "fe-common-core.h" +#include "fe-settings.h" #include "themes.h" #include "term.h" @@ -79,25 +80,8 @@ static int dirty, full_redraw; static GMainLoop *main_loop; int quitting; -static const char *banner_text = - " ___ _\n" - "|_ _|_ _ _____(_)\n" - " | || '_(_-<_-< |\n" - "|___|_| /__/__/_|\n" - "Irssi v" PACKAGE_VERSION " - http://www.irssi.org"; - -static const char *firsttimer_text = - "- - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - "Hi there! If this is your first time using Irssi, you\n" - "might want to go to our website and read the startup\n" - "documentation to get you going.\n\n" - "Our community and staff are available to assist you or\n" - "to answer any questions you may have.\n\n" - "Use the /HELP command to get detailed information about\n" - "the available commands.\n" - "- - - - - - - - - - - - - - - - - - - - - - - - - - - -"; - static int display_firsttimer = FALSE; +static unsigned int user_settings_changed = 0; static void sig_exit(void) @@ -105,6 +89,11 @@ static void sig_exit(void) quitting = TRUE; } +static void sig_settings_userinfo_changed(gpointer changedp) +{ + user_settings_changed = GPOINTER_TO_UINT(changedp); +} + /* redraw irssi's screen.. */ void irssi_redraw(void) { @@ -161,6 +150,7 @@ static void textui_init(void) fe_common_irc_init(); theme_register(gui_text_formats); + signal_add("settings userinfo changed", (SIGNAL_FUNC) sig_settings_userinfo_changed); signal_add_last("gui exit", (SIGNAL_FUNC) sig_exit); } @@ -199,14 +189,26 @@ static void textui_finish_init(void) statusbar_redraw(NULL, TRUE); if (servers == NULL && lookup_servers == NULL) { - printtext(NULL, NULL, MSGLEVEL_CRAP|MSGLEVEL_NO_ACT, - "%s", banner_text); + printformat(NULL, NULL, MSGLEVEL_CRAP|MSGLEVEL_NO_ACT, TXT_IRSSI_BANNER); } if (display_firsttimer) { - printtext(NULL, NULL, MSGLEVEL_CRAP|MSGLEVEL_NO_ACT, - "%s", firsttimer_text); + printformat(NULL, NULL, MSGLEVEL_CRAP|MSGLEVEL_NO_ACT, TXT_WELCOME_FIRSTTIME); } + + /* see irc-servers-setup.c:init_userinfo */ + if (user_settings_changed) + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_WELCOME_INIT_SETTINGS); + if (user_settings_changed & USER_SETTINGS_REAL_NAME) + fe_settings_set_print("real_name"); + if (user_settings_changed & USER_SETTINGS_USER_NAME) + fe_settings_set_print("user_name"); + if (user_settings_changed & USER_SETTINGS_NICK) + fe_settings_set_print("nick"); + if (user_settings_changed & USER_SETTINGS_HOSTNAME) + fe_settings_set_print("hostname"); + + term_environment_check(); } static void textui_deinit(void) @@ -222,7 +224,8 @@ static void textui_deinit(void) fe_perl_deinit(); #endif - dirty_check(); /* one last time to print any quit messages */ + dirty_check(); /* one last time to print any quit messages */ + signal_remove("settings userinfo changed", (SIGNAL_FUNC) sig_settings_userinfo_changed); signal_remove("gui exit", (SIGNAL_FUNC) sig_exit); lastlog_deinit(); @@ -259,12 +262,11 @@ static void check_files(void) } } - int main(int argc, char **argv) { static int version = 0; static GOptionEntry options[] = { - { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Display irssi version", NULL }, + { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Display Irssi version", NULL }, { NULL } }; int loglev; diff --git a/src/fe-text/mainwindows-layout.c b/src/fe-text/mainwindows-layout.c index fae02539..17c6647b 100644 --- a/src/fe-text/mainwindows-layout.c +++ b/src/fe-text/mainwindows-layout.c @@ -23,6 +23,7 @@ #include "misc.h" #include "lib-config/iconfig.h" #include "settings.h" +#include "levels.h" #include "mainwindows.h" #include "gui-windows.h" @@ -41,6 +42,12 @@ static void sig_layout_window_save(WINDOW_REC *window, CONFIG_NODE *node) iconfig_node_set_int(node, "parent", active->refnum); } + if (gui->view->hidden_level != MSGLEVEL_HIDDEN) { + char *level = bits2level(gui->view->hidden_level); + iconfig_node_set_str(node, "hidelevel", level); + g_free(level); + } + if (gui->use_scroll) iconfig_node_set_bool(node, "scroll", gui->scroll); } @@ -48,9 +55,9 @@ static void sig_layout_window_save(WINDOW_REC *window, CONFIG_NODE *node) static void sig_layout_window_restore(WINDOW_REC *window, CONFIG_NODE *node) { WINDOW_REC *parent; - GUI_WINDOW_REC *gui; + GUI_WINDOW_REC *gui; - gui = WINDOW_GUI(window); + gui = WINDOW_GUI(window); parent = window_find_refnum(config_node_get_int(node, "parent", -1)); if (parent != NULL) @@ -58,10 +65,13 @@ static void sig_layout_window_restore(WINDOW_REC *window, CONFIG_NODE *node) if (config_node_get_bool(node, "sticky", FALSE)) gui_window_set_sticky(window); + + textbuffer_view_set_hidden_level(gui->view, level2bits(config_node_get_str(node, "hidelevel", "HIDDEN"), NULL)); + if (config_node_get_str(node, "scroll", NULL) != NULL) { gui->use_scroll = TRUE; gui->scroll = config_node_get_bool(node, "scroll", TRUE); - textbuffer_view_set_scroll(gui->view, gui->scroll); + textbuffer_view_set_scroll(gui->view, gui->scroll); } } @@ -74,6 +84,8 @@ static void main_window_save(MAIN_WINDOW_REC *window, CONFIG_NODE *node) iconfig_node_set_int(node, "first_line", window->first_line); iconfig_node_set_int(node, "lines", window->height); + iconfig_node_set_int(node, "first_column", window->first_column); + iconfig_node_set_int(node, "columns", window->width); } static void sig_layout_save(void) @@ -88,8 +100,16 @@ static void sig_layout_save(void) static int window_node_cmp(CONFIG_NODE *n1, CONFIG_NODE *n2) { - return config_node_get_int(n1, "first_line", 0) > - config_node_get_int(n2, "first_line", 0) ? -1 : 1; + return (config_node_get_int(n1, "first_line", 0) == + config_node_get_int(n2, "first_line", 0) + && + config_node_get_int(n1, "first_column", 0) > + config_node_get_int(n2, "first_column", 0) + ) || + config_node_get_int(n1, "first_line", 0) > + config_node_get_int(n2, "first_line", 0) + ? -1 + : 1; } /* Returns list of mainwindow nodes sorted by first_line @@ -108,14 +128,45 @@ static GSList *get_sorted_windows_config(CONFIG_NODE *node) return output; } +static GSList *get_windows_config_filter_line(GSList *in) +{ + GSList *tmp, *output; + + output = NULL; + for (tmp = in; tmp != NULL; tmp = tmp->next) { + CONFIG_NODE *node = tmp->data; + if (config_node_get_int(node, "first_column", 0) == 0) + output = g_slist_append(output, node); + } + + return output; +} + +static GSList *get_windows_config_filter_column(GSList *in, int first_line, int last_line) +{ + GSList *tmp, *output; + + output = NULL; + for (tmp = in; tmp != NULL; tmp = tmp->next) { + int l1, l2; + CONFIG_NODE *node = tmp->data; + l1 = config_node_get_int(node, "first_line", -1); + l2 = l1 + config_node_get_int(node, "lines", 0) - 1; + if (l1 >= first_line && l2 <= last_line) + output = g_slist_prepend(output, node); + } + + return output; +} + static void sig_layout_restore(void) { - MAIN_WINDOW_REC *lower_window; - WINDOW_REC *window; + MAIN_WINDOW_REC *lower_window; + WINDOW_REC *window, *first; CONFIG_NODE *node; - GSList *tmp, *sorted_config; - int avail_height, height, *heights; - int i, lower_size, windows_count, diff; + GSList *tmp, *sorted_config, *lines_config; + int avail_height, height, *heights, *widths, max_wins_line; + int i, lower_size, lines_count, columns_count, diff; node = iconfig_node_traverse("mainwindows", FALSE); if (node == NULL) return; @@ -123,51 +174,56 @@ static void sig_layout_restore(void) sorted_config = get_sorted_windows_config(node); if (sorted_config == NULL) return; - windows_count = g_slist_length(sorted_config); + lines_config = get_windows_config_filter_line(sorted_config); + lines_count = g_slist_length(lines_config); - /* calculate the saved terminal height */ + /* calculate the saved terminal height */ avail_height = term_height - screen_reserved_top - screen_reserved_bottom; height = 0; - heights = g_new0(int, windows_count); - for (i = 0, tmp = sorted_config; tmp != NULL; tmp = tmp->next, i++) { + heights = g_new0(int, lines_count); + for (i = 0, tmp = lines_config; tmp != NULL; tmp = tmp->next, i++) { CONFIG_NODE *node = tmp->data; - heights[i] = config_node_get_int(node, "lines", 0); + heights[i] = config_node_get_int(node, "lines", 0); height += heights[i]; } + max_wins_line = (term_width + 1) / (NEW_WINDOW_WIDTH + 1); + if (max_wins_line < 1) + max_wins_line = 1; + if (avail_height <= (WINDOW_MIN_SIZE*2)+1) { /* we can fit only one window to screen - give it all the height we can */ - windows_count = 1; - heights[0] = avail_height; + lines_count = 1; + heights[0] = avail_height; } else if (height != avail_height) { /* Terminal's height is different from the saved one. Resize the windows so they fit to screen. */ while (height > avail_height && - windows_count*(WINDOW_MIN_SIZE+1) > avail_height) { + lines_count*(WINDOW_MIN_SIZE+1) > avail_height) { /* all windows can't fit into screen, remove the lowest ones */ - windows_count--; + lines_count--; } - /* try to keep the windows' size about the same in percents */ - for (i = 0; i < windows_count; i++) { + /* try to keep the windows' size about the same in percents */ + for (i = 0; i < lines_count; i++) { int size = avail_height*heights[i]/height; if (size < WINDOW_MIN_SIZE+1) - size = WINDOW_MIN_SIZE+1; + size = WINDOW_MIN_SIZE+1; heights[i] = size; } /* give/remove the last bits */ - height = 0; - for (i = 0; i < windows_count; i++) - height += heights[i]; + height = 0; + for (i = 0; i < lines_count; i++) + height += heights[i]; diff = height < avail_height ? 1 : -1; for (i = 0; height != avail_height; i++) { - if (i == windows_count) + if (i == lines_count) i = 0; if (heights[i] > WINDOW_MIN_SIZE+1) { @@ -178,25 +234,59 @@ static void sig_layout_restore(void) } /* create all the visible windows with correct size */ - lower_window = NULL; lower_size = 0; - for (i = 0, tmp = sorted_config; i < windows_count; tmp = tmp->next, i++) { + lower_window = NULL; lower_size = 0; first = NULL; + for (i = 0, tmp = lines_config; i < lines_count; tmp = tmp->next, i++) { + GSList *tmp2, *columns_config, *line; + int j, l1, l2; CONFIG_NODE *node = tmp->data; if (node->key == NULL) continue; - /* create a new window + mainwindow */ - signal_emit("gui window create override", 1, - GINT_TO_POINTER(0)); + l1 = config_node_get_int(node, "first_line", -1); + l2 = l1 + config_node_get_int(node, "lines", 0) - 1; + columns_config = get_windows_config_filter_column(sorted_config, l1, l2); + + window = NULL; columns_count = 0; + widths = g_new0(int, max_wins_line); + for (j = 0, tmp2 = columns_config; j < max_wins_line && tmp2 != NULL; tmp2 = tmp2->next, j++) { + int width; + WINDOW_REC *new_win; + CONFIG_NODE *node2 = tmp2->data; + if (node2->key == NULL) continue; + + /* create a new window + mainwindow */ + signal_emit("gui window create override", 1, + GINT_TO_POINTER(window == NULL ? MAIN_WINDOW_TYPE_SPLIT : MAIN_WINDOW_TYPE_RSPLIT)); - window = window_create(NULL, TRUE); - window_set_refnum(window, atoi(node->key)); + new_win = window_create(NULL, TRUE); + + window_set_refnum(new_win, atoi(node2->key)); + width = config_node_get_int(node2, "columns", NEW_WINDOW_WIDTH); + widths[j] = width; + columns_count += width + (window == NULL ? 0 : 1); + + if (window == NULL) + window = new_win; + if (first == NULL) + first = new_win; + + window_set_active(new_win); + active_mainwin = WINDOW_MAIN(new_win); + } + if (window == NULL) + continue; + line = g_slist_reverse(mainwindows_get_line(WINDOW_MAIN(window))); + for (j = g_slist_length(line), tmp2 = line; tmp2 != NULL; tmp2 = tmp2->next, j--) { + int width = MAX(NEW_WINDOW_WIDTH, widths[j-1] * term_width / columns_count); + MAIN_WINDOW_REC *rec = tmp2->data; + mainwindow_set_rsize(rec, width); + } + g_slist_free(line); + g_free(widths); if (lower_size > 0) mainwindow_set_size(lower_window, lower_size, FALSE); - window_set_active(window); - active_mainwin = WINDOW_MAIN(window); - - lower_window = WINDOW_MAIN(window); + lower_window = WINDOW_MAIN(window); lower_size = heights[i]; if (lower_size < WINDOW_MIN_SIZE+1) lower_size = WINDOW_MIN_SIZE+1; @@ -206,6 +296,11 @@ static void sig_layout_restore(void) if (lower_size > 0) mainwindow_set_size(lower_window, lower_size, FALSE); + + if (first != NULL) { + window_set_active(first); + active_mainwin = WINDOW_MAIN(first); + } } static void sig_layout_reset(void) diff --git a/src/fe-text/mainwindows.c b/src/fe-text/mainwindows.c index 5f58c25f..5f24674f 100644 --- a/src/fe-text/mainwindows.c +++ b/src/fe-text/mainwindows.c @@ -34,24 +34,27 @@ GSList *mainwindows; MAIN_WINDOW_REC *active_mainwin; +MAIN_WINDOW_BORDER_REC *clrtoeol_info; int screen_reserved_top, screen_reserved_bottom; -static int old_screen_width, old_screen_height; +int screen_reserved_left, screen_reserved_right; +static int screen_width, screen_height; #define mainwindow_create_screen(window) \ - term_window_create(0, \ + term_window_create((window)->first_column + (window)->statusbar_columns_left, \ (window)->first_line + (window)->statusbar_lines_top, \ - (window)->width, \ + (window)->width - (window)->statusbar_columns, \ (window)->height - (window)->statusbar_lines) #define mainwindow_set_screen_size(window) \ - term_window_move((window)->screen_win, 0, \ + term_window_move((window)->screen_win, \ + (window)->first_column + (window)->statusbar_columns_left, \ (window)->first_line + (window)->statusbar_lines_top, \ - (window)->width, \ + (window)->width - (window)->statusbar_columns, \ (window)->height - (window)->statusbar_lines); -static MAIN_WINDOW_REC *find_window_with_room(void) +static MAIN_WINDOW_REC *find_window_with_room() { MAIN_WINDOW_REC *biggest_rec; GSList *tmp; @@ -71,14 +74,34 @@ static MAIN_WINDOW_REC *find_window_with_room(void) return biggest_rec; } +static MAIN_WINDOW_REC *find_window_with_room_right(void) +{ + MAIN_WINDOW_REC *biggest_rec; + GSList *tmp; + int space, biggest; + + biggest = 0; biggest_rec = NULL; + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + space = MAIN_WINDOW_TEXT_WIDTH(rec); + if (space >= 2 * NEW_WINDOW_WIDTH && space > biggest) { + biggest = space; + biggest_rec = rec; + } + } + + return biggest_rec; +} + #define window_size_equals(window, mainwin) \ - ((window)->width == (mainwin)->width && \ + ((window)->width == MAIN_WINDOW_TEXT_WIDTH(mainwin) && \ (window)->height == MAIN_WINDOW_TEXT_HEIGHT(mainwin)) static void mainwindow_resize_windows(MAIN_WINDOW_REC *window) { GSList *tmp; - int resized; + int resized; mainwindow_set_screen_size(window); @@ -89,24 +112,31 @@ static void mainwindow_resize_windows(MAIN_WINDOW_REC *window) if (rec->gui_data != NULL && WINDOW_GUI(rec)->parent == window && !window_size_equals(rec, window)) { - resized = TRUE; - gui_window_resize(rec, window->width, + resized = TRUE; + gui_window_resize(rec, MAIN_WINDOW_TEXT_WIDTH(window), MAIN_WINDOW_TEXT_HEIGHT(window)); } } - if (resized) + if (resized) signal_emit("mainwindow resized", 1, window); } static void mainwindow_resize(MAIN_WINDOW_REC *window, int xdiff, int ydiff) { + int height, width; if (quitting || (xdiff == 0 && ydiff == 0)) - return; + return; - window->width += xdiff; + height = window->height + ydiff; + width = window->width + xdiff; + window->width = window->last_column-window->first_column+1; window->height = window->last_line-window->first_line+1; - window->size_dirty = TRUE; + if (height != window->height || width != window->width) { + g_warning("Resizing window %p W:%d expected:%d H:%d expected:%d", + window, window->width, width, window->height, height); + } + window->size_dirty = TRUE; } static GSList *get_sticky_windows_sorted(MAIN_WINDOW_REC *mainwin) @@ -178,14 +208,13 @@ void mainwindows_recreate(void) } } -MAIN_WINDOW_REC *mainwindow_create(void) +MAIN_WINDOW_REC *mainwindow_create(int right) { MAIN_WINDOW_REC *rec, *parent; int space; rec = g_new0(MAIN_WINDOW_REC, 1); rec->dirty = TRUE; - rec->width = term_width; if (mainwindows == NULL) { active_mainwin = rec; @@ -193,21 +222,53 @@ MAIN_WINDOW_REC *mainwindow_create(void) rec->first_line = screen_reserved_top; rec->last_line = term_height-1 - screen_reserved_bottom; rec->height = rec->last_line-rec->first_line+1; + rec->first_column = screen_reserved_left; + rec->last_column = screen_width-1 - screen_reserved_right; + rec->width = rec->last_column-rec->first_column+1; } else { parent = WINDOW_MAIN(active_win); - if (MAIN_WINDOW_TEXT_HEIGHT(parent) < - WINDOW_MIN_SIZE+NEW_WINDOW_SIZE) - parent = find_window_with_room(); - if (parent == NULL) - return NULL; /* not enough space */ - - space = parent->height / 2; - rec->first_line = parent->first_line; - rec->last_line = rec->first_line + space; - rec->height = rec->last_line-rec->first_line+1; - parent->first_line += space+1; - mainwindow_resize(parent, 0, -space-1); + if (!right) { + GSList *tmp, *line; + if (MAIN_WINDOW_TEXT_HEIGHT(parent) < + WINDOW_MIN_SIZE+NEW_WINDOW_SIZE) + parent = find_window_with_room(); + if (parent == NULL) + return NULL; /* not enough space */ + + space = parent->height / 2; + rec->first_line = parent->first_line; + rec->last_line = rec->first_line + space; + rec->height = rec->last_line-rec->first_line+1; + rec->first_column = screen_reserved_left; + rec->last_column = screen_width-1 - screen_reserved_right; + rec->width = rec->last_column-rec->first_column+1; + + line = mainwindows_get_line(parent); + for (tmp = line; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + rec->first_line += space+1; + mainwindow_resize(rec, 0, -space-1); + } + g_slist_free(line); + } else { + if (MAIN_WINDOW_TEXT_WIDTH(parent) < + 2* NEW_WINDOW_WIDTH) + parent = find_window_with_room_right(); + if (parent == NULL) + return NULL; /* not enough space */ + + space = parent->width / 2; + rec->first_line = parent->first_line; + rec->last_line = parent->last_line; + rec->height = parent->height; + rec->first_column = parent->last_column - space + 1; + rec->last_column = parent->last_column; + rec->width = rec->last_column-rec->first_column+1; + + parent->last_column -= space+1; + mainwindow_resize(parent, -space-1, 0); + } } rec->screen_win = mainwindow_create_screen(rec); @@ -218,16 +279,22 @@ MAIN_WINDOW_REC *mainwindow_create(void) return rec; } -static MAIN_WINDOW_REC *mainwindows_find_lower(int line) +static MAIN_WINDOW_REC *mainwindows_find_lower(MAIN_WINDOW_REC *window) { + int last_line; MAIN_WINDOW_REC *best; GSList *tmp; + if (window != NULL) + last_line = window->last_line; + else + last_line = -1; + best = NULL; for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { MAIN_WINDOW_REC *rec = tmp->data; - if (rec->first_line > line && + if (rec->first_line > last_line && (best == NULL || rec->first_line < best->first_line)) best = rec; } @@ -235,16 +302,64 @@ static MAIN_WINDOW_REC *mainwindows_find_lower(int line) return best; } -static MAIN_WINDOW_REC *mainwindows_find_upper(int line) +static MAIN_WINDOW_REC *mainwindows_find_right(MAIN_WINDOW_REC *window, int find_first) { + int first_line, last_line, last_column; MAIN_WINDOW_REC *best; GSList *tmp; + if (window != NULL) { + first_line = window->first_line; + last_line = window->last_line; + last_column = window->last_column; + } else { + first_line = last_line = last_column = -1; + } + + if (find_first) + last_column = -1; + best = NULL; for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { MAIN_WINDOW_REC *rec = tmp->data; - if (rec->last_line < line && + if (rec->first_line >= first_line && + rec->last_line <= last_line && + rec->first_column > last_column && + (best == NULL || rec->first_column < best->first_column)) + best = rec; + } + + return best; +} + +static MAIN_WINDOW_REC *mainwindows_find_lower_right(MAIN_WINDOW_REC *window) +{ + MAIN_WINDOW_REC *best; + + best = mainwindows_find_right(window, FALSE); + if (best == NULL) + best = mainwindows_find_lower(window); + + return best; +} + +static MAIN_WINDOW_REC *mainwindows_find_upper(MAIN_WINDOW_REC *window) +{ + int first_line; + MAIN_WINDOW_REC *best; + GSList *tmp; + + if (window != NULL) + first_line = window->first_line; + else + first_line = screen_height; + + best = NULL; + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + if (rec->last_line < first_line && (best == NULL || rec->last_line > best->last_line)) best = rec; } @@ -252,27 +367,142 @@ static MAIN_WINDOW_REC *mainwindows_find_upper(int line) return best; } -static void mainwindows_add_space(int first_line, int last_line) +static MAIN_WINDOW_REC *mainwindows_find_left(MAIN_WINDOW_REC *window, int find_last) +{ + int first_line, last_line, first_column; + MAIN_WINDOW_REC *best; + GSList *tmp; + + if (window != NULL) { + first_line = window->first_line; + last_line = window->last_line; + first_column = window->first_column; + } else { + first_line = last_line = screen_height; + first_column = screen_width; + } + + if (find_last) + first_column = screen_width; + + best = NULL; + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + if (rec->first_line >= first_line && + rec->last_line <= last_line && + rec->last_column < first_column && + (best == NULL || rec->last_column > best->last_column)) + best = rec; + } + + return best; +} + +static MAIN_WINDOW_REC *mainwindows_find_upper_left(MAIN_WINDOW_REC *window) +{ + MAIN_WINDOW_REC *best; + + best = mainwindows_find_left(window, FALSE); + if (best == NULL) + best = mainwindows_find_upper(window); + + return best; +} + +static MAIN_WINDOW_REC *mainwindows_find_left_upper(MAIN_WINDOW_REC *window) +{ + MAIN_WINDOW_REC *best; + + best = mainwindows_find_left(window, FALSE); + if (best == NULL) + best = mainwindows_find_left(mainwindows_find_upper(window), TRUE); + + return best; +} + +GSList *mainwindows_get_line(MAIN_WINDOW_REC *rec) +{ + MAIN_WINDOW_REC *win; + GSList *list; + + list = NULL; + + for (win = mainwindows_find_left(rec, FALSE); + win != NULL; + win = mainwindows_find_left(win, FALSE)) { + list = g_slist_append(list, win); + } + + if (rec != NULL) + list = g_slist_append(list, rec); + + for (win = mainwindows_find_right(rec, FALSE); + win != NULL; + win = mainwindows_find_right(win, FALSE)) { + list = g_slist_append(list, win); + } + + return list; +} + +/* add back the space which was occupied by destroyed mainwindow first_line .. last_line */ +static void mainwindows_add_space(MAIN_WINDOW_REC *destroy_win) { MAIN_WINDOW_REC *rec; - int size; + int size, rsize; - if (last_line < first_line) + if (destroy_win->last_line < destroy_win->first_line) return; - size = last_line-first_line+1; + if (destroy_win->last_column < destroy_win->first_column) + return; - rec = mainwindows_find_lower(last_line); + rsize = destroy_win->last_column-destroy_win->first_column+1; + rec = mainwindows_find_left(destroy_win, FALSE); if (rec != NULL) { - rec->first_line = first_line; - mainwindow_resize(rec, 0, size); + rec->last_column = destroy_win->last_column; + mainwindow_resize(rec, rsize+1, 0); return; } - rec = mainwindows_find_upper(first_line); + rec = mainwindows_find_right(destroy_win, FALSE); if (rec != NULL) { - rec->last_line = last_line; - mainwindow_resize(rec, 0, size); + rec->first_column = destroy_win->first_column; + mainwindow_resize(rec, rsize+1, 0); + return; + } + + size = destroy_win->last_line-destroy_win->first_line+1; + + rec = mainwindows_find_lower(destroy_win); + if (rec != NULL) { + GSList *tmp, *list; + list = mainwindows_get_line(rec); + + for (tmp = list; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + rec->first_line = destroy_win->first_line; + mainwindow_resize(rec, 0, size); + } + + g_slist_free(list); + return; + } + + rec = mainwindows_find_upper(destroy_win); + if (rec != NULL) { + GSList *tmp, *list; + list = mainwindows_get_line(rec); + + for (tmp = list; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + rec->last_line = destroy_win->last_line; + mainwindow_resize(rec, 0, size); + } + + g_slist_free(list); + return; } } @@ -302,8 +532,7 @@ void mainwindow_destroy(MAIN_WINDOW_REC *window) if (mainwindows != NULL) { gui_windows_remove_parent(window); if (!quitting) { - mainwindows_add_space(window->first_line, - window->last_line); + mainwindows_add_space(window); mainwindows_redraw(); } } @@ -313,6 +542,14 @@ void mainwindow_destroy(MAIN_WINDOW_REC *window) if (active_mainwin == window) active_mainwin = NULL; } +void mainwindow_destroy_half(MAIN_WINDOW_REC *window) +{ + int really_quitting = quitting; + quitting = TRUE; + mainwindow_destroy(window); + quitting = really_quitting; +} + void mainwindows_redraw(void) { GSList *tmp; @@ -327,12 +564,20 @@ void mainwindows_redraw(void) static int mainwindows_compare(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2) { - return w1->first_line < w2->first_line ? -1 : 1; + return w1->first_line < w2->first_line ? -1 + : w1->first_line > w2->first_line ? 1 + : w1->first_column < w2->first_column ? -1 + : w1->first_column > w2->first_column ? 1 + : 0; } static int mainwindows_compare_reverse(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2) { - return w1->first_line < w2->first_line ? 1 : -1; + return w1->first_line < w2->first_line ? 1 + : w1->first_line > w2->first_line ? -1 + : w1->first_column < w2->first_column ? 1 + : w1->first_column > w2->first_column ? -1 + : 0; } GSList *mainwindows_get_sorted(int reverse) @@ -348,123 +593,235 @@ GSList *mainwindows_get_sorted(int reverse) return list; } -static void mainwindows_resize_smaller(int xdiff, int ydiff) +static void mainwindows_resize_smaller(int ydiff) { - MAIN_WINDOW_REC *rec; + MAIN_WINDOW_REC *rec; GSList *sorted, *tmp; - int space; + int space; - sorted = mainwindows_get_sorted(TRUE); + sorted = NULL; + for (rec = mainwindows_find_lower(NULL); + rec != NULL; + rec = mainwindows_find_lower(rec)) { + sorted = g_slist_prepend(sorted, rec); + } if (sorted == NULL) return; for (;;) { + int skip_active = FALSE; space = 0; - for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + /* for each line of windows, calculate the space that can be reduced still */ + for (tmp = sorted; tmp != NULL; tmp = tmp->next) { + int min; + GSList *line, *ltmp; rec = tmp->data; - space += MAIN_WINDOW_TEXT_HEIGHT(rec)-WINDOW_MIN_SIZE; + line = mainwindows_get_line(rec); + min = screen_height - ydiff; + for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) { + int lmin; + MAIN_WINDOW_REC *win = ltmp->data; + if (win == active_mainwin && tmp == sorted) + skip_active = TRUE; + + lmin = MAIN_WINDOW_TEXT_HEIGHT(win)-WINDOW_MIN_SIZE; + if (lmin < min) + min = lmin; + } + g_slist_free(line); + space += min; } if (space >= -ydiff) break; rec = sorted->data; - if (rec == active_mainwin && sorted->next != NULL) + if (skip_active && sorted->next != NULL) rec = sorted->next->data; sorted = g_slist_remove(sorted, rec); if (sorted != NULL) { /* terminal is too small - destroy the uppest window and try again */ - mainwindow_destroy(rec); + GSList *line, *ltmp; + line = mainwindows_get_line(rec); + for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) { + MAIN_WINDOW_REC *win = ltmp->data; + mainwindow_destroy(win); + } + g_slist_free(line); } else { - /* only one window in screen.. just force the resize */ - rec->last_line += ydiff; - mainwindow_resize(rec, xdiff, ydiff); - return; + /* only one line of window in screen.. just force the resize */ + GSList *line, *ltmp; + line = mainwindows_get_line(rec); + for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) { + MAIN_WINDOW_REC *win = ltmp->data; + win->last_line += ydiff; + mainwindow_resize(win, 0, ydiff); + } + g_slist_free(line); + return; } } /* resize windows that have space */ for (tmp = sorted; tmp != NULL && ydiff < 0; tmp = tmp->next) { - rec = tmp->data; + int min; + GSList *line, *ltmp; - space = MAIN_WINDOW_TEXT_HEIGHT(rec)-WINDOW_MIN_SIZE; - if (space == 0) { - mainwindow_resize(rec, xdiff, 0); - - rec->first_line += ydiff; - rec->last_line += ydiff; - signal_emit("mainwindow moved", 1, rec); - continue; + rec = tmp->data; + line = mainwindows_get_line(rec); + min = screen_height - ydiff; + for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) { + int lmin; + MAIN_WINDOW_REC *win = ltmp->data; + lmin = MAIN_WINDOW_TEXT_HEIGHT(win)-WINDOW_MIN_SIZE; + if (lmin < min) + min = lmin; } + space = min; - if (space > -ydiff) space = -ydiff; - rec->last_line += ydiff; - ydiff += space; - rec->first_line += ydiff; - - mainwindow_resize(rec, xdiff, -space); - } + if (space == 0) { + /* move the line */ + for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) { + MAIN_WINDOW_REC *win = ltmp->data; + mainwindow_resize(win, 0, 0); + win->size_dirty = TRUE; + win->first_line += ydiff; + win->last_line += ydiff; + signal_emit("mainwindow moved", 1, win); + } + } else { + if (space > -ydiff) space = -ydiff; + for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) { + MAIN_WINDOW_REC *win = ltmp->data; + win->last_line += ydiff; + win->first_line += ydiff + space; - if (xdiff != 0) { - while (tmp != NULL) { - mainwindow_resize(tmp->data, xdiff, 0); - tmp = tmp->next; + mainwindow_resize(win, 0, -space); + } + ydiff += space; } + g_slist_free(line); } g_slist_free(sorted); } -static void mainwindows_resize_bigger(int xdiff, int ydiff) +static void mainwindows_rresize_line(int xdiff, MAIN_WINDOW_REC *win) { - GSList *sorted, *tmp; + int windows, i, extra_width, next_column, shrunk; + int *widths; + GSList *line, *tmp; - sorted = mainwindows_get_sorted(FALSE); - for (tmp = sorted; tmp != NULL; tmp = tmp->next) { - MAIN_WINDOW_REC *rec = tmp->data; + line = mainwindows_get_line(win); + windows = g_slist_length(line); + widths = g_new0(int, windows); - if (ydiff == 0 || tmp->next != NULL) { - mainwindow_resize(rec, xdiff, 0); - continue; + extra_width = screen_width - windows + 1; + for (tmp = line, i = 0; tmp != NULL; tmp = tmp->next, i++) { + MAIN_WINDOW_REC *rec = tmp->data; + widths[i] = (MAIN_WINDOW_TEXT_WIDTH(rec) * (screen_width - windows + 1)) / (screen_width - xdiff - windows + 1); + extra_width -= widths[i] + rec->statusbar_columns; + } + shrunk = FALSE; + for (i = windows; extra_width < 0; i = i > 1 ? i - 1 : windows) { + if (widths[i-1] > NEW_WINDOW_WIDTH || (i == 1 && !shrunk)) { + widths[i-1]--; + extra_width++; + shrunk = i == 1; } - - /* lowest window - give all the extra space for it */ - rec->last_line += ydiff; - mainwindow_resize(rec, xdiff, ydiff); } - g_slist_free(sorted); -} -static void mainwindows_resize_horiz(int xdiff) -{ - GSList *tmp; + next_column = 0; - for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { - MAIN_WINDOW_REC *rec = tmp->data; +#define extra ( (i >= screen_width % windows && i < extra_width + (screen_width % windows)) \ + || i + windows < extra_width + (screen_width % windows) ? 1 : 0 ) - mainwindow_resize(rec, xdiff, 0); + for (tmp = line, i = 0; tmp != NULL; tmp = tmp->next, i++) { + MAIN_WINDOW_REC *rec = tmp->data; + rec->first_column = next_column; + rec->last_column = rec->first_column + widths[i] + rec->statusbar_columns + extra - 1; + next_column = rec->last_column + 2; + mainwindow_resize(rec, widths[i] + rec->statusbar_columns + extra - rec->width, 0); + rec->size_dirty = TRUE; } +#undef extra + + g_free(widths); + g_slist_free(line); } void mainwindows_resize(int width, int height) { int xdiff, ydiff; - xdiff = width-old_screen_width; - ydiff = height-old_screen_height; - old_screen_width = width; - old_screen_height = height; + xdiff = width-screen_width; + ydiff = height-screen_height; + screen_width = width; + screen_height = height; + + if (ydiff > 0) { + /* algorithm: enlarge bottom window */ + MAIN_WINDOW_REC *rec; + GSList *line, *tmp; + line = mainwindows_get_line(mainwindows_find_upper(NULL)); + for (tmp = line; tmp != NULL; tmp = tmp->next) { + rec = tmp->data; + rec->last_line += ydiff; + mainwindow_resize(rec, 0, ydiff); + } + g_slist_free(line); + } + + if (xdiff > 0) { + /* algorithm: distribute new space on each line */ + MAIN_WINDOW_REC *win; + + for (win = mainwindows_find_lower(NULL); + win != NULL; + win = mainwindows_find_lower(win)) { + mainwindows_rresize_line(xdiff, win); + } + } + + if (xdiff < 0) { + /* algorithm: shrink each window, + destroy windows on the right if no room */ + MAIN_WINDOW_REC *win; + + for (win = mainwindows_find_lower(NULL); + win != NULL; + win = mainwindows_find_lower(win)) { + int max_windows, i, last_column; + GSList *line, *tmp; + + line = mainwindows_get_line(win); + max_windows = (screen_width + 1) / (NEW_WINDOW_WIDTH + 1); + if (max_windows < 1) + max_windows = 1; + last_column = screen_width - 1; + for (tmp = line, i = 0; tmp != NULL; tmp = tmp->next, i++) { + MAIN_WINDOW_REC *rec = tmp->data; + if (i >= max_windows) + mainwindow_destroy_half(rec); + else + last_column = rec->last_column; + } + win = line->data; + g_slist_free(line); + + mainwindows_rresize_line(screen_width - last_column + 1, win); + } + } - if (ydiff < 0) - mainwindows_resize_smaller(xdiff, ydiff); - else if (ydiff > 0) - mainwindows_resize_bigger(xdiff, ydiff); - else if (xdiff != 0) - mainwindows_resize_horiz(xdiff); + if (ydiff < 0) { + /* algorithm: shrink windows starting from bottom, + destroy windows starting from top if no room */ + mainwindows_resize_smaller(ydiff); + } - signal_emit("terminal resized", 0); + signal_emit("terminal resized", 0); irssi_redraw(); } @@ -474,31 +831,37 @@ int mainwindows_reserve_lines(int top, int bottom) MAIN_WINDOW_REC *window; int ret; - ret = -1; + ret = -1; if (top != 0) { + GSList *list, *tmp; g_return_val_if_fail(top > 0 || screen_reserved_top > top, -1); ret = screen_reserved_top; screen_reserved_top += top; - window = mainwindows_find_lower(-1); - if (window != NULL) { + list = mainwindows_get_line(mainwindows_find_lower(NULL)); + for (tmp = list; tmp != NULL; tmp = tmp->next) { + window = tmp->data; window->first_line += top; mainwindow_resize(window, 0, -top); } + g_slist_free(list); } if (bottom != 0) { + GSList *list, *tmp; g_return_val_if_fail(bottom > 0 || screen_reserved_bottom > bottom, -1); ret = screen_reserved_bottom; screen_reserved_bottom += bottom; - window = mainwindows_find_upper(term_height); - if (window != NULL) { + list = mainwindows_get_line(mainwindows_find_upper(NULL)); + for (tmp = list; tmp != NULL; tmp = tmp->next) { + window = tmp->data; window->last_line -= bottom; mainwindow_resize(window, 0, -bottom); } + g_slist_free(list); } return ret; @@ -528,47 +891,109 @@ int mainwindow_set_statusbar_lines(MAIN_WINDOW_REC *window, return ret; } -static void mainwindows_resize_two(MAIN_WINDOW_REC *grow_win, - MAIN_WINDOW_REC *shrink_win, int count) +static void mainwindows_resize_two(GSList *grow_list, + GSList *shrink_list, int count) { - irssi_set_dirty(); + GSList *tmp; + MAIN_WINDOW_REC *win; - mainwindow_resize(grow_win, 0, count); - mainwindow_resize(shrink_win, 0, -count); - grow_win->dirty = TRUE; - shrink_win->dirty = TRUE; + irssi_set_dirty(); + + for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + mainwindow_resize(win, 0, -count); + win->dirty = TRUE; + } + for (tmp = grow_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + mainwindow_resize(win, 0, count); + win->dirty = TRUE; + } } static int try_shrink_lower(MAIN_WINDOW_REC *window, int count) { MAIN_WINDOW_REC *shrink_win; - shrink_win = mainwindows_find_lower(window->last_line); - if (shrink_win != NULL && - MAIN_WINDOW_TEXT_HEIGHT(shrink_win)-count >= WINDOW_MIN_SIZE) { - window->last_line += count; - shrink_win->first_line += count; - mainwindows_resize_two(window, shrink_win, count); - return TRUE; + shrink_win = mainwindows_find_lower(window); + if (shrink_win != NULL) { + int ok; + GSList *shrink_list, *tmp; + MAIN_WINDOW_REC *win; + + ok = TRUE; + shrink_list = mainwindows_get_line(shrink_win); + + for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + if (MAIN_WINDOW_TEXT_HEIGHT(win)-count < WINDOW_MIN_SIZE) { + ok = FALSE; + break; + } + } + if (ok) { + GSList *grow_list; + grow_list = mainwindows_get_line(window); + + for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + win->first_line += count; + } + for (tmp = grow_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + win->last_line += count; + } + + mainwindows_resize_two(grow_list, shrink_list, count); + g_slist_free(grow_list); + } + + g_slist_free(shrink_list); + return ok; } - return FALSE; + return FALSE; } static int try_shrink_upper(MAIN_WINDOW_REC *window, int count) { MAIN_WINDOW_REC *shrink_win; - shrink_win = mainwindows_find_upper(window->first_line); - if (shrink_win != NULL && - MAIN_WINDOW_TEXT_HEIGHT(shrink_win)-count >= WINDOW_MIN_SIZE) { - window->first_line -= count; - shrink_win->last_line -= count; - mainwindows_resize_two(window, shrink_win, count); - return TRUE; + shrink_win = mainwindows_find_upper(window); + if (shrink_win != NULL) { + int ok; + GSList *shrink_list, *tmp; + MAIN_WINDOW_REC *win; + + ok = TRUE; + shrink_list = mainwindows_get_line(shrink_win); + + for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + if (MAIN_WINDOW_TEXT_HEIGHT(win)-count < WINDOW_MIN_SIZE) { + ok = FALSE; + break; + } + } + if (ok) { + GSList *grow_list; + grow_list = mainwindows_get_line(window); + for (tmp = grow_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + win->first_line -= count; + } + for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + win->last_line -= count; + } + mainwindows_resize_two(grow_list, shrink_list, count); + g_slist_free(grow_list); + } + g_slist_free(shrink_list); + return ok; } - return FALSE; + return FALSE; } static int mainwindow_grow(MAIN_WINDOW_REC *window, int count, @@ -588,28 +1013,52 @@ static int try_grow_lower(MAIN_WINDOW_REC *window, int count) { MAIN_WINDOW_REC *grow_win; - grow_win = mainwindows_find_lower(window->last_line); + grow_win = mainwindows_find_lower(window); if (grow_win != NULL) { - window->last_line -= count; - grow_win->first_line -= count; - mainwindows_resize_two(grow_win, window, count); + MAIN_WINDOW_REC *win; + GSList *grow_list, *shrink_list, *tmp; + grow_list = mainwindows_get_line(grow_win); + shrink_list = mainwindows_get_line(window); + for (tmp = grow_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + win->first_line -= count; + } + for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + win->last_line -= count; + } + mainwindows_resize_two(grow_list, shrink_list, count); + g_slist_free(shrink_list); + g_slist_free(grow_list); } - return grow_win != NULL; + return grow_win != NULL; } static int try_grow_upper(MAIN_WINDOW_REC *window, int count) { MAIN_WINDOW_REC *grow_win; - grow_win = mainwindows_find_upper(window->first_line); + grow_win = mainwindows_find_upper(window); if (grow_win != NULL) { - window->first_line += count; - grow_win->last_line += count; - mainwindows_resize_two(grow_win, window, count); + MAIN_WINDOW_REC *win; + GSList *grow_list, *shrink_list, *tmp; + grow_list = mainwindows_get_line(grow_win); + shrink_list = mainwindows_get_line(window); + for (tmp = grow_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + win->last_line += count; + } + for (tmp = shrink_list; tmp != NULL; tmp = tmp->next) { + win = tmp->data; + win->first_line += count; + } + mainwindows_resize_two(grow_list, shrink_list, count); + g_slist_free(shrink_list); + g_slist_free(grow_list); } - return grow_win != NULL; + return grow_win != NULL; } static int mainwindow_shrink(MAIN_WINDOW_REC *window, int count, int resize_lower) @@ -627,6 +1076,109 @@ static int mainwindow_shrink(MAIN_WINDOW_REC *window, int count, int resize_lowe return TRUE; } +static void mainwindows_rresize_two(MAIN_WINDOW_REC *grow_win, + MAIN_WINDOW_REC *shrink_win, int count) +{ + irssi_set_dirty(); + + mainwindow_resize(grow_win, count, 0); + mainwindow_resize(shrink_win, -count, 0); + grow_win->dirty = TRUE; + shrink_win->dirty = TRUE; +} + +static int try_rshrink_right(MAIN_WINDOW_REC *window, int count) +{ + MAIN_WINDOW_REC *shrink_win; + + shrink_win = mainwindows_find_right(window, FALSE); + if (shrink_win != NULL) { + if (MAIN_WINDOW_TEXT_WIDTH(shrink_win)-count < NEW_WINDOW_WIDTH) { + return FALSE; + } + + shrink_win->first_column += count; + window->last_column += count; + + mainwindows_rresize_two(window, shrink_win, count); + return TRUE; + } + + return FALSE; +} + +static int try_rshrink_left(MAIN_WINDOW_REC *window, int count) +{ + MAIN_WINDOW_REC *shrink_win; + + shrink_win = mainwindows_find_left(window, FALSE); + if (shrink_win != NULL) { + if (MAIN_WINDOW_TEXT_WIDTH(shrink_win)-count < NEW_WINDOW_WIDTH) { + return FALSE; + } + window->first_column -= count; + shrink_win->last_column -= count; + + mainwindows_rresize_two(window, shrink_win, count); + return TRUE; + } + + return FALSE; +} + +static int mainwindow_rgrow(MAIN_WINDOW_REC *window, int count) +{ + if (!try_rshrink_right(window, count)) { + if (!try_rshrink_left(window, count)) + return FALSE; + } + + return TRUE; +} + +static int try_rgrow_right(MAIN_WINDOW_REC *window, int count) +{ + MAIN_WINDOW_REC *grow_win; + + grow_win = mainwindows_find_right(window, FALSE); + if (grow_win != NULL) { + grow_win->first_column -= count; + window->last_column -= count; + mainwindows_rresize_two(grow_win, window, count); + return TRUE; + } + + return FALSE; +} + +static int try_rgrow_left(MAIN_WINDOW_REC *window, int count) +{ + MAIN_WINDOW_REC *grow_win; + + grow_win = mainwindows_find_left(window, FALSE); + if (grow_win != NULL) { + grow_win->last_column += count; + window->first_column += count; + mainwindows_rresize_two(grow_win, window, count); + return TRUE; + } + + return FALSE; +} + +static int mainwindow_rshrink(MAIN_WINDOW_REC *window, int count) +{ + if (MAIN_WINDOW_TEXT_WIDTH(window)-count < NEW_WINDOW_WIDTH) + return FALSE; + + if (!try_rgrow_right(window, count)) { + if (!try_rgrow_left(window, count)) + return FALSE; + } + + return TRUE; +} + /* Change the window height - the height includes the lines needed for statusbars. If resize_lower is TRUE, the lower window is first tried to be resized instead of upper window. */ @@ -639,6 +1191,15 @@ void mainwindow_set_size(MAIN_WINDOW_REC *window, int height, int resize_lower) mainwindow_grow(window, height, resize_lower); } +void mainwindow_set_rsize(MAIN_WINDOW_REC *window, int width) +{ + width -= window->width; + if (width < 0) + mainwindow_rshrink(window, -width); + else + mainwindow_rgrow(window, width); +} + void mainwindows_redraw_dirty(void) { GSList *tmp; @@ -653,6 +1214,8 @@ void mainwindows_redraw_dirty(void) if (rec->dirty) { rec->dirty = FALSE; gui_window_redraw(rec->active); + } else if (WINDOW_GUI(rec->active)->view->dirty) { + gui_window_redraw(rec->active); } } } @@ -707,35 +1270,52 @@ static void cmd_window_size(const char *data) /* SYNTAX: WINDOW BALANCE */ static void cmd_window_balance(void) { - GSList *sorted, *tmp; + GSList *sorted, *stmp, *line, *ltmp; int avail_size, unit_size, bigger_units; int windows, last_line, old_size; + MAIN_WINDOW_REC *win; windows = g_slist_length(mainwindows); if (windows == 1) return; + sorted = NULL; + windows = 0; + for (win = mainwindows_find_lower(NULL); + win != NULL; + win = mainwindows_find_lower(win)) { + windows++; + sorted = g_slist_append(sorted, win); + } + avail_size = term_height - screen_reserved_top-screen_reserved_bottom; unit_size = avail_size/windows; bigger_units = avail_size%windows; - sorted = mainwindows_get_sorted(FALSE); - last_line = screen_reserved_top; - for (tmp = sorted; tmp != NULL; tmp = tmp->next) { - MAIN_WINDOW_REC *rec = tmp->data; + last_line = screen_reserved_top; + for (stmp = sorted; stmp != NULL; stmp = stmp->next) { + win = stmp->data; + line = mainwindows_get_line(win); - old_size = rec->height; - rec->first_line = last_line; - rec->last_line = rec->first_line + unit_size-1; + for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) { + MAIN_WINDOW_REC *rec = ltmp->data; + old_size = rec->height; + rec->first_line = last_line; + rec->last_line = rec->first_line + unit_size-1; - if (bigger_units > 0) { - rec->last_line++; - bigger_units--; - } + if (bigger_units > 0) { + rec->last_line++; + } - rec->height = rec->last_line-rec->first_line+1; - last_line = rec->last_line+1; + rec->height = rec->last_line-rec->first_line+1; - mainwindow_resize(rec, 0, rec->height-old_size); + mainwindow_resize(rec, 0, rec->height-old_size); + } + if (line != NULL && bigger_units > 0) { + bigger_units--; + } + last_line = win->last_line+1; + + g_slist_free(line); } g_slist_free(sorted); @@ -769,29 +1349,30 @@ static void cmd_window_hide(const char *data) return; if (WINDOW_MAIN(window)->sticky_windows) { - printformat_window(active_win, MSGLEVEL_CLIENTERROR, - TXT_CANT_HIDE_STICKY_WINDOWS); - return; + if (!settings_get_bool("autounstick_windows")) { + printformat_window(active_win, MSGLEVEL_CLIENTERROR, + TXT_CANT_HIDE_STICKY_WINDOWS); + return; + } } mainwindow_destroy(WINDOW_MAIN(window)); if (active_mainwin == NULL) { active_mainwin = WINDOW_MAIN(active_win); - window_set_active(active_mainwin->active); + window_set_active(active_mainwin->active); } } -/* SYNTAX: WINDOW SHOW <number>|<name> */ -static void cmd_window_show(const char *data) +static void _cmd_window_show_opt(const char *data, int right) { - MAIN_WINDOW_REC *parent; + MAIN_WINDOW_REC *parent; WINDOW_REC *window; if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); if (is_numeric(data, '\0')) { - window = window_find_refnum(atoi(data)); + window = window_find_refnum(atoi(data)); if (window == NULL) { printformat_window(active_win, MSGLEVEL_CLIENTERROR, TXT_REFNUM_NOT_FOUND, data); @@ -804,30 +1385,150 @@ static void cmd_window_show(const char *data) return; if (WINDOW_GUI(window)->sticky) { - printformat_window(active_win, MSGLEVEL_CLIENTERROR, - TXT_CANT_SHOW_STICKY_WINDOWS); - return; + if (!settings_get_bool("autounstick_windows")) { + printformat_window(active_win, MSGLEVEL_CLIENTERROR, + TXT_CANT_SHOW_STICKY_WINDOWS); + return; + } } - parent = mainwindow_create(); + parent = mainwindow_create(right); parent->active = window; - gui_window_reparent(window, parent); + gui_window_reparent(window, parent); if (settings_get_bool("autostick_split_windows")) - gui_window_set_sticky(window); + gui_window_set_sticky(window); active_mainwin = NULL; window_set_active(window); } +/* SYNTAX: WINDOW SHOW <number>|<name> */ +static void cmd_window_show(const char *data) +{ + _cmd_window_show_opt(data, FALSE); +} + +/* SYNTAX: WINDOW RSHOW <number>|<name> */ +static void cmd_window_rshow(const char *data) +{ + _cmd_window_show_opt(data, TRUE); +} + +/* SYNTAX: WINDOW RGROW [<columns>] */ +static void cmd_window_rgrow(const char *data) +{ + int count; + + count = *data == '\0' ? 1 : atoi(data); + if (!mainwindow_rgrow(WINDOW_MAIN(active_win), count)) { + printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, + TXT_WINDOW_TOO_SMALL); + } +} + +/* SYNTAX: WINDOW RSHRINK [<lines>] */ +static void cmd_window_rshrink(const char *data) +{ + int count; + + count = *data == '\0' ? 1 : atoi(data); + if (!mainwindow_rshrink(WINDOW_MAIN(active_win), count)) { + printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, + TXT_WINDOW_TOO_SMALL); + } +} + +/* SYNTAX: WINDOW RSIZE <columns> */ +static void cmd_window_rsize(const char *data) +{ + char rsizestr[MAX_INT_STRLEN]; + int rsize; + + if (!is_numeric(data, 0)) return; + rsize = atoi(data); + + rsize -= MAIN_WINDOW_TEXT_WIDTH(WINDOW_MAIN(active_win)); + if (rsize == 0) return; + + ltoa(rsizestr, rsize < 0 ? -rsize : rsize); + if (rsize < 0) + cmd_window_rshrink(rsizestr); + else + cmd_window_rgrow(rsizestr); +} + +/* SYNTAX: WINDOW RBALANCE */ +static void cmd_window_rbalance(void) +{ + GSList *line, *ltmp; + int avail_width, unit_width, bigger_units; + int windows, last_column, old_width; + MAIN_WINDOW_REC *win; + + line = mainwindows_get_line(WINDOW_MAIN(active_win)); + windows = g_slist_length(line); + if (windows == 1) { + g_slist_free(line); + return; + } + + avail_width = term_width - screen_reserved_left-screen_reserved_right - windows + 1; + unit_width = avail_width/windows; + bigger_units = avail_width%windows; + + last_column = screen_reserved_left; + for (ltmp = line; ltmp != NULL; ltmp = ltmp->next) { + win = ltmp->data; + old_width = win->width; + win->first_column = last_column; + win->last_column = win->first_column + unit_width-1; + + if (bigger_units > 0) { + win->last_column++; + bigger_units--; + } + + mainwindow_resize(win, win->last_column - win->first_column + 1 - old_width, 0); + last_column = win->last_column+2; + } + g_slist_free(line); + + mainwindows_redraw(); +} + /* SYNTAX: WINDOW UP */ static void cmd_window_up(void) { MAIN_WINDOW_REC *rec; - rec = mainwindows_find_upper(active_mainwin->first_line); + rec = mainwindows_find_left_upper(active_mainwin); + if (rec == NULL) + rec = mainwindows_find_left_upper(NULL); + if (rec != NULL) + window_set_active(rec->active); +} + +/* SYNTAX: WINDOW DUP */ +static void cmd_window_dup(void) +{ + MAIN_WINDOW_REC *rec; + + rec = mainwindows_find_upper(active_mainwin); if (rec == NULL) - rec = mainwindows_find_upper(term_height); + rec = mainwindows_find_upper(NULL); + if (rec != NULL) + window_set_active(rec->active); +} + +/* SYNTAX: WINDOW DLEFT */ +static void cmd_window_dleft(void) +{ + MAIN_WINDOW_REC *rec; + + rec = mainwindows_find_left(active_mainwin, FALSE); + if (rec == NULL) + rec = mainwindows_find_left(active_mainwin, TRUE); if (rec != NULL) window_set_active(rec->active); } @@ -837,9 +1538,33 @@ static void cmd_window_down(void) { MAIN_WINDOW_REC *rec; - rec = mainwindows_find_lower(active_mainwin->last_line); + rec = mainwindows_find_lower_right(active_mainwin); + if (rec == NULL) + rec = mainwindows_find_lower_right(NULL); + if (rec != NULL) + window_set_active(rec->active); +} + +/* SYNTAX: WINDOW DDOWN */ +static void cmd_window_ddown(void) +{ + MAIN_WINDOW_REC *rec; + + rec = mainwindows_find_lower(active_mainwin); + if (rec == NULL) + rec = mainwindows_find_lower(NULL); + if (rec != NULL) + window_set_active(rec->active); +} + +/* SYNTAX: WINDOW DRIGHT */ +static void cmd_window_dright(void) +{ + MAIN_WINDOW_REC *rec; + + rec = mainwindows_find_right(active_mainwin, FALSE); if (rec == NULL) - rec = mainwindows_find_lower(-1); + rec = mainwindows_find_right(active_mainwin, TRUE); if (rec != NULL) window_set_active(rec->active); } @@ -997,13 +1722,37 @@ static void cmd_window_move_right(void) window_set_refnum(active_win, refnum); } +/* SYNTAX: WINDOW MOVE DLEFT */ +static void cmd_window_move_dleft(void) +{ + MAIN_WINDOW_REC *rec; + + rec = mainwindows_find_left(active_mainwin, FALSE); + if (rec == NULL) + rec = mainwindows_find_left(active_mainwin, TRUE); + if (rec != NULL) + window_reparent(active_win, rec); +} + +/* SYNTAX: WINDOW MOVE DRIGHT */ +static void cmd_window_move_dright(void) +{ + MAIN_WINDOW_REC *rec; + + rec = mainwindows_find_right(active_mainwin, FALSE); + if (rec == NULL) + rec = mainwindows_find_right(active_mainwin, TRUE); + if (rec != NULL) + window_reparent(active_win, rec); +} + /* SYNTAX: WINDOW MOVE UP */ static void cmd_window_move_up(void) { MAIN_WINDOW_REC *rec; - rec = mainwindows_find_upper(active_mainwin->first_line); - if (rec != NULL) + rec = mainwindows_find_upper_left(active_mainwin); + if (rec != NULL) window_reparent(active_win, rec); } @@ -1012,7 +1761,7 @@ static void cmd_window_move_down(void) { MAIN_WINDOW_REC *rec; - rec = mainwindows_find_lower(active_mainwin->last_line); + rec = mainwindows_find_lower_right(active_mainwin); if (rec != NULL) window_reparent(active_win, rec); } @@ -1058,12 +1807,14 @@ static void sig_window_print_info(WINDOW_REC *win) void mainwindows_init(void) { - old_screen_width = term_width; - old_screen_height = term_height; + screen_width = term_width; + screen_height = term_height; mainwindows = NULL; active_mainwin = NULL; + clrtoeol_info = g_new0(MAIN_WINDOW_BORDER_REC, 1); screen_reserved_top = screen_reserved_bottom = 0; + screen_reserved_left = screen_reserved_right = 0; command_bind("window grow", NULL, (SIGNAL_FUNC) cmd_window_grow); command_bind("window shrink", NULL, (SIGNAL_FUNC) cmd_window_shrink); @@ -1075,18 +1826,30 @@ void mainwindows_init(void) command_bind("window down", NULL, (SIGNAL_FUNC) cmd_window_down); command_bind("window left", NULL, (SIGNAL_FUNC) cmd_window_left); command_bind("window right", NULL, (SIGNAL_FUNC) cmd_window_right); + command_bind("window dup", NULL, (SIGNAL_FUNC) cmd_window_dup); + command_bind("window ddown", NULL, (SIGNAL_FUNC) cmd_window_ddown); + command_bind("window dleft", NULL, (SIGNAL_FUNC) cmd_window_dleft); + command_bind("window dright", NULL, (SIGNAL_FUNC) cmd_window_dright); command_bind("window stick", NULL, (SIGNAL_FUNC) cmd_window_stick); command_bind("window move left", NULL, (SIGNAL_FUNC) cmd_window_move_left); command_bind("window move right", NULL, (SIGNAL_FUNC) cmd_window_move_right); command_bind("window move up", NULL, (SIGNAL_FUNC) cmd_window_move_up); command_bind("window move down", NULL, (SIGNAL_FUNC) cmd_window_move_down); - signal_add("window print info", (SIGNAL_FUNC) sig_window_print_info); + command_bind("window move dleft", NULL, (SIGNAL_FUNC) cmd_window_move_dleft); + command_bind("window move dright", NULL, (SIGNAL_FUNC) cmd_window_move_dright); + command_bind("window rgrow", NULL, (SIGNAL_FUNC) cmd_window_rgrow); + command_bind("window rshrink", NULL, (SIGNAL_FUNC) cmd_window_rshrink); + command_bind("window rsize", NULL, (SIGNAL_FUNC) cmd_window_rsize); + command_bind("window rbalance", NULL, (SIGNAL_FUNC) cmd_window_rbalance); + command_bind("window rshow", NULL, (SIGNAL_FUNC) cmd_window_rshow); + signal_add("window print info", (SIGNAL_FUNC) sig_window_print_info); } void mainwindows_deinit(void) { while (mainwindows != NULL) mainwindow_destroy(mainwindows->data); + g_free(clrtoeol_info); command_unbind("window grow", (SIGNAL_FUNC) cmd_window_grow); command_unbind("window shrink", (SIGNAL_FUNC) cmd_window_shrink); @@ -1098,10 +1861,21 @@ void mainwindows_deinit(void) command_unbind("window down", (SIGNAL_FUNC) cmd_window_down); command_unbind("window left", (SIGNAL_FUNC) cmd_window_left); command_unbind("window right", (SIGNAL_FUNC) cmd_window_right); + command_unbind("window dup", (SIGNAL_FUNC) cmd_window_dup); + command_unbind("window ddown", (SIGNAL_FUNC) cmd_window_ddown); + command_unbind("window dleft", (SIGNAL_FUNC) cmd_window_dleft); + command_unbind("window dright", (SIGNAL_FUNC) cmd_window_dright); command_unbind("window stick", (SIGNAL_FUNC) cmd_window_stick); command_unbind("window move left", (SIGNAL_FUNC) cmd_window_move_left); command_unbind("window move right", (SIGNAL_FUNC) cmd_window_move_right); command_unbind("window move up", (SIGNAL_FUNC) cmd_window_move_up); command_unbind("window move down", (SIGNAL_FUNC) cmd_window_move_down); - signal_remove("window print info", (SIGNAL_FUNC) sig_window_print_info); + command_unbind("window move dleft", (SIGNAL_FUNC) cmd_window_move_dleft); + command_unbind("window move dright", (SIGNAL_FUNC) cmd_window_move_dright); + command_unbind("window rgrow", (SIGNAL_FUNC) cmd_window_rgrow); + command_unbind("window rshrink", (SIGNAL_FUNC) cmd_window_rshrink); + command_unbind("window rsize", (SIGNAL_FUNC) cmd_window_rsize); + command_unbind("window rbalance", (SIGNAL_FUNC) cmd_window_rbalance); + command_unbind("window rshow", (SIGNAL_FUNC) cmd_window_rshow); + signal_remove("window print info", (SIGNAL_FUNC) sig_window_print_info); } diff --git a/src/fe-text/mainwindows.h b/src/fe-text/mainwindows.h index 1bca333d..414275bf 100644 --- a/src/fe-text/mainwindows.h +++ b/src/fe-text/mainwindows.h @@ -5,36 +5,48 @@ #include "term.h" #define WINDOW_MIN_SIZE 2 +#define NEW_WINDOW_WIDTH 10 #define MAIN_WINDOW_TEXT_HEIGHT(window) \ ((window)->height-(window)->statusbar_lines) +#define MAIN_WINDOW_TEXT_WIDTH(window) \ + ((window)->width-(window)->statusbar_columns) + typedef struct { WINDOW_REC *active; TERM_WINDOW *screen_win; - int sticky_windows; /* number of sticky windows */ + int sticky_windows; /* number of sticky windows */ int first_line, last_line; /* first/last line used by this window (0..x) (includes statusbars) */ + int first_column, last_column; /* first/last column used by this window (0..x) (includes statusbars) */ int width, height; /* width/height of the window (includes statusbars) */ GSList *statusbars; - int statusbar_lines_top; - int statusbar_lines_bottom; + int statusbar_lines_top, statusbar_lines_bottom; int statusbar_lines; /* top+bottom */ + int statusbar_columns_left, statusbar_columns_right; + int statusbar_columns; /* left+right */ unsigned int dirty:1; /* This window needs a redraw */ unsigned int size_dirty:1; /* We'll need to resize the window, but haven't got around doing it just yet. */ } MAIN_WINDOW_REC; +typedef struct { + char *color; + TERM_WINDOW *window; +} MAIN_WINDOW_BORDER_REC; + extern GSList *mainwindows; extern MAIN_WINDOW_REC *active_mainwin; +extern MAIN_WINDOW_BORDER_REC *clrtoeol_info; extern int screen_reserved_top, screen_reserved_bottom; void mainwindows_init(void); void mainwindows_deinit(void); -MAIN_WINDOW_REC *mainwindow_create(void); +MAIN_WINDOW_REC *mainwindow_create(int); void mainwindow_destroy(MAIN_WINDOW_REC *window); void mainwindows_redraw(void); @@ -45,6 +57,7 @@ void mainwindows_recreate(void); to be resized instead of upper window. */ void mainwindow_set_size(MAIN_WINDOW_REC *window, int height, int resize_lower); +void mainwindow_set_rsize(MAIN_WINDOW_REC *window, int width); void mainwindows_resize(int width, int height); void mainwindow_change_active(MAIN_WINDOW_REC *mainwin, @@ -56,5 +69,6 @@ int mainwindow_set_statusbar_lines(MAIN_WINDOW_REC *window, void mainwindows_redraw_dirty(void); GSList *mainwindows_get_sorted(int reverse); +GSList *mainwindows_get_line(MAIN_WINDOW_REC *rec); #endif diff --git a/src/fe-text/module-formats.c b/src/fe-text/module-formats.c index 899827c2..8fa31a0e 100644 --- a/src/fe-text/module-formats.c +++ b/src/fe-text/module-formats.c @@ -41,8 +41,8 @@ FORMAT_REC gui_text_formats[] = { "refnum_not_found", "Window number $0 not found", 1, { 0 } }, { "window_too_small", "Not enough room to resize this window", 0 }, { "cant_hide_last", "You can't hide the last window", 0 }, - { "cant_hide_sticky_windows", "You can't hide sticky windows (use /WINDOW STICK OFF)", 0 }, - { "cant_show_sticky_windows", "You can't show sticky windows (use /WINDOW STICK OFF)", 0 }, + { "cant_hide_sticky_windows", "You can't hide sticky windows (use /SET autounstick_windows ON)", 0 }, + { "cant_show_sticky_windows", "You can't show sticky windows (use /SET autounstick_windows ON)", 0 }, { "window_not_sticky", "Window is not sticky", 0 }, { "window_set_sticky", "Window set sticky", 0 }, { "window_unset_sticky", "Window is not sticky anymore", 0 }, @@ -50,6 +50,7 @@ FORMAT_REC gui_text_formats[] = { "window_info_scroll", "%#Scroll : $0", 1, { 0 } }, { "window_scroll", "Window scroll mode is now $0", 1, { 0 } }, { "window_scroll_unknown", "Unknown scroll mode $0, must be ON, OFF or DEFAULT", 1, { 0 } }, + { "window_hidelevel", "Window hidden level is now $0", 1, { 0 } }, /* ---- */ { NULL, "Statusbars", 0 }, @@ -78,5 +79,26 @@ FORMAT_REC gui_text_formats[] = { "paste_warning", "Pasting $0 lines to $1. Press Ctrl-K if you wish to do this or Ctrl-C to cancel.", 2, { 1, 0 } }, { "paste_prompt", "Hit Ctrl-K to paste, Ctrl-C to abort?", 0 }, + /* ---- */ + { NULL, "Welcome", 0 }, + + { "irssi_banner", + " ___ _%:" + "|_ _|_ _ _____(_)%:" + " | || '_(_-<_-< |%:" + "|___|_| /__/__/_|%:" + "Irssi v$J - http://www.irssi.org", 0 }, + { "welcome_firsttime", + "- - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + "Hi there! If this is your first time using Irssi, you%:" + "might want to go to our website and read the startup%:" + "documentation to get you going.%:%:" + "Our community and staff are available to assist you or%:" + "to answer any questions you may have.%:%:" + "Use the /HELP command to get detailed information about%:" + "the available commands.%:" + "- - - - - - - - - - - - - - - - - - - - - - - - - - - -", 0 }, + { "welcome_init_settings", "The following settings were initialized", 0 }, + { NULL, NULL, 0 } }; diff --git a/src/fe-text/module-formats.h b/src/fe-text/module-formats.h index 3fa8c511..b753238b 100644 --- a/src/fe-text/module-formats.h +++ b/src/fe-text/module-formats.h @@ -26,6 +26,7 @@ enum { TXT_WINDOW_INFO_SCROLL, TXT_WINDOW_SCROLL, TXT_WINDOW_SCROLL_UNKNOWN, + TXT_WINDOW_HIDELEVEL, TXT_FILL_3, @@ -52,6 +53,12 @@ enum { TXT_PASTE_WARNING, TXT_PASTE_PROMPT, + TXT_FILL_5, /* Welcome */ + + TXT_IRSSI_BANNER, + TXT_WELCOME_FIRSTTIME, + TXT_WELCOME_INIT_SETTINGS, + TXT_COUNT }; diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c index de4499b4..5740a40b 100644 --- a/src/fe-text/statusbar-items.c +++ b/src/fe-text/statusbar-items.c @@ -369,8 +369,8 @@ static void item_lag(SBAR_ITEM_REC *item, int get_size_only) last_lag_unknown = lag_unknown; if (lag_unknown) { - // "??)" in C becomes ']' - // See: https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C + /* "??)" in C becomes ']' + See: https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C */ g_snprintf(str, sizeof(str), "%d (?""?)", lag / 100); } else { if (lag % 100 == 0) @@ -418,7 +418,7 @@ static void item_input(SBAR_ITEM_REC *item, int get_size_only) rec = g_hash_table_lookup(input_entries, item->bar->config->name); if (rec == NULL) { - rec = gui_entry_create(item->xpos, item->bar->real_ypos, + rec = gui_entry_create(ITEM_WINDOW_REAL_XPOS(item), item->bar->real_ypos, item->size, term_type == TERM_TYPE_UTF8); gui_entry_set_active(rec); g_hash_table_insert(input_entries, @@ -426,12 +426,21 @@ static void item_input(SBAR_ITEM_REC *item, int get_size_only) } if (get_size_only) { - item->min_size = 2+term_width/10; - item->max_size = term_width; - return; + int max_width; + WINDOW_REC *window; + + window = item->bar->parent_window != NULL + ? item->bar->parent_window->active + : NULL; + + max_width = window != NULL ? window->width : term_width; + + item->min_size = 2+max_width/10; + item->max_size = max_width; + return; } - gui_entry_move(rec, item->xpos, item->bar->real_ypos, + gui_entry_move(rec, ITEM_WINDOW_REAL_XPOS(item), item->bar->real_ypos, item->size); gui_entry_redraw(rec); /* FIXME: this is only necessary with ^L.. */ } diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c index f0dff828..40837eea 100644 --- a/src/fe-text/statusbar.c +++ b/src/fe-text/statusbar.c @@ -242,17 +242,24 @@ static void statusbar_resize_items(STATUSBAR_REC *bar, int max_width) static void statusbar_calc_item_positions(STATUSBAR_REC *bar) { - WINDOW_REC *old_active_win; + WINDOW_REC *window; + WINDOW_REC *old_active_win; GSList *tmp, *right_items; int xpos, rxpos; + int max_width; old_active_win = active_win; - if (bar->parent_window != NULL) + if (bar->parent_window != NULL) active_win = bar->parent_window->active; - statusbar_resize_items(bar, term_width); + window = bar->parent_window != NULL + ? bar->parent_window->active + : NULL; + + max_width = window != NULL ? window->width : term_width; + statusbar_resize_items(bar, max_width); - /* left-aligned items */ + /* left-aligned items */ xpos = 0; for (tmp = bar->items; tmp != NULL; tmp = tmp->next) { SBAR_ITEM_REC *rec = tmp->data; @@ -260,11 +267,11 @@ static void statusbar_calc_item_positions(STATUSBAR_REC *bar) if (!rec->config->right_alignment && (rec->size > 0 || rec->current_size > 0)) { if (SBAR_ITEM_REDRAW_NEEDED(bar, rec, xpos)) { - /* redraw the item */ + /* redraw the item */ rec->dirty = TRUE; if (bar->dirty_xpos == -1 || xpos < bar->dirty_xpos) { - irssi_set_dirty(); + irssi_set_dirty(); bar->dirty = TRUE; bar->dirty_xpos = xpos; } @@ -277,12 +284,12 @@ static void statusbar_calc_item_positions(STATUSBAR_REC *bar) /* right-aligned items - first copy them to a new list backwards, easier to draw them in right order */ - right_items = NULL; + right_items = NULL; for (tmp = bar->items; tmp != NULL; tmp = tmp->next) { SBAR_ITEM_REC *rec = tmp->data; if (rec->config->right_alignment) { - if (rec->size > 0) + if (rec->size > 0) right_items = g_slist_prepend(right_items, rec); else if (rec->current_size > 0 && (bar->dirty_xpos == -1 || @@ -291,12 +298,12 @@ static void statusbar_calc_item_positions(STATUSBAR_REC *bar) to begin from the item's old xpos */ irssi_set_dirty(); bar->dirty = TRUE; - bar->dirty_xpos = rec->xpos; + bar->dirty_xpos = rec->xpos; } } } - rxpos = term_width; + rxpos = max_width; for (tmp = right_items; tmp != NULL; tmp = tmp->next) { SBAR_ITEM_REC *rec = tmp->data; @@ -312,7 +319,7 @@ static void statusbar_calc_item_positions(STATUSBAR_REC *bar) rec->xpos = rxpos; } } - g_slist_free(right_items); + g_slist_free(right_items); active_win = old_active_win; } @@ -451,8 +458,13 @@ static void mainwindow_recalc_ypos(MAIN_WINDOW_REC *window, int placement) static void sig_mainwindow_resized(MAIN_WINDOW_REC *window) { - mainwindow_recalc_ypos(window, STATUSBAR_TOP); - mainwindow_recalc_ypos(window, STATUSBAR_BOTTOM); + GSList *tmp; + mainwindow_recalc_ypos(window, STATUSBAR_TOP); + mainwindow_recalc_ypos(window, STATUSBAR_BOTTOM); + for (tmp = window->statusbars; tmp != NULL; tmp = tmp->next) { + STATUSBAR_REC *bar = tmp->data; + statusbar_redraw(bar, TRUE); + } } STATUSBAR_REC *statusbar_create(STATUSBAR_GROUP_REC *group, @@ -728,7 +740,7 @@ void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only, g_string_append_c(out, ' '); } - gui_printtext(item->xpos, item->bar->real_ypos, out->str); + gui_printtext(ITEM_WINDOW_REAL_XPOS(item), item->bar->real_ypos, out->str); g_string_free(out, TRUE); } g_free(tmpstr); @@ -960,20 +972,42 @@ void statusbar_item_destroy(SBAR_ITEM_REC *item) g_free(item); } +static MAIN_WINDOW_BORDER_REC *set_border_info(STATUSBAR_REC *bar) +{ + MAIN_WINDOW_BORDER_REC *orig_border, *new_border; + orig_border = clrtoeol_info; + new_border = g_new0(MAIN_WINDOW_BORDER_REC, 1); + new_border->window = bar->parent_window != NULL ? bar->parent_window->screen_win : NULL; + new_border->color = bar->color; + clrtoeol_info = new_border; + return orig_border; +} + +static void restore_border_info(MAIN_WINDOW_BORDER_REC *border_info) +{ + MAIN_WINDOW_BORDER_REC *old_border; + old_border = clrtoeol_info; + clrtoeol_info = border_info; + g_free(old_border); +} + static void statusbar_redraw_needed_items(STATUSBAR_REC *bar) { - WINDOW_REC *old_active_win; + WINDOW_REC *old_active_win; GSList *tmp; char *str; old_active_win = active_win; - if (bar->parent_window != NULL) + if (bar->parent_window != NULL) active_win = bar->parent_window->active; if (bar->dirty_xpos >= 0) { + MAIN_WINDOW_BORDER_REC *orig_border; + orig_border = set_border_info(bar); str = g_strconcat(bar->color, "%>", NULL); - gui_printtext(bar->dirty_xpos, bar->real_ypos, str); + gui_printtext(BAR_WINDOW_REAL_DIRTY_XPOS(bar), bar->real_ypos, str); g_free(str); + restore_border_info(orig_border); } for (tmp = bar->items; tmp != NULL; tmp = tmp->next) { @@ -982,13 +1016,13 @@ static void statusbar_redraw_needed_items(STATUSBAR_REC *bar) if (rec->dirty || (bar->dirty_xpos != -1 && rec->xpos >= bar->dirty_xpos)) { - rec->current_size = rec->size; + rec->current_size = rec->size; rec->func(rec, FALSE); rec->dirty = FALSE; } } - active_win = old_active_win; + active_win = old_active_win; } void statusbar_redraw_dirty(void) diff --git a/src/fe-text/statusbar.h b/src/fe-text/statusbar.h index 309294b0..b0048cc4 100644 --- a/src/fe-text/statusbar.h +++ b/src/fe-text/statusbar.h @@ -23,6 +23,12 @@ typedef struct SBAR_ITEM_REC SBAR_ITEM_REC; #define STATUSBAR_VISIBLE_ACTIVE 2 #define STATUSBAR_VISIBLE_INACTIVE 3 +#define ITEM_WINDOW_REAL_XPOS(item) ( ( (item)->bar->parent_window != NULL ? \ + (item)->bar->parent_window->first_column + (item)->bar->parent_window->statusbar_columns_left : 0 ) + (item)->xpos ) + +#define BAR_WINDOW_REAL_DIRTY_XPOS(bar) ( ( (bar)->parent_window != NULL ? \ + (bar)->parent_window->first_column + (bar)->parent_window->statusbar_columns_left : 0 ) + (bar)->dirty_xpos ) + typedef struct { char *name; GSList *config_bars; diff --git a/src/fe-text/term-terminfo.c b/src/fe-text/term-terminfo.c index 6645cfb0..68947f0c 100644 --- a/src/fe-text/term-terminfo.c +++ b/src/fe-text/term-terminfo.c @@ -23,6 +23,7 @@ #include "term.h" #include "terminfo-core.h" #include "fe-windows.h" +#include "gui-printtext.h" #include "utf8.h" #include <signal.h> @@ -284,10 +285,10 @@ void term_window_clear(TERM_WINDOW *window) { int y; - terminfo_set_normal(); - if (window->y == 0 && window->height == term_height) { - term_clear(); - } else { + terminfo_set_normal(); + if (window->y == 0 && window->height == term_height && window->width == term_width) { + term_clear(); + } else { for (y = 0; y < window->height; y++) { term_move(window, 0, y); term_clrtoeol(window); @@ -452,14 +453,14 @@ void term_set_color(TERM_WINDOW *window, int col) void term_move(TERM_WINDOW *window, int x, int y) { if (x >= 0 && y >= 0) { - vcmove = TRUE; - vcx = x+window->x; - vcy = y+window->y; - - if (vcx >= term_width) - vcx = term_width-1; - if (vcy >= term_height) - vcy = term_height-1; + vcmove = TRUE; + vcx = x+window->x; + vcy = y+window->y; + + if (vcx >= term_width) + vcx = term_width-1; + if (vcy >= term_height) + vcy = term_height-1; } } @@ -552,7 +553,7 @@ int term_addstr(TERM_WINDOW *window, const char *str) while (*ptr != '\0') { tmp = g_utf8_get_char_validated(ptr, -1); /* On utf8 error, treat as single byte and try to - continue interpretting rest of string as utf8 */ + continue interpreting rest of string as utf8 */ if (tmp == (gunichar)-1 || tmp == (gunichar)-2) { len++; ptr++; @@ -574,21 +575,52 @@ int term_addstr(TERM_WINDOW *window, const char *str) void term_clrtoeol(TERM_WINDOW *window) { - /* clrtoeol() doesn't necessarily understand colors */ - if (last_fg == -1 && last_bg == -1 && - (last_attrs & (ATTR_UNDERLINE|ATTR_REVERSE|ATTR_ITALIC)) == 0) { - if (!term_lines_empty[vcy]) { - if (vcmove) term_move_real(); - terminfo_clrtoeol(); - if (vcx == 0) term_lines_empty[vcy] = TRUE; - } - } else if (vcx < term_width) { - /* we'll need to fill the line ourself. */ + if (vcx < window->x) { + /* we just wrapped outside of the split, warp the cursor back into the window */ + vcx += window->x; + vcmove = TRUE; + } + if (window->x + window->width < term_width) { + /* we need to fill a vertical split */ if (vcmove) term_move_real(); - terminfo_repeat(' ', term_width-vcx); + terminfo_repeat(' ', window->x + window->width - vcx + 1); terminfo_move(vcx, vcy); - term_lines_empty[vcy] = FALSE; + term_lines_empty[vcy] = FALSE; + } else { + /* clrtoeol() doesn't necessarily understand colors */ + if (last_fg == -1 && last_bg == -1 && + (last_attrs & (ATTR_UNDERLINE|ATTR_REVERSE|ATTR_ITALIC)) == 0) { + if (!term_lines_empty[vcy]) { + if (vcmove) term_move_real(); + terminfo_clrtoeol(); + if (vcx == 0) term_lines_empty[vcy] = TRUE; + } + } else if (vcx < term_width) { + /* we'll need to fill the line ourself. */ + if (vcmove) term_move_real(); + terminfo_repeat(' ', term_width-vcx); + terminfo_move(vcx, vcy); + term_lines_empty[vcy] = FALSE; + } + } +} + +void term_window_clrtoeol(TERM_WINDOW* window, int ypos) +{ + if (ypos >= 0 && window->y + ypos != vcy) { + /* the line is already full */ + return; } + term_clrtoeol(window); + if (window->x + window->width < term_width) { + gui_printtext_window_border(window->x + window->width, window->y + ypos); + term_set_color(window, ATTR_RESET); + } +} + +void term_window_clrtoeol_abs(TERM_WINDOW* window, int ypos) +{ + term_window_clrtoeol(window, ypos - window->y); } void term_move_cursor(int x, int y) @@ -733,3 +765,31 @@ void term_gets(GArray *buffer, int *line_count) } } } + +static const char* term_env_warning = + "You seem to be running Irssi inside %2$s, but the TERM environment variable " + "is set to '%1$s', which can cause display glitches.\n" + "Consider changing TERM to '%2$s' or '%2$s-256color' instead."; + +void term_environment_check(void) +{ + const char *term, *sty, *tmux, *multiplexer; + + term = g_getenv("TERM"); + sty = g_getenv("STY"); + tmux = g_getenv("TMUX"); + + multiplexer = (sty && *sty) ? "screen" : + (tmux && *tmux) ? "tmux" : NULL; + + if (!multiplexer) { + return; + } + + if (term && (g_str_has_prefix(term, "screen") || + g_str_has_prefix(term, "tmux"))) { + return; + } + + g_warning(term_env_warning, term, multiplexer); +} diff --git a/src/fe-text/term.h b/src/fe-text/term.h index 0c7847f6..f25154c2 100644 --- a/src/fe-text/term.h +++ b/src/fe-text/term.h @@ -85,6 +85,8 @@ void term_addch(TERM_WINDOW *window, char chr); void term_add_unichar(TERM_WINDOW *window, unichar chr); int term_addstr(TERM_WINDOW *window, const char *str); void term_clrtoeol(TERM_WINDOW *window); +void term_window_clrtoeol(TERM_WINDOW* window, int ypos); +void term_window_clrtoeol_abs(TERM_WINDOW* window, int ypos_abs); void term_move_cursor(int x, int y); @@ -105,4 +107,6 @@ void term_gets(GArray *buffer, int *line_count); void term_common_init(void); void term_common_deinit(void); +void term_environment_check(void); + #endif diff --git a/src/fe-text/textbuffer-commands.c b/src/fe-text/textbuffer-commands.c index 648862e7..97d897f3 100644 --- a/src/fe-text/textbuffer-commands.c +++ b/src/fe-text/textbuffer-commands.c @@ -89,6 +89,25 @@ static void cmd_window_scroll(const char *data) gui->scroll : settings_get_bool("scroll")); } +/* SYNTAX: WINDOW HIDELEVEL [<level>] */ +static void cmd_window_hidelevel(const char *data) +{ + GUI_WINDOW_REC *gui; + char *level; + + g_return_if_fail(data != NULL); + + gui = WINDOW_GUI(active_win); + textbuffer_view_set_hidden_level(gui->view, + combine_level(gui->view->hidden_level, data)); + textbuffer_view_redraw(gui->view); + level = gui->view->hidden_level == 0 ? g_strdup("NONE") : + bits2level(gui->view->hidden_level); + printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, + TXT_WINDOW_HIDELEVEL, level); + g_free(level); +} + static void cmd_scrollback(const char *data, SERVER_REC *server, WI_ITEM_REC *item) { @@ -358,6 +377,7 @@ void textbuffer_commands_init(void) { command_bind("clear", NULL, (SIGNAL_FUNC) cmd_clear); command_bind("window scroll", NULL, (SIGNAL_FUNC) cmd_window_scroll); + command_bind("window hidelevel", NULL, (SIGNAL_FUNC) cmd_window_hidelevel); command_bind("scrollback", NULL, (SIGNAL_FUNC) cmd_scrollback); command_bind("scrollback clear", NULL, (SIGNAL_FUNC) cmd_scrollback_clear); command_bind("scrollback levelclear", NULL, (SIGNAL_FUNC) cmd_scrollback_levelclear); @@ -377,6 +397,7 @@ void textbuffer_commands_deinit(void) { command_unbind("clear", (SIGNAL_FUNC) cmd_clear); command_unbind("window scroll", (SIGNAL_FUNC) cmd_window_scroll); + command_unbind("window hidelevel", (SIGNAL_FUNC) cmd_window_hidelevel); command_unbind("scrollback", (SIGNAL_FUNC) cmd_scrollback); command_unbind("scrollback clear", (SIGNAL_FUNC) cmd_scrollback_clear); command_unbind("scrollback levelclear", (SIGNAL_FUNC) cmd_scrollback_levelclear); diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c index cb066f5e..99625ecc 100644 --- a/src/fe-text/textbuffer-view.c +++ b/src/fe-text/textbuffer-view.c @@ -41,9 +41,15 @@ static GSList *views; #define view_is_bottom(view) \ ((view)->ypos >= -1 && (view)->ypos < (view)->height) -#define view_get_linecount(view, line) \ +#define view_get_linecount_hidden(view, line) \ textbuffer_view_get_line_cache(view, line)->count +#define view_line_is_hidden(view, line) \ + (((line)->info.level & (view)->hidden_level) != 0) + +#define view_get_linecount(view, line) \ + (view_line_is_hidden(view, line) ? 0 : view_get_linecount_hidden(view, line)) + static GSList *textbuffer_get_views(TEXT_BUFFER_REC *buffer) { GSList *tmp, *list; @@ -388,9 +394,9 @@ static void view_reset_cache(TEXT_BUFFER_VIEW_REC *view) static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, int subline, int ypos, int max) { - INDENT_FUNC indent_func; + INDENT_FUNC indent_func; LINE_CACHE_REC *cache; - const unsigned char *text, *end, *text_newline; + const unsigned char *text, *end, *text_newline; unsigned char *tmp; unichar chr; int xpos, color, drawcount, first, need_move, need_clrtoeol, char_width; @@ -399,54 +405,54 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, #endif if (view->dirty) /* don't bother drawing anything - redraw is coming */ - return 0; + return 0; cache = textbuffer_view_get_line_cache(view, line); if (subline >= cache->count) - return 0; + return 0; - color = ATTR_RESET; - need_move = TRUE; need_clrtoeol = FALSE; + color = ATTR_RESET; + need_move = TRUE; need_clrtoeol = FALSE; xpos = drawcount = 0; first = TRUE; text_newline = text = subline == 0 ? line->text : cache->lines[subline-1].start; for (;;) { if (text == text_newline) { - if (need_clrtoeol && xpos < term_width) { + if (need_clrtoeol && xpos < view->width + (view->width == term_width ? 0 : 1)) { term_set_color(view->window, ATTR_RESET); - term_clrtoeol(view->window); + term_window_clrtoeol(view->window, ypos); } if (first) first = FALSE; else { ypos++; - if (--max == 0) + if (--max == 0) break; } if (subline > 0) { - /* continuing previous line - indent it */ + /* continuing previous line - indent it */ indent_func = cache->lines[subline-1].indent_func; if (indent_func == NULL) xpos = cache->lines[subline-1].indent; - color = cache->lines[subline-1].color; + color = cache->lines[subline-1].color; #ifdef TERM_TRUECOLOR - fg24 = cache->lines[subline-1].fg24; - bg24 = cache->lines[subline-1].bg24; + fg24 = cache->lines[subline-1].fg24; + bg24 = cache->lines[subline-1].bg24; #endif } else { indent_func = NULL; } if (xpos == 0 && indent_func == NULL) - need_clrtoeol = TRUE; + need_clrtoeol = TRUE; else { /* line was indented - need to clear the - indented area first */ + indented area first */ term_set_color(view->window, ATTR_RESET); term_move(view->window, 0, ypos); - term_clrtoeol(view->window); + term_window_clrtoeol(view->window, ypos); if (indent_func != NULL) xpos = indent_func(view, line, ypos); @@ -463,9 +469,17 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, } else { /* get the beginning of the next subline */ text_newline = cache->lines[subline].start; - need_move = !cache->lines[subline].continues; + if (view->width == term_width) { + /* ensure that links / long words are not broken */ + need_move = !cache->lines[subline].continues; + } else { + /* we cannot use the need_move + optimisation unless the split spans + the whole width */ + need_move = TRUE; + } } - drawcount++; + drawcount++; subline++; } @@ -473,10 +487,10 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, /* command */ text++; if (*text == LINE_CMD_EOL) - break; + break; if (*text == LINE_CMD_CONTINUE) { - /* jump to next block */ + /* jump to next block */ memcpy(&tmp, text+1, sizeof(unsigned char *)); text = tmp; continue; @@ -511,13 +525,13 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, } xpos += char_width; - if (xpos <= term_width) { + if (xpos <= view->width) { if (unichar_isprint(chr)) { if (view->utf8) - term_add_unichar(view->window, chr); + term_add_unichar(view->window, chr); else - for (; text < end; text++) - term_addch(view->window, *text); + for (; text < end; text++) + term_addch(view->window, *text); } else { /* low-ascii */ term_set_color(view->window, ATTR_RESET|ATTR_REVERSE); @@ -528,12 +542,12 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, text = end; } - if (need_clrtoeol && xpos < term_width) { + if (need_clrtoeol && xpos < view->width + (view->width == term_width ? 0 : 1)) { term_set_color(view->window, ATTR_RESET); - term_clrtoeol(view->window); + term_window_clrtoeol(view->window, ypos); } - return drawcount; + return drawcount; } /* Recalculate view's bottom line information - try to keep the @@ -552,6 +566,9 @@ static void textbuffer_view_init_bottom(TEXT_BUFFER_VIEW_REC *view) total = 0; line = textbuffer_line_last(view->buffer); for (; line != NULL; line = line->prev) { + if (view_line_is_hidden(view, line)) + continue; + linecount = view_get_linecount(view, line); if (line == view->bottom_startline) { /* keep the old one, make sure that subline is ok */ @@ -614,6 +631,8 @@ TEXT_BUFFER_VIEW_REC *textbuffer_view_create(TEXT_BUFFER_REC *buffer, view->subline = view->bottom_subline; view->bottom = TRUE; + view->hidden_level = 0; + textbuffer_view_init_ypos(view); view->bookmarks = g_hash_table_new((GHashFunc) g_str_hash, @@ -726,8 +745,10 @@ static void view_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, return; while (line != NULL && lines > 0) { - linecount = view_line_draw(view, line, subline, ypos, lines); - ypos += linecount; lines -= linecount; + if (!view_line_is_hidden(view, line)) { + linecount = view_line_draw(view, line, subline, ypos, lines); + ypos += linecount; lines -= linecount; + } subline = 0; line = line->next; @@ -738,7 +759,7 @@ static void view_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, term_set_color(view->window, ATTR_RESET); while (lines > 0) { term_move(view->window, 0, ypos); - term_clrtoeol(view->window); + term_window_clrtoeol(view->window, ypos); ypos++; lines--; } } @@ -768,58 +789,63 @@ static void view_draw_bottom(TEXT_BUFFER_VIEW_REC *view, int lines) view_draw(view, line, subline, maxline, lines, TRUE); } -/* Returns number of lines actually scrolled */ +/* lines: this pointer is scrolled by scrollcount screen lines + subline: this pointer contains the subline position + scrollcount: the number of lines to scroll down (negative: up) + draw_nonclean: whether to redraw the screen now + + Returns number of lines actually scrolled */ static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines, int *subline, int scrollcount, int draw_nonclean) { int linecount, realcount, scroll_visible; if (*lines == NULL) - return 0; + return 0; /* scroll down */ scroll_visible = lines == &view->startline; realcount = -*subline; scrollcount += *subline; - *subline = 0; + *subline = 0; while (scrollcount > 0) { linecount = view_get_linecount(view, *lines); if ((scroll_visible && *lines == view->bottom_startline) && (scrollcount >= view->bottom_subline)) { *subline = view->bottom_subline; - realcount += view->bottom_subline; - scrollcount = 0; - break; + realcount += view->bottom_subline; + scrollcount = 0; + break; } - realcount += linecount; + realcount += linecount; scrollcount -= linecount; if (scrollcount < 0) { - realcount += scrollcount; + realcount += scrollcount; *subline = linecount+scrollcount; - scrollcount = 0; - break; + scrollcount = 0; + break; } if ((*lines)->next == NULL) break; - *lines = (*lines)->next; + *lines = (*lines)->next; } - /* scroll up */ + /* scroll up */ while (scrollcount < 0 && (*lines)->prev != NULL) { *lines = (*lines)->prev; linecount = view_get_linecount(view, *lines); - realcount -= linecount; + realcount -= linecount; scrollcount += linecount; if (scrollcount > 0) { - realcount += scrollcount; + realcount += scrollcount; *subline = scrollcount; - break; + break; } } @@ -827,19 +853,28 @@ static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines, if (realcount <= -view->height || realcount >= view->height) { /* scrolled more than screenful, redraw the whole view */ - textbuffer_view_redraw(view); + textbuffer_view_redraw(view); } else { - term_set_color(view->window, ATTR_RESET); - term_window_scroll(view->window, realcount); + if (view->width == term_width) { + /* we can try to use vt100 scroll regions */ + term_set_color(view->window, ATTR_RESET); + term_window_scroll(view->window, realcount); - if (draw_nonclean) { - if (realcount < 0) - view_draw_top(view, -realcount, TRUE); - else - view_draw_bottom(view, realcount); - } + if (draw_nonclean) { + if (realcount < 0) + view_draw_top(view, -realcount, TRUE); + else + view_draw_bottom(view, realcount); + } - term_refresh(view->window); + term_refresh(view->window); + } else { + /* do not bother with vt400 scroll + rectangles for now, redraw the + whole view */ + view->dirty = TRUE; + irssi_set_dirty(); + } } } @@ -1027,7 +1062,7 @@ static void view_insert_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) view->bottom = view_is_bottom(view); } - if (view->window != NULL) { + if (view->window != NULL && !view_line_is_hidden(view, line)) { ypos = view->ypos+1 - view_get_linecount(view, line); if (ypos >= 0) subline = 0; @@ -1042,7 +1077,7 @@ static void view_insert_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) } } - if (view->window != NULL) + if (view->window != NULL && !view_line_is_hidden(view, line)) term_refresh(view->window); } @@ -1122,6 +1157,12 @@ static int view_get_lines_height(TEXT_BUFFER_VIEW_REC *view, return height < view->height ? height : view->height; } +/* line: line to remove + linecount: linecount of that line, to be offset when the line was in/below view + + scroll the window maintaining the startline while removing line + if startline is removed, make the previous line the new startline +*/ static void view_remove_line_update_startline(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, int linecount) { @@ -1318,6 +1359,37 @@ LINE_REC *textbuffer_view_get_bookmark(TEXT_BUFFER_VIEW_REC *view, return g_hash_table_lookup(view->bookmarks, name); } +void textbuffer_view_set_hidden_level(TEXT_BUFFER_VIEW_REC *view, int level) +{ + g_return_if_fail(view != NULL); + + if (view->hidden_level != level) { + if (view->empty_linecount > 0 && view->startline != NULL) { + int old_height, new_height; + LINE_REC *hidden_start; + + hidden_start = view->startline; + while (hidden_start->prev != NULL && view_line_is_hidden(view, hidden_start->prev)) { + hidden_start = hidden_start->prev; + } + + old_height = view_get_lines_height(view, hidden_start, view->subline, NULL); + view->hidden_level = level; + new_height = view_get_lines_height(view, hidden_start, view->subline, NULL); + + view->empty_linecount -= new_height - old_height; + + if (view->empty_linecount < 0) + view->empty_linecount = 0; + else if (view->empty_linecount > view->height) + view->empty_linecount = view->height; + } else { + view->hidden_level = level; + } + textbuffer_view_resize(view, view->width, view->height); + } +} + /* Specify window where the changes in view should be drawn, NULL disables it. */ void textbuffer_view_set_window(TEXT_BUFFER_VIEW_REC *view, diff --git a/src/fe-text/textbuffer-view.h b/src/fe-text/textbuffer-view.h index 5e7a9d0a..a670df2b 100644 --- a/src/fe-text/textbuffer-view.h +++ b/src/fe-text/textbuffer-view.h @@ -49,41 +49,51 @@ typedef struct { struct _TEXT_BUFFER_VIEW_REC { TEXT_BUFFER_REC *buffer; - GSList *siblings; /* other views that use the same buffer */ + /* other views that use the same buffer */ + GSList *siblings; TERM_WINDOW *window; int width, height; int default_indent; INDENT_FUNC default_indent_func; - unsigned int longword_noindent:1; - unsigned int scroll:1; /* scroll down automatically when at bottom */ - unsigned int utf8:1; /* use UTF8 in this view */ - unsigned int break_wide:1; /* Break wide chars in this view */ TEXT_BUFFER_CACHE_REC *cache; - int ypos; /* cursor position - visible area is 0..height-1 */ + /* cursor position - visible area is 0..height-1 */ + int ypos; - LINE_REC *startline; /* line at the top of the screen */ - int subline; /* number of "real lines" to skip from `startline' */ + /* line at the top of the screen */ + LINE_REC *startline; + /* number of "real lines" to skip from `startline' */ + int subline; /* marks the bottom of the text buffer */ LINE_REC *bottom_startline; int bottom_subline; + /* Bookmarks to the lines in the buffer - removed automatically + when the line gets removed from buffer */ + GHashTable *bookmarks; + + /* these levels should be hidden */ + int hidden_level; /* how many empty lines are in screen. a screenful when started or used /CLEAR */ int empty_linecount; + + unsigned int longword_noindent:1; + /* scroll down automatically when at bottom */ + unsigned int scroll:1; + /* use UTF8 in this view */ + unsigned int utf8:1; + /* Break wide chars in this view */ + unsigned int break_wide:1; /* window is at the bottom of the text buffer */ unsigned int bottom:1; /* if !bottom - new text has been printed since we were at bottom */ unsigned int more_text:1; /* Window needs a redraw */ unsigned int dirty:1; - - /* Bookmarks to the lines in the buffer - removed automatically - when the line gets removed from buffer */ - GHashTable *bookmarks; }; /* Create new view. */ @@ -143,6 +153,8 @@ void textbuffer_view_set_bookmark_bottom(TEXT_BUFFER_VIEW_REC *view, /* Return the line for bookmark */ LINE_REC *textbuffer_view_get_bookmark(TEXT_BUFFER_VIEW_REC *view, const char *name); +/* Set hidden level for view */ +void textbuffer_view_set_hidden_level(TEXT_BUFFER_VIEW_REC *view, int level); /* Specify window where the changes in view should be drawn, NULL disables it. */ diff --git a/src/fe-text/textbuffer.c b/src/fe-text/textbuffer.c index a920fab2..01cdd118 100644 --- a/src/fe-text/textbuffer.c +++ b/src/fe-text/textbuffer.c @@ -230,6 +230,7 @@ LINE_REC *textbuffer_line_last(TEXT_BUFFER_REC *buffer) return buffer->cur_line; } +/* returns TRUE if `search' comes on or after `line' in the buffer */ int textbuffer_line_exists_after(LINE_REC *line, LINE_REC *search) { while (line != NULL) { diff --git a/src/fe-text/textbuffer.h b/src/fe-text/textbuffer.h index 303789a3..2aa22f1a 100644 --- a/src/fe-text/textbuffer.h +++ b/src/fe-text/textbuffer.h @@ -65,10 +65,10 @@ typedef struct { LINE_REC *cur_line; TEXT_CHUNK_REC *cur_text; - unsigned int last_eol:1; int last_fg; int last_bg; int last_flags; + unsigned int last_eol:1; } TEXT_BUFFER_REC; /* Create new buffer */ |