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