diff options
author | Nicholas Marriott <nicm@cvs.openbsd.org> | 2024-11-05 09:41:18 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@cvs.openbsd.org> | 2024-11-05 09:41:18 +0000 |
commit | 3419b8a436d751400846bbf274c4f9f58d2128d5 (patch) | |
tree | 50a35b2f03b11f1d904cd258710a6d89e38801cd | |
parent | ff4058cdb37c54f478e2c1271634c78ea0a05490 (diff) |
Add support for a scrollbar at the side of each pane. New options
pane-scrollbars turn them on or off, pane-scrollbars-position sets the
position (left or right), and pane-scrollbars-style to set the colours.
Mouse support will come later. From Michael Grant in GitHub issue 4221.
-rw-r--r-- | usr.bin/tmux/layout.c | 70 | ||||
-rw-r--r-- | usr.bin/tmux/options-table.c | 35 | ||||
-rw-r--r-- | usr.bin/tmux/options.c | 6 | ||||
-rw-r--r-- | usr.bin/tmux/screen-redraw.c | 309 | ||||
-rw-r--r-- | usr.bin/tmux/screen-write.c | 15 | ||||
-rw-r--r-- | usr.bin/tmux/server-client.c | 59 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.1 | 44 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.h | 27 | ||||
-rw-r--r-- | usr.bin/tmux/window-copy.c | 9 | ||||
-rw-r--r-- | usr.bin/tmux/window.c | 35 |
10 files changed, 491 insertions, 118 deletions
diff --git a/usr.bin/tmux/layout.c b/usr.bin/tmux/layout.c index 33d680d37fa..b89e9574f00 100644 --- a/usr.bin/tmux/layout.c +++ b/usr.bin/tmux/layout.c @@ -1,4 +1,4 @@ -/* $OpenBSD: layout.c,v 1.48 2021/03/11 06:31:05 nicm Exp $ */ +/* $OpenBSD: layout.c,v 1.49 2024/11/05 09:41:17 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -275,7 +275,8 @@ layout_cell_is_bottom(struct window *w, struct layout_cell *lc) * the case for the most upper or lower panes only. */ static int -layout_add_border(struct window *w, struct layout_cell *lc, int status) +layout_add_horizontal_border(struct window *w, struct layout_cell *lc, + int status) { if (status == PANE_STATUS_TOP) return (layout_cell_is_top(w, lc)); @@ -290,22 +291,41 @@ layout_fix_panes(struct window *w, struct window_pane *skip) { struct window_pane *wp; struct layout_cell *lc; - int status; + int status, scrollbars, sb_pos; + u_int sx, sy, mode; status = options_get_number(w->options, "pane-border-status"); + scrollbars = options_get_number(w->options, "pane-scrollbars"); + sb_pos = options_get_number(w->options, "pane-scrollbars-position"); + TAILQ_FOREACH(wp, &w->panes, entry) { if ((lc = wp->layout_cell) == NULL || wp == skip) continue; wp->xoff = lc->xoff; wp->yoff = lc->yoff; + sx = lc->sx; + sy = lc->sy; - if (layout_add_border(w, lc, status)) { + if (layout_add_horizontal_border(w, lc, status)) { if (status == PANE_STATUS_TOP) wp->yoff++; - window_pane_resize(wp, lc->sx, lc->sy - 1); - } else - window_pane_resize(wp, lc->sx, lc->sy); + sy--; + } + + mode = window_pane_mode(wp); + if (scrollbars == PANE_SCROLLBARS_ALWAYS || + (scrollbars == PANE_SCROLLBARS_MODAL && + mode != WINDOW_PANE_NO_MODE)) { + if (sb_pos == PANE_SCROLLBARS_LEFT) { + sx = sx - PANE_SCROLLBARS_WIDTH; + wp->xoff = wp->xoff + PANE_SCROLLBARS_WIDTH; + } else /* sb_pos == PANE_SCROLLBARS_RIGHT */ + sx = sx - PANE_SCROLLBARS_WIDTH; + wp->flags |= PANE_REDRAWSCROLLBAR; + } + + window_pane_resize(wp, sx, sy); } } @@ -337,17 +357,22 @@ layout_resize_check(struct window *w, struct layout_cell *lc, { struct layout_cell *lcchild; u_int available, minimum; - int status; + int status, scrollbars; status = options_get_number(w->options, "pane-border-status"); + scrollbars = options_get_number(w->options, "pane-scrollbars"); + if (lc->type == LAYOUT_WINDOWPANE) { /* Space available in this cell only. */ if (type == LAYOUT_LEFTRIGHT) { available = lc->sx; - minimum = PANE_MINIMUM; + if (scrollbars) + minimum = PANE_MINIMUM + PANE_SCROLLBARS_WIDTH; + else + minimum = PANE_MINIMUM; } else { available = lc->sy; - if (layout_add_border(w, lc, status)) + if (layout_add_horizontal_border(w, lc, status)) minimum = PANE_MINIMUM + 1; else minimum = PANE_MINIMUM; @@ -873,6 +898,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size, u_int sx, sy, xoff, yoff, size1, size2, minimum; u_int new_size, saved_size, resize_first = 0; int full_size = (flags & SPAWN_FULLSIZE), status; + int scrollbars; /* * If full_size is specified, add a new cell at the top of the window @@ -883,6 +909,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size, else lc = wp->layout_cell; status = options_get_number(wp->window->options, "pane-border-status"); + scrollbars = options_get_number(wp->window->options, "pane-scrollbars"); /* Copy the old cell size. */ sx = lc->sx; @@ -893,11 +920,15 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size, /* Check there is enough space for the two new panes. */ switch (type) { case LAYOUT_LEFTRIGHT: - if (sx < PANE_MINIMUM * 2 + 1) + if (scrollbars) + minimum = PANE_MINIMUM * 2 + PANE_SCROLLBARS_WIDTH; + else + minimum = PANE_MINIMUM * 2 + 1; + if (sx < minimum) return (NULL); break; case LAYOUT_TOPBOTTOM: - if (layout_add_border(wp->window, lc, status)) + if (layout_add_horizontal_border(wp->window, lc, status)) minimum = PANE_MINIMUM * 2 + 2; else minimum = PANE_MINIMUM * 2 + 1; @@ -1054,7 +1085,7 @@ layout_spread_cell(struct window *w, struct layout_cell *parent) { struct layout_cell *lc; u_int number, each, size, this; - int change, changed, status; + int change, changed, status, scrollbars; number = 0; TAILQ_FOREACH (lc, &parent->cells, entry) @@ -1062,11 +1093,16 @@ layout_spread_cell(struct window *w, struct layout_cell *parent) if (number <= 1) return (0); status = options_get_number(w->options, "pane-border-status"); + scrollbars = options_get_number(w->options, "pane-scrollbars"); - if (parent->type == LAYOUT_LEFTRIGHT) - size = parent->sx; + if (parent->type == LAYOUT_LEFTRIGHT) { + if (scrollbars) + size = parent->sx - PANE_SCROLLBARS_WIDTH; + else + size = parent->sx; + } else if (parent->type == LAYOUT_TOPBOTTOM) { - if (layout_add_border(w, parent, status)) + if (layout_add_horizontal_border(w, parent, status)) size = parent->sy - 1; else size = parent->sy; @@ -1087,7 +1123,7 @@ layout_spread_cell(struct window *w, struct layout_cell *parent) change = each - (int)lc->sx; layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change); } else if (parent->type == LAYOUT_TOPBOTTOM) { - if (layout_add_border(w, lc, status)) + if (layout_add_horizontal_border(w, lc, status)) this = each + 1; else this = each; diff --git a/usr.bin/tmux/options-table.c b/usr.bin/tmux/options-table.c index 5e729af7d74..469d1c45fb5 100644 --- a/usr.bin/tmux/options-table.c +++ b/usr.bin/tmux/options-table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: options-table.c,v 1.183 2024/10/21 12:42:06 nicm Exp $ */ +/* $OpenBSD: options-table.c,v 1.184 2024/11/05 09:41:17 nicm Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -64,6 +64,12 @@ static const char *options_table_cursor_style_list[] = { "default", "blinking-block", "block", "blinking-underline", "underline", "blinking-bar", "bar", NULL }; +static const char *options_table_pane_scrollbars_list[] = { + "off", "modal", "on", NULL +}; +static const char *options_table_pane_scrollbars_position_list[] = { + "right", "left", NULL +}; static const char *options_table_pane_status_list[] = { "off", "top", "bottom", NULL }; @@ -1161,7 +1167,32 @@ const struct options_table_entry options_table[] = { .text = "The default colour palette for colours zero to 255." }, - { .name = "popup-style", + { .name = "pane-scrollbars", + .type = OPTIONS_TABLE_CHOICE, + .scope = OPTIONS_TABLE_WINDOW, + .choices = options_table_pane_scrollbars_list, + .default_num = PANE_SCROLLBARS_OFF, + .text = "Pane scrollbar state." + }, + + { .name = "pane-scrollbars-style", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .default_str = "bg=black,fg=white", + .flags = OPTIONS_TABLE_IS_STYLE, + .separator = ",", + .text = "Style of the pane scrollbar." + }, + + { .name = "pane-scrollbars-position", + .type = OPTIONS_TABLE_CHOICE, + .scope = OPTIONS_TABLE_WINDOW, + .choices = options_table_pane_scrollbars_position_list, + .default_num = PANE_SCROLLBARS_RIGHT, + .text = "Pane scrollbar position." + }, + + { .name = "popup-style", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, .default_str = "default", diff --git a/usr.bin/tmux/options.c b/usr.bin/tmux/options.c index e4799942288..8e2107df3cb 100644 --- a/usr.bin/tmux/options.c +++ b/usr.bin/tmux/options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: options.c,v 1.70 2024/07/22 15:27:42 nicm Exp $ */ +/* $OpenBSD: options.c,v 1.71 2024/11/05 09:41:17 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -1171,7 +1171,9 @@ options_push_changes(const char *name) RB_FOREACH(wp, window_pane_tree, &all_window_panes) colour_palette_from_option(&wp->palette, wp->options); } - if (strcmp(name, "pane-border-status") == 0) { + if (strcmp(name, "pane-border-status") == 0 || + strcmp(name, "pane-scrollbars") == 0 || + strcmp(name, "pane-scrollbars-position") == 0) { RB_FOREACH(w, windows, &windows) layout_fix_panes(w, NULL); } diff --git a/usr.bin/tmux/screen-redraw.c b/usr.bin/tmux/screen-redraw.c index af3f1cee11d..cbda4a6954d 100644 --- a/usr.bin/tmux/screen-redraw.c +++ b/usr.bin/tmux/screen-redraw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: screen-redraw.c,v 1.99 2024/10/08 09:40:50 nicm Exp $ */ +/* $OpenBSD: screen-redraw.c,v 1.100 2024/11/05 09:41:17 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -30,6 +30,11 @@ static void screen_redraw_draw_pane(struct screen_redraw_ctx *, struct window_pane *); static void screen_redraw_set_context(struct client *, struct screen_redraw_ctx *); +static void screen_redraw_draw_pane_scrollbars(struct screen_redraw_ctx *); +static void screen_redraw_draw_scrollbar(struct screen_redraw_ctx *, + struct window_pane *, int, int, int, u_int, u_int, u_int); +static void screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *, + struct window_pane *); #define START_ISOLATE "\342\201\246" #define END_ISOLATE "\342\201\251" @@ -113,9 +118,10 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp, u_int px, u_int py) { struct options *oo = wp->window->options; - int split = 0; u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy; - int pane_status = ctx->pane_status; + int hsplit = 0, vsplit = 0, pane_status = ctx->pane_status; + int pane_scrollbars = ctx->pane_scrollbars, sb_w = 0; + int sb_pos = ctx->pane_scrollbars_pos; /* Inside pane. */ if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey) @@ -125,62 +131,62 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp, switch (options_get_number(oo, "pane-border-indicators")) { case PANE_BORDER_COLOUR: case PANE_BORDER_BOTH: - split = 1; + hsplit = screen_redraw_two_panes(wp->window, 0); + vsplit = screen_redraw_two_panes(wp->window, 1); break; } - /* Left/right borders. */ - if (pane_status == PANE_STATUS_OFF) { - if (screen_redraw_two_panes(wp->window, 0) && split) { - if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2) - return (SCREEN_REDRAW_BORDER_RIGHT); - if (wp->xoff != 0 && - px == wp->xoff - 1 && - py > wp->sy / 2) - return (SCREEN_REDRAW_BORDER_LEFT); - } else { - if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { - if (wp->xoff != 0 && px == wp->xoff - 1) + /* Are scrollbars enabled? */ + if (pane_scrollbars == PANE_SCROLLBARS_ALWAYS || + (pane_scrollbars == PANE_SCROLLBARS_MODAL && + window_pane_mode(wp) != WINDOW_PANE_NO_MODE)) + sb_w = PANE_SCROLLBARS_WIDTH; + + /* + * Left/right borders. The wp->sy / 2 test is to colour only half the + * active window's border when there are two panes. + */ + if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { + if (sb_pos == PANE_SCROLLBARS_LEFT) { + if (wp->xoff - sb_w == 0 && px == wp->sx + sb_w) + if (!hsplit || (hsplit && py <= wp->sy / 2)) + return (SCREEN_REDRAW_BORDER_RIGHT); + if (wp->xoff - sb_w != 0 && px == wp->xoff - sb_w - 1) + if (!hsplit || (hsplit && py > wp->sy / 2)) return (SCREEN_REDRAW_BORDER_LEFT); - if (px == ex) + } else { /* sb_pos == PANE_SCROLLBARS_RIGHT */ + if (wp->xoff == 0 && px == wp->sx + sb_w) + if (!hsplit || (hsplit && py <= wp->sy / 2)) return (SCREEN_REDRAW_BORDER_RIGHT); - } - } - } else { - if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { if (wp->xoff != 0 && px == wp->xoff - 1) - return (SCREEN_REDRAW_BORDER_LEFT); - if (px == ex) - return (SCREEN_REDRAW_BORDER_RIGHT); + if (!hsplit || (hsplit && py > wp->sy / 2)) + return (SCREEN_REDRAW_BORDER_LEFT); } } /* Top/bottom borders. */ - if (pane_status == PANE_STATUS_OFF) { - if (screen_redraw_two_panes(wp->window, 1) && split) { - if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2) - return (SCREEN_REDRAW_BORDER_BOTTOM); - if (wp->yoff != 0 && - py == wp->yoff - 1 && - px > wp->sx / 2) - return (SCREEN_REDRAW_BORDER_TOP); - } else { - if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { + if (vsplit && pane_status == PANE_STATUS_OFF && sb_w == 0) { + if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2) + return (SCREEN_REDRAW_BORDER_BOTTOM); + if (wp->yoff != 0 && py == wp->yoff - 1 && px > wp->sx / 2) + return (SCREEN_REDRAW_BORDER_TOP); + } else { + if (sb_pos == PANE_SCROLLBARS_LEFT) { + if ((wp->xoff - sb_w == 0 || px >= wp->xoff - sb_w) && + (px <= ex || (sb_w != 0 && px - 1 == ex))) { + if (wp->yoff != 0 && py == wp->yoff - 1) + return (SCREEN_REDRAW_BORDER_TOP); + if (py == ey) + return (SCREEN_REDRAW_BORDER_BOTTOM); + } + } else { /* sb_pos == PANE_SCROLLBARS_RIGHT */ + if ((wp->xoff == 0 || px >= wp->xoff) && + (px <= ex || (sb_w != 0 && px - 1 == ex))) { if (wp->yoff != 0 && py == wp->yoff - 1) return (SCREEN_REDRAW_BORDER_TOP); if (py == ey) return (SCREEN_REDRAW_BORDER_BOTTOM); } - } - } else if (pane_status == PANE_STATUS_TOP) { - if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { - if (wp->yoff != 0 && py == wp->yoff - 1) - return (SCREEN_REDRAW_BORDER_TOP); - } - } else { - if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { - if (py == ey) - return (SCREEN_REDRAW_BORDER_BOTTOM); } } @@ -243,8 +249,12 @@ screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py) return (CELL_OUTSIDE); /* - * Construct a bitmask of whether the cells to the left (bit 4), right, + * Construct a bitmask of whether the cells to the left (bit 8), right, * top, and bottom (bit 1) of this cell are borders. + * + * bits 8 4 2 1: 2 + * 8 + 4 + * 1 */ if (px == 0 || screen_redraw_cell_border(ctx, px - 1, py)) borders |= 8; @@ -313,8 +323,10 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, struct window_pane *wp, *active; int pane_status = ctx->pane_status; u_int sx = w->sx, sy = w->sy; - int border; + int border, pane_scrollbars = ctx->pane_scrollbars; u_int right, line; + int sb_pos = ctx->pane_scrollbars_pos; + int sb_w = PANE_SCROLLBARS_WIDTH; *wpp = NULL; @@ -351,6 +363,35 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, goto next2; *wpp = wp; + /* Check if CELL_SCROLLBAR */ + if (pane_scrollbars == PANE_SCROLLBARS_ALWAYS || + (pane_scrollbars == PANE_SCROLLBARS_MODAL && + window_pane_mode(wp) != WINDOW_PANE_NO_MODE)) { + + if (pane_status == PANE_STATUS_TOP) + line = wp->yoff - 1; + else + line = wp->yoff + wp->sy; + + /* + * Check if py could lie within a scrollbar. If the + * pane is at the top then py == 0 to sy; if the pane + * is not at the top, then yoff to yoff + sy. + */ + if ((pane_status && py != line) || + (wp->yoff == 0 && py < wp->sy) || + (py >= wp->yoff && py < wp->yoff + wp->sy)) { + /* Check if px lies within a scrollbar. */ + if ((sb_pos == PANE_SCROLLBARS_RIGHT && + (px >= wp->xoff + wp->sx && + px < wp->xoff + wp->sx + sb_w)) || + (sb_pos == PANE_SCROLLBARS_LEFT && + (px >= wp->xoff - sb_w && + px < wp->xoff))) + return (CELL_SCROLLBAR); + } + } + /* * If definitely inside, return. If not on border, skip. * Otherwise work out the cell. @@ -510,14 +551,13 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx) /* Update status line and change flags if unchanged. */ static uint64_t -screen_redraw_update(struct client *c, uint64_t flags) +screen_redraw_update(struct screen_redraw_ctx *ctx, uint64_t flags) { + struct client *c = ctx->c; struct window *w = c->session->curw->window; struct window_pane *wp; - struct options *wo = w->options; int redraw; enum pane_lines lines; - struct screen_redraw_ctx ctx; if (c->message_string != NULL) redraw = status_message_redraw(c); @@ -531,17 +571,17 @@ screen_redraw_update(struct client *c, uint64_t flags) if (c->overlay_draw != NULL) flags |= CLIENT_REDRAWOVERLAY; - if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) { - screen_redraw_set_context(c, &ctx); - lines = options_get_number(wo, "pane-border-lines"); + if (ctx->pane_status != PANE_STATUS_OFF) { + lines = ctx->pane_lines; redraw = 0; TAILQ_FOREACH(wp, &w->panes, entry) { - if (screen_redraw_make_pane_status(c, wp, &ctx, lines)) + if (screen_redraw_make_pane_status(c, wp, ctx, lines)) redraw = 1; } if (redraw) flags |= CLIENT_REDRAWBORDERS; } + return (flags); } @@ -568,6 +608,10 @@ screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx) ctx->pane_status = options_get_number(wo, "pane-border-status"); ctx->pane_lines = options_get_number(wo, "pane-border-lines"); + ctx->pane_scrollbars = options_get_number(wo, "pane-scrollbars"); + ctx->pane_scrollbars_pos = options_get_number(wo, + "pane-scrollbars-position"); + tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy); log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name, @@ -585,11 +629,12 @@ screen_redraw_screen(struct client *c) if (c->flags & CLIENT_SUSPENDED) return; - flags = screen_redraw_update(c, c->flags); + screen_redraw_set_context(c, &ctx); + + flags = screen_redraw_update(&ctx, c->flags); if ((flags & CLIENT_ALLREDRAWFLAGS) == 0) return; - screen_redraw_set_context(c, &ctx); tty_sync_start(&c->tty); tty_update_mode(&c->tty, c->tty.mode, NULL); @@ -598,10 +643,12 @@ screen_redraw_screen(struct client *c) screen_redraw_draw_borders(&ctx); if (ctx.pane_status != PANE_STATUS_OFF) screen_redraw_draw_pane_status(&ctx); + screen_redraw_draw_pane_scrollbars(&ctx); } if (flags & CLIENT_REDRAWWINDOW) { log_debug("%s: redrawing panes", c->name); screen_redraw_draw_panes(&ctx); + screen_redraw_draw_pane_scrollbars(&ctx); } if (ctx.statuslines != 0 && (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) { @@ -616,20 +663,35 @@ screen_redraw_screen(struct client *c) tty_reset(&c->tty); } -/* Redraw a single pane. */ +/* Redraw a single pane and its scrollbar. */ void -screen_redraw_pane(struct client *c, struct window_pane *wp) +screen_redraw_pane(struct client *c, struct window_pane *wp, + int redraw_scrollbar_only) { - struct screen_redraw_ctx ctx; + struct screen_redraw_ctx ctx; + int pane_scrollbars, mode; if (!window_pane_visible(wp)) return; + mode = window_pane_mode(wp); screen_redraw_set_context(c, &ctx); tty_sync_start(&c->tty); tty_update_mode(&c->tty, c->tty.mode, NULL); - screen_redraw_draw_pane(&ctx, wp); + if (!redraw_scrollbar_only) + screen_redraw_draw_pane(&ctx, wp); + + /* + * Redraw scrollbar if needed. Always redraw scrollbar in a mode because + * if redrawing a pane, it's because pane has scrolled. + */ + pane_scrollbars = ctx.pane_scrollbars; + if (pane_scrollbars == PANE_SCROLLBARS_MODAL && + mode == WINDOW_PANE_NO_MODE) + pane_scrollbars = PANE_SCROLLBARS_OFF; + if (pane_scrollbars != PANE_SCROLLBARS_OFF) + screen_redraw_draw_pane_scrollbar(&ctx, wp); tty_reset(&c->tty); } @@ -675,8 +737,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) const struct grid_cell *tmp; struct overlay_ranges r; u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; - int arrows = 0, border; - int isolates; + int arrows = 0, border, isolates; if (c->overlay_check != NULL) { c->overlay_check(c, c->overlay_data, x, y, 1, &r); @@ -685,7 +746,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) } cell_type = screen_redraw_check_cell(ctx, x, y, &wp); - if (cell_type == CELL_INSIDE) + if (cell_type == CELL_INSIDE || cell_type == CELL_SCROLLBAR) return; if (wp == NULL) { @@ -870,3 +931,127 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette); } } + +/* Draw the panes scrollbars */ +static void +screen_redraw_draw_pane_scrollbars(struct screen_redraw_ctx *ctx) +{ + struct client *c = ctx->c; + struct window *w = c->session->curw->window; + struct window_pane *wp; + + log_debug("%s: %s @%u", __func__, c->name, w->id); + + TAILQ_FOREACH(wp, &w->panes, entry) { + switch (ctx->pane_scrollbars) { + case PANE_SCROLLBARS_OFF: + return; + case PANE_SCROLLBARS_MODAL: + if (window_pane_mode(wp) == WINDOW_PANE_NO_MODE) + return; + break; + case PANE_SCROLLBARS_ALWAYS: + break; + } + if (window_pane_visible(wp)) + screen_redraw_draw_pane_scrollbar(ctx, wp); + } +} + +/* Draw pane scrollbar. */ +void +screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *ctx, + struct window_pane *wp) +{ + struct screen *s = wp->screen; + double percent_view; + u_int sb = ctx->pane_scrollbars, total_height, sb_h = wp->sy; + u_int sb_pos = ctx->pane_scrollbars_pos, slider_h, slider_y; + u_int sb_w = PANE_SCROLLBARS_WIDTH, cm_y, cm_size; + int sb_x, sb_y = (int)(wp->yoff - ctx->oy); /* sb top */ + + if (window_pane_mode(wp) == WINDOW_PANE_NO_MODE) { + if (sb == PANE_SCROLLBARS_MODAL) + return; + /* Show slider at the bottom of the scrollbar. */ + total_height = screen_size_y(s) + screen_hsize(s); + percent_view = (double)sb_h / total_height; + slider_h = (double)sb_h * percent_view; + slider_y = sb_h - slider_h; + } else { + if (TAILQ_FIRST(&wp->modes) == NULL) + return; + if (window_copy_get_current_offset(wp, &cm_y, &cm_size) == 0) + return; + total_height = cm_size + sb_h; + percent_view = (double)sb_h / (cm_size + sb_h); + slider_h = (double)sb_h * percent_view; + slider_y = (sb_h + 1) * ((double)cm_y / total_height); + } + + if (sb_pos == PANE_SCROLLBARS_LEFT) + sb_x = (int)wp->xoff - sb_w - ctx->ox; + else + sb_x = (int)wp->xoff + wp->sx - ctx->ox; + + if (slider_h < 1) + slider_h = 1; + if (slider_y >= sb_h) + slider_y = sb_h - 1; + + screen_redraw_draw_scrollbar(ctx, wp, sb_pos, sb_x, sb_y, sb_h, + slider_h, slider_y); +} + +static void +screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx, + struct window_pane *wp, int sb_pos, int sb_x, int sb_y, u_int sb_h, + u_int slider_h, u_int slider_y) +{ + struct client *c = ctx->c; + struct window *w = wp->window; + struct tty *tty = &c->tty; + struct grid_cell gc, slgc, *gcp; + u_int i, j, sb_w = PANE_SCROLLBARS_WIDTH; + u_int pad_col = 0; + int px, py, ox = ctx->ox, oy = ctx->oy; + int sb_pad = PANE_SCROLLBARS_PADDING, sx = ctx->sx; + int sy = ctx->sy, xoff = wp->xoff, yoff = wp->yoff; + + /* Set up default style. */ + style_apply(&gc, w->options, "pane-scrollbars-style", NULL); + utf8_set(&gc.data, ' '); + + /* Set up style for slider. */ + memcpy(&slgc, &gc, sizeof slgc); + slgc.bg = gc.fg; + + if (sb_pad != 0) { + if (sb_pos == PANE_SCROLLBARS_RIGHT) + pad_col = 0; + else + pad_col = sb_w - 1; + } + + for (i = 0; i < sb_w; i++) { + for (j = 0; j < sb_h; j++) { + px = sb_x + i; + py = sb_y + j; + if (px < xoff - ox - 1 || px >= sx || px < 0 || + py < yoff - oy - 1 || py >= sy || py < 0) + continue; + tty_cursor(tty, px, py); + if (sb_pad && i == pad_col) { + tty_cell(tty, &grid_default_cell, + &grid_default_cell, NULL, NULL); + } else { + if (j >= slider_y && j < slider_y + slider_h) + gcp = &slgc; + else + gcp = &gc; + tty_cell(tty, gcp, &grid_default_cell, NULL, + NULL); + } + } + } +} diff --git a/usr.bin/tmux/screen-write.c b/usr.bin/tmux/screen-write.c index 47de30213e1..039cab62dd8 100644 --- a/usr.bin/tmux/screen-write.c +++ b/usr.bin/tmux/screen-write.c @@ -1,4 +1,4 @@ -/* $OpenBSD: screen-write.c,v 1.228 2024/10/25 15:00:18 nicm Exp $ */ +/* $OpenBSD: screen-write.c,v 1.229 2024/11/05 09:41:17 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -151,7 +151,7 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c) */ log_debug("%s: adding %%%u to deferred redraw", __func__, wp->id); - wp->flags |= PANE_REDRAW; + wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR); return (-1); } @@ -1178,13 +1178,14 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; + u_int sy = screen_size_y(s); if (ny == 0) ny = 1; if (s->cy < s->rupper || s->cy > s->rlower) { - if (ny > screen_size_y(s) - s->cy) - ny = screen_size_y(s) - s->cy; + if (ny > sy - s->cy) + ny = sy - s->cy; if (ny == 0) return; @@ -1376,13 +1377,14 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg) struct screen *s = ctx->s; struct grid *gd = s->grid; struct grid_line *gl; + u_int rupper = s->rupper, rlower = s->rlower; gl = grid_get_line(gd, gd->hsize + s->cy); if (wrapped) gl->flags |= GRID_LINE_WRAPPED; log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, - s->rupper, s->rlower); + rupper, rlower); if (bg != ctx->bg) { screen_write_collect_flush(ctx, 1, __func__); @@ -1700,6 +1702,9 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, ttyctx.num = ctx->scrolled; ttyctx.bg = ctx->bg; tty_write(tty_cmd_scrollup, &ttyctx); + + if (ctx->wp != NULL) + ctx->wp->flags |= PANE_REDRAWSCROLLBAR; } ctx->scrolled = 0; ctx->bg = 8; diff --git a/usr.bin/tmux/server-client.c b/usr.bin/tmux/server-client.c index 75c2f1824a1..1493b6726a5 100644 --- a/usr.bin/tmux/server-client.c +++ b/usr.bin/tmux/server-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server-client.c,v 1.414 2024/10/08 06:29:44 nicm Exp $ */ +/* $OpenBSD: server-client.c,v 1.415 2024/11/05 09:41:17 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -2230,7 +2230,7 @@ server_client_loop(void) server_client_check_pane_resize(wp); server_client_check_pane_buffer(wp); } - wp->flags &= ~PANE_REDRAW; + wp->flags &= ~(PANE_REDRAW|PANE_REDRAWSCROLLBAR); } check_window_name(w); } @@ -2662,7 +2662,7 @@ server_client_check_redraw(struct client *c) struct window_pane *wp; int needed, tty_flags, mode = tty->mode; uint64_t client_flags = 0; - int redraw; + int redraw_pane, redraw_scrollbar_only; u_int bit = 0; struct timeval tv = { .tv_usec = 1000 }; static struct event ev; @@ -2671,12 +2671,13 @@ server_client_check_redraw(struct client *c) if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) return; if (c->flags & CLIENT_ALLREDRAWFLAGS) { - log_debug("%s: redraw%s%s%s%s%s", c->name, + log_debug("%s: redraw%s%s%s%s%s%s", c->name, (c->flags & CLIENT_REDRAWWINDOW) ? " window" : "", (c->flags & CLIENT_REDRAWSTATUS) ? " status" : "", (c->flags & CLIENT_REDRAWBORDERS) ? " borders" : "", (c->flags & CLIENT_REDRAWOVERLAY) ? " overlay" : "", - (c->flags & CLIENT_REDRAWPANES) ? " panes" : ""); + (c->flags & CLIENT_REDRAWPANES) ? " panes" : "", + (c->flags & CLIENT_REDRAWSCROLLBARS) ? " scrollbars" : ""); } /* @@ -2691,11 +2692,15 @@ server_client_check_redraw(struct client *c) TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->flags & PANE_REDRAW) { needed = 1; + client_flags |= CLIENT_REDRAWPANES; break; } + if (wp->flags & PANE_REDRAWSCROLLBAR) { + needed = 1; + client_flags |= CLIENT_REDRAWSCROLLBARS; + /* no break - later panes may need redraw */ + } } - if (needed) - client_flags |= CLIENT_REDRAWPANES; } if (needed && (left = EVBUFFER_LENGTH(tty->out)) != 0) { log_debug("%s: redraw deferred (%zu left)", c->name, left); @@ -2708,23 +2713,30 @@ server_client_check_redraw(struct client *c) if (~c->flags & CLIENT_REDRAWWINDOW) { TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->flags & PANE_REDRAW) { + if (wp->flags & (PANE_REDRAW)) { log_debug("%s: pane %%%u needs redraw", c->name, wp->id); c->redraw_panes |= (1 << bit); + } else if (wp->flags & PANE_REDRAWSCROLLBAR) { + log_debug("%s: pane %%%u scrollbar " + "needs redraw", c->name, wp->id); + c->redraw_scrollbars |= (1 << bit); } if (++bit == 64) { /* * If more that 64 panes, give up and * just redraw the window. */ - client_flags &= CLIENT_REDRAWPANES; + client_flags &= ~(CLIENT_REDRAWPANES| + CLIENT_REDRAWSCROLLBARS); client_flags |= CLIENT_REDRAWWINDOW; break; } } if (c->redraw_panes != 0) c->flags |= CLIENT_REDRAWPANES; + if (c->redraw_scrollbars != 0) + c->flags |= CLIENT_REDRAWSCROLLBARS; } c->flags |= client_flags; return; @@ -2740,19 +2752,32 @@ server_client_check_redraw(struct client *c) * needs to be redrawn. */ TAILQ_FOREACH(wp, &w->panes, entry) { - redraw = 0; + redraw_pane = 0; + redraw_scrollbar_only = 0; if (wp->flags & PANE_REDRAW) - redraw = 1; - else if (c->flags & CLIENT_REDRAWPANES) - redraw = !!(c->redraw_panes & (1 << bit)); + redraw_pane = 1; + else if (c->flags & CLIENT_REDRAWPANES) { + if (c->redraw_panes & (1 << bit)) + redraw_pane = 1; + } else if (c->flags & CLIENT_REDRAWSCROLLBARS) { + if (c->redraw_scrollbars & (1 << bit)) + redraw_scrollbar_only = 1; + } bit++; - if (!redraw) + if (!redraw_pane && !redraw_scrollbar_only) continue; - log_debug("%s: redrawing pane %%%u", __func__, wp->id); - screen_redraw_pane(c, wp); + if (redraw_scrollbar_only) { + log_debug("%s: redrawing (scrollbar only) pane " + "%%%u", __func__, wp->id); + } else { + log_debug("%s: redrawing pane %%%u", __func__, + wp->id); + } + screen_redraw_pane(c, wp, redraw_scrollbar_only); } c->redraw_panes = 0; - c->flags &= ~CLIENT_REDRAWPANES; + c->redraw_scrollbars = 0; + c->flags &= ~(CLIENT_REDRAWPANES|CLIENT_REDRAWSCROLLBARS); } if (c->flags & CLIENT_ALLREDRAWFLAGS) { diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1 index 6e7aebfbebd..2c70a2c4e17 100644 --- a/usr.bin/tmux/tmux.1 +++ b/usr.bin/tmux/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.967 2024/10/17 17:22:01 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.968 2024/11/05 09:41:17 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 17 2024 $ +.Dd $Mdocdate: November 5 2024 $ .Dt TMUX 1 .Os .Sh NAME @@ -5026,6 +5026,46 @@ and .Ql heavy will fall back to standard ACS line drawing when UTF-8 is not supported. .Pp +.It Xo Ic pane-scrollbars +.Op Ic off | modal | on +.Xc +When enabled, a character based scrollbar appears on the left or right +of each pane. +A filled section of the scrollbar, known as the +.Ql slider , +represents the position and size of the visible part of the pane content. +.Pp +If set to +.Ic on +the scrollbar is visible all the time. +If set to +.Ic modal +the scrollbar only appears when the pane is in copy mode or view mode. +When the scrollbar is visible, the pane is narrowed by the width of the +scrollbar and the text in the pane is reflowed. +If set to +.Ic modal , +the pane is narrowed only when the scrollbar is visible. +.Pp +See also +.Xr pane-scrollbars-style . +.Pp +.It Ic pane-scrollbars-style Ar style +Set the scrollbars style. +For how to specify +.Ar style , +see the +.Sx STYLES +section. +The foreground colour is used for the slider, the background for the rest of the +scrollbar. +Attributes are ignored. +.Pp +.It Xo Ic pane-scrollbars-position +.Op Ic left | right +.Xc +Sets which side of the pane to display pane scrollbars on. +.Pp .It Ic window-status-activity-style Ar style Set status line style for windows with an activity alert. For how to specify diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index dac5d950e4e..5b571fbe11c 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1237 2024/10/25 15:32:51 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1238 2024/11/05 09:41:17 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -739,6 +739,7 @@ struct colour_palette { #define CELL_RIGHTJOIN 10 #define CELL_JOIN 11 #define CELL_OUTSIDE 12 +#define CELL_SCROLLBAR 13 /* Cell borders. */ #define CELL_BORDERS " xqlkmjwvtun~" @@ -985,6 +986,9 @@ struct screen_redraw_ctx { int pane_status; enum pane_lines pane_lines; + int pane_scrollbars; + int pane_scrollbars_pos; + struct grid_cell no_pane_gc; int no_pane_gc_set; @@ -1103,6 +1107,7 @@ struct window_pane { #define PANE_EMPTY 0x800 #define PANE_STYLECHANGED 0x1000 #define PANE_UNSEENCHANGES 0x2000 +#define PANE_REDRAWSCROLLBAR 0x4000 int argc; char **argv; @@ -1245,6 +1250,19 @@ TAILQ_HEAD(winlink_stack, winlink); #define PANE_STATUS_TOP 1 #define PANE_STATUS_BOTTOM 2 +/* Pane scrollbars option. */ +#define PANE_SCROLLBARS_OFF 0 +#define PANE_SCROLLBARS_MODAL 1 +#define PANE_SCROLLBARS_ALWAYS 2 + +/* Pane scrollbars position option. */ +#define PANE_SCROLLBARS_RIGHT 0 +#define PANE_SCROLLBARS_LEFT 1 + +/* Pane scrollbars width and padding. */ +#define PANE_SCROLLBARS_WIDTH 1 +#define PANE_SCROLLBARS_PADDING 0 + /* Layout direction. */ enum layout_type { LAYOUT_LEFTRIGHT, @@ -1880,13 +1898,15 @@ struct client { #define CLIENT_CLIPBOARDBUFFER 0x800000000ULL #define CLIENT_BRACKETPASTING 0x1000000000ULL #define CLIENT_ASSUMEPASTING 0x2000000000ULL +#define CLIENT_REDRAWSCROLLBARS 0x4000000000ULL #define CLIENT_ALLREDRAWFLAGS \ (CLIENT_REDRAWWINDOW| \ CLIENT_REDRAWSTATUS| \ CLIENT_REDRAWSTATUSALWAYS| \ CLIENT_REDRAWBORDERS| \ CLIENT_REDRAWOVERLAY| \ - CLIENT_REDRAWPANES) + CLIENT_REDRAWPANES| \ + CLIENT_REDRAWSCROLLBARS) #define CLIENT_UNATTACHEDFLAGS \ (CLIENT_DEAD| \ CLIENT_SUSPENDED| \ @@ -1913,6 +1933,7 @@ struct client { key_code last_key; uint64_t redraw_panes; + uint64_t redraw_scrollbars; int message_ignore_keys; int message_ignore_styles; @@ -3014,7 +3035,7 @@ 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 *); +void screen_redraw_pane(struct client *, struct window_pane *, int); /* screen.c */ void screen_init(struct screen *, u_int, u_int, u_int); diff --git a/usr.bin/tmux/window-copy.c b/usr.bin/tmux/window-copy.c index e1bdea65b5c..148b32f5189 100644 --- a/usr.bin/tmux/window-copy.c +++ b/usr.bin/tmux/window-copy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window-copy.c,v 1.362 2024/10/28 08:16:51 nicm Exp $ */ +/* $OpenBSD: window-copy.c,v 1.363 2024/11/05 09:41:17 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -4319,6 +4319,8 @@ window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny) window_copy_write_line(wme, &ctx, i); screen_write_cursormove(&ctx, data->cx, data->cy, 0); screen_write_stop(&ctx); + + wp->flags |= PANE_REDRAWSCROLLBAR; } static void @@ -5367,8 +5369,7 @@ window_copy_cursor_previous_word_pos(struct window_mode_entry *wme, py = hsize + data->cy - data->oy; grid_reader_start(&gr, back_s->grid, px, py); - grid_reader_cursor_previous_word(&gr, separators, /* already= */ 0, - /* stop_at_eol= */ 1); + grid_reader_cursor_previous_word(&gr, separators, 0, 1); grid_reader_get_cursor(&gr, &px, &py); *ppx = px; *ppy = py; @@ -5481,6 +5482,7 @@ window_copy_scroll_up(struct window_mode_entry *wme, u_int ny) window_copy_write_line(wme, &ctx, screen_size_y(s) - ny - 1); screen_write_cursormove(&ctx, data->cx, data->cy, 0); screen_write_stop(&ctx); + wp->flags |= PANE_REDRAWSCROLLBAR; } static void @@ -5514,6 +5516,7 @@ window_copy_scroll_down(struct window_mode_entry *wme, u_int ny) window_copy_write_line(wme, &ctx, 1); screen_write_cursormove(&ctx, data->cx, data->cy, 0); screen_write_stop(&ctx); + wp->flags |= PANE_REDRAWSCROLLBAR; } static void diff --git a/usr.bin/tmux/window.c b/usr.bin/tmux/window.c index ab0b49e9a21..e916410608c 100644 --- a/usr.bin/tmux/window.c +++ b/usr.bin/tmux/window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window.c,v 1.295 2024/10/05 12:10:16 nicm Exp $ */ +/* $OpenBSD: window.c,v 1.296 2024/11/05 09:41:17 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -584,11 +584,31 @@ struct window_pane * window_get_active_at(struct window *w, u_int x, u_int y) { struct window_pane *wp; + int pane_scrollbars; + u_int sb_pos, sb_w, xoff, sx; + + pane_scrollbars = options_get_number(w->options, "pane-scrollbars"); + sb_pos = options_get_number(w->options, "pane-scrollbars-position"); TAILQ_FOREACH(wp, &w->panes, entry) { if (!window_pane_visible(wp)) continue; - if (x < wp->xoff || x > wp->xoff + wp->sx) + + if (pane_scrollbars == PANE_SCROLLBARS_ALWAYS || + (pane_scrollbars == PANE_SCROLLBARS_MODAL && + window_pane_mode(wp) != WINDOW_PANE_NO_MODE)) + sb_w = PANE_SCROLLBARS_WIDTH; + else + sb_w = 0; + + if (sb_pos == PANE_SCROLLBARS_LEFT) { + xoff = wp->xoff - sb_w; + sx = wp->sx + sb_w; + } else { /* sb_pos == PANE_SCROLLBARS_RIGHT */ + xoff = wp->xoff; + sx = wp->sx + sb_w; + } + if (x < xoff || x > xoff + sx) continue; if (y < wp->yoff || y > wp->yoff + wp->sy) continue; @@ -1086,6 +1106,7 @@ window_pane_set_mode(struct window_pane *wp, struct window_pane *swp, struct args *args) { struct window_mode_entry *wme; + struct window *w = wp->window; if (!TAILQ_EMPTY(&wp->modes) && TAILQ_FIRST(&wp->modes)->mode == mode) return (1); @@ -1106,9 +1127,10 @@ window_pane_set_mode(struct window_pane *wp, struct window_pane *swp, TAILQ_INSERT_HEAD(&wp->modes, wme, entry); wme->screen = wme->mode->init(wme, fs, args); } - wp->screen = wme->screen; - wp->flags |= (PANE_REDRAW|PANE_CHANGED); + + wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR|PANE_CHANGED); + layout_fix_panes(w, NULL); server_redraw_window_borders(wp->window); server_status_window(wp->window); @@ -1121,6 +1143,7 @@ void window_pane_reset_mode(struct window_pane *wp) { struct window_mode_entry *wme, *next; + struct window *w = wp->window; if (TAILQ_EMPTY(&wp->modes)) return; @@ -1141,7 +1164,9 @@ window_pane_reset_mode(struct window_pane *wp) if (next->mode->resize != NULL) next->mode->resize(next, wp->sx, wp->sy); } - wp->flags |= (PANE_REDRAW|PANE_CHANGED); + + wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR|PANE_CHANGED); + layout_fix_panes(w, NULL); server_redraw_window_borders(wp->window); server_status_window(wp->window); |