Infrastructure for drawing status lines of more than one line in height,

still only one is allowed but this lets tmux draw bigger ones.
This commit is contained in:
nicm 2017-10-16 19:30:53 +00:00
parent a5fd5782f8
commit 2f6935a630
6 changed files with 123 additions and 71 deletions

View File

@ -49,11 +49,11 @@ recalculate_sizes(void)
struct client *c; struct client *c;
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
u_int ssx, ssy, has, limit; u_int ssx, ssy, has, limit, lines;
int flag, has_status, is_zoomed, forced; int flag, is_zoomed, forced;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
has_status = options_get_number(s->options, "status"); lines = status_line_size(s);
s->attached = 0; s->attached = 0;
ssx = ssy = UINT_MAX; ssx = ssy = UINT_MAX;
@ -66,10 +66,14 @@ recalculate_sizes(void)
if (c->session == s) { if (c->session == s) {
if (c->tty.sx < ssx) if (c->tty.sx < ssx)
ssx = c->tty.sx; ssx = c->tty.sx;
if (has_status && c->flags &= ~CLIENT_STATUSOFF;
if (lines != 0 && lines + PANE_MINIMUM > c->tty.sy)
c->flags |= CLIENT_STATUSOFF;
if ((~c->flags & CLIENT_STATUSOFF) &&
!(c->flags & CLIENT_CONTROL) && !(c->flags & CLIENT_CONTROL) &&
c->tty.sy > 1 && c->tty.sy - 1 < ssy) c->tty.sy > lines &&
ssy = c->tty.sy - 1; c->tty.sy - lines < ssy)
ssy = c->tty.sy - lines;
else if (c->tty.sy < ssy) else if (c->tty.sy < ssy)
ssy = c->tty.sy; ssy = c->tty.sy;
s->attached++; s->attached++;
@ -81,8 +85,8 @@ recalculate_sizes(void)
} }
s->flags &= ~SESSION_UNATTACHED; s->flags &= ~SESSION_UNATTACHED;
if (has_status && ssy == 0) if (lines != 0 && ssy == 0)
ssy = 1; ssy = lines;
if (s->sx == ssx && s->sy == ssy) if (s->sx == ssx && s->sy == ssy)
continue; continue;

View File

