diff --git a/menu.c b/menu.c index 7449d88d..cd361e00 100644 --- a/menu.c +++ b/menu.c @@ -181,15 +181,17 @@ menu_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy) } /* Return parts of the input range which are not obstructed by the menu. */ -void +struct visible_ranges * menu_check_cb(__unused struct client *c, void *data, u_int px, u_int py, - u_int nx, struct overlay_ranges *r) + u_int nx) { struct menu_data *md = data; struct menu *menu = md->menu; + struct visible_ranges *r; - server_client_overlay_range(md->px, md->py, menu->width + 4, - menu->count + 2, px, py, nx, r); + r = server_client_overlay_range(md->px, md->py, menu->width + 4, + menu->count + 2, px, py, nx); + return (r); } void diff --git a/popup.c b/popup.c index 2146693a..6d0e1ffd 100644 --- a/popup.c +++ b/popup.c @@ -164,48 +164,41 @@ popup_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy) } /* Return parts of the input range which are not obstructed by the popup. */ -static void -popup_check_cb(struct client* c, void *data, u_int px, u_int py, u_int nx, - struct overlay_ranges *r) +static struct visible_ranges * +popup_check_cb(struct client* c, void *data, u_int px, u_int py, u_int nx) { struct popup_data *pd = data; - struct overlay_ranges or[2]; + struct visible_ranges *or[2], *r; u_int i, j, k = 0; if (pd->md != NULL) { /* Check each returned range for the menu against the popup. */ - menu_check_cb(c, pd->md, px, py, nx, r); - for (i = 0; i < 2; i++) { - server_client_overlay_range(pd->px, pd->py, pd->sx, - pd->sy, r->px[i], py, r->nx[i], &or[i]); + r = menu_check_cb(c, pd->md, px, py, nx); + for (i = 0; i < r->used; i++) { + or[i] = server_client_overlay_range(pd->px, pd->py, pd->sx, + pd->sy, r->px[i], py, r->nx[i]); } /* * or has up to OVERLAY_MAX_RANGES non-overlapping ranges, * ordered from left to right. Collect them in the output. */ - for (i = 0; i < 2; i++) { - /* Each or[i] only has 2 ranges. */ - for (j = 0; j < 2; j++) { - if (or[i].nx[j] > 0) { - r->px[k] = or[i].px[j]; - r->nx[k] = or[i].nx[j]; + for (i = 0; i < r->used; i++) { + /* Each or[i] only has up to 2 ranges. */ + for (j = 0; j < or[i]->used; j++) { + if (or[i]->nx[j] > 0) { + r->px[k] = or[i]->px[j]; + r->nx[k] = or[i]->nx[j]; k++; } } } - /* Zero remaining ranges if any. */ - for (i = k; i < OVERLAY_MAX_RANGES; i++) { - r->px[i] = 0; - r->nx[i] = 0; - } - - return; + return (r); } - server_client_overlay_range(pd->px, pd->py, pd->sx, pd->sy, px, py, nx, - r); + return (server_client_overlay_range(pd->px, pd->py, pd->sx, pd->sy, px, py, + nx)); } static void diff --git a/screen-redraw.c b/screen-redraw.c index cce06011..da3f40b5 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -817,13 +817,13 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) struct window_pane *wp, *active = server_client_get_pane(c); struct grid_cell gc; const struct grid_cell *tmp; - struct overlay_ranges r; + struct visible_ranges *r; u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; int isolates; if (c->overlay_check != NULL) { - c->overlay_check(c, c->overlay_data, x, y, 1, &r); - if (r.nx[0] + r.nx[1] == 0) + r = c->overlay_check(c, c->overlay_data, x, y, 1); + if (r->nx[0] + r->nx[1] == 0) return; } @@ -943,7 +943,8 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) struct screen *s = wp->screen; struct colour_palette *palette = &wp->palette; struct grid_cell defaults; - u_int i, j, top, x, y, width; + struct visible_ranges *vr; + u_int i, j, top, x, y, px, width, r; if (wp->base.mode & MODE_SYNC) screen_write_stop_sync(wp); @@ -987,8 +988,23 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u", __func__, c->name, wp->id, i, j, x, y, width); + /* xxxx Breaking up the tty_draw_line like this isn't fully working. */ + vr = tty_check_overlay_range(tty, x, y, width); + tty_default_colours(&defaults, wp); - tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette); + + for (r=0; r < vr->used; r++) { + if (vr->nx[r] == 0) + continue; + /* Convert window coordinates to tty coordinates. */ + px = vr->px[r]; + /* i is px of cell, add px of region, sub the + * pane offset. If you don't sub offset, + * contents of pane shifted. note: i apparently unnec. + */ + tty_draw_line(tty, s, /* i + */ vr->px[r] - wp->xoff, j, + vr->nx[r], px, y, &defaults, palette); + } } #ifdef ENABLE_SIXEL diff --git a/screen.c b/screen.c index 7f4f9383..247d596d 100644 --- a/screen.c +++ b/screen.c @@ -770,3 +770,72 @@ screen_mode_to_string(int mode) tmp[strlen(tmp) - 1] = '\0'; return (tmp); } + +#ifdef DEBUG +/* Debug function. Usage in gdb: + * printf "%S",screen_print(s) + */ +__unused char * +screen_print(struct screen *s) { + static char buf[16384]; + const char *acs; + u_int x, y; + size_t last = 0, n; + struct utf8_data ud; + struct grid_line *gl; + struct grid_cell_entry *gce; + + for (y = 0; y < screen_hsize(s)+s->grid->sy; y++) { + if (last + 6 > sizeof buf) goto out; + n = snprintf(buf + last, sizeof buf - last, "%.4d ", y); + last += n; + buf[last++] = '"'; + gl = &s->grid->linedata[y]; + + for (x = 0; x < gl->cellused; x++) { + gce = &gl->celldata[x]; + + if (gce->flags & GRID_FLAG_PADDING) + continue; + + if (~gce->flags & GRID_FLAG_EXTENDED) { + /* single-byte cell stored inline */ + if (last + 2 > sizeof buf) goto out; + buf[last++] = gce->data.data; + } else if (gce->flags & GRID_FLAG_TAB) { + if (last + 2 > sizeof buf) goto out; + buf[last++] = '\t'; + } else if ((gce->data.data & 0xff) && + (gce->flags & GRID_ATTR_CHARSET)) { + /* single-byte ACS inline: try to map */ + acs = tty_acs_get(NULL, gce->data.data); + if (acs != NULL) { + n = strlen(acs); + if (last + n + 1 > sizeof buf) goto out; + memcpy(buf + last, acs, n); + last += n; + continue; + } + buf[last++] = gce->data.data; + } else { + /* extended cell: convert utf8_char -> bytes */ + utf8_to_data(gl->extddata[gce->offset].data, + &ud); + if (ud.size > 0) { + if (last + ud.size + 1 > sizeof buf) + goto out; + memcpy(buf + last, ud.data, ud.size); + last += ud.size; + } + } + } + + if (last + 3 > sizeof buf) goto out; + buf[last++] = '"'; + buf[last++] = '\n'; + } + +out: buf[last] = '\0'; + return (buf); +} +#endif diff --git a/server-client.c b/server-client.c index 1ea2fe3e..a222ac6f 100644 --- a/server-client.c +++ b/server-client.c @@ -165,34 +165,37 @@ server_client_clear_overlay(struct client *c) * Given overlay position and dimensions, return parts of the input range which * are visible. */ -void +struct visible_ranges * server_client_overlay_range(u_int x, u_int y, u_int sx, u_int sy, u_int px, - u_int py, u_int nx, struct overlay_ranges *r) + u_int py, u_int nx) { - u_int ox, onx; + u_int ox, onx; + static struct visible_ranges r = {NULL, NULL, 0, 0}; - /* Return up to 2 ranges. */ - r->px[2] = 0; - r->nx[2] = 0; + /* For efficiency vr is static and space reused. */ + if (r.size == 0) { + r.px = xcalloc(2, sizeof(u_int)); + r.nx = xcalloc(2, sizeof(u_int)); + r.size = 2; + } /* Trivial case of no overlap in the y direction. */ if (py < y || py > y + sy - 1) { - r->px[0] = px; - r->nx[0] = nx; - r->px[1] = 0; - r->nx[1] = 0; - return; + r.px[0] = px; + r.nx[0] = nx; + r.used = 1; + return (&r); } /* Visible bit to the left of the popup. */ if (px < x) { - r->px[0] = px; - r->nx[0] = x - px; - if (r->nx[0] > nx) - r->nx[0] = nx; + r.px[0] = px; + r.nx[0] = x - px; + if (r.nx[0] > nx) + r.nx[0] = nx; } else { - r->px[0] = 0; - r->nx[0] = 0; + r.px[0] = 0; + r.nx[0] = 0; } /* Visible bit to the right of the popup. */ @@ -201,12 +204,14 @@ server_client_overlay_range(u_int x, u_int y, u_int sx, u_int sy, u_int px, ox = px; onx = px + nx; if (onx > ox) { - r->px[1] = ox; - r->nx[1] = onx - ox; + r.px[1] = ox; + r.nx[1] = onx - ox; } else { - r->px[1] = 0; - r->nx[1] = 0; + r.px[1] = 0; + r.nx[1] = 0; } + r.used = 2; + return (&r); } /* Check if this client is inside this server. */ diff --git a/tmux.h b/tmux.h index 33da541a..ec1bd543 100644 --- a/tmux.h +++ b/tmux.h @@ -1922,11 +1922,19 @@ struct overlay_ranges { u_int nx[OVERLAY_MAX_RANGES]; }; +/* Visible range array element. */ +struct visible_ranges { + u_int *px; /* Start */ + u_int *nx; /* Length */ + size_t used; + size_t size; +}; + /* Client connection. */ typedef int (*prompt_input_cb)(struct client *, void *, const char *, int); typedef void (*prompt_free_cb)(void *); -typedef void (*overlay_check_cb)(struct client*, void *, u_int, u_int, u_int, - struct overlay_ranges *); +typedef struct visible_ranges *(*overlay_check_cb)(struct client*, void *, + u_int, u_int, u_int); typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *, u_int *); typedef void (*overlay_draw_cb)(struct client *, void *, @@ -2551,6 +2559,8 @@ void tty_set_path(struct tty *, const char *); void tty_default_attributes(struct tty *, const struct grid_cell *, struct colour_palette *, u_int, struct hyperlinks *); void tty_update_mode(struct tty *, int, struct screen *); +struct visible_ranges *tty_check_overlay_range(struct tty *, u_int, u_int, + u_int); /* tty-draw.c */ void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int, @@ -2567,6 +2577,7 @@ void tty_close(struct tty *); void tty_free(struct tty *); void tty_update_features(struct tty *); void tty_set_selection(struct tty *, const char *, const char *, size_t); +u_int tty_cell_width(const struct grid_cell *, u_int); void tty_write(void (*)(struct tty *, const struct tty_ctx *), struct tty_ctx *); void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *); @@ -2909,8 +2920,8 @@ void server_client_set_overlay(struct client *, u_int, overlay_check_cb, overlay_mode_cb, overlay_draw_cb, overlay_key_cb, overlay_free_cb, overlay_resize_cb, void *); void server_client_clear_overlay(struct client *); -void server_client_overlay_range(u_int, u_int, u_int, u_int, u_int, u_int, - u_int, struct overlay_ranges *); +struct visible_ranges *server_client_overlay_range(u_int, u_int, u_int, u_int, u_int, u_int, + u_int); void server_client_set_key_table(struct client *, const char *); const char *server_client_get_key_table(struct client *); int server_client_check_nested(struct client *); @@ -3231,6 +3242,7 @@ void screen_select_cell(struct screen *, struct grid_cell *, void screen_alternate_on(struct screen *, struct grid_cell *, int); void screen_alternate_off(struct screen *, struct grid_cell *, int); const char *screen_mode_to_string(int); +__unused char * screen_print(struct screen *s); /* window.c */ extern struct windows windows; @@ -3611,8 +3623,7 @@ int menu_display(struct menu *, int, int, struct cmdq_item *, const char *, const char *, struct cmd_find_state *, menu_choice_cb, void *); struct screen *menu_mode_cb(struct client *, void *, u_int *, u_int *); -void menu_check_cb(struct client *, void *, u_int, u_int, u_int, - struct overlay_ranges *); +struct visible_ranges *menu_check_cb(struct client *, void *, u_int, u_int, u_int); void menu_draw_cb(struct client *, void *, struct screen_redraw_ctx *); void menu_free_cb(struct client *, void *); diff --git a/tty.c b/tty.c index bc1df836..5ff225d6 100644 --- a/tty.c +++ b/tty.c @@ -66,8 +66,7 @@ static void tty_emulate_repeat(struct tty *, enum tty_code_code, enum tty_code_code, u_int); static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int); static int tty_check_overlay(struct tty *, u_int, u_int); -static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int, - struct overlay_ranges *); +struct visible_ranges *tty_check_overlay_range(struct tty *, u_int, u_int, u_int); #ifdef ENABLE_SIXEL static void tty_write_one(void (*)(struct tty *, const struct tty_ctx *), @@ -1161,7 +1160,7 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py, u_int px, u_int nx, u_int bg) { struct client *c = tty->client; - struct overlay_ranges r; + struct visible_ranges *r; u_int i; log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py); @@ -1198,13 +1197,17 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py, * Couldn't use an escape sequence, use spaces. Clear only the visible * bit if there is an overlay. */ - tty_check_overlay_range(tty, px, py, nx, &r); - for (i = 0; i < OVERLAY_MAX_RANGES; i++) { - if (r.nx[i] == 0) + tty_cursor(tty, px, py); + tty_repeat_space(tty, nx); + /* + r = tty_check_overlay_range(tty, px, py, nx); + for (i = 0; i < r->used; i++) { + if (r->nx[i] == 0) continue; - tty_cursor(tty, r.px[i], py); - tty_repeat_space(tty, r.nx[i]); + tty_cursor(tty, r->px[i], py); + tty_repeat_space(tty, r->nx[i]); } + */ } /* Clear a line, adjusting to visible part of pane. */ @@ -1418,6 +1421,20 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc) return (&new); } +/* + * Compute the effective display width (in terminal columns) of a grid cell + * when it will be drawn at terminal column atcol. + */ +u_int +tty_cell_width(const struct grid_cell *gcp, u_int atcol) +{ + /* Tabs expand to the next tab stop (tab width = 8). */ + if (gcp->flags & GRID_FLAG_TAB) + return (8 - (atcol % 8)); + /* Normal characters: width stored in cell (1 or 2 usually). */ + return (gcp->data.width); +} + /* * Check if a single character is obstructed by the overlay and return a * boolean. @@ -1425,37 +1442,41 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc) static int tty_check_overlay(struct tty *tty, u_int px, u_int py) { - struct overlay_ranges r; + struct visible_ranges *r; /* * A unit width range will always return nx[2] == 0 from a check, even * with multiple overlays, so it's sufficient to check just the first * two entries. */ - tty_check_overlay_range(tty, px, py, 1, &r); - if (r.nx[0] + r.nx[1] == 0) + r = tty_check_overlay_range(tty, px, py, 1); + if (r->nx[0] + r->nx[1] == 0) return (0); return (1); } /* Return parts of the input range which are visible. */ -static void -tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx, - struct overlay_ranges *r) +struct visible_ranges * +tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx) { + static struct visible_ranges r = {NULL, NULL, 0, 0}; struct client *c = tty->client; - if (c->overlay_check == NULL) { - r->px[0] = px; - r->nx[0] = nx; - r->px[1] = 0; - r->nx[1] = 0; - r->px[2] = 0; - r->nx[2] = 0; - return; + /* For efficiency vr is static and space reused. */ + if (r.size == 0) { + r.px = xcalloc(1, sizeof(u_int)); + r.nx = xcalloc(1, sizeof(u_int)); + r.size = 1; } - c->overlay_check(c, c->overlay_data, px, py, nx, r); + if (c->overlay_check == NULL) { + r.px[0] = px; + r.nx[0] = nx; + r.used = 1; + return (&r); + } + + return (c->overlay_check(c, c->overlay_data, px, py, nx)); } #ifdef ENABLE_SIXEL @@ -1983,7 +2004,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) { const struct grid_cell *gcp = ctx->cell; struct screen *s = ctx->s; - struct overlay_ranges r; + struct visible_ranges *r; u_int px, py, i, vis = 0; px = ctx->xoff + ctx->ocx - ctx->wox; @@ -2000,9 +2021,9 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) /* Handle partially obstructed wide characters. */ if (gcp->data.width > 1) { - tty_check_overlay_range(tty, px, py, gcp->data.width, &r); - for (i = 0; i < OVERLAY_MAX_RANGES; i++) - vis += r.nx[i]; + r = tty_check_overlay_range(tty, px, py, gcp->data.width); + for (i = 0; i < r->used; i++) + vis += r->nx[i]; if (vis < gcp->data.width) { tty_draw_line(tty, s, s->cx, s->cy, gcp->data.width, px, py, &ctx->defaults, ctx->palette); @@ -2028,7 +2049,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) { - struct overlay_ranges r; + struct visible_ranges *r; u_int i, px, py, cx; char *cp = ctx->ptr; @@ -2059,14 +2080,14 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) px = ctx->xoff + ctx->ocx - ctx->wox; py = ctx->yoff + ctx->ocy - ctx->woy; - tty_check_overlay_range(tty, px, py, ctx->num, &r); - for (i = 0; i < OVERLAY_MAX_RANGES; i++) { - if (r.nx[i] == 0) + r = tty_check_overlay_range(tty, px, py, ctx->num); + for (i = 0; i < r->used; i++) { + if (r->nx[i] == 0) continue; /* Convert back to pane position for printing. */ - cx = r.px[i] - ctx->xoff + ctx->wox; + cx = r->px[i] - ctx->xoff + ctx->wox; tty_cursor_pane_unless_wrap(tty, ctx, cx, ctx->ocy); - tty_putn(tty, cp + r.px[i] - px, r.nx[i], r.nx[i]); + tty_putn(tty, cp + r->px[i] - px, r->nx[i], r->nx[i]); } }