Use format_draw for command prompt prefix to allow styles, GitHub issue
[tmux-openbsd.git] / screen-redraw.c
blob8dd75f40ca099a9b5bf3b89cdde890592fb3d6f3
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 /* Border in relation to a pane. */
38 enum screen_redraw_border_type {
39 SCREEN_REDRAW_OUTSIDE,
40 SCREEN_REDRAW_INSIDE,
41 SCREEN_REDRAW_BORDER_LEFT,
42 SCREEN_REDRAW_BORDER_RIGHT,
43 SCREEN_REDRAW_BORDER_TOP,
44 SCREEN_REDRAW_BORDER_BOTTOM
46 #define BORDER_MARKERS " +,.-"
48 /* Get cell border character. */
49 static void
50 screen_redraw_border_set(struct window_pane *wp, enum pane_lines pane_lines,
51 int cell_type, struct grid_cell *gc)
53 u_int idx;
55 switch (pane_lines) {
56 case PANE_LINES_NUMBER:
57 if (cell_type == CELL_OUTSIDE) {
58 gc->attr |= GRID_ATTR_CHARSET;
59 utf8_set(&gc->data, CELL_BORDERS[CELL_OUTSIDE]);
60 break;
62 gc->attr &= ~GRID_ATTR_CHARSET;
63 if (wp != NULL && window_pane_index(wp, &idx) == 0)
64 utf8_set(&gc->data, '0' + (idx % 10));
65 else
66 utf8_set(&gc->data, '*');
67 break;
68 case PANE_LINES_DOUBLE:
69 gc->attr &= ~GRID_ATTR_CHARSET;
70 utf8_copy(&gc->data, tty_acs_double_borders(cell_type));
71 break;
72 case PANE_LINES_HEAVY:
73 gc->attr &= ~GRID_ATTR_CHARSET;
74 utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
75 break;
76 case PANE_LINES_SIMPLE:
77 gc->attr &= ~GRID_ATTR_CHARSET;
78 utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
79 break;
80 default:
81 gc->attr |= GRID_ATTR_CHARSET;
82 utf8_set(&gc->data, CELL_BORDERS[cell_type]);
83 break;
87 /* Return if window has only two panes. */
88 static int
89 screen_redraw_two_panes(struct window *w, int direction)
91 struct window_pane *wp;
93 wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
94 if (wp == NULL)
95 return (0); /* one pane */
96 if (TAILQ_NEXT(wp, entry) != NULL)
97 return (0); /* more than two panes */
98 if (direction == 0 && wp->xoff == 0)
99 return (0);
100 if (direction == 1 && wp->yoff == 0)
101 return (0);
102 return (1);
105 /* Check if cell is on the border of a pane. */
106 static enum screen_redraw_border_type
107 screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py,
108 int pane_status)
110 struct options *oo = wp->window->options;
111 int split = 0;
112 u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
114 /* Inside pane. */
115 if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
116 return (SCREEN_REDRAW_INSIDE);
118 /* Get pane indicator. */
119 switch (options_get_number(oo, "pane-border-indicators")) {
120 case PANE_BORDER_COLOUR:
121 case PANE_BORDER_BOTH:
122 split = 1;
123 break;
126 /* Left/right borders. */
127 if (pane_status == PANE_STATUS_OFF) {
128 if (screen_redraw_two_panes(wp->window, 0) && split) {
129 if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2)
130 return (SCREEN_REDRAW_BORDER_RIGHT);
131 if (wp->xoff != 0 &&
132 px == wp->xoff - 1 &&
133 py > wp->sy / 2)
134 return (SCREEN_REDRAW_BORDER_LEFT);
135 } else {
136 if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
137 if (wp->xoff != 0 && px == wp->xoff - 1)
138 return (SCREEN_REDRAW_BORDER_LEFT);
139 if (px == ex)
140 return (SCREEN_REDRAW_BORDER_RIGHT);
143 } else {
144 if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
145 if (wp->xoff != 0 && px == wp->xoff - 1)
146 return (SCREEN_REDRAW_BORDER_LEFT);
147 if (px == ex)
148 return (SCREEN_REDRAW_BORDER_RIGHT);
152 /* Top/bottom borders. */
153 if (pane_status == PANE_STATUS_OFF) {
154 if (screen_redraw_two_panes(wp->window, 1) && split) {
155 if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
156 return (SCREEN_REDRAW_BORDER_BOTTOM);
157 if (wp->yoff != 0 &&
158 py == wp->yoff - 1 &&
159 px > wp->sx / 2)
160 return (SCREEN_REDRAW_BORDER_TOP);
161 } else {
162 if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
163 if (wp->yoff != 0 && py == wp->yoff - 1)
164 return (SCREEN_REDRAW_BORDER_TOP);
165 if (py == ey)
166 return (SCREEN_REDRAW_BORDER_BOTTOM);
169 } else if (pane_status == PANE_STATUS_TOP) {
170 if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
171 if (wp->yoff != 0 && py == wp->yoff - 1)
172 return (SCREEN_REDRAW_BORDER_TOP);
174 } else {
175 if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
176 if (py == ey)
177 return (SCREEN_REDRAW_BORDER_BOTTOM);
181 /* Outside pane. */
182 return (SCREEN_REDRAW_OUTSIDE);
185 /* Check if a cell is on a border. */
186 static int
187 screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status)
189 struct window *w = c->session->curw->window;
190 struct window_pane *wp;
192 /* Outside the window? */
193 if (px > w->sx || py > w->sy)
194 return (0);
196 /* On the window border? */
197 if (px == w->sx || py == w->sy)
198 return (1);
200 /* Check all the panes. */
201 TAILQ_FOREACH(wp, &w->panes, entry) {
202 if (!window_pane_visible(wp))
203 continue;
204 switch (screen_redraw_pane_border(wp, px, py, pane_status)) {
205 case SCREEN_REDRAW_INSIDE:
206 return (0);
207 case SCREEN_REDRAW_OUTSIDE:
208 break;
209 default:
210 return (1);
214 return (0);
217 /* Work out type of border cell from surrounding cells. */
218 static int
219 screen_redraw_type_of_cell(struct client *c, u_int px, u_int py,
220 int pane_status)
222 struct window *w = c->session->curw->window;
223 u_int sx = w->sx, sy = w->sy;
224 int borders = 0;
226 /* Is this outside the window? */
227 if (px > sx || py > sy)
228 return (CELL_OUTSIDE);
231 * Construct a bitmask of whether the cells to the left (bit 4), right,
232 * top, and bottom (bit 1) of this cell are borders.
234 if (px == 0 || screen_redraw_cell_border(c, px - 1, py, pane_status))
235 borders |= 8;
236 if (px <= sx && screen_redraw_cell_border(c, px + 1, py, pane_status))
237 borders |= 4;
238 if (pane_status == PANE_STATUS_TOP) {
239 if (py != 0 &&
240 screen_redraw_cell_border(c, px, py - 1, pane_status))
241 borders |= 2;
242 if (screen_redraw_cell_border(c, px, py + 1, pane_status))
243 borders |= 1;
244 } else if (pane_status == PANE_STATUS_BOTTOM) {
245 if (py == 0 ||
246 screen_redraw_cell_border(c, px, py - 1, pane_status))
247 borders |= 2;
248 if (py != sy - 1 &&
249 screen_redraw_cell_border(c, px, py + 1, pane_status))
250 borders |= 1;
251 } else {
252 if (py == 0 ||
253 screen_redraw_cell_border(c, px, py - 1, pane_status))
254 borders |= 2;
255 if (screen_redraw_cell_border(c, px, py + 1, pane_status))
256 borders |= 1;
260 * Figure out what kind of border this cell is. Only one bit set
261 * doesn't make sense (can't have a border cell with no others
262 * connected).
264 switch (borders) {
265 case 15: /* 1111, left right top bottom */
266 return (CELL_JOIN);
267 case 14: /* 1110, left right top */
268 return (CELL_BOTTOMJOIN);
269 case 13: /* 1101, left right bottom */
270 return (CELL_TOPJOIN);
271 case 12: /* 1100, left right */
272 return (CELL_LEFTRIGHT);
273 case 11: /* 1011, left top bottom */
274 return (CELL_RIGHTJOIN);
275 case 10: /* 1010, left top */
276 return (CELL_BOTTOMRIGHT);
277 case 9: /* 1001, left bottom */
278 return (CELL_TOPRIGHT);
279 case 7: /* 0111, right top bottom */
280 return (CELL_LEFTJOIN);
281 case 6: /* 0110, right top */
282 return (CELL_BOTTOMLEFT);
283 case 5: /* 0101, right bottom */
284 return (CELL_TOPLEFT);
285 case 3: /* 0011, top bottom */
286 return (CELL_TOPBOTTOM);
288 return (CELL_OUTSIDE);
291 /* Check if cell inside a pane. */
292 static int
293 screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
294 struct window_pane **wpp)
296 struct window *w = c->session->curw->window;
297 struct window_pane *wp, *active;
298 int border;
299 u_int right, line;
301 *wpp = NULL;
303 if (px > w->sx || py > w->sy)
304 return (CELL_OUTSIDE);
305 if (px == w->sx || py == w->sy) /* window border */
306 return (screen_redraw_type_of_cell(c, px, py, pane_status));
308 if (pane_status != PANE_STATUS_OFF) {
309 active = wp = server_client_get_pane(c);
310 do {
311 if (!window_pane_visible(wp))
312 goto next1;
314 if (pane_status == PANE_STATUS_TOP)
315 line = wp->yoff - 1;
316 else
317 line = wp->yoff + wp->sy;
318 right = wp->xoff + 2 + wp->status_size - 1;
320 if (py == line && px >= wp->xoff + 2 && px <= right)
321 return (CELL_INSIDE);
323 next1:
324 wp = TAILQ_NEXT(wp, entry);
325 if (wp == NULL)
326 wp = TAILQ_FIRST(&w->panes);
327 } while (wp != active);
330 active = wp = server_client_get_pane(c);
331 do {
332 if (!window_pane_visible(wp))
333 goto next2;
334 *wpp = wp;
337 * If definitely inside, return. If not on border, skip.
338 * Otherwise work out the cell.
340 border = screen_redraw_pane_border(wp, px, py, pane_status);
341 if (border == SCREEN_REDRAW_INSIDE)
342 return (CELL_INSIDE);
343 if (border == SCREEN_REDRAW_OUTSIDE)
344 goto next2;
345 return (screen_redraw_type_of_cell(c, px, py, pane_status));
347 next2:
348 wp = TAILQ_NEXT(wp, entry);
349 if (wp == NULL)
350 wp = TAILQ_FIRST(&w->panes);
351 } while (wp != active);
353 return (CELL_OUTSIDE);
356 /* Check if the border of a particular pane. */
357 static int
358 screen_redraw_check_is(u_int px, u_int py, int pane_status,
359 struct window_pane *wp)
361 enum screen_redraw_border_type border;
363 border = screen_redraw_pane_border(wp, px, py, pane_status);
364 if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE)
365 return (1);
366 return (0);
369 /* Update pane status. */
370 static int
371 screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
372 struct screen_redraw_ctx *rctx, enum pane_lines pane_lines)
374 struct window *w = wp->window;
375 struct grid_cell gc;
376 const char *fmt;
377 struct format_tree *ft;
378 char *expanded;
379 int pane_status = rctx->pane_status;
380 u_int width, i, cell_type, px, py;
381 struct screen_write_ctx ctx;
382 struct screen old;
384 ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
385 format_defaults(ft, c, c->session, c->session->curw, wp);
387 if (wp == server_client_get_pane(c))
388 style_apply(&gc, w->options, "pane-active-border-style", ft);
389 else
390 style_apply(&gc, w->options, "pane-border-style", ft);
391 fmt = options_get_string(wp->options, "pane-border-format");
393 expanded = format_expand_time(ft, fmt);
394 if (wp->sx < 4)
395 wp->status_size = width = 0;
396 else
397 wp->status_size = width = wp->sx - 4;
399 memcpy(&old, &wp->status_screen, sizeof old);
400 screen_init(&wp->status_screen, width, 1, 0);
401 wp->status_screen.mode = 0;
403 screen_write_start(&ctx, &wp->status_screen);
405 for (i = 0; i < width; i++) {
406 px = wp->xoff + 2 + i;
407 if (rctx->pane_status == PANE_STATUS_TOP)
408 py = wp->yoff - 1;
409 else
410 py = wp->yoff + wp->sy;
411 cell_type = screen_redraw_type_of_cell(c, px, py, pane_status);
412 screen_redraw_border_set(wp, pane_lines, cell_type, &gc);
413 screen_write_cell(&ctx, &gc);
415 gc.attr &= ~GRID_ATTR_CHARSET;
417 screen_write_cursormove(&ctx, 0, 0, 0);
418 format_draw(&ctx, &gc, width, expanded, NULL, 0);
419 screen_write_stop(&ctx);
421 free(expanded);
422 format_free(ft);
424 if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
425 screen_free(&old);
426 return (0);
428 screen_free(&old);
429 return (1);
432 /* Draw pane status. */
433 static void
434 screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
436 struct client *c = ctx->c;
437 struct window *w = c->session->curw->window;
438 struct tty *tty = &c->tty;
439 struct window_pane *wp;
440 struct screen *s;
441 u_int i, x, width, xoff, yoff, size;
443 log_debug("%s: %s @%u", __func__, c->name, w->id);
445 TAILQ_FOREACH(wp, &w->panes, entry) {
446 if (!window_pane_visible(wp))
447 continue;
448 s = &wp->status_screen;
450 size = wp->status_size;
451 if (ctx->pane_status == PANE_STATUS_TOP)
452 yoff = wp->yoff - 1;
453 else
454 yoff = wp->yoff + wp->sy;
455 xoff = wp->xoff + 2;
457 if (xoff + size <= ctx->ox ||
458 xoff >= ctx->ox + ctx->sx ||
459 yoff < ctx->oy ||
460 yoff >= ctx->oy + ctx->sy)
461 continue;
463 if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) {
464 /* All visible. */
465 i = 0;
466 x = xoff - ctx->ox;
467 width = size;
468 } else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) {
469 /* Both left and right not visible. */
470 i = ctx->ox;
471 x = 0;
472 width = ctx->sx;
473 } else if (xoff < ctx->ox) {
474 /* Left not visible. */
475 i = ctx->ox - xoff;
476 x = 0;
477 width = size - i;
478 } else {
479 /* Right not visible. */
480 i = 0;
481 x = xoff - ctx->ox;
482 width = size - x;
485 if (ctx->statustop)
486 yoff += ctx->statuslines;
487 tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy,
488 &grid_default_cell, NULL);
490 tty_cursor(tty, 0, 0);
493 /* Update status line and change flags if unchanged. */
494 static int
495 screen_redraw_update(struct client *c, int flags)
497 struct window *w = c->session->curw->window;
498 struct window_pane *wp;
499 struct options *wo = w->options;
500 int redraw;
501 enum pane_lines lines;
502 struct screen_redraw_ctx ctx;
504 if (c->message_string != NULL)
505 redraw = status_message_redraw(c);
506 else if (c->prompt_string != NULL)
507 redraw = status_prompt_redraw(c);
508 else
509 redraw = status_redraw(c);
510 if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS))
511 flags &= ~CLIENT_REDRAWSTATUS;
513 if (c->overlay_draw != NULL)
514 flags |= CLIENT_REDRAWOVERLAY;
516 if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) {
517 screen_redraw_set_context(c, &ctx);
518 lines = options_get_number(wo, "pane-border-lines");
519 redraw = 0;
520 TAILQ_FOREACH(wp, &w->panes, entry) {
521 if (screen_redraw_make_pane_status(c, wp, &ctx, lines))
522 redraw = 1;
524 if (redraw)
525 flags |= CLIENT_REDRAWBORDERS;
527 return (flags);
530 /* Set up redraw context. */
531 static void
532 screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
534 struct session *s = c->session;
535 struct options *oo = s->options;
536 struct window *w = s->curw->window;
537 struct options *wo = w->options;
538 u_int lines;
540 memset(ctx, 0, sizeof *ctx);
541 ctx->c = c;
543 lines = status_line_size(c);
544 if (c->message_string != NULL || c->prompt_string != NULL)
545 lines = (lines == 0) ? 1 : lines;
546 if (lines != 0 && options_get_number(oo, "status-position") == 0)
547 ctx->statustop = 1;
548 ctx->statuslines = lines;
550 ctx->pane_status = options_get_number(wo, "pane-border-status");
551 ctx->pane_lines = options_get_number(wo, "pane-border-lines");
553 tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
555 log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
556 w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines,
557 ctx->statustop);
560 /* Redraw entire screen. */
561 void
562 screen_redraw_screen(struct client *c)
564 struct screen_redraw_ctx ctx;
565 int flags;
567 if (c->flags & CLIENT_SUSPENDED)
568 return;
570 flags = screen_redraw_update(c, c->flags);
571 if ((flags & CLIENT_ALLREDRAWFLAGS) == 0)
572 return;
574 screen_redraw_set_context(c, &ctx);
575 tty_sync_start(&c->tty);
576 tty_update_mode(&c->tty, c->tty.mode, NULL);
578 if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
579 log_debug("%s: redrawing borders", c->name);
580 if (ctx.pane_status != PANE_STATUS_OFF)
581 screen_redraw_draw_pane_status(&ctx);
582 screen_redraw_draw_borders(&ctx);
584 if (flags & CLIENT_REDRAWWINDOW) {
585 log_debug("%s: redrawing panes", c->name);
586 screen_redraw_draw_panes(&ctx);
588 if (ctx.statuslines != 0 &&
589 (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) {
590 log_debug("%s: redrawing status", c->name);
591 screen_redraw_draw_status(&ctx);
593 if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
594 log_debug("%s: redrawing overlay", c->name);
595 c->overlay_draw(c, c->overlay_data, &ctx);
598 tty_reset(&c->tty);
601 /* Redraw a single pane. */
602 void
603 screen_redraw_pane(struct client *c, struct window_pane *wp)
605 struct screen_redraw_ctx ctx;
607 if (!window_pane_visible(wp))
608 return;
610 screen_redraw_set_context(c, &ctx);
611 tty_sync_start(&c->tty);
612 tty_update_mode(&c->tty, c->tty.mode, NULL);
614 screen_redraw_draw_pane(&ctx, wp);
616 tty_reset(&c->tty);
619 /* Get border cell style. */
620 static const struct grid_cell *
621 screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
622 u_int y, struct window_pane *wp)
624 struct client *c = ctx->c;
625 struct session *s = c->session;
626 struct window *w = s->curw->window;
627 struct window_pane *active = server_client_get_pane(c);
628 struct options *oo = w->options;
629 struct format_tree *ft;
631 if (wp->border_gc_set)
632 return (&wp->border_gc);
633 wp->border_gc_set = 1;
635 ft = format_create_defaults(NULL, c, s, s->curw, wp);
636 if (screen_redraw_check_is(x, y, ctx->pane_status, active))
637 style_apply(&wp->border_gc, oo, "pane-active-border-style", ft);
638 else
639 style_apply(&wp->border_gc, oo, "pane-border-style", ft);
640 format_free(ft);
642 return (&wp->border_gc);
645 /* Draw a border cell. */
646 static void
647 screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
649 struct client *c = ctx->c;
650 struct session *s = c->session;
651 struct window *w = s->curw->window;
652 struct options *oo = w->options;
653 struct tty *tty = &c->tty;
654 struct format_tree *ft;
655 struct window_pane *wp, *active = server_client_get_pane(c);
656 struct grid_cell gc;
657 const struct grid_cell *tmp;
658 struct overlay_ranges r;
659 u_int cell_type, x = ctx->ox + i, y = ctx->oy + j;
660 int arrows = 0, border;
661 int pane_status = ctx->pane_status, isolates;
663 if (c->overlay_check != NULL) {
664 c->overlay_check(c, c->overlay_data, x, y, 1, &r);
665 if (r.nx[0] + r.nx[1] == 0)
666 return;
669 cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
670 if (cell_type == CELL_INSIDE)
671 return;
673 if (wp == NULL) {
674 if (!ctx->no_pane_gc_set) {
675 ft = format_create_defaults(NULL, c, s, s->curw, NULL);
676 memcpy(&ctx->no_pane_gc, &grid_default_cell, sizeof gc);
677 style_add(&ctx->no_pane_gc, oo, "pane-border-style",
678 ft);
679 format_free(ft);
680 ctx->no_pane_gc_set = 1;
682 memcpy(&gc, &ctx->no_pane_gc, sizeof gc);
683 } else {
684 tmp = screen_redraw_draw_borders_style(ctx, x, y, wp);
685 if (tmp == NULL)
686 return;
687 memcpy(&gc, tmp, sizeof gc);
689 if (server_is_marked(s, s->curw, marked_pane.wp) &&
690 screen_redraw_check_is(x, y, pane_status, marked_pane.wp))
691 gc.attr ^= GRID_ATTR_REVERSE;
693 screen_redraw_border_set(wp, ctx->pane_lines, cell_type, &gc);
695 if (cell_type == CELL_TOPBOTTOM &&
696 (c->flags & CLIENT_UTF8) &&
697 tty_term_has(tty->term, TTYC_BIDI))
698 isolates = 1;
699 else
700 isolates = 0;
702 if (ctx->statustop)
703 tty_cursor(tty, i, ctx->statuslines + j);
704 else
705 tty_cursor(tty, i, j);
706 if (isolates)
707 tty_puts(tty, END_ISOLATE);
709 switch (options_get_number(oo, "pane-border-indicators")) {
710 case PANE_BORDER_ARROWS:
711 case PANE_BORDER_BOTH:
712 arrows = 1;
713 break;
716 if (wp != NULL && arrows) {
717 border = screen_redraw_pane_border(active, x, y, pane_status);
718 if (((i == wp->xoff + 1 &&
719 (cell_type == CELL_LEFTRIGHT ||
720 (cell_type == CELL_TOPJOIN &&
721 border == SCREEN_REDRAW_BORDER_BOTTOM) ||
722 (cell_type == CELL_BOTTOMJOIN &&
723 border == SCREEN_REDRAW_BORDER_TOP))) ||
724 (j == wp->yoff + 1 &&
725 (cell_type == CELL_TOPBOTTOM ||
726 (cell_type == CELL_LEFTJOIN &&
727 border == SCREEN_REDRAW_BORDER_RIGHT) ||
728 (cell_type == CELL_RIGHTJOIN &&
729 border == SCREEN_REDRAW_BORDER_LEFT)))) &&
730 screen_redraw_check_is(x, y, pane_status, active))
731 utf8_set(&gc.data, BORDER_MARKERS[border]);
734 tty_cell(tty, &gc, &grid_default_cell, NULL);
735 if (isolates)
736 tty_puts(tty, START_ISOLATE);
739 /* Draw the borders. */
740 static void
741 screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
743 struct client *c = ctx->c;
744 struct session *s = c->session;
745 struct window *w = s->curw->window;
746 struct window_pane *wp;
747 u_int i, j;
749 log_debug("%s: %s @%u", __func__, c->name, w->id);
751 TAILQ_FOREACH(wp, &w->panes, entry)
752 wp->border_gc_set = 0;
754 for (j = 0; j < c->tty.sy - ctx->statuslines; j++) {
755 for (i = 0; i < c->tty.sx; i++)
756 screen_redraw_draw_borders_cell(ctx, i, j);
760 /* Draw the panes. */
761 static void
762 screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
764 struct client *c = ctx->c;
765 struct window *w = c->session->curw->window;
766 struct window_pane *wp;
768 log_debug("%s: %s @%u", __func__, c->name, w->id);
770 TAILQ_FOREACH(wp, &w->panes, entry) {
771 if (window_pane_visible(wp))
772 screen_redraw_draw_pane(ctx, wp);
776 /* Draw the status line. */
777 static void
778 screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
780 struct client *c = ctx->c;
781 struct window *w = c->session->curw->window;
782 struct tty *tty = &c->tty;
783 struct screen *s = c->status.active;
784 u_int i, y;
786 log_debug("%s: %s @%u", __func__, c->name, w->id);
788 if (ctx->statustop)
789 y = 0;
790 else
791 y = c->tty.sy - ctx->statuslines;
792 for (i = 0; i < ctx->statuslines; i++) {
793 tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i,
794 &grid_default_cell, NULL);
798 /* Draw one pane. */
799 static void
800 screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
802 struct client *c = ctx->c;
803 struct window *w = c->session->curw->window;
804 struct tty *tty = &c->tty;
805 struct screen *s = wp->screen;
806 struct colour_palette *palette = &wp->palette;
807 struct grid_cell defaults;
808 u_int i, j, top, x, y, width;
810 log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
812 if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
813 return;
814 if (ctx->statustop)
815 top = ctx->statuslines;
816 else
817 top = 0;
818 for (j = 0; j < wp->sy; j++) {
819 if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy)
820 continue;
821 y = top + wp->yoff + j - ctx->oy;
823 if (wp->xoff >= ctx->ox &&
824 wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
825 /* All visible. */
826 i = 0;
827 x = wp->xoff - ctx->ox;
828 width = wp->sx;
829 } else if (wp->xoff < ctx->ox &&
830 wp->xoff + wp->sx > ctx->ox + ctx->sx) {
831 /* Both left and right not visible. */
832 i = ctx->ox;
833 x = 0;
834 width = ctx->sx;
835 } else if (wp->xoff < ctx->ox) {
836 /* Left not visible. */
837 i = ctx->ox - wp->xoff;
838 x = 0;
839 width = wp->sx - i;
840 } else {
841 /* Right not visible. */
842 i = 0;
843 x = wp->xoff - ctx->ox;
844 width = ctx->sx - x;
846 log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
847 __func__, c->name, wp->id, i, j, x, y, width);
849 tty_default_colours(&defaults, wp);
850 tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette);