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