@ -33,11 +33,11 @@ static int screen_redraw_make_pane_status(struct client *, struct window *,
struct window_pane *); struct window_pane *);
static void screen_redraw_draw_pane_status(struct client *, int); static void screen_redraw_draw_pane_status(struct client *, int);
static void screen_redraw_draw_borders(struct client *, int, int, u_int); static void screen_redraw_draw_borders(struct client *, int, u_int, u_int);
static void screen_redraw_draw_panes(struct client *, u_int); static void screen_redraw_draw_panes(struct client *, u_int, u_int);
static void screen_redraw_draw_status(struct client *, u_int); static void screen_redraw_draw_status(struct client *, u_int, u_int);
static void screen_redraw_draw_number(struct client *, struct window_pane *, static void screen_redraw_draw_number(struct client *, struct window_pane *,
u_int); u_int, u_int);
#define CELL_INSIDE 0 #define CELL_INSIDE 0
#define CELL_LEFTRIGHT 1 #define CELL_LEFTRIGHT 1
@ -377,36 +377,38 @@ screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct options *wo = w->options; struct options *wo = w->options;
u_int top; u_int top, lines;
int status, pane_status, spos; int position, pane_status;
/* Suspended clients should not be updated. */
if (c->flags & CLIENT_SUSPENDED) if (c->flags & CLIENT_SUSPENDED)
return; return;
/* Get status line, er, status. */ if (c->flags & CLIENT_STATUSOFF)
spos = options_get_number(oo, "status-position"); lines = 0;
if (c->message_string != NULL || c->prompt_string != NULL)
status = 1;
else else
status = options_get_number(oo, "status"); lines = status_line_size(c->session);
top = 0; if (c->message_string != NULL || c->prompt_string != NULL)
if (status && spos == 0) lines = (lines == 0) ? 1 : lines;
position = options_get_number(oo, "status-position");
if (lines != 0 && position == 0)
top = 1; top = 1;
if (!status) else
top = 0;
if (lines == 0)
draw_status = 0; draw_status = 0;
/* Draw the elements. */
if (draw_borders) { if (draw_borders) {
pane_status = options_get_number(wo, "pane-border-status"); pane_status = options_get_number(wo, "pane-border-status");
screen_redraw_draw_borders(c, status, pane_status, top); screen_redraw_draw_borders(c, pane_status, lines, top);
if (pane_status != CELL_STATUS_OFF) if (pane_status != CELL_STATUS_OFF)
screen_redraw_draw_pane_status(c, pane_status); screen_redraw_draw_pane_status(c, pane_status);
} }
if (draw_panes) if (draw_panes)
screen_redraw_draw_panes(c, top); screen_redraw_draw_panes(c, lines, top);
if (draw_status) if (draw_status)
screen_redraw_draw_status(c, top); screen_redraw_draw_status(c, lines, top);
tty_reset(tty); tty_reset(tty);
} }
@ -421,7 +423,7 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
yoff = wp->yoff; yoff = wp->yoff;
if (status_at_line(c) == 0) if (status_at_line(c) == 0)
yoff++; yoff += status_line_size(c->session);
log_debug("%s: redraw pane %%%u (at %u,%u)", c->name, wp->id, log_debug("%s: redraw pane %%%u (at %u,%u)", c->name, wp->id,
wp->xoff, yoff); wp->xoff, yoff);
@ -433,7 +435,7 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
/* Draw the borders. */ /* Draw the borders. */
static void static void
screen_redraw_draw_borders(struct client *c, int status, int pane_status, screen_redraw_draw_borders(struct client *c, int pane_status, u_int lines,
u_int top) u_int top)
{ {
struct session *s = c->session; struct session *s = c->session;
@ -449,7 +451,7 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status,
const char *tmp; const char *tmp;
size_t msglen = 0; size_t msglen = 0;
small = (tty->sy - status + top > w->sy) || (tty->sx > w->sx); small = (tty->sy - lines + top > w->sy) || (tty->sx > w->sx);
if (small) { if (small) {
flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT); flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT);
if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT)) if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT))
@ -458,18 +460,20 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status,
tmp = "force-width"; tmp = "force-width";
else if (flags == WINDOW_FORCEHEIGHT) else if (flags == WINDOW_FORCEHEIGHT)
tmp = "force-height"; tmp = "force-height";
else if (c->flags & CLIENT_STATUSOFF)
tmp = "status line";
else else
tmp = "a smaller client"; tmp = "a smaller client";
xsnprintf(msg, sizeof msg, "(size %ux%u from %s)", xsnprintf(msg, sizeof msg, "(size %ux%u from %s)",
w->sx, w->sy, tmp); w->sx, w->sy, tmp);
msglen = strlen(msg); msglen = strlen(msg);
if (tty->sy - 1 - status + top > w->sy && tty->sx >= msglen) { if (tty->sy - 1 - lines + top > w->sy && tty->sx >= msglen) {
msgx = tty->sx - msglen; msgx = tty->sx - msglen;
msgy = tty->sy - 1 - status + top; msgy = tty->sy - 1 - lines + top;
} else if (tty->sx - w->sx > msglen) { } else if (tty->sx - w->sx > msglen) {
msgx = tty->sx - msglen; msgx = tty->sx - msglen;
msgy = tty->sy - 1 - status + top; msgy = tty->sy - 1 - lines + top;
} else } else
small = 0; small = 0;
} }
@ -483,7 +487,7 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status,
memcpy(&m_active_gc, &active_gc, sizeof m_active_gc); memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
m_active_gc.attr ^= GRID_ATTR_REVERSE; m_active_gc.attr ^= GRID_ATTR_REVERSE;
for (j = 0; j < tty->sy - status; j++) { for (j = 0; j < tty->sy - lines; j++) {
for (i = 0; i < tty->sx; i++) { for (i = 0; i < tty->sx; i++) {
type = screen_redraw_check_cell(c, i, j, pane_status, type = screen_redraw_check_cell(c, i, j, pane_status,
&wp); &wp);
@ -505,7 +509,10 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status,
tty_attributes(tty, &active_gc, NULL); tty_attributes(tty, &active_gc, NULL);
else else
tty_attributes(tty, &other_gc, NULL); tty_attributes(tty, &other_gc, NULL);
tty_cursor(tty, i, top + j); if (top)
tty_cursor(tty, i, lines + j);
else
tty_cursor(tty, i, j);
tty_putc(tty, CELL_BORDERS[type]); tty_putc(tty, CELL_BORDERS[type]);
} }
} }
@ -520,38 +527,47 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status,
/* Draw the panes. */ /* Draw the panes. */
static void static void
screen_redraw_draw_panes(struct client *c, u_int top) screen_redraw_draw_panes(struct client *c, u_int lines, u_int top)
{ {
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window_pane *wp; struct window_pane *wp;
u_int i; u_int i, y;
if (top)
y = lines;
else
y = 0;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
for (i = 0; i < wp->sy; i++) for (i = 0; i < wp->sy; i++)
tty_draw_pane(tty, wp, i, wp->xoff, top + wp->yoff); tty_draw_pane(tty, wp, i, wp->xoff, y + wp->yoff);
if (c->flags & CLIENT_IDENTIFY) if (c->flags & CLIENT_IDENTIFY)
screen_redraw_draw_number(c, wp, top); screen_redraw_draw_number(c, wp, lines, top);
} }
} }
/* Draw the status line. */ /* Draw the status line. */
static void static void
screen_redraw_draw_status(struct client *c, u_int top) screen_redraw_draw_status(struct client *c, u_int lines, u_int top)
{ {
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
u_int i, y;
if (top) if (top)
tty_draw_line(tty, NULL, &c->status, 0, 0, 0); y = 0;
else else
tty_draw_line(tty, NULL, &c->status, 0, 0, tty->sy - 1); y = tty->sy - lines;
for (i = 0; i < lines; i++)
tty_draw_line(tty, NULL, &c->status, i, 0, y);
} }
/* Draw number on a pane. */ /* Draw number on a pane. */
static void static void
screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top) screen_redraw_draw_number(struct client *c, struct window_pane *wp,
u_int lines, u_int top)
{ {
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct session *s = c->session; struct session *s = c->session;
@ -576,7 +592,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top)
xoff = wp->xoff; yoff = wp->yoff; xoff = wp->xoff; yoff = wp->yoff;
if (top) if (top)
yoff++; yoff += lines;
if (wp->sx < len * 6 || wp->sy < 5) { if (wp->sx < len * 6 || wp->sy < 5) {
tty_cursor(tty, xoff + px - len / 2, yoff + py); tty_cursor(tty, xoff + px - len / 2, yoff + py);

View File

@ -1201,7 +1201,7 @@ server_client_reset_state(struct client *c)
struct window_pane *wp = w->active, *loop; struct window_pane *wp = w->active, *loop;
struct screen *s = wp->screen; struct screen *s = wp->screen;
struct options *oo = c->session->options; struct options *oo = c->session->options;
int status, mode, o; int lines, mode;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return; return;
@ -1209,13 +1209,14 @@ server_client_reset_state(struct client *c)
tty_region_off(&c->tty); tty_region_off(&c->tty);
tty_margin_off(&c->tty); tty_margin_off(&c->tty);
status = options_get_number(oo, "status"); if (status_at_line(c) != 0)
if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) lines = 0;
else
lines = status_line_size(c->session);
if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - lines)
tty_cursor(&c->tty, 0, 0); tty_cursor(&c->tty, 0, 0);
else { else
o = status && options_get_number(oo, "status-position") == 0; tty_cursor(&c->tty, wp->xoff + s->cx, lines + wp->yoff + s->cy);
tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy);
}
/* /*
* Set mouse mode if requested. To support dragging, always use button * Set mouse mode if requested. To support dragging, always use button

View File

@ -210,9 +210,24 @@ status_at_line(struct client *c)
{ {
struct session *s = c->session; struct session *s = c->session;
if (c->flags & CLIENT_STATUSOFF)
return (-1);
if (s->statusat != 1) if (s->statusat != 1)
return (s->statusat); return (s->statusat);
return (c->tty.sy - 1); return (c->tty.sy - status_line_size(s));
}
/*
* Get size of status line for session. 0 means off. Note that status line may
* be forced off for an individual client if it is too small (the
* CLIENT_STATUSOFF flag is set for this).
*/
u_int
status_line_size(struct session *s)
{
if (s->statusat == -1)
return (0);
return (1);
} }
/* Retrieve options for left string. */ /* Retrieve options for left string. */
@ -296,7 +311,7 @@ status_redraw(struct client *c)
time_t t; time_t t;
char *left, *right; char *left, *right;
const char *sep; const char *sep;
u_int offset, needed; u_int offset, needed, lines;
u_int wlstart, wlwidth, wlavailable, wloffset, wlsize; u_int wlstart, wlwidth, wlavailable, wloffset, wlsize;
size_t llen, rlen, seplen; size_t llen, rlen, seplen;
int larrow, rarrow; int larrow, rarrow;
@ -309,7 +324,8 @@ status_redraw(struct client *c)
} }
/* No status line? */ /* No status line? */
if (c->tty.sy == 0 || !options_get_number(s->options, "status")) lines = status_line_size(s);
if (c->tty.sy == 0 || lines == 0)
return (1); return (1);
left = right = NULL; left = right = NULL;
larrow = rarrow = 0; larrow = rarrow = 0;
@ -322,14 +338,13 @@ status_redraw(struct client *c)
/* Create the target screen. */ /* Create the target screen. */
memcpy(&old_status, &c->status, sizeof old_status); memcpy(&old_status, &c->status, sizeof old_status);
screen_init(&c->status, c->tty.sx, 1, 0); screen_init(&c->status, c->tty.sx, lines, 0);
screen_write_start(&ctx, NULL, &c->status); screen_write_start(&ctx, NULL, &c->status);
for (offset = 0; offset < c->tty.sx; offset++) screen_write_clearscreen(&ctx, stdgc.bg);
screen_write_putc(&ctx, &stdgc, ' ');
screen_write_stop(&ctx); screen_write_stop(&ctx);
/* If the height is one line, blank status line. */ /* If the height is too small, blank status line. */
if (c->tty.sy <= 1) if (c->tty.sy < lines)
goto out; goto out;
/* Work out left and right strings. */ /* Work out left and right strings. */
@ -637,11 +652,17 @@ status_message_redraw(struct client *c)
struct screen old_status; struct screen old_status;
size_t len; size_t len;
struct grid_cell gc; struct grid_cell gc;
u_int lines;
if (c->tty.sx == 0 || c->tty.sy == 0) if (c->tty.sx == 0 || c->tty.sy == 0)
return (0); return (0);
memcpy(&old_status, &c->status, sizeof old_status); memcpy(&old_status, &c->status, sizeof old_status);
lines = status_line_size(c->session);
if (lines <= 1)
screen_init(&c->status, c->tty.sx, 1, 0); screen_init(&c->status, c->tty.sx, 1, 0);
else
screen_init(&c->status, c->tty.sx, lines, 0);
len = screen_write_strlen("%s", c->message_string); len = screen_write_strlen("%s", c->message_string);
if (len > c->tty.sx) if (len > c->tty.sx)
@ -650,12 +671,9 @@ status_message_redraw(struct client *c)
style_apply(&gc, s->options, "message-style"); style_apply(&gc, s->options, "message-style");
screen_write_start(&ctx, NULL, &c->status); screen_write_start(&ctx, NULL, &c->status);
screen_write_clearscreen(&ctx, gc.bg);
screen_write_cursormove(&ctx, 0, 0); screen_write_cursormove(&ctx, 0, lines - 1);
screen_write_nputs(&ctx, len, &gc, "%s", c->message_string); screen_write_nputs(&ctx, len, &gc, "%s", c->message_string);
for (; len < c->tty.sx; len++)
screen_write_putc(&ctx, &gc, ' ');
screen_write_stop(&ctx); screen_write_stop(&ctx);
if (grid_compare(c->status.grid, old_status.grid) == 0) { if (grid_compare(c->status.grid, old_status.grid) == 0) {
@ -782,12 +800,24 @@ status_prompt_redraw(struct client *c)
struct session *s = c->session; struct session *s = c->session;
struct screen old_status; struct screen old_status;
u_int i, offset, left, start, pcursor, pwidth, width; u_int i, offset, left, start, pcursor, pwidth, width;
u_int lines;
size_t len, off;
struct grid_cell gc, cursorgc; struct grid_cell gc, cursorgc;
if (c->tty.sx == 0 || c->tty.sy == 0) if (c->tty.sx == 0 || c->tty.sy == 0)
return (0); return (0);
memcpy(&old_status, &c->status, sizeof old_status); memcpy(&old_status, &c->status, sizeof old_status);
lines = status_line_size(c->session);
if (lines <= 1)
screen_init(&c->status, c->tty.sx, 1, 0); screen_init(&c->status, c->tty.sx, 1, 0);
else
screen_init(&c->status, c->tty.sx, lines, 0);
len = screen_write_strlen("%s", c->prompt_string);
if (len > c->tty.sx)
len = c->tty.sx;
off = 0;
if (c->prompt_mode == PROMPT_COMMAND) if (c->prompt_mode == PROMPT_COMMAND)
style_apply(&gc, s->options, "message-command-style"); style_apply(&gc, s->options, "message-command-style");
@ -802,11 +832,10 @@ status_prompt_redraw(struct client *c)
start = c->tty.sx; start = c->tty.sx;
screen_write_start(&ctx, NULL, &c->status); screen_write_start(&ctx, NULL, &c->status);
screen_write_cursormove(&ctx, 0, 0); screen_write_clearscreen(&ctx, gc.bg);
screen_write_cursormove(&ctx, 0, lines - 1);
screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string); screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string);
while (c->status.cx < screen_size_x(&c->status)) screen_write_cursormove(&ctx, start, lines - 1);
screen_write_putc(&ctx, &gc, ' ');
screen_write_cursormove(&ctx, start, 0);
left = c->tty.sx - start; left = c->tty.sx - start;
if (left == 0) if (left == 0)

