mirror of
https://github.com/tmux/tmux.git
synced 2026-01-11 16:30:22 +00:00
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:
180
layout-custom.c
180
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,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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user