diff --git a/CHANGES b/CHANGES index bd26873f..ad456cfa 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +12 January 2009 + +* Make the window pane code handle panes of different sizes, and add a -l + and -p arguments to split-window to specify the new window size in lines + or as a percentage. + 11 January 2009 * GCC screws up copying (window-copy.c) so build with -O0 until I have time to @@ -876,7 +882,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.194 2009-01-12 00:52:37 nicm Exp $ +$Id: CHANGES,v 1.195 2009-01-12 18:22:47 nicm Exp $ LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 56434f67..66360f65 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -1,4 +1,4 @@ -/* $Id: cmd-list-windows.c,v 1.26 2009-01-11 23:31:46 nicm Exp $ */ +/* $Id: cmd-list-windows.c,v 1.27 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -81,8 +81,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) ctx->print(ctx, " pane %d:" " %s [%ux%u] [history %u/%u, %llu bytes]", i, name, - screen_size_x(&wp->base), screen_size_y(&wp->base), - gd->hsize, gd->hlimit, size); + wp->sx, wp->sy, gd->hsize, gd->hlimit, size); } } diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 4590206c..4a157e20 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -1,4 +1,4 @@ -/* $Id: cmd-respawn-window.c,v 1.7 2009-01-11 23:31:46 nicm Exp $ */ +/* $Id: cmd-respawn-window.c,v 1.8 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -48,9 +48,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; struct window *w; struct session *s; - const char *env[] = { - NULL /* TMUX= */, "TERM=screen", NULL - }; + const char *env[] = CHILD_ENVIRON; char buf[256]; u_int i; diff --git a/cmd-split-window.c b/cmd-split-window.c index a2879f41..37b220e2 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -1,4 +1,4 @@ -/* $Id: cmd-split-window.c,v 1.2 2009-01-11 23:41:29 nicm Exp $ */ +/* $Id: cmd-split-window.c,v 1.3 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -39,11 +39,14 @@ struct cmd_split_window_data { char *target; char *cmd; int flag_detached; + + int lines; + int percentage; }; const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", - "[-d] [-t target-window] [command]", + "[-d] [-t target-window] [-l lines|-p percentage] [command]", 0, cmd_split_window_init, cmd_split_window_parse, @@ -63,22 +66,49 @@ cmd_split_window_init(struct cmd *self, unused int arg) data->target = NULL; data->cmd = NULL; data->flag_detached = 0; + data->lines = -1; + data->percentage = -1; } int cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_split_window_data *data; - int opt; + int opt, n; + const char *errstr; self->entry->init(self, 0); data = self->data; - while ((opt = getopt(argc, argv, "dt:")) != -1) { + while ((opt = getopt(argc, argv, "dl:p:t:")) != -1) { switch (opt) { case 'd': data->flag_detached = 1; break; + case 'l': + if (data->percentage != -1) + goto usage; + if (data->lines == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "number %s", errstr); + goto error; + } + data->lines = n; + } + break; + case 'p': + if (data->lines != -1) + goto usage; + if (data->percentage == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "number %s", errstr); + goto error; + } + data->percentage = n; + } + break; case 't': if (data->target == NULL) data->target = xstrdup(optarg); @@ -100,6 +130,7 @@ cmd_split_window_parse(struct cmd *self, int argc, char **argv, char **cause) usage: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); +error: self->entry->free(self); return (-1); } @@ -110,17 +141,17 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_split_window_data *data = self->data; struct session *s; struct winlink *wl; - const char *env[] = { - NULL /* TMUX= */, "TERM=screen", NULL - }; + struct window *w; + const char *env[] = CHILD_ENVIRON; char buf[256]; char *cmd, *cwd; - u_int i, sx, sy, hlimit; + u_int i, hlimit, size; if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL) return; + w = wl->window; - if (wl->window->panes[1] != NULL) { + if (w->panes[1] != NULL) { ctx->error(ctx, "window is already split"); return; } @@ -138,19 +169,26 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) else cwd = ctx->cmdclient->cwd; + size = w->sy / 2; + if (data->lines != -1) + size = data->lines; + if (data->percentage != -1) { + if (data->percentage > 100) + data->percentage = 100; + size = (w->sy * data->percentage) / 100; + } + if (size > w->sy) + size = w->sy; /* let window_add_pane sort it out */ + hlimit = options_get_number(&s->options, "history-limit"); - sx = wl->window->sx; - sy = wl->window->sy - (wl->window->sy / 2); - wl->window->panes[1] = window_pane_create(wl->window, sx, sy, hlimit); - if (window_pane_spawn(wl->window->panes[1], cmd, cwd, env) != 0) { + if (window_add_pane(w, size, cmd, cwd, env, hlimit) < 0) { ctx->error(ctx, "command failed: %s", cmd); return; } - window_resize(wl->window, wl->window->sx, wl->window->sy); - server_redraw_window(wl->window); + server_redraw_window(w); if (!data->flag_detached) { - wl->window->active = wl->window->panes[1]; + w->active = w->panes[1]; session_select(s, wl->idx); server_redraw_session(s); } else diff --git a/screen-redraw.c b/screen-redraw.c index df57c7da..f8c8eed5 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1,4 +1,4 @@ -/* $Id: screen-redraw.c,v 1.16 2009-01-11 23:31:46 nicm Exp $ */ +/* $Id: screen-redraw.c,v 1.17 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -30,11 +30,10 @@ void screen_redraw_line(struct client *, struct screen *, u_int, u_int); void screen_redraw_screen(struct client *c, struct screen *s) { - struct winlink *wl = c->session->curw; - u_int i, cx, cy, sy; - int status; - - status = options_get_number(&c->session->options, "status"); + struct window *w = c->session->curw->window; + struct window_pane *wp; + u_int i, cx, cy, sy; + int status; /* Override the normal screen if one is given. */ if (s != NULL) { @@ -50,44 +49,44 @@ screen_redraw_screen(struct client *c, struct screen *s) */ /* Draw the top window. */ - s = wl->window->panes[0]->screen; + wp = w->panes[0]; + s = wp->screen; + sy = screen_size_y(s); - if (screen_size_y(s) == c->sy && wl->window->panes[1] == NULL) + if (screen_size_y(s) == c->sy && w->panes[1] == NULL) sy--; cx = s->cx; cy = s->cy; for (i = 0; i < sy; i++) - screen_redraw_line(c, s, 0, i); + screen_redraw_line(c, s, wp->yoff, i); s->cx = cx; s->cy = cy; /* Draw the bottom window. */ - if (wl->window->panes[1] != NULL) { - s = wl->window->panes[1]->screen; + if (c->sy > 2 && w->panes[1] != NULL) { + wp = w->panes[1]; + s = wp->screen; + sy = screen_size_y(s); - if (!status && screen_size_y(s) == c->sy - (c->sy / 2) - 1) + if (wp->yoff + screen_size_y(s) == s->cy) sy--; cx = s->cx; cy = s->cy; for (i = 0; i < sy; i++) - screen_redraw_line(c, s, wl->window->sy / 2, i); + screen_redraw_line(c, s, wp->yoff, i); s->cx = cx; s->cy = cy; } /* Fill in empty space. */ - if (wl->window->sx < c->sx) { - screen_redraw_blankx( - c, wl->window->sx, c->sx - wl->window->sx); - } - if (wl->window->sy < c->sy - status) { - screen_redraw_blanky( - c, wl->window->sy, c->sy - wl->window->sy); - } + if (w->sx < c->sx) + screen_redraw_blankx(c, w->sx, c->sx - w->sx); + if (w->sy < c->sy - status) + screen_redraw_blanky(c, w->sy, c->sy - w->sy); /* Draw separator line. */ - s = wl->window->panes[0]->screen; - if (screen_size_y(s) != wl->window->sy) + s = w->panes[0]->screen; + if (c->sy > 1 && screen_size_y(s) != w->sy) screen_redraw_blanky(c, screen_size_y(s), 1); /* Draw the status line. */ @@ -147,9 +146,12 @@ screen_redraw_line(struct client *c, struct screen *s, u_int oy, u_int py) { const struct grid_cell *gc; struct grid_cell tc; - u_int i; + u_int i, sx; - for (i = 0; i < screen_size_x(s); i++) { + sx = screen_size_x(s); + if (sx > c->sx) + sx = c->sx; + for (i = 0; i < sx; i++) { s->cx = i; s->cy = py; diff --git a/server.c b/server.c index c9139ba9..dfc71588 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.95 2009-01-11 23:31:46 nicm Exp $ */ +/* $Id: server.c,v 1.96 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -565,8 +565,7 @@ server_handle_client(struct client *c) { struct winlink *wl = c->session->curw; struct window_pane *wp = wl->window->active; - int key, prefix; - u_int oy; + int key, prefix, status; /* Process keys. */ prefix = options_get_number(&c->session->options, "prefix"); @@ -592,14 +591,12 @@ server_handle_client(struct client *c) } /* Ensure the cursor is in the right place and correctly on or off. */ + status = options_get_number(&c->session->options, "status"); if (c->prompt_string == NULL && c->message_string == NULL && - !server_locked && wp->screen->mode & MODE_CURSOR) { - oy = 0; - if (wp == wl->window->panes[1]) - oy = wp->window->sy / 2; - + !server_locked && wp->screen->mode & MODE_CURSOR && + wp->yoff + wp->screen->cy < c->sy - status) { tty_write(&c->tty, wp->screen, 0, TTY_CURSORMODE, 1); - tty_cursor(&c->tty, wp->screen->cx, wp->screen->cy, oy); + tty_cursor(&c->tty, wp->screen->cx, wp->screen->cy, wp->yoff); } else tty_write(&c->tty, wp->screen, 0, TTY_CURSORMODE, 0); } diff --git a/session.c b/session.c index bc8c6126..72dfec75 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $Id: session.c,v 1.49 2009-01-10 19:37:35 nicm Exp $ */ +/* $Id: session.c,v 1.50 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -197,7 +197,7 @@ session_new(struct session *s, const char *name, const char *cmd, const char *cwd, int idx) { struct window *w; - const char *env[] = { NULL /* TMUX= */, "TERM=screen", NULL }; + const char *env[] = CHILD_ENVIRON; char buf[256]; u_int i, hlimit; diff --git a/status.c b/status.c index 6efe6f51..147b9b05 100644 --- a/status.c +++ b/status.c @@ -1,4 +1,4 @@ -/* $Id: status.c,v 1.60 2009-01-11 23:31:46 nicm Exp $ */ +/* $Id: status.c,v 1.61 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -258,18 +258,17 @@ off: * status is off. Not sure this is the right place for this. */ screen_write_start(&ctx, NULL, &c->status); - wp = s->curw->window->panes[1]; - sy = c->sy - (c->sy / 2); - if (wp == NULL) { - wp = s->curw->window->panes[0]; - sy = c->sy; + wp = s->curw->window->panes[0]; + sy = wp->sy; + if (s->curw->window->panes[1] != NULL) { + wp = s->curw->window->panes[1]; + sy += wp->sy + 1; } screen_write_cursormove(&ctx, 0, 0); - if (screen_size_y(wp->screen) < sy) { + if (sy < c->sy - 1) { /* If the screen is too small, use blank. */ for (offset = 0; offset < c->sx; offset++) screen_write_putc(&ctx, &gc, ' '); - abort(); } else { screen_write_copy(&ctx, wp->screen, 0, wp->screen->grid->hsize + screen_size_y(wp->screen) - 1, c->sx, 1); diff --git a/tmux.h b/tmux.h index 7e3ba3b7..ba53033d 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.224 2009-01-11 23:41:29 nicm Exp $ */ +/* $Id: tmux.h,v 1.225 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION -6 +#define PROTOCOL_VERSION -7 /* Shut up gcc warnings about empty if bodies. */ #define RB_AUGMENT(x) do {} while (0) @@ -121,6 +121,9 @@ extern const char *__progname; /* Default prompt history length. */ #define PROMPT_HISTORY 100 +/* Default environment. */ +#define CHILD_ENVIRON { NULL /* TMUX= */, "TERM=screen", NULL } + /* Fatal errors. */ #define fatal(msg) log_fatal("%s: %s", __func__, msg); #define fatalx(msg) log_fatalx("%s: %s", __func__, msg); @@ -570,6 +573,11 @@ struct window_mode { /* Child window structure. */ struct window_pane { struct window *window; + + u_int sx; + u_int sy; + + u_int yoff; char *cmd; char *cwd; @@ -1353,12 +1361,15 @@ struct window *window_create(const char *, const char *, const char *, const char **, u_int, u_int, u_int); void window_destroy(struct window *); int window_resize(struct window *, u_int, u_int); +int window_add_pane(struct window *, + u_int, const char *, const char *, const char **, u_int); int window_remove_pane(struct window *, int); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, const char *, const char **); int window_pane_resize(struct window_pane *, u_int, u_int); +void window_calculate_sizes(struct window *); int window_pane_set_mode( struct window_pane *, const struct window_mode *); void window_pane_reset_mode(struct window_pane *); diff --git a/tty-write.c b/tty-write.c index 7151f895..093c5430 100644 --- a/tty-write.c +++ b/tty-write.c @@ -1,4 +1,4 @@ -/* $Id: tty-write.c,v 1.4 2009-01-11 23:31:46 nicm Exp $ */ +/* $Id: tty-write.c,v 1.5 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -36,7 +36,7 @@ tty_vwrite_window(void *ptr, enum tty_cmd cmd, va_list ap) struct window_pane *wp = ptr; struct client *c; va_list aq; - u_int i, oy; + u_int i; if (wp->window->flags & WINDOW_HIDDEN) return; @@ -47,13 +47,8 @@ tty_vwrite_window(void *ptr, enum tty_cmd cmd, va_list ap) continue; if (c->session->curw->window == wp->window) { - if (wp == wp->window->panes[0]) - oy = 0; - else - oy = wp->window->sy / 2; - va_copy(aq, ap); - tty_vwrite(&c->tty, wp->screen, oy, cmd, aq); + tty_vwrite(&c->tty, wp->screen, wp->yoff, cmd, aq); va_end(aq); } } diff --git a/window.c b/window.c index 9f7cdf43..511c4ab8 100644 --- a/window.c +++ b/window.c @@ -1,4 +1,4 @@ -/* $Id: window.c,v 1.55 2009-01-11 23:31:46 nicm Exp $ */ +/* $Id: window.c,v 1.56 2009-01-12 18:22:47 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -213,14 +213,12 @@ window_create(const char *name, const char *cmd, w = xmalloc(sizeof *w); w->flags = 0; - w->panes[0] = window_pane_create(w, sx, sy, hlimit); + w->panes[0] = NULL; w->panes[1] = NULL; w->sx = sx; w->sy = sy; - w->active = w->panes[0]; - options_init(&w->options, &global_window_options); if (name == NULL) { @@ -249,10 +247,11 @@ window_create(const char *name, const char *cmd, ARRAY_ADD(&windows, w); w->references = 0; - if (window_pane_spawn(w->active, cmd, cwd, envp) != 0) { + if (window_add_pane(w, w->sy, cmd, cwd, envp, hlimit) < 0) { window_destroy(w); return (NULL); } + w->active = w->panes[0]; return (w); } @@ -280,15 +279,88 @@ window_destroy(struct window *w) int window_resize(struct window *w, u_int sx, u_int sy) { - if (w->panes[1] != NULL) { - window_pane_resize(w->panes[0], sx, sy / 2 - 1); - window_pane_resize(w->panes[1], sx, sy - (sy / 2)); - } else + int change; + u_int y0, y1; + + if (w->panes[1] == NULL) window_pane_resize(w->panes[0], sx, sy); + else { + if (sy <= 3) { + y0 = 1; + y1 = 1; + } else { + y0 = w->panes[0]->sy; + y1 = w->panes[1]->sy; + + change = sy - w->sy; + if (change > 0) { + while (change > 0) { + if (y1 < y0) + y1++; + else + y0++; + change--; + } + } else if (change < 0) { + while (change < 0) { + if (y1 > y0) + y1--; + else + y0--; + change++; + } + } + } + window_pane_resize(w->panes[0], sx, y0); + window_pane_resize(w->panes[1], sx, y1); + w->panes[1]->yoff = y0 + 1; + } w->sx = sx; w->sy = sy; + return (0); +} +int +window_add_pane(struct window *w, u_int y1, + const char *cmd, const char *cwd, const char **envp, u_int hlimit) +{ + struct window_pane *wp; + u_int y0; + + if (w->panes[1] != NULL) + return (-1); + + if (w->panes[0] == NULL) { + /* No existing panes. */ + wp = w->panes[0] = window_pane_create(w, w->sx, w->sy, hlimit); + wp->yoff = 0; + } else { + /* One existing pane. */ + if (y1 > w->sy) + y1 = w->sy; + y0 = w->sy - y1; + if (y0 == 0) { + y0 = 1; + y1--; + } + if (y0 > 1) + y0--; + else if (y1 > 1) + y1--; + window_pane_resize(w->panes[0], w->sx, y0); + + wp = w->panes[1] = window_pane_create(w, w->sx, y1, hlimit); + wp->yoff = y0 + 1; + } + + if (window_pane_spawn(wp, cmd, cwd, envp) != 0) { + if (wp == w->panes[0]) + window_remove_pane(w, 0); + else + window_remove_pane(w, 1); + return (-1); + } return (0); } @@ -302,8 +374,10 @@ window_remove_pane(struct window *w, int pane) w->panes[0] = w->panes[1]; w->panes[1] = NULL; } - window_resize(w, w->sx, w->sy); w->active = w->panes[0]; + + window_pane_resize(w->active, w->sx, w->sy); + w->active->yoff = 0; return (0); } return (1); @@ -326,11 +400,16 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->mode = NULL; + wp->sx = sx; + wp->sy = sy; + + wp->yoff = 0; + screen_init(&wp->base, sx, sy, hlimit); wp->screen = &wp->base; input_init(wp); - + return (wp); } @@ -412,8 +491,10 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) { struct winsize ws; - if (sx == screen_size_x(&wp->base) && sy == screen_size_y(&wp->base)) + if (sx == wp->sx && sy == wp->sy) return (-1); + wp->sx = sx; + wp->sy = sy; memset(&ws, 0, sizeof ws); ws.ws_col = sx;