Discussion:
per-pane status line (similar to ticket 21)
(too old to reply)
John O'Meara
2015-04-20 13:02:52 UTC
Permalink
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
Nicholas Marriott
2015-04-20 13:45:20 UTC
Permalink
Thanks I will take a look at this at some point (possibly not soon though!).
Post by John O'Meara
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);
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
Nicholas Marriott
2015-04-20 14:38:46 UTC
Permalink
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'Meara
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);
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
Thomas Adam
2015-04-20 14:50:56 UTC
Permalink
On 20 April 2015 at 15:38, Nicholas Marriott
Post by Nicholas Marriott
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.
Done.

Note that I took a quick look at both this patch, and John O'Meara's,
and this one here looks a lot less obtrusive, since it doesn't just
comment out the pane redrawing stuff, etc.

-- Thomas Adam
Nicholas Marriott
2015-04-25 20:31:44 UTC
Permalink
Hi

I like the other diff a bit more than yours so I think I will go with
it, does it meet your needs too, or any comments?
Post by John O'Meara
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);
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
Nicholas Marriott
2015-04-25 21:04:58 UTC
Permalink
Here is latest, notably fixing a redraw bug with status lines at bottom
and merging pane-status and pane-status-position.


Index: cmd-set-option.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/cmd-set-option.c,v
retrieving revision 1.74
diff -u -p -r1.74 cmd-set-option.c
--- cmd-set-option.c 24 Apr 2015 23:17:11 -0000 1.74
+++ cmd-set-option.c 25 Apr 2015 21:03:17 -0000
@@ -183,6 +183,12 @@ 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) {
+ RB_FOREACH(w, windows, &windows)
+ layout_fix_panes(w, w->sx, w->sy);
+ }
+
/* Update sizes and redraw. May not need it but meh. */
recalculate_sizes();
TAILQ_FOREACH(c, &clients, entry) {
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 25 Apr 2015 21:03:17 -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 = (status == 1);
TAILQ_FOREACH(wp, &w->panes, entry) {
if ((lc = wp->layout_cell) == NULL)
continue;
+
+ if (status != 0)
+ 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 25 Apr 2015 21:03:17 -0000
@@ -51,6 +51,9 @@ const char *options_table_status_positio
const char *options_table_bell_action_list[] = {
"none", "any", "current", NULL
};
+const char *options_table_pane_status_list[] = {
+ "off", "top", "bottom", NULL
+};

/* Server options. */
const struct options_table_entry server_options_table[] = {
@@ -610,6 +613,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 +640,22 @@ const struct options_table_entry window_
{ .name = "pane-border-style",
.type = OPTIONS_TABLE_STYLE,
.default_str = "default"
+ },
+
+ { .name = "pane-status",
+ .type = OPTIONS_TABLE_CHOICE,
+ .choices = options_table_pane_status_list,
+ .default_num = 0
+ },
+
+ { .name = "pane-status-format",
+ .type = OPTIONS_TABLE_STRING,
+ .default_str = "#{pane_index} \"#{pane_title}\""
+ },
+
+ { .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 25 Apr 2015 21:03:17 -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 *, int);
+
+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 *);
@@ -50,6 +54,10 @@ void screen_redraw_draw_number(struct cl

#define CELL_BORDERS " xqlkmjwvtun~"

+#define CELL_STATUS_OFF 0
+#define CELL_STATUS_TOP 1
+#define CELL_STATUS_BOTTOM 2
+
/* Check if cell is on the border of a particular pane. */
int
screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
@@ -100,16 +108,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 != CELL_STATUS_OFF) {
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (!window_pane_visible(wp))
+ continue;
+
+ if (pane_status == CELL_STATUS_TOP)
+ 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 +160,13 @@ 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 == CELL_STATUS_TOP) {
+ 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 +207,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 +222,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 != CELL_STATUS_OFF)
+ 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 +248,81 @@ 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_size = outlen;
+ return (wp->status_size != old_size);
+}
+
+/* Draw pane status. */
+void
+screen_redraw_draw_pane_status(struct client *c, int pane_status)
+{
+ 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 (pane_status == CELL_STATUS_TOP)
+ 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 != CELL_STATUS_OFF && (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 != CELL_STATUS_OFF && (draw_borders || draw_status))
+ screen_redraw_draw_pane_status(c, pane_status);
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.136
diff -u -p -r1.136 server-client.c
--- server-client.c 25 Apr 2015 18:33:59 -0000 1.136
+++ server-client.c 25 Apr 2015 21:03:18 -0000
@@ -876,7 +876,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;
@@ -912,11 +912,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.1
===================================================================
RCS file: /cvs/src/usr.bin/tmux/tmux.1,v
retrieving revision 1.422
diff -u -p -r1.422 tmux.1
--- tmux.1 21 Apr 2015 22:32:40 -0000 1.422
+++ tmux.1 25 Apr 2015 21:03:19 -0000
@@ -2954,6 +2954,9 @@ see the
option.
Attributes are ignored.
.Pp
+.It Ic pane-active-status-style
+Set the style of the active pane's status line.
+.Pp
.It Ic pane-base-index Ar index
Like
.Ic base-index ,
@@ -2967,6 +2970,18 @@ see the
.Ic message-command-style
option.
Attributes are ignored.
+.Pp
+.It Xo Ic pane-status
+.Op Ic off | top | bottom
+.Xc
+Turn pane status lines off or set their position.
+A pane's status line is shown on the pane border.
+.Pp
+.It Ic pane-status-format Ar format
+Set the text shown in pane status lines.
+.Pp
+.It Ic pane-status-style Ar style
+Set the style of pane status lines.
.Pp
.It Xo Ic remain-on-exit
.Op Ic on | off
Index: tmux.h
===================================================================
RCS file: /cvs/src/usr.bin/tmux/tmux.h,v
retrieving revision 1.501
diff -u -p -r1.501 tmux.h
--- tmux.h 25 Apr 2015 18:33:59 -0000 1.501
+++ tmux.h 25 Apr 2015 21:03:19 -0000
@@ -936,6 +936,9 @@ struct window_pane {
struct screen *screen;
struct screen base;

+ struct screen status_screen;
+ size_t status_size;
+
/* 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.126
diff -u -p -r1.126 window.c
--- window.c 25 Apr 2015 18:56:05 -0000 1.126
+++ window.c 25 Apr 2015 21:03:19 -0000
@@ -732,6 +732,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 Nicholas Marriott
Hi
I like the other diff a bit more than yours so I think I will go with
it, does it meet your needs too, or any comments?
Post by John O'Meara
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);
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
Loading...