Merge branch 'obsd-master'

pull/392/head
Thomas Adam 2016-04-29 18:01:09 +01:00
commit 55d472a9fe
8 changed files with 247 additions and 44 deletions

View File

@ -201,6 +201,12 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
if (strcmp(oe->name, "monitor-silence") == 0) if (strcmp(oe->name, "monitor-silence") == 0)
alerts_reset_all(); alerts_reset_all();
/* When the pane-border-status option has been changed, resize panes. */
if (strcmp(oe->name, "pane-border-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. */ /* Update sizes and redraw. May not need it but meh. */
recalculate_sizes(); recalculate_sizes();
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {

View File

@ -32,8 +32,11 @@
* cell a pointer to its parent cell. * cell a pointer to its parent cell.
*/ */
int layout_resize_pane_grow(struct layout_cell *, enum layout_type, int); static int layout_resize_pane_grow(struct layout_cell *, enum layout_type,
int layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int); int);
static int layout_resize_pane_shrink(struct layout_cell *,
enum layout_type, int);
static int layout_need_status(struct layout_cell *, int);
struct layout_cell * struct layout_cell *
layout_create_cell(struct layout_cell *lcparent) layout_create_cell(struct layout_cell *lcparent)
@ -163,6 +166,30 @@ layout_fix_offsets(struct layout_cell *lc)
} }
} }
/*
* Returns 1 if we need to reserve space for the pane status line. This is the
* case for the most upper panes only.
*/
static 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. */ /* Update pane offsets and sizes based on their cells. */
void void
layout_fix_panes(struct window *w, u_int wsx, u_int wsy) layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
@ -170,13 +197,25 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc; struct layout_cell *lc;
u_int sx, sy; u_int sx, sy;
int shift, status, at_top;
status = options_get_number(w->options, "pane-border-status");
at_top = (status == 1);
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if ((lc = wp->layout_cell) == NULL) if ((lc = wp->layout_cell) == NULL)
continue; continue;
if (status != 0)
shift = layout_need_status(lc, at_top);
else
shift = 0;
wp->xoff = lc->xoff; wp->xoff = lc->xoff;
wp->yoff = lc->yoff; wp->yoff = lc->yoff;
if (shift && at_top)
wp->yoff += 1;
/* /*
* Layout cells are limited by the smallest size of other cells * Layout cells are limited by the smallest size of other cells
* within the same row or column; if this isn't the case * within the same row or column; if this isn't the case
@ -214,6 +253,9 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
sy = lc->sy; sy = lc->sy;
} }
if (shift)
sy -= 1;
window_pane_resize(wp, sx, sy); window_pane_resize(wp, sx, sy);
} }
} }
@ -520,7 +562,7 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
} }
/* Helper function to grow pane. */ /* Helper function to grow pane. */
int static int
layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type, layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
int needed) int needed)
{ {
@ -561,7 +603,7 @@ layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
} }
/* Helper function to shrink pane. */ /* Helper function to shrink pane. */
int static int
layout_resize_pane_shrink(struct layout_cell *lc, enum layout_type type, layout_resize_pane_shrink(struct layout_cell *lc, enum layout_type type,
int needed) int needed)
{ {

View File

@ -50,6 +50,9 @@ const char *options_table_status_position_list[] = {
const char *options_table_bell_action_list[] = { const char *options_table_bell_action_list[] = {
"none", "any", "current", "other", NULL "none", "any", "current", "other", NULL
}; };
const char *options_table_pane_status_list[] = {
"off", "top", "bottom", NULL
};
/* Server options. */ /* Server options. */
const struct options_table_entry options_table[] = { const struct options_table_entry options_table[] = {
@ -692,6 +695,19 @@ const struct options_table_entry options_table[] = {
.style = "pane-border-style" .style = "pane-border-style"
}, },
{ .name = "pane-border-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] \"#{pane_title}\""
},
{ .name = "pane-border-status",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_pane_status_list,
.default_num = 0
},
{ .name = "pane-border-style", { .name = "pane-border-style",
.type = OPTIONS_TABLE_STYLE, .type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,

View File

@ -24,12 +24,16 @@
int screen_redraw_cell_border1(struct window_pane *, u_int, u_int); 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_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 **); struct window_pane **);
int screen_redraw_check_is(u_int, u_int, int, struct window *, int screen_redraw_check_is(u_int, u_int, int, int, struct window *,
struct window_pane *, struct window_pane *); struct window_pane *, 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_panes(struct client *, u_int);
void screen_redraw_draw_status(struct client *, u_int); void screen_redraw_draw_status(struct client *, u_int);
void screen_redraw_draw_number(struct client *, struct window_pane *, u_int); void screen_redraw_draw_number(struct client *, struct window_pane *, u_int);
@ -50,6 +54,10 @@ void screen_redraw_draw_number(struct client *, struct window_pane *, u_int);
#define CELL_BORDERS " xqlkmjwvtun~" #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. */ /* Check if cell is on the border of a particular pane. */
int int
screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py) screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
@ -64,15 +72,15 @@ screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
if (wp->xoff != 0 && px == wp->xoff - 1) if (wp->xoff != 0 && px == wp->xoff - 1)
return (1); return (1);
if (px == wp->xoff + wp->sx) if (px == wp->xoff + wp->sx)
return (1); return (2);
} }
/* Top/bottom borders. */ /* Top/bottom borders. */
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= wp->xoff + wp->sx) { if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= wp->xoff + wp->sx) {
if (wp->yoff != 0 && py == wp->yoff - 1) if (wp->yoff != 0 && py == wp->yoff - 1)
return (1); return (3);
if (py == wp->yoff + wp->sy) if (py == wp->yoff + wp->sy)
return (1); return (4);
} }
/* Outside pane. */ /* Outside pane. */
@ -92,7 +100,7 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py)
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
if ((retval = screen_redraw_cell_border1(wp, px, py)) != -1) if ((retval = screen_redraw_cell_border1(wp, px, py)) != -1)
return (retval); return (!!retval);
} }
return (0); return (0);
@ -100,16 +108,33 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py)
/* Check if cell inside a pane. */ /* Check if cell inside a pane. */
int 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_pane **wpp)
{ {
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
int borders; int borders;
u_int right, line;
if (px > w->sx || py > w->sy) if (px > w->sx || py > w->sy)
return (CELL_OUTSIDE); 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) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
@ -135,8 +160,13 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py,
borders |= 8; borders |= 8;
if (px <= w->sx && screen_redraw_cell_border(c, px + 1, py)) if (px <= w->sx && screen_redraw_cell_border(c, px + 1, py))
borders |= 4; borders |= 4;
if (py == 0 || screen_redraw_cell_border(c, px, py - 1)) if (pane_status == CELL_STATUS_TOP) {
borders |= 2; 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)) if (py <= w->sy && screen_redraw_cell_border(c, px, py + 1))
borders |= 1; borders |= 1;
@ -177,11 +207,18 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py,
/* Check if the border of a particular pane. */ /* Check if the border of a particular pane. */
int int
screen_redraw_check_is(u_int px, u_int py, int type, struct window *w, screen_redraw_check_is(u_int px, u_int py, int type, int pane_status,
struct window_pane *wantwp, struct window_pane *wp) struct window *w, struct window_pane *wantwp, struct window_pane *wp)
{ {
int border;
/* Is this off the active pane border? */ /* Is this off the active pane border? */
if (screen_redraw_cell_border1(wantwp, px, py) != 1) border = screen_redraw_cell_border1(wantwp, px, py);
if (border == 0 || border == -1)
return (0);
if (pane_status == CELL_STATUS_TOP && border == 4)
return (0);
if (pane_status == CELL_STATUS_BOTTOM && border == 3)
return (0); return (0);
/* If there are more than two panes, that's enough. */ /* If there are more than two panes, that's enough. */
@ -192,6 +229,10 @@ screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE)) if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE))
return (1); 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. */ /* Check if the pane covers the whole width. */
if (wp->xoff == 0 && wp->sx == w->sx) { if (wp->xoff == 0 && wp->sx == w->sx) {
/* This can either be the top pane or the bottom pane. */ /* This can either be the top pane or the bottom pane. */
@ -214,7 +255,77 @@ screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
return (0); 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 grid_cell gc;
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, w->options, "pane-active-border-style");
else
style_apply(&gc, w->options, "pane-border-style");
fmt = options_get_string(w->options, "pane-border-format");
ft = format_create(NULL, 0);
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;
out = format_expand(ft, fmt);
outlen = screen_write_cstrlen("%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_cnputs(&ctx, outlen, &gc, "%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. */ /* Redraw entire screen. */
@ -222,10 +333,12 @@ void
screen_redraw_screen(struct client *c, int draw_panes, int draw_status, screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
int draw_borders) int draw_borders)
{ {
struct options *oo = c->session->options; struct options *oo = c->session->options;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
u_int top; struct window *w = c->session->curw->window;
int status, spos; struct window_pane *wp;
u_int top;
int status, pane_status, spos;
/* Suspended clients should not be updated. */ /* Suspended clients should not be updated. */
if (c->flags & CLIENT_SUSPENDED) if (c->flags & CLIENT_SUSPENDED)
@ -243,12 +356,24 @@ screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
if (!status) if (!status)
draw_status = 0; draw_status = 0;
/* Update pane status lines. */
pane_status = options_get_number(w->options, "pane-border-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) if (draw_borders)
screen_redraw_draw_borders(c, status, top); screen_redraw_draw_borders(c, status, pane_status, top);
if (draw_panes) if (draw_panes)
screen_redraw_draw_panes(c, top); screen_redraw_draw_panes(c, top);
if (draw_status) if (draw_status)
screen_redraw_draw_status(c, top); 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); tty_reset(tty);
} }
@ -272,7 +397,8 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
/* Draw the borders. */ /* Draw the borders. */
void 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 session *s = c->session; struct session *s = c->session;
struct window *w = s->curw->window; struct window *w = s->curw->window;
@ -323,16 +449,17 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top)
for (j = 0; j < tty->sy - status; j++) { for (j = 0; j < tty->sy - status; j++) {
for (i = 0; i < tty->sx; i++) { 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) if (type == CELL_INSIDE)
continue; continue;
if (type == CELL_OUTSIDE && small && if (type == CELL_OUTSIDE && small &&
i > msgx && j == msgy) i > msgx && j == msgy)
continue; continue;
active = screen_redraw_check_is(i, j, type, w, active = screen_redraw_check_is(i, j, type, pane_status,
w->active, wp); w, w->active, wp);
if (server_is_marked(s, s->curw, marked_pane.wp) && if (server_is_marked(s, s->curw, marked_pane.wp) &&
screen_redraw_check_is(i, j, type, w, screen_redraw_check_is(i, j, type, pane_status, w,
marked_pane.wp, wp)) { marked_pane.wp, wp)) {
if (active) if (active)
tty_attributes(tty, &m_active_gc, NULL); tty_attributes(tty, &m_active_gc, NULL);

View File

@ -929,7 +929,7 @@ server_client_check_redraw(struct client *c)
struct session *s = c->session; struct session *s = c->session;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window_pane *wp; struct window_pane *wp;
int flags, redraw; int flags, masked, redraw;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return; return;
@ -969,15 +969,15 @@ server_client_check_redraw(struct client *c)
} }
} }
if (c->flags & CLIENT_BORDERS) { masked = c->flags & (CLIENT_BORDERS|CLIENT_STATUS);
if (masked != 0)
tty_update_mode(tty, tty->mode, NULL); tty_update_mode(tty, tty->mode, NULL);
if (masked == CLIENT_BORDERS)
screen_redraw_screen(c, 0, 0, 1); screen_redraw_screen(c, 0, 0, 1);
} else if (masked == CLIENT_STATUS)
if (c->flags & CLIENT_STATUS) {
tty_update_mode(tty, tty->mode, NULL);
screen_redraw_screen(c, 0, 1, 0); screen_redraw_screen(c, 0, 1, 0);
} else if (masked != 0)
screen_redraw_screen(c, 0, 1, 1);
tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags; tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags;
tty_update_mode(tty, tty->mode, NULL); tty_update_mode(tty, tty->mode, NULL);

