Annotation of src/usr.bin/tmux/screen-write.c, Revision 1.25
1.25 ! nicm 1: /* $OpenBSD: screen-write.c,v 1.24 2009/09/07 10:49:32 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.24 nicm 55: /* Calculate string length, with embedded formatting. */
56: size_t printflike2
57: screen_write_cstrlen(int utf8flag, const char *fmt, ...)
58: {
59: va_list ap;
60: char *msg, *msg2, *ptr, *ptr2;
61: size_t size;
62:
63: va_start(ap, fmt);
64: xvasprintf(&msg, fmt, ap);
65: va_end(ap);
66: msg2 = xmalloc(strlen(msg) + 1);
67:
68: ptr = msg;
69: ptr2 = msg2;
70: while (*ptr != '\0') {
71: if (ptr[0] == '#' && ptr[1] == '[') {
72: while (*ptr != ']' && *ptr != '\0')
73: ptr++;
74: if (*ptr == ']')
75: ptr++;
76: continue;
77: }
78: *ptr2++ = *ptr++;
79: }
80: *ptr2 = '\0';
81:
82: size = screen_write_strlen(utf8flag, "%s", msg2);
83:
84: xfree(msg);
85: xfree(msg2);
86:
87: return (size);
88: }
89:
1.2 nicm 90: /* Calculate string length. */
1.3 nicm 91: size_t printflike2
92: screen_write_strlen(int utf8flag, const char *fmt, ...)
1.2 nicm 93: {
94: va_list ap;
95: char *msg;
96: u_char *ptr, utf8buf[4];
97: size_t left, size = 0;
98:
99: va_start(ap, fmt);
100: xvasprintf(&msg, fmt, ap);
101: va_end(ap);
102:
103: ptr = msg;
104: while (*ptr != '\0') {
1.3 nicm 105: if (utf8flag && *ptr > 0x7f) {
1.2 nicm 106: memset(utf8buf, 0xff, sizeof utf8buf);
107:
108: left = strlen(ptr);
109: if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
110: memcpy(utf8buf, ptr, 2);
111: ptr += 2;
112: } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) {
113: memcpy(utf8buf, ptr, 3);
114: ptr += 3;
115: } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) {
116: memcpy(utf8buf, ptr, 4);
117: ptr += 4;
118: } else {
119: *utf8buf = *ptr;
120: ptr++;
121: }
122: size += utf8_width(utf8buf);
123: } else {
124: size++;
125: ptr++;
126: }
1.7 ray 127: }
1.2 nicm 128:
1.19 nicm 129: xfree(msg);
1.2 nicm 130: return (size);
131: }
132:
1.3 nicm 133: /* Write simple string (no UTF-8 or maximum length). */
1.1 nicm 134: void printflike3
135: screen_write_puts(
136: struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...)
137: {
138: va_list ap;
139:
140: va_start(ap, fmt);
1.3 nicm 141: screen_write_vnputs(ctx, -1, gc, 0, fmt, ap);
1.2 nicm 142: va_end(ap);
143: }
144:
145: /* Write string with length limit (-1 for unlimited). */
1.3 nicm 146: void printflike5
1.2 nicm 147: screen_write_nputs(struct screen_write_ctx *ctx,
1.3 nicm 148: ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...)
1.2 nicm 149: {
150: va_list ap;
151:
152: va_start(ap, fmt);
1.3 nicm 153: screen_write_vnputs(ctx, maxlen, gc, utf8flag, fmt, ap);
1.2 nicm 154: va_end(ap);
155: }
156:
157: void
1.3 nicm 158: screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
159: struct grid_cell *gc, int utf8flag, const char *fmt, va_list ap)
1.2 nicm 160: {
161: char *msg;
162: u_char *ptr, utf8buf[4];
163: size_t left, size = 0;
164: int width;
165:
1.1 nicm 166: xvasprintf(&msg, fmt, ap);
167:
1.2 nicm 168: ptr = msg;
169: while (*ptr != '\0') {
1.3 nicm 170: if (utf8flag && *ptr > 0x7f) {
1.2 nicm 171: memset(utf8buf, 0xff, sizeof utf8buf);
172:
173: left = strlen(ptr);
174: if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
175: memcpy(utf8buf, ptr, 2);
176: ptr += 2;
177: } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) {
178: memcpy(utf8buf, ptr, 3);
179: ptr += 3;
180: } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) {
181: memcpy(utf8buf, ptr, 4);
182: ptr += 4;
183: } else {
184: *utf8buf = *ptr;
185: ptr++;
186: }
1.7 ray 187:
1.2 nicm 188: width = utf8_width(utf8buf);
189: if (maxlen > 0 && size + width > (size_t) maxlen) {
190: while (size < (size_t) maxlen) {
191: screen_write_putc(ctx, gc, ' ');
192: size++;
193: }
194: break;
195: }
196: size += width;
197:
198: gc->flags |= GRID_FLAG_UTF8;
199: screen_write_cell(ctx, gc, utf8buf);
200: gc->flags &= ~GRID_FLAG_UTF8;
201:
202: } else {
1.8 nicm 203: if (maxlen > 0 && size + 1 > (size_t) maxlen)
1.2 nicm 204: break;
205:
206: size++;
207: screen_write_putc(ctx, gc, *ptr);
208: ptr++;
209: }
210: }
1.1 nicm 211:
212: xfree(msg);
1.24 nicm 213: }
214:
215: /* Write string, similar to nputs, but with embedded formatting (#[]). */
216: void printflike5
217: screen_write_cnputs(struct screen_write_ctx *ctx,
218: ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...)
219: {
220: struct grid_cell lgc;
221: va_list ap;
222: char *msg;
223: u_char *ptr, *last, utf8buf[4];
224: size_t left, size = 0;
225: int width;
226:
227: va_start(ap, fmt);
228: xvasprintf(&msg, fmt, ap);
229: va_end(ap);
230:
231: memcpy(&lgc, gc, sizeof lgc);
232:
233: ptr = msg;
234: while (*ptr != '\0') {
235: if (ptr[0] == '#' && ptr[1] == '[') {
236: ptr += 2;
237: last = ptr + strcspn(ptr, "]");
238: if (*last == '\0') {
239: /* No ]. Not much point in doing anything. */
240: break;
241: }
242: *last = '\0';
243:
244: screen_write_parsestyle(gc, &lgc, ptr);
245: ptr = last + 1;
246: continue;
247: }
248:
249: if (utf8flag && *ptr > 0x7f) {
250: memset(utf8buf, 0xff, sizeof utf8buf);
251:
252: left = strlen(ptr);
253: if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
254: memcpy(utf8buf, ptr, 2);
255: ptr += 2;
256: } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) {
257: memcpy(utf8buf, ptr, 3);
258: ptr += 3;
259: } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) {
260: memcpy(utf8buf, ptr, 4);
261: ptr += 4;
262: } else {
263: *utf8buf = *ptr;
264: ptr++;
265: }
266:
267: width = utf8_width(utf8buf);
268: if (maxlen > 0 && size + width > (size_t) maxlen) {
269: while (size < (size_t) maxlen) {
270: screen_write_putc(ctx, gc, ' ');
271: size++;
272: }
273: break;
274: }
275: size += width;
276:
277: lgc.flags |= GRID_FLAG_UTF8;
278: screen_write_cell(ctx, &lgc, utf8buf);
279: lgc.flags &= ~GRID_FLAG_UTF8;
280:
281: } else {
282: if (maxlen > 0 && size + 1 > (size_t) maxlen)
283: break;
284:
285: size++;
286: screen_write_putc(ctx, &lgc, *ptr);
287: ptr++;
288: }
289: }
290:
291: xfree(msg);
292: }
293:
294: /* Parse an embedded style of the form "fg=colour,bg=colour,bright,...". */
295: void
296: screen_write_parsestyle(
297: struct grid_cell *defgc, struct grid_cell *gc, const char *in)
298: {
299: const char delimiters[] = " ,";
300: char tmp[32];
301: int val;
302: size_t end;
1.25 ! nicm 303: u_char fg, bg, attr, flags;
1.24 nicm 304:
305: if (*in == '\0')
306: return;
307: if (strchr(delimiters, in[strlen(in) - 1]) != NULL)
308: return;
309:
310: fg = gc->fg;
311: bg = gc->bg;
1.25 ! nicm 312: attr = gc->attr;
! 313: flags = gc->flags;
1.24 nicm 314: do {
315: end = strcspn(in, delimiters);
316: if (end > (sizeof tmp) - 1)
317: return;
318: memcpy(tmp, in, end);
319: tmp[end] = '\0';
320:
321: if (strcasecmp(tmp, "default") == 0) {
322: fg = defgc->fg;
323: bg = defgc->bg;
324: attr = defgc->attr;
325: } else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
326: if ((val = colour_fromstring(tmp + 3)) == -1)
327: return;
328: if (*in == 'f' || *in == 'F') {
1.25 ! nicm 329: if (val != 8) {
! 330: if (val & 0x100) {
! 331: flags |= GRID_FLAG_FG256;
! 332: val &= ~0x100;
! 333: } else
! 334: flags &= ~GRID_FLAG_FG256;
1.24 nicm 335: fg = val;
1.25 ! nicm 336: } else
1.24 nicm 337: fg = defgc->fg;
338: } else if (*in == 'b' || *in == 'B') {
1.25 ! nicm 339: if (val != 8) {
! 340: if (val & 0x100) {
! 341: flags |= GRID_FLAG_BG256;
! 342: val &= ~0x100;
! 343: } else
! 344: flags &= ~GRID_FLAG_BG256;
1.24 nicm 345: bg = val;
1.25 ! nicm 346: } else
1.24 nicm 347: bg = defgc->bg;
348: } else
349: return;
350: } else {
351: if ((val = attributes_fromstring(tmp)) == -1)
352: return;
353: attr |= val;
354: }
355:
356: in += end + strspn(in + end, delimiters);
357: } while (*in != '\0');
358: gc->fg = fg;
359: gc->bg = bg;
360: gc->attr = attr;
1.25 ! nicm 361: gc->flags = flags;
1.1 nicm 362: }
363:
364: /* Copy from another screen. */
365: void
366: screen_write_copy(struct screen_write_ctx *ctx,
367: struct screen *src, u_int px, u_int py, u_int nx, u_int ny)
368: {
369: struct screen *s = ctx->s;
370: struct grid *gd = src->grid;
1.21 nicm 371: struct grid_line *gl;
1.1 nicm 372: const struct grid_cell *gc;
373: u_char *udata;
374: u_int xx, yy, cx, cy;
375:
376: cx = s->cx;
377: cy = s->cy;
378: for (yy = py; yy < py + ny; yy++) {
1.21 nicm 379: gl = &gd->linedata[yy];
1.1 nicm 380: for (xx = px; xx < px + nx; xx++) {
1.21 nicm 381: udata = NULL;
382:
383: if (xx >= gl->cellsize || yy >= gd->hsize + gd->sy)
1.1 nicm 384: gc = &grid_default_cell;
1.21 nicm 385: else {
386: gc = &gl->celldata[xx];
387: if (gc->flags & GRID_FLAG_UTF8)
388: udata = gl->utf8data[xx].data;
1.1 nicm 389: }
390:
391: screen_write_cell(ctx, gc, udata);
392: }
393: cy++;
394: screen_write_cursormove(ctx, cx, cy);
395: }
396: }
397:
1.17 nicm 398: /* Set up context for TTY command. */
1.1 nicm 399: void
1.17 nicm 400: screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
1.1 nicm 401: {
402: struct screen *s = ctx->s;
403:
1.17 nicm 404: ttyctx->wp = ctx->wp;
1.1 nicm 405:
1.17 nicm 406: ttyctx->ocx = s->cx;
407: ttyctx->ocy = s->cy;
408:
409: ttyctx->orlower = s->rlower;
410: ttyctx->orupper = s->rupper;
1.1 nicm 411: }
412:
413: /* Cursor up by ny. */
414: void
415: screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
416: {
417: struct screen *s = ctx->s;
418:
419: if (ny == 0)
420: ny = 1;
421:
1.12 nicm 422: if (s->cy < s->rupper) {
423: /* Above region. */
424: if (ny > s->cy)
425: ny = s->cy;
426: } else {
427: /* Below region. */
428: if (ny > s->cy - s->rupper)
429: ny = s->cy - s->rupper;
430: }
1.1 nicm 431: if (ny == 0)
432: return;
433:
434: s->cy -= ny;
435: }
436:
437: /* Cursor down by ny. */
438: void
439: screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
440: {
441: struct screen *s = ctx->s;
442:
443: if (ny == 0)
444: ny = 1;
445:
1.12 nicm 446: if (s->cy > s->rlower) {
447: /* Below region. */
448: if (ny > screen_size_y(s) - 1 - s->cy)
449: ny = screen_size_y(s) - 1 - s->cy;
450: } else {
451: /* Above region. */
452: if (ny > s->rlower - s->cy)
453: ny = s->rlower - s->cy;
454: }
1.1 nicm 455: if (ny == 0)
456: return;
457:
458: s->cy += ny;
459: }
460:
461: /* Cursor right by nx. */
462: void
463: screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
464: {
465: struct screen *s = ctx->s;
466:
467: if (nx == 0)
468: nx = 1;
469:
470: if (nx > screen_size_x(s) - 1 - s->cx)
471: nx = screen_size_x(s) - 1 - s->cx;
472: if (nx == 0)
473: return;
474:
475: s->cx += nx;
476: }
477:
478: /* Cursor left by nx. */
479: void
480: screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
481: {
482: struct screen *s = ctx->s;
483:
484: if (nx == 0)
485: nx = 1;
486:
487: if (nx > s->cx)
488: nx = s->cx;
489: if (nx == 0)
490: return;
491:
492: s->cx -= nx;
1.5 nicm 493: }
494:
495: /* VT100 alignment test. */
496: void
497: screen_write_alignmenttest(struct screen_write_ctx *ctx)
498: {
499: struct screen *s = ctx->s;
1.17 nicm 500: struct tty_ctx ttyctx;
1.5 nicm 501: struct grid_cell gc;
502: u_int xx, yy;
503:
1.17 nicm 504: screen_write_initctx(ctx, &ttyctx);
505:
1.5 nicm 506: memcpy(&gc, &grid_default_cell, sizeof gc);
507: gc.data = 'E';
1.7 ray 508:
1.5 nicm 509: for (yy = 0; yy < screen_size_y(s); yy++) {
510: for (xx = 0; xx < screen_size_x(s); xx++)
511: grid_view_set_cell(s->grid, xx, yy, &gc);
512: }
1.7 ray 513:
1.5 nicm 514: s->cx = 0;
515: s->cy = 0;
516:
517: s->rupper = 0;
518: s->rlower = screen_size_y(s) - 1;
519:
1.17 nicm 520: tty_write(tty_cmd_alignmenttest, &ttyctx);
1.1 nicm 521: }
522:
523: /* Insert nx characters. */
524: void
525: screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx)
526: {
527: struct screen *s = ctx->s;
1.17 nicm 528: struct tty_ctx ttyctx;
1.1 nicm 529:
530: if (nx == 0)
531: nx = 1;
532:
1.9 nicm 533: if (nx > screen_size_x(s) - s->cx)
534: nx = screen_size_x(s) - s->cx;
1.1 nicm 535: if (nx == 0)
536: return;
537:
1.17 nicm 538: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 539:
540: if (s->cx <= screen_size_x(s) - 1)
541: grid_view_insert_cells(s->grid, s->cx, s->cy, nx);
542:
1.17 nicm 543: ttyctx.num = nx;
544: tty_write(tty_cmd_insertcharacter, &ttyctx);
1.1 nicm 545: }
546:
547: /* Delete nx characters. */
548: void
549: screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx)
550: {
551: struct screen *s = ctx->s;
1.17 nicm 552: struct tty_ctx ttyctx;
1.1 nicm 553:
554: if (nx == 0)
555: nx = 1;
556:
1.9 nicm 557: if (nx > screen_size_x(s) - s->cx)
558: nx = screen_size_x(s) - s->cx;
1.1 nicm 559: if (nx == 0)
560: return;
561:
1.17 nicm 562: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 563:
564: if (s->cx <= screen_size_x(s) - 1)
565: grid_view_delete_cells(s->grid, s->cx, s->cy, nx);
566:
1.17 nicm 567: ttyctx.num = nx;
568: tty_write(tty_cmd_deletecharacter, &ttyctx);
1.1 nicm 569: }
570:
571: /* Insert ny lines. */
572: void
573: screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
574: {
575: struct screen *s = ctx->s;
1.17 nicm 576: struct tty_ctx ttyctx;
1.1 nicm 577:
578: if (ny == 0)
579: ny = 1;
580:
1.11 nicm 581: if (s->cy < s->rupper || s->cy > s->rlower) {
582: if (ny > screen_size_y(s) - s->cy)
583: ny = screen_size_y(s) - s->cy;
584: if (ny == 0)
585: return;
586:
1.17 nicm 587: screen_write_initctx(ctx, &ttyctx);
1.11 nicm 588:
589: grid_view_insert_lines(s->grid, s->cy, ny);
590:
1.17 nicm 591: ttyctx.num = ny;
592: tty_write(tty_cmd_insertline, &ttyctx);
1.11 nicm 593: return;
594: }
595:
596: if (ny > s->rlower + 1 - s->cy)
597: ny = s->rlower + 1 - s->cy;
1.1 nicm 598: if (ny == 0)
599: return;
1.11 nicm 600:
1.17 nicm 601: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 602:
603: if (s->cy < s->rupper || s->cy > s->rlower)
604: grid_view_insert_lines(s->grid, s->cy, ny);
1.10 nicm 605: else
606: grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny);
1.1 nicm 607:
1.17 nicm 608: ttyctx.num = ny;
609: tty_write(tty_cmd_insertline, &ttyctx);
1.1 nicm 610: }
611:
612: /* Delete ny lines. */
613: void
614: screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
615: {
616: struct screen *s = ctx->s;
1.17 nicm 617: struct tty_ctx ttyctx;
1.1 nicm 618:
619: if (ny == 0)
620: ny = 1;
621:
1.11 nicm 622: if (s->cy < s->rupper || s->cy > s->rlower) {
623: if (ny > screen_size_y(s) - s->cy)
624: ny = screen_size_y(s) - s->cy;
625: if (ny == 0)
626: return;
627:
1.17 nicm 628: screen_write_initctx(ctx, &ttyctx);
1.11 nicm 629:
630: grid_view_delete_lines(s->grid, s->cy, ny);
631:
1.17 nicm 632: ttyctx.num = ny;
633: tty_write(tty_cmd_deleteline, &ttyctx);
1.11 nicm 634: return;
635: }
636:
637: if (ny > s->rlower + 1 - s->cy)
638: ny = s->rlower + 1 - s->cy;
1.1 nicm 639: if (ny == 0)
640: return;
641:
1.17 nicm 642: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 643:
644: if (s->cy < s->rupper || s->cy > s->rlower)
645: grid_view_delete_lines(s->grid, s->cy, ny);
1.10 nicm 646: else
647: grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny);
1.1 nicm 648:
1.17 nicm 649: ttyctx.num = ny;
650: tty_write(tty_cmd_deleteline, &ttyctx);
1.1 nicm 651: }
652:
653: /* Clear line at cursor. */
654: void
655: screen_write_clearline(struct screen_write_ctx *ctx)
656: {
657: struct screen *s = ctx->s;
1.17 nicm 658: struct tty_ctx ttyctx;
1.1 nicm 659:
1.17 nicm 660: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 661:
662: grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1);
663:
1.17 nicm 664: tty_write(tty_cmd_clearline, &ttyctx);
1.1 nicm 665: }
666:
667: /* Clear to end of line from cursor. */
668: void
669: screen_write_clearendofline(struct screen_write_ctx *ctx)
670: {
671: struct screen *s = ctx->s;
1.17 nicm 672: struct tty_ctx ttyctx;
1.1 nicm 673: u_int sx;
674:
1.17 nicm 675: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 676:
677: sx = screen_size_x(s);
678:
679: if (s->cx <= sx - 1)
680: grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
681:
1.17 nicm 682: tty_write(tty_cmd_clearendofline, &ttyctx);
1.1 nicm 683: }
684:
685: /* Clear to start of line from cursor. */
686: void
687: screen_write_clearstartofline(struct screen_write_ctx *ctx)
688: {
689: struct screen *s = ctx->s;
1.17 nicm 690: struct tty_ctx ttyctx;
1.1 nicm 691: u_int sx;
692:
1.17 nicm 693: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 694:
695: sx = screen_size_x(s);
696:
697: if (s->cx > sx - 1)
698: grid_view_clear(s->grid, 0, s->cy, sx, 1);
699: else
700: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
701:
1.17 nicm 702: tty_write(tty_cmd_clearstartofline, &ttyctx);
1.1 nicm 703: }
704:
705: /* Move cursor to px,py. */
706: void
707: screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
708: {
709: struct screen *s = ctx->s;
710:
711: if (px > screen_size_x(s) - 1)
712: px = screen_size_x(s) - 1;
713: if (py > screen_size_y(s) - 1)
714: py = screen_size_y(s) - 1;
715:
716: s->cx = px;
717: s->cy = py;
718: }
719:
720: /* Set cursor mode. */
721: void
722: screen_write_cursormode(struct screen_write_ctx *ctx, int state)
723: {
724: struct screen *s = ctx->s;
725:
726: if (state)
727: s->mode |= MODE_CURSOR;
728: else
729: s->mode &= ~MODE_CURSOR;
730: }
731:
732: /* Reverse index (up with scroll). */
733: void
734: screen_write_reverseindex(struct screen_write_ctx *ctx)
735: {
736: struct screen *s = ctx->s;
1.17 nicm 737: struct tty_ctx ttyctx;
1.1 nicm 738:
1.17 nicm 739: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 740:
741: if (s->cy == s->rupper)
742: grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
743: else if (s->cy > 0)
744: s->cy--;
745:
1.17 nicm 746: tty_write(tty_cmd_reverseindex, &ttyctx);
1.1 nicm 747: }
748:
749: /* Set scroll region. */
750: void
751: screen_write_scrollregion(
752: struct screen_write_ctx *ctx, u_int rupper, u_int rlower)
753: {
754: struct screen *s = ctx->s;
755:
756: if (rupper > screen_size_y(s) - 1)
757: rupper = screen_size_y(s) - 1;
758: if (rlower > screen_size_y(s) - 1)
759: rlower = screen_size_y(s) - 1;
1.13 nicm 760: if (rupper >= rlower) /* cannot be one line */
1.1 nicm 761: return;
762:
763: /* Cursor moves to top-left. */
764: s->cx = 0;
765: s->cy = 0;
766:
767: s->rupper = rupper;
768: s->rlower = rlower;
769: }
770:
771: /* Set insert mode. */
772: void
773: screen_write_insertmode(struct screen_write_ctx *ctx, int state)
774: {
775: struct screen *s = ctx->s;
776:
777: if (state)
778: s->mode |= MODE_INSERT;
779: else
780: s->mode &= ~MODE_INSERT;
781: }
782:
783: /* Set mouse mode. */
784: void
785: screen_write_mousemode(struct screen_write_ctx *ctx, int state)
786: {
787: struct screen *s = ctx->s;
788:
789: if (state)
790: s->mode |= MODE_MOUSE;
791: else
792: s->mode &= ~MODE_MOUSE;
793: }
794:
795: /* Line feed (down with scroll). */
796: void
1.20 nicm 797: screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
1.1 nicm 798: {
1.20 nicm 799: struct screen *s = ctx->s;
800: struct grid_line *gl;
801: struct tty_ctx ttyctx;
1.1 nicm 802:
1.17 nicm 803: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 804:
1.20 nicm 805: gl = &s->grid->linedata[s->grid->hsize + s->cy];
806: if (wrapped)
807: gl->flags |= GRID_LINE_WRAPPED;
808: else
809: gl->flags &= ~GRID_LINE_WRAPPED;
810:
1.1 nicm 811: if (s->cy == s->rlower)
812: grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
813: else if (s->cy < screen_size_y(s) - 1)
814: s->cy++;
815:
1.17 nicm 816: tty_write(tty_cmd_linefeed, &ttyctx);
1.1 nicm 817: }
818:
819: /* Carriage return (cursor to start of line). */
820: void
821: screen_write_carriagereturn(struct screen_write_ctx *ctx)
822: {
823: struct screen *s = ctx->s;
824:
825: s->cx = 0;
826: }
827:
828: /* Set keypad cursor keys mode. */
829: void
830: screen_write_kcursormode(struct screen_write_ctx *ctx, int state)
831: {
832: struct screen *s = ctx->s;
833:
834: if (state)
835: s->mode |= MODE_KCURSOR;
836: else
837: s->mode &= ~MODE_KCURSOR;
838: }
839:
840: /* Set keypad number keys mode. */
841: void
842: screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state)
843: {
844: struct screen *s = ctx->s;
845:
846: if (state)
847: s->mode |= MODE_KKEYPAD;
848: else
849: s->mode &= ~MODE_KKEYPAD;
850: }
851:
852: /* Clear to end of screen from cursor. */
853: void
854: screen_write_clearendofscreen(struct screen_write_ctx *ctx)
855: {
856: struct screen *s = ctx->s;
1.17 nicm 857: struct tty_ctx ttyctx;
1.1 nicm 858: u_int sx, sy;
859:
1.17 nicm 860: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 861:
862: sx = screen_size_x(s);
863: sy = screen_size_y(s);
864:
865: if (s->cx <= sx - 1)
866: grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
867: grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1));
868:
1.17 nicm 869: tty_write(tty_cmd_clearendofscreen, &ttyctx);
1.1 nicm 870: }
871:
872: /* Clear to start of screen. */
873: void
874: screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
875: {
876: struct screen *s = ctx->s;
1.17 nicm 877: struct tty_ctx ttyctx;
1.1 nicm 878: u_int sx;
879:
1.17 nicm 880: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 881:
882: sx = screen_size_x(s);
883:
884: if (s->cy > 0)
1.4 nicm 885: grid_view_clear(s->grid, 0, 0, sx, s->cy);
1.1 nicm 886: if (s->cx > sx - 1)
887: grid_view_clear(s->grid, 0, s->cy, sx, 1);
888: else
1.4 nicm 889: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
1.1 nicm 890:
1.17 nicm 891: tty_write(tty_cmd_clearstartofscreen, &ttyctx);
1.1 nicm 892: }
893:
894: /* Clear entire screen. */
895: void
896: screen_write_clearscreen(struct screen_write_ctx *ctx)
897: {
898: struct screen *s = ctx->s;
1.17 nicm 899: struct tty_ctx ttyctx;
1.1 nicm 900:
1.17 nicm 901: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 902:
903: grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s));
904:
1.17 nicm 905: tty_write(tty_cmd_clearscreen, &ttyctx);
1.1 nicm 906: }
907:
908: /* Write cell data. */
909: void
910: screen_write_cell(
911: struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata)
912: {
913: struct screen *s = ctx->s;
914: struct grid *gd = s->grid;
1.15 nicm 915: struct tty_ctx ttyctx;
1.1 nicm 916: struct grid_utf8 gu, *tmp_gu;
917: u_int width, xx, i;
1.18 nicm 918: struct grid_cell tmp_gc, tmp_gc2, *tmp_gcp;
1.6 nicm 919: int insert = 0;
1.1 nicm 920:
921: /* Ignore padding. */
922: if (gc->flags & GRID_FLAG_PADDING)
923: return;
924:
925: /* Find character width. */
926: if (gc->flags & GRID_FLAG_UTF8) {
927: width = utf8_width(udata);
928:
929: gu.width = width;
930: memcpy(&gu.data, udata, sizeof gu.data);
931: } else
932: width = 1;
933:
934: /* If the width is zero, combine onto the previous character. */
935: if (width == 0) {
936: if (s->cx == 0)
937: return;
1.18 nicm 938: tmp_gcp = grid_view_get_cell(gd, s->cx - 1, s->cy);
939: if (!(tmp_gcp->flags & GRID_FLAG_UTF8)) {
940: tmp_gcp->flags |= GRID_FLAG_UTF8;
1.1 nicm 941: memset(&gu.data, 0xff, sizeof gu.data);
1.18 nicm 942: *gu.data = tmp_gcp->data;
1.1 nicm 943: gu.width = 1;
944: grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu);
945: }
946: tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy);
947:
948: for (i = 0; i < UTF8_SIZE; i++) {
949: if (tmp_gu->data[i] == 0xff)
950: break;
951: }
952: memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i);
953:
954: /* Assume the previous character has just been input. */
1.17 nicm 955: screen_write_initctx(ctx, &ttyctx);
956: ttyctx.ptr = udata;
957: tty_write(tty_cmd_utf8character, &ttyctx);
1.1 nicm 958: return;
959: }
960:
961: /* If the character is wider than the screen, don't print it. */
962: if (width > screen_size_x(s)) {
963: memcpy(&tmp_gc, gc, sizeof tmp_gc);
964: tmp_gc.data = '_';
965: width = 1;
966: gc = &tmp_gc;
967: }
968:
1.6 nicm 969: /* If in insert mode, make space for the cells. */
970: if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) {
971: xx = screen_size_x(s) - s->cx - width;
972: grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx);
973: insert = 1;
974: }
975:
1.20 nicm 976: /* Check this will fit on the current line and wrap if not. */
1.1 nicm 977: if (s->cx > screen_size_x(s) - width) {
978: screen_write_carriagereturn(ctx);
1.20 nicm 979: screen_write_linefeed(ctx, 1);
1.1 nicm 980: }
981:
982: /* Sanity checks. */
983: if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1)
984: return;
985:
986: /* Handle overwriting of UTF-8 characters. */
987: screen_write_overwrite(ctx);
988:
989: /*
990: * If the new character is UTF-8 wide, fill in padding cells. Have
991: * already ensured there is enough room.
992: */
993: for (xx = s->cx + 1; xx < s->cx + width; xx++) {
1.18 nicm 994: tmp_gcp = grid_view_get_cell(gd, xx, s->cy);
995: if (tmp_gcp != NULL)
996: tmp_gcp->flags |= GRID_FLAG_PADDING;
1.1 nicm 997: }
998:
999: /* Set the cell. */
1000: grid_view_set_cell(gd, s->cx, s->cy, gc);
1001: if (gc->flags & GRID_FLAG_UTF8)
1002: grid_view_set_utf8(gd, s->cx, s->cy, &gu);
1003:
1004: /* Move the cursor. */
1.17 nicm 1005: screen_write_initctx(ctx, &ttyctx);
1.1 nicm 1006: s->cx += width;
1007:
1008: /* Draw to the screen if necessary. */
1.17 nicm 1009: if (insert) {
1010: ttyctx.num = width;
1011: tty_write(tty_cmd_insertcharacter, &ttyctx);
1012: }
1.15 nicm 1013: ttyctx.utf8 = &gu;
1.1 nicm 1014: if (screen_check_selection(s, s->cx - width, s->cy)) {
1.18 nicm 1015: memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2);
1016: tmp_gc2.data = gc->data;
1.25 ! nicm 1017: tmp_gc2.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
! 1018: tmp_gc2.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256);
1.18 nicm 1019: ttyctx.cell = &tmp_gc2;
1.16 nicm 1020: tty_write(tty_cmd_cell, &ttyctx);
1.15 nicm 1021: } else {
1022: ttyctx.cell = gc;
1.16 nicm 1023: tty_write(tty_cmd_cell, &ttyctx);
1.15 nicm 1024: }
1.1 nicm 1025: }
1026:
1027: /*
1028: * UTF-8 wide characters are a bit of an annoyance. They take up more than one
1029: * cell on the screen, so following cells must not be drawn by marking them as
1030: * padding.
1031: *
1032: * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
1033: * character, it is necessary to also overwrite any other cells which covered
1034: * by the same character.
1035: */
1036: void
1037: screen_write_overwrite(struct screen_write_ctx *ctx)
1038: {
1039: struct screen *s = ctx->s;
1040: struct grid *gd = s->grid;
1041: const struct grid_cell *gc;
1042: const struct grid_utf8 *gu;
1043: u_int xx;
1044:
1045: gc = grid_view_peek_cell(gd, s->cx, s->cy);
1046: if (gc->flags & GRID_FLAG_PADDING) {
1047: /*
1048: * A padding cell, so clear any following and leading padding
1049: * cells back to the character. Don't overwrite the current
1050: * cell as that happens later anyway.
1051: */
1052: xx = s->cx + 1;
1053: while (--xx > 0) {
1054: gc = grid_view_peek_cell(gd, xx, s->cy);
1055: if (!(gc->flags & GRID_FLAG_PADDING))
1056: break;
1057: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1058: }
1059:
1060: /* Overwrite the character at the start of this padding. */
1061: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1062:
1063: /* Overwrite following padding cells. */
1064: xx = s->cx;
1065: while (++xx < screen_size_x(s)) {
1066: gc = grid_view_peek_cell(gd, xx, s->cy);
1067: if (!(gc->flags & GRID_FLAG_PADDING))
1068: break;
1069: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1070: }
1.22 nicm 1071: } else if (gc->flags & GRID_FLAG_UTF8) {
1072: gu = grid_view_peek_utf8(gd, s->cx, s->cy);
1073: if (gu->width > 1) {
1074: /*
1075: * An UTF-8 wide cell; overwrite following padding cells only.
1076: */
1077: xx = s->cx;
1078: while (++xx < screen_size_x(s)) {
1079: gc = grid_view_peek_cell(gd, xx, s->cy);
1080: if (!(gc->flags & GRID_FLAG_PADDING))
1081: break;
1082: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1083: }
1.1 nicm 1084: }
1085: }
1086: }