Include menus when working out what parts of a pane are visible to avoid

overwriting them, GitHub issue 5593.
This commit is contained in:
nicm
2026-10-02 15:20:41 +00:00
committed by tmux update bot
parent aed667218b
commit a21247a508
2 changed files with 106 additions and 96 deletions

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: screen-write.c,v 1.297 2026/10/02 14:16:42 nicm Exp $ */
/* $OpenBSD: screen-write.c,v 1.298 2026/10/02 15:20:41 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -189,11 +189,12 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
return (1);
}
/* Return 1 if there is a floating window pane overlapping this pane. */
/* Return 1 if a menu or floating pane overlaps this pane. */
static int
screen_write_pane_is_obscured(struct screen_write_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
struct menu_data *md;
if (ctx->wp == NULL)
return (0);
@@ -204,6 +205,16 @@ screen_write_pane_is_obscured(struct screen_write_ctx *ctx)
}
ctx->flags |= SCREEN_WRITE_CHECKED_IF_OBSCURED;
md = wp->window->menu;
if (md != NULL &&
(int)menu_x(md) < wp->xoff + (int)wp->sx &&
(int)(menu_x(md) + menu_width(md)) > wp->xoff &&
(int)menu_y(md) < wp->yoff + (int)wp->sy &&
(int)(menu_y(md) + menu_height(md)) > wp->yoff) {
ctx->flags |= SCREEN_WRITE_OBSCURED;
return (1);
}
if (ctx->wp->xoff < 0 ||
ctx->wp->yoff < 0 ||
ctx->wp->xoff + ctx->wp->sx > ctx->wp->window->sx ||
@@ -2435,13 +2446,18 @@ screen_write_collect_flush_line(struct screen_write_ctx *ctx, u_int y)
ttyctx.n = w_length;
tty_write(tty_cmd_clearcharacter, &ttyctx);
} else {
screen_write_initctx(ctx, &ttyctx, 0, 0);
ttyctx.cell = &ci->gc;
if (ci->wrapped)
ttyctx.flags |= TTY_CTX_WRAPPED;
ttyctx.data.data = cl->data + w_start;
ttyctx.data.size = w_length;
tty_write(tty_cmd_cells, &ttyctx);
screen_write_initctx(ctx, &ttyctx, 0, 1);
if (ttyctx.flags & TTY_CTX_PANE_OBSCURED) {
ttyctx.n = w_length;
tty_write(tty_cmd_redrawline, &ttyctx);
} else {
ttyctx.cell = &ci->gc;
if (ci->wrapped)
ttyctx.flags |= TTY_CTX_WRAPPED;
ttyctx.data.data = cl->data + w_start;
ttyctx.data.size = w_length;
tty_write(tty_cmd_cells, &ttyctx);
}
}
items++;
written = 1;
@@ -2844,6 +2860,11 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
/* Create space for character in insert mode. */
if (s->mode & MODE_INSERT) {
screen_write_collect_flush(ctx, 0, __func__);
if (wp != NULL && screen_write_pane_is_obscured(ctx)) {
if (screen_write_should_draw_line(ctx, s->cy))
screen_write_redraw_line(ctx, &ttyctx, s->cy);
return;
}
ttyctx.n = width;
if (screen_write_should_draw_line(ctx, s->cy))
tty_write(tty_cmd_insertcharacter, &ttyctx);

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: window-visible.c,v 1.5 2026/07/19 17:25:38 nicm Exp $ */
/* $OpenBSD: window-visible.c,v 1.6 2026/10/02 15:20:41 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -25,7 +25,7 @@
/*
* Check if a single character is within a visible range (not obscured by a
* floating pane).
* menu or floating pane).
*/
int
window_position_is_visible(struct visible_ranges *r, u_int px)
@@ -43,9 +43,45 @@ window_position_is_visible(struct visible_ranges *r, u_int px)
return (0);
}
/* Remove width cells starting at px from the visible ranges. */
static void
window_visible_ranges_remove(struct visible_ranges *r, int px, u_int width)
{
struct visible_range *ri;
u_int i;
int start, end, right = px + width;
if (width == 0)
return;
for (i = 0; i < r->used; i++) {
ri = &r->ranges[i];
start = ri->px;
end = start + ri->nx;
if (ri->nx == 0 || right <= start || px >= end)
continue;
if (px <= start) {
/* Remove the left part or the whole range. */
ri->px = right < end ? right : end;
ri->nx = end - ri->px;
} else {
/* Keep the left part, and split off any right part. */
ri->nx = px - start;
if (right < end) {
server_client_ensure_ranges(r, r->used + 1);
memmove(&r->ranges[i + 2], &r->ranges[i + 1],
(r->used - i - 1) * sizeof *r->ranges);
r->ranges[i + 1].px = right;
r->ranges[i + 1].nx = end - right;
r->used++;
}
}
}
}
/*
* Construct ranges array for the line at starting at px,py of width cells of
* base_wp that are unobsructed. All ranges are in window coordinates.
* base_wp that are unobstructed. All ranges are in window coordinates.
*/
struct visible_ranges *
window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
@@ -53,11 +89,10 @@ window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
{
struct window_pane *wp;
struct window *w;
struct visible_range *ri;
struct menu_data *md;
static struct visible_ranges sr = { NULL, 0, 0 };
int found_self, sb_w, sb_pos;
int lb, rb, tb, bb, sx, ex, no_border;
u_int i, s;
int lb, rb, tb, bb, no_border;
if (py < 0 || width == 0)
goto empty;
@@ -95,6 +130,13 @@ window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
r->used = 1;
}
/* The menu is above every pane in the window. */
md = w->menu;
if (md != NULL &&
(u_int)py >= menu_y(md) &&
(u_int)py - menu_y(md) < menu_height(md)) {
window_visible_ranges_remove(r, menu_x(md), menu_width(md));
}
found_self = 0;
TAILQ_FOREACH_REVERSE(wp, &w->z_index, window_panes_zindex, zentry) {
@@ -129,89 +171,36 @@ window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
else
sb_w = sb_pos = 0;
for (i = 0; i < r->used; i++) {
ri = &r->ranges[i];
if (ri->nx == 0)
continue;
if (no_border) {
lb = wp->xoff;
rb = wp->xoff + (int)wp->sx - 1;
} else if (sb_pos == PANE_SCROLLBARS_LEFT) {
if (wp->xoff > sb_w)
lb = wp->xoff - 1 - sb_w;
else
lb = 0;
} else { /* PANE_SCROLLBARS_RIGHT or none. */
if (wp->xoff > 0)
lb = wp->xoff - 1;
else
lb = 0;
}
if (!no_border) {
if (sb_pos == PANE_SCROLLBARS_LEFT)
rb = wp->xoff + (int)wp->sx;
else /* PANE_SCROLLBARS_RIGHT or none. */
rb = wp->xoff + (int)wp->sx + sb_w;
}
if (lb < 0)
if (no_border) {
lb = wp->xoff;
rb = wp->xoff + (int)wp->sx - 1;
} else if (sb_pos == PANE_SCROLLBARS_LEFT) {
if (wp->xoff > sb_w)
lb = wp->xoff - 1 - sb_w;
else
lb = 0;
} else { /* PANE_SCROLLBARS_RIGHT or none. */
if (wp->xoff > 0)
lb = wp->xoff - 1;
else
lb = 0;
if (rb < 0)
continue;
if (no_border && rb >= (int)w->sx)
rb = w->sx - 1;
else if (!no_border && rb > (int)w->sx)
rb = w->sx - 1;
if (lb > rb)
continue;
sx = ri->px;
ex = sx + ri->nx - 1;
if (lb > sx && lb <= ex && rb > ex) {
/*
* If the left edge of floating pane falls
* inside this range and right edge covers up
* to right of range, then shrink left edge of
* range.
*/
ri->nx = lb - sx;
} else if (rb >= sx && rb <= ex && lb <= sx) {
/*
* Else if the right edge of floating pane falls
* inside of this range and left edge covers
* the left of range, then move px forward to
* right edge of pane.
*/
ri->nx = ex - rb;
ri->px = rb + 1;
} else if (lb > sx && rb <= ex) {
/*
* Else if pane fully inside range then split
* into 2 ranges.
*/
server_client_ensure_ranges(r, r->used + 1);
for (s = r->used; s > i; s--) {
memcpy(&r->ranges[s], &r->ranges[s - 1],
sizeof *r->ranges);
}
ri = &r->ranges[i];
r->ranges[i + 1].px = rb + 1;
r->ranges[i + 1].nx = ex - rb;
/* ri->px was copied, unchanged. */
ri->nx = lb - sx;
r->used++;
} else if (lb <= sx && rb > ex) {
/*
* If floating pane completely covers this range
* then delete it (make it 0 length).
*/
ri->nx = 0;
} else {
/*
* The range is already obscured, do
* nothing.
*/
}
}
if (!no_border) {
if (sb_pos == PANE_SCROLLBARS_LEFT)
rb = wp->xoff + (int)wp->sx;
else /* PANE_SCROLLBARS_RIGHT or none. */
rb = wp->xoff + (int)wp->sx + sb_w;
}
if (lb < 0)
lb = 0;
if (rb < 0)
continue;
if (no_border && rb >= (int)w->sx)
rb = w->sx - 1;
else if (!no_border && rb > (int)w->sx)
rb = w->sx - 1;
if (lb <= rb)
window_visible_ranges_remove(r, lb, rb - lb + 1);
}
return (r);