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