2
tmux.h
View File

@ -1381,6 +1381,7 @@ struct client {
#define CLIENT_DOUBLECLICK 0x100000 #define CLIENT_DOUBLECLICK 0x100000
#define CLIENT_TRIPLECLICK 0x200000 #define CLIENT_TRIPLECLICK 0x200000
#define CLIENT_SIZECHANGED 0x400000 #define CLIENT_SIZECHANGED 0x400000
#define CLIENT_STATUSOFF 0x800000
int flags; int flags;
struct key_table *keytable; struct key_table *keytable;
@ -1928,6 +1929,7 @@ void status_timer_start(struct client *);
void status_timer_start_all(void); void status_timer_start_all(void);
void status_update_saved(struct session *s); void status_update_saved(struct session *s);
int status_at_line(struct client *); int status_at_line(struct client *);
u_int status_line_size(struct session *);
struct window *status_get_window_at(struct client *, u_int); struct window *status_get_window_at(struct client *, u_int);
int status_redraw(struct client *); int status_redraw(struct client *);
void printflike(2, 3) status_message_set(struct client *, const char *, ...); void printflike(2, 3) status_message_set(struct client *, const char *, ...);

2
tty.c
View File

@ -1038,7 +1038,7 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
ctx->xoff = wp->xoff; ctx->xoff = wp->xoff;
ctx->yoff = wp->yoff; ctx->yoff = wp->yoff;
if (status_at_line(c) == 0) if (status_at_line(c) == 0)
ctx->yoff++; ctx->yoff += status_line_size(c->session);
cmdfn(&c->tty, ctx); cmdfn(&c->tty, ctx);
} }