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