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>
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
*);
35 #define CELL_TOPBOTTOM 1
36 #define CELL_LEFTRIGHT 2
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
46 #define CELL_OUTSIDE 12
48 #define CELL_BORDERS " xqlkmjwvtun~"
50 #define START_ISOLATE "\342\201\246"
51 #define END_ISOLATE "\342\201\251"
53 static const struct utf8_data screen_redraw_double_borders
[] = {
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 */
69 static const struct utf8_data screen_redraw_heavy_borders
[] = {
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 */
85 enum screen_redraw_border_type
{
86 SCREEN_REDRAW_OUTSIDE
,
91 /* Get cell border character. */
93 screen_redraw_border_set(struct window_pane
*wp
, int pane_lines
, int cell_type
,
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
]);
105 gc
->attr
&= ~GRID_ATTR_CHARSET
;
106 if (wp
!= NULL
&& window_pane_index(wp
, &idx
) == 0)
107 utf8_set(&gc
->data
, '0' + (idx
% 10));
109 utf8_set(&gc
->data
, '*');
111 case PANE_LINES_DOUBLE
:
112 gc
->attr
&= ~GRID_ATTR_CHARSET
;
113 utf8_copy(&gc
->data
, &screen_redraw_double_borders
[cell_type
]);
115 case PANE_LINES_HEAVY
:
116 gc
->attr
&= ~GRID_ATTR_CHARSET
;
117 utf8_copy(&gc
->data
, &screen_redraw_heavy_borders
[cell_type
]);
119 case PANE_LINES_SIMPLE
:
120 gc
->attr
&= ~GRID_ATTR_CHARSET
;
121 utf8_set(&gc
->data
, " |-+++++++++."[cell_type
]);
124 gc
->attr
|= GRID_ATTR_CHARSET
;
125 utf8_set(&gc
->data
, CELL_BORDERS
[cell_type
]);
130 /* Return if window has only two panes. */
132 screen_redraw_two_panes(struct window
*w
, int direction
)
134 struct window_pane
*wp
;
136 wp
= TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
);
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)
143 if (direction
== 1 && wp
->yoff
== 0)
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
,
153 u_int ex
= wp
->xoff
+ wp
->sx
, ey
= wp
->yoff
+ wp
->sy
;
156 if (px
>= wp
->xoff
&& px
< ex
&& py
>= wp
->yoff
&& py
< ey
)
157 return (SCREEN_REDRAW_INSIDE
);
159 /* Left/right borders. */
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
);
165 px
== wp
->xoff
- 1 &&
167 return (SCREEN_REDRAW_BORDER
);
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
);
173 return (SCREEN_REDRAW_BORDER
);
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
);
181 return (SCREEN_REDRAW_BORDER
);
185 /* Top/bottom borders. */
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
);
191 py
== wp
->yoff
- 1 &&
193 return (SCREEN_REDRAW_BORDER
);
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
);
199 return (SCREEN_REDRAW_BORDER
);
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
);
208 if ((wp
->xoff
== 0 || px
>= wp
->xoff
- 1) && px
<= ex
) {
210 return (SCREEN_REDRAW_BORDER
);
215 return (SCREEN_REDRAW_OUTSIDE
);
218 /* Check if a cell is on a border. */
220 screen_redraw_cell_border(struct client
*c
, u_int px
, u_int py
, int pane_status
)
222 struct window
*w
= c
->session
->curw
->window
;
223 struct window_pane
*wp
;
225 /* Outside the window? */
226 if (px
> w
->sx
|| py
> w
->sy
)
229 /* On the window border? */
230 if (px
== w
->sx
|| py
== w
->sy
)
233 /* Check all the panes. */
234 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
235 if (!window_pane_visible(wp
))
237 switch (screen_redraw_pane_border(wp
, px
, py
, pane_status
)) {
238 case SCREEN_REDRAW_INSIDE
:
240 case SCREEN_REDRAW_BORDER
:
242 case SCREEN_REDRAW_OUTSIDE
:
250 /* Work out type of border cell from surrounding cells. */
252 screen_redraw_type_of_cell(struct client
*c
, u_int px
, u_int py
,
255 struct window
*w
= c
->session
->curw
->window
;
256 u_int sx
= w
->sx
, sy
= w
->sy
;
259 /* Is this outside the window? */
260 if (px
> sx
|| py
> sy
)
261 return (CELL_OUTSIDE
);
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.
267 if (px
== 0 || screen_redraw_cell_border(c
, px
- 1, py
, pane_status
))
269 if (px
<= sx
&& screen_redraw_cell_border(c
, px
+ 1, py
, pane_status
))
271 if (pane_status
== PANE_STATUS_TOP
) {
273 screen_redraw_cell_border(c
, px
, py
- 1, pane_status
))
275 if (screen_redraw_cell_border(c
, px
, py
+ 1, pane_status
))
277 } else if (pane_status
== PANE_STATUS_BOTTOM
) {
279 screen_redraw_cell_border(c
, px
, py
- 1, pane_status
))
282 screen_redraw_cell_border(c
, px
, py
+ 1, pane_status
))
286 screen_redraw_cell_border(c
, px
, py
- 1, pane_status
))
288 if (screen_redraw_cell_border(c
, px
, py
+ 1, pane_status
))
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
298 case 15: /* 1111, left right top bottom */
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 */
305 return (CELL_LEFTRIGHT
);
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 */
319 return (CELL_TOPBOTTOM
);
321 return (CELL_OUTSIDE
);
324 /* Check if cell inside a pane. */
326 screen_redraw_check_cell(struct client
*c
, u_int px
, u_int py
, int pane_status
,
327 struct window_pane
**wpp
)
329 struct window
*w
= c
->session
->curw
->window
;
330 struct window_pane
*wp
, *active
;
336 if (px
> w
->sx
|| py
> w
->sy
)
337 return (CELL_OUTSIDE
);
338 if (px
== w
->sx
|| py
== w
->sy
) /* window border */
339 return (screen_redraw_type_of_cell(c
, px
, py
, pane_status
));
341 if (pane_status
!= PANE_STATUS_OFF
) {
342 active
= wp
= server_client_get_pane(c
);
344 if (!window_pane_visible(wp
))
347 if (pane_status
== PANE_STATUS_TOP
)
350 line
= wp
->yoff
+ wp
->sy
;
351 right
= wp
->xoff
+ 2 + wp
->status_size
- 1;
353 if (py
== line
&& px
>= wp
->xoff
+ 2 && px
<= right
)
354 return (CELL_INSIDE
);
357 wp
= TAILQ_NEXT(wp
, entry
);
359 wp
= TAILQ_FIRST(&w
->panes
);
360 } while (wp
!= active
);
363 active
= wp
= server_client_get_pane(c
);
365 if (!window_pane_visible(wp
))
370 * If definitely inside, return. If not on border, skip.
371 * Otherwise work out the cell.
373 border
= screen_redraw_pane_border(wp
, px
, py
, pane_status
);
374 if (border
== SCREEN_REDRAW_INSIDE
)
375 return (CELL_INSIDE
);
376 if (border
== SCREEN_REDRAW_OUTSIDE
)
378 return (screen_redraw_type_of_cell(c
, px
, py
, pane_status
));
381 wp
= TAILQ_NEXT(wp
, entry
);
383 wp
= TAILQ_FIRST(&w
->panes
);
384 } while (wp
!= active
);
386 return (CELL_OUTSIDE
);
389 /* Check if the border of a particular pane. */
391 screen_redraw_check_is(u_int px
, u_int py
, int pane_status
,
392 struct window_pane
*wp
)
394 enum screen_redraw_border_type border
;
396 border
= screen_redraw_pane_border(wp
, px
, py
, pane_status
);
397 if (border
== SCREEN_REDRAW_BORDER
)
402 /* Update pane status. */
404 screen_redraw_make_pane_status(struct client
*c
, struct window_pane
*wp
,
405 struct screen_redraw_ctx
*rctx
, int pane_lines
)
407 struct window
*w
= wp
->window
;
410 struct format_tree
*ft
;
412 int pane_status
= rctx
->pane_status
;
413 u_int width
, i
, cell_type
, px
, py
;
414 struct screen_write_ctx ctx
;
417 ft
= format_create(c
, NULL
, FORMAT_PANE
|wp
->id
, FORMAT_STATUS
);
418 format_defaults(ft
, c
, c
->session
, c
->session
->curw
, wp
);
420 if (wp
== server_client_get_pane(c
))
421 style_apply(&gc
, w
->options
, "pane-active-border-style", ft
);
423 style_apply(&gc
, w
->options
, "pane-border-style", ft
);
424 fmt
= options_get_string(w
->options
, "pane-border-format");
426 expanded
= format_expand_time(ft
, fmt
);
428 wp
->status_size
= width
= 0;
430 wp
->status_size
= width
= wp
->sx
- 4;
432 memcpy(&old
, &wp
->status_screen
, sizeof old
);
433 screen_init(&wp
->status_screen
, width
, 1, 0);
434 wp
->status_screen
.mode
= 0;
436 screen_write_start(&ctx
, &wp
->status_screen
);
438 for (i
= 0; i
< width
; i
++) {
439 px
= wp
->xoff
+ 2 + i
;
440 if (rctx
->pane_status
== PANE_STATUS_TOP
)
443 py
= wp
->yoff
+ wp
->sy
;
444 cell_type
= screen_redraw_type_of_cell(c
, px
, py
, pane_status
);
445 screen_redraw_border_set(wp
, pane_lines
, cell_type
, &gc
);
446 screen_write_cell(&ctx
, &gc
);
448 gc
.attr
&= ~GRID_ATTR_CHARSET
;
450 screen_write_cursormove(&ctx
, 0, 0, 0);
451 format_draw(&ctx
, &gc
, width
, expanded
, NULL
);
452 screen_write_stop(&ctx
);
457 if (grid_compare(wp
->status_screen
.grid
, old
.grid
) == 0) {
465 /* Draw pane status. */
467 screen_redraw_draw_pane_status(struct screen_redraw_ctx
*ctx
)
469 struct client
*c
= ctx
->c
;
470 struct window
*w
= c
->session
->curw
->window
;
471 struct tty
*tty
= &c
->tty
;
472 struct window_pane
*wp
;
474 u_int i
, x
, width
, xoff
, yoff
, size
;
476 log_debug("%s: %s @%u", __func__
, c
->name
, w
->id
);
478 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
479 if (!window_pane_visible(wp
))
481 s
= &wp
->status_screen
;
483 size
= wp
->status_size
;
484 if (ctx
->pane_status
== PANE_STATUS_TOP
)
487 yoff
= wp
->yoff
+ wp
->sy
;
490 if (xoff
+ size
<= ctx
->ox
||
491 xoff
>= ctx
->ox
+ ctx
->sx
||
493 yoff
>= ctx
->oy
+ ctx
->sy
)
496 if (xoff
>= ctx
->ox
&& xoff
+ size
<= ctx
->ox
+ ctx
->sx
) {
501 } else if (xoff
< ctx
->ox
&& xoff
+ size
> ctx
->ox
+ ctx
->sx
) {
502 /* Both left and right not visible. */
506 } else if (xoff
< ctx
->ox
) {
507 /* Left not visible. */
512 /* Right not visible. */
519 yoff
+= ctx
->statuslines
;
520 tty_draw_line(tty
, s
, i
, 0, width
, x
, yoff
- ctx
->oy
,
521 &grid_default_cell
, NULL
);
523 tty_cursor(tty
, 0, 0);
526 /* Update status line and change flags if unchanged. */
528 screen_redraw_update(struct client
*c
, int flags
)
530 struct window
*w
= c
->session
->curw
->window
;
531 struct window_pane
*wp
;
532 struct options
*wo
= w
->options
;
534 struct screen_redraw_ctx ctx
;
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
);
541 redraw
= status_redraw(c
);
542 if (!redraw
&& (~flags
& CLIENT_REDRAWSTATUSALWAYS
))
543 flags
&= ~CLIENT_REDRAWSTATUS
;
545 if (c
->overlay_draw
!= NULL
)
546 flags
|= CLIENT_REDRAWOVERLAY
;
548 if (options_get_number(wo
, "pane-border-status") != PANE_STATUS_OFF
) {
549 screen_redraw_set_context(c
, &ctx
);
550 lines
= options_get_number(wo
, "pane-border-lines");
552 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
553 if (screen_redraw_make_pane_status(c
, wp
, &ctx
, lines
))
557 flags
|= CLIENT_REDRAWBORDERS
;
562 /* Set up redraw context. */
564 screen_redraw_set_context(struct client
*c
, struct screen_redraw_ctx
*ctx
)
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
;
572 memset(ctx
, 0, sizeof *ctx
);
575 lines
= status_line_size(c
);
576 if (c
->message_string
!= NULL
|| c
->prompt_string
!= NULL
)
577 lines
= (lines
== 0) ? 1 : lines
;
578 if (lines
!= 0 && options_get_number(oo
, "status-position") == 0)
580 ctx
->statuslines
= lines
;
582 ctx
->pane_status
= options_get_number(wo
, "pane-border-status");
583 ctx
->pane_lines
= options_get_number(wo
, "pane-border-lines");
585 tty_window_offset(&c
->tty
, &ctx
->ox
, &ctx
->oy
, &ctx
->sx
, &ctx
->sy
);
587 log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__
, c
->name
,
588 w
->id
, ctx
->ox
, ctx
->oy
, ctx
->sx
, ctx
->sy
, ctx
->statuslines
,
592 /* Redraw entire screen. */
594 screen_redraw_screen(struct client
*c
)
596 struct screen_redraw_ctx ctx
;
599 if (c
->flags
& CLIENT_SUSPENDED
)
602 flags
= screen_redraw_update(c
, c
->flags
);
603 if ((flags
& CLIENT_ALLREDRAWFLAGS
) == 0)
606 screen_redraw_set_context(c
, &ctx
);
607 tty_sync_start(&c
->tty
);
608 tty_update_mode(&c
->tty
, c
->tty
.mode
, NULL
);
610 if (flags
& (CLIENT_REDRAWWINDOW
|CLIENT_REDRAWBORDERS
)) {
611 log_debug("%s: redrawing borders", c
->name
);
612 if (ctx
.pane_status
!= PANE_STATUS_OFF
)
613 screen_redraw_draw_pane_status(&ctx
);
614 screen_redraw_draw_borders(&ctx
);
616 if (flags
& CLIENT_REDRAWWINDOW
) {
617 log_debug("%s: redrawing panes", c
->name
);
618 screen_redraw_draw_panes(&ctx
);
620 if (ctx
.statuslines
!= 0 &&
621 (flags
& (CLIENT_REDRAWSTATUS
|CLIENT_REDRAWSTATUSALWAYS
))) {
622 log_debug("%s: redrawing status", c
->name
);
623 screen_redraw_draw_status(&ctx
);
625 if (c
->overlay_draw
!= NULL
&& (flags
& CLIENT_REDRAWOVERLAY
)) {
626 log_debug("%s: redrawing overlay", c
->name
);
627 c
->overlay_draw(c
, c
->overlay_data
, &ctx
);
633 /* Redraw a single pane. */
635 screen_redraw_pane(struct client
*c
, struct window_pane
*wp
)
637 struct screen_redraw_ctx ctx
;
639 if (!window_pane_visible(wp
))
642 screen_redraw_set_context(c
, &ctx
);
643 tty_sync_start(&c
->tty
);
644 tty_update_mode(&c
->tty
, c
->tty
.mode
, NULL
);
646 screen_redraw_draw_pane(&ctx
, wp
);
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
)
656 struct client
*c
= ctx
->c
;
657 struct session
*s
= c
->session
;
658 struct window
*w
= s
->curw
->window
;
659 struct window_pane
*active
= server_client_get_pane(c
);
660 struct options
*oo
= w
->options
;
661 struct format_tree
*ft
;
663 if (wp
->border_gc_set
)
664 return (&wp
->border_gc
);
665 wp
->border_gc_set
= 1;
667 ft
= format_create_defaults(NULL
, c
, s
, s
->curw
, wp
);
668 if (screen_redraw_check_is(x
, y
, ctx
->pane_status
, active
))
669 style_apply(&wp
->border_gc
, oo
, "pane-active-border-style", ft
);
671 style_apply(&wp
->border_gc
, oo
, "pane-border-style", ft
);
674 return (&wp
->border_gc
);
677 /* Draw a border cell. */
679 screen_redraw_draw_borders_cell(struct screen_redraw_ctx
*ctx
, u_int i
, u_int j
)
681 struct client
*c
= ctx
->c
;
682 struct session
*s
= c
->session
;
683 struct window
*w
= s
->curw
->window
;
684 struct options
*oo
= w
->options
;
685 struct tty
*tty
= &c
->tty
;
686 struct format_tree
*ft
;
687 struct window_pane
*wp
;
688 u_int cell_type
, x
= ctx
->ox
+ i
, y
= ctx
->oy
+ j
;
689 int pane_status
= ctx
->pane_status
, isolates
;
691 const struct grid_cell
*tmp
;
693 if (c
->overlay_check
!= NULL
&&
694 !c
->overlay_check(c
, c
->overlay_data
, x
, y
))
697 cell_type
= screen_redraw_check_cell(c
, x
, y
, pane_status
, &wp
);
698 if (cell_type
== CELL_INSIDE
)
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",
708 ctx
->no_pane_gc_set
= 1;
710 memcpy(&gc
, &ctx
->no_pane_gc
, sizeof gc
);
712 tmp
= screen_redraw_draw_borders_style(ctx
, x
, y
, wp
);
715 memcpy(&gc
, tmp
, sizeof gc
);
717 if (server_is_marked(s
, s
->curw
, marked_pane
.wp
) &&
718 screen_redraw_check_is(x
, y
, pane_status
, marked_pane
.wp
))
719 gc
.attr
^= GRID_ATTR_REVERSE
;
721 screen_redraw_border_set(wp
, ctx
->pane_lines
, cell_type
, &gc
);
723 if (cell_type
== CELL_TOPBOTTOM
&&
724 (c
->flags
& CLIENT_UTF8
) &&
725 tty_term_has(tty
->term
, TTYC_BIDI
))
731 tty_cursor(tty
, i
, ctx
->statuslines
+ j
);
733 tty_cursor(tty
, i
, j
);
735 tty_puts(tty
, END_ISOLATE
);
736 tty_cell(tty
, &gc
, &grid_default_cell
, NULL
);
738 tty_puts(tty
, START_ISOLATE
);
741 /* Draw the borders. */
743 screen_redraw_draw_borders(struct screen_redraw_ctx
*ctx
)
745 struct client
*c
= ctx
->c
;
746 struct session
*s
= c
->session
;
747 struct window
*w
= s
->curw
->window
;
748 struct window_pane
*wp
;
751 log_debug("%s: %s @%u", __func__
, c
->name
, w
->id
);
753 TAILQ_FOREACH(wp
, &w
->panes
, entry
)
754 wp
->border_gc_set
= 0;
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
);
762 /* Draw the panes. */
764 screen_redraw_draw_panes(struct screen_redraw_ctx
*ctx
)
766 struct client
*c
= ctx
->c
;
767 struct window
*w
= c
->session
->curw
->window
;
768 struct window_pane
*wp
;
770 log_debug("%s: %s @%u", __func__
, c
->name
, w
->id
);
772 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
773 if (window_pane_visible(wp
))
774 screen_redraw_draw_pane(ctx
, wp
);
778 /* Draw the status line. */
780 screen_redraw_draw_status(struct screen_redraw_ctx
*ctx
)
782 struct client
*c
= ctx
->c
;
783 struct window
*w
= c
->session
->curw
->window
;
784 struct tty
*tty
= &c
->tty
;
785 struct screen
*s
= c
->status
.active
;
788 log_debug("%s: %s @%u", __func__
, c
->name
, w
->id
);
793 y
= c
->tty
.sy
- ctx
->statuslines
;
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
);
802 screen_redraw_draw_pane(struct screen_redraw_ctx
*ctx
, struct window_pane
*wp
)
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
;
812 log_debug("%s: %s @%u %%%u", __func__
, c
->name
, w
->id
, wp
->id
);
814 if (wp
->xoff
+ wp
->sx
<= ctx
->ox
|| wp
->xoff
>= ctx
->ox
+ ctx
->sx
)
817 top
= ctx
->statuslines
;
820 for (j
= 0; j
< wp
->sy
; j
++) {
821 if (wp
->yoff
+ j
< ctx
->oy
|| wp
->yoff
+ j
>= ctx
->oy
+ ctx
->sy
)
823 y
= top
+ wp
->yoff
+ j
- ctx
->oy
;
825 if (wp
->xoff
>= ctx
->ox
&&
826 wp
->xoff
+ wp
->sx
<= ctx
->ox
+ ctx
->sx
) {
829 x
= wp
->xoff
- ctx
->ox
;
831 } else if (wp
->xoff
< ctx
->ox
&&
832 wp
->xoff
+ wp
->sx
> ctx
->ox
+ ctx
->sx
) {
833 /* Both left and right not visible. */
837 } else if (wp
->xoff
< ctx
->ox
) {
838 /* Left not visible. */
839 i
= ctx
->ox
- wp
->xoff
;
843 /* Right not visible. */
845 x
= wp
->xoff
- ctx
->ox
;
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
);
851 tty_default_colours(&defaults
, wp
);
852 tty_draw_line(tty
, s
, i
, j
, width
, x
, y
, &defaults
, palette
);