1 /* $OpenBSD$ */
2
3 /*
4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5 *
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.
9 *
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.
17 */
18
19 #include <sys/types.h>
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "tmux.h"
25
26 static struct screen_write_citem *screen_write_collect_trim(
27 struct screen_write_ctx *, u_int, u_int, u_int, int *);
28 static void screen_write_collect_clear(struct screen_write_ctx *, u_int,
29 u_int);
30 static void screen_write_collect_scroll(struct screen_write_ctx *, u_int);
31 static void screen_write_collect_flush(struct screen_write_ctx *, int,
32 const char *);
33
34 static int screen_write_overwrite(struct screen_write_ctx *,
35 struct grid_cell *, u_int);
36 static const struct grid_cell *screen_write_combine(struct screen_write_ctx *,
37 const struct utf8_data *, u_int *);
38
39 struct screen_write_citem {
40 u_int x;
41 int wrapped;
42
43 enum { TEXT, CLEAR } type;
44 u_int used;
45 u_int bg;
46
47 struct grid_cell gc;
48
49 TAILQ_ENTRY(screen_write_citem) entry;
50 };
51 struct screen_write_cline {
52 char *data;
53 TAILQ_HEAD(, screen_write_citem) items;
54 };
55 TAILQ_HEAD(, screen_write_citem) screen_write_citem_freelist =
56 TAILQ_HEAD_INITIALIZER(screen_write_citem_freelist);
57
58 static struct screen_write_citem *
screen_write_get_citem(void)59 screen_write_get_citem(void)
60 {
61 struct screen_write_citem *ci;
62
63 ci = TAILQ_FIRST(&screen_write_citem_freelist);
64 if (ci != NULL) {
65 TAILQ_REMOVE(&screen_write_citem_freelist, ci, entry);
66 memset(ci, 0, sizeof *ci);
67 return (ci);
68 }
69 return (xcalloc(1, sizeof *ci));
70 }
71
72 static void
screen_write_free_citem(struct screen_write_citem * ci)73 screen_write_free_citem(struct screen_write_citem *ci)
74 {
75 TAILQ_INSERT_TAIL(&screen_write_citem_freelist, ci, entry);
76 }
77
78 static void
screen_write_offset_timer(__unused int fd,__unused short events,void * data)79 screen_write_offset_timer(__unused int fd, __unused short events, void *data)
80 {
81 struct window *w = data;
82
83 tty_update_window_offset(w);
84 }
85
86 /* Set cursor position. */
87 static void
screen_write_set_cursor(struct screen_write_ctx * ctx,int cx,int cy)88 screen_write_set_cursor(struct screen_write_ctx *ctx, int cx, int cy)
89 {
90 struct window_pane *wp = ctx->wp;
91 struct window *w;
92 struct screen *s = ctx->s;
93 struct timeval tv = { .tv_usec = 10000 };
94
95 if (cx != -1 && (u_int)cx == s->cx && cy != -1 && (u_int)cy == s->cy)
96 return;
97
98 if (cx != -1) {
99 if ((u_int)cx > screen_size_x(s)) /* allow last column */
100 cx = screen_size_x(s) - 1;
101 s->cx = cx;
102 }
103 if (cy != -1) {
104 if ((u_int)cy > screen_size_y(s) - 1)
105 cy = screen_size_y(s) - 1;
106 s->cy = cy;
107 }
108
109 if (wp == NULL)
110 return;
111 w = wp->window;
112
113 if (!event_initialized(&w->offset_timer))
114 evtimer_set(&w->offset_timer, screen_write_offset_timer, w);
115 if (!evtimer_pending(&w->offset_timer, NULL))
116 evtimer_add(&w->offset_timer, &tv);
117 }
118
119 /* Do a full redraw. */
120 static void
screen_write_redraw_cb(const struct tty_ctx * ttyctx)121 screen_write_redraw_cb(const struct tty_ctx *ttyctx)
122 {
123 struct window_pane *wp = ttyctx->arg;
124
125 if (wp != NULL)
126 wp->flags |= PANE_REDRAW;
127 }
128
129 /* Update context for client. */
130 static int
screen_write_set_client_cb(struct tty_ctx * ttyctx,struct client * c)131 screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
132 {
133 struct window_pane *wp = ttyctx->arg;
134
135 if (c->session->curw->window != wp->window)
136 return (0);
137 if (wp->layout_cell == NULL)
138 return (0);
139
140 if (wp->flags & (PANE_REDRAW|PANE_DROP))
141 return (-1);
142 if (c->flags & CLIENT_REDRAWPANES) {
143 /*
144 * Redraw is already deferred to redraw another pane - redraw
145 * this one also when that happens.
146 */
147 log_debug("%s: adding %%%u to deferred redraw", __func__,
148 wp->id);
149 wp->flags |= PANE_REDRAW;
150 return (-1);
151 }
152
153 ttyctx->bigger = tty_window_offset(&c->tty, &ttyctx->wox, &ttyctx->woy,
154 &ttyctx->wsx, &ttyctx->wsy);
155
156 ttyctx->xoff = ttyctx->rxoff = wp->xoff;
157 ttyctx->yoff = ttyctx->ryoff = wp->yoff;
158
159 if (status_at_line(c) == 0)
160 ttyctx->yoff += status_line_size(c);
161
162 return (1);
163 }
164
165 /* Set up context for TTY command. */
166 static void
screen_write_initctx(struct screen_write_ctx * ctx,struct tty_ctx * ttyctx,int sync)167 screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
168 int sync)
169 {
170 struct screen *s = ctx->s;
171
172 memset(ttyctx, 0, sizeof *ttyctx);
173
174 if (ctx->wp != NULL) {
175 tty_default_colours(&ttyctx->defaults, ctx->wp);
176 ttyctx->palette = ctx->wp->palette;
177 } else {
178 memcpy(&ttyctx->defaults, &grid_default_cell,
179 sizeof ttyctx->defaults);
180 ttyctx->palette = NULL;
181 }
182
183 ttyctx->s = s;
184 ttyctx->sx = screen_size_x(s);
185 ttyctx->sy = screen_size_y(s);
186
187 ttyctx->ocx = s->cx;
188 ttyctx->ocy = s->cy;
189 ttyctx->orlower = s->rlower;
190 ttyctx->orupper = s->rupper;
191
192 if (ctx->init_ctx_cb != NULL)
193 ctx->init_ctx_cb(ctx, ttyctx);
194 else {
195 ttyctx->redraw_cb = screen_write_redraw_cb;
196 if (ctx->wp == NULL)
197 ttyctx->set_client_cb = NULL;
198 else
199 ttyctx->set_client_cb = screen_write_set_client_cb;
200 ttyctx->arg = ctx->wp;
201 }
202
203 if (ctx->wp != NULL &&
204 (~ctx->flags & SCREEN_WRITE_SYNC) &&
205 (sync || ctx->wp != ctx->wp->window->active)) {
206 tty_write(tty_cmd_syncstart, ttyctx);
207 ctx->flags |= SCREEN_WRITE_SYNC;
208 }
209 }
210
211 /* Make write list. */
212 void
screen_write_make_list(struct screen * s)213 screen_write_make_list(struct screen *s)
214 {
215 u_int y;
216
217 s->write_list = xcalloc(screen_size_y(s), sizeof *s->write_list);
218 for (y = 0; y < screen_size_y(s); y++)
219 TAILQ_INIT(&s->write_list[y].items);
220 }
221
222 /* Free write list. */
223 void
screen_write_free_list(struct screen * s)224 screen_write_free_list(struct screen *s)
225 {
226 u_int y;
227
228 for (y = 0; y < screen_size_y(s); y++)
229 free(s->write_list[y].data);
230 free(s->write_list);
231 }
232
233 /* Set up for writing. */
234 static void
screen_write_init(struct screen_write_ctx * ctx,struct screen * s)235 screen_write_init(struct screen_write_ctx *ctx, struct screen *s)
236 {
237 memset(ctx, 0, sizeof *ctx);
238
239 ctx->s = s;
240
241 if (ctx->s->write_list == NULL)
242 screen_write_make_list(ctx->s);
243 ctx->item = screen_write_get_citem();
244
245 ctx->scrolled = 0;
246 ctx->bg = 8;
247 }
248
249 /* Initialize writing with a pane. */
250 void
screen_write_start_pane(struct screen_write_ctx * ctx,struct window_pane * wp,struct screen * s)251 screen_write_start_pane(struct screen_write_ctx *ctx, struct window_pane *wp,
252 struct screen *s)
253 {
254 if (s == NULL)
255 s = wp->screen;
256 screen_write_init(ctx, s);
257 ctx->wp = wp;
258
259 if (log_get_level() != 0) {
260 log_debug("%s: size %ux%u, pane %%%u (at %u,%u)",
261 __func__, screen_size_x(ctx->s), screen_size_y(ctx->s),
262 wp->id, wp->xoff, wp->yoff);
263 }
264 }
265
266 /* Initialize writing with a callback. */
267 void
screen_write_start_callback(struct screen_write_ctx * ctx,struct screen * s,screen_write_init_ctx_cb cb,void * arg)268 screen_write_start_callback(struct screen_write_ctx *ctx, struct screen *s,
269 screen_write_init_ctx_cb cb, void *arg)
270 {
271 screen_write_init(ctx, s);
272
273 ctx->init_ctx_cb = cb;
274 ctx->arg = arg;
275
276 if (log_get_level() != 0) {
277 log_debug("%s: size %ux%u, with callback", __func__,
278 screen_size_x(ctx->s), screen_size_y(ctx->s));
279 }
280 }
281
282 /* Initialize writing. */
283 void
screen_write_start(struct screen_write_ctx * ctx,struct screen * s)284 screen_write_start(struct screen_write_ctx *ctx, struct screen *s)
285 {
286 screen_write_init(ctx, s);
287
288 if (log_get_level() != 0) {
289 log_debug("%s: size %ux%u, no pane", __func__,
290 screen_size_x(ctx->s), screen_size_y(ctx->s));
291 }
292 }
293
294 /* Finish writing. */
295 void
screen_write_stop(struct screen_write_ctx * ctx)296 screen_write_stop(struct screen_write_ctx *ctx)
297 {
298 screen_write_collect_end(ctx);
299 screen_write_collect_flush(ctx, 0, __func__);
300
301 screen_write_free_citem(ctx->item);
302 }
303
304 /* Reset screen state. */
305 void
screen_write_reset(struct screen_write_ctx * ctx)306 screen_write_reset(struct screen_write_ctx *ctx)
307 {
308 struct screen *s = ctx->s;
309
310 screen_reset_tabs(s);
311 screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
312
313 s->mode = MODE_CURSOR | MODE_WRAP;
314
315 screen_write_clearscreen(ctx, 8);
316 screen_write_set_cursor(ctx, 0, 0);
317 }
318
319 /* Write character. */
320 void
screen_write_putc(struct screen_write_ctx * ctx,const struct grid_cell * gcp,u_char ch)321 screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
322 u_char ch)
323 {
324 struct grid_cell gc;
325
326 memcpy(&gc, gcp, sizeof gc);
327
328 utf8_set(&gc.data, ch);
329 screen_write_cell(ctx, &gc);
330 }
331
332 /* Calculate string length. */
333 size_t
screen_write_strlen(const char * fmt,...)334 screen_write_strlen(const char *fmt, ...)
335 {
336 va_list ap;
337 char *msg;
338 struct utf8_data ud;
339 u_char *ptr;
340 size_t left, size = 0;
341 enum utf8_state more;
342
343 va_start(ap, fmt);
344 xvasprintf(&msg, fmt, ap);
345 va_end(ap);
346
347 ptr = msg;
348 while (*ptr != '\0') {
349 if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
350 ptr++;
351
352 left = strlen(ptr);
353 if (left < (size_t)ud.size - 1)
354 break;
355 while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
356 ptr++;
357 ptr++;
358
359 if (more == UTF8_DONE)
360 size += ud.width;
361 } else {
362 if (*ptr > 0x1f && *ptr < 0x7f)
363 size++;
364 ptr++;
365 }
366 }
367
368 free(msg);
369 return (size);
370 }
371
372 /* Write string wrapped over lines. */
373 int
screen_write_text(struct screen_write_ctx * ctx,u_int cx,u_int width,u_int lines,int more,const struct grid_cell * gcp,const char * fmt,...)374 screen_write_text(struct screen_write_ctx *ctx, u_int cx, u_int width,
375 u_int lines, int more, const struct grid_cell *gcp, const char *fmt, ...)
376 {
377 struct screen *s = ctx->s;
378 va_list ap;
379 char *tmp;
380 u_int cy = s->cy, i, end, next, idx = 0, at, left;
381 struct utf8_data *text;
382 struct grid_cell gc;
383
384 memcpy(&gc, gcp, sizeof gc);
385
386 va_start(ap, fmt);
387 xvasprintf(&tmp, fmt, ap);
388 va_end(ap);
389
390 text = utf8_fromcstr(tmp);
391 free(tmp);
392
393 left = (cx + width) - s->cx;
394 for (;;) {
395 /* Find the end of what can fit on the line. */
396 at = 0;
397 for (end = idx; text[end].size != 0; end++) {
398 if (text[end].size == 1 && text[end].data[0] == '\n')
399 break;
400 if (at + text[end].width > left)
401 break;
402 at += text[end].width;
403 }
404
405 /*
406 * If we're on a space, that's the end. If not, walk back to
407 * try and find one.
408 */
409 if (text[end].size == 0)
410 next = end;
411 else if (text[end].size == 1 && text[end].data[0] == '\n')
412 next = end + 1;
413 else if (text[end].size == 1 && text[end].data[0] == ' ')
414 next = end + 1;
415 else {
416 for (i = end; i > idx; i--) {
417 if (text[i].size == 1 && text[i].data[0] == ' ')
418 break;
419 }
420 if (i != idx) {
421 next = i + 1;
422 end = i;
423 } else
424 next = end;
425 }
426
427 /* Print the line. */
428 for (i = idx; i < end; i++) {
429 utf8_copy(&gc.data, &text[i]);
430 screen_write_cell(ctx, &gc);
431 }
432
433 /* If at the bottom, stop. */
434 idx = next;
435 if (s->cy == cy + lines - 1 || text[idx].size == 0)
436 break;
437
438 screen_write_cursormove(ctx, cx, s->cy + 1, 0);
439 left = width;
440 }
441
442 /*
443 * Fail if on the last line and there is more to come or at the end, or
444 * if the text was not entirely consumed.
445 */
446 if ((s->cy == cy + lines - 1 && (!more || s->cx == cx + width)) ||
447 text[idx].size != 0) {
448 free(text);
449 return (0);
450 }
451 free(text);
452
453 /*
454 * If no more to come, move to the next line. Otherwise, leave on
455 * the same line (except if at the end).
456 */
457 if (!more || s->cx == cx + width)
458 screen_write_cursormove(ctx, cx, s->cy + 1, 0);
459 return (1);
460 }
461
462 /* Write simple string (no maximum length). */
463 void
screen_write_puts(struct screen_write_ctx * ctx,const struct grid_cell * gcp,const char * fmt,...)464 screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
465 const char *fmt, ...)
466 {
467 va_list ap;
468
469 va_start(ap, fmt);
470 screen_write_vnputs(ctx, -1, gcp, fmt, ap);
471 va_end(ap);
472 }
473
474 /* Write string with length limit (-1 for unlimited). */
475 void
screen_write_nputs(struct screen_write_ctx * ctx,ssize_t maxlen,const struct grid_cell * gcp,const char * fmt,...)476 screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
477 const struct grid_cell *gcp, const char *fmt, ...)
478 {
479 va_list ap;
480
481 va_start(ap, fmt);
482 screen_write_vnputs(ctx, maxlen, gcp, fmt, ap);
483 va_end(ap);
484 }
485
486 void
screen_write_vnputs(struct screen_write_ctx * ctx,ssize_t maxlen,const struct grid_cell * gcp,const char * fmt,va_list ap)487 screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
488 const struct grid_cell *gcp, const char *fmt, va_list ap)
489 {
490 struct grid_cell gc;
491 struct utf8_data *ud = &gc.data;
492 char *msg;
493 u_char *ptr;
494 size_t left, size = 0;
495 enum utf8_state more;
496
497 memcpy(&gc, gcp, sizeof gc);
498 xvasprintf(&msg, fmt, ap);
499
500 ptr = msg;
501 while (*ptr != '\0') {
502 if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
503 ptr++;
504
505 left = strlen(ptr);
506 if (left < (size_t)ud->size - 1)
507 break;
508 while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
509 ptr++;
510 ptr++;
511
512 if (more != UTF8_DONE)
513 continue;
514 if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
515 while (size < (size_t)maxlen) {
516 screen_write_putc(ctx, &gc, ' ');
517 size++;
518 }
519 break;
520 }
521 size += ud->width;
522 screen_write_cell(ctx, &gc);
523 } else {
524 if (maxlen > 0 && size + 1 > (size_t)maxlen)
525 break;
526
527 if (*ptr == '\001')
528 gc.attr ^= GRID_ATTR_CHARSET;
529 else if (*ptr == '\n') {
530 screen_write_linefeed(ctx, 0, 8);
531 screen_write_carriagereturn(ctx);
532 } else if (*ptr > 0x1f && *ptr < 0x7f) {
533 size++;
534 screen_write_putc(ctx, &gc, *ptr);
535 }
536 ptr++;
537 }
538 }
539
540 free(msg);
541 }
542
543 /*
544 * Copy from another screen but without the selection stuff. Assumes the target
545 * region is already big enough.
546 */
547 void
screen_write_fast_copy(struct screen_write_ctx * ctx,struct screen * src,u_int px,u_int py,u_int nx,u_int ny)548 screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
549 u_int px, u_int py, u_int nx, u_int ny)
550 {
551 struct screen *s = ctx->s;
552 struct grid *gd = src->grid;
553 struct grid_cell gc;
554 u_int xx, yy, cx, cy;
555
556 if (nx == 0 || ny == 0)
557 return;
558
559 cy = s->cy;
560 for (yy = py; yy < py + ny; yy++) {
561 if (yy >= gd->hsize + gd->sy)
562 break;
563 cx = s->cx;
564 for (xx = px; xx < px + nx; xx++) {
565 if (xx >= grid_get_line(gd, yy)->cellsize)
566 break;
567 grid_get_cell(gd, xx, yy, &gc);
568 if (xx + gc.data.width > px + nx)
569 break;
570 grid_view_set_cell(ctx->s->grid, cx, cy, &gc);
571 cx++;
572 }
573 cy++;
574 }
575 }
576
577 /* Draw a horizontal line on screen. */
578 void
screen_write_hline(struct screen_write_ctx * ctx,u_int nx,int left,int right)579 screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right)
580 {
581 struct screen *s = ctx->s;
582 struct grid_cell gc;
583 u_int cx, cy, i;
584
585 cx = s->cx;
586 cy = s->cy;
587
588 memcpy(&gc, &grid_default_cell, sizeof gc);
589 gc.attr |= GRID_ATTR_CHARSET;
590
591 screen_write_putc(ctx, &gc, left ? 't' : 'q');
592 for (i = 1; i < nx - 1; i++)
593 screen_write_putc(ctx, &gc, 'q');
594 screen_write_putc(ctx, &gc, right ? 'u' : 'q');
595
596 screen_write_set_cursor(ctx, cx, cy);
597 }
598
599 /* Draw a horizontal line on screen. */
600 void
screen_write_vline(struct screen_write_ctx * ctx,u_int ny,int top,int bottom)601 screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom)
602 {
603 struct screen *s = ctx->s;
604 struct grid_cell gc;
605 u_int cx, cy, i;
606
607 cx = s->cx;
608 cy = s->cy;
609
610 memcpy(&gc, &grid_default_cell, sizeof gc);
611 gc.attr |= GRID_ATTR_CHARSET;
612
613 screen_write_putc(ctx, &gc, top ? 'w' : 'x');
614 for (i = 1; i < ny - 1; i++) {
615 screen_write_set_cursor(ctx, cx, cy + i);
616 screen_write_putc(ctx, &gc, 'x');
617 }
618 screen_write_set_cursor(ctx, cx, cy + ny - 1);
619 screen_write_putc(ctx, &gc, bottom ? 'v' : 'x');
620
621 screen_write_set_cursor(ctx, cx, cy);
622 }
623
624 /* Draw a menu on screen. */
625 void
screen_write_menu(struct screen_write_ctx * ctx,struct menu * menu,int choice,const struct grid_cell * choice_gc)626 screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu,
627 int choice, const struct grid_cell *choice_gc)
628 {
629 struct screen *s = ctx->s;
630 struct grid_cell default_gc;
631 const struct grid_cell *gc = &default_gc;
632 u_int cx, cy, i, j;
633 const char *name;
634
635 cx = s->cx;
636 cy = s->cy;
637
638 memcpy(&default_gc, &grid_default_cell, sizeof default_gc);
639
640 screen_write_box(ctx, menu->width + 4, menu->count + 2);
641 screen_write_cursormove(ctx, cx + 2, cy, 0);
642 format_draw(ctx, &default_gc, menu->width, menu->title, NULL);
643
644 for (i = 0; i < menu->count; i++) {
645 name = menu->items[i].name;
646 if (name == NULL) {
647 screen_write_cursormove(ctx, cx, cy + 1 + i, 0);
648 screen_write_hline(ctx, menu->width + 4, 1, 1);
649 } else {
650 if (choice >= 0 && i == (u_int)choice && *name != '-')
651 gc = choice_gc;
652 screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
653 for (j = 0; j < menu->width; j++)
654 screen_write_putc(ctx, gc, ' ');
655 screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
656 if (*name == '-') {
657 name++;
658 default_gc.attr |= GRID_ATTR_DIM;
659 format_draw(ctx, gc, menu->width, name, NULL);
660 default_gc.attr &= ~GRID_ATTR_DIM;
661 } else
662 format_draw(ctx, gc, menu->width, name, NULL);
663 gc = &default_gc;
664 }
665 }
666
667 screen_write_set_cursor(ctx, cx, cy);
668 }
669
670 /* Draw a box on screen. */
671 void
screen_write_box(struct screen_write_ctx * ctx,u_int nx,u_int ny)672 screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny)
673 {
674 struct screen *s = ctx->s;
675 struct grid_cell gc;
676 u_int cx, cy, i;
677
678 cx = s->cx;
679 cy = s->cy;
680
681 memcpy(&gc, &grid_default_cell, sizeof gc);
682 gc.attr |= GRID_ATTR_CHARSET;
683
684 screen_write_putc(ctx, &gc, 'l');
685 for (i = 1; i < nx - 1; i++)
686 screen_write_putc(ctx, &gc, 'q');
687 screen_write_putc(ctx, &gc, 'k');
688
689 screen_write_set_cursor(ctx, cx, cy + ny - 1);
690 screen_write_putc(ctx, &gc, 'm');
691 for (i = 1; i < nx - 1; i++)
692 screen_write_putc(ctx, &gc, 'q');
693 screen_write_putc(ctx, &gc, 'j');
694
695 for (i = 1; i < ny - 1; i++) {
696 screen_write_set_cursor(ctx, cx, cy + i);
697 screen_write_putc(ctx, &gc, 'x');
698 }
699 for (i = 1; i < ny - 1; i++) {
700 screen_write_set_cursor(ctx, cx + nx - 1, cy + i);
701 screen_write_putc(ctx, &gc, 'x');
702 }
703
704 screen_write_set_cursor(ctx, cx, cy);
705 }
706
707 /*
708 * Write a preview version of a window. Assumes target area is big enough and
709 * already cleared.
710 */
711 void
screen_write_preview(struct screen_write_ctx * ctx,struct screen * src,u_int nx,u_int ny)712 screen_write_preview(struct screen_write_ctx *ctx, struct screen *src, u_int nx,
713 u_int ny)
714 {
715 struct screen *s = ctx->s;
716 struct grid_cell gc;
717 u_int cx, cy, px, py;
718
719 cx = s->cx;
720 cy = s->cy;
721
722 /*
723 * If the cursor is on, pick the area around the cursor, otherwise use
724 * the top left.
725 */
726 if (src->mode & MODE_CURSOR) {
727 px = src->cx;
728 if (px < nx / 3)
729 px = 0;
730 else
731 px = px - nx / 3;
732 if (px + nx > screen_size_x(src)) {
733 if (nx > screen_size_x(src))
734 px = 0;
735 else
736 px = screen_size_x(src) - nx;
737 }
738 py = src->cy;
739 if (py < ny / 3)
740 py = 0;
741 else
742 py = py - ny / 3;
743 if (py + ny > screen_size_y(src)) {
744 if (ny > screen_size_y(src))
745 py = 0;
746 else
747 py = screen_size_y(src) - ny;
748 }
749 } else {
750 px = 0;
751 py = 0;
752 }
753
754 screen_write_fast_copy(ctx, src, px, src->grid->hsize + py, nx, ny);
755
756 if (src->mode & MODE_CURSOR) {
757 grid_view_get_cell(src->grid, src->cx, src->cy, &gc);
758 gc.attr |= GRID_ATTR_REVERSE;
759 screen_write_set_cursor(ctx, cx + (src->cx - px),
760 cy + (src->cy - py));
761 screen_write_cell(ctx, &gc);
762 }
763 }
764
765 /* Set a mode. */
766 void
screen_write_mode_set(struct screen_write_ctx * ctx,int mode)767 screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
768 {
769 struct screen *s = ctx->s;
770
771 s->mode |= mode;
772 }
773
774 /* Clear a mode. */
775 void
screen_write_mode_clear(struct screen_write_ctx * ctx,int mode)776 screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
777 {
778 struct screen *s = ctx->s;
779
780 s->mode &= ~mode;
781 }
782
783 /* Cursor up by ny. */
784 void
screen_write_cursorup(struct screen_write_ctx * ctx,u_int ny)785 screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
786 {
787 struct screen *s = ctx->s;
788 u_int cx = s->cx, cy = s->cy;
789
790 if (ny == 0)
791 ny = 1;
792
793 if (cy < s->rupper) {
794 /* Above region. */
795 if (ny > cy)
796 ny = cy;
797 } else {
798 /* Below region. */
799 if (ny > cy - s->rupper)
800 ny = cy - s->rupper;
801 }
802 if (cx == screen_size_x(s))
803 cx--;
804
805 cy -= ny;
806
807 screen_write_set_cursor(ctx, cx, cy);
808 }
809
810 /* Cursor down by ny. */
811 void
screen_write_cursordown(struct screen_write_ctx * ctx,u_int ny)812 screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
813 {
814 struct screen *s = ctx->s;
815 u_int cx = s->cx, cy = s->cy;
816
817 if (ny == 0)
818 ny = 1;
819
820 if (cy > s->rlower) {
821 /* Below region. */
822 if (ny > screen_size_y(s) - 1 - cy)
823 ny = screen_size_y(s) - 1 - cy;
824 } else {
825 /* Above region. */
826 if (ny > s->rlower - cy)
827 ny = s->rlower - cy;
828 }
829 if (cx == screen_size_x(s))
830 cx--;
831 else if (ny == 0)
832 return;
833
834 cy += ny;
835
836 screen_write_set_cursor(ctx, cx, cy);
837 }
838
839 /* Cursor right by nx. */
840 void
screen_write_cursorright(struct screen_write_ctx * ctx,u_int nx)841 screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
842 {
843 struct screen *s = ctx->s;
844 u_int cx = s->cx, cy = s->cy;
845
846 if (nx == 0)
847 nx = 1;
848
849 if (nx > screen_size_x(s) - 1 - cx)
850 nx = screen_size_x(s) - 1 - cx;
851 if (nx == 0)
852 return;
853
854 cx += nx;
855
856 screen_write_set_cursor(ctx, cx, cy);
857 }
858
859 /* Cursor left by nx. */
860 void
screen_write_cursorleft(struct screen_write_ctx * ctx,u_int nx)861 screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
862 {
863 struct screen *s = ctx->s;
864 u_int cx = s->cx, cy = s->cy;
865
866 if (nx == 0)
867 nx = 1;
868
869 if (nx > cx)
870 nx = cx;
871 if (nx == 0)
872 return;
873
874 cx -= nx;
875
876 screen_write_set_cursor(ctx, cx, cy);
877 }
878
879 /* Backspace; cursor left unless at start of wrapped line when can move up. */
880 void
screen_write_backspace(struct screen_write_ctx * ctx)881 screen_write_backspace(struct screen_write_ctx *ctx)
882 {
883 struct screen *s = ctx->s;
884 struct grid_line *gl;
885 u_int cx = s->cx, cy = s->cy;
886
887 if (cx == 0) {
888 if (cy == 0)
889 return;
890 gl = grid_get_line(s->grid, s->grid->hsize + cy - 1);
891 if (gl->flags & GRID_LINE_WRAPPED) {
892 cy--;
893 cx = screen_size_x(s) - 1;
894 }
895 } else
896 cx--;
897
898 screen_write_set_cursor(ctx, cx, cy);
899 }
900
901 /* VT100 alignment test. */
902 void
screen_write_alignmenttest(struct screen_write_ctx * ctx)903 screen_write_alignmenttest(struct screen_write_ctx *ctx)
904 {
905 struct screen *s = ctx->s;
906 struct tty_ctx ttyctx;
907 struct grid_cell gc;
908 u_int xx, yy;
909
910 memcpy(&gc, &grid_default_cell, sizeof gc);
911 utf8_set(&gc.data, 'E');
912
913 for (yy = 0; yy < screen_size_y(s); yy++) {
914 for (xx = 0; xx < screen_size_x(s); xx++)
915 grid_view_set_cell(s->grid, xx, yy, &gc);
916 }
917
918 screen_write_set_cursor(ctx, 0, 0);
919
920 s->rupper = 0;
921 s->rlower = screen_size_y(s) - 1;
922
923 screen_write_initctx(ctx, &ttyctx, 1);
924
925 screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1);
926 tty_write(tty_cmd_alignmenttest, &ttyctx);
927 }
928
929 /* Insert nx characters. */
930 void
screen_write_insertcharacter(struct screen_write_ctx * ctx,u_int nx,u_int bg)931 screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
932 {
933 struct screen *s = ctx->s;
934 struct tty_ctx ttyctx;
935
936 if (nx == 0)
937 nx = 1;
938
939 if (nx > screen_size_x(s) - s->cx)
940 nx = screen_size_x(s) - s->cx;
941 if (nx == 0)
942 return;
943
944 if (s->cx > screen_size_x(s) - 1)
945 return;
946
947 screen_write_initctx(ctx, &ttyctx, 0);
948 ttyctx.bg = bg;
949
950 grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg);
951
952 screen_write_collect_flush(ctx, 0, __func__);
953 ttyctx.num = nx;
954 tty_write(tty_cmd_insertcharacter, &ttyctx);
955 }
956
957 /* Delete nx characters. */
958 void
screen_write_deletecharacter(struct screen_write_ctx * ctx,u_int nx,u_int bg)959 screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
960 {
961 struct screen *s = ctx->s;
962 struct tty_ctx ttyctx;
963
964 if (nx == 0)
965 nx = 1;
966
967 if (nx > screen_size_x(s) - s->cx)
968 nx = screen_size_x(s) - s->cx;
969 if (nx == 0)
970 return;
971
972 if (s->cx > screen_size_x(s) - 1)
973 return;
974
975 screen_write_initctx(ctx, &ttyctx, 0);
976 ttyctx.bg = bg;
977
978 grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg);
979
980 screen_write_collect_flush(ctx, 0, __func__);
981 ttyctx.num = nx;
982 tty_write(tty_cmd_deletecharacter, &ttyctx);
983 }
984
985 /* Clear nx characters. */
986 void
screen_write_clearcharacter(struct screen_write_ctx * ctx,u_int nx,u_int bg)987 screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
988 {
989 struct screen *s = ctx->s;
990 struct tty_ctx ttyctx;
991
992 if (nx == 0)
993 nx = 1;
994
995 if (nx > screen_size_x(s) - s->cx)
996 nx = screen_size_x(s) - s->cx;
997 if (nx == 0)
998 return;
999
1000 if (s->cx > screen_size_x(s) - 1)
1001 return;
1002
1003 screen_write_initctx(ctx, &ttyctx, 0);
1004 ttyctx.bg = bg;
1005
1006 grid_view_clear(s->grid, s->cx, s->cy, nx, 1, bg);
1007
1008 screen_write_collect_flush(ctx, 0, __func__);
1009 ttyctx.num = nx;
1010 tty_write(tty_cmd_clearcharacter, &ttyctx);
1011 }
1012
1013 /* Insert ny lines. */
1014 void
screen_write_insertline(struct screen_write_ctx * ctx,u_int ny,u_int bg)1015 screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
1016 {
1017 struct screen *s = ctx->s;
1018 struct grid *gd = s->grid;
1019 struct tty_ctx ttyctx;
1020
1021 if (ny == 0)
1022 ny = 1;
1023
1024 if (s->cy < s->rupper || s->cy > s->rlower) {
1025 if (ny > screen_size_y(s) - s->cy)
1026 ny = screen_size_y(s) - s->cy;
1027 if (ny == 0)
1028 return;
1029
1030 screen_write_initctx(ctx, &ttyctx, 1);
1031 ttyctx.bg = bg;
1032
1033 grid_view_insert_lines(gd, s->cy, ny, bg);
1034
1035 screen_write_collect_flush(ctx, 0, __func__);
1036 ttyctx.num = ny;
1037 tty_write(tty_cmd_insertline, &ttyctx);
1038 return;
1039 }
1040
1041 if (ny > s->rlower + 1 - s->cy)
1042 ny = s->rlower + 1 - s->cy;
1043 if (ny == 0)
1044 return;
1045
1046 screen_write_initctx(ctx, &ttyctx, 1);
1047 ttyctx.bg = bg;
1048
1049 if (s->cy < s->rupper || s->cy > s->rlower)
1050 grid_view_insert_lines(gd, s->cy, ny, bg);
1051 else
1052 grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg);
1053
1054 screen_write_collect_flush(ctx, 0, __func__);
1055
1056 ttyctx.num = ny;
1057 tty_write(tty_cmd_insertline, &ttyctx);
1058 }
1059
1060 /* Delete ny lines. */
1061 void
screen_write_deleteline(struct screen_write_ctx * ctx,u_int ny,u_int bg)1062 screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
1063 {
1064 struct screen *s = ctx->s;
1065 struct grid *gd = s->grid;
1066 struct tty_ctx ttyctx;
1067
1068 if (ny == 0)
1069 ny = 1;
1070
1071 if (s->cy < s->rupper || s->cy > s->rlower) {
1072 if (ny > screen_size_y(s) - s->cy)
1073 ny = screen_size_y(s) - s->cy;
1074 if (ny == 0)
1075 return;
1076
1077 screen_write_initctx(ctx, &ttyctx, 1);
1078 ttyctx.bg = bg;
1079
1080 grid_view_delete_lines(gd, s->cy, ny, bg);
1081
1082 screen_write_collect_flush(ctx, 0, __func__);
1083 ttyctx.num = ny;
1084 tty_write(tty_cmd_deleteline, &ttyctx);
1085 return;
1086 }
1087
1088 if (ny > s->rlower + 1 - s->cy)
1089 ny = s->rlower + 1 - s->cy;
1090 if (ny == 0)
1091 return;
1092
1093 screen_write_initctx(ctx, &ttyctx, 1);
1094 ttyctx.bg = bg;
1095
1096 if (s->cy < s->rupper || s->cy > s->rlower)
1097 grid_view_delete_lines(gd, s->cy, ny, bg);
1098 else
1099 grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg);
1100
1101 screen_write_collect_flush(ctx, 0, __func__);
1102 ttyctx.num = ny;
1103 tty_write(tty_cmd_deleteline, &ttyctx);
1104 }
1105
1106 /* Clear line at cursor. */
1107 void
screen_write_clearline(struct screen_write_ctx * ctx,u_int bg)1108 screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
1109 {
1110 struct screen *s = ctx->s;
1111 struct grid_line *gl;
1112 u_int sx = screen_size_x(s);
1113 struct screen_write_citem *ci = ctx->item;
1114
1115 gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
1116 if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
1117 return;
1118
1119 grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
1120
1121 screen_write_collect_clear(ctx, s->cy, 1);
1122 ci->x = 0;
1123 ci->used = sx;
1124 ci->type = CLEAR;
1125 ci->bg = bg;
1126 TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry);
1127 ctx->item = screen_write_get_citem();
1128 }
1129
1130 /* Clear to end of line from cursor. */
1131 void
screen_write_clearendofline(struct screen_write_ctx * ctx,u_int bg)1132 screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
1133 {
1134 struct screen *s = ctx->s;
1135 struct grid_line *gl;
1136 u_int sx = screen_size_x(s);
1137 struct screen_write_citem *ci = ctx->item, *before;
1138
1139 if (s->cx == 0) {
1140 screen_write_clearline(ctx, bg);
1141 return;
1142 }
1143
1144 gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
1145 if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg)))
1146 return;
1147
1148 grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
1149
1150 before = screen_write_collect_trim(ctx, s->cy, s->cx, sx - s->cx, NULL);
1151 ci->x = s->cx;
1152 ci->used = sx - s->cx;
1153 ci->type = CLEAR;
1154 ci->bg = bg;
1155 if (before == NULL)
1156 TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry);
1157 else
1158 TAILQ_INSERT_BEFORE(before, ci, entry);
1159 ctx->item = screen_write_get_citem();
1160 }
1161
1162 /* Clear to start of line from cursor. */
1163 void
screen_write_clearstartofline(struct screen_write_ctx * ctx,u_int bg)1164 screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
1165 {
1166 struct screen *s = ctx->s;
1167 u_int sx = screen_size_x(s);
1168 struct screen_write_citem *ci = ctx->item, *before;
1169
1170 if (s->cx >= sx - 1) {
1171 screen_write_clearline(ctx, bg);
1172 return;
1173 }
1174
1175 if (s->cx > sx - 1)
1176 grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
1177 else
1178 grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
1179
1180 before = screen_write_collect_trim(ctx, s->cy, 0, s->cx + 1, NULL);
1181 ci->x = 0;
1182 ci->used = s->cx + 1;
1183 ci->type = CLEAR;
1184 ci->bg = bg;
1185 if (before == NULL)
1186 TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry);
1187 else
1188 TAILQ_INSERT_BEFORE(before, ci, entry);
1189 ctx->item = screen_write_get_citem();
1190 }
1191
1192 /* Move cursor to px,py. */
1193 void
screen_write_cursormove(struct screen_write_ctx * ctx,int px,int py,int origin)1194 screen_write_cursormove(struct screen_write_ctx *ctx, int px, int py,
1195 int origin)
1196 {
1197 struct screen *s = ctx->s;
1198
1199 if (origin && py != -1 && (s->mode & MODE_ORIGIN)) {
1200 if ((u_int)py > s->rlower - s->rupper)
1201 py = s->rlower;
1202 else
1203 py += s->rupper;
1204 }
1205
1206 if (px != -1 && (u_int)px > screen_size_x(s) - 1)
1207 px = screen_size_x(s) - 1;
1208 if (py != -1 && (u_int)py > screen_size_y(s) - 1)
1209 py = screen_size_y(s) - 1;
1210
1211 log_debug("%s: from %u,%u to %u,%u", __func__, s->cx, s->cy, px, py);
1212 screen_write_set_cursor(ctx, px, py);
1213 }
1214
1215 /* Reverse index (up with scroll). */
1216 void
screen_write_reverseindex(struct screen_write_ctx * ctx,u_int bg)1217 screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg)
1218 {
1219 struct screen *s = ctx->s;
1220 struct tty_ctx ttyctx;
1221
1222 if (s->cy == s->rupper) {
1223 grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg);
1224 screen_write_collect_flush(ctx, 0, __func__);
1225
1226 screen_write_initctx(ctx, &ttyctx, 1);
1227 ttyctx.bg = bg;
1228
1229 tty_write(tty_cmd_reverseindex, &ttyctx);
1230 } else if (s->cy > 0)
1231 screen_write_set_cursor(ctx, -1, s->cy - 1);
1232
1233 }
1234
1235 /* Set scroll region. */
1236 void
screen_write_scrollregion(struct screen_write_ctx * ctx,u_int rupper,u_int rlower)1237 screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
1238 u_int rlower)
1239 {
1240 struct screen *s = ctx->s;
1241
1242 if (rupper > screen_size_y(s) - 1)
1243 rupper = screen_size_y(s) - 1;
1244 if (rlower > screen_size_y(s) - 1)
1245 rlower = screen_size_y(s) - 1;
1246 if (rupper >= rlower) /* cannot be one line */
1247 return;
1248
1249 screen_write_collect_flush(ctx, 0, __func__);
1250
1251 /* Cursor moves to top-left. */
1252 screen_write_set_cursor(ctx, 0, 0);
1253
1254 s->rupper = rupper;
1255 s->rlower = rlower;
1256 }
1257
1258 /* Line feed. */
1259 void
screen_write_linefeed(struct screen_write_ctx * ctx,int wrapped,u_int bg)1260 screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
1261 {
1262 struct screen *s = ctx->s;
1263 struct grid *gd = s->grid;
1264 struct grid_line *gl;
1265
1266 gl = grid_get_line(gd, gd->hsize + s->cy);
1267 if (wrapped)
1268 gl->flags |= GRID_LINE_WRAPPED;
1269
1270 log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy,
1271 s->rupper, s->rlower);
1272
1273 if (bg != ctx->bg) {
1274 screen_write_collect_flush(ctx, 1, __func__);
1275 ctx->bg = bg;
1276 }
1277
1278 if (s->cy == s->rlower) {
1279 grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
1280 screen_write_collect_scroll(ctx, bg);
1281 ctx->scrolled++;
1282 } else if (s->cy < screen_size_y(s) - 1)
1283 screen_write_set_cursor(ctx, -1, s->cy + 1);
1284 }
1285
1286 /* Scroll up. */
1287 void
screen_write_scrollup(struct screen_write_ctx * ctx,u_int lines,u_int bg)1288 screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg)
1289 {
1290 struct screen *s = ctx->s;
1291 struct grid *gd = s->grid;
1292 u_int i;
1293
1294 if (lines == 0)
1295 lines = 1;
1296 else if (lines > s->rlower - s->rupper + 1)
1297 lines = s->rlower - s->rupper + 1;
1298
1299 if (bg != ctx->bg) {
1300 screen_write_collect_flush(ctx, 1, __func__);
1301 ctx->bg = bg;
1302 }
1303
1304 for (i = 0; i < lines; i++) {
1305 grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
1306 screen_write_collect_scroll(ctx, bg);
1307 }
1308 ctx->scrolled += lines;
1309 }
1310
1311 /* Scroll down. */
1312 void
screen_write_scrolldown(struct screen_write_ctx * ctx,u_int lines,u_int bg)1313 screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg)
1314 {
1315 struct screen *s = ctx->s;
1316 struct grid *gd = s->grid;
1317 struct tty_ctx ttyctx;
1318 u_int i;
1319
1320 screen_write_initctx(ctx, &ttyctx, 1);
1321 ttyctx.bg = bg;
1322
1323 if (lines == 0)
1324 lines = 1;
1325 else if (lines > s->rlower - s->rupper + 1)
1326 lines = s->rlower - s->rupper + 1;
1327
1328 for (i = 0; i < lines; i++)
1329 grid_view_scroll_region_down(gd, s->rupper, s->rlower, bg);
1330
1331 screen_write_collect_flush(ctx, 0, __func__);
1332 ttyctx.num = lines;
1333 tty_write(tty_cmd_scrolldown, &ttyctx);
1334 }
1335
1336 /* Carriage return (cursor to start of line). */
1337 void
screen_write_carriagereturn(struct screen_write_ctx * ctx)1338 screen_write_carriagereturn(struct screen_write_ctx *ctx)
1339 {
1340 screen_write_set_cursor(ctx, 0, -1);
1341 }
1342
1343 /* Clear to end of screen from cursor. */
1344 void
screen_write_clearendofscreen(struct screen_write_ctx * ctx,u_int bg)1345 screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
1346 {
1347 struct screen *s = ctx->s;
1348 struct grid *gd = s->grid;
1349 struct tty_ctx ttyctx;
1350 u_int sx = screen_size_x(s), sy = screen_size_y(s);
1351
1352 screen_write_initctx(ctx, &ttyctx, 1);
1353 ttyctx.bg = bg;
1354
1355 /* Scroll into history if it is enabled and clearing entire screen. */
1356 if (s->cx == 0 && s->cy == 0 && (gd->flags & GRID_HISTORY))
1357 grid_view_clear_history(gd, bg);
1358 else {
1359 if (s->cx <= sx - 1)
1360 grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg);
1361 grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg);
1362 }
1363
1364 screen_write_collect_clear(ctx, s->cy + 1, sy - (s->cy + 1));
1365 screen_write_collect_flush(ctx, 0, __func__);
1366 tty_write(tty_cmd_clearendofscreen, &ttyctx);
1367 }
1368
1369 /* Clear to start of screen. */
1370 void
screen_write_clearstartofscreen(struct screen_write_ctx * ctx,u_int bg)1371 screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
1372 {
1373 struct screen *s = ctx->s;
1374 struct tty_ctx ttyctx;
1375 u_int sx = screen_size_x(s);
1376
1377 screen_write_initctx(ctx, &ttyctx, 1);
1378 ttyctx.bg = bg;
1379
1380 if (s->cy > 0)
1381 grid_view_clear(s->grid, 0, 0, sx, s->cy, bg);
1382 if (s->cx > sx - 1)
1383 grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
1384 else
1385 grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
1386
1387 screen_write_collect_clear(ctx, 0, s->cy);
1388 screen_write_collect_flush(ctx, 0, __func__);
1389 tty_write(tty_cmd_clearstartofscreen, &ttyctx);
1390 }
1391
1392 /* Clear entire screen. */
1393 void
screen_write_clearscreen(struct screen_write_ctx * ctx,u_int bg)1394 screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
1395 {
1396 struct screen *s = ctx->s;
1397 struct tty_ctx ttyctx;
1398 u_int sx = screen_size_x(s), sy = screen_size_y(s);
1399
1400 screen_write_initctx(ctx, &ttyctx, 1);
1401 ttyctx.bg = bg;
1402
1403 /* Scroll into history if it is enabled. */
1404 if (s->grid->flags & GRID_HISTORY)
1405 grid_view_clear_history(s->grid, bg);
1406 else
1407 grid_view_clear(s->grid, 0, 0, sx, sy, bg);
1408
1409 screen_write_collect_clear(ctx, 0, sy);
1410 tty_write(tty_cmd_clearscreen, &ttyctx);
1411 }
1412
1413 /* Clear entire history. */
1414 void
screen_write_clearhistory(struct screen_write_ctx * ctx)1415 screen_write_clearhistory(struct screen_write_ctx *ctx)
1416 {
1417 grid_clear_history(ctx->s->grid);
1418 }
1419
1420 /* Trim collected items. */
1421 static struct screen_write_citem *
screen_write_collect_trim(struct screen_write_ctx * ctx,u_int y,u_int x,u_int used,int * wrapped)1422 screen_write_collect_trim(struct screen_write_ctx *ctx, u_int y, u_int x,
1423 u_int used, int *wrapped)
1424 {
1425 struct screen_write_cline *cl = &ctx->s->write_list[y];
1426 struct screen_write_citem *ci, *ci2, *tmp, *before = NULL;
1427 u_int sx = x, ex = x + used - 1;
1428 u_int csx, cex;
1429
1430 if (TAILQ_EMPTY(&cl->items))
1431 return (NULL);
1432 TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) {
1433 csx = ci->x;
1434 cex = ci->x + ci->used - 1;
1435
1436 /* Item is entirely before. */
1437 if (cex < sx) {
1438 log_debug("%s: %p %u-%u before %u-%u", __func__, ci,
1439 csx, cex, sx, ex);
1440 continue;
1441 }
1442
1443 /* Item is entirely after. */
1444 if (csx > ex) {
1445 log_debug("%s: %p %u-%u after %u-%u", __func__, ci,
1446 csx, cex, sx, ex);
1447 before = ci;
1448 break;
1449 }
1450
1451 /* Item is entirely inside. */
1452 if (csx >= sx && cex <= ex) {
1453 log_debug("%s: %p %u-%u inside %u-%u", __func__, ci,
1454 csx, cex, sx, ex);
1455 TAILQ_REMOVE(&cl->items, ci, entry);
1456 screen_write_free_citem(ci);
1457 if (csx == 0 && ci->wrapped && wrapped != NULL)
1458 *wrapped = 1;
1459 continue;
1460 }
1461
1462 /* Item under the start. */
1463 if (csx < sx && cex >= sx && cex <= ex) {
1464 log_debug("%s: %p %u-%u start %u-%u", __func__, ci,
1465 csx, cex, sx, ex);
1466 ci->used = sx - csx;
1467 log_debug("%s: %p now %u-%u", __func__, ci, ci->x,
1468 ci->x + ci->used + 1);
1469 continue;
1470 }
1471
1472 /* Item covers the end. */
1473 if (cex > ex && csx >= sx && csx <= ex) {
1474 log_debug("%s: %p %u-%u end %u-%u", __func__, ci,
1475 csx, cex, sx, ex);
1476 ci->x = ex + 1;
1477 ci->used = cex - ex;
1478 log_debug("%s: %p now %u-%u", __func__, ci, ci->x,
1479 ci->x + ci->used + 1);
1480 before = ci;
1481 break;
1482 }
1483
1484 /* Item must cover both sides. */
1485 log_debug("%s: %p %u-%u under %u-%u", __func__, ci,
1486 csx, cex, sx, ex);
1487 ci2 = screen_write_get_citem();
1488 ci2->type = ci->type;
1489 ci2->bg = ci->bg;
1490 memcpy(&ci2->gc, &ci->gc, sizeof ci2->gc);
1491 TAILQ_INSERT_AFTER(&cl->items, ci, ci2, entry);
1492
1493 ci->used = sx - csx;
1494 ci2->x = ex + 1;
1495 ci2->used = cex - ex;
1496
1497 log_debug("%s: %p now %u-%u (%p) and %u-%u (%p)", __func__, ci,
1498 ci->x, ci->x + ci->used - 1, ci, ci2->x,
1499 ci2->x + ci2->used - 1, ci2);
1500 before = ci2;
1501 break;
1502 }
1503 return (before);
1504 }
1505
1506 /* Clear collected lines. */
1507 static void
screen_write_collect_clear(struct screen_write_ctx * ctx,u_int y,u_int n)1508 screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n)
1509 {
1510 struct screen_write_cline *cl;
1511 u_int i;
1512
1513 for (i = y; i < y + n; i++) {
1514 cl = &ctx->s->write_list[i];
1515 TAILQ_CONCAT(&screen_write_citem_freelist, &cl->items, entry);
1516 }
1517 }
1518
1519 /* Scroll collected lines up. */
1520 static void
screen_write_collect_scroll(struct screen_write_ctx * ctx,u_int bg)1521 screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg)
1522 {
1523 struct screen *s = ctx->s;
1524 struct screen_write_cline *cl;
1525 u_int y;
1526 char *saved;
1527 struct screen_write_citem *ci;
1528
1529 log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy,
1530 s->rupper, s->rlower);
1531
1532 screen_write_collect_clear(ctx, s->rupper, 1);
1533 saved = ctx->s->write_list[s->rupper].data;
1534 for (y = s->rupper; y < s->rlower; y++) {
1535 cl = &ctx->s->write_list[y + 1];
1536 TAILQ_CONCAT(&ctx->s->write_list[y].items, &cl->items, entry);
1537 ctx->s->write_list[y].data = cl->data;
1538 }
1539 ctx->s->write_list[s->rlower].data = saved;
1540
1541 ci = screen_write_get_citem();
1542 ci->x = 0;
1543 ci->used = screen_size_x(s);
1544 ci->type = CLEAR;
1545 ci->bg = bg;
1546 TAILQ_INSERT_TAIL(&ctx->s->write_list[s->rlower].items, ci, entry);
1547 }
1548
1549 /* Flush collected lines. */
1550 static void
screen_write_collect_flush(struct screen_write_ctx * ctx,int scroll_only,const char * from)1551 screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only,
1552 const char *from)
1553 {
1554 struct screen *s = ctx->s;
1555 struct screen_write_citem *ci, *tmp;
1556 struct screen_write_cline *cl;
1557 u_int y, cx, cy, last, items = 0;
1558 struct tty_ctx ttyctx;
1559
1560 if (ctx->scrolled != 0) {
1561 log_debug("%s: scrolled %u (region %u-%u)", __func__,
1562 ctx->scrolled, s->rupper, s->rlower);
1563 if (ctx->scrolled > s->rlower - s->rupper + 1)
1564 ctx->scrolled = s->rlower - s->rupper + 1;
1565
1566 screen_write_initctx(ctx, &ttyctx, 1);
1567 ttyctx.num = ctx->scrolled;
1568 ttyctx.bg = ctx->bg;
1569 tty_write(tty_cmd_scrollup, &ttyctx);
1570 }
1571 ctx->scrolled = 0;
1572 ctx->bg = 8;
1573
1574 if (scroll_only)
1575 return;
1576
1577 cx = s->cx; cy = s->cy;
1578 for (y = 0; y < screen_size_y(s); y++) {
1579 cl = &ctx->s->write_list[y];
1580 last = UINT_MAX;
1581 TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) {
1582 if (last != UINT_MAX && ci->x <= last) {
1583 fatalx("collect list not in order: %u <= %u",
1584 ci->x, last);
1585 }
1586 screen_write_set_cursor(ctx, ci->x, y);
1587 if (ci->type == CLEAR) {
1588 screen_write_initctx(ctx, &ttyctx, 1);
1589 ttyctx.bg = ci->bg;
1590 ttyctx.num = ci->used;
1591 tty_write(tty_cmd_clearcharacter, &ttyctx);
1592 } else {
1593 screen_write_initctx(ctx, &ttyctx, 0);
1594 ttyctx.cell = &ci->gc;
1595 ttyctx.wrapped = ci->wrapped;
1596 ttyctx.ptr = cl->data + ci->x;
1597 ttyctx.num = ci->used;
1598 tty_write(tty_cmd_cells, &ttyctx);
1599 }
1600 items++;
1601
1602 TAILQ_REMOVE(&cl->items, ci, entry);
1603 screen_write_free_citem(ci);
1604 last = ci->x;
1605 }
1606 }
1607 s->cx = cx; s->cy = cy;
1608
1609 log_debug("%s: flushed %u items (%s)", __func__, items, from);
1610 }
1611
1612 /* Finish and store collected cells. */
1613 void
screen_write_collect_end(struct screen_write_ctx * ctx)1614 screen_write_collect_end(struct screen_write_ctx *ctx)
1615 {
1616 struct screen *s = ctx->s;
1617 struct screen_write_citem *ci = ctx->item, *before;
1618 struct screen_write_cline *cl = &s->write_list[s->cy];
1619 struct grid_cell gc;
1620 u_int xx;
1621 int wrapped = ci->wrapped;
1622
1623 if (ci->used == 0)
1624 return;
1625
1626 before = screen_write_collect_trim(ctx, s->cy, s->cx, ci->used,
1627 &wrapped);
1628 ci->x = s->cx;
1629 ci->wrapped = wrapped;
1630 if (before == NULL)
1631 TAILQ_INSERT_TAIL(&cl->items, ci, entry);
1632 else
1633 TAILQ_INSERT_BEFORE(before, ci, entry);
1634 ctx->item = screen_write_get_citem();
1635
1636 log_debug("%s: %u %.*s (at %u,%u)", __func__, ci->used,
1637 (int)ci->used, cl->data + ci->x, s->cx, s->cy);
1638
1639 if (s->cx != 0) {
1640 for (xx = s->cx; xx > 0; xx--) {
1641 grid_view_get_cell(s->grid, xx, s->cy, &gc);
1642 if (~gc.flags & GRID_FLAG_PADDING)
1643 break;
1644 grid_view_set_cell(s->grid, xx, s->cy,
1645 &grid_default_cell);
1646 }
1647 if (gc.data.width > 1) {
1648 grid_view_set_cell(s->grid, xx, s->cy,
1649 &grid_default_cell);
1650 }
1651 }
1652
1653 grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x,
1654 ci->used);
1655 screen_write_set_cursor(ctx, s->cx + ci->used, -1);
1656
1657 for (xx = s->cx; xx < screen_size_x(s); xx++) {
1658 grid_view_get_cell(s->grid, xx, s->cy, &gc);
1659 if (~gc.flags & GRID_FLAG_PADDING)
1660 break;
1661 grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell);
1662 }
1663 }
1664
1665 /* Write cell data, collecting if necessary. */
1666 void
screen_write_collect_add(struct screen_write_ctx * ctx,const struct grid_cell * gc)1667 screen_write_collect_add(struct screen_write_ctx *ctx,
1668 const struct grid_cell *gc)
1669 {
1670 struct screen *s = ctx->s;
1671 struct screen_write_citem *ci;
1672 u_int sx = screen_size_x(s);
1673 int collect;
1674
1675 /*
1676 * Don't need to check that the attributes and whatnot are still the
1677 * same - input_parse will end the collection when anything that isn't
1678 * a plain character is encountered.
1679 */
1680
1681 collect = 1;
1682 if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f)
1683 collect = 0;
1684 else if (gc->attr & GRID_ATTR_CHARSET)
1685 collect = 0;
1686 else if (~s->mode & MODE_WRAP)
1687 collect = 0;
1688 else if (s->mode & MODE_INSERT)
1689 collect = 0;
1690 else if (s->sel != NULL)
1691 collect = 0;
1692 if (!collect) {
1693 screen_write_collect_end(ctx);
1694 screen_write_collect_flush(ctx, 0, __func__);
1695 screen_write_cell(ctx, gc);
1696 return;
1697 }
1698
1699 if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx)
1700 screen_write_collect_end(ctx);
1701 ci = ctx->item; /* may have changed */
1702
1703 if (s->cx > sx - 1) {
1704 log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
1705 ci->wrapped = 1;
1706 screen_write_linefeed(ctx, 1, 8);
1707 screen_write_set_cursor(ctx, 0, -1);
1708 }
1709
1710 if (ci->used == 0)
1711 memcpy(&ci->gc, gc, sizeof ci->gc);
1712 if (ctx->s->write_list[s->cy].data == NULL)
1713 ctx->s->write_list[s->cy].data = xmalloc(screen_size_x(ctx->s));
1714 ctx->s->write_list[s->cy].data[s->cx + ci->used++] = gc->data.data[0];
1715 }
1716
1717 /* Write cell data. */
1718 void
screen_write_cell(struct screen_write_ctx * ctx,const struct grid_cell * gc)1719 screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
1720 {
1721 struct screen *s = ctx->s;
1722 struct grid *gd = s->grid;
1723 struct grid_line *gl;
1724 struct grid_cell_entry *gce;
1725 struct grid_cell tmp_gc, now_gc;
1726 struct tty_ctx ttyctx;
1727 u_int sx = screen_size_x(s), sy = screen_size_y(s);
1728 u_int width = gc->data.width, xx, last, cx, cy;
1729 int selected, skip = 1;
1730
1731 /* Ignore padding cells. */
1732 if (gc->flags & GRID_FLAG_PADDING)
1733 return;
1734
1735 /* If the width is zero, combine onto the previous character. */
1736 if (width == 0) {
1737 screen_write_collect_flush(ctx, 0, __func__);
1738 if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) {
1739 cx = s->cx; cy = s->cy;
1740 screen_write_set_cursor(ctx, xx, s->cy);
1741 screen_write_initctx(ctx, &ttyctx, 0);
1742 ttyctx.cell = gc;
1743 tty_write(tty_cmd_cell, &ttyctx);
1744 s->cx = cx; s->cy = cy;
1745 }
1746 return;
1747 }
1748
1749 /* Flush any existing scrolling. */
1750 screen_write_collect_flush(ctx, 1, __func__);
1751
1752 /* If this character doesn't fit, ignore it. */
1753 if ((~s->mode & MODE_WRAP) &&
1754 width > 1 &&
1755 (width > sx || (s->cx != sx && s->cx > sx - width)))
1756 return;
1757
1758 /* If in insert mode, make space for the cells. */
1759 if (s->mode & MODE_INSERT) {
1760 grid_view_insert_cells(s->grid, s->cx, s->cy, width, 8);
1761 skip = 0;
1762 }
1763
1764 /* Check this will fit on the current line and wrap if not. */
1765 if ((s->mode & MODE_WRAP) && s->cx > sx - width) {
1766 log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
1767 screen_write_linefeed(ctx, 1, 8);
1768 screen_write_set_cursor(ctx, 0, -1);
1769 screen_write_collect_flush(ctx, 1, __func__);
1770 }
1771
1772 /* Sanity check cursor position. */
1773 if (s->cx > sx - width || s->cy > sy - 1)
1774 return;
1775 screen_write_initctx(ctx, &ttyctx, 0);
1776
1777 /* Handle overwriting of UTF-8 characters. */
1778 gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
1779 if (gl->flags & GRID_LINE_EXTENDED) {
1780 grid_view_get_cell(gd, s->cx, s->cy, &now_gc);
1781 if (screen_write_overwrite(ctx, &now_gc, width))
1782 skip = 0;
1783 }
1784
1785 /*
1786 * If the new character is UTF-8 wide, fill in padding cells. Have
1787 * already ensured there is enough room.
1788 */
1789 for (xx = s->cx + 1; xx < s->cx + width; xx++) {
1790 log_debug("%s: new padding at %u,%u", __func__, xx, s->cy);
1791 grid_view_set_padding(gd, xx, s->cy);
1792 skip = 0;
1793 }
1794
1795 /* If no change, do not draw. */
1796 if (skip) {
1797 if (s->cx >= gl->cellsize)
1798 skip = grid_cells_equal(gc, &grid_default_cell);
1799 else {
1800 gce = &gl->celldata[s->cx];
1801 if (gce->flags & GRID_FLAG_EXTENDED)
1802 skip = 0;
1803 else if (gc->flags != gce->flags)
1804 skip = 0;
1805 else if (gc->attr != gce->data.attr)
1806 skip = 0;
1807 else if (gc->fg != gce->data.fg)
1808 skip = 0;
1809 else if (gc->bg != gce->data.bg)
1810 skip = 0;
1811 else if (gc->data.width != 1)
1812 skip = 0;
1813 else if (gc->data.size != 1)
1814 skip = 0;
1815 else if (gce->data.data != gc->data.data[0])
1816 skip = 0;
1817 }
1818 }
1819
1820 /* Update the selected flag and set the cell. */
1821 selected = screen_check_selection(s, s->cx, s->cy);
1822 if (selected && (~gc->flags & GRID_FLAG_SELECTED)) {
1823 memcpy(&tmp_gc, gc, sizeof tmp_gc);
1824 tmp_gc.flags |= GRID_FLAG_SELECTED;
1825 grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
1826 } else if (!selected && (gc->flags & GRID_FLAG_SELECTED)) {
1827 memcpy(&tmp_gc, gc, sizeof tmp_gc);
1828 tmp_gc.flags &= ~GRID_FLAG_SELECTED;
1829 grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
1830 } else if (!skip)
1831 grid_view_set_cell(gd, s->cx, s->cy, gc);
1832 if (selected)
1833 skip = 0;
1834
1835 /*
1836 * Move the cursor. If not wrapping, stick at the last character and
1837 * replace it.
1838 */
1839 last = !(s->mode & MODE_WRAP);
1840 if (s->cx <= sx - last - width)
1841 screen_write_set_cursor(ctx, s->cx + width, -1);
1842 else
1843 screen_write_set_cursor(ctx, sx - last, -1);
1844
1845 /* Create space for character in insert mode. */
1846 if (s->mode & MODE_INSERT) {
1847 screen_write_collect_flush(ctx, 0, __func__);
1848 ttyctx.num = width;
1849 tty_write(tty_cmd_insertcharacter, &ttyctx);
1850 }
1851
1852 /* Write to the screen. */
1853 if (!skip) {
1854 if (selected) {
1855 screen_select_cell(s, &tmp_gc, gc);
1856 ttyctx.cell = &tmp_gc;
1857 } else
1858 ttyctx.cell = gc;
1859 tty_write(tty_cmd_cell, &ttyctx);
1860 }
1861 }
1862
1863 /* Combine a UTF-8 zero-width character onto the previous. */
1864 static const struct grid_cell *
screen_write_combine(struct screen_write_ctx * ctx,const struct utf8_data * ud,u_int * xx)1865 screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
1866 u_int *xx)
1867 {
1868 struct screen *s = ctx->s;
1869 struct grid *gd = s->grid;
1870 static struct grid_cell gc;
1871 u_int n;
1872
1873 /* Can't combine if at 0. */
1874 if (s->cx == 0)
1875 return (NULL);
1876
1877 /* Empty data is out. */
1878 if (ud->size == 0)
1879 fatalx("UTF-8 data empty");
1880
1881 /* Retrieve the previous cell. */
1882 for (n = 1; n <= s->cx; n++) {
1883 grid_view_get_cell(gd, s->cx - n, s->cy, &gc);
1884 if (~gc.flags & GRID_FLAG_PADDING)
1885 break;
1886 }
1887 if (n > s->cx)
1888 return (NULL);
1889 *xx = s->cx - n;
1890
1891 /* Check there is enough space. */
1892 if (gc.data.size + ud->size > sizeof gc.data.data)
1893 return (NULL);
1894
1895 log_debug("%s: %.*s onto %.*s at %u,%u", __func__, (int)ud->size,
1896 ud->data, (int)gc.data.size, gc.data.data, *xx, s->cy);
1897
1898 /* Append the data. */
1899 memcpy(gc.data.data + gc.data.size, ud->data, ud->size);
1900 gc.data.size += ud->size;
1901
1902 /* Set the new cell. */
1903 grid_view_set_cell(gd, *xx, s->cy, &gc);
1904
1905 return (&gc);
1906 }
1907
1908 /*
1909 * UTF-8 wide characters are a bit of an annoyance. They take up more than one
1910 * cell on the screen, so following cells must not be drawn by marking them as
1911 * padding.
1912 *
1913 * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
1914 * character, it is necessary to also overwrite any other cells which covered
1915 * by the same character.
1916 */
1917 static int
screen_write_overwrite(struct screen_write_ctx * ctx,struct grid_cell * gc,u_int width)1918 screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
1919 u_int width)
1920 {
1921 struct screen *s = ctx->s;
1922 struct grid *gd = s->grid;
1923 struct grid_cell tmp_gc;
1924 u_int xx;
1925 int done = 0;
1926
1927 if (gc->flags & GRID_FLAG_PADDING) {
1928 /*
1929 * A padding cell, so clear any following and leading padding
1930 * cells back to the character. Don't overwrite the current
1931 * cell as that happens later anyway.
1932 */
1933 xx = s->cx + 1;
1934 while (--xx > 0) {
1935 grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
1936 if (~tmp_gc.flags & GRID_FLAG_PADDING)
1937 break;
1938 log_debug("%s: padding at %u,%u", __func__, xx, s->cy);
1939 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1940 }
1941
1942 /* Overwrite the character at the start of this padding. */
1943 log_debug("%s: character at %u,%u", __func__, xx, s->cy);
1944 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1945 done = 1;
1946 }
1947
1948 /*
1949 * Overwrite any padding cells that belong to any UTF-8 characters
1950 * we'll be overwriting with the current character.
1951 */
1952 if (width != 1 ||
1953 gc->data.width != 1 ||
1954 gc->flags & GRID_FLAG_PADDING) {
1955 xx = s->cx + width - 1;
1956 while (++xx < screen_size_x(s)) {
1957 grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
1958 if (~tmp_gc.flags & GRID_FLAG_PADDING)
1959 break;
1960 log_debug("%s: overwrite at %u,%u", __func__, xx,
1961 s->cy);
1962 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1963 done = 1;
1964 }
1965 }
1966
1967 return (done);
1968 }
1969
1970 /* Set external clipboard. */
1971 void
screen_write_setselection(struct screen_write_ctx * ctx,u_char * str,u_int len)1972 screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
1973 {
1974 struct tty_ctx ttyctx;
1975
1976 screen_write_initctx(ctx, &ttyctx, 0);
1977 ttyctx.ptr = str;
1978 ttyctx.num = len;
1979
1980 tty_write(tty_cmd_setselection, &ttyctx);
1981 }
1982
1983 /* Write unmodified string. */
1984 void
screen_write_rawstring(struct screen_write_ctx * ctx,u_char * str,u_int len)1985 screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
1986 {
1987 struct tty_ctx ttyctx;
1988
1989 screen_write_initctx(ctx, &ttyctx, 0);
1990 ttyctx.ptr = str;
1991 ttyctx.num = len;
1992
1993 tty_write(tty_cmd_rawstring, &ttyctx);
1994 }
1995
1996 /* Turn alternate screen on. */
1997 void
screen_write_alternateon(struct screen_write_ctx * ctx,struct grid_cell * gc,int cursor)1998 screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc,
1999 int cursor)
2000 {
2001 struct tty_ctx ttyctx;
2002 struct window_pane *wp = ctx->wp;
2003
2004 if (wp != NULL && !options_get_number(wp->options, "alternate-screen"))
2005 return;
2006
2007 screen_write_collect_flush(ctx, 0, __func__);
2008 screen_alternate_on(ctx->s, gc, cursor);
2009
2010 screen_write_initctx(ctx, &ttyctx, 1);
2011 ttyctx.redraw_cb(&ttyctx);
2012 }
2013
2014 /* Turn alternate screen off. */
2015 void
screen_write_alternateoff(struct screen_write_ctx * ctx,struct grid_cell * gc,int cursor)2016 screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc,
2017 int cursor)
2018 {
2019 struct tty_ctx ttyctx;
2020 struct window_pane *wp = ctx->wp;
2021
2022 if (wp != NULL && !options_get_number(wp->options, "alternate-screen"))
2023 return;
2024
2025 screen_write_collect_flush(ctx, 0, __func__);
2026 screen_alternate_off(ctx->s, gc, cursor);
2027
2028 screen_write_initctx(ctx, &ttyctx, 1);
2029 ttyctx.redraw_cb(&ttyctx);
2030 }
2031