Home | History | Annotate | Line # | Download | only in dist
screen-redraw.c revision 1.1.1.15
      1   1.1.1.5  christos /* $OpenBSD$ */
      2       1.1      jmmv 
      3       1.1      jmmv /*
      4   1.1.1.6  christos  * 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.1.1.9  christos #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.1.1.9  christos static void	screen_redraw_draw_borders(struct screen_redraw_ctx *);
     27   1.1.1.9  christos static void	screen_redraw_draw_panes(struct screen_redraw_ctx *);
     28   1.1.1.9  christos static void	screen_redraw_draw_status(struct screen_redraw_ctx *);
     29  1.1.1.10  christos static void	screen_redraw_draw_pane(struct screen_redraw_ctx *,
     30  1.1.1.10  christos 		    struct window_pane *);
     31  1.1.1.12  christos static void	screen_redraw_set_context(struct client *,
     32  1.1.1.12  christos 		    struct screen_redraw_ctx *);
     33       1.1      jmmv 
     34  1.1.1.12  christos #define START_ISOLATE "\342\201\246"
     35  1.1.1.12  christos #define END_ISOLATE   "\342\201\251"
     36  1.1.1.12  christos 
     37  1.1.1.13       wiz /* Border in relation to a pane. */
     38  1.1.1.12  christos enum screen_redraw_border_type {
     39  1.1.1.12  christos 	SCREEN_REDRAW_OUTSIDE,
     40  1.1.1.12  christos 	SCREEN_REDRAW_INSIDE,
     41  1.1.1.13       wiz 	SCREEN_REDRAW_BORDER_LEFT,
     42  1.1.1.13       wiz 	SCREEN_REDRAW_BORDER_RIGHT,
     43  1.1.1.13       wiz 	SCREEN_REDRAW_BORDER_TOP,
     44  1.1.1.13       wiz 	SCREEN_REDRAW_BORDER_BOTTOM
     45  1.1.1.12  christos };
     46  1.1.1.13       wiz #define BORDER_MARKERS "  +,.-"
     47  1.1.1.12  christos 
     48  1.1.1.12  christos /* Get cell border character. */
     49  1.1.1.12  christos static void
     50  1.1.1.13       wiz screen_redraw_border_set(struct window *w, struct window_pane *wp,
     51  1.1.1.13       wiz     enum pane_lines pane_lines, int cell_type, struct grid_cell *gc)
     52  1.1.1.12  christos {
     53  1.1.1.12  christos 	u_int	idx;
     54  1.1.1.12  christos 
     55  1.1.1.13       wiz 	if (cell_type == CELL_OUTSIDE && w->fill_character != NULL) {
     56  1.1.1.13       wiz 		utf8_copy(&gc->data, &w->fill_character[0]);
     57  1.1.1.13       wiz 		return;
     58  1.1.1.13       wiz 	}
     59  1.1.1.13       wiz 
     60  1.1.1.12  christos 	switch (pane_lines) {
     61  1.1.1.12  christos 	case PANE_LINES_NUMBER:
     62  1.1.1.12  christos 		if (cell_type == CELL_OUTSIDE) {
     63  1.1.1.12  christos 			gc->attr |= GRID_ATTR_CHARSET;
     64  1.1.1.12  christos 			utf8_set(&gc->data, CELL_BORDERS[CELL_OUTSIDE]);
     65  1.1.1.12  christos 			break;
     66  1.1.1.12  christos 		}
     67  1.1.1.12  christos 		gc->attr &= ~GRID_ATTR_CHARSET;
     68  1.1.1.12  christos 		if (wp != NULL && window_pane_index(wp, &idx) == 0)
     69  1.1.1.12  christos 			utf8_set(&gc->data, '0' + (idx % 10));
     70  1.1.1.12  christos 		else
     71  1.1.1.12  christos 			utf8_set(&gc->data, '*');
     72  1.1.1.12  christos 		break;
     73  1.1.1.12  christos 	case PANE_LINES_DOUBLE:
     74  1.1.1.12  christos 		gc->attr &= ~GRID_ATTR_CHARSET;
     75  1.1.1.13       wiz 		utf8_copy(&gc->data, tty_acs_double_borders(cell_type));
     76  1.1.1.12  christos 		break;
     77  1.1.1.12  christos 	case PANE_LINES_HEAVY:
     78  1.1.1.12  christos 		gc->attr &= ~GRID_ATTR_CHARSET;
     79  1.1.1.13       wiz 		utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
     80  1.1.1.12  christos 		break;
     81  1.1.1.12  christos 	case PANE_LINES_SIMPLE:
     82  1.1.1.12  christos 		gc->attr &= ~GRID_ATTR_CHARSET;
     83  1.1.1.13       wiz 		utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
     84  1.1.1.12  christos 		break;
     85  1.1.1.12  christos 	default:
     86  1.1.1.12  christos 		gc->attr |= GRID_ATTR_CHARSET;
     87  1.1.1.12  christos 		utf8_set(&gc->data, CELL_BORDERS[cell_type]);
     88  1.1.1.12  christos 		break;
     89  1.1.1.12  christos 	}
     90  1.1.1.12  christos }
     91  1.1.1.12  christos 
     92  1.1.1.12  christos /* Return if window has only two panes. */
     93   1.1.1.7  christos static int
     94  1.1.1.12  christos screen_redraw_two_panes(struct window *w, int direction)
     95       1.1      jmmv {
     96  1.1.1.12  christos 	struct window_pane	*wp;
     97  1.1.1.12  christos 
     98  1.1.1.12  christos 	wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
     99  1.1.1.12  christos 	if (wp == NULL)
    100  1.1.1.12  christos 		return (0); /* one pane */
    101  1.1.1.12  christos 	if (TAILQ_NEXT(wp, entry) != NULL)
    102  1.1.1.12  christos 		return (0); /* more than two panes */
    103  1.1.1.12  christos 	if (direction == 0 && wp->xoff == 0)
    104  1.1.1.12  christos 		return (0);
    105  1.1.1.12  christos 	if (direction == 1 && wp->yoff == 0)
    106       1.1      jmmv 		return (0);
    107  1.1.1.12  christos 	return (1);
    108  1.1.1.12  christos }
    109  1.1.1.12  christos 
    110  1.1.1.12  christos /* Check if cell is on the border of a pane. */
    111  1.1.1.12  christos static enum screen_redraw_border_type
    112  1.1.1.15       wiz screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
    113  1.1.1.15       wiz     u_int px, u_int py)
    114  1.1.1.12  christos {
    115  1.1.1.13       wiz 	struct options	*oo = wp->window->options;
    116  1.1.1.13       wiz 	int		 split = 0;
    117  1.1.1.15       wiz 	u_int		 ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
    118  1.1.1.15       wiz 	int		 pane_status = ctx->pane_status;
    119  1.1.1.12  christos 
    120  1.1.1.12  christos 	/* Inside pane. */
    121  1.1.1.12  christos 	if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
    122  1.1.1.12  christos 		return (SCREEN_REDRAW_INSIDE);
    123       1.1      jmmv 
    124  1.1.1.13       wiz 	/* Get pane indicator. */
    125  1.1.1.13       wiz 	switch (options_get_number(oo, "pane-border-indicators")) {
    126  1.1.1.13       wiz 	case PANE_BORDER_COLOUR:
    127  1.1.1.13       wiz 	case PANE_BORDER_BOTH:
    128  1.1.1.13       wiz 		split = 1;
    129  1.1.1.13       wiz 		break;
    130  1.1.1.13       wiz 	}
    131  1.1.1.13       wiz 
    132       1.1      jmmv 	/* Left/right borders. */
    133  1.1.1.12  christos 	if (pane_status == PANE_STATUS_OFF) {
    134  1.1.1.13       wiz 		if (screen_redraw_two_panes(wp->window, 0) && split) {
    135  1.1.1.12  christos 			if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2)
    136  1.1.1.13       wiz 				return (SCREEN_REDRAW_BORDER_RIGHT);
    137  1.1.1.12  christos 			if (wp->xoff != 0 &&
    138  1.1.1.12  christos 			    px == wp->xoff - 1 &&
    139  1.1.1.12  christos 			    py > wp->sy / 2)
    140  1.1.1.13       wiz 				return (SCREEN_REDRAW_BORDER_LEFT);
    141  1.1.1.12  christos 		} else {
    142  1.1.1.12  christos 			if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
    143  1.1.1.12  christos 				if (wp->xoff != 0 && px == wp->xoff - 1)
    144  1.1.1.13       wiz 					return (SCREEN_REDRAW_BORDER_LEFT);
    145  1.1.1.12  christos 				if (px == ex)
    146  1.1.1.13       wiz 					return (SCREEN_REDRAW_BORDER_RIGHT);
    147  1.1.1.12  christos 			}
    148  1.1.1.12  christos 		}
    149  1.1.1.12  christos 	} else {
    150  1.1.1.12  christos 		if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
    151  1.1.1.12  christos 			if (wp->xoff != 0 && px == wp->xoff - 1)
    152  1.1.1.13       wiz 				return (SCREEN_REDRAW_BORDER_LEFT);
    153  1.1.1.12  christos 			if (px == ex)
    154  1.1.1.13       wiz 				return (SCREEN_REDRAW_BORDER_RIGHT);
    155  1.1.1.12  christos 		}
    156       1.1      jmmv 	}
    157       1.1      jmmv 
    158       1.1      jmmv 	/* Top/bottom borders. */
    159  1.1.1.12  christos 	if (pane_status == PANE_STATUS_OFF) {
    160  1.1.1.13       wiz 		if (screen_redraw_two_panes(wp->window, 1) && split) {
    161  1.1.1.12  christos 			if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
    162  1.1.1.13       wiz 				return (SCREEN_REDRAW_BORDER_BOTTOM);
    163  1.1.1.12  christos 			if (wp->yoff != 0 &&
    164  1.1.1.12  christos 			    py == wp->yoff - 1 &&
    165  1.1.1.12  christos 			    px > wp->sx / 2)
    166  1.1.1.13       wiz 				return (SCREEN_REDRAW_BORDER_TOP);
    167  1.1.1.12  christos 		} else {
    168  1.1.1.12  christos 			if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
    169  1.1.1.12  christos 				if (wp->yoff != 0 && py == wp->yoff - 1)
    170  1.1.1.13       wiz 					return (SCREEN_REDRAW_BORDER_TOP);
    171  1.1.1.12  christos 				if (py == ey)
    172  1.1.1.13       wiz 					return (SCREEN_REDRAW_BORDER_BOTTOM);
    173  1.1.1.12  christos 			}
    174  1.1.1.12  christos 		}
    175  1.1.1.12  christos 	} else if (pane_status == PANE_STATUS_TOP) {
    176  1.1.1.12  christos 		if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
    177  1.1.1.12  christos 			if (wp->yoff != 0 && py == wp->yoff - 1)
    178  1.1.1.13       wiz 				return (SCREEN_REDRAW_BORDER_TOP);
    179  1.1.1.12  christos 		}
    180  1.1.1.12  christos 	} else {
    181  1.1.1.12  christos 		if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
    182  1.1.1.12  christos 			if (py == ey)
    183  1.1.1.13       wiz 				return (SCREEN_REDRAW_BORDER_BOTTOM);
    184  1.1.1.12  christos 		}
    185       1.1      jmmv 	}
    186       1.1      jmmv 
    187       1.1      jmmv 	/* Outside pane. */
    188  1.1.1.12  christos 	return (SCREEN_REDRAW_OUTSIDE);
    189       1.1      jmmv }
    190       1.1      jmmv 
    191  1.1.1.12  christos /* Check if a cell is on a border. */
    192   1.1.1.7  christos static int
    193  1.1.1.15       wiz screen_redraw_cell_border(struct screen_redraw_ctx *ctx, u_int px, u_int py)
    194       1.1      jmmv {
    195  1.1.1.15       wiz 	struct client		*c = ctx->c;
    196       1.1      jmmv 	struct window		*w = c->session->curw->window;
    197       1.1      jmmv 	struct window_pane	*wp;
    198  1.1.1.12  christos 
    199  1.1.1.12  christos 	/* Outside the window? */
    200  1.1.1.12  christos 	if (px > w->sx || py > w->sy)
    201  1.1.1.12  christos 		return (0);
    202  1.1.1.12  christos 
    203  1.1.1.12  christos 	/* On the window border? */
    204  1.1.1.12  christos 	if (px == w->sx || py == w->sy)
    205  1.1.1.12  christos 		return (1);
    206       1.1      jmmv 
    207       1.1      jmmv 	/* Check all the panes. */
    208       1.1      jmmv 	TAILQ_FOREACH(wp, &w->panes, entry) {
    209       1.1      jmmv 		if (!window_pane_visible(wp))
    210       1.1      jmmv 			continue;
    211  1.1.1.15       wiz 		switch (screen_redraw_pane_border(ctx, wp, px, py)) {
    212  1.1.1.12  christos 		case SCREEN_REDRAW_INSIDE:
    213  1.1.1.12  christos 			return (0);
    214  1.1.1.12  christos 		case SCREEN_REDRAW_OUTSIDE:
    215  1.1.1.12  christos 			break;
    216  1.1.1.13       wiz 		default:
    217  1.1.1.13       wiz 			return (1);
    218  1.1.1.12  christos 		}
    219       1.1      jmmv 	}
    220       1.1      jmmv 
    221       1.1      jmmv 	return (0);
    222       1.1      jmmv }
    223       1.1      jmmv 
    224  1.1.1.12  christos /* Work out type of border cell from surrounding cells. */
    225  1.1.1.12  christos static int
    226  1.1.1.15       wiz screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py)
    227  1.1.1.12  christos {
    228  1.1.1.15       wiz 	struct client	*c = ctx->c;
    229  1.1.1.15       wiz 	int		 pane_status = ctx->pane_status;
    230  1.1.1.12  christos 	struct window	*w = c->session->curw->window;
    231  1.1.1.12  christos 	u_int		 sx = w->sx, sy = w->sy;
    232  1.1.1.12  christos 	int		 borders = 0;
    233  1.1.1.12  christos 
    234  1.1.1.12  christos 	/* Is this outside the window? */
    235  1.1.1.12  christos 	if (px > sx || py > sy)
    236  1.1.1.12  christos 		return (CELL_OUTSIDE);
    237  1.1.1.12  christos 
    238  1.1.1.12  christos 	/*
    239  1.1.1.12  christos 	 * Construct a bitmask of whether the cells to the left (bit 4), right,
    240  1.1.1.12  christos 	 * top, and bottom (bit 1) of this cell are borders.
    241  1.1.1.12  christos 	 */
    242  1.1.1.15       wiz 	if (px == 0 || screen_redraw_cell_border(ctx, px - 1, py))
    243  1.1.1.12  christos 		borders |= 8;
    244  1.1.1.15       wiz 	if (px <= sx && screen_redraw_cell_border(ctx, px + 1, py))
    245  1.1.1.12  christos 		borders |= 4;
    246  1.1.1.12  christos 	if (pane_status == PANE_STATUS_TOP) {
    247  1.1.1.12  christos 		if (py != 0 &&
    248  1.1.1.15       wiz 		    screen_redraw_cell_border(ctx, px, py - 1))
    249  1.1.1.12  christos 			borders |= 2;
    250  1.1.1.15       wiz 		if (screen_redraw_cell_border(ctx, px, py + 1))
    251  1.1.1.12  christos 			borders |= 1;
    252  1.1.1.12  christos 	} else if (pane_status == PANE_STATUS_BOTTOM) {
    253  1.1.1.12  christos 		if (py == 0 ||
    254  1.1.1.15       wiz 		    screen_redraw_cell_border(ctx, px, py - 1))
    255  1.1.1.12  christos 			borders |= 2;
    256  1.1.1.12  christos 		if (py != sy - 1 &&
    257  1.1.1.15       wiz 		    screen_redraw_cell_border(ctx, px, py + 1))
    258  1.1.1.12  christos 			borders |= 1;
    259  1.1.1.12  christos 	} else {
    260  1.1.1.12  christos 		if (py == 0 ||
    261  1.1.1.15       wiz 		    screen_redraw_cell_border(ctx, px, py - 1))
    262  1.1.1.12  christos 			borders |= 2;
    263  1.1.1.15       wiz 		if (screen_redraw_cell_border(ctx, px, py + 1))
    264  1.1.1.12  christos 			borders |= 1;
    265  1.1.1.12  christos 	}
    266  1.1.1.12  christos 
    267  1.1.1.12  christos 	/*
    268  1.1.1.12  christos 	 * Figure out what kind of border this cell is. Only one bit set
    269  1.1.1.12  christos 	 * doesn't make sense (can't have a border cell with no others
    270  1.1.1.12  christos 	 * connected).
    271  1.1.1.12  christos 	 */
    272  1.1.1.12  christos 	switch (borders) {
    273  1.1.1.12  christos 	case 15:	/* 1111, left right top bottom */
    274  1.1.1.12  christos 		return (CELL_JOIN);
    275  1.1.1.12  christos 	case 14:	/* 1110, left right top */
    276  1.1.1.12  christos 		return (CELL_BOTTOMJOIN);
    277  1.1.1.12  christos 	case 13:	/* 1101, left right bottom */
    278  1.1.1.12  christos 		return (CELL_TOPJOIN);
    279  1.1.1.12  christos 	case 12:	/* 1100, left right */
    280  1.1.1.12  christos 		return (CELL_LEFTRIGHT);
    281  1.1.1.12  christos 	case 11:	/* 1011, left top bottom */
    282  1.1.1.12  christos 		return (CELL_RIGHTJOIN);
    283  1.1.1.12  christos 	case 10:	/* 1010, left top */
    284  1.1.1.12  christos 		return (CELL_BOTTOMRIGHT);
    285  1.1.1.12  christos 	case 9:		/* 1001, left bottom */
    286  1.1.1.12  christos 		return (CELL_TOPRIGHT);
    287  1.1.1.12  christos 	case 7:		/* 0111, right top bottom */
    288  1.1.1.12  christos 		return (CELL_LEFTJOIN);
    289  1.1.1.12  christos 	case 6:		/* 0110, right top */
    290  1.1.1.12  christos 		return (CELL_BOTTOMLEFT);
    291  1.1.1.12  christos 	case 5:		/* 0101, right bottom */
    292  1.1.1.12  christos 		return (CELL_TOPLEFT);
    293  1.1.1.12  christos 	case 3:		/* 0011, top bottom */
    294  1.1.1.12  christos 		return (CELL_TOPBOTTOM);
    295  1.1.1.12  christos 	}
    296  1.1.1.12  christos 	return (CELL_OUTSIDE);
    297  1.1.1.12  christos }
    298  1.1.1.12  christos 
    299       1.1      jmmv /* Check if cell inside a pane. */
    300   1.1.1.7  christos static int
    301  1.1.1.15       wiz screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
    302   1.1.1.3  christos     struct window_pane **wpp)
    303       1.1      jmmv {
    304  1.1.1.15       wiz 	struct client		*c = ctx->c;
    305       1.1      jmmv 	struct window		*w = c->session->curw->window;
    306  1.1.1.12  christos 	struct window_pane	*wp, *active;
    307  1.1.1.15       wiz 	int			 pane_status = ctx->pane_status;
    308  1.1.1.12  christos 	int			 border;
    309   1.1.1.7  christos 	u_int			 right, line;
    310   1.1.1.7  christos 
    311   1.1.1.7  christos 	*wpp = NULL;
    312       1.1      jmmv 
    313       1.1      jmmv 	if (px > w->sx || py > w->sy)
    314       1.1      jmmv 		return (CELL_OUTSIDE);
    315  1.1.1.12  christos 	if (px == w->sx || py == w->sy) /* window border */
    316  1.1.1.15       wiz 		return (screen_redraw_type_of_cell(ctx, px, py));
    317       1.1      jmmv 
    318  1.1.1.11  christos 	if (pane_status != PANE_STATUS_OFF) {
    319  1.1.1.12  christos 		active = wp = server_client_get_pane(c);
    320  1.1.1.12  christos 		do {
    321   1.1.1.7  christos 			if (!window_pane_visible(wp))
    322  1.1.1.12  christos 				goto next1;
    323   1.1.1.7  christos 
    324  1.1.1.11  christos 			if (pane_status == PANE_STATUS_TOP)
    325   1.1.1.7  christos 				line = wp->yoff - 1;
    326   1.1.1.7  christos 			else
    327   1.1.1.7  christos 				line = wp->yoff + wp->sy;
    328   1.1.1.7  christos 			right = wp->xoff + 2 + wp->status_size - 1;
    329   1.1.1.7  christos 
    330   1.1.1.7  christos 			if (py == line && px >= wp->xoff + 2 && px <= right)
    331   1.1.1.7  christos 				return (CELL_INSIDE);
    332  1.1.1.12  christos 
    333  1.1.1.12  christos 		next1:
    334  1.1.1.12  christos 			wp = TAILQ_NEXT(wp, entry);
    335  1.1.1.12  christos 			if (wp == NULL)
    336  1.1.1.12  christos 				wp = TAILQ_FIRST(&w->panes);
    337  1.1.1.12  christos 		} while (wp != active);
    338   1.1.1.7  christos 	}
    339   1.1.1.7  christos 
    340  1.1.1.12  christos 	active = wp = server_client_get_pane(c);
    341  1.1.1.12  christos 	do {
    342       1.1      jmmv 		if (!window_pane_visible(wp))
    343  1.1.1.12  christos 			goto next2;
    344   1.1.1.3  christos 		*wpp = wp;
    345       1.1      jmmv 
    346       1.1      jmmv 		/*
    347  1.1.1.12  christos 		 * If definitely inside, return. If not on border, skip.
    348  1.1.1.12  christos 		 * Otherwise work out the cell.
    349       1.1      jmmv 		 */
    350  1.1.1.15       wiz 		border = screen_redraw_pane_border(ctx, wp, px, py);
    351  1.1.1.12  christos 		if (border == SCREEN_REDRAW_INSIDE)
    352  1.1.1.12  christos 			return (CELL_INSIDE);
    353  1.1.1.12  christos 		if (border == SCREEN_REDRAW_OUTSIDE)
    354  1.1.1.12  christos 			goto next2;
    355  1.1.1.15       wiz 		return (screen_redraw_type_of_cell(ctx, px, py));
    356  1.1.1.12  christos 
    357  1.1.1.12  christos 	next2:
    358  1.1.1.12  christos 		wp = TAILQ_NEXT(wp, entry);
    359  1.1.1.12  christos 		if (wp == NULL)
    360  1.1.1.12  christos 			wp = TAILQ_FIRST(&w->panes);
    361  1.1.1.12  christos 	} while (wp != active);
    362       1.1      jmmv 
    363       1.1      jmmv 	return (CELL_OUTSIDE);
    364       1.1      jmmv }
    365       1.1      jmmv 
    366   1.1.1.5  christos /* Check if the border of a particular pane. */
    367   1.1.1.7  christos static int
    368  1.1.1.15       wiz screen_redraw_check_is(struct screen_redraw_ctx *ctx, u_int px, u_int py,
    369  1.1.1.12  christos     struct window_pane *wp)
    370   1.1.1.3  christos {
    371  1.1.1.12  christos 	enum screen_redraw_border_type	border;
    372   1.1.1.3  christos 
    373  1.1.1.15       wiz 	border = screen_redraw_pane_border(ctx, wp, px, py);
    374  1.1.1.13       wiz 	if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE)
    375   1.1.1.3  christos 		return (1);
    376  1.1.1.12  christos 	return (0);
    377   1.1.1.7  christos }
    378   1.1.1.7  christos 
    379   1.1.1.7  christos /* Update pane status. */
    380   1.1.1.7  christos static int
    381  1.1.1.12  christos screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
    382  1.1.1.13       wiz     struct screen_redraw_ctx *rctx, enum pane_lines pane_lines)
    383   1.1.1.7  christos {
    384  1.1.1.12  christos 	struct window		*w = wp->window;
    385   1.1.1.7  christos 	struct grid_cell	 gc;
    386   1.1.1.7  christos 	const char		*fmt;
    387   1.1.1.7  christos 	struct format_tree	*ft;
    388  1.1.1.10  christos 	char			*expanded;
    389  1.1.1.12  christos 	int			 pane_status = rctx->pane_status;
    390  1.1.1.12  christos 	u_int			 width, i, cell_type, px, py;
    391   1.1.1.7  christos 	struct screen_write_ctx	 ctx;
    392   1.1.1.7  christos 	struct screen		 old;
    393   1.1.1.7  christos 
    394  1.1.1.12  christos 	ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
    395  1.1.1.12  christos 	format_defaults(ft, c, c->session, c->session->curw, wp);
    396   1.1.1.7  christos 
    397  1.1.1.12  christos 	if (wp == server_client_get_pane(c))
    398  1.1.1.12  christos 		style_apply(&gc, w->options, "pane-active-border-style", ft);
    399  1.1.1.12  christos 	else
    400  1.1.1.12  christos 		style_apply(&gc, w->options, "pane-border-style", ft);
    401  1.1.1.13       wiz 	fmt = options_get_string(wp->options, "pane-border-format");
    402   1.1.1.7  christos 
    403  1.1.1.10  christos 	expanded = format_expand_time(ft, fmt);
    404  1.1.1.10  christos 	if (wp->sx < 4)
    405  1.1.1.10  christos 		wp->status_size = width = 0;
    406  1.1.1.10  christos 	else
    407  1.1.1.10  christos 		wp->status_size = width = wp->sx - 4;
    408  1.1.1.10  christos 
    409   1.1.1.7  christos 	memcpy(&old, &wp->status_screen, sizeof old);
    410  1.1.1.10  christos 	screen_init(&wp->status_screen, width, 1, 0);
    411   1.1.1.7  christos 	wp->status_screen.mode = 0;
    412   1.1.1.7  christos 
    413  1.1.1.12  christos 	screen_write_start(&ctx, &wp->status_screen);
    414  1.1.1.10  christos 
    415  1.1.1.12  christos 	for (i = 0; i < width; i++) {
    416  1.1.1.12  christos 		px = wp->xoff + 2 + i;
    417  1.1.1.15       wiz 		if (pane_status == PANE_STATUS_TOP)
    418  1.1.1.12  christos 			py = wp->yoff - 1;
    419  1.1.1.12  christos 		else
    420  1.1.1.12  christos 			py = wp->yoff + wp->sy;
    421  1.1.1.15       wiz 		cell_type = screen_redraw_type_of_cell(rctx, px, py);
    422  1.1.1.13       wiz 		screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc);
    423  1.1.1.12  christos 		screen_write_cell(&ctx, &gc);
    424  1.1.1.12  christos 	}
    425  1.1.1.10  christos 	gc.attr &= ~GRID_ATTR_CHARSET;
    426  1.1.1.10  christos 
    427  1.1.1.10  christos 	screen_write_cursormove(&ctx, 0, 0, 0);
    428  1.1.1.13       wiz 	format_draw(&ctx, &gc, width, expanded, NULL, 0);
    429   1.1.1.7  christos 	screen_write_stop(&ctx);
    430   1.1.1.7  christos 
    431  1.1.1.10  christos 	free(expanded);
    432   1.1.1.7  christos 	format_free(ft);
    433   1.1.1.7  christos 
    434   1.1.1.7  christos 	if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
    435   1.1.1.7  christos 		screen_free(&old);
    436   1.1.1.7  christos 		return (0);
    437   1.1.1.7  christos 	}
    438   1.1.1.7  christos 	screen_free(&old);
    439   1.1.1.7  christos 	return (1);
    440   1.1.1.7  christos }
    441   1.1.1.7  christos 
    442   1.1.1.7  christos /* Draw pane status. */
    443   1.1.1.7  christos static void
    444  1.1.1.10  christos screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
    445   1.1.1.7  christos {
    446  1.1.1.10  christos 	struct client		*c = ctx->c;
    447   1.1.1.7  christos 	struct window		*w = c->session->curw->window;
    448   1.1.1.7  christos 	struct tty		*tty = &c->tty;
    449   1.1.1.7  christos 	struct window_pane	*wp;
    450  1.1.1.10  christos 	struct screen		*s;
    451  1.1.1.10  christos 	u_int			 i, x, width, xoff, yoff, size;
    452  1.1.1.10  christos 
    453  1.1.1.10  christos 	log_debug("%s: %s @%u", __func__, c->name, w->id);
    454   1.1.1.7  christos 
    455   1.1.1.7  christos 	TAILQ_FOREACH(wp, &w->panes, entry) {
    456   1.1.1.7  christos 		if (!window_pane_visible(wp))
    457   1.1.1.7  christos 			continue;
    458  1.1.1.10  christos 		s = &wp->status_screen;
    459  1.1.1.10  christos 
    460  1.1.1.10  christos 		size = wp->status_size;
    461  1.1.1.11  christos 		if (ctx->pane_status == PANE_STATUS_TOP)
    462   1.1.1.7  christos 			yoff = wp->yoff - 1;
    463   1.1.1.7  christos 		else
    464   1.1.1.7  christos 			yoff = wp->yoff + wp->sy;
    465  1.1.1.10  christos 		xoff = wp->xoff + 2;
    466  1.1.1.10  christos 
    467  1.1.1.10  christos 		if (xoff + size <= ctx->ox ||
    468  1.1.1.10  christos 		    xoff >= ctx->ox + ctx->sx ||
    469  1.1.1.10  christos 		    yoff < ctx->oy ||
    470  1.1.1.10  christos 		    yoff >= ctx->oy + ctx->sy)
    471  1.1.1.10  christos 			continue;
    472   1.1.1.7  christos 
    473  1.1.1.10  christos 		if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) {
    474  1.1.1.10  christos 			/* All visible. */
    475  1.1.1.10  christos 			i = 0;
    476  1.1.1.10  christos 			x = xoff - ctx->ox;
    477  1.1.1.10  christos 			width = size;
    478  1.1.1.10  christos 		} else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) {
    479  1.1.1.10  christos 			/* Both left and right not visible. */
    480  1.1.1.10  christos 			i = ctx->ox;
    481  1.1.1.10  christos 			x = 0;
    482  1.1.1.10  christos 			width = ctx->sx;
    483  1.1.1.10  christos 		} else if (xoff < ctx->ox) {
    484  1.1.1.10  christos 			/* Left not visible. */
    485  1.1.1.10  christos 			i = ctx->ox - xoff;
    486  1.1.1.10  christos 			x = 0;
    487  1.1.1.10  christos 			width = size - i;
    488  1.1.1.10  christos 		} else {
    489  1.1.1.10  christos 			/* Right not visible. */
    490  1.1.1.10  christos 			i = 0;
    491  1.1.1.10  christos 			x = xoff - ctx->ox;
    492  1.1.1.10  christos 			width = size - x;
    493  1.1.1.10  christos 		}
    494  1.1.1.10  christos 
    495  1.1.1.11  christos 		if (ctx->statustop)
    496  1.1.1.11  christos 			yoff += ctx->statuslines;
    497  1.1.1.12  christos 		tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy,
    498  1.1.1.12  christos 		    &grid_default_cell, NULL);
    499   1.1.1.7  christos 	}
    500   1.1.1.7  christos 	tty_cursor(tty, 0, 0);
    501   1.1.1.7  christos }
    502   1.1.1.7  christos 
    503   1.1.1.7  christos /* Update status line and change flags if unchanged. */
    504  1.1.1.15       wiz static uint64_t
    505  1.1.1.15       wiz screen_redraw_update(struct client *c, uint64_t flags)
    506   1.1.1.7  christos {
    507  1.1.1.13       wiz 	struct window			*w = c->session->curw->window;
    508  1.1.1.13       wiz 	struct window_pane		*wp;
    509  1.1.1.13       wiz 	struct options			*wo = w->options;
    510  1.1.1.13       wiz 	int				 redraw;
    511  1.1.1.13       wiz 	enum pane_lines			 lines;
    512  1.1.1.13       wiz 	struct screen_redraw_ctx	 ctx;
    513   1.1.1.7  christos 
    514   1.1.1.7  christos 	if (c->message_string != NULL)
    515   1.1.1.7  christos 		redraw = status_message_redraw(c);
    516   1.1.1.7  christos 	else if (c->prompt_string != NULL)
    517   1.1.1.7  christos 		redraw = status_prompt_redraw(c);
    518   1.1.1.7  christos 	else
    519   1.1.1.7  christos 		redraw = status_redraw(c);
    520  1.1.1.10  christos 	if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS))
    521  1.1.1.10  christos 		flags &= ~CLIENT_REDRAWSTATUS;
    522   1.1.1.7  christos 
    523  1.1.1.11  christos 	if (c->overlay_draw != NULL)
    524  1.1.1.11  christos 		flags |= CLIENT_REDRAWOVERLAY;
    525  1.1.1.11  christos 
    526  1.1.1.11  christos 	if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) {
    527  1.1.1.12  christos 		screen_redraw_set_context(c, &ctx);
    528  1.1.1.12  christos 		lines = options_get_number(wo, "pane-border-lines");
    529   1.1.1.7  christos 		redraw = 0;
    530   1.1.1.7  christos 		TAILQ_FOREACH(wp, &w->panes, entry) {
    531  1.1.1.12  christos 			if (screen_redraw_make_pane_status(c, wp, &ctx, lines))
    532   1.1.1.7  christos 				redraw = 1;
    533   1.1.1.7  christos 		}
    534   1.1.1.7  christos 		if (redraw)
    535  1.1.1.10  christos 			flags |= CLIENT_REDRAWBORDERS;
    536   1.1.1.7  christos 	}
    537  1.1.1.10  christos 	return (flags);
    538   1.1.1.3  christos }
    539   1.1.1.3  christos 
    540  1.1.1.10  christos /* Set up redraw context. */
    541  1.1.1.10  christos static void
    542  1.1.1.10  christos screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
    543       1.1      jmmv {
    544  1.1.1.10  christos 	struct session	*s = c->session;
    545  1.1.1.10  christos 	struct options	*oo = s->options;
    546  1.1.1.10  christos 	struct window	*w = s->curw->window;
    547  1.1.1.10  christos 	struct options	*wo = w->options;
    548  1.1.1.11  christos 	u_int		 lines;
    549   1.1.1.2      jmmv 
    550  1.1.1.10  christos 	memset(ctx, 0, sizeof *ctx);
    551  1.1.1.10  christos 	ctx->c = c;
    552   1.1.1.9  christos 
    553  1.1.1.11  christos 	lines = status_line_size(c);
    554   1.1.1.9  christos 	if (c->message_string != NULL || c->prompt_string != NULL)
    555  1.1.1.11  christos 		lines = (lines == 0) ? 1 : lines;
    556  1.1.1.11  christos 	if (lines != 0 && options_get_number(oo, "status-position") == 0)
    557  1.1.1.11  christos 		ctx->statustop = 1;
    558  1.1.1.11  christos 	ctx->statuslines = lines;
    559  1.1.1.11  christos 
    560  1.1.1.10  christos 	ctx->pane_status = options_get_number(wo, "pane-border-status");
    561  1.1.1.12  christos 	ctx->pane_lines = options_get_number(wo, "pane-border-lines");
    562   1.1.1.9  christos 
    563  1.1.1.10  christos 	tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
    564  1.1.1.10  christos 
    565  1.1.1.10  christos 	log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
    566  1.1.1.11  christos 	    w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines,
    567  1.1.1.11  christos 	    ctx->statustop);
    568  1.1.1.10  christos }
    569  1.1.1.10  christos 
    570  1.1.1.10  christos /* Redraw entire screen. */
    571  1.1.1.10  christos void
    572  1.1.1.10  christos screen_redraw_screen(struct client *c)
    573  1.1.1.10  christos {
    574  1.1.1.10  christos 	struct screen_redraw_ctx	ctx;
    575  1.1.1.15       wiz 	uint64_t			flags;
    576   1.1.1.9  christos 
    577  1.1.1.10  christos 	if (c->flags & CLIENT_SUSPENDED)
    578  1.1.1.10  christos 		return;
    579   1.1.1.9  christos 
    580  1.1.1.10  christos 	flags = screen_redraw_update(c, c->flags);
    581  1.1.1.12  christos 	if ((flags & CLIENT_ALLREDRAWFLAGS) == 0)
    582  1.1.1.12  christos 		return;
    583  1.1.1.12  christos 
    584  1.1.1.10  christos 	screen_redraw_set_context(c, &ctx);
    585  1.1.1.12  christos 	tty_sync_start(&c->tty);
    586  1.1.1.12  christos 	tty_update_mode(&c->tty, c->tty.mode, NULL);
    587   1.1.1.3  christos 
    588  1.1.1.10  christos 	if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
    589  1.1.1.12  christos 		log_debug("%s: redrawing borders", c->name);
    590  1.1.1.11  christos 		if (ctx.pane_status != PANE_STATUS_OFF)
    591  1.1.1.10  christos 			screen_redraw_draw_pane_status(&ctx);
    592   1.1.1.9  christos 		screen_redraw_draw_borders(&ctx);
    593   1.1.1.7  christos 	}
    594  1.1.1.12  christos 	if (flags & CLIENT_REDRAWWINDOW) {
    595  1.1.1.12  christos 		log_debug("%s: redrawing panes", c->name);
    596   1.1.1.9  christos 		screen_redraw_draw_panes(&ctx);
    597  1.1.1.12  christos 	}
    598  1.1.1.11  christos 	if (ctx.statuslines != 0 &&
    599  1.1.1.12  christos 	    (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) {
    600  1.1.1.12  christos 		log_debug("%s: redrawing status", c->name);
    601   1.1.1.9  christos 		screen_redraw_draw_status(&ctx);
    602  1.1.1.12  christos 	}
    603  1.1.1.12  christos 	if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
    604  1.1.1.12  christos 		log_debug("%s: redrawing overlay", c->name);
    605  1.1.1.13       wiz 		c->overlay_draw(c, c->overlay_data, &ctx);
    606  1.1.1.12  christos 	}
    607  1.1.1.12  christos 
    608  1.1.1.10  christos 	tty_reset(&c->tty);
    609   1.1.1.3  christos }
    610       1.1      jmmv 
    611  1.1.1.10  christos /* Redraw a single pane. */
    612   1.1.1.3  christos void
    613   1.1.1.3  christos screen_redraw_pane(struct client *c, struct window_pane *wp)
    614   1.1.1.3  christos {
    615  1.1.1.10  christos 	struct screen_redraw_ctx	 ctx;
    616   1.1.1.3  christos 
    617  1.1.1.13       wiz 	if (!window_pane_visible(wp))
    618       1.1      jmmv 		return;
    619       1.1      jmmv 
    620  1.1.1.10  christos 	screen_redraw_set_context(c, &ctx);
    621  1.1.1.12  christos 	tty_sync_start(&c->tty);
    622  1.1.1.12  christos 	tty_update_mode(&c->tty, c->tty.mode, NULL);
    623   1.1.1.7  christos 
    624  1.1.1.10  christos 	screen_redraw_draw_pane(&ctx, wp);
    625  1.1.1.12  christos 
    626   1.1.1.3  christos 	tty_reset(&c->tty);
    627   1.1.1.3  christos }
    628   1.1.1.3  christos 
    629  1.1.1.12  christos /* Get border cell style. */
    630  1.1.1.12  christos static const struct grid_cell *
    631  1.1.1.12  christos screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
    632  1.1.1.12  christos     u_int y, struct window_pane *wp)
    633  1.1.1.12  christos {
    634  1.1.1.12  christos 	struct client		*c = ctx->c;
    635  1.1.1.12  christos 	struct session		*s = c->session;
    636  1.1.1.12  christos 	struct window		*w = s->curw->window;
    637  1.1.1.12  christos 	struct window_pane	*active = server_client_get_pane(c);
    638  1.1.1.12  christos 	struct options		*oo = w->options;
    639  1.1.1.12  christos 	struct format_tree	*ft;
    640  1.1.1.12  christos 
    641  1.1.1.12  christos 	if (wp->border_gc_set)
    642  1.1.1.12  christos 		return (&wp->border_gc);
    643  1.1.1.12  christos 	wp->border_gc_set = 1;
    644  1.1.1.12  christos 
    645  1.1.1.12  christos 	ft = format_create_defaults(NULL, c, s, s->curw, wp);
    646  1.1.1.15       wiz 	if (screen_redraw_check_is(ctx, x, y, active))
    647  1.1.1.12  christos 		style_apply(&wp->border_gc, oo, "pane-active-border-style", ft);
    648  1.1.1.12  christos 	else
    649  1.1.1.12  christos 		style_apply(&wp->border_gc, oo, "pane-border-style", ft);
    650  1.1.1.12  christos 	format_free(ft);
    651  1.1.1.12  christos 
    652  1.1.1.12  christos 	return (&wp->border_gc);
    653  1.1.1.12  christos }
    654  1.1.1.12  christos 
    655   1.1.1.9  christos /* Draw a border cell. */
    656   1.1.1.9  christos static void
    657  1.1.1.12  christos screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
    658  1.1.1.10  christos {
    659  1.1.1.10  christos 	struct client		*c = ctx->c;
    660  1.1.1.10  christos 	struct session		*s = c->session;
    661  1.1.1.13       wiz 	struct window		*w = s->curw->window;
    662  1.1.1.13       wiz 	struct options		*oo = w->options;
    663  1.1.1.10  christos 	struct tty		*tty = &c->tty;
    664  1.1.1.13       wiz 	struct format_tree	*ft;
    665  1.1.1.13       wiz 	struct window_pane	*wp, *active = server_client_get_pane(c);
    666  1.1.1.12  christos 	struct grid_cell	 gc;
    667  1.1.1.12  christos 	const struct grid_cell	*tmp;
    668  1.1.1.13       wiz 	struct overlay_ranges	 r;
    669  1.1.1.13       wiz 	u_int			 cell_type, x = ctx->ox + i, y = ctx->oy + j;
    670  1.1.1.13       wiz 	int			 arrows = 0, border;
    671  1.1.1.15       wiz 	int			 isolates;
    672   1.1.1.9  christos 
    673  1.1.1.13       wiz 	if (c->overlay_check != NULL) {
    674  1.1.1.13       wiz 		c->overlay_check(c, c->overlay_data, x, y, 1, &r);
    675  1.1.1.13       wiz 		if (r.nx[0] + r.nx[1] == 0)
    676  1.1.1.13       wiz 			return;
    677  1.1.1.13       wiz 	}
    678   1.1.1.9  christos 
    679  1.1.1.15       wiz 	cell_type = screen_redraw_check_cell(ctx, x, y, &wp);
    680  1.1.1.12  christos 	if (cell_type == CELL_INSIDE)
    681  1.1.1.12  christos 		return;
    682  1.1.1.12  christos 
    683  1.1.1.13       wiz 	if (wp == NULL) {
    684  1.1.1.13       wiz 		if (!ctx->no_pane_gc_set) {
    685  1.1.1.13       wiz 			ft = format_create_defaults(NULL, c, s, s->curw, NULL);
    686  1.1.1.13       wiz 			memcpy(&ctx->no_pane_gc, &grid_default_cell, sizeof gc);
    687  1.1.1.13       wiz 			style_add(&ctx->no_pane_gc, oo, "pane-border-style",
    688  1.1.1.13       wiz 			    ft);
    689  1.1.1.13       wiz 			format_free(ft);
    690  1.1.1.13       wiz 			ctx->no_pane_gc_set = 1;
    691  1.1.1.13       wiz 		}
    692  1.1.1.13       wiz 		memcpy(&gc, &ctx->no_pane_gc, sizeof gc);
    693  1.1.1.13       wiz 	} else {
    694  1.1.1.12  christos 		tmp = screen_redraw_draw_borders_style(ctx, x, y, wp);
    695  1.1.1.12  christos 		if (tmp == NULL)
    696  1.1.1.12  christos 			return;
    697  1.1.1.12  christos 		memcpy(&gc, tmp, sizeof gc);
    698  1.1.1.12  christos 
    699  1.1.1.12  christos 		if (server_is_marked(s, s->curw, marked_pane.wp) &&
    700  1.1.1.15       wiz 		    screen_redraw_check_is(ctx, x, y, marked_pane.wp))
    701  1.1.1.12  christos 			gc.attr ^= GRID_ATTR_REVERSE;
    702  1.1.1.12  christos 	}
    703  1.1.1.13       wiz 	screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc);
    704  1.1.1.12  christos 
    705  1.1.1.12  christos 	if (cell_type == CELL_TOPBOTTOM &&
    706  1.1.1.12  christos 	    (c->flags & CLIENT_UTF8) &&
    707  1.1.1.12  christos 	    tty_term_has(tty->term, TTYC_BIDI))
    708  1.1.1.12  christos 		isolates = 1;
    709   1.1.1.9  christos 	else
    710  1.1.1.12  christos 		isolates = 0;
    711  1.1.1.12  christos 
    712  1.1.1.11  christos 	if (ctx->statustop)
    713  1.1.1.11  christos 		tty_cursor(tty, i, ctx->statuslines + j);
    714   1.1.1.9  christos 	else
    715  1.1.1.10  christos 		tty_cursor(tty, i, j);
    716  1.1.1.12  christos 	if (isolates)
    717  1.1.1.12  christos 		tty_puts(tty, END_ISOLATE);
    718  1.1.1.13       wiz 
    719  1.1.1.13       wiz 	switch (options_get_number(oo, "pane-border-indicators")) {
    720  1.1.1.13       wiz 	case PANE_BORDER_ARROWS:
    721  1.1.1.13       wiz 	case PANE_BORDER_BOTH:
    722  1.1.1.13       wiz 		arrows = 1;
    723  1.1.1.13       wiz 		break;
    724  1.1.1.13       wiz 	}
    725  1.1.1.13       wiz 
    726  1.1.1.13       wiz 	if (wp != NULL && arrows) {
    727  1.1.1.15       wiz 		border = screen_redraw_pane_border(ctx, active, x, y);
    728  1.1.1.13       wiz 		if (((i == wp->xoff + 1 &&
    729  1.1.1.13       wiz 		    (cell_type == CELL_LEFTRIGHT ||
    730  1.1.1.13       wiz 		    (cell_type == CELL_TOPJOIN &&
    731  1.1.1.13       wiz 		    border == SCREEN_REDRAW_BORDER_BOTTOM) ||
    732  1.1.1.13       wiz 		    (cell_type == CELL_BOTTOMJOIN &&
    733  1.1.1.13       wiz 		    border == SCREEN_REDRAW_BORDER_TOP))) ||
    734  1.1.1.13       wiz 		    (j == wp->yoff + 1 &&
    735  1.1.1.13       wiz 		    (cell_type == CELL_TOPBOTTOM ||
    736  1.1.1.13       wiz 		    (cell_type == CELL_LEFTJOIN &&
    737  1.1.1.13       wiz 		    border == SCREEN_REDRAW_BORDER_RIGHT) ||
    738  1.1.1.13       wiz 		    (cell_type == CELL_RIGHTJOIN &&
    739  1.1.1.13       wiz 		    border == SCREEN_REDRAW_BORDER_LEFT)))) &&
    740  1.1.1.15       wiz 		    screen_redraw_check_is(ctx, x, y, active)) {
    741  1.1.1.13       wiz 			gc.attr |= GRID_ATTR_CHARSET;
    742  1.1.1.13       wiz 			utf8_set(&gc.data, BORDER_MARKERS[border]);
    743  1.1.1.13       wiz 		}
    744  1.1.1.13       wiz 	}
    745  1.1.1.13       wiz 
    746  1.1.1.14       wiz 	tty_cell(tty, &gc, &grid_default_cell, NULL, NULL);
    747  1.1.1.12  christos 	if (isolates)
    748  1.1.1.12  christos 		tty_puts(tty, START_ISOLATE);
    749   1.1.1.9  christos }
    750   1.1.1.9  christos 
    751   1.1.1.3  christos /* Draw the borders. */
    752   1.1.1.7  christos static void
    753   1.1.1.9  christos screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
    754   1.1.1.3  christos {
    755   1.1.1.9  christos 	struct client		*c = ctx->c;
    756   1.1.1.5  christos 	struct session		*s = c->session;
    757   1.1.1.5  christos 	struct window		*w = s->curw->window;
    758  1.1.1.12  christos 	struct window_pane	*wp;
    759  1.1.1.15       wiz 	u_int			 i, j;
    760  1.1.1.10  christos 
    761  1.1.1.10  christos 	log_debug("%s: %s @%u", __func__, c->name, w->id);
    762   1.1.1.3  christos 
    763  1.1.1.12  christos 	TAILQ_FOREACH(wp, &w->panes, entry)
    764  1.1.1.12  christos 		wp->border_gc_set = 0;
    765  1.1.1.12  christos 
    766  1.1.1.12  christos 	for (j = 0; j < c->tty.sy - ctx->statuslines; j++) {
    767  1.1.1.12  christos 		for (i = 0; i < c->tty.sx; i++)
    768  1.1.1.12  christos 			screen_redraw_draw_borders_cell(ctx, i, j);
    769       1.1      jmmv 	}
    770   1.1.1.3  christos }
    771       1.1      jmmv 
    772   1.1.1.3  christos /* Draw the panes. */
    773   1.1.1.7  christos static void
    774   1.1.1.9  christos screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
    775   1.1.1.3  christos {
    776   1.1.1.9  christos 	struct client		*c = ctx->c;
    777   1.1.1.3  christos 	struct window		*w = c->session->curw->window;
    778   1.1.1.3  christos 	struct window_pane	*wp;
    779       1.1      jmmv 
    780  1.1.1.10  christos 	log_debug("%s: %s @%u", __func__, c->name, w->id);
    781  1.1.1.10  christos 
    782       1.1      jmmv 	TAILQ_FOREACH(wp, &w->panes, entry) {
    783  1.1.1.11  christos 		if (window_pane_visible(wp))
    784  1.1.1.11  christos 			screen_redraw_draw_pane(ctx, wp);
    785       1.1      jmmv 	}
    786       1.1      jmmv }
    787       1.1      jmmv 
    788   1.1.1.3  christos /* Draw the status line. */
    789   1.1.1.7  christos static void
    790   1.1.1.9  christos screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
    791       1.1      jmmv {
    792   1.1.1.9  christos 	struct client	*c = ctx->c;
    793  1.1.1.10  christos 	struct window	*w = c->session->curw->window;
    794   1.1.1.3  christos 	struct tty	*tty = &c->tty;
    795  1.1.1.10  christos 	struct screen	*s = c->status.active;
    796   1.1.1.9  christos 	u_int		 i, y;
    797       1.1      jmmv 
    798  1.1.1.10  christos 	log_debug("%s: %s @%u", __func__, c->name, w->id);
    799  1.1.1.10  christos 
    800  1.1.1.11  christos 	if (ctx->statustop)
    801   1.1.1.9  christos 		y = 0;
    802   1.1.1.3  christos 	else
    803  1.1.1.11  christos 		y = c->tty.sy - ctx->statuslines;
    804  1.1.1.12  christos 	for (i = 0; i < ctx->statuslines; i++) {
    805  1.1.1.12  christos 		tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i,
    806  1.1.1.12  christos 		    &grid_default_cell, NULL);
    807  1.1.1.12  christos 	}
    808  1.1.1.10  christos }
    809  1.1.1.10  christos 
    810  1.1.1.10  christos /* Draw one pane. */
    811  1.1.1.10  christos static void
    812  1.1.1.10  christos screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
    813  1.1.1.10  christos {
    814  1.1.1.13       wiz 	struct client		*c = ctx->c;
    815  1.1.1.13       wiz 	struct window		*w = c->session->curw->window;
    816  1.1.1.13       wiz 	struct tty		*tty = &c->tty;
    817  1.1.1.13       wiz 	struct screen		*s = wp->screen;
    818  1.1.1.13       wiz 	struct colour_palette	*palette = &wp->palette;
    819  1.1.1.13       wiz 	struct grid_cell	 defaults;
    820  1.1.1.13       wiz 	u_int			 i, j, top, x, y, width;
    821  1.1.1.10  christos 
    822  1.1.1.10  christos 	log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
    823  1.1.1.10  christos 
    824  1.1.1.10  christos 	if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
    825  1.1.1.10  christos 		return;
    826  1.1.1.11  christos 	if (ctx->statustop)
    827  1.1.1.11  christos 		top = ctx->statuslines;
    828  1.1.1.10  christos 	else
    829  1.1.1.10  christos 		top = 0;
    830  1.1.1.10  christos 	for (j = 0; j < wp->sy; j++) {
    831  1.1.1.10  christos 		if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy)
    832  1.1.1.10  christos 			continue;
    833  1.1.1.10  christos 		y = top + wp->yoff + j - ctx->oy;
    834  1.1.1.10  christos 
    835  1.1.1.10  christos 		if (wp->xoff >= ctx->ox &&
    836  1.1.1.10  christos 		    wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
    837  1.1.1.10  christos 			/* All visible. */
    838  1.1.1.10  christos 			i = 0;
    839  1.1.1.10  christos 			x = wp->xoff - ctx->ox;
    840  1.1.1.10  christos 			width = wp->sx;
    841  1.1.1.10  christos 		} else if (wp->xoff < ctx->ox &&
    842  1.1.1.10  christos 		    wp->xoff + wp->sx > ctx->ox + ctx->sx) {
    843  1.1.1.10  christos 			/* Both left and right not visible. */
    844  1.1.1.10  christos 			i = ctx->ox;
    845  1.1.1.10  christos 			x = 0;
    846  1.1.1.10  christos 			width = ctx->sx;
    847  1.1.1.10  christos 		} else if (wp->xoff < ctx->ox) {
    848  1.1.1.10  christos 			/* Left not visible. */
    849  1.1.1.10  christos 			i = ctx->ox - wp->xoff;
    850  1.1.1.10  christos 			x = 0;
    851  1.1.1.10  christos 			width = wp->sx - i;
    852  1.1.1.10  christos 		} else {
    853  1.1.1.10  christos 			/* Right not visible. */
    854  1.1.1.10  christos 			i = 0;
    855  1.1.1.10  christos 			x = wp->xoff - ctx->ox;
    856  1.1.1.10  christos 			width = ctx->sx - x;
    857  1.1.1.10  christos 		}
    858  1.1.1.10  christos 		log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
    859  1.1.1.10  christos 		    __func__, c->name, wp->id, i, j, x, y, width);
    860  1.1.1.10  christos 
    861  1.1.1.12  christos 		tty_default_colours(&defaults, wp);
    862  1.1.1.13       wiz 		tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette);
    863  1.1.1.10  christos 	}
    864  1.1.1.14       wiz 
    865  1.1.1.14       wiz #ifdef ENABLE_SIXEL
    866  1.1.1.14       wiz 	tty_draw_images(c, wp, s);
    867  1.1.1.14       wiz #endif
    868       1.1      jmmv }
    869