summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2009-07-19 13:21:41 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2009-07-19 13:21:41 +0000
commit0a2a020bb1719511145e8cf18794a0b585188946 (patch)
tree6dc87cd44a35c71c97e69f7dc981810a92a68fc1 /usr.bin
parent46b6a514f4de53a5ae1a61be419d3e14534f3ab4 (diff)
Improved layout code.
Each window now has a tree of layout cells associated with it. In this tree, each node is either a horizontal or vertical cell containing a list of other cells running from left-to-right or top-to-bottom, or a leaf cell which is associated with a pane. The major functional changes are: - panes may now be split arbitrarily both horizontally (splitw -h, C-b %) and vertically (splitw -v, C-b "); - panes may be resized both horizontally and vertically (resizep -L/-R/-U/-D, bound to C-b left/right/up/down and C-b M-left/right/up/down); - layouts are now applied and then may be modified by resizing or splitting panes, rather than being fixed and reapplied when the window is resized or panes are added; - manual-vertical layout is no longer necessary, and active-only layout is gone (but may return in future); - the main-pane layouts now reduce the size of the main pane to fit all panes if possible. Thanks to all who tested.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/tmux/Makefile4
-rw-r--r--usr.bin/tmux/cmd-break-pane.c6
-rw-r--r--usr.bin/tmux/cmd-choose-window.c6
-rw-r--r--usr.bin/tmux/cmd-down-pane.c3
-rw-r--r--usr.bin/tmux/cmd-kill-pane.c4
-rw-r--r--usr.bin/tmux/cmd-list-windows.c7
-rw-r--r--usr.bin/tmux/cmd-next-layout.c7
-rw-r--r--usr.bin/tmux/cmd-previous-layout.c9
-rw-r--r--usr.bin/tmux/cmd-resize-pane.c37
-rw-r--r--usr.bin/tmux/cmd-respawn-window.c4
-rw-r--r--usr.bin/tmux/cmd-rotate-window.c21
-rw-r--r--usr.bin/tmux/cmd-select-layout.c24
-rw-r--r--usr.bin/tmux/cmd-select-pane.c3
-rw-r--r--usr.bin/tmux/cmd-split-window.c99
-rw-r--r--usr.bin/tmux/cmd-swap-pane.c16
-rw-r--r--usr.bin/tmux/cmd-up-pane.c3
-rw-r--r--usr.bin/tmux/key-bindings.c15
-rw-r--r--usr.bin/tmux/layout-manual.c172
-rw-r--r--usr.bin/tmux/layout-set.c436
-rw-r--r--usr.bin/tmux/layout.c789
-rw-r--r--usr.bin/tmux/resize.c4
-rw-r--r--usr.bin/tmux/server.c8
-rw-r--r--usr.bin/tmux/tmux.185
-rw-r--r--usr.bin/tmux/tmux.h85
-rw-r--r--usr.bin/tmux/window.c55
25 files changed, 1282 insertions, 620 deletions
diff --git a/usr.bin/tmux/Makefile b/usr.bin/tmux/Makefile
index 7411d963c53..9f371d71814 100644
--- a/usr.bin/tmux/Makefile
+++ b/usr.bin/tmux/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.8 2009/07/17 18:45:08 nicm Exp $
+# $OpenBSD: Makefile,v 1.9 2009/07/19 13:21:40 nicm Exp $
PROG= tmux
SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
@@ -27,7 +27,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \
cmd-up-pane.c cmd-display-message.c cmd.c \
colour.c grid-view.c grid.c input-keys.c \
- input.c key-bindings.c key-string.c layout-manual.c layout.c log.c \
+ input.c key-bindings.c key-string.c layout-set.c layout.c log.c \
mode-key.c names.c options-cmd.c options.c paste.c procname.c \
resize.c screen-redraw.c screen-write.c screen.c server-fn.c \
server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \
diff --git a/usr.bin/tmux/cmd-break-pane.c b/usr.bin/tmux/cmd-break-pane.c
index 186bb0226f7..b77e1536276 100644
--- a/usr.bin/tmux/cmd-break-pane.c
+++ b/usr.bin/tmux/cmd-break-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-break-pane.c,v 1.2 2009/07/13 23:11:35 nicm Exp $ */
+/* $OpenBSD: cmd-break-pane.c,v 1.3 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -74,17 +74,17 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
if (wl->window->active == NULL)
wl->window->active = TAILQ_NEXT(wp, entry);
}
- layout_refresh(wl->window, 0);
+ layout_close_pane(wp);
w = wp->window = window_create1(s->sx, s->sy);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
w->name = default_window_name(w);
+ layout_init(w);
wl = session_attach(s, w, -1, &cause); /* can't fail */
if (!(data->chflags & CMD_CHFLAG('d')))
session_select(s, wl->idx);
- layout_refresh(w, 0);
server_redraw_session(s);
diff --git a/usr.bin/tmux/cmd-choose-window.c b/usr.bin/tmux/cmd-choose-window.c
index 7a3e7a9fece..99f7f7a67bc 100644
--- a/usr.bin/tmux/cmd-choose-window.c
+++ b/usr.bin/tmux/cmd-choose-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-choose-window.c,v 1.3 2009/07/17 07:05:58 nicm Exp $ */
+/* $OpenBSD: cmd-choose-window.c,v 1.4 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -76,8 +76,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
idx++;
window_choose_add(wl->window->active,
- wm->idx, "%3d: %s [%ux%u %s] (%u panes)", wm->idx, w->name,
- w->sx, w->sy, layout_name(w), window_count_panes(w));
+ wm->idx, "%3d: %s [%ux%u] (%u panes)",
+ wm->idx, w->name, w->sx, w->sy, window_count_panes(w));
}
cdata = xmalloc(sizeof *cdata);
diff --git a/usr.bin/tmux/cmd-down-pane.c b/usr.bin/tmux/cmd-down-pane.c
index d93fe3dc3a3..b9b4b24eae0 100644
--- a/usr.bin/tmux/cmd-down-pane.c
+++ b/usr.bin/tmux/cmd-down-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-down-pane.c,v 1.3 2009/07/14 07:23:36 nicm Exp $ */
+/* $OpenBSD: cmd-down-pane.c,v 1.4 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -54,7 +54,6 @@ cmd_down_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
w->active = TAILQ_NEXT(w->active, entry);
if (w->active == NULL)
w->active = TAILQ_FIRST(&w->panes);
- layout_refresh(w, 1);
} while (!window_pane_visible(w->active));
return (0);
diff --git a/usr.bin/tmux/cmd-kill-pane.c b/usr.bin/tmux/cmd-kill-pane.c
index ca642e5df8c..319da2bcbf6 100644
--- a/usr.bin/tmux/cmd-kill-pane.c
+++ b/usr.bin/tmux/cmd-kill-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-kill-pane.c,v 1.3 2009/07/17 20:37:03 nicm Exp $ */
+/* $OpenBSD: cmd-kill-pane.c,v 1.4 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -66,8 +66,8 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
return (0);
}
+ layout_close_pane(wp);
window_remove_pane(wl->window, wp);
server_redraw_window(wl->window);
- layout_refresh(wl->window, 0);
return (0);
}
diff --git a/usr.bin/tmux/cmd-list-windows.c b/usr.bin/tmux/cmd-list-windows.c
index fa76fc7fbd6..62c4fdc5dd4 100644
--- a/usr.bin/tmux/cmd-list-windows.c
+++ b/usr.bin/tmux/cmd-list-windows.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-list-windows.c,v 1.2 2009/07/13 23:11:35 nicm Exp $ */
+/* $OpenBSD: cmd-list-windows.c,v 1.3 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -78,9 +78,8 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
else
name = "unknown";
ctx->print(ctx,
- " %s [%ux%u %s] [history %u/%u, %llu bytes]",
- name, wp->sx, wp->sy, layout_name(w), gd->hsize,
- gd->hlimit, size);
+ " %s [%ux%u] [history %u/%u, %llu bytes]",
+ name, wp->sx, wp->sy, gd->hsize, gd->hlimit, size);
}
}
diff --git a/usr.bin/tmux/cmd-next-layout.c b/usr.bin/tmux/cmd-next-layout.c
index f9b073ba4b8..d791344b86f 100644
--- a/usr.bin/tmux/cmd-next-layout.c
+++ b/usr.bin/tmux/cmd-next-layout.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-next-layout.c,v 1.2 2009/07/13 23:11:35 nicm Exp $ */
+/* $OpenBSD: cmd-next-layout.c,v 1.3 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -44,12 +44,13 @@ cmd_next_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
+ u_int layout;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
- layout_next(wl->window);
- ctx->info(ctx, "layout now: %s", layout_name(wl->window));
+ layout = layout_set_next(wl->window);
+ ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}
diff --git a/usr.bin/tmux/cmd-previous-layout.c b/usr.bin/tmux/cmd-previous-layout.c
index 0652bab3e54..032402846e5 100644
--- a/usr.bin/tmux/cmd-previous-layout.c
+++ b/usr.bin/tmux/cmd-previous-layout.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-previous-layout.c,v 1.2 2009/07/13 23:11:35 nicm Exp $ */
+/* $OpenBSD: cmd-previous-layout.c,v 1.3 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -44,12 +44,13 @@ cmd_previous_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
-
+ u_int layout;
+
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
- layout_previous(wl->window);
- ctx->info(ctx, "layout now: %s", layout_name(wl->window));
+ layout = layout_set_previous(wl->window);
+ ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}
diff --git a/usr.bin/tmux/cmd-resize-pane.c b/usr.bin/tmux/cmd-resize-pane.c
index 217c9638ecd..4a5c48a0eac 100644
--- a/usr.bin/tmux/cmd-resize-pane.c
+++ b/usr.bin/tmux/cmd-resize-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-resize-pane.c,v 1.2 2009/07/13 23:11:35 nicm Exp $ */
+/* $OpenBSD: cmd-resize-pane.c,v 1.3 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -32,7 +32,8 @@ int cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_resize_pane_entry = {
"resize-pane", "resizep",
CMD_PANE_WINDOW_USAGE "[-DU] [adjustment]",
- CMD_ARG01, CMD_CHFLAG('D')|CMD_CHFLAG('U'),
+ CMD_ARG01,
+ CMD_CHFLAG('D')|CMD_CHFLAG('L')|CMD_CHFLAG('R')|CMD_CHFLAG('U'),
cmd_resize_pane_init,
cmd_pane_parse,
cmd_resize_pane_exec,
@@ -50,15 +51,31 @@ cmd_resize_pane_init(struct cmd *self, int key)
cmd_pane_init(self, key);
data = self->data;
+ if (key == KEYC_ADDCTL(KEYC_UP))
+ data->chflags |= CMD_CHFLAG('U');
if (key == KEYC_ADDCTL(KEYC_DOWN))
data->chflags |= CMD_CHFLAG('D');
+ if (key == KEYC_ADDCTL(KEYC_LEFT))
+ data->chflags |= CMD_CHFLAG('L');
+ if (key == KEYC_ADDCTL(KEYC_RIGHT))
+ data->chflags |= CMD_CHFLAG('R');
- if (key == KEYC_ADDESC(KEYC_UP))
+ if (key == KEYC_ADDESC(KEYC_UP)) {
+ data->chflags |= CMD_CHFLAG('U');
data->arg = xstrdup("5");
+ }
if (key == KEYC_ADDESC(KEYC_DOWN)) {
data->chflags |= CMD_CHFLAG('D');
data->arg = xstrdup("5");
}
+ if (key == KEYC_ADDESC(KEYC_LEFT)) {
+ data->chflags |= CMD_CHFLAG('L');
+ data->arg = xstrdup("5");
+ }
+ if (key == KEYC_ADDESC(KEYC_RIGHT)) {
+ data->chflags |= CMD_CHFLAG('R');
+ data->arg = xstrdup("5");
+ }
}
int
@@ -92,12 +109,14 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
}
}
- if (!(data->chflags & CMD_CHFLAG('D')))
- adjust = -adjust;
- if (layout_resize(wp, adjust) != 0) {
- ctx->error(ctx, "layout %s "
- "does not support resizing", layout_name(wp->window));
- return (-1);
+ if (data->chflags & (CMD_CHFLAG('L')|CMD_CHFLAG('R'))) {
+ if (data->chflags & CMD_CHFLAG('L'))
+ adjust = -adjust;
+ layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust);
+ } else {
+ if (data->chflags & CMD_CHFLAG('U'))
+ adjust = -adjust;
+ layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust);
}
server_redraw_window(wl->window);
diff --git a/usr.bin/tmux/cmd-respawn-window.c b/usr.bin/tmux/cmd-respawn-window.c
index 55e820ee3e2..a64e186c7d9 100644
--- a/usr.bin/tmux/cmd-respawn-window.c
+++ b/usr.bin/tmux/cmd-respawn-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-respawn-window.c,v 1.2 2009/07/13 23:11:35 nicm Exp $ */
+/* $OpenBSD: cmd-respawn-window.c,v 1.3 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -70,6 +70,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
+ layout_free(w);
window_destroy_panes(w);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy);
@@ -78,6 +79,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
xfree(cause);
return (-1);
}
+ layout_init(w);
screen_reinit(&wp->base);
recalculate_sizes();
diff --git a/usr.bin/tmux/cmd-rotate-window.c b/usr.bin/tmux/cmd-rotate-window.c
index dd728565c47..1b8ec77f52e 100644
--- a/usr.bin/tmux/cmd-rotate-window.c
+++ b/usr.bin/tmux/cmd-rotate-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-rotate-window.c,v 1.6 2009/07/14 07:23:36 nicm Exp $ */
+/* $OpenBSD: cmd-rotate-window.c,v 1.7 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -59,6 +59,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *wl;
struct window *w;
struct window_pane *wp, *wp2;
+ struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
@@ -70,42 +71,56 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
+ lc = wp->layout_cell;
xoff = wp->xoff; yoff = wp->yoff;
sx = wp->sx; sy = wp->sy;
TAILQ_FOREACH(wp, &w->panes, entry) {
if ((wp2 = TAILQ_NEXT(wp, 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_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
window_set_active_pane(w, wp);
+ server_redraw_window(w);
} 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);
+ server_redraw_window(w);
}
- layout_refresh(w, 0);
-
return (0);
}
diff --git a/usr.bin/tmux/cmd-select-layout.c b/usr.bin/tmux/cmd-select-layout.c
index d605eb2638e..70dfd1f6e17 100644
--- a/usr.bin/tmux/cmd-select-layout.c
+++ b/usr.bin/tmux/cmd-select-layout.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-select-layout.c,v 1.2 2009/07/13 23:11:35 nicm Exp $ */
+/* $OpenBSD: cmd-select-layout.c,v 1.3 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -49,17 +49,17 @@ cmd_select_layout_init(struct cmd *self, int key)
data = self->data;
switch (key) {
- case KEYC_ADDESC('0'):
- data->arg = xstrdup("manual-vertical");
- break;
case KEYC_ADDESC('1'):
data->arg = xstrdup("even-horizontal");
break;
case KEYC_ADDESC('2'):
data->arg = xstrdup("even-vertical");
break;
- case KEYC_ADDESC('9'):
- data->arg = xstrdup("active-only");
+ case KEYC_ADDESC('3'):
+ data->arg = xstrdup("main-horizontal");
+ break;
+ case KEYC_ADDESC('4'):
+ data->arg = xstrdup("main-vertical");
break;
}
}
@@ -74,13 +74,13 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
return (-1);
- if ((layout = layout_lookup(data->arg)) == -1) {
- ctx->error(ctx, "unknown or ambiguous layout: %s", data->arg);
- return (-1);
- }
+ if ((layout = layout_set_lookup(data->arg)) == -1) {
+ ctx->error(ctx, "unknown or ambiguous layout: %s", data->arg);
+ return (-1);
+ }
- if (layout_select(wl->window, layout) == 0)
- ctx->info(ctx, "layout now: %s", layout_name(wl->window));
+ layout = layout_set_select(wl->window, layout);
+ ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
return (0);
}
diff --git a/usr.bin/tmux/cmd-select-pane.c b/usr.bin/tmux/cmd-select-pane.c
index dfed7e9bbe9..463802f2806 100644
--- a/usr.bin/tmux/cmd-select-pane.c
+++ b/usr.bin/tmux/cmd-select-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-select-pane.c,v 1.3 2009/07/14 07:23:36 nicm Exp $ */
+/* $OpenBSD: cmd-select-pane.c,v 1.4 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -63,7 +63,6 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
}
window_set_active_pane(wl->window, wp);
- layout_refresh(wl->window, 1);
return (0);
}
diff --git a/usr.bin/tmux/cmd-split-window.c b/usr.bin/tmux/cmd-split-window.c
index 7094649437f..2d7787ab933 100644
--- a/usr.bin/tmux/cmd-split-window.c
+++ b/usr.bin/tmux/cmd-split-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-split-window.c,v 1.4 2009/07/13 23:11:35 nicm Exp $ */
+/* $OpenBSD: cmd-split-window.c,v 1.5 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -39,13 +39,14 @@ struct cmd_split_window_data {
char *target;
char *cmd;
int flag_detached;
+ int flag_horizontal;
int percentage;
- int lines;
+ int size;
};
const struct cmd_entry cmd_split_window_entry = {
"split-window", "splitw",
- "[-d] [-p percentage|-l lines] [-t target-window] [command]",
+ "[-dhv] [-p percentage|-l size] [-t target-window] [command]",
0, 0,
cmd_split_window_init,
cmd_split_window_parse,
@@ -57,7 +58,7 @@ const struct cmd_entry cmd_split_window_entry = {
};
void
-cmd_split_window_init(struct cmd *self, unused int arg)
+cmd_split_window_init(struct cmd *self, int key)
{
struct cmd_split_window_data *data;
@@ -65,50 +66,63 @@ cmd_split_window_init(struct cmd *self, unused int arg)
data->target = NULL;
data->cmd = NULL;
data->flag_detached = 0;
+ data->flag_horizontal = 0;
data->percentage = -1;
- data->lines = -1;
+ data->size = -1;
+
+ switch (key) {
+ case '%':
+ data->flag_horizontal = 1;
+ break;
+ case '"':
+ data->flag_horizontal = 0;
+ break;
+ }
}
int
cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause)
{
struct cmd_split_window_data *data;
- int opt, n;
+ int opt;
const char *errstr;
self->entry->init(self, 0);
data = self->data;
- while ((opt = getopt(argc, argv, "dl:p:t:")) != -1) {
+ while ((opt = getopt(argc, argv, "dhl:p:t:v")) != -1) {
switch (opt) {
case 'd':
data->flag_detached = 1;
break;
+ case 'h':
+ data->flag_horizontal = 1;
+ break;
case 't':
if (data->target == NULL)
data->target = xstrdup(optarg);
break;
case 'l':
- if (data->percentage == -1 && data->lines == -1) {
- n = strtonum(optarg, 1, INT_MAX, &errstr);
- if (errstr != NULL) {
- xasprintf(cause, "lines %s", errstr);
- goto error;
- }
- data->lines = n;
+ if (data->percentage != -1 || data->size != -1)
+ break;
+ data->size = strtonum(optarg, 1, INT_MAX, &errstr);
+ if (errstr != NULL) {
+ xasprintf(cause, "size %s", errstr);
+ goto error;
}
break;
case 'p':
- if (data->lines == -1 && data->percentage == -1) {
- n = strtonum(optarg, 1, 100, &errstr);
- if (errstr != NULL) {
- xasprintf(
- cause, "percentage %s", errstr);
- goto error;
- }
- data->percentage = n;
+ if (data->size != -1 || data->percentage != -1)
+ break;
+ data->percentage = strtonum(optarg, 1, 100, &errstr);
+ if (errstr != NULL) {
+ xasprintf(cause, "percentage %s", errstr);
+ goto error;
}
break;
+ case 'v':
+ data->flag_horizontal = 0;
+ break;
default:
goto usage;
}
@@ -142,7 +156,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
const char **env;
char *cmd, *cwd, *cause;
u_int hlimit;
- int lines;
+ int size;
+ enum layout_type type;
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
@@ -158,19 +173,27 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
else
cwd = ctx->cmdclient->cwd;
- lines = -1;
- if (data->lines != -1)
- lines = data->lines;
+ size = -1;
+ if (data->size != -1)
+ size = data->size;
else if (data->percentage != -1)
- lines = (w->active->sy * data->percentage) / 100;
-
+ size = (w->active->sy * data->percentage) / 100;
hlimit = options_get_number(&s->options, "history-limit");
- wp = window_add_pane(w, lines, cmd, cwd, env, hlimit, &cause);
- if (wp == NULL) {
- ctx->error(ctx, "create pane failed: %s", cause);
- xfree(cause);
- return (-1);
+
+ type = LAYOUT_TOPBOTTOM;
+ if (data->flag_horizontal)
+ type = LAYOUT_LEFTRIGHT;
+
+ wp = window_add_pane(w, hlimit, &cause);
+ if (wp == NULL)
+ goto error;
+ if (window_pane_spawn(wp, cmd, cwd, env, &cause) != 0)
+ goto error;
+ if (layout_split_pane(w->active, type, size, wp) != 0) {
+ cause = xstrdup("pane too small");
+ goto error;
}
+
server_redraw_window(w);
if (!data->flag_detached) {
@@ -179,9 +202,15 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
server_redraw_session(s);
} else
server_status_session(s);
- layout_refresh(w, 0);
return (0);
+
+error:
+ if (wp != NULL)
+ window_remove_pane(w, wp);
+ ctx->error(ctx, "create pane failed: %s", cause);
+ xfree(cause);
+ return (-1);
}
void
@@ -228,6 +257,8 @@ cmd_split_window_print(struct cmd *self, char *buf, size_t len)
return (off);
if (off < len && data->flag_detached)
off += xsnprintf(buf + off, len - off, " -d");
+ if (off < len && data->flag_horizontal)
+ off += xsnprintf(buf + off, len - off, " -h");
if (off < len && data->target != NULL)
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
if (off < len && data->cmd != NULL)
diff --git a/usr.bin/tmux/cmd-swap-pane.c b/usr.bin/tmux/cmd-swap-pane.c
index 85ecde214fc..2100ba4a188 100644
--- a/usr.bin/tmux/cmd-swap-pane.c
+++ b/usr.bin/tmux/cmd-swap-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-swap-pane.c,v 1.4 2009/07/14 07:23:36 nicm Exp $ */
+/* $OpenBSD: cmd-swap-pane.c,v 1.5 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -157,6 +157,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *wl;
struct window *w;
struct window_pane *tmp_wp, *src_wp, *dst_wp;
+ struct layout_cell *lc;
u_int xx, yy;
if (data == NULL)
@@ -207,12 +208,15 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
else
TAILQ_INSERT_AFTER(&w->panes, tmp_wp, src_wp, entry);
+ lc = src_wp->layout_cell;
xx = src_wp->xoff;
yy = src_wp->yoff;
- src_wp->xoff = dst_wp->xoff;
- src_wp->yoff = dst_wp->yoff;
- dst_wp->xoff = xx;
- dst_wp->yoff = yy;
+ src_wp->layout_cell = dst_wp->layout_cell;
+ if (src_wp->layout_cell != NULL)
+ src_wp->layout_cell->wp = src_wp;
+ dst_wp->layout_cell = lc;
+ if (dst_wp->layout_cell != NULL)
+ dst_wp->layout_cell->wp = dst_wp;
xx = src_wp->sx;
yy = src_wp->sy;
@@ -224,8 +228,8 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
if (!window_pane_visible(tmp_wp))
tmp_wp = src_wp;
window_set_active_pane(w, tmp_wp);
- layout_refresh(w, 0);
}
+ server_redraw_window(w);
return (0);
}
diff --git a/usr.bin/tmux/cmd-up-pane.c b/usr.bin/tmux/cmd-up-pane.c
index b0e371f7a6d..7c3c06a0cac 100644
--- a/usr.bin/tmux/cmd-up-pane.c
+++ b/usr.bin/tmux/cmd-up-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-up-pane.c,v 1.3 2009/07/14 07:23:36 nicm Exp $ */
+/* $OpenBSD: cmd-up-pane.c,v 1.4 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -54,7 +54,6 @@ cmd_up_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
w->active = TAILQ_PREV(w->active, window_panes, entry);
if (w->active == NULL)
w->active = TAILQ_LAST(&w->panes, window_panes);
- layout_refresh(w, 1);
} while (!window_pane_visible(w->active));
return (0);
diff --git a/usr.bin/tmux/key-bindings.c b/usr.bin/tmux/key-bindings.c
index e5e66077cbb..79e7f5e6f25 100644
--- a/usr.bin/tmux/key-bindings.c
+++ b/usr.bin/tmux/key-bindings.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: key-bindings.c,v 1.5 2009/07/17 18:45:08 nicm Exp $ */
+/* $OpenBSD: key-bindings.c,v 1.6 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -93,7 +93,8 @@ key_bindings_init(void)
} table[] = {
{ ' ', 0, &cmd_next_layout_entry },
{ '!', 0, &cmd_break_pane_entry },
- { '"', 0, &cmd_split_window_entry },
+ { '"', 0, &cmd_split_window_entry },
+ { '%', 0, &cmd_split_window_entry },
{ '#', 0, &cmd_list_buffers_entry },
{ '&', 0, &cmd_confirm_before_entry },
{ ',', 0, &cmd_command_prompt_entry },
@@ -132,10 +133,10 @@ key_bindings_init(void)
{ '{', 0, &cmd_swap_pane_entry },
{ '}', 0, &cmd_swap_pane_entry },
{ '\002', 0, &cmd_send_prefix_entry },
- { KEYC_ADDESC('0'), 0, &cmd_select_layout_entry },
{ KEYC_ADDESC('1'), 0, &cmd_select_layout_entry },
{ KEYC_ADDESC('2'), 0, &cmd_select_layout_entry },
- { KEYC_ADDESC('9'), 0, &cmd_select_layout_entry },
+ { KEYC_ADDESC('3'), 0, &cmd_select_layout_entry },
+ { KEYC_ADDESC('4'), 0, &cmd_select_layout_entry },
{ KEYC_PPAGE, 0, &cmd_scroll_mode_entry },
{ KEYC_ADDESC('n'), 0, &cmd_next_window_entry },
{ KEYC_ADDESC('p'), 0, &cmd_previous_window_entry },
@@ -143,8 +144,12 @@ key_bindings_init(void)
{ KEYC_DOWN, 0, &cmd_down_pane_entry },
{ KEYC_ADDESC(KEYC_UP), 1, &cmd_resize_pane_entry },
{ KEYC_ADDESC(KEYC_DOWN), 1, &cmd_resize_pane_entry },
+ { KEYC_ADDESC(KEYC_LEFT), 1, &cmd_resize_pane_entry },
+ { KEYC_ADDESC(KEYC_RIGHT),1, &cmd_resize_pane_entry },
{ KEYC_ADDCTL(KEYC_UP), 1, &cmd_resize_pane_entry },
- { KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry },
+ { KEYC_ADDCTL(KEYC_DOWN), 1, &cmd_resize_pane_entry },
+ { KEYC_ADDCTL(KEYC_LEFT), 1, &cmd_resize_pane_entry },
+ { KEYC_ADDCTL(KEYC_RIGHT),1, &cmd_resize_pane_entry },
{ KEYC_ADDESC('o'), 0, &cmd_rotate_window_entry },
{ '\017', 0, &cmd_rotate_window_entry },
};
diff --git a/usr.bin/tmux/layout-manual.c b/usr.bin/tmux/layout-manual.c
deleted file mode 100644
index c2ee82c3cb2..00000000000
--- a/usr.bin/tmux/layout-manual.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/* $OpenBSD: layout-manual.c,v 1.2 2009/07/14 07:23:36 nicm Exp $ */
-
-/*
- * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-
-#include "tmux.h"
-
-void layout_manual_v_update_offsets(struct window *);
-
-void
-layout_manual_v_refresh(struct window *w, unused int active_only)
-{
- struct window_pane *wp;
- u_int npanes, total, height;
- int left;
-
- if (active_only)
- return;
-
- if (TAILQ_EMPTY(&w->panes))
- return;
-
- /* Check the new size. */
- npanes = window_count_panes(w);
- if (w->sy <= PANE_MINIMUM * npanes) {
- /*
- * Make the first pane the smaller of the minimum and total (it
- * must fit to be visible) and the rest the minimum size.
- */
- height = PANE_MINIMUM;
- if (height > w->sy)
- height = w->sy + 1;
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if (wp == TAILQ_FIRST(&w->panes))
- wp->sy = height - 1;
- else
- wp->sy = PANE_MINIMUM - 1;
- }
- /* And increase the first by the rest if possible. */
- if (w->sy >= PANE_MINIMUM)
- TAILQ_FIRST(&w->panes)->sy += 1 + w->sy % PANE_MINIMUM;
- } else {
- /* In theory they will all fit. Find the current total. */
- total = 0;
- TAILQ_FOREACH(wp, &w->panes, entry)
- total += wp->sy;
- total += npanes - 1;
-
- /* Growing or shrinking? */
- left = w->sy - total;
- if (left > 0) {
- /* Growing. Expand evenly. */
- while (left > 0) {
- TAILQ_FOREACH(wp, &w->panes, entry) {
- wp->sy++;
- if (--left == 0)
- break;
- }
- }
- } else {
- /* Shrinking. Reduce evenly down to minimum. */
- while (left < 0) {
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if (wp->sy <= PANE_MINIMUM - 1)
- continue;
- wp->sy--;
- if (++left == 0)
- break;
- }
- }
- }
- }
-
- /* Now do the resize. */
- TAILQ_FOREACH(wp, &w->panes, entry) {
- wp->sy--;
- window_pane_resize(wp, w->sx, wp->sy + 1);
- }
-
- /* Fill in the offsets. */
- layout_manual_v_update_offsets(w);
-
- /* Switch the active window if necessary. */
- window_set_active_pane(w, w->active);
-}
-
-void
-layout_manual_v_resize(struct window_pane *wp, int adjust)
-{
- struct window *w = wp->window;
- struct window_pane *wq;
-
- if (adjust > 0) {
- /*
- * If this is not the last pane, keep trying to increase size
- * and remove it from the next panes. If it is the last, do
- * so on the previous pane.
- */
- if (TAILQ_NEXT(wp, entry) == NULL) {
- if (wp == TAILQ_FIRST(&w->panes)) {
- /* Only one pane. */
- return;
- }
- wp = TAILQ_PREV(wp, window_panes, entry);
- }
- while (adjust-- > 0) {
- wq = wp;
- while ((wq = TAILQ_NEXT(wq, entry)) != NULL) {
- if (wq->sy <= PANE_MINIMUM)
- continue;
- window_pane_resize(wq, wq->sx, wq->sy - 1);
- break;
- }
- if (wq == NULL)
- break;
- window_pane_resize(wp, wp->sx, wp->sy + 1);
- }
- } else {
- adjust = -adjust;
- /*
- * If this is not the last pane, keep trying to reduce size
- * and add to the following pane. If it is the last, do so on
- * the previous pane.
- */
- wq = TAILQ_NEXT(wp, entry);
- if (wq == NULL) {
- if (wp == TAILQ_FIRST(&w->panes)) {
- /* Only one pane. */
- return;
- }
- wq = wp;
- wp = TAILQ_PREV(wq, window_panes, entry);
- }
- while (adjust-- > 0) {
- if (wp->sy <= PANE_MINIMUM)
- break;
- window_pane_resize(wq, wq->sx, wq->sy + 1);
- window_pane_resize(wp, wp->sx, wp->sy - 1);
- }
- }
-
- layout_manual_v_update_offsets(w);
-}
-
-void
-layout_manual_v_update_offsets(struct window *w)
-{
- struct window_pane *wp;
- u_int yoff;
-
- yoff = 0;
- TAILQ_FOREACH(wp, &w->panes, entry) {
- wp->xoff = 0;
- wp->yoff = yoff;
- yoff += wp->sy + 1;
- }
-}
diff --git a/usr.bin/tmux/layout-set.c b/usr.bin/tmux/layout-set.c
new file mode 100644
index 00000000000..7bdaa8b2851
--- /dev/null
+++ b/usr.bin/tmux/layout-set.c
@@ -0,0 +1,436 @@
+/* $OpenBSD: layout-set.c,v 1.1 2009/07/19 13:21:40 nicm Exp $ */
+
+/*
+ * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * Set window layouts - predefined methods to arrange windows. These are one-off
+ * and generate a layout tree.
+ */
+
+void layout_set_even_h(struct window *);
+void layout_set_even_v(struct window *);
+void layout_set_main_h(struct window *);
+void layout_set_main_v(struct window *);
+
+const struct {
+ const char *name;
+ void (*arrange)(struct window *);
+} layout_sets[] = {
+ { "even-horizontal", layout_set_even_h },
+ { "even-vertical", layout_set_even_v },
+ { "main-horizontal", layout_set_main_h },
+ { "main-vertical", layout_set_main_v },
+};
+
+const char *
+layout_set_name(u_int layout)
+{
+ return (layout_sets[layout].name);
+}
+
+int
+layout_set_lookup(const char *name)
+{
+ u_int i;
+ int matched = -1;
+
+ for (i = 0; i < nitems(layout_sets); i++) {
+ if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
+ if (matched != -1) /* ambiguous */
+ return (-1);
+ matched = i;
+ }
+ }
+
+ return (matched);
+}
+
+u_int
+layout_set_select(struct window *w, u_int layout)
+{
+ if (layout > nitems(layout_sets) - 1)
+ layout = nitems(layout_sets) - 1;
+
+ if (layout_sets[layout].arrange != NULL)
+ layout_sets[layout].arrange(w);
+
+ w->layout = layout;
+ return (layout);
+}
+
+u_int
+layout_set_next(struct window *w)
+{
+ u_int layout = w->layout;
+
+ if (layout_sets[layout].arrange != NULL)
+ layout_sets[layout].arrange(w);
+
+ w->layout++;
+ if (w->layout > nitems(layout_sets) - 1)
+ w->layout = 0;
+ return (layout);
+}
+
+u_int
+layout_set_previous(struct window *w)
+{
+ u_int layout = w->layout;
+
+ if (layout_sets[layout].arrange != NULL)
+ layout_sets[layout].arrange(w);
+
+ if (w->layout == 0)
+ w->layout = nitems(layout_sets) - 1;
+ else
+ w->layout--;
+ return (layout);
+}
+
+void
+layout_set_even_h(struct window *w)
+{
+ struct window_pane *wp;
+ struct layout_cell *lc, *lcnew;
+ u_int i, n, width, xoff;
+
+ layout_print_cell(w->layout_root, __func__, 1);
+
+ /* Get number of panes. */
+ n = window_count_panes(w);
+ if (n <= 1)
+ return;
+
+ /* How many can we fit? */
+ if (w->sx / n < PANE_MINIMUM + 1) {
+ width = PANE_MINIMUM + 1;
+ n = UINT_MAX;
+ } else
+ width = w->sx / n;
+
+ /* Free the old root and construct a new. */
+ layout_free(w);
+ lc = w->layout_root = layout_create_cell(NULL);
+ layout_set_size(lc, w->sx, w->sy, 0, 0);
+ layout_make_node(lc, LAYOUT_LEFTRIGHT);
+
+ /* Build new leaf cells. */
+ i = xoff = 0;
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ /* Create child cell. */
+ lcnew = layout_create_cell(lc);
+ layout_set_size(lcnew, width - 1, w->sy, xoff, 0);
+ layout_make_leaf(lcnew, wp);
+ TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
+
+ i++;
+ xoff += width;
+ }
+
+ /* Allocate any remaining space. */
+ if (w->sx > xoff - 1) {
+ lc = TAILQ_LAST(&lc->cells, layout_cells);
+ layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, w->sx - (xoff - 1));
+ }
+
+ /* Fix cell offsets. */
+ layout_fix_offsets(lc);
+ layout_fix_panes(w, w->sx, w->sy);
+
+ layout_print_cell(w->layout_root, __func__, 1);
+
+ server_redraw_window(w);
+}
+
+void
+layout_set_even_v(struct window *w)
+{
+ struct window_pane *wp;
+ struct layout_cell *lc, *lcnew;
+ u_int i, n, height, yoff;
+
+ layout_print_cell(w->layout_root, __func__, 1);
+
+ /* Get number of panes. */
+ n = window_count_panes(w);
+ if (n <= 1)
+ return;
+
+ /* How many can we fit? */
+ if (w->sy / n < PANE_MINIMUM + 1) {
+ height = PANE_MINIMUM + 1;
+ n = UINT_MAX;
+ } else
+ height = w->sy / n;
+
+ /* Free the old root and construct a new. */
+ layout_free(w);
+ lc = w->layout_root = layout_create_cell(NULL);
+ layout_set_size(lc, w->sx, w->sy, 0, 0);
+ layout_make_node(lc, LAYOUT_TOPBOTTOM);
+
+ /* Build new leaf cells. */
+ i = yoff = 0;
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ /* Create child cell. */
+ lcnew = layout_create_cell(lc);
+ layout_set_size(lcnew, w->sx, height - 1, 0, yoff);
+ layout_make_leaf(lcnew, wp);
+ TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
+
+ i++;
+ yoff += height;
+ }
+
+ /* Allocate any remaining space. */
+ if (w->sy > yoff - 1) {
+ lc = TAILQ_LAST(&lc->cells, layout_cells);
+ layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, w->sy - (yoff - 1));
+ }
+
+ /* Fix cell offsets. */
+ layout_fix_offsets(lc);
+ layout_fix_panes(w, w->sx, w->sy);
+
+ layout_print_cell(w->layout_root, __func__, 1);
+
+ server_redraw_window(w);
+}
+
+void
+layout_set_main_h(struct window *w)
+{
+ struct window_pane *wp;
+ struct layout_cell *lc, *lcmain, *lcrow, *lcchild;
+ u_int n, mainheight, width, height, used;
+ u_int i, j, columns, rows, totalrows;
+
+ layout_print_cell(w->layout_root, __func__, 1);
+
+ /* Get number of panes. */
+ n = window_count_panes(w);
+ if (n <= 1)
+ return;
+ n--; /* take off main pane */
+
+ /* How many rows and columns will be needed? */
+ columns = w->sx / (PANE_MINIMUM + 1); /* maximum columns */
+ rows = 1 + (n - 1) / columns;
+ columns = 1 + (n - 1) / rows;
+ width = w->sx / columns;
+
+ /* Get the main pane height and add one for separator line. */
+ mainheight = options_get_number(&w->options, "main-pane-height") + 1;
+ if (mainheight < PANE_MINIMUM + 1)
+ mainheight = PANE_MINIMUM + 1;
+
+ /* Try and make everything fit. */
+ totalrows = rows * (PANE_MINIMUM + 1) - 1;
+ if (mainheight + totalrows > w->sy) {
+ if (totalrows + PANE_MINIMUM + 1 > w->sy)
+ mainheight = PANE_MINIMUM + 2;
+ else
+ mainheight = w->sy - totalrows;
+ height = PANE_MINIMUM + 1;
+ } else
+ height = (w->sy - mainheight) / rows;
+
+ /* Free old tree and create a new root. */
+ layout_free(w);
+ lc = w->layout_root = layout_create_cell(NULL);
+ layout_set_size(lc, w->sx, mainheight + rows * height, 0, 0);
+ layout_make_node(lc, LAYOUT_TOPBOTTOM);
+
+ /* Create the main pane. */
+ lcmain = layout_create_cell(lc);
+ layout_set_size(lcmain, w->sx, mainheight - 1, 0, 0);
+ layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
+ TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
+
+ /* Create a grid of the remaining cells. */
+ wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
+ for (j = 0; j < rows; j++) {
+ /* If this is the last cell, all done. */
+ if (wp == NULL)
+ break;
+
+ /* Create the new row. */
+ lcrow = layout_create_cell(lc);
+ layout_set_size(lcrow, w->sx, height - 1, 0, 0);
+ TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
+
+ /* If only one column, just use the row directly. */
+ if (columns == 1) {
+ layout_make_leaf(lcrow, wp);
+ wp = TAILQ_NEXT(wp, entry);
+ continue;
+ }
+
+ /* Add in the columns. */
+ layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
+ for (i = 0; i < columns; i++) {
+ /* Create and add a pane cell. */
+ lcchild = layout_create_cell(lcrow);
+ layout_set_size(lcchild, width - 1, height - 1, 0, 0);
+ layout_make_leaf(lcchild, wp);
+ TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
+
+ /* Move to the next cell. */
+ if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
+ break;
+ }
+
+ /* Adjust the row to fit the full width if necessary. */
+ if (i == columns)
+ i--;
+ used = ((i + 1) * width) - 1;
+ if (w->sx <= used)
+ continue;
+ lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
+ layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used);
+ }
+
+ /* Adjust the last row height to fit if necessary. */
+ used = mainheight + (rows * height) - 1;
+ if (w->sy > used) {
+ lcrow = TAILQ_LAST(&lc->cells, layout_cells);
+ layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
+ }
+
+ /* Fix cell offsets. */
+ layout_fix_offsets(lc);
+ layout_fix_panes(w, w->sx, w->sy);
+
+ layout_print_cell(w->layout_root, __func__, 1);
+
+ server_redraw_window(w);
+}
+
+void
+layout_set_main_v(struct window *w)
+{
+ struct window_pane *wp;
+ struct layout_cell *lc, *lcmain, *lccolumn, *lcchild;
+ u_int n, mainwidth, width, height, used;
+ u_int i, j, columns, rows, totalcolumns;
+
+ layout_print_cell(w->layout_root, __func__, 1);
+
+ /* Get number of panes. */
+ n = window_count_panes(w);
+ if (n <= 1)
+ return;
+ n--; /* take off main pane */
+
+ /* How many rows and columns will be needed? */
+ rows = w->sy / (PANE_MINIMUM + 1); /* maximum rows */
+ columns = 1 + (n - 1) / rows;
+ rows = 1 + (n - 1) / columns;
+ height = w->sy / rows;
+
+ /* Get the main pane width and add one for separator line. */
+ mainwidth = options_get_number(&w->options, "main-pane-width") + 1;
+ if (mainwidth < PANE_MINIMUM + 1)
+ mainwidth = PANE_MINIMUM + 1;
+
+ /* Try and make everything fit. */
+ totalcolumns = columns * (PANE_MINIMUM + 1) - 1;
+ if (mainwidth + totalcolumns > w->sx) {
+ if (totalcolumns + PANE_MINIMUM + 1 > w->sx)
+ mainwidth = PANE_MINIMUM + 2;
+ else
+ mainwidth = w->sx - totalcolumns;
+ width = PANE_MINIMUM + 1;
+ } else
+ width = (w->sx - mainwidth) / columns;
+
+ /* Free old tree and create a new root. */
+ layout_free(w);
+ lc = w->layout_root = layout_create_cell(NULL);
+ layout_set_size(lc, mainwidth + columns * width, w->sy, 0, 0);
+ layout_make_node(lc, LAYOUT_LEFTRIGHT);
+
+ /* Create the main pane. */
+ lcmain = layout_create_cell(lc);
+ layout_set_size(lcmain, mainwidth - 1, w->sy, 0, 0);
+ layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
+ TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
+
+ /* Create a grid of the remaining cells. */
+ wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
+ for (j = 0; j < columns; j++) {
+ /* If this is the last cell, all done. */
+ if (wp == NULL)
+ break;
+
+ /* Create the new column. */
+ lccolumn = layout_create_cell(lc);
+ layout_set_size(lccolumn, width - 1, w->sy, 0, 0);
+ TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry);
+
+ /* If only one row, just use the row directly. */
+ if (rows == 1) {
+ layout_make_leaf(lccolumn, wp);
+ wp = TAILQ_NEXT(wp, entry);
+ continue;
+ }
+
+ /* Add in the rows. */
+ layout_make_node(lccolumn, LAYOUT_TOPBOTTOM);
+ for (i = 0; i < rows; i++) {
+ /* Create and add a pane cell. */
+ lcchild = layout_create_cell(lccolumn);
+ layout_set_size(lcchild, width - 1, height - 1, 0, 0);
+ layout_make_leaf(lcchild, wp);
+ TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry);
+
+ /* Move to the next cell. */
+ if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
+ break;
+ }
+
+ /* Adjust the column to fit the full height if necessary. */
+ if (i == rows)
+ i--;
+ used = ((i + 1) * height) - 1;
+ if (w->sy <= used)
+ continue;
+ lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
+ layout_resize_adjust(lcchild, LAYOUT_TOPBOTTOM, w->sy - used);
+ }
+
+ /* Adjust the last column width to fit if necessary. */
+ used = mainwidth + (columns * width) - 1;
+ if (w->sx > used) {
+ lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
+ layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used);
+ }
+
+ /* Fix cell offsets. */
+ layout_fix_offsets(lc);
+ layout_fix_panes(w, w->sx, w->sy);
+
+ layout_print_cell(w->layout_root, __func__, 1);
+
+ server_redraw_window(w);
+}
diff --git a/usr.bin/tmux/layout.c b/usr.bin/tmux/layout.c
index f4511e06286..e71a9bfd26e 100644
--- a/usr.bin/tmux/layout.c
+++ b/usr.bin/tmux/layout.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: layout.c,v 1.2 2009/07/14 07:23:36 nicm Exp $ */
+/* $OpenBSD: layout.c,v 1.3 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -18,349 +18,632 @@
#include <sys/types.h>
-#include <string.h>
+#include <stdlib.h>
#include "tmux.h"
/*
- * Each layout has two functions, _refresh to relayout the panes and _resize to
- * resize a single pane.
+ * The window layout is a tree of cells each of which can be one of: a
+ * left-right container for a list of cells, a top-bottom container for a list
+ * of cells, or a container for a window pane.
*
- * Second argument (int) to _refresh is 1 if the only change has been that the
- * active pane has changed. If 0 then panes, active pane or both may have
- * changed.
+ * Each window has a pointer to the root of its layout tree (containing its
+ * panes), every pane has a pointer back to the cell containing it, and each
+ * cell a pointer to its parent cell.
*/
-void layout_active_only_refresh(struct window *, int);
-void layout_even_h_refresh(struct window *, int);
-void layout_even_v_refresh(struct window *, int);
-void layout_main_h_refresh(struct window *, int);
-void layout_main_v_refresh(struct window *, int);
-
-const struct {
- const char *name;
- void (*refresh)(struct window *, int);
- void (*resize)(struct window_pane *, int);
-} layouts[] = {
- { "manual-vertical", layout_manual_v_refresh, layout_manual_v_resize },
- { "active-only", layout_active_only_refresh, NULL },
- { "even-horizontal", layout_even_h_refresh, NULL },
- { "even-vertical", layout_even_v_refresh, NULL },
- { "main-horizontal", layout_main_h_refresh, NULL },
- { "main-vertical", layout_main_v_refresh, NULL },
-};
-
-const char *
-layout_name(struct window *w)
+int layout_resize_pane_grow(struct layout_cell *, enum layout_type, int);
+int layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int);
+
+struct layout_cell *
+layout_create_cell(struct layout_cell *lcparent)
{
- return (layouts[w->layout].name);
+ struct layout_cell *lc;
+
+ lc = xmalloc(sizeof *lc);
+ lc->type = LAYOUT_WINDOWPANE;
+ lc->parent = lcparent;
+
+ TAILQ_INIT(&lc->cells);
+
+ lc->sx = UINT_MAX;
+ lc->sy = UINT_MAX;
+
+ lc->xoff = UINT_MAX;
+ lc->yoff = UINT_MAX;
+
+ lc->wp = NULL;
+
+ return (lc);
}
-int
-layout_lookup(const char *name)
+void
+layout_free_cell(struct layout_cell *lc)
{
- u_int i;
- int matched = -1;
-
- for (i = 0; i < nitems(layouts); i++) {
- if (strncmp(layouts[i].name, name, strlen(name)) == 0) {
- if (matched != -1) /* ambiguous */
- return (-1);
- matched = i;
+ struct layout_cell *lcchild;
+
+ switch (lc->type) {
+ case LAYOUT_LEFTRIGHT:
+ case LAYOUT_TOPBOTTOM:
+ while (!TAILQ_EMPTY(&lc->cells)) {
+ lcchild = TAILQ_FIRST(&lc->cells);
+ TAILQ_REMOVE(&lc->cells, lcchild, entry);
+ layout_free_cell(lcchild);
}
+ break;
+ case LAYOUT_WINDOWPANE:
+ if (lc->wp != NULL)
+ lc->wp->layout_cell = NULL;
+ break;
}
- return (matched);
+ xfree(lc);
}
-int
-layout_select(struct window *w, u_int layout)
+void
+layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
{
- if (layout > nitems(layouts) - 1 || layout == w->layout)
- return (-1);
- w->layout = layout;
-
- layout_refresh(w, 0);
- return (0);
+ struct layout_cell *lcchild;
+
+ log_debug(
+ "%s:%*s%p type %u [parent %p] wp=%p [%u,%u %ux%u]", hdr, n, " ", lc,
+ lc->type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx, lc->sy);
+ switch (lc->type) {
+ case LAYOUT_LEFTRIGHT:
+ case LAYOUT_TOPBOTTOM:
+ TAILQ_FOREACH(lcchild, &lc->cells, entry)
+ layout_print_cell(lcchild, hdr, n + 1);
+ break;
+ case LAYOUT_WINDOWPANE:
+ break;
+ }
}
void
-layout_next(struct window *w)
+layout_set_size(
+ struct layout_cell *lc, u_int sx, u_int sy, u_int xoff, u_int yoff)
{
- w->layout++;
- if (w->layout > nitems(layouts) - 1)
- w->layout = 0;
- layout_refresh(w, 0);
+ lc->sx = sx;
+ lc->sy = sy;
+
+ lc->xoff = xoff;
+ lc->yoff = yoff;
}
void
-layout_previous(struct window *w)
+layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
{
- if (w->layout == 0)
- w->layout = nitems(layouts) - 1;
- else
- w->layout--;
- layout_refresh(w, 0);
+ lc->type = LAYOUT_WINDOWPANE;
+
+ TAILQ_INIT(&lc->cells);
+
+ wp->layout_cell = lc;
+ lc->wp = wp;
}
void
-layout_refresh(struct window *w, int active_only)
+layout_make_node(struct layout_cell *lc, enum layout_type type)
{
- layouts[w->layout].refresh(w, active_only);
- server_redraw_window(w);
-}
+ if (type == LAYOUT_WINDOWPANE)
+ fatalx("bad layout type");
+ lc->type = type;
-int
-layout_resize(struct window_pane *wp, int adjust)
-{
- struct window *w = wp->window;
+ TAILQ_INIT(&lc->cells);
- if (layouts[w->layout].resize == NULL)
- return (-1);
- layouts[w->layout].resize(wp, adjust);
- return (0);
+ if (lc->wp != NULL)
+ lc->wp->layout_cell = NULL;
+ lc->wp = NULL;
}
+/* Fix cell offsets based on their sizes. */
void
-layout_active_only_refresh(struct window *w, unused int active_only)
+layout_fix_offsets(struct layout_cell *lc)
{
- struct window_pane *wp;
- u_int xoff;
-
- xoff = w->sx;
- TAILQ_FOREACH(wp, &w->panes, entry) {
- /* Put the active pane on screen and the rest to the right. */
- if (wp == w->active)
- wp->xoff = 0;
- else {
- wp->xoff = xoff;
- xoff += w->sx;
+ struct layout_cell *lcchild;
+ u_int xoff, yoff;
+
+ if (lc->type == LAYOUT_LEFTRIGHT) {
+ xoff = lc->xoff;
+ TAILQ_FOREACH(lcchild, &lc->cells, entry) {
+ lcchild->xoff = xoff;
+ lcchild->yoff = lc->yoff;
+ if (lcchild->type != LAYOUT_WINDOWPANE)
+ layout_fix_offsets(lcchild);
+ xoff += lcchild->sx + 1;
+ }
+ } else {
+ yoff = lc->yoff;
+ TAILQ_FOREACH(lcchild, &lc->cells, entry) {
+ lcchild->xoff = lc->xoff;
+ lcchild->yoff = yoff;
+ if (lcchild->type != LAYOUT_WINDOWPANE)
+ layout_fix_offsets(lcchild);
+ yoff += lcchild->sy + 1;
}
- wp->yoff = 0;
- window_pane_resize(wp, w->sx, w->sy);
}
}
+/* Update pane offsets and sizes based on their cells. */
void
-layout_even_h_refresh(struct window *w, int active_only)
+layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
{
struct window_pane *wp;
- u_int i, n, width, xoff;
+ struct layout_cell *lc;
+ u_int sx, sy;
- if (active_only)
- return;
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if ((lc = wp->layout_cell) == NULL)
+ continue;
+ wp->xoff = lc->xoff;
+ wp->yoff = lc->yoff;
+
+ /*
+ * Layout cells are limited by the smallest size of other cells
+ * within the same row or column; if this isn't the case
+ * resizing becomes difficult.
+ *
+ * However, panes do not have to take up their entire cell, so
+ * they can be cropped to the window edge if the layout
+ * overflows and they are partly visible.
+ *
+ * This stops cells being hidden unnecessarily.
+ */
+
+ /*
+ * Work out the horizontal size. If the pane is actually
+ * outside the window or the entire pane is already visible,
+ * don't crop.
+ */
+ if (lc->xoff >= wsx || lc->xoff + lc->sx < wsx)
+ sx = lc->sx;
+ else {
+ sx = wsx - lc->xoff;
+ if (sx < 1)
+ sx = lc->sx;
+ }
+
+ /*
+ * Similarly for the vertical size; the minimum vertical size
+ * is two because scroll regions cannot be one line.
+ */
+ if (lc->yoff >= wsy || lc->yoff + lc->sy < wsy)
+ sy = lc->sy;
+ else {
+ sy = wsy - lc->yoff;
+ if (sy < 2)
+ sy = lc->sy;
+ }
- /* If the screen is too small, show active only. */
- if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) {
- layout_active_only_refresh(w, active_only);
- return;
+ window_pane_resize(wp, sx, sy);
}
+}
- /* Get number of panes. */
- n = window_count_panes(w);
- if (n == 0)
- return;
-
- /* How many can we fit? */
- if (w->sx / n < PANE_MINIMUM) {
- width = PANE_MINIMUM;
- n = UINT_MAX;
- } else
- width = w->sx / n;
+/* Calculate how much size is available to be removed from a cell. */
+u_int
+layout_resize_check(struct layout_cell *lc, enum layout_type type)
+{
+ struct layout_cell *lcchild;
+ u_int available, minimum;
- /* Fit the panes. */
- i = xoff = 0;
- TAILQ_FOREACH(wp, &w->panes, entry) {
- wp->xoff = xoff;
- wp->yoff = 0;
- if (i != n - 1)
- window_pane_resize(wp, width - 1, w->sy);
+ if (lc->type == LAYOUT_WINDOWPANE) {
+ /* Space available in this cell only. */
+ if (type == LAYOUT_LEFTRIGHT)
+ available = lc->sx;
else
- window_pane_resize(wp, width, w->sy);
-
- i++;
- xoff += width;
+ available = lc->sy;
+
+ if (available > PANE_MINIMUM)
+ available -= PANE_MINIMUM;
+ else
+ available = 0;
+ } else if (lc->type == type) {
+ /* Same type: total of available space in all child cells. */
+ available = 0;
+ TAILQ_FOREACH(lcchild, &lc->cells, entry)
+ available += layout_resize_check(lcchild, type);
+ } else {
+ /* Different type: minimum of available space in child cells. */
+ minimum = UINT_MAX;
+ TAILQ_FOREACH(lcchild, &lc->cells, entry) {
+ available = layout_resize_check(lcchild, type);
+ if (available < minimum)
+ minimum = available;
+ }
+ available = minimum;
}
- /* Any space left? */
- while (xoff++ < w->sx) {
- wp = TAILQ_LAST(&w->panes, window_panes);
- window_pane_resize(wp, wp->sx + 1, wp->sy);
- }
+ return (available);
}
+/*
+ * Adjust cell size evenly, including altering its children. This function
+ * expects the change to have already been bounded to the space available.
+ */
void
-layout_even_v_refresh(struct window *w, int active_only)
+layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
{
- struct window_pane *wp;
- u_int i, n, height, yoff;
+ struct layout_cell *lcchild;
- if (active_only)
+ /* Adjust the cell size. */
+ if (type == LAYOUT_LEFTRIGHT)
+ lc->sx += change;
+ else
+ lc->sy += change;
+
+ /* If this is a leaf cell, that is all that is necessary. */
+ if (type == LAYOUT_WINDOWPANE)
return;
- /* If the screen is too small, show active only. */
- if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) {
- layout_active_only_refresh(w, active_only);
+ /* Child cell runs in a different direction. */
+ if (lc->type != type) {
+ TAILQ_FOREACH(lcchild, &lc->cells, entry)
+ layout_resize_adjust(lcchild, type, change);
return;
}
- /* Get number of panes. */
- n = window_count_panes(w);
- if (n == 0)
- return;
+ /*
+ * Child cell runs in the same direction. Adjust each child equally
+ * until no further change is possible.
+ */
+ while (change != 0) {
+ TAILQ_FOREACH(lcchild, &lc->cells, entry) {
+ if (change == 0)
+ break;
+ if (change > 0) {
+ layout_resize_adjust(lcchild, type, 1);
+ change--;
+ continue;
+ }
+ if (layout_resize_check(lcchild, type) > 0) {
+ layout_resize_adjust(lcchild, type, -1);
+ change++;
+ }
+ }
+ }
+}
- /* How many can we fit? */
- if (w->sy / n < PANE_MINIMUM) {
- height = PANE_MINIMUM;
- n = UINT_MAX;
- } else
- height = w->sy / n;
+void
+layout_init(struct window *w)
+{
+ struct layout_cell *lc;
- /* Fit the panes. */
- i = yoff = 0;
- TAILQ_FOREACH(wp, &w->panes, entry) {
- wp->xoff = 0;
- wp->yoff = yoff;
- if (i != n - 1)
- window_pane_resize(wp, w->sx, height - 1);
- else
- window_pane_resize(wp, w->sx, height);
+ lc = w->layout_root = layout_create_cell(NULL);
+ layout_set_size(lc, w->sx, w->sy, 0, 0);
+ layout_make_leaf(lc, TAILQ_FIRST(&w->panes));
- i++;
- yoff += height;
- }
+ layout_fix_panes(w, w->sx, w->sy);
+}
- /* Any space left? */
- while (yoff++ < w->sy) {
- wp = TAILQ_LAST(&w->panes, window_panes);
- window_pane_resize(wp, wp->sx, wp->sy + 1);
+void
+layout_free(struct window *w)
+{
+ layout_free_cell(w->layout_root);
+}
+
+/* Resize the entire layout after window resize. */
+void
+layout_resize(struct window *w, u_int sx, u_int sy)
+{
+ struct layout_cell *lc = w->layout_root;
+ int xlimit, ylimit, xchange, ychange;
+
+ /*
+ * Adjust horizontally. Do not attempt to reduce the layout lower than
+ * the minimum (more than the amount returned by layout_resize_check).
+ *
+ * This can mean that the window size is smaller than the total layout
+ * size: redrawing this is handled at a higher level, but it does leave
+ * a problem with growing the window size here: if the current size is
+ * < the minimum, growing proportionately by adding to each pane is
+ * wrong as it would keep the layout size larger than the window size.
+ * Instead, spread the difference between the minimum and the new size
+ * out proportionately - this should leave the layout fitting the new
+ * window size.
+ */
+ xchange = sx - w->sx;
+ xlimit = layout_resize_check(lc, LAYOUT_LEFTRIGHT);
+ if (xchange < 0 && xchange < -xlimit)
+ xchange = -xlimit;
+ if (xlimit == 0) {
+ if (sx <= lc->sx) /* lc->sx is minimum possible */
+ xchange = 0;
+ else
+ xchange = sx - lc->sx;
}
+ if (xchange != 0)
+ layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, xchange);
+
+ /* Adjust vertically in a similar fashion. */
+ ychange = sy - w->sy;
+ ylimit = layout_resize_check(lc, LAYOUT_TOPBOTTOM);
+ if (ychange < 0 && ychange < -ylimit)
+ ychange = -ylimit;
+ if (ylimit == 0) {
+ if (sy <= lc->sy) /* lc->sy is minimum possible */
+ ychange = 0;
+ else
+ ychange = sy - lc->sy;
+ }
+ if (ychange != 0)
+ layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, ychange);
+
+ /* Fix cell offsets. */
+ layout_fix_offsets(lc);
+ layout_fix_panes(w, sx, sy);
}
+/* Resize a single pane within the layout. */
void
-layout_main_v_refresh(struct window *w, int active_only)
+layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
{
- struct window_pane *wp;
- u_int i, n, mainwidth, height, yoff;
+ struct layout_cell *lc, *lcparent;
+ int needed, size;
- if (active_only)
- return;
+ lc = wp->layout_cell;
- /* Get number of panes. */
- n = window_count_panes(w);
- if (n == 0)
+ /* Find next parent of the same type. */
+ lcparent = lc->parent;
+ while (lcparent != NULL && lcparent->type != type) {
+ lc = lcparent;
+ lcparent = lc->parent;
+ }
+ if (lcparent == NULL)
return;
- /* Get the main pane width and add one for separator line. */
- mainwidth = options_get_number(&w->options, "main-pane-width") + 1;
+ /* If this is the last cell, move back one. */
+ if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
+ lc = TAILQ_PREV(lc, layout_cells, entry);
+
+ /* Grow or shrink the cell. */
+ needed = change;
+ while (needed != 0) {
+ if (change > 0) {
+ size = layout_resize_pane_grow(lc, type, needed);
+ needed -= size;
+ } else {
+ size = layout_resize_pane_shrink(lc, type, needed);
+ needed += size;
+ }
- /* Need >1 pane and minimum columns; if fewer, display active only. */
- if (n == 1 ||
- w->sx < mainwidth + PANE_MINIMUM || w->sy < PANE_MINIMUM) {
- layout_active_only_refresh(w, active_only);
- return;
+ if (size == 0) /* no more change possible */
+ break;
}
- n--;
+
+ /* Fix cell offsets. */
+ layout_fix_offsets(wp->window->layout_root);
+ layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
+}
- /* How many can we fit, not including first? */
- if (w->sy / n < PANE_MINIMUM) {
- height = PANE_MINIMUM;
- n = w->sy / PANE_MINIMUM;
- } else
- height = w->sy / n;
+int
+layout_resize_pane_grow(
+ struct layout_cell *lc, enum layout_type type, int needed)
+{
+ struct layout_cell *lcadd, *lcremove;
+ u_int size;
+
+ /* Growing. Always add to the current cell. */
+ lcadd = lc;
+
+ /* Look towards the tail for a suitable cell for reduction. */
+ lcremove = TAILQ_NEXT(lc, entry);
+ while (lcremove != NULL) {
+ size = layout_resize_check(lcremove, type);
+ if (size > 0)
+ break;
+ lcremove = TAILQ_NEXT(lcremove, entry);
+ }
- /* Fit the panes. */
- i = yoff = 0;
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if (wp == TAILQ_FIRST(&w->panes)) {
- wp->xoff = 0;
- wp->yoff = 0;
- window_pane_resize(wp, mainwidth - 1, w->sy);
- continue;
+ /* If none found, look towards the head. */
+ if (lcremove == NULL) {
+ lcremove = TAILQ_PREV(lc, layout_cells, entry);
+ while (lcremove != NULL) {
+ size = layout_resize_check(lcremove, type);
+ if (size > 0)
+ break;
+ lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
}
-
- wp->xoff = mainwidth;
- wp->yoff = yoff;
- if (i != n - 1)
- window_pane_resize(wp, w->sx - mainwidth, height - 1);
- else
- window_pane_resize(wp, w->sx - mainwidth, height);
-
- i++;
- yoff += height;
+ if (lcremove == NULL)
+ return (0);
}
- /* Any space left? */
- while (yoff++ < w->sy) {
- wp = TAILQ_LAST(&w->panes, window_panes);
- while (wp != NULL && wp == TAILQ_FIRST(&w->panes))
- wp = TAILQ_PREV(wp, window_panes, entry);
- if (wp == NULL)
- break;
- window_pane_resize(wp, wp->sx, wp->sy + 1);
- }
+ /* Change the cells. */
+ if (size > (u_int) needed)
+ size = needed;
+ layout_resize_adjust(lcadd, type, size);
+ layout_resize_adjust(lcremove, type, -size);
+ return (size);
}
-void
-layout_main_h_refresh(struct window *w, int active_only)
+int
+layout_resize_pane_shrink(
+ struct layout_cell *lc, enum layout_type type, int needed)
{
- struct window_pane *wp;
- u_int i, n, mainheight, width, xoff;
-
- if (active_only)
- return;
-
- /* Get number of panes. */
- n = window_count_panes(w);
- if (n == 0)
- return;
+ struct layout_cell *lcadd, *lcremove;
+ u_int size;
+
+ /* Shrinking. Find cell to remove from by walking towards head. */
+ lcremove = lc;
+ do {
+ size = layout_resize_check(lcremove, type);
+ if (size != 0)
+ break;
+ lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
+ } while (lcremove != NULL);
+ if (lcremove == NULL)
+ return (0);
+
+ /* And add onto the next cell (from the original cell). */
+ lcadd = TAILQ_NEXT(lc, entry);
+ if (lcadd == NULL)
+ return (0);
+
+ /* Change the cells. */
+ if (size > (u_int) -needed)
+ size = -needed;
+ layout_resize_adjust(lcadd, type, size);
+ layout_resize_adjust(lcremove, type, -size);
+ return (size);
+}
- /* Get the main pane height and add one for separator line. */
- mainheight = options_get_number(&w->options, "main-pane-height") + 1;
+/* Split a pane into two. size is a hint, or -1 for default half/half split. */
+int
+layout_split_pane(struct window_pane *wp,
+ enum layout_type type, int size, struct window_pane *new_wp)
+{
+ struct layout_cell *lc, *lcparent, *lcnew;
+ u_int sx, sy, xoff, yoff, size1, size2;
+
+ lc = wp->layout_cell;
+
+ /* Copy the old cell size. */
+ sx = lc->sx;
+ sy = lc->sy;
+ xoff = lc->xoff;
+ yoff = lc->yoff;
+
+ /* Check there is enough space for the two new panes. */
+ switch (type) {
+ case LAYOUT_LEFTRIGHT:
+ if (sx < PANE_MINIMUM * 2 + 1)
+ return (-1);
+ break;
+ case LAYOUT_TOPBOTTOM:
+ if (sy < PANE_MINIMUM * 2 + 1)
+ return (-1);
+ break;
+ default:
+ fatalx("bad layout type");
+ }
+
+ if (lc->parent != NULL && lc->parent->type == type) {
+ /*
+ * If the parent exists and is of the same type as the split,
+ * create a new cell and insert it after this one.
+ */
+
+ /* Create the new child cell. */
+ lcnew = layout_create_cell(lc->parent);
+ TAILQ_INSERT_AFTER(&lc->parent->cells, lc, lcnew, entry);
+ } else {
+ /*
+ * Otherwise create a new parent and insert it.
+ */
+
+ /* Create and insert the replacement parent. */
+ lcparent = layout_create_cell(lc->parent);
+ layout_make_node(lcparent, type);
+ layout_set_size(lcparent, sx, sy, xoff, yoff);
+ if (lc->parent == NULL)
+ wp->window->layout_root = lcparent;
+ else
+ TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry);
+
+ /* Insert the old cell. */
+ lc->parent = lcparent;
+ TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
+
+ /* Create the new child cell. */
+ lcnew = layout_create_cell(lcparent);
+ TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
+ }
- /* Need >1 pane and minimum rows; if fewer, display active only. */
- if (n == 1 ||
- w->sy < mainheight + PANE_MINIMUM || w->sx < PANE_MINIMUM) {
- layout_active_only_refresh(w, active_only);
- return;
+ /* Set new cell sizes. size is the target size or -1 for middle split,
+ * size1 is the size of the top/left and size2 the bottom/right.
+ */
+ switch (type) {
+ case LAYOUT_LEFTRIGHT:
+ if (size < 0)
+ size2 = ((sx + 1) / 2) - 1;
+ else
+ size2 = size;
+ if (size2 < PANE_MINIMUM)
+ size2 = PANE_MINIMUM;
+ else if (size2 > sx - 2)
+ size2 = sx - 2;
+ size1 = sx - 1 - size2;
+ layout_set_size(lc, size1, sy, xoff, yoff);
+ layout_set_size(lcnew, size2, sy, xoff + lc->sx + 1, yoff);
+ break;
+ case LAYOUT_TOPBOTTOM:
+ if (size < 0)
+ size2 = ((sy + 1) / 2) - 1;
+ else
+ size2 = size;
+ if (size2 < PANE_MINIMUM)
+ size2 = PANE_MINIMUM;
+ else if (size2 > sy - 2)
+ size2 = sy - 2;
+ size1 = sy - 1 - size2;
+ layout_set_size(lc, sx, size1, xoff, yoff);
+ layout_set_size(lcnew, sx, size2, xoff, yoff + lc->sy + 1);
+ break;
+ default:
+ fatalx("bad layout type");
}
- n--;
- /* How many can we fit, not including first? */
- if (w->sx / n < PANE_MINIMUM) {
- width = PANE_MINIMUM;
- n = w->sx / PANE_MINIMUM;
- } else
- width = w->sx / n;
+ /* Assign the panes. */
+ layout_make_leaf(lc, wp);
+ layout_make_leaf(lcnew, new_wp);
- /* Fit the panes. */
- i = xoff = 0;
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if (wp == TAILQ_FIRST(&w->panes)) {
- wp->xoff = 0;
- wp->yoff = 0;
- window_pane_resize(wp, w->sx, mainheight - 1);
- continue;
- }
+ /* Fix pane offsets and sizes. */
+ layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
- wp->xoff = xoff;
- wp->yoff = mainheight;
- if (i != n - 1)
- window_pane_resize(wp, width - 1, w->sy - mainheight);
- else
- window_pane_resize(wp, width - 1, w->sy - mainheight);
+ return (0);
+}
- i++;
- xoff += width;
+/* Destroy the layout associated with a pane and redistribute the space. */
+void
+layout_close_pane(struct window_pane *wp)
+{
+ struct layout_cell *lc, *lcother, *lcparent;
+
+ lc = wp->layout_cell;
+ lcparent = lc->parent;
+
+ /*
+ * If no parent, this is the last pane so window close is imminent and
+ * there is no need to resize anything.
+ */
+ if (lcparent == NULL) {
+ layout_free_cell(lc);
+ wp->window->layout_root = NULL;
+ return;
}
- /* Any space left? */
- while (xoff++ < w->sx + 1) {
- wp = TAILQ_LAST(&w->panes, window_panes);
- while (wp != NULL && wp == TAILQ_FIRST(&w->panes))
- wp = TAILQ_PREV(wp, window_panes, entry);
- if (wp == NULL)
- break;
- window_pane_resize(wp, wp->sx + 1, wp->sy);
+ /* Merge the space into the previous or next cell. */
+ if (lc == TAILQ_FIRST(&lcparent->cells))
+ lcother = TAILQ_NEXT(lc, entry);
+ else
+ lcother = TAILQ_PREV(lc, layout_cells, entry);
+ if (lcparent->type == LAYOUT_LEFTRIGHT)
+ layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
+ else
+ layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
+
+ /* Remove this from the parent's list. */
+ TAILQ_REMOVE(&lcparent->cells, lc, entry);
+ layout_free_cell(lc);
+
+ /*
+ * If the parent now has one cell, remove the parent from the tree and
+ * replace it by that cell.
+ */
+ lc = TAILQ_FIRST(&lcparent->cells);
+ if (TAILQ_NEXT(lc, entry) == NULL) {
+ TAILQ_REMOVE(&lcparent->cells, lc, entry);
+
+ lc->parent = lcparent->parent;
+ if (lc->parent == NULL) {
+ lc->xoff = 0; lc->yoff = 0;
+ wp->window->layout_root = lc;
+ } else
+ TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
+
+ layout_free_cell(lcparent);
}
+
+ /* Fix pane offsets and sizes. */
+ layout_fix_offsets(wp->window->layout_root);
+ layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
}
+
diff --git a/usr.bin/tmux/resize.c b/usr.bin/tmux/resize.c
index 29d9f883bbb..7f5aaa48aac 100644
--- a/usr.bin/tmux/resize.c
+++ b/usr.bin/tmux/resize.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: resize.c,v 1.2 2009/07/14 07:23:36 nicm Exp $ */
+/* $OpenBSD: resize.c,v 1.3 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -132,6 +132,7 @@ recalculate_sizes(void)
log_debug(
"window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy);
+ layout_resize(w, ssx, ssy);
window_resize(w, ssx, ssy);
/*
@@ -148,6 +149,5 @@ recalculate_sizes(void)
}
server_redraw_window(w);
- layout_refresh(w, 0);
}
}
diff --git a/usr.bin/tmux/server.c b/usr.bin/tmux/server.c
index 3e4c2adf8a1..a33a5ff91bc 100644
--- a/usr.bin/tmux/server.c
+++ b/usr.bin/tmux/server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server.c,v 1.10 2009/07/18 14:59:25 nicm Exp $ */
+/* $OpenBSD: server.c,v 1.11 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -840,7 +840,9 @@ server_handle_client(struct client *c)
/* Ensure cursor position and mode settings. */
status = options_get_number(&c->session->options, "status");
- if (wp->yoff + s->cy < c->tty.sy - status)
+ if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
+ tty_cursor(&c->tty, 0, 0, 0, 0);
+ else
tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff);
mode = s->mode;
@@ -1072,9 +1074,9 @@ server_check_window(struct window *w)
* pane dies).
*/
if (wp->fd == -1 && !flag) {
+ layout_close_pane(wp);
window_remove_pane(w, wp);
server_redraw_window(w);
- layout_refresh(w, 0);
} else
destroyed = 0;
wp = wq;
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index 5bf07fa834a..7948f8eeac4 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.37 2009/07/18 14:59:25 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.38 2009/07/19 13:21:40 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 18 2009 $
+.Dd $Mdocdate: July 19 2009 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -393,15 +393,17 @@ each pane takes up a certain area of the display and is a separate terminal.
A window may be split into panes using the
.Ic split-window
command.
-.Pp
-Panes are numbered beginning from zero; in horizontal layouts zero is the
-leftmost pane and in vertical the topmost.
-.Pp
-Panes may be arranged using several layouts.
-The layout may be cycled with the
-.Ic next-layout
+Windows may be split horizontally (with the
+.Fl h
+flag) or vertically.
+Panes may be resized with the
+.Ic resize-pane
command (bound to
-.Ql C-space
+.Ql C-up ,
+.Ql C-down
+.Ql C-left
+and
+.Ql C-right
by default), the current pane may be changed with the
.Ic up-pane
and
@@ -410,12 +412,22 @@ commands and the
.Ic rotate-window
and
.Ic swap-pane
-commands may be used to swap panes without changing the window layout.
+commands may be used to swap panes without changing their position.
+Panes are numbered beginning from zero in the order they are created.
+.Pp
+A number of preset
+.Em layouts
+are available.
+These may be selected with the
+.Ic select-layout
+command or cycled with
+.Ic next-layout
+(bound to
+.Ql C-space
+by default); once a layout is chosen, panes within it may be moved and resized as normal.
.Pp
The following layouts are supported:
.Bl -tag -width Ds
-.It Ic active-only
-Only the active pane is shown \(en all other panes are hidden.
.It Ic even-horizontal
Panes are spread out evenly from left to right across the window.
.It Ic even-vertical
@@ -434,11 +446,6 @@ bottom along the right.
See the
.Em main-pane-width
window option.
-.It Ic manual
-Manual layout splits windows vertically (running across); only with this layout
-may panes be resized using the
-.Ic resize-pane
-command.
.El
.Sh STATUS LINE
.Nm
@@ -980,7 +987,7 @@ Rename the current window, or the window at
if specified, to
.Ar new-name .
.It Xo Ic resize-pane
-.Op Fl DU
+.Op Fl DLUR
.Op Fl p Ar pane-index
.Op Fl t Ar target-window
.Op Ar adjustment
@@ -988,11 +995,15 @@ if specified, to
.D1 (alias: Ic resizep )
Resize a pane, upward with
.Fl U
-(the default) or downward with
-.Fl D .
+(the default), downward with
+.Fl D ,
+to the left with
+.Fl L
+and to the right with
+.Fl R.
The
.Ar adjustment
-is given in lines (the default is 1).
+is given in lines or cells (the default is 1).
.It Xo Ic respawn-window
.Op Fl k
.Op Fl t Ar target-window
@@ -1520,38 +1531,30 @@ is used.
Execute commands from
.Ar path .
.It Xo Ic split-window
-.Op Fl d
+.Op Fl dhv
.Oo Fl l
-.Ar lines |
+.Ar size |
.Fl p Ar percentage Oc
.Op Fl t Ar target-window
.Op Ar command
.Xc
.D1 (alias: splitw )
-Creates a new window by splitting it vertically.
+Creates a new pane by splitting the active pane:
+.Fl h
+does a horizontal split and
+.Fl v
+a vertical split; if neither is specified,
+.Fl v
+is assumed.
The
.Fl l
and
.Fl p
-options specify the size of the new window in lines, or as a percentage,
-respectively.
+options specify the size of the new window in lines (for vertical split) or in
+cells (for horizontal split), or as a percentage, respectively.
All other options have the same meaning as in the
.Ic new-window
command.
-.Pp
-A few notes with regard to panes:
-.Bl -enum -compact
-.It
-If attempting to split a window with less than eight lines, an error will be
-shown.
-.It
-If the window is resized, as many panes are shown as can fit without reducing
-them below four lines.
-.It
-The minimum pane size is four lines (including the separator line).
-.It
-The panes are indexed from top (0) to bottom, with no numbers skipped.
-.El
.It Xo Ic start-server
.Xc
.D1 (alias: Ic start )
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index 0cc5ca01fb6..be72774fb6d 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.38 2009/07/18 14:59:25 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.39 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -47,8 +47,11 @@ extern const char *__progname;
/* Default prompt history length. */
#define PROMPT_HISTORY 100
-/* Minimum pane size. */
-#define PANE_MINIMUM 5 /* includes separator line */
+/*
+ * Minimum layout cell size, NOT including separator line. The scroll region
+ * cannot be one line in height so this must be at least two.
+ */
+#define PANE_MINIMUM 2
/* Automatic name refresh interval, in milliseconds. */
#define NAME_INTERVAL 500
@@ -592,6 +595,7 @@ struct window_mode {
/* Child window structure. */
struct window_pane {
struct window *window;
+ struct layout_cell *layout_cell;
u_int sx;
u_int sy;
@@ -635,7 +639,9 @@ struct window {
struct window_pane *active;
struct window_panes panes;
+
u_int layout;
+ struct layout_cell *layout_root;
u_int sx;
u_int sy;
@@ -664,6 +670,34 @@ struct winlink {
RB_HEAD(winlinks, winlink);
SLIST_HEAD(winlink_stack, winlink);
+/* Layout direction. */
+enum layout_type {
+ LAYOUT_LEFTRIGHT,
+ LAYOUT_TOPBOTTOM,
+ LAYOUT_WINDOWPANE
+};
+
+/* Layout cells queue. */
+TAILQ_HEAD(layout_cells, layout_cell);
+
+/* Layout cell. */
+struct layout_cell {
+ enum layout_type type;
+
+ struct layout_cell *parent;
+
+ u_int sx;
+ u_int sy;
+
+ u_int xoff;
+ u_int yoff;
+
+ struct window_pane *wp;
+ struct layout_cells cells;
+
+ TAILQ_ENTRY(layout_cell) entry;
+};
+
/* Paste buffer. */
struct paste_buffer {
char *data;
@@ -1446,8 +1480,7 @@ struct window *window_create(const char *, const char *,
void window_destroy(struct window *);
int window_resize(struct window *, u_int, u_int);
void window_set_active_pane(struct window *, struct window_pane *);
-struct window_pane *window_add_pane(struct window *, int,
- const char *, const char *, const char **, u_int, char **);
+struct window_pane *window_add_pane(struct window *, u_int, char **);
void window_remove_pane(struct window *, struct window_pane *);
struct window_pane *window_pane_at_index(struct window *, u_int);
u_int window_pane_index(struct window *, struct window_pane *);
@@ -1467,20 +1500,38 @@ void window_pane_mouse(struct window_pane *,
struct client *, u_char, u_char, u_char);
int window_pane_visible(struct window_pane *);
char *window_pane_search(
- struct window_pane *, const char *, u_int *);
+ struct window_pane *, const char *, u_int *);
/* layout.c */
-const char * layout_name(struct window *);
-int layout_lookup(const char *);
-void layout_refresh(struct window *, int);
-int layout_resize(struct window_pane *, int);
-int layout_select(struct window *, u_int);
-void layout_next(struct window *);
-void layout_previous(struct window *);
-
-/* layout-manual.c */
-void layout_manual_v_refresh(struct window *, int);
-void layout_manual_v_resize(struct window_pane *, int);
+struct layout_cell *layout_create_cell(struct layout_cell *);
+void layout_free_cell(struct layout_cell *);
+void layout_print_cell(struct layout_cell *, const char *, u_int);
+void layout_set_size(
+ struct layout_cell *, u_int, u_int, u_int, u_int);
+void layout_make_leaf(
+ struct layout_cell *, struct window_pane *);
+void layout_make_node(struct layout_cell *, enum layout_type);
+void layout_fix_offsets(struct layout_cell *);
+void layout_fix_panes(struct window *, u_int, u_int);
+u_int layout_resize_check(struct layout_cell *, enum layout_type);
+void layout_resize_adjust(
+ struct layout_cell *, enum layout_type, int);
+void layout_init(struct window *);
+void layout_free(struct window *);
+void layout_resize(struct window *, u_int, u_int);
+void layout_resize_pane(
+ struct window_pane *, enum layout_type, int);
+int layout_split_pane(struct window_pane *,
+ enum layout_type, int, struct window_pane *);
+void layout_close_pane(struct window_pane *);
+
+/* layout-set.c */
+const char *layout_set_name(u_int);
+int layout_set_lookup(const char *);
+u_int layout_set_select(struct window *, u_int);
+u_int layout_set_next(struct window *);
+u_int layout_set_previous(struct window *);
+void layout_set_active_changed(struct window *);
/* window-clock.c */
extern const struct window_mode window_clock_mode;
diff --git a/usr.bin/tmux/window.c b/usr.bin/tmux/window.c
index f4f60fc6f57..c632b1eeba4 100644
--- a/usr.bin/tmux/window.c
+++ b/usr.bin/tmux/window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: window.c,v 1.13 2009/07/17 18:45:08 nicm Exp $ */
+/* $OpenBSD: window.c,v 1.14 2009/07/19 13:21:40 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -35,7 +35,7 @@
#include "tmux.h"
/*
- * Each window is attached to one or two panes, each of which is a pty. This
+ * Each window is attached to a number of panes, each of which is a pty. This
* file contains code to handle them.
*
* A pane has two buffers attached, these are filled and emptied by the main
@@ -230,8 +230,10 @@ window_create1(u_int sx, u_int sy)
TAILQ_INIT(&w->panes);
w->active = NULL;
- w->layout = 0;
+ w->layout = 0;
+ w->layout_root = NULL;
+
w->sx = sx;
w->sy = sy;
@@ -254,15 +256,20 @@ struct window *
window_create(const char *name, const char *cmd, const char *cwd,
const char **envp, u_int sx, u_int sy, u_int hlimit, char **cause)
{
- struct window *w;
+ struct window *w;
+ struct window_pane *wp;
w = window_create1(sx, sy);
- if (window_add_pane(w, -1, cmd, cwd, envp, hlimit, cause) == NULL) {
+ if ((wp = window_add_pane(w, hlimit, cause)) == NULL) {
+ window_destroy(w);
+ return (NULL);
+ }
+ layout_init(w);
+ if (window_pane_spawn(wp, cmd, cwd, envp, cause) != 0) {
window_destroy(w);
return (NULL);
}
w->active = TAILQ_FIRST(&w->panes);
-
if (name != NULL) {
w->name = xstrdup(name);
options_set_number(&w->options, "automatic-rename", 0);
@@ -282,6 +289,9 @@ window_destroy(struct window *w)
while (!ARRAY_EMPTY(&windows) && ARRAY_LAST(&windows) == NULL)
ARRAY_TRUNC(&windows, 1);
+ if (w->layout_root != NULL)
+ layout_free(w);
+
options_free(&w->options);
window_destroy_panes(w);
@@ -304,7 +314,6 @@ void
window_set_active_pane(struct window *w, struct window_pane *wp)
{
w->active = wp;
-
while (!window_pane_visible(w->active)) {
w->active = TAILQ_PREV(w->active, window_panes, entry);
if (w->active == NULL)
@@ -315,41 +324,15 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
}
struct window_pane *
-window_add_pane(struct window *w, int wanty, const char *cmd,
- const char *cwd, const char **envp, u_int hlimit, char **cause)
+window_add_pane(struct window *w, u_int hlimit, unused char **cause)
{
struct window_pane *wp;
- u_int sizey;
- if (TAILQ_EMPTY(&w->panes))
- wanty = w->sy;
- else {
- sizey = w->active->sy - 1; /* for separator */
- if (sizey < PANE_MINIMUM * 2) {
- *cause = xstrdup("pane too small");
- return (NULL);
- }
-
- if (wanty == -1)
- wanty = sizey / 2;
-
- if (wanty < PANE_MINIMUM)
- wanty = PANE_MINIMUM;
- if ((u_int) wanty > sizey - PANE_MINIMUM)
- wanty = sizey - PANE_MINIMUM;
-
- window_pane_resize(w->active, w->sx, sizey - wanty);
- }
-
- wp = window_pane_create(w, w->sx, wanty, hlimit);
+ wp = window_pane_create(w, w->sx, w->sy, hlimit);
if (TAILQ_EMPTY(&w->panes))
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
else
TAILQ_INSERT_AFTER(&w->panes, w->active, wp, entry);
- if (window_pane_spawn(wp, cmd, cwd, envp, cause) != 0) {
- window_remove_pane(w, wp);
- return (NULL);
- }
return (wp);
}
@@ -435,6 +418,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->mode = NULL;
+ wp->layout_cell = NULL;
+
wp->xoff = 0;
wp->yoff = 0;