Zoomed panes are now like full screen floating panes.

This commit is contained in:
Michael Grant
2026-09-30 23:10:40 +01:00
parent 5a820e63b7
commit 7810f8abf3
29 changed files with 752 additions and 621 deletions

View File

@@ -59,10 +59,6 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
cmdq_error(item, "pane is already floating"); cmdq_error(item, "pane is already floating");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (w->flags & WINDOW_ZOOMED) {
cmdq_error(item, "can't float a pane while window is zoomed");
return (CMD_RETURN_ERROR);
}
if (layout_floating_args_parse(item, args, lines, w, fg, &cause) != 0) { if (layout_floating_args_parse(item, args, lines, w, fg, &cause) != 0) {
cmdq_error(item, "failed to float pane: %s", cause); cmdq_error(item, "failed to float pane: %s", cause);
@@ -73,8 +69,7 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
layout_set_size(lc, fg->sx, fg->sy, fg->xoff, fg->yoff); layout_set_size(lc, fg->sx, fg->sy, fg->xoff, fg->yoff);
lc->flags |= LAYOUT_CELL_FLOATING; lc->flags |= LAYOUT_CELL_FLOATING;
TAILQ_REMOVE(&w->z_index, wp, zentry); window_raise_pane(wp);
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
if (!args_has(args, 'd')) if (!args_has(args, 'd'))
window_set_active_pane(w, wp, 1); window_set_active_pane(w, wp, 1);
@@ -125,8 +120,6 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (idx == -1) if (idx == -1)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
server_unzoom_window(w);
if (window_count_panes(w, 1) == 1) { if (window_count_panes(w, 1) == 1) {
if (server_link_window(src_s, wl, dst_s, idx, 0, if (server_link_window(src_s, wl, dst_s, idx, 0,
!args_has(args, 'd'), &cause) != 0) { !args_has(args, 'd'), &cause) != 0) {

View File

@@ -470,12 +470,9 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
lg.yoff++; lg.yoff++;
} }
window_push_zoom(w, 0, 1);
lc = layout_floating_pane(w, wp, &lg); lc = layout_floating_pane(w, wp, &lg);
if (lc == NULL) { if (lc == NULL)
window_pop_zoom(w);
goto out; goto out;
}
sc.item = item; sc.item = item;
sc.s = s; sc.s = s;
@@ -501,10 +498,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "create pane failed: %s", cause); cmdq_error(item, "create pane failed: %s", cause);
free(cause); free(cause);
cause = NULL; cause = NULL;
window_pop_zoom(w);
goto fail; goto fail;
} }
window_pop_zoom(w);
new_wp->flags |= PANE_CAPTUREALLKEYS; new_wp->flags |= PANE_CAPTUREALLKEYS;
if (!args_has(args, 'E')) if (!args_has(args, 'E'))
new_wp->flags |= PANE_CLOSEONCANCEL; new_wp->flags |= PANE_CLOSEONCANCEL;

View File

@@ -64,6 +64,59 @@ const struct cmd_entry cmd_move_pane_entry = {
.exec = cmd_join_pane_exec .exec = cmd_join_pane_exec
}; };
/* Does a position name change the stacking order rather than the geometry? */
static int
cmd_join_pane_is_stacking(const char *position)
{
return (strcmp(position, "front") == 0 ||
strcmp(position, "back") == 0 ||
strcmp(position, "forward") == 0 ||
strcmp(position, "backward") == 0 ||
strcmp(position, "forward-loop") == 0 ||
strcmp(position, "backward-loop") == 0);
}
/* Get the stacking group of a pane: modal, always on top, or other. */
static int
cmd_join_pane_group(struct window_pane *wp)
{
if (wp == wp->window->modal)
return (0);
if (wp->flags & PANE_FLOATOVERZOOM)
return (1);
return (2);
}
/* Get the visible pane just in front of a pane in its group, if any. */
static struct window_pane *
cmd_join_pane_forward(struct window_pane *wp)
{
struct window_pane *owp = wp;
do {
owp = TAILQ_PREV(owp, window_panes_zindex, zentry);
} while (owp != NULL && !window_pane_is_visible(owp));
if (owp == NULL || cmd_join_pane_group(owp) != cmd_join_pane_group(wp))
return (NULL);
return (owp);
}
/* Get the visible pane just behind a pane in its group, if any. */
static struct window_pane *
cmd_join_pane_backward(struct window_pane *wp)
{
struct window_pane *owp = wp;
do {
owp = TAILQ_NEXT(owp, zentry);
} while (owp != NULL && !window_pane_is_visible(owp));
if (owp == NULL ||
!window_pane_is_raised(owp) ||
cmd_join_pane_group(owp) != cmd_join_pane_group(wp))
return (NULL);
return (owp);
}
static enum cmd_retval static enum cmd_retval
cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl, cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
struct window_pane *wp, const char *position) struct window_pane *wp, const char *position)
@@ -128,62 +181,35 @@ cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
xoff = (3 * wx) / 4 - px / 2; xoff = (3 * wx) / 4 - px / 2;
yoff = (3 * wy) / 4 - py / 2; yoff = (3 * wy) / 4 - py / 2;
} else if (strcmp(position, "front") == 0) { } else if (strcmp(position, "front") == 0) {
TAILQ_REMOVE(&w->z_index, wp, zentry); window_raise_pane(wp);
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
} else if (strcmp(position, "back") == 0) { } else if (strcmp(position, "back") == 0) {
TAILQ_REMOVE(&w->z_index, wp, zentry); window_lower_pane(wp);
TAILQ_FOREACH(owp, &w->z_index, zentry) {
if (!window_pane_is_floating_with_hidden(owp))
break;
}
if (owp != NULL)
TAILQ_INSERT_BEFORE(owp, wp, zentry);
else
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
} else if (strcmp(position, "forward") == 0) { } else if (strcmp(position, "forward") == 0) {
owp = TAILQ_PREV(wp, window_panes_zindex, zentry); owp = cmd_join_pane_forward(wp);
while (owp != NULL && owp->layout_cell == NULL)
owp = TAILQ_PREV(owp, window_panes_zindex, zentry);
if (owp != NULL) { if (owp != NULL) {
TAILQ_REMOVE(&w->z_index, wp, zentry); TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_INSERT_BEFORE(owp, wp, zentry); TAILQ_INSERT_BEFORE(owp, wp, zentry);
} }
} else if (strcmp(position, "backward") == 0) { } else if (strcmp(position, "backward") == 0) {
owp = TAILQ_NEXT(wp, zentry); owp = cmd_join_pane_backward(wp);
while (owp != NULL && owp->layout_cell == NULL) if (owp != NULL) {
owp = TAILQ_NEXT(owp, zentry);
if (owp != NULL && window_pane_is_floating(owp)) {
TAILQ_REMOVE(&w->z_index, wp, zentry); TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry); TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry);
} }
} else if (strcmp(position, "forward-loop") == 0) { } else if (strcmp(position, "forward-loop") == 0) {
owp = TAILQ_PREV(wp, window_panes_zindex, zentry); owp = cmd_join_pane_forward(wp);
while (owp != NULL && owp->layout_cell == NULL) if (owp != NULL) {
owp = TAILQ_PREV(owp, window_panes_zindex, zentry); TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_REMOVE(&w->z_index, wp, zentry);
if (owp != NULL)
TAILQ_INSERT_BEFORE(owp, wp, zentry); TAILQ_INSERT_BEFORE(owp, wp, zentry);
else { } else
TAILQ_FOREACH(owp, &w->z_index, zentry) { window_lower_pane(wp);
if (!window_pane_is_floating_with_hidden(owp))
break;
}
if (owp != NULL)
TAILQ_INSERT_BEFORE(owp, wp, zentry);
else
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
}
} else if (strcmp(position, "backward-loop") == 0) { } else if (strcmp(position, "backward-loop") == 0) {
owp = TAILQ_NEXT(wp, zentry); owp = cmd_join_pane_backward(wp);
while (owp != NULL && owp->layout_cell == NULL) if (owp != NULL) {
owp = TAILQ_NEXT(owp, zentry);
if (owp != NULL && window_pane_is_floating(owp)) {
TAILQ_REMOVE(&w->z_index, wp, zentry); TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry); TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry);
} else { } else
TAILQ_REMOVE(&w->z_index, wp, zentry); window_raise_pane(wp);
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
}
} else { } else {
cmdq_error(item, "unknown position: %s", position); cmdq_error(item, "unknown position: %s", position);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -345,6 +371,7 @@ cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl,
struct window_pane *owp; struct window_pane *owp;
const char *errstr; const char *errstr;
u_int n, z; u_int n, z;
int group;
z = strtonum(s, 0, UINT_MAX, &errstr); z = strtonum(s, 0, UINT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
@@ -353,11 +380,16 @@ cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl,
} }
TAILQ_REMOVE(&w->z_index, wp, zentry); TAILQ_REMOVE(&w->z_index, wp, zentry);
/* The pane stays in front of or behind panes of the other groups. */
group = cmd_join_pane_group(wp);
n = 0; n = 0;
TAILQ_FOREACH(owp, &w->z_index, zentry) { TAILQ_FOREACH(owp, &w->z_index, zentry) {
if (!window_pane_is_floating_with_hidden(owp)) if (cmd_join_pane_group(owp) < group)
continue;
if (cmd_join_pane_group(owp) > group ||
!window_pane_is_raised(owp))
break; break;
if (owp->layout_cell == NULL) if (!window_pane_is_visible(owp))
continue; continue;
if (n >= z) if (n >= z)
break; break;
@@ -386,10 +418,6 @@ cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w,
cmdq_error(item, "pane is not floating"); cmdq_error(item, "pane is not floating");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (w->flags & WINDOW_ZOOMED) {
cmdq_error(item, "can't tile a pane while window is zoomed");
return (CMD_RETURN_ERROR);
}
lc->fg.sx = lc->g.sx; lc->fg.sx = lc->g.sx;
lc->fg.sy = lc->g.sy; lc->fg.sy = lc->g.sy;
@@ -402,8 +430,10 @@ cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w,
} }
lc->flags &= ~LAYOUT_CELL_FLOATING; lc->flags &= ~LAYOUT_CELL_FLOATING;
TAILQ_REMOVE(&w->z_index, wp, zentry); if (~wp->flags & PANE_ZOOMED) {
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
}
if (!args_has(args, 'd')) if (!args_has(args, 'd'))
window_set_active_pane(w, wp, 1); window_set_active_pane(w, wp, 1);
@@ -453,6 +483,12 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "pane is not floating"); cmdq_error(item, "pane is not floating");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
/* Moving unzooms a zoomed pane; reordering does not. */
s = args_get(args, 'P');
if ((dst_wp->flags & PANE_ZOOMED) &&
!args_has(args, 'z') &&
(s == NULL || !cmd_join_pane_is_stacking(s)))
window_unzoom_pane(dst_wp, 1);
if ((s = args_get(args, 'P')) != NULL) if ((s = args_get(args, 'P')) != NULL)
return (cmd_join_pane_place(item, dst_wl, dst_wp, s)); return (cmd_join_pane_place(item, dst_wl, dst_wp, s));
if ((s = args_get(args, 'z')) != NULL) if ((s = args_get(args, 'z')) != NULL)
@@ -470,9 +506,6 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
server_unzoom_window(dst_w);
server_unzoom_window(src_w);
if (src_wp == dst_wp) { if (src_wp == dst_wp) {
if (window_pane_is_floating(src_wp)) if (window_pane_is_floating(src_wp))
return (cmd_join_pane_tile(item, args, src_w, src_wp)); return (cmd_join_pane_tile(item, args, src_w, src_wp));
@@ -504,13 +537,11 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp->window = dst_w; src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options); options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
if (flags & SPAWN_BEFORE) { if (flags & SPAWN_BEFORE)
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry); TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
TAILQ_INSERT_BEFORE(dst_wp, src_wp, zentry); else
} else {
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
TAILQ_INSERT_AFTER(&dst_w->z_index, dst_wp, src_wp, zentry); TAILQ_INSERT_TAIL(&dst_w->z_index, src_wp, zentry);
}
layout_assign_pane(lc, src_wp, 0); layout_assign_pane(lc, src_wp, 0);
colour_palette_from_option(&src_wp->palette, src_wp->options); colour_palette_from_option(&src_wp->palette, src_wp->options);

View File

@@ -78,7 +78,6 @@ cmd_kill_pane_all(struct cmdq_item *item, const char *filter)
struct window_pane *wp = target->wp; struct window_pane *wp = target->wp;
struct window_pane *loopwp, *tmpwp; struct window_pane *loopwp, *tmpwp;
server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) { TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp) if (loopwp == wp)
continue; continue;

View File

@@ -41,8 +41,8 @@ const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane", .name = "resize-pane",
.alias = "resizep", .alias = "resizep",
.args = { "D::L::MR::Tt:U::x:y:Z", 0, 1, NULL }, .args = { "aD::L::MR::Tt:U::x:y:Z", 0, 1, NULL },
.usage = "[-MTZ] [-D lines] [-L columns] [-R columns] [-U lines] " .usage = "[-aMTZ] [-D lines] [-L columns] [-R columns] [-U lines] "
"[-x width] [-y height] " CMD_TARGET_PANE_USAGE, "[-x width] [-y height] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -84,16 +84,17 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
return (cmd_resize_pane_mouse_update(self, item)); return (cmd_resize_pane_mouse_update(self, item));
if (args_has(args, 'Z')) { if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED) if (args_has(args, 'a'))
window_unzoom(w, 1); window_unzoom(w, 1);
else if (wp->flags & PANE_ZOOMED)
window_unzoom_pane(wp, 1);
else else
window_zoom(wp); window_zoom(wp);
server_redraw_window(w); server_redraw_window(w);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (!window_pane_is_floating(wp)) if (wp->flags & PANE_ZOOMED)
server_unzoom_window(w); window_unzoom_pane(wp, 1);
lc = wp->layout_cell; /* may have been replaced by unzoom */
if (args_has(args, 'x')) { if (args_has(args, 'x')) {
x = args_percentage(args, 'x', 0, PANE_MAXIMUM, w->sx, &cause); x = args_percentage(args, 'x', 0, PANE_MAXIMUM, w->sx, &cause);
@@ -207,6 +208,8 @@ cmd_resize_pane_mouse_update(__unused struct cmd *self, struct cmdq_item *item)
if (wp == NULL || c == NULL || c->session != s) if (wp == NULL || c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (wp->flags & PANE_ZOOMED)
return (CMD_RETURN_NORMAL);
if (!window_pane_is_floating(wp)) { if (!window_pane_is_floating(wp)) {
c->tty.mouse_drag_update = cmd_resize_pane_mouse_resize_tiled; c->tty.mouse_drag_update = cmd_resize_pane_mouse_resize_tiled;
cmd_resize_pane_mouse_resize_tiled(c, &event->m); cmd_resize_pane_mouse_resize_tiled(c, &event->m);

View File

@@ -40,77 +40,99 @@ const struct cmd_entry cmd_rotate_window_entry = {
.exec = cmd_rotate_window_exec .exec = cmd_rotate_window_exec
}; };
struct cmd_rotate_window_slot {
struct layout_cell *lc;
int xoff;
int yoff;
u_int sx;
u_int sy;
};
static enum cmd_retval static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item) cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = cmd_get_args(self);
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl; struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp, *wp2; struct window_pane *wp, *zwp = NULL, **all, **tiled;
struct layout_cell *lc; struct window_pane **rotated;
u_int sx, sy, xoff, yoff; struct cmd_rotate_window_slot *slots;
u_int i, j, n = 0, nt = 0;
int active = -1;
window_push_zoom(w, 0, args_has(args, 'Z')); if (args_has(args, 'Z'))
zwp = window_zoomed_pane(w);
if (args_has(args, 'D')) { /*
wp = TAILQ_LAST(&w->panes, window_panes); * Only tiled panes rotate. Floating panes keep their place in the
TAILQ_REMOVE(&w->panes, wp, entry); * list and their cell.
TAILQ_INSERT_HEAD(&w->panes, wp, entry); */
TAILQ_FOREACH(wp, &w->panes, entry)
n++;
all = xcalloc(n, sizeof *all);
tiled = xcalloc(n, sizeof *tiled);
rotated = xcalloc(n, sizeof *rotated);
slots = xcalloc(n, sizeof *slots);
lc = wp->layout_cell; n = 0;
xoff = wp->xoff; yoff = wp->yoff; TAILQ_FOREACH(wp, &w->panes, entry) {
sx = wp->sx; sy = wp->sy; all[n++] = wp;
TAILQ_FOREACH(wp, &w->panes, entry) { if (!layout_cell_is_tiled(wp->layout_cell))
if ((wp2 = TAILQ_NEXT(wp, entry)) == NULL) continue;
break; tiled[nt] = wp;
wp->layout_cell = wp2->layout_cell; slots[nt].lc = wp->layout_cell;
if (wp->layout_cell != NULL) slots[nt].xoff = wp->xoff;
wp->layout_cell->wp = wp; slots[nt].yoff = wp->yoff;
wp->xoff = wp2->xoff; wp->yoff = wp2->yoff; slots[nt].sx = wp->sx;
window_pane_resize(wp, wp2->sx, wp2->sy); slots[nt].sy = wp->sy;
} if (wp == w->active)
wp->layout_cell = lc; active = nt;
if (wp->layout_cell != NULL) nt++;
wp->layout_cell->wp = wp; }
wp->xoff = xoff; wp->yoff = yoff; for (i = 0; i < nt; i++) {
window_pane_resize(wp, sx, sy); if (args_has(args, 'D'))
rotated[i] = tiled[(i + nt - 1) % nt];
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) else
wp = TAILQ_LAST(&w->panes, window_panes); rotated[i] = tiled[(i + 1) % nt];
} else {
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_INSERT_TAIL(&w->panes, wp, entry);
lc = wp->layout_cell;
xoff = wp->xoff; yoff = wp->yoff;
sx = wp->sx; sy = wp->sy;
TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) {
if ((wp2 = TAILQ_PREV(wp, window_panes, entry)) == NULL)
break;
wp->layout_cell = wp2->layout_cell;
if (wp->layout_cell != NULL)
wp->layout_cell->wp = wp;
wp->xoff = wp2->xoff; wp->yoff = wp2->yoff;
window_pane_resize(wp, wp2->sx, wp2->sy);
}
wp->layout_cell = lc;
if (wp->layout_cell != NULL)
wp->layout_cell->wp = wp;
wp->xoff = xoff; wp->yoff = yoff;
window_pane_resize(wp, sx, sy);
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
} }
window_set_active_pane(w, wp, 1); /* Put the rotated panes back into the tiled places in the list. */
cmd_find_from_winlink_pane(current, wl, wp, 0); for (i = 0; i < n; i++)
window_pop_zoom(w); TAILQ_REMOVE(&w->panes, all[i], entry);
for (i = j = 0; i < n; i++) {
if (layout_cell_is_tiled(all[i]->layout_cell))
wp = rotated[j++];
else
wp = all[i];
TAILQ_INSERT_TAIL(&w->panes, wp, entry);
}
/* Each rotated pane takes over the cell of the place it moved to. */
for (i = 0; i < nt; i++) {
wp = rotated[i];
wp->layout_cell = slots[i].lc;
wp->layout_cell->wp = wp;
wp->xoff = slots[i].xoff;
wp->yoff = slots[i].yoff;
window_pane_resize(wp, slots[i].sx, slots[i].sy);
}
if (active != -1) {
wp = rotated[active];
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
if (zwp != NULL)
window_zoom_move(zwp, wp);
}
redraw_invalidate_scene(w); redraw_invalidate_scene(w);
server_redraw_window(w); server_redraw_window(w);
free(all);
free(tiled);
free(rotated);
free(slots);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -155,7 +155,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
struct winlink *wl = target->wl; struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = target->s; struct session *s = target->s;
struct window_pane *wp = target->wp, *lastwp; struct window_pane *wp = target->wp, *lastwp, *zwp = NULL;
struct options *oo = wp->options; struct options *oo = wp->options;
char *title; char *title;
const char *style; const char *style;
@@ -190,15 +190,17 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
visible = 1; visible = 1;
else else
visible = window_pane_is_visible(lastwp); visible = window_pane_is_visible(lastwp);
if (!visible && window_push_zoom(w, 0, Zflag)) if (!visible && Zflag)
server_redraw_window(w); zwp = window_zoomed_pane(w);
window_redraw_active_switch(w, lastwp); window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp, 1)) { if (window_set_active_pane(w, lastwp, 1)) {
cmd_find_from_winlink(current, wl, 0); cmd_find_from_winlink(current, wl, 0);
cmd_select_pane_redraw(w); cmd_select_pane_redraw(w);
} }
if (!visible && window_pop_zoom(w)) if (zwp != NULL) {
window_zoom_move(zwp, lastwp);
server_redraw_window(w); server_redraw_window(w);
}
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -221,23 +223,14 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'L')) { if (args_has(args, 'L'))
window_push_zoom(w, 0, 1);
wp = window_pane_find_left(wp); wp = window_pane_find_left(wp);
window_pop_zoom(w); else if (args_has(args, 'R'))
} else if (args_has(args, 'R')) {
window_push_zoom(w, 0, 1);
wp = window_pane_find_right(wp); wp = window_pane_find_right(wp);
window_pop_zoom(w); else if (args_has(args, 'U'))
} else if (args_has(args, 'U')) {
window_push_zoom(w, 0, 1);
wp = window_pane_find_up(wp); wp = window_pane_find_up(wp);
window_pop_zoom(w); else if (args_has(args, 'D'))
} else if (args_has(args, 'D')) {
window_push_zoom(w, 0, 1);
wp = window_pane_find_down(wp); wp = window_pane_find_down(wp);
window_pop_zoom(w);
}
if (wp == NULL) if (wp == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -277,15 +270,17 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
visible = 1; visible = 1;
else else
visible = window_pane_is_visible(wp); visible = window_pane_is_visible(wp);
if (!visible && window_push_zoom(w, 0, Zflag)) if (!visible && Zflag)
server_redraw_window(w); zwp = window_zoomed_pane(w);
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp, 1)) if (window_set_active_pane(w, wp, 1))
cmd_find_from_winlink_pane(current, wl, wp, 0); cmd_find_from_winlink_pane(current, wl, wp, 0);
cmdq_insert_hook(s, item, current, "after-select-pane"); cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w); cmd_select_pane_redraw(w);
if (!visible && window_pop_zoom(w)) if (zwp != NULL) {
window_zoom_move(zwp, wp);
server_redraw_window(w); server_redraw_window(w);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -89,7 +89,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_state fs; struct cmd_find_state fs;
struct key_event *event = cmdq_get_event(item); struct key_event *event = cmdq_get_event(item);
int input, empty, is_floating, flags = 0; int input, empty, is_floating, flags = 0;
int restore_zoom = 0;
const char *template, *style, *value; const char *template, *style, *value;
char *cause = NULL, *cp, *title; char *cause = NULL, *cp, *title;
const struct options_table_entry *oe; const struct options_table_entry *oe;
@@ -97,16 +96,9 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
enum pane_lines lines; enum pane_lines lines;
u_int count = args_count(args); u_int count = args_count(args);
if (window_active_pane_is_over_zoom(w))
restore_zoom = 1;
if (cmd_get_entry(self) == &cmd_new_pane_entry) if (cmd_get_entry(self) == &cmd_new_pane_entry)
is_floating = !args_has(args, 'L'); is_floating = !args_has(args, 'L');
else { else {
if (!window_pane_is_visible(wp))
restore_zoom = 0;
if (!restore_zoom)
window_unzoom(w, 1);
is_floating = window_pane_is_floating(wp); is_floating = window_pane_is_floating(wp);
flags |= SPAWN_SPLIT; flags |= SPAWN_SPLIT;
} }
@@ -143,8 +135,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
flags |= SPAWN_MODAL|SPAWN_FLOATOVERZOOM; flags |= SPAWN_MODAL|SPAWN_FLOATOVERZOOM;
if (is_floating && args_has(args, 'A')) if (is_floating && args_has(args, 'A'))
flags |= SPAWN_FLOATOVERZOOM; flags |= SPAWN_FLOATOVERZOOM;
if ((w->flags & WINDOW_ZOOMED) && (flags & SPAWN_FLOATOVERZOOM))
restore_zoom = 1;
input = args_has(args, 'I'); input = args_has(args, 'I');
if (input || (count == 1 && *args_string(args, 0) == '\0')) if (input || (count == 1 && *args_string(args, 0) == '\0'))
@@ -180,8 +170,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
if (restore_zoom)
window_pop_zoom(w);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -288,13 +276,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (~flags & SPAWN_DETACHED) if (~flags & SPAWN_DETACHED)
cmd_find_from_winlink_pane(current, wl, new_wp, 0); cmd_find_from_winlink_pane(current, wl, new_wp, 0);
if (restore_zoom) {
window_pop_zoom(wp->window);
server_redraw_window(wp->window);
} else if ((~flags & SPAWN_FLOATING) && !args_has(args, 'O')) {
window_pop_zoom(wp->window);
server_redraw_window(wp->window);
}
server_redraw_session(s); server_redraw_session(s);
if (args_has(args, 'M') && is_floating) { if (args_has(args, 'M') && is_floating) {
@@ -343,8 +324,6 @@ fail:
layout_close_pane(new_wp); layout_close_pane(new_wp);
window_remove_pane(wp->window, new_wp); window_remove_pane(wp->window, new_wp);
} }
if (restore_zoom || (~flags & SPAWN_FLOATING))
window_pop_zoom(wp->window);
if (sc.argv != NULL) if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv); cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ); environ_free(sc.environ);

View File

