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