1 1.2 wiz /* $OpenBSD$ */ 2 1.1 jmmv 3 1.1 jmmv /* 4 1.2 wiz * 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.2 wiz #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.2 wiz static void screen_redraw_draw_borders(struct screen_redraw_ctx *); 27 1.2 wiz static void screen_redraw_draw_panes(struct screen_redraw_ctx *); 28 1.2 wiz static void screen_redraw_draw_status(struct screen_redraw_ctx *); 29 1.2 wiz static void screen_redraw_draw_pane(struct screen_redraw_ctx *, 30 1.2 wiz struct window_pane *); 31 1.2 wiz static void screen_redraw_set_context(struct client *, 32 1.2 wiz struct screen_redraw_ctx *); 33 1.2 wiz static void screen_redraw_draw_pane_scrollbars(struct screen_redraw_ctx *); 34 1.2 wiz static void screen_redraw_draw_scrollbar(struct screen_redraw_ctx *, 35 1.2 wiz struct window_pane *, int, int, int, u_int, u_int, u_int); 36 1.2 wiz static void screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *, 37 1.2 wiz struct window_pane *); 38 1.2 wiz 39 1.2 wiz #define START_ISOLATE "\342\201\246" 40 1.2 wiz #define END_ISOLATE "\342\201\251" 41 1.2 wiz 42 1.2 wiz /* Border in relation to a pane. */ 43 1.2 wiz enum screen_redraw_border_type { 44 1.2 wiz SCREEN_REDRAW_OUTSIDE, 45 1.2 wiz SCREEN_REDRAW_INSIDE, 46 1.2 wiz SCREEN_REDRAW_BORDER_LEFT, 47 1.2 wiz SCREEN_REDRAW_BORDER_RIGHT, 48 1.2 wiz SCREEN_REDRAW_BORDER_TOP, 49 1.2 wiz SCREEN_REDRAW_BORDER_BOTTOM 50 1.2 wiz }; 51 1.2 wiz #define BORDER_MARKERS " +,.-" 52 1.2 wiz 53 1.2 wiz /* Get cell border character. */ 54 1.2 wiz static void 55 1.2 wiz screen_redraw_border_set(struct window *w, struct window_pane *wp, 56 1.2 wiz enum pane_lines pane_lines, int cell_type, struct grid_cell *gc) 57 1.1 jmmv { 58 1.2 wiz u_int idx; 59 1.2 wiz 60 1.2 wiz if (cell_type == CELL_OUTSIDE && w->fill_character != NULL) { 61 1.2 wiz utf8_copy(&gc->data, &w->fill_character[0]); 62 1.2 wiz return; 63 1.2 wiz } 64 1.2 wiz 65 1.2 wiz switch (pane_lines) { 66 1.2 wiz case PANE_LINES_NUMBER: 67 1.2 wiz if (cell_type == CELL_OUTSIDE) { 68 1.2 wiz gc->attr |= GRID_ATTR_CHARSET; 69 1.2 wiz utf8_set(&gc->data, CELL_BORDERS[CELL_OUTSIDE]); 70 1.2 wiz break; 71 1.2 wiz } 72 1.2 wiz gc->attr &= ~GRID_ATTR_CHARSET; 73 1.2 wiz if (wp != NULL && window_pane_index(wp, &idx) == 0) 74 1.2 wiz utf8_set(&gc->data, '0' + (idx % 10)); 75 1.2 wiz else 76 1.2 wiz utf8_set(&gc->data, '*'); 77 1.2 wiz break; 78 1.2 wiz case PANE_LINES_DOUBLE: 79 1.2 wiz gc->attr &= ~GRID_ATTR_CHARSET; 80 1.2 wiz utf8_copy(&gc->data, tty_acs_double_borders(cell_type)); 81 1.2 wiz break; 82 1.2 wiz case PANE_LINES_HEAVY: 83 1.2 wiz gc->attr &= ~GRID_ATTR_CHARSET; 84 1.2 wiz utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type)); 85 1.2 wiz break; 86 1.2 wiz case PANE_LINES_SIMPLE: 87 1.2 wiz gc->attr &= ~GRID_ATTR_CHARSET; 88 1.2 wiz utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]); 89 1.2 wiz break; 90 1.2 wiz case PANE_LINES_SPACES: 91 1.2 wiz gc->attr &= ~GRID_ATTR_CHARSET; 92 1.2 wiz utf8_set(&gc->data, ' '); 93 1.2 wiz break; 94 1.2 wiz default: 95 1.2 wiz gc->attr |= GRID_ATTR_CHARSET; 96 1.2 wiz utf8_set(&gc->data, CELL_BORDERS[cell_type]); 97 1.2 wiz break; 98 1.2 wiz } 99 1.2 wiz } 100 1.2 wiz 101 1.2 wiz /* Return if window has only two panes. */ 102 1.2 wiz static int 103 1.2 wiz screen_redraw_two_panes(struct window *w, int direction) 104 1.2 wiz { 105 1.2 wiz struct window_pane *wp; 106 1.2 wiz 107 1.2 wiz wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 108 1.2 wiz if (wp == NULL) 109 1.2 wiz return (0); /* one pane */ 110 1.2 wiz if (TAILQ_NEXT(wp, entry) != NULL) 111 1.2 wiz return (0); /* more than two panes */ 112 1.2 wiz if (direction == 0 && wp->xoff == 0) 113 1.2 wiz return (0); 114 1.2 wiz if (direction == 1 && wp->yoff == 0) 115 1.2 wiz return (0); 116 1.2 wiz return (1); 117 1.2 wiz } 118 1.2 wiz 119 1.2 wiz /* Check if cell is on the border of a pane. */ 120 1.2 wiz static enum screen_redraw_border_type 121 1.2 wiz screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp, 122 1.2 wiz u_int px, u_int py) 123 1.2 wiz { 124 1.2 wiz struct options *oo = wp->window->options; 125 1.2 wiz u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy; 126 1.2 wiz int hsplit = 0, vsplit = 0, pane_status = ctx->pane_status; 127 1.2 wiz int pane_scrollbars = ctx->pane_scrollbars, sb_w = 0; 128 1.2 wiz int sb_pos; 129 1.2 wiz 130 1.2 wiz if (pane_scrollbars != 0) 131 1.2 wiz sb_pos = ctx->pane_scrollbars_pos; 132 1.2 wiz else 133 1.2 wiz sb_pos = 0; 134 1.2 wiz 135 1.1 jmmv /* Inside pane. */ 136 1.2 wiz if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey) 137 1.2 wiz return (SCREEN_REDRAW_INSIDE); 138 1.2 wiz 139 1.2 wiz /* Get pane indicator. */ 140 1.2 wiz switch (options_get_number(oo, "pane-border-indicators")) { 141 1.2 wiz case PANE_BORDER_COLOUR: 142 1.2 wiz case PANE_BORDER_BOTH: 143 1.2 wiz hsplit = screen_redraw_two_panes(wp->window, 0); 144 1.2 wiz vsplit = screen_redraw_two_panes(wp->window, 1); 145 1.2 wiz break; 146 1.2 wiz } 147 1.1 jmmv 148 1.2 wiz /* Are scrollbars enabled? */ 149 1.2 wiz if (window_pane_show_scrollbar(wp, pane_scrollbars)) 150 1.2 wiz sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad; 151 1.2 wiz 152 1.2 wiz /* 153 1.2 wiz * Left/right borders. The wp->sy / 2 test is to colour only half the 154 1.2 wiz * active window's border when there are two panes. 155 1.2 wiz */ 156 1.2 wiz if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { 157 1.2 wiz if (sb_pos == PANE_SCROLLBARS_LEFT) { 158 1.2 wiz if (wp->xoff - sb_w == 0 && px == wp->sx + sb_w) 159 1.2 wiz if (!hsplit || (hsplit && py <= wp->sy / 2)) 160 1.2 wiz return (SCREEN_REDRAW_BORDER_RIGHT); 161 1.2 wiz if (wp->xoff - sb_w != 0) { 162 1.2 wiz if (px == wp->xoff - sb_w - 1 && 163 1.2 wiz (!hsplit || (hsplit && py > wp->sy / 2))) 164 1.2 wiz return (SCREEN_REDRAW_BORDER_LEFT); 165 1.2 wiz if (px == wp->xoff + wp->sx + sb_w - 1) 166 1.2 wiz return (SCREEN_REDRAW_BORDER_RIGHT); 167 1.2 wiz } 168 1.2 wiz } else { /* sb_pos == PANE_SCROLLBARS_RIGHT or disabled*/ 169 1.2 wiz if (wp->xoff == 0 && px == wp->sx + sb_w) 170 1.2 wiz if (!hsplit || (hsplit && py <= wp->sy / 2)) 171 1.2 wiz return (SCREEN_REDRAW_BORDER_RIGHT); 172 1.2 wiz if (wp->xoff != 0) { 173 1.2 wiz if (px == wp->xoff - 1 && 174 1.2 wiz (!hsplit || (hsplit && py > wp->sy / 2))) 175 1.2 wiz return (SCREEN_REDRAW_BORDER_LEFT); 176 1.2 wiz if (px == wp->xoff + wp->sx + sb_w) 177 1.2 wiz return (SCREEN_REDRAW_BORDER_RIGHT); 178 1.2 wiz } 179 1.2 wiz } 180 1.1 jmmv } 181 1.1 jmmv 182 1.1 jmmv /* Top/bottom borders. */ 183 1.2 wiz if (vsplit && pane_status == PANE_STATUS_OFF && sb_w == 0) { 184 1.2 wiz if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2) 185 1.2 wiz return (SCREEN_REDRAW_BORDER_BOTTOM); 186 1.2 wiz if (wp->yoff != 0 && py == wp->yoff - 1 && px > wp->sx / 2) 187 1.2 wiz return (SCREEN_REDRAW_BORDER_TOP); 188 1.2 wiz } else { 189 1.2 wiz if (sb_pos == PANE_SCROLLBARS_LEFT) { 190 1.2 wiz if ((wp->xoff - sb_w == 0 || px >= wp->xoff - sb_w) && 191 1.2 wiz (px <= ex || (sb_w != 0 && px < ex + sb_w))) { 192 1.2 wiz if (wp->yoff != 0 && py == wp->yoff - 1) 193 1.2 wiz return (SCREEN_REDRAW_BORDER_TOP); 194 1.2 wiz if (py == ey) 195 1.2 wiz return (SCREEN_REDRAW_BORDER_BOTTOM); 196 1.2 wiz } 197 1.2 wiz } else { /* sb_pos == PANE_SCROLLBARS_RIGHT */ 198 1.2 wiz if ((wp->xoff == 0 || px >= wp->xoff) && 199 1.2 wiz (px <= ex || (sb_w != 0 && px < ex + sb_w))) { 200 1.2 wiz if (wp->yoff != 0 && py == wp->yoff - 1) 201 1.2 wiz return (SCREEN_REDRAW_BORDER_TOP); 202 1.2 wiz if (py == ey) 203 1.2 wiz return (SCREEN_REDRAW_BORDER_BOTTOM); 204 1.2 wiz } 205 1.2 wiz } 206 1.1 jmmv } 207 1.1 jmmv 208 1.1 jmmv /* Outside pane. */ 209 1.2 wiz return (SCREEN_REDRAW_OUTSIDE); 210 1.1 jmmv } 211 1.1 jmmv 212 1.2 wiz /* Check if a cell is on a border. */ 213 1.2 wiz static int 214 1.2 wiz screen_redraw_cell_border(struct screen_redraw_ctx *ctx, u_int px, u_int py) 215 1.1 jmmv { 216 1.2 wiz struct client *c = ctx->c; 217 1.1 jmmv struct window *w = c->session->curw->window; 218 1.1 jmmv struct window_pane *wp; 219 1.2 wiz u_int sy = w->sy; 220 1.2 wiz 221 1.2 wiz if (ctx->pane_status == PANE_STATUS_BOTTOM) 222 1.2 wiz sy--; 223 1.2 wiz 224 1.2 wiz /* Outside the window? */ 225 1.2 wiz if (px > w->sx || py > sy) 226 1.2 wiz return (0); 227 1.2 wiz 228 1.2 wiz /* On the window border? */ 229 1.2 wiz if (px == w->sx || py == sy) 230 1.2 wiz return (1); 231 1.1 jmmv 232 1.1 jmmv /* Check all the panes. */ 233 1.1 jmmv TAILQ_FOREACH(wp, &w->panes, entry) { 234 1.1 jmmv if (!window_pane_visible(wp)) 235 1.1 jmmv continue; 236 1.2 wiz switch (screen_redraw_pane_border(ctx, wp, px, py)) { 237 1.2 wiz case SCREEN_REDRAW_INSIDE: 238 1.2 wiz return (0); 239 1.2 wiz case SCREEN_REDRAW_OUTSIDE: 240 1.2 wiz break; 241 1.2 wiz default: 242 1.2 wiz return (1); 243 1.2 wiz } 244 1.1 jmmv } 245 1.1 jmmv 246 1.1 jmmv return (0); 247 1.1 jmmv } 248 1.1 jmmv 249 1.2 wiz /* Work out type of border cell from surrounding cells. */ 250 1.2 wiz static int 251 1.2 wiz screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py) 252 1.2 wiz { 253 1.2 wiz struct client *c = ctx->c; 254 1.2 wiz int pane_status = ctx->pane_status; 255 1.2 wiz struct window *w = c->session->curw->window; 256 1.2 wiz u_int sx = w->sx, sy = w->sy; 257 1.2 wiz int borders = 0; 258 1.2 wiz 259 1.2 wiz if (pane_status == PANE_STATUS_BOTTOM) 260 1.2 wiz sy--; 261 1.2 wiz 262 1.2 wiz /* Is this outside the window? */ 263 1.2 wiz if (px > sx || py > sy) 264 1.2 wiz return (CELL_OUTSIDE); 265 1.2 wiz 266 1.2 wiz /* 267 1.2 wiz * Construct a bitmask of whether the cells to the left (bit 8), right, 268 1.2 wiz * top, and bottom (bit 1) of this cell are borders. 269 1.2 wiz * 270 1.2 wiz * bits 8 4 2 1: 2 271 1.2 wiz * 8 + 4 272 1.2 wiz * 1 273 1.2 wiz */ 274 1.2 wiz if (px == 0 || screen_redraw_cell_border(ctx, px - 1, py)) 275 1.2 wiz borders |= 8; 276 1.2 wiz if (px <= sx && screen_redraw_cell_border(ctx, px + 1, py)) 277 1.2 wiz borders |= 4; 278 1.2 wiz if (pane_status == PANE_STATUS_TOP) { 279 1.2 wiz if (py != 0 && 280 1.2 wiz screen_redraw_cell_border(ctx, px, py - 1)) 281 1.2 wiz borders |= 2; 282 1.2 wiz if (screen_redraw_cell_border(ctx, px, py + 1)) 283 1.2 wiz borders |= 1; 284 1.2 wiz } else if (pane_status == PANE_STATUS_BOTTOM) { 285 1.2 wiz if (py == 0 || 286 1.2 wiz screen_redraw_cell_border(ctx, px, py - 1)) 287 1.2 wiz borders |= 2; 288 1.2 wiz if (py != sy && 289 1.2 wiz screen_redraw_cell_border(ctx, px, py + 1)) 290 1.2 wiz borders |= 1; 291 1.2 wiz } else { 292 1.2 wiz if (py == 0 || 293 1.2 wiz screen_redraw_cell_border(ctx, px, py - 1)) 294 1.2 wiz borders |= 2; 295 1.2 wiz if (screen_redraw_cell_border(ctx, px, py + 1)) 296 1.2 wiz borders |= 1; 297 1.2 wiz } 298 1.2 wiz 299 1.2 wiz /* 300 1.2 wiz * Figure out what kind of border this cell is. Only one bit set 301 1.2 wiz * doesn't make sense (can't have a border cell with no others 302 1.2 wiz * connected). 303 1.2 wiz */ 304 1.2 wiz switch (borders) { 305 1.2 wiz case 15: /* 1111, left right top bottom */ 306 1.2 wiz return (CELL_JOIN); 307 1.2 wiz case 14: /* 1110, left right top */ 308 1.2 wiz return (CELL_BOTTOMJOIN); 309 1.2 wiz case 13: /* 1101, left right bottom */ 310 1.2 wiz return (CELL_TOPJOIN); 311 1.2 wiz case 12: /* 1100, left right */ 312 1.2 wiz return (CELL_LEFTRIGHT); 313 1.2 wiz case 11: /* 1011, left top bottom */ 314 1.2 wiz return (CELL_RIGHTJOIN); 315 1.2 wiz case 10: /* 1010, left top */ 316 1.2 wiz return (CELL_BOTTOMRIGHT); 317 1.2 wiz case 9: /* 1001, left bottom */ 318 1.2 wiz return (CELL_TOPRIGHT); 319 1.2 wiz case 7: /* 0111, right top bottom */ 320 1.2 wiz return (CELL_LEFTJOIN); 321 1.2 wiz case 6: /* 0110, right top */ 322 1.2 wiz return (CELL_BOTTOMLEFT); 323 1.2 wiz case 5: /* 0101, right bottom */ 324 1.2 wiz return (CELL_TOPLEFT); 325 1.2 wiz case 3: /* 0011, top bottom */ 326 1.2 wiz return (CELL_TOPBOTTOM); 327 1.2 wiz } 328 1.2 wiz return (CELL_OUTSIDE); 329 1.2 wiz } 330 1.2 wiz 331 1.1 jmmv /* Check if cell inside a pane. */ 332 1.2 wiz static int 333 1.2 wiz screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, 334 1.2 wiz struct window_pane **wpp) 335 1.1 jmmv { 336 1.2 wiz struct client *c = ctx->c; 337 1.1 jmmv struct window *w = c->session->curw->window; 338 1.2 wiz struct window_pane *wp, *active; 339 1.2 wiz int pane_status = ctx->pane_status; 340 1.2 wiz u_int sx = w->sx, sy = w->sy; 341 1.2 wiz int border, pane_scrollbars = ctx->pane_scrollbars; 342 1.2 wiz u_int right, line; 343 1.2 wiz int sb_pos = ctx->pane_scrollbars_pos; 344 1.2 wiz int sb_w; 345 1.2 wiz 346 1.2 wiz *wpp = NULL; 347 1.1 jmmv 348 1.2 wiz if (px > sx || py > sy) 349 1.1 jmmv return (CELL_OUTSIDE); 350 1.2 wiz if (px == sx || py == sy) /* window border */ 351 1.2 wiz return (screen_redraw_type_of_cell(ctx, px, py)); 352 1.2 wiz 353 1.2 wiz if (pane_status != PANE_STATUS_OFF) { 354 1.2 wiz active = wp = server_client_get_pane(c); 355 1.2 wiz do { 356 1.2 wiz if (!window_pane_visible(wp)) 357 1.2 wiz goto next1; 358 1.1 jmmv 359 1.2 wiz if (pane_status == PANE_STATUS_TOP) 360 1.2 wiz line = wp->yoff - 1; 361 1.2 wiz else 362 1.2 wiz line = wp->yoff + sy; 363 1.2 wiz right = wp->xoff + 2 + wp->status_size - 1; 364 1.2 wiz 365 1.2 wiz if (py == line && px >= wp->xoff + 2 && px <= right) 366 1.2 wiz return (CELL_INSIDE); 367 1.2 wiz 368 1.2 wiz next1: 369 1.2 wiz wp = TAILQ_NEXT(wp, entry); 370 1.2 wiz if (wp == NULL) 371 1.2 wiz wp = TAILQ_FIRST(&w->panes); 372 1.2 wiz } while (wp != active); 373 1.2 wiz } 374 1.2 wiz 375 1.2 wiz active = wp = server_client_get_pane(c); 376 1.2 wiz do { 377 1.1 jmmv if (!window_pane_visible(wp)) 378 1.2 wiz goto next2; 379 1.2 wiz *wpp = wp; 380 1.1 jmmv 381 1.2 wiz /* Check if CELL_SCROLLBAR */ 382 1.2 wiz if (window_pane_show_scrollbar(wp, pane_scrollbars)) { 383 1.1 jmmv 384 1.2 wiz if (pane_status == PANE_STATUS_TOP) 385 1.2 wiz line = wp->yoff - 1; 386 1.2 wiz else 387 1.2 wiz line = wp->yoff + wp->sy; 388 1.1 jmmv 389 1.2 wiz /* 390 1.2 wiz * Check if py could lie within a scrollbar. If the 391 1.2 wiz * pane is at the top then py == 0 to sy; if the pane 392 1.2 wiz * is not at the top, then yoff to yoff + sy. 393 1.2 wiz */ 394 1.2 wiz sb_w = wp->scrollbar_style.width + 395 1.2 wiz wp->scrollbar_style.pad; 396 1.2 wiz if ((pane_status && py != line) || 397 1.2 wiz (wp->yoff == 0 && py < wp->sy) || 398 1.2 wiz (py >= wp->yoff && py < wp->yoff + wp->sy)) { 399 1.2 wiz /* Check if px lies within a scrollbar. */ 400 1.2 wiz if ((sb_pos == PANE_SCROLLBARS_RIGHT && 401 1.2 wiz (px >= wp->xoff + wp->sx && 402 1.2 wiz px < wp->xoff + wp->sx + sb_w)) || 403 1.2 wiz (sb_pos == PANE_SCROLLBARS_LEFT && 404 1.2 wiz (px >= wp->xoff - sb_w && 405 1.2 wiz px < wp->xoff))) 406 1.2 wiz return (CELL_SCROLLBAR); 407 1.2 wiz } 408 1.2 wiz } 409 1.1 jmmv 410 1.1 jmmv /* 411 1.2 wiz * If definitely inside, return. If not on border, skip. 412 1.2 wiz * Otherwise work out the cell. 413 1.1 jmmv */ 414 1.2 wiz border = screen_redraw_pane_border(ctx, wp, px, py); 415 1.2 wiz if (border == SCREEN_REDRAW_INSIDE) 416 1.2 wiz return (CELL_INSIDE); 417 1.2 wiz if (border == SCREEN_REDRAW_OUTSIDE) 418 1.2 wiz goto next2; 419 1.2 wiz return (screen_redraw_type_of_cell(ctx, px, py)); 420 1.2 wiz 421 1.2 wiz next2: 422 1.2 wiz wp = TAILQ_NEXT(wp, entry); 423 1.2 wiz if (wp == NULL) 424 1.2 wiz wp = TAILQ_FIRST(&w->panes); 425 1.2 wiz } while (wp != active); 426 1.1 jmmv 427 1.1 jmmv return (CELL_OUTSIDE); 428 1.1 jmmv } 429 1.1 jmmv 430 1.2 wiz /* Check if the border of a particular pane. */ 431 1.2 wiz static int 432 1.2 wiz screen_redraw_check_is(struct screen_redraw_ctx *ctx, u_int px, u_int py, 433 1.2 wiz struct window_pane *wp) 434 1.2 wiz { 435 1.2 wiz enum screen_redraw_border_type border; 436 1.2 wiz 437 1.2 wiz border = screen_redraw_pane_border(ctx, wp, px, py); 438 1.2 wiz if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE) 439 1.2 wiz return (1); 440 1.2 wiz return (0); 441 1.2 wiz } 442 1.2 wiz 443 1.2 wiz /* Update pane status. */ 444 1.2 wiz static int 445 1.2 wiz screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, 446 1.2 wiz struct screen_redraw_ctx *rctx, enum pane_lines pane_lines) 447 1.1 jmmv { 448 1.2 wiz struct window *w = wp->window; 449 1.2 wiz struct grid_cell gc; 450 1.2 wiz const char *fmt; 451 1.2 wiz struct format_tree *ft; 452 1.2 wiz char *expanded; 453 1.2 wiz int pane_status = rctx->pane_status, sb_w = 0; 454 1.2 wiz int pane_scrollbars = rctx->pane_scrollbars; 455 1.2 wiz u_int width, i, cell_type, px, py; 456 1.2 wiz struct screen_write_ctx ctx; 457 1.2 wiz struct screen old; 458 1.2 wiz 459 1.2 wiz if (window_pane_show_scrollbar(wp, pane_scrollbars)) 460 1.2 wiz sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad; 461 1.2 wiz 462 1.2 wiz ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS); 463 1.2 wiz format_defaults(ft, c, c->session, c->session->curw, wp); 464 1.2 wiz 465 1.2 wiz if (wp == server_client_get_pane(c)) 466 1.2 wiz style_apply(&gc, w->options, "pane-active-border-style", ft); 467 1.2 wiz else 468 1.2 wiz style_apply(&gc, w->options, "pane-border-style", ft); 469 1.2 wiz fmt = options_get_string(wp->options, "pane-border-format"); 470 1.1 jmmv 471 1.2 wiz expanded = format_expand_time(ft, fmt); 472 1.2 wiz if (wp->sx < 4) 473 1.2 wiz wp->status_size = width = 0; 474 1.1 jmmv else 475 1.2 wiz wp->status_size = width = wp->sx + sb_w - 2; 476 1.1 jmmv 477 1.2 wiz memcpy(&old, &wp->status_screen, sizeof old); 478 1.2 wiz screen_init(&wp->status_screen, width, 1, 0); 479 1.2 wiz wp->status_screen.mode = 0; 480 1.2 wiz 481 1.2 wiz screen_write_start(&ctx, &wp->status_screen); 482 1.2 wiz 483 1.2 wiz for (i = 0; i < width; i++) { 484 1.2 wiz px = wp->xoff + 2 + i; 485 1.2 wiz if (pane_status == PANE_STATUS_TOP) 486 1.2 wiz py = wp->yoff - 1; 487 1.2 wiz else 488 1.2 wiz py = wp->yoff + wp->sy; 489 1.2 wiz cell_type = screen_redraw_type_of_cell(rctx, px, py); 490 1.2 wiz screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc); 491 1.2 wiz screen_write_cell(&ctx, &gc); 492 1.1 jmmv } 493 1.2 wiz gc.attr &= ~GRID_ATTR_CHARSET; 494 1.2 wiz 495 1.2 wiz screen_write_cursormove(&ctx, 0, 0, 0); 496 1.2 wiz format_draw(&ctx, &gc, width, expanded, NULL, 0); 497 1.2 wiz screen_write_stop(&ctx); 498 1.1 jmmv 499 1.2 wiz free(expanded); 500 1.2 wiz format_free(ft); 501 1.2 wiz 502 1.2 wiz if (grid_compare(wp->status_screen.grid, old.grid) == 0) { 503 1.2 wiz screen_free(&old); 504 1.2 wiz return (0); 505 1.1 jmmv } 506 1.2 wiz screen_free(&old); 507 1.2 wiz return (1); 508 1.2 wiz } 509 1.2 wiz 510 1.2 wiz /* Draw pane status. */ 511 1.2 wiz static void 512 1.2 wiz screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx) 513 1.2 wiz { 514 1.2 wiz struct client *c = ctx->c; 515 1.2 wiz struct window *w = c->session->curw->window; 516 1.2 wiz struct tty *tty = &c->tty; 517 1.2 wiz struct window_pane *wp; 518 1.2 wiz struct screen *s; 519 1.2 wiz u_int i, x, width, xoff, yoff, size; 520 1.1 jmmv 521 1.2 wiz log_debug("%s: %s @%u", __func__, c->name, w->id); 522 1.1 jmmv 523 1.1 jmmv TAILQ_FOREACH(wp, &w->panes, entry) { 524 1.1 jmmv if (!window_pane_visible(wp)) 525 1.1 jmmv continue; 526 1.2 wiz s = &wp->status_screen; 527 1.2 wiz 528 1.2 wiz size = wp->status_size; 529 1.2 wiz if (ctx->pane_status == PANE_STATUS_TOP) 530 1.2 wiz yoff = wp->yoff - 1; 531 1.2 wiz else 532 1.2 wiz yoff = wp->yoff + wp->sy; 533 1.2 wiz xoff = wp->xoff + 2; 534 1.2 wiz 535 1.2 wiz if (xoff + size <= ctx->ox || 536 1.2 wiz xoff >= ctx->ox + ctx->sx || 537 1.2 wiz yoff < ctx->oy || 538 1.2 wiz yoff >= ctx->oy + ctx->sy) 539 1.2 wiz continue; 540 1.2 wiz 541 1.2 wiz if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) { 542 1.2 wiz /* All visible. */ 543 1.2 wiz i = 0; 544 1.2 wiz x = xoff - ctx->ox; 545 1.2 wiz width = size; 546 1.2 wiz } else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) { 547 1.2 wiz /* Both left and right not visible. */ 548 1.2 wiz i = ctx->ox; 549 1.2 wiz x = 0; 550 1.2 wiz width = ctx->sx; 551 1.2 wiz } else if (xoff < ctx->ox) { 552 1.2 wiz /* Left not visible. */ 553 1.2 wiz i = ctx->ox - xoff; 554 1.2 wiz x = 0; 555 1.2 wiz width = size - i; 556 1.2 wiz } else { 557 1.2 wiz /* Right not visible. */ 558 1.2 wiz i = 0; 559 1.2 wiz x = xoff - ctx->ox; 560 1.2 wiz width = size - x; 561 1.2 wiz } 562 1.2 wiz 563 1.2 wiz if (ctx->statustop) 564 1.2 wiz yoff += ctx->statuslines; 565 1.2 wiz tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy, 566 1.2 wiz &grid_default_cell, NULL); 567 1.2 wiz } 568 1.2 wiz tty_cursor(tty, 0, 0); 569 1.2 wiz } 570 1.2 wiz 571 1.2 wiz /* Update status line and change flags if unchanged. */ 572 1.2 wiz static uint64_t 573 1.2 wiz screen_redraw_update(struct screen_redraw_ctx *ctx, uint64_t flags) 574 1.2 wiz { 575 1.2 wiz struct client *c = ctx->c; 576 1.2 wiz struct window *w = c->session->curw->window; 577 1.2 wiz struct window_pane *wp; 578 1.2 wiz int redraw; 579 1.2 wiz enum pane_lines lines; 580 1.2 wiz 581 1.2 wiz if (c->message_string != NULL) 582 1.2 wiz redraw = status_message_redraw(c); 583 1.2 wiz else if (c->prompt_string != NULL) 584 1.2 wiz redraw = status_prompt_redraw(c); 585 1.2 wiz else 586 1.2 wiz redraw = status_redraw(c); 587 1.2 wiz if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS)) 588 1.2 wiz flags &= ~CLIENT_REDRAWSTATUS; 589 1.2 wiz 590 1.2 wiz if (c->overlay_draw != NULL) 591 1.2 wiz flags |= CLIENT_REDRAWOVERLAY; 592 1.2 wiz 593 1.2 wiz if (ctx->pane_status != PANE_STATUS_OFF) { 594 1.2 wiz lines = ctx->pane_lines; 595 1.2 wiz redraw = 0; 596 1.2 wiz TAILQ_FOREACH(wp, &w->panes, entry) { 597 1.2 wiz if (screen_redraw_make_pane_status(c, wp, ctx, lines)) 598 1.2 wiz redraw = 1; 599 1.1 jmmv } 600 1.2 wiz if (redraw) 601 1.2 wiz flags |= CLIENT_REDRAWBORDERS; 602 1.1 jmmv } 603 1.1 jmmv 604 1.2 wiz return (flags); 605 1.1 jmmv } 606 1.1 jmmv 607 1.2 wiz /* Set up redraw context. */ 608 1.2 wiz static void 609 1.2 wiz screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx) 610 1.2 wiz { 611 1.2 wiz struct session *s = c->session; 612 1.2 wiz struct options *oo = s->options; 613 1.2 wiz struct window *w = s->curw->window; 614 1.2 wiz struct options *wo = w->options; 615 1.2 wiz u_int lines; 616 1.2 wiz 617 1.2 wiz memset(ctx, 0, sizeof *ctx); 618 1.2 wiz ctx->c = c; 619 1.2 wiz 620 1.2 wiz lines = status_line_size(c); 621 1.2 wiz if (c->message_string != NULL || c->prompt_string != NULL) 622 1.2 wiz lines = (lines == 0) ? 1 : lines; 623 1.2 wiz if (lines != 0 && options_get_number(oo, "status-position") == 0) 624 1.2 wiz ctx->statustop = 1; 625 1.2 wiz ctx->statuslines = lines; 626 1.2 wiz 627 1.2 wiz ctx->pane_status = options_get_number(wo, "pane-border-status"); 628 1.2 wiz ctx->pane_lines = options_get_number(wo, "pane-border-lines"); 629 1.2 wiz 630 1.2 wiz ctx->pane_scrollbars = options_get_number(wo, "pane-scrollbars"); 631 1.2 wiz ctx->pane_scrollbars_pos = options_get_number(wo, 632 1.2 wiz "pane-scrollbars-position"); 633 1.2 wiz 634 1.2 wiz tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy); 635 1.2 wiz 636 1.2 wiz log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name, 637 1.2 wiz w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines, 638 1.2 wiz ctx->statustop); 639 1.2 wiz } 640 1.2 wiz 641 1.2 wiz /* Redraw entire screen. */ 642 1.1 jmmv void 643 1.2 wiz screen_redraw_screen(struct client *c) 644 1.1 jmmv { 645 1.2 wiz struct screen_redraw_ctx ctx; 646 1.2 wiz uint64_t flags; 647 1.2 wiz 648 1.2 wiz if (c->flags & CLIENT_SUSPENDED) 649 1.2 wiz return; 650 1.2 wiz 651 1.2 wiz screen_redraw_set_context(c, &ctx); 652 1.2 wiz 653 1.2 wiz flags = screen_redraw_update(&ctx, c->flags); 654 1.2 wiz if ((flags & CLIENT_ALLREDRAWFLAGS) == 0) 655 1.2 wiz return; 656 1.2 wiz 657 1.2 wiz tty_sync_start(&c->tty); 658 1.2 wiz tty_update_mode(&c->tty, c->tty.mode, NULL); 659 1.2 wiz 660 1.2 wiz if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) { 661 1.2 wiz log_debug("%s: redrawing borders", c->name); 662 1.2 wiz screen_redraw_draw_borders(&ctx); 663 1.2 wiz if (ctx.pane_status != PANE_STATUS_OFF) 664 1.2 wiz screen_redraw_draw_pane_status(&ctx); 665 1.2 wiz screen_redraw_draw_pane_scrollbars(&ctx); 666 1.2 wiz } 667 1.2 wiz if (flags & CLIENT_REDRAWWINDOW) { 668 1.2 wiz log_debug("%s: redrawing panes", c->name); 669 1.2 wiz screen_redraw_draw_panes(&ctx); 670 1.2 wiz screen_redraw_draw_pane_scrollbars(&ctx); 671 1.2 wiz } 672 1.2 wiz if (ctx.statuslines != 0 && 673 1.2 wiz (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) { 674 1.2 wiz log_debug("%s: redrawing status", c->name); 675 1.2 wiz screen_redraw_draw_status(&ctx); 676 1.2 wiz } 677 1.2 wiz if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) { 678 1.2 wiz log_debug("%s: redrawing overlay", c->name); 679 1.2 wiz c->overlay_draw(c, c->overlay_data, &ctx); 680 1.2 wiz } 681 1.1 jmmv 682 1.1 jmmv tty_reset(&c->tty); 683 1.1 jmmv } 684 1.1 jmmv 685 1.2 wiz /* Redraw a single pane and its scrollbar. */ 686 1.1 jmmv void 687 1.2 wiz screen_redraw_pane(struct client *c, struct window_pane *wp, 688 1.2 wiz int redraw_scrollbar_only) 689 1.2 wiz { 690 1.2 wiz struct screen_redraw_ctx ctx; 691 1.2 wiz 692 1.2 wiz if (!window_pane_visible(wp)) 693 1.2 wiz return; 694 1.2 wiz 695 1.2 wiz screen_redraw_set_context(c, &ctx); 696 1.2 wiz tty_sync_start(&c->tty); 697 1.2 wiz tty_update_mode(&c->tty, c->tty.mode, NULL); 698 1.2 wiz 699 1.2 wiz if (!redraw_scrollbar_only) 700 1.2 wiz screen_redraw_draw_pane(&ctx, wp); 701 1.2 wiz 702 1.2 wiz if (window_pane_show_scrollbar(wp, ctx.pane_scrollbars)) 703 1.2 wiz screen_redraw_draw_pane_scrollbar(&ctx, wp); 704 1.2 wiz 705 1.2 wiz tty_reset(&c->tty); 706 1.2 wiz } 707 1.2 wiz 708 1.2 wiz /* Get border cell style. */ 709 1.2 wiz static const struct grid_cell * 710 1.2 wiz screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x, 711 1.2 wiz u_int y, struct window_pane *wp) 712 1.1 jmmv { 713 1.2 wiz struct client *c = ctx->c; 714 1.2 wiz struct session *s = c->session; 715 1.2 wiz struct window *w = s->curw->window; 716 1.2 wiz struct window_pane *active = server_client_get_pane(c); 717 1.2 wiz struct options *oo = w->options; 718 1.2 wiz struct format_tree *ft; 719 1.2 wiz 720 1.2 wiz if (wp->border_gc_set) 721 1.2 wiz return (&wp->border_gc); 722 1.2 wiz wp->border_gc_set = 1; 723 1.2 wiz 724 1.2 wiz ft = format_create_defaults(NULL, c, s, s->curw, wp); 725 1.2 wiz if (screen_redraw_check_is(ctx, x, y, active)) 726 1.2 wiz style_apply(&wp->border_gc, oo, "pane-active-border-style", ft); 727 1.2 wiz else 728 1.2 wiz style_apply(&wp->border_gc, oo, "pane-border-style", ft); 729 1.2 wiz format_free(ft); 730 1.2 wiz 731 1.2 wiz return (&wp->border_gc); 732 1.2 wiz } 733 1.2 wiz 734 1.2 wiz /* Draw a border cell. */ 735 1.2 wiz static void 736 1.2 wiz screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) 737 1.2 wiz { 738 1.2 wiz struct client *c = ctx->c; 739 1.2 wiz struct session *s = c->session; 740 1.2 wiz struct window *w = s->curw->window; 741 1.2 wiz struct options *oo = w->options; 742 1.1 jmmv struct tty *tty = &c->tty; 743 1.2 wiz struct format_tree *ft; 744 1.2 wiz struct window_pane *wp, *active = server_client_get_pane(c); 745 1.2 wiz struct grid_cell gc; 746 1.2 wiz const struct grid_cell *tmp; 747 1.2 wiz struct overlay_ranges r; 748 1.2 wiz u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; 749 1.2 wiz int arrows = 0, border, isolates; 750 1.2 wiz 751 1.2 wiz if (c->overlay_check != NULL) { 752 1.2 wiz c->overlay_check(c, c->overlay_data, x, y, 1, &r); 753 1.2 wiz if (r.nx[0] + r.nx[1] == 0) 754 1.2 wiz return; 755 1.2 wiz } 756 1.2 wiz 757 1.2 wiz cell_type = screen_redraw_check_cell(ctx, x, y, &wp); 758 1.2 wiz if (cell_type == CELL_INSIDE || cell_type == CELL_SCROLLBAR) 759 1.2 wiz return; 760 1.2 wiz 761 1.2 wiz if (wp == NULL) { 762 1.2 wiz if (!ctx->no_pane_gc_set) { 763 1.2 wiz ft = format_create_defaults(NULL, c, s, s->curw, NULL); 764 1.2 wiz memcpy(&ctx->no_pane_gc, &grid_default_cell, sizeof gc); 765 1.2 wiz style_add(&ctx->no_pane_gc, oo, "pane-border-style", 766 1.2 wiz ft); 767 1.2 wiz format_free(ft); 768 1.2 wiz ctx->no_pane_gc_set = 1; 769 1.2 wiz } 770 1.2 wiz memcpy(&gc, &ctx->no_pane_gc, sizeof gc); 771 1.2 wiz } else { 772 1.2 wiz tmp = screen_redraw_draw_borders_style(ctx, x, y, wp); 773 1.2 wiz if (tmp == NULL) 774 1.2 wiz return; 775 1.2 wiz memcpy(&gc, tmp, sizeof gc); 776 1.2 wiz 777 1.2 wiz if (server_is_marked(s, s->curw, marked_pane.wp) && 778 1.2 wiz screen_redraw_check_is(ctx, x, y, marked_pane.wp)) 779 1.2 wiz gc.attr ^= GRID_ATTR_REVERSE; 780 1.2 wiz } 781 1.2 wiz screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc); 782 1.2 wiz 783 1.2 wiz if (cell_type == CELL_TOPBOTTOM && 784 1.2 wiz (c->flags & CLIENT_UTF8) && 785 1.2 wiz tty_term_has(tty->term, TTYC_BIDI)) 786 1.2 wiz isolates = 1; 787 1.2 wiz else 788 1.2 wiz isolates = 0; 789 1.2 wiz 790 1.2 wiz if (ctx->statustop) 791 1.2 wiz tty_cursor(tty, i, ctx->statuslines + j); 792 1.2 wiz else 793 1.2 wiz tty_cursor(tty, i, j); 794 1.2 wiz if (isolates) 795 1.2 wiz tty_puts(tty, END_ISOLATE); 796 1.2 wiz 797 1.2 wiz switch (options_get_number(oo, "pane-border-indicators")) { 798 1.2 wiz case PANE_BORDER_ARROWS: 799 1.2 wiz case PANE_BORDER_BOTH: 800 1.2 wiz arrows = 1; 801 1.2 wiz break; 802 1.2 wiz } 803 1.2 wiz 804 1.2 wiz if (wp != NULL && arrows) { 805 1.2 wiz border = screen_redraw_pane_border(ctx, active, x, y); 806 1.2 wiz if (((i == wp->xoff + 1 && 807 1.2 wiz (cell_type == CELL_LEFTRIGHT || 808 1.2 wiz (cell_type == CELL_TOPJOIN && 809 1.2 wiz border == SCREEN_REDRAW_BORDER_BOTTOM) || 810 1.2 wiz (cell_type == CELL_BOTTOMJOIN && 811 1.2 wiz border == SCREEN_REDRAW_BORDER_TOP))) || 812 1.2 wiz (j == wp->yoff + 1 && 813 1.2 wiz (cell_type == CELL_TOPBOTTOM || 814 1.2 wiz (cell_type == CELL_LEFTJOIN && 815 1.2 wiz border == SCREEN_REDRAW_BORDER_RIGHT) || 816 1.2 wiz (cell_type == CELL_RIGHTJOIN && 817 1.2 wiz border == SCREEN_REDRAW_BORDER_LEFT)))) && 818 1.2 wiz screen_redraw_check_is(ctx, x, y, active)) { 819 1.2 wiz gc.attr |= GRID_ATTR_CHARSET; 820 1.2 wiz utf8_set(&gc.data, BORDER_MARKERS[border]); 821 1.2 wiz } 822 1.2 wiz } 823 1.2 wiz 824 1.2 wiz tty_cell(tty, &gc, &grid_default_cell, NULL, NULL); 825 1.2 wiz if (isolates) 826 1.2 wiz tty_puts(tty, START_ISOLATE); 827 1.2 wiz } 828 1.2 wiz 829 1.2 wiz /* Draw the borders. */ 830 1.2 wiz static void 831 1.2 wiz screen_redraw_draw_borders(struct screen_redraw_ctx *ctx) 832 1.2 wiz { 833 1.2 wiz struct client *c = ctx->c; 834 1.1 jmmv struct session *s = c->session; 835 1.2 wiz struct window *w = s->curw->window; 836 1.2 wiz struct window_pane *wp; 837 1.2 wiz u_int i, j; 838 1.2 wiz 839 1.2 wiz log_debug("%s: %s @%u", __func__, c->name, w->id); 840 1.2 wiz 841 1.2 wiz TAILQ_FOREACH(wp, &w->panes, entry) 842 1.2 wiz wp->border_gc_set = 0; 843 1.2 wiz 844 1.2 wiz for (j = 0; j < c->tty.sy - ctx->statuslines; j++) { 845 1.2 wiz for (i = 0; i < c->tty.sx; i++) 846 1.2 wiz screen_redraw_draw_borders_cell(ctx, i, j); 847 1.2 wiz } 848 1.2 wiz } 849 1.2 wiz 850 1.2 wiz /* Draw the panes. */ 851 1.2 wiz static void 852 1.2 wiz screen_redraw_draw_panes(struct screen_redraw_ctx *ctx) 853 1.2 wiz { 854 1.2 wiz struct client *c = ctx->c; 855 1.2 wiz struct window *w = c->session->curw->window; 856 1.2 wiz struct window_pane *wp; 857 1.2 wiz 858 1.2 wiz log_debug("%s: %s @%u", __func__, c->name, w->id); 859 1.2 wiz 860 1.2 wiz TAILQ_FOREACH(wp, &w->panes, entry) { 861 1.2 wiz if (window_pane_visible(wp)) 862 1.2 wiz screen_redraw_draw_pane(ctx, wp); 863 1.2 wiz } 864 1.2 wiz } 865 1.2 wiz 866 1.2 wiz /* Draw the status line. */ 867 1.2 wiz static void 868 1.2 wiz screen_redraw_draw_status(struct screen_redraw_ctx *ctx) 869 1.2 wiz { 870 1.2 wiz struct client *c = ctx->c; 871 1.2 wiz struct window *w = c->session->curw->window; 872 1.2 wiz struct tty *tty = &c->tty; 873 1.2 wiz struct screen *s = c->status.active; 874 1.2 wiz u_int i, y; 875 1.2 wiz 876 1.2 wiz log_debug("%s: %s @%u", __func__, c->name, w->id); 877 1.2 wiz 878 1.2 wiz if (ctx->statustop) 879 1.2 wiz y = 0; 880 1.2 wiz else 881 1.2 wiz y = c->tty.sy - ctx->statuslines; 882 1.2 wiz for (i = 0; i < ctx->statuslines; i++) { 883 1.2 wiz tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i, 884 1.2 wiz &grid_default_cell, NULL); 885 1.2 wiz } 886 1.2 wiz } 887 1.2 wiz 888 1.2 wiz /* Draw one pane. */ 889 1.2 wiz static void 890 1.2 wiz screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) 891 1.2 wiz { 892 1.2 wiz struct client *c = ctx->c; 893 1.2 wiz struct window *w = c->session->curw->window; 894 1.2 wiz struct tty *tty = &c->tty; 895 1.2 wiz struct screen *s = wp->screen; 896 1.2 wiz struct colour_palette *palette = &wp->palette; 897 1.2 wiz struct grid_cell defaults; 898 1.2 wiz u_int i, j, top, x, y, width; 899 1.1 jmmv 900 1.2 wiz log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id); 901 1.1 jmmv 902 1.2 wiz if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx) 903 1.1 jmmv return; 904 1.2 wiz if (ctx->statustop) 905 1.2 wiz top = ctx->statuslines; 906 1.2 wiz else 907 1.2 wiz top = 0; 908 1.2 wiz for (j = 0; j < wp->sy; j++) { 909 1.2 wiz if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy) 910 1.2 wiz continue; 911 1.2 wiz y = top + wp->yoff + j - ctx->oy; 912 1.1 jmmv 913 1.2 wiz if (wp->xoff >= ctx->ox && 914 1.2 wiz wp->xoff + wp->sx <= ctx->ox + ctx->sx) { 915 1.2 wiz /* All visible. */ 916 1.2 wiz i = 0; 917 1.2 wiz x = wp->xoff - ctx->ox; 918 1.2 wiz width = wp->sx; 919 1.2 wiz } else if (wp->xoff < ctx->ox && 920 1.2 wiz wp->xoff + wp->sx > ctx->ox + ctx->sx) { 921 1.2 wiz /* Both left and right not visible. */ 922 1.2 wiz i = ctx->ox; 923 1.2 wiz x = 0; 924 1.2 wiz width = ctx->sx; 925 1.2 wiz } else if (wp->xoff < ctx->ox) { 926 1.2 wiz /* Left not visible. */ 927 1.2 wiz i = ctx->ox - wp->xoff; 928 1.2 wiz x = 0; 929 1.2 wiz width = wp->sx - i; 930 1.2 wiz } else { 931 1.2 wiz /* Right not visible. */ 932 1.2 wiz i = 0; 933 1.2 wiz x = wp->xoff - ctx->ox; 934 1.2 wiz width = ctx->sx - x; 935 1.2 wiz } 936 1.2 wiz log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u", 937 1.2 wiz __func__, c->name, wp->id, i, j, x, y, width); 938 1.2 wiz 939 1.2 wiz tty_default_colours(&defaults, wp); 940 1.2 wiz tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette); 941 1.2 wiz } 942 1.1 jmmv 943 1.2 wiz #ifdef ENABLE_SIXEL 944 1.2 wiz tty_draw_images(c, wp, s); 945 1.2 wiz #endif 946 1.2 wiz } 947 1.2 wiz 948 1.2 wiz /* Draw the panes scrollbars */ 949 1.2 wiz static void 950 1.2 wiz screen_redraw_draw_pane_scrollbars(struct screen_redraw_ctx *ctx) 951 1.2 wiz { 952 1.2 wiz struct client *c = ctx->c; 953 1.2 wiz struct window *w = c->session->curw->window; 954 1.2 wiz struct window_pane *wp; 955 1.2 wiz 956 1.2 wiz log_debug("%s: %s @%u", __func__, c->name, w->id); 957 1.2 wiz 958 1.2 wiz TAILQ_FOREACH(wp, &w->panes, entry) { 959 1.2 wiz if (window_pane_show_scrollbar(wp, ctx->pane_scrollbars) && 960 1.2 wiz window_pane_visible(wp)) 961 1.2 wiz screen_redraw_draw_pane_scrollbar(ctx, wp); 962 1.1 jmmv } 963 1.2 wiz } 964 1.1 jmmv 965 1.2 wiz /* Draw pane scrollbar. */ 966 1.2 wiz void 967 1.2 wiz screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *ctx, 968 1.2 wiz struct window_pane *wp) 969 1.2 wiz { 970 1.2 wiz struct screen *s = wp->screen; 971 1.2 wiz double percent_view; 972 1.2 wiz u_int sb = ctx->pane_scrollbars, total_height, sb_h = wp->sy; 973 1.2 wiz u_int sb_pos = ctx->pane_scrollbars_pos, slider_h, slider_y; 974 1.2 wiz int sb_w = wp->scrollbar_style.width; 975 1.2 wiz int sb_pad = wp->scrollbar_style.pad; 976 1.2 wiz u_int cm_y, cm_size; 977 1.2 wiz int xoff = wp->xoff, ox = ctx->ox; 978 1.2 wiz int sb_x, sb_y = (int)(wp->yoff - ctx->oy); /* sb top */ 979 1.2 wiz 980 1.2 wiz if (window_pane_mode(wp) == WINDOW_PANE_NO_MODE) { 981 1.2 wiz if (sb == PANE_SCROLLBARS_MODAL) 982 1.2 wiz return; 983 1.2 wiz /* Show slider at the bottom of the scrollbar. */ 984 1.2 wiz total_height = screen_size_y(s) + screen_hsize(s); 985 1.2 wiz percent_view = (double)sb_h / total_height; 986 1.2 wiz slider_h = (double)sb_h * percent_view; 987 1.2 wiz slider_y = sb_h - slider_h; 988 1.2 wiz } else { 989 1.2 wiz if (TAILQ_FIRST(&wp->modes) == NULL) 990 1.2 wiz return; 991 1.2 wiz if (window_copy_get_current_offset(wp, &cm_y, &cm_size) == 0) 992 1.2 wiz return; 993 1.2 wiz total_height = cm_size + sb_h; 994 1.2 wiz percent_view = (double)sb_h / (cm_size + sb_h); 995 1.2 wiz slider_h = (double)sb_h * percent_view; 996 1.2 wiz slider_y = (sb_h + 1) * ((double)cm_y / total_height); 997 1.2 wiz } 998 1.1 jmmv 999 1.2 wiz if (sb_pos == PANE_SCROLLBARS_LEFT) 1000 1.2 wiz sb_x = xoff - sb_w - sb_pad - ox; 1001 1.1 jmmv else 1002 1.2 wiz sb_x = xoff + wp->sx - ox; 1003 1.2 wiz 1004 1.2 wiz if (slider_h < 1) 1005 1.2 wiz slider_h = 1; 1006 1.2 wiz if (slider_y >= sb_h) 1007 1.2 wiz slider_y = sb_h - 1; 1008 1.2 wiz 1009 1.2 wiz screen_redraw_draw_scrollbar(ctx, wp, sb_pos, sb_x, sb_y, sb_h, 1010 1.2 wiz slider_h, slider_y); 1011 1.2 wiz 1012 1.2 wiz /* Store current position and height of the slider */ 1013 1.2 wiz wp->sb_slider_y = slider_y; /* top of slider y pos in scrollbar */ 1014 1.2 wiz wp->sb_slider_h = slider_h; /* height of slider */ 1015 1.2 wiz } 1016 1.2 wiz 1017 1.2 wiz static void 1018 1.2 wiz screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx, 1019 1.2 wiz struct window_pane *wp, int sb_pos, int sb_x, int sb_y, u_int sb_h, 1020 1.2 wiz u_int slider_h, u_int slider_y) 1021 1.2 wiz { 1022 1.2 wiz struct client *c = ctx->c; 1023 1.2 wiz struct tty *tty = &c->tty; 1024 1.2 wiz struct grid_cell gc, slgc, *gcp; 1025 1.2 wiz struct style *sb_style = &wp->scrollbar_style; 1026 1.2 wiz u_int i, j, imax, jmax; 1027 1.2 wiz u_int sb_w = sb_style->width, sb_pad = sb_style->pad; 1028 1.2 wiz int px, py, ox = ctx->ox, oy = ctx->oy; 1029 1.2 wiz int sx = ctx->sx, sy = ctx->sy, xoff = wp->xoff; 1030 1.2 wiz int yoff = wp->yoff; 1031 1.2 wiz 1032 1.2 wiz if (ctx->statustop) { 1033 1.2 wiz sb_y += ctx->statuslines; 1034 1.2 wiz sy += ctx->statuslines; 1035 1.2 wiz } 1036 1.1 jmmv 1037 1.2 wiz /* Set up style for slider. */ 1038 1.2 wiz gc = sb_style->gc; 1039 1.2 wiz memcpy(&slgc, &gc, sizeof slgc); 1040 1.2 wiz slgc.fg = gc.bg; 1041 1.2 wiz slgc.bg = gc.fg; 1042 1.2 wiz 1043 1.2 wiz imax = sb_w + sb_pad; 1044 1.2 wiz if ((int)imax + sb_x > sx) 1045 1.2 wiz imax = sx - sb_x; 1046 1.2 wiz jmax = sb_h; 1047 1.2 wiz if ((int)jmax + sb_y > sy) 1048 1.2 wiz jmax = sy - sb_y; 1049 1.2 wiz 1050 1.2 wiz for (j = 0; j < jmax; j++) { 1051 1.2 wiz py = sb_y + j; 1052 1.2 wiz for (i = 0; i < imax; i++) { 1053 1.2 wiz px = sb_x + i; 1054 1.2 wiz if (px < xoff - ox - (int)sb_w - (int)sb_pad || 1055 1.2 wiz px >= sx || px < 0 || 1056 1.2 wiz py < yoff - oy - 1 || 1057 1.2 wiz py >= sy || py < 0) 1058 1.2 wiz continue; 1059 1.2 wiz tty_cursor(tty, px, py); 1060 1.2 wiz if ((sb_pos == PANE_SCROLLBARS_LEFT && 1061 1.2 wiz i >= sb_w && i < sb_w + sb_pad) || 1062 1.2 wiz (sb_pos == PANE_SCROLLBARS_RIGHT && 1063 1.2 wiz i < sb_pad)) { 1064 1.2 wiz tty_cell(tty, &grid_default_cell, 1065 1.2 wiz &grid_default_cell, NULL, NULL); 1066 1.2 wiz } else { 1067 1.2 wiz if (j >= slider_y && j < slider_y + slider_h) 1068 1.2 wiz gcp = &slgc; 1069 1.2 wiz else 1070 1.2 wiz gcp = &gc; 1071 1.2 wiz tty_cell(tty, gcp, &grid_default_cell, NULL, 1072 1.2 wiz NULL); 1073 1.1 jmmv } 1074 1.1 jmmv } 1075 1.1 jmmv } 1076 1.1 jmmv } 1077