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);
Post by John O'MearaHi 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);
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,
/* 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
https://lists.sourceforge.net/lists/listinfo/tmux-users