Annotation of src/usr.bin/tmux/screen-write.c, Revision 1.23
1.23 ! nicm 1: /* $OpenBSD: screen-write.c,v 1.22 2009/08/20 19:14:42 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <string.h>
22:
23: #include "tmux.h"
24:
1.17 nicm 25: void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *);
1.1 nicm 26: void screen_write_overwrite(struct screen_write_ctx *);
27:
28: /* Initialise writing with a window. */
29: void
30: screen_write_start(
31: struct screen_write_ctx *ctx, struct window_pane *wp, struct screen *s)
32: {
33: ctx->wp = wp;
34: if (wp != NULL && s == NULL)
35: ctx->s = wp->screen;
36: else
37: ctx->s = s;
38: }
39:
40: /* Finish writing. */
41: void
42: screen_write_stop(unused struct screen_write_ctx *ctx)
43: {
44: }
45:
46: /* Write character. */
47: void
48: screen_write_putc(
49: struct screen_write_ctx *ctx, struct grid_cell *gc, u_char ch)
50: {
51: gc->data = ch;
52: screen_write_cell(ctx, gc, NULL);
53: }
54:
1.2 nicm 55: /* Calculate string length. */
1.3 nicm 56: size_t printflike2
57: screen_write_strlen(int utf8flag, const char *fmt, ...)
1.2 nicm 58: {
59: va_list ap;
60: char *msg;
61: u_char *ptr, utf8buf[4];
62: size_t left, size = 0;
63:
64: va_start(ap, fmt);
65: xvasprintf(&msg, fmt, ap);
66: va_end(ap);
67:
68: ptr = msg;
69: while (*ptr != '\0') {
1.3 nicm 70: if (utf8flag && *ptr > 0x7f) {
1.2 nicm 71: memset(utf8buf, 0xff, sizeof utf8buf);
72:
73: left = strlen(ptr);
74: if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
75: memcpy(utf8buf, ptr, 2);
76: ptr += 2;
77: } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) {
78: memcpy(utf8buf, ptr, 3);
79: ptr += 3;
80: } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) {
81: memcpy(utf8buf, ptr, 4);
82: ptr += 4;
83: } else {
84: *utf8buf = *ptr;
85: ptr++;
86: }
87: size += utf8_width(utf8buf);
88: } else {
89: size++;
90: ptr++;
91: }
1.7 ray 92: }
1.2 nicm 93:
1.19 nicm 94: xfree(msg);
1.2 nicm 95: return (size);
96: }
97:
1.3 nicm 98: /* Write simple string (no UTF-8 or maximum length). */
1.1 nicm 99: void printflike3
100: screen_write_puts(
101: struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...)
102: {
103: va_list ap;
104:
105: va_start(ap, fmt);
1.3 nicm 106: screen_write_vnputs(ctx, -1, gc, 0, fmt, ap);
1.2 nicm 107: va_end(ap);
108: }
109:
110: /* Write string with length limit (-1 for unlimited). */
1.3 nicm 111: void printflike5
1.2 nicm 112: screen_write_nputs(struct screen_write_ctx *ctx,
1.3 nicm 113: ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...)
1.2 nicm 114: {
115: va_list ap;
116:
117: va_start(ap, fmt);
1.3 nicm 118: screen_write_vnputs(ctx, maxlen, gc, utf8flag, fmt, ap);
1.2 nicm 119: va_end(ap);
120: }
121:
122: void
1.3 nicm 123: screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
124: struct grid_cell *gc, int utf8flag, const char *fmt, va_list ap)
1.2 nicm 125: {
126: char *msg;
127: u_char *ptr, utf8buf[4];
128: size_t left, size = 0;
129: int width;
130:
1.1 nicm 131: xvasprintf(&msg, fmt, ap);
132:
1.2 nicm 133: ptr = msg;
134: while (*ptr != '\0') {
1.3 nicm 135: if (utf8flag && *ptr > 0x7f) {
1.2 nicm 136: memset(utf8buf, 0xff, sizeof utf8buf);
137:
138: left = strlen(ptr);
139: if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
140: memcpy(utf8buf, ptr, 2);
141: ptr += 2;
142: } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) {
143: memcpy(utf8buf, ptr, 3);
144: ptr += 3;
145: } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) {
146: memcpy(utf8buf, ptr, 4);
147: ptr += 4;
148: } else {
149: *utf8buf = *ptr;
150: ptr++;
151: }
1.7 ray 152:
1.2 nicm 153: width = utf8_width(utf8buf);
154: if (maxlen > 0 && size + width > (size_t) maxlen) {
155: while (size < (size_t) maxlen) {
156: screen_write_putc(ctx, gc, ' ');
157: size++;
158: }
159: break;
160: }
161: size += width;
162:
163: gc->flags |= GRID_FLAG_UTF8;
164: screen_write_cell(ctx, gc, utf8buf);
165: gc->flags &= ~GRID_FLAG_UTF8;
166:
167: } else {
1.8 nicm 168: if (maxlen > 0 && size + 1 > (size_t) maxlen)
1.2 nicm 169: break;
170:
171: size++;
172: screen_write_putc(ctx, gc, *ptr);
173: ptr++;
174: }
175: }
1.1 nicm 176:
177: xfree(msg);
178: }
179:
180: /* Copy from another screen. */
181: void
182: screen_write_copy(struct screen_write_ctx *ctx,
183: struct screen *src, u_int px, u_int py, u_int nx, u_int ny)
184: {
185: struct screen *s = ctx->s;
186: struct grid *gd = src->grid;
1.21 nicm 187: struct grid_line *gl;
1.1 nicm 188: const struct grid_cell *gc;
189: u_char *udata;
190: u_int xx, yy, cx, cy;
191:
192: cx = s->cx;
193: cy = s->cy;
194: for (yy = py; yy < py + ny; yy++) {
1.21 nicm 195: gl = &gd->linedata[yy];
1.1 nicm 196: for (xx = px; xx < px + nx; xx++) {
1.21 nicm 197: udata = NULL;
198:
199: if (xx >= gl->cellsize || yy >= gd->hsize + gd->sy)
1.1 nicm 200: gc = &grid_default_cell;
1.21 nicm 201: else {
202: gc = &gl->celldata[xx];
203: if (gc->flags & GRID_FLAG_UTF8)
204: udata = gl->utf8data[xx].data;
1.1 nicm 205: }
206:
207: screen_write_cell(ctx, gc, udata);
208: }
209: cy++;
210: screen_write_cursormove(ctx, cx, cy);
211: }
212: }
213:
1.17 nicm 214: /* Set up context for TTY command. */
1.1 nicm 215: void
1.17 nicm 216: screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
1.1 nicm 217: {
218: struct screen *s = ctx->s;
219:
1.17 nicm 220: ttyctx->wp = ctx->wp;
1.1 nicm 221:
1.17 nicm 222: ttyctx->ocx = s->cx;
223: ttyctx->ocy = s->cy;
224:
225: ttyctx->orlower = s->rlower;
226: ttyctx->orupper = s->rupper;
1.1 nicm 227: }
228:
229: /* Cursor up by ny. */
230: void
231: screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
232: {
233: struct screen *s = ctx->s;
234:
235: if (ny == 0)
236: ny = 1;
237:
1.12 nicm 238: if (s->cy < s->rupper) {
239: /* Above region. */
240: if (ny > s->cy)
241: ny = s->cy;
242: } else {
243: /* Below region. */
244: if (ny > s->cy - s->rupper)
245: ny = s->cy - s->rupper;
246: }
1.1 nicm 247: if (ny == 0)
248: return;
249:
250: s->cy -= ny;
251: }
252:
253: /* Cursor down by ny. */
254: void
255: screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
256: {
257: struct screen *s = ctx->s;
258:
259: if (ny == 0)
260: ny = 1;
261:
1.12 nicm 262: if (s->cy > s->rlower) {
263: /* Below region. */
264: if (ny > screen_size_y(s) - 1 - s->cy)
265: ny = screen_size_y(s) - 1 - s->cy;
266: } else {
267: /* Above region. */
268: if (ny > s->rlower - s->cy)
269: ny = s->rlower - s->cy;
270: }
1.1 nicm 271: if (ny == 0)
272: return;
273:
274: s->cy += ny;
275: }
276:
277: /* Cursor right by nx. */
278: void
279: screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
280: {
281: struct screen *s = ctx->s;
282:
283: if (nx == 0)
284: nx = 1;
285:
286: if (nx > screen_size_x(s) - 1 - s->cx)
287: nx = screen_size_x(s) - 1 - s->cx;
288: if (nx == 0)
289: return;
290:
291: s->cx += nx;
292: }
293:
294: /* Cursor left by nx. */
295: void
296: screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
297: {
298: struct screen *s = ctx->s;
299:
300: if (nx == 0)
301: nx = 1;
302:
303: if (nx > s->cx)
304: nx = s->cx;
305: if (nx == 0)
306: return;
307:
308: s->cx -= nx;
1.5 nicm 309: }
310:
311: /* VT100 alignment test. */
312: void
313: screen_write_alignmenttest(struct screen_write_ctx *ctx)
314: {
315: struct screen *s = ctx->s;
1.17 nicm 316: struct tty_ctx ttyctx;
1.5 nicm 317: struct grid_cell gc;
318: u_int xx, yy;
319:
1.17 nicm 320: screen_write_initctx(ctx, &ttyctx);
321:
1.5 nicm 322: memcpy(&gc, &grid_default_cell, sizeof gc);
323: gc.data = 'E';
1.7 ray 324:
1.5 nicm 325: for (yy = 0; yy < screen_size_y(s); yy++) {
326: for (xx = 0; xx < screen_size_x(s); xx++)
327: grid_view_set_cell(s->grid, xx, yy, &gc);
328: }
1.7 ray 329:
1.5 nicm 330: s->cx = 0;
331: s->cy = 0;
332:
333: s->rupper = 0;
334: s->rlower = screen_size_y(s) - 1;
335:
1.17 nicm 336: tty_write(tty_cmd_alignmenttest, &ttyctx);
1.1 nicm 337: }
338:
339: /* Insert nx characters. */
340: void
341: screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx)
342: {
343: struct screen *s = ctx->s;
1.17 nicm 344: struct tty_ctx ttyctx;
1.1 nicm 345:
346: if (nx == 0)
347: nx = 1;
348:
1.9 nicm 349: if (nx > screen_size_x(s) - s->cx)
350: nx = screen_size_x(s) - s->cx;
1.1 nicm 351: if (nx == 0)
352: return;
353:
1.17 nicm 354: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 355:
356: if (s->cx <= screen_size_x(s) - 1)
357: grid_view_insert_cells(s->grid, s->cx, s->cy, nx);
358:
1.17 nicm 359: ttyctx.num = nx;
360: tty_write(tty_cmd_insertcharacter, &ttyctx);
1.1 nicm 361: }
362:
363: /* Delete nx characters. */
364: void
365: screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx)
366: {
367: struct screen *s = ctx->s;
1.17 nicm 368: struct tty_ctx ttyctx;
1.1 nicm 369:
370: if (nx == 0)
371: nx = 1;
372:
1.9 nicm 373: if (nx > screen_size_x(s) - s->cx)
374: nx = screen_size_x(s) - s->cx;
1.1 nicm 375: if (nx == 0)
376: return;
377:
1.17 nicm 378: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 379:
380: if (s->cx <= screen_size_x(s) - 1)
381: grid_view_delete_cells(s->grid, s->cx, s->cy, nx);
382:
1.17 nicm 383: ttyctx.num = nx;
384: tty_write(tty_cmd_deletecharacter, &ttyctx);
1.1 nicm 385: }
386:
387: /* Insert ny lines. */
388: void
389: screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
390: {
391: struct screen *s = ctx->s;
1.17 nicm 392: struct tty_ctx ttyctx;
1.1 nicm 393:
394: if (ny == 0)
395: ny = 1;
396:
1.11 nicm 397: if (s->cy < s->rupper || s->cy > s->rlower) {
398: if (ny > screen_size_y(s) - s->cy)
399: ny = screen_size_y(s) - s->cy;
400: if (ny == 0)
401: return;
402:
1.17 nicm 403: screen_write_initctx(ctx, &ttyctx);
1.11 nicm 404:
405: grid_view_insert_lines(s->grid, s->cy, ny);
406:
1.17 nicm 407: ttyctx.num = ny;
408: tty_write(tty_cmd_insertline, &ttyctx);
1.11 nicm 409: return;
410: }
411:
412: if (ny > s->rlower + 1 - s->cy)
413: ny = s->rlower + 1 - s->cy;
1.1 nicm 414: if (ny == 0)
415: return;
1.11 nicm 416:
1.17 nicm 417: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 418:
419: if (s->cy < s->rupper || s->cy > s->rlower)
420: grid_view_insert_lines(s->grid, s->cy, ny);
1.10 nicm 421: else
422: grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny);
1.1 nicm 423:
1.17 nicm 424: ttyctx.num = ny;
425: tty_write(tty_cmd_insertline, &ttyctx);
1.1 nicm 426: }
427:
428: /* Delete ny lines. */
429: void
430: screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
431: {
432: struct screen *s = ctx->s;
1.17 nicm 433: struct tty_ctx ttyctx;
1.1 nicm 434:
435: if (ny == 0)
436: ny = 1;
437:
1.11 nicm 438: if (s->cy < s->rupper || s->cy > s->rlower) {
439: if (ny > screen_size_y(s) - s->cy)
440: ny = screen_size_y(s) - s->cy;
441: if (ny == 0)
442: return;
443:
1.17 nicm 444: screen_write_initctx(ctx, &ttyctx);
1.11 nicm 445:
446: grid_view_delete_lines(s->grid, s->cy, ny);
447:
1.17 nicm 448: ttyctx.num = ny;
449: tty_write(tty_cmd_deleteline, &ttyctx);
1.11 nicm 450: return;
451: }
452:
453: if (ny > s->rlower + 1 - s->cy)
454: ny = s->rlower + 1 - s->cy;
1.1 nicm 455: if (ny == 0)
456: return;
457:
1.17 nicm 458: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 459:
460: if (s->cy < s->rupper || s->cy > s->rlower)
461: grid_view_delete_lines(s->grid, s->cy, ny);
1.10 nicm 462: else
463: grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny);
1.1 nicm 464:
1.17 nicm 465: ttyctx.num = ny;
466: tty_write(tty_cmd_deleteline, &ttyctx);
1.1 nicm 467: }
468:
469: /* Clear line at cursor. */
470: void
471: screen_write_clearline(struct screen_write_ctx *ctx)
472: {
473: struct screen *s = ctx->s;
1.17 nicm 474: struct tty_ctx ttyctx;
1.1 nicm 475:
1.17 nicm 476: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 477:
478: grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1);
479:
1.17 nicm 480: tty_write(tty_cmd_clearline, &ttyctx);
1.1 nicm 481: }
482:
483: /* Clear to end of line from cursor. */
484: void
485: screen_write_clearendofline(struct screen_write_ctx *ctx)
486: {
487: struct screen *s = ctx->s;
1.17 nicm 488: struct tty_ctx ttyctx;
1.1 nicm 489: u_int sx;
490:
1.17 nicm 491: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 492:
493: sx = screen_size_x(s);
494:
495: if (s->cx <= sx - 1)
496: grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
497:
1.17 nicm 498: tty_write(tty_cmd_clearendofline, &ttyctx);
1.1 nicm 499: }
500:
501: /* Clear to start of line from cursor. */
502: void
503: screen_write_clearstartofline(struct screen_write_ctx *ctx)
504: {
505: struct screen *s = ctx->s;
1.17 nicm 506: struct tty_ctx ttyctx;
1.1 nicm 507: u_int sx;
508:
1.17 nicm 509: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 510:
511: sx = screen_size_x(s);
512:
513: if (s->cx > sx - 1)
514: grid_view_clear(s->grid, 0, s->cy, sx, 1);
515: else
516: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
517:
1.17 nicm 518: tty_write(tty_cmd_clearstartofline, &ttyctx);
1.1 nicm 519: }
520:
521: /* Move cursor to px,py. */
522: void
523: screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
524: {
525: struct screen *s = ctx->s;
526:
527: if (px > screen_size_x(s) - 1)
528: px = screen_size_x(s) - 1;
529: if (py > screen_size_y(s) - 1)
530: py = screen_size_y(s) - 1;
531:
532: s->cx = px;
533: s->cy = py;
534: }
535:
536: /* Set cursor mode. */
537: void
538: screen_write_cursormode(struct screen_write_ctx *ctx, int state)
539: {
540: struct screen *s = ctx->s;
541:
542: if (state)
543: s->mode |= MODE_CURSOR;
544: else
545: s->mode &= ~MODE_CURSOR;
546: }
547:
548: /* Reverse index (up with scroll). */
549: void
550: screen_write_reverseindex(struct screen_write_ctx *ctx)
551: {
552: struct screen *s = ctx->s;
1.17 nicm 553: struct tty_ctx ttyctx;
1.1 nicm 554:
1.17 nicm 555: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 556:
557: if (s->cy == s->rupper)
558: grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
559: else if (s->cy > 0)
560: s->cy--;
561:
1.17 nicm 562: tty_write(tty_cmd_reverseindex, &ttyctx);
1.1 nicm 563: }
564:
565: /* Set scroll region. */
566: void
567: screen_write_scrollregion(
568: struct screen_write_ctx *ctx, u_int rupper, u_int rlower)
569: {
570: struct screen *s = ctx->s;
571:
572: if (rupper > screen_size_y(s) - 1)
573: rupper = screen_size_y(s) - 1;
574: if (rlower > screen_size_y(s) - 1)
575: rlower = screen_size_y(s) - 1;
1.13 nicm 576: if (rupper >= rlower) /* cannot be one line */
1.1 nicm 577: return;
578:
579: /* Cursor moves to top-left. */
580: s->cx = 0;
581: s->cy = 0;
582:
583: s->rupper = rupper;
584: s->rlower = rlower;
585: }
586:
587: /* Set insert mode. */
588: void
589: screen_write_insertmode(struct screen_write_ctx *ctx, int state)
590: {
591: struct screen *s = ctx->s;
592:
593: if (state)
594: s->mode |= MODE_INSERT;
595: else
596: s->mode &= ~MODE_INSERT;
597: }
598:
599: /* Set mouse mode. */
600: void
601: screen_write_mousemode(struct screen_write_ctx *ctx, int state)
602: {
603: struct screen *s = ctx->s;
604:
605: if (state)
606: s->mode |= MODE_MOUSE;
607: else
608: s->mode &= ~MODE_MOUSE;
609: }
610:
611: /* Line feed (down with scroll). */
612: void
1.20 nicm 613: screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
1.1 nicm 614: {
1.20 nicm 615: struct screen *s = ctx->s;
616: struct grid_line *gl;
617: struct tty_ctx ttyctx;
1.1 nicm 618:
1.17 nicm 619: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 620:
1.20 nicm 621: gl = &s->grid->linedata[s->grid->hsize + s->cy];
622: if (wrapped)
623: gl->flags |= GRID_LINE_WRAPPED;
624: else
625: gl->flags &= ~GRID_LINE_WRAPPED;
626:
1.1 nicm 627: if (s->cy == s->rlower)
628: grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
629: else if (s->cy < screen_size_y(s) - 1)
630: s->cy++;
631:
1.17 nicm 632: tty_write(tty_cmd_linefeed, &ttyctx);
1.1 nicm 633: }
634:
635: /* Carriage return (cursor to start of line). */
636: void
637: screen_write_carriagereturn(struct screen_write_ctx *ctx)
638: {
639: struct screen *s = ctx->s;
640:
641: s->cx = 0;
642: }
643:
644: /* Set keypad cursor keys mode. */
645: void
646: screen_write_kcursormode(struct screen_write_ctx *ctx, int state)
647: {
648: struct screen *s = ctx->s;
649:
650: if (state)
651: s->mode |= MODE_KCURSOR;
652: else
653: s->mode &= ~MODE_KCURSOR;
654: }
655:
656: /* Set keypad number keys mode. */
657: void
658: screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state)
659: {
660: struct screen *s = ctx->s;
661:
662: if (state)
663: s->mode |= MODE_KKEYPAD;
664: else
665: s->mode &= ~MODE_KKEYPAD;
666: }
667:
668: /* Clear to end of screen from cursor. */
669: void
670: screen_write_clearendofscreen(struct screen_write_ctx *ctx)
671: {
672: struct screen *s = ctx->s;
1.17 nicm 673: struct tty_ctx ttyctx;
1.1 nicm 674: u_int sx, sy;
675:
1.17 nicm 676: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 677:
678: sx = screen_size_x(s);
679: sy = screen_size_y(s);
680:
681: if (s->cx <= sx - 1)
682: grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
683: grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1));
684:
1.17 nicm 685: tty_write(tty_cmd_clearendofscreen, &ttyctx);
1.1 nicm 686: }
687:
688: /* Clear to start of screen. */
689: void
690: screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
691: {
692: struct screen *s = ctx->s;
1.17 nicm 693: struct tty_ctx ttyctx;
1.1 nicm 694: u_int sx;
695:
1.17 nicm 696: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 697:
698: sx = screen_size_x(s);
699:
700: if (s->cy > 0)
1.4 nicm 701: grid_view_clear(s->grid, 0, 0, sx, s->cy);
1.1 nicm 702: if (s->cx > sx - 1)
703: grid_view_clear(s->grid, 0, s->cy, sx, 1);
704: else
1.4 nicm 705: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
1.1 nicm 706:
1.17 nicm 707: tty_write(tty_cmd_clearstartofscreen, &ttyctx);
1.1 nicm 708: }
709:
710: /* Clear entire screen. */
711: void
712: screen_write_clearscreen(struct screen_write_ctx *ctx)
713: {
714: struct screen *s = ctx->s;
1.17 nicm 715: struct tty_ctx ttyctx;
1.1 nicm 716:
1.17 nicm 717: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 718:
719: grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s));
720:
1.17 nicm 721: tty_write(tty_cmd_clearscreen, &ttyctx);
1.1 nicm 722: }
723:
724: /* Write cell data. */
725: void
726: screen_write_cell(
727: struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata)
728: {
729: struct screen *s = ctx->s;
730: struct grid *gd = s->grid;
1.15 nicm 731: struct tty_ctx ttyctx;
1.1 nicm 732: struct grid_utf8 gu, *tmp_gu;
733: u_int width, xx, i;
1.18 nicm 734: struct grid_cell tmp_gc, tmp_gc2, *tmp_gcp;
1.6 nicm 735: int insert = 0;
1.1 nicm 736:
737: /* Ignore padding. */
738: if (gc->flags & GRID_FLAG_PADDING)
739: return;
740:
741: /* Find character width. */
742: if (gc->flags & GRID_FLAG_UTF8) {
743: width = utf8_width(udata);
744:
745: gu.width = width;
746: memcpy(&gu.data, udata, sizeof gu.data);
747: } else
748: width = 1;
749:
750: /* If the width is zero, combine onto the previous character. */
751: if (width == 0) {
752: if (s->cx == 0)
753: return;
1.18 nicm 754: tmp_gcp = grid_view_get_cell(gd, s->cx - 1, s->cy);
755: if (!(tmp_gcp->flags & GRID_FLAG_UTF8)) {
756: tmp_gcp->flags |= GRID_FLAG_UTF8;
1.1 nicm 757: memset(&gu.data, 0xff, sizeof gu.data);
1.18 nicm 758: *gu.data = tmp_gcp->data;
1.1 nicm 759: gu.width = 1;
760: grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu);
761: }
762: tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy);
763:
764: for (i = 0; i < UTF8_SIZE; i++) {
765: if (tmp_gu->data[i] == 0xff)
766: break;
767: }
768: memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i);
769:
770: /* Assume the previous character has just been input. */
1.17 nicm 771: screen_write_initctx(ctx, &ttyctx);
772: ttyctx.ptr = udata;
773: tty_write(tty_cmd_utf8character, &ttyctx);
1.1 nicm 774: return;
775: }
776:
777: /* If the character is wider than the screen, don't print it. */
778: if (width > screen_size_x(s)) {
779: memcpy(&tmp_gc, gc, sizeof tmp_gc);
780: tmp_gc.data = '_';
781: width = 1;
782: gc = &tmp_gc;
783: }
784:
1.6 nicm 785: /* If in insert mode, make space for the cells. */
786: if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) {
787: xx = screen_size_x(s) - s->cx - width;
788: grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx);
789: insert = 1;
790: }
791:
1.20 nicm 792: /* Check this will fit on the current line and wrap if not. */
1.1 nicm 793: if (s->cx > screen_size_x(s) - width) {
794: screen_write_carriagereturn(ctx);
1.20 nicm 795: screen_write_linefeed(ctx, 1);
1.1 nicm 796: }
797:
798: /* Sanity checks. */
799: if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1)
800: return;
801:
802: /* Handle overwriting of UTF-8 characters. */
803: screen_write_overwrite(ctx);
804:
805: /*
806: * If the new character is UTF-8 wide, fill in padding cells. Have
807: * already ensured there is enough room.
808: */
809: for (xx = s->cx + 1; xx < s->cx + width; xx++) {
1.18 nicm 810: tmp_gcp = grid_view_get_cell(gd, xx, s->cy);
811: if (tmp_gcp != NULL)
812: tmp_gcp->flags |= GRID_FLAG_PADDING;
1.1 nicm 813: }
814:
815: /* Set the cell. */
816: grid_view_set_cell(gd, s->cx, s->cy, gc);
817: if (gc->flags & GRID_FLAG_UTF8)
818: grid_view_set_utf8(gd, s->cx, s->cy, &gu);
819:
820: /* Move the cursor. */
1.17 nicm 821: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 822: s->cx += width;
823:
824: /* Draw to the screen if necessary. */
1.17 nicm 825: if (insert) {
826: ttyctx.num = width;
827: tty_write(tty_cmd_insertcharacter, &ttyctx);
828: }
1.15 nicm 829: ttyctx.utf8 = &gu;
1.1 nicm 830: if (screen_check_selection(s, s->cx - width, s->cy)) {
1.18 nicm 831: memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2);
832: tmp_gc2.data = gc->data;
833: tmp_gc2.flags = gc->flags;
834: ttyctx.cell = &tmp_gc2;
1.16 nicm 835: tty_write(tty_cmd_cell, &ttyctx);
1.15 nicm 836: } else {
837: ttyctx.cell = gc;
1.16 nicm 838: tty_write(tty_cmd_cell, &ttyctx);
1.15 nicm 839: }
1.1 nicm 840: }
841:
842: /*
843: * UTF-8 wide characters are a bit of an annoyance. They take up more than one
844: * cell on the screen, so following cells must not be drawn by marking them as
845: * padding.
846: *
847: * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
848: * character, it is necessary to also overwrite any other cells which covered
849: * by the same character.
850: */
851: void
852: screen_write_overwrite(struct screen_write_ctx *ctx)
853: {
854: struct screen *s = ctx->s;
855: struct grid *gd = s->grid;
856: const struct grid_cell *gc;
857: const struct grid_utf8 *gu;
858: u_int xx;
859:
860: gc = grid_view_peek_cell(gd, s->cx, s->cy);
861: if (gc->flags & GRID_FLAG_PADDING) {
862: /*
863: * A padding cell, so clear any following and leading padding
864: * cells back to the character. Don't overwrite the current
865: * cell as that happens later anyway.
866: */
867: xx = s->cx + 1;
868: while (--xx > 0) {
869: gc = grid_view_peek_cell(gd, xx, s->cy);
870: if (!(gc->flags & GRID_FLAG_PADDING))
871: break;
872: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
873: }
874:
875: /* Overwrite the character at the start of this padding. */
876: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
877:
878: /* Overwrite following padding cells. */
879: xx = s->cx;
880: while (++xx < screen_size_x(s)) {
881: gc = grid_view_peek_cell(gd, xx, s->cy);
882: if (!(gc->flags & GRID_FLAG_PADDING))
883: break;
884: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
885: }
1.22 nicm 886: } else if (gc->flags & GRID_FLAG_UTF8) {
887: gu = grid_view_peek_utf8(gd, s->cx, s->cy);
888: if (gu->width > 1) {
889: /*
890: * An UTF-8 wide cell; overwrite following padding cells only.
891: */
892: xx = s->cx;
893: while (++xx < screen_size_x(s)) {
894: gc = grid_view_peek_cell(gd, xx, s->cy);
895: if (!(gc->flags & GRID_FLAG_PADDING))
896: break;
897: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
898: }
1.1 nicm 899: }
900: }
901: }