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