diff --git a/screen-redraw.c b/screen-redraw.c index 5df141ba..a026339d 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -887,28 +887,30 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx) /* Construct ranges of line at px,py of width cells of base_wp that are unobsructed. */ -void +struct visible_ranges * screen_redraw_get_visible_ranges(u_int px, u_int py, u_int width, - struct window_pane *base_wp, struct visible_range **vr_p, - int *vr_count_p) { - struct window_pane *wp; - struct window *w; - struct visible_range *vr; - int found_self, r, s; - int vr_len, vr_count; + struct window_pane *base_wp) { + struct window_pane *wp; + struct window *w; + static struct visible_ranges ranges = { NULL, 0, 0 }; + static struct visible_range *vr; + int found_self; + u_int r, s; - /* Caller must call free(vr). */ - vr = xcalloc(4, sizeof(struct visible_range *)); - vr_len = 4; + /* For efficiency ranges is static and space reused. */ + if (ranges.array == NULL) { + ranges.array = xcalloc(4, sizeof(struct visible_range *)); + ranges.size = 4; + } + + /* Start with the entire width of the range. */ + vr = ranges.array; vr[0].px = px; vr[0].nx = width; - vr_count = 1; + ranges.n = 1; - if (base_wp == NULL) { - *vr_p = vr; - *vr_count_p = vr_count; - return; - } + if (base_wp == NULL) + return (&ranges); w = base_wp->window; @@ -917,50 +919,59 @@ screen_redraw_get_visible_ranges(u_int px, u_int py, u_int width, found_self = 1; continue; } - if (found_self && wp->layout_cell == NULL && - !(wp->flags & PANE_MINIMISED) && - (py >= wp->yoff && py <= wp->yoff + wp->sy)) { - for (r=0; rxoff > vr[r].px && - wp->xoff < vr[r].px + vr[r].nx && - wp->xoff + wp->sx > vr[r].px + vr[r].nx) { - vr[r].nx = wp->xoff; - /* else if the right edge of wp - falls inside of this range and left - edge is less than the start of the range, - then move px forward */ - } else if (wp->xoff + wp->sx > vr[r].px && - wp->xoff + wp->sx < vr[r].px + vr[r].nx && - wp->xoff < vr[r].px) { - vr[r].px = vr[r].px + (wp->xoff + wp->sx); - vr[r].nx = vr[r].nx - (wp->xoff + wp->sx); - /* else if wp fully inside range - then split range into 2 ranges */ - } else if (wp->xoff > vr[r].px && - wp->xoff + wp->sx < vr[r].px + vr[r].nx) { - /* make space */ - if (vr_len == vr_count) { - vr = xreallocarray(vr, vr_len + - 4, sizeof *vr); - vr_len += 4; - } - for (s=vr_count; s>r; s--) { - vr[s].px = vr[s-1].px; - vr[s].nx = vr[s-1].nx; - } - vr[r].nx = wp->xoff; - vr[r+1].px = wp->xoff + wp->sx; - vr_count++; - } /* XXX what if it's completely obscured? */ + + if (!found_self || wp->layout_cell != NULL || + (wp->flags & PANE_MINIMISED) || + (py < wp->yoff || py > wp->yoff + wp->sy)) + continue; + + for (r=0; rxoff > vr[r].px && + wp->xoff < vr[r].px + vr[r].nx && + wp->xoff + wp->sx >= vr[r].px + vr[r].nx) { + vr[r].nx = wp->xoff; } + /* Else if the right edge of floating wp + falls inside of this range and left + edge covers the left of range, + then move px forward to right edge of wp. */ + else if (wp->xoff + wp->sx > vr[r].px && + wp->xoff + wp->sx < vr[r].px + vr[r].nx && + wp->xoff <= vr[r].px) { + vr[r].px = vr[r].px + (wp->xoff + wp->sx); + vr[r].nx = vr[r].nx - (wp->xoff + wp->sx); + } + /* Else if wp fully inside range + then split range into 2 ranges. */ + else if (wp->xoff > vr[r].px && + wp->xoff + wp->sx < vr[r].px + vr[r].nx) { + if (ranges.size == ranges.n) { + ranges.array = xreallocarray(vr, + ranges.size += 4, sizeof *vr); + ranges.array = vr; + } + for (s=ranges.n; s>r; s--) { + vr[s].px = vr[s-1].px; + vr[s].nx = vr[s-1].nx; + } + vr[r].nx = wp->xoff; + vr[r+1].px = wp->xoff + wp->sx; + ranges.n++; + } + /* If floating wp completely covers this range + then delete it (make it 0 length). */ + else if (wp->xoff <= vr[r].px && + wp->xoff+wp->sx >= vr[r].px+vr[r].nx) { + vr[r].nx = 0; + } + /* Else the range is already obscured, do nothing. */ } } - *vr_p = vr; - *vr_count_p = vr_count; + return (&ranges); } @@ -974,9 +985,9 @@ 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; + struct visible_ranges *visible_ranges; struct visible_range *vr; - int vr_count, r; - u_int i, j, top, x, y, width; + u_int i, j, top, x, y, width, r; log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id); @@ -1019,15 +1030,21 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) __func__, c->name, wp->id, i, j, x, y, width); /* Get visible ranges of line before we draw it. */ - screen_redraw_get_visible_ranges(x, y, width, wp, - &vr, &vr_count); + visible_ranges = screen_redraw_get_visible_ranges(x, y, width, + wp); + vr = visible_ranges->array; tty_default_colours(&defaults, wp); - for (r=0; rn; r++) { + if (vr[r].nx == 0) + continue; + /* i is px of cell, add px of region, sub the + pane offset. If you don't sub offset, + contents of pane shifted. */ + tty_draw_line(tty, s, i+vr[r].px-wp->xoff, j, vr[r].nx, vr[r].px, y, &defaults, palette); - free(vr); + } } #ifdef ENABLE_SIXEL diff --git a/screen-write.c b/screen-write.c index 4b3a7098..b31a813c 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1747,13 +1747,13 @@ screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg) { struct screen *s = ctx->s; struct screen_write_cline *cl_src, *cl_dst; - u_int y, r_start, r_end; + u_int y, r, r_start, r_end; u_int ci_start, ci_end, new_end; char *saved; struct screen_write_citem *ci, *new_ci; struct window_pane *wp = ctx->wp; + struct visible_ranges *visible_ranges; struct visible_range *vr; - int vr_count, r; log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, s->rupper, s->rlower); @@ -1766,11 +1766,10 @@ screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg) for (y = s->rupper; y < s->rlower; y++) { cl_src = &s->write_list[y + 1]; cl_dst = &s->write_list[y]; - vr = NULL; - vr_count = 0; - screen_redraw_get_visible_ranges(0, y, screen_size_x(s), wp, - &vr, &vr_count); + visible_ranges = screen_redraw_get_visible_ranges(0, y, + screen_size_x(s), wp); + vr = visible_ranges->array; TAILQ_INIT(&cl_dst->items); @@ -1779,7 +1778,8 @@ screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg) /* For each visible range, copy corresponding items from cl_src to cl_dst. */ - for (r = 0; r < vr_count; r++) { + for (r = 0; r < visible_ranges->n; r++) { + if (vr[r].nx == 0) continue; r_start = vr[r].px; r_end = vr[r].px + vr[r].nx; @@ -1806,7 +1806,6 @@ screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg) entry); } } - free(vr); } s->write_list[s->rlower].data = saved; @@ -1821,12 +1820,12 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, struct screen *s = ctx->s; struct screen_write_citem *ci, *tmp; struct screen_write_cline *cl; - u_int y, cx, cy, last, items = 0; + u_int y, cx, cy, last, items = 0, r; u_int r_start, r_end, ci_start, ci_end; u_int wr_start, wr_end, wr_length; struct tty_ctx ttyctx; - struct visible_range *vr = NULL; - int vr_count = 0; + struct visible_ranges *visible_ranges; + struct visible_range *vr; struct window_pane *wp = ctx->wp; if (ctx->scrolled != 0) { @@ -1854,8 +1853,9 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, for (y = 0; y < screen_size_y(s); y++) { cl = &ctx->s->write_list[y]; - screen_redraw_get_visible_ranges(0, y, screen_size_x(s), wp, - &vr, &vr_count); + visible_ranges = screen_redraw_get_visible_ranges(0, y, + screen_size_x(s), wp); + vr = visible_ranges->array; last = UINT_MAX; TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { @@ -1863,7 +1863,8 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, fatalx("collect list not in order: %u <= %u", ci->x, last); } - for (int r = 0; r < vr_count; r++) { + for (r = 0; r < visible_ranges->n; r++) { + if (vr[r].nx == 0) continue; r_start = vr[r].px; r_end = vr[r].px + vr[r].nx; ci_start = ci->x; @@ -1900,7 +1901,6 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, screen_write_free_citem(ci); last = ci->x; } - free(vr); } s->cx = cx; s->cy = cy; diff --git a/tmux.h b/tmux.h index 8a95cbb1..fbb9f421 100644 --- a/tmux.h +++ b/tmux.h @@ -2235,8 +2235,13 @@ struct mode_tree_sort_criteria { }; struct visible_range { - u_int px; - u_int nx; + u_int px; /* Start */ + u_int nx; /* Length */ +}; +struct visible_ranges { + struct visible_range *array; + size_t n; /* Elements used */ + size_t size; /* Array size */ }; /* tmux.c */ @@ -3169,8 +3174,8 @@ void screen_write_alternateoff(struct screen_write_ctx *, /* screen-redraw.c */ void screen_redraw_screen(struct client *); void screen_redraw_pane(struct client *, struct window_pane *, int); -void screen_redraw_get_visible_ranges(u_int, u_int, u_int, - struct window_pane *, struct visible_range **, int *); +struct visible_ranges *screen_redraw_get_visible_ranges(u_int, u_int, u_int, + struct window_pane *); /* screen.c */