@@ -68,7 +68,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
struct window_pane *tmp_wp, *src_wp, *dst_wp; struct window_pane *tmp_wp, *src_wp, *dst_wp;
struct layout_cell *src_lc, *dst_lc; struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
int src_idx, dst_idx; int src_idx, dst_idx, src_zoomed, dst_zoomed;
dst_w = target->wl->window; dst_w = target->wl->window;
dst_wp = target->wp; dst_wp = target->wp;
@@ -82,8 +82,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (window_push_zoom(dst_w, 0, args_has(args, 'Z'))) dst_zoomed = (args_has(args, 'Z') && (dst_w->flags & WINDOW_ZOOMED));
server_redraw_window(dst_w);
if (args_has(args, 'D')) { if (args_has(args, 'D')) {
if (window_pane_is_floating(dst_wp)) { if (window_pane_is_floating(dst_wp)) {
@@ -111,8 +110,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
} }
if (src_w != dst_w && window_push_zoom(src_w, 0, args_has(args, 'Z'))) src_zoomed = (args_has(args, 'Z') && (src_w->flags & WINDOW_ZOOMED));
server_redraw_window(src_w);
if (src_wp == dst_wp) if (src_wp == dst_wp)
goto out; goto out;
@@ -140,6 +138,12 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
else else
TAILQ_INSERT_AFTER(&dst_w->z_index, tmp_wp, src_wp, zentry); TAILQ_INSERT_AFTER(&dst_w->z_index, tmp_wp, src_wp, zentry);
/* Zoom belongs to the position in the window, like the cell. */
if ((src_wp->flags ^ dst_wp->flags) & PANE_ZOOMED) {
src_wp->flags ^= PANE_ZOOMED;
dst_wp->flags ^= PANE_ZOOMED;
}
src_lc = src_wp->layout_cell; src_lc = src_wp->layout_cell;
dst_lc = dst_wp->layout_cell; dst_lc = dst_wp->layout_cell;
src_lc->wp = dst_wp; src_lc->wp = dst_wp;
@@ -197,9 +201,16 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
events_fire_window("window-layout-changed", dst_w); events_fire_window("window-layout-changed", dst_w);
out: out:
if (window_pop_zoom(src_w)) /* With -Z, leave the active pane zoomed if the window was. */
server_redraw_window(src_w); if (src_zoomed) {
if (src_w != dst_w && window_pop_zoom(dst_w)) window_unzoom(src_w, 1);
server_redraw_window(dst_w); if (src_w->active != NULL)
window_zoom(src_w->active);
}
if (src_w != dst_w && dst_zoomed) {
window_unzoom(dst_w, 1);
if (dst_w->active != NULL)
window_zoom(dst_w->active);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -59,7 +59,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp, *zwp = NULL;
const char *tablename; const char *tablename;
struct key_table *table; struct key_table *table;
struct sort_criteria sort_crit; struct sort_criteria sort_crit;
@@ -143,12 +143,14 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
visible = 1; visible = 1;
else else
visible = window_pane_is_visible(wp); visible = window_pane_is_visible(wp);
if (!visible && window_push_zoom(w, 0, Zflag)) if (!visible && Zflag)
server_redraw_window(w); zwp = window_zoomed_pane(w);
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1); window_set_active_pane(w, wp, 1);
if (!visible && window_pop_zoom(w)) if (zwp != NULL) {
window_zoom_move(zwp, wp);
server_redraw_window(w); server_redraw_window(w);
}
} }
if (wl != NULL) { if (wl != NULL) {
session_set_current(s, wl); session_set_current(s, wl);

View File

@@ -866,10 +866,7 @@ format_cb_window_layout(struct format_tree *ft)
if (w == NULL) if (w == NULL)
return (NULL); return (NULL);
if (w->saved_layout_root != NULL) lcroot = w->layout_root;
lcroot = w->saved_layout_root;
else
lcroot = w->layout_root;
if (c != NULL && if (c != NULL &&
(c->flags & CLIENT_CONTROL) && (c->flags & CLIENT_CONTROL) &&
@@ -893,7 +890,7 @@ format_cb_window_visible_layout(struct format_tree *ft)
(c->flags & CLIENT_CONTROL) && (c->flags & CLIENT_CONTROL) &&
(~c->flags & CLIENT_CONTROL_NEWLAYOUTS)) (~c->flags & CLIENT_CONTROL_NEWLAYOUTS))
flags |= LAYOUT_CUSTOM_OLD_FORMAT; flags |= LAYOUT_CUSTOM_OLD_FORMAT;
return (layout_dump(w, w->layout_root, flags)); return (layout_dump_visible(w, flags));
} }
/* Callback for pane_start_command. */ /* Callback for pane_start_command. */
@@ -2706,36 +2703,12 @@ static void *
format_cb_pane_unzoomed_height(struct format_tree *ft) format_cb_pane_unzoomed_height(struct format_tree *ft)
{ {
struct window_pane *wp = ft->wp; struct window_pane *wp = ft->wp;
struct window *w; int xoff, yoff;
struct layout_cell *lc, *root; u_int sx, sy;
int status, floating;
u_int sy;
if (wp == NULL) if (wp == NULL || wp->layout_cell == NULL)
return (NULL); return (NULL);
w = wp->window; layout_get_pane_geometry(wp, 1, &xoff, &yoff, &sx, &sy);
lc = wp->saved_layout_cell;
if (lc == NULL)
lc = wp->layout_cell;
if (lc == NULL)
return (NULL);
sy = lc->g.sy;
floating = (lc->flags & LAYOUT_CELL_FLOATING);
root = w->saved_layout_root;
if (root == NULL)
root = w->layout_root;
if (lc == wp->saved_layout_cell && !floating)
status = window_get_pane_status(w);
else
status = window_pane_get_pane_status(wp);
if (!floating &&
root != NULL &&
layout_add_horizontal_border(root, lc, status) &&
sy > 1)
sy--;
return (format_printf("%u", sy)); return (format_printf("%u", sy));
} }
@@ -2744,36 +2717,12 @@ static void *
format_cb_pane_unzoomed_width(struct format_tree *ft) format_cb_pane_unzoomed_width(struct format_tree *ft)
{ {
struct window_pane *wp = ft->wp; struct window_pane *wp = ft->wp;
struct layout_cell *lc; int xoff, yoff;
int saved, sb_w, sb_pad; u_int sx, sy;
u_int sx;
if (wp == NULL) if (wp == NULL || wp->layout_cell == NULL)
return (NULL); return (NULL);
layout_get_pane_geometry(wp, 1, &xoff, &yoff, &sx, &sy);
lc = wp->saved_layout_cell;
saved = (lc != NULL);
if (lc == NULL)
lc = wp->layout_cell;
if (lc == NULL)
return (NULL);
sx = lc->g.sx;
if ((saved && !SCREEN_IS_ALTERNATE(&wp->base) &&
wp->window->sb == PANE_SCROLLBARS_ALWAYS) ||
(!saved && window_pane_scrollbar_reserve(wp))) {
sb_w = wp->scrollbar_style.width;
sb_pad = wp->scrollbar_style.pad;
if (sb_w < 1)
sb_w = 1;
if (sb_pad < 0)
sb_pad = 0;
if ((int)sx - sb_w - sb_pad < PANE_MINIMUM)
sx = PANE_MINIMUM;
else
sx -= sb_w + sb_pad;
}
return (format_printf("%u", sx)); return (format_printf("%u", sx));
} }

View File

@@ -307,32 +307,68 @@ bad:
return (xstrdup("0000,")); return (xstrdup("0000,"));
} }
/*
* Dump the layout as it is seen while a pane is zoomed: the zoomed pane fills
* the window with the floating panes in front of it. The cells are temporary
* and do not belong to the panes.
*/
char *
layout_dump_visible(struct window *w, int flags)
{
struct window_pane *zwp = window_zoomed_pane(w), *wp;
struct layout_cell *root, *lc, *lcnext;
char *out;
if (zwp == NULL)
return (layout_dump(w, w->layout_root, flags));
root = layout_create_cell(NULL);
layout_set_size(root, w->sx, w->sy, 0, 0);
root->wp = zwp;
TAILQ_FOREACH(wp, &w->z_index, zentry) {
if (wp == zwp)
break;
if (!window_pane_is_unzoomed_float(wp) ||
!window_pane_is_visible(wp))
continue;
if (root->type == LAYOUT_WINDOWPANE) {
lc = layout_create_cell(root);
layout_set_size(lc, w->sx, w->sy, 0, 0);
lc->wp = zwp;
root->wp = NULL;
root->type = LAYOUT_TOPBOTTOM;
TAILQ_INSERT_TAIL(&root->cells, lc, entry);
}
lc = layout_create_cell(root);
memcpy(&lc->g, &wp->layout_cell->g, sizeof lc->g);
lc->flags |= LAYOUT_CELL_FLOATING;
lc->wp = wp;
TAILQ_INSERT_TAIL(&root->cells, lc, entry);
}
out = layout_dump(w, root, flags);
if (root->type != LAYOUT_WINDOWPANE) {
TAILQ_FOREACH_SAFE(lc, &root->cells, entry, lcnext) {
TAILQ_REMOVE(&root->cells, lc, entry);
free(lc);
}
}
free(root);
return (out);
}
/* Get a floating pane cell's z-index in the layout being dumped. */ /* Get a floating pane cell's z-index in the layout being dumped. */
static u_int static u_int
layout_cell_zindex(struct layout_cell *lc) layout_cell_zindex(struct layout_cell *lc)
{ {
struct window_pane *wp = lc->wp, *wq; struct window_pane *wp = lc->wp, *wq;
struct window *w = wp->window; struct window *w = wp->window;
struct layout_cell *other;
int saved = (lc == wp->saved_layout_cell);
u_int i = 0; u_int i = 0;
if (saved &&
w->active != NULL &&
(w->active->flags & PANE_ZOOMED) &&
(w->active->saved_layout_cell->flags & LAYOUT_CELL_FLOATING)) {
if (wp == w->active)
return (0);
i++;
}
TAILQ_FOREACH(wq, &w->z_index, zentry) { TAILQ_FOREACH(wq, &w->z_index, zentry) {
if (wq == wp) if (wq == wp)
break; break;
if (saved) if (window_pane_is_floating(wq))
other = wq->saved_layout_cell;
else
other = wq->layout_cell;
if (other != NULL && (other->flags & LAYOUT_CELL_FLOATING))
i++; i++;
} }
return (i); return (i);

129
layout.c
View File

@@ -415,18 +415,89 @@ layout_add_horizontal_border(struct layout_cell *root, struct layout_cell *lc,
return (0); return (0);
} }
/*
* Work out the offset and size a pane should have from its cell. A zoomed pane
* fills the window unless layout is set, which gives the place it has in the
* layout.
*/
void
layout_get_pane_geometry(struct window_pane *wp, int layout, int *xoff,
int *yoff, u_int *sx, u_int *sy)
{
struct window *w = wp->window;
struct layout_cell *lc = wp->layout_cell;
int status, sb_w, sb_pad, border, reserve;
if (layout && !window_pane_is_floating(wp))
status = window_get_pane_status(w);
else
status = window_pane_get_pane_status(wp);
if ((wp->flags & PANE_ZOOMED) && !layout) {
/* A zoomed pane fills the window, whatever its cell. */
*xoff = 0;
*yoff = 0;
*sx = w->sx;
*sy = w->sy;
border = (status == PANE_STATUS_TOP ||
status == PANE_STATUS_BOTTOM);
} else {
*xoff = lc->g.xoff;
*yoff = lc->g.yoff;
*sx = lc->g.sx;
*sy = lc->g.sy;
border = (!window_pane_is_floating(wp) &&
layout_add_horizontal_border(w->layout_root, lc, status));
}
if (border) {
if (status == PANE_STATUS_TOP)
(*yoff)++;
if (*sy > 1)
(*sy)--;
}
/*
* The layout ignores anything a mode does to the scrollbars while the
* window is zoomed.
*/
if (layout && (w->flags & WINDOW_ZOOMED))
reserve = (!SCREEN_IS_ALTERNATE(&wp->base) &&
w->sb == PANE_SCROLLBARS_ALWAYS);
else
reserve = window_pane_scrollbar_reserve(wp);
if (reserve) {
sb_w = wp->scrollbar_style.width;
sb_pad = wp->scrollbar_style.pad;
if (sb_w < 1)
sb_w = 1;
if (sb_pad < 0)
sb_pad = 0;
if (w->sb_pos == PANE_SCROLLBARS_LEFT) {
if ((int)*sx - sb_w - sb_pad < PANE_MINIMUM) {
*xoff = *xoff + (int)*sx - PANE_MINIMUM;
*sx = PANE_MINIMUM;
} else {
*sx = *sx - sb_w - sb_pad;
*xoff = *xoff + sb_w + sb_pad;
}
} else /* sb_pos == PANE_SCROLLBARS_RIGHT */
if ((int)*sx - sb_w - sb_pad < PANE_MINIMUM)
*sx = PANE_MINIMUM;
else
*sx = *sx - sb_w - sb_pad;
}
}
/* Update pane offsets and sizes based on their cells. */ /* Update pane offsets and sizes based on their cells. */
void void
layout_fix_panes(struct window *w, struct window_pane *skip) layout_fix_panes(struct window *w, struct window_pane *skip)
{ {
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc, *root = w->layout_root;
int status, sb_w, sb_pad;
int old_xoff, old_yoff, changed = 0; int old_xoff, old_yoff, changed = 0;
u_int sx, sy, old_sx, old_sy; u_int old_sx, old_sy, sx, sy;
int xoff, yoff;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if ((lc = wp->layout_cell) == NULL || wp == skip) if (wp->layout_cell == NULL || wp == skip)
continue; continue;
old_xoff = wp->xoff; old_xoff = wp->xoff;
@@ -434,43 +505,11 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
old_sx = wp->sx; old_sx = wp->sx;
old_sy = wp->sy; old_sy = wp->sy;
wp->xoff = lc->g.xoff; layout_get_pane_geometry(wp, 0, &xoff, &yoff, &sx, &sy);
wp->yoff = lc->g.yoff; wp->xoff = xoff;
sx = lc->g.sx; wp->yoff = yoff;
sy = lc->g.sy; if (window_pane_scrollbar_reserve(wp))
status = window_pane_get_pane_status(wp);
if (!window_pane_is_floating(wp) &&
layout_add_horizontal_border(root, lc, status)) {
if (status == PANE_STATUS_TOP)
wp->yoff++;
if (sy > 1)
sy--;
}
if (window_pane_scrollbar_reserve(wp)) {
sb_w = wp->scrollbar_style.width;
sb_pad = wp->scrollbar_style.pad;
if (sb_w < 1)
sb_w = 1;
if (sb_pad < 0)
sb_pad = 0;
if (w->sb_pos == PANE_SCROLLBARS_LEFT) {
if ((int)sx - sb_w - sb_pad < PANE_MINIMUM) {
wp->xoff = wp->xoff +
(int)sx - PANE_MINIMUM;
sx = PANE_MINIMUM;
} else {
sx = sx - sb_w - sb_pad;
wp->xoff = wp->xoff + sb_w + sb_pad;
}
} else /* sb_pos == PANE_SCROLLBARS_RIGHT */
if ((int)sx - sb_w - sb_pad < PANE_MINIMUM)
sx = PANE_MINIMUM;
else
sx = sx - sb_w - sb_pad;
wp->flags |= PANE_REDRAWSCROLLBAR; wp->flags |= PANE_REDRAWSCROLLBAR;
}
window_pane_resize(wp, sx, sy); window_pane_resize(wp, sx, sy);
@@ -1683,10 +1722,6 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
return (NULL); return (NULL);
} }
if (window_active_pane_is_over_zoom(w))
window_push_zoom(w, 0, 1);
else
window_push_zoom(w, 1, (flags & SPAWN_ZOOM));
lc = layout_split_pane(wp, type, size, flags); lc = layout_split_pane(wp, type, size, flags);
if (lc == NULL) if (lc == NULL)
*cause = xstrdup("no space for a new pane"); *cause = xstrdup("no space for a new pane");
@@ -1713,12 +1748,6 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args,
return (NULL); return (NULL);
} }
if (flags & SPAWN_FLOATOVERZOOM)
window_push_zoom(wp->window, 0, 1);
else if (window_active_pane_is_over_zoom(w))
window_push_zoom(wp->window, 0, 1);
else
window_push_zoom(wp->window, 1, (flags & SPAWN_ZOOM));
lcnew = layout_floating_pane(w, wp, &fg); lcnew = layout_floating_pane(w, wp, &fg);
return (lcnew); return (lcnew);
} }

