diff options
Diffstat (limited to 'screen-write.c')
-rw-r--r-- | screen-write.c | 301 |
1 files changed, 241 insertions, 60 deletions
diff --git a/screen-write.c b/screen-write.c index afa1e96a..9571cbec 100644 --- a/screen-write.c +++ b/screen-write.c @@ -27,8 +27,8 @@ static void screen_write_collect_clear(struct screen_write_ctx *, u_int, u_int); static int screen_write_collect_clear_end(struct screen_write_ctx *, u_int, u_int, u_int); -static int screen_write_collect_clear_start(struct screen_write_ctx *, u_int, - u_int, u_int); +static int screen_write_collect_clear_start(struct screen_write_ctx *, + u_int, u_int, u_int); static void screen_write_collect_scroll(struct screen_write_ctx *); static void screen_write_collect_flush(struct screen_write_ctx *, int, const char *); @@ -101,6 +101,50 @@ screen_write_set_cursor(struct screen_write_ctx *ctx, int cx, int cy) evtimer_add(&w->offset_timer, &tv); } +/* Do a full redraw. */ +static void +screen_write_redraw_cb(const struct tty_ctx *ttyctx) +{ + struct window_pane *wp = ttyctx->arg; + + wp->flags |= PANE_REDRAW; +} + +/* Update context for client. */ +static int +screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c) +{ + struct window_pane *wp = ttyctx->arg; + + if (c->session->curw->window != wp->window) + return (0); + if (wp->layout_cell == NULL) + return (0); + + if (wp->flags & (PANE_REDRAW|PANE_DROP)) + return (-1); + if (c->flags & CLIENT_REDRAWPANES) { + /* + * Redraw is already deferred to redraw another pane - redraw + * this one also when that happens. + */ + log_debug("adding %%%u to deferred redraw", wp->id); + wp->flags |= PANE_REDRAW; + return (-1); + } + + ttyctx->bigger = tty_window_offset(&c->tty, &ttyctx->wox, &ttyctx->woy, + &ttyctx->wsx, &ttyctx->wsy); + + ttyctx->xoff = ttyctx->rxoff = wp->xoff; + ttyctx->yoff = ttyctx->ryoff = wp->yoff; + + if (status_at_line(c) == 0) + ttyctx->yoff += status_line_size(c); + + return (1); +} + /* Set up context for TTY command. */ static void screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, @@ -110,14 +154,35 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, memset(ttyctx, 0, sizeof *ttyctx); - ttyctx->wp = ctx->wp; + if (ctx->wp != NULL) { + tty_default_colours(&ttyctx->defaults, ctx->wp); + ttyctx->palette = ctx->wp->palette; + } else { + memcpy(&ttyctx->defaults, &grid_default_cell, + sizeof ttyctx->defaults); + ttyctx->palette = NULL; + } + + ttyctx->s = s; + ttyctx->sx = screen_size_x(s); + ttyctx->sy = screen_size_y(s); ttyctx->ocx = s->cx; ttyctx->ocy = s->cy; - ttyctx->orlower = s->rlower; ttyctx->orupper = s->rupper; + if (ctx->init_ctx_cb != NULL) + ctx->init_ctx_cb(ctx, ttyctx); + else { + ttyctx->redraw_cb = screen_write_redraw_cb; + if (ctx->wp == NULL) + ttyctx->set_client_cb = NULL; + else + ttyctx->set_client_cb = screen_write_set_client_cb; + ttyctx->arg = ctx->wp; + } + if (ctx->wp != NULL && !ctx->sync && (sync || ctx->wp != ctx->wp->window->active)) { @@ -148,18 +213,13 @@ screen_write_free_list(struct screen *s) free(s->write_list); } -/* Initialize writing with a window. */ -void -screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, - struct screen *s) +/* Set up for writing. */ +static void +screen_write_init(struct screen_write_ctx *ctx, struct screen *s) { memset(ctx, 0, sizeof *ctx); - ctx->wp = wp; - if (wp != NULL && s == NULL) - ctx->s = wp->screen; - else - ctx->s = s; + ctx->s = s; if (ctx->s->write_list == NULL) screen_write_make_list(ctx->s); @@ -167,17 +227,51 @@ screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, ctx->scrolled = 0; ctx->bg = 8; +} + +/* Initialize writing with a pane. */ +void +screen_write_start_pane(struct screen_write_ctx *ctx, struct window_pane *wp, + struct screen *s) +{ + if (s == NULL) + s = wp->screen; + screen_write_init(ctx, s); + ctx->wp = wp; if (log_get_level() != 0) { - if (wp != NULL) { - log_debug("%s: size %ux%u, pane %%%u (at %u,%u)", - __func__, screen_size_x(ctx->s), - screen_size_y(ctx->s), wp->id, wp->xoff, wp->yoff); - } else { - log_debug("%s: size %ux%u, no pane", - __func__, screen_size_x(ctx->s), - screen_size_y(ctx->s)); - } + log_debug("%s: size %ux%u, pane %%%u (at %u,%u)", + __func__, screen_size_x(ctx->s), screen_size_y(ctx->s), + wp->id, wp->xoff, wp->yoff); + } +} + +/* Initialize writing with a callback. */ +void +screen_write_start_callback(struct screen_write_ctx *ctx, struct screen *s, + screen_write_init_ctx_cb cb, void *arg) +{ + screen_write_init(ctx, s); + + ctx->init_ctx_cb = cb; + ctx->arg = arg; + + if (log_get_level() != 0) { + log_debug("%s: size %ux%u, with callback", __func__, + screen_size_x(ctx->s), screen_size_y(ctx->s)); + } +} + + +/* Initialize writing. */ +void +screen_write_start(struct screen_write_ctx *ctx, struct screen *s) +{ + screen_write_init(ctx, s); + + if (log_get_level() != 0) { + log_debug("%s: size %ux%u, no pane", __func__, + screen_size_x(ctx->s), screen_size_y(ctx->s)); } } @@ -266,7 +360,97 @@ screen_write_strlen(const char *fmt, ...) return (size); } -/* Write simple string (no UTF-8 or maximum length). */ +/* Write string wrapped over lines. */ +int +screen_write_text(struct screen_write_ctx *ctx, u_int cx, u_int width, + u_int lines, int more, const struct grid_cell *gcp, const char *fmt, ...) +{ + struct screen *s = ctx->s; + va_list ap; + char *tmp; + u_int cy = s->cy, i, end, next, idx = 0, at, left; + struct utf8_data *text; + struct grid_cell gc; + + memcpy(&gc, gcp, sizeof gc); + + va_start(ap, fmt); + xvasprintf(&tmp, fmt, ap); + va_end(ap); + + text = utf8_fromcstr(tmp); + free(tmp); + + left = (cx + width) - s->cx; + for (;;) { + /* Find the end of what can fit on the line. */ + at = 0; + for (end = idx; text[end].size != 0; end++) { + if (text[end].size == 1 && text[end].data[0] == '\n') + break; + if (at + text[end].width > left) + break; + at += text[end].width; + } + + /* + * If we're on a space, that's the end. If not, walk back to + * try and find one. + */ + if (text[end].size == 0) + next = end; + else if (text[end].size == 1 && text[end].data[0] == '\n') + next = end + 1; + else if (text[end].size == 1 && text[end].data[0] == ' ') + next = end + 1; + else { + for (i = end; i > idx; i--) { + if (text[i].size == 1 && text[i].data[0] == ' ') + break; + } + if (i != idx) { + next = i + 1; + end = i; + } else + next = end; + } + + /* Print the line. */ + for (i = idx; i < end; i++) { + utf8_copy(&gc.data, &text[i]); + screen_write_cell(ctx, &gc); + } + + /* If at the bottom, stop. */ + idx = next; + if (s->cy == cy + lines - 1 || text[idx].size == 0) + break; + + screen_write_cursormove(ctx, cx, s->cy + 1, 0); + left = width; + } + + /* + * Fail if on the last line and there is more to come or at the end, or + * if the text was not entirely consumed. + */ + if ((s->cy == cy + lines - 1 && (!more || s->cx == cx + width)) || + text[idx].size != 0) { + free(text); + return (0); + } + free(text); + + /* + * If no more to come, move to the next line. Otherwise, leave on + * the same line (except if at the end). + */ + if (!more || s->cx == cx + width) + screen_write_cursormove(ctx, cx, s->cy + 1, 0); + return (1); +} + +/* Write simple string (no maximum length). */ void screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp, const char *fmt, ...) @@ -344,44 +528,9 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, free(msg); } -/* Copy from another screen. Assumes target region is big enough. */ -void -screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px, - u_int py, u_int nx, u_int ny, bitstr_t *mbs, const struct grid_cell *mgc) -{ - struct screen *s = ctx->s; - struct grid *gd = src->grid; - struct grid_cell gc; - u_int xx, yy, cx, cy, b; - - if (nx == 0 || ny == 0) - return; - - cx = s->cx; - cy = s->cy; - - for (yy = py; yy < py + ny; yy++) { - for (xx = px; xx < px + nx; xx++) { - grid_get_cell(gd, xx, yy, &gc); - if (mbs != NULL) { - b = (yy * screen_size_x(src)) + xx; - if (bit_test(mbs, b)) { - gc.attr = mgc->attr; - gc.fg = mgc->fg; - gc.bg = mgc->bg; - } - } - if (xx + gc.data.width <= px + nx) - screen_write_cell(ctx, &gc); - } - cy++; - screen_write_set_cursor(ctx, cx, cy); - } -} - /* - * Copy from another screen but without the selection stuff. Also assumes the - * target region is already big enough. + * Copy from another screen but without the selection stuff. Assumes the target + * region is already big enough. */ void screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, @@ -1831,3 +1980,35 @@ screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len) tty_write(tty_cmd_rawstring, &ttyctx); } + +/* Turn alternate screen on. */ +void +screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, + int cursor) +{ + struct tty_ctx ttyctx; + struct window_pane *wp = ctx->wp; + + if (wp != NULL && !options_get_number(wp->options, "alternate-screen")) + return; + screen_alternate_on(ctx->s, gc, cursor); + + screen_write_initctx(ctx, &ttyctx, 1); + ttyctx.redraw_cb(&ttyctx); +} + +/* Turn alternate screen off. */ +void +screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc, + int cursor) +{ + struct tty_ctx ttyctx; + struct window_pane *wp = ctx->wp; + + if (wp != NULL && !options_get_number(wp->options, "alternate-screen")) + return; + screen_alternate_off(ctx->s, gc, cursor); + + screen_write_initctx(ctx, &ttyctx, 1); + ttyctx.redraw_cb(&ttyctx); +} |