diff options
author | nicm <nicm> | 2016-04-29 15:00:48 +0000 |
---|---|---|
committer | nicm <nicm> | 2016-04-29 15:00:48 +0000 |
commit | 0509be07404a4f4626bbdab56d858f657dc68604 (patch) | |
tree | ae0d8196081ac903121f0d2e4ac754a763a3689d | |
parent | 0d84fdd95303a6ed4dcd761425e35f3731b86725 (diff) | |
download | rtmux-0509be07404a4f4626bbdab56d858f657dc68604.tar.gz rtmux-0509be07404a4f4626bbdab56d858f657dc68604.tar.bz2 rtmux-0509be07404a4f4626bbdab56d858f657dc68604.zip |
Add option to include status text in the pane borders. If
pane-border-status is set to "top" or "bottom" (rather than "off"),
every pane has a permanent top or bottom border containing the text from
pane-border-format.
Based on a diff sent long ago by Jonathan Slenders, mostly rewritten and
simplified by me.
-rw-r--r-- | cmd-set-option.c | 6 | ||||
-rw-r--r-- | layout.c | 50 | ||||
-rw-r--r-- | options-table.c | 16 | ||||
-rw-r--r-- | screen-redraw.c | 175 | ||||
-rw-r--r-- | server-client.c | 14 | ||||
-rw-r--r-- | tmux.1 | 8 | ||||
-rw-r--r-- | tmux.h | 3 | ||||
-rw-r--r-- | window.c | 2 |
8 files changed, 239 insertions, 35 deletions
diff --git a/cmd-set-option.c b/cmd-set-option.c index b1771436..6fc6c8ba 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -201,6 +201,12 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) if (strcmp(oe->name, "monitor-silence") == 0) 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. */ recalculate_sizes(); TAILQ_FOREACH(c, &clients, entry) { @@ -32,8 +32,11 @@ * cell a pointer to its parent cell. */ -int layout_resize_pane_grow(struct layout_cell *, enum layout_type, int); -int layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int); +static int layout_resize_pane_grow(struct layout_cell *, enum layout_type, + 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 * 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. */ void 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 layout_cell *lc; 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) { 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 @@ -214,6 +253,9 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy) sy = lc->sy; } + if (shift) + sy -= 1; + 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. */ -int +static int layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type, int needed) { @@ -561,7 +603,7 @@ layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type, } /* Helper function to shrink pane. */ -int +static int layout_resize_pane_shrink(struct layout_cell *lc, enum layout_type type, int needed) { diff --git a/options-table.c b/options-table.c index af0f41ed..c55ce715 100644 --- a/options-table.c +++ b/options-table.c @@ -51,6 +51,9 @@ const char *options_table_status_position_list[] = { const char *options_table_bell_action_list[] = { "none", "any", "current", "other", NULL }; +const char *options_table_pane_status_list[] = { + "off", "top", "bottom", NULL +}; /* Server options. */ const struct options_table_entry options_table[] = { @@ -693,6 +696,19 @@ const struct options_table_entry options_table[] = { .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", .type = OPTIONS_TABLE_STYLE, .scope = OPTIONS_TABLE_WINDOW, diff --git a/screen-redraw.c b/screen-redraw.c index 952a8515..694f6c27 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -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_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 *); -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 *, u_int); @@ -50,6 +54,10 @@ void screen_redraw_draw_number(struct client *, struct window_pane *, u_int); #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) @@ -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) return (1); if (px == wp->xoff + wp->sx) - return (1); + return (2); } /* Top/bottom borders. */ if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= wp->xoff + wp->sx) { if (wp->yoff != 0 && py == wp->yoff - 1) - return (1); + return (3); if (py == wp->yoff + wp->sy) - return (1); + return (4); } /* Outside pane. */ @@ -92,7 +100,7 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py) if (!window_pane_visible(wp)) continue; if ((retval = screen_redraw_cell_border1(wp, px, py)) != -1) - return (retval); + return (!!retval); } 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. */ 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 *c, u_int px, u_int py, 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,11 +207,18 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, /* Check if the border of a particular pane. */ int -screen_redraw_check_is(u_int px, u_int py, int type, struct window *w, - struct window_pane *wantwp, struct window_pane *wp) +screen_redraw_check_is(u_int px, u_int py, int type, int pane_status, + struct window *w, struct window_pane *wantwp, struct window_pane *wp) { + int 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); /* 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)) 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 +255,77 @@ screen_redraw_check_is(u_int px, u_int py, int type, struct window *w, 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. */ @@ -222,10 +333,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 +356,24 @@ screen_redraw_screen(struct client *c, int draw_panes, int draw_status, if (!status) 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) - 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 +397,8 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) /* 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 session *s = c->session; 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 (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; - active = screen_redraw_check_is(i, j, type, w, - w->active, wp); + active = screen_redraw_check_is(i, j, type, pane_status, + w, w->active, 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)) { if (active) tty_attributes(tty, &m_active_gc, NULL); diff --git a/server-client.c b/server-client.c index 9dad52fe..08f48b31 100644 --- a/server-client.c +++ b/server-client.c @@ -921,7 +921,7 @@ server_client_check_redraw(struct client *c) struct session *s = c->session; struct tty *tty = &c->tty; struct window_pane *wp; - int flags, redraw; + int flags, masked, redraw; if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) return; @@ -961,15 +961,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); + if (masked == CLIENT_BORDERS) screen_redraw_screen(c, 0, 0, 1); - } - - if (c->flags & CLIENT_STATUS) { - tty_update_mode(tty, tty->mode, NULL); + else if (masked == CLIENT_STATUS) 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_update_mode(tty, tty->mode, NULL); @@ -3065,6 +3065,14 @@ Like .Ic base-index , but set the starting index for pane numbers. .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 Set the pane border style for panes aside from the active pane. For how to specify @@ -894,6 +894,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; @@ -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); wp->screen = &wp->base; + screen_init(&wp->status_screen, 1, 1, 0); + if (gethostname(host, sizeof host) == 0) screen_set_title(&wp->base, host); |