diff --git a/cmd-split-window.c b/cmd-split-window.c index 82bdbfdc..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 = 20; - sc.yoff = 20; + sc.xoff = 10; + sc.yoff = 10; sc.sx = sx; sc.sy = sy; diff --git a/menu.c b/menu.c index fd3a9fe4..b43bfd8d 100644 --- a/menu.c +++ b/menu.c @@ -217,7 +217,7 @@ menu_draw_cb(struct client *c, void *data, for (i = 0; i < screen_size_y(&md->s); i++) { tty_draw_line(tty, s, 0, i, menu->width + 4, px, py + i, - &grid_default_cell, NULL); + &grid_default_cell, NULL, NULL); } } diff --git a/popup.c b/popup.c index 4d837a9b..1011c3c2 100644 --- a/popup.c +++ b/popup.c @@ -250,7 +250,7 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) } for (i = 0; i < pd->sy; i++) { tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &defaults, - palette); + palette, NULL); } screen_free(&s); if (pd->md != NULL) { diff --git a/screen-redraw.c b/screen-redraw.c index a026339d..01b73c38 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -104,7 +104,11 @@ screen_redraw_two_panes(struct window *w, int direction) { struct window_pane *wp; - wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); + wp = TAILQ_FIRST(&w->panes); + do { + wp = TAILQ_NEXT(wp, entry); + } while (wp && wp->layout_cell == NULL); + if (wp == NULL) return (0); /* one pane */ if (TAILQ_NEXT(wp, entry) != NULL) @@ -230,7 +234,7 @@ screen_redraw_cell_border(struct screen_redraw_ctx *ctx, u_int px, u_int py) return (1); /* Check all the panes. */ - TAILQ_FOREACH(wp, &w->panes, entry) { + TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { if (!window_pane_visible(wp)) continue; switch (screen_redraw_pane_border(ctx, wp, px, py)) { @@ -335,7 +339,7 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, { struct client *c = ctx->c; struct window *w = c->session->curw->window; - struct window_pane *wp, *active; + struct window_pane *wp, *start; int pane_status = ctx->pane_status; u_int sx = w->sx, sy = w->sy; int border, pane_scrollbars = ctx->pane_scrollbars; @@ -351,7 +355,18 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, return (screen_redraw_type_of_cell(ctx, px, py)); if (pane_status != PANE_STATUS_OFF) { - active = wp = server_client_get_pane(c); + /* Look for higest z-index window at px,py. xxxx scrollbars? */ + TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { + if (! (wp->flags & PANE_MINIMISED) && + (px >= wp->xoff - 1 && px<= wp->xoff + wp->sx + 1) && + (py >= wp->yoff - 1 && py<= wp->yoff + wp->sy + 1)) + break; + } + if (wp != NULL) + start = wp; + else + start = wp = server_client_get_pane(c); + do { if (!window_pane_visible(wp)) goto next1; @@ -369,10 +384,22 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, wp = TAILQ_NEXT(wp, entry); if (wp == NULL) wp = TAILQ_FIRST(&w->panes); - } while (wp != active); + } while (wp != start); } - active = wp = server_client_get_pane(c); + + /* Look for higest z-index window at px,py. xxxx scrollbars? */ + TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) { + if (! (wp->flags & PANE_MINIMISED) && + (px >= wp->xoff-1 && px<= wp->xoff+wp->sx+1) && + (py >= wp->yoff-1 && py<= wp->yoff+wp->sy+1)) + break; + } + if (wp == NULL) + start = wp = server_client_get_pane(c); + else + start = wp; + do { if (!window_pane_visible(wp)) goto next2; @@ -422,7 +449,7 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, wp = TAILQ_NEXT(wp, entry); if (wp == NULL) wp = TAILQ_FIRST(&w->panes); - } while (wp != active); + } while (wp != start); return (CELL_OUTSIDE); } @@ -516,6 +543,7 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx) struct tty *tty = &c->tty; struct window_pane *wp; struct screen *s; + struct visible_ranges *visible_ranges; u_int i, x, width, xoff, yoff, size; log_debug("%s: %s @%u", __func__, c->name, w->id); @@ -562,8 +590,11 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx) if (ctx->statustop) yoff += ctx->statuslines; + visible_ranges = screen_redraw_get_visible_ranges(wp, i, 0, + width); + tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy, - &grid_default_cell, NULL); + &grid_default_cell, NULL, visible_ranges); } tty_cursor(tty, 0, 0); } @@ -722,6 +753,7 @@ screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x, wp->border_gc_set = 1; ft = format_create_defaults(NULL, c, s, s->curw, wp); + if (screen_redraw_check_is(ctx, x, y, active)) style_apply(&wp->border_gc, oo, "pane-active-border-style", ft); else @@ -881,21 +913,22 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx) y = c->tty.sy - ctx->statuslines; for (i = 0; i < ctx->statuslines; i++) { tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i, - &grid_default_cell, NULL); + &grid_default_cell, NULL, NULL); } } /* Construct ranges of line at px,py of width cells of base_wp that are unobsructed. */ struct visible_ranges * -screen_redraw_get_visible_ranges(u_int px, u_int py, u_int width, - struct window_pane *base_wp) { +screen_redraw_get_visible_ranges(struct window_pane *base_wp, u_int px, + u_int py, u_int width) { 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; + int found_self, sb_w; + u_int r, s, lb, rb, tb, bb; + int pane_scrollbars; /* For efficiency ranges is static and space reused. */ if (ranges.array == NULL) { @@ -913,6 +946,7 @@ screen_redraw_get_visible_ranges(u_int px, u_int py, u_int width, return (&ranges); w = base_wp->window; + pane_scrollbars = options_get_number(w->options, "pane-scrollbars"); TAILQ_FOREACH(wp, &w->panes, entry) { if (wp == base_wp) { @@ -920,35 +954,43 @@ screen_redraw_get_visible_ranges(u_int px, u_int py, u_int width, continue; } + tb = wp->yoff-1; + bb = wp->yoff + wp->sy; if (!found_self || wp->layout_cell != NULL || (wp->flags & PANE_MINIMISED) || - (py < wp->yoff || py > wp->yoff + wp->sy)) + (py < tb || py > bb)) continue; + /* Are scrollbars enabled? */ + if (window_pane_show_scrollbar(wp, pane_scrollbars)) + sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad; + for (r=0; rxoff - 1; + rb = wp->xoff + wp->sx + sb_w + 1; /* If the left edge of floating wp falls inside this range and right edge covers up to right of range, then shrink left edge of range. */ - if (wp->xoff > 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; + if (lb > vr[r].px && + lb < vr[r].px + vr[r].nx && + rb >= vr[r].px + vr[r].nx) { + vr[r].nx = lb; } /* 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 (rb > vr[r].px && + rb < vr[r].px + vr[r].nx && + lb <= vr[r].px) { + vr[r].px = vr[r].px + rb; + vr[r].nx = vr[r].nx - rb; } /* 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) { + else if (lb > vr[r].px && + rb < vr[r].px + vr[r].nx) { if (ranges.size == ranges.n) { ranges.array = xreallocarray(vr, ranges.size += 4, sizeof *vr); @@ -958,14 +1000,14 @@ screen_redraw_get_visible_ranges(u_int px, u_int py, u_int width, 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[r].nx = lb; + vr[r+1].px = rb; 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) { + else if (lb <= vr[r].px && + rb >= vr[r].px+vr[r].nx) { vr[r].nx = 0; } /* Else the range is already obscured, do nothing. */ @@ -1030,11 +1072,13 @@ 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. */ - visible_ranges = screen_redraw_get_visible_ranges(x, y, width, - wp); + visible_ranges = screen_redraw_get_visible_ranges(wp, x, y, + width); vr = visible_ranges->array; tty_default_colours(&defaults, wp); + /* xxxx tty_draw_line should drawn only visible ranges. see xxxx commment in tty_draw_line. */ + /*tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette, visible_ranges); */ for (r=0; rn; r++) { if (vr[r].nx == 0) @@ -1043,7 +1087,8 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) 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); + vr[r].nx, vr[r].px, y, &defaults, palette, + visible_ranges); } } diff --git a/screen-write.c b/screen-write.c index ac6415cb..099a9754 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1745,67 +1745,24 @@ screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n) static void 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, r_start, r_end; - u_int ci_start, ci_end, new_end; - char *saved; - struct screen_write_citem *ci, *ci_tmp, *new_ci; - struct window_pane *wp = ctx->wp; - struct visible_ranges *visible_ranges; - struct visible_range *vr; + struct screen *s = ctx->s; + struct screen_write_cline *cl; + u_int y; + char *saved; + struct screen_write_citem *ci; 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 = s->write_list[s->rupper].data; + saved = ctx->s->write_list[s->rupper].data; for (y = s->rupper; y < s->rlower; y++) { - cl_src = &s->write_list[y + 1]; - cl_dst = &s->write_list[y]; - - visible_ranges = screen_redraw_get_visible_ranges(0, y, - screen_size_x(s), wp); - vr = visible_ranges->array; - - /* For each visible range, copy corresponding items from cl_src - to cl_dst. */ - 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; - - TAILQ_FOREACH_SAFE(ci, &cl_src->items, entry, ci_tmp) { - 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)); - - TAILQ_INSERT_TAIL(&cl_dst->items, new_ci, entry); - TAILQ_REMOVE(&cl_src->items, ci, entry); - } - } - if (! TAILQ_EMPTY(&cl_src->items)) { - screen_write_collect_clear(ctx, y+1, 1); - TAILQ_INIT(&cl_src->items); - } - ctx->s->write_list[y].data = cl_src->data; + 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; } - s->write_list[s->rlower].data = saved; - return; - /* Also worked without this clear, is this needed? */ + ctx->s->write_list[s->rlower].data = saved; + ci = screen_write_get_citem(); ci->x = 0; ci->used = screen_size_x(s); @@ -1855,8 +1812,8 @@ 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]; - visible_ranges = screen_redraw_get_visible_ranges(0, y, - screen_size_x(s), wp); + visible_ranges = screen_redraw_get_visible_ranges(wp, 0, y, + screen_size_x(s)); vr = visible_ranges->array; last = UINT_MAX; @@ -1865,6 +1822,7 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, fatalx("collect list not in order: %u <= %u", ci->x, last); } + wr_length = 0; for (r = 0; r < visible_ranges->n; r++) { if (vr[r].nx == 0) continue; r_start = vr[r].px; @@ -1880,6 +1838,7 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, wr_end = (ci_end > r_end) ? r_end : ci_end; wr_length = wr_end - wr_start; + if (wr_length == 0) continue; @@ -1889,7 +1848,7 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, ttyctx.bg = ci->bg; ttyctx.num = wr_length; tty_write(tty_cmd_clearcharacter, - &ttyctx); + &ttyctx); } else { screen_write_initctx(ctx, &ttyctx, 0); ttyctx.cell = &ci->gc; @@ -1899,10 +1858,11 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, tty_write(tty_cmd_cells, &ttyctx); } items++; + + TAILQ_REMOVE(&cl->items, ci, entry); + screen_write_free_citem(ci); + last = ci->x; } - TAILQ_REMOVE(&cl->items, ci, entry); - screen_write_free_citem(ci); - last = ci->x; } } s->cx = cx; s->cy = cy; diff --git a/tmux.h b/tmux.h index fbb9f421..cb9fee24 100644 --- a/tmux.h +++ b/tmux.h @@ -2531,7 +2531,8 @@ void tty_set_title(struct tty *, const char *); void tty_set_path(struct tty *, const char *); void tty_update_mode(struct tty *, int, struct screen *); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int, - u_int, u_int, const struct grid_cell *, struct colour_palette *); + u_int, u_int, const struct grid_cell *, struct colour_palette *, + struct visible_ranges *); #ifdef ENABLE_SIXEL void tty_draw_images(struct client *, struct window_pane *, struct screen *); @@ -3174,8 +3175,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); -struct visible_ranges *screen_redraw_get_visible_ranges(u_int, u_int, u_int, - struct window_pane *); +struct visible_ranges *screen_redraw_get_visible_ranges(struct window_pane *, + u_int, u_int, u_int); /* screen.c */ diff --git a/tty.c b/tty.c index 86cfb316..40b019f9 100644 --- a/tty.c +++ b/tty.c @@ -1365,22 +1365,30 @@ tty_clear_pane_area(struct tty *tty, const struct tty_ctx *ctx, u_int py, tty_clear_area(tty, &ctx->defaults, y, ry, x, rx, bg); } +/* Redraw a line at py of a screen taking into account obscured ranges. + * Menus and popups are always on top, ctx->arg == NULL. + */ static void tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py) { - struct screen *s = ctx->s; - u_int nx = ctx->sx, i, x, rx, ry; + struct screen *s = ctx->s; + struct window_pane *wp = ctx->arg; + struct visible_ranges *visible_ranges = NULL; + u_int nx = ctx->sx, i, x, rx, ry; log_debug("%s: %s %u %d", __func__, tty->client->name, py, ctx->bigger); + if (wp) + visible_ranges = screen_redraw_get_visible_ranges(wp, 0, py, nx); + if (!ctx->bigger) { tty_draw_line(tty, s, 0, py, nx, ctx->xoff, ctx->yoff + py, - &ctx->defaults, ctx->palette); + &ctx->defaults, ctx->palette, visible_ranges); return; } if (tty_clamp_line(tty, ctx, 0, py, nx, &i, &x, &rx, &ry)) { tty_draw_line(tty, s, i, py, rx, x, ry, &ctx->defaults, - ctx->palette); + ctx->palette, visible_ranges); } } @@ -1457,10 +1465,38 @@ tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx, c->overlay_check(c, c->overlay_data, px, py, nx, r); } +/* Check if a single character is within a visible range (not obscured by a + * floating window pane). Returns a boolean. + */ +static int +tty_check_in_visible_range(struct visible_ranges *visible_ranges, u_int px) +{ + struct visible_range *vr; + u_int r; + + /* No visible_ranges if called from a popup or menu. Always on top. */ + if (visible_ranges == NULL) + return (0); + + vr = visible_ranges->array; + + /* Verify if px is in a visible range. */ + for (r=0; rn; r++) { + if (vr[r].nx == 0) + continue; + if (px >= vr[r].px && + px <= (vr[r].px + vr[r].nx)) + return (0); + } + + /* px not found in any visible range, it is obscured by a pane. */ + return (1); +} + void tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, u_int atx, u_int aty, const struct grid_cell *defaults, - struct colour_palette *palette) + struct colour_palette *palette, struct visible_ranges *visible_ranges) { struct grid *gd = s->grid; struct grid_cell gc, last; @@ -1517,6 +1553,10 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, atx != 0 || tty->cx < tty->sx || nx < tty->sx) { + /* Do I need to check + !tty_is_obstructed(c->session->curw->window->active + here too? It's not certain that the active pane is + the one being drawn in. (delete this comment) */ if (nx < tty->sx && atx == 0 && px + sx != nx && @@ -1543,6 +1583,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, gcp = tty_check_codeset(tty, &gc); if (len != 0 && (!tty_check_overlay(tty, atx + ux + width, aty) || + !tty_check_in_visible_range(visible_ranges, + atx + ux + width) || (gcp->attr & GRID_ATTR_CHARSET) || gcp->flags != last.flags || gcp->attr != last.attr || @@ -1577,7 +1619,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, tty_check_overlay_range(tty, atx + ux, aty, gcp->data.width, &r); - hidden = 0; + hidden = 0; /* need to check visible_ranges too? xxxx */ for (j = 0; j < OVERLAY_MAX_RANGES; j++) hidden += r.nx[j]; hidden = gcp->data.width - hidden; @@ -1997,11 +2039,40 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) tty_putc(tty, '\n'); } +/* Return 1 if there is a floating window pane overlapping this pane. */ +static int +tty_is_obscured(const struct tty_ctx *ctx) +{ + struct window_pane *base_wp = ctx->arg, *wp; + struct window *w; + int found_self = 0; + + if (base_wp == NULL) + return(0); + w = base_wp->window; + + /* Check if there is a floating pane. xxxx borders? scrollbars? */ + 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) && + (wp->yoff > base_wp->yoff && + wp->yoff + wp->sy < base_wp->yoff + base_wp->sy) && + (wp->xoff > base_wp->xoff && + wp->xoff + wp->sx < base_wp->xoff + base_wp->sx)) + return (1); + } + return (0); +} + void tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) { - struct client *c = tty->client; - u_int i; + struct client *c = tty->client; + u_int i; if (ctx->bigger || (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) || @@ -2009,7 +2080,8 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) !tty_term_has(tty->term, TTYC_CSR) || ctx->sx == 1 || ctx->sy == 1 || - c->overlay_check != NULL) { + c->overlay_check != NULL || + tty_is_obscured(ctx)) { tty_redraw_region(tty, ctx); return; } @@ -2168,6 +2240,8 @@ 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 window_pane *wp = ctx->arg; + struct visible_ranges *visible_ranges; u_int px, py, i, vis = 0; px = ctx->xoff + ctx->ocx - ctx->wox; @@ -2176,6 +2250,9 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) (gcp->data.width == 1 && !tty_check_overlay(tty, px, py))) return; + if (wp) + visible_ranges = screen_redraw_get_visible_ranges(wp, px, py, 1); + /* Handle partially obstructed wide characters. */ if (gcp->data.width > 1) { tty_check_overlay_range(tty, px, py, gcp->data.width, &r); @@ -2183,7 +2260,8 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) 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); + px, py, &ctx->defaults, ctx->palette, + visible_ranges); return; } }