aboutsummaryrefslogtreecommitdiff
path: root/screen-write.c
diff options
context:
space:
mode:
Diffstat (limited to 'screen-write.c')
-rw-r--r--screen-write.c301
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);
+}