diff --git a/screen-write.c b/screen-write.c index 62327a49f..905f9a4c7 100644 --- a/screen-write.c +++ b/screen-write.c @@ -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 @@ -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); diff --git a/window-visible.c b/window-visible.c index a49bfa2ef..a1ee90307 100644 --- a/window-visible.c +++ b/window-visible.c @@ -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 @@ -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);