25
tmux.1
View File

@ -2778,19 +2778,18 @@ will be passed through
and formats (see and formats (see
.Sx FORMATS ) .Sx FORMATS )
will be expanded. will be expanded.
It may also contain any of the following special character sequences:
.Bl -column "Character pair" "Replaced with" -offset indent It may also contain the a special character sequence #[] to change the colour
.It Sy "Character pair" Ta Sy "Replaced with" or attributes, for example
.It Li "#[attributes]" Ta "Colour or attribute change" .Ql #[fg=red,bright]
.It Li "##" Ta "A literal" Ql # to set a bright red foreground.
.El See the
.Ic message-command-style
option for a description of colours and attributes.
.Pp .Pp
For details on how the names and titles can be set see the For details on how the names and titles can be set see the
.Sx "NAMES AND TITLES" .Sx "NAMES AND TITLES"
section. section.
For a list of allowed attributes see the
.Ic message-command-style
option.
.Pp .Pp
Examples are: Examples are:
.Bd -literal -offset indent .Bd -literal -offset indent
@ -3069,6 +3068,14 @@ Like
.Ic base-index , .Ic base-index ,
but set the starting index for pane numbers. but set the starting index for pane numbers.
.Pp .Pp
.It Ic pane-border-format Ar format
Set the text shown in pane border status lines.
.Pp
.It Xo Ic pane-border-status
.Op Ic off | top | bottom
.Xc
Turn pane border status lines off or set their position.
.Pp
.It Ic pane-border-style Ar style .It Ic pane-border-style Ar style
Set the pane border style for panes aside from the active pane. Set the pane border style for panes aside from the active pane.
For how to specify For how to specify

3
tmux.h
View File

@ -896,6 +896,9 @@ struct window_pane {
struct screen *screen; struct screen *screen;
struct screen base; struct screen base;
struct screen status_screen;
size_t status_size;
/* Saved in alternative screen mode. */ /* Saved in alternative screen mode. */
u_int saved_cx; u_int saved_cx;
u_int saved_cy; u_int saved_cy;

View File

@ -764,6 +764,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
screen_init(&wp->base, sx, sy, hlimit); screen_init(&wp->base, sx, sy, hlimit);
wp->screen = &wp->base; wp->screen = &wp->base;
screen_init(&wp->status_screen, 1, 1, 0);
if (gethostname(host, sizeof host) == 0) if (gethostname(host, sizeof host) == 0)
screen_set_title(&wp->base, host); screen_set_title(&wp->base, host);