Here is the diff I have been sitting on for ages, mostly written by Jonathan Slenders.
I remembered it only doing top status lines but in fact it does both. IIRC there are still some issues, particularly with the mouse. I expect you will need to wait until SourceForge is synced from OpenBSD before this will apply. Not sure when Thomas next plans to do that. Index: cmd-set-option.c =================================================================== RCS file: /cvs/src/usr.bin/tmux/cmd-set-option.c,v retrieving revision 1.71 diff -u -p -r1.71 cmd-set-option.c --- cmd-set-option.c 20 Oct 2014 22:29:25 -0000 1.71 +++ cmd-set-option.c 20 Apr 2015 14:35:26 -0000 @@ -186,6 +186,16 @@ cmd_set_option_exec(struct cmd *self, st } } + /* When the pane-status option has been changed, resize panes. */ + if (strcmp(oe->name, "pane-status") == 0 || + strcmp(oe->name, "pane-status-position") == 0) { + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + if ((w = ARRAY_ITEM(&windows, i)) == NULL) + continue; + layout_fix_panes(w, w->sx, w->sy); + } + } + /* Update sizes and redraw. May not need it but meh. */ recalculate_sizes(); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { Index: layout.c =================================================================== RCS file: /cvs/src/usr.bin/tmux/layout.c,v retrieving revision 1.23 diff -u -p -r1.23 layout.c --- layout.c 19 Apr 2015 21:34:21 -0000 1.23 +++ layout.c 20 Apr 2015 14:35:27 -0000 @@ -34,6 +34,7 @@ int layout_resize_pane_grow(struct layout_cell *, enum layout_type, int); int layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int); +int layout_need_status(struct layout_cell *, int); struct layout_cell * layout_create_cell(struct layout_cell *lcparent) @@ -163,6 +164,30 @@ layout_fix_offsets(struct layout_cell *l } } +/* + * Returns 1 if we need to reserve space for the pane status line. This is the + * case for the most upper panes only. + */ +int +layout_need_status(struct layout_cell *lc, int at_top) +{ + struct layout_cell *first_lc; + + if (lc->parent) { + if (lc->parent->type == LAYOUT_LEFTRIGHT) + return (layout_need_status(lc->parent, at_top)); + + if (at_top) + first_lc = TAILQ_FIRST(&(lc->parent->cells)); + else + first_lc = TAILQ_LAST(&(lc->parent->cells), layout_cells); + if (lc == first_lc) + return (layout_need_status(lc->parent, at_top)); + return (0); + } + return (1); +} + /* Update pane offsets and sizes based on their cells. */ void layout_fix_panes(struct window *w, u_int wsx, u_int wsy) @@ -170,13 +195,25 @@ layout_fix_panes(struct window *w, u_int struct window_pane *wp; struct layout_cell *lc; u_int sx, sy; + int shift, status, at_top; + status = options_get_number(&w->options, "pane-status"); + at_top = options_get_number(&w->options, "pane-status-position") == 0; TAILQ_FOREACH(wp, &w->panes, entry) { if ((lc = wp->layout_cell) == NULL) continue; + + if (status) + shift = layout_need_status(lc, at_top); + else + shift = 0; + wp->xoff = lc->xoff; wp->yoff = lc->yoff; + if (shift && at_top) + wp->yoff += 1; + /* * Layout cells are limited by the smallest size of other cells * within the same row or column; if this isn't the case @@ -213,6 +250,9 @@ layout_fix_panes(struct window *w, u_int if (sy < 2) sy = lc->sy; } + + if (shift) + sy -= 1; window_pane_resize(wp, sx, sy); } Index: options-table.c =================================================================== RCS file: /cvs/src/usr.bin/tmux/options-table.c,v retrieving revision 1.55 diff -u -p -r1.55 options-table.c --- options-table.c 19 Apr 2015 21:34:21 -0000 1.55 +++ options-table.c 20 Apr 2015 14:35:27 -0000 @@ -592,7 +592,6 @@ const struct options_table_entry window_ .maximum = INT_MAX, .default_num = 0 }, - { .name = "pane-active-border-bg", .type = OPTIONS_TABLE_COLOUR, .default_num = 8, @@ -610,6 +609,11 @@ const struct options_table_entry window_ .default_str = "fg=green" }, + { .name = "pane-active-status-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "bg=green" + }, + { .name = "pane-base-index", .type = OPTIONS_TABLE_NUMBER, .minimum = 0, @@ -632,6 +636,27 @@ const struct options_table_entry window_ { .name = "pane-border-style", .type = OPTIONS_TABLE_STYLE, .default_str = "default" + }, + + { .name = "pane-status", + .type = OPTIONS_TABLE_FLAG, + .default_num = 1 + }, + + { .name = "pane-status-format", + .type = OPTIONS_TABLE_STRING, + .default_str = "#{pane_index} \"#{pane_title}\"" + }, + + { .name = "pane-status-position", + .type = OPTIONS_TABLE_CHOICE, + .choices = options_table_status_position_list, + .default_num = 0 + }, + + { .name = "pane-status-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "fg=green" }, { .name = "remain-on-exit", Index: screen-redraw.c =================================================================== RCS file: /cvs/src/usr.bin/tmux/screen-redraw.c,v retrieving revision 1.30 diff -u -p -r1.30 screen-redraw.c --- screen-redraw.c 19 Apr 2015 21:05:27 -0000 1.30 +++ screen-redraw.c 20 Apr 2015 14:35:27 -0000 @@ -24,12 +24,16 @@ int screen_redraw_cell_border1(struct window_pane *, u_int, u_int); int screen_redraw_cell_border(struct client *, u_int, u_int); -int screen_redraw_check_cell(struct client *, u_int, u_int, +int screen_redraw_check_cell(struct client *, u_int, u_int, int, struct window_pane **); -int screen_redraw_check_active(u_int, u_int, int, struct window *, +int screen_redraw_check_active(u_int, u_int, int, int, struct window *, struct window_pane *); -void screen_redraw_draw_borders(struct client *, int, u_int); +int screen_redraw_make_pane_status(struct client *, struct window *, + struct window_pane *); +void screen_redraw_draw_pane_status(struct client *); + +void screen_redraw_draw_borders(struct client *, int, int, u_int); void screen_redraw_draw_panes(struct client *, u_int); void screen_redraw_draw_status(struct client *, u_int); void screen_redraw_draw_number(struct client *, struct window_pane *); @@ -100,16 +104,33 @@ screen_redraw_cell_border(struct client /* Check if cell inside a pane. */ int -screen_redraw_check_cell(struct client *c, u_int px, u_int py, +screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status, struct window_pane **wpp) { struct window *w = c->session->curw->window; struct window_pane *wp; int borders; + u_int right, line; if (px > w->sx || py > w->sy) return (CELL_OUTSIDE); + if (pane_status) { + TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_visible(wp)) + continue; + + if (wp->status_position == 0) + line = wp->yoff - 1; + else + line = wp->yoff + wp->sy; + right = wp->xoff + 2 + wp->status_size - 1; + + if (py == line && px >= wp->xoff + 2 && px <= right) + return (CELL_INSIDE); + } + } + TAILQ_FOREACH(wp, &w->panes, entry) { if (!window_pane_visible(wp)) continue; @@ -135,8 +156,15 @@ screen_redraw_check_cell(struct client * borders |= 8; if (px <= w->sx && screen_redraw_cell_border(c, px + 1, py)) borders |= 4; - if (py == 0 || screen_redraw_cell_border(c, px, py - 1)) - borders |= 2; + if (pane_status) { + if (py != 0 && + screen_redraw_cell_border(c, px, py - 1)) + borders |= 2; + } else { + if (py == 0 || + screen_redraw_cell_border(c, px, py - 1)) + borders |= 2; + } if (py <= w->sy && screen_redraw_cell_border(c, px, py + 1)) borders |= 1; @@ -177,8 +205,8 @@ screen_redraw_check_cell(struct client * /* Check active pane indicator. */ int -screen_redraw_check_active(u_int px, u_int py, int type, struct window *w, - struct window_pane *wp) +screen_redraw_check_active(u_int px, u_int py, int type, int pane_status, + struct window *w, struct window_pane *wp) { /* Is this off the active pane border? */ if (screen_redraw_cell_border1(w->active, px, py) != 1) @@ -192,6 +220,10 @@ screen_redraw_check_active(u_int px, u_i if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE)) return (1); + /* With status lines mark the entire line. */ + if (pane_status) + return (1); + /* Check if the pane covers the whole width. */ if (wp->xoff == 0 && wp->sx == w->sx) { /* This can either be the top pane or the bottom pane. */ @@ -214,7 +246,83 @@ screen_redraw_check_active(u_int px, u_i return (0); } - return (type); + return (1); +} + +/* Update pane status. */ +int +screen_redraw_make_pane_status(struct client *c, struct window *w, + struct window_pane *wp) +{ + struct options *oo = &w->options; + struct grid_cell gc; + int utf8flag; + const char *fmt; + struct format_tree *ft; + char *out; + size_t outlen, old_size = wp->status_size; + struct screen_write_ctx ctx; + + if (wp == w->active) + style_apply(&gc, oo, "pane-active-status-style"); + else + style_apply(&gc, oo, "pane-status-style"); + + fmt = options_get_string(oo, "pane-status-format"); + + ft = format_create(); + format_defaults(ft, c, NULL, NULL, wp); + + screen_free(&wp->status_screen); + screen_init(&wp->status_screen, wp->sx, 1, 0); + wp->status_screen.mode = 0; + + utf8flag = options_get_number(oo, "utf8"); + + out = format_expand(ft, fmt); + outlen = screen_write_cstrlen(utf8flag, "%s", out); + if (outlen > wp->sx - 4) + outlen = wp->sx - 4; + screen_resize(&wp->status_screen, outlen, 1, 0); + + screen_write_start(&ctx, NULL, &wp->status_screen); + screen_write_cursormove(&ctx, 0, 0); + screen_write_clearline(&ctx); + screen_write_nputs(&ctx, outlen, &gc, utf8flag, "%s", out); + screen_write_stop(&ctx); + + format_free(ft); + + wp->status_position = options_get_number(oo, "pane-status-position"); + wp->status_size = outlen; + + return (wp->status_size != old_size); +} + +/* Draw pane status. */ +void +screen_redraw_draw_pane_status(struct client *c) +{ + struct window *w = c->session->curw->window; + struct options *oo = &c->session->options; + struct tty *tty = &c->tty; + struct window_pane *wp; + int spos; + u_int yoff; + + spos = options_get_number(oo, "status-position"); + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->status_position == 0) + yoff = wp->yoff - 1; + else + yoff = wp->yoff + wp->sy; + if (spos == 0) + yoff += 1; + + tty_draw_line(tty, NULL, &wp->status_screen, 0, wp->xoff + 2, yoff); + + } + tty_cursor(tty, 0, 0); } /* Redraw entire screen. */ @@ -222,10 +330,12 @@ void screen_redraw_screen(struct client *c, int draw_panes, int draw_status, int draw_borders) { - struct options *oo = &c->session->options; - struct tty *tty = &c->tty; - u_int top; - int status, spos; + struct options *oo = &c->session->options; + struct tty *tty = &c->tty; + struct window *w = c->session->curw->window; + struct window_pane *wp; + u_int top; + int status, pane_status, spos; /* Suspended clients should not be updated. */ if (c->flags & CLIENT_SUSPENDED) @@ -243,12 +353,24 @@ screen_redraw_screen(struct client *c, i if (!status) draw_status = 0; + /* Update pane status lines. */ + pane_status = options_get_number(&w->options, "pane-status"); + if (pane_status && (draw_borders || draw_status)) { + TAILQ_FOREACH(wp, &w->panes, entry) { + if (screen_redraw_make_pane_status(c, w, wp)) + draw_borders = draw_status = 1; + } + } + + /* Draw the elements. */ if (draw_borders) - screen_redraw_draw_borders(c, status, top); + screen_redraw_draw_borders(c, status, pane_status, top); if (draw_panes) screen_redraw_draw_panes(c, top); if (draw_status) screen_redraw_draw_status(c, top); + if (pane_status && (draw_borders || draw_status)) + screen_redraw_draw_pane_status(c); tty_reset(tty); } @@ -272,7 +394,8 @@ screen_redraw_pane(struct client *c, str /* Draw the borders. */ void -screen_redraw_draw_borders(struct client *c, int status, u_int top) +screen_redraw_draw_borders(struct client *c, int status, int pane_status, + u_int top) { struct window *w = c->session->curw->window; struct options *oo = &w->options; @@ -316,13 +439,15 @@ screen_redraw_draw_borders(struct client for (j = 0; j < tty->sy - status; j++) { for (i = 0; i < tty->sx; i++) { - type = screen_redraw_check_cell(c, i, j, &wp); + type = screen_redraw_check_cell(c, i, j, pane_status, + &wp); if (type == CELL_INSIDE) continue; if (type == CELL_OUTSIDE && small && i > msgx && j == msgy) continue; - if (screen_redraw_check_active(i, j, type, w, wp)) + if (screen_redraw_check_active(i, j, type, pane_status, + w, wp)) tty_attributes(tty, &active_gc, NULL); else tty_attributes(tty, &other_gc, NULL); Index: server-client.c =================================================================== RCS file: /cvs/src/usr.bin/tmux/server-client.c,v retrieving revision 1.131 diff -u -p -r1.131 server-client.c --- server-client.c 19 Apr 2015 21:34:21 -0000 1.131 +++ server-client.c 20 Apr 2015 14:35:28 -0000 @@ -878,7 +878,7 @@ server_client_check_redraw(struct client { struct session *s = c->session; struct window_pane *wp; - int flags, redraw; + int flags, masked, redraw; if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) return; @@ -914,11 +914,13 @@ server_client_check_redraw(struct client } } - if (c->flags & CLIENT_BORDERS) + masked = c->flags & (CLIENT_BORDERS|CLIENT_STATUS); + if (masked == CLIENT_BORDERS) screen_redraw_screen(c, 0, 0, 1); - - if (c->flags & CLIENT_STATUS) + else if (masked == CLIENT_STATUS) screen_redraw_screen(c, 0, 1, 0); + else if (masked != 0) + screen_redraw_screen(c, 0, 1, 1); c->tty.flags |= flags; Index: tmux.h =================================================================== RCS file: /cvs/src/usr.bin/tmux/tmux.h,v retrieving revision 1.492 diff -u -p -r1.492 tmux.h --- tmux.h 19 Apr 2015 21:34:21 -0000 1.492 +++ tmux.h 20 Apr 2015 14:35:28 -0000 @@ -937,6 +937,10 @@ struct window_pane { struct screen *screen; struct screen base; + struct screen status_screen; + size_t status_size; + int status_position; + /* Saved in alternative screen mode. */ u_int saved_cx; u_int saved_cy; Index: window.c =================================================================== RCS file: /cvs/src/usr.bin/tmux/window.c,v retrieving revision 1.119 diff -u -p -r1.119 window.c --- window.c 20 Apr 2015 07:50:49 -0000 1.119 +++ window.c 20 Apr 2015 14:35:29 -0000 @@ -722,6 +722,8 @@ window_pane_create(struct window *w, u_i screen_init(&wp->base, sx, sy, hlimit); wp->screen = &wp->base; + screen_init(&wp->status_screen, 1, 1, 0); + input_init(wp); return (wp); On Mon, Apr 20, 2015 at 09:02:52AM -0400, John O'Meara wrote: > Hi list, > > I had made a patch for myself to add a per-pane status bar a few weeks > ago, and saw yesterday that there was a ticket open for a similar feature. > Nicholas pointed out that he had already done work on this, but suggested > I post my patch anyway. > > Firstly, sorry for duplicating effort. I hope this patch is helpful but I > understand if it isn't. > > Secondly, the ticket does request top-of-pane title, where my patch > currently only does bottom-of-pane, but it uses the expansion system that > the regular status line uses, so the pane title and whatever else might be > wanted can go there (I use pane-tty and pane-title, for example). If it is > desired for this patch to move forward, I will work on adding a > pane-status-position option to allow it to be placed top-of-pane (as well > as other suggestions I receive) > > The patch works by decreasing the pane height by 1 when pane-status is > enabled, and drawing the pane status line in the opened up space. > Adjustments are made for border drawing, window selection, and mouse > movements to work properly with the adjusted pane size. Redrawing is > handled similar to the regular status line, in that the statuses are > pre-rendered in memory and only sent to the screen if they differ from the > last render. Rendering is per-client to allow things like client-tty > expansions to work correctly. > > Usage is documented in the man page, and the default options move the > pane-title from status-right to pane-status-format (leaving only the time > in status-right), allowing for a quick example when run with default > settings. > > Thanks, > > -- John O'Meara > diff --git a/layout.c b/layout.c > index b91b86c..c66ca00 100644 > --- a/layout.c > +++ b/layout.c > @@ -170,6 +170,9 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy) > struct window_pane *wp; > struct layout_cell *lc; > u_int sx, sy; > + int has_pane_status; > + > + has_pane_status = options_get_number(&w->options, "pane-status"); > > TAILQ_FOREACH(wp, &w->panes, entry) { > if ((lc = wp->layout_cell) == NULL) > @@ -207,9 +210,9 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy) > * is two because scroll regions cannot be one line. > */ > if (lc->yoff >= wsy || lc->yoff + lc->sy < wsy) > - sy = lc->sy; > + sy = lc->sy - has_pane_status; > else { > - sy = wsy - lc->yoff; > + sy = wsy - lc->yoff - has_pane_status; > if (sy < 2) > sy = lc->sy; > } > @@ -527,9 +530,12 @@ layout_resize_pane_mouse(struct client *c) > struct window_pane *wp; > struct mouse_event *m = &c->tty.mouse; > int pane_border; > + int has_pane_status; > > w = c->session->curw->window; > > + has_pane_status = options_get_number(&w->options, "pane-status"); > + > pane_border = 0; > if (m->event & MOUSE_EVENT_DRAG && m->flags & MOUSE_RESIZE_PANE) { > TAILQ_FOREACH(wp, &w->panes, entry) { > @@ -538,12 +544,12 @@ layout_resize_pane_mouse(struct client *c) > > if (wp->xoff + wp->sx == m->lx && > wp->yoff <= 1 + m->ly && > - wp->yoff + wp->sy >= m->ly) { > + wp->yoff + wp->sy + has_pane_status >= m->ly) { > layout_resize_pane(wp, LAYOUT_LEFTRIGHT, > m->x - m->lx); > pane_border = 1; > } > - if (wp->yoff + wp->sy == m->ly && > + if (wp->yoff + wp->sy + has_pane_status == m->ly && > wp->xoff <= 1 + m->lx && > wp->xoff + wp->sx >= m->lx) { > layout_resize_pane(wp, LAYOUT_TOPBOTTOM, > @@ -557,8 +563,8 @@ layout_resize_pane_mouse(struct client *c) > TAILQ_FOREACH(wp, &w->panes, entry) { > if ((wp->xoff + wp->sx == m->x && > wp->yoff <= 1 + m->y && > - wp->yoff + wp->sy >= m->y) || > - (wp->yoff + wp->sy == m->y && > + wp->yoff + wp->sy + has_pane_status >= m->y) || > + (wp->yoff + wp->sy + has_pane_status == m->y && > wp->xoff <= 1 + m->x && > wp->xoff + wp->sx >= m->x)) { > pane_border = 1; > diff --git a/options-table.c b/options-table.c > index 2bcf29b..be9af3f 100644 > --- a/options-table.c > +++ b/options-table.c > @@ -396,7 +396,7 @@ const struct options_table_entry session_options_table[] > = { > > { .name = "status-right", > .type = OPTIONS_TABLE_STRING, > - .default_str = " \"#{=21:pane_title}\" %H:%M %d-%b-%y" > + .default_str = "%H:%M %d-%b-%y" > }, > > { .name = "status-right-attr", > @@ -652,6 +652,39 @@ const struct options_table_entry window_options_table[] > = { > .default_str = "default" > }, > > + { .name = "pane-status", > + .type = OPTIONS_TABLE_FLAG, > + .default_num = 1 > + }, > + > + { .name = "pane-status-attr", > + .type = OPTIONS_TABLE_ATTRIBUTES, > + .default_num = 0, > + .style = "pane-status-style" > + }, > + > + { .name = "pane-status-bg", > + .type = OPTIONS_TABLE_COLOUR, > + .default_num = 2, > + .style = "pane-status-style" > + }, > + > + { .name = "pane-status-fg", > + .type = OPTIONS_TABLE_COLOUR, > + .default_num = 0, > + .style = "pane-status-style" > + }, > + > + { .name = "pane-status-format", > + .type = OPTIONS_TABLE_STRING, > + .default_str = "[#T]" > + }, > + > + { .name = "pane-status-style", > + .type = OPTIONS_TABLE_STYLE, > + .default_str = "default" > + }, > + > { .name = "remain-on-exit", > .type = OPTIONS_TABLE_FLAG, > .default_num = 0 > diff --git a/resize.c b/resize.c > index 9ad73c8..edf44d5 100644 > --- a/resize.c > +++ b/resize.c > @@ -128,8 +128,16 @@ recalculate_sizes(void) > forced |= WINDOW_FORCEHEIGHT; > } > > +#if 0 /* This optimization to not resize panes if the window size doesn't > + change fails to handle the case where pane sizes may have changed > + due to options like 'pane-status' changing. Unfortunately, we > + can't at this point know if this function was called because of an > + option change, let alone specific option changes. For now, we'll > + just skip the optimization and take the computational hit rather > + than have a stale display. */ > if (w->sx == ssx && w->sy == ssy) > continue; > +#endif > log_debug("window size %u,%u (was %u,%u)", ssx, ssy, w->sx, > w->sy); > > diff --git a/screen-redraw.c b/screen-redraw.c > index c2b2ece..a36a2fe 100644 > --- a/screen-redraw.c > +++ b/screen-redraw.c > @@ -54,13 +54,17 @@ void screen_redraw_draw_number(struct client *, > struct window_pane *); > int > screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py) > { > + int has_pane_status; > + > + has_pane_status = options_get_number(&wp->window->options, > "pane-status"); > + > /* Inside pane. */ > if (px >= wp->xoff && px < wp->xoff + wp->sx && > - py >= wp->yoff && py < wp->yoff + wp->sy) > + py >= wp->yoff && py < wp->yoff + wp->sy + has_pane_status) > return (0); > > /* Left/right borders. */ > - if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= wp->yoff + wp->sy) { > + if ((wp->yoff == 0 || py >= wp->yoff - 1 + has_pane_status) && py <= > wp->yoff + wp->sy + has_pane_status) { > if (wp->xoff != 0 && px == wp->xoff - 1) > return (1); > if (px == wp->xoff + wp->sx) > @@ -71,7 +75,7 @@ screen_redraw_cell_border1(struct window_pane *wp, u_int > px, u_int py) > if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= wp->xoff + wp->sx) { > if (wp->yoff != 0 && py == wp->yoff - 1) > return (1); > - if (py == wp->yoff + wp->sy) > + if (py == wp->yoff + wp->sy + has_pane_status) > return (1); > } > > @@ -106,6 +110,9 @@ screen_redraw_check_cell(struct client *c, u_int px, > u_int py, > struct window *w = c->session->curw->window; > struct window_pane *wp; > int borders; > + int has_pane_status; > + > + has_pane_status = options_get_number(&w->options, "pane-status"); > > if (px > w->sx || py > w->sy) > return (CELL_OUTSIDE); > @@ -119,7 +126,7 @@ screen_redraw_check_cell(struct client *c, u_int px, > u_int py, > if ((wp->xoff != 0 && px < wp->xoff - 1) || > px > wp->xoff + wp->sx || > (wp->yoff != 0 && py < wp->yoff - 1) || > - py > wp->yoff + wp->sy) > + py > wp->yoff + wp->sy + has_pane_status) > continue; > > /* If definitely inside, return so. */ > @@ -180,6 +187,10 @@ int > screen_redraw_check_active(u_int px, u_int py, int type, struct window *w, > struct window_pane *wp) > { > + int has_pane_status; > + > + has_pane_status = options_get_number(&wp->window->options, > "pane-status"); > + > /* Is this off the active pane border? */ > if (screen_redraw_cell_border1(w->active, px, py) != 1) > return (0); > @@ -204,7 +215,7 @@ screen_redraw_check_active(u_int px, u_int py, int type, > struct window *w, > } > > /* Check if the pane covers the whole height. */ > - if (wp->yoff == 0 && wp->sy == w->sy) { > + if (wp->yoff == 0 && wp->sy + has_pane_status == w->sy) { > /* This can either be the left pane or the right pane. */ > if (wp->xoff == 0) { /* left pane */ > if (wp == w->active) > @@ -217,6 +228,24 @@ screen_redraw_check_active(u_int px, u_int py, int type, > struct window *w, > return (type); > } > > +void > +screen_redraw_draw_pane_status(struct client *c, u_int top) > +{ > + struct window *w = c->session->curw->window; > + struct window_pane *wp; > + struct pane_status *ps = TAILQ_FIRST(&c->pane_statuses); > + > + TAILQ_FOREACH(wp, &w->panes, entry) { > + if (!window_pane_visible(wp)) > + continue; > + if (!ps) { > + fatalx("pane status not found"); > + } > + tty_draw_line(&c->tty, &ps->status, 0, wp->xoff, top + wp->yoff > + wp->sy); > + ps = TAILQ_NEXT(ps, entry); > + } > +} > + > /* Redraw entire screen. */ > void > screen_redraw_screen(struct client *c, int draw_panes, int draw_status, > @@ -226,6 +255,7 @@ screen_redraw_screen(struct client *c, int draw_panes, > int draw_status, > struct tty *tty = &c->tty; > u_int top; > int status, spos; > + int draw_pane_status; > > /* Suspended clients should not be updated. */ > if (c->flags & CLIENT_SUSPENDED) > @@ -238,6 +268,10 @@ screen_redraw_screen(struct client *c, int draw_panes, > int draw_status, > else > status = options_get_number(oo, "status"); > top = 0; > + if (draw_status && > options_get_number(&c->session->curw->window->options, "pane-status")) > + draw_pane_status = 1; > + else > + draw_pane_status = 0; > if (status && spos == 0) > top = 1; > if (!status) > @@ -249,6 +283,9 @@ screen_redraw_screen(struct client *c, int draw_panes, > int draw_status, > screen_redraw_draw_panes(c, top); > if (draw_status) > screen_redraw_draw_status(c, top); > + if (draw_pane_status){ > + screen_redraw_draw_pane_status(c, top); > + } > tty_reset(tty); > } > > diff --git a/server-client.c b/server-client.c > index f7ce35c..fa278af 100644 > --- a/server-client.c > +++ b/server-client.c > @@ -749,6 +749,7 @@ server_client_check_redraw(struct client *c) > redraw = status_prompt_redraw(c); > else > redraw = status_redraw(c); > + redraw |= pane_status_redraw(c); > if (!redraw) > c->flags &= ~CLIENT_STATUS; > } > diff --git a/status.c b/status.c > index 5f8895f..b7546bb 100644 > --- a/status.c > +++ b/status.c > @@ -38,7 +38,7 @@ void status_job_free(void *); > void status_job_callback(struct job *); > char *status_print(struct client *, struct winlink *, time_t, > struct grid_cell *); > -char *status_replace(struct client *, struct winlink *, const char *, > time_t); > +char *status_replace(struct client *, struct winlink *, struct window_pane > *wp, const char *, time_t); > void status_replace1(struct client *, char **, char **, char *, size_t); > void status_message_callback(int, short, void *); > > @@ -87,7 +87,7 @@ status_redraw_get_left(struct client *c, time_t t, int > utf8flag, > style_apply_update(gc, &s->options, "status-left-style"); > > template = options_get_string(&s->options, "status-left"); > - left = status_replace(c, NULL, template, t); > + left = status_replace(c, NULL, NULL, template, t); > > *size = options_get_number(&s->options, "status-left-length"); > leftlen = screen_write_cstrlen(utf8flag, "%s", left); > @@ -109,7 +109,7 @@ status_redraw_get_right(struct client *c, time_t t, int > utf8flag, > style_apply_update(gc, &s->options, "status-right-style"); > > template = options_get_string(&s->options, "status-right"); > - right = status_replace(c, NULL, template, t); > + right = status_replace(c, NULL, NULL, template, t); > > *size = options_get_number(&s->options, "status-right-length"); > rightlen = screen_write_cstrlen(utf8flag, "%s", right); > @@ -362,6 +362,86 @@ out: > return (1); > } > > +/* Draw status for panes */ > +int > +pane_status_redraw(struct client *c) > +{ > + struct screen_write_ctx ctx; > + int utf8flag; > + struct grid_cell stdgc; > + char *msg; > + struct window *w = c->session->curw->window; > + struct window_pane *wp; > + struct pane_statuses old_pane_statuses; > + struct pane_status *pane_status; > + struct pane_status *t; > + int diff = 0; > + unsigned int len; > + > + if (options_get_number(&w->options, "pane-status") == 0) { > + return 0; > + } > + > + memcpy(&old_pane_statuses, &c->pane_statuses, sizeof old_pane_statuses); > + TAILQ_INIT(&c->pane_statuses); > + > + utf8flag = options_get_number(&c->session->options, "status-utf8"); > + > + /* Create set of statuses for each pane */ > + TAILQ_FOREACH(wp, &w->panes, entry) { > + if (!window_pane_visible(wp)) > + continue; > + pane_status = malloc(sizeof *pane_status); > + if (!pane_status) { > + continue; > + } > + memcpy(&stdgc, &grid_default_cell, sizeof stdgc); > + colour_set_fg(&stdgc, options_get_number(&wp->window->options, > "pane-status-fg")); > + colour_set_bg(&stdgc, options_get_number(&wp->window->options, > "pane-status-bg")); > + stdgc.attr |= options_get_number(&wp->window->options, > "pane-status-attr"); > + screen_init(&pane_status->status, wp->sx, 1, 0); > + msg = status_replace(c, NULL, wp, > options_get_string(&wp->window->options, "pane-status-format"), time(NULL)); > + len = screen_write_strlen(utf8flag, "%s", msg); > + if (len > wp->sx) { > + len = wp->sx; > + } > + screen_write_start(&ctx, NULL, &pane_status->status); > + screen_write_cursormove(&ctx, 0, 0); > + screen_write_cnputs(&ctx, len, &stdgc, utf8flag, "%s", msg); > + screen_write_stop(&ctx); > + free(msg); > + TAILQ_INSERT_TAIL(&c->pane_statuses, pane_status, entry); > + } > + > + /* Check if any of the status lines have changed, or if the number > + * of status lines have changed. */ > + { > + struct pane_status *old; > + struct pane_status *new; > + old = TAILQ_FIRST(&old_pane_statuses); > + new = TAILQ_FIRST(&c->pane_statuses); > + while (old != TAILQ_END(&old_pane_statuses) && new != > TAILQ_END(&c->pane_statuses)) { > + if (grid_compare(old->status.grid, new->status.grid) != > 0) { > + //screen_free(&old_status); > + diff = 1; > + } > + //screen_free(&old_status); > + old = TAILQ_NEXT(old, entry); > + new = TAILQ_NEXT(new, entry); > + } > + if (old != TAILQ_END(&old_pane_statuses) || new != > TAILQ_END(&c->pane_statuses)) { > + diff = 1; > + } > + } > + /* discard old */ > + TAILQ_FOREACH_SAFE(pane_status, &old_pane_statuses, entry, t) { > + screen_free(&pane_status->status); > + free(pane_status); > + } > + return diff; > +} > + > + > /* Replace a single special sequence (prefixed by #). */ > void > status_replace1(struct client *c, char **iptr, char **optr, char *out, > @@ -431,7 +511,7 @@ skip_to: > > /* Replace special sequences in fmt. */ > char * > -status_replace(struct client *c, struct winlink *wl, const char *fmt, time_t > t) > +status_replace(struct client *c, struct winlink *wl, struct window_pane *wp, > const char *fmt, time_t t) > { > static char out[BUFSIZ]; > char in[BUFSIZ], ch, *iptr, *optr, *expanded; > @@ -461,7 +541,7 @@ status_replace(struct client *c, struct winlink *wl, > const char *fmt, time_t t) > *optr = '\0'; > > ft = format_create(); > - format_defaults(ft, c, NULL, wl, NULL); > + format_defaults(ft, c, NULL, wl, wp); > expanded = format_expand(ft, out); > format_free(ft); > return (expanded); > @@ -626,7 +706,7 @@ status_print(struct client *c, struct winlink *wl, time_t > t, > else if (wl->flags & (WINLINK_ACTIVITY|WINLINK_SILENCE)) > style_apply_update(gc, oo, "window-status-activity-style"); > > - text = status_replace(c, wl, fmt, t); > + text = status_replace(c, wl, NULL, fmt, t); > return (text); > } > > diff --git a/tmux.1 b/tmux.1 > index 8a0879b..b277376 100644 > --- a/tmux.1 > +++ b/tmux.1 > @@ -2617,7 +2617,7 @@ Set the position of the status line. > Display > .Ar string > to the right of the status bar. > -By default, the current window title in double quotes, the date and the time > +By default, the date and the time > are shown. > As with > .Ic status-left , > @@ -2918,6 +2918,33 @@ see the > option. > Attributes are ignored. > .Pp > +.It Xo Ic pane-status > +.Op Ic on | off > +.Xc > +Show or hide a status line at the bottom of each pane. > +.Pp > +.It Ic pane-status-format Ar string > +Display > +.Ar string > +in the status bar of each pane in the window. > +By default, the pane title is shown in brackets. > +As with > +.Ic status-left , > +.Ar string > +will be passed to > +.Xr strftime 3 , > +character pairs are replaced, and UTF-8 is dependent on the > +.Ic status-utf8 > +option. > +.Pp > +.It Ic pane-status-style Ar style > +Set the pane status line style. > +For how to specify > +.Ar style , > +see the > +.Ic message-command-style > +opption. > +.Pp > .It Xo Ic remain-on-exit > .Op Ic on | off > .Xc > diff --git a/tmux.h b/tmux.h > index e296ac7..bc1e659 100644 > --- a/tmux.h > +++ b/tmux.h > @@ -923,6 +923,12 @@ TAILQ_HEAD(window_panes, window_pane); > RB_HEAD(window_pane_tree, window_pane); > ARRAY_DECL(window_pane_list, struct window_pane *); > > +struct pane_status { > + struct screen status; > + TAILQ_ENTRY(pane_status) entry; > +}; > +TAILQ_HEAD(pane_statuses, pane_status); > + > /* Window structure. */ > struct window { > u_int id; > @@ -1283,6 +1289,7 @@ struct client { > struct status_out_tree status_new; > struct timeval status_timer; > struct screen status; > + struct pane_statuses pane_statuses; > > #define CLIENT_TERMINAL 0x1 > #define CLIENT_PREFIX 0x2 > @@ -1923,6 +1930,7 @@ void status_free_jobs(struct status_out_tree *); > void status_update_jobs(struct client *); > void status_set_window_at(struct client *, u_int); > int status_redraw(struct client *); > +int pane_status_redraw(struct client *c); > void printflike(2, 3) status_message_set(struct client *, const char *, ...); > void status_message_clear(struct client *); > int status_message_redraw(struct client *); > @@ -2058,6 +2066,7 @@ void screen_write_setselection(struct > screen_write_ctx *, u_char *, u_int); > void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int); > > /* screen-redraw.c */ > +void screen_redraw_draw_pane_status(struct client *c, u_int top); > void screen_redraw_screen(struct client *, int, int, int); > void screen_redraw_pane(struct client *, struct window_pane *); > > diff --git a/window.c b/window.c > index fff2cfc..b7e6f53 100644 > --- a/window.c > +++ b/window.c > @@ -1180,6 +1180,9 @@ window_pane_find_up(struct window_pane *wp) > u_int edge, left, right, end; > struct window_pane_list list; > int found; > + int has_pane_status; > + > + has_pane_status = options_get_number(&wp->window->options, > "pane-status"); > > if (wp == NULL || !window_pane_visible(wp)) > return (NULL); > @@ -1195,7 +1198,7 @@ window_pane_find_up(struct window_pane *wp) > TAILQ_FOREACH(next, &wp->window->panes, entry) { > if (next == wp || !window_pane_visible(next)) > continue; > - if (next->yoff + next->sy + 1 != edge) > + if (next->yoff + next->sy + 1 + has_pane_status != edge) > continue; > end = next->xoff + next->sx - 1; > > @@ -1223,12 +1226,15 @@ window_pane_find_down(struct window_pane *wp) > u_int edge, left, right, end; > struct window_pane_list list; > int found; > + int has_pane_status; > + > + has_pane_status = options_get_number(&wp->window->options, > "pane-status"); > > if (wp == NULL || !window_pane_visible(wp)) > return (NULL); > ARRAY_INIT(&list); > > - edge = wp->yoff + wp->sy + 1; > + edge = wp->yoff + wp->sy + 1 + has_pane_status; > if (edge >= wp->window->sy) > edge = 0; > > ------------------------------------------------------------------------------ > BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT > Develop your own process in accordance with the BPMN 2 standard > Learn Process modeling best practices with Bonita BPM through live exercises > http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual- event?utm_ > source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF > _______________________________________________ > tmux-users mailing list > tmux-users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/tmux-users ------------------------------------------------------------------------------ BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT Develop your own process in accordance with the BPMN 2 standard Learn Process modeling best practices with Bonita BPM through live exercises http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual- event?utm_ source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users