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