Fix scrolling, redraw, and borders of floating panes.

This commit is contained in:
Michael Grant
2025-10-19 14:11:08 +01:00
parent a6514e2656
commit 379e4d976c
7 changed files with 193 additions and 109 deletions

View File

@@ -262,8 +262,8 @@ cmd_new_floating_window_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
sc.xoff = 20; sc.xoff = 10;
sc.yoff = 20; sc.yoff = 10;
sc.sx = sx; sc.sx = sx;
sc.sy = sy; sc.sy = sy;

2
menu.c
View File

@@ -217,7 +217,7 @@ menu_draw_cb(struct client *c, void *data,
for (i = 0; i < screen_size_y(&md->s); i++) { for (i = 0; i < screen_size_y(&md->s); i++) {
tty_draw_line(tty, s, 0, i, menu->width + 4, px, py + i, tty_draw_line(tty, s, 0, i, menu->width + 4, px, py + i,
&grid_default_cell, NULL); &grid_default_cell, NULL, NULL);
} }
} }

View File

@@ -250,7 +250,7 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
} }
for (i = 0; i < pd->sy; i++) { for (i = 0; i < pd->sy; i++) {
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &defaults, tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &defaults,
palette); palette, NULL);
} }
screen_free(&s); screen_free(&s);
if (pd->md != NULL) { if (pd->md != NULL) {

View File

@@ -104,7 +104,11 @@ screen_redraw_two_panes(struct window *w, int direction)
{ {
struct window_pane *wp; 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) if (wp == NULL)
return (0); /* one pane */ return (0); /* one pane */
if (TAILQ_NEXT(wp, entry) != NULL) 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); return (1);
/* Check all the panes. */ /* Check all the panes. */
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH_REVERSE(wp, &w->panes, window_panes, entry) {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
switch (screen_redraw_pane_border(ctx, wp, px, py)) { 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 client *c = ctx->c;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp, *active; struct window_pane *wp, *start;
int pane_status = ctx->pane_status; int pane_status = ctx->pane_status;
u_int sx = w->sx, sy = w->sy; u_int sx = w->sx, sy = w->sy;
int border, pane_scrollbars = ctx->pane_scrollbars; 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)); return (screen_redraw_type_of_cell(ctx, px, py));
if (pane_status != PANE_STATUS_OFF) { 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 { do {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
goto next1; 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); wp = TAILQ_NEXT(wp, entry);
if (wp == NULL) if (wp == NULL)
wp = TAILQ_FIRST(&w->panes); 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 { do {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
goto next2; 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); wp = TAILQ_NEXT(wp, entry);
if (wp == NULL) if (wp == NULL)
wp = TAILQ_FIRST(&w->panes); wp = TAILQ_FIRST(&w->panes);
} while (wp != active); } while (wp != start);
return (CELL_OUTSIDE); return (CELL_OUTSIDE);
} }
@@ -516,6 +543,7 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window_pane *wp; struct window_pane *wp;
struct screen *s; struct screen *s;
struct visible_ranges *visible_ranges;
u_int i, x, width, xoff, yoff, size; u_int i, x, width, xoff, yoff, size;
log_debug("%s: %s @%u", __func__, c->name, w->id); 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) if (ctx->statustop)
yoff += ctx->statuslines; 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, 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); 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; wp->border_gc_set = 1;
ft = format_create_defaults(NULL, c, s, s->curw, wp); ft = format_create_defaults(NULL, c, s, s->curw, wp);
if (screen_redraw_check_is(ctx, x, y, active)) if (screen_redraw_check_is(ctx, x, y, active))
style_apply(&wp->border_gc, oo, "pane-active-border-style", ft); style_apply(&wp->border_gc, oo, "pane-active-border-style", ft);
else else
@@ -881,21 +913,22 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
y = c->tty.sy - ctx->statuslines; y = c->tty.sy - ctx->statuslines;
for (i = 0; i < ctx->statuslines; i++) { for (i = 0; i < ctx->statuslines; i++) {
tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + 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 /* Construct ranges of line at px,py of width cells of base_wp that are
unobsructed. */ unobsructed. */
struct visible_ranges * struct visible_ranges *
screen_redraw_get_visible_ranges(u_int px, u_int py, u_int width, screen_redraw_get_visible_ranges(struct window_pane *base_wp, u_int px,
struct window_pane *base_wp) { u_int py, u_int width) {
struct window_pane *wp; struct window_pane *wp;
struct window *w; struct window *w;
static struct visible_ranges ranges = { NULL, 0, 0 }; static struct visible_ranges ranges = { NULL, 0, 0 };
static struct visible_range *vr; static struct visible_range *vr;
int found_self; int found_self, sb_w;
u_int r, s; u_int r, s, lb, rb, tb, bb;
int pane_scrollbars;
/* For efficiency ranges is static and space reused. */ /* For efficiency ranges is static and space reused. */
if (ranges.array == NULL) { if (ranges.array == NULL) {
@@ -913,6 +946,7 @@ screen_redraw_get_visible_ranges(u_int px, u_int py, u_int width,
return (&ranges); return (&ranges);
w = base_wp->window; w = base_wp->window;
pane_scrollbars = options_get_number(w->options, "pane-scrollbars");
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp == base_wp) { if (wp == base_wp) {
@@ -920,35 +954,43 @@ screen_redraw_get_visible_ranges(u_int px, u_int py, u_int width,
continue; continue;
} }
tb = wp->yoff-1;
bb = wp->yoff + wp->sy;
if (!found_self || wp->layout_cell != NULL || if (!found_self || wp->layout_cell != NULL ||
(wp->flags & PANE_MINIMISED) || (wp->flags & PANE_MINIMISED) ||
(py < wp->yoff || py > wp->yoff + wp->sy)) (py < tb || py > bb))
continue; 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; r<ranges.n; r++) { for (r=0; r<ranges.n; r++) {
lb = wp->xoff - 1;
rb = wp->xoff + wp->sx + sb_w + 1;
/* If the left edge of floating wp /* If the left edge of floating wp
falls inside this range and right falls inside this range and right
edge covers up to right of range, edge covers up to right of range,
then shrink left edge of range. */ then shrink left edge of range. */
if (wp->xoff > vr[r].px && if (lb > vr[r].px &&
wp->xoff < vr[r].px + vr[r].nx && lb < vr[r].px + vr[r].nx &&
wp->xoff + wp->sx >= vr[r].px + vr[r].nx) { rb >= vr[r].px + vr[r].nx) {
vr[r].nx = wp->xoff; vr[r].nx = lb;
} }
/* Else if the right edge of floating wp /* Else if the right edge of floating wp
falls inside of this range and left falls inside of this range and left
edge covers the left of range, edge covers the left of range,
then move px forward to right edge of wp. */ then move px forward to right edge of wp. */
else if (wp->xoff + wp->sx > vr[r].px && else if (rb > vr[r].px &&
wp->xoff + wp->sx < vr[r].px + vr[r].nx && rb < vr[r].px + vr[r].nx &&
wp->xoff <= vr[r].px) { lb <= vr[r].px) {
vr[r].px = vr[r].px + (wp->xoff + wp->sx); vr[r].px = vr[r].px + rb;
vr[r].nx = vr[r].nx - (wp->xoff + wp->sx); vr[r].nx = vr[r].nx - rb;
} }
/* Else if wp fully inside range /* Else if wp fully inside range
then split range into 2 ranges. */ then split range into 2 ranges. */
else if (wp->xoff > vr[r].px && else if (lb > vr[r].px &&
wp->xoff + wp->sx < vr[r].px + vr[r].nx) { rb < vr[r].px + vr[r].nx) {
if (ranges.size == ranges.n) { if (ranges.size == ranges.n) {
ranges.array = xreallocarray(vr, ranges.array = xreallocarray(vr,
ranges.size += 4, sizeof *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].px = vr[s-1].px;
vr[s].nx = vr[s-1].nx; vr[s].nx = vr[s-1].nx;
} }
vr[r].nx = wp->xoff; vr[r].nx = lb;
vr[r+1].px = wp->xoff + wp->sx; vr[r+1].px = rb;
ranges.n++; ranges.n++;
} }
/* If floating wp completely covers this range /* If floating wp completely covers this range
then delete it (make it 0 length). */ then delete it (make it 0 length). */
else if (wp->xoff <= vr[r].px && else if (lb <= vr[r].px &&
wp->xoff+wp->sx >= vr[r].px+vr[r].nx) { rb >= vr[r].px+vr[r].nx) {
vr[r].nx = 0; vr[r].nx = 0;
} }
/* Else the range is already obscured, do nothing. */ /* 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); __func__, c->name, wp->id, i, j, x, y, width);
/* Get visible ranges of line before we draw it. */ /* Get visible ranges of line before we draw it. */
visible_ranges = screen_redraw_get_visible_ranges(x, y, width, visible_ranges = screen_redraw_get_visible_ranges(wp, x, y,
wp); width);
vr = visible_ranges->array; vr = visible_ranges->array;
tty_default_colours(&defaults, wp); 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; r<visible_ranges->n; r++) { for (r=0; r<visible_ranges->n; r++) {
if (vr[r].nx == 0) 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, pane offset. If you don't sub offset,
contents of pane shifted. */ contents of pane shifted. */
tty_draw_line(tty, s, i+vr[r].px-wp->xoff, j, 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);
} }
} }

View File

@@ -1745,67 +1745,24 @@ screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n)
static void static void
screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg) screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct screen_write_cline *cl_src, *cl_dst; struct screen_write_cline *cl;
u_int y, r, r_start, r_end; u_int y;
u_int ci_start, ci_end, new_end; char *saved;
char *saved; struct screen_write_citem *ci;
struct screen_write_citem *ci, *ci_tmp, *new_ci;
struct window_pane *wp = ctx->wp;
struct visible_ranges *visible_ranges;
struct visible_range *vr;
log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy,
s->rupper, s->rlower); s->rupper, s->rlower);
screen_write_collect_clear(ctx, s->rupper, 1); 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++) { for (y = s->rupper; y < s->rlower; y++) {
cl_src = &s->write_list[y + 1]; cl = &ctx->s->write_list[y + 1];
cl_dst = &s->write_list[y]; TAILQ_CONCAT(&ctx->s->write_list[y].items, &cl->items, entry);
ctx->s->write_list[y].data = cl->data;
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;
} }
s->write_list[s->rlower].data = saved; ctx->s->write_list[s->rlower].data = saved;
return;
/* Also worked without this clear, is this needed? */
ci = screen_write_get_citem(); ci = screen_write_get_citem();
ci->x = 0; ci->x = 0;
ci->used = screen_size_x(s); 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++) { for (y = 0; y < screen_size_y(s); y++) {
cl = &ctx->s->write_list[y]; cl = &ctx->s->write_list[y];
visible_ranges = screen_redraw_get_visible_ranges(0, y, visible_ranges = screen_redraw_get_visible_ranges(wp, 0, y,
screen_size_x(s), wp); screen_size_x(s));
vr = visible_ranges->array; vr = visible_ranges->array;
last = UINT_MAX; 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", fatalx("collect list not in order: %u <= %u",
ci->x, last); ci->x, last);
} }
wr_length = 0;
for (r = 0; r < visible_ranges->n; r++) { for (r = 0; r < visible_ranges->n; r++) {
if (vr[r].nx == 0) continue; if (vr[r].nx == 0) continue;
r_start = vr[r].px; 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) ? wr_end = (ci_end > r_end) ?
r_end : ci_end; r_end : ci_end;
wr_length = wr_end - wr_start; wr_length = wr_end - wr_start;
if (wr_length == 0) if (wr_length == 0)
continue; continue;
@@ -1889,7 +1848,7 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only,
ttyctx.bg = ci->bg; ttyctx.bg = ci->bg;
ttyctx.num = wr_length; ttyctx.num = wr_length;
tty_write(tty_cmd_clearcharacter, tty_write(tty_cmd_clearcharacter,
&ttyctx); &ttyctx);
} else { } else {
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.cell = &ci->gc; 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); tty_write(tty_cmd_cells, &ttyctx);
} }
items++; 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; s->cx = cx; s->cy = cy;

