4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
26 static struct screen_write_citem
*screen_write_collect_trim(
27 struct screen_write_ctx
*, u_int
, u_int
, u_int
, int *);
28 static void screen_write_collect_clear(struct screen_write_ctx
*, u_int
,
30 static void screen_write_collect_scroll(struct screen_write_ctx
*, u_int
);
31 static void screen_write_collect_flush(struct screen_write_ctx
*, int,
34 static int screen_write_overwrite(struct screen_write_ctx
*,
35 struct grid_cell
*, u_int
);
36 static const struct grid_cell
*screen_write_combine(struct screen_write_ctx
*,
37 const struct utf8_data
*, u_int
*);
39 struct screen_write_citem
{
43 enum { TEXT
, CLEAR
} type
;
49 TAILQ_ENTRY(screen_write_citem
) entry
;
51 struct screen_write_cline
{
53 TAILQ_HEAD(, screen_write_citem
) items
;
55 TAILQ_HEAD(, screen_write_citem
) screen_write_citem_freelist
=
56 TAILQ_HEAD_INITIALIZER(screen_write_citem_freelist
);
58 static struct screen_write_citem
*
59 screen_write_get_citem(void)
61 struct screen_write_citem
*ci
;
63 ci
= TAILQ_FIRST(&screen_write_citem_freelist
);
65 TAILQ_REMOVE(&screen_write_citem_freelist
, ci
, entry
);
66 memset(ci
, 0, sizeof *ci
);
69 return (xcalloc(1, sizeof *ci
));
73 screen_write_free_citem(struct screen_write_citem
*ci
)
75 TAILQ_INSERT_TAIL(&screen_write_citem_freelist
, ci
, entry
);
79 screen_write_offset_timer(__unused
int fd
, __unused
short events
, void *data
)
81 struct window
*w
= data
;
83 tty_update_window_offset(w
);
86 /* Set cursor position. */
88 screen_write_set_cursor(struct screen_write_ctx
*ctx
, int cx
, int cy
)
90 struct window_pane
*wp
= ctx
->wp
;
92 struct screen
*s
= ctx
->s
;
93 struct timeval tv
= { .tv_usec
= 10000 };
95 if (cx
!= -1 && (u_int
)cx
== s
->cx
&& cy
!= -1 && (u_int
)cy
== s
->cy
)
99 if ((u_int
)cx
> screen_size_x(s
)) /* allow last column */
100 cx
= screen_size_x(s
) - 1;
104 if ((u_int
)cy
> screen_size_y(s
) - 1)
105 cy
= screen_size_y(s
) - 1;
113 if (!event_initialized(&w
->offset_timer
))
114 evtimer_set(&w
->offset_timer
, screen_write_offset_timer
, w
);
115 if (!evtimer_pending(&w
->offset_timer
, NULL
))
116 evtimer_add(&w
->offset_timer
, &tv
);
119 /* Do a full redraw. */
121 screen_write_redraw_cb(const struct tty_ctx
*ttyctx
)
123 struct window_pane
*wp
= ttyctx
->arg
;
126 wp
->flags
|= PANE_REDRAW
;
129 /* Update context for client. */
131 screen_write_set_client_cb(struct tty_ctx
*ttyctx
, struct client
*c
)
133 struct window_pane
*wp
= ttyctx
->arg
;
135 if (c
->session
->curw
->window
!= wp
->window
)
137 if (wp
->layout_cell
== NULL
)
140 if (wp
->flags
& (PANE_REDRAW
|PANE_DROP
))
142 if (c
->flags
& CLIENT_REDRAWPANES
) {
144 * Redraw is already deferred to redraw another pane - redraw
145 * this one also when that happens.
147 log_debug("%s: adding %%%u to deferred redraw", __func__
,
149 wp
->flags
|= PANE_REDRAW
;
153 ttyctx
->bigger
= tty_window_offset(&c
->tty
, &ttyctx
->wox
, &ttyctx
->woy
,
154 &ttyctx
->wsx
, &ttyctx
->wsy
);
156 ttyctx
->xoff
= ttyctx
->rxoff
= wp
->xoff
;
157 ttyctx
->yoff
= ttyctx
->ryoff
= wp
->yoff
;
159 if (status_at_line(c
) == 0)
160 ttyctx
->yoff
+= status_line_size(c
);
165 /* Set up context for TTY command. */
167 screen_write_initctx(struct screen_write_ctx
*ctx
, struct tty_ctx
*ttyctx
,
170 struct screen
*s
= ctx
->s
;
172 memset(ttyctx
, 0, sizeof *ttyctx
);
175 ttyctx
->sx
= screen_size_x(s
);
176 ttyctx
->sy
= screen_size_y(s
);
180 ttyctx
->orlower
= s
->rlower
;
181 ttyctx
->orupper
= s
->rupper
;
183 memcpy(&ttyctx
->defaults
, &grid_default_cell
, sizeof ttyctx
->defaults
);
184 if (ctx
->init_ctx_cb
!= NULL
) {
185 ctx
->init_ctx_cb(ctx
, ttyctx
);
186 if (ttyctx
->palette
!= NULL
) {
187 ttyctx
->defaults
.fg
= ttyctx
->palette
->fg
;
188 ttyctx
->defaults
.bg
= ttyctx
->palette
->bg
;
191 ttyctx
->redraw_cb
= screen_write_redraw_cb
;
192 if (ctx
->wp
!= NULL
) {
193 tty_default_colours(&ttyctx
->defaults
, ctx
->wp
);
194 ttyctx
->palette
= &ctx
->wp
->palette
;
195 ttyctx
->set_client_cb
= screen_write_set_client_cb
;
196 ttyctx
->arg
= ctx
->wp
;
200 if (~ctx
->flags
& SCREEN_WRITE_SYNC
) {
202 * For the active pane or for an overlay (no pane), we want to
203 * only use synchronized updates if requested (commands that
204 * move the cursor); for other panes, always use it, since the
205 * cursor will have to move.
207 if (ctx
->wp
!= NULL
) {
208 if (ctx
->wp
!= ctx
->wp
->window
->active
)
213 ttyctx
->num
= 0x10|sync
;
214 tty_write(tty_cmd_syncstart
, ttyctx
);
215 ctx
->flags
|= SCREEN_WRITE_SYNC
;
219 /* Make write list. */
221 screen_write_make_list(struct screen
*s
)
225 s
->write_list
= xcalloc(screen_size_y(s
), sizeof *s
->write_list
);
226 for (y
= 0; y
< screen_size_y(s
); y
++)
227 TAILQ_INIT(&s
->write_list
[y
].items
);
230 /* Free write list. */
232 screen_write_free_list(struct screen
*s
)
236 for (y
= 0; y
< screen_size_y(s
); y
++)
237 free(s
->write_list
[y
].data
);
241 /* Set up for writing. */
243 screen_write_init(struct screen_write_ctx
*ctx
, struct screen
*s
)
245 memset(ctx
, 0, sizeof *ctx
);
249 if (ctx
->s
->write_list
== NULL
)
250 screen_write_make_list(ctx
->s
);
251 ctx
->item
= screen_write_get_citem();
257 /* Initialize writing with a pane. */
259 screen_write_start_pane(struct screen_write_ctx
*ctx
, struct window_pane
*wp
,
264 screen_write_init(ctx
, s
);
267 if (log_get_level() != 0) {
268 log_debug("%s: size %ux%u, pane %%%u (at %u,%u)",
269 __func__
, screen_size_x(ctx
->s
), screen_size_y(ctx
->s
),
270 wp
->id
, wp
->xoff
, wp
->yoff
);
274 /* Initialize writing with a callback. */
276 screen_write_start_callback(struct screen_write_ctx
*ctx
, struct screen
*s
,
277 screen_write_init_ctx_cb cb
, void *arg
)
279 screen_write_init(ctx
, s
);
281 ctx
->init_ctx_cb
= cb
;
284 if (log_get_level() != 0) {
285 log_debug("%s: size %ux%u, with callback", __func__
,
286 screen_size_x(ctx
->s
), screen_size_y(ctx
->s
));
290 /* Initialize writing. */
292 screen_write_start(struct screen_write_ctx
*ctx
, struct screen
*s
)
294 screen_write_init(ctx
, s
);
296 if (log_get_level() != 0) {
297 log_debug("%s: size %ux%u, no pane", __func__
,
298 screen_size_x(ctx
->s
), screen_size_y(ctx
->s
));
302 /* Finish writing. */
304 screen_write_stop(struct screen_write_ctx
*ctx
)
306 screen_write_collect_end(ctx
);
307 screen_write_collect_flush(ctx
, 0, __func__
);
309 screen_write_free_citem(ctx
->item
);
312 /* Reset screen state. */
314 screen_write_reset(struct screen_write_ctx
*ctx
)
316 struct screen
*s
= ctx
->s
;
318 screen_reset_tabs(s
);
319 screen_write_scrollregion(ctx
, 0, screen_size_y(s
) - 1);
321 s
->mode
= MODE_CURSOR
| MODE_WRAP
;
323 screen_write_clearscreen(ctx
, 8);
324 screen_write_set_cursor(ctx
, 0, 0);
327 /* Write character. */
329 screen_write_putc(struct screen_write_ctx
*ctx
, const struct grid_cell
*gcp
,
334 memcpy(&gc
, gcp
, sizeof gc
);
336 utf8_set(&gc
.data
, ch
);
337 screen_write_cell(ctx
, &gc
);
340 /* Calculate string length. */
342 screen_write_strlen(const char *fmt
, ...)
348 size_t left
, size
= 0;
349 enum utf8_state more
;
352 xvasprintf(&msg
, fmt
, ap
);
356 while (*ptr
!= '\0') {
357 if (*ptr
> 0x7f && utf8_open(&ud
, *ptr
) == UTF8_MORE
) {
361 if (left
< (size_t)ud
.size
- 1)
363 while ((more
= utf8_append(&ud
, *ptr
)) == UTF8_MORE
)
367 if (more
== UTF8_DONE
)
370 if (*ptr
> 0x1f && *ptr
< 0x7f)
380 /* Write string wrapped over lines. */
382 screen_write_text(struct screen_write_ctx
*ctx
, u_int cx
, u_int width
,
383 u_int lines
, int more
, const struct grid_cell
*gcp
, const char *fmt
, ...)
385 struct screen
*s
= ctx
->s
;
388 u_int cy
= s
->cy
, i
, end
, next
, idx
= 0, at
, left
;
389 struct utf8_data
*text
;
392 memcpy(&gc
, gcp
, sizeof gc
);
395 xvasprintf(&tmp
, fmt
, ap
);
398 text
= utf8_fromcstr(tmp
);
401 left
= (cx
+ width
) - s
->cx
;
403 /* Find the end of what can fit on the line. */
405 for (end
= idx
; text
[end
].size
!= 0; end
++) {
406 if (text
[end
].size
== 1 && text
[end
].data
[0] == '\n')
408 if (at
+ text
[end
].width
> left
)
410 at
+= text
[end
].width
;
414 * If we're on a space, that's the end. If not, walk back to
417 if (text
[end
].size
== 0)
419 else if (text
[end
].size
== 1 && text
[end
].data
[0] == '\n')
421 else if (text
[end
].size
== 1 && text
[end
].data
[0] == ' ')
424 for (i
= end
; i
> idx
; i
--) {
425 if (text
[i
].size
== 1 && text
[i
].data
[0] == ' ')
435 /* Print the line. */
436 for (i
= idx
; i
< end
; i
++) {
437 utf8_copy(&gc
.data
, &text
[i
]);
438 screen_write_cell(ctx
, &gc
);
441 /* If at the bottom, stop. */
443 if (s
->cy
== cy
+ lines
- 1 || text
[idx
].size
== 0)
446 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0);
451 * Fail if on the last line and there is more to come or at the end, or
452 * if the text was not entirely consumed.
454 if ((s
->cy
== cy
+ lines
- 1 && (!more
|| s
->cx
== cx
+ width
)) ||
455 text
[idx
].size
!= 0) {
462 * If no more to come, move to the next line. Otherwise, leave on
463 * the same line (except if at the end).
465 if (!more
|| s
->cx
== cx
+ width
)
466 screen_write_cursormove(ctx
, cx
, s
->cy
+ 1, 0);
470 /* Write simple string (no maximum length). */
472 screen_write_puts(struct screen_write_ctx
*ctx
, const struct grid_cell
*gcp
,
473 const char *fmt
, ...)
478 screen_write_vnputs(ctx
, -1, gcp
, fmt
, ap
);
482 /* Write string with length limit (-1 for unlimited). */
484 screen_write_nputs(struct screen_write_ctx
*ctx
, ssize_t maxlen
,
485 const struct grid_cell
*gcp
, const char *fmt
, ...)
490 screen_write_vnputs(ctx
, maxlen
, gcp
, fmt
, ap
);
495 screen_write_vnputs(struct screen_write_ctx
*ctx
, ssize_t maxlen
,
496 const struct grid_cell
*gcp
, const char *fmt
, va_list ap
)
499 struct utf8_data
*ud
= &gc
.data
;
502 size_t left
, size
= 0;
503 enum utf8_state more
;
505 memcpy(&gc
, gcp
, sizeof gc
);
506 xvasprintf(&msg
, fmt
, ap
);
509 while (*ptr
!= '\0') {
510 if (*ptr
> 0x7f && utf8_open(ud
, *ptr
) == UTF8_MORE
) {
514 if (left
< (size_t)ud
->size
- 1)
516 while ((more
= utf8_append(ud
, *ptr
)) == UTF8_MORE
)
520 if (more
!= UTF8_DONE
)
522 if (maxlen
> 0 && size
+ ud
->width
> (size_t)maxlen
) {
523 while (size
< (size_t)maxlen
) {
524 screen_write_putc(ctx
, &gc
, ' ');
530 screen_write_cell(ctx
, &gc
);
532 if (maxlen
> 0 && size
+ 1 > (size_t)maxlen
)
536 gc
.attr
^= GRID_ATTR_CHARSET
;
537 else if (*ptr
== '\n') {
538 screen_write_linefeed(ctx
, 0, 8);
539 screen_write_carriagereturn(ctx
);
540 } else if (*ptr
> 0x1f && *ptr
< 0x7f) {
542 screen_write_putc(ctx
, &gc
, *ptr
);
552 * Copy from another screen but without the selection stuff. Assumes the target
553 * region is already big enough.
556 screen_write_fast_copy(struct screen_write_ctx
*ctx
, struct screen
*src
,
557 u_int px
, u_int py
, u_int nx
, u_int ny
)
559 struct screen
*s
= ctx
->s
;
560 struct grid
*gd
= src
->grid
;
562 u_int xx
, yy
, cx
, cy
;
564 if (nx
== 0 || ny
== 0)
568 for (yy
= py
; yy
< py
+ ny
; yy
++) {
569 if (yy
>= gd
->hsize
+ gd
->sy
)
572 for (xx
= px
; xx
< px
+ nx
; xx
++) {
573 if (xx
>= grid_get_line(gd
, yy
)->cellsize
)
575 grid_get_cell(gd
, xx
, yy
, &gc
);
576 if (xx
+ gc
.data
.width
> px
+ nx
)
578 grid_view_set_cell(ctx
->s
->grid
, cx
, cy
, &gc
);
585 /* Draw a horizontal line on screen. */
587 screen_write_hline(struct screen_write_ctx
*ctx
, u_int nx
, int left
, int right
)
589 struct screen
*s
= ctx
->s
;
596 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
597 gc
.attr
|= GRID_ATTR_CHARSET
;
599 screen_write_putc(ctx
, &gc
, left
? 't' : 'q');
600 for (i
= 1; i
< nx
- 1; i
++)
601 screen_write_putc(ctx
, &gc
, 'q');
602 screen_write_putc(ctx
, &gc
, right
? 'u' : 'q');
604 screen_write_set_cursor(ctx
, cx
, cy
);
607 /* Draw a vertical line on screen. */
609 screen_write_vline(struct screen_write_ctx
*ctx
, u_int ny
, int top
, int bottom
)
611 struct screen
*s
= ctx
->s
;
618 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
619 gc
.attr
|= GRID_ATTR_CHARSET
;
621 screen_write_putc(ctx
, &gc
, top
? 'w' : 'x');
622 for (i
= 1; i
< ny
- 1; i
++) {
623 screen_write_set_cursor(ctx
, cx
, cy
+ i
);
624 screen_write_putc(ctx
, &gc
, 'x');
626 screen_write_set_cursor(ctx
, cx
, cy
+ ny
- 1);
627 screen_write_putc(ctx
, &gc
, bottom
? 'v' : 'x');
629 screen_write_set_cursor(ctx
, cx
, cy
);
632 /* Draw a menu on screen. */
634 screen_write_menu(struct screen_write_ctx
*ctx
, struct menu
*menu
,
635 int choice
, const struct grid_cell
*choice_gc
)
637 struct screen
*s
= ctx
->s
;
638 struct grid_cell default_gc
;
639 const struct grid_cell
*gc
= &default_gc
;
646 memcpy(&default_gc
, &grid_default_cell
, sizeof default_gc
);
648 screen_write_box(ctx
, menu
->width
+ 4, menu
->count
+ 2);
649 screen_write_cursormove(ctx
, cx
+ 2, cy
, 0);
650 format_draw(ctx
, &default_gc
, menu
->width
, menu
->title
, NULL
);
652 for (i
= 0; i
< menu
->count
; i
++) {
653 name
= menu
->items
[i
].name
;
655 screen_write_cursormove(ctx
, cx
, cy
+ 1 + i
, 0);
656 screen_write_hline(ctx
, menu
->width
+ 4, 1, 1);
658 if (choice
>= 0 && i
== (u_int
)choice
&& *name
!= '-')
660 screen_write_cursormove(ctx
, cx
+ 2, cy
+ 1 + i
, 0);
661 for (j
= 0; j
< menu
->width
; j
++)
662 screen_write_putc(ctx
, gc
, ' ');
663 screen_write_cursormove(ctx
, cx
+ 2, cy
+ 1 + i
, 0);
666 default_gc
.attr
|= GRID_ATTR_DIM
;
667 format_draw(ctx
, gc
, menu
->width
, name
, NULL
);
668 default_gc
.attr
&= ~GRID_ATTR_DIM
;
670 format_draw(ctx
, gc
, menu
->width
, name
, NULL
);
675 screen_write_set_cursor(ctx
, cx
, cy
);
678 /* Draw a box on screen. */
680 screen_write_box(struct screen_write_ctx
*ctx
, u_int nx
, u_int ny
)
682 struct screen
*s
= ctx
->s
;
689 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
690 gc
.attr
|= GRID_ATTR_CHARSET
;
691 gc
.flags
|= GRID_FLAG_NOPALETTE
;
693 screen_write_putc(ctx
, &gc
, 'l');
694 for (i
= 1; i
< nx
- 1; i
++)
695 screen_write_putc(ctx
, &gc
, 'q');
696 screen_write_putc(ctx
, &gc
, 'k');
698 screen_write_set_cursor(ctx
, cx
, cy
+ ny
- 1);
699 screen_write_putc(ctx
, &gc
, 'm');
700 for (i
= 1; i
< nx
- 1; i
++)
701 screen_write_putc(ctx
, &gc
, 'q');
702 screen_write_putc(ctx
, &gc
, 'j');
704 for (i
= 1; i
< ny
- 1; i
++) {
705 screen_write_set_cursor(ctx
, cx
, cy
+ i
);
706 screen_write_putc(ctx
, &gc
, 'x');
708 for (i
= 1; i
< ny
- 1; i
++) {
709 screen_write_set_cursor(ctx
, cx
+ nx
- 1, cy
+ i
);
710 screen_write_putc(ctx
, &gc
, 'x');
713 screen_write_set_cursor(ctx
, cx
, cy
);
717 * Write a preview version of a window. Assumes target area is big enough and
721 screen_write_preview(struct screen_write_ctx
*ctx
, struct screen
*src
, u_int nx
,
724 struct screen
*s
= ctx
->s
;
726 u_int cx
, cy
, px
, py
;
732 * If the cursor is on, pick the area around the cursor, otherwise use
735 if (src
->mode
& MODE_CURSOR
) {
741 if (px
+ nx
> screen_size_x(src
)) {
742 if (nx
> screen_size_x(src
))
745 px
= screen_size_x(src
) - nx
;
752 if (py
+ ny
> screen_size_y(src
)) {
753 if (ny
> screen_size_y(src
))
756 py
= screen_size_y(src
) - ny
;
763 screen_write_fast_copy(ctx
, src
, px
, src
->grid
->hsize
+ py
, nx
, ny
);
765 if (src
->mode
& MODE_CURSOR
) {
766 grid_view_get_cell(src
->grid
, src
->cx
, src
->cy
, &gc
);
767 gc
.attr
|= GRID_ATTR_REVERSE
;
768 screen_write_set_cursor(ctx
, cx
+ (src
->cx
- px
),
769 cy
+ (src
->cy
- py
));
770 screen_write_cell(ctx
, &gc
);
776 screen_write_mode_set(struct screen_write_ctx
*ctx
, int mode
)
778 struct screen
*s
= ctx
->s
;
782 if (log_get_level() != 0)
783 log_debug("%s: %s", __func__
, screen_mode_to_string(mode
));
788 screen_write_mode_clear(struct screen_write_ctx
*ctx
, int mode
)
790 struct screen
*s
= ctx
->s
;
794 if (log_get_level() != 0)
795 log_debug("%s: %s", __func__
, screen_mode_to_string(mode
));
798 /* Cursor up by ny. */
800 screen_write_cursorup(struct screen_write_ctx
*ctx
, u_int ny
)
802 struct screen
*s
= ctx
->s
;
803 u_int cx
= s
->cx
, cy
= s
->cy
;
808 if (cy
< s
->rupper
) {
814 if (ny
> cy
- s
->rupper
)
817 if (cx
== screen_size_x(s
))
822 screen_write_set_cursor(ctx
, cx
, cy
);
825 /* Cursor down by ny. */
827 screen_write_cursordown(struct screen_write_ctx
*ctx
, u_int ny
)
829 struct screen
*s
= ctx
->s
;
830 u_int cx
= s
->cx
, cy
= s
->cy
;
835 if (cy
> s
->rlower
) {
837 if (ny
> screen_size_y(s
) - 1 - cy
)
838 ny
= screen_size_y(s
) - 1 - cy
;
841 if (ny
> s
->rlower
- cy
)
844 if (cx
== screen_size_x(s
))
851 screen_write_set_cursor(ctx
, cx
, cy
);
854 /* Cursor right by nx. */
856 screen_write_cursorright(struct screen_write_ctx
*ctx
, u_int nx
)
858 struct screen
*s
= ctx
->s
;
859 u_int cx
= s
->cx
, cy
= s
->cy
;
864 if (nx
> screen_size_x(s
) - 1 - cx
)
865 nx
= screen_size_x(s
) - 1 - cx
;
871 screen_write_set_cursor(ctx
, cx
, cy
);
874 /* Cursor left by nx. */
876 screen_write_cursorleft(struct screen_write_ctx
*ctx
, u_int nx
)
878 struct screen
*s
= ctx
->s
;
879 u_int cx
= s
->cx
, cy
= s
->cy
;
891 screen_write_set_cursor(ctx
, cx
, cy
);
894 /* Backspace; cursor left unless at start of wrapped line when can move up. */
896 screen_write_backspace(struct screen_write_ctx
*ctx
)
898 struct screen
*s
= ctx
->s
;
899 struct grid_line
*gl
;
900 u_int cx
= s
->cx
, cy
= s
->cy
;
905 gl
= grid_get_line(s
->grid
, s
->grid
->hsize
+ cy
- 1);
906 if (gl
->flags
& GRID_LINE_WRAPPED
) {
908 cx
= screen_size_x(s
) - 1;
913 screen_write_set_cursor(ctx
, cx
, cy
);
916 /* VT100 alignment test. */
918 screen_write_alignmenttest(struct screen_write_ctx
*ctx
)
920 struct screen
*s
= ctx
->s
;
921 struct tty_ctx ttyctx
;
925 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
926 utf8_set(&gc
.data
, 'E');
928 for (yy
= 0; yy
< screen_size_y(s
); yy
++) {
929 for (xx
= 0; xx
< screen_size_x(s
); xx
++)
930 grid_view_set_cell(s
->grid
, xx
, yy
, &gc
);
933 screen_write_set_cursor(ctx
, 0, 0);
936 s
->rlower
= screen_size_y(s
) - 1;
938 screen_write_initctx(ctx
, &ttyctx
, 1);
940 screen_write_collect_clear(ctx
, 0, screen_size_y(s
) - 1);
941 tty_write(tty_cmd_alignmenttest
, &ttyctx
);
944 /* Insert nx characters. */
946 screen_write_insertcharacter(struct screen_write_ctx
*ctx
, u_int nx
, u_int bg
)
948 struct screen
*s
= ctx
->s
;
949 struct tty_ctx ttyctx
;
954 if (nx
> screen_size_x(s
) - s
->cx
)
955 nx
= screen_size_x(s
) - s
->cx
;
959 if (s
->cx
> screen_size_x(s
) - 1)
962 screen_write_initctx(ctx
, &ttyctx
, 0);
965 grid_view_insert_cells(s
->grid
, s
->cx
, s
->cy
, nx
, bg
);
967 screen_write_collect_flush(ctx
, 0, __func__
);
969 tty_write(tty_cmd_insertcharacter
, &ttyctx
);
972 /* Delete nx characters. */
974 screen_write_deletecharacter(struct screen_write_ctx
*ctx
, u_int nx
, u_int bg
)
976 struct screen
*s
= ctx
->s
;
977 struct tty_ctx ttyctx
;
982 if (nx
> screen_size_x(s
) - s
->cx
)
983 nx
= screen_size_x(s
) - s
->cx
;
987 if (s
->cx
> screen_size_x(s
) - 1)
990 screen_write_initctx(ctx
, &ttyctx
, 0);
993 grid_view_delete_cells(s
->grid
, s
->cx
, s
->cy
, nx
, bg
);
995 screen_write_collect_flush(ctx
, 0, __func__
);
997 tty_write(tty_cmd_deletecharacter
, &ttyctx
);
1000 /* Clear nx characters. */
1002 screen_write_clearcharacter(struct screen_write_ctx
*ctx
, u_int nx
, u_int bg
)
1004 struct screen
*s
= ctx
->s
;
1005 struct tty_ctx ttyctx
;
1010 if (nx
> screen_size_x(s
) - s
->cx
)
1011 nx
= screen_size_x(s
) - s
->cx
;
1015 if (s
->cx
> screen_size_x(s
) - 1)
1018 screen_write_initctx(ctx
, &ttyctx
, 0);
1021 grid_view_clear(s
->grid
, s
->cx
, s
->cy
, nx
, 1, bg
);
1023 screen_write_collect_flush(ctx
, 0, __func__
);
1025 tty_write(tty_cmd_clearcharacter
, &ttyctx
);
1028 /* Insert ny lines. */
1030 screen_write_insertline(struct screen_write_ctx
*ctx
, u_int ny
, u_int bg
)
1032 struct screen
*s
= ctx
->s
;
1033 struct grid
*gd
= s
->grid
;
1034 struct tty_ctx ttyctx
;
1039 if (s
->cy
< s
->rupper
|| s
->cy
> s
->rlower
) {
1040 if (ny
> screen_size_y(s
) - s
->cy
)
1041 ny
= screen_size_y(s
) - s
->cy
;
1045 screen_write_initctx(ctx
, &ttyctx
, 1);
1048 grid_view_insert_lines(gd
, s
->cy
, ny
, bg
);
1050 screen_write_collect_flush(ctx
, 0, __func__
);
1052 tty_write(tty_cmd_insertline
, &ttyctx
);
1056 if (ny
> s
->rlower
+ 1 - s
->cy
)
1057 ny
= s
->rlower
+ 1 - s
->cy
;
1061 screen_write_initctx(ctx
, &ttyctx
, 1);
1064 if (s
->cy
< s
->rupper
|| s
->cy
> s
->rlower
)
1065 grid_view_insert_lines(gd
, s
->cy
, ny
, bg
);
1067 grid_view_insert_lines_region(gd
, s
->rlower
, s
->cy
, ny
, bg
);
1069 screen_write_collect_flush(ctx
, 0, __func__
);
1072 tty_write(tty_cmd_insertline
, &ttyctx
);
1075 /* Delete ny lines. */
1077 screen_write_deleteline(struct screen_write_ctx
*ctx
, u_int ny
, u_int bg
)
1079 struct screen
*s
= ctx
->s
;
1080 struct grid
*gd
= s
->grid
;
1081 struct tty_ctx ttyctx
;
1086 if (s
->cy
< s
->rupper
|| s
->cy
> s
->rlower
) {
1087 if (ny
> screen_size_y(s
) - s
->cy
)
1088 ny
= screen_size_y(s
) - s
->cy
;
1092 screen_write_initctx(ctx
, &ttyctx
, 1);
1095 grid_view_delete_lines(gd
, s
->cy
, ny
, bg
);
1097 screen_write_collect_flush(ctx
, 0, __func__
);
1099 tty_write(tty_cmd_deleteline
, &ttyctx
);
1103 if (ny
> s
->rlower
+ 1 - s
->cy
)
1104 ny
= s
->rlower
+ 1 - s
->cy
;
1108 screen_write_initctx(ctx
, &ttyctx
, 1);
1111 if (s
->cy
< s
->rupper
|| s
->cy
> s
->rlower
)
1112 grid_view_delete_lines(gd
, s
->cy
, ny
, bg
);
1114 grid_view_delete_lines_region(gd
, s
->rlower
, s
->cy
, ny
, bg
);
1116 screen_write_collect_flush(ctx
, 0, __func__
);
1118 tty_write(tty_cmd_deleteline
, &ttyctx
);
1121 /* Clear line at cursor. */
1123 screen_write_clearline(struct screen_write_ctx
*ctx
, u_int bg
)
1125 struct screen
*s
= ctx
->s
;
1126 struct grid_line
*gl
;
1127 u_int sx
= screen_size_x(s
);
1128 struct screen_write_citem
*ci
= ctx
->item
;
1130 gl
= grid_get_line(s
->grid
, s
->grid
->hsize
+ s
->cy
);
1131 if (gl
->cellsize
== 0 && COLOUR_DEFAULT(bg
))
1134 grid_view_clear(s
->grid
, 0, s
->cy
, sx
, 1, bg
);
1136 screen_write_collect_clear(ctx
, s
->cy
, 1);
1141 TAILQ_INSERT_TAIL(&ctx
->s
->write_list
[s
->cy
].items
, ci
, entry
);
1142 ctx
->item
= screen_write_get_citem();
1145 /* Clear to end of line from cursor. */
1147 screen_write_clearendofline(struct screen_write_ctx
*ctx
, u_int bg
)
1149 struct screen
*s
= ctx
->s
;
1150 struct grid_line
*gl
;
1151 u_int sx
= screen_size_x(s
);
1152 struct screen_write_citem
*ci
= ctx
->item
, *before
;
1155 screen_write_clearline(ctx
, bg
);
1159 gl
= grid_get_line(s
->grid
, s
->grid
->hsize
+ s
->cy
);
1160 if (s
->cx
> sx
- 1 || (s
->cx
>= gl
->cellsize
&& COLOUR_DEFAULT(bg
)))
1163 grid_view_clear(s
->grid
, s
->cx
, s
->cy
, sx
- s
->cx
, 1, bg
);
1165 before
= screen_write_collect_trim(ctx
, s
->cy
, s
->cx
, sx
- s
->cx
, NULL
);
1167 ci
->used
= sx
- s
->cx
;
1171 TAILQ_INSERT_TAIL(&ctx
->s
->write_list
[s
->cy
].items
, ci
, entry
);
1173 TAILQ_INSERT_BEFORE(before
, ci
, entry
);
1174 ctx
->item
= screen_write_get_citem();
1177 /* Clear to start of line from cursor. */
1179 screen_write_clearstartofline(struct screen_write_ctx
*ctx
, u_int bg
)
1181 struct screen
*s
= ctx
->s
;
1182 u_int sx
= screen_size_x(s
);
1183 struct screen_write_citem
*ci
= ctx
->item
, *before
;
1185 if (s
->cx
>= sx
- 1) {
1186 screen_write_clearline(ctx
, bg
);
1191 grid_view_clear(s
->grid
, 0, s
->cy
, sx
, 1, bg
);
1193 grid_view_clear(s
->grid
, 0, s
->cy
, s
->cx
+ 1, 1, bg
);
1195 before
= screen_write_collect_trim(ctx
, s
->cy
, 0, s
->cx
+ 1, NULL
);
1197 ci
->used
= s
->cx
+ 1;
1201 TAILQ_INSERT_TAIL(&ctx
->s
->write_list
[s
->cy
].items
, ci
, entry
);
1203 TAILQ_INSERT_BEFORE(before
, ci
, entry
);
1204 ctx
->item
= screen_write_get_citem();
1207 /* Move cursor to px,py. */
1209 screen_write_cursormove(struct screen_write_ctx
*ctx
, int px
, int py
,
1212 struct screen
*s
= ctx
->s
;
1214 if (origin
&& py
!= -1 && (s
->mode
& MODE_ORIGIN
)) {
1215 if ((u_int
)py
> s
->rlower
- s
->rupper
)
1221 if (px
!= -1 && (u_int
)px
> screen_size_x(s
) - 1)
1222 px
= screen_size_x(s
) - 1;
1223 if (py
!= -1 && (u_int
)py
> screen_size_y(s
) - 1)
1224 py
= screen_size_y(s
) - 1;
1226 log_debug("%s: from %u,%u to %u,%u", __func__
, s
->cx
, s
->cy
, px
, py
);
1227 screen_write_set_cursor(ctx
, px
, py
);
1230 /* Reverse index (up with scroll). */
1232 screen_write_reverseindex(struct screen_write_ctx
*ctx
, u_int bg
)
1234 struct screen
*s
= ctx
->s
;
1235 struct tty_ctx ttyctx
;
1237 if (s
->cy
== s
->rupper
) {
1238 grid_view_scroll_region_down(s
->grid
, s
->rupper
, s
->rlower
, bg
);
1239 screen_write_collect_flush(ctx
, 0, __func__
);
1241 screen_write_initctx(ctx
, &ttyctx
, 1);
1244 tty_write(tty_cmd_reverseindex
, &ttyctx
);
1245 } else if (s
->cy
> 0)
1246 screen_write_set_cursor(ctx
, -1, s
->cy
- 1);
1250 /* Set scroll region. */
1252 screen_write_scrollregion(struct screen_write_ctx
*ctx
, u_int rupper
,
1255 struct screen
*s
= ctx
->s
;
1257 if (rupper
> screen_size_y(s
) - 1)
1258 rupper
= screen_size_y(s
) - 1;
1259 if (rlower
> screen_size_y(s
) - 1)
1260 rlower
= screen_size_y(s
) - 1;
1261 if (rupper
>= rlower
) /* cannot be one line */
1264 screen_write_collect_flush(ctx
, 0, __func__
);
1266 /* Cursor moves to top-left. */
1267 screen_write_set_cursor(ctx
, 0, 0);
1275 screen_write_linefeed(struct screen_write_ctx
*ctx
, int wrapped
, u_int bg
)
1277 struct screen
*s
= ctx
->s
;
1278 struct grid
*gd
= s
->grid
;
1279 struct grid_line
*gl
;
1281 gl
= grid_get_line(gd
, gd
->hsize
+ s
->cy
);
1283 gl
->flags
|= GRID_LINE_WRAPPED
;
1285 log_debug("%s: at %u,%u (region %u-%u)", __func__
, s
->cx
, s
->cy
,
1286 s
->rupper
, s
->rlower
);
1288 if (bg
!= ctx
->bg
) {
1289 screen_write_collect_flush(ctx
, 1, __func__
);
1293 if (s
->cy
== s
->rlower
) {
1294 grid_view_scroll_region_up(gd
, s
->rupper
, s
->rlower
, bg
);
1295 screen_write_collect_scroll(ctx
, bg
);
1297 } else if (s
->cy
< screen_size_y(s
) - 1)
1298 screen_write_set_cursor(ctx
, -1, s
->cy
+ 1);
1303 screen_write_scrollup(struct screen_write_ctx
*ctx
, u_int lines
, u_int bg
)
1305 struct screen
*s
= ctx
->s
;
1306 struct grid
*gd
= s
->grid
;
1311 else if (lines
> s
->rlower
- s
->rupper
+ 1)
1312 lines
= s
->rlower
- s
->rupper
+ 1;
1314 if (bg
!= ctx
->bg
) {
1315 screen_write_collect_flush(ctx
, 1, __func__
);
1319 for (i
= 0; i
< lines
; i
++) {
1320 grid_view_scroll_region_up(gd
, s
->rupper
, s
->rlower
, bg
);
1321 screen_write_collect_scroll(ctx
, bg
);
1323 ctx
->scrolled
+= lines
;
1328 screen_write_scrolldown(struct screen_write_ctx
*ctx
, u_int lines
, u_int bg
)
1330 struct screen
*s
= ctx
->s
;
1331 struct grid
*gd
= s
->grid
;
1332 struct tty_ctx ttyctx
;
1335 screen_write_initctx(ctx
, &ttyctx
, 1);
1340 else if (lines
> s
->rlower
- s
->rupper
+ 1)
1341 lines
= s
->rlower
- s
->rupper
+ 1;
1343 for (i
= 0; i
< lines
; i
++)
1344 grid_view_scroll_region_down(gd
, s
->rupper
, s
->rlower
, bg
);
1346 screen_write_collect_flush(ctx
, 0, __func__
);
1348 tty_write(tty_cmd_scrolldown
, &ttyctx
);
1351 /* Carriage return (cursor to start of line). */
1353 screen_write_carriagereturn(struct screen_write_ctx
*ctx
)
1355 screen_write_set_cursor(ctx
, 0, -1);
1358 /* Clear to end of screen from cursor. */
1360 screen_write_clearendofscreen(struct screen_write_ctx
*ctx
, u_int bg
)
1362 struct screen
*s
= ctx
->s
;
1363 struct grid
*gd
= s
->grid
;
1364 struct tty_ctx ttyctx
;
1365 u_int sx
= screen_size_x(s
), sy
= screen_size_y(s
);
1367 screen_write_initctx(ctx
, &ttyctx
, 1);
1370 /* Scroll into history if it is enabled and clearing entire screen. */
1371 if (s
->cx
== 0 && s
->cy
== 0 && (gd
->flags
& GRID_HISTORY
))
1372 grid_view_clear_history(gd
, bg
);
1374 if (s
->cx
<= sx
- 1)
1375 grid_view_clear(gd
, s
->cx
, s
->cy
, sx
- s
->cx
, 1, bg
);
1376 grid_view_clear(gd
, 0, s
->cy
+ 1, sx
, sy
- (s
->cy
+ 1), bg
);
1379 screen_write_collect_clear(ctx
, s
->cy
+ 1, sy
- (s
->cy
+ 1));
1380 screen_write_collect_flush(ctx
, 0, __func__
);
1381 tty_write(tty_cmd_clearendofscreen
, &ttyctx
);
1384 /* Clear to start of screen. */
1386 screen_write_clearstartofscreen(struct screen_write_ctx
*ctx
, u_int bg
)
1388 struct screen
*s
= ctx
->s
;
1389 struct tty_ctx ttyctx
;
1390 u_int sx
= screen_size_x(s
);
1392 screen_write_initctx(ctx
, &ttyctx
, 1);
1396 grid_view_clear(s
->grid
, 0, 0, sx
, s
->cy
, bg
);
1398 grid_view_clear(s
->grid
, 0, s
->cy
, sx
, 1, bg
);
1400 grid_view_clear(s
->grid
, 0, s
->cy
, s
->cx
+ 1, 1, bg
);
1402 screen_write_collect_clear(ctx
, 0, s
->cy
);
1403 screen_write_collect_flush(ctx
, 0, __func__
);
1404 tty_write(tty_cmd_clearstartofscreen
, &ttyctx
);
1407 /* Clear entire screen. */
1409 screen_write_clearscreen(struct screen_write_ctx
*ctx
, u_int bg
)
1411 struct screen
*s
= ctx
->s
;
1412 struct tty_ctx ttyctx
;
1413 u_int sx
= screen_size_x(s
), sy
= screen_size_y(s
);
1415 screen_write_initctx(ctx
, &ttyctx
, 1);
1418 /* Scroll into history if it is enabled. */
1419 if (s
->grid
->flags
& GRID_HISTORY
)
1420 grid_view_clear_history(s
->grid
, bg
);
1422 grid_view_clear(s
->grid
, 0, 0, sx
, sy
, bg
);
1424 screen_write_collect_clear(ctx
, 0, sy
);
1425 tty_write(tty_cmd_clearscreen
, &ttyctx
);
1428 /* Clear entire history. */
1430 screen_write_clearhistory(struct screen_write_ctx
*ctx
)
1432 grid_clear_history(ctx
->s
->grid
);
1435 /* Force a full redraw. */
1437 screen_write_fullredraw(struct screen_write_ctx
*ctx
)
1439 struct tty_ctx ttyctx
;
1441 screen_write_collect_flush(ctx
, 0, __func__
);
1443 screen_write_initctx(ctx
, &ttyctx
, 1);
1444 ttyctx
.redraw_cb(&ttyctx
);
1447 /* Trim collected items. */
1448 static struct screen_write_citem
*
1449 screen_write_collect_trim(struct screen_write_ctx
*ctx
, u_int y
, u_int x
,
1450 u_int used
, int *wrapped
)
1452 struct screen_write_cline
*cl
= &ctx
->s
->write_list
[y
];
1453 struct screen_write_citem
*ci
, *ci2
, *tmp
, *before
= NULL
;
1454 u_int sx
= x
, ex
= x
+ used
- 1;
1457 if (TAILQ_EMPTY(&cl
->items
))
1459 TAILQ_FOREACH_SAFE(ci
, &cl
->items
, entry
, tmp
) {
1461 cex
= ci
->x
+ ci
->used
- 1;
1463 /* Item is entirely before. */
1465 log_debug("%s: %p %u-%u before %u-%u", __func__
, ci
,
1470 /* Item is entirely after. */
1472 log_debug("%s: %p %u-%u after %u-%u", __func__
, ci
,
1478 /* Item is entirely inside. */
1479 if (csx
>= sx
&& cex
<= ex
) {
1480 log_debug("%s: %p %u-%u inside %u-%u", __func__
, ci
,
1482 TAILQ_REMOVE(&cl
->items
, ci
, entry
);
1483 screen_write_free_citem(ci
);
1484 if (csx
== 0 && ci
->wrapped
&& wrapped
!= NULL
)
1489 /* Item under the start. */
1490 if (csx
< sx
&& cex
>= sx
&& cex
<= ex
) {
1491 log_debug("%s: %p %u-%u start %u-%u", __func__
, ci
,
1493 ci
->used
= sx
- csx
;
1494 log_debug("%s: %p now %u-%u", __func__
, ci
, ci
->x
,
1495 ci
->x
+ ci
->used
+ 1);
1499 /* Item covers the end. */
1500 if (cex
> ex
&& csx
>= sx
&& csx
<= ex
) {
1501 log_debug("%s: %p %u-%u end %u-%u", __func__
, ci
,
1504 ci
->used
= cex
- ex
;
1505 log_debug("%s: %p now %u-%u", __func__
, ci
, ci
->x
,
1506 ci
->x
+ ci
->used
+ 1);
1511 /* Item must cover both sides. */
1512 log_debug("%s: %p %u-%u under %u-%u", __func__
, ci
,
1514 ci2
= screen_write_get_citem();
1515 ci2
->type
= ci
->type
;
1517 memcpy(&ci2
->gc
, &ci
->gc
, sizeof ci2
->gc
);
1518 TAILQ_INSERT_AFTER(&cl
->items
, ci
, ci2
, entry
);
1520 ci
->used
= sx
- csx
;
1522 ci2
->used
= cex
- ex
;
1524 log_debug("%s: %p now %u-%u (%p) and %u-%u (%p)", __func__
, ci
,
1525 ci
->x
, ci
->x
+ ci
->used
- 1, ci
, ci2
->x
,
1526 ci2
->x
+ ci2
->used
- 1, ci2
);
1533 /* Clear collected lines. */
1535 screen_write_collect_clear(struct screen_write_ctx
*ctx
, u_int y
, u_int n
)
1537 struct screen_write_cline
*cl
;
1540 for (i
= y
; i
< y
+ n
; i
++) {
1541 cl
= &ctx
->s
->write_list
[i
];
1542 TAILQ_CONCAT(&screen_write_citem_freelist
, &cl
->items
, entry
);
1546 /* Scroll collected lines up. */
1548 screen_write_collect_scroll(struct screen_write_ctx
*ctx
, u_int bg
)
1550 struct screen
*s
= ctx
->s
;
1551 struct screen_write_cline
*cl
;
1554 struct screen_write_citem
*ci
;
1556 log_debug("%s: at %u,%u (region %u-%u)", __func__
, s
->cx
, s
->cy
,
1557 s
->rupper
, s
->rlower
);
1559 screen_write_collect_clear(ctx
, s
->rupper
, 1);
1560 saved
= ctx
->s
->write_list
[s
->rupper
].data
;
1561 for (y
= s
->rupper
; y
< s
->rlower
; y
++) {
1562 cl
= &ctx
->s
->write_list
[y
+ 1];
1563 TAILQ_CONCAT(&ctx
->s
->write_list
[y
].items
, &cl
->items
, entry
);
1564 ctx
->s
->write_list
[y
].data
= cl
->data
;
1566 ctx
->s
->write_list
[s
->rlower
].data
= saved
;
1568 ci
= screen_write_get_citem();
1570 ci
->used
= screen_size_x(s
);
1573 TAILQ_INSERT_TAIL(&ctx
->s
->write_list
[s
->rlower
].items
, ci
, entry
);
1576 /* Flush collected lines. */
1578 screen_write_collect_flush(struct screen_write_ctx
*ctx
, int scroll_only
,
1581 struct screen
*s
= ctx
->s
;
1582 struct screen_write_citem
*ci
, *tmp
;
1583 struct screen_write_cline
*cl
;
1584 u_int y
, cx
, cy
, last
, items
= 0;
1585 struct tty_ctx ttyctx
;
1587 if (ctx
->scrolled
!= 0) {
1588 log_debug("%s: scrolled %u (region %u-%u)", __func__
,
1589 ctx
->scrolled
, s
->rupper
, s
->rlower
);
1590 if (ctx
->scrolled
> s
->rlower
- s
->rupper
+ 1)
1591 ctx
->scrolled
= s
->rlower
- s
->rupper
+ 1;
1593 screen_write_initctx(ctx
, &ttyctx
, 1);
1594 ttyctx
.num
= ctx
->scrolled
;
1595 ttyctx
.bg
= ctx
->bg
;
1596 tty_write(tty_cmd_scrollup
, &ttyctx
);
1604 cx
= s
->cx
; cy
= s
->cy
;
1605 for (y
= 0; y
< screen_size_y(s
); y
++) {
1606 cl
= &ctx
->s
->write_list
[y
];
1608 TAILQ_FOREACH_SAFE(ci
, &cl
->items
, entry
, tmp
) {
1609 if (last
!= UINT_MAX
&& ci
->x
<= last
) {
1610 fatalx("collect list not in order: %u <= %u",
1613 screen_write_set_cursor(ctx
, ci
->x
, y
);
1614 if (ci
->type
== CLEAR
) {
1615 screen_write_initctx(ctx
, &ttyctx
, 1);
1617 ttyctx
.num
= ci
->used
;
1618 tty_write(tty_cmd_clearcharacter
, &ttyctx
);
1620 screen_write_initctx(ctx
, &ttyctx
, 0);
1621 ttyctx
.cell
= &ci
->gc
;
1622 ttyctx
.wrapped
= ci
->wrapped
;
1623 ttyctx
.ptr
= cl
->data
+ ci
->x
;
1624 ttyctx
.num
= ci
->used
;
1625 tty_write(tty_cmd_cells
, &ttyctx
);
1629 TAILQ_REMOVE(&cl
->items
, ci
, entry
);
1630 screen_write_free_citem(ci
);
1634 s
->cx
= cx
; s
->cy
= cy
;
1636 log_debug("%s: flushed %u items (%s)", __func__
, items
, from
);
1639 /* Finish and store collected cells. */
1641 screen_write_collect_end(struct screen_write_ctx
*ctx
)
1643 struct screen
*s
= ctx
->s
;
1644 struct screen_write_citem
*ci
= ctx
->item
, *before
;
1645 struct screen_write_cline
*cl
= &s
->write_list
[s
->cy
];
1646 struct grid_cell gc
;
1648 int wrapped
= ci
->wrapped
;
1653 before
= screen_write_collect_trim(ctx
, s
->cy
, s
->cx
, ci
->used
,
1656 ci
->wrapped
= wrapped
;
1658 TAILQ_INSERT_TAIL(&cl
->items
, ci
, entry
);
1660 TAILQ_INSERT_BEFORE(before
, ci
, entry
);
1661 ctx
->item
= screen_write_get_citem();
1663 log_debug("%s: %u %.*s (at %u,%u)", __func__
, ci
->used
,
1664 (int)ci
->used
, cl
->data
+ ci
->x
, s
->cx
, s
->cy
);
1667 for (xx
= s
->cx
; xx
> 0; xx
--) {
1668 grid_view_get_cell(s
->grid
, xx
, s
->cy
, &gc
);
1669 if (~gc
.flags
& GRID_FLAG_PADDING
)
1671 grid_view_set_cell(s
->grid
, xx
, s
->cy
,
1672 &grid_default_cell
);
1674 if (gc
.data
.width
> 1) {
1675 grid_view_set_cell(s
->grid
, xx
, s
->cy
,
1676 &grid_default_cell
);
1680 grid_view_set_cells(s
->grid
, s
->cx
, s
->cy
, &ci
->gc
, cl
->data
+ ci
->x
,
1682 screen_write_set_cursor(ctx
, s
->cx
+ ci
->used
, -1);
1684 for (xx
= s
->cx
; xx
< screen_size_x(s
); xx
++) {
1685 grid_view_get_cell(s
->grid
, xx
, s
->cy
, &gc
);
1686 if (~gc
.flags
& GRID_FLAG_PADDING
)
1688 grid_view_set_cell(s
->grid
, xx
, s
->cy
, &grid_default_cell
);
1692 /* Write cell data, collecting if necessary. */
1694 screen_write_collect_add(struct screen_write_ctx
*ctx
,
1695 const struct grid_cell
*gc
)
1697 struct screen
*s
= ctx
->s
;
1698 struct screen_write_citem
*ci
;
1699 u_int sx
= screen_size_x(s
);
1703 * Don't need to check that the attributes and whatnot are still the
1704 * same - input_parse will end the collection when anything that isn't
1705 * a plain character is encountered.
1709 if (gc
->data
.width
!= 1 || gc
->data
.size
!= 1 || *gc
->data
.data
>= 0x7f)
1711 else if (gc
->attr
& GRID_ATTR_CHARSET
)
1713 else if (~s
->mode
& MODE_WRAP
)
1715 else if (s
->mode
& MODE_INSERT
)
1717 else if (s
->sel
!= NULL
)
1720 screen_write_collect_end(ctx
);
1721 screen_write_collect_flush(ctx
, 0, __func__
);
1722 screen_write_cell(ctx
, gc
);
1726 if (s
->cx
> sx
- 1 || ctx
->item
->used
> sx
- 1 - s
->cx
)
1727 screen_write_collect_end(ctx
);
1728 ci
= ctx
->item
; /* may have changed */
1730 if (s
->cx
> sx
- 1) {
1731 log_debug("%s: wrapped at %u,%u", __func__
, s
->cx
, s
->cy
);
1733 screen_write_linefeed(ctx
, 1, 8);
1734 screen_write_set_cursor(ctx
, 0, -1);
1738 memcpy(&ci
->gc
, gc
, sizeof ci
->gc
);
1739 if (ctx
->s
->write_list
[s
->cy
].data
== NULL
)
1740 ctx
->s
->write_list
[s
->cy
].data
= xmalloc(screen_size_x(ctx
->s
));
1741 ctx
->s
->write_list
[s
->cy
].data
[s
->cx
+ ci
->used
++] = gc
->data
.data
[0];
1744 /* Write cell data. */
1746 screen_write_cell(struct screen_write_ctx
*ctx
, const struct grid_cell
*gc
)
1748 struct screen
*s
= ctx
->s
;
1749 struct grid
*gd
= s
->grid
;
1750 const struct utf8_data
*ud
= &gc
->data
;
1751 const struct utf8_data zwj
= { "\342\200\215", 0, 3, 0 };
1752 struct grid_line
*gl
;
1753 struct grid_cell_entry
*gce
;
1754 struct grid_cell tmp_gc
, now_gc
;
1755 struct tty_ctx ttyctx
;
1756 u_int sx
= screen_size_x(s
), sy
= screen_size_y(s
);
1757 u_int width
= gc
->data
.width
, xx
, last
, cx
, cy
;
1758 int selected
, skip
= 1;
1760 /* Ignore padding cells. */
1761 if (gc
->flags
& GRID_FLAG_PADDING
)
1765 * If this is a zero width joiner, set the flag so the next character
1766 * will be treated as zero width and appended. Note that we assume a
1767 * ZWJ will not change the width - the width of the first character is
1770 if (ud
->size
== 3 && memcmp(ud
->data
, "\342\200\215", 3) == 0) {
1771 log_debug("zero width joiner at %u,%u", s
->cx
, s
->cy
);
1772 ctx
->flags
|= SCREEN_WRITE_ZWJ
;
1777 * If the width is zero, combine onto the previous character. We always
1778 * combine with the cell to the left of the cursor position. In theory,
1779 * the application could have moved the cursor somewhere else, but if
1780 * they are silly enough to do that, who cares?
1782 if (ctx
->flags
& SCREEN_WRITE_ZWJ
) {
1783 screen_write_collect_flush(ctx
, 0, __func__
);
1784 screen_write_combine(ctx
, &zwj
, &xx
);
1786 if (width
== 0 || (ctx
->flags
& SCREEN_WRITE_ZWJ
)) {
1787 ctx
->flags
&= ~SCREEN_WRITE_ZWJ
;
1788 screen_write_collect_flush(ctx
, 0, __func__
);
1789 if ((gc
= screen_write_combine(ctx
, ud
, &xx
)) != NULL
) {
1790 cx
= s
->cx
; cy
= s
->cy
;
1791 screen_write_set_cursor(ctx
, xx
, s
->cy
);
1792 screen_write_initctx(ctx
, &ttyctx
, 0);
1794 tty_write(tty_cmd_cell
, &ttyctx
);
1795 s
->cx
= cx
; s
->cy
= cy
;
1800 /* Flush any existing scrolling. */
1801 screen_write_collect_flush(ctx
, 1, __func__
);
1803 /* If this character doesn't fit, ignore it. */
1804 if ((~s
->mode
& MODE_WRAP
) &&
1806 (width
> sx
|| (s
->cx
!= sx
&& s
->cx
> sx
- width
)))
1809 /* If in insert mode, make space for the cells. */
1810 if (s
->mode
& MODE_INSERT
) {
1811 grid_view_insert_cells(s
->grid
, s
->cx
, s
->cy
, width
, 8);
1815 /* Check this will fit on the current line and wrap if not. */
1816 if ((s
->mode
& MODE_WRAP
) && s
->cx
> sx
- width
) {
1817 log_debug("%s: wrapped at %u,%u", __func__
, s
->cx
, s
->cy
);
1818 screen_write_linefeed(ctx
, 1, 8);
1819 screen_write_set_cursor(ctx
, 0, -1);
1820 screen_write_collect_flush(ctx
, 1, __func__
);
1823 /* Sanity check cursor position. */
1824 if (s
->cx
> sx
- width
|| s
->cy
> sy
- 1)
1826 screen_write_initctx(ctx
, &ttyctx
, 0);
1828 /* Handle overwriting of UTF-8 characters. */
1829 gl
= grid_get_line(s
->grid
, s
->grid
->hsize
+ s
->cy
);
1830 if (gl
->flags
& GRID_LINE_EXTENDED
) {
1831 grid_view_get_cell(gd
, s
->cx
, s
->cy
, &now_gc
);
1832 if (screen_write_overwrite(ctx
, &now_gc
, width
))
1837 * If the new character is UTF-8 wide, fill in padding cells. Have
1838 * already ensured there is enough room.
1840 for (xx
= s
->cx
+ 1; xx
< s
->cx
+ width
; xx
++) {
1841 log_debug("%s: new padding at %u,%u", __func__
, xx
, s
->cy
);
1842 grid_view_set_padding(gd
, xx
, s
->cy
);
1846 /* If no change, do not draw. */
1848 if (s
->cx
>= gl
->cellsize
)
1849 skip
= grid_cells_equal(gc
, &grid_default_cell
);
1851 gce
= &gl
->celldata
[s
->cx
];
1852 if (gce
->flags
& GRID_FLAG_EXTENDED
)
1854 else if (gc
->flags
!= gce
->flags
)
1856 else if (gc
->attr
!= gce
->data
.attr
)
1858 else if (gc
->fg
!= gce
->data
.fg
)
1860 else if (gc
->bg
!= gce
->data
.bg
)
1862 else if (gc
->data
.width
!= 1)
1864 else if (gc
->data
.size
!= 1)
1866 else if (gce
->data
.data
!= gc
->data
.data
[0])
1871 /* Update the selected flag and set the cell. */
1872 selected
= screen_check_selection(s
, s
->cx
, s
->cy
);
1873 if (selected
&& (~gc
->flags
& GRID_FLAG_SELECTED
)) {
1874 memcpy(&tmp_gc
, gc
, sizeof tmp_gc
);
1875 tmp_gc
.flags
|= GRID_FLAG_SELECTED
;
1876 grid_view_set_cell(gd
, s
->cx
, s
->cy
, &tmp_gc
);
1877 } else if (!selected
&& (gc
->flags
& GRID_FLAG_SELECTED
)) {
1878 memcpy(&tmp_gc
, gc
, sizeof tmp_gc
);
1879 tmp_gc
.flags
&= ~GRID_FLAG_SELECTED
;
1880 grid_view_set_cell(gd
, s
->cx
, s
->cy
, &tmp_gc
);
1882 grid_view_set_cell(gd
, s
->cx
, s
->cy
, gc
);
1887 * Move the cursor. If not wrapping, stick at the last character and
1890 last
= !(s
->mode
& MODE_WRAP
);
1891 if (s
->cx
<= sx
- last
- width
)
1892 screen_write_set_cursor(ctx
, s
->cx
+ width
, -1);
1894 screen_write_set_cursor(ctx
, sx
- last
, -1);
1896 /* Create space for character in insert mode. */
1897 if (s
->mode
& MODE_INSERT
) {
1898 screen_write_collect_flush(ctx
, 0, __func__
);
1900 tty_write(tty_cmd_insertcharacter
, &ttyctx
);
1903 /* Write to the screen. */
1906 screen_select_cell(s
, &tmp_gc
, gc
);
1907 ttyctx
.cell
= &tmp_gc
;
1910 tty_write(tty_cmd_cell
, &ttyctx
);
1914 /* Combine a UTF-8 zero-width character onto the previous. */
1915 static const struct grid_cell
*
1916 screen_write_combine(struct screen_write_ctx
*ctx
, const struct utf8_data
*ud
,
1919 struct screen
*s
= ctx
->s
;
1920 struct grid
*gd
= s
->grid
;
1921 static struct grid_cell gc
;
1924 /* Can't combine if at 0. */
1928 /* Empty data is out. */
1930 fatalx("UTF-8 data empty");
1932 /* Retrieve the previous cell. */
1933 for (n
= 1; n
<= s
->cx
; n
++) {
1934 grid_view_get_cell(gd
, s
->cx
- n
, s
->cy
, &gc
);
1935 if (~gc
.flags
& GRID_FLAG_PADDING
)
1942 /* Check there is enough space. */
1943 if (gc
.data
.size
+ ud
->size
> sizeof gc
.data
.data
)
1946 log_debug("%s: %.*s onto %.*s at %u,%u", __func__
, (int)ud
->size
,
1947 ud
->data
, (int)gc
.data
.size
, gc
.data
.data
, *xx
, s
->cy
);
1949 /* Append the data. */
1950 memcpy(gc
.data
.data
+ gc
.data
.size
, ud
->data
, ud
->size
);
1951 gc
.data
.size
+= ud
->size
;
1953 /* Set the new cell. */
1954 grid_view_set_cell(gd
, *xx
, s
->cy
, &gc
);
1960 * UTF-8 wide characters are a bit of an annoyance. They take up more than one
1961 * cell on the screen, so following cells must not be drawn by marking them as
1964 * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
1965 * character, it is necessary to also overwrite any other cells which covered
1966 * by the same character.
1969 screen_write_overwrite(struct screen_write_ctx
*ctx
, struct grid_cell
*gc
,
1972 struct screen
*s
= ctx
->s
;
1973 struct grid
*gd
= s
->grid
;
1974 struct grid_cell tmp_gc
;
1978 if (gc
->flags
& GRID_FLAG_PADDING
) {
1980 * A padding cell, so clear any following and leading padding
1981 * cells back to the character. Don't overwrite the current
1982 * cell as that happens later anyway.
1986 grid_view_get_cell(gd
, xx
, s
->cy
, &tmp_gc
);
1987 if (~tmp_gc
.flags
& GRID_FLAG_PADDING
)
1989 log_debug("%s: padding at %u,%u", __func__
, xx
, s
->cy
);
1990 grid_view_set_cell(gd
, xx
, s
->cy
, &grid_default_cell
);
1993 /* Overwrite the character at the start of this padding. */
1994 log_debug("%s: character at %u,%u", __func__
, xx
, s
->cy
);
1995 grid_view_set_cell(gd
, xx
, s
->cy
, &grid_default_cell
);
2000 * Overwrite any padding cells that belong to any UTF-8 characters
2001 * we'll be overwriting with the current character.
2004 gc
->data
.width
!= 1 ||
2005 gc
->flags
& GRID_FLAG_PADDING
) {
2006 xx
= s
->cx
+ width
- 1;
2007 while (++xx
< screen_size_x(s
)) {
2008 grid_view_get_cell(gd
, xx
, s
->cy
, &tmp_gc
);
2009 if (~tmp_gc
.flags
& GRID_FLAG_PADDING
)
2011 log_debug("%s: overwrite at %u,%u", __func__
, xx
,
2013 grid_view_set_cell(gd
, xx
, s
->cy
, &grid_default_cell
);
2021 /* Set external clipboard. */
2023 screen_write_setselection(struct screen_write_ctx
*ctx
, u_char
*str
, u_int len
)
2025 struct tty_ctx ttyctx
;
2027 screen_write_initctx(ctx
, &ttyctx
, 0);
2031 tty_write(tty_cmd_setselection
, &ttyctx
);
2034 /* Write unmodified string. */
2036 screen_write_rawstring(struct screen_write_ctx
*ctx
, u_char
*str
, u_int len
)
2038 struct tty_ctx ttyctx
;
2040 screen_write_initctx(ctx
, &ttyctx
, 0);
2044 tty_write(tty_cmd_rawstring
, &ttyctx
);
2047 /* Turn alternate screen on. */
2049 screen_write_alternateon(struct screen_write_ctx
*ctx
, struct grid_cell
*gc
,
2052 struct tty_ctx ttyctx
;
2053 struct window_pane
*wp
= ctx
->wp
;
2055 if (wp
!= NULL
&& !options_get_number(wp
->options
, "alternate-screen"))
2058 screen_write_collect_flush(ctx
, 0, __func__
);
2059 screen_alternate_on(ctx
->s
, gc
, cursor
);
2061 screen_write_initctx(ctx
, &ttyctx
, 1);
2062 ttyctx
.redraw_cb(&ttyctx
);
2065 /* Turn alternate screen off. */
2067 screen_write_alternateoff(struct screen_write_ctx
*ctx
, struct grid_cell
*gc
,
2070 struct tty_ctx ttyctx
;
2071 struct window_pane
*wp
= ctx
->wp
;
2073 if (wp
!= NULL
&& !options_get_number(wp
->options
, "alternate-screen"))
2076 screen_write_collect_flush(ctx
, 0, __func__
);
2077 screen_alternate_off(ctx
->s
, gc
, cursor
);
2079 screen_write_initctx(ctx
, &ttyctx
, 1);
2080 ttyctx
.redraw_cb(&ttyctx
);