diff --git a/cmd-split-window.c b/cmd-split-window.c index 515bd789..564f7daf 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -262,8 +262,8 @@ cmd_new_floating_window_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_ERROR); } } - sc.xoff = 0; - sc.yoff = 0; + sc.xoff = 10; + sc.yoff = 10; sc.sx = sx; sc.sy = sy; diff --git a/screen-redraw.c b/screen-redraw.c index 23488abb..5df141ba 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -885,34 +885,41 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx) } } -struct visual_range { - u_int px; - u_int nx; -}; +/* Construct ranges of line at px,py of width cells of base_wp that are + unobsructed. */ +void +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; -static void -screen_redraw_get_visual_ranges(u_int px, u_int py, u_int width, - struct window_pane *base_wp, struct window *w, - struct visual_range **vr_p, int *vr_count_p) { - struct visual_range *vr; - int found_self, r, s; - int vr_len, vr_count; - struct window_pane *wp; - - vr = xcalloc(4, sizeof(struct visual_range *)); - vr_len = 4; // 4 initial slots - vr[0].px = px; // initialise first slot + /* Caller must call free(vr). */ + vr = xcalloc(4, sizeof(struct visible_range *)); + vr_len = 4; + vr[0].px = px; vr[0].nx = width; vr_count = 1; + if (base_wp == NULL) { + *vr_p = vr; + *vr_count_p = vr_count; + return; + } + + w = base_wp->window; + TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp == base_wp) { // wp == current pane + if (wp == base_wp) { found_self = 1; continue; } if (found_self && wp->layout_cell == NULL && !(wp->flags & PANE_MINIMISED) && - (wp->yoff >= py && py <= wp->yoff + wp->sy)) { + (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) + 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 && + } 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].nx) - vr[r].px = wp->xoff + wp->sx; + 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 && + } else if (wp->xoff > vr[r].px && wp->xoff + wp->sx < vr[r].px + vr[r].nx) { /* make space */ if (vr_len == vr_count) { @@ -946,7 +954,8 @@ screen_redraw_get_visual_ranges(u_int px, u_int py, u_int width, } vr[r].nx = wp->xoff; vr[r+1].px = wp->xoff + wp->sx; - } + vr_count++; + } /* XXX what if it's completely obscured? */ } } } @@ -965,7 +974,7 @@ 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 visual_range *vr; + struct visible_range *vr; int vr_count, r; u_int i, j, top, x, y, width; @@ -1009,12 +1018,15 @@ 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); - screen_redraw_get_visual_ranges(x, y, width, wp, w, &vr, &vr_count); + /* Get visible ranges of line before we draw it. */ + screen_redraw_get_visible_ranges(x, y, width, wp, + &vr, &vr_count); tty_default_colours(&defaults, wp); for (r=0; rs; - struct screen_write_cline *cl; - u_int y; - char *saved; - struct screen_write_citem *ci; + struct screen *s = ctx->s; + struct screen_write_cline *cl_src, *cl_dst; + u_int y, 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_range *vr; + int vr_count, r; log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, s->rupper, s->rlower); screen_write_collect_clear(ctx, s->rupper, 1); - saved = ctx->s->write_list[s->rupper].data; - for (y = s->rupper; y < s->rlower; y++) { - cl = &ctx->s->write_list[y + 1]; - TAILQ_CONCAT(&ctx->s->write_list[y].items, &cl->items, entry); - ctx->s->write_list[y].data = cl->data; - } - ctx->s->write_list[s->rlower].data = saved; + saved = s->write_list[s->rupper].data; - ci = screen_write_get_citem(); - ci->x = 0; - ci->used = screen_size_x(s); - ci->type = CLEAR; - ci->bg = bg; - TAILQ_INSERT_TAIL(&ctx->s->write_list[s->rlower].items, ci, entry); + /* For each line being scrolled, copy visible ranges from the line + below to the line above. */ + 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); + + TAILQ_INIT(&cl_dst->items); + + if (cl_dst->data == NULL) + cl_dst->data = xmalloc(screen_size_x(s)); + + /* For each visible range, copy corresponding items from cl_src + to cl_dst. */ + for (r = 0; r < vr_count; r++) { + r_start = vr[r].px; + r_end = vr[r].px + vr[r].nx; + + TAILQ_FOREACH(ci, &cl_src->items, entry) { + ci_start = ci->x; + ci_end = ci->x + ci->used; + + if (ci_end <= r_start || ci_start >= r_end) + continue; + + new_ci = screen_write_get_citem(); + new_ci->x = (ci_start < r_start) ? r_start : + ci_start; + new_end = (ci_end > r_end) ? r_end : ci_end; + new_ci->used = new_end - new_ci->x; + new_ci->type = ci->type; + new_ci->wrapped = ci->wrapped; + new_ci->bg = bg; + memcpy(&new_ci->gc, &ci->gc, sizeof(ci->gc)); + if (ci->type == TEXT) + memcpy(cl_dst->data, cl_src->data, + screen_size_x(s)); + TAILQ_INSERT_TAIL(&cl_dst->items, new_ci, + entry); + } + } + free(vr); + } + s->write_list[s->rlower].data = saved; + + screen_write_collect_clear(ctx, s->rlower, 1); } /* Flush collected lines. */ @@ -1780,7 +1822,12 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, struct screen_write_citem *ci, *tmp; struct screen_write_cline *cl; u_int y, cx, cy, last, items = 0; + 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 window_pane *wp = ctx->wp; if (ctx->scrolled != 0) { log_debug("%s: scrolled %u (region %u-%u)", __func__, @@ -1803,34 +1850,57 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, return; cx = s->cx; cy = s->cy; + 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); + last = UINT_MAX; TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { if (last != UINT_MAX && ci->x <= last) { fatalx("collect list not in order: %u <= %u", ci->x, last); } - screen_write_set_cursor(ctx, ci->x, y); - if (ci->type == CLEAR) { - screen_write_initctx(ctx, &ttyctx, 1); - ttyctx.bg = ci->bg; - ttyctx.num = ci->used; - tty_write(tty_cmd_clearcharacter, &ttyctx); - } else { - screen_write_initctx(ctx, &ttyctx, 0); - ttyctx.cell = &ci->gc; - ttyctx.wrapped = ci->wrapped; - ttyctx.ptr = cl->data + ci->x; - ttyctx.num = ci->used; - tty_write(tty_cmd_cells, &ttyctx); - } - items++; + for (int r = 0; r < vr_count; r++) { + r_start = vr[r].px; + r_end = vr[r].px + vr[r].nx; + ci_start = ci->x; + ci_end = ci->x + ci->used; + if (ci_end <= r_start || ci_start >= r_end) + continue; + + wr_start = (ci_start < r_start) ? r_start : + ci_start; + wr_end = (ci_end > r_end) ? r_end : ci_end; + wr_length = wr_end - wr_start; + if (wr_length == 0) + continue; + + screen_write_set_cursor(ctx, wr_start, y); + if (ci->type == CLEAR) { + screen_write_initctx(ctx, &ttyctx, 1); + ttyctx.bg = ci->bg; + ttyctx.num = wr_length; + tty_write(tty_cmd_clearcharacter, + &ttyctx); + } else { + screen_write_initctx(ctx, &ttyctx, 0); + ttyctx.cell = &ci->gc; + ttyctx.wrapped = ci->wrapped; + ttyctx.ptr = cl->data + wr_start; + ttyctx.num = wr_length; + tty_write(tty_cmd_cells, &ttyctx); + } + items++; + } TAILQ_REMOVE(&cl->items, ci, entry); screen_write_free_citem(ci); last = ci->x; } + free(vr); } s->cx = cx; s->cy = cy; @@ -1967,6 +2037,27 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) u_int sx = screen_size_x(s), sy = screen_size_y(s); u_int width = ud->width, xx, not_wrap; int selected, skip = 1; + struct window_pane *base_wp = ctx->wp, *wp; + struct window *w; + u_int found_self, px, py; + + + if (base_wp != NULL) { + w = base_wp->window; + px = ctx->s->cx; + py = ctx->s->cy; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp == base_wp) { + found_self = 1; + continue; + } + if (found_self && wp->layout_cell == NULL && + !(wp->flags & PANE_MINIMISED) && + (py >= wp->yoff && py <= wp->yoff + wp->sy) && + (px >= wp->xoff && px <= wp->xoff + wp->sx)) + return; + } + } /* Ignore padding cells. */ if (gc->flags & GRID_FLAG_PADDING) diff --git a/tmux.h b/tmux.h index 79a2bd6c..8a95cbb1 100644 --- a/tmux.h +++ b/tmux.h @@ -2234,6 +2234,11 @@ struct mode_tree_sort_criteria { int reversed; }; +struct visible_range { + u_int px; + u_int nx; +}; + /* tmux.c */ extern struct options *global_options; extern struct options *global_s_options; @@ -3164,6 +3169,9 @@ 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 *); + /* screen.c */ void screen_init(struct screen *, u_int, u_int, u_int);