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