7
tmux.h
View File

@@ -2531,7 +2531,8 @@ void tty_set_title(struct tty *, const char *);
void tty_set_path(struct tty *, const char *); void tty_set_path(struct tty *, const char *);
void tty_update_mode(struct tty *, int, struct screen *); void tty_update_mode(struct tty *, int, struct screen *);
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int, 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 #ifdef ENABLE_SIXEL
void tty_draw_images(struct client *, struct window_pane *, struct screen *); 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 */ /* screen-redraw.c */
void screen_redraw_screen(struct client *); void screen_redraw_screen(struct client *);
void screen_redraw_pane(struct client *, struct window_pane *, int); 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 visible_ranges *screen_redraw_get_visible_ranges(struct window_pane *,
struct window_pane *); u_int, u_int, u_int);
/* screen.c */ /* screen.c */

98
tty.c
View File

@@ -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); 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 static void
tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py) tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py)
{ {
struct screen *s = ctx->s; struct screen *s = ctx->s;
u_int nx = ctx->sx, i, x, rx, ry; 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); 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) { if (!ctx->bigger) {
tty_draw_line(tty, s, 0, py, nx, ctx->xoff, ctx->yoff + py, tty_draw_line(tty, s, 0, py, nx, ctx->xoff, ctx->yoff + py,
&ctx->defaults, ctx->palette); &ctx->defaults, ctx->palette, visible_ranges);
return; return;
} }
if (tty_clamp_line(tty, ctx, 0, py, nx, &i, &x, &rx, &ry)) { 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, 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); 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; r<visible_ranges->n; 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 void
tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, 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, 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 *gd = s->grid;
struct grid_cell gc, last; 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 || atx != 0 ||
tty->cx < tty->sx || tty->cx < tty->sx ||
nx < 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 && if (nx < tty->sx &&
atx == 0 && atx == 0 &&
px + sx != nx && 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); gcp = tty_check_codeset(tty, &gc);
if (len != 0 && if (len != 0 &&
(!tty_check_overlay(tty, atx + ux + width, aty) || (!tty_check_overlay(tty, atx + ux + width, aty) ||
!tty_check_in_visible_range(visible_ranges,
atx + ux + width) ||
(gcp->attr & GRID_ATTR_CHARSET) || (gcp->attr & GRID_ATTR_CHARSET) ||
gcp->flags != last.flags || gcp->flags != last.flags ||
gcp->attr != last.attr || 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, tty_check_overlay_range(tty, atx + ux, aty, gcp->data.width,
&r); &r);
hidden = 0; hidden = 0; /* need to check visible_ranges too? xxxx */
for (j = 0; j < OVERLAY_MAX_RANGES; j++) for (j = 0; j < OVERLAY_MAX_RANGES; j++)
hidden += r.nx[j]; hidden += r.nx[j];
hidden = gcp->data.width - hidden; hidden = gcp->data.width - hidden;
@@ -1997,11 +2039,40 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
tty_putc(tty, '\n'); 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 void
tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
{ {
struct client *c = tty->client; struct client *c = tty->client;
u_int i; u_int i;
if (ctx->bigger || if (ctx->bigger ||
(!tty_full_width(tty, ctx) && !tty_use_margin(tty)) || (!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) || !tty_term_has(tty->term, TTYC_CSR) ||
ctx->sx == 1 || ctx->sx == 1 ||
ctx->sy == 1 || ctx->sy == 1 ||
c->overlay_check != NULL) { c->overlay_check != NULL ||
tty_is_obscured(ctx)) {
tty_redraw_region(tty, ctx); tty_redraw_region(tty, ctx);
return; return;
} }
@@ -2168,6 +2240,8 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
const struct grid_cell *gcp = ctx->cell; const struct grid_cell *gcp = ctx->cell;
struct screen *s = ctx->s; struct screen *s = ctx->s;
struct overlay_ranges r; struct overlay_ranges r;
struct window_pane *wp = ctx->arg;
struct visible_ranges *visible_ranges;
u_int px, py, i, vis = 0; u_int px, py, i, vis = 0;
px = ctx->xoff + ctx->ocx - ctx->wox; 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))) (gcp->data.width == 1 && !tty_check_overlay(tty, px, py)))
return; return;
if (wp)
visible_ranges = screen_redraw_get_visible_ranges(wp, px, py, 1);
/* Handle partially obstructed wide characters. */ /* Handle partially obstructed wide characters. */
if (gcp->data.width > 1) { if (gcp->data.width > 1) {
tty_check_overlay_range(tty, px, py, gcp->data.width, &r); 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]; vis += r.nx[i];
if (vis < gcp->data.width) { if (vis < gcp->data.width) {
tty_draw_line(tty, s, s->cx, s->cy, 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; return;
} }
} }