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