Home | History | Annotate | Line # | Download | only in dist
screen-redraw.c revision 1.2
      1  1.2   wiz /* $OpenBSD$ */
      2  1.1  jmmv 
      3  1.1  jmmv /*
      4  1.2   wiz  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5  1.1  jmmv  *
      6  1.1  jmmv  * Permission to use, copy, modify, and distribute this software for any
      7  1.1  jmmv  * purpose with or without fee is hereby granted, provided that the above
      8  1.1  jmmv  * copyright notice and this permission notice appear in all copies.
      9  1.1  jmmv  *
     10  1.1  jmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  1.1  jmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  1.1  jmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  1.1  jmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  1.1  jmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15  1.1  jmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16  1.1  jmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  1.1  jmmv  */
     18  1.1  jmmv 
     19  1.1  jmmv #include <sys/types.h>
     20  1.1  jmmv 
     21  1.2   wiz #include <stdlib.h>
     22  1.1  jmmv #include <string.h>
     23  1.1  jmmv 
     24  1.1  jmmv #include "tmux.h"
     25  1.1  jmmv 
     26  1.2   wiz static void	screen_redraw_draw_borders(struct screen_redraw_ctx *);
     27  1.2   wiz static void	screen_redraw_draw_panes(struct screen_redraw_ctx *);
     28  1.2   wiz static void	screen_redraw_draw_status(struct screen_redraw_ctx *);
     29  1.2   wiz static void	screen_redraw_draw_pane(struct screen_redraw_ctx *,
     30  1.2   wiz 		    struct window_pane *);
     31  1.2   wiz static void	screen_redraw_set_context(struct client *,
     32  1.2   wiz 		    struct screen_redraw_ctx *);
     33  1.2   wiz static void	screen_redraw_draw_pane_scrollbars(struct screen_redraw_ctx *);
     34  1.2   wiz static void	screen_redraw_draw_scrollbar(struct screen_redraw_ctx *,
     35  1.2   wiz 		    struct window_pane *, int, int, int, u_int, u_int, u_int);
     36  1.2   wiz static void	screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *,
     37  1.2   wiz 		    struct window_pane *);
     38  1.2   wiz 
     39  1.2   wiz #define START_ISOLATE "\342\201\246"
     40  1.2   wiz #define END_ISOLATE   "\342\201\251"
     41  1.2   wiz 
     42  1.2   wiz /* Border in relation to a pane. */
     43  1.2   wiz enum screen_redraw_border_type {
     44  1.2   wiz 	SCREEN_REDRAW_OUTSIDE,
     45  1.2   wiz 	SCREEN_REDRAW_INSIDE,
     46  1.2   wiz 	SCREEN_REDRAW_BORDER_LEFT,
     47  1.2   wiz 	SCREEN_REDRAW_BORDER_RIGHT,
     48  1.2   wiz 	SCREEN_REDRAW_BORDER_TOP,
     49  1.2   wiz 	SCREEN_REDRAW_BORDER_BOTTOM
     50  1.2   wiz };
     51  1.2   wiz #define BORDER_MARKERS "  +,.-"
     52  1.2   wiz 
     53  1.2   wiz /* Get cell border character. */
     54  1.2   wiz static void
     55  1.2   wiz screen_redraw_border_set(struct window *w, struct window_pane *wp,
     56  1.2   wiz     enum pane_lines pane_lines, int cell_type, struct grid_cell *gc)
     57  1.1  jmmv {
     58  1.2   wiz 	u_int	idx;
     59  1.2   wiz 
     60  1.2   wiz 	if (cell_type == CELL_OUTSIDE && w->fill_character != NULL) {
     61  1.2   wiz 		utf8_copy(&gc->data, &w->fill_character[0]);
     62  1.2   wiz 		return;
     63  1.2   wiz 	}
     64  1.2   wiz 
     65  1.2   wiz 	switch (pane_lines) {
     66  1.2   wiz 	case PANE_LINES_NUMBER:
     67  1.2   wiz 		if (cell_type == CELL_OUTSIDE) {
     68  1.2   wiz 			gc->attr |= GRID_ATTR_CHARSET;
     69  1.2   wiz 			utf8_set(&gc->data, CELL_BORDERS[CELL_OUTSIDE]);
     70  1.2   wiz 			break;
     71  1.2   wiz 		}
     72  1.2   wiz 		gc->attr &= ~GRID_ATTR_CHARSET;
     73  1.2   wiz 		if (wp != NULL && window_pane_index(wp, &idx) == 0)
     74  1.2   wiz 			utf8_set(&gc->data, '0' + (idx % 10));
     75  1.2   wiz 		else
     76  1.2   wiz 			utf8_set(&gc->data, '*');
     77  1.2   wiz 		break;
     78  1.2   wiz 	case PANE_LINES_DOUBLE:
     79  1.2   wiz 		gc->attr &= ~GRID_ATTR_CHARSET;
     80  1.2   wiz 		utf8_copy(&gc->data, tty_acs_double_borders(cell_type));
     81  1.2   wiz 		break;
     82  1.2   wiz 	case PANE_LINES_HEAVY:
     83  1.2   wiz 		gc->attr &= ~GRID_ATTR_CHARSET;
     84  1.2   wiz 		utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
     85  1.2   wiz 		break;
     86  1.2   wiz 	case PANE_LINES_SIMPLE:
     87  1.2   wiz 		gc->attr &= ~GRID_ATTR_CHARSET;
     88  1.2   wiz 		utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
     89  1.2   wiz 		break;
     90  1.2   wiz 	case PANE_LINES_SPACES:
     91  1.2   wiz 		gc->attr &= ~GRID_ATTR_CHARSET;
     92  1.2   wiz 		utf8_set(&gc->data, ' ');
     93  1.2   wiz 		break;
     94  1.2   wiz 	default:
     95  1.2   wiz 		gc->attr |= GRID_ATTR_CHARSET;
     96  1.2   wiz 		utf8_set(&gc->data, CELL_BORDERS[cell_type]);
     97  1.2   wiz 		break;
     98  1.2   wiz 	}
     99  1.2   wiz }
    100  1.2   wiz 
    101  1.2   wiz /* Return if window has only two panes. */
    102  1.2   wiz static int
    103  1.2   wiz screen_redraw_two_panes(struct window *w, int direction)
    104  1.2   wiz {
    105  1.2   wiz 	struct window_pane	*wp;
    106  1.2   wiz 
    107  1.2   wiz 	wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
    108  1.2   wiz 	if (wp == NULL)
    109  1.2   wiz 		return (0); /* one pane */
    110  1.2   wiz 	if (TAILQ_NEXT(wp, entry) != NULL)
    111  1.2   wiz 		return (0); /* more than two panes */
    112  1.2   wiz 	if (direction == 0 && wp->xoff == 0)
    113  1.2   wiz 		return (0);
    114  1.2   wiz 	if (direction == 1 && wp->yoff == 0)
    115  1.2   wiz 		return (0);
    116  1.2   wiz 	return (1);
    117  1.2   wiz }
    118  1.2   wiz 
    119  1.2   wiz /* Check if cell is on the border of a pane. */
    120  1.2   wiz static enum screen_redraw_border_type
    121  1.2   wiz screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
    122  1.2   wiz     u_int px, u_int py)
    123  1.2   wiz {
    124  1.2   wiz 	struct options	*oo = wp->window->options;
    125  1.2   wiz 	u_int		 ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
    126  1.2   wiz 	int		 hsplit = 0, vsplit = 0, pane_status = ctx->pane_status;
    127  1.2   wiz 	int		 pane_scrollbars = ctx->pane_scrollbars, sb_w = 0;
    128  1.2   wiz 	int		 sb_pos;
    129  1.2   wiz 
    130  1.2   wiz 	if (pane_scrollbars != 0)
    131  1.2   wiz 		sb_pos = ctx->pane_scrollbars_pos;
    132  1.2   wiz 	else
    133  1.2   wiz 		sb_pos = 0;
    134  1.2   wiz 
    135  1.1  jmmv 	/* Inside pane. */
    136  1.2   wiz 	if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
    137  1.2   wiz 		return (SCREEN_REDRAW_INSIDE);
    138  1.2   wiz 
    139  1.2   wiz 	/* Get pane indicator. */
    140  1.2   wiz 	switch (options_get_number(oo, "pane-border-indicators")) {
    141  1.2   wiz 	case PANE_BORDER_COLOUR:
    142  1.2   wiz 	case PANE_BORDER_BOTH:
    143  1.2   wiz 		hsplit = screen_redraw_two_panes(wp->window, 0);
    144  1.2   wiz 		vsplit = screen_redraw_two_panes(wp->window, 1);
    145  1.2   wiz 		break;
    146  1.2   wiz 	}
    147  1.1  jmmv 
    148  1.2   wiz 	/* Are scrollbars enabled? */
    149  1.2   wiz 	if (window_pane_show_scrollbar(wp, pane_scrollbars))
    150  1.2   wiz 		sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
    151  1.2   wiz 
    152  1.2   wiz 	/*
    153  1.2   wiz 	 * Left/right borders. The wp->sy / 2 test is to colour only half the
    154  1.2   wiz 	 * active window's border when there are two panes.
    155  1.2   wiz 	 */
    156  1.2   wiz 	if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
    157  1.2   wiz 		if (sb_pos == PANE_SCROLLBARS_LEFT) {
    158  1.2   wiz 			if (wp->xoff - sb_w == 0 && px == wp->sx + sb_w)
    159  1.2   wiz 				if (!hsplit || (hsplit && py <= wp->sy / 2))
    160  1.2   wiz 					return (SCREEN_REDRAW_BORDER_RIGHT);
    161  1.2   wiz 			if (wp->xoff - sb_w != 0) {
    162  1.2   wiz 				if (px == wp->xoff - sb_w - 1 &&
    163  1.2   wiz 				    (!hsplit || (hsplit && py > wp->sy / 2)))
    164  1.2   wiz 					return (SCREEN_REDRAW_BORDER_LEFT);
    165  1.2   wiz 				if (px == wp->xoff + wp->sx + sb_w - 1)
    166  1.2   wiz 					return (SCREEN_REDRAW_BORDER_RIGHT);
    167  1.2   wiz 			}
    168  1.2   wiz 		} else { /* sb_pos == PANE_SCROLLBARS_RIGHT or disabled*/
    169  1.2   wiz 			if (wp->xoff == 0 && px == wp->sx + sb_w)
    170  1.2   wiz 				if (!hsplit || (hsplit && py <= wp->sy / 2))
    171  1.2   wiz 					return (SCREEN_REDRAW_BORDER_RIGHT);
    172  1.2   wiz 			if (wp->xoff != 0) {
    173  1.2   wiz 				if (px == wp->xoff - 1 &&
    174  1.2   wiz 				    (!hsplit || (hsplit && py > wp->sy / 2)))
    175  1.2   wiz 					return (SCREEN_REDRAW_BORDER_LEFT);
    176  1.2   wiz 				if (px == wp->xoff + wp->sx + sb_w)
    177  1.2   wiz 					return (SCREEN_REDRAW_BORDER_RIGHT);
    178  1.2   wiz 			}
    179  1.2   wiz 		}
    180  1.1  jmmv 	}
    181  1.1  jmmv 
    182  1.1  jmmv 	/* Top/bottom borders. */
    183  1.2   wiz 	if (vsplit && pane_status == PANE_STATUS_OFF && sb_w == 0) {
    184  1.2   wiz 		if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
    185  1.2   wiz 			return (SCREEN_REDRAW_BORDER_BOTTOM);
    186  1.2   wiz 		if (wp->yoff != 0 && py == wp->yoff - 1 && px > wp->sx / 2)
    187  1.2   wiz 			return (SCREEN_REDRAW_BORDER_TOP);
    188  1.2   wiz 	} else {
    189  1.2   wiz 		if (sb_pos == PANE_SCROLLBARS_LEFT) {
    190  1.2   wiz 			if ((wp->xoff - sb_w == 0 || px >= wp->xoff - sb_w) &&
    191  1.2   wiz 			    (px <= ex || (sb_w != 0 && px < ex + sb_w))) {
    192  1.2   wiz 				if (wp->yoff != 0 && py == wp->yoff - 1)
    193  1.2   wiz 					return (SCREEN_REDRAW_BORDER_TOP);
    194  1.2   wiz 				if (py == ey)
    195  1.2   wiz 					return (SCREEN_REDRAW_BORDER_BOTTOM);
    196  1.2   wiz 			}
    197  1.2   wiz 		} else { /* sb_pos == PANE_SCROLLBARS_RIGHT */
    198  1.2   wiz 			if ((wp->xoff == 0 || px >= wp->xoff) &&
    199  1.2   wiz 			    (px <= ex || (sb_w != 0 && px < ex + sb_w))) {
    200  1.2   wiz 				if (wp->yoff != 0 && py == wp->yoff - 1)
    201  1.2   wiz 					return (SCREEN_REDRAW_BORDER_TOP);
    202  1.2   wiz 				if (py == ey)
    203  1.2   wiz 					return (SCREEN_REDRAW_BORDER_BOTTOM);
    204  1.2   wiz 			}
    205  1.2   wiz 		}
    206  1.1  jmmv 	}
    207  1.1  jmmv 
    208  1.1  jmmv 	/* Outside pane. */
    209  1.2   wiz 	return (SCREEN_REDRAW_OUTSIDE);
    210  1.1  jmmv }
    211  1.1  jmmv 
    212  1.2   wiz /* Check if a cell is on a border. */
    213  1.2   wiz static int
    214  1.2   wiz screen_redraw_cell_border(struct screen_redraw_ctx *ctx, u_int px, u_int py)
    215  1.1  jmmv {
    216  1.2   wiz 	struct client		*c = ctx->c;
    217  1.1  jmmv 	struct window		*w = c->session->curw->window;
    218  1.1  jmmv 	struct window_pane	*wp;
    219  1.2   wiz 	u_int			 sy = w->sy;
    220  1.2   wiz 
    221  1.2   wiz 	if (ctx->pane_status == PANE_STATUS_BOTTOM)
    222  1.2   wiz 		sy--;
    223  1.2   wiz 
    224  1.2   wiz 	/* Outside the window? */
    225  1.2   wiz 	if (px > w->sx || py > sy)
    226  1.2   wiz 		return (0);
    227  1.2   wiz 
    228  1.2   wiz 	/* On the window border? */
    229  1.2   wiz 	if (px == w->sx || py == sy)
    230  1.2   wiz 		return (1);
    231  1.1  jmmv 
    232  1.1  jmmv 	/* Check all the panes. */
    233  1.1  jmmv 	TAILQ_FOREACH(wp, &w->panes, entry) {
    234  1.1  jmmv 		if (!window_pane_visible(wp))
    235  1.1  jmmv 			continue;
    236  1.2   wiz 		switch (screen_redraw_pane_border(ctx, wp, px, py)) {
    237  1.2   wiz 		case SCREEN_REDRAW_INSIDE:
    238  1.2   wiz 			return (0);
    239  1.2   wiz 		case SCREEN_REDRAW_OUTSIDE:
    240  1.2   wiz 			break;
    241  1.2   wiz 		default:
    242  1.2   wiz 			return (1);
    243  1.2   wiz 		}
    244  1.1  jmmv 	}
    245  1.1  jmmv 
    246  1.1  jmmv 	return (0);
    247  1.1  jmmv }
    248  1.1  jmmv 
    249  1.2   wiz /* Work out type of border cell from surrounding cells. */
    250  1.2   wiz static int
    251  1.2   wiz screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py)
    252  1.2   wiz {
    253  1.2   wiz 	struct client	*c = ctx->c;
    254  1.2   wiz 	int		 pane_status = ctx->pane_status;
    255  1.2   wiz 	struct window	*w = c->session->curw->window;
    256  1.2   wiz 	u_int		 sx = w->sx, sy = w->sy;
    257  1.2   wiz 	int		 borders = 0;
    258  1.2   wiz 
    259  1.2   wiz 	if (pane_status == PANE_STATUS_BOTTOM)
    260  1.2   wiz 		sy--;
    261  1.2   wiz 
    262  1.2   wiz 	/* Is this outside the window? */
    263  1.2   wiz 	if (px > sx || py > sy)
    264  1.2   wiz 		return (CELL_OUTSIDE);
    265  1.2   wiz 
    266  1.2   wiz 	/*
    267  1.2   wiz 	 * Construct a bitmask of whether the cells to the left (bit 8), right,
    268  1.2   wiz 	 * top, and bottom (bit 1) of this cell are borders.
    269  1.2   wiz 	 *
    270  1.2   wiz 	 * bits 8 4 2 1:     2
    271  1.2   wiz 	 *		   8 + 4
    272  1.2   wiz 	 *		     1
    273  1.2   wiz 	 */
    274  1.2   wiz 	if (px == 0 || screen_redraw_cell_border(ctx, px - 1, py))
    275  1.2   wiz 		borders |= 8;
    276  1.2   wiz 	if (px <= sx && screen_redraw_cell_border(ctx, px + 1, py))
    277  1.2   wiz 		borders |= 4;
    278  1.2   wiz 	if (pane_status == PANE_STATUS_TOP) {
    279  1.2   wiz 		if (py != 0 &&
    280  1.2   wiz 		    screen_redraw_cell_border(ctx, px, py - 1))
    281  1.2   wiz 			borders |= 2;
    282  1.2   wiz 		if (screen_redraw_cell_border(ctx, px, py + 1))
    283  1.2   wiz 			borders |= 1;
    284  1.2   wiz 	} else if (pane_status == PANE_STATUS_BOTTOM) {
    285  1.2   wiz 		if (py == 0 ||
    286  1.2   wiz 		    screen_redraw_cell_border(ctx, px, py - 1))
    287  1.2   wiz 			borders |= 2;
    288  1.2   wiz 		if (py != sy &&
    289  1.2   wiz 		    screen_redraw_cell_border(ctx, px, py + 1))
    290  1.2   wiz 			borders |= 1;
    291  1.2   wiz 	} else {
    292  1.2   wiz 		if (py == 0 ||
    293  1.2   wiz 		    screen_redraw_cell_border(ctx, px, py - 1))
    294  1.2   wiz 			borders |= 2;
    295  1.2   wiz 		if (screen_redraw_cell_border(ctx, px, py + 1))
    296  1.2   wiz 			borders |= 1;
    297  1.2   wiz 	}
    298  1.2   wiz 
    299  1.2   wiz 	/*
    300  1.2   wiz 	 * Figure out what kind of border this cell is. Only one bit set
    301  1.2   wiz 	 * doesn't make sense (can't have a border cell with no others
    302  1.2   wiz 	 * connected).
    303  1.2   wiz 	 */
    304  1.2   wiz 	switch (borders) {
    305  1.2   wiz 	case 15:	/* 1111, left right top bottom */
    306  1.2   wiz 		return (CELL_JOIN);
    307  1.2   wiz 	case 14:	/* 1110, left right top */
    308  1.2   wiz 		return (CELL_BOTTOMJOIN);
    309  1.2   wiz 	case 13:	/* 1101, left right bottom */
    310  1.2   wiz 		return (CELL_TOPJOIN);
    311  1.2   wiz 	case 12:	/* 1100, left right */
    312  1.2   wiz 		return (CELL_LEFTRIGHT);
    313  1.2   wiz 	case 11:	/* 1011, left top bottom */
    314  1.2   wiz 		return (CELL_RIGHTJOIN);
    315  1.2   wiz 	case 10:	/* 1010, left top */
    316  1.2   wiz 		return (CELL_BOTTOMRIGHT);
    317  1.2   wiz 	case 9:		/* 1001, left bottom */
    318  1.2   wiz 		return (CELL_TOPRIGHT);
    319  1.2   wiz 	case 7:		/* 0111, right top bottom */
    320  1.2   wiz 		return (CELL_LEFTJOIN);
    321  1.2   wiz 	case 6:		/* 0110, right top */
    322  1.2   wiz 		return (CELL_BOTTOMLEFT);
    323  1.2   wiz 	case 5:		/* 0101, right bottom */
    324  1.2   wiz 		return (CELL_TOPLEFT);
    325  1.2   wiz 	case 3:		/* 0011, top bottom */
    326  1.2   wiz 		return (CELL_TOPBOTTOM);
    327  1.2   wiz 	}
    328  1.2   wiz 	return (CELL_OUTSIDE);
    329  1.2   wiz }
    330  1.2   wiz 
    331  1.1  jmmv /* Check if cell inside a pane. */
    332  1.2   wiz static int
    333  1.2   wiz screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
    334  1.2   wiz     struct window_pane **wpp)
    335  1.1  jmmv {
    336  1.2   wiz 	struct client		*c = ctx->c;
    337  1.1  jmmv 	struct window		*w = c->session->curw->window;
    338  1.2   wiz 	struct window_pane	*wp, *active;
    339  1.2   wiz 	int			 pane_status = ctx->pane_status;
    340  1.2   wiz 	u_int			 sx = w->sx, sy = w->sy;
    341  1.2   wiz 	int			 border, pane_scrollbars = ctx->pane_scrollbars;
    342  1.2   wiz 	u_int			 right, line;
    343  1.2   wiz 	int			 sb_pos = ctx->pane_scrollbars_pos;
    344  1.2   wiz 	int			 sb_w;
    345  1.2   wiz 
    346  1.2   wiz 	*wpp = NULL;
    347  1.1  jmmv 
    348  1.2   wiz 	if (px > sx || py > sy)
    349  1.1  jmmv 		return (CELL_OUTSIDE);
    350  1.2   wiz 	if (px == sx || py == sy) /* window border */
    351  1.2   wiz 		return (screen_redraw_type_of_cell(ctx, px, py));
    352  1.2   wiz 
    353  1.2   wiz 	if (pane_status != PANE_STATUS_OFF) {
    354  1.2   wiz 		active = wp = server_client_get_pane(c);
    355  1.2   wiz 		do {
    356  1.2   wiz 			if (!window_pane_visible(wp))
    357  1.2   wiz 				goto next1;
    358  1.1  jmmv 
    359  1.2   wiz 			if (pane_status == PANE_STATUS_TOP)
    360  1.2   wiz 				line = wp->yoff - 1;
    361  1.2   wiz 			else
    362  1.2   wiz 				line = wp->yoff + sy;
    363  1.2   wiz 			right = wp->xoff + 2 + wp->status_size - 1;
    364  1.2   wiz 
    365  1.2   wiz 			if (py == line && px >= wp->xoff + 2 && px <= right)
    366  1.2   wiz 				return (CELL_INSIDE);
    367  1.2   wiz 
    368  1.2   wiz 		next1:
    369  1.2   wiz 			wp = TAILQ_NEXT(wp, entry);
    370  1.2   wiz 			if (wp == NULL)
    371  1.2   wiz 				wp = TAILQ_FIRST(&w->panes);
    372  1.2   wiz 		} while (wp != active);
    373  1.2   wiz 	}
    374  1.2   wiz 
    375  1.2   wiz 	active = wp = server_client_get_pane(c);
    376  1.2   wiz 	do {
    377  1.1  jmmv 		if (!window_pane_visible(wp))
    378  1.2   wiz 			goto next2;
    379  1.2   wiz 		*wpp = wp;
    380  1.1  jmmv 
    381  1.2   wiz 		/* Check if CELL_SCROLLBAR */
    382  1.2   wiz 		if (window_pane_show_scrollbar(wp, pane_scrollbars)) {
    383  1.1  jmmv 
    384  1.2   wiz 			if (pane_status == PANE_STATUS_TOP)
    385  1.2   wiz 				line = wp->yoff - 1;
    386  1.2   wiz 			else
    387  1.2   wiz 				line = wp->yoff + wp->sy;
    388  1.1  jmmv 
    389  1.2   wiz 			/*
    390  1.2   wiz 			 * Check if py could lie within a scrollbar. If the
    391  1.2   wiz 			 * pane is at the top then py == 0 to sy; if the pane
    392  1.2   wiz 			 * is not at the top, then yoff to yoff + sy.
    393  1.2   wiz 			 */
    394  1.2   wiz 			sb_w = wp->scrollbar_style.width +
    395  1.2   wiz 			    wp->scrollbar_style.pad;
    396  1.2   wiz 			if ((pane_status && py != line) ||
    397  1.2   wiz 			    (wp->yoff == 0 && py < wp->sy) ||
    398  1.2   wiz 			     (py >= wp->yoff && py < wp->yoff + wp->sy)) {
    399  1.2   wiz 				/* Check if px lies within a scrollbar. */
    400  1.2   wiz 				if ((sb_pos == PANE_SCROLLBARS_RIGHT &&
    401  1.2   wiz 				     (px >= wp->xoff + wp->sx &&
    402  1.2   wiz 				      px < wp->xoff + wp->sx + sb_w)) ||
    403  1.2   wiz 				    (sb_pos == PANE_SCROLLBARS_LEFT &&
    404  1.2   wiz 				     (px >= wp->xoff - sb_w &&
    405  1.2   wiz 				      px < wp->xoff)))
    406  1.2   wiz 					return (CELL_SCROLLBAR);
    407  1.2   wiz 			}
    408  1.2   wiz 		}
    409  1.1  jmmv 
    410  1.1  jmmv 		/*
    411  1.2   wiz 		 * If definitely inside, return. If not on border, skip.
    412  1.2   wiz 		 * Otherwise work out the cell.
    413  1.1  jmmv 		 */
    414  1.2   wiz 		border = screen_redraw_pane_border(ctx, wp, px, py);
    415  1.2   wiz 		if (border == SCREEN_REDRAW_INSIDE)
    416  1.2   wiz 			return (CELL_INSIDE);
    417  1.2   wiz 		if (border == SCREEN_REDRAW_OUTSIDE)
    418  1.2   wiz 			goto next2;
    419  1.2   wiz 		return (screen_redraw_type_of_cell(ctx, px, py));
    420  1.2   wiz 
    421  1.2   wiz 	next2:
    422  1.2   wiz 		wp = TAILQ_NEXT(wp, entry);
    423  1.2   wiz 		if (wp == NULL)
    424  1.2   wiz 			wp = TAILQ_FIRST(&w->panes);
    425  1.2   wiz 	} while (wp != active);
    426  1.1  jmmv 
    427  1.1  jmmv 	return (CELL_OUTSIDE);
    428  1.1  jmmv }
    429  1.1  jmmv 
    430  1.2   wiz /* Check if the border of a particular pane. */
    431  1.2   wiz static int
    432  1.2   wiz screen_redraw_check_is(struct screen_redraw_ctx *ctx, u_int px, u_int py,
    433  1.2   wiz     struct window_pane *wp)
    434  1.2   wiz {
    435  1.2   wiz 	enum screen_redraw_border_type	border;
    436  1.2   wiz 
    437  1.2   wiz 	border = screen_redraw_pane_border(ctx, wp, px, py);
    438  1.2   wiz 	if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE)
    439  1.2   wiz 		return (1);
    440  1.2   wiz 	return (0);
    441  1.2   wiz }
    442  1.2   wiz 
    443  1.2   wiz /* Update pane status. */
    444  1.2   wiz static int
    445  1.2   wiz screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
    446  1.2   wiz     struct screen_redraw_ctx *rctx, enum pane_lines pane_lines)
    447  1.1  jmmv {
    448  1.2   wiz 	struct window		*w = wp->window;
    449  1.2   wiz 	struct grid_cell	 gc;
    450  1.2   wiz 	const char		*fmt;
    451  1.2   wiz 	struct format_tree	*ft;
    452  1.2   wiz 	char			*expanded;
    453  1.2   wiz 	int			 pane_status = rctx->pane_status, sb_w = 0;
    454  1.2   wiz 	int			 pane_scrollbars = rctx->pane_scrollbars;
    455  1.2   wiz 	u_int			 width, i, cell_type, px, py;
    456  1.2   wiz 	struct screen_write_ctx	 ctx;
    457  1.2   wiz 	struct screen		 old;
    458  1.2   wiz 
    459  1.2   wiz 	if (window_pane_show_scrollbar(wp, pane_scrollbars))
    460  1.2   wiz 		sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
    461  1.2   wiz 
    462  1.2   wiz 	ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
    463  1.2   wiz 	format_defaults(ft, c, c->session, c->session->curw, wp);
    464  1.2   wiz 
    465  1.2   wiz 	if (wp == server_client_get_pane(c))
    466  1.2   wiz 		style_apply(&gc, w->options, "pane-active-border-style", ft);
    467  1.2   wiz 	else
    468  1.2   wiz 		style_apply(&gc, w->options, "pane-border-style", ft);
    469  1.2   wiz 	fmt = options_get_string(wp->options, "pane-border-format");
    470  1.1  jmmv 
    471  1.2   wiz 	expanded = format_expand_time(ft, fmt);
    472  1.2   wiz 	if (wp->sx < 4)
    473  1.2   wiz 		wp->status_size = width = 0;
    474  1.1  jmmv 	else
    475  1.2   wiz 		wp->status_size = width = wp->sx + sb_w - 2;
    476  1.1  jmmv 
    477  1.2   wiz 	memcpy(&old, &wp->status_screen, sizeof old);
    478  1.2   wiz 	screen_init(&wp->status_screen, width, 1, 0);
    479  1.2   wiz 	wp->status_screen.mode = 0;
    480  1.2   wiz 
    481  1.2   wiz 	screen_write_start(&ctx, &wp->status_screen);
    482  1.2   wiz 
    483  1.2   wiz 	for (i = 0; i < width; i++) {
    484  1.2   wiz 		px = wp->xoff + 2 + i;
    485  1.2   wiz 		if (pane_status == PANE_STATUS_TOP)
    486  1.2   wiz 			py = wp->yoff - 1;
    487  1.2   wiz 		else
    488  1.2   wiz 			py = wp->yoff + wp->sy;
    489  1.2   wiz 		cell_type = screen_redraw_type_of_cell(rctx, px, py);
    490  1.2   wiz 		screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc);
    491  1.2   wiz 		screen_write_cell(&ctx, &gc);
    492  1.1  jmmv 	}
    493  1.2   wiz 	gc.attr &= ~GRID_ATTR_CHARSET;
    494  1.2   wiz 
    495  1.2   wiz 	screen_write_cursormove(&ctx, 0, 0, 0);
    496  1.2   wiz 	format_draw(&ctx, &gc, width, expanded, NULL, 0);
    497  1.2   wiz 	screen_write_stop(&ctx);
    498  1.1  jmmv 
    499  1.2   wiz 	free(expanded);
    500  1.2   wiz 	format_free(ft);
    501  1.2   wiz 
    502  1.2   wiz 	if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
    503  1.2   wiz 		screen_free(&old);
    504  1.2   wiz 		return (0);
    505  1.1  jmmv 	}
    506  1.2   wiz 	screen_free(&old);
    507  1.2   wiz 	return (1);
    508  1.2   wiz }
    509  1.2   wiz 
    510  1.2   wiz /* Draw pane status. */
    511  1.2   wiz static void
    512  1.2   wiz screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
    513  1.2   wiz {
    514  1.2   wiz 	struct client		*c = ctx->c;
    515  1.2   wiz 	struct window		*w = c->session->curw->window;
    516  1.2   wiz 	struct tty		*tty = &c->tty;
    517  1.2   wiz 	struct window_pane	*wp;
    518  1.2   wiz 	struct screen		*s;
    519  1.2   wiz 	u_int			 i, x, width, xoff, yoff, size;
    520  1.1  jmmv 
    521  1.2   wiz 	log_debug("%s: %s @%u", __func__, c->name, w->id);
    522  1.1  jmmv 
    523  1.1  jmmv 	TAILQ_FOREACH(wp, &w->panes, entry) {
    524  1.1  jmmv 		if (!window_pane_visible(wp))
    525  1.1  jmmv 			continue;
    526  1.2   wiz 		s = &wp->status_screen;
    527  1.2   wiz 
    528  1.2   wiz 		size = wp->status_size;
    529  1.2   wiz 		if (ctx->pane_status == PANE_STATUS_TOP)
    530  1.2   wiz 			yoff = wp->yoff - 1;
    531  1.2   wiz 		else
    532  1.2   wiz 			yoff = wp->yoff + wp->sy;
    533  1.2   wiz 		xoff = wp->xoff + 2;
    534  1.2   wiz 
    535  1.2   wiz 		if (xoff + size <= ctx->ox ||
    536  1.2   wiz 		    xoff >= ctx->ox + ctx->sx ||
    537  1.2   wiz 		    yoff < ctx->oy ||
    538  1.2   wiz 		    yoff >= ctx->oy + ctx->sy)
    539  1.2   wiz 			continue;
    540  1.2   wiz 
    541  1.2   wiz 		if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) {
    542  1.2   wiz 			/* All visible. */
    543  1.2   wiz 			i = 0;
    544  1.2   wiz 			x = xoff - ctx->ox;
    545  1.2   wiz 			width = size;
    546  1.2   wiz 		} else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) {
    547  1.2   wiz 			/* Both left and right not visible. */
    548  1.2   wiz 			i = ctx->ox;
    549  1.2   wiz 			x = 0;
    550  1.2   wiz 			width = ctx->sx;
    551  1.2   wiz 		} else if (xoff < ctx->ox) {
    552  1.2   wiz 			/* Left not visible. */
    553  1.2   wiz 			i = ctx->ox - xoff;
    554  1.2   wiz 			x = 0;
    555  1.2   wiz 			width = size - i;
    556  1.2   wiz 		} else {
    557  1.2   wiz 			/* Right not visible. */
    558  1.2   wiz 			i = 0;
    559  1.2   wiz 			x = xoff - ctx->ox;
    560  1.2   wiz 			width = size - x;
    561  1.2   wiz 		}
    562  1.2   wiz 
    563  1.2   wiz 		if (ctx->statustop)
    564  1.2   wiz 			yoff += ctx->statuslines;
    565  1.2   wiz 		tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy,
    566  1.2   wiz 		    &grid_default_cell, NULL);
    567  1.2   wiz 	}
    568  1.2   wiz 	tty_cursor(tty, 0, 0);
    569  1.2   wiz }
    570  1.2   wiz 
    571  1.2   wiz /* Update status line and change flags if unchanged. */
    572  1.2   wiz static uint64_t
    573  1.2   wiz screen_redraw_update(struct screen_redraw_ctx *ctx, uint64_t flags)
    574  1.2   wiz {
    575  1.2   wiz 	struct client			*c = ctx->c;
    576  1.2   wiz 	struct window			*w = c->session->curw->window;
    577  1.2   wiz 	struct window_pane		*wp;
    578  1.2   wiz 	int				 redraw;
    579  1.2   wiz 	enum pane_lines			 lines;
    580  1.2   wiz 
    581  1.2   wiz 	if (c->message_string != NULL)
    582  1.2   wiz 		redraw = status_message_redraw(c);
    583  1.2   wiz 	else if (c->prompt_string != NULL)
    584  1.2   wiz 		redraw = status_prompt_redraw(c);
    585  1.2   wiz 	else
    586  1.2   wiz 		redraw = status_redraw(c);
    587  1.2   wiz 	if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS))
    588  1.2   wiz 		flags &= ~CLIENT_REDRAWSTATUS;
    589  1.2   wiz 
    590  1.2   wiz 	if (c->overlay_draw != NULL)
    591  1.2   wiz 		flags |= CLIENT_REDRAWOVERLAY;
    592  1.2   wiz 
    593  1.2   wiz 	if (ctx->pane_status != PANE_STATUS_OFF) {
    594  1.2   wiz 		lines = ctx->pane_lines;
    595  1.2   wiz 		redraw = 0;
    596  1.2   wiz 		TAILQ_FOREACH(wp, &w->panes, entry) {
    597  1.2   wiz 			if (screen_redraw_make_pane_status(c, wp, ctx, lines))
    598  1.2   wiz 				redraw = 1;
    599  1.1  jmmv 		}
    600  1.2   wiz 		if (redraw)
    601  1.2   wiz 			flags |= CLIENT_REDRAWBORDERS;
    602  1.1  jmmv 	}
    603  1.1  jmmv 
    604  1.2   wiz 	return (flags);
    605  1.1  jmmv }
    606  1.1  jmmv 
    607  1.2   wiz /* Set up redraw context. */
    608  1.2   wiz static void
    609  1.2   wiz screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
    610  1.2   wiz {
    611  1.2   wiz 	struct session	*s = c->session;
    612  1.2   wiz 	struct options	*oo = s->options;
    613  1.2   wiz 	struct window	*w = s->curw->window;
    614  1.2   wiz 	struct options	*wo = w->options;
    615  1.2   wiz 	u_int		 lines;
    616  1.2   wiz 
    617  1.2   wiz 	memset(ctx, 0, sizeof *ctx);
    618  1.2   wiz 	ctx->c = c;
    619  1.2   wiz 
    620  1.2   wiz 	lines = status_line_size(c);
    621  1.2   wiz 	if (c->message_string != NULL || c->prompt_string != NULL)
    622  1.2   wiz 		lines = (lines == 0) ? 1 : lines;
    623  1.2   wiz 	if (lines != 0 && options_get_number(oo, "status-position") == 0)
    624  1.2   wiz 		ctx->statustop = 1;
    625  1.2   wiz 	ctx->statuslines = lines;
    626  1.2   wiz 
    627  1.2   wiz 	ctx->pane_status = options_get_number(wo, "pane-border-status");
    628  1.2   wiz 	ctx->pane_lines = options_get_number(wo, "pane-border-lines");
    629  1.2   wiz 
    630  1.2   wiz 	ctx->pane_scrollbars = options_get_number(wo, "pane-scrollbars");
    631  1.2   wiz 	ctx->pane_scrollbars_pos = options_get_number(wo,
    632  1.2   wiz 	    "pane-scrollbars-position");
    633  1.2   wiz 
    634  1.2   wiz 	tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
    635  1.2   wiz 
    636  1.2   wiz 	log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
    637  1.2   wiz 	    w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines,
    638  1.2   wiz 	    ctx->statustop);
    639  1.2   wiz }
    640  1.2   wiz 
    641  1.2   wiz /* Redraw entire screen. */
    642  1.1  jmmv void
    643  1.2   wiz screen_redraw_screen(struct client *c)
    644  1.1  jmmv {
    645  1.2   wiz 	struct screen_redraw_ctx	ctx;
    646  1.2   wiz 	uint64_t			flags;
    647  1.2   wiz 
    648  1.2   wiz 	if (c->flags & CLIENT_SUSPENDED)
    649  1.2   wiz 		return;
    650  1.2   wiz 
    651  1.2   wiz 	screen_redraw_set_context(c, &ctx);
    652  1.2   wiz 
    653  1.2   wiz 	flags = screen_redraw_update(&ctx, c->flags);
    654  1.2   wiz 	if ((flags & CLIENT_ALLREDRAWFLAGS) == 0)
    655  1.2   wiz 		return;
    656  1.2   wiz 
    657  1.2   wiz 	tty_sync_start(&c->tty);
    658  1.2   wiz 	tty_update_mode(&c->tty, c->tty.mode, NULL);
    659  1.2   wiz 
    660  1.2   wiz 	if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
    661  1.2   wiz 		log_debug("%s: redrawing borders", c->name);
    662  1.2   wiz 		screen_redraw_draw_borders(&ctx);
    663  1.2   wiz 		if (ctx.pane_status != PANE_STATUS_OFF)
    664  1.2   wiz 			screen_redraw_draw_pane_status(&ctx);
    665  1.2   wiz 		screen_redraw_draw_pane_scrollbars(&ctx);
    666  1.2   wiz 	}
    667  1.2   wiz 	if (flags & CLIENT_REDRAWWINDOW) {
    668  1.2   wiz 		log_debug("%s: redrawing panes", c->name);
    669  1.2   wiz 		screen_redraw_draw_panes(&ctx);
    670  1.2   wiz 		screen_redraw_draw_pane_scrollbars(&ctx);
    671  1.2   wiz 	}
    672  1.2   wiz 	if (ctx.statuslines != 0 &&
    673  1.2   wiz 	    (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) {
    674  1.2   wiz 		log_debug("%s: redrawing status", c->name);
    675  1.2   wiz 		screen_redraw_draw_status(&ctx);
    676  1.2   wiz 	}
    677  1.2   wiz 	if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
    678  1.2   wiz 		log_debug("%s: redrawing overlay", c->name);
    679  1.2   wiz 		c->overlay_draw(c, c->overlay_data, &ctx);
    680  1.2   wiz 	}
    681  1.1  jmmv 
    682  1.1  jmmv 	tty_reset(&c->tty);
    683  1.1  jmmv }
    684  1.1  jmmv 
    685  1.2   wiz /* Redraw a single pane and its scrollbar. */
    686  1.1  jmmv void
    687  1.2   wiz screen_redraw_pane(struct client *c, struct window_pane *wp,
    688  1.2   wiz     int redraw_scrollbar_only)
    689  1.2   wiz {
    690  1.2   wiz 	struct screen_redraw_ctx	ctx;
    691  1.2   wiz 
    692  1.2   wiz 	if (!window_pane_visible(wp))
    693  1.2   wiz 		return;
    694  1.2   wiz 
    695  1.2   wiz 	screen_redraw_set_context(c, &ctx);
    696  1.2   wiz 	tty_sync_start(&c->tty);
    697  1.2   wiz 	tty_update_mode(&c->tty, c->tty.mode, NULL);
    698  1.2   wiz 
    699  1.2   wiz 	if (!redraw_scrollbar_only)
    700  1.2   wiz 		screen_redraw_draw_pane(&ctx, wp);
    701  1.2   wiz 
    702  1.2   wiz 	if (window_pane_show_scrollbar(wp, ctx.pane_scrollbars))
    703  1.2   wiz 		screen_redraw_draw_pane_scrollbar(&ctx, wp);
    704  1.2   wiz 
    705  1.2   wiz 	tty_reset(&c->tty);
    706  1.2   wiz }
    707  1.2   wiz 
    708  1.2   wiz /* Get border cell style. */
    709  1.2   wiz static const struct grid_cell *
    710  1.2   wiz screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
    711  1.2   wiz     u_int y, struct window_pane *wp)
    712  1.1  jmmv {
    713  1.2   wiz 	struct client		*c = ctx->c;
    714  1.2   wiz 	struct session		*s = c->session;
    715  1.2   wiz 	struct window		*w = s->curw->window;
    716  1.2   wiz 	struct window_pane	*active = server_client_get_pane(c);
    717  1.2   wiz 	struct options		*oo = w->options;
    718  1.2   wiz 	struct format_tree	*ft;
    719  1.2   wiz 
    720  1.2   wiz 	if (wp->border_gc_set)
    721  1.2   wiz 		return (&wp->border_gc);
    722  1.2   wiz 	wp->border_gc_set = 1;
    723  1.2   wiz 
    724  1.2   wiz 	ft = format_create_defaults(NULL, c, s, s->curw, wp);
    725  1.2   wiz 	if (screen_redraw_check_is(ctx, x, y, active))
    726  1.2   wiz 		style_apply(&wp->border_gc, oo, "pane-active-border-style", ft);
    727  1.2   wiz 	else
    728  1.2   wiz 		style_apply(&wp->border_gc, oo, "pane-border-style", ft);
    729  1.2   wiz 	format_free(ft);
    730  1.2   wiz 
    731  1.2   wiz 	return (&wp->border_gc);
    732  1.2   wiz }
    733  1.2   wiz 
    734  1.2   wiz /* Draw a border cell. */
    735  1.2   wiz static void
    736  1.2   wiz screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
    737  1.2   wiz {
    738  1.2   wiz 	struct client		*c = ctx->c;
    739  1.2   wiz 	struct session		*s = c->session;
    740  1.2   wiz 	struct window		*w = s->curw->window;
    741  1.2   wiz 	struct options		*oo = w->options;
    742  1.1  jmmv 	struct tty		*tty = &c->tty;
    743  1.2   wiz 	struct format_tree	*ft;
    744  1.2   wiz 	struct window_pane	*wp, *active = server_client_get_pane(c);
    745  1.2   wiz 	struct grid_cell	 gc;
    746  1.2   wiz 	const struct grid_cell	*tmp;
    747  1.2   wiz 	struct overlay_ranges	 r;
    748  1.2   wiz 	u_int			 cell_type, x = ctx->ox + i, y = ctx->oy + j;
    749  1.2   wiz 	int			 arrows = 0, border, isolates;
    750  1.2   wiz 
    751  1.2   wiz 	if (c->overlay_check != NULL) {
    752  1.2   wiz 		c->overlay_check(c, c->overlay_data, x, y, 1, &r);
    753  1.2   wiz 		if (r.nx[0] + r.nx[1] == 0)
    754  1.2   wiz 			return;
    755  1.2   wiz 	}
    756  1.2   wiz 
    757  1.2   wiz 	cell_type = screen_redraw_check_cell(ctx, x, y, &wp);
    758  1.2   wiz 	if (cell_type == CELL_INSIDE || cell_type == CELL_SCROLLBAR)
    759  1.2   wiz 		return;
    760  1.2   wiz 
    761  1.2   wiz 	if (wp == NULL) {
    762  1.2   wiz 		if (!ctx->no_pane_gc_set) {
    763  1.2   wiz 			ft = format_create_defaults(NULL, c, s, s->curw, NULL);
    764  1.2   wiz 			memcpy(&ctx->no_pane_gc, &grid_default_cell, sizeof gc);
    765  1.2   wiz 			style_add(&ctx->no_pane_gc, oo, "pane-border-style",
    766  1.2   wiz 			    ft);
    767  1.2   wiz 			format_free(ft);
    768  1.2   wiz 			ctx->no_pane_gc_set = 1;
    769  1.2   wiz 		}
    770  1.2   wiz 		memcpy(&gc, &ctx->no_pane_gc, sizeof gc);
    771  1.2   wiz 	} else {
    772  1.2   wiz 		tmp = screen_redraw_draw_borders_style(ctx, x, y, wp);
    773  1.2   wiz 		if (tmp == NULL)
    774  1.2   wiz 			return;
    775  1.2   wiz 		memcpy(&gc, tmp, sizeof gc);
    776  1.2   wiz 
    777  1.2   wiz 		if (server_is_marked(s, s->curw, marked_pane.wp) &&
    778  1.2   wiz 		    screen_redraw_check_is(ctx, x, y, marked_pane.wp))
    779  1.2   wiz 			gc.attr ^= GRID_ATTR_REVERSE;
    780  1.2   wiz 	}
    781  1.2   wiz 	screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc);
    782  1.2   wiz 
    783  1.2   wiz 	if (cell_type == CELL_TOPBOTTOM &&
    784  1.2   wiz 	    (c->flags & CLIENT_UTF8) &&
    785  1.2   wiz 	    tty_term_has(tty->term, TTYC_BIDI))
    786  1.2   wiz 		isolates = 1;
    787  1.2   wiz 	else
    788  1.2   wiz 		isolates = 0;
    789  1.2   wiz 
    790  1.2   wiz 	if (ctx->statustop)
    791  1.2   wiz 		tty_cursor(tty, i, ctx->statuslines + j);
    792  1.2   wiz 	else
    793  1.2   wiz 		tty_cursor(tty, i, j);
    794  1.2   wiz 	if (isolates)
    795  1.2   wiz 		tty_puts(tty, END_ISOLATE);
    796  1.2   wiz 
    797  1.2   wiz 	switch (options_get_number(oo, "pane-border-indicators")) {
    798  1.2   wiz 	case PANE_BORDER_ARROWS:
    799  1.2   wiz 	case PANE_BORDER_BOTH:
    800  1.2   wiz 		arrows = 1;
    801  1.2   wiz 		break;
    802  1.2   wiz 	}
    803  1.2   wiz 
    804  1.2   wiz 	if (wp != NULL && arrows) {
    805  1.2   wiz 		border = screen_redraw_pane_border(ctx, active, x, y);
    806  1.2   wiz 		if (((i == wp->xoff + 1 &&
    807  1.2   wiz 		    (cell_type == CELL_LEFTRIGHT ||
    808  1.2   wiz 		    (cell_type == CELL_TOPJOIN &&
    809  1.2   wiz 		    border == SCREEN_REDRAW_BORDER_BOTTOM) ||
    810  1.2   wiz 		    (cell_type == CELL_BOTTOMJOIN &&
    811  1.2   wiz 		    border == SCREEN_REDRAW_BORDER_TOP))) ||
    812  1.2   wiz 		    (j == wp->yoff + 1 &&
    813  1.2   wiz 		    (cell_type == CELL_TOPBOTTOM ||
    814  1.2   wiz 		    (cell_type == CELL_LEFTJOIN &&
    815  1.2   wiz 		    border == SCREEN_REDRAW_BORDER_RIGHT) ||
    816  1.2   wiz 		    (cell_type == CELL_RIGHTJOIN &&
    817  1.2   wiz 		    border == SCREEN_REDRAW_BORDER_LEFT)))) &&
    818  1.2   wiz 		    screen_redraw_check_is(ctx, x, y, active)) {
    819  1.2   wiz 			gc.attr |= GRID_ATTR_CHARSET;
    820  1.2   wiz 			utf8_set(&gc.data, BORDER_MARKERS[border]);
    821  1.2   wiz 		}
    822  1.2   wiz 	}
    823  1.2   wiz 
    824  1.2   wiz 	tty_cell(tty, &gc, &grid_default_cell, NULL, NULL);
    825  1.2   wiz 	if (isolates)
    826  1.2   wiz 		tty_puts(tty, START_ISOLATE);
    827  1.2   wiz }
    828  1.2   wiz 
    829  1.2   wiz /* Draw the borders. */
    830  1.2   wiz static void
    831  1.2   wiz screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
    832  1.2   wiz {
    833  1.2   wiz 	struct client		*c = ctx->c;
    834  1.1  jmmv 	struct session		*s = c->session;
    835  1.2   wiz 	struct window		*w = s->curw->window;
    836  1.2   wiz 	struct window_pane	*wp;
    837  1.2   wiz 	u_int			 i, j;
    838  1.2   wiz 
    839  1.2   wiz 	log_debug("%s: %s @%u", __func__, c->name, w->id);
    840  1.2   wiz 
    841  1.2   wiz 	TAILQ_FOREACH(wp, &w->panes, entry)
    842  1.2   wiz 		wp->border_gc_set = 0;
    843  1.2   wiz 
    844  1.2   wiz 	for (j = 0; j < c->tty.sy - ctx->statuslines; j++) {
    845  1.2   wiz 		for (i = 0; i < c->tty.sx; i++)
    846  1.2   wiz 			screen_redraw_draw_borders_cell(ctx, i, j);
    847  1.2   wiz 	}
    848  1.2   wiz }
    849  1.2   wiz 
    850  1.2   wiz /* Draw the panes. */
    851  1.2   wiz static void
    852  1.2   wiz screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
    853  1.2   wiz {
    854  1.2   wiz 	struct client		*c = ctx->c;
    855  1.2   wiz 	struct window		*w = c->session->curw->window;
    856  1.2   wiz 	struct window_pane	*wp;
    857  1.2   wiz 
    858  1.2   wiz 	log_debug("%s: %s @%u", __func__, c->name, w->id);
    859  1.2   wiz 
    860  1.2   wiz 	TAILQ_FOREACH(wp, &w->panes, entry) {
    861  1.2   wiz 		if (window_pane_visible(wp))
    862  1.2   wiz 			screen_redraw_draw_pane(ctx, wp);
    863  1.2   wiz 	}
    864  1.2   wiz }
    865  1.2   wiz 
    866  1.2   wiz /* Draw the status line. */
    867  1.2   wiz static void
    868  1.2   wiz screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
    869  1.2   wiz {
    870  1.2   wiz 	struct client	*c = ctx->c;
    871  1.2   wiz 	struct window	*w = c->session->curw->window;
    872  1.2   wiz 	struct tty	*tty = &c->tty;
    873  1.2   wiz 	struct screen	*s = c->status.active;
    874  1.2   wiz 	u_int		 i, y;
    875  1.2   wiz 
    876  1.2   wiz 	log_debug("%s: %s @%u", __func__, c->name, w->id);
    877  1.2   wiz 
    878  1.2   wiz 	if (ctx->statustop)
    879  1.2   wiz 		y = 0;
    880  1.2   wiz 	else
    881  1.2   wiz 		y = c->tty.sy - ctx->statuslines;
    882  1.2   wiz 	for (i = 0; i < ctx->statuslines; i++) {
    883  1.2   wiz 		tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i,
    884  1.2   wiz 		    &grid_default_cell, NULL);
    885  1.2   wiz 	}
    886  1.2   wiz }
    887  1.2   wiz 
    888  1.2   wiz /* Draw one pane. */
    889  1.2   wiz static void
    890  1.2   wiz screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
    891  1.2   wiz {
    892  1.2   wiz 	struct client		*c = ctx->c;
    893  1.2   wiz 	struct window		*w = c->session->curw->window;
    894  1.2   wiz 	struct tty		*tty = &c->tty;
    895  1.2   wiz 	struct screen		*s = wp->screen;
    896  1.2   wiz 	struct colour_palette	*palette = &wp->palette;
    897  1.2   wiz 	struct grid_cell	 defaults;
    898  1.2   wiz 	u_int			 i, j, top, x, y, width;
    899  1.1  jmmv 
    900  1.2   wiz 	log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
    901  1.1  jmmv 
    902  1.2   wiz 	if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
    903  1.1  jmmv 		return;
    904  1.2   wiz 	if (ctx->statustop)
    905  1.2   wiz 		top = ctx->statuslines;
    906  1.2   wiz 	else
    907  1.2   wiz 		top = 0;
    908  1.2   wiz 	for (j = 0; j < wp->sy; j++) {
    909  1.2   wiz 		if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy)
    910  1.2   wiz 			continue;
    911  1.2   wiz 		y = top + wp->yoff + j - ctx->oy;
    912  1.1  jmmv 
    913  1.2   wiz 		if (wp->xoff >= ctx->ox &&
    914  1.2   wiz 		    wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
    915  1.2   wiz 			/* All visible. */
    916  1.2   wiz 			i = 0;
    917  1.2   wiz 			x = wp->xoff - ctx->ox;
    918  1.2   wiz 			width = wp->sx;
    919  1.2   wiz 		} else if (wp->xoff < ctx->ox &&
    920  1.2   wiz 		    wp->xoff + wp->sx > ctx->ox + ctx->sx) {
    921  1.2   wiz 			/* Both left and right not visible. */
    922  1.2   wiz 			i = ctx->ox;
    923  1.2   wiz 			x = 0;
    924  1.2   wiz 			width = ctx->sx;
    925  1.2   wiz 		} else if (wp->xoff < ctx->ox) {
    926  1.2   wiz 			/* Left not visible. */
    927  1.2   wiz 			i = ctx->ox - wp->xoff;
    928  1.2   wiz 			x = 0;
    929  1.2   wiz 			width = wp->sx - i;
    930  1.2   wiz 		} else {
    931  1.2   wiz 			/* Right not visible. */
    932  1.2   wiz 			i = 0;
    933  1.2   wiz 			x = wp->xoff - ctx->ox;
    934  1.2   wiz 			width = ctx->sx - x;
    935  1.2   wiz 		}
    936  1.2   wiz 		log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
    937  1.2   wiz 		    __func__, c->name, wp->id, i, j, x, y, width);
    938  1.2   wiz 
    939  1.2   wiz 		tty_default_colours(&defaults, wp);
    940  1.2   wiz 		tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette);
    941  1.2   wiz 	}
    942  1.1  jmmv 
    943  1.2   wiz #ifdef ENABLE_SIXEL
    944  1.2   wiz 	tty_draw_images(c, wp, s);
    945  1.2   wiz #endif
    946  1.2   wiz }
    947  1.2   wiz 
    948  1.2   wiz /* Draw the panes scrollbars */
    949  1.2   wiz static void
    950  1.2   wiz screen_redraw_draw_pane_scrollbars(struct screen_redraw_ctx *ctx)
    951  1.2   wiz {
    952  1.2   wiz 	struct client		*c = ctx->c;
    953  1.2   wiz 	struct window		*w = c->session->curw->window;
    954  1.2   wiz 	struct window_pane	*wp;
    955  1.2   wiz 
    956  1.2   wiz 	log_debug("%s: %s @%u", __func__, c->name, w->id);
    957  1.2   wiz 
    958  1.2   wiz 	TAILQ_FOREACH(wp, &w->panes, entry) {
    959  1.2   wiz 		if (window_pane_show_scrollbar(wp, ctx->pane_scrollbars) &&
    960  1.2   wiz 		    window_pane_visible(wp))
    961  1.2   wiz 			screen_redraw_draw_pane_scrollbar(ctx, wp);
    962  1.1  jmmv 	}
    963  1.2   wiz }
    964  1.1  jmmv 
    965  1.2   wiz /* Draw pane scrollbar. */
    966  1.2   wiz void
    967  1.2   wiz screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *ctx,
    968  1.2   wiz     struct window_pane *wp)
    969  1.2   wiz {
    970  1.2   wiz 	struct screen	*s = wp->screen;
    971  1.2   wiz 	double		 percent_view;
    972  1.2   wiz 	u_int		 sb = ctx->pane_scrollbars, total_height, sb_h = wp->sy;
    973  1.2   wiz 	u_int		 sb_pos = ctx->pane_scrollbars_pos, slider_h, slider_y;
    974  1.2   wiz 	int		 sb_w = wp->scrollbar_style.width;
    975  1.2   wiz 	int		 sb_pad = wp->scrollbar_style.pad;
    976  1.2   wiz         u_int		 cm_y, cm_size;
    977  1.2   wiz         int		 xoff = wp->xoff, ox = ctx->ox;
    978  1.2   wiz 	int		 sb_x, sb_y = (int)(wp->yoff - ctx->oy); /* sb top */
    979  1.2   wiz 
    980  1.2   wiz 	if (window_pane_mode(wp) == WINDOW_PANE_NO_MODE) {
    981  1.2   wiz 		if (sb == PANE_SCROLLBARS_MODAL)
    982  1.2   wiz 			return;
    983  1.2   wiz 		/* Show slider at the bottom of the scrollbar. */
    984  1.2   wiz 		total_height = screen_size_y(s) + screen_hsize(s);
    985  1.2   wiz 		percent_view = (double)sb_h / total_height;
    986  1.2   wiz 		slider_h = (double)sb_h * percent_view;
    987  1.2   wiz 		slider_y = sb_h - slider_h;
    988  1.2   wiz 	} else {
    989  1.2   wiz 		if (TAILQ_FIRST(&wp->modes) == NULL)
    990  1.2   wiz 			return;
    991  1.2   wiz 		if (window_copy_get_current_offset(wp, &cm_y, &cm_size) == 0)
    992  1.2   wiz 			return;
    993  1.2   wiz 		total_height = cm_size + sb_h;
    994  1.2   wiz 		percent_view = (double)sb_h / (cm_size + sb_h);
    995  1.2   wiz 		slider_h = (double)sb_h * percent_view;
    996  1.2   wiz 		slider_y = (sb_h + 1) * ((double)cm_y / total_height);
    997  1.2   wiz 	}
    998  1.1  jmmv 
    999  1.2   wiz 	if (sb_pos == PANE_SCROLLBARS_LEFT)
   1000  1.2   wiz 		sb_x = xoff - sb_w - sb_pad - ox;
   1001  1.1  jmmv 	else
   1002  1.2   wiz 		sb_x = xoff + wp->sx - ox;
   1003  1.2   wiz 
   1004  1.2   wiz 	if (slider_h < 1)
   1005  1.2   wiz 		slider_h = 1;
   1006  1.2   wiz 	if (slider_y >= sb_h)
   1007  1.2   wiz 		slider_y = sb_h - 1;
   1008  1.2   wiz 
   1009  1.2   wiz 	screen_redraw_draw_scrollbar(ctx, wp, sb_pos, sb_x, sb_y, sb_h,
   1010  1.2   wiz 	    slider_h, slider_y);
   1011  1.2   wiz 
   1012  1.2   wiz 	/* Store current position and height of the slider */
   1013  1.2   wiz 	wp->sb_slider_y = slider_y;  /* top of slider y pos in scrollbar */
   1014  1.2   wiz 	wp->sb_slider_h = slider_h;  /* height of slider */
   1015  1.2   wiz }
   1016  1.2   wiz 
   1017  1.2   wiz static void
   1018  1.2   wiz screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
   1019  1.2   wiz     struct window_pane *wp, int sb_pos, int sb_x, int sb_y, u_int sb_h,
   1020  1.2   wiz     u_int slider_h, u_int slider_y)
   1021  1.2   wiz {
   1022  1.2   wiz 	struct client		*c = ctx->c;
   1023  1.2   wiz 	struct tty		*tty = &c->tty;
   1024  1.2   wiz 	struct grid_cell	 gc, slgc, *gcp;
   1025  1.2   wiz 	struct style		*sb_style = &wp->scrollbar_style;
   1026  1.2   wiz 	u_int			 i, j, imax, jmax;
   1027  1.2   wiz 	u_int			 sb_w = sb_style->width, sb_pad = sb_style->pad;
   1028  1.2   wiz 	int			 px, py, ox = ctx->ox, oy = ctx->oy;
   1029  1.2   wiz 	int			 sx = ctx->sx, sy = ctx->sy, xoff = wp->xoff;
   1030  1.2   wiz 	int			 yoff = wp->yoff;
   1031  1.2   wiz 
   1032  1.2   wiz 	if (ctx->statustop) {
   1033  1.2   wiz 		sb_y += ctx->statuslines;
   1034  1.2   wiz 		sy += ctx->statuslines;
   1035  1.2   wiz 	}
   1036  1.1  jmmv 
   1037  1.2   wiz 	/* Set up style for slider. */
   1038  1.2   wiz 	gc = sb_style->gc;
   1039  1.2   wiz 	memcpy(&slgc, &gc, sizeof slgc);
   1040  1.2   wiz 	slgc.fg = gc.bg;
   1041  1.2   wiz 	slgc.bg = gc.fg;
   1042  1.2   wiz 
   1043  1.2   wiz 	imax = sb_w + sb_pad;
   1044  1.2   wiz 	if ((int)imax + sb_x > sx)
   1045  1.2   wiz 		imax = sx - sb_x;
   1046  1.2   wiz 	jmax = sb_h;
   1047  1.2   wiz 	if ((int)jmax + sb_y > sy)
   1048  1.2   wiz 		jmax = sy - sb_y;
   1049  1.2   wiz 
   1050  1.2   wiz 	for (j = 0; j < jmax; j++) {
   1051  1.2   wiz 		py = sb_y + j;
   1052  1.2   wiz 		for (i = 0; i < imax; i++) {
   1053  1.2   wiz 			px = sb_x + i;
   1054  1.2   wiz 			if (px < xoff - ox - (int)sb_w - (int)sb_pad ||
   1055  1.2   wiz 			    px >= sx || px < 0 ||
   1056  1.2   wiz 			    py < yoff - oy - 1 ||
   1057  1.2   wiz 			    py >= sy || py < 0)
   1058  1.2   wiz 				continue;
   1059  1.2   wiz 			tty_cursor(tty, px, py);
   1060  1.2   wiz 			if ((sb_pos == PANE_SCROLLBARS_LEFT &&
   1061  1.2   wiz 			    i >= sb_w && i < sb_w + sb_pad) ||
   1062  1.2   wiz 			    (sb_pos == PANE_SCROLLBARS_RIGHT &&
   1063  1.2   wiz 			     i < sb_pad)) {
   1064  1.2   wiz 				tty_cell(tty, &grid_default_cell,
   1065  1.2   wiz 				    &grid_default_cell, NULL, NULL);
   1066  1.2   wiz 			} else {
   1067  1.2   wiz 				if (j >= slider_y && j < slider_y + slider_h)
   1068  1.2   wiz 					gcp = &slgc;
   1069  1.2   wiz 				else
   1070  1.2   wiz 					gcp = &gc;
   1071  1.2   wiz 				tty_cell(tty, gcp, &grid_default_cell, NULL,
   1072  1.2   wiz 				    NULL);
   1073  1.1  jmmv 			}
   1074  1.1  jmmv 		}
   1075  1.1  jmmv 	}
   1076  1.1  jmmv }
   1077