From a8520ba59e32133414c710b26ec23bf3c19f8b23 Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 17 May 2026 16:01:42 +0000 Subject: [PATCH] Bring over some of layout and positioning code for floating panes, by Michael Grant. --- cmd-break-pane.c | 2 +- cmd-join-pane.c | 2 +- cmd-select-pane.c | 2 +- format.c | 10 +-- layout-custom.c | 176 +++++++++++++++++++++++++++++++++------------- layout-set.c | 12 ++-- layout.c | 95 +++++++++++++++++++------ log.c | 2 + server-fn.c | 2 +- tmux.h | 22 +++--- window-tree.c | 4 +- window.c | 86 +++++++++++----------- 12 files changed, 282 insertions(+), 133 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index add3743b..790b8df2 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -73,7 +73,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) } server_unzoom_window(w); - if (window_count_panes(w) == 1) { + if (window_count_panes(w, 1) == 1) { if (server_link_window(src_s, wl, dst_s, idx, 0, !args_has(args, 'd'), &cause) != 0) { cmdq_error(item, "%s", cause); diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 6eb0ea65..f8975a67 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -171,7 +171,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) } else server_status_session(dst_s); - if (window_count_panes(src_w) == 0) + if (window_count_panes(src_w, 1) == 0) server_kill_window(src_w, 1); else notify_window("window-layout-changed", src_w); diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 3cabe07e..51c29ec2 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -103,7 +103,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) * spawned without being visited (for example split-window -d). */ lastwp = TAILQ_FIRST(&w->last_panes); - if (lastwp == NULL && window_count_panes(w) == 2) { + if (lastwp == NULL && window_count_panes(w, 1) == 2) { lastwp = TAILQ_PREV(w->active, window_panes, entry); if (lastwp == NULL) lastwp = TAILQ_NEXT(w->active, entry); diff --git a/format.c b/format.c index 8a0accf7..472316ec 100644 --- a/format.c +++ b/format.c @@ -2046,7 +2046,7 @@ static void * format_cb_pane_bottom(struct format_tree *ft) { if (ft->wp != NULL) - return (format_printf("%u", ft->wp->yoff + ft->wp->sy - 1)); + return (format_printf("%d", ft->wp->yoff + ft->wp->sy - 1)); return (NULL); } @@ -2205,7 +2205,7 @@ static void * format_cb_pane_left(struct format_tree *ft) { if (ft->wp != NULL) - return (format_printf("%u", ft->wp->xoff)); + return (format_printf("%d", ft->wp->xoff)); return (NULL); } @@ -2329,7 +2329,7 @@ static void * format_cb_pane_right(struct format_tree *ft) { if (ft->wp != NULL) - return (format_printf("%u", ft->wp->xoff + ft->wp->sx - 1)); + return (format_printf("%d", ft->wp->xoff + ft->wp->sx - 1)); return (NULL); } @@ -2371,7 +2371,7 @@ static void * format_cb_pane_top(struct format_tree *ft) { if (ft->wp != NULL) - return (format_printf("%u", ft->wp->yoff)); + return (format_printf("%d", ft->wp->yoff)); return (NULL); } @@ -2918,7 +2918,7 @@ static void * format_cb_window_panes(struct format_tree *ft) { if (ft->w != NULL) - return (format_printf("%u", window_count_panes(ft->w))); + return (format_printf("%u", window_count_panes(ft->w, 1))); return (NULL); } diff --git a/layout-custom.c b/layout-custom.c index 27d5bf82..aa36d2c4 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -27,10 +27,11 @@ static struct layout_cell *layout_find_bottomright(struct layout_cell *); static u_short layout_checksum(const char *); static int layout_append(struct layout_cell *, char *, size_t); -static struct layout_cell *layout_construct(struct layout_cell *, - const char **); +static int layout_construct(struct layout_cell *, + const char **, struct layout_cell **, + struct layout_cell **); static void layout_assign(struct window_pane **, - struct layout_cell *); + struct layout_cell *, int); /* Find the bottom-right cell. */ static struct layout_cell * @@ -58,14 +59,30 @@ layout_checksum(const char *layout) /* Dump layout as a string. */ char * -layout_dump(__unused struct window *w, struct layout_cell *root) +layout_dump(struct window *w, struct layout_cell *root) { - char layout[8192], *out; + char layout[8192], *out; + int bracket = 0; + struct window_pane *wp; *layout = '\0'; if (layout_append(root, layout, sizeof layout) != 0) return (NULL); + TAILQ_FOREACH(wp, &w->z_index, zentry) { + if (~wp->flags & PANE_FLOATING) + break; + if (!bracket) { + strlcat(layout, "<", sizeof layout); + bracket = 1; + } + if (layout_append(wp->layout_cell, layout, sizeof layout) != 0) + return (NULL); + strlcat(layout, ",", sizeof layout); + } + if (bracket) + layout[strlen(layout) - 1] = '>'; + xasprintf(&out, "%04hx,%s", layout_checksum(layout), layout); return (out); } @@ -81,12 +98,13 @@ layout_append(struct layout_cell *lc, char *buf, size_t len) if (len == 0) return (-1); - + if (lc == NULL) + return (0); if (lc->wp != NULL) { - tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%u,%u,%u", + tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%d,%d,%u", lc->sx, lc->sy, lc->xoff, lc->yoff, lc->wp->id); } else { - tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%u,%u", + tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%d,%d", lc->sx, lc->sy, lc->xoff, lc->yoff); } if (tmplen > (sizeof tmp) - 1) @@ -109,6 +127,7 @@ layout_append(struct layout_cell *lc, char *buf, size_t len) } buf[strlen(buf) - 1] = brackets[0]; break; + case LAYOUT_FLOATING: case LAYOUT_WINDOWPANE: break; } @@ -124,6 +143,7 @@ layout_check(struct layout_cell *lc) u_int n = 0; switch (lc->type) { + case LAYOUT_FLOATING: case LAYOUT_WINDOWPANE: break; case LAYOUT_LEFTRIGHT: @@ -156,7 +176,7 @@ layout_check(struct layout_cell *lc) int layout_parse(struct window *w, const char *layout, char **cause) { - struct layout_cell *lc, *lcchild; + struct layout_cell *lcchild, *tiled_lc = NULL, *floating_lc = NULL; struct window_pane *wp; u_int npanes, ncells, sx = 0, sy = 0; u_short csum; @@ -174,20 +194,27 @@ layout_parse(struct window *w, const char *layout, char **cause) } /* Build the layout. */ - lc = layout_construct(NULL, &layout); - if (lc == NULL) { + if (layout_construct(NULL, &layout, &tiled_lc, &floating_lc) != 0) { *cause = xstrdup("invalid layout"); return (-1); } + if (tiled_lc == NULL) { + /* A stub layout cell for an empty window. */ + tiled_lc = layout_create_cell(NULL); + tiled_lc->type = LAYOUT_LEFTRIGHT; + layout_set_size(tiled_lc, w->sx, w->sy, 0, 0); + } if (*layout != '\0') { *cause = xstrdup("invalid layout"); goto fail; } /* Check this window will fit into the layout. */ + npanes = window_count_panes(w, 1); for (;;) { - npanes = window_count_panes(w); - ncells = layout_count_cells(lc); + ncells = layout_count_cells(tiled_lc); + if (floating_lc != NULL) + ncells += layout_count_cells(floating_lc); if (npanes > ncells) { xasprintf(cause, "have %u panes but need %u", npanes, ncells); @@ -196,9 +223,17 @@ layout_parse(struct window *w, const char *layout, char **cause) if (npanes == ncells) break; - /* Fewer panes than cells - close the bottom right. */ - lcchild = layout_find_bottomright(lc); - layout_destroy_cell(w, lcchild, &lc); + /* + * Fewer panes than cells - close floating panes first + * then close the bottom right until none remain. + */ + if (floating_lc != NULL && !TAILQ_EMPTY(&floating_lc->cells)) { + lcchild = TAILQ_FIRST(&floating_lc->cells); + layout_destroy_cell(w, lcchild, &floating_lc); + } else { + lcchild = layout_find_bottomright(tiled_lc); + layout_destroy_cell(w, lcchild, &tiled_lc); + } } /* @@ -206,91 +241,108 @@ layout_parse(struct window *w, const char *layout, char **cause) * an incorrect top cell size - if it is larger than the top child then * correct that (if this is still wrong the check code will catch it). */ - switch (lc->type) { + + switch (tiled_lc->type) { case LAYOUT_WINDOWPANE: break; case LAYOUT_LEFTRIGHT: - TAILQ_FOREACH(lcchild, &lc->cells, entry) { + TAILQ_FOREACH(lcchild, &tiled_lc->cells, entry) { sy = lcchild->sy + 1; sx += lcchild->sx + 1; } break; case LAYOUT_TOPBOTTOM: - TAILQ_FOREACH(lcchild, &lc->cells, entry) { + TAILQ_FOREACH(lcchild, &tiled_lc->cells, entry) { sx = lcchild->sx + 1; sy += lcchild->sy + 1; } break; + case LAYOUT_FLOATING: + *cause = xstrdup("invalid layout"); + goto fail; } - if (lc->type != LAYOUT_WINDOWPANE && (lc->sx != sx || lc->sy != sy)) { - log_debug("fix layout %u,%u to %u,%u", lc->sx, lc->sy, sx,sy); - layout_print_cell(lc, __func__, 0); - lc->sx = sx - 1; lc->sy = sy - 1; + if (tiled_lc->type != LAYOUT_WINDOWPANE && + (tiled_lc->sx != sx || tiled_lc->sy != sy)) { + layout_print_cell(tiled_lc, __func__, 0); + tiled_lc->sx = sx - 1; tiled_lc->sy = sy - 1; } /* Check the new layout. */ - if (!layout_check(lc)) { + if (!layout_check(tiled_lc)) { *cause = xstrdup("size mismatch after applying layout"); goto fail; } - /* Resize to the layout size. */ - window_resize(w, lc->sx, lc->sy, -1, -1); + /* Resize window to the layout size. */ + if (sx != 0 && sy != 0) + 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); - w->layout_root = lc; + w->layout_root = tiled_lc; /* Assign the panes into the cells. */ wp = TAILQ_FIRST(&w->panes); - layout_assign(&wp, lc); + if (tiled_lc != NULL) + layout_assign(&wp, tiled_lc, 0); + if (floating_lc != NULL) + layout_assign(&wp, floating_lc, PANE_FLOATING); /* Update pane offsets and sizes. */ layout_fix_offsets(w); layout_fix_panes(w, NULL); recalculate_sizes(); + layout_print_cell(tiled_lc, __func__, 0); - layout_print_cell(lc, __func__, 0); + /* Free the floating layout cell, no longer needed. */ + if (floating_lc != NULL) + layout_free_cell(floating_lc); notify_window("window-layout-changed", w); return (0); fail: - layout_free_cell(lc); + layout_free_cell(tiled_lc); + layout_free_cell(floating_lc); return (-1); } /* Assign panes into cells. */ static void -layout_assign(struct window_pane **wp, struct layout_cell *lc) +layout_assign(struct window_pane **wp, struct layout_cell *lc, int flags) { struct layout_cell *lcchild; + if (lc == NULL) + return; + switch (lc->type) { case LAYOUT_WINDOWPANE: layout_make_leaf(lc, *wp); + (*wp)->flags |= flags; *wp = TAILQ_NEXT(*wp, entry); return; case LAYOUT_LEFTRIGHT: case LAYOUT_TOPBOTTOM: + case LAYOUT_FLOATING: TAILQ_FOREACH(lcchild, &lc->cells, entry) - layout_assign(wp, lcchild); + layout_assign(wp, lcchild, 1); return; } } -/* Construct a cell from all or part of a layout tree. */ static struct layout_cell * -layout_construct(struct layout_cell *lcparent, const char **layout) +layout_construct_cell(struct layout_cell *lcparent, const char **layout) { - struct layout_cell *lc, *lcchild; - u_int sx, sy, xoff, yoff; + struct layout_cell *lc; + u_int sx, sy; + int xoff, yoff; const char *saved; if (!isdigit((u_char) **layout)) return (NULL); - if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4) + if (sscanf(*layout, "%ux%u,%d,%d", &sx, &sy, &xoff, &yoff) != 4) return (NULL); while (isdigit((u_char) **layout)) @@ -325,17 +377,41 @@ layout_construct(struct layout_cell *lcparent, const char **layout) lc->xoff = xoff; lc->yoff = yoff; + return (lc); +} + +/* + * Given a character string layout, recursively construct cells. + * Possible return values: + * lc LAYOUT_WINDOWPANE, no children + * lc LAYOUT_LEFTRIGHT or LAYOUT_TOPBOTTOM, with children + * floating_lc LAYOUT_FLOATING, with children + */ +static int +layout_construct(struct layout_cell *lcparent, const char **layout, + struct layout_cell **lc, struct layout_cell **floating_lc) +{ + struct layout_cell *lcchild, *saved_lc; + + *lc = layout_construct_cell(lcparent, layout); + switch (**layout) { case ',': case '}': case ']': + case '>': case '\0': - return (lc); + return (0); case '{': - lc->type = LAYOUT_LEFTRIGHT; + (*lc)->type = LAYOUT_LEFTRIGHT; break; case '[': - lc->type = LAYOUT_TOPBOTTOM; + (*lc)->type = LAYOUT_TOPBOTTOM; + break; + case '<': + saved_lc = *lc; + *lc = layout_create_cell(lcparent); + (*lc)->type = LAYOUT_FLOATING; break; default: goto fail; @@ -343,13 +419,12 @@ layout_construct(struct layout_cell *lcparent, const char **layout) do { (*layout)++; - lcchild = layout_construct(lc, layout); - if (lcchild == NULL) + if (layout_construct(*lc, layout, &lcchild, floating_lc) != 0) goto fail; - TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry); + TAILQ_INSERT_TAIL(&(*lc)->cells, lcchild, entry); } while (**layout == ','); - switch (lc->type) { + switch ((*lc)->type) { case LAYOUT_LEFTRIGHT: if (**layout != '}') goto fail; @@ -358,14 +433,21 @@ layout_construct(struct layout_cell *lcparent, const char **layout) if (**layout != ']') goto fail; break; + case LAYOUT_FLOATING: + if (**layout != '>') + goto fail; + *floating_lc = *lc; + *lc = saved_lc; + break; default: goto fail; } (*layout)++; - return (lc); + return (0); fail: - layout_free_cell(lc); - return (NULL); + layout_free_cell(*lc); + layout_free_cell(*floating_lc); + return (-1); } diff --git a/layout-set.c b/layout-set.c index bd68f663..f9944ed9 100644 --- a/layout-set.c +++ b/layout-set.c @@ -133,7 +133,7 @@ layout_set_even(struct window *w, enum layout_type type) layout_print_cell(w->layout_root, __func__, 1); /* Get number of panes. */ - n = window_count_panes(w); + n = window_count_panes(w, 0); if (n <= 1) return; @@ -201,7 +201,7 @@ layout_set_main_h(struct window *w) layout_print_cell(w->layout_root, __func__, 1); /* Get number of panes. */ - n = window_count_panes(w); + n = window_count_panes(w, 0); if (n <= 1) return; n--; /* take off main pane */ @@ -299,7 +299,7 @@ layout_set_main_h_mirrored(struct window *w) layout_print_cell(w->layout_root, __func__, 1); /* Get number of panes. */ - n = window_count_panes(w); + n = window_count_panes(w, 0); if (n <= 1) return; n--; /* take off main pane */ @@ -397,7 +397,7 @@ layout_set_main_v(struct window *w) layout_print_cell(w->layout_root, __func__, 1); /* Get number of panes. */ - n = window_count_panes(w); + n = window_count_panes(w, 0); if (n <= 1) return; n--; /* take off main pane */ @@ -495,7 +495,7 @@ layout_set_main_v_mirrored(struct window *w) layout_print_cell(w->layout_root, __func__, 1); /* Get number of panes. */ - n = window_count_panes(w); + n = window_count_panes(w, 0); if (n <= 1) return; n--; /* take off main pane */ @@ -593,7 +593,7 @@ layout_set_tiled(struct window *w) layout_print_cell(w->layout_root, __func__, 1); /* Get number of panes. */ - n = window_count_panes(w); + n = window_count_panes(w, 0); if (n <= 1) return; diff --git a/layout.c b/layout.c index d3df5e7f..5afd697b 100644 --- a/layout.c +++ b/layout.c @@ -46,7 +46,10 @@ static int layout_set_size_check(struct window *, struct layout_cell *, enum layout_type, int); static void layout_resize_child_cells(struct window *, struct layout_cell *); +void layout_redistribute_cells(struct window *, struct layout_cell *, + enum layout_type); +/* Create a new layout cell. */ struct layout_cell * layout_create_cell(struct layout_cell *lcparent) { @@ -61,14 +64,15 @@ layout_create_cell(struct layout_cell *lcparent) lc->sx = UINT_MAX; lc->sy = UINT_MAX; - lc->xoff = UINT_MAX; - lc->yoff = UINT_MAX; + lc->xoff = INT_MAX; + lc->yoff = INT_MAX; lc->wp = NULL; return (lc); } +/* Free a layout cell. */ void layout_free_cell(struct layout_cell *lc) { @@ -83,21 +87,40 @@ layout_free_cell(struct layout_cell *lc) layout_free_cell(lcchild); } break; + case LAYOUT_FLOATING: + /* + * A floating layout cell is only used temporarily while + * select-layout constructs a layout. Remove the children from + * the temporary layout, then free temporary floating layout + * cell. Each floating pane has stub layout. + */ + while (!TAILQ_EMPTY(&lc->cells)) { + lcchild = TAILQ_FIRST(&lc->cells); + TAILQ_REMOVE(&lc->cells, lcchild, entry); + lcchild->parent = NULL; + } + break; case LAYOUT_WINDOWPANE: - if (lc->wp != NULL) + if (lc->wp != NULL) { + lc->wp->layout_cell->parent = NULL; lc->wp->layout_cell = NULL; + } break; } free(lc); } +/* Log a cell. */ void layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n) { struct layout_cell *lcchild; const char *type; + if (lc == NULL) + return; + switch (lc->type) { case LAYOUT_LEFTRIGHT: type = "LEFTRIGHT"; @@ -105,6 +128,9 @@ layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n) case LAYOUT_TOPBOTTOM: type = "TOPBOTTOM"; break; + case LAYOUT_FLOATING: + type = "FLOATING"; + break; case LAYOUT_WINDOWPANE: type = "WINDOWPANE"; break; @@ -112,12 +138,13 @@ layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n) type = "UNKNOWN"; break; } - log_debug("%s:%*s%p type %s [parent %p] wp=%p [%u,%u %ux%u]", hdr, n, + log_debug("%s:%*s%p type %s [parent %p] wp=%p [%d,%d %ux%u]", hdr, n, " ", lc, type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx, lc->sy); switch (lc->type) { case LAYOUT_LEFTRIGHT: case LAYOUT_TOPBOTTOM: + case LAYOUT_FLOATING: TAILQ_FOREACH(lcchild, &lc->cells, entry) layout_print_cell(lcchild, hdr, n + 1); break; @@ -126,14 +153,17 @@ layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n) } } +/* Search for a cell by the border position. */ struct layout_cell * layout_search_by_border(struct layout_cell *lc, u_int x, u_int y) { struct layout_cell *lcchild, *last = NULL; TAILQ_FOREACH(lcchild, &lc->cells, entry) { - if (x >= lcchild->xoff && x < lcchild->xoff + lcchild->sx && - y >= lcchild->yoff && y < lcchild->yoff + lcchild->sy) { + if ((int)x >= lcchild->xoff && + (int)x < lcchild->xoff + (int)lcchild->sx && + (int)y >= lcchild->yoff && + (int)y < lcchild->yoff + (int)lcchild->sy) { /* Inside the cell - recurse. */ return (layout_search_by_border(lcchild, x, y)); } @@ -145,14 +175,17 @@ layout_search_by_border(struct layout_cell *lc, u_int x, u_int y) switch (lc->type) { case LAYOUT_LEFTRIGHT: - if (x < lcchild->xoff && x >= last->xoff + last->sx) + if ((int)x < lcchild->xoff && + (int)x >= last->xoff + (int)last->sx) return (last); break; case LAYOUT_TOPBOTTOM: - if (y < lcchild->yoff && y >= last->yoff + last->sy) + if ((int)y < lcchild->yoff && + (int)y >= last->yoff + (int)last->sy) return (last); break; case LAYOUT_WINDOWPANE: + case LAYOUT_FLOATING: break; } @@ -162,9 +195,9 @@ layout_search_by_border(struct layout_cell *lc, u_int x, u_int y) return (NULL); } +/* Set cell size. */ void -layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff, - u_int yoff) +layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, int xoff, int yoff) { lc->sx = sx; lc->sy = sy; @@ -173,6 +206,7 @@ layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff, lc->yoff = yoff; } +/* Make a cell a leaf cell. */ void layout_make_leaf(struct layout_cell *lc, struct window_pane *wp) { @@ -184,6 +218,7 @@ layout_make_leaf(struct layout_cell *lc, struct window_pane *wp) lc->wp = wp; } +/* Make a cell a node cell. */ void layout_make_node(struct layout_cell *lc, enum layout_type type) { @@ -203,7 +238,7 @@ static void layout_fix_offsets1(struct layout_cell *lc) { struct layout_cell *lcchild; - u_int xoff, yoff; + int xoff, yoff; if (lc->type == LAYOUT_LEFTRIGHT) { xoff = lc->xoff; @@ -246,6 +281,8 @@ layout_cell_is_top(struct window *w, struct layout_cell *lc) while (lc != w->layout_root) { next = lc->parent; + if (next == NULL) + return (0); if (next->type == LAYOUT_TOPBOTTOM && lc != TAILQ_FIRST(&next->cells)) return (0); @@ -262,6 +299,8 @@ layout_cell_is_bottom(struct window *w, struct layout_cell *lc) while (lc != w->layout_root) { next = lc->parent; + if (next == NULL) + return (0); if (next->type == LAYOUT_TOPBOTTOM && lc != TAILQ_LAST(&next->cells, layout_cells)) return (0); @@ -307,7 +346,8 @@ layout_fix_panes(struct window *w, struct window_pane *skip) sx = lc->sx; sy = lc->sy; - if (layout_add_horizontal_border(w, lc, status)) { + if ((~wp->flags & PANE_FLOATING) && + layout_add_horizontal_border(w, lc, status)) { if (status == PANE_STATUS_TOP) wp->yoff++; sy--; @@ -346,14 +386,14 @@ u_int layout_count_cells(struct layout_cell *lc) { struct layout_cell *lcchild; - u_int count; + u_int count = 0; switch (lc->type) { case LAYOUT_WINDOWPANE: return (1); case LAYOUT_LEFTRIGHT: case LAYOUT_TOPBOTTOM: - count = 0; + case LAYOUT_FLOATING: TAILQ_FOREACH(lcchild, &lc->cells, entry) count += layout_count_cells(lcchild); return (count); @@ -470,13 +510,22 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc, struct layout_cell *lcother, *lcparent; /* - * If no parent, this is the last pane so window close is imminent and - * there is no need to resize anything. + * If no parent, this is either a floating pane or the last + * pane so window close is imminent and there is no need to + * resize anything. */ lcparent = lc->parent; if (lcparent == NULL) { + if (lc->wp != NULL && ~lc->wp->flags & PANE_FLOATING) + *lcroot = NULL; + layout_free_cell(lc); + return; + } + + /* A floating cell need only be removed from the parent. */ + if (lcparent->type == LAYOUT_FLOATING) { + TAILQ_REMOVE(&lcparent->cells, lc, entry); layout_free_cell(lc); - *lcroot = NULL; return; } @@ -499,12 +548,13 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc, * replace it by that cell. */ lc = TAILQ_FIRST(&lcparent->cells); - if (TAILQ_NEXT(lc, entry) == NULL) { + if (lc != NULL && TAILQ_NEXT(lc, entry) == NULL) { TAILQ_REMOVE(&lcparent->cells, lc, entry); lc->parent = lcparent->parent; if (lc->parent == NULL) { - lc->xoff = 0; lc->yoff = 0; + lc->xoff = 0; + lc->yoff = 0; *lcroot = lc; } else TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry); @@ -513,6 +563,7 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc, } } +/* Initialize layout for pane. */ void layout_init(struct window *w, struct window_pane *wp) { @@ -524,6 +575,7 @@ layout_init(struct window *w, struct window_pane *wp) layout_fix_panes(w, NULL); } +/* Free layout for pane. */ void layout_free(struct window *w) { @@ -741,7 +793,7 @@ layout_resize_pane_shrink(struct window *w, struct layout_cell *lc, return (size); } -/* Assign window pane to newly split cell. */ +/* Assign window pane to new cell. */ void layout_assign_pane(struct layout_cell *lc, struct window_pane *wp, int do_not_resize) @@ -1085,6 +1137,9 @@ layout_close_pane(struct window_pane *wp) { struct window *w = wp->window; + if (wp->layout_cell == NULL) + return; + /* Remove the cell. */ layout_destroy_cell(w, wp->layout_cell, &w->layout_root); diff --git a/log.c b/log.c index ede6e257..98a03763 100644 --- a/log.c +++ b/log.c @@ -150,6 +150,7 @@ fatal(const char *msg, ...) log_vwrite(msg, ap, tmp); va_end(ap); + abort ();//XXX exit(1); } @@ -163,5 +164,6 @@ fatalx(const char *msg, ...) log_vwrite(msg, ap, "fatal: "); va_end(ap); + abort ();//XXX exit(1); } diff --git a/server-fn.c b/server-fn.c index 6c4c9c61..585a01f9 100644 --- a/server-fn.c +++ b/server-fn.c @@ -185,7 +185,7 @@ server_kill_pane(struct window_pane *wp) { struct window *w = wp->window; - if (window_count_panes(w) == 1) { + if (window_count_panes(w, 1) == 1) { server_kill_window(w, 1); recalculate_sizes(); } else { diff --git a/tmux.h b/tmux.h index 2c034b8e..2209732e 100644 --- a/tmux.h +++ b/tmux.h @@ -1302,9 +1302,11 @@ struct window_pane { TAILQ_ENTRY(window_pane) entry; /* link in list of all panes */ TAILQ_ENTRY(window_pane) sentry; /* link in list of last visited */ + TAILQ_ENTRY(window_pane) zentry; /* z-index link in list of all panes */ RB_ENTRY(window_pane) tree_entry; }; TAILQ_HEAD(window_panes, window_pane); +TAILQ_HEAD(window_panes_zindex, window_pane); RB_HEAD(window_pane_tree, window_pane); /* Window structure. */ @@ -1324,6 +1326,7 @@ struct window { struct window_pane *active; struct window_panes last_panes; + struct window_panes z_index; struct window_panes panes; int lastlayout; @@ -1417,6 +1420,7 @@ TAILQ_HEAD(winlink_stack, winlink); enum layout_type { LAYOUT_LEFTRIGHT, LAYOUT_TOPBOTTOM, + LAYOUT_FLOATING, LAYOUT_WINDOWPANE }; @@ -1432,8 +1436,8 @@ struct layout_cell { u_int sx; u_int sy; - u_int xoff; - u_int yoff; + int xoff; + int yoff; struct window_pane *wp; struct layout_cells cells; @@ -1710,10 +1714,10 @@ struct tty_ctx { u_int orlower; /* Target region (usually pane) offset and size. */ - u_int xoff; - u_int yoff; - u_int rxoff; - u_int ryoff; + int xoff; + int yoff; + int rxoff; + int ryoff; u_int sx; u_int sy; @@ -2284,6 +2288,7 @@ struct spawn_context { #define SPAWN_FULLSIZE 0x20 #define SPAWN_EMPTY 0x40 #define SPAWN_ZOOM 0x80 +#define SPAWN_FLOATING 0x100 }; /* Paste buffer. */ @@ -3362,7 +3367,7 @@ struct window_pane *window_pane_next_by_number(struct window *, struct window_pane *window_pane_previous_by_number(struct window *, struct window_pane *, u_int); int window_pane_index(struct window_pane *, u_int *); -u_int window_count_panes(struct window *); +u_int window_count_panes(struct window *, int); void window_destroy_panes(struct window *); struct window_pane *window_pane_find_by_id_str(const char *); struct window_pane *window_pane_find_by_id(u_int); @@ -3430,8 +3435,7 @@ void layout_destroy_cell(struct window *, struct layout_cell *, void layout_resize_layout(struct window *, struct layout_cell *, enum layout_type, int, int); struct layout_cell *layout_search_by_border(struct layout_cell *, u_int, u_int); -void layout_set_size(struct layout_cell *, u_int, u_int, u_int, - u_int); +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_offsets(struct window *); diff --git a/window-tree.c b/window-tree.c index b58d5ed5..9b5269b7 100644 --- a/window-tree.c +++ b/window-tree.c @@ -387,7 +387,7 @@ window_tree_build(void *modedata, struct sort_criteria *sort_crit, *tag = (uint64_t)data->fs.wl; break; case WINDOW_TREE_PANE: - if (window_count_panes(data->fs.wl->window) == 1) + if (window_count_panes(data->fs.wl->window, 1) == 1) *tag = (uint64_t)data->fs.wl; else *tag = (uint64_t)data->fs.wp; @@ -578,7 +578,7 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s, struct format_tree *ft; struct options *oo; - total = window_count_panes(w); + total = window_count_panes(w, 1); if (sx / total < 24) { visible = sx / 24; diff --git a/window.c b/window.c index f554ee67..72ccb7cc 100644 --- a/window.c +++ b/window.c @@ -73,7 +73,7 @@ static struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); static void window_pane_destroy(struct window_pane *); static void window_pane_full_size_offset(struct window_pane *wp, - u_int *xoff, u_int *yoff, u_int *sx, u_int *sy); + int *xoff, int *yoff, u_int *sx, u_int *sy); RB_GENERATE(windows, window, entry, window_cmp); RB_GENERATE(winlinks, winlink, entry, winlink_cmp); @@ -308,6 +308,7 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) w->flags = 0; TAILQ_INIT(&w->panes); + TAILQ_INIT(&w->z_index); TAILQ_INIT(&w->last_panes); w->active = NULL; @@ -523,6 +524,8 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify) if (wp == w->active) return (0); + if (w->flags & WINDOW_ZOOMED) + window_unzoom(w, 1); lastwp = w->active; window_pane_stack_remove(&w->last_panes, wp); @@ -665,7 +668,7 @@ window_zoom(struct window_pane *wp) if (w->flags & WINDOW_ZOOMED) return (-1); - if (window_count_panes(w) == 1) + if (window_count_panes(w, 1) == 1) return (-1); if (w->active != wp) @@ -852,14 +855,15 @@ window_pane_index(struct window_pane *wp, u_int *i) } u_int -window_count_panes(struct window *w) +window_count_panes(struct window *w, int with_floating) { struct window_pane *wp; - u_int n; + u_int n = 0; - n = 0; - TAILQ_FOREACH(wp, &w->panes, entry) - n++; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (with_floating || ~wp->flags & PANE_FLOATING) + n++; + } return (n); } @@ -1377,7 +1381,7 @@ window_pane_choose_best(struct window_pane **list, u_int size) * scrollbars if they were visible but not including the border(s). */ static void -window_pane_full_size_offset(struct window_pane *wp, u_int *xoff, u_int *yoff, +window_pane_full_size_offset(struct window_pane *wp, int *xoff, int *yoff, u_int *sx, u_int *sy) { struct window *w = wp->window; @@ -1411,9 +1415,9 @@ window_pane_find_up(struct window_pane *wp) { struct window *w; struct window_pane *next, *best, **list; - u_int edge, left, right, end, size; - int status, found; - u_int xoff, yoff, sx, sy; + int edge, left, right, end, status, found; + int xoff, yoff; + u_int size, sx, sy; if (wp == NULL) return (NULL); @@ -1428,25 +1432,25 @@ window_pane_find_up(struct window_pane *wp) edge = yoff; if (status == PANE_STATUS_TOP) { if (edge == 1) - edge = w->sy + 1; + edge = (int)w->sy + 1; } else if (status == PANE_STATUS_BOTTOM) { if (edge == 0) - edge = w->sy; + edge = (int)w->sy; } else { if (edge == 0) - edge = w->sy + 1; + edge = (int)w->sy + 1; } left = xoff; - right = xoff + sx; + right = xoff + (int)sx; TAILQ_FOREACH(next, &w->panes, entry) { window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy); if (next == wp) continue; - if (yoff + sy + 1 != edge) + if (yoff + (int)sy + 1 != edge) continue; - end = xoff + sx - 1; + end = xoff + (int)sx - 1; found = 0; if (xoff < left && end > right) @@ -1472,9 +1476,9 @@ window_pane_find_down(struct window_pane *wp) { struct window *w; struct window_pane *next, *best, **list; - u_int edge, left, right, end, size; - int status, found; - u_int xoff, yoff, sx, sy; + int edge, left, right, end, status, found; + int xoff, yoff; + u_int size, sx, sy; if (wp == NULL) return (NULL); @@ -1486,20 +1490,20 @@ window_pane_find_down(struct window_pane *wp) window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); - edge = yoff + sy + 1; + edge = yoff + (int)sy + 1; if (status == PANE_STATUS_TOP) { - if (edge >= w->sy) + if (edge >= (int)w->sy) edge = 1; } else if (status == PANE_STATUS_BOTTOM) { - if (edge >= w->sy - 1) + if (edge >= (int)w->sy - 1) edge = 0; } else { - if (edge >= w->sy) + if (edge >= (int)w->sy) edge = 0; } left = wp->xoff; - right = wp->xoff + wp->sx; + right = wp->xoff + (int)wp->sx; TAILQ_FOREACH(next, &w->panes, entry) { window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy); @@ -1507,7 +1511,7 @@ window_pane_find_down(struct window_pane *wp) continue; if (yoff != edge) continue; - end = xoff + sx - 1; + end = xoff + (int)sx - 1; found = 0; if (xoff < left && end > right) @@ -1533,9 +1537,9 @@ window_pane_find_left(struct window_pane *wp) { struct window *w; struct window_pane *next, *best, **list; - u_int edge, top, bottom, end, size; - int found; - u_int xoff, yoff, sx, sy; + int edge, top, bottom, end, found; + int xoff, yoff; + u_int size, sx, sy; if (wp == NULL) return (NULL); @@ -1548,18 +1552,18 @@ window_pane_find_left(struct window_pane *wp) edge = xoff; if (edge == 0) - edge = w->sx + 1; + edge = (int)w->sx + 1; top = yoff; - bottom = yoff + sy; + bottom = yoff + (int)sy; TAILQ_FOREACH(next, &w->panes, entry) { window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy); if (next == wp) continue; - if (xoff + sx + 1 != edge) + if (xoff + (int)sx + 1 != edge) continue; - end = yoff + sy - 1; + end = yoff + (int)sy - 1; found = 0; if (yoff < top && end > bottom) @@ -1585,9 +1589,9 @@ window_pane_find_right(struct window_pane *wp) { struct window *w; struct window_pane *next, *best, **list; - u_int edge, top, bottom, end, size; - int found; - u_int xoff, yoff, sx, sy; + int edge, top, bottom, end, found; + int xoff, yoff; + u_int size, sx, sy; if (wp == NULL) return (NULL); @@ -1598,12 +1602,12 @@ window_pane_find_right(struct window_pane *wp) window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); - edge = xoff + sx + 1; - if (edge >= w->sx) + edge = xoff + (int)sx + 1; + if (edge >= (int)w->sx) edge = 0; top = wp->yoff; - bottom = wp->yoff + wp->sy; + bottom = wp->yoff + (int)wp->sy; TAILQ_FOREACH(next, &w->panes, entry) { window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy); @@ -1611,7 +1615,7 @@ window_pane_find_right(struct window_pane *wp) continue; if (xoff != edge) continue; - end = yoff + sy - 1; + end = yoff + (int)sy - 1; found = 0; if (yoff < top && end > bottom) @@ -1631,6 +1635,7 @@ window_pane_find_right(struct window_pane *wp) return (best); } +/* Add window to stack. */ void window_pane_stack_push(struct window_panes *stack, struct window_pane *wp) { @@ -1641,6 +1646,7 @@ window_pane_stack_push(struct window_panes *stack, struct window_pane *wp) } } +/* Remove window from stack. */ void window_pane_stack_remove(struct window_panes *stack, struct window_pane *wp) {