1. Rework floating panes to have a stub layout_cell, 2. Add new <..> format to list-windows & select-layout for floating anes, 3. Fix zooming to work with floating panes, 4. Fix several display issues.

This commit is contained in:
Michael Grant
2025-12-08 14:28:17 +00:00
parent a6ec2b76c2
commit eaa467618b
15 changed files with 357 additions and 160 deletions

View File

@@ -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,33 @@ layout_checksum(const char *layout)
/* Dump layout as a string. */
char *
layout_dump(struct layout_cell *root)
layout_dump(struct window *w, struct layout_cell *root)
{
char layout[8192], *out;
char layout[8192], *out;
int braket;
struct window_pane *wp;
*layout = '\0';
if (layout_append(root, layout, sizeof layout) != 0)
return (NULL);
braket = 0;
TAILQ_FOREACH(wp, &w->z_index, zentry) {
if (~wp->flags & PANE_FLOATING)
break;
if (!braket) {
strcat(layout, "<");
braket = 1;
}
if (layout_append(wp->layout_cell, layout, sizeof layout) != 0)
return (NULL);
strcat(layout, ",");
}
if (braket) {
/* Overwrite the trailing ','. */
layout[strlen(layout) - 1] = '>';
}
xasprintf(&out, "%04hx,%s", layout_checksum(layout), layout);
return (out);
}
@@ -81,7 +101,8 @@ 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",
lc->sx, lc->sy, lc->xoff, lc->yoff, lc->wp->id);
@@ -109,6 +130,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;
}
@@ -125,6 +147,7 @@ layout_check(struct layout_cell *lc)
switch (lc->type) {
case LAYOUT_WINDOWPANE:
case LAYOUT_FLOATING:
break;
case LAYOUT_LEFTRIGHT:
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
@@ -156,7 +179,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;
@@ -173,11 +196,16 @@ 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;
@@ -186,8 +214,10 @@ layout_parse(struct window *w, const char *layout, char **cause)
/* Check this window will fit into the layout. */
for (;;) {
npanes = window_count_panes(w);
ncells = layout_count_cells(lc);
ncells = layout_count_cells(tiled_lc);
ncells += layout_count_cells(floating_lc);
if (npanes > ncells) {
/* Modify this to open a new pane */
xasprintf(cause, "have %u panes but need %u", npanes,
ncells);
goto fail;
@@ -195,9 +225,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.
*/
if (floating_lc && ! 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);
}
}
/*
@@ -205,85 +243,112 @@ 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)) {
log_debug("fix layout %u,%u to %u,%u", tiled_lc->sx,
tiled_lc->sy, sx,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);
layout_assign(&wp, tiled_lc, 0);
layout_assign(&wp, floating_lc, 1);
/* Fix z_indexes. */
while (!TAILQ_EMPTY(&w->z_index)) {
wp = TAILQ_FIRST(&w->z_index);
TAILQ_REMOVE(&w->z_index, wp, zentry);
}
layout_fix_zindexes(w, floating_lc);
layout_fix_zindexes(w, tiled_lc);
/* Update pane offsets and sizes. */
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
recalculate_sizes();
layout_print_cell(lc, __func__, 0);
layout_print_cell(tiled_lc, __func__, 0);
layout_print_cell(floating_lc, __func__, 0);
/* Free the floating layout cell, no longer needed. */
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 floating)
{
struct layout_cell *lcchild;
if (lc == NULL)
return;
switch (lc->type) {
case LAYOUT_WINDOWPANE:
layout_make_leaf(lc, *wp);
if (floating) {
(*wp)->flags |= PANE_FLOATING;
}
*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;
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
const char *saved;
@@ -324,17 +389,42 @@ 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;
@@ -342,13 +432,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;
@@ -357,14 +446,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);
}