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