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