Home | History | Annotate | Line # | Download | only in dist
screen-redraw.c revision 1.1.1.8.2.1
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  */
     18 
     19 #include <sys/types.h>
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 
     24 #include "tmux.h"
     25 
     26 struct screen_redraw_ctx {
     27 	struct client	*c;
     28 
     29 	u_int		 lines;
     30 	int		 top;
     31 
     32 	int		 pane_status;
     33 
     34 	u_int		 sx;
     35 	u_int		 sy;
     36 };
     37 
     38 static int	screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
     39 static int	screen_redraw_cell_border(struct client *, u_int, u_int);
     40 static int	screen_redraw_check_cell(struct client *, u_int, u_int, int,
     41 		    struct window_pane **);
     42 static int	screen_redraw_check_is(u_int, u_int, int, int, struct window *,
     43 		    struct window_pane *, struct window_pane *);
     44 
     45 static int 	screen_redraw_make_pane_status(struct client *, struct window *,
     46 		    struct window_pane *);
     47 static void	screen_redraw_draw_pane_status(struct client *, int);
     48 
     49 static void	screen_redraw_draw_borders(struct screen_redraw_ctx *);
     50 static void	screen_redraw_draw_panes(struct screen_redraw_ctx *);
     51 static void	screen_redraw_draw_status(struct screen_redraw_ctx *);
     52 static void	screen_redraw_draw_number(struct screen_redraw_ctx *,
     53 		    struct window_pane *);
     54 
     55 #define CELL_INSIDE 0
     56 #define CELL_LEFTRIGHT 1
     57 #define CELL_TOPBOTTOM 2
     58 #define CELL_TOPLEFT 3
     59 #define CELL_TOPRIGHT 4
     60 #define CELL_BOTTOMLEFT 5
     61 #define CELL_BOTTOMRIGHT 6
     62 #define CELL_TOPJOIN 7
     63 #define CELL_BOTTOMJOIN 8
     64 #define CELL_LEFTJOIN 9
     65 #define CELL_RIGHTJOIN 10
     66 #define CELL_JOIN 11
     67 #define CELL_OUTSIDE 12
     68 
     69 #define CELL_BORDERS " xqlkmjwvtun~"
     70 
     71 #define CELL_STATUS_OFF 0
     72 #define CELL_STATUS_TOP 1
     73 #define CELL_STATUS_BOTTOM 2
     74 
     75 /* Check if cell is on the border of a particular pane. */
     76 static int
     77 screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
     78 {
     79 	/* Inside pane. */
     80 	if (px >= wp->xoff && px < wp->xoff + wp->sx &&
     81 	    py >= wp->yoff && py < wp->yoff + wp->sy)
     82 		return (0);
     83 
     84 	/* Left/right borders. */
     85 	if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= wp->yoff + wp->sy) {
     86 		if (wp->xoff != 0 && px == wp->xoff - 1)
     87 			return (1);
     88 		if (px == wp->xoff + wp->sx)
     89 			return (2);
     90 	}
     91 
     92 	/* Top/bottom borders. */
     93 	if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= wp->xoff + wp->sx) {
     94 		if (wp->yoff != 0 && py == wp->yoff - 1)
     95 			return (3);
     96 		if (py == wp->yoff + wp->sy)
     97 			return (4);
     98 	}
     99 
    100 	/* Outside pane. */
    101 	return (-1);
    102 }
    103 
    104 /* Check if a cell is on the pane border. */
    105 static int
    106 screen_redraw_cell_border(struct client *c, u_int px, u_int py)
    107 {
    108 	struct window		*w = c->session->curw->window;
    109 	struct window_pane	*wp;
    110 	int			 retval;
    111 
    112 	/* Check all the panes. */
    113 	TAILQ_FOREACH(wp, &w->panes, entry) {
    114 		if (!window_pane_visible(wp))
    115 			continue;
    116 		if ((retval = screen_redraw_cell_border1(wp, px, py)) != -1)
    117 			return (!!retval);
    118 	}
    119 
    120 	return (0);
    121 }
    122 
    123 /* Check if cell inside a pane. */
    124 static int
    125 screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
    126     struct window_pane **wpp)
    127 {
    128 	struct window		*w = c->session->curw->window;
    129 	struct window_pane	*wp;
    130 	int			 borders;
    131 	u_int			 right, line;
    132 
    133 	*wpp = NULL;
    134 
    135 	if (px > w->sx || py > w->sy)
    136 		return (CELL_OUTSIDE);
    137 
    138 	if (pane_status != CELL_STATUS_OFF) {
    139 		TAILQ_FOREACH(wp, &w->panes, entry) {
    140 			if (!window_pane_visible(wp))
    141 				continue;
    142 
    143 			if (pane_status == CELL_STATUS_TOP)
    144 				line = wp->yoff - 1;
    145 			else
    146 				line = wp->yoff + wp->sy;
    147 			right = wp->xoff + 2 + wp->status_size - 1;
    148 
    149 			if (py == line && px >= wp->xoff + 2 && px <= right)
    150 				return (CELL_INSIDE);
    151 		}
    152 	}
    153 
    154 	TAILQ_FOREACH(wp, &w->panes, entry) {
    155 		if (!window_pane_visible(wp))
    156 			continue;
    157 		*wpp = wp;
    158 
    159 		/* If outside the pane and its border, skip it. */
    160 		if ((wp->xoff != 0 && px < wp->xoff - 1) ||
    161 		    px > wp->xoff + wp->sx ||
    162 		    (wp->yoff != 0 && py < wp->yoff - 1) ||
    163 		    py > wp->yoff + wp->sy)
    164 			continue;
    165 
    166 		/* If definitely inside, return so. */
    167 		if (!screen_redraw_cell_border(c, px, py))
    168 			return (CELL_INSIDE);
    169 
    170 		/*
    171 		 * Construct a bitmask of whether the cells to the left (bit
    172 		 * 4), right, top, and bottom (bit 1) of this cell are borders.
    173 		 */
    174 		borders = 0;
    175 		if (px == 0 || screen_redraw_cell_border(c, px - 1, py))
    176 			borders |= 8;
    177 		if (px <= w->sx && screen_redraw_cell_border(c, px + 1, py))
    178 			borders |= 4;
    179 		if (pane_status == CELL_STATUS_TOP) {
    180 			if (py != 0 && screen_redraw_cell_border(c, px, py - 1))
    181 				borders |= 2;
    182 		} else {
    183 			if (py == 0 || screen_redraw_cell_border(c, px, py - 1))
    184 				borders |= 2;
    185 		}
    186 		if (py <= w->sy && screen_redraw_cell_border(c, px, py + 1))
    187 			borders |= 1;
    188 
    189 		/*
    190 		 * Figure out what kind of border this cell is. Only one bit
    191 		 * set doesn't make sense (can't have a border cell with no
    192 		 * others connected).
    193 		 */
    194 		switch (borders) {
    195 		case 15:	/* 1111, left right top bottom */
    196 			return (CELL_JOIN);
    197 		case 14:	/* 1110, left right top */
    198 			return (CELL_BOTTOMJOIN);
    199 		case 13:	/* 1101, left right bottom */
    200 			return (CELL_TOPJOIN);
    201 		case 12:	/* 1100, left right */
    202 			return (CELL_TOPBOTTOM);
    203 		case 11:	/* 1011, left top bottom */
    204 			return (CELL_RIGHTJOIN);
    205 		case 10:	/* 1010, left top */
    206 			return (CELL_BOTTOMRIGHT);
    207 		case 9:		/* 1001, left bottom */
    208 			return (CELL_TOPRIGHT);
    209 		case 7:		/* 0111, right top bottom */
    210 			return (CELL_LEFTJOIN);
    211 		case 6:		/* 0110, right top */
    212 			return (CELL_BOTTOMLEFT);
    213 		case 5:		/* 0101, right bottom */
    214 			return (CELL_TOPLEFT);
    215 		case 3:		/* 0011, top bottom */
    216 			return (CELL_LEFTRIGHT);
    217 		}
    218 	}
    219 
    220 	return (CELL_OUTSIDE);
    221 }
    222 
    223 /* Check if the border of a particular pane. */
    224 static int
    225 screen_redraw_check_is(u_int px, u_int py, int type, int pane_status,
    226     struct window *w, struct window_pane *wantwp, struct window_pane *wp)
    227 {
    228 	int	border;
    229 
    230 	/* Is this off the active pane border? */
    231 	border = screen_redraw_cell_border1(wantwp, px, py);
    232 	if (border == 0 || border == -1)
    233 		return (0);
    234 	if (pane_status == CELL_STATUS_TOP && border == 4)
    235 		return (0);
    236 	if (pane_status == CELL_STATUS_BOTTOM && border == 3)
    237 		return (0);
    238 
    239 	/* If there are more than two panes, that's enough. */
    240 	if (window_count_panes(w) != 2)
    241 		return (1);
    242 
    243 	/* Else if the cell is not a border cell, forget it. */
    244 	if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE))
    245 		return (1);
    246 
    247 	/* With status lines mark the entire line. */
    248 	if (pane_status != CELL_STATUS_OFF)
    249 		return (1);
    250 
    251 	/* Check if the pane covers the whole width. */
    252 	if (wp->xoff == 0 && wp->sx == w->sx) {
    253 		/* This can either be the top pane or the bottom pane. */
    254 		if (wp->yoff == 0) { /* top pane */
    255 			if (wp == wantwp)
    256 				return (px <= wp->sx / 2);
    257 			return (px > wp->sx / 2);
    258 		}
    259 		return (0);
    260 	}
    261 
    262 	/* Check if the pane covers the whole height. */
    263 	if (wp->yoff == 0 && wp->sy == w->sy) {
    264 		/* This can either be the left pane or the right pane. */
    265 		if (wp->xoff == 0) { /* left pane */
    266 			if (wp == wantwp)
    267 				return (py <= wp->sy / 2);
    268 			return (py > wp->sy / 2);
    269 		}
    270 		return (0);
    271 	}
    272 
    273 	return (1);
    274 }
    275 
    276 /* Update pane status. */
    277 static int
    278 screen_redraw_make_pane_status(struct client *c, struct window *w,
    279     struct window_pane *wp)
    280 {
    281 	struct grid_cell	 gc;
    282 	const char		*fmt;
    283 	struct format_tree	*ft;
    284 	char			*out;
    285 	size_t			 outlen;
    286 	struct screen_write_ctx	 ctx;
    287 	struct screen		 old;
    288 
    289 	if (wp == w->active)
    290 		style_apply(&gc, w->options, "pane-active-border-style");
    291 	else
    292 		style_apply(&gc, w->options, "pane-border-style");
    293 
    294 	fmt = options_get_string(w->options, "pane-border-format");
    295 
    296 	ft = format_create(c, NULL, FORMAT_PANE|wp->id, 0);
    297 	format_defaults(ft, c, NULL, NULL, wp);
    298 
    299 	memcpy(&old, &wp->status_screen, sizeof old);
    300 	screen_init(&wp->status_screen, wp->sx, 1, 0);
    301 	wp->status_screen.mode = 0;
    302 
    303 	out = format_expand(ft, fmt);
    304 	outlen = screen_write_cstrlen("%s", out);
    305 	if (outlen > wp->sx - 4)
    306 		outlen = wp->sx - 4;
    307 	screen_resize(&wp->status_screen, outlen, 1, 0);
    308 
    309 	screen_write_start(&ctx, NULL, &wp->status_screen);
    310 	screen_write_cursormove(&ctx, 0, 0);
    311 	screen_write_clearline(&ctx, 8);
    312 	screen_write_cnputs(&ctx, outlen, &gc, "%s", out);
    313 	screen_write_stop(&ctx);
    314 
    315 	free(out);
    316 	format_free(ft);
    317 
    318 	wp->status_size = outlen;
    319 
    320 	if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
    321 		screen_free(&old);
    322 		return (0);
    323 	}
    324 	screen_free(&old);
    325 	return (1);
    326 }
    327 
    328 /* Draw pane status. */
    329 static void
    330 screen_redraw_draw_pane_status(struct client *c, int pane_status)
    331 {
    332 	struct window		*w = c->session->curw->window;
    333 	struct options		*oo = c->session->options;
    334 	struct tty		*tty = &c->tty;
    335 	struct window_pane	*wp;
    336 	int			 spos;
    337 	u_int			 yoff;
    338 
    339 	spos = options_get_number(oo, "status-position");
    340 	TAILQ_FOREACH(wp, &w->panes, entry) {
    341 		if (!window_pane_visible(wp))
    342 			continue;
    343 		if (pane_status == CELL_STATUS_TOP)
    344 			yoff = wp->yoff - 1;
    345 		else
    346 			yoff = wp->yoff + wp->sy;
    347 		if (spos == 0)
    348 			yoff += 1;
    349 
    350 		tty_draw_line(tty, NULL, &wp->status_screen, 0, wp->xoff + 2,
    351 		    yoff);
    352 	}
    353 	tty_cursor(tty, 0, 0);
    354 }
    355 
    356 /* Update status line and change flags if unchanged. */
    357 void
    358 screen_redraw_update(struct client *c)
    359 {
    360 	struct window		*w = c->session->curw->window;
    361 	struct window_pane	*wp;
    362 	struct options		*wo = w->options;
    363 	int			 redraw;
    364 
    365 	if (c->message_string != NULL)
    366 		redraw = status_message_redraw(c);
    367 	else if (c->prompt_string != NULL)
    368 		redraw = status_prompt_redraw(c);
    369 	else
    370 		redraw = status_redraw(c);
    371 	if (!redraw)
    372 		c->flags &= ~CLIENT_STATUS;
    373 
    374 	if (options_get_number(wo, "pane-border-status") != CELL_STATUS_OFF) {
    375 		redraw = 0;
    376 		TAILQ_FOREACH(wp, &w->panes, entry) {
    377 			if (screen_redraw_make_pane_status(c, w, wp))
    378 				redraw = 1;
    379 		}
    380 		if (redraw)
    381 			c->flags |= CLIENT_BORDERS;
    382 	}
    383 }
    384 
    385 /* Redraw entire screen. */
    386 void
    387 screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
    388     int draw_borders)
    389 {
    390 	struct options			*oo = c->session->options;
    391 	struct tty			*tty = &c->tty;
    392 	struct window			*w = c->session->curw->window;
    393 	struct options			*wo = w->options;
    394 	struct screen_redraw_ctx	 ctx;
    395 
    396 	if (c->flags & CLIENT_SUSPENDED)
    397 		return;
    398 
    399 	memset(&ctx, 0, sizeof ctx);
    400 	ctx.c = c;
    401 
    402 	if (c->flags & CLIENT_STATUSOFF)
    403 		ctx.lines = 0;
    404 	else
    405 		ctx.lines = status_line_size(c->session);
    406 	if (c->message_string != NULL || c->prompt_string != NULL)
    407 		ctx.lines = (ctx.lines == 0) ? 1 : ctx.lines;
    408 
    409 	if (ctx.lines != 0 && options_get_number(oo, "status-position") == 0)
    410 		ctx.top = 1;
    411 	ctx.pane_status = options_get_number(wo, "pane-border-status");
    412 
    413 	ctx.sx = tty->sx;
    414 	ctx.sy = tty->sy - ctx.lines;
    415 
    416 	if (ctx.lines == 0)
    417 		draw_status = 0;
    418 
    419 	if (draw_borders) {
    420 		if (ctx.pane_status != CELL_STATUS_OFF)
    421 			screen_redraw_draw_pane_status(c, ctx.pane_status);
    422 		screen_redraw_draw_borders(&ctx);
    423 	}
    424 	if (draw_panes)
    425 		screen_redraw_draw_panes(&ctx);
    426 	if (draw_status)
    427 		screen_redraw_draw_status(&ctx);
    428 	tty_reset(tty);
    429 }
    430 
    431 /* Draw a single pane. */
    432 void
    433 screen_redraw_pane(struct client *c, struct window_pane *wp)
    434 {
    435 	u_int	i, yoff;
    436 
    437 	if (!window_pane_visible(wp))
    438 		return;
    439 
    440 	yoff = wp->yoff;
    441 	if (status_at_line(c) == 0)
    442 		yoff += status_line_size(c->session);
    443 
    444 	log_debug("%s: redraw pane %%%u (at %u,%u)", c->name, wp->id,
    445 	    wp->xoff, yoff);
    446 
    447 	for (i = 0; i < wp->sy; i++)
    448 		tty_draw_pane(&c->tty, wp, i, wp->xoff, yoff);
    449 	tty_reset(&c->tty);
    450 }
    451 
    452 /* Draw a border cell. */
    453 static void
    454 screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int x, u_int y,
    455     int small, u_int msgx, u_int msgy, struct grid_cell *m_active_gc,
    456     struct grid_cell *active_gc, struct grid_cell *m_other_gc,
    457     struct grid_cell *other_gc)
    458 {
    459 	struct client           *c = ctx->c;
    460 	struct session          *s = c->session;
    461 	struct window           *w = s->curw->window;
    462 	struct tty              *tty = &c->tty;
    463 	struct window_pane      *wp;
    464 	struct window_pane      *active = w->active;
    465 	struct window_pane      *marked = marked_pane.wp;
    466 	u_int                    type;
    467 	int                      flag, pane_status = ctx->pane_status;
    468 
    469 	type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
    470 	if (type == CELL_INSIDE)
    471 		return;
    472 	if (type == CELL_OUTSIDE && small && x > msgx && y == msgy)
    473 		return;
    474 	flag = screen_redraw_check_is(x, y, type, pane_status, w, active, wp);
    475 
    476 	if (server_is_marked(s, s->curw, marked_pane.wp) &&
    477 	    screen_redraw_check_is(x, y, type, pane_status, w, marked, wp)) {
    478 		if (flag)
    479 			tty_attributes(tty, m_active_gc, NULL);
    480 		else
    481 			tty_attributes(tty, m_other_gc, NULL);
    482 	} else if (flag)
    483 		tty_attributes(tty, active_gc, NULL);
    484 	else
    485 		tty_attributes(tty, other_gc, NULL);
    486 	if (ctx->top)
    487 		tty_cursor(tty, x, ctx->lines + y);
    488 	else
    489 		tty_cursor(tty, x, y);
    490 	tty_putc(tty, CELL_BORDERS[type]);
    491 }
    492 
    493 /* Draw the borders. */
    494 static void
    495 screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
    496 {
    497 	struct client		*c = ctx->c;
    498 	struct session		*s = c->session;
    499 	struct window		*w = s->curw->window;
    500 	struct options		*oo = w->options;
    501 	struct tty		*tty = &c->tty;
    502 	struct grid_cell	 m_active_gc, active_gc, m_other_gc, other_gc;
    503 	struct grid_cell	 msg_gc;
    504 	u_int		 	 i, j, msgx = 0, msgy = 0;
    505 	int			 small, flags;
    506 	char			 msg[256];
    507 	const char		*tmp;
    508 	size_t			 msglen = 0;
    509 
    510 	small = (ctx->sy + ctx->top > w->sy) || (ctx->sx > w->sx);
    511 	if (small) {
    512 		flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT);
    513 		if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT))
    514 			tmp = "force-width, force-height";
    515 		else if (flags == WINDOW_FORCEWIDTH)
    516 			tmp = "force-width";
    517 		else if (flags == WINDOW_FORCEHEIGHT)
    518 			tmp = "force-height";
    519 		else if (c->flags & CLIENT_STATUSOFF)
    520 			tmp = "status line";
    521 		else
    522 			tmp = "a smaller client";
    523 		xsnprintf(msg, sizeof msg, "(size %ux%u from %s)",
    524 		    w->sx, w->sy, tmp);
    525 		msglen = strlen(msg);
    526 
    527 		if (ctx->sy - 1 + ctx->top > w->sy && ctx->sx >= msglen) {
    528 			msgx = ctx->sx - msglen;
    529 			msgy = ctx->sy - 1 + ctx->top;
    530 		} else if (ctx->sx - w->sx > msglen) {
    531 			msgx = ctx->sx - msglen;
    532 			msgy = ctx->sy - 1 + ctx->top;
    533 		} else
    534 			small = 0;
    535 	}
    536 
    537 	style_apply(&other_gc, oo, "pane-border-style");
    538 	style_apply(&active_gc, oo, "pane-active-border-style");
    539 	active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET;
    540 
    541 	memcpy(&m_other_gc, &other_gc, sizeof m_other_gc);
    542 	m_other_gc.attr ^= GRID_ATTR_REVERSE;
    543 	memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
    544 	m_active_gc.attr ^= GRID_ATTR_REVERSE;
    545 
    546 	for (j = 0; j < ctx->sy; j++) {
    547 		for (i = 0; i < ctx->sx; i++) {
    548 			screen_redraw_draw_borders_cell(ctx, i, j, small,
    549 			    msgx, msgy, &m_active_gc, &active_gc, &m_other_gc,
    550 			    &other_gc);
    551 		}
    552 	}
    553 
    554 	if (small) {
    555 		memcpy(&msg_gc, &grid_default_cell, sizeof msg_gc);
    556 		tty_attributes(tty, &msg_gc, NULL);
    557 		tty_cursor(tty, msgx, msgy);
    558 		tty_puts(tty, msg);
    559 	}
    560 }
    561 
    562 /* Draw the panes. */
    563 static void
    564 screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
    565 {
    566 	struct client		*c = ctx->c;
    567 	struct window		*w = c->session->curw->window;
    568 	struct tty		*tty = &c->tty;
    569 	struct window_pane	*wp;
    570 	u_int		 	 i, y;
    571 
    572 	if (ctx->top)
    573 		y = ctx->lines;
    574 	else
    575 		y = 0;
    576 	TAILQ_FOREACH(wp, &w->panes, entry) {
    577 		if (!window_pane_visible(wp))
    578 			continue;
    579 		for (i = 0; i < wp->sy; i++)
    580 			tty_draw_pane(tty, wp, i, wp->xoff, y + wp->yoff);
    581 		if (c->flags & CLIENT_IDENTIFY)
    582 			screen_redraw_draw_number(ctx, wp);
    583 	}
    584 }
    585 
    586 /* Draw the status line. */
    587 static void
    588 screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
    589 {
    590 	struct client	*c = ctx->c;
    591 	struct tty	*tty = &c->tty;
    592 	u_int		 i, y;
    593 
    594 	if (ctx->top)
    595 		y = 0;
    596 	else
    597 		y = ctx->sy;
    598 	for (i = 0; i < ctx->lines; i++)
    599 		tty_draw_line(tty, NULL, &c->status.status, i, 0, y);
    600 }
    601 
    602 /* Draw number on a pane. */
    603 static void
    604 screen_redraw_draw_number(struct screen_redraw_ctx *ctx, struct window_pane *wp)
    605 {
    606 	struct client		*c = ctx->c;
    607 	struct tty		*tty = &c->tty;
    608 	struct session		*s = c->session;
    609 	struct options		*oo = s->options;
    610 	struct window		*w = wp->window;
    611 	struct grid_cell	 gc;
    612 	u_int			 idx, px, py, i, j, xoff, yoff;
    613 	int			 colour, active_colour;
    614 	char			 buf[16], *ptr;
    615 	size_t			 len;
    616 
    617 	if (window_pane_index(wp, &idx) != 0)
    618 		fatalx("index not found");
    619 	len = xsnprintf(buf, sizeof buf, "%u", idx);
    620 
    621 	if (wp->sx < len)
    622 		return;
    623 	colour = options_get_number(oo, "display-panes-colour");
    624 	active_colour = options_get_number(oo, "display-panes-active-colour");
    625 
    626 	px = wp->sx / 2; py = wp->sy / 2;
    627 	xoff = wp->xoff; yoff = wp->yoff;
    628 
    629 	if (ctx->top)
    630 		yoff += ctx->lines;
    631 
    632 	if (wp->sx < len * 6 || wp->sy < 5) {
    633 		tty_cursor(tty, xoff + px - len / 2, yoff + py);
    634 		goto draw_text;
    635 	}
    636 
    637 	px -= len * 3;
    638 	py -= 2;
    639 
    640 	memcpy(&gc, &grid_default_cell, sizeof gc);
    641 	if (w->active == wp)
    642 		gc.bg = active_colour;
    643 	else
    644 		gc.bg = colour;
    645 	gc.flags |= GRID_FLAG_NOPALETTE;
    646 
    647 	tty_attributes(tty, &gc, wp);
    648 	for (ptr = buf; *ptr != '\0'; ptr++) {
    649 		if (*ptr < '0' || *ptr > '9')
    650 			continue;
    651 		idx = *ptr - '0';
    652 
    653 		for (j = 0; j < 5; j++) {
    654 			for (i = px; i < px + 5; i++) {
    655 				tty_cursor(tty, xoff + i, yoff + py + j);
    656 				if (window_clock_table[idx][j][i - px])
    657 					tty_putc(tty, ' ');
    658 			}
    659 		}
    660 		px += 6;
    661 	}
    662 
    663 	len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
    664 	if (wp->sx < len || wp->sy < 6)
    665 		return;
    666 	tty_cursor(tty, xoff + wp->sx - len, yoff);
    667 
    668 draw_text:
    669 	memcpy(&gc, &grid_default_cell, sizeof gc);
    670 	if (w->active == wp)
    671 		gc.fg = active_colour;
    672 	else
    673 		gc.fg = colour;
    674 	gc.flags |= GRID_FLAG_NOPALETTE;
    675 
    676 	tty_attributes(tty, &gc, wp);
    677 	tty_puts(tty, buf);
    678 
    679 	tty_cursor(tty, 0, 0);
    680 }
    681