Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 1 | /* $OpenBSD$ */ |
| 2 | |
| 3 | /* |
nicm | 995af0e | 2016-01-19 15:59:12 +0000 | [diff] [blame] | 4 | * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 5 | * |
| 6 | * Permission to use, copy, modify, and distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above |
| 8 | * copyright notice and this permission notice appear in all copies. |
| 9 | * |
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER |
| 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
| 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 17 | */ |
| 18 | |
| 19 | #include <sys/types.h> |
| 20 | |
nicm | c363c23 | 2017-12-22 23:16:41 +0000 | [diff] [blame] | 21 | #include <stdlib.h> |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 22 | #include <string.h> |
| 23 | |
| 24 | #include "tmux.h" |
| 25 | |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 26 | static void screen_redraw_draw_borders(struct screen_redraw_ctx *); |
| 27 | static void screen_redraw_draw_panes(struct screen_redraw_ctx *); |
| 28 | static void screen_redraw_draw_status(struct screen_redraw_ctx *); |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 29 | static void screen_redraw_draw_pane(struct screen_redraw_ctx *, |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 30 | struct window_pane *); |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 31 | static void screen_redraw_set_context(struct client *, |
| 32 | struct screen_redraw_ctx *); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 33 | |
Nicholas Marriott | 029599c | 2009-07-24 16:21:42 +0000 | [diff] [blame] | 34 | #define CELL_INSIDE 0 |
nicm | 3dddc11 | 2021-02-05 12:29:18 +0000 | [diff] [blame] | 35 | #define CELL_TOPBOTTOM 1 |
| 36 | #define CELL_LEFTRIGHT 2 |
Nicholas Marriott | 1331738 | 2009-07-24 19:14:38 +0000 | [diff] [blame] | 37 | #define CELL_TOPLEFT 3 |
| 38 | #define CELL_TOPRIGHT 4 |
| 39 | #define CELL_BOTTOMLEFT 5 |
| 40 | #define CELL_BOTTOMRIGHT 6 |
| 41 | #define CELL_TOPJOIN 7 |
| 42 | #define CELL_BOTTOMJOIN 8 |
| 43 | #define CELL_LEFTJOIN 9 |
| 44 | #define CELL_RIGHTJOIN 10 |
| 45 | #define CELL_JOIN 11 |
| 46 | #define CELL_OUTSIDE 12 |
| 47 | |
Nicholas Marriott | cb564bb | 2010-09-11 16:19:22 +0000 | [diff] [blame] | 48 | #define CELL_BORDERS " xqlkmjwvtun~" |
nicm | 3dddc11 | 2021-02-05 12:29:18 +0000 | [diff] [blame] | 49 | |
| 50 | #define START_ISOLATE "\342\201\246" |
| 51 | #define END_ISOLATE "\342\201\251" |
Nicholas Marriott | cb564bb | 2010-09-11 16:19:22 +0000 | [diff] [blame] | 52 | |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 53 | static const struct utf8_data screen_redraw_double_borders[] = { |
| 54 | { "", 0, 0, 0 }, |
| 55 | { "\342\225\221", 0, 3, 1 }, /* U+2551 */ |
| 56 | { "\342\225\220", 0, 3, 1 }, /* U+2550 */ |
| 57 | { "\342\225\224", 0, 3, 1 }, /* U+2554 */ |
| 58 | { "\342\225\227", 0, 3, 1 }, /* U+2557 */ |
| 59 | { "\342\225\232", 0, 3, 1 }, /* U+255A */ |
| 60 | { "\342\225\235", 0, 3, 1 }, /* U+255D */ |
| 61 | { "\342\225\246", 0, 3, 1 }, /* U+2566 */ |
| 62 | { "\342\225\251", 0, 3, 1 }, /* U+2569 */ |
| 63 | { "\342\225\240", 0, 3, 1 }, /* U+2560 */ |
| 64 | { "\342\225\243", 0, 3, 1 }, /* U+2563 */ |
| 65 | { "\342\225\254", 0, 3, 1 }, /* U+256C */ |
| 66 | { "\302\267", 0, 2, 1 } /* U+00B7 */ |
| 67 | }; |
| 68 | |
| 69 | static const struct utf8_data screen_redraw_heavy_borders[] = { |
| 70 | { "", 0, 0, 0 }, |
| 71 | { "\342\224\203", 0, 3, 1 }, /* U+2503 */ |
| 72 | { "\342\224\201", 0, 3, 1 }, /* U+2501 */ |
| 73 | { "\342\224\223", 0, 3, 1 }, /* U+2513 */ |
| 74 | { "\342\224\217", 0, 3, 1 }, /* U+250F */ |
| 75 | { "\342\224\227", 0, 3, 1 }, /* U+2517 */ |
| 76 | { "\342\224\233", 0, 3, 1 }, /* U+251B */ |
| 77 | { "\342\224\263", 0, 3, 1 }, /* U+2533 */ |
| 78 | { "\342\224\273", 0, 3, 1 }, /* U+253B */ |
| 79 | { "\342\224\243", 0, 3, 1 }, /* U+2523 */ |
| 80 | { "\342\224\253", 0, 3, 1 }, /* U+252B */ |
| 81 | { "\342\225\213", 0, 3, 1 }, /* U+254B */ |
| 82 | { "\302\267", 0, 2, 1 } /* U+00B7 */ |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 83 | }; |
| 84 | |
| 85 | enum screen_redraw_border_type { |
| 86 | SCREEN_REDRAW_OUTSIDE, |
| 87 | SCREEN_REDRAW_INSIDE, |
| 88 | SCREEN_REDRAW_BORDER |
| 89 | }; |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 90 | |
| 91 | /* Get cell border character. */ |
| 92 | static void |
| 93 | screen_redraw_border_set(struct window_pane *wp, int pane_lines, int cell_type, |
| 94 | struct grid_cell *gc) |
| 95 | { |
| 96 | u_int idx; |
| 97 | |
| 98 | switch (pane_lines) { |
| 99 | case PANE_LINES_NUMBER: |
| 100 | if (cell_type == CELL_OUTSIDE) { |
| 101 | gc->attr |= GRID_ATTR_CHARSET; |
| 102 | utf8_set(&gc->data, CELL_BORDERS[CELL_OUTSIDE]); |
| 103 | break; |
| 104 | } |
| 105 | gc->attr &= ~GRID_ATTR_CHARSET; |
| 106 | if (wp != NULL && window_pane_index(wp, &idx) == 0) |
| 107 | utf8_set(&gc->data, '0' + (idx % 10)); |
| 108 | else |
| 109 | utf8_set(&gc->data, '*'); |
| 110 | break; |
| 111 | case PANE_LINES_DOUBLE: |
| 112 | gc->attr &= ~GRID_ATTR_CHARSET; |
| 113 | utf8_copy(&gc->data, &screen_redraw_double_borders[cell_type]); |
| 114 | break; |
| 115 | case PANE_LINES_HEAVY: |
| 116 | gc->attr &= ~GRID_ATTR_CHARSET; |
| 117 | utf8_copy(&gc->data, &screen_redraw_heavy_borders[cell_type]); |
| 118 | break; |
| 119 | case PANE_LINES_SIMPLE: |
| 120 | gc->attr &= ~GRID_ATTR_CHARSET; |
| 121 | utf8_set(&gc->data, " |-+++++++++."[cell_type]); |
| 122 | break; |
| 123 | default: |
| 124 | gc->attr |= GRID_ATTR_CHARSET; |
| 125 | utf8_set(&gc->data, CELL_BORDERS[cell_type]); |
| 126 | break; |
| 127 | } |
| 128 | } |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 129 | |
| 130 | /* Return if window has only two panes. */ |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 131 | static int |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 132 | screen_redraw_two_panes(struct window *w, int direction) |
Nicholas Marriott | 7e4f8b4 | 2010-01-03 12:51:05 +0000 | [diff] [blame] | 133 | { |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 134 | struct window_pane *wp; |
| 135 | |
| 136 | wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); |
| 137 | if (wp == NULL) |
| 138 | return (0); /* one pane */ |
| 139 | if (TAILQ_NEXT(wp, entry) != NULL) |
| 140 | return (0); /* more than two panes */ |
| 141 | if (direction == 0 && wp->xoff == 0) |
Nicholas Marriott | 7e4f8b4 | 2010-01-03 12:51:05 +0000 | [diff] [blame] | 142 | return (0); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 143 | if (direction == 1 && wp->yoff == 0) |
| 144 | return (0); |
| 145 | return (1); |
| 146 | } |
| 147 | |
| 148 | /* Check if cell is on the border of a pane. */ |
| 149 | static enum screen_redraw_border_type |
| 150 | screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py, |
| 151 | int pane_status) |
| 152 | { |
| 153 | u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy; |
| 154 | |
| 155 | /* Inside pane. */ |
| 156 | if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey) |
| 157 | return (SCREEN_REDRAW_INSIDE); |
Nicholas Marriott | 7e4f8b4 | 2010-01-03 12:51:05 +0000 | [diff] [blame] | 158 | |
| 159 | /* Left/right borders. */ |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 160 | if (pane_status == PANE_STATUS_OFF) { |
| 161 | if (screen_redraw_two_panes(wp->window, 0)) { |
| 162 | if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2) |
| 163 | return (SCREEN_REDRAW_BORDER); |
| 164 | if (wp->xoff != 0 && |
| 165 | px == wp->xoff - 1 && |
| 166 | py > wp->sy / 2) |
| 167 | return (SCREEN_REDRAW_BORDER); |
| 168 | } else { |
| 169 | if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { |
| 170 | if (wp->xoff != 0 && px == wp->xoff - 1) |
| 171 | return (SCREEN_REDRAW_BORDER); |
| 172 | if (px == ex) |
| 173 | return (SCREEN_REDRAW_BORDER); |
| 174 | } |
| 175 | } |
| 176 | } else { |
| 177 | if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { |
| 178 | if (wp->xoff != 0 && px == wp->xoff - 1) |
| 179 | return (SCREEN_REDRAW_BORDER); |
| 180 | if (px == ex) |
| 181 | return (SCREEN_REDRAW_BORDER); |
| 182 | } |
Nicholas Marriott | 7e4f8b4 | 2010-01-03 12:51:05 +0000 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | /* Top/bottom borders. */ |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 186 | if (pane_status == PANE_STATUS_OFF) { |
| 187 | if (screen_redraw_two_panes(wp->window, 1)) { |
| 188 | if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2) |
| 189 | return (SCREEN_REDRAW_BORDER); |
| 190 | if (wp->yoff != 0 && |
| 191 | py == wp->yoff - 1 && |
| 192 | px > wp->sx / 2) |
| 193 | return (SCREEN_REDRAW_BORDER); |
| 194 | } else { |
| 195 | if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { |
| 196 | if (wp->yoff != 0 && py == wp->yoff - 1) |
| 197 | return (SCREEN_REDRAW_BORDER); |
| 198 | if (py == ey) |
| 199 | return (SCREEN_REDRAW_BORDER); |
| 200 | } |
| 201 | } |
| 202 | } else if (pane_status == PANE_STATUS_TOP) { |
| 203 | if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { |
| 204 | if (wp->yoff != 0 && py == wp->yoff - 1) |
| 205 | return (SCREEN_REDRAW_BORDER); |
| 206 | } |
| 207 | } else { |
| 208 | if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { |
| 209 | if (py == ey) |
| 210 | return (SCREEN_REDRAW_BORDER); |
| 211 | } |
Nicholas Marriott | 7e4f8b4 | 2010-01-03 12:51:05 +0000 | [diff] [blame] | 212 | } |
| 213 | |
| 214 | /* Outside pane. */ |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 215 | return (SCREEN_REDRAW_OUTSIDE); |
Nicholas Marriott | 7e4f8b4 | 2010-01-03 12:51:05 +0000 | [diff] [blame] | 216 | } |
| 217 | |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 218 | /* Check if a cell is on a border. */ |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 219 | static int |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 220 | screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status) |
Nicholas Marriott | 1331738 | 2009-07-24 19:14:38 +0000 | [diff] [blame] | 221 | { |
| 222 | struct window *w = c->session->curw->window; |
| 223 | struct window_pane *wp; |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 224 | |
| 225 | /* Outside the window? */ |
| 226 | if (px > w->sx || py > w->sy) |
| 227 | return (0); |
| 228 | |
| 229 | /* On the window border? */ |
| 230 | if (px == w->sx || py == w->sy) |
| 231 | return (1); |
Nicholas Marriott | 1331738 | 2009-07-24 19:14:38 +0000 | [diff] [blame] | 232 | |
| 233 | /* Check all the panes. */ |
| 234 | TAILQ_FOREACH(wp, &w->panes, entry) { |
| 235 | if (!window_pane_visible(wp)) |
| 236 | continue; |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 237 | switch (screen_redraw_pane_border(wp, px, py, pane_status)) { |
| 238 | case SCREEN_REDRAW_INSIDE: |
| 239 | return (0); |
| 240 | case SCREEN_REDRAW_BORDER: |
| 241 | return (1); |
| 242 | case SCREEN_REDRAW_OUTSIDE: |
| 243 | break; |
| 244 | } |
Nicholas Marriott | 1331738 | 2009-07-24 19:14:38 +0000 | [diff] [blame] | 245 | } |
| 246 | |
| 247 | return (0); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 248 | } |
| 249 | |
| 250 | /* Work out type of border cell from surrounding cells. */ |
| 251 | static int |
| 252 | screen_redraw_type_of_cell(struct client *c, u_int px, u_int py, |
| 253 | int pane_status) |
| 254 | { |
| 255 | struct window *w = c->session->curw->window; |
| 256 | u_int sx = w->sx, sy = w->sy; |
| 257 | int borders = 0; |
| 258 | |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 259 | /* Is this outside the window? */ |
nicm | 1f5e520 | 2020-07-22 06:21:46 +0000 | [diff] [blame] | 260 | if (px > sx || py > sy) |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 261 | return (CELL_OUTSIDE); |
| 262 | |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 263 | /* |
| 264 | * Construct a bitmask of whether the cells to the left (bit 4), right, |
| 265 | * top, and bottom (bit 1) of this cell are borders. |
| 266 | */ |
| 267 | if (px == 0 || screen_redraw_cell_border(c, px - 1, py, pane_status)) |
| 268 | borders |= 8; |
| 269 | if (px <= sx && screen_redraw_cell_border(c, px + 1, py, pane_status)) |
| 270 | borders |= 4; |
| 271 | if (pane_status == PANE_STATUS_TOP) { |
| 272 | if (py != 0 && |
| 273 | screen_redraw_cell_border(c, px, py - 1, pane_status)) |
| 274 | borders |= 2; |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 275 | if (screen_redraw_cell_border(c, px, py + 1, pane_status)) |
| 276 | borders |= 1; |
nicm | b6aeb86 | 2020-06-27 10:23:10 +0000 | [diff] [blame] | 277 | } else if (pane_status == PANE_STATUS_BOTTOM) { |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 278 | if (py == 0 || |
| 279 | screen_redraw_cell_border(c, px, py - 1, pane_status)) |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 280 | borders |= 2; |
| 281 | if (py != sy - 1 && |
| 282 | screen_redraw_cell_border(c, px, py + 1, pane_status)) |
| 283 | borders |= 1; |
nicm | b6aeb86 | 2020-06-27 10:23:10 +0000 | [diff] [blame] | 284 | } else { |
| 285 | if (py == 0 || |
| 286 | screen_redraw_cell_border(c, px, py - 1, pane_status)) |
| 287 | borders |= 2; |
| 288 | if (screen_redraw_cell_border(c, px, py + 1, pane_status)) |
| 289 | borders |= 1; |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 290 | } |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 291 | |
| 292 | /* |
| 293 | * Figure out what kind of border this cell is. Only one bit set |
| 294 | * doesn't make sense (can't have a border cell with no others |
| 295 | * connected). |
| 296 | */ |
| 297 | switch (borders) { |
| 298 | case 15: /* 1111, left right top bottom */ |
| 299 | return (CELL_JOIN); |
| 300 | case 14: /* 1110, left right top */ |
| 301 | return (CELL_BOTTOMJOIN); |
| 302 | case 13: /* 1101, left right bottom */ |
| 303 | return (CELL_TOPJOIN); |
| 304 | case 12: /* 1100, left right */ |
nicm | 3dddc11 | 2021-02-05 12:29:18 +0000 | [diff] [blame] | 305 | return (CELL_LEFTRIGHT); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 306 | case 11: /* 1011, left top bottom */ |
| 307 | return (CELL_RIGHTJOIN); |
| 308 | case 10: /* 1010, left top */ |
| 309 | return (CELL_BOTTOMRIGHT); |
| 310 | case 9: /* 1001, left bottom */ |
| 311 | return (CELL_TOPRIGHT); |
| 312 | case 7: /* 0111, right top bottom */ |
| 313 | return (CELL_LEFTJOIN); |
| 314 | case 6: /* 0110, right top */ |
| 315 | return (CELL_BOTTOMLEFT); |
| 316 | case 5: /* 0101, right bottom */ |
| 317 | return (CELL_TOPLEFT); |
| 318 | case 3: /* 0011, top bottom */ |
nicm | 3dddc11 | 2021-02-05 12:29:18 +0000 | [diff] [blame] | 319 | return (CELL_TOPBOTTOM); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 320 | } |
| 321 | return (CELL_OUTSIDE); |
Nicholas Marriott | 1331738 | 2009-07-24 19:14:38 +0000 | [diff] [blame] | 322 | } |
Nicholas Marriott | 029599c | 2009-07-24 16:21:42 +0000 | [diff] [blame] | 323 | |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 324 | /* Check if cell inside a pane. */ |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 325 | static int |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 326 | screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status, |
Nicholas Marriott | 111d993 | 2013-03-25 11:41:49 +0000 | [diff] [blame] | 327 | struct window_pane **wpp) |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 328 | { |
| 329 | struct window *w = c->session->curw->window; |
nicm | 303d342 | 2020-05-16 16:20:59 +0000 | [diff] [blame] | 330 | struct window_pane *wp, *active; |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 331 | int border; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 332 | u_int right, line; |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 333 | |
| 334 | *wpp = NULL; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 335 | |
nicm | 1f5e520 | 2020-07-22 06:21:46 +0000 | [diff] [blame] | 336 | if (px > w->sx || py > w->sy) |
Nicholas Marriott | 029599c | 2009-07-24 16:21:42 +0000 | [diff] [blame] | 337 | return (CELL_OUTSIDE); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 338 | if (px == w->sx || py == w->sy) /* window border */ |
| 339 | return (screen_redraw_type_of_cell(c, px, py, pane_status)); |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 340 | |
nicm | d83f356 | 2019-06-26 13:03:47 +0000 | [diff] [blame] | 341 | if (pane_status != PANE_STATUS_OFF) { |
nicm | 303d342 | 2020-05-16 16:20:59 +0000 | [diff] [blame] | 342 | active = wp = server_client_get_pane(c); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 343 | do { |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 344 | if (!window_pane_visible(wp)) |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 345 | goto next1; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 346 | |
nicm | d83f356 | 2019-06-26 13:03:47 +0000 | [diff] [blame] | 347 | if (pane_status == PANE_STATUS_TOP) |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 348 | line = wp->yoff - 1; |
| 349 | else |
| 350 | line = wp->yoff + wp->sy; |
| 351 | right = wp->xoff + 2 + wp->status_size - 1; |
| 352 | |
| 353 | if (py == line && px >= wp->xoff + 2 && px <= right) |
| 354 | return (CELL_INSIDE); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 355 | |
| 356 | next1: |
| 357 | wp = TAILQ_NEXT(wp, entry); |
| 358 | if (wp == NULL) |
| 359 | wp = TAILQ_FIRST(&w->panes); |
nicm | 303d342 | 2020-05-16 16:20:59 +0000 | [diff] [blame] | 360 | } while (wp != active); |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 361 | } |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 362 | |
nicm | 303d342 | 2020-05-16 16:20:59 +0000 | [diff] [blame] | 363 | active = wp = server_client_get_pane(c); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 364 | do { |
Nicholas Marriott | fe20c0d | 2009-07-14 07:23:36 +0000 | [diff] [blame] | 365 | if (!window_pane_visible(wp)) |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 366 | goto next2; |
Nicholas Marriott | 111d993 | 2013-03-25 11:41:49 +0000 | [diff] [blame] | 367 | *wpp = wp; |
Nicholas Marriott | fe20c0d | 2009-07-14 07:23:36 +0000 | [diff] [blame] | 368 | |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 369 | /* |
| 370 | * If definitely inside, return. If not on border, skip. |
| 371 | * Otherwise work out the cell. |
| 372 | */ |
| 373 | border = screen_redraw_pane_border(wp, px, py, pane_status); |
| 374 | if (border == SCREEN_REDRAW_INSIDE) |
Nicholas Marriott | 029599c | 2009-07-24 16:21:42 +0000 | [diff] [blame] | 375 | return (CELL_INSIDE); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 376 | if (border == SCREEN_REDRAW_OUTSIDE) |
| 377 | goto next2; |
| 378 | return (screen_redraw_type_of_cell(c, px, py, pane_status)); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 379 | |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 380 | next2: |
| 381 | wp = TAILQ_NEXT(wp, entry); |
| 382 | if (wp == NULL) |
| 383 | wp = TAILQ_FIRST(&w->panes); |
nicm | 303d342 | 2020-05-16 16:20:59 +0000 | [diff] [blame] | 384 | } while (wp != active); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 385 | |
Nicholas Marriott | 029599c | 2009-07-24 16:21:42 +0000 | [diff] [blame] | 386 | return (CELL_OUTSIDE); |
Nicholas Marriott | 111d993 | 2013-03-25 11:41:49 +0000 | [diff] [blame] | 387 | } |
| 388 | |
nicm | a863834 | 2015-06-04 11:43:51 +0000 | [diff] [blame] | 389 | /* Check if the border of a particular pane. */ |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 390 | static int |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 391 | screen_redraw_check_is(u_int px, u_int py, int pane_status, |
| 392 | struct window_pane *wp) |
Nicholas Marriott | 111d993 | 2013-03-25 11:41:49 +0000 | [diff] [blame] | 393 | { |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 394 | enum screen_redraw_border_type border; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 395 | |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 396 | border = screen_redraw_pane_border(wp, px, py, pane_status); |
| 397 | if (border == SCREEN_REDRAW_BORDER) |
Nicholas Marriott | 111d993 | 2013-03-25 11:41:49 +0000 | [diff] [blame] | 398 | return (1); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 399 | return (0); |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 400 | } |
| 401 | |
| 402 | /* Update pane status. */ |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 403 | static int |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 404 | screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, |
| 405 | struct screen_redraw_ctx *rctx, int pane_lines) |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 406 | { |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 407 | struct window *w = wp->window; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 408 | struct grid_cell gc; |
| 409 | const char *fmt; |
| 410 | struct format_tree *ft; |
nicm | 9793138 | 2019-03-18 20:53:33 +0000 | [diff] [blame] | 411 | char *expanded; |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 412 | int pane_status = rctx->pane_status; |
nicm | f6095ca | 2020-12-07 09:46:58 +0000 | [diff] [blame] | 413 | u_int width, i, cell_type, px, py; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 414 | struct screen_write_ctx ctx; |
nicm | e0add11 | 2016-10-12 17:36:52 +0000 | [diff] [blame] | 415 | struct screen old; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 416 | |
nicm | 90dba3e | 2019-07-24 21:16:17 +0000 | [diff] [blame] | 417 | ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 418 | format_defaults(ft, c, c->session, c->session->curw, wp); |
| 419 | |
nicm | 303d342 | 2020-05-16 16:20:59 +0000 | [diff] [blame] | 420 | if (wp == server_client_get_pane(c)) |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 421 | style_apply(&gc, w->options, "pane-active-border-style", ft); |
| 422 | else |
| 423 | style_apply(&gc, w->options, "pane-border-style", ft); |
| 424 | fmt = options_get_string(w->options, "pane-border-format"); |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 425 | |
nicm | 9793138 | 2019-03-18 20:53:33 +0000 | [diff] [blame] | 426 | expanded = format_expand_time(ft, fmt); |
nicm | e3b1358 | 2019-04-17 14:41:08 +0000 | [diff] [blame] | 427 | if (wp->sx < 4) |
| 428 | wp->status_size = width = 0; |
| 429 | else |
| 430 | wp->status_size = width = wp->sx - 4; |
nicm | 9793138 | 2019-03-18 20:53:33 +0000 | [diff] [blame] | 431 | |
nicm | e0add11 | 2016-10-12 17:36:52 +0000 | [diff] [blame] | 432 | memcpy(&old, &wp->status_screen, sizeof old); |
nicm | 9793138 | 2019-03-18 20:53:33 +0000 | [diff] [blame] | 433 | screen_init(&wp->status_screen, width, 1, 0); |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 434 | wp->status_screen.mode = 0; |
| 435 | |
nicm | 9605b08 | 2020-05-16 15:34:08 +0000 | [diff] [blame] | 436 | screen_write_start(&ctx, &wp->status_screen); |
nicm | 9793138 | 2019-03-18 20:53:33 +0000 | [diff] [blame] | 437 | |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 438 | for (i = 0; i < width; i++) { |
| 439 | px = wp->xoff + 2 + i; |
| 440 | if (rctx->pane_status == PANE_STATUS_TOP) |
nicm | f6095ca | 2020-12-07 09:46:58 +0000 | [diff] [blame] | 441 | py = wp->yoff - 1; |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 442 | else |
nicm | f6095ca | 2020-12-07 09:46:58 +0000 | [diff] [blame] | 443 | py = wp->yoff + wp->sy; |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 444 | cell_type = screen_redraw_type_of_cell(c, px, py, pane_status); |
| 445 | screen_redraw_border_set(wp, pane_lines, cell_type, &gc); |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 446 | screen_write_cell(&ctx, &gc); |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 447 | } |
nicm | 9793138 | 2019-03-18 20:53:33 +0000 | [diff] [blame] | 448 | gc.attr &= ~GRID_ATTR_CHARSET; |
| 449 | |
nicm | 938156d | 2019-03-12 20:02:47 +0000 | [diff] [blame] | 450 | screen_write_cursormove(&ctx, 0, 0, 0); |
nicm | 9793138 | 2019-03-18 20:53:33 +0000 | [diff] [blame] | 451 | format_draw(&ctx, &gc, width, expanded, NULL); |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 452 | screen_write_stop(&ctx); |
| 453 | |
nicm | 9793138 | 2019-03-18 20:53:33 +0000 | [diff] [blame] | 454 | free(expanded); |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 455 | format_free(ft); |
nicm | e0add11 | 2016-10-12 17:36:52 +0000 | [diff] [blame] | 456 | |
| 457 | if (grid_compare(wp->status_screen.grid, old.grid) == 0) { |
| 458 | screen_free(&old); |
| 459 | return (0); |
| 460 | } |
| 461 | screen_free(&old); |
| 462 | return (1); |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 463 | } |
| 464 | |
| 465 | /* Draw pane status. */ |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 466 | static void |
nicm | 3bc08b0 | 2018-08-18 16:14:03 +0000 | [diff] [blame] | 467 | screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx) |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 468 | { |
nicm | 88327c7 | 2018-08-19 16:45:03 +0000 | [diff] [blame] | 469 | struct client *c = ctx->c; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 470 | struct window *w = c->session->curw->window; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 471 | struct tty *tty = &c->tty; |
| 472 | struct window_pane *wp; |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 473 | struct screen *s; |
| 474 | u_int i, x, width, xoff, yoff, size; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 475 | |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 476 | log_debug("%s: %s @%u", __func__, c->name, w->id); |
| 477 | |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 478 | TAILQ_FOREACH(wp, &w->panes, entry) { |
nicm | e0add11 | 2016-10-12 17:36:52 +0000 | [diff] [blame] | 479 | if (!window_pane_visible(wp)) |
| 480 | continue; |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 481 | s = &wp->status_screen; |
| 482 | |
| 483 | size = wp->status_size; |
nicm | d83f356 | 2019-06-26 13:03:47 +0000 | [diff] [blame] | 484 | if (ctx->pane_status == PANE_STATUS_TOP) |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 485 | yoff = wp->yoff - 1; |
| 486 | else |
| 487 | yoff = wp->yoff + wp->sy; |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 488 | xoff = wp->xoff + 2; |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 489 | |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 490 | if (xoff + size <= ctx->ox || |
| 491 | xoff >= ctx->ox + ctx->sx || |
| 492 | yoff < ctx->oy || |
| 493 | yoff >= ctx->oy + ctx->sy) |
| 494 | continue; |
| 495 | |
| 496 | if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) { |
| 497 | /* All visible. */ |
| 498 | i = 0; |
| 499 | x = xoff - ctx->ox; |
| 500 | width = size; |
| 501 | } else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) { |
| 502 | /* Both left and right not visible. */ |
| 503 | i = ctx->ox; |
| 504 | x = 0; |
| 505 | width = ctx->sx; |
| 506 | } else if (xoff < ctx->ox) { |
| 507 | /* Left not visible. */ |
| 508 | i = ctx->ox - xoff; |
| 509 | x = 0; |
| 510 | width = size - i; |
| 511 | } else { |
| 512 | /* Right not visible. */ |
| 513 | i = 0; |
| 514 | x = xoff - ctx->ox; |
| 515 | width = size - x; |
| 516 | } |
| 517 | |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 518 | if (ctx->statustop) |
| 519 | yoff += ctx->statuslines; |
nicm | 9605b08 | 2020-05-16 15:34:08 +0000 | [diff] [blame] | 520 | tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy, |
| 521 | &grid_default_cell, NULL); |
nicm | 0509be0 | 2016-04-29 15:00:48 +0000 | [diff] [blame] | 522 | } |
| 523 | tty_cursor(tty, 0, 0); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 524 | } |
| 525 | |
nicm | b8f2dd8 | 2016-10-09 16:24:34 +0000 | [diff] [blame] | 526 | /* Update status line and change flags if unchanged. */ |
nicm | cac4ead | 2018-08-19 20:13:07 +0000 | [diff] [blame] | 527 | static int |
| 528 | screen_redraw_update(struct client *c, int flags) |
nicm | b8f2dd8 | 2016-10-09 16:24:34 +0000 | [diff] [blame] | 529 | { |
| 530 | struct window *w = c->session->curw->window; |
| 531 | struct window_pane *wp; |
| 532 | struct options *wo = w->options; |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 533 | int redraw, lines; |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 534 | struct screen_redraw_ctx ctx; |
nicm | b8f2dd8 | 2016-10-09 16:24:34 +0000 | [diff] [blame] | 535 | |
| 536 | if (c->message_string != NULL) |
| 537 | redraw = status_message_redraw(c); |
| 538 | else if (c->prompt_string != NULL) |
| 539 | redraw = status_prompt_redraw(c); |
| 540 | else |
| 541 | redraw = status_redraw(c); |
nicm | cac4ead | 2018-08-19 20:13:07 +0000 | [diff] [blame] | 542 | if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS)) |
| 543 | flags &= ~CLIENT_REDRAWSTATUS; |
nicm | b8f2dd8 | 2016-10-09 16:24:34 +0000 | [diff] [blame] | 544 | |
nicm | 5fef946 | 2019-05-26 18:27:52 +0000 | [diff] [blame] | 545 | if (c->overlay_draw != NULL) |
| 546 | flags |= CLIENT_REDRAWOVERLAY; |
| 547 | |
nicm | d83f356 | 2019-06-26 13:03:47 +0000 | [diff] [blame] | 548 | if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) { |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 549 | screen_redraw_set_context(c, &ctx); |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 550 | lines = options_get_number(wo, "pane-border-lines"); |
nicm | b8f2dd8 | 2016-10-09 16:24:34 +0000 | [diff] [blame] | 551 | redraw = 0; |
| 552 | TAILQ_FOREACH(wp, &w->panes, entry) { |
nicm | 5340bf5 | 2020-06-23 14:10:43 +0000 | [diff] [blame] | 553 | if (screen_redraw_make_pane_status(c, wp, &ctx, lines)) |
nicm | b8f2dd8 | 2016-10-09 16:24:34 +0000 | [diff] [blame] | 554 | redraw = 1; |
| 555 | } |
| 556 | if (redraw) |
nicm | cac4ead | 2018-08-19 20:13:07 +0000 | [diff] [blame] | 557 | flags |= CLIENT_REDRAWBORDERS; |
nicm | b8f2dd8 | 2016-10-09 16:24:34 +0000 | [diff] [blame] | 558 | } |
nicm | cac4ead | 2018-08-19 20:13:07 +0000 | [diff] [blame] | 559 | return (flags); |
nicm | b8f2dd8 | 2016-10-09 16:24:34 +0000 | [diff] [blame] | 560 | } |
| 561 | |
nicm | 3bc08b0 | 2018-08-18 16:14:03 +0000 | [diff] [blame] | 562 | /* Set up redraw context. */ |
| 563 | static void |
| 564 | screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx) |
| 565 | { |
nicm | 88327c7 | 2018-08-19 16:45:03 +0000 | [diff] [blame] | 566 | struct session *s = c->session; |
| 567 | struct options *oo = s->options; |
| 568 | struct window *w = s->curw->window; |
| 569 | struct options *wo = w->options; |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 570 | u_int lines; |
nicm | 3bc08b0 | 2018-08-18 16:14:03 +0000 | [diff] [blame] | 571 | |
| 572 | memset(ctx, 0, sizeof *ctx); |
| 573 | ctx->c = c; |
| 574 | |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 575 | lines = status_line_size(c); |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 576 | if (c->message_string != NULL || c->prompt_string != NULL) |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 577 | lines = (lines == 0) ? 1 : lines; |
| 578 | if (lines != 0 && options_get_number(oo, "status-position") == 0) |
| 579 | ctx->statustop = 1; |
| 580 | ctx->statuslines = lines; |
| 581 | |
nicm | 3bc08b0 | 2018-08-18 16:14:03 +0000 | [diff] [blame] | 582 | ctx->pane_status = options_get_number(wo, "pane-border-status"); |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 583 | ctx->pane_lines = options_get_number(wo, "pane-border-lines"); |
nicm | 3bc08b0 | 2018-08-18 16:14:03 +0000 | [diff] [blame] | 584 | |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 585 | tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy); |
| 586 | |
| 587 | log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name, |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 588 | w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines, |
| 589 | ctx->statustop); |
nicm | 3bc08b0 | 2018-08-18 16:14:03 +0000 | [diff] [blame] | 590 | } |
| 591 | |
Nicholas Marriott | ae2ea52 | 2009-07-14 19:03:16 +0000 | [diff] [blame] | 592 | /* Redraw entire screen. */ |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 593 | void |
nicm | 88327c7 | 2018-08-19 16:45:03 +0000 | [diff] [blame] | 594 | screen_redraw_screen(struct client *c) |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 595 | { |
nicm | 88327c7 | 2018-08-19 16:45:03 +0000 | [diff] [blame] | 596 | struct screen_redraw_ctx ctx; |
nicm | cac4ead | 2018-08-19 20:13:07 +0000 | [diff] [blame] | 597 | int flags; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 598 | |
Nicholas Marriott | d5269a2 | 2011-07-08 21:51:40 +0000 | [diff] [blame] | 599 | if (c->flags & CLIENT_SUSPENDED) |
| 600 | return; |
| 601 | |
nicm | cac4ead | 2018-08-19 20:13:07 +0000 | [diff] [blame] | 602 | flags = screen_redraw_update(c, c->flags); |
nicm | 21a39c9 | 2020-05-16 14:42:06 +0000 | [diff] [blame] | 603 | if ((flags & CLIENT_ALLREDRAWFLAGS) == 0) |
| 604 | return; |
| 605 | |
nicm | 3bc08b0 | 2018-08-18 16:14:03 +0000 | [diff] [blame] | 606 | screen_redraw_set_context(c, &ctx); |
nicm | b2443aa | 2020-04-16 13:35:24 +0000 | [diff] [blame] | 607 | tty_sync_start(&c->tty); |
nicm | ff860e5 | 2021-04-13 05:25:05 +0000 | [diff] [blame] | 608 | tty_update_mode(&c->tty, c->tty.mode, NULL); |
nicm | 2f6935a | 2017-10-16 19:30:53 +0000 | [diff] [blame] | 609 | |
nicm | cac4ead | 2018-08-19 20:13:07 +0000 | [diff] [blame] | 610 | if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) { |
nicm | 1d2bd86 | 2020-04-18 06:20:50 +0000 | [diff] [blame] | 611 | log_debug("%s: redrawing borders", c->name); |
nicm | d83f356 | 2019-06-26 13:03:47 +0000 | [diff] [blame] | 612 | if (ctx.pane_status != PANE_STATUS_OFF) |
nicm | 88327c7 | 2018-08-19 16:45:03 +0000 | [diff] [blame] | 613 | screen_redraw_draw_pane_status(&ctx); |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 614 | screen_redraw_draw_borders(&ctx); |
nicm | 88327c7 | 2018-08-19 16:45:03 +0000 | [diff] [blame] | 615 | } |
nicm | 1d2bd86 | 2020-04-18 06:20:50 +0000 | [diff] [blame] | 616 | if (flags & CLIENT_REDRAWWINDOW) { |
| 617 | log_debug("%s: redrawing panes", c->name); |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 618 | screen_redraw_draw_panes(&ctx); |
nicm | 1d2bd86 | 2020-04-18 06:20:50 +0000 | [diff] [blame] | 619 | } |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 620 | if (ctx.statuslines != 0 && |
nicm | 1d2bd86 | 2020-04-18 06:20:50 +0000 | [diff] [blame] | 621 | (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) { |
| 622 | log_debug("%s: redrawing status", c->name); |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 623 | screen_redraw_draw_status(&ctx); |
nicm | 1d2bd86 | 2020-04-18 06:20:50 +0000 | [diff] [blame] | 624 | } |
| 625 | if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) { |
| 626 | log_debug("%s: redrawing overlay", c->name); |
nicm | 7789639 | 2021-08-13 18:54:54 +0000 | [diff] [blame] | 627 | c->overlay_draw(c, c->overlay_data, &ctx); |
nicm | 1d2bd86 | 2020-04-18 06:20:50 +0000 | [diff] [blame] | 628 | } |
nicm | b2443aa | 2020-04-16 13:35:24 +0000 | [diff] [blame] | 629 | |
nicm | 3bc08b0 | 2018-08-18 16:14:03 +0000 | [diff] [blame] | 630 | tty_reset(&c->tty); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 631 | } |
| 632 | |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 633 | /* Redraw a single pane. */ |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 634 | void |
| 635 | screen_redraw_pane(struct client *c, struct window_pane *wp) |
| 636 | { |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 637 | struct screen_redraw_ctx ctx; |
Nicholas Marriott | 230d0fb | 2012-01-29 09:37:02 +0000 | [diff] [blame] | 638 | |
nicm | 93cc8df | 2021-08-05 09:43:51 +0000 | [diff] [blame] | 639 | if (!window_pane_visible(wp)) |
Nicholas Marriott | 446fb0c | 2013-03-25 10:12:01 +0000 | [diff] [blame] | 640 | return; |
| 641 | |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 642 | screen_redraw_set_context(c, &ctx); |
nicm | b2443aa | 2020-04-16 13:35:24 +0000 | [diff] [blame] | 643 | tty_sync_start(&c->tty); |
nicm | ff860e5 | 2021-04-13 05:25:05 +0000 | [diff] [blame] | 644 | tty_update_mode(&c->tty, c->tty.mode, NULL); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 645 | |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 646 | screen_redraw_draw_pane(&ctx, wp); |
nicm | b2443aa | 2020-04-16 13:35:24 +0000 | [diff] [blame] | 647 | |
Nicholas Marriott | 181e1bc | 2009-08-10 19:42:03 +0000 | [diff] [blame] | 648 | tty_reset(&c->tty); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 649 | } |
Nicholas Marriott | 0431996 | 2009-08-31 20:46:19 +0000 | [diff] [blame] | 650 | |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 651 | /* Get border cell style. */ |
| 652 | static const struct grid_cell * |
| 653 | screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x, |
| 654 | u_int y, struct window_pane *wp) |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 655 | { |
nicm | 88327c7 | 2018-08-19 16:45:03 +0000 | [diff] [blame] | 656 | struct client *c = ctx->c; |
| 657 | struct session *s = c->session; |
| 658 | struct window *w = s->curw->window; |
nicm | 303d342 | 2020-05-16 16:20:59 +0000 | [diff] [blame] | 659 | struct window_pane *active = server_client_get_pane(c); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 660 | struct options *oo = w->options; |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 661 | struct format_tree *ft; |
| 662 | |
| 663 | if (wp->border_gc_set) |
| 664 | return (&wp->border_gc); |
| 665 | wp->border_gc_set = 1; |
| 666 | |
| 667 | ft = format_create_defaults(NULL, c, s, s->curw, wp); |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 668 | if (screen_redraw_check_is(x, y, ctx->pane_status, active)) |
| 669 | style_apply(&wp->border_gc, oo, "pane-active-border-style", ft); |
| 670 | else |
| 671 | style_apply(&wp->border_gc, oo, "pane-border-style", ft); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 672 | format_free(ft); |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 673 | |
| 674 | return (&wp->border_gc); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 675 | } |
| 676 | |
| 677 | /* Draw a border cell. */ |
| 678 | static void |
| 679 | screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) |
| 680 | { |
| 681 | struct client *c = ctx->c; |
| 682 | struct session *s = c->session; |
nicm | 9013600 | 2021-08-11 09:05:21 +0000 | [diff] [blame] | 683 | struct window *w = s->curw->window; |
| 684 | struct options *oo = w->options; |
nicm | 88327c7 | 2018-08-19 16:45:03 +0000 | [diff] [blame] | 685 | struct tty *tty = &c->tty; |
nicm | 9013600 | 2021-08-11 09:05:21 +0000 | [diff] [blame] | 686 | struct format_tree *ft; |
nicm | 88327c7 | 2018-08-19 16:45:03 +0000 | [diff] [blame] | 687 | struct window_pane *wp; |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 688 | u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; |
nicm | 3dddc11 | 2021-02-05 12:29:18 +0000 | [diff] [blame] | 689 | int pane_status = ctx->pane_status, isolates; |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 690 | struct grid_cell gc; |
| 691 | const struct grid_cell *tmp; |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 692 | |
nicm | 7789639 | 2021-08-13 18:54:54 +0000 | [diff] [blame] | 693 | if (c->overlay_check != NULL && |
| 694 | !c->overlay_check(c, c->overlay_data, x, y)) |
nicm | 8a838b0 | 2020-03-24 08:09:43 +0000 | [diff] [blame] | 695 | return; |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 696 | |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 697 | cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp); |
| 698 | if (cell_type == CELL_INSIDE) |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 699 | return; |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 700 | |
nicm | 9013600 | 2021-08-11 09:05:21 +0000 | [diff] [blame] | 701 | if (wp == NULL) { |
| 702 | if (!ctx->no_pane_gc_set) { |
| 703 | ft = format_create_defaults(NULL, c, s, s->curw, NULL); |
| 704 | memcpy(&ctx->no_pane_gc, &grid_default_cell, sizeof gc); |
| 705 | style_add(&ctx->no_pane_gc, oo, "pane-border-style", |
| 706 | ft); |
| 707 | format_free(ft); |
| 708 | ctx->no_pane_gc_set = 1; |
| 709 | } |
| 710 | memcpy(&gc, &ctx->no_pane_gc, sizeof gc); |
| 711 | } else { |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 712 | tmp = screen_redraw_draw_borders_style(ctx, x, y, wp); |
| 713 | if (tmp == NULL) |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 714 | return; |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 715 | memcpy(&gc, tmp, sizeof gc); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 716 | |
| 717 | if (server_is_marked(s, s->curw, marked_pane.wp) && |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 718 | screen_redraw_check_is(x, y, pane_status, marked_pane.wp)) |
| 719 | gc.attr ^= GRID_ATTR_REVERSE; |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 720 | } |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 721 | screen_redraw_border_set(wp, ctx->pane_lines, cell_type, &gc); |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 722 | |
nicm | 3dddc11 | 2021-02-05 12:29:18 +0000 | [diff] [blame] | 723 | if (cell_type == CELL_TOPBOTTOM && |
| 724 | (c->flags & CLIENT_UTF8) && |
| 725 | tty_term_has(tty->term, TTYC_BIDI)) |
| 726 | isolates = 1; |
| 727 | else |
| 728 | isolates = 0; |
| 729 | |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 730 | if (ctx->statustop) |
| 731 | tty_cursor(tty, i, ctx->statuslines + j); |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 732 | else |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 733 | tty_cursor(tty, i, j); |
nicm | 3dddc11 | 2021-02-05 12:29:18 +0000 | [diff] [blame] | 734 | if (isolates) |
| 735 | tty_puts(tty, END_ISOLATE); |
nicm | e2a2674 | 2020-05-16 16:26:34 +0000 | [diff] [blame] | 736 | tty_cell(tty, &gc, &grid_default_cell, NULL); |
nicm | 3dddc11 | 2021-02-05 12:29:18 +0000 | [diff] [blame] | 737 | if (isolates) |
| 738 | tty_puts(tty, START_ISOLATE); |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 739 | } |
| 740 | |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 741 | /* Draw the borders. */ |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 742 | static void |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 743 | screen_redraw_draw_borders(struct screen_redraw_ctx *ctx) |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 744 | { |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 745 | struct client *c = ctx->c; |
nicm | a863834 | 2015-06-04 11:43:51 +0000 | [diff] [blame] | 746 | struct session *s = c->session; |
| 747 | struct window *w = s->curw->window; |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 748 | struct window_pane *wp; |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 749 | u_int i, j; |
nicm | e092926 | 2014-11-14 02:19:47 +0000 | [diff] [blame] | 750 | |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 751 | log_debug("%s: %s @%u", __func__, c->name, w->id); |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 752 | |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 753 | TAILQ_FOREACH(wp, &w->panes, entry) |
| 754 | wp->border_gc_set = 0; |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 755 | |
nicm | f03b611 | 2020-05-16 15:01:30 +0000 | [diff] [blame] | 756 | for (j = 0; j < c->tty.sy - ctx->statuslines; j++) { |
| 757 | for (i = 0; i < c->tty.sx; i++) |
| 758 | screen_redraw_draw_borders_cell(ctx, i, j); |
nicm | e092926 | 2014-11-14 02:19:47 +0000 | [diff] [blame] | 759 | } |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 760 | } |
| 761 | |
| 762 | /* Draw the panes. */ |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 763 | static void |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 764 | screen_redraw_draw_panes(struct screen_redraw_ctx *ctx) |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 765 | { |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 766 | struct client *c = ctx->c; |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 767 | struct window *w = c->session->curw->window; |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 768 | struct window_pane *wp; |
nicm | 2f6935a | 2017-10-16 19:30:53 +0000 | [diff] [blame] | 769 | |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 770 | log_debug("%s: %s @%u", __func__, c->name, w->id); |
| 771 | |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 772 | TAILQ_FOREACH(wp, &w->panes, entry) { |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 773 | if (window_pane_visible(wp)) |
| 774 | screen_redraw_draw_pane(ctx, wp); |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 775 | } |
| 776 | } |
| 777 | |
| 778 | /* Draw the status line. */ |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 779 | static void |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 780 | screen_redraw_draw_status(struct screen_redraw_ctx *ctx) |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 781 | { |
nicm | d0a600c | 2018-08-14 11:31:34 +0000 | [diff] [blame] | 782 | struct client *c = ctx->c; |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 783 | struct window *w = c->session->curw->window; |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 784 | struct tty *tty = &c->tty; |
nicm | b588b17 | 2019-03-16 19:12:13 +0000 | [diff] [blame] | 785 | struct screen *s = c->status.active; |
nicm | 2f6935a | 2017-10-16 19:30:53 +0000 | [diff] [blame] | 786 | u_int i, y; |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 787 | |
| 788 | log_debug("%s: %s @%u", __func__, c->name, w->id); |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 789 | |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 790 | if (ctx->statustop) |
nicm | 2f6935a | 2017-10-16 19:30:53 +0000 | [diff] [blame] | 791 | y = 0; |
nicm | 9f02feb | 2014-01-31 14:19:24 +0000 | [diff] [blame] | 792 | else |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 793 | y = c->tty.sy - ctx->statuslines; |
nicm | 9605b08 | 2020-05-16 15:34:08 +0000 | [diff] [blame] | 794 | for (i = 0; i < ctx->statuslines; i++) { |
| 795 | tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i, |
| 796 | &grid_default_cell, NULL); |
| 797 | } |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 798 | } |
| 799 | |
| 800 | /* Draw one pane. */ |
| 801 | static void |
| 802 | screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) |
| 803 | { |
nicm | 7eea3d7 | 2021-08-11 20:49:55 +0000 | [diff] [blame] | 804 | struct client *c = ctx->c; |
| 805 | struct window *w = c->session->curw->window; |
| 806 | struct tty *tty = &c->tty; |
| 807 | struct screen *s = wp->screen; |
| 808 | struct colour_palette *palette = &wp->palette; |
| 809 | struct grid_cell defaults; |
| 810 | u_int i, j, top, x, y, width; |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 811 | |
| 812 | log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id); |
| 813 | |
| 814 | if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx) |
| 815 | return; |
nicm | 89db309 | 2019-05-07 20:01:41 +0000 | [diff] [blame] | 816 | if (ctx->statustop) |
| 817 | top = ctx->statuslines; |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 818 | else |
| 819 | top = 0; |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 820 | for (j = 0; j < wp->sy; j++) { |
| 821 | if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy) |
| 822 | continue; |
| 823 | y = top + wp->yoff + j - ctx->oy; |
| 824 | |
| 825 | if (wp->xoff >= ctx->ox && |
| 826 | wp->xoff + wp->sx <= ctx->ox + ctx->sx) { |
| 827 | /* All visible. */ |
| 828 | i = 0; |
| 829 | x = wp->xoff - ctx->ox; |
| 830 | width = wp->sx; |
| 831 | } else if (wp->xoff < ctx->ox && |
| 832 | wp->xoff + wp->sx > ctx->ox + ctx->sx) { |
| 833 | /* Both left and right not visible. */ |
| 834 | i = ctx->ox; |
| 835 | x = 0; |
| 836 | width = ctx->sx; |
| 837 | } else if (wp->xoff < ctx->ox) { |
| 838 | /* Left not visible. */ |
| 839 | i = ctx->ox - wp->xoff; |
| 840 | x = 0; |
| 841 | width = wp->sx - i; |
| 842 | } else { |
| 843 | /* Right not visible. */ |
| 844 | i = 0; |
| 845 | x = wp->xoff - ctx->ox; |
| 846 | width = ctx->sx - x; |
| 847 | } |
| 848 | log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u", |
| 849 | __func__, c->name, wp->id, i, j, x, y, width); |
| 850 | |
nicm | 9605b08 | 2020-05-16 15:34:08 +0000 | [diff] [blame] | 851 | tty_default_colours(&defaults, wp); |
nicm | 7eea3d7 | 2021-08-11 20:49:55 +0000 | [diff] [blame] | 852 | tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette); |
nicm | 6469953 | 2018-10-18 08:38:01 +0000 | [diff] [blame] | 853 | } |
Nicholas Marriott | 0431996 | 2009-08-31 20:46:19 +0000 | [diff] [blame] | 854 | } |