15494e770Schristos /* $OpenBSD$ */ 2698d5317Sjmmv 3698d5317Sjmmv /* 4ed4e6cd4Schristos * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 5698d5317Sjmmv * 6698d5317Sjmmv * Permission to use, copy, modify, and distribute this software for any 7698d5317Sjmmv * purpose with or without fee is hereby granted, provided that the above 8698d5317Sjmmv * copyright notice and this permission notice appear in all copies. 9698d5317Sjmmv * 10698d5317Sjmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11698d5317Sjmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12698d5317Sjmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13698d5317Sjmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14698d5317Sjmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15698d5317Sjmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16698d5317Sjmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17698d5317Sjmmv */ 18698d5317Sjmmv 19698d5317Sjmmv #include <sys/types.h> 20698d5317Sjmmv 218f3b9483Schristos #include <stdlib.h> 22698d5317Sjmmv #include <string.h> 23698d5317Sjmmv 24698d5317Sjmmv #include "tmux.h" 25698d5317Sjmmv 268f3b9483Schristos static void screen_redraw_draw_borders(struct screen_redraw_ctx *); 278f3b9483Schristos static void screen_redraw_draw_panes(struct screen_redraw_ctx *); 288f3b9483Schristos static void screen_redraw_draw_status(struct screen_redraw_ctx *); 29ef36e747Schristos static void screen_redraw_draw_pane(struct screen_redraw_ctx *, 30ef36e747Schristos struct window_pane *); 319fb66d81Schristos static void screen_redraw_set_context(struct client *, 329fb66d81Schristos struct screen_redraw_ctx *); 33698d5317Sjmmv 349fb66d81Schristos #define START_ISOLATE "\342\201\246" 359fb66d81Schristos #define END_ISOLATE "\342\201\251" 369fb66d81Schristos 376db26757Swiz /* Border in relation to a pane. */ 389fb66d81Schristos enum screen_redraw_border_type { 399fb66d81Schristos SCREEN_REDRAW_OUTSIDE, 409fb66d81Schristos SCREEN_REDRAW_INSIDE, 416db26757Swiz SCREEN_REDRAW_BORDER_LEFT, 426db26757Swiz SCREEN_REDRAW_BORDER_RIGHT, 436db26757Swiz SCREEN_REDRAW_BORDER_TOP, 446db26757Swiz SCREEN_REDRAW_BORDER_BOTTOM 459fb66d81Schristos }; 466db26757Swiz #define BORDER_MARKERS " +,.-" 479fb66d81Schristos 489fb66d81Schristos /* Get cell border character. */ 499fb66d81Schristos static void 506db26757Swiz screen_redraw_border_set(struct window *w, struct window_pane *wp, 516db26757Swiz enum pane_lines pane_lines, int cell_type, struct grid_cell *gc) 52698d5317Sjmmv { 539fb66d81Schristos u_int idx; 549fb66d81Schristos 556db26757Swiz if (cell_type == CELL_OUTSIDE && w->fill_character != NULL) { 566db26757Swiz utf8_copy(&gc->data, &w->fill_character[0]); 576db26757Swiz return; 586db26757Swiz } 596db26757Swiz 609fb66d81Schristos switch (pane_lines) { 619fb66d81Schristos case PANE_LINES_NUMBER: 629fb66d81Schristos if (cell_type == CELL_OUTSIDE) { 639fb66d81Schristos gc->attr |= GRID_ATTR_CHARSET; 649fb66d81Schristos utf8_set(&gc->data, CELL_BORDERS[CELL_OUTSIDE]); 659fb66d81Schristos break; 669fb66d81Schristos } 679fb66d81Schristos gc->attr &= ~GRID_ATTR_CHARSET; 689fb66d81Schristos if (wp != NULL && window_pane_index(wp, &idx) == 0) 699fb66d81Schristos utf8_set(&gc->data, '0' + (idx % 10)); 709fb66d81Schristos else 719fb66d81Schristos utf8_set(&gc->data, '*'); 729fb66d81Schristos break; 739fb66d81Schristos case PANE_LINES_DOUBLE: 749fb66d81Schristos gc->attr &= ~GRID_ATTR_CHARSET; 756db26757Swiz utf8_copy(&gc->data, tty_acs_double_borders(cell_type)); 769fb66d81Schristos break; 779fb66d81Schristos case PANE_LINES_HEAVY: 789fb66d81Schristos gc->attr &= ~GRID_ATTR_CHARSET; 796db26757Swiz utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type)); 809fb66d81Schristos break; 819fb66d81Schristos case PANE_LINES_SIMPLE: 829fb66d81Schristos gc->attr &= ~GRID_ATTR_CHARSET; 836db26757Swiz utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]); 849fb66d81Schristos break; 859fb66d81Schristos default: 869fb66d81Schristos gc->attr |= GRID_ATTR_CHARSET; 879fb66d81Schristos utf8_set(&gc->data, CELL_BORDERS[cell_type]); 889fb66d81Schristos break; 899fb66d81Schristos } 909fb66d81Schristos } 919fb66d81Schristos 929fb66d81Schristos /* Return if window has only two panes. */ 939fb66d81Schristos static int 949fb66d81Schristos screen_redraw_two_panes(struct window *w, int direction) 959fb66d81Schristos { 969fb66d81Schristos struct window_pane *wp; 979fb66d81Schristos 989fb66d81Schristos wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 999fb66d81Schristos if (wp == NULL) 1009fb66d81Schristos return (0); /* one pane */ 1019fb66d81Schristos if (TAILQ_NEXT(wp, entry) != NULL) 1029fb66d81Schristos return (0); /* more than two panes */ 1039fb66d81Schristos if (direction == 0 && wp->xoff == 0) 104698d5317Sjmmv return (0); 1059fb66d81Schristos if (direction == 1 && wp->yoff == 0) 1069fb66d81Schristos return (0); 1079fb66d81Schristos return (1); 1089fb66d81Schristos } 1099fb66d81Schristos 1109fb66d81Schristos /* Check if cell is on the border of a pane. */ 1119fb66d81Schristos static enum screen_redraw_border_type 112*f8cf1a91Swiz screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp, 113*f8cf1a91Swiz u_int px, u_int py) 1149fb66d81Schristos { 1156db26757Swiz struct options *oo = wp->window->options; 1166db26757Swiz int split = 0; 1179fb66d81Schristos u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy; 118*f8cf1a91Swiz int pane_status = ctx->pane_status; 1199fb66d81Schristos 1209fb66d81Schristos /* Inside pane. */ 1219fb66d81Schristos if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey) 1229fb66d81Schristos return (SCREEN_REDRAW_INSIDE); 123698d5317Sjmmv 1246db26757Swiz /* Get pane indicator. */ 1256db26757Swiz switch (options_get_number(oo, "pane-border-indicators")) { 1266db26757Swiz case PANE_BORDER_COLOUR: 1276db26757Swiz case PANE_BORDER_BOTH: 1286db26757Swiz split = 1; 1296db26757Swiz break; 1306db26757Swiz } 1316db26757Swiz 132698d5317Sjmmv /* Left/right borders. */ 1339fb66d81Schristos if (pane_status == PANE_STATUS_OFF) { 1346db26757Swiz if (screen_redraw_two_panes(wp->window, 0) && split) { 1359fb66d81Schristos if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2) 1366db26757Swiz return (SCREEN_REDRAW_BORDER_RIGHT); 1379fb66d81Schristos if (wp->xoff != 0 && 1389fb66d81Schristos px == wp->xoff - 1 && 1399fb66d81Schristos py > wp->sy / 2) 1406db26757Swiz return (SCREEN_REDRAW_BORDER_LEFT); 1419fb66d81Schristos } else { 1429fb66d81Schristos if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { 143698d5317Sjmmv if (wp->xoff != 0 && px == wp->xoff - 1) 1446db26757Swiz return (SCREEN_REDRAW_BORDER_LEFT); 1459fb66d81Schristos if (px == ex) 1466db26757Swiz return (SCREEN_REDRAW_BORDER_RIGHT); 1479fb66d81Schristos } 1489fb66d81Schristos } 1499fb66d81Schristos } else { 1509fb66d81Schristos if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { 1519fb66d81Schristos if (wp->xoff != 0 && px == wp->xoff - 1) 1526db26757Swiz return (SCREEN_REDRAW_BORDER_LEFT); 1539fb66d81Schristos if (px == ex) 1546db26757Swiz return (SCREEN_REDRAW_BORDER_RIGHT); 1559fb66d81Schristos } 156698d5317Sjmmv } 157698d5317Sjmmv 158698d5317Sjmmv /* Top/bottom borders. */ 1599fb66d81Schristos if (pane_status == PANE_STATUS_OFF) { 1606db26757Swiz if (screen_redraw_two_panes(wp->window, 1) && split) { 1619fb66d81Schristos if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2) 1626db26757Swiz return (SCREEN_REDRAW_BORDER_BOTTOM); 1639fb66d81Schristos if (wp->yoff != 0 && 1649fb66d81Schristos py == wp->yoff - 1 && 1659fb66d81Schristos px > wp->sx / 2) 1666db26757Swiz return (SCREEN_REDRAW_BORDER_TOP); 1679fb66d81Schristos } else { 1689fb66d81Schristos if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { 169698d5317Sjmmv if (wp->yoff != 0 && py == wp->yoff - 1) 1706db26757Swiz return (SCREEN_REDRAW_BORDER_TOP); 1719fb66d81Schristos if (py == ey) 1726db26757Swiz return (SCREEN_REDRAW_BORDER_BOTTOM); 1739fb66d81Schristos } 1749fb66d81Schristos } 1759fb66d81Schristos } else if (pane_status == PANE_STATUS_TOP) { 1769fb66d81Schristos if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { 1779fb66d81Schristos if (wp->yoff != 0 && py == wp->yoff - 1) 1786db26757Swiz return (SCREEN_REDRAW_BORDER_TOP); 1799fb66d81Schristos } 1809fb66d81Schristos } else { 1819fb66d81Schristos if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { 1829fb66d81Schristos if (py == ey) 1836db26757Swiz return (SCREEN_REDRAW_BORDER_BOTTOM); 1849fb66d81Schristos } 185698d5317Sjmmv } 186698d5317Sjmmv 187698d5317Sjmmv /* Outside pane. */ 1889fb66d81Schristos return (SCREEN_REDRAW_OUTSIDE); 189698d5317Sjmmv } 190698d5317Sjmmv 1919fb66d81Schristos /* Check if a cell is on a border. */ 1924e179ddaSchristos static int 193*f8cf1a91Swiz screen_redraw_cell_border(struct screen_redraw_ctx *ctx, u_int px, u_int py) 194698d5317Sjmmv { 195*f8cf1a91Swiz struct client *c = ctx->c; 196698d5317Sjmmv struct window *w = c->session->curw->window; 197698d5317Sjmmv struct window_pane *wp; 1989fb66d81Schristos 1999fb66d81Schristos /* Outside the window? */ 2009fb66d81Schristos if (px > w->sx || py > w->sy) 2019fb66d81Schristos return (0); 2029fb66d81Schristos 2039fb66d81Schristos /* On the window border? */ 2049fb66d81Schristos if (px == w->sx || py == w->sy) 2059fb66d81Schristos return (1); 206698d5317Sjmmv 207698d5317Sjmmv /* Check all the panes. */ 208698d5317Sjmmv TAILQ_FOREACH(wp, &w->panes, entry) { 209698d5317Sjmmv if (!window_pane_visible(wp)) 210698d5317Sjmmv continue; 211*f8cf1a91Swiz switch (screen_redraw_pane_border(ctx, wp, px, py)) { 2129fb66d81Schristos case SCREEN_REDRAW_INSIDE: 2139fb66d81Schristos return (0); 2149fb66d81Schristos case SCREEN_REDRAW_OUTSIDE: 2159fb66d81Schristos break; 2166db26757Swiz default: 2176db26757Swiz return (1); 2189fb66d81Schristos } 219698d5317Sjmmv } 220698d5317Sjmmv 221698d5317Sjmmv return (0); 222698d5317Sjmmv } 223698d5317Sjmmv 2249fb66d81Schristos /* Work out type of border cell from surrounding cells. */ 2254e179ddaSchristos static int 226*f8cf1a91Swiz screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py) 227698d5317Sjmmv { 228*f8cf1a91Swiz struct client *c = ctx->c; 229*f8cf1a91Swiz int pane_status = ctx->pane_status; 230698d5317Sjmmv struct window *w = c->session->curw->window; 2319fb66d81Schristos u_int sx = w->sx, sy = w->sy; 2329fb66d81Schristos int borders = 0; 2334e179ddaSchristos 2349fb66d81Schristos /* Is this outside the window? */ 2359fb66d81Schristos if (px > sx || py > sy) 236698d5317Sjmmv return (CELL_OUTSIDE); 237698d5317Sjmmv 238698d5317Sjmmv /* 2399fb66d81Schristos * Construct a bitmask of whether the cells to the left (bit 4), right, 2409fb66d81Schristos * top, and bottom (bit 1) of this cell are borders. 241698d5317Sjmmv */ 242*f8cf1a91Swiz if (px == 0 || screen_redraw_cell_border(ctx, px - 1, py)) 243698d5317Sjmmv borders |= 8; 244*f8cf1a91Swiz if (px <= sx && screen_redraw_cell_border(ctx, px + 1, py)) 245698d5317Sjmmv borders |= 4; 2466483eba0Schristos if (pane_status == PANE_STATUS_TOP) { 2479fb66d81Schristos if (py != 0 && 248*f8cf1a91Swiz screen_redraw_cell_border(ctx, px, py - 1)) 2494e179ddaSchristos borders |= 2; 250*f8cf1a91Swiz if (screen_redraw_cell_border(ctx, px, py + 1)) 251698d5317Sjmmv borders |= 1; 2529fb66d81Schristos } else if (pane_status == PANE_STATUS_BOTTOM) { 2539fb66d81Schristos if (py == 0 || 254*f8cf1a91Swiz screen_redraw_cell_border(ctx, px, py - 1)) 2559fb66d81Schristos borders |= 2; 2569fb66d81Schristos if (py != sy - 1 && 257*f8cf1a91Swiz screen_redraw_cell_border(ctx, px, py + 1)) 2589fb66d81Schristos borders |= 1; 2599fb66d81Schristos } else { 2609fb66d81Schristos if (py == 0 || 261*f8cf1a91Swiz screen_redraw_cell_border(ctx, px, py - 1)) 2629fb66d81Schristos borders |= 2; 263*f8cf1a91Swiz if (screen_redraw_cell_border(ctx, px, py + 1)) 2649fb66d81Schristos borders |= 1; 2659fb66d81Schristos } 266698d5317Sjmmv 267698d5317Sjmmv /* 2689fb66d81Schristos * Figure out what kind of border this cell is. Only one bit set 2699fb66d81Schristos * doesn't make sense (can't have a border cell with no others 2709fb66d81Schristos * connected). 271698d5317Sjmmv */ 272698d5317Sjmmv switch (borders) { 273698d5317Sjmmv case 15: /* 1111, left right top bottom */ 274698d5317Sjmmv return (CELL_JOIN); 275698d5317Sjmmv case 14: /* 1110, left right top */ 276698d5317Sjmmv return (CELL_BOTTOMJOIN); 277698d5317Sjmmv case 13: /* 1101, left right bottom */ 278698d5317Sjmmv return (CELL_TOPJOIN); 279698d5317Sjmmv case 12: /* 1100, left right */ 2809fb66d81Schristos return (CELL_LEFTRIGHT); 281698d5317Sjmmv case 11: /* 1011, left top bottom */ 282698d5317Sjmmv return (CELL_RIGHTJOIN); 283698d5317Sjmmv case 10: /* 1010, left top */ 284698d5317Sjmmv return (CELL_BOTTOMRIGHT); 285698d5317Sjmmv case 9: /* 1001, left bottom */ 286698d5317Sjmmv return (CELL_TOPRIGHT); 287698d5317Sjmmv case 7: /* 0111, right top bottom */ 288698d5317Sjmmv return (CELL_LEFTJOIN); 289698d5317Sjmmv case 6: /* 0110, right top */ 290698d5317Sjmmv return (CELL_BOTTOMLEFT); 291698d5317Sjmmv case 5: /* 0101, right bottom */ 292698d5317Sjmmv return (CELL_TOPLEFT); 293698d5317Sjmmv case 3: /* 0011, top bottom */ 2949fb66d81Schristos return (CELL_TOPBOTTOM); 295698d5317Sjmmv } 2969fb66d81Schristos return (CELL_OUTSIDE); 297698d5317Sjmmv } 298698d5317Sjmmv 2999fb66d81Schristos /* Check if cell inside a pane. */ 3009fb66d81Schristos static int 301*f8cf1a91Swiz screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, 3029fb66d81Schristos struct window_pane **wpp) 3039fb66d81Schristos { 304*f8cf1a91Swiz struct client *c = ctx->c; 3059fb66d81Schristos struct window *w = c->session->curw->window; 3069fb66d81Schristos struct window_pane *wp, *active; 307*f8cf1a91Swiz int pane_status = ctx->pane_status; 3089fb66d81Schristos int border; 3099fb66d81Schristos u_int right, line; 3109fb66d81Schristos 3119fb66d81Schristos *wpp = NULL; 3129fb66d81Schristos 3139fb66d81Schristos if (px > w->sx || py > w->sy) 3149fb66d81Schristos return (CELL_OUTSIDE); 3159fb66d81Schristos if (px == w->sx || py == w->sy) /* window border */ 316*f8cf1a91Swiz return (screen_redraw_type_of_cell(ctx, px, py)); 3179fb66d81Schristos 3189fb66d81Schristos if (pane_status != PANE_STATUS_OFF) { 3199fb66d81Schristos active = wp = server_client_get_pane(c); 3209fb66d81Schristos do { 3219fb66d81Schristos if (!window_pane_visible(wp)) 3229fb66d81Schristos goto next1; 3239fb66d81Schristos 3249fb66d81Schristos if (pane_status == PANE_STATUS_TOP) 3259fb66d81Schristos line = wp->yoff - 1; 3269fb66d81Schristos else 3279fb66d81Schristos line = wp->yoff + wp->sy; 3289fb66d81Schristos right = wp->xoff + 2 + wp->status_size - 1; 3299fb66d81Schristos 3309fb66d81Schristos if (py == line && px >= wp->xoff + 2 && px <= right) 3319fb66d81Schristos return (CELL_INSIDE); 3329fb66d81Schristos 3339fb66d81Schristos next1: 3349fb66d81Schristos wp = TAILQ_NEXT(wp, entry); 3359fb66d81Schristos if (wp == NULL) 3369fb66d81Schristos wp = TAILQ_FIRST(&w->panes); 3379fb66d81Schristos } while (wp != active); 3389fb66d81Schristos } 3399fb66d81Schristos 3409fb66d81Schristos active = wp = server_client_get_pane(c); 3419fb66d81Schristos do { 3429fb66d81Schristos if (!window_pane_visible(wp)) 3439fb66d81Schristos goto next2; 3449fb66d81Schristos *wpp = wp; 3459fb66d81Schristos 3469fb66d81Schristos /* 3479fb66d81Schristos * If definitely inside, return. If not on border, skip. 3489fb66d81Schristos * Otherwise work out the cell. 3499fb66d81Schristos */ 350*f8cf1a91Swiz border = screen_redraw_pane_border(ctx, wp, px, py); 3519fb66d81Schristos if (border == SCREEN_REDRAW_INSIDE) 3529fb66d81Schristos return (CELL_INSIDE); 3539fb66d81Schristos if (border == SCREEN_REDRAW_OUTSIDE) 3549fb66d81Schristos goto next2; 355*f8cf1a91Swiz return (screen_redraw_type_of_cell(ctx, px, py)); 3569fb66d81Schristos 3579fb66d81Schristos next2: 3589fb66d81Schristos wp = TAILQ_NEXT(wp, entry); 3599fb66d81Schristos if (wp == NULL) 3609fb66d81Schristos wp = TAILQ_FIRST(&w->panes); 3619fb66d81Schristos } while (wp != active); 3629fb66d81Schristos 363698d5317Sjmmv return (CELL_OUTSIDE); 364698d5317Sjmmv } 365698d5317Sjmmv 3665494e770Schristos /* Check if the border of a particular pane. */ 3674e179ddaSchristos static int 368*f8cf1a91Swiz screen_redraw_check_is(struct screen_redraw_ctx *ctx, u_int px, u_int py, 3699fb66d81Schristos struct window_pane *wp) 370928fc495Schristos { 3719fb66d81Schristos enum screen_redraw_border_type border; 3724e179ddaSchristos 373*f8cf1a91Swiz border = screen_redraw_pane_border(ctx, wp, px, py); 3746db26757Swiz if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE) 375928fc495Schristos return (1); 376928fc495Schristos return (0); 377928fc495Schristos } 378928fc495Schristos 3794e179ddaSchristos /* Update pane status. */ 3804e179ddaSchristos static int 3819fb66d81Schristos screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, 3826db26757Swiz struct screen_redraw_ctx *rctx, enum pane_lines pane_lines) 3834e179ddaSchristos { 3849fb66d81Schristos struct window *w = wp->window; 3854e179ddaSchristos struct grid_cell gc; 3864e179ddaSchristos const char *fmt; 3874e179ddaSchristos struct format_tree *ft; 388ef36e747Schristos char *expanded; 3899fb66d81Schristos int pane_status = rctx->pane_status; 3909fb66d81Schristos u_int width, i, cell_type, px, py; 3914e179ddaSchristos struct screen_write_ctx ctx; 3924e179ddaSchristos struct screen old; 3934e179ddaSchristos 3946483eba0Schristos ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS); 3959fb66d81Schristos format_defaults(ft, c, c->session, c->session->curw, wp); 3969fb66d81Schristos 3979fb66d81Schristos if (wp == server_client_get_pane(c)) 3989fb66d81Schristos style_apply(&gc, w->options, "pane-active-border-style", ft); 3999fb66d81Schristos else 4009fb66d81Schristos style_apply(&gc, w->options, "pane-border-style", ft); 4016db26757Swiz fmt = options_get_string(wp->options, "pane-border-format"); 4024e179ddaSchristos 403ef36e747Schristos expanded = format_expand_time(ft, fmt); 404ef36e747Schristos if (wp->sx < 4) 405ef36e747Schristos wp->status_size = width = 0; 406ef36e747Schristos else 407ef36e747Schristos wp->status_size = width = wp->sx - 4; 408ef36e747Schristos 4094e179ddaSchristos memcpy(&old, &wp->status_screen, sizeof old); 410ef36e747Schristos screen_init(&wp->status_screen, width, 1, 0); 4114e179ddaSchristos wp->status_screen.mode = 0; 4124e179ddaSchristos 4139fb66d81Schristos screen_write_start(&ctx, &wp->status_screen); 414ef36e747Schristos 4159fb66d81Schristos for (i = 0; i < width; i++) { 4169fb66d81Schristos px = wp->xoff + 2 + i; 417*f8cf1a91Swiz if (pane_status == PANE_STATUS_TOP) 4189fb66d81Schristos py = wp->yoff - 1; 4199fb66d81Schristos else 4209fb66d81Schristos py = wp->yoff + wp->sy; 421*f8cf1a91Swiz cell_type = screen_redraw_type_of_cell(rctx, px, py); 4226db26757Swiz screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc); 4239fb66d81Schristos screen_write_cell(&ctx, &gc); 4249fb66d81Schristos } 425ef36e747Schristos gc.attr &= ~GRID_ATTR_CHARSET; 426ef36e747Schristos 427ef36e747Schristos screen_write_cursormove(&ctx, 0, 0, 0); 4286db26757Swiz format_draw(&ctx, &gc, width, expanded, NULL, 0); 4294e179ddaSchristos screen_write_stop(&ctx); 4304e179ddaSchristos 431ef36e747Schristos free(expanded); 4324e179ddaSchristos format_free(ft); 4334e179ddaSchristos 4344e179ddaSchristos if (grid_compare(wp->status_screen.grid, old.grid) == 0) { 4354e179ddaSchristos screen_free(&old); 4364e179ddaSchristos return (0); 4374e179ddaSchristos } 4384e179ddaSchristos screen_free(&old); 4394e179ddaSchristos return (1); 4404e179ddaSchristos } 4414e179ddaSchristos 4424e179ddaSchristos /* Draw pane status. */ 4434e179ddaSchristos static void 444ef36e747Schristos screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx) 4454e179ddaSchristos { 446ef36e747Schristos struct client *c = ctx->c; 4474e179ddaSchristos struct window *w = c->session->curw->window; 4484e179ddaSchristos struct tty *tty = &c->tty; 4494e179ddaSchristos struct window_pane *wp; 450ef36e747Schristos struct screen *s; 451ef36e747Schristos u_int i, x, width, xoff, yoff, size; 4524e179ddaSchristos 453ef36e747Schristos log_debug("%s: %s @%u", __func__, c->name, w->id); 454ef36e747Schristos 4554e179ddaSchristos TAILQ_FOREACH(wp, &w->panes, entry) { 4564e179ddaSchristos if (!window_pane_visible(wp)) 4574e179ddaSchristos continue; 458ef36e747Schristos s = &wp->status_screen; 459ef36e747Schristos 460ef36e747Schristos size = wp->status_size; 4616483eba0Schristos if (ctx->pane_status == PANE_STATUS_TOP) 4624e179ddaSchristos yoff = wp->yoff - 1; 4634e179ddaSchristos else 4644e179ddaSchristos yoff = wp->yoff + wp->sy; 465ef36e747Schristos xoff = wp->xoff + 2; 4664e179ddaSchristos 467ef36e747Schristos if (xoff + size <= ctx->ox || 468ef36e747Schristos xoff >= ctx->ox + ctx->sx || 469ef36e747Schristos yoff < ctx->oy || 470ef36e747Schristos yoff >= ctx->oy + ctx->sy) 471ef36e747Schristos continue; 472ef36e747Schristos 473ef36e747Schristos if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) { 474ef36e747Schristos /* All visible. */ 475ef36e747Schristos i = 0; 476ef36e747Schristos x = xoff - ctx->ox; 477ef36e747Schristos width = size; 478ef36e747Schristos } else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) { 479ef36e747Schristos /* Both left and right not visible. */ 480ef36e747Schristos i = ctx->ox; 481ef36e747Schristos x = 0; 482ef36e747Schristos width = ctx->sx; 483ef36e747Schristos } else if (xoff < ctx->ox) { 484ef36e747Schristos /* Left not visible. */ 485ef36e747Schristos i = ctx->ox - xoff; 486ef36e747Schristos x = 0; 487ef36e747Schristos width = size - i; 488ef36e747Schristos } else { 489ef36e747Schristos /* Right not visible. */ 490ef36e747Schristos i = 0; 491ef36e747Schristos x = xoff - ctx->ox; 492ef36e747Schristos width = size - x; 493ef36e747Schristos } 494ef36e747Schristos 4956483eba0Schristos if (ctx->statustop) 4966483eba0Schristos yoff += ctx->statuslines; 4979fb66d81Schristos tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy, 4989fb66d81Schristos &grid_default_cell, NULL); 4994e179ddaSchristos } 5004e179ddaSchristos tty_cursor(tty, 0, 0); 5014e179ddaSchristos } 5024e179ddaSchristos 5034e179ddaSchristos /* Update status line and change flags if unchanged. */ 504*f8cf1a91Swiz static uint64_t 505*f8cf1a91Swiz screen_redraw_update(struct client *c, uint64_t flags) 5064e179ddaSchristos { 5074e179ddaSchristos struct window *w = c->session->curw->window; 5084e179ddaSchristos struct window_pane *wp; 5094e179ddaSchristos struct options *wo = w->options; 5106db26757Swiz int redraw; 5116db26757Swiz enum pane_lines lines; 5129fb66d81Schristos struct screen_redraw_ctx ctx; 5134e179ddaSchristos 5144e179ddaSchristos if (c->message_string != NULL) 5154e179ddaSchristos redraw = status_message_redraw(c); 5164e179ddaSchristos else if (c->prompt_string != NULL) 5174e179ddaSchristos redraw = status_prompt_redraw(c); 5184e179ddaSchristos else 5194e179ddaSchristos redraw = status_redraw(c); 520ef36e747Schristos if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS)) 521ef36e747Schristos flags &= ~CLIENT_REDRAWSTATUS; 5224e179ddaSchristos 5236483eba0Schristos if (c->overlay_draw != NULL) 5246483eba0Schristos flags |= CLIENT_REDRAWOVERLAY; 5256483eba0Schristos 5266483eba0Schristos if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) { 5279fb66d81Schristos screen_redraw_set_context(c, &ctx); 5289fb66d81Schristos lines = options_get_number(wo, "pane-border-lines"); 5294e179ddaSchristos redraw = 0; 5304e179ddaSchristos TAILQ_FOREACH(wp, &w->panes, entry) { 5319fb66d81Schristos if (screen_redraw_make_pane_status(c, wp, &ctx, lines)) 5324e179ddaSchristos redraw = 1; 5334e179ddaSchristos } 5344e179ddaSchristos if (redraw) 535ef36e747Schristos flags |= CLIENT_REDRAWBORDERS; 5364e179ddaSchristos } 537ef36e747Schristos return (flags); 538ef36e747Schristos } 539ef36e747Schristos 540ef36e747Schristos /* Set up redraw context. */ 541ef36e747Schristos static void 542ef36e747Schristos screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx) 543ef36e747Schristos { 544ef36e747Schristos struct session *s = c->session; 545ef36e747Schristos struct options *oo = s->options; 546ef36e747Schristos struct window *w = s->curw->window; 547ef36e747Schristos struct options *wo = w->options; 5486483eba0Schristos u_int lines; 549ef36e747Schristos 550ef36e747Schristos memset(ctx, 0, sizeof *ctx); 551ef36e747Schristos ctx->c = c; 552ef36e747Schristos 5536483eba0Schristos lines = status_line_size(c); 554ef36e747Schristos if (c->message_string != NULL || c->prompt_string != NULL) 5556483eba0Schristos lines = (lines == 0) ? 1 : lines; 5566483eba0Schristos if (lines != 0 && options_get_number(oo, "status-position") == 0) 5576483eba0Schristos ctx->statustop = 1; 5586483eba0Schristos ctx->statuslines = lines; 5596483eba0Schristos 560ef36e747Schristos ctx->pane_status = options_get_number(wo, "pane-border-status"); 5619fb66d81Schristos ctx->pane_lines = options_get_number(wo, "pane-border-lines"); 562ef36e747Schristos 563ef36e747Schristos tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy); 564ef36e747Schristos 565ef36e747Schristos log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name, 5666483eba0Schristos w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines, 5676483eba0Schristos ctx->statustop); 568928fc495Schristos } 569928fc495Schristos 570698d5317Sjmmv /* Redraw entire screen. */ 571698d5317Sjmmv void 572ef36e747Schristos screen_redraw_screen(struct client *c) 573698d5317Sjmmv { 5748f3b9483Schristos struct screen_redraw_ctx ctx; 575*f8cf1a91Swiz uint64_t flags; 576698d5317Sjmmv 577d530c4d0Sjmmv if (c->flags & CLIENT_SUSPENDED) 578d530c4d0Sjmmv return; 579d530c4d0Sjmmv 580ef36e747Schristos flags = screen_redraw_update(c, c->flags); 5819fb66d81Schristos if ((flags & CLIENT_ALLREDRAWFLAGS) == 0) 5829fb66d81Schristos return; 5839fb66d81Schristos 584ef36e747Schristos screen_redraw_set_context(c, &ctx); 5859fb66d81Schristos tty_sync_start(&c->tty); 5869fb66d81Schristos tty_update_mode(&c->tty, c->tty.mode, NULL); 5878f3b9483Schristos 588ef36e747Schristos if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) { 5899fb66d81Schristos log_debug("%s: redrawing borders", c->name); 5906483eba0Schristos if (ctx.pane_status != PANE_STATUS_OFF) 591ef36e747Schristos screen_redraw_draw_pane_status(&ctx); 5928f3b9483Schristos screen_redraw_draw_borders(&ctx); 5934e179ddaSchristos } 5949fb66d81Schristos if (flags & CLIENT_REDRAWWINDOW) { 5959fb66d81Schristos log_debug("%s: redrawing panes", c->name); 5968f3b9483Schristos screen_redraw_draw_panes(&ctx); 5979fb66d81Schristos } 5986483eba0Schristos if (ctx.statuslines != 0 && 5999fb66d81Schristos (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) { 6009fb66d81Schristos log_debug("%s: redrawing status", c->name); 6018f3b9483Schristos screen_redraw_draw_status(&ctx); 6029fb66d81Schristos } 6039fb66d81Schristos if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) { 6049fb66d81Schristos log_debug("%s: redrawing overlay", c->name); 6056db26757Swiz c->overlay_draw(c, c->overlay_data, &ctx); 6069fb66d81Schristos } 6079fb66d81Schristos 608ef36e747Schristos tty_reset(&c->tty); 609698d5317Sjmmv } 610698d5317Sjmmv 611ef36e747Schristos /* Redraw a single pane. */ 612698d5317Sjmmv void 613698d5317Sjmmv screen_redraw_pane(struct client *c, struct window_pane *wp) 614698d5317Sjmmv { 615ef36e747Schristos struct screen_redraw_ctx ctx; 616928fc495Schristos 6176db26757Swiz if (!window_pane_visible(wp)) 618928fc495Schristos return; 619928fc495Schristos 620ef36e747Schristos screen_redraw_set_context(c, &ctx); 6219fb66d81Schristos tty_sync_start(&c->tty); 6229fb66d81Schristos tty_update_mode(&c->tty, c->tty.mode, NULL); 623698d5317Sjmmv 624ef36e747Schristos screen_redraw_draw_pane(&ctx, wp); 6259fb66d81Schristos 626698d5317Sjmmv tty_reset(&c->tty); 627698d5317Sjmmv } 628698d5317Sjmmv 6299fb66d81Schristos /* Get border cell style. */ 6309fb66d81Schristos static const struct grid_cell * 6319fb66d81Schristos screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x, 6329fb66d81Schristos u_int y, struct window_pane *wp) 6338f3b9483Schristos { 6348f3b9483Schristos struct client *c = ctx->c; 6358f3b9483Schristos struct session *s = c->session; 6368f3b9483Schristos struct window *w = s->curw->window; 6379fb66d81Schristos struct window_pane *active = server_client_get_pane(c); 6389fb66d81Schristos struct options *oo = w->options; 6399fb66d81Schristos struct format_tree *ft; 6409fb66d81Schristos 6419fb66d81Schristos if (wp->border_gc_set) 6429fb66d81Schristos return (&wp->border_gc); 6439fb66d81Schristos wp->border_gc_set = 1; 6449fb66d81Schristos 6459fb66d81Schristos ft = format_create_defaults(NULL, c, s, s->curw, wp); 646*f8cf1a91Swiz if (screen_redraw_check_is(ctx, x, y, active)) 6479fb66d81Schristos style_apply(&wp->border_gc, oo, "pane-active-border-style", ft); 6489fb66d81Schristos else 6499fb66d81Schristos style_apply(&wp->border_gc, oo, "pane-border-style", ft); 6509fb66d81Schristos format_free(ft); 6519fb66d81Schristos 6529fb66d81Schristos return (&wp->border_gc); 6539fb66d81Schristos } 6549fb66d81Schristos 6559fb66d81Schristos /* Draw a border cell. */ 6569fb66d81Schristos static void 6579fb66d81Schristos screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) 6589fb66d81Schristos { 6599fb66d81Schristos struct client *c = ctx->c; 6609fb66d81Schristos struct session *s = c->session; 6616db26757Swiz struct window *w = s->curw->window; 6626db26757Swiz struct options *oo = w->options; 6638f3b9483Schristos struct tty *tty = &c->tty; 6646db26757Swiz struct format_tree *ft; 6656db26757Swiz struct window_pane *wp, *active = server_client_get_pane(c); 6669fb66d81Schristos struct grid_cell gc; 6679fb66d81Schristos const struct grid_cell *tmp; 6686db26757Swiz struct overlay_ranges r; 6696db26757Swiz u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; 6706db26757Swiz int arrows = 0, border; 671*f8cf1a91Swiz int isolates; 6728f3b9483Schristos 6736db26757Swiz if (c->overlay_check != NULL) { 6746db26757Swiz c->overlay_check(c, c->overlay_data, x, y, 1, &r); 6756db26757Swiz if (r.nx[0] + r.nx[1] == 0) 6768f3b9483Schristos return; 6776db26757Swiz } 6789fb66d81Schristos 679*f8cf1a91Swiz cell_type = screen_redraw_check_cell(ctx, x, y, &wp); 6809fb66d81Schristos if (cell_type == CELL_INSIDE) 6819fb66d81Schristos return; 6829fb66d81Schristos 6836db26757Swiz if (wp == NULL) { 6846db26757Swiz if (!ctx->no_pane_gc_set) { 6856db26757Swiz ft = format_create_defaults(NULL, c, s, s->curw, NULL); 6866db26757Swiz memcpy(&ctx->no_pane_gc, &grid_default_cell, sizeof gc); 6876db26757Swiz style_add(&ctx->no_pane_gc, oo, "pane-border-style", 6886db26757Swiz ft); 6896db26757Swiz format_free(ft); 6906db26757Swiz ctx->no_pane_gc_set = 1; 6916db26757Swiz } 6926db26757Swiz memcpy(&gc, &ctx->no_pane_gc, sizeof gc); 6936db26757Swiz } else { 6949fb66d81Schristos tmp = screen_redraw_draw_borders_style(ctx, x, y, wp); 6959fb66d81Schristos if (tmp == NULL) 6969fb66d81Schristos return; 6979fb66d81Schristos memcpy(&gc, tmp, sizeof gc); 6988f3b9483Schristos 6998f3b9483Schristos if (server_is_marked(s, s->curw, marked_pane.wp) && 700*f8cf1a91Swiz screen_redraw_check_is(ctx, x, y, marked_pane.wp)) 7019fb66d81Schristos gc.attr ^= GRID_ATTR_REVERSE; 7029fb66d81Schristos } 7036db26757Swiz screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc); 7049fb66d81Schristos 7059fb66d81Schristos if (cell_type == CELL_TOPBOTTOM && 7069fb66d81Schristos (c->flags & CLIENT_UTF8) && 7079fb66d81Schristos tty_term_has(tty->term, TTYC_BIDI)) 7089fb66d81Schristos isolates = 1; 7098f3b9483Schristos else 7109fb66d81Schristos isolates = 0; 7119fb66d81Schristos 7126483eba0Schristos if (ctx->statustop) 7136483eba0Schristos tty_cursor(tty, i, ctx->statuslines + j); 7148f3b9483Schristos else 715ef36e747Schristos tty_cursor(tty, i, j); 7169fb66d81Schristos if (isolates) 7179fb66d81Schristos tty_puts(tty, END_ISOLATE); 7186db26757Swiz 7196db26757Swiz switch (options_get_number(oo, "pane-border-indicators")) { 7206db26757Swiz case PANE_BORDER_ARROWS: 7216db26757Swiz case PANE_BORDER_BOTH: 7226db26757Swiz arrows = 1; 7236db26757Swiz break; 7246db26757Swiz } 7256db26757Swiz 7266db26757Swiz if (wp != NULL && arrows) { 727*f8cf1a91Swiz border = screen_redraw_pane_border(ctx, active, x, y); 7286db26757Swiz if (((i == wp->xoff + 1 && 7296db26757Swiz (cell_type == CELL_LEFTRIGHT || 7306db26757Swiz (cell_type == CELL_TOPJOIN && 7316db26757Swiz border == SCREEN_REDRAW_BORDER_BOTTOM) || 7326db26757Swiz (cell_type == CELL_BOTTOMJOIN && 7336db26757Swiz border == SCREEN_REDRAW_BORDER_TOP))) || 7346db26757Swiz (j == wp->yoff + 1 && 7356db26757Swiz (cell_type == CELL_TOPBOTTOM || 7366db26757Swiz (cell_type == CELL_LEFTJOIN && 7376db26757Swiz border == SCREEN_REDRAW_BORDER_RIGHT) || 7386db26757Swiz (cell_type == CELL_RIGHTJOIN && 7396db26757Swiz border == SCREEN_REDRAW_BORDER_LEFT)))) && 740*f8cf1a91Swiz screen_redraw_check_is(ctx, x, y, active)) { 7416db26757Swiz gc.attr |= GRID_ATTR_CHARSET; 7426db26757Swiz utf8_set(&gc.data, BORDER_MARKERS[border]); 7436db26757Swiz } 7446db26757Swiz } 7456db26757Swiz 746c23f9150Swiz tty_cell(tty, &gc, &grid_default_cell, NULL, NULL); 7479fb66d81Schristos if (isolates) 7489fb66d81Schristos tty_puts(tty, START_ISOLATE); 7498f3b9483Schristos } 7508f3b9483Schristos 751928fc495Schristos /* Draw the borders. */ 7524e179ddaSchristos static void 7538f3b9483Schristos screen_redraw_draw_borders(struct screen_redraw_ctx *ctx) 754928fc495Schristos { 7558f3b9483Schristos struct client *c = ctx->c; 7565494e770Schristos struct session *s = c->session; 7575494e770Schristos struct window *w = s->curw->window; 7589fb66d81Schristos struct window_pane *wp; 759ef36e747Schristos u_int i, j; 7605494e770Schristos 761ef36e747Schristos log_debug("%s: %s @%u", __func__, c->name, w->id); 762928fc495Schristos 7639fb66d81Schristos TAILQ_FOREACH(wp, &w->panes, entry) 7649fb66d81Schristos wp->border_gc_set = 0; 765928fc495Schristos 7669fb66d81Schristos for (j = 0; j < c->tty.sy - ctx->statuslines; j++) { 7679fb66d81Schristos for (i = 0; i < c->tty.sx; i++) 7689fb66d81Schristos screen_redraw_draw_borders_cell(ctx, i, j); 769928fc495Schristos } 770928fc495Schristos } 771928fc495Schristos 772928fc495Schristos /* Draw the panes. */ 7734e179ddaSchristos static void 7748f3b9483Schristos screen_redraw_draw_panes(struct screen_redraw_ctx *ctx) 775928fc495Schristos { 7768f3b9483Schristos struct client *c = ctx->c; 777928fc495Schristos struct window *w = c->session->curw->window; 778928fc495Schristos struct window_pane *wp; 779928fc495Schristos 780ef36e747Schristos log_debug("%s: %s @%u", __func__, c->name, w->id); 781ef36e747Schristos 782928fc495Schristos TAILQ_FOREACH(wp, &w->panes, entry) { 7836483eba0Schristos if (window_pane_visible(wp)) 784ef36e747Schristos screen_redraw_draw_pane(ctx, wp); 785928fc495Schristos } 786928fc495Schristos } 787928fc495Schristos 788928fc495Schristos /* Draw the status line. */ 7894e179ddaSchristos static void 7908f3b9483Schristos screen_redraw_draw_status(struct screen_redraw_ctx *ctx) 791928fc495Schristos { 7928f3b9483Schristos struct client *c = ctx->c; 793ef36e747Schristos struct window *w = c->session->curw->window; 794928fc495Schristos struct tty *tty = &c->tty; 795ef36e747Schristos struct screen *s = c->status.active; 7968f3b9483Schristos u_int i, y; 797928fc495Schristos 798ef36e747Schristos log_debug("%s: %s @%u", __func__, c->name, w->id); 799ef36e747Schristos 8006483eba0Schristos if (ctx->statustop) 8018f3b9483Schristos y = 0; 802928fc495Schristos else 8036483eba0Schristos y = c->tty.sy - ctx->statuslines; 8049fb66d81Schristos for (i = 0; i < ctx->statuslines; i++) { 8059fb66d81Schristos tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i, 8069fb66d81Schristos &grid_default_cell, NULL); 8079fb66d81Schristos } 808ef36e747Schristos } 809ef36e747Schristos 810ef36e747Schristos /* Draw one pane. */ 811ef36e747Schristos static void 812ef36e747Schristos screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) 813ef36e747Schristos { 814ef36e747Schristos struct client *c = ctx->c; 815ef36e747Schristos struct window *w = c->session->curw->window; 816ef36e747Schristos struct tty *tty = &c->tty; 8176db26757Swiz struct screen *s = wp->screen; 8186db26757Swiz struct colour_palette *palette = &wp->palette; 8199fb66d81Schristos struct grid_cell defaults; 820ef36e747Schristos u_int i, j, top, x, y, width; 821ef36e747Schristos 822ef36e747Schristos log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id); 823ef36e747Schristos 824ef36e747Schristos if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx) 825ef36e747Schristos return; 8266483eba0Schristos if (ctx->statustop) 8276483eba0Schristos top = ctx->statuslines; 828ef36e747Schristos else 829ef36e747Schristos top = 0; 830ef36e747Schristos for (j = 0; j < wp->sy; j++) { 831ef36e747Schristos if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy) 832ef36e747Schristos continue; 833ef36e747Schristos y = top + wp->yoff + j - ctx->oy; 834ef36e747Schristos 835ef36e747Schristos if (wp->xoff >= ctx->ox && 836ef36e747Schristos wp->xoff + wp->sx <= ctx->ox + ctx->sx) { 837ef36e747Schristos /* All visible. */ 838ef36e747Schristos i = 0; 839ef36e747Schristos x = wp->xoff - ctx->ox; 840ef36e747Schristos width = wp->sx; 841ef36e747Schristos } else if (wp->xoff < ctx->ox && 842ef36e747Schristos wp->xoff + wp->sx > ctx->ox + ctx->sx) { 843ef36e747Schristos /* Both left and right not visible. */ 844ef36e747Schristos i = ctx->ox; 845ef36e747Schristos x = 0; 846ef36e747Schristos width = ctx->sx; 847ef36e747Schristos } else if (wp->xoff < ctx->ox) { 848ef36e747Schristos /* Left not visible. */ 849ef36e747Schristos i = ctx->ox - wp->xoff; 850ef36e747Schristos x = 0; 851ef36e747Schristos width = wp->sx - i; 852ef36e747Schristos } else { 853ef36e747Schristos /* Right not visible. */ 854ef36e747Schristos i = 0; 855ef36e747Schristos x = wp->xoff - ctx->ox; 856ef36e747Schristos width = ctx->sx - x; 857ef36e747Schristos } 858ef36e747Schristos log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u", 859ef36e747Schristos __func__, c->name, wp->id, i, j, x, y, width); 860ef36e747Schristos 8619fb66d81Schristos tty_default_colours(&defaults, wp); 8626db26757Swiz tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette); 863ef36e747Schristos } 864c23f9150Swiz 865c23f9150Swiz #ifdef ENABLE_SIXEL 866c23f9150Swiz tty_draw_images(c, wp, s); 867c23f9150Swiz #endif 868928fc495Schristos } 869