From 8a90fce47655ed24a4656b8ebebb7b0c2fbc34dc Mon Sep 17 00:00:00 2001 From: Michael Grant Date: Tue, 10 Mar 2026 13:21:01 +0000 Subject: [PATCH] Fix for window size taller than tty. --- cmd-copy-mode.c | 4 +++- screen-write.c | 24 ++++++++++++++++-------- server-client.c | 6 ++++-- tmux.h | 2 +- window-copy.c | 29 ++++++++++++++++++++--------- 5 files changed, 44 insertions(+), 21 deletions(-) diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index fff0d9dd..5ac0192f 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -63,6 +63,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item) struct client *c = cmdq_get_client(item); struct session *s; struct window_pane *wp = target->wp, *swp; + u_int tty_ox, tty_oy, tty_sx, tty_sy; if (args_has(args, 'q')) { window_pane_reset_mode_all(wp); @@ -94,8 +95,9 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item) if (args_has(args, 'd')) window_copy_pagedown(wp, 0, args_has(args, 'e')); if (args_has(args, 'S')) { + tty_window_offset(&c->tty, &tty_ox, &tty_oy, &tty_sx, &tty_sy); window_copy_scroll(wp, c->tty.mouse_slider_mpos, event->m.y, - args_has(args, 'e')); + tty_oy, args_has(args, 'e')); return (CMD_RETURN_NORMAL); } diff --git a/screen-write.c b/screen-write.c index 72f5c7bc..92759adc 100644 --- a/screen-write.c +++ b/screen-write.c @@ -575,6 +575,7 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, struct grid *gd = src->grid; struct grid_cell gc; u_int xx, yy, cx = s->cx, cy = s->cy; + int yoff = 0; struct visible_ranges *r; if (nx == 0 || ny == 0) @@ -584,9 +585,12 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, if (yy >= gd->hsize + gd->sy) break; s->cx = cx; - if (wp != NULL) - screen_write_initctx(ctx, &ttyctx, 0); - r = screen_redraw_get_visible_ranges(wp, px, py, nx, NULL); + screen_write_initctx(ctx, &ttyctx, 0); + if (wp != NULL) { + yoff = wp->yoff; + } + r = screen_redraw_get_visible_ranges(wp, px, s->cy + yoff, nx, + NULL); for (xx = px; xx < px + nx; xx++) { if (xx >= grid_get_line(gd, yy)->cellsize && s->cx >= grid_get_line(ctx->s->grid, @@ -2300,7 +2304,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) struct tty_ctx ttyctx; u_int sx = screen_size_x(s), sy = screen_size_y(s); u_int width = ud->width, xx, not_wrap, i, n, vis; - int selected, skip = 1, redraw = 0; + int selected, skip = 1, redraw = 0, yoff = 0; struct visible_ranges *r; struct visible_range *ri; @@ -2400,8 +2404,10 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) if (selected) skip = 0; - /* xxx cache r in wp ? */ - r = screen_redraw_get_visible_ranges(wp, s->cx, s->cy, width, NULL); + if (wp != NULL) + yoff = wp->yoff; + r = screen_redraw_get_visible_ranges(wp, s->cx, s->cy + yoff, width, + NULL); /* * Move the cursor. If not wrapping, stick at the last character and @@ -2459,7 +2465,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) struct window_pane *wp = ctx->wp; struct grid *gd = s->grid; const struct utf8_data *ud = &gc->data; - u_int i, n, cx = s->cx, cy = s->cy, vis; + u_int i, n, cx = s->cx, cy = s->cy, vis, yoff = 0; struct grid_cell last; struct tty_ctx ttyctx; int force_wide = 0, zero_width = 0; @@ -2556,7 +2562,9 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) * be obscured in the middle, only on left or right, but there * could be an empty range in the visible ranges so we add them all up. */ - r = screen_redraw_get_visible_ranges(wp, cx - n, cy, n, NULL); + if (wp != NULL) + yoff = wp->yoff; + r = screen_redraw_get_visible_ranges(wp, cx - n, cy + yoff, n, NULL); for (i=0, vis=0; i < r->used; i++) vis += r->ranges[i].nx; if (vis < n) { /* diff --git a/server-client.c b/server-client.c index e8433a51..60e0f410 100644 --- a/server-client.c +++ b/server-client.c @@ -875,9 +875,11 @@ have_event: * scrollbar. */ if (where == NOWHERE) { - if (c->tty.mouse_scrolling_flag) + if (c->tty.mouse_scrolling_flag) { where = SCROLLBAR_SLIDER; - else { + m->wp = c->tty.mouse_wp->id; + m->w = c->tty.mouse_wp->window->id; + } else { px = x; if (m->statusat == 0 && y >= m->statuslines) py = y - m->statuslines; diff --git a/tmux.h b/tmux.h index 8106aafb..de841a27 100644 --- a/tmux.h +++ b/tmux.h @@ -3537,7 +3537,7 @@ void printflike(3, 4) window_copy_add(struct window_pane *, int, const char *, ...); void printflike(3, 0) window_copy_vadd(struct window_pane *, int, const char *, va_list); -void window_copy_scroll(struct window_pane *, int, u_int, int); +void window_copy_scroll(struct window_pane *, int, u_int, u_int, int); void window_copy_pageup(struct window_pane *, int); void window_copy_pagedown(struct window_pane *, int, int); void window_copy_start_drag(struct client *, struct mouse_event *); diff --git a/window-copy.c b/window-copy.c index 900b9ccc..9835706d 100644 --- a/window-copy.c +++ b/window-copy.c @@ -42,7 +42,7 @@ static void window_copy_formats(struct window_mode_entry *, struct format_tree *); static struct screen *window_copy_get_screen(struct window_mode_entry *); static void window_copy_scroll1(struct window_mode_entry *, - struct window_pane *wp, int, u_int, int); + struct window_pane *wp, int, u_int, u_int, int); static void window_copy_pageup1(struct window_mode_entry *, int); static int window_copy_pagedown1(struct window_mode_entry *, int, int); static void window_copy_next_paragraph(struct window_mode_entry *); @@ -596,19 +596,19 @@ window_copy_vadd(struct window_pane *wp, int parse, const char *fmt, va_list ap) void window_copy_scroll(struct window_pane *wp, int sl_mpos, u_int my, - int scroll_exit) + u_int tty_oy, int scroll_exit) { struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes); if (wme != NULL) { window_set_active_pane(wp->window, wp, 0); - window_copy_scroll1(wme, wp, sl_mpos, my, scroll_exit); + window_copy_scroll1(wme, wp, sl_mpos, my, tty_oy, scroll_exit); } } static void window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp, - int sl_mpos, u_int my, int scroll_exit) + int sl_mpos, u_int my, u_int tty_oy, int scroll_exit) { struct window_copy_mode_data *data = wme->data; u_int ox, oy, px, py, n, offset, size; @@ -616,21 +616,29 @@ window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp, u_int slider_height = wp->sb_slider_h; u_int sb_height = wp->sy, sb_top = wp->yoff; u_int sy = screen_size_y(data->backing); + u_int my_w; int new_slider_y, delta; /* * sl_mpos is where in the slider the user is dragging, mouse is * dragging this y point relative to top of slider. + * + * my is a raw tty y coordinate; sb_top (= wp->yoff) is a window + * coordinate. Convert my to window coordinates by adding tty_oy + * (the window pan offset). sl_mpos already has the statuslines + * adjustment baked in (see server_client_check_mouse), so no further + * statuslines correction is needed here. */ - if (my <= sb_top + sl_mpos) { + my_w = my + tty_oy; + if (my_w <= sb_top + (u_int)sl_mpos) { /* Slider banged into top. */ new_slider_y = sb_top - wp->yoff; - } else if (my - sl_mpos > sb_top + sb_height - slider_height) { + } else if (my_w - sl_mpos > sb_top + sb_height - slider_height) { /* Slider banged into bottom. */ new_slider_y = sb_top - wp->yoff + (sb_height - slider_height); } else { /* Slider is somewhere in the middle. */ - new_slider_y = my - wp->yoff - sl_mpos; + new_slider_y = my_w - wp->yoff - sl_mpos; } if (TAILQ_FIRST(&wp->modes) == NULL || @@ -1503,8 +1511,11 @@ window_copy_cmd_scroll_to_mouse(struct window_copy_cmd_state *cs) struct client *c = cs->c; struct mouse_event *m = cs->m; int scroll_exit = args_has(cs->wargs, 'e'); + u_int tty_ox, tty_oy, tty_sx, tty_sy; - window_copy_scroll(wp, c->tty.mouse_slider_mpos, m->y, scroll_exit); + tty_window_offset(&c->tty, &tty_ox, &tty_oy, &tty_sx, &tty_sy); + window_copy_scroll(wp, c->tty.mouse_slider_mpos, m->y, tty_oy, + scroll_exit); return (WINDOW_COPY_CMD_NOTHING); } @@ -4705,7 +4716,7 @@ window_copy_write_lines(struct window_mode_entry *wme, u_int yy; for (yy = py; yy < py + ny; yy++) - window_copy_write_line(wme, ctx, py); + window_copy_write_line(wme, ctx, yy); } static void