xref: /netbsd-src/external/bsd/tmux/dist/screen-redraw.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
15494e770Schristos /* $OpenBSD$ */
2698d5317Sjmmv 
3698d5317Sjmmv /*
4ed4e6cd4Schristos  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5698d5317Sjmmv  *
6698d5317Sjmmv  * Permission to use, copy, modify, and distribute this software for any
7698d5317Sjmmv  * purpose with or without fee is hereby granted, provided that the above
8698d5317Sjmmv  * copyright notice and this permission notice appear in all copies.
9698d5317Sjmmv  *
10698d5317Sjmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11698d5317Sjmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12698d5317Sjmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13698d5317Sjmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14698d5317Sjmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15698d5317Sjmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16698d5317Sjmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17698d5317Sjmmv  */
18698d5317Sjmmv 
19698d5317Sjmmv #include <sys/types.h>
20698d5317Sjmmv 
218f3b9483Schristos #include <stdlib.h>
22698d5317Sjmmv #include <string.h>
23698d5317Sjmmv 
24698d5317Sjmmv #include "tmux.h"
25698d5317Sjmmv 
268f3b9483Schristos static void	screen_redraw_draw_borders(struct screen_redraw_ctx *);
278f3b9483Schristos static void	screen_redraw_draw_panes(struct screen_redraw_ctx *);
288f3b9483Schristos static void	screen_redraw_draw_status(struct screen_redraw_ctx *);
29ef36e747Schristos static void	screen_redraw_draw_pane(struct screen_redraw_ctx *,
30ef36e747Schristos 		    struct window_pane *);
319fb66d81Schristos static void	screen_redraw_set_context(struct client *,
329fb66d81Schristos 		    struct screen_redraw_ctx *);
33698d5317Sjmmv 
349fb66d81Schristos #define START_ISOLATE "\342\201\246"
359fb66d81Schristos #define END_ISOLATE   "\342\201\251"
369fb66d81Schristos 
376db26757Swiz /* Border in relation to a pane. */
389fb66d81Schristos enum screen_redraw_border_type {
399fb66d81Schristos 	SCREEN_REDRAW_OUTSIDE,
409fb66d81Schristos 	SCREEN_REDRAW_INSIDE,
416db26757Swiz 	SCREEN_REDRAW_BORDER_LEFT,
426db26757Swiz 	SCREEN_REDRAW_BORDER_RIGHT,
436db26757Swiz 	SCREEN_REDRAW_BORDER_TOP,
446db26757Swiz 	SCREEN_REDRAW_BORDER_BOTTOM
459fb66d81Schristos };
466db26757Swiz #define BORDER_MARKERS "  +,.-"
479fb66d81Schristos 
489fb66d81Schristos /* Get cell border character. */
499fb66d81Schristos static void
506db26757Swiz screen_redraw_border_set(struct window *w, struct window_pane *wp,
516db26757Swiz     enum pane_lines pane_lines, int cell_type, struct grid_cell *gc)
52698d5317Sjmmv {
539fb66d81Schristos 	u_int	idx;
549fb66d81Schristos 
556db26757Swiz 	if (cell_type == CELL_OUTSIDE && w->fill_character != NULL) {
566db26757Swiz 		utf8_copy(&gc->data, &w->fill_character[0]);
576db26757Swiz 		return;
586db26757Swiz 	}
596db26757Swiz 
609fb66d81Schristos 	switch (pane_lines) {
619fb66d81Schristos 	case PANE_LINES_NUMBER:
629fb66d81Schristos 		if (cell_type == CELL_OUTSIDE) {
639fb66d81Schristos 			gc->attr |= GRID_ATTR_CHARSET;
649fb66d81Schristos 			utf8_set(&gc->data, CELL_BORDERS[CELL_OUTSIDE]);
659fb66d81Schristos 			break;
669fb66d81Schristos 		}
679fb66d81Schristos 		gc->attr &= ~GRID_ATTR_CHARSET;
689fb66d81Schristos 		if (wp != NULL && window_pane_index(wp, &idx) == 0)
699fb66d81Schristos 			utf8_set(&gc->data, '0' + (idx % 10));
709fb66d81Schristos 		else
719fb66d81Schristos 			utf8_set(&gc->data, '*');
729fb66d81Schristos 		break;
739fb66d81Schristos 	case PANE_LINES_DOUBLE:
749fb66d81Schristos 		gc->attr &= ~GRID_ATTR_CHARSET;
756db26757Swiz 		utf8_copy(&gc->data, tty_acs_double_borders(cell_type));
769fb66d81Schristos 		break;
779fb66d81Schristos 	case PANE_LINES_HEAVY:
789fb66d81Schristos 		gc->attr &= ~GRID_ATTR_CHARSET;
796db26757Swiz 		utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
809fb66d81Schristos 		break;
819fb66d81Schristos 	case PANE_LINES_SIMPLE:
829fb66d81Schristos 		gc->attr &= ~GRID_ATTR_CHARSET;
836db26757Swiz 		utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
849fb66d81Schristos 		break;
859fb66d81Schristos 	default:
869fb66d81Schristos 		gc->attr |= GRID_ATTR_CHARSET;
879fb66d81Schristos 		utf8_set(&gc->data, CELL_BORDERS[cell_type]);
889fb66d81Schristos 		break;
899fb66d81Schristos 	}
909fb66d81Schristos }
919fb66d81Schristos 
929fb66d81Schristos /* Return if window has only two panes. */
939fb66d81Schristos static int
949fb66d81Schristos screen_redraw_two_panes(struct window *w, int direction)
959fb66d81Schristos {
969fb66d81Schristos 	struct window_pane	*wp;
979fb66d81Schristos 
989fb66d81Schristos 	wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
999fb66d81Schristos 	if (wp == NULL)
1009fb66d81Schristos 		return (0); /* one pane */
1019fb66d81Schristos 	if (TAILQ_NEXT(wp, entry) != NULL)
1029fb66d81Schristos 		return (0); /* more than two panes */
1039fb66d81Schristos 	if (direction == 0 && wp->xoff == 0)
104698d5317Sjmmv 		return (0);
1059fb66d81Schristos 	if (direction == 1 && wp->yoff == 0)
1069fb66d81Schristos 		return (0);
1079fb66d81Schristos 	return (1);
1089fb66d81Schristos }
1099fb66d81Schristos 
1109fb66d81Schristos /* Check if cell is on the border of a pane. */
1119fb66d81Schristos static enum screen_redraw_border_type
112*f8cf1a91Swiz screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
113*f8cf1a91Swiz     u_int px, u_int py)
1149fb66d81Schristos {
1156db26757Swiz 	struct options	*oo = wp->window->options;
1166db26757Swiz 	int		 split = 0;
1179fb66d81Schristos 	u_int		 ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
118*f8cf1a91Swiz 	int		 pane_status = ctx->pane_status;
1199fb66d81Schristos 
1209fb66d81Schristos 	/* Inside pane. */
1219fb66d81Schristos 	if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
1229fb66d81Schristos 		return (SCREEN_REDRAW_INSIDE);
123698d5317Sjmmv 
1246db26757Swiz 	/* Get pane indicator. */
1256db26757Swiz 	switch (options_get_number(oo, "pane-border-indicators")) {
1266db26757Swiz 	case PANE_BORDER_COLOUR:
1276db26757Swiz 	case PANE_BORDER_BOTH:
1286db26757Swiz 		split = 1;
1296db26757Swiz 		break;
1306db26757Swiz 	}
1316db26757Swiz 
132698d5317Sjmmv 	/* Left/right borders. */
1339fb66d81Schristos 	if (pane_status == PANE_STATUS_OFF) {
1346db26757Swiz 		if (screen_redraw_two_panes(wp->window, 0) && split) {
1359fb66d81Schristos 			if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2)
1366db26757Swiz 				return (SCREEN_REDRAW_BORDER_RIGHT);
1379fb66d81Schristos 			if (wp->xoff != 0 &&
1389fb66d81Schristos 			    px == wp->xoff - 1 &&
1399fb66d81Schristos 			    py > wp->sy / 2)
1406db26757Swiz 				return (SCREEN_REDRAW_BORDER_LEFT);
1419fb66d81Schristos 		} else {
1429fb66d81Schristos 			if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
143698d5317Sjmmv 				if (wp->xoff != 0 && px == wp->xoff - 1)
1446db26757Swiz 					return (SCREEN_REDRAW_BORDER_LEFT);
1459fb66d81Schristos 				if (px == ex)
1466db26757Swiz 					return (SCREEN_REDRAW_BORDER_RIGHT);
1479fb66d81Schristos 			}
1489fb66d81Schristos 		}
1499fb66d81Schristos 	} else {
1509fb66d81Schristos 		if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
1519fb66d81Schristos 			if (wp->xoff != 0 && px == wp->xoff - 1)
1526db26757Swiz 				return (SCREEN_REDRAW_BORDER_LEFT);
1539fb66d81Schristos 			if (px == ex)
1546db26757Swiz 				return (SCREEN_REDRAW_BORDER_RIGHT);
1559fb66d81Schristos 		}
156698d5317Sjmmv 	}
157698d5317Sjmmv 
158698d5317Sjmmv 	/* Top/bottom borders. */
1599fb66d81Schristos 	if (pane_status == PANE_STATUS_OFF) {
1606db26757Swiz 		if (screen_redraw_two_panes(wp->window, 1) && split) {
1619fb66d81Schristos 			if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
1626db26757Swiz 				return (SCREEN_REDRAW_BORDER_BOTTOM);
1639fb66d81Schristos 			if (wp->yoff != 0 &&
1649fb66d81Schristos 			    py == wp->yoff - 1 &&
1659fb66d81Schristos 			    px > wp->sx / 2)
1666db26757Swiz 				return (SCREEN_REDRAW_BORDER_TOP);
1679fb66d81Schristos 		} else {
1689fb66d81Schristos 			if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
169698d5317Sjmmv 				if (wp->yoff != 0 && py == wp->yoff - 1)
1706db26757Swiz 					return (SCREEN_REDRAW_BORDER_TOP);
1719fb66d81Schristos 				if (py == ey)
1726db26757Swiz 					return (SCREEN_REDRAW_BORDER_BOTTOM);
1739fb66d81Schristos 			}
1749fb66d81Schristos 		}
1759fb66d81Schristos 	} else if (pane_status == PANE_STATUS_TOP) {
1769fb66d81Schristos 		if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
1779fb66d81Schristos 			if (wp->yoff != 0 && py == wp->yoff - 1)
1786db26757Swiz 				return (SCREEN_REDRAW_BORDER_TOP);
1799fb66d81Schristos 		}
1809fb66d81Schristos 	} else {
1819fb66d81Schristos 		if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
1829fb66d81Schristos 			if (py == ey)
1836db26757Swiz 				return (SCREEN_REDRAW_BORDER_BOTTOM);
1849fb66d81Schristos 		}
185698d5317Sjmmv 	}
186698d5317Sjmmv 
187698d5317Sjmmv 	/* Outside pane. */
1889fb66d81Schristos 	return (SCREEN_REDRAW_OUTSIDE);
189698d5317Sjmmv }
190698d5317Sjmmv 
1919fb66d81Schristos /* Check if a cell is on a border. */
1924e179ddaSchristos static int
193*f8cf1a91Swiz screen_redraw_cell_border(struct screen_redraw_ctx *ctx, u_int px, u_int py)
194698d5317Sjmmv {
195*f8cf1a91Swiz 	struct client		*c = ctx->c;
196698d5317Sjmmv 	struct window		*w = c->session->curw->window;
197698d5317Sjmmv 	struct window_pane	*wp;
1989fb66d81Schristos 
1999fb66d81Schristos 	/* Outside the window? */
2009fb66d81Schristos 	if (px > w->sx || py > w->sy)
2019fb66d81Schristos 		return (0);
2029fb66d81Schristos 
2039fb66d81Schristos 	/* On the window border? */
2049fb66d81Schristos 	if (px == w->sx || py == w->sy)
2059fb66d81Schristos 		return (1);
206698d5317Sjmmv 
207698d5317Sjmmv 	/* Check all the panes. */
208698d5317Sjmmv 	TAILQ_FOREACH(wp, &w->panes, entry) {
209698d5317Sjmmv 		if (!window_pane_visible(wp))
210698d5317Sjmmv 			continue;
211*f8cf1a91Swiz 		switch (screen_redraw_pane_border(ctx, wp, px, py)) {
2129fb66d81Schristos 		case SCREEN_REDRAW_INSIDE:
2139fb66d81Schristos 			return (0);
2149fb66d81Schristos 		case SCREEN_REDRAW_OUTSIDE:
2159fb66d81Schristos 			break;
2166db26757Swiz 		default:
2176db26757Swiz 			return (1);
2189fb66d81Schristos 		}
219698d5317Sjmmv 	}
220698d5317Sjmmv 
221698d5317Sjmmv 	return (0);
222698d5317Sjmmv }
223698d5317Sjmmv 
2249fb66d81Schristos /* Work out type of border cell from surrounding cells. */
2254e179ddaSchristos static int
226*f8cf1a91Swiz screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py)
227698d5317Sjmmv {
228*f8cf1a91Swiz 	struct client	*c = ctx->c;
229*f8cf1a91Swiz 	int		 pane_status = ctx->pane_status;
230698d5317Sjmmv 	struct window	*w = c->session->curw->window;
2319fb66d81Schristos 	u_int		 sx = w->sx, sy = w->sy;
2329fb66d81Schristos 	int		 borders = 0;
2334e179ddaSchristos 
2349fb66d81Schristos 	/* Is this outside the window? */
2359fb66d81Schristos 	if (px > sx || py > sy)
236698d5317Sjmmv 		return (CELL_OUTSIDE);
237698d5317Sjmmv 
238698d5317Sjmmv 	/*
2399fb66d81Schristos 	 * Construct a bitmask of whether the cells to the left (bit 4), right,
2409fb66d81Schristos 	 * top, and bottom (bit 1) of this cell are borders.
241698d5317Sjmmv 	 */
242*f8cf1a91Swiz 	if (px == 0 || screen_redraw_cell_border(ctx, px - 1, py))
243698d5317Sjmmv 		borders |= 8;
244*f8cf1a91Swiz 	if (px <= sx && screen_redraw_cell_border(ctx, px + 1, py))
245698d5317Sjmmv 		borders |= 4;
2466483eba0Schristos 	if (pane_status == PANE_STATUS_TOP) {
2479fb66d81Schristos 		if (py != 0 &&
248*f8cf1a91Swiz 		    screen_redraw_cell_border(ctx, px, py - 1))
2494e179ddaSchristos 			borders |= 2;
250*f8cf1a91Swiz 		if (screen_redraw_cell_border(ctx, px, py + 1))
251698d5317Sjmmv 			borders |= 1;
2529fb66d81Schristos 	} else if (pane_status == PANE_STATUS_BOTTOM) {
2539fb66d81Schristos 		if (py == 0 ||
254*f8cf1a91Swiz 		    screen_redraw_cell_border(ctx, px, py - 1))
2559fb66d81Schristos 			borders |= 2;
2569fb66d81Schristos 		if (py != sy - 1 &&
257*f8cf1a91Swiz 		    screen_redraw_cell_border(ctx, px, py + 1))
2589fb66d81Schristos 			borders |= 1;
2599fb66d81Schristos 	} else {
2609fb66d81Schristos 		if (py == 0 ||
261*f8cf1a91Swiz 		    screen_redraw_cell_border(ctx, px, py - 1))
2629fb66d81Schristos 			borders |= 2;
263*f8cf1a91Swiz 		if (screen_redraw_cell_border(ctx, px, py + 1))
2649fb66d81Schristos 			borders |= 1;
2659fb66d81Schristos 	}
266698d5317Sjmmv 
267698d5317Sjmmv 	/*
2689fb66d81Schristos 	 * Figure out what kind of border this cell is. Only one bit set
2699fb66d81Schristos 	 * doesn't make sense (can't have a border cell with no others
2709fb66d81Schristos 	 * connected).
271698d5317Sjmmv 	 */
272698d5317Sjmmv 	switch (borders) {
273698d5317Sjmmv 	case 15:	/* 1111, left right top bottom */
274698d5317Sjmmv 		return (CELL_JOIN);
275698d5317Sjmmv 	case 14:	/* 1110, left right top */
276698d5317Sjmmv 		return (CELL_BOTTOMJOIN);
277698d5317Sjmmv 	case 13:	/* 1101, left right bottom */
278698d5317Sjmmv 		return (CELL_TOPJOIN);
279698d5317Sjmmv 	case 12:	/* 1100, left right */
2809fb66d81Schristos 		return (CELL_LEFTRIGHT);
281698d5317Sjmmv 	case 11:	/* 1011, left top bottom */
282698d5317Sjmmv 		return (CELL_RIGHTJOIN);
283698d5317Sjmmv 	case 10:	/* 1010, left top */
284698d5317Sjmmv 		return (CELL_BOTTOMRIGHT);
285698d5317Sjmmv 	case 9:		/* 1001, left bottom */
286698d5317Sjmmv 		return (CELL_TOPRIGHT);
287698d5317Sjmmv 	case 7:		/* 0111, right top bottom */
288698d5317Sjmmv 		return (CELL_LEFTJOIN);
289698d5317Sjmmv 	case 6:		/* 0110, right top */
290698d5317Sjmmv 		return (CELL_BOTTOMLEFT);
291698d5317Sjmmv 	case 5:		/* 0101, right bottom */
292698d5317Sjmmv 		return (CELL_TOPLEFT);
293698d5317Sjmmv 	case 3:		/* 0011, top bottom */
2949fb66d81Schristos 		return (CELL_TOPBOTTOM);
295698d5317Sjmmv 	}
2969fb66d81Schristos 	return (CELL_OUTSIDE);
297698d5317Sjmmv }
298698d5317Sjmmv 
2999fb66d81Schristos /* Check if cell inside a pane. */
3009fb66d81Schristos static int
301*f8cf1a91Swiz screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
3029fb66d81Schristos     struct window_pane **wpp)
3039fb66d81Schristos {
304*f8cf1a91Swiz 	struct client		*c = ctx->c;
3059fb66d81Schristos 	struct window		*w = c->session->curw->window;
3069fb66d81Schristos 	struct window_pane	*wp, *active;
307*f8cf1a91Swiz 	int			 pane_status = ctx->pane_status;
3089fb66d81Schristos 	int			 border;
3099fb66d81Schristos 	u_int			 right, line;
3109fb66d81Schristos 
3119fb66d81Schristos 	*wpp = NULL;
3129fb66d81Schristos 
3139fb66d81Schristos 	if (px > w->sx || py > w->sy)
3149fb66d81Schristos 		return (CELL_OUTSIDE);
3159fb66d81Schristos 	if (px == w->sx || py == w->sy) /* window border */
316*f8cf1a91Swiz 		return (screen_redraw_type_of_cell(ctx, px, py));
3179fb66d81Schristos 
3189fb66d81Schristos 	if (pane_status != PANE_STATUS_OFF) {
3199fb66d81Schristos 		active = wp = server_client_get_pane(c);
3209fb66d81Schristos 		do {
3219fb66d81Schristos 			if (!window_pane_visible(wp))
3229fb66d81Schristos 				goto next1;
3239fb66d81Schristos 
3249fb66d81Schristos 			if (pane_status == PANE_STATUS_TOP)
3259fb66d81Schristos 				line = wp->yoff - 1;
3269fb66d81Schristos 			else
3279fb66d81Schristos 				line = wp->yoff + wp->sy;
3289fb66d81Schristos 			right = wp->xoff + 2 + wp->status_size - 1;
3299fb66d81Schristos 
3309fb66d81Schristos 			if (py == line && px >= wp->xoff + 2 && px <= right)
3319fb66d81Schristos 				return (CELL_INSIDE);
3329fb66d81Schristos 
3339fb66d81Schristos 		next1:
3349fb66d81Schristos 			wp = TAILQ_NEXT(wp, entry);
3359fb66d81Schristos 			if (wp == NULL)
3369fb66d81Schristos 				wp = TAILQ_FIRST(&w->panes);
3379fb66d81Schristos 		} while (wp != active);
3389fb66d81Schristos 	}
3399fb66d81Schristos 
3409fb66d81Schristos 	active = wp = server_client_get_pane(c);
3419fb66d81Schristos 	do {
3429fb66d81Schristos 		if (!window_pane_visible(wp))
3439fb66d81Schristos 			goto next2;
3449fb66d81Schristos 		*wpp = wp;
3459fb66d81Schristos 
3469fb66d81Schristos 		/*
3479fb66d81Schristos 		 * If definitely inside, return. If not on border, skip.
3489fb66d81Schristos 		 * Otherwise work out the cell.
3499fb66d81Schristos 		 */
350*f8cf1a91Swiz 		border = screen_redraw_pane_border(ctx, wp, px, py);
3519fb66d81Schristos 		if (border == SCREEN_REDRAW_INSIDE)
3529fb66d81Schristos 			return (CELL_INSIDE);
3539fb66d81Schristos 		if (border == SCREEN_REDRAW_OUTSIDE)
3549fb66d81Schristos 			goto next2;
355*f8cf1a91Swiz 		return (screen_redraw_type_of_cell(ctx, px, py));
3569fb66d81Schristos 
3579fb66d81Schristos 	next2:
3589fb66d81Schristos 		wp = TAILQ_NEXT(wp, entry);
3599fb66d81Schristos 		if (wp == NULL)
3609fb66d81Schristos 			wp = TAILQ_FIRST(&w->panes);
3619fb66d81Schristos 	} while (wp != active);
3629fb66d81Schristos 
363698d5317Sjmmv 	return (CELL_OUTSIDE);
364698d5317Sjmmv }
365698d5317Sjmmv 
3665494e770Schristos /* Check if the border of a particular pane. */
3674e179ddaSchristos static int
368*f8cf1a91Swiz screen_redraw_check_is(struct screen_redraw_ctx *ctx, u_int px, u_int py,
3699fb66d81Schristos     struct window_pane *wp)
370928fc495Schristos {
3719fb66d81Schristos 	enum screen_redraw_border_type	border;
3724e179ddaSchristos 
373*f8cf1a91Swiz 	border = screen_redraw_pane_border(ctx, wp, px, py);
3746db26757Swiz 	if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE)
375928fc495Schristos 		return (1);
376928fc495Schristos 	return (0);
377928fc495Schristos }
378928fc495Schristos 
3794e179ddaSchristos /* Update pane status. */
3804e179ddaSchristos static int
3819fb66d81Schristos screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
3826db26757Swiz     struct screen_redraw_ctx *rctx, enum pane_lines pane_lines)
3834e179ddaSchristos {
3849fb66d81Schristos 	struct window		*w = wp->window;
3854e179ddaSchristos 	struct grid_cell	 gc;
3864e179ddaSchristos 	const char		*fmt;
3874e179ddaSchristos 	struct format_tree	*ft;
388ef36e747Schristos 	char			*expanded;
3899fb66d81Schristos 	int			 pane_status = rctx->pane_status;
3909fb66d81Schristos 	u_int			 width, i, cell_type, px, py;
3914e179ddaSchristos 	struct screen_write_ctx	 ctx;
3924e179ddaSchristos 	struct screen		 old;
3934e179ddaSchristos 
3946483eba0Schristos 	ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
3959fb66d81Schristos 	format_defaults(ft, c, c->session, c->session->curw, wp);
3969fb66d81Schristos 
3979fb66d81Schristos 	if (wp == server_client_get_pane(c))
3989fb66d81Schristos 		style_apply(&gc, w->options, "pane-active-border-style", ft);
3999fb66d81Schristos 	else
4009fb66d81Schristos 		style_apply(&gc, w->options, "pane-border-style", ft);
4016db26757Swiz 	fmt = options_get_string(wp->options, "pane-border-format");
4024e179ddaSchristos 
403ef36e747Schristos 	expanded = format_expand_time(ft, fmt);
404ef36e747Schristos 	if (wp->sx < 4)
405ef36e747Schristos 		wp->status_size = width = 0;
406ef36e747Schristos 	else
407ef36e747Schristos 		wp->status_size = width = wp->sx - 4;
408ef36e747Schristos 
4094e179ddaSchristos 	memcpy(&old, &wp->status_screen, sizeof old);
410ef36e747Schristos 	screen_init(&wp->status_screen, width, 1, 0);
4114e179ddaSchristos 	wp->status_screen.mode = 0;
4124e179ddaSchristos 
4139fb66d81Schristos 	screen_write_start(&ctx, &wp->status_screen);
414ef36e747Schristos 
4159fb66d81Schristos 	for (i = 0; i < width; i++) {
4169fb66d81Schristos 		px = wp->xoff + 2 + i;
417*f8cf1a91Swiz 		if (pane_status == PANE_STATUS_TOP)
4189fb66d81Schristos 			py = wp->yoff - 1;
4199fb66d81Schristos 		else
4209fb66d81Schristos 			py = wp->yoff + wp->sy;
421*f8cf1a91Swiz 		cell_type = screen_redraw_type_of_cell(rctx, px, py);
4226db26757Swiz 		screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc);
4239fb66d81Schristos 		screen_write_cell(&ctx, &gc);
4249fb66d81Schristos 	}
425ef36e747Schristos 	gc.attr &= ~GRID_ATTR_CHARSET;
426ef36e747Schristos 
427ef36e747Schristos 	screen_write_cursormove(&ctx, 0, 0, 0);
4286db26757Swiz 	format_draw(&ctx, &gc, width, expanded, NULL, 0);
4294e179ddaSchristos 	screen_write_stop(&ctx);
4304e179ddaSchristos 
431ef36e747Schristos 	free(expanded);
4324e179ddaSchristos 	format_free(ft);
4334e179ddaSchristos 
4344e179ddaSchristos 	if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
4354e179ddaSchristos 		screen_free(&old);
4364e179ddaSchristos 		return (0);
4374e179ddaSchristos 	}
4384e179ddaSchristos 	screen_free(&old);
4394e179ddaSchristos 	return (1);
4404e179ddaSchristos }
4414e179ddaSchristos 
4424e179ddaSchristos /* Draw pane status. */
4434e179ddaSchristos static void
444ef36e747Schristos screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
4454e179ddaSchristos {
446ef36e747Schristos 	struct client		*c = ctx->c;
4474e179ddaSchristos 	struct window		*w = c->session->curw->window;
4484e179ddaSchristos 	struct tty		*tty = &c->tty;
4494e179ddaSchristos 	struct window_pane	*wp;
450ef36e747Schristos 	struct screen		*s;
451ef36e747Schristos 	u_int			 i, x, width, xoff, yoff, size;
4524e179ddaSchristos 
453ef36e747Schristos 	log_debug("%s: %s @%u", __func__, c->name, w->id);
454ef36e747Schristos 
4554e179ddaSchristos 	TAILQ_FOREACH(wp, &w->panes, entry) {
4564e179ddaSchristos 		if (!window_pane_visible(wp))
4574e179ddaSchristos 			continue;
458ef36e747Schristos 		s = &wp->status_screen;
459ef36e747Schristos 
460ef36e747Schristos 		size = wp->status_size;
4616483eba0Schristos 		if (ctx->pane_status == PANE_STATUS_TOP)
4624e179ddaSchristos 			yoff = wp->yoff - 1;
4634e179ddaSchristos 		else
4644e179ddaSchristos 			yoff = wp->yoff + wp->sy;
465ef36e747Schristos 		xoff = wp->xoff + 2;
4664e179ddaSchristos 
467ef36e747Schristos 		if (xoff + size <= ctx->ox ||
468ef36e747Schristos 		    xoff >= ctx->ox + ctx->sx ||
469ef36e747Schristos 		    yoff < ctx->oy ||
470ef36e747Schristos 		    yoff >= ctx->oy + ctx->sy)
471ef36e747Schristos 			continue;
472ef36e747Schristos 
473ef36e747Schristos 		if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) {
474ef36e747Schristos 			/* All visible. */
475ef36e747Schristos 			i = 0;
476ef36e747Schristos 			x = xoff - ctx->ox;
477ef36e747Schristos 			width = size;
478ef36e747Schristos 		} else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) {
479ef36e747Schristos 			/* Both left and right not visible. */
480ef36e747Schristos 			i = ctx->ox;
481ef36e747Schristos 			x = 0;
482ef36e747Schristos 			width = ctx->sx;
483ef36e747Schristos 		} else if (xoff < ctx->ox) {
484ef36e747Schristos 			/* Left not visible. */
485ef36e747Schristos 			i = ctx->ox - xoff;
486ef36e747Schristos 			x = 0;
487ef36e747Schristos 			width = size - i;
488ef36e747Schristos 		} else {
489ef36e747Schristos 			/* Right not visible. */
490ef36e747Schristos 			i = 0;
491ef36e747Schristos 			x = xoff - ctx->ox;
492ef36e747Schristos 			width = size - x;
493ef36e747Schristos 		}
494ef36e747Schristos 
4956483eba0Schristos 		if (ctx->statustop)
4966483eba0Schristos 			yoff += ctx->statuslines;
4979fb66d81Schristos 		tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy,
4989fb66d81Schristos 		    &grid_default_cell, NULL);
4994e179ddaSchristos 	}
5004e179ddaSchristos 	tty_cursor(tty, 0, 0);
5014e179ddaSchristos }
5024e179ddaSchristos 
5034e179ddaSchristos /* Update status line and change flags if unchanged. */
504*f8cf1a91Swiz static uint64_t
505*f8cf1a91Swiz screen_redraw_update(struct client *c, uint64_t flags)
5064e179ddaSchristos {
5074e179ddaSchristos 	struct window			*w = c->session->curw->window;
5084e179ddaSchristos 	struct window_pane		*wp;
5094e179ddaSchristos 	struct options			*wo = w->options;
5106db26757Swiz 	int				 redraw;
5116db26757Swiz 	enum pane_lines			 lines;
5129fb66d81Schristos 	struct screen_redraw_ctx	 ctx;
5134e179ddaSchristos 
5144e179ddaSchristos 	if (c->message_string != NULL)
5154e179ddaSchristos 		redraw = status_message_redraw(c);
5164e179ddaSchristos 	else if (c->prompt_string != NULL)
5174e179ddaSchristos 		redraw = status_prompt_redraw(c);
5184e179ddaSchristos 	else
5194e179ddaSchristos 		redraw = status_redraw(c);
520ef36e747Schristos 	if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS))
521ef36e747Schristos 		flags &= ~CLIENT_REDRAWSTATUS;
5224e179ddaSchristos 
5236483eba0Schristos 	if (c->overlay_draw != NULL)
5246483eba0Schristos 		flags |= CLIENT_REDRAWOVERLAY;
5256483eba0Schristos 
5266483eba0Schristos 	if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) {
5279fb66d81Schristos 		screen_redraw_set_context(c, &ctx);
5289fb66d81Schristos 		lines = options_get_number(wo, "pane-border-lines");
5294e179ddaSchristos 		redraw = 0;
5304e179ddaSchristos 		TAILQ_FOREACH(wp, &w->panes, entry) {
5319fb66d81Schristos 			if (screen_redraw_make_pane_status(c, wp, &ctx, lines))
5324e179ddaSchristos 				redraw = 1;
5334e179ddaSchristos 		}
5344e179ddaSchristos 		if (redraw)
535ef36e747Schristos 			flags |= CLIENT_REDRAWBORDERS;
5364e179ddaSchristos 	}
537ef36e747Schristos 	return (flags);
538ef36e747Schristos }
539ef36e747Schristos 
540ef36e747Schristos /* Set up redraw context. */
541ef36e747Schristos static void
542ef36e747Schristos screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
543ef36e747Schristos {
544ef36e747Schristos 	struct session	*s = c->session;
545ef36e747Schristos 	struct options	*oo = s->options;
546ef36e747Schristos 	struct window	*w = s->curw->window;
547ef36e747Schristos 	struct options	*wo = w->options;
5486483eba0Schristos 	u_int		 lines;
549ef36e747Schristos 
550ef36e747Schristos 	memset(ctx, 0, sizeof *ctx);
551ef36e747Schristos 	ctx->c = c;
552ef36e747Schristos 
5536483eba0Schristos 	lines = status_line_size(c);
554ef36e747Schristos 	if (c->message_string != NULL || c->prompt_string != NULL)
5556483eba0Schristos 		lines = (lines == 0) ? 1 : lines;
5566483eba0Schristos 	if (lines != 0 && options_get_number(oo, "status-position") == 0)
5576483eba0Schristos 		ctx->statustop = 1;
5586483eba0Schristos 	ctx->statuslines = lines;
5596483eba0Schristos 
560ef36e747Schristos 	ctx->pane_status = options_get_number(wo, "pane-border-status");
5619fb66d81Schristos 	ctx->pane_lines = options_get_number(wo, "pane-border-lines");
562ef36e747Schristos 
563ef36e747Schristos 	tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
564ef36e747Schristos 
565ef36e747Schristos 	log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
5666483eba0Schristos 	    w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines,
5676483eba0Schristos 	    ctx->statustop);
568928fc495Schristos }
569928fc495Schristos 
570698d5317Sjmmv /* Redraw entire screen. */
571698d5317Sjmmv void
572ef36e747Schristos screen_redraw_screen(struct client *c)
573698d5317Sjmmv {
5748f3b9483Schristos 	struct screen_redraw_ctx	ctx;
575*f8cf1a91Swiz 	uint64_t			flags;
576698d5317Sjmmv 
577d530c4d0Sjmmv 	if (c->flags & CLIENT_SUSPENDED)
578d530c4d0Sjmmv 		return;
579d530c4d0Sjmmv 
580ef36e747Schristos 	flags = screen_redraw_update(c, c->flags);
5819fb66d81Schristos 	if ((flags & CLIENT_ALLREDRAWFLAGS) == 0)
5829fb66d81Schristos 		return;
5839fb66d81Schristos 
584ef36e747Schristos 	screen_redraw_set_context(c, &ctx);
5859fb66d81Schristos 	tty_sync_start(&c->tty);
5869fb66d81Schristos 	tty_update_mode(&c->tty, c->tty.mode, NULL);
5878f3b9483Schristos 
588ef36e747Schristos 	if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
5899fb66d81Schristos 		log_debug("%s: redrawing borders", c->name);
5906483eba0Schristos 		if (ctx.pane_status != PANE_STATUS_OFF)
591ef36e747Schristos 			screen_redraw_draw_pane_status(&ctx);
5928f3b9483Schristos 		screen_redraw_draw_borders(&ctx);
5934e179ddaSchristos 	}
5949fb66d81Schristos 	if (flags & CLIENT_REDRAWWINDOW) {
5959fb66d81Schristos 		log_debug("%s: redrawing panes", c->name);
5968f3b9483Schristos 		screen_redraw_draw_panes(&ctx);
5979fb66d81Schristos 	}
5986483eba0Schristos 	if (ctx.statuslines != 0 &&
5999fb66d81Schristos 	    (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) {
6009fb66d81Schristos 		log_debug("%s: redrawing status", c->name);
6018f3b9483Schristos 		screen_redraw_draw_status(&ctx);
6029fb66d81Schristos 	}
6039fb66d81Schristos 	if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
6049fb66d81Schristos 		log_debug("%s: redrawing overlay", c->name);
6056db26757Swiz 		c->overlay_draw(c, c->overlay_data, &ctx);
6069fb66d81Schristos 	}
6079fb66d81Schristos 
608ef36e747Schristos 	tty_reset(&c->tty);
609698d5317Sjmmv }
610698d5317Sjmmv 
611ef36e747Schristos /* Redraw a single pane. */
612698d5317Sjmmv void
613698d5317Sjmmv screen_redraw_pane(struct client *c, struct window_pane *wp)
614698d5317Sjmmv {
615ef36e747Schristos 	struct screen_redraw_ctx	 ctx;
616928fc495Schristos 
6176db26757Swiz 	if (!window_pane_visible(wp))
618928fc495Schristos 		return;
619928fc495Schristos 
620ef36e747Schristos 	screen_redraw_set_context(c, &ctx);
6219fb66d81Schristos 	tty_sync_start(&c->tty);
6229fb66d81Schristos 	tty_update_mode(&c->tty, c->tty.mode, NULL);
623698d5317Sjmmv 
624ef36e747Schristos 	screen_redraw_draw_pane(&ctx, wp);
6259fb66d81Schristos 
626698d5317Sjmmv 	tty_reset(&c->tty);
627698d5317Sjmmv }
628698d5317Sjmmv 
6299fb66d81Schristos /* Get border cell style. */
6309fb66d81Schristos static const struct grid_cell *
6319fb66d81Schristos screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
6329fb66d81Schristos     u_int y, struct window_pane *wp)
6338f3b9483Schristos {
6348f3b9483Schristos 	struct client		*c = ctx->c;
6358f3b9483Schristos 	struct session		*s = c->session;
6368f3b9483Schristos 	struct window		*w = s->curw->window;
6379fb66d81Schristos 	struct window_pane	*active = server_client_get_pane(c);
6389fb66d81Schristos 	struct options		*oo = w->options;
6399fb66d81Schristos 	struct format_tree	*ft;
6409fb66d81Schristos 
6419fb66d81Schristos 	if (wp->border_gc_set)
6429fb66d81Schristos 		return (&wp->border_gc);
6439fb66d81Schristos 	wp->border_gc_set = 1;
6449fb66d81Schristos 
6459fb66d81Schristos 	ft = format_create_defaults(NULL, c, s, s->curw, wp);
646*f8cf1a91Swiz 	if (screen_redraw_check_is(ctx, x, y, active))
6479fb66d81Schristos 		style_apply(&wp->border_gc, oo, "pane-active-border-style", ft);
6489fb66d81Schristos 	else
6499fb66d81Schristos 		style_apply(&wp->border_gc, oo, "pane-border-style", ft);
6509fb66d81Schristos 	format_free(ft);
6519fb66d81Schristos 
6529fb66d81Schristos 	return (&wp->border_gc);
6539fb66d81Schristos }
6549fb66d81Schristos 
6559fb66d81Schristos /* Draw a border cell. */
6569fb66d81Schristos static void
6579fb66d81Schristos screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
6589fb66d81Schristos {
6599fb66d81Schristos 	struct client		*c = ctx->c;
6609fb66d81Schristos 	struct session		*s = c->session;
6616db26757Swiz 	struct window		*w = s->curw->window;
6626db26757Swiz 	struct options		*oo = w->options;
6638f3b9483Schristos 	struct tty		*tty = &c->tty;
6646db26757Swiz 	struct format_tree	*ft;
6656db26757Swiz 	struct window_pane	*wp, *active = server_client_get_pane(c);
6669fb66d81Schristos 	struct grid_cell	 gc;
6679fb66d81Schristos 	const struct grid_cell	*tmp;
6686db26757Swiz 	struct overlay_ranges	 r;
6696db26757Swiz 	u_int			 cell_type, x = ctx->ox + i, y = ctx->oy + j;
6706db26757Swiz 	int			 arrows = 0, border;
671*f8cf1a91Swiz 	int			 isolates;
6728f3b9483Schristos 
6736db26757Swiz 	if (c->overlay_check != NULL) {
6746db26757Swiz 		c->overlay_check(c, c->overlay_data, x, y, 1, &r);
6756db26757Swiz 		if (r.nx[0] + r.nx[1] == 0)
6768f3b9483Schristos 			return;
6776db26757Swiz 	}
6789fb66d81Schristos 
679*f8cf1a91Swiz 	cell_type = screen_redraw_check_cell(ctx, x, y, &wp);
6809fb66d81Schristos 	if (cell_type == CELL_INSIDE)
6819fb66d81Schristos 		return;
6829fb66d81Schristos 
6836db26757Swiz 	if (wp == NULL) {
6846db26757Swiz 		if (!ctx->no_pane_gc_set) {
6856db26757Swiz 			ft = format_create_defaults(NULL, c, s, s->curw, NULL);
6866db26757Swiz 			memcpy(&ctx->no_pane_gc, &grid_default_cell, sizeof gc);
6876db26757Swiz 			style_add(&ctx->no_pane_gc, oo, "pane-border-style",
6886db26757Swiz 			    ft);
6896db26757Swiz 			format_free(ft);
6906db26757Swiz 			ctx->no_pane_gc_set = 1;
6916db26757Swiz 		}
6926db26757Swiz 		memcpy(&gc, &ctx->no_pane_gc, sizeof gc);
6936db26757Swiz 	} else {
6949fb66d81Schristos 		tmp = screen_redraw_draw_borders_style(ctx, x, y, wp);
6959fb66d81Schristos 		if (tmp == NULL)
6969fb66d81Schristos 			return;
6979fb66d81Schristos 		memcpy(&gc, tmp, sizeof gc);
6988f3b9483Schristos 
6998f3b9483Schristos 		if (server_is_marked(s, s->curw, marked_pane.wp) &&
700*f8cf1a91Swiz 		    screen_redraw_check_is(ctx, x, y, marked_pane.wp))
7019fb66d81Schristos 			gc.attr ^= GRID_ATTR_REVERSE;
7029fb66d81Schristos 	}
7036db26757Swiz 	screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc);
7049fb66d81Schristos 
7059fb66d81Schristos 	if (cell_type == CELL_TOPBOTTOM &&
7069fb66d81Schristos 	    (c->flags & CLIENT_UTF8) &&
7079fb66d81Schristos 	    tty_term_has(tty->term, TTYC_BIDI))
7089fb66d81Schristos 		isolates = 1;
7098f3b9483Schristos 	else
7109fb66d81Schristos 		isolates = 0;
7119fb66d81Schristos 
7126483eba0Schristos 	if (ctx->statustop)
7136483eba0Schristos 		tty_cursor(tty, i, ctx->statuslines + j);
7148f3b9483Schristos 	else
715ef36e747Schristos 		tty_cursor(tty, i, j);
7169fb66d81Schristos 	if (isolates)
7179fb66d81Schristos 		tty_puts(tty, END_ISOLATE);
7186db26757Swiz 
7196db26757Swiz 	switch (options_get_number(oo, "pane-border-indicators")) {
7206db26757Swiz 	case PANE_BORDER_ARROWS:
7216db26757Swiz 	case PANE_BORDER_BOTH:
7226db26757Swiz 		arrows = 1;
7236db26757Swiz 		break;
7246db26757Swiz 	}
7256db26757Swiz 
7266db26757Swiz 	if (wp != NULL && arrows) {
727*f8cf1a91Swiz 		border = screen_redraw_pane_border(ctx, active, x, y);
7286db26757Swiz 		if (((i == wp->xoff + 1 &&
7296db26757Swiz 		    (cell_type == CELL_LEFTRIGHT ||
7306db26757Swiz 		    (cell_type == CELL_TOPJOIN &&
7316db26757Swiz 		    border == SCREEN_REDRAW_BORDER_BOTTOM) ||
7326db26757Swiz 		    (cell_type == CELL_BOTTOMJOIN &&
7336db26757Swiz 		    border == SCREEN_REDRAW_BORDER_TOP))) ||
7346db26757Swiz 		    (j == wp->yoff + 1 &&
7356db26757Swiz 		    (cell_type == CELL_TOPBOTTOM ||
7366db26757Swiz 		    (cell_type == CELL_LEFTJOIN &&
7376db26757Swiz 		    border == SCREEN_REDRAW_BORDER_RIGHT) ||
7386db26757Swiz 		    (cell_type == CELL_RIGHTJOIN &&
7396db26757Swiz 		    border == SCREEN_REDRAW_BORDER_LEFT)))) &&
740*f8cf1a91Swiz 		    screen_redraw_check_is(ctx, x, y, active)) {
7416db26757Swiz 			gc.attr |= GRID_ATTR_CHARSET;
7426db26757Swiz 			utf8_set(&gc.data, BORDER_MARKERS[border]);
7436db26757Swiz 		}
7446db26757Swiz 	}
7456db26757Swiz 
746c23f9150Swiz 	tty_cell(tty, &gc, &grid_default_cell, NULL, NULL);
7479fb66d81Schristos 	if (isolates)
7489fb66d81Schristos 		tty_puts(tty, START_ISOLATE);
7498f3b9483Schristos }
7508f3b9483Schristos 
751928fc495Schristos /* Draw the borders. */
7524e179ddaSchristos static void
7538f3b9483Schristos screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
754928fc495Schristos {
7558f3b9483Schristos 	struct client		*c = ctx->c;
7565494e770Schristos 	struct session		*s = c->session;
7575494e770Schristos 	struct window		*w = s->curw->window;
7589fb66d81Schristos 	struct window_pane	*wp;
759ef36e747Schristos 	u_int			 i, j;
7605494e770Schristos 
761ef36e747Schristos 	log_debug("%s: %s @%u", __func__, c->name, w->id);
762928fc495Schristos 
7639fb66d81Schristos 	TAILQ_FOREACH(wp, &w->panes, entry)
7649fb66d81Schristos 		wp->border_gc_set = 0;
765928fc495Schristos 
7669fb66d81Schristos 	for (j = 0; j < c->tty.sy - ctx->statuslines; j++) {
7679fb66d81Schristos 		for (i = 0; i < c->tty.sx; i++)
7689fb66d81Schristos 			screen_redraw_draw_borders_cell(ctx, i, j);
769928fc495Schristos 	}
770928fc495Schristos }
771928fc495Schristos 
772928fc495Schristos /* Draw the panes. */
7734e179ddaSchristos static void
7748f3b9483Schristos screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
775928fc495Schristos {
7768f3b9483Schristos 	struct client		*c = ctx->c;
777928fc495Schristos 	struct window		*w = c->session->curw->window;
778928fc495Schristos 	struct window_pane	*wp;
779928fc495Schristos 
780ef36e747Schristos 	log_debug("%s: %s @%u", __func__, c->name, w->id);
781ef36e747Schristos 
782928fc495Schristos 	TAILQ_FOREACH(wp, &w->panes, entry) {
7836483eba0Schristos 		if (window_pane_visible(wp))
784ef36e747Schristos 			screen_redraw_draw_pane(ctx, wp);
785928fc495Schristos 	}
786928fc495Schristos }
787928fc495Schristos 
788928fc495Schristos /* Draw the status line. */
7894e179ddaSchristos static void
7908f3b9483Schristos screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
791928fc495Schristos {
7928f3b9483Schristos 	struct client	*c = ctx->c;
793ef36e747Schristos 	struct window	*w = c->session->curw->window;
794928fc495Schristos 	struct tty	*tty = &c->tty;
795ef36e747Schristos 	struct screen	*s = c->status.active;
7968f3b9483Schristos 	u_int		 i, y;
797928fc495Schristos 
798ef36e747Schristos 	log_debug("%s: %s @%u", __func__, c->name, w->id);
799ef36e747Schristos 
8006483eba0Schristos 	if (ctx->statustop)
8018f3b9483Schristos 		y = 0;
802928fc495Schristos 	else
8036483eba0Schristos 		y = c->tty.sy - ctx->statuslines;
8049fb66d81Schristos 	for (i = 0; i < ctx->statuslines; i++) {
8059fb66d81Schristos 		tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i,
8069fb66d81Schristos 		    &grid_default_cell, NULL);
8079fb66d81Schristos 	}
808ef36e747Schristos }
809ef36e747Schristos 
810ef36e747Schristos /* Draw one pane. */
811ef36e747Schristos static void
812ef36e747Schristos screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
813ef36e747Schristos {
814ef36e747Schristos 	struct client		*c = ctx->c;
815ef36e747Schristos 	struct window		*w = c->session->curw->window;
816ef36e747Schristos 	struct tty		*tty = &c->tty;
8176db26757Swiz 	struct screen		*s = wp->screen;
8186db26757Swiz 	struct colour_palette	*palette = &wp->palette;
8199fb66d81Schristos 	struct grid_cell	 defaults;
820ef36e747Schristos 	u_int			 i, j, top, x, y, width;
821ef36e747Schristos 
822ef36e747Schristos 	log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
823ef36e747Schristos 
824ef36e747Schristos 	if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
825ef36e747Schristos 		return;
8266483eba0Schristos 	if (ctx->statustop)
8276483eba0Schristos 		top = ctx->statuslines;
828ef36e747Schristos 	else
829ef36e747Schristos 		top = 0;
830ef36e747Schristos 	for (j = 0; j < wp->sy; j++) {
831ef36e747Schristos 		if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy)
832ef36e747Schristos 			continue;
833ef36e747Schristos 		y = top + wp->yoff + j - ctx->oy;
834ef36e747Schristos 
835ef36e747Schristos 		if (wp->xoff >= ctx->ox &&
836ef36e747Schristos 		    wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
837ef36e747Schristos 			/* All visible. */
838ef36e747Schristos 			i = 0;
839ef36e747Schristos 			x = wp->xoff - ctx->ox;
840ef36e747Schristos 			width = wp->sx;
841ef36e747Schristos 		} else if (wp->xoff < ctx->ox &&
842ef36e747Schristos 		    wp->xoff + wp->sx > ctx->ox + ctx->sx) {
843ef36e747Schristos 			/* Both left and right not visible. */
844ef36e747Schristos 			i = ctx->ox;
845ef36e747Schristos 			x = 0;
846ef36e747Schristos 			width = ctx->sx;
847ef36e747Schristos 		} else if (wp->xoff < ctx->ox) {
848ef36e747Schristos 			/* Left not visible. */
849ef36e747Schristos 			i = ctx->ox - wp->xoff;
850ef36e747Schristos 			x = 0;
851ef36e747Schristos 			width = wp->sx - i;
852ef36e747Schristos 		} else {
853ef36e747Schristos 			/* Right not visible. */
854ef36e747Schristos 			i = 0;
855ef36e747Schristos 			x = wp->xoff - ctx->ox;
856ef36e747Schristos 			width = ctx->sx - x;
857ef36e747Schristos 		}
858ef36e747Schristos 		log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
859ef36e747Schristos 		    __func__, c->name, wp->id, i, j, x, y, width);
860ef36e747Schristos 
8619fb66d81Schristos 		tty_default_colours(&defaults, wp);
8626db26757Swiz 		tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette);
863ef36e747Schristos 	}
864c23f9150Swiz 
865c23f9150Swiz #ifdef ENABLE_SIXEL
866c23f9150Swiz 	tty_draw_images(c, wp, s);
867c23f9150Swiz #endif
868928fc495Schristos }
869