Annotation of src/usr.bin/tmux/screen-write.c, Revision 1.13
1.13 ! nicm 1: /* $OpenBSD: screen-write.c,v 1.12 2009/07/09 17:57:11 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:
25: void screen_write_save(struct screen_write_ctx *);
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:
213: /* Save cursor and region positions. */
214: void
215: screen_write_save(struct screen_write_ctx *ctx)
216: {
217: struct screen *s = ctx->s;
218:
219: s->old_cx = s->cx;
220: s->old_cy = s->cy;
221:
222: s->old_rlower = s->rlower;
223: s->old_rupper = s->rupper;
224: }
225:
226: /* Cursor up by ny. */
227: void
228: screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
229: {
230: struct screen *s = ctx->s;
231:
232: if (ny == 0)
233: ny = 1;
234:
1.12 nicm 235: if (s->cy < s->rupper) {
236: /* Above region. */
237: if (ny > s->cy)
238: ny = s->cy;
239: } else {
240: /* Below region. */
241: if (ny > s->cy - s->rupper)
242: ny = s->cy - s->rupper;
243: }
1.1 nicm 244: if (ny == 0)
245: return;
246:
247: s->cy -= ny;
248: }
249:
250: /* Cursor down by ny. */
251: void
252: screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
253: {
254: struct screen *s = ctx->s;
255:
256: if (ny == 0)
257: ny = 1;
258:
1.12 nicm 259: if (s->cy > s->rlower) {
260: /* Below region. */
261: if (ny > screen_size_y(s) - 1 - s->cy)
262: ny = screen_size_y(s) - 1 - s->cy;
263: } else {
264: /* Above region. */
265: if (ny > s->rlower - s->cy)
266: ny = s->rlower - s->cy;
267: }
1.1 nicm 268: if (ny == 0)
269: return;
270:
271: s->cy += ny;
272: }
273:
274: /* Cursor right by nx. */
275: void
276: screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
277: {
278: struct screen *s = ctx->s;
279:
280: if (nx == 0)
281: nx = 1;
282:
283: if (nx > screen_size_x(s) - 1 - s->cx)
284: nx = screen_size_x(s) - 1 - s->cx;
285: if (nx == 0)
286: return;
287:
288: s->cx += nx;
289: }
290:
291: /* Cursor left by nx. */
292: void
293: screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
294: {
295: struct screen *s = ctx->s;
296:
297: if (nx == 0)
298: nx = 1;
299:
300: if (nx > s->cx)
301: nx = s->cx;
302: if (nx == 0)
303: return;
304:
305: s->cx -= nx;
1.5 nicm 306: }
307:
308: /* VT100 alignment test. */
309: void
310: screen_write_alignmenttest(struct screen_write_ctx *ctx)
311: {
312: struct screen *s = ctx->s;
313: struct grid_cell gc;
314: u_int xx, yy;
315:
316: memcpy(&gc, &grid_default_cell, sizeof gc);
317: gc.data = 'E';
1.7 ray 318:
1.5 nicm 319: for (yy = 0; yy < screen_size_y(s); yy++) {
320: for (xx = 0; xx < screen_size_x(s); xx++)
321: grid_view_set_cell(s->grid, xx, yy, &gc);
322: }
1.7 ray 323:
1.5 nicm 324: s->cx = 0;
325: s->cy = 0;
326:
327: s->rupper = 0;
328: s->rlower = screen_size_y(s) - 1;
329:
330: tty_write_cmd(ctx->wp, TTY_ALIGNMENTTEST);
1.1 nicm 331: }
332:
333: /* Insert nx characters. */
334: void
335: screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx)
336: {
337: struct screen *s = ctx->s;
338:
339: if (nx == 0)
340: nx = 1;
341:
1.9 nicm 342: if (nx > screen_size_x(s) - s->cx)
343: nx = screen_size_x(s) - s->cx;
1.1 nicm 344: if (nx == 0)
345: return;
346:
347: screen_write_save(ctx);
348:
349: if (s->cx <= screen_size_x(s) - 1)
350: grid_view_insert_cells(s->grid, s->cx, s->cy, nx);
351:
352: tty_write_cmd(ctx->wp, TTY_INSERTCHARACTER, nx);
353: }
354:
355: /* Delete nx characters. */
356: void
357: screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx)
358: {
359: struct screen *s = ctx->s;
360:
361: if (nx == 0)
362: nx = 1;
363:
1.9 nicm 364: if (nx > screen_size_x(s) - s->cx)
365: nx = screen_size_x(s) - s->cx;
1.1 nicm 366: if (nx == 0)
367: return;
368:
369: screen_write_save(ctx);
370:
371: if (s->cx <= screen_size_x(s) - 1)
372: grid_view_delete_cells(s->grid, s->cx, s->cy, nx);
373:
374: tty_write_cmd(ctx->wp, TTY_DELETECHARACTER, nx);
375: }
376:
377: /* Insert ny lines. */
378: void
379: screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
380: {
381: struct screen *s = ctx->s;
382:
383: if (ny == 0)
384: ny = 1;
385:
1.11 nicm 386: if (s->cy < s->rupper || s->cy > s->rlower) {
387: if (ny > screen_size_y(s) - s->cy)
388: ny = screen_size_y(s) - s->cy;
389: if (ny == 0)
390: return;
391:
392: screen_write_save(ctx);
393:
394: grid_view_insert_lines(s->grid, s->cy, ny);
395:
396: tty_write_cmd(ctx->wp, TTY_INSERTLINE, ny);
397: return;
398: }
399:
400: if (ny > s->rlower + 1 - s->cy)
401: ny = s->rlower + 1 - s->cy;
1.1 nicm 402: if (ny == 0)
403: return;
1.11 nicm 404:
1.1 nicm 405: screen_write_save(ctx);
406:
407: if (s->cy < s->rupper || s->cy > s->rlower)
408: grid_view_insert_lines(s->grid, s->cy, ny);
1.10 nicm 409: else
410: grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny);
1.1 nicm 411:
412: tty_write_cmd(ctx->wp, TTY_INSERTLINE, ny);
413: }
414:
415: /* Delete ny lines. */
416: void
417: screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
418: {
419: struct screen *s = ctx->s;
420:
421: if (ny == 0)
422: ny = 1;
423:
1.11 nicm 424: if (s->cy < s->rupper || s->cy > s->rlower) {
425: if (ny > screen_size_y(s) - s->cy)
426: ny = screen_size_y(s) - s->cy;
427: if (ny == 0)
428: return;
429:
430: screen_write_save(ctx);
431:
432: grid_view_delete_lines(s->grid, s->cy, ny);
433:
434: tty_write_cmd(ctx->wp, TTY_DELETELINE, ny);
435: return;
436: }
437:
438: if (ny > s->rlower + 1 - s->cy)
439: ny = s->rlower + 1 - s->cy;
1.1 nicm 440: if (ny == 0)
441: return;
442:
443: screen_write_save(ctx);
444:
445: if (s->cy < s->rupper || s->cy > s->rlower)
446: grid_view_delete_lines(s->grid, s->cy, ny);
1.10 nicm 447: else
448: grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny);
1.1 nicm 449:
450: tty_write_cmd(ctx->wp, TTY_DELETELINE, ny);
451: }
452:
453: /* Clear line at cursor. */
454: void
455: screen_write_clearline(struct screen_write_ctx *ctx)
456: {
457: struct screen *s = ctx->s;
458:
459: screen_write_save(ctx);
460:
461: grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1);
462:
463: tty_write_cmd(ctx->wp, TTY_CLEARLINE);
464: }
465:
466: /* Clear to end of line from cursor. */
467: void
468: screen_write_clearendofline(struct screen_write_ctx *ctx)
469: {
470: struct screen *s = ctx->s;
471: u_int sx;
472:
473: screen_write_save(ctx);
474:
475: sx = screen_size_x(s);
476:
477: if (s->cx <= sx - 1)
478: grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
479:
480: tty_write_cmd(ctx->wp, TTY_CLEARENDOFLINE);
481: }
482:
483: /* Clear to start of line from cursor. */
484: void
485: screen_write_clearstartofline(struct screen_write_ctx *ctx)
486: {
487: struct screen *s = ctx->s;
488: u_int sx;
489:
490: screen_write_save(ctx);
491:
492: sx = screen_size_x(s);
493:
494: if (s->cx > sx - 1)
495: grid_view_clear(s->grid, 0, s->cy, sx, 1);
496: else
497: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
498:
499: tty_write_cmd(ctx->wp, TTY_CLEARSTARTOFLINE);
500: }
501:
502: /* Move cursor to px,py. */
503: void
504: screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
505: {
506: struct screen *s = ctx->s;
507:
508: if (px > screen_size_x(s) - 1)
509: px = screen_size_x(s) - 1;
510: if (py > screen_size_y(s) - 1)
511: py = screen_size_y(s) - 1;
512:
513: s->cx = px;
514: s->cy = py;
515: }
516:
517: /* Set cursor mode. */
518: void
519: screen_write_cursormode(struct screen_write_ctx *ctx, int state)
520: {
521: struct screen *s = ctx->s;
522:
523: if (state)
524: s->mode |= MODE_CURSOR;
525: else
526: s->mode &= ~MODE_CURSOR;
527: }
528:
529: /* Reverse index (up with scroll). */
530: void
531: screen_write_reverseindex(struct screen_write_ctx *ctx)
532: {
533: struct screen *s = ctx->s;
534:
535: screen_write_save(ctx);
536:
537: if (s->cy == s->rupper)
538: grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
539: else if (s->cy > 0)
540: s->cy--;
541:
542: tty_write_cmd(ctx->wp, TTY_REVERSEINDEX);
543: }
544:
545: /* Set scroll region. */
546: void
547: screen_write_scrollregion(
548: struct screen_write_ctx *ctx, u_int rupper, u_int rlower)
549: {
550: struct screen *s = ctx->s;
551:
552: if (rupper > screen_size_y(s) - 1)
553: rupper = screen_size_y(s) - 1;
554: if (rlower > screen_size_y(s) - 1)
555: rlower = screen_size_y(s) - 1;
1.13 ! nicm 556: if (rupper >= rlower) /* cannot be one line */
1.1 nicm 557: return;
558:
559: /* Cursor moves to top-left. */
560: s->cx = 0;
561: s->cy = 0;
562:
563: s->rupper = rupper;
564: s->rlower = rlower;
565: }
566:
567: /* Set insert mode. */
568: void
569: screen_write_insertmode(struct screen_write_ctx *ctx, int state)
570: {
571: struct screen *s = ctx->s;
572:
573: if (state)
574: s->mode |= MODE_INSERT;
575: else
576: s->mode &= ~MODE_INSERT;
577: }
578:
579: /* Set mouse mode. */
580: void
581: screen_write_mousemode(struct screen_write_ctx *ctx, int state)
582: {
583: struct screen *s = ctx->s;
584:
585: if (state)
586: s->mode |= MODE_MOUSE;
587: else
588: s->mode &= ~MODE_MOUSE;
589: }
590:
591: /* Line feed (down with scroll). */
592: void
593: screen_write_linefeed(struct screen_write_ctx *ctx)
594: {
595: struct screen *s = ctx->s;
596:
597: screen_write_save(ctx);
598:
599: if (s->cy == s->rlower)
600: grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
601: else if (s->cy < screen_size_y(s) - 1)
602: s->cy++;
603:
604: tty_write_cmd(ctx->wp, TTY_LINEFEED);
605: }
606:
607: /* Carriage return (cursor to start of line). */
608: void
609: screen_write_carriagereturn(struct screen_write_ctx *ctx)
610: {
611: struct screen *s = ctx->s;
612:
613: s->cx = 0;
614: }
615:
616: /* Set keypad cursor keys mode. */
617: void
618: screen_write_kcursormode(struct screen_write_ctx *ctx, int state)
619: {
620: struct screen *s = ctx->s;
621:
622: if (state)
623: s->mode |= MODE_KCURSOR;
624: else
625: s->mode &= ~MODE_KCURSOR;
626: }
627:
628: /* Set keypad number keys mode. */
629: void
630: screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state)
631: {
632: struct screen *s = ctx->s;
633:
634: if (state)
635: s->mode |= MODE_KKEYPAD;
636: else
637: s->mode &= ~MODE_KKEYPAD;
638: }
639:
640: /* Clear to end of screen from cursor. */
641: void
642: screen_write_clearendofscreen(struct screen_write_ctx *ctx)
643: {
644: struct screen *s = ctx->s;
645: u_int sx, sy;
646:
647: screen_write_save(ctx);
648:
649: sx = screen_size_x(s);
650: sy = screen_size_y(s);
651:
652: if (s->cx <= sx - 1)
653: grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
654: grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1));
655:
656: tty_write_cmd(ctx->wp, TTY_CLEARENDOFSCREEN);
657: }
658:
659: /* Clear to start of screen. */
660: void
661: screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
662: {
663: struct screen *s = ctx->s;
664: u_int sx;
665:
666: screen_write_save(ctx);
667:
668: sx = screen_size_x(s);
669:
670: if (s->cy > 0)
1.4 nicm 671: grid_view_clear(s->grid, 0, 0, sx, s->cy);
1.1 nicm 672: if (s->cx > sx - 1)
673: grid_view_clear(s->grid, 0, s->cy, sx, 1);
674: else
1.4 nicm 675: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
1.1 nicm 676:
677: tty_write_cmd(ctx->wp, TTY_CLEARSTARTOFSCREEN);
678: }
679:
680: /* Clear entire screen. */
681: void
682: screen_write_clearscreen(struct screen_write_ctx *ctx)
683: {
684: struct screen *s = ctx->s;
685:
686: screen_write_save(ctx);
687:
688: grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s));
689:
690: tty_write_cmd(ctx->wp, TTY_CLEARSCREEN);
691: }
692:
693: /* Write cell data. */
694: void
695: screen_write_cell(
696: struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata)
697: {
698: struct screen *s = ctx->s;
699: struct grid *gd = s->grid;
700: struct grid_utf8 gu, *tmp_gu;
701: u_int width, xx, i;
702: struct grid_cell tmp_gc, *tmp_gc2;
703: size_t size;
1.6 nicm 704: int insert = 0;
1.1 nicm 705:
706: /* Ignore padding. */
707: if (gc->flags & GRID_FLAG_PADDING)
708: return;
709:
710: /* Find character width. */
711: if (gc->flags & GRID_FLAG_UTF8) {
712: width = utf8_width(udata);
713:
714: gu.width = width;
715: memcpy(&gu.data, udata, sizeof gu.data);
716: } else
717: width = 1;
718:
719: /* If the width is zero, combine onto the previous character. */
720: if (width == 0) {
721: if (s->cx == 0)
722: return;
723: tmp_gc2 = grid_view_get_cell(gd, s->cx - 1, s->cy);
724: if (!(tmp_gc2->flags & GRID_FLAG_UTF8)) {
725: tmp_gc2->flags |= GRID_FLAG_UTF8;
726: memset(&gu.data, 0xff, sizeof gu.data);
727: *gu.data = tmp_gc2->data;
728: gu.width = 1;
729: grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu);
730: }
731: tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy);
732:
733: for (i = 0; i < UTF8_SIZE; i++) {
734: if (tmp_gu->data[i] == 0xff)
735: break;
736: }
737: memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i);
738:
739: /* Assume the previous character has just been input. */
740: for (size = 0; size < UTF8_SIZE; size++) {
741: if (udata[size] == 0xff)
742: break;
743: }
744: tty_write_cmd(ctx->wp, TTY_RAW, udata, size);
745: return;
746: }
747:
748: /* If the character is wider than the screen, don't print it. */
749: if (width > screen_size_x(s)) {
750: memcpy(&tmp_gc, gc, sizeof tmp_gc);
751: tmp_gc.data = '_';
752: width = 1;
753: gc = &tmp_gc;
754: }
755:
1.6 nicm 756: /* If in insert mode, make space for the cells. */
757: if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) {
758: xx = screen_size_x(s) - s->cx - width;
759: grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx);
760: insert = 1;
761: }
762:
1.1 nicm 763: /* Check this will fit on the current line; scroll if not. */
764: if (s->cx > screen_size_x(s) - width) {
765: screen_write_carriagereturn(ctx);
766: screen_write_linefeed(ctx);
767: }
768:
769: /* Sanity checks. */
770: if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1)
771: return;
772:
773: /* Handle overwriting of UTF-8 characters. */
774: screen_write_overwrite(ctx);
775:
776: /*
777: * If the new character is UTF-8 wide, fill in padding cells. Have
778: * already ensured there is enough room.
779: */
780: for (xx = s->cx + 1; xx < s->cx + width; xx++) {
781: tmp_gc2 = grid_view_get_cell(gd, xx, s->cy);
782: if (tmp_gc2 != NULL)
783: tmp_gc2->flags |= GRID_FLAG_PADDING;
784: }
785:
786: /* Set the cell. */
787: grid_view_set_cell(gd, s->cx, s->cy, gc);
788: if (gc->flags & GRID_FLAG_UTF8)
789: grid_view_set_utf8(gd, s->cx, s->cy, &gu);
790:
791: /* Move the cursor. */
792: screen_write_save(ctx);
793: s->cx += width;
794:
795: /* Draw to the screen if necessary. */
1.6 nicm 796: if (insert)
797: tty_write_cmd(ctx->wp, TTY_INSERTCHARACTER, width);
1.1 nicm 798: if (screen_check_selection(s, s->cx - width, s->cy)) {
799: s->sel.cell.data = gc->data;
800: tty_write_cmd(ctx->wp, TTY_CELL, &s->sel.cell, &gu);
801: } else
802: tty_write_cmd(ctx->wp, TTY_CELL, gc, &gu);
803: }
804:
805: /*
806: * UTF-8 wide characters are a bit of an annoyance. They take up more than one
807: * cell on the screen, so following cells must not be drawn by marking them as
808: * padding.
809: *
810: * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
811: * character, it is necessary to also overwrite any other cells which covered
812: * by the same character.
813: */
814: void
815: screen_write_overwrite(struct screen_write_ctx *ctx)
816: {
817: struct screen *s = ctx->s;
818: struct grid *gd = s->grid;
819: const struct grid_cell *gc;
820: const struct grid_utf8 *gu;
821: u_int xx;
822:
823: gc = grid_view_peek_cell(gd, s->cx, s->cy);
824: gu = grid_view_peek_utf8(gd, s->cx, s->cy);
825:
826: if (gc->flags & GRID_FLAG_PADDING) {
827: /*
828: * A padding cell, so clear any following and leading padding
829: * cells back to the character. Don't overwrite the current
830: * cell as that happens later anyway.
831: */
832: xx = s->cx + 1;
833: while (--xx > 0) {
834: gc = grid_view_peek_cell(gd, xx, s->cy);
835: if (!(gc->flags & GRID_FLAG_PADDING))
836: break;
837: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
838: }
839:
840: /* Overwrite the character at the start of this padding. */
841: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
842:
843: /* Overwrite following padding cells. */
844: xx = s->cx;
845: while (++xx < screen_size_x(s)) {
846: gc = grid_view_peek_cell(gd, xx, s->cy);
847: if (!(gc->flags & GRID_FLAG_PADDING))
848: break;
849: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
850: }
851: } else if (gc->flags & GRID_FLAG_UTF8 && gu->width > 1) {
852: /*
853: * An UTF-8 wide cell; overwrite following padding cells only.
854: */
855: xx = s->cx;
856: while (++xx < screen_size_x(s)) {
857: gc = grid_view_peek_cell(gd, xx, s->cy);
858: if (!(gc->flags & GRID_FLAG_PADDING))
859: break;
860: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
861: }
862: }
863: }