View File

@@ -621,7 +621,7 @@ mode_tree_zoom(struct mode_tree_data *mtd, struct args *args)
struct window_pane *wp = mtd->wp; struct window_pane *wp = mtd->wp;
if (args_has(args, 'Z')) { if (args_has(args, 'Z')) {
mtd->zoomed = (wp->window->flags & WINDOW_ZOOMED); mtd->zoomed = (wp->flags & PANE_ZOOMED);
if (!mtd->zoomed && window_zoom(wp) == 0) if (!mtd->zoomed && window_zoom(wp) == 0)
server_redraw_window(wp->window); server_redraw_window(wp->window);
} else } else
@@ -710,8 +710,8 @@ mode_tree_free(struct mode_tree_data *mtd)
{ {
struct window_pane *wp = mtd->wp; struct window_pane *wp = mtd->wp;
if (mtd->zoomed == 0) if (mtd->zoomed == 0 && window_unzoom_pane(wp, 1) == 0)
server_unzoom_window(wp->window); server_redraw_window(wp->window);
mode_tree_clear_prompt(mtd); mode_tree_clear_prompt(mtd);
mode_tree_free_items(&mtd->children); mode_tree_free_items(&mtd->children);

View File

@@ -72,6 +72,9 @@ static const char *options_table_pane_scrollbars_position_list[] = {
static const char *options_table_pane_status_list[] = { static const char *options_table_pane_status_list[] = {
"off", "top", "bottom", "top-floating", "bottom-floating", NULL "off", "top", "bottom", "top-floating", "bottom-floating", NULL
}; };
static const char *options_table_pane_raise_on_focus_list[] = {
"floating", "all", "off", NULL
};
static const char *options_table_pane_border_indicators_list[] = { static const char *options_table_pane_border_indicators_list[] = {
"off", "colour", "arrows", "both", NULL "off", "colour", "arrows", "both", NULL
}; };
@@ -1631,6 +1634,16 @@ const struct options_table_entry options_table[] = {
.text = "The default colour palette for colours zero to 255." .text = "The default colour palette for colours zero to 255."
}, },
{ .name = "pane-raise-on-focus",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_pane_raise_on_focus_list,
.default_num = PANE_RAISE_FLOATING,
.text = "Which panes are raised to the front when they are made "
"active: floating panes only, floating and zoomed panes, or "
"none."
},
{ .name = "pane-scrollbars", { .name = "pane-scrollbars",
.type = OPTIONS_TABLE_CHOICE, .type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,

View File

@@ -56,6 +56,7 @@ for mode in before after detached modal; do
-x 20 -y 8 -X 8 -Y 3 '') || exit 1 -x 20 -y 8 -X 8 -Y 3 '') || exit 1
if [ "$mode" = before ]; then if [ "$mode" = before ]; then
run resize-pane -Z -t "$base" run resize-pane -Z -t "$base"
run select-pane -t "$float"
fi fi
run set -gu @unzoomed run set -gu @unzoomed
check_zoom check_zoom
@@ -131,28 +132,29 @@ for z in 1 0 99; do
check_zoom check_zoom
done done
run resize-pane -Z -t "$base" run resize-pane -Z -t "$base"
check "$float" '#{pane_z}' 2 check "$float" '#{pane_z}' 1
check "$hidden" '#{pane_z}' 2
check "$base" '#{pane_z}' 4 check "$base" '#{pane_z}' 4
run kill-pane -t "$hidden" run kill-pane -t "$hidden"
run kill-pane -t "$back" run kill-pane -t "$back"
# Explicit zoom toggling and operations on tiled panes retain their # Zooming a float keeps it floating. Resizing a zoomed float unzooms just that
# existing behaviour. The over-zoom flag alone does not make a pane a float: # pane, but operations on other panes leave a zoom alone.
# zooming the float itself gives it a tiled cell until unzoom.
run resize-pane -Z -t "$float" run resize-pane -Z -t "$float"
check "$float" '#{pane_zoomed_flag}:#{pane_floating_flag}' '1:0' check "$float" '#{pane_zoomed_flag}:#{pane_floating_flag}' '1:1'
run resize-pane -t "$float" -x 25 run resize-pane -t "$float" -x 25
check "$float" '#{window_zoomed_flag}:#{pane_floating_flag}:#{pane_width}' \ check "$float" '#{window_zoomed_flag}:#{pane_floating_flag}:#{pane_width}' \
'0:1:23' '0:1:23'
run resize-pane -Z -t "$base" run resize-pane -Z -t "$base"
run resize-pane -t "$other" -D 1 run resize-pane -t "$other" -D 1
check "$base" '#{window_zoomed_flag}' 0 check "$base" '#{window_zoomed_flag}' 1
run resize-pane -Z -t "$base"
# A hidden ordinary float must still be unzoomed before resizing it. # A float covered by a zoom can be resized without unzooming.
hidden=$(run new-pane -dPF '#{pane_id}' -t "$base" '') || exit 1 hidden=$(run new-pane -dPF '#{pane_id}' -t "$base" '') || exit 1
run resize-pane -Z -t "$base" run resize-pane -Z -t "$base"
run resize-pane -t "$hidden" -x 25 run resize-pane -t "$hidden" -x 25
check "$hidden" '#{window_zoomed_flag}:#{pane_floating_flag}:#{pane_width}' \ check "$hidden" '#{window_zoomed_flag}:#{pane_floating_flag}:#{pane_width}' \
'0:1:23' '1:1:23'
exit 0 exit 0

View File

@@ -537,8 +537,8 @@ case "$(fmt "$ignored" '#{pane_flags}')" in
*) ;; *) ;;
esac esac
# Existing floating panes are filtered when zoom begins: -A panes remain in the # Existing floating panes stay floating when zoom begins: -A panes remain above
# visible layout and ordinary floating panes do not. # the zoom and ordinary floating panes are covered by it.
check_ok new-window -d -t modal: -n existing-over-zoom 'cat' check_ok new-window -d -t modal: -n existing-over-zoom 'cat'
base=$(fmt modal:existing-over-zoom '#{pane_id}') base=$(fmt modal:existing-over-zoom '#{pane_id}')
check_ok split-window -dh -t "$base" 'cat' check_ok split-window -dh -t "$base" 'cat'
@@ -552,10 +552,10 @@ check_ok select-window -t modal:existing-over-zoom
check_ok select-pane -t "$base" check_ok select-pane -t "$base"
check_ok resize-pane -Z -t "$base" check_ok resize-pane -Z -t "$base"
must_equal "$(fmt "$over" '#{pane_floating_flag}')" 1 must_equal "$(fmt "$over" '#{pane_floating_flag}')" 1
must_equal "$(fmt "$under" '#{pane_floating_flag}')" 0 must_equal "$(fmt "$under" '#{pane_floating_flag}')" 1
must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 1:1 must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 1:1
# Geometry changed in the visible zoom layout is copied back when unzooming. # Geometry changed while zoomed is kept when unzooming.
check_ok select-pane -t "$over" check_ok select-pane -t "$over"
left=$(fmt "$over" '#{pane_left}') left=$(fmt "$over" '#{pane_left}')
top=$(fmt "$over" '#{pane_top}') top=$(fmt "$over" '#{pane_top}')
@@ -593,8 +593,8 @@ done
must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 1:1 must_equal "$(fmt "$base" '#{window_zoomed_flag}:#{pane_zoomed_flag}')" 1:1
# A pane with -A is also above a zoom target which was itself floating. The # A pane with -A is also above a zoom target which was itself floating. The
# temporary tiled target must sit behind retained floating panes, then return # target must sit behind the -A pane, then return to the normal floating z
# to the normal floating z order when unzoomed. # order when unzoomed.
check_ok new-window -d -t modal: -n floating-zoom-target 'cat' check_ok new-window -d -t modal: -n floating-zoom-target 'cat'
base=$(fmt modal:floating-zoom-target '#{pane_id}') base=$(fmt modal:floating-zoom-target '#{pane_id}')
check_ok split-window -dh -t "$base" 'cat' check_ok split-window -dh -t "$base" 'cat'
@@ -606,13 +606,13 @@ over=$($TMUX new-pane -AdPF '#{pane_id}' -t "$base" \
fail "float-over-zoom pane creation failed" fail "float-over-zoom pane creation failed"
check_ok select-window -t modal:floating-zoom-target check_ok select-window -t modal:floating-zoom-target
check_ok select-pane -t "$target" check_ok select-pane -t "$target"
must_equal "$(fmt "$target" '#{pane_z}')" 0 must_equal "$(fmt "$target" '#{pane_z}')" 1
must_equal "$(fmt "$over" '#{pane_z}')" 1 must_equal "$(fmt "$over" '#{pane_z}')" 0
check_ok resize-pane -Z -t "$target" check_ok resize-pane -Z -t "$target"
must_equal "$(fmt "$target" \ must_equal "$(fmt "$target" \
'#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_floating_flag}:#{pane_z}')" \ '#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_floating_flag}:#{pane_z}')" \
1:1:0:2 1:1:1:1
must_equal "$(fmt "$over" '#{pane_floating_flag}:#{pane_z}')" 1:0 must_equal "$(fmt "$over" '#{pane_floating_flag}:#{pane_z}')" 1:0
check_ok select-pane -t "$over" check_ok select-pane -t "$over"
must_equal "$(fmt "$over" '#{window_zoomed_flag}:#{pane_active}')" 1:1 must_equal "$(fmt "$over" '#{window_zoomed_flag}:#{pane_active}')" 1:1
@@ -620,13 +620,14 @@ check_ok resize-pane -Z -t "$target"
must_equal "$(fmt "$over" '#{pane_active}:#{pane_z}')" 1:0 must_equal "$(fmt "$over" '#{pane_active}:#{pane_z}')" 1:0
must_equal "$(fmt "$target" '#{pane_floating_flag}:#{pane_z}')" 1:1 must_equal "$(fmt "$target" '#{pane_floating_flag}:#{pane_z}')" 1:1
# If the target remains active, it returns to the front on unzoom. # A pane with -A stays in front of the target, even when the target is active
# and is zoomed and unzoomed again.
check_ok select-pane -t "$target" check_ok select-pane -t "$target"
check_ok resize-pane -Z -t "$target" check_ok resize-pane -Z -t "$target"
must_equal "$(fmt "$over" '#{pane_floating_flag}:#{pane_z}')" 1:0 must_equal "$(fmt "$over" '#{pane_floating_flag}:#{pane_z}')" 1:0
check_ok resize-pane -Z -t "$target" check_ok resize-pane -Z -t "$target"
must_equal "$(fmt "$target" '#{pane_active}:#{pane_z}')" 1:0 must_equal "$(fmt "$target" '#{pane_active}:#{pane_z}')" 1:1
must_equal "$(fmt "$over" '#{pane_z}')" 1 must_equal "$(fmt "$over" '#{pane_z}')" 0
cleanup cleanup
exit 0 exit 0

View File

@@ -166,7 +166,8 @@ check_panes P:0 "0:$p3 1:$p0 2:$p2 3:$p1"
# break-pane and join-pane. # break-pane and join-pane.
# break-pane moves a pane to a new window; -P -F prints where it went and -n # break-pane moves a pane to a new window; -P -F prints where it went and -n
# names the new window. Moving a pane out of a zoomed window unzooms it first. # names the new window. Moving another pane out of a zoomed window leaves the
# zoom alone.
check_ok resize-pane -Z -t "$p0" check_ok resize-pane -Z -t "$p0"
out=$($TMUX break-pane -d -P -F '#{window_index}:#{pane_id}' -n broken \ out=$($TMUX break-pane -d -P -F '#{window_index}:#{pane_id}' -n broken \
-s "$p1" -t P:) -s "$p1" -t P:)
@@ -176,13 +177,14 @@ if [ "$out" != "1:$p1" ]; then
fi fi
check_fmt 'P:1' '#{window_name}:#{window_panes}' 'broken:1' check_fmt 'P:1' '#{window_name}:#{window_panes}' 'broken:1'
check_fmt 'P:0' '#{window_panes}' '3' check_fmt 'P:0' '#{window_panes}' '3'
check_fmt 'P:0' '#{window_zoomed_flag}' '0' check_fmt 'P:0' '#{window_zoomed_flag}' '1'
# join-pane -v moves it back (the source window, left empty, is destroyed) and # join-pane -v moves it back (the source window, left empty, is destroyed) and
# also unzooms the destination before changing its layout. # also leaves the destination zoomed while changing its layout.
check_ok resize-pane -Z -t "$p0"
check_ok join-pane -d -v -s P:broken.0 -t "$p2" check_ok join-pane -d -v -s P:broken.0 -t "$p2"
check_fmt 'P:0' '#{window_panes}' '4' check_fmt 'P:0' '#{window_panes}' '4'
check_fmt 'P:0' '#{window_zoomed_flag}' '1'
check_ok resize-pane -Z -t "$p0"
check_fmt 'P:0' '#{window_zoomed_flag}' '0' check_fmt 'P:0' '#{window_zoomed_flag}' '0'
if $TMUX has-session -t P:broken 2>/dev/null; then if $TMUX has-session -t P:broken 2>/dev/null; then
echo "Window 'broken' still exists after join-pane." echo "Window 'broken' still exists after join-pane."
@@ -317,14 +319,23 @@ check_fmt "$p0" '#{window_zoomed_flag}:#{pane_width}x#{pane_height}' \
check_ok resize-pane -Z -t "$p0" check_ok resize-pane -Z -t "$p0"
check_fmt "$p0" '#{window_zoomed_flag}' '0' check_fmt "$p0" '#{window_zoomed_flag}' '0'
# Splitting while zoomed unzooms first. # Splitting while zoomed with -d leaves the zoom alone; without -d the new
# pane is active and covered, so selecting it unzooms.
check_ok resize-pane -Z -t "$p0" check_ok resize-pane -Z -t "$p0"
check_fmt 'P:0' '#{window_zoomed_flag}' '1' check_fmt 'P:0' '#{window_zoomed_flag}' '1'
check_ok split-window -d -v -t "$p0" check_ok split-window -d -v -t "$p0"
check_fmt 'P:0' '#{window_zoomed_flag}' '0' check_fmt 'P:0' '#{window_zoomed_flag}' '1'
check_fmt 'P:0' '#{window_panes}' '5' check_fmt 'P:0' '#{window_panes}' '5'
p6=$($TMUX display-message -p -t P:0.2 '#{pane_id}') p6=$($TMUX display-message -p -t P:0.2 '#{pane_id}')
check_ok kill-pane -t "$p6" check_ok kill-pane -t "$p6"
check_fmt 'P:0' '#{window_zoomed_flag}' '1'
check_ok resize-pane -Z -t "$p0"
check_fmt 'P:0' '#{window_zoomed_flag}' '0'
check_ok resize-pane -Z -t "$p0"
check_ok split-window -v -t "$p0"
check_fmt 'P:0' '#{window_zoomed_flag}' '0'
p6=$($TMUX display-message -p -t P:0 '#{pane_id}')
check_ok kill-pane -t "$p6"
# Zoom and unzoom preserve the exact tiled layout. Selecting another pane # Zoom and unzoom preserve the exact tiled layout. Selecting another pane
# without -Z unzooms, while -Z transfers zoom to the selected pane. # without -Z unzooms, while -Z transfers zoom to the selected pane.
@@ -378,7 +389,8 @@ check_fmt "$p0" '#{window_zoomed_flag}:#{pane_zoomed_flag}:#{pane_active}' \
check_ok resize-pane -Z -t "$p0" check_ok resize-pane -Z -t "$p0"
check_layout P:0 "$layout" check_layout P:0 "$layout"
# Killing either a hidden ordinary pane or the zoom target unzooms. # Killing a hidden ordinary pane leaves the zoom, and killing the zoom target
# shows what was underneath.
check_ok new-window -d -t P:12 -n zoom-kill 'cat' check_ok new-window -d -t P:12 -n zoom-kill 'cat'
zk0=$($TMUX display-message -p -t P:12.0 '#{pane_id}') zk0=$($TMUX display-message -p -t P:12.0 '#{pane_id}')
zk1=$($TMUX split-window -d -P -F '#{pane_id}' -t P:12.0 'cat') zk1=$($TMUX split-window -d -P -F '#{pane_id}' -t P:12.0 'cat')
@@ -386,8 +398,7 @@ zk2=$($TMUX split-window -d -P -F '#{pane_id}' -t P:12.0 'cat')
check_ok resize-pane -Z -t "$zk0" check_ok resize-pane -Z -t "$zk0"
check_ok kill-pane -t "$zk1" check_ok kill-pane -t "$zk1"
check_fmt "$zk0" '#{window_panes}:#{window_zoomed_flag}:#{pane_zoomed_flag}' \ check_fmt "$zk0" '#{window_panes}:#{window_zoomed_flag}:#{pane_zoomed_flag}' \
'2:0:0' '2:1:1'
check_ok resize-pane -Z -t "$zk0"
check_ok kill-pane -t "$zk0" check_ok kill-pane -t "$zk0"
check_fmt "$zk2" '#{window_panes}:#{window_zoomed_flag}:#{pane_zoomed_flag}' \ check_fmt "$zk2" '#{window_panes}:#{window_zoomed_flag}:#{pane_zoomed_flag}' \
'1:0:0' '1:0:0'
@@ -406,7 +417,7 @@ while [ "$($TMUX display-message -p -t P:13 '#{window_panes}')" != 2 ]; do
[ $i -gt 50 ] && { echo "Hidden pane did not exit."; exit 1; } [ $i -gt 50 ] && { echo "Hidden pane did not exit."; exit 1; }
sleep 0.1 sleep 0.1
done done
check_fmt "$ze0" '#{window_zoomed_flag}:#{pane_zoomed_flag}' '0:0' check_fmt "$ze0" '#{window_zoomed_flag}:#{pane_zoomed_flag}' '1:1'
check_ok resize-pane -Z -t "$ze2" check_ok resize-pane -Z -t "$ze2"
check_ok send-keys -t "$ze2" C-d check_ok send-keys -t "$ze2" C-d
i=0 i=0

View File

@@ -355,6 +355,24 @@ check_ok resize-pane -Z -t "$p1"
check_ok rotate-window -D -t R:0 check_ok rotate-window -D -t R:0
check_fmt 'R:0' '#{window_layout}' "$layout" check_fmt 'R:0' '#{window_layout}' "$layout"
# Floating panes are not rotated: they keep their geometry and stay floating
# while the tiled panes rotate around them.
fp=$($TMUX new-pane -dPF '#{pane_id}' -t R:0 -x 20 -y 8 -X 8 -Y 3 '')
fgeom=$($TMUX display-message -p -t "$fp" \
'#{pane_floating_flag}:#{pane_left}:#{pane_top}:#{pane_width}:#{pane_height}')
check_ok select-pane -t "$p0"
check_ok rotate-window -U -t R:0
check_fmt "$fp" \
'#{pane_floating_flag}:#{pane_left}:#{pane_top}:#{pane_width}:#{pane_height}' \
"$fgeom"
check_fmt "$p1" '#{pane_floating_flag}:#{pane_top}:#{pane_active}' '0:0:1'
check_ok rotate-window -D -t R:0
check_fmt "$fp" \
'#{pane_floating_flag}:#{pane_left}:#{pane_top}:#{pane_width}:#{pane_height}' \
"$fgeom"
check_fmt "$p0" '#{pane_floating_flag}:#{pane_top}:#{pane_active}' '0:0:1'
check_ok kill-pane -t "$fp"
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# kill-window. # kill-window.

View File

@@ -42,7 +42,6 @@ resize_fire_window_resized(struct window *w, u_int old_sx, u_int old_sy)
void void
resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel) resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
{ {
struct window_pane *zwp;
u_int old_sx = w->sx, old_sy = w->sy; u_int old_sx = w->sx, old_sy = w->sy;
/* Check size limits. */ /* Check size limits. */
@@ -55,11 +54,6 @@ resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
if (sy > WINDOW_MAXIMUM) if (sy > WINDOW_MAXIMUM)
sy = WINDOW_MAXIMUM; sy = WINDOW_MAXIMUM;
/* If the window is zoomed, unzoom. */
zwp = window_zoomed_pane(w);
if (zwp != NULL)
window_unzoom(w, 1);
/* Resize the layout first. */ /* Resize the layout first. */
layout_resize(w, sx, sy); layout_resize(w, sx, sy);
@@ -72,9 +66,9 @@ resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
log_debug("%s: @%u resized to %ux%u; layout %ux%u", __func__, w->id, log_debug("%s: @%u resized to %ux%u; layout %ux%u", __func__, w->id,
sx, sy, w->layout_root->g.sx, w->layout_root->g.sy); sx, sy, w->layout_root->g.sx, w->layout_root->g.sy);
/* Restore the window zoom state. */ /* Zoomed panes follow the window size. */
if (zwp != NULL && window_has_pane(w, zwp)) if (w->flags & WINDOW_ZOOMED)
window_zoom(zwp); layout_fix_panes(w, NULL);
tty_update_window_offset(w); tty_update_window_offset(w);
server_redraw_window(w); server_redraw_window(w);

View File

@@ -358,7 +358,7 @@ redraw_pane_to_scene(struct redraw_build_ctx *bctx, struct window_pane *wp,
int wx = wp->xoff + px, wy = wp->yoff + py; int wx = wp->xoff + px, wy = wp->yoff + py;
int left, right, top, bottom; int left, right, top, bottom;
if (window_pane_is_floating(wp)) { if (window_pane_is_unzoomed_float(wp)) {
left = wp->xoff - 1; left = wp->xoff - 1;
right = wp->xoff + wp->sx; right = wp->xoff + wp->sx;
top = wp->yoff - 1; top = wp->yoff - 1;
@@ -676,7 +676,7 @@ redraw_mark_pane_borders(struct redraw_build_ctx *bctx, struct window_pane *wp,
enum pane_lines pane_lines = window_pane_get_pane_lines(wp); enum pane_lines pane_lines = window_pane_get_pane_lines(wp);
int pane_status, left, right, top, bottom, wx, wy; int pane_status, left, right, top, bottom, wx, wy;
int mark_top, mark_bottom, mark_left, mark_right, mask = 0; int mark_top, mark_bottom, mark_left, mark_right, mask = 0;
int floating = window_pane_is_floating(wp); int floating = window_pane_is_unzoomed_float(wp);
if (floating && pane_lines == PANE_LINES_NONE) if (floating && pane_lines == PANE_LINES_NONE)
return; return;

View File

@@ -675,7 +675,7 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
return (KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER); return (KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER);
} else /* py > sl_bottom */ } else /* py > sl_bottom */
return (KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN); return (KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN);
} else if (window_pane_is_floating(wp) && } else if (window_pane_is_unzoomed_float(wp) &&
window_pane_get_pane_lines(wp) != PANE_LINES_NONE && window_pane_get_pane_lines(wp) != PANE_LINES_NONE &&
(px == bdr_left || (px == bdr_left ||
py == wp->yoff - 1 || py == wp->yoff - 1 ||
@@ -691,7 +691,7 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
TAILQ_FOREACH(fwp, &w->panes, entry) { TAILQ_FOREACH(fwp, &w->panes, entry) {
if (!window_pane_is_visible(fwp)) if (!window_pane_is_visible(fwp))
continue; continue;
if (window_pane_is_floating(fwp) && if (window_pane_is_unzoomed_float(fwp) &&
window_pane_get_pane_lines(fwp) == PANE_LINES_NONE) window_pane_get_pane_lines(fwp) == PANE_LINES_NONE)
continue; continue;
if (window_pane_scrollbar_reserve(fwp)) { if (window_pane_scrollbar_reserve(fwp)) {

View File

@@ -226,11 +226,9 @@ server_kill_pane(struct window_pane *wp)
server_kill_window(w, 1); server_kill_window(w, 1);
recalculate_sizes(); recalculate_sizes();
} else { } else {
window_push_zoom(w, 0, wp->flags & PANE_FLOATOVERZOOM);
server_client_remove_pane(wp); server_client_remove_pane(wp);
layout_close_pane(wp); layout_close_pane(wp);
window_remove_pane(w, wp); window_remove_pane(w, wp);
window_pop_zoom(w);
server_redraw_window(w); server_redraw_window(w);
} }
} }
@@ -423,17 +421,14 @@ server_destroy_pane(struct window_pane *wp, int notify)
if (notify) if (notify)
server_fire_pane_exit("pane-exited", wp); server_fire_pane_exit("pane-exited", wp);
window_push_zoom(w, 0, wp->flags & PANE_FLOATOVERZOOM);
server_client_remove_pane(wp); server_client_remove_pane(wp);
layout_close_pane(wp); layout_close_pane(wp);
window_remove_pane(w, wp); window_remove_pane(w, wp);
if (TAILQ_EMPTY(&w->panes)) if (TAILQ_EMPTY(&w->panes))
server_kill_window(w, 1); server_kill_window(w, 1);
else { else
window_pop_zoom(w);
server_redraw_window(w); server_redraw_window(w);
}
} }
static void static void

13
spawn.c
View File

@@ -362,13 +362,6 @@ spawn_pane(struct spawn_context *sc, char **cause)
new_wp->layout_cell->flags |= LAYOUT_CELL_FLOATING; new_wp->layout_cell->flags |= LAYOUT_CELL_FLOATING;
if (sc->flags & SPAWN_FLOATOVERZOOM) if (sc->flags & SPAWN_FLOATOVERZOOM)
new_wp->flags |= PANE_FLOATOVERZOOM; new_wp->flags |= PANE_FLOATOVERZOOM;
/*
* If window currently zoomed, window_set_active_pane calls
* window_unzoom which it copies back the saved_layout_cell.
*/
if (w->flags & WINDOW_ZOOMED)
new_wp->saved_layout_cell = new_wp->layout_cell;
} }
/* /*
@@ -593,6 +586,8 @@ complete:
if (sc->flags & SPAWN_RESPAWN) if (sc->flags & SPAWN_RESPAWN)
return (new_wp); return (new_wp);
if (sc->flags & SPAWN_ZOOM)
window_zoom(new_wp);
if (sc->flags & SPAWN_MODAL) { if (sc->flags & SPAWN_MODAL) {
w->modal_last = w->active; w->modal_last = w->active;
w->modal = new_wp; w->modal = new_wp;
@@ -747,10 +742,8 @@ spawn_editor(struct client *c, const char *buf, size_t len,
lg.sy = w->sy * 9 / 10; lg.sy = w->sy * 9 / 10;
lg.xoff = w->sx / 2 - lg.sx / 2; lg.xoff = w->sx / 2 - lg.sx / 2;
lg.yoff = w->sy / 2 - lg.sy / 2; lg.yoff = w->sy / 2 - lg.sy / 2;
window_push_zoom(w, 0, 1);
lc = layout_floating_pane(w, NULL, &lg); lc = layout_floating_pane(w, NULL, &lg);
if (lc == NULL) { if (lc == NULL) {
window_pop_zoom(w);
spawn_editor_free(es); spawn_editor_free(es);
return (NULL); return (NULL);
} }
@@ -774,11 +767,9 @@ spawn_editor(struct client *c, const char *buf, size_t len,
environ_free(env); environ_free(env);
if (wp == NULL) { if (wp == NULL) {
free(cause); free(cause);
window_pop_zoom(w);
spawn_editor_free(es); spawn_editor_free(es);
return (NULL); return (NULL);
} }
window_pop_zoom(w);
options_set_number(wp->options, "remain-on-exit", 0); options_set_number(wp->options, "remain-on-exit", 0);
es->pid = wp->pid; es->pid = wp->pid;
wp->editor = es; wp->editor = es;

22
tmux.h
View File

@@ -1156,6 +1156,11 @@ enum pane_lines {
PANE_LINES_ROUNDED PANE_LINES_ROUNDED
}; };
/* Panes raised when they are made active. */
#define PANE_RAISE_FLOATING 0
#define PANE_RAISE_ALL 1
#define PANE_RAISE_OFF 2
/* Pane border indicator option. */ /* Pane border indicator option. */
#define PANE_BORDER_OFF 0 #define PANE_BORDER_OFF 0
#define PANE_BORDER_COLOUR 1 #define PANE_BORDER_COLOUR 1
@@ -1312,7 +1317,6 @@ struct window_pane {
struct options *options; struct options *options;
struct layout_cell *layout_cell; struct layout_cell *layout_cell;
struct layout_cell *saved_layout_cell;
u_int sx; u_int sx;
u_int sy; u_int sy;
@@ -1455,14 +1459,12 @@ struct window {
struct window_pane *active; struct window_pane *active;
struct window_pane *modal; struct window_pane *modal;
struct window_pane *modal_last; struct window_pane *modal_last;
struct window_pane *was_zoomed;
struct window_panes last_panes; struct window_panes last_panes;
struct window_panes z_index; struct window_panes z_index;
struct window_panes panes; struct window_panes panes;
int lastlayout; int lastlayout;
struct layout_cell *layout_root; struct layout_cell *layout_root;
struct layout_cell *saved_layout_root;
char *old_layout; char *old_layout;
u_int sx; u_int sx;
@@ -1496,7 +1498,6 @@ struct window {
#define WINDOW_ACTIVITY 0x2 #define WINDOW_ACTIVITY 0x2
#define WINDOW_SILENCE 0x4 #define WINDOW_SILENCE 0x4
#define WINDOW_ZOOMED 0x8 #define WINDOW_ZOOMED 0x8
#define WINDOW_WASZOOMED 0x10
#define WINDOW_RESIZE 0x20 #define WINDOW_RESIZE 0x20
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
@@ -3719,12 +3720,13 @@ struct window_pane *window_add_pane(struct window *, struct window_pane *,
u_int, int); u_int, int);
void window_resize(struct window *, u_int, u_int, int, int); void window_resize(struct window *, u_int, u_int, int, int);
void window_pane_send_resize(struct window_pane *, u_int, u_int); void window_pane_send_resize(struct window_pane *, u_int, u_int);
void window_raise_pane(struct window_pane *);
void window_lower_pane(struct window_pane *);
int window_zoom(struct window_pane *); int window_zoom(struct window_pane *);
int window_unzoom_pane(struct window_pane *, int);
int window_unzoom(struct window *, int); int window_unzoom(struct window *, int);
int window_active_pane_is_over_zoom(struct window *);
struct window_pane *window_zoomed_pane(struct window *); struct window_pane *window_zoomed_pane(struct window *);
int window_push_zoom(struct window *, int, int); void window_zoom_move(struct window_pane *, struct window_pane *);
int window_pop_zoom(struct window *);
void window_lost_pane(struct window *, struct window_pane *); void window_lost_pane(struct window *, struct window_pane *);
void window_remove_pane(struct window *, struct window_pane *); void window_remove_pane(struct window *, struct window_pane *);
struct window_pane *window_pane_at_index(struct window *, u_int); struct window_pane *window_pane_at_index(struct window *, u_int);
@@ -3815,7 +3817,8 @@ int window_pane_get_pane_status(struct window_pane *);
struct style_range *window_pane_status_get_range(struct window_pane *, u_int, struct style_range *window_pane_status_get_range(struct window_pane *, u_int,
u_int); u_int);
int window_pane_is_floating(struct window_pane *); int window_pane_is_floating(struct window_pane *);
int window_pane_is_floating_with_hidden(struct window_pane *); int window_pane_is_unzoomed_float(struct window_pane *);
int window_pane_is_raised(struct window_pane *);
/* window-border.c */ /* window-border.c */
void window_set_fill_cells(struct window *); void window_set_fill_cells(struct window *);
@@ -3852,6 +3855,8 @@ int layout_cell_has_tiled_child(struct layout_cell *);
int layout_add_horizontal_border(struct layout_cell *, int layout_add_horizontal_border(struct layout_cell *,
struct layout_cell *, int); struct layout_cell *, int);
void layout_fix_offsets(struct window *); void layout_fix_offsets(struct window *);
void layout_get_pane_geometry(struct window_pane *, int, int *,
int *, u_int *, u_int *);
void layout_fix_panes(struct window *, struct window_pane *); void layout_fix_panes(struct window *, struct window_pane *);
void layout_resize_adjust(struct window *, struct layout_cell *, void layout_resize_adjust(struct window *, struct layout_cell *,
enum layout_type, int); enum layout_type, int);
@@ -3901,6 +3906,7 @@ int layout_insert_tile(struct window *, struct layout_cell *);
/* layout-custom.c */ /* layout-custom.c */
#define LAYOUT_CUSTOM_OLD_FORMAT 0x1 #define LAYOUT_CUSTOM_OLD_FORMAT 0x1
char *layout_dump(struct window *, struct layout_cell *, int); char *layout_dump(struct window *, struct layout_cell *, int);
char *layout_dump_visible(struct window *, int);
int layout_parse(struct window *, const char *, char **); int layout_parse(struct window *, const char *, char **);
/* layout-set.c */ /* layout-set.c */

View File

@@ -150,21 +150,7 @@ window_panes_add_area(struct window_panes_modedata *data,
static int static int
window_panes_pane_floating(struct window_pane *wp) window_panes_pane_floating(struct window_pane *wp)
{ {
struct layout_cell *lc = wp->saved_layout_cell; return (window_pane_is_floating(wp));
if (lc == NULL)
lc = wp->layout_cell;
if (lc == NULL || (~lc->flags & LAYOUT_CELL_FLOATING))
return (0);
return (1);
}
static int
window_panes_pane_visible(struct window_pane *wp)
{
if (wp->saved_layout_cell != NULL)
return (1);
return (window_pane_is_visible(wp));
} }
static int static int
@@ -172,12 +158,10 @@ window_panes_get_geometry(struct window_pane *wp, struct layout_cell *root,
u_int osx, u_int osy, u_int dsx, u_int dsy, u_int *xp, u_int *yp, u_int osx, u_int osy, u_int dsx, u_int dsy, u_int *xp, u_int *yp,
u_int *sxp, u_int *syp) u_int *sxp, u_int *syp)
{ {
struct layout_cell *lc = wp->saved_layout_cell; struct layout_cell *lc = wp->layout_cell;
int status; int status;
u_int x, y, sx, sy, x2, y2; u_int x, y, sx, sy, x2, y2;
if (lc == NULL)
lc = wp->layout_cell;
if (lc == NULL || osx == 0 || osy == 0 || dsx == 0 || dsy == 0) if (lc == NULL || osx == 0 || osy == 0 || dsx == 0 || dsy == 0)
return (0); return (0);
@@ -375,12 +359,7 @@ window_panes_mark_pane_status_borders(u_char *map, struct window *w,
return; return;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_panes_pane_visible(wp)) lc = wp->layout_cell;
continue;
lc = wp->saved_layout_cell;
if (lc == NULL)
lc = wp->layout_cell;
if (lc == NULL || if (lc == NULL ||
!layout_add_horizontal_border(root, lc, status)) !layout_add_horizontal_border(root, lc, status))
continue; continue;
@@ -404,9 +383,7 @@ window_panes_get_floating_borders(struct window_pane *wp, u_int osx, u_int osy,
{ {
struct layout_cell *lc; struct layout_cell *lc;
lc = wp->saved_layout_cell; lc = wp->layout_cell;
if (lc == NULL)
lc = wp->layout_cell;
if (lc == NULL || (~lc->flags & LAYOUT_CELL_FLOATING)) if (lc == NULL || (~lc->flags & LAYOUT_CELL_FLOATING))
return (0); return (0);
@@ -801,8 +778,6 @@ window_panes_draw_pane(struct window_panes_modedata *data,
struct screen *s = &wp->base; struct screen *s = &wp->base;
u_int pane, x, y, sx, sy; u_int pane, x, y, sx, sy;
if (!window_panes_pane_visible(wp))
return;
if (!window_panes_get_geometry(wp, root, osx, osy, dsx, dsy, &x, &y, if (!window_panes_get_geometry(wp, root, osx, osy, dsx, dsy, &x, &y,
&sx, &sy)) &sx, &sy))
return; return;
@@ -839,9 +814,7 @@ window_panes_draw_screen(struct window_mode_entry *wme)
if (!window_panes_get_source(data, NULL, NULL, &w)) if (!window_panes_get_source(data, NULL, NULL, &w))
return; return;
root = w->saved_layout_root; root = w->layout_root;
if (root == NULL)
root = w->layout_root;
if (root == NULL) if (root == NULL)
return; return;
@@ -941,7 +914,7 @@ window_panes_init(struct window_mode_entry *wme, struct cmdq_item *item,
if (args_has(args, 'Z')) if (args_has(args, 'Z'))
data->zoomed = -1; data->zoomed = -1;
else { else {
data->zoomed = (w->flags & WINDOW_ZOOMED); data->zoomed = (wp->flags & PANE_ZOOMED);
if (!data->zoomed) if (!data->zoomed)
window_panes_set_preview(data); window_panes_set_preview(data);
if (!data->zoomed && window_zoom(wp) == 0) if (!data->zoomed && window_zoom(wp) == 0)
@@ -967,8 +940,8 @@ window_panes_free(struct window_mode_entry *wme)
evtimer_del(&data->timer); evtimer_del(&data->timer);
if (data->zoomed == 0) if (data->zoomed == 0 && window_unzoom_pane(wme->wp, 1) == 0)
server_unzoom_window(w); server_redraw_window(w);
server_redraw_window(w); server_redraw_window(w);
server_redraw_window_borders(w); server_redraw_window_borders(w);
server_status_window(w); server_status_window(w);
@@ -1092,8 +1065,6 @@ window_panes_key(struct window_mode_entry *wme, struct client *c,
return; return;
} }
if (wp->window->flags & WINDOW_ZOOMED)
window_unzoom(wp->window, 1);
window_panes_run_command(data, c, target); window_panes_run_command(data, c, target);
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
} }

View File

@@ -380,7 +380,7 @@ window_switch_init(struct window_mode_entry *wme,
if (!args_has(args, 'Z')) if (!args_has(args, 'Z'))
data->zoomed = -1; data->zoomed = -1;
else { else {
data->zoomed = (wp->window->flags & WINDOW_ZOOMED); data->zoomed = (wp->flags & PANE_ZOOMED);
if (!data->zoomed && window_zoom(wp) == 0) if (!data->zoomed && window_zoom(wp) == 0)
server_redraw_window(wp->window); server_redraw_window(wp->window);
} }
@@ -398,8 +398,9 @@ window_switch_free(struct window_mode_entry *wme)
struct window_switch_modedata *data = wme->data; struct window_switch_modedata *data = wme->data;
u_int i; u_int i;
if (data->zoomed == 0) if (data->zoomed == 0 &&
server_unzoom_window(wme->wp->window); window_unzoom_pane(wme->wp, 1) == 0)
server_redraw_window(wme->wp->window);
for (i = 0; i < data->item_size; i++) for (i = 0; i < data->item_size; i++)
window_switch_free_item(data->item_list[i]); window_switch_free_item(data->item_list[i]);

View File

@@ -103,7 +103,7 @@ window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
continue; continue;
} }
if (window_pane_is_floating(wp) && if (window_pane_is_unzoomed_float(wp) &&
window_pane_get_pane_lines(wp) == PANE_LINES_NONE) window_pane_get_pane_lines(wp) == PANE_LINES_NONE)
no_border = 1; no_border = 1;
else else
@@ -120,7 +120,8 @@ window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
py < tb || py < tb ||
py > bb) py > bb)
continue; continue;
if (!window_pane_is_floating(wp) && (py == tb || py == bb)) if (!window_pane_is_unzoomed_float(wp) &&
(py == tb || py == bb))
continue; continue;
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad; sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;

461
window.c
View File

@@ -457,21 +457,11 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel)
static void static void
window_destroy(struct window *w) window_destroy(struct window *w)
{ {
struct window_pane *wp;
log_debug("window @%u destroyed (%d references)", w->id, w->references); log_debug("window @%u destroyed (%d references)", w->id, w->references);
if (w->flags & WINDOW_ZOOMED) {
w->flags &= ~WINDOW_ZOOMED;
TAILQ_FOREACH(wp, &w->panes, entry) {
wp->flags &= ~PANE_ZOOMED;
wp->saved_layout_cell = NULL;
}
}
RB_REMOVE(windows, &windows, w); RB_REMOVE(windows, &windows, w);
layout_free_cell(w->layout_root, 0); layout_free_cell(w->layout_root, 0);
layout_free_cell(w->saved_layout_root, 0);
free(w->old_layout); free(w->old_layout);
menu_destroy(w); menu_destroy(w);
@@ -656,7 +646,7 @@ window_pane_contains(struct window_pane *wp, u_int x, u_int y)
return (0); return (0);
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
if (!window_pane_is_floating(wp)) { if (!window_pane_is_unzoomed_float(wp)) {
if ((int)x < xoff || x > xoff + sx) if ((int)x < xoff || x > xoff + sx)
return (0); return (0);
if ((int)y < yoff || y > yoff + sy) if ((int)y < yoff || y > yoff + sy)
@@ -685,7 +675,7 @@ window_pane_floating_overlaps(struct window_pane *fwp, struct window_pane *wp)
int fxoff, fyoff, xoff, yoff, border = 0; int fxoff, fyoff, xoff, yoff, border = 0;
u_int fsx, fsy, sx, sy; u_int fsx, fsy, sx, sy;
if (!window_pane_is_floating(fwp)) if (!window_pane_is_unzoomed_float(fwp) && (~fwp->flags & PANE_ZOOMED))
return (0); return (0);
window_pane_full_size_offset(fwp, &fxoff, &fyoff, &fsx, &fsy); window_pane_full_size_offset(fwp, &fxoff, &fyoff, &fsx, &fsy);
@@ -761,8 +751,29 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
return (0); return (0);
if (w->modal != NULL && wp != w->modal) if (w->modal != NULL && wp != w->modal)
return (0); return (0);
if ((w->flags & WINDOW_ZOOMED) && !window_pane_is_visible(wp)) if (!window_pane_is_visible(wp)) {
window_unzoom(w, 1); /*
* The pane is covered by a zoomed pane. A tiled pane that is
* not zoomed can only be reached by unzooming (any floats
* stay); anything else can be raised above the zoom.
*/
if (window_pane_is_raised(wp))
window_raise_pane(wp);
else
window_unzoom(w, 1);
} else {
/* Raise the pane if the option says to. */
switch (options_get_number(w->options, "pane-raise-on-focus")) {
case PANE_RAISE_FLOATING:
if (window_pane_is_unzoomed_float(wp))
window_raise_pane(wp);
break;
case PANE_RAISE_ALL:
if (window_pane_is_raised(wp))
window_raise_pane(wp);
break;
}
}
lastwp = w->active; lastwp = w->active;
window_pane_stack_remove(&w->last_panes, wp); window_pane_stack_remove(&w->last_panes, wp);
@@ -830,14 +841,6 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp)
if (wp == w->active) if (wp == w->active)
break; break;
/* If the pane is floating, move to the front. */
if (window_pane_is_floating(wp)) {
TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
wp->flags |= PANE_REDRAW;
redraw_invalidate_scene(w);
}
wp = w->active; wp = w->active;
if (wp == NULL) if (wp == NULL)
break; break;
@@ -860,11 +863,12 @@ window_get_active_at(struct window *w, u_int x, u_int y)
} }
/* /*
* A floating pane is above every tiled pane, including their status * A floating pane or a zoomed pane is above every tiled pane, including
* lines, so check those first. * their status lines, so check those first. They are in stacking order.
*/ */
TAILQ_FOREACH(wp, &w->z_index, zentry) { TAILQ_FOREACH(wp, &w->z_index, zentry) {
if (window_pane_is_floating(wp) && if ((window_pane_is_unzoomed_float(wp) ||
(wp->flags & PANE_ZOOMED)) &&
window_pane_contains(wp, x, y)) window_pane_contains(wp, x, y))
return (wp); return (wp);
} }
@@ -876,7 +880,7 @@ window_get_active_at(struct window *w, u_int x, u_int y)
*/ */
TAILQ_FOREACH(wp, &w->z_index, zentry) { TAILQ_FOREACH(wp, &w->z_index, zentry) {
if (!window_pane_is_visible(wp) || if (!window_pane_is_visible(wp) ||
window_pane_is_floating(wp)) window_pane_is_unzoomed_float(wp))
continue; continue;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, window_pane_full_size_offset(wp, &xoff, &yoff, &sx,
@@ -892,7 +896,7 @@ window_get_active_at(struct window *w, u_int x, u_int y)
if (!window_pane_is_visible(wp)) if (!window_pane_is_visible(wp))
continue; continue;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
if (!window_pane_is_floating(wp)) { if (!window_pane_is_unzoomed_float(wp)) {
/* /*
* Tiled - to and including the right border, excluding * Tiled - to and including the right border, excluding
* the bottom border. * the bottom border.
@@ -966,117 +970,164 @@ window_find_string(struct window *w, const char *s)
return (window_get_active_at(w, x, y)); return (window_get_active_at(w, x, y));
} }
int /*
window_zoom(struct window_pane *wp) * Move a pane to the front of the panes that are raised above the layout:
* behind the modal pane and any always-on-top pane.
*/
void
window_raise_pane(struct window_pane *wp)
{ {
struct window *w = wp->window; struct window *w = wp->window;
struct window_pane *wp1; struct window_pane *wp1;
struct layout_cell *lc;
struct layout_geometry lg;
if (w->flags & WINDOW_ZOOMED) TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_FOREACH(wp1, &w->z_index, zentry) {
if (wp == w->modal)
break;
if (wp1 == w->modal)
continue;
if ((wp->flags & PANE_FLOATOVERZOOM) ||
(~wp1->flags & PANE_FLOATOVERZOOM))
break;
}
if (wp1 == NULL)
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
else
TAILQ_INSERT_BEFORE(wp1, wp, zentry);
wp->flags |= PANE_REDRAW;
redraw_invalidate_scene(w);
}
/* Move a pane to the back of the panes it is stacked with. */
void
window_lower_pane(struct window_pane *wp)
{
struct window *w = wp->window;
struct window_pane *wp1;
if (wp == w->modal)
return;
TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_FOREACH(wp1, &w->z_index, zentry) {
if (wp1 == w->modal)
continue;
if (wp->flags & PANE_FLOATOVERZOOM) {
if (~wp1->flags & PANE_FLOATOVERZOOM)
break;
} else if (!window_pane_is_raised(wp1))
break;
}
if (wp1 == NULL)
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
else
TAILQ_INSERT_BEFORE(wp1, wp, zentry);
wp->flags |= PANE_REDRAW;
redraw_invalidate_scene(w);
}
/* Set or clear WINDOW_ZOOMED depending on whether any pane is zoomed. */
static void
window_update_zoomed(struct window *w)
{
struct window_pane *wp;
w->flags &= ~WINDOW_ZOOMED;
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->flags & PANE_ZOOMED) {
w->flags |= WINDOW_ZOOMED;
break;
}
}
}
/* Clear the zoomed flag on a pane and put it back behind the floats. */
static void
window_unzoom_one(struct window_pane *wp)
{
struct window *w = wp->window;
wp->flags &= ~PANE_ZOOMED;
if (!window_pane_is_floating(wp)) {
TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
}
window_update_zoomed(w);
}
/* Fire the events after panes have been unzoomed. */
static void
window_unzoomed(struct window *w, int notify)
{
layout_fix_panes(w, NULL);
if (notify) {
if (~w->flags & WINDOW_ZOOMED)
events_fire_window("window-unzoomed", w);
events_fire_window("window-layout-changed", w);
}
redraw_invalidate_scene(w);
}
/*
* Zoom a pane. A zoomed pane is shown at the size of the window above the
* layout, and above any panes behind it in the stacking order; other panes can
* be zoomed on top of it.
*/
int
window_zoom(struct window_pane *wp)
{
struct window *w = wp->window;
int was_zoomed = (w->flags & WINDOW_ZOOMED);
if (wp->flags & PANE_ZOOMED)
return (-1); return (-1);
if (window_count_panes(w, 1) == 1) if (window_count_panes(w, 1) == 1)
return (-1); return (-1);
if (w->active != wp &&
(w->active == NULL ||
(~w->active->flags & PANE_FLOATOVERZOOM) ||
!window_pane_is_floating(w->active)))
window_set_active_pane(w, wp, 1);
wp->flags |= PANE_ZOOMED; wp->flags |= PANE_ZOOMED;
TAILQ_FOREACH(wp1, &w->panes, entry) {
wp1->saved_layout_cell = wp1->layout_cell;
wp1->layout_cell = NULL;
}
w->saved_layout_root = w->layout_root;
layout_init(w, wp);
TAILQ_FOREACH(wp1, &w->panes, entry) {
lc = wp1->saved_layout_cell;
if (wp1 == wp ||
(~wp1->flags & PANE_FLOATOVERZOOM) ||
lc == NULL ||
(~lc->flags & LAYOUT_CELL_FLOATING))
continue;
memcpy(&lg, &lc->g, sizeof lg);
lc = layout_floating_pane(w, wp, &lg);
layout_assign_pane(lc, wp1, 0);
}
/* A floating zoom target is now tiled, so put it behind the floats. */
if (wp->saved_layout_cell->flags & LAYOUT_CELL_FLOATING) {
TAILQ_REMOVE(&w->z_index, wp, zentry);
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
}
w->flags |= WINDOW_ZOOMED; w->flags |= WINDOW_ZOOMED;
events_fire_window("window-zoomed", w); window_raise_pane(wp);
events_fire_window("window-layout-changed", w); layout_fix_panes(w, NULL);
if (w->active != wp)
window_set_active_pane(w, wp, 1);
if (!was_zoomed)
events_fire_window("window-zoomed", w);
events_fire_window("window-layout-changed", w);
redraw_invalidate_scene(w); redraw_invalidate_scene(w);
return (0); return (0);
} }
/* Unzoom one pane. */
int
window_unzoom_pane(struct window_pane *wp, int notify)
{
struct window *w = wp->window;
if (~wp->flags & PANE_ZOOMED)
return (-1);
window_unzoom_one(wp);
window_unzoomed(w, notify);
return (0);
}
/* Unzoom every pane. */
int int
window_unzoom(struct window *w, int notify) window_unzoom(struct window *w, int notify)
{ {
struct window_pane *wp, *zoomed = NULL; struct window_pane *wp, *wp1;
struct layout_cell *slc;
if (~w->flags & WINDOW_ZOOMED) if (~w->flags & WINDOW_ZOOMED)
return (-1); return (-1);
TAILQ_FOREACH_SAFE(wp, &w->panes, entry, wp1) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->flags & PANE_ZOOMED) if (wp->flags & PANE_ZOOMED)
zoomed = wp; window_unzoom_one(wp);
if (~wp->flags & PANE_FLOATOVERZOOM)
continue;
if (wp->flags & PANE_ZOOMED)
continue;
slc = wp->saved_layout_cell;
if (slc == NULL || wp->layout_cell == NULL)
continue;
memcpy(&slc->g, &wp->layout_cell->g, sizeof slc->g);
memcpy(&slc->fg, &wp->layout_cell->fg, sizeof slc->fg);
} }
window_unzoomed(w, notify);
w->flags &= ~WINDOW_ZOOMED;
layout_free(w, 0);
w->layout_root = w->saved_layout_root;
w->saved_layout_root = NULL;
TAILQ_FOREACH(wp, &w->panes, entry) {
wp->layout_cell = wp->saved_layout_cell;
wp->saved_layout_cell = NULL;
wp->flags &= ~PANE_ZOOMED;
}
/* Put a floating zoom target back into the floating part of the list. */
if (zoomed != NULL && window_pane_is_floating(zoomed)) {
TAILQ_REMOVE(&w->z_index, zoomed, zentry);
if (zoomed == w->active)
TAILQ_INSERT_HEAD(&w->z_index, zoomed, zentry);
else {
TAILQ_FOREACH(wp, &w->z_index, zentry) {
if (!window_pane_is_floating(wp))
break;
}
if (wp == NULL)
TAILQ_INSERT_TAIL(&w->z_index, zoomed, zentry);
else
TAILQ_INSERT_BEFORE(wp, zoomed, zentry);
}
}
layout_fix_panes(w, NULL);
if (notify) {
events_fire_window("window-unzoomed", w);
events_fire_window("window-layout-changed", w);
}
redraw_invalidate_scene(w);
return (0); return (0);
} }
/* Get the zoomed pane at the front of the stacking order. */
struct window_pane * struct window_pane *
window_zoomed_pane(struct window *w) window_zoomed_pane(struct window *w)
{ {
@@ -1084,63 +1135,26 @@ window_zoomed_pane(struct window *w)
if (~w->flags & WINDOW_ZOOMED) if (~w->flags & WINDOW_ZOOMED)
return (NULL); return (NULL);
TAILQ_FOREACH_REVERSE(wp, &w->z_index, window_panes_zindex, zentry) { TAILQ_FOREACH(wp, &w->z_index, zentry) {
if (wp->layout_cell != NULL && !window_pane_is_floating(wp)) if (wp->flags & PANE_ZOOMED)
return (wp); return (wp);
} }
return (NULL); return (NULL);
} }
int /*
window_active_pane_is_over_zoom(struct window *w) * Move zoom from one pane to another, so a command that made another pane
* active can leave the window looking zoomed.
*/
void
window_zoom_move(struct window_pane *from, struct window_pane *to)
{ {
if (~w->flags & WINDOW_ZOOMED) if (from == to)
return (0); return;
if (w->active == NULL) if (from != NULL)
return (0); window_unzoom_pane(from, 1);
if (~w->active->flags & PANE_FLOATOVERZOOM) if (to != NULL)
return (0); window_zoom(to);
return (window_pane_is_floating(w->active));
}
int
window_push_zoom(struct window *w, int always, int flag)
{
struct window_pane *wp = window_zoomed_pane(w);
log_debug("%s: @%u %d", __func__, w->id,
flag && (w->flags & WINDOW_ZOOMED));
if (flag && (always || (w->flags & WINDOW_ZOOMED)))
w->flags |= WINDOW_WASZOOMED;
else
w->flags &= ~WINDOW_WASZOOMED;
if (w->flags & WINDOW_WASZOOMED)
w->was_zoomed = wp;
else
w->was_zoomed = NULL;
return (window_unzoom(w, 1) == 0);
}
int
window_pop_zoom(struct window *w)
{
struct window_pane *wp = w->was_zoomed;
log_debug("%s: @%u %d", __func__, w->id,
!!(w->flags & WINDOW_WASZOOMED));
if (w->flags & WINDOW_WASZOOMED) {
w->flags &= ~WINDOW_WASZOOMED;
w->was_zoomed = NULL;
if (w->active != NULL &&
((~w->active->flags & PANE_FLOATOVERZOOM) ||
!window_pane_is_floating(w->active)))
wp = w->active;
if (wp == NULL || !window_has_pane(w, wp))
wp = w->active;
if (wp != NULL)
return (window_zoom(wp) == 0);
}
return (0);
} }
struct window_pane * struct window_pane *
@@ -1171,10 +1185,12 @@ window_add_pane(struct window *w, struct window_pane *other, u_int hlimit,
} }
if (~flags & SPAWN_FLOATING) if (~flags & SPAWN_FLOATING)
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
else if (w->modal != NULL)
TAILQ_INSERT_AFTER(&w->z_index, w->modal, wp, zentry);
else { else {
if (flags & SPAWN_FLOATOVERZOOM)
wp->flags |= PANE_FLOATOVERZOOM;
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry); TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
if (~flags & SPAWN_MODAL)
window_raise_pane(wp);
} }
redraw_invalidate_scene(w); redraw_invalidate_scene(w);
return (wp); return (wp);
@@ -1191,8 +1207,14 @@ window_lost_pane(struct window *w, struct window_pane *wp)
server_clear_marked(); server_clear_marked();
if (wp == w->modal_last) if (wp == w->modal_last)
w->modal_last = NULL; w->modal_last = NULL;
if (wp == w->was_zoomed)
w->was_zoomed = NULL; /* Remove zoom now so the panes it covered are visible again. */
if (wp->flags & PANE_ZOOMED) {
wp->flags &= ~PANE_ZOOMED;
window_update_zoomed(w);
if (~w->flags & WINDOW_ZOOMED)
events_fire_window("window-unzoomed", w);
}
window_pane_stack_remove(&w->last_panes, wp); window_pane_stack_remove(&w->last_panes, wp);
if (wp == w->active) { if (wp == w->active) {
@@ -1206,6 +1228,16 @@ window_lost_pane(struct window *w, struct window_pane *wp)
w->active = lastwp; w->active = lastwp;
else else
w->active = TAILQ_FIRST(&w->last_panes); w->active = TAILQ_FIRST(&w->last_panes);
if (w->active != NULL && !window_pane_is_visible(w->active)) {
/* Use the topmost pane that can be seen. */
TAILQ_FOREACH(lastwp, &w->z_index, zentry) {
if (lastwp != wp &&
window_pane_is_visible(lastwp))
break;
}
if (lastwp != NULL)
w->active = lastwp;
}
if (w->active == NULL) { if (w->active == NULL) {
w->active = TAILQ_PREV(wp, window_panes, entry); w->active = TAILQ_PREV(wp, window_panes, entry);
if (w->active == NULL) if (w->active == NULL)
@@ -1231,6 +1263,10 @@ window_remove_pane(struct window *w, struct window_pane *wp)
TAILQ_REMOVE(&w->z_index, wp, zentry); TAILQ_REMOVE(&w->z_index, wp, zentry);
redraw_invalidate_scene(w); redraw_invalidate_scene(w);
window_pane_destroy(wp); window_pane_destroy(wp);
/* A window with one pane left has nothing to zoom. */
if ((w->flags & WINDOW_ZOOMED) && window_count_panes(w, 1) == 1)
window_unzoom(w, 1);
} }
struct window_pane * struct window_pane *
@@ -1297,11 +1333,11 @@ window_pane_zindex(struct window_pane *wp, u_int *i)
*i = 0; *i = 0;
TAILQ_FOREACH(wq, &w->z_index, zentry) { TAILQ_FOREACH(wq, &w->z_index, zentry) {
if (wq == wp) { if (wq == wp) {
if (!window_pane_is_floating(wp)) if (!window_pane_is_raised(wp))
(*i)++; (*i)++;
return (0); return (0);
} }
if (window_pane_is_floating(wq)) if (window_pane_is_raised(wq) && window_pane_is_visible(wq))
(*i)++; (*i)++;
} }
@@ -2107,9 +2143,20 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
int int
window_pane_is_visible(struct window_pane *wp) window_pane_is_visible(struct window_pane *wp)
{ {
if (~wp->window->flags & WINDOW_ZOOMED) struct window *w = wp->window;
struct window_pane *wp1;
if (~w->flags & WINDOW_ZOOMED)
return (1); return (1);
return (wp->layout_cell != NULL);
/* A pane is covered by any zoomed pane in front of it. */
TAILQ_FOREACH(wp1, &w->z_index, zentry) {
if (wp1 == wp)
return (1);
if (wp1->flags & PANE_ZOOMED)
return (0);
}
return (1);
} }
int int
@@ -2211,6 +2258,37 @@ window_pane_full_size_offset(struct window_pane *wp, int *xoff, int *yoff,
*sy = wp->sy; *sy = wp->sy;
} }
/*
* Get the full size and offset of a pane as if nothing were zoomed, for moving
* between panes.
*/
static void
window_pane_layout_size_offset(struct window_pane *wp, int *xoff, int *yoff,
u_int *sx, u_int *sy)
{
struct window *w = wp->window;
int pxoff, pyoff;
u_int psx, psy, sb_w;
if (~wp->flags & PANE_ZOOMED) {
window_pane_full_size_offset(wp, xoff, yoff, sx, sy);
return;
}
layout_get_pane_geometry(wp, 1, &pxoff, &pyoff, &psx, &psy);
if (window_pane_scrollbar_reserve(wp))
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
else
sb_w = 0;
if (w->sb_pos == PANE_SCROLLBARS_LEFT)
*xoff = pxoff - sb_w;
else
*xoff = pxoff;
*sx = psx + sb_w;
*yoff = pyoff;
*sy = psy;
}
/* /*
* Find the pane directly above another. We build a list of those adjacent to * Find the pane directly above another. We build a list of those adjacent to
* top edge and then choose the best. * top edge and then choose the best.
@@ -2232,7 +2310,7 @@ window_pane_find_up(struct window_pane *wp)
list = NULL; list = NULL;
size = 0; size = 0;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); window_pane_layout_size_offset(wp, &xoff, &yoff, &sx, &sy);
edge = yoff; edge = yoff;
if (status == PANE_STATUS_TOP) { if (status == PANE_STATUS_TOP) {
@@ -2250,7 +2328,7 @@ window_pane_find_up(struct window_pane *wp)
right = xoff + (int)sx; right = xoff + (int)sx;
TAILQ_FOREACH(next, &w->panes, entry) { TAILQ_FOREACH(next, &w->panes, entry) {
window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy); window_pane_layout_size_offset(next, &xoff, &yoff, &sx, &sy);
if (next == wp) if (next == wp)
continue; continue;
if (yoff + (int)sy + 1 != edge) if (yoff + (int)sy + 1 != edge)
@@ -2293,7 +2371,7 @@ window_pane_find_down(struct window_pane *wp)
list = NULL; list = NULL;
size = 0; size = 0;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); window_pane_layout_size_offset(wp, &xoff, &yoff, &sx, &sy);
edge = yoff + (int)sy + 1; edge = yoff + (int)sy + 1;
if (status == PANE_STATUS_TOP) { if (status == PANE_STATUS_TOP) {
@@ -2311,7 +2389,7 @@ window_pane_find_down(struct window_pane *wp)
right = wp->xoff + (int)wp->sx; right = wp->xoff + (int)wp->sx;
TAILQ_FOREACH(next, &w->panes, entry) { TAILQ_FOREACH(next, &w->panes, entry) {
window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy); window_pane_layout_size_offset(next, &xoff, &yoff, &sx, &sy);
if (next == wp) if (next == wp)
continue; continue;
if (yoff != edge) if (yoff != edge)
@@ -2353,7 +2431,7 @@ window_pane_find_left(struct window_pane *wp)
list = NULL; list = NULL;
size = 0; size = 0;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); window_pane_layout_size_offset(wp, &xoff, &yoff, &sx, &sy);
edge = xoff; edge = xoff;
if (edge == 0) if (edge == 0)
@@ -2363,7 +2441,7 @@ window_pane_find_left(struct window_pane *wp)
bottom = yoff + (int)sy; bottom = yoff + (int)sy;
TAILQ_FOREACH(next, &w->panes, entry) { TAILQ_FOREACH(next, &w->panes, entry) {
window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy); window_pane_layout_size_offset(next, &xoff, &yoff, &sx, &sy);
if (next == wp) if (next == wp)
continue; continue;
if (xoff + (int)sx + 1 != edge) if (xoff + (int)sx + 1 != edge)
@@ -2405,7 +2483,7 @@ window_pane_find_right(struct window_pane *wp)
list = NULL; list = NULL;
size = 0; size = 0;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); window_pane_layout_size_offset(wp, &xoff, &yoff, &sx, &sy);
edge = xoff + (int)sx + 1; edge = xoff + (int)sx + 1;
if (edge >= (int)w->sx) if (edge >= (int)w->sx)
@@ -2415,7 +2493,7 @@ window_pane_find_right(struct window_pane *wp)
bottom = wp->yoff + (int)wp->sy; bottom = wp->yoff + (int)wp->sy;
TAILQ_FOREACH(next, &w->panes, entry) { TAILQ_FOREACH(next, &w->panes, entry) {
window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy); window_pane_layout_size_offset(next, &xoff, &yoff, &sx, &sy);
if (next == wp) if (next == wp)
continue; continue;
if (xoff != edge) if (xoff != edge)
@@ -2906,7 +2984,7 @@ window_pane_get_pane_lines(struct window_pane *wp)
{ {
struct options *oo; struct options *oo;
if (!window_pane_is_floating(wp)) if (!window_pane_is_unzoomed_float(wp))
oo = wp->window->options; oo = wp->window->options;
else else
oo = wp->options; oo = wp->options;
@@ -2937,7 +3015,7 @@ window_pane_get_pane_status(struct window_pane *wp)
(wp->flags & PANE_ZOOMED)) (wp->flags & PANE_ZOOMED))
return (PANE_STATUS_OFF); return (PANE_STATUS_OFF);
if (!window_pane_is_floating(wp)) if (!window_pane_is_unzoomed_float(wp))
return (window_get_pane_status(wp->window)); return (window_get_pane_status(wp->window));
if (window_pane_get_pane_lines(wp) == PANE_LINES_NONE) if (window_pane_get_pane_lines(wp) == PANE_LINES_NONE)
return (PANE_STATUS_OFF); return (PANE_STATUS_OFF);
@@ -2960,14 +3038,19 @@ window_pane_is_floating(struct window_pane *wp)
return (1); return (1);
} }
/*
* Is the pane floating and drawn as a floating pane? A zoomed pane is a
* floating pane in the layout but fills the window like a tiled one.
*/
int int
window_pane_is_floating_with_hidden(struct window_pane *wp) window_pane_is_unzoomed_float(struct window_pane *wp)
{ {
struct layout_cell *lc = wp->layout_cell; return (window_pane_is_floating(wp) && (~wp->flags & PANE_ZOOMED));
}
if (lc == NULL)
lc = wp->saved_layout_cell; /* Is the pane a float or a zoomed pane, that is above the tiled panes? */
if (lc == NULL || (lc->flags & LAYOUT_CELL_FLOATING) == 0) int
return (0); window_pane_is_raised(struct window_pane *wp)
return (1); {
return (window_pane_is_floating(wp) || (wp->flags & PANE_ZOOMED));
} }