Annotation of src/usr.bin/tmux/screen-write.c, Revision 1.19
1.19 ! nicm 1: /* $OpenBSD: screen-write.c,v 1.18 2009/07/27 11:33:21 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;
187: const struct grid_cell *gc;
188: struct grid_utf8 *gu;
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++) {
195: for (xx = px; xx < px + nx; xx++) {
196: if (xx >= gd->sx || yy >= gd->hsize + gd->sy)
197: gc = &grid_default_cell;
198: else
199: gc = grid_peek_cell(gd, xx, yy);
200:
201: udata = NULL;
202: if (gc->flags & GRID_FLAG_UTF8) {
203: gu = grid_get_utf8(gd, xx, yy);
204: udata = gu->data;
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
613: screen_write_linefeed(struct screen_write_ctx *ctx)
614: {
615: struct screen *s = ctx->s;
1.17 nicm 616: struct tty_ctx ttyctx;
1.1 nicm 617:
1.17 nicm 618: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 619:
620: if (s->cy == s->rlower)
621: grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
622: else if (s->cy < screen_size_y(s) - 1)
623: s->cy++;
624:
1.17 nicm 625: tty_write(tty_cmd_linefeed, &ttyctx);
1.1 nicm 626: }
627:
628: /* Carriage return (cursor to start of line). */
629: void
630: screen_write_carriagereturn(struct screen_write_ctx *ctx)
631: {
632: struct screen *s = ctx->s;
633:
634: s->cx = 0;
635: }
636:
637: /* Set keypad cursor keys mode. */
638: void
639: screen_write_kcursormode(struct screen_write_ctx *ctx, int state)
640: {
641: struct screen *s = ctx->s;
642:
643: if (state)
644: s->mode |= MODE_KCURSOR;
645: else
646: s->mode &= ~MODE_KCURSOR;
647: }
648:
649: /* Set keypad number keys mode. */
650: void
651: screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state)
652: {
653: struct screen *s = ctx->s;
654:
655: if (state)
656: s->mode |= MODE_KKEYPAD;
657: else
658: s->mode &= ~MODE_KKEYPAD;
659: }
660:
661: /* Clear to end of screen from cursor. */
662: void
663: screen_write_clearendofscreen(struct screen_write_ctx *ctx)
664: {
665: struct screen *s = ctx->s;
1.17 nicm 666: struct tty_ctx ttyctx;
1.1 nicm 667: u_int sx, sy;
668:
1.17 nicm 669: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 670:
671: sx = screen_size_x(s);
672: sy = screen_size_y(s);
673:
674: if (s->cx <= sx - 1)
675: grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
676: grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1));
677:
1.17 nicm 678: tty_write(tty_cmd_clearendofscreen, &ttyctx);
1.1 nicm 679: }
680:
681: /* Clear to start of screen. */
682: void
683: screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
684: {
685: struct screen *s = ctx->s;
1.17 nicm 686: struct tty_ctx ttyctx;
1.1 nicm 687: u_int sx;
688:
1.17 nicm 689: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 690:
691: sx = screen_size_x(s);
692:
693: if (s->cy > 0)
1.4 nicm 694: grid_view_clear(s->grid, 0, 0, sx, s->cy);
1.1 nicm 695: if (s->cx > sx - 1)
696: grid_view_clear(s->grid, 0, s->cy, sx, 1);
697: else
1.4 nicm 698: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
1.1 nicm 699:
1.17 nicm 700: tty_write(tty_cmd_clearstartofscreen, &ttyctx);
1.1 nicm 701: }
702:
703: /* Clear entire screen. */
704: void
705: screen_write_clearscreen(struct screen_write_ctx *ctx)
706: {
707: struct screen *s = ctx->s;
1.17 nicm 708: struct tty_ctx ttyctx;
1.1 nicm 709:
1.17 nicm 710: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 711:
712: grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s));
713:
1.17 nicm 714: tty_write(tty_cmd_clearscreen, &ttyctx);
1.1 nicm 715: }
716:
717: /* Write cell data. */
718: void
719: screen_write_cell(
720: struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata)
721: {
722: struct screen *s = ctx->s;
723: struct grid *gd = s->grid;
1.15 nicm 724: struct tty_ctx ttyctx;
1.1 nicm 725: struct grid_utf8 gu, *tmp_gu;
726: u_int width, xx, i;
1.18 nicm 727: struct grid_cell tmp_gc, tmp_gc2, *tmp_gcp;
1.6 nicm 728: int insert = 0;
1.1 nicm 729:
730: /* Ignore padding. */
731: if (gc->flags & GRID_FLAG_PADDING)
732: return;
733:
734: /* Find character width. */
735: if (gc->flags & GRID_FLAG_UTF8) {
736: width = utf8_width(udata);
737:
738: gu.width = width;
739: memcpy(&gu.data, udata, sizeof gu.data);
740: } else
741: width = 1;
742:
743: /* If the width is zero, combine onto the previous character. */
744: if (width == 0) {
745: if (s->cx == 0)
746: return;
1.18 nicm 747: tmp_gcp = grid_view_get_cell(gd, s->cx - 1, s->cy);
748: if (!(tmp_gcp->flags & GRID_FLAG_UTF8)) {
749: tmp_gcp->flags |= GRID_FLAG_UTF8;
1.1 nicm 750: memset(&gu.data, 0xff, sizeof gu.data);
1.18 nicm 751: *gu.data = tmp_gcp->data;
1.1 nicm 752: gu.width = 1;
753: grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu);
754: }
755: tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy);
756:
757: for (i = 0; i < UTF8_SIZE; i++) {
758: if (tmp_gu->data[i] == 0xff)
759: break;
760: }
761: memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i);
762:
763: /* Assume the previous character has just been input. */
1.17 nicm 764: screen_write_initctx(ctx, &ttyctx);
765: ttyctx.ptr = udata;
766: tty_write(tty_cmd_utf8character, &ttyctx);
1.1 nicm 767: return;
768: }
769:
770: /* If the character is wider than the screen, don't print it. */
771: if (width > screen_size_x(s)) {
772: memcpy(&tmp_gc, gc, sizeof tmp_gc);
773: tmp_gc.data = '_';
774: width = 1;
775: gc = &tmp_gc;
776: }
777:
1.6 nicm 778: /* If in insert mode, make space for the cells. */
779: if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) {
780: xx = screen_size_x(s) - s->cx - width;
781: grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx);
782: insert = 1;
783: }
784:
1.1 nicm 785: /* Check this will fit on the current line; scroll if not. */
786: if (s->cx > screen_size_x(s) - width) {
787: screen_write_carriagereturn(ctx);
788: screen_write_linefeed(ctx);
789: }
790:
791: /* Sanity checks. */
792: if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1)
793: return;
794:
795: /* Handle overwriting of UTF-8 characters. */
796: screen_write_overwrite(ctx);
797:
798: /*
799: * If the new character is UTF-8 wide, fill in padding cells. Have
800: * already ensured there is enough room.
801: */
802: for (xx = s->cx + 1; xx < s->cx + width; xx++) {
1.18 nicm 803: tmp_gcp = grid_view_get_cell(gd, xx, s->cy);
804: if (tmp_gcp != NULL)
805: tmp_gcp->flags |= GRID_FLAG_PADDING;
1.1 nicm 806: }
807:
808: /* Set the cell. */
809: grid_view_set_cell(gd, s->cx, s->cy, gc);
810: if (gc->flags & GRID_FLAG_UTF8)
811: grid_view_set_utf8(gd, s->cx, s->cy, &gu);
812:
813: /* Move the cursor. */
1.17 nicm 814: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 815: s->cx += width;
816:
817: /* Draw to the screen if necessary. */
1.17 nicm 818: if (insert) {
819: ttyctx.num = width;
820: tty_write(tty_cmd_insertcharacter, &ttyctx);
821: }
1.15 nicm 822: ttyctx.utf8 = &gu;
1.1 nicm 823: if (screen_check_selection(s, s->cx - width, s->cy)) {
1.18 nicm 824: memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2);
825: tmp_gc2.data = gc->data;
826: tmp_gc2.flags = gc->flags;
827: ttyctx.cell = &tmp_gc2;
1.16 nicm 828: tty_write(tty_cmd_cell, &ttyctx);
1.15 nicm 829: } else {
830: ttyctx.cell = gc;
1.16 nicm 831: tty_write(tty_cmd_cell, &ttyctx);
1.15 nicm 832: }
1.1 nicm 833: }
834:
835: /*
836: * UTF-8 wide characters are a bit of an annoyance. They take up more than one
837: * cell on the screen, so following cells must not be drawn by marking them as
838: * padding.
839: *
840: * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
841: * character, it is necessary to also overwrite any other cells which covered
842: * by the same character.
843: */
844: void
845: screen_write_overwrite(struct screen_write_ctx *ctx)
846: {
847: struct screen *s = ctx->s;
848: struct grid *gd = s->grid;
849: const struct grid_cell *gc;
850: const struct grid_utf8 *gu;
851: u_int xx;
852:
853: gc = grid_view_peek_cell(gd, s->cx, s->cy);
854: gu = grid_view_peek_utf8(gd, s->cx, s->cy);
855:
856: if (gc->flags & GRID_FLAG_PADDING) {
857: /*
858: * A padding cell, so clear any following and leading padding
859: * cells back to the character. Don't overwrite the current
860: * cell as that happens later anyway.
861: */
862: xx = s->cx + 1;
863: while (--xx > 0) {
864: gc = grid_view_peek_cell(gd, xx, s->cy);
865: if (!(gc->flags & GRID_FLAG_PADDING))
866: break;
867: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
868: }
869:
870: /* Overwrite the character at the start of this padding. */
871: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
872:
873: /* Overwrite following padding cells. */
874: xx = s->cx;
875: while (++xx < screen_size_x(s)) {
876: gc = grid_view_peek_cell(gd, xx, s->cy);
877: if (!(gc->flags & GRID_FLAG_PADDING))
878: break;
879: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
880: }
881: } else if (gc->flags & GRID_FLAG_UTF8 && gu->width > 1) {
882: /*
883: * An UTF-8 wide cell; overwrite following padding cells only.
884: */
885: xx = s->cx;
886: while (++xx < screen_size_x(s)) {
887: gc = grid_view_peek_cell(gd, xx, s->cy);
888: if (!(gc->flags & GRID_FLAG_PADDING))
889: break;
890: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
891: }
892: }
893: }