diff --git a/layout-custom.c b/layout-custom.c index 0fc3f5d16..c5a348ac0 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -265,7 +265,7 @@ layout_parse(struct window *w, const char *layout, char **cause) window_resize(w, tiled_lc->sx, tiled_lc->sy, -1, -1); /* Destroy the old layout and swap to the new. */ - layout_free_cell(w->layout_root); + layout_free_cell(w->layout_root, 0); w->layout_root = tiled_lc; /* Assign the panes into the cells. */ @@ -291,7 +291,7 @@ layout_parse(struct window *w, const char *layout, char **cause) return (0); fail: - layout_free_cell(tiled_lc); + layout_free_cell(tiled_lc, 0); return (-1); } @@ -423,6 +423,6 @@ layout_construct(struct layout_cell *lcparent, const char **layout, return (0); fail: - layout_free_cell(*lc); + layout_free_cell(*lc, 0); return (-1); } diff --git a/layout-set.c b/layout-set.c index 157133904..cf78585c2 100644 --- a/layout-set.c +++ b/layout-set.c @@ -124,12 +124,12 @@ layout_set_previous(struct window *w) } static struct window_pane * -layout_first_tiled(struct window *w) +layout_set_first_tiled(struct window *w) { struct window_pane *wp; TAILQ_FOREACH(wp, &w->panes, entry) { - if (!window_pane_is_floating(wp)) + if (wp->layout_cell && layout_cell_is_tiled(wp->layout_cell)) return (wp); } return (NULL); @@ -139,19 +139,15 @@ static void layout_set_even(struct window *w, enum layout_type type) { struct window_pane *wp; - struct layout_cell *lc, *lcnew; + struct layout_cell *lcroot, *lcchild; u_int n, sx, sy; layout_print_cell(w->layout_root, __func__, 1); - /* Get number of panes. */ n = window_count_panes(w, 0); if (n <= 1) return; - /* Free the old root and construct a new. */ - layout_free(w); - lc = w->layout_root = layout_create_cell(NULL); if (type == LAYOUT_LEFTRIGHT) { sx = (n * (PANE_MINIMUM + 1)) - 1; if (sx < w->sx) @@ -163,30 +159,30 @@ layout_set_even(struct window *w, enum layout_type type) sy = w->sy; sx = w->sx; } - layout_set_size(lc, sx, sy, 0, 0); - layout_make_node(lc, type); - /* Build new leaf cells. */ + layout_free(w, 1); + lcroot = w->layout_root = layout_create_cell(NULL); + layout_set_size(lcroot, sx, sy, 0, 0); + layout_make_node(lcroot, type); + TAILQ_FOREACH(wp, &w->panes, entry) { - if (window_pane_is_floating(wp)) - continue; - lcnew = layout_create_cell(lc); - layout_make_leaf(lcnew, wp); - lcnew->sx = w->sx; - lcnew->sy = w->sy; - TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); + lcchild = wp->layout_cell; + TAILQ_INSERT_TAIL(&lcroot->cells, lcchild, entry); + lcchild->parent = lcroot; + if (layout_cell_is_tiled(lcchild)) { + lcchild->sx = w->sx; + lcchild->sy = w->sy; + } } - /* Spread out cells. */ - layout_spread_cell(w, lc); + layout_spread_cell(w, lcroot); - /* Fix cell offsets. */ layout_fix_offsets(w); layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); - window_resize(w, lc->sx, lc->sy, -1, -1); + window_resize(w, lcroot->sx, lcroot->sy, -1, -1); notify_window("window-layout-changed", w); server_redraw_window(w); } @@ -206,15 +202,14 @@ layout_set_even_v(struct window *w) static void layout_set_main_h(struct window *w) { - struct window_pane *wp; - struct layout_cell *lc, *lcmain, *lcother, *lcchild; + struct window_pane *wp, *wpmain; + struct layout_cell *lcroot, *lcmain, *lcother, *lcchild; u_int n, mainh, otherh, sx, sy; char *cause; const char *s; layout_print_cell(w->layout_root, __func__, 1); - /* Get number of panes. */ n = window_count_panes(w, 0); if (n <= 1) return; @@ -255,52 +250,48 @@ layout_set_main_h(struct window *w) if (sx < w->sx) sx = w->sx; - /* Free old tree and create a new root. */ - layout_free(w); - lc = w->layout_root = layout_create_cell(NULL); - layout_set_size(lc, sx, mainh + otherh + 1, 0, 0); - layout_make_node(lc, LAYOUT_TOPBOTTOM); + layout_free(w, 1); + lcroot = w->layout_root = layout_create_cell(NULL); + layout_set_size(lcroot, sx, mainh + otherh + 1, 0, 0); + layout_make_node(lcroot, LAYOUT_TOPBOTTOM); - /* Create the main pane. */ - lcmain = layout_create_cell(lc); + wpmain = layout_set_first_tiled(w); + lcmain = wpmain->layout_cell; + lcmain->parent = lcroot; layout_set_size(lcmain, sx, mainh, 0, 0); - layout_make_leaf(lcmain, layout_first_tiled(w)); - TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); + TAILQ_INSERT_TAIL(&lcroot->cells, lcmain, entry); - /* Create the other pane. */ - lcother = layout_create_cell(lc); - layout_set_size(lcother, sx, otherh, 0, 0); if (n == 1) { - wp = TAILQ_NEXT(layout_first_tiled(w), entry); - while (wp != NULL && window_pane_is_floating(wp)) + wp = TAILQ_NEXT(wpmain, entry); + while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell)) wp = TAILQ_NEXT(wp, entry); - layout_make_leaf(lcother, wp); - TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); + TAILQ_INSERT_TAIL(&lcroot->cells, wp->layout_cell, entry); + wp->layout_cell->parent = lcroot; } else { + lcother = layout_create_cell(lcroot); + layout_set_size(lcother, sx, otherh, 0, 0); layout_make_node(lcother, LAYOUT_LEFTRIGHT); - TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); + TAILQ_INSERT_TAIL(&lcroot->cells, lcother, entry); - /* Add the remaining panes as children. */ TAILQ_FOREACH(wp, &w->panes, entry) { - if (window_pane_is_floating(wp)) + if (wp == wpmain) continue; - if (wp == layout_first_tiled(w)) - continue; - lcchild = layout_create_cell(lcother); - layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0); - layout_make_leaf(lcchild, wp); + lcchild = wp->layout_cell; TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); + lcchild->parent = lcother; + if (layout_cell_is_tiled(lcchild)) + layout_set_size(lcchild, PANE_MINIMUM, otherh, + 0, 0); } layout_spread_cell(w, lcother); } - /* Fix cell offsets. */ layout_fix_offsets(w); layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); - window_resize(w, lc->sx, lc->sy, -1, -1); + window_resize(w, lcroot->sx, lcroot->sy, -1, -1); notify_window("window-layout-changed", w); server_redraw_window(w); } @@ -308,15 +299,14 @@ layout_set_main_h(struct window *w) static void layout_set_main_h_mirrored(struct window *w) { - struct window_pane *wp; - struct layout_cell *lc, *lcmain, *lcother, *lcchild; + struct window_pane *wp, *wpmain; + struct layout_cell *lcroot, *lcmain, *lcother, *lcchild; u_int n, mainh, otherh, sx, sy; char *cause; const char *s; layout_print_cell(w->layout_root, __func__, 1); - /* Get number of panes. */ n = window_count_panes(w, 0); if (n <= 1) return; @@ -357,52 +347,48 @@ layout_set_main_h_mirrored(struct window *w) if (sx < w->sx) sx = w->sx; - /* Free old tree and create a new root. */ - layout_free(w); - lc = w->layout_root = layout_create_cell(NULL); - layout_set_size(lc, sx, mainh + otherh + 1, 0, 0); - layout_make_node(lc, LAYOUT_TOPBOTTOM); + layout_free(w, 1); + lcroot = w->layout_root = layout_create_cell(NULL); + layout_set_size(lcroot, sx, mainh + otherh + 1, 0, 0); + layout_make_node(lcroot, LAYOUT_TOPBOTTOM); + + wpmain = layout_set_first_tiled(w); + lcmain = wpmain->layout_cell; + lcmain->parent = lcroot; + layout_set_size(lcmain, sx, mainh, 0, 0); + TAILQ_INSERT_TAIL(&lcroot->cells, lcmain, entry); - /* Create the other pane. */ - lcother = layout_create_cell(lc); - layout_set_size(lcother, sx, otherh, 0, 0); if (n == 1) { - wp = TAILQ_NEXT(layout_first_tiled(w), entry); - while (wp != NULL && window_pane_is_floating(wp)) + wp = TAILQ_NEXT(wpmain, entry); + while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell)) wp = TAILQ_NEXT(wp, entry); - layout_make_leaf(lcother, wp); - TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); + TAILQ_INSERT_HEAD(&lcroot->cells, wp->layout_cell, entry); + wp->layout_cell->parent = lcroot; } else { + lcother = layout_create_cell(lcroot); + layout_set_size(lcother, sx, otherh, 0, 0); layout_make_node(lcother, LAYOUT_LEFTRIGHT); - TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); + TAILQ_INSERT_HEAD(&lcroot->cells, lcother, entry); - /* Add the remaining panes as children. */ TAILQ_FOREACH(wp, &w->panes, entry) { - if (window_pane_is_floating(wp)) + if (wp == wpmain) continue; - if (wp == layout_first_tiled(w)) - continue; - lcchild = layout_create_cell(lcother); - layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0); - layout_make_leaf(lcchild, wp); + lcchild = wp->layout_cell; TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); + lcchild->parent = lcother; + if (layout_cell_is_tiled(lcchild)) + layout_set_size(lcchild, PANE_MINIMUM, otherh, + 0, 0); } layout_spread_cell(w, lcother); } - /* Create the main pane. */ - lcmain = layout_create_cell(lc); - layout_set_size(lcmain, sx, mainh, 0, 0); - layout_make_leaf(lcmain, layout_first_tiled(w)); - TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); - - /* Fix cell offsets. */ layout_fix_offsets(w); layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); - window_resize(w, lc->sx, lc->sy, -1, -1); + window_resize(w, lcroot->sx, lcroot->sy, -1, -1); notify_window("window-layout-changed", w); server_redraw_window(w); } @@ -410,21 +396,20 @@ layout_set_main_h_mirrored(struct window *w) static void layout_set_main_v(struct window *w) { - struct window_pane *wp; - struct layout_cell *lc, *lcmain, *lcother, *lcchild; + struct window_pane *wp, *wpmain; + struct layout_cell *lcroot, *lcmain, *lcother, *lcchild; u_int n, mainw, otherw, sx, sy; char *cause; const char *s; layout_print_cell(w->layout_root, __func__, 1); - /* Get number of panes. */ n = window_count_panes(w, 0); if (n <= 1) return; n--; /* take off main pane */ - /* Find available width - take off one line for the border. */ + /* Find available width - take off one column for the border. */ sx = w->sx - 1; /* Get the main pane width. */ @@ -459,52 +444,48 @@ layout_set_main_v(struct window *w) if (sy < w->sy) sy = w->sy; - /* Free old tree and create a new root. */ - layout_free(w); - lc = w->layout_root = layout_create_cell(NULL); - layout_set_size(lc, mainw + otherw + 1, sy, 0, 0); - layout_make_node(lc, LAYOUT_LEFTRIGHT); + layout_free(w, 1); + lcroot = w->layout_root = layout_create_cell(NULL); + layout_set_size(lcroot, mainw + otherw + 1, sy, 0, 0); + layout_make_node(lcroot, LAYOUT_LEFTRIGHT); - /* Create the main pane. */ - lcmain = layout_create_cell(lc); + wpmain = layout_set_first_tiled(w); + lcmain = wpmain->layout_cell; + lcmain->parent = lcroot; layout_set_size(lcmain, mainw, sy, 0, 0); - layout_make_leaf(lcmain, layout_first_tiled(w)); - TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); + TAILQ_INSERT_TAIL(&lcroot->cells, lcmain, entry); - /* Create the other pane. */ - lcother = layout_create_cell(lc); - layout_set_size(lcother, otherw, sy, 0, 0); if (n == 1) { - wp = TAILQ_NEXT(layout_first_tiled(w), entry); - while (wp != NULL && window_pane_is_floating(wp)) + wp = TAILQ_NEXT(wpmain, entry); + while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell)) wp = TAILQ_NEXT(wp, entry); - layout_make_leaf(lcother, wp); - TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); + TAILQ_INSERT_TAIL(&lcroot->cells, wp->layout_cell, entry); + wp->layout_cell->parent = lcroot; } else { + lcother = layout_create_cell(lcroot); layout_make_node(lcother, LAYOUT_TOPBOTTOM); - TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); + layout_set_size(lcother, otherw, sy, 0, 0); + TAILQ_INSERT_TAIL(&lcroot->cells, lcother, entry); - /* Add the remaining panes as children. */ TAILQ_FOREACH(wp, &w->panes, entry) { - if (window_pane_is_floating(wp)) + if (wp == wpmain) continue; - if (wp == layout_first_tiled(w)) - continue; - lcchild = layout_create_cell(lcother); - layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0); - layout_make_leaf(lcchild, wp); + lcchild = wp->layout_cell; TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); + lcchild->parent = lcother; + if (layout_cell_is_tiled(lcchild)) + layout_set_size(lcchild, otherw, PANE_MINIMUM, + 0, 0); } layout_spread_cell(w, lcother); } - /* Fix cell offsets. */ layout_fix_offsets(w); layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); - window_resize(w, lc->sx, lc->sy, -1, -1); + window_resize(w, lcroot->sx, lcroot->sy, -1, -1); notify_window("window-layout-changed", w); server_redraw_window(w); } @@ -512,8 +493,8 @@ layout_set_main_v(struct window *w) static void layout_set_main_v_mirrored(struct window *w) { - struct window_pane *wp; - struct layout_cell *lc, *lcmain, *lcother, *lcchild; + struct window_pane *wp, *wpmain; + struct layout_cell *lcroot, *lcmain, *lcother, *lcchild; u_int n, mainw, otherw, sx, sy; char *cause; const char *s; @@ -526,7 +507,7 @@ layout_set_main_v_mirrored(struct window *w) return; n--; /* take off main pane */ - /* Find available width - take off one line for the border. */ + /* Find available width - take off one column for the border. */ sx = w->sx - 1; /* Get the main pane width. */ @@ -561,62 +542,58 @@ layout_set_main_v_mirrored(struct window *w) if (sy < w->sy) sy = w->sy; - /* Free old tree and create a new root. */ - layout_free(w); - lc = w->layout_root = layout_create_cell(NULL); - layout_set_size(lc, mainw + otherw + 1, sy, 0, 0); - layout_make_node(lc, LAYOUT_LEFTRIGHT); + layout_free(w, 1); + lcroot = w->layout_root = layout_create_cell(NULL); + layout_set_size(lcroot, mainw + otherw + 1, sy, 0, 0); + layout_make_node(lcroot, LAYOUT_LEFTRIGHT); + + wpmain = layout_set_first_tiled(w); + lcmain = wpmain->layout_cell; + lcmain->parent = lcroot; + layout_set_size(lcmain, mainw, sy, 0, 0); + TAILQ_INSERT_TAIL(&lcroot->cells, lcmain, entry); - /* Create the other pane. */ - lcother = layout_create_cell(lc); - layout_set_size(lcother, otherw, sy, 0, 0); if (n == 1) { - wp = TAILQ_NEXT(layout_first_tiled(w), entry); - while (wp != NULL && window_pane_is_floating(wp)) + wp = TAILQ_NEXT(wpmain, entry); + while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell)) wp = TAILQ_NEXT(wp, entry); - layout_make_leaf(lcother, wp); - TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); + TAILQ_INSERT_HEAD(&lcroot->cells, wp->layout_cell, entry); + wp->layout_cell->parent = lcroot; } else { + lcother = layout_create_cell(lcroot); layout_make_node(lcother, LAYOUT_TOPBOTTOM); - TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); + layout_set_size(lcother, otherw, sy, 0, 0); + TAILQ_INSERT_HEAD(&lcroot->cells, lcother, entry); - /* Add the remaining panes as children. */ TAILQ_FOREACH(wp, &w->panes, entry) { - if (window_pane_is_floating(wp)) + if (wp == wpmain) continue; - if (wp == layout_first_tiled(w)) - continue; - lcchild = layout_create_cell(lcother); - layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0); - layout_make_leaf(lcchild, wp); + lcchild = wp->layout_cell; TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); + lcchild->parent = lcother; + if (layout_cell_is_tiled(lcchild)) + layout_set_size(lcchild, otherw, PANE_MINIMUM, + 0, 0); } layout_spread_cell(w, lcother); } - /* Create the main pane. */ - lcmain = layout_create_cell(lc); - layout_set_size(lcmain, mainw, sy, 0, 0); - layout_make_leaf(lcmain, layout_first_tiled(w)); - TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); - - /* Fix cell offsets. */ layout_fix_offsets(w); layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); - window_resize(w, lc->sx, lc->sy, -1, -1); + window_resize(w, lcroot->sx, lcroot->sy, -1, -1); notify_window("window-layout-changed", w); server_redraw_window(w); } -void +static void layout_set_tiled(struct window *w) { struct options *oo = w->options; struct window_pane *wp; - struct layout_cell *lc, *lcrow, *lcchild; + struct layout_cell *lcroot, *lcrow, *lcchild; u_int n, width, height, used, sx, sy; u_int i, j, columns, rows, max_columns; @@ -647,56 +624,59 @@ layout_set_tiled(struct window *w) if (height < PANE_MINIMUM) height = PANE_MINIMUM; - /* Free old tree and create a new root. */ - layout_free(w); - lc = w->layout_root = layout_create_cell(NULL); sx = ((width + 1) * columns) - 1; if (sx < w->sx) sx = w->sx; sy = ((height + 1) * rows) - 1; if (sy < w->sy) sy = w->sy; - layout_set_size(lc, sx, sy, 0, 0); - layout_make_node(lc, LAYOUT_TOPBOTTOM); - /* Create a grid of the cells, skipping any floating panes. */ + layout_free(w, 1); + lcroot = w->layout_root = layout_create_cell(NULL); + layout_set_size(lcroot, sx, sy, 0, 0); + layout_make_node(lcroot, LAYOUT_TOPBOTTOM); + + /* Create a grid of the tiled cells. */ wp = TAILQ_FIRST(&w->panes); - while (wp != NULL && window_pane_is_floating(wp)) - wp = TAILQ_NEXT(wp, entry); for (j = 0; j < rows; j++) { + while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell)) + wp = TAILQ_NEXT(wp, entry); /* If this is the last cell, all done. */ if (wp == NULL) break; - /* Create the new row. */ - lcrow = layout_create_cell(lc); - layout_set_size(lcrow, w->sx, height, 0, 0); - TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); + lcchild = wp->layout_cell; /* If only one column, just use the row directly. */ if (n - (j * columns) == 1 || columns == 1) { - layout_make_leaf(lcrow, wp); + lcchild->parent = lcroot; + TAILQ_INSERT_TAIL(&lcroot->cells, lcchild, entry); + layout_set_size(lcchild, w->sx, height, 0, 0); wp = TAILQ_NEXT(wp, entry); - while (wp != NULL && window_pane_is_floating(wp)) - wp = TAILQ_NEXT(wp, entry); continue; } - /* Add in the columns. */ + /* Create the new row. */ + lcrow = layout_create_cell(lcroot); layout_make_node(lcrow, LAYOUT_LEFTRIGHT); + layout_set_size(lcrow, w->sx, height, 0, 0); + TAILQ_INSERT_TAIL(&lcroot->cells, lcrow, entry); + + /* Add in the columns. */ for (i = 0; i < columns; i++) { /* Create and add a pane cell. */ - lcchild = layout_create_cell(lcrow); - layout_set_size(lcchild, width, height, 0, 0); - layout_make_leaf(lcchild, wp); + lcchild->parent = lcrow; TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); + layout_set_size(lcchild, width, height, 0, 0); /* Move to the next non-floating cell. */ wp = TAILQ_NEXT(wp, entry); - while (wp != NULL && window_pane_is_floating(wp)) + while (wp != NULL && + !layout_cell_is_tiled(wp->layout_cell)) wp = TAILQ_NEXT(wp, entry); if (wp == NULL) break; + lcchild = wp->layout_cell; } /* @@ -713,21 +693,19 @@ layout_set_tiled(struct window *w) w->sx - used); } - /* Adjust the last row height to fit if necessary. */ used = (rows * height) + rows - 1; if (w->sy > used) { - lcrow = TAILQ_LAST(&lc->cells, layout_cells); + lcrow = TAILQ_LAST(&lcroot->cells, layout_cells); layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM, w->sy - used); } - /* Fix cell offsets. */ layout_fix_offsets(w); layout_fix_panes(w, NULL); layout_print_cell(w->layout_root, __func__, 1); - window_resize(w, lc->sx, lc->sy, -1, -1); + window_resize(w, lcroot->sx, lcroot->sy, -1, -1); notify_window("window-layout-changed", w); server_redraw_window(w); } diff --git a/layout.c b/layout.c index c38197b44..2a605d6cc 100644 --- a/layout.c +++ b/layout.c @@ -88,20 +88,24 @@ layout_create_cell(struct layout_cell *lcparent) /* Free a layout cell. */ void -layout_free_cell(struct layout_cell *lc) +layout_free_cell(struct layout_cell *lc, int only_nodes) { - struct layout_cell *lcchild; + struct layout_cell *lcchild, *lcnext; - if (lc == NULL) + if (lc == NULL || (only_nodes && lc->type == LAYOUT_WINDOWPANE)) return; switch (lc->type) { case LAYOUT_LEFTRIGHT: case LAYOUT_TOPBOTTOM: - while (!TAILQ_EMPTY(&lc->cells)) { - lcchild = TAILQ_FIRST(&lc->cells); - TAILQ_REMOVE(&lc->cells, lcchild, entry); - layout_free_cell(lcchild); + lcchild = TAILQ_FIRST(&lc->cells); + while (lcchild != NULL) { + lcnext = TAILQ_NEXT(lcchild, entry); + if (!only_nodes || lcchild->type != LAYOUT_WINDOWPANE) { + TAILQ_REMOVE(&lc->cells, lcchild, entry); + layout_free_cell(lcchild, only_nodes); + } + lcchild = lcnext; } break; case LAYOUT_WINDOWPANE: @@ -255,7 +259,7 @@ layout_fix_zindexes(struct window *w, struct layout_cell *lc) } } -static int +int layout_cell_is_tiled(struct layout_cell *lc) { int is_leaf = lc->type == LAYOUT_WINDOWPANE; @@ -699,13 +703,13 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc, if (lcparent == NULL) { if (lc->wp != NULL) *lcroot = NULL; - layout_free_cell(lc); + layout_free_cell(lc, 0); return; } if (!layout_cell_is_tiled(lc)) { TAILQ_REMOVE(&lcparent->cells, lc, entry); - layout_free_cell(lc); + layout_free_cell(lc, 0); goto out; } @@ -721,7 +725,7 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc, /* Remove this from the parent's list. */ TAILQ_REMOVE(&lcparent->cells, lc, entry); - layout_free_cell(lc); + layout_free_cell(lc, 0); out: /* @@ -742,7 +746,7 @@ out: } else TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry); - layout_free_cell(lcparent); + layout_free_cell(lcparent, 0); } } @@ -760,9 +764,9 @@ layout_init(struct window *w, struct window_pane *wp) /* Free layout for pane. */ void -layout_free(struct window *w) +layout_free(struct window *w, int only_nodes) { - layout_free_cell(w->layout_root); + layout_free_cell(w->layout_root, only_nodes); } /* Resize the entire layout after window resize. */ @@ -1507,7 +1511,8 @@ layout_spread_cell(struct window *w, struct layout_cell *parent) number = 0; TAILQ_FOREACH (lc, &parent->cells, entry) - number++; + if (layout_cell_is_tiled(lc)) + number++; if (number <= 1) return (0); status = window_get_pane_status(w); @@ -1535,6 +1540,8 @@ layout_spread_cell(struct window *w, struct layout_cell *parent) changed = 0; TAILQ_FOREACH (lc, &parent->cells, entry) { + if (!layout_cell_is_tiled(lc)) + continue; change = 0; if (parent->type == LAYOUT_LEFTRIGHT) { change = each - (int)lc->sx; diff --git a/screen-redraw.c b/screen-redraw.c index 1cd314bb7..21499d426 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1655,12 +1655,14 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags) if (wp != NULL) { if (wp->base.mode & MODE_SYNC) screen_write_stop_sync(wp); + screen_write_clear_dirty(wp); } else { TAILQ_FOREACH(loop, &scene->w->panes, entry) { if (!window_pane_is_visible(loop)) continue; if (loop->base.mode & MODE_SYNC) screen_write_stop_sync(loop); + screen_write_clear_dirty(loop); } } } diff --git a/screen-write.c b/screen-write.c index e4cd09caf..901db2d5b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -38,6 +38,7 @@ static int screen_write_overwrite(struct screen_write_ctx *, struct grid_cell *, u_int); static int screen_write_combine(struct screen_write_ctx *, const struct grid_cell *); +static void screen_write_flush_dirty(struct window_pane *); struct screen_write_citem { u_int x; @@ -214,20 +215,48 @@ screen_write_pane_is_obscured(struct screen_write_ctx *ctx) return (0); } -/* Should we draw to TTY for this screen? */ +/* Should we draw to the TTY? */ static int -screen_write_should_draw(struct screen_write_ctx *ctx) +screen_write_should_draw_lines(struct screen_write_ctx *ctx, u_int y, u_int ny) { struct window_pane *wp = ctx->wp; struct screen *s = ctx->s; + u_int sy = screen_size_y(s); + bitstr_t *bs; - if (s->mode & MODE_SYNC) - return (0); if (wp != NULL && (wp->flags & (PANE_REDRAW|PANE_DROP))) return (0); + if (s->mode & MODE_SYNC) { + if (wp != NULL && y < sy && ny != 0) { + bs = wp->sync_dirty; + if (ny > sy - y) + ny = sy - y; + if (bs == NULL || wp->sync_dirty_size != sy) { + if (bs != NULL && wp->sync_dirty_size != sy) { + y = 0; + ny = sy; + } + free(bs); + + bs = wp->sync_dirty = bit_alloc(sy); + if (bs == NULL) + fatal("bit_alloc failed"); + wp->sync_dirty_size = sy; + } + bit_nset(bs, y, y + ny - 1); + } + return (0); + } return (1); } +/* Should we draw this line to the TTY? */ +static int +screen_write_should_draw_line(struct screen_write_ctx *ctx, u_int y) +{ + return (screen_write_should_draw_lines(ctx, y, 1)); +} + /* Set up context for TTY command. */ static void screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, @@ -993,7 +1022,7 @@ screen_write_sync_callback(__unused int fd, __unused short events, void *arg) if (wp->base.mode & MODE_SYNC) { wp->base.mode &= ~MODE_SYNC; - wp->flags |= PANE_REDRAW; + screen_write_flush_dirty(wp); } } @@ -1025,7 +1054,7 @@ screen_write_stop_sync(struct window_pane *wp) evtimer_del(&wp->sync_timer); wp->base.mode &= ~MODE_SYNC; - wp->flags |= PANE_REDRAW; + screen_write_flush_dirty(wp); log_debug("%s: %%%u stopped sync mode", __func__, wp->id); } @@ -1180,9 +1209,6 @@ screen_write_redraw_line(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, struct visible_ranges *r; struct visible_range *ri; - if (!screen_write_should_draw(ctx)) - return; - r = window_visible_ranges(wp, xoff, yoff + yy, sx, NULL); for (i = 0; i < r->used; i++) { ri = &r->ranges[i]; @@ -1221,6 +1247,44 @@ screen_write_redraw_line(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, } } +/* Redraw dirty lines. */ +static void +screen_write_flush_dirty(struct window_pane *wp) +{ + struct screen_write_ctx ctx; + struct tty_ctx ttyctx; + struct screen *s = &wp->base; + u_int y, sy = screen_size_y(s), lines = 0; + + if (wp->sync_dirty == NULL) + return; + + screen_write_start_pane(&ctx, wp, s); + screen_write_initctx(&ctx, &ttyctx, 1, 1); + + for (y = 0; y < sy; y++) { + if (bit_test(wp->sync_dirty, y)) { + screen_write_redraw_line(&ctx, &ttyctx, y); + lines++; + } + } + log_debug("%s: %%%u had %u dirty lines", __func__, wp->id, lines); + + screen_write_stop(&ctx); + screen_write_clear_dirty(wp); +} + +/* Clear any dirty lines. */ +void +screen_write_clear_dirty(struct window_pane *wp) +{ + if (wp != NULL && wp->sync_dirty != NULL) { + free(wp->sync_dirty); + wp->sync_dirty = NULL; + wp->sync_dirty_size = 0; + } +} + /* Redraw all visible cells in a pane. */ static void screen_write_redraw_pane(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx) @@ -1263,7 +1327,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) screen_write_initctx(ctx, &ttyctx, 1, 1); - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_lines(ctx, 0, screen_size_y(s))) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { tty_write(tty_cmd_alignmenttest, &ttyctx); @@ -1304,7 +1368,7 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) screen_write_collect_flush(ctx, 0, __func__); ttyctx.n = nx; - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_line(ctx, s->cy)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { tty_write(tty_cmd_insertcharacter, &ttyctx); @@ -1345,7 +1409,7 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) screen_write_collect_flush(ctx, 0, __func__); ttyctx.n = nx; - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_line(ctx, s->cy)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { tty_write(tty_cmd_deletecharacter, &ttyctx); @@ -1386,7 +1450,7 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) screen_write_collect_flush(ctx, 0, __func__); ttyctx.n = nx; - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_line(ctx, s->cy)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { tty_write(tty_cmd_clearcharacter, &ttyctx); @@ -1427,7 +1491,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg) screen_write_collect_flush(ctx, 0, __func__); ttyctx.n = ny; - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_lines(ctx, s->cy, sy - s->cy)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { tty_write(tty_cmd_insertline, &ttyctx); @@ -1454,7 +1518,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg) screen_write_collect_flush(ctx, 0, __func__); ttyctx.n = ny; - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_lines(ctx, s->cy, s->rlower + 1 - s->cy)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { tty_write(tty_cmd_insertline, &ttyctx); @@ -1471,7 +1535,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; - u_int sy = screen_size_y(s); + u_int sy = screen_size_y(s), ry; if (ny == 0) ny = 1; @@ -1495,7 +1559,8 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) screen_write_collect_flush(ctx, 0, __func__); ttyctx.n = ny; - if (!screen_write_should_draw(ctx)) + ry = s->rlower + 1 - s->rupper; + if (!screen_write_should_draw_lines(ctx, s->rupper, ry)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { tty_write(tty_cmd_deleteline, &ttyctx); @@ -1506,8 +1571,9 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) return; } - if (ny > s->rlower + 1 - s->cy) - ny = s->rlower + 1 - s->cy; + ry = s->rlower + 1 - s->cy; + if (ny > ry) + ny = ry; if (ny == 0) return; @@ -1522,7 +1588,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) screen_write_collect_flush(ctx, 0, __func__); ttyctx.n = ny; - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_lines(ctx, s->cy, ry)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { tty_write(tty_cmd_deleteline, &ttyctx); @@ -1656,7 +1722,9 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg) { struct screen *s = ctx->s; struct tty_ctx ttyctx; + u_int ry; +<<<<<<< HEAD if (s->cy == s->rupper) { #ifdef ENABLE_SIXEL if (image_free_all(s) && ctx->wp != NULL) @@ -1665,20 +1733,29 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg) grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); screen_write_collect_flush(ctx, 0, __func__); +======= + if (s->cy != s->rupper) { + if (s->cy > 0) + screen_write_set_cursor(ctx, -1, s->cy - 1); + return; + } +>>>>>>> obsd-master - screen_write_initctx(ctx, &ttyctx, 1, 1); - ttyctx.bg = bg; + grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); + screen_write_collect_flush(ctx, 0, __func__); - if (!screen_write_should_draw(ctx)) - return; - if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { - tty_write(tty_cmd_reverseindex, &ttyctx); - return; - } + screen_write_initctx(ctx, &ttyctx, 1, 1); + ttyctx.bg = bg; - screen_write_redraw_pane(ctx, &ttyctx); - } else if (s->cy > 0) - screen_write_set_cursor(ctx, -1, s->cy - 1); + ry = s->rlower + 1 - s->rupper; + if (!screen_write_should_draw_lines(ctx, s->rupper, ry)) + return; + if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { + tty_write(tty_cmd_reverseindex, &ttyctx); + return; + } + + screen_write_redraw_pane(ctx, &ttyctx); } /* Set scroll region. */ @@ -1728,6 +1805,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg) ctx->bg = bg; } +<<<<<<< HEAD if (s->cy == s->rlower) { #ifdef ENABLE_SIXEL if (rlower == screen_size_y(s) - 1) @@ -1742,6 +1820,17 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg) ctx->scrolled++; } else if (s->cy < screen_size_y(s) - 1) screen_write_set_cursor(ctx, -1, s->cy + 1); +======= + if (s->cy != s->rlower) { + if (s->cy < screen_size_y(s) - 1) + screen_write_set_cursor(ctx, -1, s->cy + 1); + return; + } + + grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); + screen_write_collect_scroll(ctx, bg); + ctx->scrolled++; +>>>>>>> obsd-master } /* Scroll up. */ @@ -1781,7 +1870,7 @@ screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg) struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; - u_int i; + u_int i, ry; screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.bg = bg; @@ -1802,7 +1891,8 @@ screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg) screen_write_collect_flush(ctx, 0, __func__); ttyctx.n = lines; - if (!screen_write_should_draw(ctx)) + ry = s->rlower + 1 - s->rupper; + if (!screen_write_should_draw_lines(ctx, s->rupper, ry)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED || ctx->wp == NULL) { tty_write(tty_cmd_scrolldown, &ttyctx); @@ -1855,7 +1945,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) screen_write_collect_clear(ctx, s->cy + 1, sy - (s->cy + 1)); screen_write_collect_flush(ctx, 0, __func__); - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_lines(ctx, s->cy, sy - s->cy)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED) { tty_write(tty_cmd_clearendofscreen, &ttyctx); @@ -1930,7 +2020,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg) screen_write_collect_clear(ctx, 0, s->cy); screen_write_collect_flush(ctx, 0, __func__); - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_lines(ctx, 0, s->cy + 1)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED) { tty_write(tty_cmd_clearstartofscreen, &ttyctx); @@ -2003,7 +2093,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg) screen_write_collect_clear(ctx, 0, sy); - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_lines(ctx, s->cy, sy - s->cy)) return; if (~ttyctx.flags & TTY_CTX_PANE_OBSCURED) { tty_write(tty_cmd_clearscreen, &ttyctx); @@ -2317,12 +2407,21 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, const char *from) { struct screen *s = ctx->s; + struct window_pane *wp = ctx->wp; u_int y, cx, cy, items = 0; struct screen_write_citem *ci, *tmp; struct screen_write_cline *cl; - if (!screen_write_should_draw(ctx)) + if (wp != NULL && (wp->flags & (PANE_REDRAW|PANE_DROP))) goto discard; + if (s->mode & MODE_SYNC) { + for (y = 0; y < screen_size_y(s); y++) { + cl = &s->write_list[y]; + if (!TAILQ_EMPTY(&cl->items)) + screen_write_should_draw_line(ctx, y); + } + goto discard; + } if (ctx->scrolled != 0) { if (!screen_write_collect_flush_scrolled(ctx)) @@ -2660,12 +2759,12 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) if (s->mode & MODE_INSERT) { screen_write_collect_flush(ctx, 0, __func__); ttyctx.n = width; - if (screen_write_should_draw(ctx)) + if (screen_write_should_draw_line(ctx, s->cy)) tty_write(tty_cmd_insertcharacter, &ttyctx); } /* If not writing, done now. */ - if (skip || !screen_write_should_draw(ctx)) + if (skip || !screen_write_should_draw_line(ctx, s->cy)) return; /* Do a full line redraw if needed. */ @@ -2685,7 +2784,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) for (i = 0, vis = 0; i < r->used; i++) vis += r->ranges[i].nx; if (vis >= width) { - if (screen_write_should_draw(ctx)) + if (screen_write_should_draw_line(ctx, s->cy)) tty_write(tty_cmd_cell, &ttyctx); return; } @@ -2695,7 +2794,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) * spaces in the visible regions. */ utf8_set(&tmp_gc.data, ' '); - if (!screen_write_should_draw(ctx)) + if (!screen_write_should_draw_line(ctx, s->cy)) return; for (i = 0; i < r->used; i++) { ri = &r->ranges[i]; @@ -2838,7 +2937,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) ttyctx.cell = &last; if (force_wide) ttyctx.flags |= TTY_CTX_CELL_INVALIDATE; - if (screen_write_should_draw(ctx)) + if (screen_write_should_draw_line(ctx, cy)) tty_write(tty_cmd_cell, &ttyctx); screen_write_set_cursor(ctx, cx, cy); diff --git a/spawn.c b/spawn.c index 59e107292..91010d775 100644 --- a/spawn.c +++ b/spawn.c @@ -104,7 +104,7 @@ spawn_window(struct spawn_context *sc, char **cause) sc->wp0 = TAILQ_FIRST(&w->panes); TAILQ_REMOVE(&w->panes, sc->wp0, entry); - layout_free(w); + layout_free(w, 0); window_destroy_panes(w); TAILQ_INSERT_HEAD(&w->panes, sc->wp0, entry); diff --git a/tmux.h b/tmux.h index da4d80dfc..661eee027 100644 --- a/tmux.h +++ b/tmux.h @@ -1294,6 +1294,9 @@ struct window_pane { #define PANE_UNSEENCHANGES 0x4000 #define PANE_REDRAWSCROLLBAR 0x8000 + bitstr_t *sync_dirty; + u_int sync_dirty_size; + u_int sb_slider_y; u_int sb_slider_h; int sb_auto_visible; @@ -3442,6 +3445,7 @@ void screen_write_mode_set(struct screen_write_ctx *, int); void screen_write_mode_clear(struct screen_write_ctx *, int); void screen_write_start_sync(struct window_pane *); void screen_write_stop_sync(struct window_pane *); +void screen_write_clear_dirty(struct window_pane *); void screen_write_cursorup(struct screen_write_ctx *, u_int); void screen_write_cursordown(struct screen_write_ctx *, u_int); void screen_write_cursorright(struct screen_write_ctx *, u_int); @@ -3676,7 +3680,7 @@ struct visible_ranges *window_visible_ranges(struct window_pane *, int, int, /* layout.c */ u_int layout_count_cells(struct layout_cell *); struct layout_cell *layout_create_cell(struct layout_cell *); -void layout_free_cell(struct layout_cell *); +void layout_free_cell(struct layout_cell *, int); void layout_print_cell(struct layout_cell *, const char *, u_int); void layout_destroy_cell(struct window *, struct layout_cell *, struct layout_cell **); @@ -3687,6 +3691,7 @@ void layout_set_size(struct layout_cell *, u_int, u_int, int, int); void layout_make_leaf(struct layout_cell *, struct window_pane *); void layout_make_node(struct layout_cell *, enum layout_type); void layout_fix_zindexes(struct window *, struct layout_cell *); +int layout_cell_is_tiled(struct layout_cell *); void layout_fix_offsets(struct window *); void layout_fix_panes(struct window *, struct window_pane *); void layout_resize_adjust(struct window *, struct layout_cell *, @@ -3695,7 +3700,7 @@ void layout_resize_set_size(struct window *, struct layout_cell *, enum layout_type, u_int); struct layout_cell *layout_cell_get_neighbour(struct layout_cell *); void layout_init(struct window *, struct window_pane *); -void layout_free(struct window *); +void layout_free(struct window *, int); void layout_resize(struct window *, u_int, u_int); void layout_resize_pane(struct window_pane *, enum layout_type, int, int); diff --git a/window.c b/window.c index 341aefd4e..1fb012389 100644 --- a/window.c +++ b/window.c @@ -357,8 +357,8 @@ window_destroy(struct window *w) window_unzoom(w, 0); RB_REMOVE(windows, &windows, w); - layout_free_cell(w->layout_root); - layout_free_cell(w->saved_layout_root); + layout_free_cell(w->layout_root, 0); + layout_free_cell(w->saved_layout_root, 0); free(w->old_layout); window_destroy_panes(w); @@ -785,7 +785,7 @@ window_unzoom(struct window *w, int notify) return (-1); w->flags &= ~WINDOW_ZOOMED; - layout_free(w); + layout_free(w, 0); w->layout_root = w->saved_layout_root; w->saved_layout_root = NULL; @@ -1210,6 +1210,7 @@ window_pane_destroy(struct window_pane *wp) window_pane_clear_prompt(wp); window_pane_free_modes(wp); + screen_write_clear_dirty(wp); free(wp->searchstr); if (wp->fd != -1) {