Annotation of src/usr.bin/tmux/screen-write.c, Revision 1.108
1.108 ! nicm 1: /* $OpenBSD: screen-write.c,v 1.107 2017/02/08 15:41:41 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.87 nicm 26: static void screen_write_initctx(struct screen_write_ctx *,
27: struct tty_ctx *);
1.92 nicm 28: static void screen_write_flush(struct screen_write_ctx *);
1.87 nicm 29:
1.89 nicm 30: static int screen_write_overwrite(struct screen_write_ctx *,
31: struct grid_cell *, u_int);
1.104 nicm 32: static const struct grid_cell *screen_write_combine(struct screen_write_ctx *,
33: const struct utf8_data *, u_int *);
1.1 nicm 34:
1.88 nicm 35: static const struct grid_cell screen_write_pad_cell = {
1.91 nicm 36: GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 }
1.88 nicm 37: };
38:
1.92 nicm 39: #define screen_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x))
40: #define screen_dirty_clear(s, sx, sy, ex, ey) \
41: do { \
42: if (s->dirty != NULL) { \
43: bit_nclear(s->dirty, \
44: screen_dirty_bit(s, sx, sy), \
45: screen_dirty_bit(s, ex, ey)); \
46: } \
47: } while (0)
48:
49: /* Initialize writing with a window. */
1.1 nicm 50: void
1.71 nicm 51: screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
52: struct screen *s)
1.1 nicm 53: {
1.108 ! nicm 54: u_int size;
! 55: char tmp[16];
1.92 nicm 56:
1.1 nicm 57: ctx->wp = wp;
58: if (wp != NULL && s == NULL)
59: ctx->s = wp->screen;
60: else
61: ctx->s = s;
1.92 nicm 62:
63: size = screen_size_x(ctx->s) * screen_size_y(ctx->s);
64: if (ctx->s->dirtysize != size) {
65: free(ctx->s->dirty);
66: ctx->s->dirty = NULL;
67: ctx->s->dirtysize = size;
68: }
69: ctx->dirty = 0;
70:
71: ctx->cells = ctx->written = ctx->skipped = 0;
72:
1.108 ! nicm 73: if (wp != NULL)
1.92 nicm 74: snprintf(tmp, sizeof tmp, "pane %%%u", wp->id);
75: log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s),
1.108 ! nicm 76: screen_size_y(ctx->s), wp == NULL ? "no pane" : tmp);
1.1 nicm 77: }
78:
79: /* Finish writing. */
80: void
1.92 nicm 81: screen_write_stop(struct screen_write_ctx *ctx)
82: {
83: screen_write_flush(ctx);
84:
85: log_debug("%s: %u of %u written (dirty %u, skipped %u)", __func__,
86: ctx->written, ctx->cells, ctx->cells - ctx->written, ctx->skipped);
87: }
88:
89: /* Flush outstanding cell writes. */
90: static void
91: screen_write_flush(struct screen_write_ctx *ctx)
1.1 nicm 92: {
1.92 nicm 93: struct screen *s = ctx->s;
94: struct tty_ctx ttyctx;
95: u_int x, y, offset, cx, cy, dirty;
96: struct grid_cell gc;
97:
98: if (ctx->dirty == 0)
99: return;
100: dirty = 0;
1.98 nicm 101: log_debug("%s: dirty %u", __func__, ctx->dirty);
1.92 nicm 102:
103: cx = s->cx;
104: cy = s->cy;
105:
106: offset = 0;
107: for (y = 0; y < screen_size_y(s); y++) {
108: for (x = 0; x < screen_size_x(s); x++) {
109: offset++;
110: if (!bit_test(s->dirty, offset - 1))
111: continue;
112: bit_clear(s->dirty, offset - 1);
113:
114: screen_write_cursormove(ctx, x, y);
115: grid_view_get_cell(s->grid, x, y, &gc);
116:
117: screen_write_initctx(ctx, &ttyctx);
118: ttyctx.cell = &gc;
119: tty_write(tty_cmd_cell, &ttyctx);
120: ctx->written++;
121:
122: if (++dirty == ctx->dirty)
123: break;
124: }
125: if (dirty == ctx->dirty)
126: break;
127: }
1.100 nicm 128: ctx->dirty = 0;
1.92 nicm 129:
130: s->cx = cx;
131: s->cy = cy;
1.52 nicm 132: }
133:
134: /* Reset screen state. */
135: void
136: screen_write_reset(struct screen_write_ctx *ctx)
137: {
1.61 nicm 138: struct screen *s = ctx->s;
1.52 nicm 139:
1.61 nicm 140: screen_reset_tabs(s);
141: screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
1.63 nicm 142:
1.67 nicm 143: s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|MODE_FOCUSON);
1.82 nicm 144: s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR);
1.52 nicm 145:
1.99 nicm 146: screen_write_clearscreen(ctx, 8);
1.52 nicm 147: screen_write_cursormove(ctx, 0, 0);
1.1 nicm 148: }
149:
150: /* Write character. */
151: void
1.86 nicm 152: screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
1.69 nicm 153: u_char ch)
1.1 nicm 154: {
1.86 nicm 155: struct grid_cell gc;
156:
157: memcpy(&gc, gcp, sizeof gc);
158:
159: utf8_set(&gc.data, ch);
160: screen_write_cell(ctx, &gc);
1.1 nicm 161: }
162:
1.24 nicm 163: /* Calculate string length, with embedded formatting. */
1.71 nicm 164: size_t
1.75 nicm 165: screen_write_cstrlen(const char *fmt, ...)
1.24 nicm 166: {
167: va_list ap;
168: char *msg, *msg2, *ptr, *ptr2;
169: size_t size;
170:
171: va_start(ap, fmt);
172: xvasprintf(&msg, fmt, ap);
173: va_end(ap);
174: msg2 = xmalloc(strlen(msg) + 1);
175:
176: ptr = msg;
177: ptr2 = msg2;
178: while (*ptr != '\0') {
179: if (ptr[0] == '#' && ptr[1] == '[') {
180: while (*ptr != ']' && *ptr != '\0')
181: ptr++;
182: if (*ptr == ']')
183: ptr++;
184: continue;
185: }
186: *ptr2++ = *ptr++;
187: }
188: *ptr2 = '\0';
189:
1.75 nicm 190: size = screen_write_strlen("%s", msg2);
1.24 nicm 191:
1.56 nicm 192: free(msg);
193: free(msg2);
1.24 nicm 194:
195: return (size);
196: }
197:
1.2 nicm 198: /* Calculate string length. */
1.71 nicm 199: size_t
1.75 nicm 200: screen_write_strlen(const char *fmt, ...)
1.2 nicm 201: {
1.36 nicm 202: va_list ap;
203: char *msg;
1.76 nicm 204: struct utf8_data ud;
1.36 nicm 205: u_char *ptr;
206: size_t left, size = 0;
1.79 nicm 207: enum utf8_state more;
1.2 nicm 208:
209: va_start(ap, fmt);
210: xvasprintf(&msg, fmt, ap);
211: va_end(ap);
212:
213: ptr = msg;
214: while (*ptr != '\0') {
1.79 nicm 215: if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
1.36 nicm 216: ptr++;
1.2 nicm 217:
218: left = strlen(ptr);
1.77 nicm 219: if (left < (size_t)ud.size - 1)
1.36 nicm 220: break;
1.79 nicm 221: while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
1.2 nicm 222: ptr++;
1.36 nicm 223: ptr++;
224:
1.79 nicm 225: if (more == UTF8_DONE)
1.78 nicm 226: size += ud.width;
1.2 nicm 227: } else {
1.75 nicm 228: if (*ptr > 0x1f && *ptr < 0x7f)
229: size++;
1.2 nicm 230: ptr++;
231: }
1.7 ray 232: }
1.2 nicm 233:
1.56 nicm 234: free(msg);
1.2 nicm 235: return (size);
236: }
237:
1.3 nicm 238: /* Write simple string (no UTF-8 or maximum length). */
1.71 nicm 239: void
1.86 nicm 240: screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
1.71 nicm 241: const char *fmt, ...)
1.1 nicm 242: {
243: va_list ap;
244:
245: va_start(ap, fmt);
1.86 nicm 246: screen_write_vnputs(ctx, -1, gcp, fmt, ap);
1.2 nicm 247: va_end(ap);
248: }
249:
250: /* Write string with length limit (-1 for unlimited). */
1.71 nicm 251: void
252: screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.86 nicm 253: const struct grid_cell *gcp, const char *fmt, ...)
1.2 nicm 254: {
255: va_list ap;
256:
257: va_start(ap, fmt);
1.86 nicm 258: screen_write_vnputs(ctx, maxlen, gcp, fmt, ap);
1.2 nicm 259: va_end(ap);
260: }
261:
262: void
1.3 nicm 263: screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.86 nicm 264: const struct grid_cell *gcp, const char *fmt, va_list ap)
1.2 nicm 265: {
1.86 nicm 266: struct grid_cell gc;
267: struct utf8_data *ud = &gc.data;
1.36 nicm 268: char *msg;
269: u_char *ptr;
270: size_t left, size = 0;
1.79 nicm 271: enum utf8_state more;
1.2 nicm 272:
1.86 nicm 273: memcpy(&gc, gcp, sizeof gc);
1.1 nicm 274: xvasprintf(&msg, fmt, ap);
275:
1.2 nicm 276: ptr = msg;
277: while (*ptr != '\0') {
1.86 nicm 278: if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
1.36 nicm 279: ptr++;
1.2 nicm 280:
281: left = strlen(ptr);
1.86 nicm 282: if (left < (size_t)ud->size - 1)
1.36 nicm 283: break;
1.86 nicm 284: while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
1.2 nicm 285: ptr++;
1.36 nicm 286: ptr++;
1.7 ray 287:
1.86 nicm 288: if (more != UTF8_DONE)
289: continue;
290: if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
291: while (size < (size_t)maxlen) {
292: screen_write_putc(ctx, &gc, ' ');
293: size++;
1.2 nicm 294: }
1.86 nicm 295: break;
1.2 nicm 296: }
1.86 nicm 297: size += ud->width;
298: screen_write_cell(ctx, &gc);
1.2 nicm 299: } else {
1.86 nicm 300: if (maxlen > 0 && size + 1 > (size_t)maxlen)
1.2 nicm 301: break;
302:
1.57 nicm 303: if (*ptr == '\001')
1.86 nicm 304: gc.attr ^= GRID_ATTR_CHARSET;
1.75 nicm 305: else if (*ptr > 0x1f && *ptr < 0x7f) {
1.57 nicm 306: size++;
1.86 nicm 307: screen_write_putc(ctx, &gc, *ptr);
1.57 nicm 308: }
1.2 nicm 309: ptr++;
310: }
311: }
1.1 nicm 312:
1.56 nicm 313: free(msg);
1.24 nicm 314: }
315:
316: /* Write string, similar to nputs, but with embedded formatting (#[]). */
1.71 nicm 317: void
1.75 nicm 318: screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.86 nicm 319: const struct grid_cell *gcp, const char *fmt, ...)
1.24 nicm 320: {
1.86 nicm 321: struct grid_cell gc;
322: struct utf8_data *ud = &gc.data;
1.24 nicm 323: va_list ap;
324: char *msg;
1.36 nicm 325: u_char *ptr, *last;
1.24 nicm 326: size_t left, size = 0;
1.79 nicm 327: enum utf8_state more;
1.24 nicm 328:
1.86 nicm 329: memcpy(&gc, gcp, sizeof gc);
330:
1.24 nicm 331: va_start(ap, fmt);
332: xvasprintf(&msg, fmt, ap);
333: va_end(ap);
334:
335: ptr = msg;
336: while (*ptr != '\0') {
337: if (ptr[0] == '#' && ptr[1] == '[') {
338: ptr += 2;
339: last = ptr + strcspn(ptr, "]");
340: if (*last == '\0') {
341: /* No ]. Not much point in doing anything. */
342: break;
343: }
344: *last = '\0';
345:
1.86 nicm 346: style_parse(gcp, &gc, ptr);
1.24 nicm 347: ptr = last + 1;
348: continue;
349: }
350:
1.86 nicm 351: if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
1.36 nicm 352: ptr++;
1.24 nicm 353:
354: left = strlen(ptr);
1.86 nicm 355: if (left < (size_t)ud->size - 1)
1.36 nicm 356: break;
1.86 nicm 357: while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
1.24 nicm 358: ptr++;
1.36 nicm 359: ptr++;
1.24 nicm 360:
1.86 nicm 361: if (more != UTF8_DONE)
362: continue;
363: if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
364: while (size < (size_t)maxlen) {
365: screen_write_putc(ctx, &gc, ' ');
366: size++;
1.24 nicm 367: }
1.86 nicm 368: break;
1.24 nicm 369: }
1.86 nicm 370: size += ud->width;
371: screen_write_cell(ctx, &gc);
1.24 nicm 372: } else {
1.86 nicm 373: if (maxlen > 0 && size + 1 > (size_t)maxlen)
1.24 nicm 374: break;
375:
1.75 nicm 376: if (*ptr > 0x1f && *ptr < 0x7f) {
377: size++;
1.86 nicm 378: screen_write_putc(ctx, &gc, *ptr);
1.75 nicm 379: }
1.24 nicm 380: ptr++;
381: }
382: }
383:
1.56 nicm 384: free(msg);
1.1 nicm 385: }
386:
387: /* Copy from another screen. */
388: void
1.95 nicm 389: screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
1.102 nicm 390: u_int py, u_int nx, u_int ny, bitstr_t *markbs,
391: const struct grid_cell *markgc)
1.1 nicm 392: {
393: struct screen *s = ctx->s;
394: struct grid *gd = src->grid;
1.77 nicm 395: struct grid_cell gc;
1.102 nicm 396: u_int xx, yy, cx, cy, b;
1.1 nicm 397:
398: cx = s->cx;
399: cy = s->cy;
1.96 nicm 400:
1.1 nicm 401: for (yy = py; yy < py + ny; yy++) {
1.96 nicm 402: for (xx = px; xx < px + nx; xx++) {
403: grid_get_cell(gd, xx, yy, &gc);
1.102 nicm 404: if (markbs != NULL) {
405: b = (yy * screen_size_x(src)) + xx;
406: if (bit_test(markbs, b)) {
407: gc.attr = markgc->attr;
408: gc.fg = markgc->fg;
409: gc.bg = markgc->bg;
410: }
411: }
1.96 nicm 412: screen_write_cell(ctx, &gc);
413: }
414:
1.1 nicm 415: cy++;
416: screen_write_cursormove(ctx, cx, cy);
417: }
418: }
419:
1.17 nicm 420: /* Set up context for TTY command. */
1.87 nicm 421: static void
422: screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
1.1 nicm 423: {
1.87 nicm 424: struct screen *s = ctx->s;
1.1 nicm 425:
1.17 nicm 426: ttyctx->wp = ctx->wp;
1.1 nicm 427:
1.17 nicm 428: ttyctx->ocx = s->cx;
429: ttyctx->ocy = s->cy;
430:
431: ttyctx->orlower = s->rlower;
432: ttyctx->orupper = s->rupper;
1.87 nicm 433: }
1.31 nicm 434:
1.61 nicm 435: /* Set a mode. */
436: void
437: screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
438: {
439: struct screen *s = ctx->s;
440:
441: s->mode |= mode;
442: }
443:
444: /* Clear a mode. */
445: void
446: screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
447: {
448: struct screen *s = ctx->s;
449:
450: s->mode &= ~mode;
451: }
452:
1.1 nicm 453: /* Cursor up by ny. */
454: void
455: screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
456: {
457: struct screen *s = ctx->s;
458:
459: if (ny == 0)
460: ny = 1;
461:
1.12 nicm 462: if (s->cy < s->rupper) {
463: /* Above region. */
464: if (ny > s->cy)
465: ny = s->cy;
466: } else {
467: /* Below region. */
468: if (ny > s->cy - s->rupper)
469: ny = s->cy - s->rupper;
470: }
1.66 nicm 471: if (s->cx == screen_size_x(s))
472: s->cx--;
1.1 nicm 473: if (ny == 0)
474: return;
475:
476: s->cy -= ny;
477: }
478:
479: /* Cursor down by ny. */
480: void
481: screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
482: {
483: struct screen *s = ctx->s;
484:
485: if (ny == 0)
486: ny = 1;
487:
1.12 nicm 488: if (s->cy > s->rlower) {
489: /* Below region. */
490: if (ny > screen_size_y(s) - 1 - s->cy)
491: ny = screen_size_y(s) - 1 - s->cy;
492: } else {
493: /* Above region. */
494: if (ny > s->rlower - s->cy)
495: ny = s->rlower - s->cy;
496: }
1.66 nicm 497: if (s->cx == screen_size_x(s))
498: s->cx--;
1.1 nicm 499: if (ny == 0)
500: return;
501:
502: s->cy += ny;
503: }
504:
1.101 nicm 505: /* Cursor right by nx. */
1.1 nicm 506: void
507: screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
508: {
509: struct screen *s = ctx->s;
510:
511: if (nx == 0)
512: nx = 1;
513:
514: if (nx > screen_size_x(s) - 1 - s->cx)
515: nx = screen_size_x(s) - 1 - s->cx;
516: if (nx == 0)
517: return;
518:
519: s->cx += nx;
520: }
521:
522: /* Cursor left by nx. */
523: void
524: screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
525: {
526: struct screen *s = ctx->s;
527:
528: if (nx == 0)
529: nx = 1;
530:
531: if (nx > s->cx)
532: nx = s->cx;
533: if (nx == 0)
534: return;
535:
536: s->cx -= nx;
1.5 nicm 537: }
538:
1.29 nicm 539: /* Backspace; cursor left unless at start of wrapped line when can move up. */
540: void
541: screen_write_backspace(struct screen_write_ctx *ctx)
542: {
543: struct screen *s = ctx->s;
544: struct grid_line *gl;
545:
546: if (s->cx == 0) {
547: if (s->cy == 0)
548: return;
549: gl = &s->grid->linedata[s->grid->hsize + s->cy - 1];
550: if (gl->flags & GRID_LINE_WRAPPED) {
551: s->cy--;
552: s->cx = screen_size_x(s) - 1;
553: }
554: } else
555: s->cx--;
556: }
557:
1.5 nicm 558: /* VT100 alignment test. */
559: void
560: screen_write_alignmenttest(struct screen_write_ctx *ctx)
561: {
562: struct screen *s = ctx->s;
1.17 nicm 563: struct tty_ctx ttyctx;
1.5 nicm 564: struct grid_cell gc;
565: u_int xx, yy;
1.92 nicm 566: u_int sx = screen_size_x(s), sy = screen_size_y(s);
1.5 nicm 567:
1.87 nicm 568: screen_write_initctx(ctx, &ttyctx);
1.17 nicm 569:
1.92 nicm 570: screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
571:
1.5 nicm 572: memcpy(&gc, &grid_default_cell, sizeof gc);
1.77 nicm 573: utf8_set(&gc.data, 'E');
1.7 ray 574:
1.5 nicm 575: for (yy = 0; yy < screen_size_y(s); yy++) {
576: for (xx = 0; xx < screen_size_x(s); xx++)
577: grid_view_set_cell(s->grid, xx, yy, &gc);
578: }
1.7 ray 579:
1.5 nicm 580: s->cx = 0;
581: s->cy = 0;
582:
583: s->rupper = 0;
584: s->rlower = screen_size_y(s) - 1;
585:
1.17 nicm 586: tty_write(tty_cmd_alignmenttest, &ttyctx);
1.1 nicm 587: }
588:
589: /* Insert nx characters. */
590: void
1.99 nicm 591: screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
1.1 nicm 592: {
593: struct screen *s = ctx->s;
1.17 nicm 594: struct tty_ctx ttyctx;
1.1 nicm 595:
596: if (nx == 0)
597: nx = 1;
598:
1.9 nicm 599: if (nx > screen_size_x(s) - s->cx)
600: nx = screen_size_x(s) - s->cx;
1.1 nicm 601: if (nx == 0)
602: return;
603:
1.107 nicm 604: if (s->cx > screen_size_x(s) - 1)
605: return;
606:
1.92 nicm 607: screen_write_flush(ctx);
1.87 nicm 608: screen_write_initctx(ctx, &ttyctx);
1.107 nicm 609: ttyctx.bg = bg;
1.1 nicm 610:
1.107 nicm 611: grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg);
1.1 nicm 612:
1.17 nicm 613: ttyctx.num = nx;
614: tty_write(tty_cmd_insertcharacter, &ttyctx);
1.1 nicm 615: }
616:
617: /* Delete nx characters. */
618: void
1.99 nicm 619: screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
1.1 nicm 620: {
621: struct screen *s = ctx->s;
1.17 nicm 622: struct tty_ctx ttyctx;
1.1 nicm 623:
624: if (nx == 0)
625: nx = 1;
626:
1.9 nicm 627: if (nx > screen_size_x(s) - s->cx)
628: nx = screen_size_x(s) - s->cx;
1.1 nicm 629: if (nx == 0)
630: return;
631:
1.107 nicm 632: if (s->cx > screen_size_x(s) - 1)
633: return;
634:
1.92 nicm 635: screen_write_flush(ctx);
1.87 nicm 636: screen_write_initctx(ctx, &ttyctx);
1.107 nicm 637: ttyctx.bg = bg;
1.1 nicm 638:
1.107 nicm 639: grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg);
1.1 nicm 640:
1.17 nicm 641: ttyctx.num = nx;
642: tty_write(tty_cmd_deletecharacter, &ttyctx);
1.59 nicm 643: }
644:
645: /* Clear nx characters. */
646: void
647: screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx)
648: {
649: struct screen *s = ctx->s;
650: struct tty_ctx ttyctx;
651:
652: if (nx == 0)
653: nx = 1;
654:
655: if (nx > screen_size_x(s) - s->cx)
656: nx = screen_size_x(s) - s->cx;
657: if (nx == 0)
658: return;
659:
1.107 nicm 660: if (s->cx > screen_size_x(s) - 1)
661: return;
662:
1.87 nicm 663: screen_write_initctx(ctx, &ttyctx);
1.59 nicm 664:
1.107 nicm 665: screen_dirty_clear(s, s->cx, s->cy, s->cx + nx - 1, s->cy);
666: grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8);
1.59 nicm 667:
668: ttyctx.num = nx;
669: tty_write(tty_cmd_clearcharacter, &ttyctx);
1.1 nicm 670: }
671:
672: /* Insert ny lines. */
673: void
1.99 nicm 674: screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
1.1 nicm 675: {
676: struct screen *s = ctx->s;
1.107 nicm 677: struct grid *gd = s->grid;
1.17 nicm 678: struct tty_ctx ttyctx;
1.1 nicm 679:
680: if (ny == 0)
681: ny = 1;
682:
1.11 nicm 683: if (s->cy < s->rupper || s->cy > s->rlower) {
684: if (ny > screen_size_y(s) - s->cy)
685: ny = screen_size_y(s) - s->cy;
686: if (ny == 0)
687: return;
688:
1.92 nicm 689: screen_write_flush(ctx);
1.87 nicm 690: screen_write_initctx(ctx, &ttyctx);
1.107 nicm 691: ttyctx.bg = bg;
1.11 nicm 692:
1.107 nicm 693: grid_view_insert_lines(gd, s->cy, ny, bg);
1.11 nicm 694:
1.17 nicm 695: ttyctx.num = ny;
696: tty_write(tty_cmd_insertline, &ttyctx);
1.11 nicm 697: return;
698: }
699:
700: if (ny > s->rlower + 1 - s->cy)
701: ny = s->rlower + 1 - s->cy;
1.1 nicm 702: if (ny == 0)
703: return;
1.41 nicm 704:
1.92 nicm 705: screen_write_flush(ctx);
1.87 nicm 706: screen_write_initctx(ctx, &ttyctx);
1.107 nicm 707: ttyctx.bg = bg;
1.1 nicm 708:
709: if (s->cy < s->rupper || s->cy > s->rlower)
1.107 nicm 710: grid_view_insert_lines(gd, s->cy, ny, bg);
711: else
712: grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg);
1.1 nicm 713:
1.17 nicm 714: ttyctx.num = ny;
715: tty_write(tty_cmd_insertline, &ttyctx);
1.1 nicm 716: }
717:
718: /* Delete ny lines. */
719: void
1.99 nicm 720: screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
1.1 nicm 721: {
722: struct screen *s = ctx->s;
1.107 nicm 723: struct grid *gd = s->grid;
1.17 nicm 724: struct tty_ctx ttyctx;
1.1 nicm 725:
726: if (ny == 0)
727: ny = 1;
728:
1.11 nicm 729: if (s->cy < s->rupper || s->cy > s->rlower) {
730: if (ny > screen_size_y(s) - s->cy)
731: ny = screen_size_y(s) - s->cy;
732: if (ny == 0)
733: return;
734:
1.92 nicm 735: screen_write_flush(ctx);
1.87 nicm 736: screen_write_initctx(ctx, &ttyctx);
1.107 nicm 737: ttyctx.bg = bg;
1.11 nicm 738:
1.107 nicm 739: grid_view_delete_lines(gd, s->cy, ny, bg);
1.11 nicm 740:
1.17 nicm 741: ttyctx.num = ny;
742: tty_write(tty_cmd_deleteline, &ttyctx);
1.11 nicm 743: return;
744: }
1.41 nicm 745:
1.11 nicm 746: if (ny > s->rlower + 1 - s->cy)
747: ny = s->rlower + 1 - s->cy;
1.1 nicm 748: if (ny == 0)
749: return;
750:
1.92 nicm 751: screen_write_flush(ctx);
1.87 nicm 752: screen_write_initctx(ctx, &ttyctx);
1.107 nicm 753: ttyctx.bg = bg;
1.1 nicm 754:
755: if (s->cy < s->rupper || s->cy > s->rlower)
1.107 nicm 756: grid_view_delete_lines(gd, s->cy, ny, bg);
757: else
758: grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg);
1.1 nicm 759:
1.17 nicm 760: ttyctx.num = ny;
761: tty_write(tty_cmd_deleteline, &ttyctx);
1.1 nicm 762: }
763:
764: /* Clear line at cursor. */
765: void
1.99 nicm 766: screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
1.1 nicm 767: {
1.92 nicm 768: struct screen *s = ctx->s;
769: struct grid_line *gl;
770: struct tty_ctx ttyctx;
771: u_int sx = screen_size_x(s);
1.1 nicm 772:
1.92 nicm 773: gl = &s->grid->linedata[s->grid->hsize + s->cy];
1.99 nicm 774: if (gl->cellsize == 0 && bg == 8)
1.92 nicm 775: return;
1.1 nicm 776:
1.108 ! nicm 777: screen_write_initctx(ctx, &ttyctx);
! 778: ttyctx.bg = bg;
! 779:
1.99 nicm 780: screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
781: grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
782:
1.17 nicm 783: tty_write(tty_cmd_clearline, &ttyctx);
1.1 nicm 784: }
785:
786: /* Clear to end of line from cursor. */
787: void
1.99 nicm 788: screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
1.1 nicm 789: {
1.92 nicm 790: struct screen *s = ctx->s;
791: struct grid_line *gl;
792: struct tty_ctx ttyctx;
793: u_int sx = screen_size_x(s);
1.1 nicm 794:
1.92 nicm 795: gl = &s->grid->linedata[s->grid->hsize + s->cy];
1.99 nicm 796: if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8))
1.92 nicm 797: return;
1.108 ! nicm 798:
! 799: screen_write_initctx(ctx, &ttyctx);
! 800: ttyctx.bg = bg;
1.1 nicm 801:
1.99 nicm 802: screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
803: grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
804:
1.41 nicm 805: tty_write(tty_cmd_clearendofline, &ttyctx);
1.1 nicm 806: }
807:
808: /* Clear to start of line from cursor. */
809: void
1.99 nicm 810: screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
1.1 nicm 811: {
812: struct screen *s = ctx->s;
1.17 nicm 813: struct tty_ctx ttyctx;
1.92 nicm 814: u_int sx = screen_size_x(s);
1.1 nicm 815:
1.87 nicm 816: screen_write_initctx(ctx, &ttyctx);
1.99 nicm 817: ttyctx.bg = bg;
1.1 nicm 818:
1.92 nicm 819: if (s->cx > sx - 1) {
820: screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
1.99 nicm 821: grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
1.92 nicm 822: } else {
823: screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
1.99 nicm 824: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
1.92 nicm 825: }
1.1 nicm 826:
1.17 nicm 827: tty_write(tty_cmd_clearstartofline, &ttyctx);
1.1 nicm 828: }
829:
1.101 nicm 830: /* Move cursor to px,py. */
1.1 nicm 831: void
832: screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
833: {
834: struct screen *s = ctx->s;
835:
836: if (px > screen_size_x(s) - 1)
837: px = screen_size_x(s) - 1;
838: if (py > screen_size_y(s) - 1)
839: py = screen_size_y(s) - 1;
840:
841: s->cx = px;
842: s->cy = py;
843: }
844:
1.101 nicm 845: /* Reverse index (up with scroll). */
1.1 nicm 846: void
847: screen_write_reverseindex(struct screen_write_ctx *ctx)
848: {
849: struct screen *s = ctx->s;
1.17 nicm 850: struct tty_ctx ttyctx;
1.1 nicm 851:
1.87 nicm 852: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 853:
1.92 nicm 854: if (s->cy == s->rupper) {
855: screen_write_flush(ctx);
1.1 nicm 856: grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
1.92 nicm 857: } else if (s->cy > 0)
1.1 nicm 858: s->cy--;
859:
1.17 nicm 860: tty_write(tty_cmd_reverseindex, &ttyctx);
1.1 nicm 861: }
862:
863: /* Set scroll region. */
864: void
1.83 nicm 865: screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
866: u_int rlower)
1.1 nicm 867: {
868: struct screen *s = ctx->s;
869:
870: if (rupper > screen_size_y(s) - 1)
871: rupper = screen_size_y(s) - 1;
872: if (rlower > screen_size_y(s) - 1)
873: rlower = screen_size_y(s) - 1;
1.13 nicm 874: if (rupper >= rlower) /* cannot be one line */
1.1 nicm 875: return;
876:
877: /* Cursor moves to top-left. */
878: s->cx = 0;
879: s->cy = 0;
880:
881: s->rupper = rupper;
882: s->rlower = rlower;
883: }
884:
1.34 nicm 885: /* Line feed. */
1.1 nicm 886: void
1.34 nicm 887: screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
1.1 nicm 888: {
1.20 nicm 889: struct screen *s = ctx->s;
890: struct grid_line *gl;
1.34 nicm 891: struct tty_ctx ttyctx;
1.92 nicm 892: u_int sx = screen_size_x(s), sy = screen_size_y(s);
1.34 nicm 893:
1.87 nicm 894: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 895:
1.20 nicm 896: gl = &s->grid->linedata[s->grid->hsize + s->cy];
897: if (wrapped)
898: gl->flags |= GRID_LINE_WRAPPED;
1.73 nicm 899: else
900: gl->flags &= ~GRID_LINE_WRAPPED;
1.20 nicm 901:
1.92 nicm 902: if (s->cy == s->rlower) {
903: screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper);
904: screen_write_flush(ctx);
1.1 nicm 905: grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
1.92 nicm 906: } else if (s->cy < sy - 1)
1.1 nicm 907: s->cy++;
908:
1.34 nicm 909: ttyctx.num = wrapped;
1.41 nicm 910: tty_write(tty_cmd_linefeed, &ttyctx);
1.1 nicm 911: }
912:
913: /* Carriage return (cursor to start of line). */
914: void
915: screen_write_carriagereturn(struct screen_write_ctx *ctx)
916: {
917: struct screen *s = ctx->s;
918:
919: s->cx = 0;
920: }
921:
922: /* Clear to end of screen from cursor. */
923: void
1.99 nicm 924: screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
1.1 nicm 925: {
926: struct screen *s = ctx->s;
1.107 nicm 927: struct grid *gd = s->grid;
1.17 nicm 928: struct tty_ctx ttyctx;
1.92 nicm 929: u_int sx = screen_size_x(s), sy = screen_size_y(s);
1.1 nicm 930:
1.87 nicm 931: screen_write_initctx(ctx, &ttyctx);
1.99 nicm 932: ttyctx.bg = bg;
1.1 nicm 933:
1.46 nicm 934: /* Scroll into history if it is enabled and clearing entire screen. */
1.107 nicm 935: if (s->cx == 0 && s->cy == 0 && gd->flags & GRID_HISTORY) {
1.92 nicm 936: screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
1.107 nicm 937: grid_view_clear_history(gd, bg);
1.92 nicm 938: } else {
939: if (s->cx <= sx - 1) {
940: screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
1.107 nicm 941: grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg);
1.92 nicm 942: }
943: screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1);
1.107 nicm 944: grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg);
1.46 nicm 945: }
1.1 nicm 946:
1.17 nicm 947: tty_write(tty_cmd_clearendofscreen, &ttyctx);
1.1 nicm 948: }
949:
950: /* Clear to start of screen. */
951: void
1.105 nicm 952: screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
1.1 nicm 953: {
954: struct screen *s = ctx->s;
1.17 nicm 955: struct tty_ctx ttyctx;
1.92 nicm 956: u_int sx = screen_size_x(s);
1.1 nicm 957:
1.87 nicm 958: screen_write_initctx(ctx, &ttyctx);
1.105 nicm 959: ttyctx.bg = bg;
1.1 nicm 960:
1.92 nicm 961: if (s->cy > 0) {
962: screen_dirty_clear(s, 0, 0, sx - 1, s->cy);
1.105 nicm 963: grid_view_clear(s->grid, 0, 0, sx, s->cy, bg);
1.92 nicm 964: }
965: if (s->cx > sx - 1) {
966: screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
1.105 nicm 967: grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
1.92 nicm 968: } else {
969: screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
1.105 nicm 970: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
1.92 nicm 971: }
1.1 nicm 972:
1.17 nicm 973: tty_write(tty_cmd_clearstartofscreen, &ttyctx);
1.1 nicm 974: }
975:
976: /* Clear entire screen. */
977: void
1.99 nicm 978: screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
1.1 nicm 979: {
980: struct screen *s = ctx->s;
1.17 nicm 981: struct tty_ctx ttyctx;
1.92 nicm 982: u_int sx = screen_size_x(s), sy = screen_size_y(s);
1.1 nicm 983:
1.87 nicm 984: screen_write_initctx(ctx, &ttyctx);
1.99 nicm 985: ttyctx.bg = bg;
1.1 nicm 986:
1.92 nicm 987: screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
988:
1.46 nicm 989: /* Scroll into history if it is enabled. */
990: if (s->grid->flags & GRID_HISTORY)
1.99 nicm 991: grid_view_clear_history(s->grid, bg);
1.83 nicm 992: else
1.99 nicm 993: grid_view_clear(s->grid, 0, 0, sx, sy, bg);
1.1 nicm 994:
1.17 nicm 995: tty_write(tty_cmd_clearscreen, &ttyctx);
1.51 nicm 996: }
997:
998: /* Clear entire history. */
999: void
1000: screen_write_clearhistory(struct screen_write_ctx *ctx)
1001: {
1002: struct screen *s = ctx->s;
1003: struct grid *gd = s->grid;
1004:
1.99 nicm 1005: grid_move_lines(gd, 0, gd->hsize, gd->sy, 8);
1.93 nicm 1006: gd->hscrolled = gd->hsize = 0;
1.1 nicm 1007: }
1008:
1009: /* Write cell data. */
1010: void
1.60 nicm 1011: screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
1.1 nicm 1012: {
1013: struct screen *s = ctx->s;
1014: struct grid *gd = s->grid;
1.15 nicm 1015: struct tty_ctx ttyctx;
1.64 nicm 1016: u_int width, xx, last;
1.92 nicm 1017: u_int sx = screen_size_x(s), sy = screen_size_y(s);
1018: struct grid_line *gl;
1.89 nicm 1019: struct grid_cell tmp_gc, now_gc;
1.92 nicm 1020: struct grid_cell_entry *gce;
1.106 nicm 1021: int insert, skip, selected;
1.92 nicm 1022:
1023: ctx->cells++;
1.1 nicm 1024:
1025: /* Ignore padding. */
1026: if (gc->flags & GRID_FLAG_PADDING)
1027: return;
1.77 nicm 1028: width = gc->data.width;
1.1 nicm 1029:
1.32 nicm 1030: /*
1.103 nicm 1031: * If this is a wide character and there is no room on the screen for
1.32 nicm 1032: * the entire character, don't print it.
1033: */
1.92 nicm 1034: if (!(s->mode & MODE_WRAP) && (width > 1 &&
1035: (width > sx || (s->cx != sx && s->cx > sx - width))))
1.32 nicm 1036: return;
1037:
1.35 nicm 1038: /*
1039: * If the width is zero, combine onto the previous character, if
1.41 nicm 1040: * there is space.
1.35 nicm 1041: */
1.1 nicm 1042: if (width == 0) {
1.104 nicm 1043: if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) {
1044: screen_write_cursormove(ctx, xx, s->cy);
1.87 nicm 1045: screen_write_initctx(ctx, &ttyctx);
1.104 nicm 1046: ttyctx.cell = gc;
1047: tty_write(tty_cmd_cell, &ttyctx);
1.1 nicm 1048: }
1049: return;
1050: }
1051:
1.6 nicm 1052: /* If in insert mode, make space for the cells. */
1.98 nicm 1053: if (s->mode & MODE_INSERT) {
1054: if (s->cx <= sx - width) {
1055: screen_write_flush(ctx);
1056: xx = sx - s->cx - width;
1.99 nicm 1057: grid_view_insert_cells(s->grid, s->cx, s->cy, xx, 8);
1.98 nicm 1058: }
1.6 nicm 1059: insert = 1;
1.64 nicm 1060: } else
1061: insert = 0;
1.89 nicm 1062: skip = !insert;
1.6 nicm 1063:
1.20 nicm 1064: /* Check this will fit on the current line and wrap if not. */
1.92 nicm 1065: if ((s->mode & MODE_WRAP) && s->cx > sx - width) {
1.34 nicm 1066: screen_write_linefeed(ctx, 1);
1.30 nicm 1067: s->cx = 0; /* carriage return */
1.1 nicm 1068: }
1069:
1.64 nicm 1070: /* Sanity check cursor position. */
1.92 nicm 1071: if (s->cx > sx - width || s->cy > sy - 1)
1.1 nicm 1072: return;
1073:
1.106 nicm 1074: /* Initialise the redraw context. */
1075: screen_write_initctx(ctx, &ttyctx);
1076:
1.1 nicm 1077: /* Handle overwriting of UTF-8 characters. */
1.92 nicm 1078: gl = &s->grid->linedata[s->grid->hsize + s->cy];
1079: if (gl->flags & GRID_LINE_EXTENDED) {
1080: grid_view_get_cell(gd, s->cx, s->cy, &now_gc);
1081: if (screen_write_overwrite(ctx, &now_gc, width))
1082: skip = 0;
1083: }
1.1 nicm 1084:
1085: /*
1086: * If the new character is UTF-8 wide, fill in padding cells. Have
1087: * already ensured there is enough room.
1088: */
1.89 nicm 1089: for (xx = s->cx + 1; xx < s->cx + width; xx++) {
1.88 nicm 1090: grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell);
1.89 nicm 1091: skip = 0;
1092: }
1093:
1094: /* If no change, do not draw. */
1.92 nicm 1095: if (skip) {
1096: if (s->cx >= gl->cellsize)
1097: skip = grid_cells_equal(gc, &grid_default_cell);
1098: else {
1099: gce = &gl->celldata[s->cx];
1100: if (gce->flags & GRID_FLAG_EXTENDED)
1101: skip = 0;
1.95 nicm 1102: else if (gc->flags != gce->flags)
1.92 nicm 1103: skip = 0;
1104: else if (gc->attr != gce->data.attr)
1105: skip = 0;
1106: else if (gc->fg != gce->data.fg)
1107: skip = 0;
1108: else if (gc->bg != gce->data.bg)
1109: skip = 0;
1.95 nicm 1110: else if (gc->data.width != 1)
1111: skip = 0;
1112: else if (gce->data.data != gc->data.data[0])
1.92 nicm 1113: skip = 0;
1114: }
1115: }
1.1 nicm 1116:
1.90 nicm 1117: /* Update the selection the flag and set the cell. */
1118: selected = screen_check_selection(s, s->cx, s->cy);
1119: if (selected && ~gc->flags & GRID_FLAG_SELECTED) {
1120: skip = 0;
1121: memcpy(&tmp_gc, gc, sizeof tmp_gc);
1122: tmp_gc.flags |= GRID_FLAG_SELECTED;
1123: grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
1124: } else if (!selected && gc->flags & GRID_FLAG_SELECTED) {
1125: skip = 0;
1126: memcpy(&tmp_gc, gc, sizeof tmp_gc);
1127: tmp_gc.flags &= ~GRID_FLAG_SELECTED;
1128: grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
1129: } else if (!skip)
1.89 nicm 1130: grid_view_set_cell(gd, s->cx, s->cy, gc);
1.1 nicm 1131:
1.64 nicm 1132: /*
1133: * Move the cursor. If not wrapping, stick at the last character and
1134: * replace it.
1135: */
1.65 nicm 1136: last = !(s->mode & MODE_WRAP);
1.92 nicm 1137: if (s->cx <= sx - last - width)
1.64 nicm 1138: s->cx += width;
1139: else
1.92 nicm 1140: s->cx = sx - last;
1.1 nicm 1141:
1.89 nicm 1142: /* Create space for character in insert mode. */
1.17 nicm 1143: if (insert) {
1144: ttyctx.num = width;
1145: tty_write(tty_cmd_insertcharacter, &ttyctx);
1146: }
1.89 nicm 1147:
1148: /* Write to the screen. */
1149: if (selected) {
1.92 nicm 1150: screen_write_flush(ctx);
1.97 nicm 1151: screen_select_cell(s, &tmp_gc, gc);
1.33 nicm 1152: ttyctx.cell = &tmp_gc;
1.16 nicm 1153: tty_write(tty_cmd_cell, &ttyctx);
1.92 nicm 1154: ctx->written++;
1.89 nicm 1155: } else if (!skip) {
1.106 nicm 1156: /*
1157: * If wp is NULL, we are not updating the terminal and don't
1158: * care about actually writing the cells (tty_write will just
1159: * return). So don't even bother allocating the dirty array.
1160: */
1161: if (ctx->wp != NULL && s->dirty == NULL) {
1162: log_debug("%s: allocating %u bits", __func__,
1163: s->dirtysize);
1164: s->dirty = bit_alloc(s->dirtysize);
1165: }
1166: if (s->dirty != NULL) {
1167: bit_set(s->dirty, screen_dirty_bit(s,
1168: ttyctx.ocx, ttyctx.ocy));
1169: ctx->dirty++;
1.92 nicm 1170: }
1171: } else
1172: ctx->skipped++;
1.35 nicm 1173: }
1174:
1175: /* Combine a UTF-8 zero-width character onto the previous. */
1.104 nicm 1176: static const struct grid_cell *
1177: screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
1178: u_int *xx)
1.35 nicm 1179: {
1180: struct screen *s = ctx->s;
1181: struct grid *gd = s->grid;
1.104 nicm 1182: static struct grid_cell gc;
1183: u_int n;
1.35 nicm 1184:
1185: /* Can't combine if at 0. */
1186: if (s->cx == 0)
1.104 nicm 1187: return (NULL);
1.35 nicm 1188:
1.60 nicm 1189: /* Empty data is out. */
1190: if (ud->size == 0)
1.37 nicm 1191: fatalx("UTF-8 data empty");
1192:
1.60 nicm 1193: /* Retrieve the previous cell. */
1.104 nicm 1194: for (n = 1; n < s->cx; n++) {
1195: grid_view_get_cell(gd, s->cx - n, s->cy, &gc);
1196: if (~gc.flags & GRID_FLAG_PADDING)
1197: break;
1198: }
1199: if (n == s->cx)
1200: return (NULL);
1201: *xx = s->cx - n;
1.35 nicm 1202:
1.60 nicm 1203: /* Check there is enough space. */
1.77 nicm 1204: if (gc.data.size + ud->size > sizeof gc.data.data)
1.104 nicm 1205: return (NULL);
1206:
1207: log_debug("%s: %.*s onto %.*s at %u,%u", __func__, (int)ud->size,
1208: ud->data, (int)gc.data.size, gc.data.data, *xx, s->cy);
1.35 nicm 1209:
1.77 nicm 1210: /* Append the data. */
1211: memcpy(gc.data.data + gc.data.size, ud->data, ud->size);
1212: gc.data.size += ud->size;
1213:
1214: /* Set the new cell. */
1.104 nicm 1215: grid_view_set_cell(gd, *xx, s->cy, &gc);
1.35 nicm 1216:
1.104 nicm 1217: return (&gc);
1.1 nicm 1218: }
1219:
1220: /*
1221: * UTF-8 wide characters are a bit of an annoyance. They take up more than one
1222: * cell on the screen, so following cells must not be drawn by marking them as
1223: * padding.
1224: *
1225: * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
1226: * character, it is necessary to also overwrite any other cells which covered
1227: * by the same character.
1228: */
1.89 nicm 1229: static int
1230: screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
1231: u_int width)
1.1 nicm 1232: {
1233: struct screen *s = ctx->s;
1234: struct grid *gd = s->grid;
1.89 nicm 1235: struct grid_cell tmp_gc;
1.1 nicm 1236: u_int xx;
1.89 nicm 1237: int done = 0;
1.1 nicm 1238:
1.89 nicm 1239: if (gc->flags & GRID_FLAG_PADDING) {
1.1 nicm 1240: /*
1241: * A padding cell, so clear any following and leading padding
1242: * cells back to the character. Don't overwrite the current
1243: * cell as that happens later anyway.
1244: */
1245: xx = s->cx + 1;
1246: while (--xx > 0) {
1.89 nicm 1247: grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
1248: if (~tmp_gc.flags & GRID_FLAG_PADDING)
1.1 nicm 1249: break;
1250: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1251: }
1252:
1253: /* Overwrite the character at the start of this padding. */
1254: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1.89 nicm 1255: done = 1;
1.43 nicm 1256: }
1.1 nicm 1257:
1.43 nicm 1258: /*
1.95 nicm 1259: * Overwrite any padding cells that belong to any UTF-8 characters
1260: * we'll be overwriting with the current character.
1.43 nicm 1261: */
1.95 nicm 1262: if (width != 1 ||
1263: gc->data.width != 1 ||
1264: gc->flags & GRID_FLAG_PADDING) {
1.89 nicm 1265: xx = s->cx + width - 1;
1266: while (++xx < screen_size_x(s)) {
1267: grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
1268: if (~tmp_gc.flags & GRID_FLAG_PADDING)
1269: break;
1270: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1271: done = 1;
1272: }
1.1 nicm 1273: }
1.89 nicm 1274:
1275: return (done);
1.50 nicm 1276: }
1277:
1.107 nicm 1278: /* Set external clipboard. */
1.50 nicm 1279: void
1280: screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
1281: {
1282: struct tty_ctx ttyctx;
1283:
1.87 nicm 1284: screen_write_initctx(ctx, &ttyctx);
1.50 nicm 1285: ttyctx.ptr = str;
1286: ttyctx.num = len;
1287:
1288: tty_write(tty_cmd_setselection, &ttyctx);
1.47 nicm 1289: }
1290:
1.107 nicm 1291: /* Write unmodified string. */
1.47 nicm 1292: void
1293: screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
1294: {
1.87 nicm 1295: struct tty_ctx ttyctx;
1.47 nicm 1296:
1.87 nicm 1297: screen_write_initctx(ctx, &ttyctx);
1.47 nicm 1298: ttyctx.ptr = str;
1299: ttyctx.num = len;
1300:
1301: tty_write(tty_cmd_rawstring, &ttyctx);
1.1 nicm 1302: }