diff options
Diffstat (limited to 'screen-write.c')
-rw-r--r-- | screen-write.c | 496 |
1 files changed, 351 insertions, 145 deletions
diff --git a/screen-write.c b/screen-write.c index 6b6a750..6892d04 100644 --- a/screen-write.c +++ b/screen-write.c @@ -30,11 +30,10 @@ static void screen_write_collect_clear(struct screen_write_ctx *, u_int, static void screen_write_collect_scroll(struct screen_write_ctx *, u_int); static void screen_write_collect_flush(struct screen_write_ctx *, int, const char *); - static int screen_write_overwrite(struct screen_write_ctx *, struct grid_cell *, u_int); -static const struct grid_cell *screen_write_combine(struct screen_write_ctx *, - const struct utf8_data *, u_int *); +static int screen_write_combine(struct screen_write_ctx *, + const struct grid_cell *); struct screen_write_citem { u_int x; @@ -132,6 +131,12 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c) { struct window_pane *wp = ttyctx->arg; + if (ttyctx->allow_invisible_panes) { + if (session_has(c->session, wp->window)) + return (1); + return (0); + } + if (c->session->curw->window != wp->window) return (0); if (wp->layout_cell == NULL) @@ -320,7 +325,9 @@ screen_write_reset(struct screen_write_ctx *ctx) screen_reset_tabs(s); screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); - s->mode = MODE_CURSOR | MODE_WRAP; + s->mode = MODE_CURSOR|MODE_WRAP; + if (options_get_number(global_options, "extended-keys") == 2) + s->mode |= MODE_KEXTENDED; screen_write_clearscreen(ctx, 8); screen_write_set_cursor(ctx, 0, 0); @@ -584,9 +591,46 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, } } +/* Select character set for drawing border lines. */ +static void +screen_write_box_border_set(enum box_lines lines, int cell_type, + struct grid_cell *gc) +{ + switch (lines) { + case BOX_LINES_NONE: + break; + case BOX_LINES_DOUBLE: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_copy(&gc->data, tty_acs_double_borders(cell_type)); + break; + case BOX_LINES_HEAVY: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type)); + break; + case BOX_LINES_ROUNDED: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_copy(&gc->data, tty_acs_rounded_borders(cell_type)); + break; + case BOX_LINES_SIMPLE: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]); + break; + case BOX_LINES_PADDED: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_set(&gc->data, PADDED_BORDERS[cell_type]); + break; + case BOX_LINES_SINGLE: + case BOX_LINES_DEFAULT: + gc->attr |= GRID_ATTR_CHARSET; + utf8_set(&gc->data, CELL_BORDERS[cell_type]); + break; + } +} + /* Draw a horizontal line on screen. */ void -screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right) +screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right, + enum box_lines lines, const struct grid_cell *border_gc) { struct screen *s = ctx->s; struct grid_cell gc; @@ -595,13 +639,27 @@ screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right) cx = s->cx; cy = s->cy; - memcpy(&gc, &grid_default_cell, sizeof gc); + if (border_gc != NULL) + memcpy(&gc, border_gc, sizeof gc); + else + memcpy(&gc, &grid_default_cell, sizeof gc); gc.attr |= GRID_ATTR_CHARSET; - screen_write_putc(ctx, &gc, left ? 't' : 'q'); + if (left) + screen_write_box_border_set(lines, CELL_LEFTJOIN, &gc); + else + screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); + screen_write_cell(ctx, &gc); + + screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); for (i = 1; i < nx - 1; i++) - screen_write_putc(ctx, &gc, 'q'); - screen_write_putc(ctx, &gc, right ? 'u' : 'q'); + screen_write_cell(ctx, &gc); + + if (right) + screen_write_box_border_set(lines, CELL_RIGHTJOIN, &gc); + else + screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); + screen_write_cell(ctx, &gc); screen_write_set_cursor(ctx, cx, cy); } @@ -633,84 +691,53 @@ screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom) /* Draw a menu on screen. */ void -screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, - int choice, const struct grid_cell *choice_gc) +screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, int choice, + enum box_lines lines, const struct grid_cell *menu_gc, + const struct grid_cell *border_gc, const struct grid_cell *choice_gc) { struct screen *s = ctx->s; struct grid_cell default_gc; const struct grid_cell *gc = &default_gc; - u_int cx, cy, i, j; + u_int cx, cy, i, j, width = menu->width; const char *name; cx = s->cx; cy = s->cy; - memcpy(&default_gc, &grid_default_cell, sizeof default_gc); + memcpy(&default_gc, menu_gc, sizeof default_gc); - screen_write_box(ctx, menu->width + 4, menu->count + 2, - BOX_LINES_DEFAULT, &default_gc, menu->title); + screen_write_box(ctx, menu->width + 4, menu->count + 2, lines, + border_gc, menu->title); for (i = 0; i < menu->count; i++) { name = menu->items[i].name; if (name == NULL) { screen_write_cursormove(ctx, cx, cy + 1 + i, 0); - screen_write_hline(ctx, menu->width + 4, 1, 1); - } else { - if (choice >= 0 && i == (u_int)choice && *name != '-') - gc = choice_gc; - screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0); - for (j = 0; j < menu->width; j++) - screen_write_putc(ctx, gc, ' '); - screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0); - if (*name == '-') { - name++; - default_gc.attr |= GRID_ATTR_DIM; - format_draw(ctx, gc, menu->width, name, NULL, - 0); - default_gc.attr &= ~GRID_ATTR_DIM; - } else - format_draw(ctx, gc, menu->width, name, NULL, - gc == choice_gc); - gc = &default_gc; + screen_write_hline(ctx, width + 4, 1, 1, lines, + border_gc); + continue; } - } - screen_write_set_cursor(ctx, cx, cy); -} + if (choice >= 0 && i == (u_int)choice && *name != '-') + gc = choice_gc; -static void -screen_write_box_border_set(enum box_lines box_lines, int cell_type, - struct grid_cell *gc) -{ - switch (box_lines) { - case BOX_LINES_NONE: - break; - case BOX_LINES_DOUBLE: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_copy(&gc->data, tty_acs_double_borders(cell_type)); - break; - case BOX_LINES_HEAVY: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type)); - break; - case BOX_LINES_ROUNDED: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_copy(&gc->data, tty_acs_rounded_borders(cell_type)); - break; - case BOX_LINES_SIMPLE: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]); - break; - case BOX_LINES_PADDED: - gc->attr &= ~GRID_ATTR_CHARSET; - utf8_set(&gc->data, PADDED_BORDERS[cell_type]); - break; - case BOX_LINES_SINGLE: - case BOX_LINES_DEFAULT: - gc->attr |= GRID_ATTR_CHARSET; - utf8_set(&gc->data, CELL_BORDERS[cell_type]); - break; + screen_write_cursormove(ctx, cx + 1, cy + 1 + i, 0); + for (j = 0; j < width + 2; j++) + screen_write_putc(ctx, gc, ' '); + + screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0); + if (*name == '-') { + default_gc.attr |= GRID_ATTR_DIM; + format_draw(ctx, gc, width, name + 1, NULL, 0); + default_gc.attr &= ~GRID_ATTR_DIM; + continue; + } + + format_draw(ctx, gc, width, name, NULL, 0); + gc = &default_gc; } + + screen_write_set_cursor(ctx, cx, cy); } /* Draw a box on screen. */ @@ -984,6 +1011,11 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) memcpy(&gc, &grid_default_cell, sizeof gc); utf8_set(&gc.data, 'E'); +#ifdef ENABLE_SIXEL + if (image_free_all(s) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + for (yy = 0; yy < screen_size_y(s); yy++) { for (xx = 0; xx < screen_size_x(s); xx++) grid_view_set_cell(s->grid, xx, yy, &gc); @@ -1018,6 +1050,11 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) if (s->cx > screen_size_x(s) - 1) return; +#ifdef ENABLE_SIXEL + if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + screen_write_initctx(ctx, &ttyctx, 0); ttyctx.bg = bg; @@ -1046,6 +1083,11 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) if (s->cx > screen_size_x(s) - 1) return; +#ifdef ENABLE_SIXEL + if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + screen_write_initctx(ctx, &ttyctx, 0); ttyctx.bg = bg; @@ -1074,6 +1116,11 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) if (s->cx > screen_size_x(s) - 1) return; +#ifdef ENABLE_SIXEL + if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + screen_write_initctx(ctx, &ttyctx, 0); ttyctx.bg = bg; @@ -1092,9 +1139,18 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg) struct grid *gd = s->grid; struct tty_ctx ttyctx; +#ifdef ENABLE_SIXEL + u_int sy = screen_size_y(s); +#endif + if (ny == 0) ny = 1; +#ifdef ENABLE_SIXEL + if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + if (s->cy < s->rupper || s->cy > s->rlower) { if (ny > screen_size_y(s) - s->cy) ny = screen_size_y(s) - s->cy; @@ -1138,13 +1194,19 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; + u_int sy = screen_size_y(s); if (ny == 0) ny = 1; +#ifdef ENABLE_SIXEL + if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + if (s->cy < s->rupper || s->cy > s->rlower) { - if (ny > screen_size_y(s) - s->cy) - ny = screen_size_y(s) - s->cy; + if (ny > sy - s->cy) + ny = sy - s->cy; if (ny == 0) return; @@ -1190,6 +1252,11 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg) if (gl->cellsize == 0 && COLOUR_DEFAULT(bg)) return; +#ifdef ENABLE_SIXEL + if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); screen_write_collect_clear(ctx, s->cy, 1); @@ -1219,6 +1286,11 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg) if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg))) return; +#ifdef ENABLE_SIXEL + if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg); before = screen_write_collect_trim(ctx, s->cy, s->cx, sx - s->cx, NULL); @@ -1246,6 +1318,11 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg) return; } +#ifdef ENABLE_SIXEL + if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + if (s->cx > sx - 1) grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); else @@ -1294,6 +1371,11 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg) struct tty_ctx ttyctx; if (s->cy == s->rupper) { +#ifdef ENABLE_SIXEL + if (image_free_all(s) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); screen_write_collect_flush(ctx, 0, __func__); @@ -1336,13 +1418,17 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg) struct screen *s = ctx->s; struct grid *gd = s->grid; struct grid_line *gl; +#ifdef ENABLE_SIXEL + int redraw = 0; +#endif + u_int rupper = s->rupper, rlower = s->rlower; gl = grid_get_line(gd, gd->hsize + s->cy); if (wrapped) gl->flags |= GRID_LINE_WRAPPED; log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, - s->rupper, s->rlower); + rupper, rlower); if (bg != ctx->bg) { screen_write_collect_flush(ctx, 1, __func__); @@ -1350,6 +1436,14 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg) } if (s->cy == s->rlower) { +#ifdef ENABLE_SIXEL + if (rlower == screen_size_y(s) - 1) + redraw = image_scroll_up(s, 1); + else + redraw = image_check_line(s, rupper, rlower - rupper); + if (redraw && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); screen_write_collect_scroll(ctx, bg); ctx->scrolled++; @@ -1375,6 +1469,11 @@ screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg) ctx->bg = bg; } +#ifdef ENABLE_SIXEL + if (image_scroll_up(s, lines) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + for (i = 0; i < lines; i++) { grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); screen_write_collect_scroll(ctx, bg); @@ -1399,6 +1498,11 @@ screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg) else if (lines > s->rlower - s->rupper + 1) lines = s->rlower - s->rupper + 1; +#ifdef ENABLE_SIXEL + if (image_free_all(s) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + for (i = 0; i < lines; i++) grid_view_scroll_region_down(gd, s->rupper, s->rlower, bg); @@ -1423,6 +1527,11 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) struct tty_ctx ttyctx; u_int sx = screen_size_x(s), sy = screen_size_y(s); +#ifdef ENABLE_SIXEL + if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + screen_write_initctx(ctx, &ttyctx, 1); ttyctx.bg = bg; @@ -1452,6 +1561,11 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg) struct tty_ctx ttyctx; u_int sx = screen_size_x(s); +#ifdef ENABLE_SIXEL + if (image_check_line(s, 0, s->cy - 1) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + screen_write_initctx(ctx, &ttyctx, 1); ttyctx.bg = bg; @@ -1475,6 +1589,11 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg) struct tty_ctx ttyctx; u_int sx = screen_size_x(s), sy = screen_size_y(s); +#ifdef ENABLE_SIXEL + if (image_free_all(s) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + screen_write_initctx(ctx, &ttyctx, 1); ttyctx.bg = bg; @@ -1506,7 +1625,8 @@ screen_write_fullredraw(struct screen_write_ctx *ctx) screen_write_collect_flush(ctx, 0, __func__); screen_write_initctx(ctx, &ttyctx, 1); - ttyctx.redraw_cb(&ttyctx); + if (ttyctx.redraw_cb != NULL) + ttyctx.redraw_cb(&ttyctx); } /* Trim collected items. */ @@ -1742,6 +1862,11 @@ screen_write_collect_end(struct screen_write_ctx *ctx) } } +#ifdef ENABLE_SIXEL + if (image_check_area(s, s->cx, s->cy, ci->used, 1) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; +#endif + grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x, ci->used); screen_write_set_cursor(ctx, s->cx + ci->used, -1); @@ -1813,54 +1938,21 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) struct screen *s = ctx->s; struct grid *gd = s->grid; const struct utf8_data *ud = &gc->data; - const struct utf8_data zwj = { "\342\200\215", 0, 3, 0 }; struct grid_line *gl; struct grid_cell_entry *gce; struct grid_cell tmp_gc, now_gc; struct tty_ctx ttyctx; u_int sx = screen_size_x(s), sy = screen_size_y(s); - u_int width = gc->data.width, xx, last, cx, cy; + u_int width = ud->width, xx, not_wrap; int selected, skip = 1; /* Ignore padding cells. */ if (gc->flags & GRID_FLAG_PADDING) return; - /* - * If this is a zero width joiner, set the flag so the next character - * will be treated as zero width and appended. Note that we assume a - * ZWJ will not change the width - the width of the first character is - * used. - */ - if (ud->size == 3 && memcmp(ud->data, "\342\200\215", 3) == 0) { - log_debug("zero width joiner at %u,%u", s->cx, s->cy); - ctx->flags |= SCREEN_WRITE_ZWJ; + /* Get the previous cell to check for combining. */ + if (screen_write_combine(ctx, gc) != 0) return; - } - - /* - * If the width is zero, combine onto the previous character. We always - * combine with the cell to the left of the cursor position. In theory, - * the application could have moved the cursor somewhere else, but if - * they are silly enough to do that, who cares? - */ - if (ctx->flags & SCREEN_WRITE_ZWJ) { - screen_write_collect_flush(ctx, 0, __func__); - screen_write_combine(ctx, &zwj, &xx); - } - if (width == 0 || (ctx->flags & SCREEN_WRITE_ZWJ)) { - ctx->flags &= ~SCREEN_WRITE_ZWJ; - screen_write_collect_flush(ctx, 0, __func__); - if ((gc = screen_write_combine(ctx, ud, &xx)) != NULL) { - cx = s->cx; cy = s->cy; - screen_write_set_cursor(ctx, xx, s->cy); - screen_write_initctx(ctx, &ttyctx, 0); - ttyctx.cell = gc; - tty_write(tty_cmd_cell, &ttyctx); - s->cx = cx; s->cy = cy; - } - return; - } /* Flush any existing scrolling. */ screen_write_collect_flush(ctx, 1, __func__); @@ -1952,11 +2044,11 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) * Move the cursor. If not wrapping, stick at the last character and * replace it. */ - last = !(s->mode & MODE_WRAP); - if (s->cx <= sx - last - width) + not_wrap = !(s->mode & MODE_WRAP); + if (s->cx <= sx - not_wrap - width) screen_write_set_cursor(ctx, s->cx + width, -1); else - screen_write_set_cursor(ctx, sx - last, -1); + screen_write_set_cursor(ctx, sx - not_wrap, -1); /* Create space for character in insert mode. */ if (s->mode & MODE_INSERT) { @@ -1976,49 +2068,102 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) } } -/* Combine a UTF-8 zero-width character onto the previous. */ -static const struct grid_cell * -screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud, - u_int *xx) +/* Combine a UTF-8 zero-width character onto the previous if necessary. */ +static int +screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) { struct screen *s = ctx->s; struct grid *gd = s->grid; - static struct grid_cell gc; - u_int n; - - /* Can't combine if at 0. */ - if (s->cx == 0) - return (NULL); + const struct utf8_data *ud = &gc->data; + u_int n, cx = s->cx, cy = s->cy; + struct grid_cell last; + struct tty_ctx ttyctx; + int force_wide = 0, zero_width = 0; - /* Empty data is out. */ - if (ud->size == 0) - fatalx("UTF-8 data empty"); + /* + * Is this character which makes no sense without being combined? If + * this is true then flag it here and discard the character (return 1) + * if we cannot combine it. + */ + if (utf8_is_zwj(ud)) + zero_width = 1; + else if (utf8_is_vs(ud)) + zero_width = force_wide = 1; + else if (ud->width == 0) + zero_width = 1; + + /* Cannot combine empty character or at left. */ + if (ud->size < 2 || cx == 0) + return (zero_width); + log_debug("%s: character %.*s at %u,%u (width %u)", __func__, + (int)ud->size, ud->data, cx, cy, ud->width); + + /* Find the cell to combine with. */ + n = 1; + grid_view_get_cell(gd, cx - n, cy, &last); + if (cx != 1 && (last.flags & GRID_FLAG_PADDING)) { + n = 2; + grid_view_get_cell(gd, cx - n, cy, &last); + } + if (n != last.data.width || (last.flags & GRID_FLAG_PADDING)) + return (zero_width); - /* Retrieve the previous cell. */ - for (n = 1; n <= s->cx; n++) { - grid_view_get_cell(gd, s->cx - n, s->cy, &gc); - if (~gc.flags & GRID_FLAG_PADDING) - break; + /* + * Check if we need to combine characters. This could be zero width + * (set above), a modifier character (with an existing Unicode + * character) or a previous ZWJ. + */ + if (!zero_width) { + if (utf8_is_modifier(ud)) { + if (last.data.size < 2) + return (0); + force_wide = 1; + } else if (!utf8_has_zwj(&last.data)) + return (0); } - if (n > s->cx) - return (NULL); - *xx = s->cx - n; - /* Check there is enough space. */ - if (gc.data.size + ud->size > sizeof gc.data.data) - return (NULL); + /* Check if this combined character would be too long. */ + if (last.data.size + ud->size > sizeof last.data.data) + return (0); - log_debug("%s: %.*s onto %.*s at %u,%u", __func__, (int)ud->size, - ud->data, (int)gc.data.size, gc.data.data, *xx, s->cy); + /* Combining; flush any pending output. */ + screen_write_collect_flush(ctx, 0, __func__); + + log_debug("%s: %.*s -> %.*s at %u,%u (offset %u, width %u)", __func__, + (int)ud->size, ud->data, (int)last.data.size, last.data.data, + cx - n, cy, n, last.data.width); /* Append the data. */ - memcpy(gc.data.data + gc.data.size, ud->data, ud->size); - gc.data.size += ud->size; + memcpy(last.data.data + last.data.size, ud->data, ud->size); + last.data.size += ud->size; + + /* Force the width to 2 for modifiers and variation selector. */ + if (last.data.width == 1 && force_wide) { + last.data.width = 2; + n = 2; + cx++; + } else + force_wide = 0; /* Set the new cell. */ - grid_view_set_cell(gd, *xx, s->cy, &gc); + grid_view_set_cell(gd, cx - n, cy, &last); + if (force_wide) + grid_view_set_padding(gd, cx, cy); + + /* + * Redraw the combined cell. If forcing the cell to width 2, reset the + * cached cursor position in the tty, since we don't really know + * whether the terminal thought the character was width 1 or width 2 + * and what it is going to do now. + */ + screen_write_set_cursor(ctx, cx - n, cy); + screen_write_initctx(ctx, &ttyctx, 0); + ttyctx.cell = &last; + ttyctx.num = force_wide; /* reset cached cursor position */ + tty_write(tty_cmd_cell, &ttyctx); + screen_write_set_cursor(ctx, cx, cy); - return (&gc); + return (1); } /* @@ -2085,12 +2230,14 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc, /* Set external clipboard. */ void -screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len) +screen_write_setselection(struct screen_write_ctx *ctx, const char *flags, + u_char *str, u_int len) { struct tty_ctx ttyctx; screen_write_initctx(ctx, &ttyctx, 0); ttyctx.ptr = str; + ttyctx.ptr2 = (void *)flags; ttyctx.num = len; tty_write(tty_cmd_setselection, &ttyctx); @@ -2098,17 +2245,74 @@ screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len) /* Write unmodified string. */ void -screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len) +screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len, + int allow_invisible_panes) { struct tty_ctx ttyctx; screen_write_initctx(ctx, &ttyctx, 0); ttyctx.ptr = str; ttyctx.num = len; + ttyctx.allow_invisible_panes = allow_invisible_panes; tty_write(tty_cmd_rawstring, &ttyctx); } +#ifdef ENABLE_SIXEL +/* Write a SIXEL image. */ +void +screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si, + u_int bg) +{ + struct screen *s = ctx->s; + struct grid *gd = s->grid; + struct tty_ctx ttyctx; + u_int x, y, sx, sy, cx = s->cx, cy = s->cy, i, lines; + struct sixel_image *new; + + sixel_size_in_cells(si, &x, &y); + if (x > screen_size_x(s) || y > screen_size_y(s)) { + if (x > screen_size_x(s) - cx) + sx = screen_size_x(s) - cx; + else + sx = x; + if (y > screen_size_y(s) - 1) + sy = screen_size_y(s) - 1; + else + sy = y; + new = sixel_scale(si, 0, 0, 0, y - sy, sx, sy, 1); + sixel_free(si); + si = new; + sixel_size_in_cells(si, &x, &y); + } + + sy = screen_size_y(s) - cy; + if (sy < y) { + lines = y - sy + 1; + if (image_scroll_up(s, lines) && ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAW; + for (i = 0; i < lines; i++) { + grid_view_scroll_region_up(gd, 0, screen_size_y(s) - 1, + bg); + screen_write_collect_scroll(ctx, bg); + } + ctx->scrolled += lines; + if (lines > cy) + screen_write_cursormove(ctx, -1, 0, 0); + else + screen_write_cursormove(ctx, -1, cy - lines, 0); + } + screen_write_collect_flush(ctx, 0, __func__); + + screen_write_initctx(ctx, &ttyctx, 0); + ttyctx.ptr = image_store(s, si); + + tty_write(tty_cmd_sixelimage, &ttyctx); + + screen_write_cursormove(ctx, 0, cy + y, 0); +} +#endif + /* Turn alternate screen on. */ void screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, @@ -2124,7 +2328,8 @@ screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_alternate_on(ctx->s, gc, cursor); screen_write_initctx(ctx, &ttyctx, 1); - ttyctx.redraw_cb(&ttyctx); + if (ttyctx.redraw_cb != NULL) + ttyctx.redraw_cb(&ttyctx); } /* Turn alternate screen off. */ @@ -2142,5 +2347,6 @@ screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_alternate_off(ctx->s, gc, cursor); screen_write_initctx(ctx, &ttyctx, 1); - ttyctx.redraw_cb(&ttyctx); + if (ttyctx.redraw_cb != NULL) + ttyctx.redraw_cb(&ttyctx); } |