diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/fe-common/core/fe-windows.h | 8 | ||||
-rw-r--r-- | src/fe-common/core/formats.c | 27 | ||||
-rw-r--r-- | src/fe-common/core/window-commands.c | 7 | ||||
-rw-r--r-- | src/fe-common/core/window-items.c | 2 | ||||
-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-windows.c | 14 | ||||
-rw-r--r-- | src/fe-text/mainwindows-layout.c | 159 | ||||
-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 | 4 | ||||
-rw-r--r-- | src/fe-text/statusbar-items.c | 19 | ||||
-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 | 82 | ||||
-rw-r--r-- | src/fe-text/term.h | 2 | ||||
-rw-r--r-- | src/fe-text/textbuffer-view.c | 121 |
17 files changed, 1382 insertions, 355 deletions
diff --git a/src/fe-common/core/fe-windows.h b/src/fe-common/core/fe-windows.h index 32d6cfcd..aaa773c8 100644 --- a/src/fe-common/core/fe-windows.h +++ b/src/fe-common/core/fe-windows.h @@ -11,6 +11,14 @@ enum { DATA_LEVEL_HILIGHT }; +enum { + MAIN_WINDOW_TYPE_NONE = -1, + MAIN_WINDOW_TYPE_DEFAULT = 0, + MAIN_WINDOW_TYPE_HIDDEN = 1, + MAIN_WINDOW_TYPE_SPLIT = 2, + MAIN_WINDOW_TYPE_RSPLIT = 3 +}; + typedef struct { char *servertag; char *name; diff --git a/src/fe-common/core/formats.c b/src/fe-common/core/formats.c index 37db6f7c..4c819c2d 100644 --- a/src/fe-common/core/formats.c +++ b/src/fe-common/core/formats.c @@ -480,27 +480,30 @@ int format_real_length(const char *str, int len) start = str; tmp = g_string_new(NULL); - while (*str != '\0' && len > 0) { + while (*str != '\0') { + oldstr = str; if (*str == '%' && str[1] != '\0') { str++; if (*str != '%') { adv = format_expand_styles(tmp, &str, NULL); - str += adv; - if (adv) - continue; - } - - /* %% or unknown %code, written as-is */ - if (*str != '%') { - if (--len == 0) - break; + if (adv) { + str += adv; + continue; + } + /* discount for unknown % */ + if (--len < 0) { + str = oldstr; + break; + } + oldstr = str; } } - oldstr = str; len -= string_advance(&str, utf8); - if (len < 0) + if (len < 0) { str = oldstr; + break; + } } g_string_free(tmp, TRUE); diff --git a/src/fe-common/core/window-commands.c b/src/fe-common/core/window-commands.c index 57c81ac2..a81c0180 100644 --- a/src/fe-common/core/window-commands.c +++ b/src/fe-common/core/window-commands.c @@ -169,7 +169,7 @@ static void cmd_window(const char *data, void *server, WI_ITEM_REC *item) command_runsub("window", data, server, item); } -/* SYNTAX: WINDOW NEW [HIDDEN|SPLIT] */ +/* SYNTAX: WINDOW NEW [HIDDEN|SPLIT|RSPLIT] */ static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item) { WINDOW_REC *window; @@ -177,8 +177,9 @@ static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item) g_return_if_fail(data != NULL); - type = (g_ascii_strncasecmp(data, "hid", 3) == 0 || g_ascii_strcasecmp(data, "tab") == 0) ? 1 : - (g_ascii_strcasecmp(data, "split") == 0 ? 2 : 0); + type = (g_ascii_strncasecmp(data, "hid", 3) == 0 || g_ascii_strcasecmp(data, "tab") == 0) ? MAIN_WINDOW_TYPE_HIDDEN : + g_ascii_strcasecmp(data, "split") == 0 ? MAIN_WINDOW_TYPE_SPLIT : + g_ascii_strncasecmp(data, "rs", 2) == 0 ? MAIN_WINDOW_TYPE_RSPLIT : MAIN_WINDOW_TYPE_DEFAULT; signal_emit("gui window create override", 1, GINT_TO_POINTER(type)); window = window_create(NULL, FALSE); diff --git a/src/fe-common/core/window-items.c b/src/fe-common/core/window-items.c index bd6ae5e9..8eab7124 100644 --- a/src/fe-common/core/window-items.c +++ b/src/fe-common/core/window-items.c @@ -314,7 +314,7 @@ void window_item_create(WI_ITEM_REC *item, int automatic) /* create new window to use */ if (settings_get_bool("autocreate_split_windows")) { signal_emit("gui window create override", 1, - GINT_TO_POINTER(0)); + GINT_TO_POINTER(MAIN_WINDOW_TYPE_SPLIT)); } window = window_create(item, automatic); } else { 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-windows.c b/src/fe-text/gui-windows.c index 34c55772..3efb9803 100644 --- a/src/fe-text/gui-windows.c +++ b/src/fe-text/gui-windows.c @@ -75,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); @@ -285,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/mainwindows-layout.c b/src/fe-text/mainwindows-layout.c index acbcb6b9..17c6647b 100644 --- a/src/fe-text/mainwindows-layout.c +++ b/src/fe-text/mainwindows-layout.c @@ -55,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) @@ -71,7 +71,7 @@ static void sig_layout_window_restore(WINDOW_REC *window, CONFIG_NODE *node) 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); } } @@ -84,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) @@ -98,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 @@ -118,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; @@ -133,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) { @@ -188,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)); + + new_win = window_create(NULL, TRUE); - window = window_create(NULL, TRUE); - window_set_refnum(window, atoi(node->key)); + 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; @@ -216,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 b8a26192..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 }, diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c index c7d6bcfb..5740a40b 100644 --- a/src/fe-text/statusbar-items.c +++ b/src/fe-text/statusbar-items.c @@ -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 ba8bdcaf..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,23 +575,54 @@ 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) { curs_x = x; diff --git a/src/fe-text/term.h b/src/fe-text/term.h index 4b1e2874..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); diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c index b54f1c8e..99625ecc 100644 --- a/src/fe-text/textbuffer-view.c +++ b/src/fe-text/textbuffer-view.c @@ -394,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; @@ -405,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); @@ -469,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++; } @@ -479,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; @@ -517,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); @@ -534,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 @@ -751,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--; } } @@ -793,51 +801,51 @@ static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines, 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; } } @@ -845,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(); + } } } |