Do not try to strdup NULL, from seL4 at disroot dot org in GitHub issue
[tmux-openbsd.git] / screen-redraw.c
blob5ef9e64c4f9c7a7b957677a53b0b5b363163db8b
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include "tmux.h"
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 *);
29 static void screen_redraw_draw_pane(struct screen_redraw_ctx *,
30 struct window_pane *);
31 static void screen_redraw_set_context(struct client *,
32 struct screen_redraw_ctx *);
34 #define START_ISOLATE "\342\201\246"
35 #define END_ISOLATE "\342\201\251"
37 enum screen_redraw_border_type {
38 SCREEN_REDRAW_OUTSIDE,
39 SCREEN_REDRAW_INSIDE,
40 SCREEN_REDRAW_BORDER
43 /* Get cell border character. */
44 static void
45 screen_redraw_border_set(struct window_pane *wp, enum pane_lines pane_lines,
46 int cell_type, struct grid_cell *gc)
48 u_int idx;
50 switch (pane_lines) {
51 case PANE_LINES_NUMBER:
52 if (cell_type == CELL_OUTSIDE) {
53 gc->attr |= GRID_ATTR_CHARSET;
54 utf8_set(&gc->data, CELL_BORDERS[CELL_OUTSIDE]);
55 break;
57 gc->attr &= ~GRID_ATTR_CHARSET;
58 if (wp != NULL && window_pane_index(wp, &idx) == 0)
59 utf8_set(&gc->data, '0' + (idx % 10));
60 else
61 utf8_set(&gc->data, '*');
62 break;
63 case PANE_LINES_DOUBLE:
64 gc->attr &= ~GRID_ATTR_CHARSET;
65 utf8_copy(&gc->data, tty_acs_double_borders(cell_type));
66 break;
67 case PANE_LINES_HEAVY:
68 gc->attr &= ~GRID_ATTR_CHARSET;
69 utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
70 break;
71 case PANE_LINES_SIMPLE:
72 gc->attr &= ~GRID_ATTR_CHARSET;
73 utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
74 break;
75 default:
76 gc->attr |= GRID_ATTR_CHARSET;
77 utf8_set(&gc->data, CELL_BORDERS[cell_type]);
78 break;
82 /* Return if window has only two panes. */
83 static int
84 screen_redraw_two_panes(struct window *w, int direction)
86 struct window_pane *wp;
88 wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
89 if (wp == NULL)
90 return (0); /* one pane */
91 if (TAILQ_NEXT(wp, entry) != NULL)
92 return (0); /* more than two panes */
93 if (direction == 0 && wp->xoff == 0)
94 return (0);
95 if (direction == 1 && wp->yoff == 0)
96 return (0);
97 return (1);
100 /* Check if cell is on the border of a pane. */
101 static enum screen_redraw_border_type
102 screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py,
103 int pane_status)
105 u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
107 /* Inside pane. */
108 if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
109 return (SCREEN_REDRAW_INSIDE);
111 /* Left/right borders. */
112 if (pane_status == PANE_STATUS_OFF) {
113 if (screen_redraw_two_panes(wp->window, 0)) {
114 if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2)
115 return (SCREEN_REDRAW_BORDER);
116 if (wp->xoff != 0 &&
117 px == wp->xoff - 1 &&
118 py > wp->sy / 2)
119 return (SCREEN_REDRAW_BORDER);
120 } else {
121 if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
122 if (wp->xoff != 0 && px == wp->xoff - 1)
123 return (SCREEN_REDRAW_BORDER);
124 if (px == ex)
125 return (SCREEN_REDRAW_BORDER);
128 } else {
129 if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
130 if (wp->xoff != 0 && px == wp->xoff - 1)
131 return (SCREEN_REDRAW_BORDER);
132 if (px == ex)
133 return (SCREEN_REDRAW_BORDER);
137 /* Top/bottom borders. */
138 if (pane_status == PANE_STATUS_OFF) {
139 if (screen_redraw_two_panes(wp->window, 1)) {
140 if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
141 return (SCREEN_REDRAW_BORDER);
142 if (wp->yoff != 0 &&
143 py == wp->yoff - 1 &&
144 px > wp->sx / 2)
145 return (SCREEN_REDRAW_BORDER);
146 } else {
147 if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
148 if (wp->yoff != 0 && py == wp->yoff - 1)
149 return (SCREEN_REDRAW_BORDER);
150 if (py == ey)
151 return (SCREEN_REDRAW_BORDER);
154 } else if (pane_status == PANE_STATUS_TOP) {
155 if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
156 if (wp->yoff != 0 && py == wp->yoff - 1)
157 return (SCREEN_REDRAW_BORDER);
159 } else {
160 if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
161 if (py == ey)
162 return (SCREEN_REDRAW_BORDER);
166 /* Outside pane. */
167 return (SCREEN_REDRAW_OUTSIDE);
170 /* Check if a cell is on a border. */
171 static int
172 screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status)
174 struct window *w = c->session->curw->window;
175 struct window_pane *wp;
177 /* Outside the window? */
178 if (px > w->sx || py > w->sy)
179 return (0);
181 /* On the window border? */
182 if (px == w->sx || py == w->sy)
183 return (1);
185 /* Check all the panes. */
186 TAILQ_FOREACH(wp, &w->panes, entry) {
187 if (!window_pane_visible(wp))
188 continue;
189 switch (screen_redraw_pane_border(wp, px, py, pane_status)) {
190 case SCREEN_REDRAW_INSIDE:
191 return (0);
192 case SCREEN_REDRAW_BORDER:
193 return (1);
194 case SCREEN_REDRAW_OUTSIDE:
195 break;
199 return (0);
202 /* Work out type of border cell from surrounding cells. */
203 static int
204 screen_redraw_type_of_cell(struct client *c, u_int px, u_int py,
205 int pane_status)
207 struct window *w = c->session->curw->window;
208 u_int sx = w->sx, sy = w->sy;
209 int borders = 0;
211 /* Is this outside the window? */
212 if (px > sx || py > sy)
213 return (CELL_OUTSIDE);
216 * Construct a bitmask of whether the cells to the left (bit 4), right,
217 * top, and bottom (bit 1) of this cell are borders.
219 if (px == 0 || screen_redraw_cell_border(c, px - 1, py, pane_status))
220 borders |= 8;
221 if (px <= sx && screen_redraw_cell_border(c, px + 1, py, pane_status))
222 borders |= 4;
223 if (pane_status == PANE_STATUS_TOP) {
224 if (py != 0 &&
225 screen_redraw_cell_border(c, px, py - 1, pane_status))
226 borders |= 2;
227 if (screen_redraw_cell_border(c, px, py + 1, pane_status))
228 borders |= 1;
229 } else if (pane_status == PANE_STATUS_BOTTOM) {
230 if (py == 0 ||
231 screen_redraw_cell_border(c, px, py - 1, pane_status))
232 borders |= 2;
233 if (py != sy - 1 &&
234 screen_redraw_cell_border(c, px, py + 1, pane_status))
235 borders |= 1;
236 } else {
237 if (py == 0 ||
238 screen_redraw_cell_border(c, px, py - 1, pane_status))
239 borders |= 2;
240 if (screen_redraw_cell_border(c, px, py + 1, pane_status))
241 borders |= 1;
245 * Figure out what kind of border this cell is. Only one bit set
246 * doesn't make sense (can't have a border cell with no others
247 * connected).
249 switch (borders) {
250 case 15: /* 1111, left right top bottom */
251 return (CELL_JOIN);
252 case 14: /* 1110, left right top */
253 return (CELL_BOTTOMJOIN);
254 case 13: /* 1101, left right bottom */
255 return (CELL_TOPJOIN);
256 case 12: /* 1100, left right */
257 return (CELL_LEFTRIGHT);
258 case 11: /* 1011, left top bottom */
259 return (CELL_RIGHTJOIN);
260 case 10: /* 1010, left top */
261 return (CELL_BOTTOMRIGHT);
262 case 9: /* 1001, left bottom */
263 return (CELL_TOPRIGHT);
264 case 7: /* 0111, right top bottom */
265 return (CELL_LEFTJOIN);
266 case 6: /* 0110, right top */
267 return (CELL_BOTTOMLEFT);
268 case 5: /* 0101, right bottom */
269 return (CELL_TOPLEFT);
270 case 3: /* 0011, top bottom */
271 return (CELL_TOPBOTTOM);
273 return (CELL_OUTSIDE);
276 /* Check if cell inside a pane. */
277 static int
278 screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
279 struct window_pane **wpp)
281 struct window *w = c->session->curw->window;
282 struct window_pane *wp, *active;
283 int border;
284 u_int right, line;
286 *wpp = NULL;
288 if (px > w->sx || py > w->sy)
289 return (CELL_OUTSIDE);
290 if (px == w->sx || py == w->sy) /* window border */
291 return (screen_redraw_type_of_cell(c, px, py, pane_status));
293 if (pane_status != PANE_STATUS_OFF) {
294 active = wp = server_client_get_pane(c);
295 do {
296 if (!window_pane_visible(wp))
297 goto next1;
299 if (pane_status == PANE_STATUS_TOP)
300 line = wp->yoff - 1;
301 else
302 line = wp->yoff + wp->sy;
303 right = wp->xoff + 2 + wp->status_size - 1;
305 if (py == line && px >= wp->xoff + 2 && px <= right)
306 return (CELL_INSIDE);
308 next1:
309 wp = TAILQ_NEXT(wp, entry);
310 if (wp == NULL)
311 wp = TAILQ_FIRST(&w->panes);
312 } while (wp != active);
315 active = wp = server_client_get_pane(c);
316 do {
317 if (!window_pane_visible(wp))
318 goto next2;
319 *wpp = wp;
322 * If definitely inside, return. If not on border, skip.
323 * Otherwise work out the cell.
325 border = screen_redraw_pane_border(wp, px, py, pane_status);
326 if (border == SCREEN_REDRAW_INSIDE)
327 return (CELL_INSIDE);
328 if (border == SCREEN_REDRAW_OUTSIDE)
329 goto next2;
330 return (screen_redraw_type_of_cell(c, px, py, pane_status));
332 next2:
333 wp = TAILQ_NEXT(wp, entry);
334 if (wp == NULL)
335 wp = TAILQ_FIRST(&w->panes);
336 } while (wp != active);
338 return (CELL_OUTSIDE);
341 /* Check if the border of a particular pane. */
342 static int
343 screen_redraw_check_is(u_int px, u_int py, int pane_status,
344 struct window_pane *wp)
346 enum screen_redraw_border_type border;
348 border = screen_redraw_pane_border(wp, px, py, pane_status);
349 if (border == SCREEN_REDRAW_BORDER)
350 return (1);
351 return (0);
354 /* Update pane status. */
355 static int
356 screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
357 struct screen_redraw_ctx *rctx, enum pane_lines pane_lines)
359 struct window *w = wp->window;
360 struct grid_cell gc;
361 const char *fmt;
362 struct format_tree *ft;
363 char *expanded;
364 int pane_status = rctx->pane_status;
365 u_int width, i, cell_type, px, py;
366 struct screen_write_ctx ctx;
367 struct screen old;
369 ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
370 format_defaults(ft, c, c->session, c->session->curw, wp);
372 if (wp == server_client_get_pane(c))
373 style_apply(&gc, w->options, "pane-active-border-style", ft);
374 else
375 style_apply(&gc, w->options, "pane-border-style", ft);
376 fmt = options_get_string(wp->options, "pane-border-format");
378 expanded = format_expand_time(ft, fmt);
379 if (wp->sx < 4)
380 wp->status_size = width = 0;
381 else
382 wp->status_size = width = wp->sx - 4;
384 memcpy(&old, &wp->status_screen, sizeof old);
385 screen_init(&wp->status_screen, width, 1, 0);
386 wp->status_screen.mode = 0;
388 screen_write_start(&ctx, &wp->status_screen);
390 for (i = 0; i < width; i++) {
391 px = wp->xoff + 2 + i;
392 if (rctx->pane_status == PANE_STATUS_TOP)
393 py = wp->yoff - 1;
394 else
395 py = wp->yoff + wp->sy;
396 cell_type = screen_redraw_type_of_cell(c, px, py, pane_status);
397 screen_redraw_border_set(wp, pane_lines, cell_type, &gc);
398 screen_write_cell(&ctx, &gc);
400 gc.attr &= ~GRID_ATTR_CHARSET;
402 screen_write_cursormove(&ctx, 0, 0, 0);
403 format_draw(&ctx, &gc, width, expanded, NULL, 0);
404 screen_write_stop(&ctx);
406 free(expanded);
407 format_free(ft);
409 if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
410 screen_free(&old);
411 return (0);
413 screen_free(&old);
414 return (1);
417 /* Draw pane status. */
418 static void
419 screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
421 struct client *c = ctx->c;
422 struct window *w = c->session->curw->window;
423 struct tty *tty = &c->tty;
424 struct window_pane *wp;
425 struct screen *s;
426 u_int i, x, width, xoff, yoff, size;
428 log_debug("%s: %s @%u", __func__, c->name, w->id);
430 TAILQ_FOREACH(wp, &w->panes, entry) {
431 if (!window_pane_visible(wp))
432 continue;
433 s = &wp->status_screen;
435 size = wp->status_size;
436 if (ctx->pane_status == PANE_STATUS_TOP)
437 yoff = wp->yoff - 1;
438 else
439 yoff = wp->yoff + wp->sy;
440 xoff = wp->xoff + 2;
442 if (xoff + size <= ctx->ox ||
443 xoff >= ctx->ox + ctx->sx ||
444 yoff < ctx->oy ||
445 yoff >= ctx->oy + ctx->sy)
446 continue;
448 if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) {
449 /* All visible. */
450 i = 0;
451 x = xoff - ctx->ox;
452 width = size;
453 } else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) {
454 /* Both left and right not visible. */
455 i = ctx->ox;
456 x = 0;
457 width = ctx->sx;
458 } else if (xoff < ctx->ox) {
459 /* Left not visible. */
460 i = ctx->ox - xoff;
461 x = 0;
462 width = size - i;
463 } else {
464 /* Right not visible. */
465 i = 0;
466 x = xoff - ctx->ox;
467 width = size - x;
470 if (ctx->statustop)
471 yoff += ctx->statuslines;
472 tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy,
473 &grid_default_cell, NULL);
475 tty_cursor(tty, 0, 0);
478 /* Update status line and change flags if unchanged. */
479 static int
480 screen_redraw_update(struct client *c, int flags)
482 struct window *w = c->session->curw->window;
483 struct window_pane *wp;
484 struct options *wo = w->options;
485 int redraw;
486 enum pane_lines lines;
487 struct screen_redraw_ctx ctx;
489 if (c->message_string != NULL)
490 redraw = status_message_redraw(c);
491 else if (c->prompt_string != NULL)
492 redraw = status_prompt_redraw(c);
493 else
494 redraw = status_redraw(c);
495 if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS))
496 flags &= ~CLIENT_REDRAWSTATUS;
498 if (c->overlay_draw != NULL)
499 flags |= CLIENT_REDRAWOVERLAY;
501 if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) {
502 screen_redraw_set_context(c, &ctx);
503 lines = options_get_number(wo, "pane-border-lines");
504 redraw = 0;
505 TAILQ_FOREACH(wp, &w->panes, entry) {
506 if (screen_redraw_make_pane_status(c, wp, &ctx, lines))
507 redraw = 1;
509 if (redraw)
510 flags |= CLIENT_REDRAWBORDERS;
512 return (flags);
515 /* Set up redraw context. */
516 static void
517 screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
519 struct session *s = c->session;
520 struct options *oo = s->options;
521 struct window *w = s->curw->window;
522 struct options *wo = w->options;
523 u_int lines;
525 memset(ctx, 0, sizeof *ctx);
526 ctx->c = c;
528 lines = status_line_size(c);
529 if (c->message_string != NULL || c->prompt_string != NULL)
530 lines = (lines == 0) ? 1 : lines;
531 if (lines != 0 && options_get_number(oo, "status-position") == 0)
532 ctx->statustop = 1;
533 ctx->statuslines = lines;
535 ctx->pane_status = options_get_number(wo, "pane-border-status");
536 ctx->pane_lines = options_get_number(wo, "pane-border-lines");
538 tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
540 log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
541 w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines,
542 ctx->statustop);
545 /* Redraw entire screen. */
546 void
547 screen_redraw_screen(struct client *c)
549 struct screen_redraw_ctx ctx;
550 int flags;
552 if (c->flags & CLIENT_SUSPENDED)
553 return;
555 flags = screen_redraw_update(c, c->flags);
556 if ((flags & CLIENT_ALLREDRAWFLAGS) == 0)
557 return;
559 screen_redraw_set_context(c, &ctx);
560 tty_sync_start(&c->tty);
561 tty_update_mode(&c->tty, c->tty.mode, NULL);
563 if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
564 log_debug("%s: redrawing borders", c->name);
565 if (ctx.pane_status != PANE_STATUS_OFF)
566 screen_redraw_draw_pane_status(&ctx);
567 screen_redraw_draw_borders(&ctx);
569 if (flags & CLIENT_REDRAWWINDOW) {
570 log_debug("%s: redrawing panes", c->name);
571 screen_redraw_draw_panes(&ctx);
573 if (ctx.statuslines != 0 &&
574 (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) {
575 log_debug("%s: redrawing status", c->name);
576 screen_redraw_draw_status(&ctx);
578 if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
579 log_debug("%s: redrawing overlay", c->name);
580 c->overlay_draw(c, c->overlay_data, &ctx);
583 tty_reset(&c->tty);
586 /* Redraw a single pane. */
587 void
588 screen_redraw_pane(struct client *c, struct window_pane *wp)
590 struct screen_redraw_ctx ctx;
592 if (!window_pane_visible(wp))
593 return;
595 screen_redraw_set_context(c, &ctx);
596 tty_sync_start(&c->tty);
597 tty_update_mode(&c->tty, c->tty.mode, NULL);
599 screen_redraw_draw_pane(&ctx, wp);
601 tty_reset(&c->tty);
604 /* Get border cell style. */
605 static const struct grid_cell *
606 screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
607 u_int y, struct window_pane *wp)
609 struct client *c = ctx->c;
610 struct session *s = c->session;
611 struct window *w = s->curw->window;
612 struct window_pane *active = server_client_get_pane(c);
613 struct options *oo = w->options;
614 struct format_tree *ft;
616 if (wp->border_gc_set)
617 return (&wp->border_gc);
618 wp->border_gc_set = 1;
620 ft = format_create_defaults(NULL, c, s, s->curw, wp);
621 if (screen_redraw_check_is(x, y, ctx->pane_status, active))
622 style_apply(&wp->border_gc, oo, "pane-active-border-style", ft);
623 else
624 style_apply(&wp->border_gc, oo, "pane-border-style", ft);
625 format_free(ft);
627 return (&wp->border_gc);
630 /* Draw a border cell. */
631 static void
632 screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
634 struct client *c = ctx->c;
635 struct session *s = c->session;
636 struct window *w = s->curw->window;
637 struct options *oo = w->options;
638 struct tty *tty = &c->tty;
639 struct format_tree *ft;
640 struct window_pane *wp;
641 struct grid_cell gc;
642 const struct grid_cell *tmp;
643 struct overlay_ranges r;
644 u_int cell_type, x = ctx->ox + i, y = ctx->oy + j;
645 int pane_status = ctx->pane_status, isolates;
647 if (c->overlay_check != NULL) {
648 c->overlay_check(c, c->overlay_data, x, y, 1, &r);
649 if (r.nx[0] + r.nx[1] == 0)
650 return;
653 cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
654 if (cell_type == CELL_INSIDE)
655 return;
657 if (wp == NULL) {
658 if (!ctx->no_pane_gc_set) {
659 ft = format_create_defaults(NULL, c, s, s->curw, NULL);
660 memcpy(&ctx->no_pane_gc, &grid_default_cell, sizeof gc);
661 style_add(&ctx->no_pane_gc, oo, "pane-border-style",
662 ft);
663 format_free(ft);
664 ctx->no_pane_gc_set = 1;
666 memcpy(&gc, &ctx->no_pane_gc, sizeof gc);
667 } else {
668 tmp = screen_redraw_draw_borders_style(ctx, x, y, wp);
669 if (tmp == NULL)
670 return;
671 memcpy(&gc, tmp, sizeof gc);
673 if (server_is_marked(s, s->curw, marked_pane.wp) &&
674 screen_redraw_check_is(x, y, pane_status, marked_pane.wp))
675 gc.attr ^= GRID_ATTR_REVERSE;
677 screen_redraw_border_set(wp, ctx->pane_lines, cell_type, &gc);
679 if (cell_type == CELL_TOPBOTTOM &&
680 (c->flags & CLIENT_UTF8) &&
681 tty_term_has(tty->term, TTYC_BIDI))
682 isolates = 1;
683 else
684 isolates = 0;
686 if (ctx->statustop)
687 tty_cursor(tty, i, ctx->statuslines + j);
688 else
689 tty_cursor(tty, i, j);
690 if (isolates)
691 tty_puts(tty, END_ISOLATE);
692 tty_cell(tty, &gc, &grid_default_cell, NULL);
693 if (isolates)
694 tty_puts(tty, START_ISOLATE);
697 /* Draw the borders. */
698 static void
699 screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
701 struct client *c = ctx->c;
702 struct session *s = c->session;
703 struct window *w = s->curw->window;
704 struct window_pane *wp;
705 u_int i, j;
707 log_debug("%s: %s @%u", __func__, c->name, w->id);
709 TAILQ_FOREACH(wp, &w->panes, entry)
710 wp->border_gc_set = 0;
712 for (j = 0; j < c->tty.sy - ctx->statuslines; j++) {
713 for (i = 0; i < c->tty.sx; i++)
714 screen_redraw_draw_borders_cell(ctx, i, j);
718 /* Draw the panes. */
719 static void
720 screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
722 struct client *c = ctx->c;
723 struct window *w = c->session->curw->window;
724 struct window_pane *wp;
726 log_debug("%s: %s @%u", __func__, c->name, w->id);
728 TAILQ_FOREACH(wp, &w->panes, entry) {
729 if (window_pane_visible(wp))
730 screen_redraw_draw_pane(ctx, wp);
734 /* Draw the status line. */
735 static void
736 screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
738 struct client *c = ctx->c;
739 struct window *w = c->session->curw->window;
740 struct tty *tty = &c->tty;
741 struct screen *s = c->status.active;
742 u_int i, y;
744 log_debug("%s: %s @%u", __func__, c->name, w->id);
746 if (ctx->statustop)
747 y = 0;
748 else
749 y = c->tty.sy - ctx->statuslines;
750 for (i = 0; i < ctx->statuslines; i++) {
751 tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i,
752 &grid_default_cell, NULL);
756 /* Draw one pane. */
757 static void
758 screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
760 struct client *c = ctx->c;
761 struct window *w = c->session->curw->window;
762 struct tty *tty = &c->tty;
763 struct screen *s = wp->screen;
764 struct colour_palette *palette = &wp->palette;
765 struct grid_cell defaults;
766 u_int i, j, top, x, y, width;
768 log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
770 if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
771 return;
772 if (ctx->statustop)
773 top = ctx->statuslines;
774 else
775 top = 0;
776 for (j = 0; j < wp->sy; j++) {
777 if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy)
778 continue;
779 y = top + wp->yoff + j - ctx->oy;
781 if (wp->xoff >= ctx->ox &&
782 wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
783 /* All visible. */
784 i = 0;
785 x = wp->xoff - ctx->ox;
786 width = wp->sx;
787 } else if (wp->xoff < ctx->ox &&
788 wp->xoff + wp->sx > ctx->ox + ctx->sx) {
789 /* Both left and right not visible. */
790 i = ctx->ox;
791 x = 0;
792 width = ctx->sx;
793 } else if (wp->xoff < ctx->ox) {
794 /* Left not visible. */
795 i = ctx->ox - wp->xoff;
796 x = 0;
797 width = wp->sx - i;
798 } else {
799 /* Right not visible. */
800 i = 0;
801 x = wp->xoff - ctx->ox;
802 width = ctx->sx - x;
804 log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
805 __func__, c->name, wp->id, i, j, x, y, width);
807 tty_default_colours(&defaults, wp);
808 tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette);