diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 5e9b444e..7655d541 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -30,8 +30,8 @@ const struct cmd_entry cmd_copy_mode_entry = { .name = "copy-mode", .alias = NULL, - .args = { "deHMs:t:uq", 0, 0, NULL }, - .usage = "[-deHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE, + .args = { "deHMs:t:uqS", 0, 0, NULL }, + .usage = "[-deHMuqS] [-s src-pane] " CMD_TARGET_PANE_USAGE, .source = { 's', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 }, @@ -92,7 +92,12 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item) if (args_has(args, 'u')) window_copy_pageup(wp, 0); if (args_has(args, 'd')) - window_copy_pagedown(wp, 0, args_has(args, 'e')); + window_copy_pagedown(wp, 0, args_has(args, 'e')); + if (args_has(args, 'S')) { + window_copy_scroll(wp, c->tty.mouse_slider_mpos, + event->m.y, args_has(args, 'e')); + return (CMD_RETURN_NORMAL); + } return (CMD_RETURN_NORMAL); } diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 135729f5..d5bc2f9d 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -219,6 +219,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) free(title); return (CMD_RETURN_NORMAL); } + wp->flags |= PANE_REDRAWSCROLLBAR; if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE)) activewp = server_client_get_pane(c); diff --git a/key-bindings.c b/key-bindings.c index 6d2a0109..4dec1543 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -640,6 +640,9 @@ key_bindings_init(void) "bind -Tcopy-mode-vi M-x { send -X jump-to-mark }", "bind -Tcopy-mode-vi C-Up { send -X scroll-up }", "bind -Tcopy-mode-vi C-Down { send -X scroll-down }", + "bind -n MouseDown1ScrollbarUp { copy-mode -u }", + "bind -n MouseDown1ScrollbarDown { copy-mode -d }", + "bind -n MouseDrag1ScrollbarSlider { copy-mode -S }" }; u_int i; struct cmd_parse_result *pr; diff --git a/layout.c b/layout.c index 04a13b0c..cfafc8ca 100644 --- a/layout.c +++ b/layout.c @@ -119,7 +119,7 @@ layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n) case LAYOUT_LEFTRIGHT: case LAYOUT_TOPBOTTOM: TAILQ_FOREACH(lcchild, &lc->cells, entry) - layout_print_cell(lcchild, hdr, n + 1); + layout_print_cell(lcchild, hdr, n + 1); break; case LAYOUT_WINDOWPANE: break; @@ -230,7 +230,7 @@ layout_fix_offsets1(struct layout_cell *lc) void layout_fix_offsets(struct window *w) { - struct layout_cell *lc = w->layout_root; + struct layout_cell *lc = w->layout_root; lc->xoff = 0; lc->yoff = 0; @@ -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,46 @@ 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, sb_w; + u_int sx, sy; + u_int 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"); + sb_w = PANE_SCROLLBARS_WIDTH; + 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 = sy - 1; + } + + 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 - sb_w; + wp->xoff = wp->xoff + sb_w; + } else { + /* sb_pos == PANE_SCROLLBARS_RIGHT */ + sx = sx - sb_w; + } + wp->flags |= PANE_REDRAWSCROLLBAR; + } + + window_pane_resize(wp, sx, sy); } } @@ -337,17 +362,23 @@ layout_resize_check(struct window *w, struct layout_cell *lc, { struct layout_cell *lcchild; u_int available, minimum; - int status; + int status, scrollbars, sb_w; status = options_get_number(w->options, "pane-border-status"); + scrollbars = options_get_number(w->options, "pane-scrollbars"); + sb_w = PANE_SCROLLBARS_WIDTH; + 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 + sb_w; + 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; @@ -872,7 +903,8 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size, struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2; 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 full_size = (flags & SPAWN_FULLSIZE); + int status, scrollbars, sb_w; /* * If full_size is specified, add a new cell at the top of the window @@ -883,6 +915,8 @@ 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"); + sb_w = PANE_SCROLLBARS_WIDTH; /* Copy the old cell size. */ sx = lc->sx; @@ -893,11 +927,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 + sb_w; + 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 +1092,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, sb_w; number = 0; TAILQ_FOREACH (lc, &parent->cells, entry) @@ -1062,11 +1100,17 @@ 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"); + sb_w = PANE_SCROLLBARS_WIDTH; - if (parent->type == LAYOUT_LEFTRIGHT) - size = parent->sx; + if (parent->type == LAYOUT_LEFTRIGHT) { + if (scrollbars) + size = parent->sx - sb_w; + 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 +1131,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/options-table.c b/options-table.c index bc7b12e5..16e57642 100644 --- a/options-table.c +++ b/options-table.c @@ -63,6 +63,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 }; @@ -1160,7 +1166,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/options.c b/options.c index bcdab82e..6576064a 100644 --- a/options.c +++ b/options.c @@ -425,7 +425,7 @@ options_array_set(struct options_entry *o, u_int idx, const char *value, struct options_array_item *a; char *new; struct cmd_parse_result *pr; - long long number; + long long number; if (!OPTIONS_IS_ARRAY(o)) { if (cause != NULL) @@ -1175,6 +1175,11 @@ options_push_changes(const char *name) RB_FOREACH(w, windows, &windows) layout_fix_panes(w, NULL); } + if (strcmp(name, "pane-scrollbars") == 0 || + strcmp(name, "pane-scrollbars-position") == 0) { + RB_FOREACH(w, windows, &windows) + layout_fix_panes(w, NULL); + } RB_FOREACH(s, sessions, &sessions) status_update_cache(s); diff --git a/screen-redraw.c b/screen-redraw.c index 410bd78d..a8a3ff83 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -30,6 +30,13 @@ 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 client *, + struct window_pane *, int, u_int, u_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" @@ -107,15 +114,81 @@ screen_redraw_two_panes(struct window *w, int direction) return (1); } +/* + * This is how panes are referenced in screen_redraw_pane_border: + * + * sb_pos == PANE_SCROLLBARS_RIGHT: + * + * .0................o..............X. + * :a zSSSBa zSSS: <- dotted border is outside of tmux, + * |___wp->sx___|_| |___wp->sx___|_| this is the terminal window + * | sb_w^ | sb_w^ + * ^wp->xoff ^wp->xoff + * + * sb_pos == PANE_SCROLLBARS_LEFT: + * + * .0...................o...........X. + * :SSSa zBSSSa z: <- Notes, see below + * |_||___wp->sx___||_||___wp->sx___| + * sb_w^ | sb_w^ | + * ^wp->xoff ^wp->xoff + * + * Terminal window tmux runs inide is X+1 characters wide + * 0 is the first column of the terminal + * X is the last column of the terminal, so 0-79 is 80 chars wide (px is [0..X]) + * o is the offset of righthand pane in diagram (not a variable) + * a is the first column of each pane + * z is the last column of each pane + * wp->xoff (rel to terminal) is character offset of the pane, + * it will be 0 for left pane and o for right pane above. + * wp->sx is size of pane (usable width of pane in characters) + * sb_w is the width of the scrollbar in characters + * S is the scrollbar, (in this example sb_w would be 3) + * B is the pane border, if there is a right and left and they are superimposed + * + * The vertical situation looks like this: + * ..... + * :Border (if pane-border-status==top) + * 0: | <- wp->yoff + * : | + * : | + * : wp->sy + * : | + * : | + * :Border + * o: | <- wp->yoff + * : | + * : | + * : wp->sy + * : | + * : | + * :Border (if pane-border-status==bottom) + * Y:Status line(s) + * ..... + * + * 0 is first line of terminal + * Y is last line of terminal (py is [0..Y]) + * o is the offset of the lower window in diagram (not a variable) + * wp->yoff (rel to terminal) is first line of pane + * wp->sy is usable size of pane in lines (6 in above example) + * There can be zero to 5 status lines + * Panes can have an optional border status + * + */ + /* Check if cell is on the border of a pane. */ static enum screen_redraw_border_type 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; + int hsplit = 0; + int vsplit = 0; u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy; int pane_status = ctx->pane_status; + int pane_scrollbars = ctx->pane_scrollbars; + int sb_pos = ctx->pane_scrollbars_pos; + int sb_w = PANE_SCROLLBARS_WIDTH; /* Inside pane. */ if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey) @@ -125,62 +198,85 @@ 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) - return (SCREEN_REDRAW_BORDER_LEFT); - if (px == ex) - return (SCREEN_REDRAW_BORDER_RIGHT); - } - } + if (pane_scrollbars == PANE_SCROLLBARS_ALWAYS || + (pane_scrollbars == PANE_SCROLLBARS_MODAL && + window_pane_mode(wp) != WINDOW_PANE_NO_MODE)) { + pane_scrollbars = 1; } 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); + sb_w = 0; + } + + /* Left/right borders. + * + * The wp->sy / 2 test is used to show half the active + * window's border and the other half the other + * window. It's easy to do this when 1 window + * vertically, so this feature only works when there's + * exactly 2 side-by-side panes. This could be + * genralised in the future. + */ + 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); + } 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); + if (wp->xoff != 0 && + px == wp->xoff - 1) + 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 (wp->yoff != 0 && py == wp->yoff - 1) + if (vsplit && + pane_status == PANE_STATUS_OFF && + pane_scrollbars == PANE_SCROLLBARS_OFF) { + 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 || + (pane_scrollbars && 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 || + (pane_scrollbars && 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 +339,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; @@ -315,6 +415,9 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, u_int sx = w->sx, sy = w->sy; int border; u_int right, line; + int pane_scrollbars = ctx->pane_scrollbars; + int sb_pos = ctx->pane_scrollbars_pos; + int sb_w = PANE_SCROLLBARS_WIDTH; *wpp = NULL; @@ -351,6 +454,37 @@ 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 scroller + * if pane at the top then py==0 included + * if pane 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 scroller + */ + 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 +644,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 +664,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 +701,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 +722,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 +736,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,11 +756,13 @@ 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) { struct screen_redraw_ctx ctx; + int pane_scrollbars; + int pane_mode; if (!window_pane_visible(wp)) return; @@ -631,6 +773,26 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) 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_mode = window_pane_mode(wp); + + if (wp->flags & PANE_REDRAWSCROLLBAR || + pane_mode != WINDOW_PANE_NO_MODE) { + + pane_scrollbars = ctx.pane_scrollbars; + + if (pane_scrollbars == PANE_SCROLLBARS_MODAL && + pane_mode == WINDOW_PANE_NO_MODE) { + pane_scrollbars = 0; + } + if (pane_scrollbars != 0) { + screen_redraw_draw_pane_scrollbar(&ctx, wp); + } + } + tty_reset(&c->tty); } @@ -651,10 +813,13 @@ screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x, wp->border_gc_set = 1; ft = format_create_defaults(NULL, c, s, s->curw, wp); - if (screen_redraw_check_is(ctx, x, y, active)) - style_apply(&wp->border_gc, oo, "pane-active-border-style", ft); - else + if (screen_redraw_check_is(ctx, x, y, active)) { + log_debug("%s: %s y:%u active", __func__, c->name, y); + style_apply(&wp->border_gc, oo, "pane-active-border-style", ft); + } else { + log_debug("%s: %s y:%u", __func__, c->name, y); style_apply(&wp->border_gc, oo, "pane-border-style", ft); + } format_free(ft); return (&wp->border_gc); @@ -685,7 +850,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) { @@ -874,3 +1039,151 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) tty_draw_images(c, wp, s); #endif } + +/* 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 scrollbar + * + * sb_x and sb_y are the upper left character of the scrollbar + * sb_h is scrollbar height, the number of lines in the scrollbar + * slider_h is the height of the slider in lines + * slider_y is the line within sb_h of the current vertical position + * The height and position of the slider are proportional to the number of + * lines in the scroll back buffer + number of lines on the screen + * (total_height) and the percentage of the number of visible lines to the + * total height (percent_view). + */ +void +screen_redraw_draw_pane_scrollbar(struct screen_redraw_ctx *ctx, + struct window_pane *wp) +{ + struct client *c = ctx->c; + struct screen *s = wp->screen; + double percent_view; + u_int sb = ctx->pane_scrollbars; + u_int sb_pos = ctx->pane_scrollbars_pos; + u_int sb_w = PANE_SCROLLBARS_WIDTH; + u_int sb_x; + u_int sb_y = wp->yoff; + u_int sb_h = wp->sy; + u_int slider_h; + u_int slider_y; + u_int total_height; + + if (window_pane_mode(wp) == WINDOW_PANE_NO_MODE) { + /* not in a 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 = (u_int)((double)sb_h * percent_view); + slider_y = sb_h - slider_h; + } else { + /* copy-mode or view-mode */ + u_int cm_y_pos, cm_size; + + if (TAILQ_FIRST(&wp->modes) == NULL || + window_copy_get_current_offset(wp, &cm_y_pos, &cm_size) == 0) + return; + total_height = cm_size + sb_h; + percent_view = (double)sb_h / (cm_size + sb_h); + slider_h = (u_int)((double)sb_h * percent_view); + slider_y = (u_int)(sb_h + 1) * ((double)cm_y_pos / total_height); + } + + if (sb_pos == PANE_SCROLLBARS_LEFT) + sb_x = wp->xoff - sb_w; + else + sb_x = wp->xoff + wp->sx; + + if (slider_h < 1) + slider_h = 1; + if (slider_y >= sb_h) + slider_y = sb_h - 1; + + screen_redraw_draw_scrollbar(c, wp, sb_pos, sb_x, sb_y, sb_h, + slider_h, slider_y); + + /* Store current position and height of the slider */ + wp->sb_slider_y = slider_y; /* top of slider y pos in scrollbar */ + wp->sb_slider_h = slider_h; /* height of slider */ +} + +static void +screen_redraw_draw_scrollbar(struct client *c, struct window_pane *wp, + int sb_pos, u_int px, u_int py, u_int sb_h, u_int slider_h, u_int slider_y) +{ + struct window *w = wp->window; + struct tty *tty = &c->tty; + struct grid_cell gc; + u_int i, j; + int fg, bg; + u_int pad_col = 0; + u_int sb_w = PANE_SCROLLBARS_WIDTH; + u_int sb_pad = PANE_SCROLLBARS_PADDING; + + log_debug("%s: scrollbar pos:%d w:%u @%u,%u h:%u eh:%u ep:%u", + __func__, sb_pos, sb_w, px, py, sb_h, slider_h, slider_y); + + /* Set up default colour. */ + style_apply(&gc, w->options, "pane-scrollbars-style", NULL); + fg = gc.fg; + bg = gc.bg; + utf8_set(&gc.data, ' '); + + if (sb_pad) { + if (sb_pos == PANE_SCROLLBARS_RIGHT) + pad_col = 0; + else + pad_col = sb_w - 1; + } + + gc.bg = bg; + for (i = 0; i < sb_w; i++) { + for (j = 0; j < sb_h; j++) { + tty_cursor(tty, px+i, py+j); + + 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) { + gc.bg = fg; + gc.fg = bg; + } else { + gc.bg = bg; + gc.fg = fg; + } + tty_cell(tty, &gc, &grid_default_cell, NULL, + NULL); + } + } + } +} diff --git a/screen-write.c b/screen-write.c index 2128eda9..d5c9f99a 100644 --- a/screen-write.c +++ b/screen-write.c @@ -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); } @@ -1792,6 +1792,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/server-client.c b/server-client.c index dbc8a8e9..2ce9a816 100644 --- a/server-client.c +++ b/server-client.c @@ -66,7 +66,7 @@ RB_GENERATE(client_windows, client_window, entry, server_client_window_cmp); u_int server_client_how_many(void) { - struct client *c; + struct client *c; u_int n; n = 0; @@ -572,6 +572,7 @@ server_client_check_mouse(struct client *c, struct key_event *event) { struct mouse_event *m = &event->m; struct session *s = c->session, *fs; + struct options *wo = s->curw->window->options; struct winlink *fwl; struct window_pane *wp, *fwp; u_int x, y, b, sx, sy, px, py; @@ -579,6 +580,9 @@ server_client_check_mouse(struct client *c, struct key_event *event) key_code key; struct timeval tv; struct style_range *sr; + int pane_scrollbars, sb_w, pane_status; + u_int line = 0, sb_pos; + u_int slider_top, slider_bottom, where_in_slider = 0; enum { NOTYPE, MOVE, DOWN, @@ -594,7 +598,11 @@ server_client_check_mouse(struct client *c, struct key_event *event) STATUS_LEFT, STATUS_RIGHT, STATUS_DEFAULT, - BORDER } where = NOWHERE; + BORDER, + SCROLLBAR_UP, + SCROLLBAR_SLIDER, + SCROLLBAR_DOWN, + } where = NOWHERE; log_debug("%s mouse %02x at %u,%u (last %u,%u) (%d)", c->name, m->b, m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag); @@ -743,54 +751,117 @@ have_event: } } - /* Not on status line. Adjust position and check for border or pane. */ + /* + * Not on status line. Adjust position and check for + * border, pane, or scrollbar. + */ if (where == NOWHERE) { - px = x; - if (m->statusat == 0 && y >= m->statuslines) - py = y - m->statuslines; - else if (m->statusat > 0 && y >= (u_int)m->statusat) - py = m->statusat - 1; - else - py = y; - - tty_window_offset(&c->tty, &m->ox, &m->oy, &sx, &sy); - log_debug("mouse window @%u at %u,%u (%ux%u)", - s->curw->window->id, m->ox, m->oy, sx, sy); - if (px > sx || py > sy) - return (KEYC_UNKNOWN); - px = px + m->ox; - py = py + m->oy; - - /* Try the pane borders if not zoomed. */ - if (~s->curw->window->flags & WINDOW_ZOOMED) { - TAILQ_FOREACH(wp, &s->curw->window->panes, entry) { - if ((wp->xoff + wp->sx == px && - wp->yoff <= 1 + py && - wp->yoff + wp->sy >= py) || - (wp->yoff + wp->sy == py && - wp->xoff <= 1 + px && - wp->xoff + wp->sx >= px)) - break; - } - if (wp != NULL) - where = BORDER; - } - - /* Otherwise try inside the pane. */ - if (where == NOWHERE) { - wp = window_get_active_at(s->curw->window, px, py); - if (wp != NULL) - where = PANE; + if (c->tty.mouse_scrolling_flag) { + where = SCROLLBAR_SLIDER; + } else { + px = x; + if (m->statusat == 0 && y >= m->statuslines) + py = y - m->statuslines; + else if (m->statusat > 0 && y >= (u_int)m->statusat) + py = m->statusat - 1; else + py = y; + + tty_window_offset(&c->tty, &m->ox, &m->oy, &sx, &sy); + log_debug("mouse window @%u at %u,%u (%ux%u)", + s->curw->window->id, m->ox, m->oy, sx, sy); + if (px > sx || py > sy) return (KEYC_UNKNOWN); + px = px + m->ox; + py = py + m->oy; + + /* try inside the pane. */ + wp = window_get_active_at(s->curw->window, px, py); + + if (wp == NULL) + return (KEYC_UNKNOWN); + + /* Try the scrollbar which is actually next to a pane */ + pane_scrollbars = options_get_number(wo, "pane-scrollbars"); + sb_pos = options_get_number(wo, "pane-scrollbars-position"); + 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; + + pane_status = options_get_number(wo, "pane-border-status"); + + if (pane_status == PANE_STATUS_TOP) + line = wp->yoff - 1; + else if (pane_status == PANE_STATUS_BOTTOM) + line = wp->yoff + wp->sy; + + /* check if py could lie within a scroller + * if pane at the top then py==0 included + * if pane 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 scroller + log_debug("wps @%u at %u,%u (%ux%u)", wp->id, + m->ox, m->oy, px, py); + */ + 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))) { + + /* definitely in the scrollbar */ + slider_top = wp->yoff + wp->sb_slider_y; + slider_bottom = wp->yoff + wp->sb_slider_y + wp->sb_slider_h - 1; + if (py < slider_top) + where = SCROLLBAR_UP; + else if (py >= slider_top && + py <= slider_bottom) { + where = SCROLLBAR_SLIDER; + where_in_slider = py - wp->sb_slider_y - wp->yoff; + } else + /* py > slider_bottom */ + where = SCROLLBAR_DOWN; + } else { + where = PANE; + } + } else { + /* Try the pane borders if not zoomed. */ + if (~s->curw->window->flags & WINDOW_ZOOMED) { + TAILQ_FOREACH(wp, &s->curw->window->panes, entry) { + if ((wp->xoff + wp->sx == px && + wp->yoff <= 1 + py && + wp->yoff + wp->sy >= py) || + (wp->yoff + wp->sy == py && + wp->xoff <= 1 + px && + wp->xoff + wp->sx >= px)) + break; + } + if (wp != NULL) + where = BORDER; + } + } + + if (where == PANE) + log_debug("mouse %u,%u on pane %%%u", x, y, wp->id); + else if (where == BORDER) + log_debug("mouse on pane %%%u border", wp->id); + else if (where == SCROLLBAR_UP || + where == SCROLLBAR_SLIDER || + where == SCROLLBAR_DOWN) + log_debug("mouse on pane %%%u scrollbar", wp->id); + m->wp = wp->id; + m->w = wp->window->id; } - if (where == PANE) - log_debug("mouse %u,%u on pane %%%u", x, y, wp->id); - else if (where == BORDER) - log_debug("mouse on pane %%%u border", wp->id); - m->wp = wp->id; - m->w = wp->window->id; - } + } else + m->wp = -1; /* Stop dragging if needed. */ if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag != 0) { @@ -799,6 +870,7 @@ have_event: c->tty.mouse_drag_update = NULL; c->tty.mouse_drag_release = NULL; + c->tty.mouse_scrolling_flag = 0; /* * End a mouse drag by passing a MouseDragEnd key corresponding @@ -816,6 +888,8 @@ have_event: key = KEYC_MOUSEDRAGEND1_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAGEND1_STATUS_DEFAULT; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAGEND1_SCROLLBAR_SLIDER; if (where == BORDER) key = KEYC_MOUSEDRAGEND1_BORDER; break; @@ -830,6 +904,8 @@ have_event: key = KEYC_MOUSEDRAGEND2_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAGEND2_STATUS_DEFAULT; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAGEND2_SCROLLBAR_SLIDER; if (where == BORDER) key = KEYC_MOUSEDRAGEND2_BORDER; break; @@ -844,6 +920,8 @@ have_event: key = KEYC_MOUSEDRAGEND3_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAGEND3_STATUS_DEFAULT; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAGEND3_SCROLLBAR_SLIDER; if (where == BORDER) key = KEYC_MOUSEDRAGEND3_BORDER; break; @@ -858,6 +936,8 @@ have_event: key = KEYC_MOUSEDRAGEND6_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAGEND6_STATUS_DEFAULT; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAGEND6_SCROLLBAR_SLIDER; if (where == BORDER) key = KEYC_MOUSEDRAGEND6_BORDER; break; @@ -872,6 +952,8 @@ have_event: key = KEYC_MOUSEDRAGEND7_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAGEND7_STATUS_DEFAULT; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAGEND7_SCROLLBAR_SLIDER; if (where == BORDER) key = KEYC_MOUSEDRAGEND7_BORDER; break; @@ -886,6 +968,8 @@ have_event: key = KEYC_MOUSEDRAGEND8_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAGEND8_STATUS_DEFAULT; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAGEND8_SCROLLBAR_SLIDER; if (where == BORDER) key = KEYC_MOUSEDRAGEND8_BORDER; break; @@ -900,6 +984,8 @@ have_event: key = KEYC_MOUSEDRAGEND9_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAGEND9_STATUS_DEFAULT; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAGEND9_SCROLLBAR_SLIDER; if (where == BORDER) key = KEYC_MOUSEDRAGEND9_BORDER; break; @@ -914,6 +1000,8 @@ have_event: key = KEYC_MOUSEDRAGEND10_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAGEND10_STATUS_DEFAULT; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAGEND10_SCROLLBAR_SLIDER; if (where == BORDER) key = KEYC_MOUSEDRAGEND10_BORDER; break; @@ -928,6 +1016,8 @@ have_event: key = KEYC_MOUSEDRAGEND11_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAGEND11_STATUS_DEFAULT; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAGEND11_SCROLLBAR_SLIDER; if (where == BORDER) key = KEYC_MOUSEDRAGEND11_BORDER; break; @@ -936,6 +1026,7 @@ have_event: break; } c->tty.mouse_drag_flag = 0; + c->tty.mouse_slider_mpos = -1; goto out; } @@ -974,6 +1065,12 @@ have_event: key = KEYC_MOUSEDRAG1_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAG1_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDRAG1_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAG1_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDRAG1_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDRAG1_BORDER; break; @@ -988,6 +1085,12 @@ have_event: key = KEYC_MOUSEDRAG2_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAG2_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDRAG2_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAG2_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDRAG2_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDRAG2_BORDER; break; @@ -1002,6 +1105,12 @@ have_event: key = KEYC_MOUSEDRAG3_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAG3_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDRAG3_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAG3_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDRAG3_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDRAG3_BORDER; break; @@ -1016,6 +1125,12 @@ have_event: key = KEYC_MOUSEDRAG6_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAG6_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDRAG6_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAG6_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDRAG6_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDRAG6_BORDER; break; @@ -1030,6 +1145,12 @@ have_event: key = KEYC_MOUSEDRAG7_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAG7_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDRAG7_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAG7_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDRAG7_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDRAG7_BORDER; break; @@ -1044,6 +1165,12 @@ have_event: key = KEYC_MOUSEDRAG8_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAG8_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDRAG8_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAG8_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDRAG8_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDRAG8_BORDER; break; @@ -1058,6 +1185,12 @@ have_event: key = KEYC_MOUSEDRAG9_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAG9_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDRAG9_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAG9_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDRAG9_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDRAG9_BORDER; break; @@ -1072,6 +1205,12 @@ have_event: key = KEYC_MOUSEDRAG10_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAG10_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDRAG10_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAG10_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDRAG10_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDRAG10_BORDER; break; @@ -1086,6 +1225,12 @@ have_event: key = KEYC_MOUSEDRAG11_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDRAG11_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDRAG11_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDRAG11_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDRAG11_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDRAG11_BORDER; break; @@ -1094,9 +1239,16 @@ have_event: /* * Begin a drag by setting the flag to a non-zero value that - * corresponds to the mouse button in use. + * corresponds to the mouse button in use. If starting to + * drag the scrollbar, store the relative position in the + * slider where the user grabed. */ c->tty.mouse_drag_flag = MOUSE_BUTTONS(b) + 1; + if (c->tty.mouse_scrolling_flag == 0 && + where == SCROLLBAR_SLIDER) { + c->tty.mouse_scrolling_flag = 1; + c->tty.mouse_slider_mpos = where_in_slider; + } break; case WHEEL: if (MOUSE_BUTTONS(b) == MOUSE_WHEEL_UP) { @@ -1140,6 +1292,12 @@ have_event: key = KEYC_MOUSEUP1_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEUP1_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEUP1_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEUP1_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEUP1_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEUP1_BORDER; break; @@ -1154,6 +1312,12 @@ have_event: key = KEYC_MOUSEUP2_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEUP2_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEUP2_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEUP2_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEUP2_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEUP2_BORDER; break; @@ -1168,6 +1332,12 @@ have_event: key = KEYC_MOUSEUP3_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEUP3_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEUP3_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEUP3_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEUP3_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEUP3_BORDER; break; @@ -1182,6 +1352,12 @@ have_event: key = KEYC_MOUSEUP6_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEUP6_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEUP6_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEUP6_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEUP6_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEUP6_BORDER; break; @@ -1196,6 +1372,12 @@ have_event: key = KEYC_MOUSEUP7_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEUP7_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEUP7_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEUP7_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEUP7_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEUP7_BORDER; break; @@ -1210,6 +1392,12 @@ have_event: key = KEYC_MOUSEUP8_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEUP8_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEUP8_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEUP8_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEUP8_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEUP8_BORDER; break; @@ -1224,6 +1412,12 @@ have_event: key = KEYC_MOUSEUP9_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEUP9_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEUP9_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEUP9_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEUP9_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEUP9_BORDER; break; @@ -1237,7 +1431,13 @@ have_event: if (where == STATUS_RIGHT) key = KEYC_MOUSEUP1_STATUS_RIGHT; if (where == STATUS_DEFAULT) - key = KEYC_MOUSEUP1_STATUS_DEFAULT; + key = KEYC_MOUSEUP10_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEUP10_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEUP10_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEUP1_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEUP1_BORDER; break; @@ -1252,6 +1452,12 @@ have_event: key = KEYC_MOUSEUP11_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEUP11_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEUP11_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEUP11_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEUP11_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEUP11_BORDER; break; @@ -1270,6 +1476,12 @@ have_event: key = KEYC_MOUSEDOWN1_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDOWN1_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDOWN1_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDOWN1_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDOWN1_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDOWN1_BORDER; break; @@ -1284,6 +1496,12 @@ have_event: key = KEYC_MOUSEDOWN2_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDOWN2_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDOWN2_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDOWN2_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDOWN2_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDOWN2_BORDER; break; @@ -1298,6 +1516,12 @@ have_event: key = KEYC_MOUSEDOWN3_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDOWN3_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDOWN3_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDOWN3_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDOWN3_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDOWN3_BORDER; break; @@ -1312,6 +1536,12 @@ have_event: key = KEYC_MOUSEDOWN6_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDOWN6_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDOWN6_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDOWN6_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDOWN6_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDOWN6_BORDER; break; @@ -1326,6 +1556,12 @@ have_event: key = KEYC_MOUSEDOWN7_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDOWN7_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDOWN7_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDOWN7_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDOWN7_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDOWN7_BORDER; break; @@ -1340,6 +1576,12 @@ have_event: key = KEYC_MOUSEDOWN8_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDOWN8_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDOWN8_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDOWN8_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDOWN8_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDOWN8_BORDER; break; @@ -1354,6 +1596,12 @@ have_event: key = KEYC_MOUSEDOWN9_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDOWN9_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDOWN9_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDOWN9_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDOWN9_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDOWN9_BORDER; break; @@ -1368,6 +1616,12 @@ have_event: key = KEYC_MOUSEDOWN10_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDOWN10_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDOWN10_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDOWN10_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDOWN10_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDOWN10_BORDER; break; @@ -1382,6 +1636,12 @@ have_event: key = KEYC_MOUSEDOWN11_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_MOUSEDOWN11_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_MOUSEDOWN11_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_MOUSEDOWN11_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_MOUSEDOWN11_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_MOUSEDOWN11_BORDER; break; @@ -1400,6 +1660,12 @@ have_event: key = KEYC_SECONDCLICK1_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_SECONDCLICK1_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_SECONDCLICK1_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_SECONDCLICK1_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_SECONDCLICK1_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_SECONDCLICK1_BORDER; break; @@ -1414,6 +1680,12 @@ have_event: key = KEYC_SECONDCLICK2_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_SECONDCLICK2_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_SECONDCLICK2_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_SECONDCLICK2_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_SECONDCLICK2_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_SECONDCLICK2_BORDER; break; @@ -1428,6 +1700,12 @@ have_event: key = KEYC_SECONDCLICK3_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_SECONDCLICK3_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_SECONDCLICK3_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_SECONDCLICK3_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_SECONDCLICK3_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_SECONDCLICK3_BORDER; break; @@ -1442,6 +1720,12 @@ have_event: key = KEYC_SECONDCLICK6_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_SECONDCLICK6_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_SECONDCLICK6_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_SECONDCLICK6_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_SECONDCLICK6_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_SECONDCLICK6_BORDER; break; @@ -1456,6 +1740,12 @@ have_event: key = KEYC_SECONDCLICK7_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_SECONDCLICK7_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_SECONDCLICK7_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_SECONDCLICK7_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_SECONDCLICK7_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_SECONDCLICK7_BORDER; break; @@ -1470,6 +1760,12 @@ have_event: key = KEYC_SECONDCLICK8_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_SECONDCLICK8_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_SECONDCLICK8_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_SECONDCLICK8_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_SECONDCLICK8_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_SECONDCLICK8_BORDER; break; @@ -1484,6 +1780,12 @@ have_event: key = KEYC_SECONDCLICK9_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_SECONDCLICK9_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_SECONDCLICK9_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_SECONDCLICK9_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_SECONDCLICK9_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_SECONDCLICK9_BORDER; break; @@ -1498,6 +1800,12 @@ have_event: key = KEYC_SECONDCLICK10_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_SECONDCLICK10_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_SECONDCLICK10_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_SECONDCLICK10_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_SECONDCLICK10_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_SECONDCLICK10_BORDER; break; @@ -1512,6 +1820,12 @@ have_event: key = KEYC_SECONDCLICK11_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_SECONDCLICK11_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_SECONDCLICK11_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_SECONDCLICK11_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_SECONDCLICK11_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_SECONDCLICK11_BORDER; break; @@ -1530,6 +1844,12 @@ have_event: key = KEYC_DOUBLECLICK1_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_DOUBLECLICK1_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_DOUBLECLICK1_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_DOUBLECLICK1_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_DOUBLECLICK1_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_DOUBLECLICK1_BORDER; break; @@ -1544,6 +1864,12 @@ have_event: key = KEYC_DOUBLECLICK2_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_DOUBLECLICK2_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_DOUBLECLICK2_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_DOUBLECLICK2_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_DOUBLECLICK2_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_DOUBLECLICK2_BORDER; break; @@ -1558,6 +1884,12 @@ have_event: key = KEYC_DOUBLECLICK3_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_DOUBLECLICK3_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_DOUBLECLICK3_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_DOUBLECLICK3_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_DOUBLECLICK3_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_DOUBLECLICK3_BORDER; break; @@ -1572,6 +1904,12 @@ have_event: key = KEYC_DOUBLECLICK6_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_DOUBLECLICK6_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_DOUBLECLICK6_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_DOUBLECLICK6_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_DOUBLECLICK6_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_DOUBLECLICK6_BORDER; break; @@ -1586,6 +1924,12 @@ have_event: key = KEYC_DOUBLECLICK7_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_DOUBLECLICK7_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_DOUBLECLICK7_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_DOUBLECLICK7_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_DOUBLECLICK7_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_DOUBLECLICK7_BORDER; break; @@ -1600,6 +1944,12 @@ have_event: key = KEYC_DOUBLECLICK8_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_DOUBLECLICK8_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_DOUBLECLICK8_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_DOUBLECLICK8_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_DOUBLECLICK8_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_DOUBLECLICK8_BORDER; break; @@ -1614,6 +1964,12 @@ have_event: key = KEYC_DOUBLECLICK9_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_DOUBLECLICK9_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_DOUBLECLICK9_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_DOUBLECLICK9_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_DOUBLECLICK9_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_DOUBLECLICK9_BORDER; break; @@ -1628,6 +1984,12 @@ have_event: key = KEYC_DOUBLECLICK10_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_DOUBLECLICK10_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_DOUBLECLICK10_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_DOUBLECLICK10_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_DOUBLECLICK10_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_DOUBLECLICK10_BORDER; break; @@ -1642,6 +2004,12 @@ have_event: key = KEYC_DOUBLECLICK11_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_DOUBLECLICK11_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_DOUBLECLICK11_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_DOUBLECLICK11_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_DOUBLECLICK11_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_DOUBLECLICK11_BORDER; break; @@ -1660,6 +2028,12 @@ have_event: key = KEYC_TRIPLECLICK1_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_TRIPLECLICK1_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_TRIPLECLICK1_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_TRIPLECLICK1_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_TRIPLECLICK1_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_TRIPLECLICK1_BORDER; break; @@ -1674,6 +2048,12 @@ have_event: key = KEYC_TRIPLECLICK2_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_TRIPLECLICK2_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_TRIPLECLICK2_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_TRIPLECLICK2_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_TRIPLECLICK2_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_TRIPLECLICK2_BORDER; break; @@ -1688,6 +2068,12 @@ have_event: key = KEYC_TRIPLECLICK3_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_TRIPLECLICK3_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_TRIPLECLICK3_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_TRIPLECLICK3_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_TRIPLECLICK3_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_TRIPLECLICK3_BORDER; break; @@ -1702,6 +2088,12 @@ have_event: key = KEYC_TRIPLECLICK6_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_TRIPLECLICK6_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_TRIPLECLICK6_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_TRIPLECLICK6_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_TRIPLECLICK6_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_TRIPLECLICK6_BORDER; break; @@ -1716,6 +2108,12 @@ have_event: key = KEYC_TRIPLECLICK7_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_TRIPLECLICK7_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_TRIPLECLICK7_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_TRIPLECLICK7_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_TRIPLECLICK7_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_TRIPLECLICK7_BORDER; break; @@ -1730,6 +2128,12 @@ have_event: key = KEYC_TRIPLECLICK8_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_TRIPLECLICK8_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_TRIPLECLICK8_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_TRIPLECLICK8_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_TRIPLECLICK8_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_TRIPLECLICK8_BORDER; break; @@ -1744,6 +2148,12 @@ have_event: key = KEYC_TRIPLECLICK9_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_TRIPLECLICK9_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_TRIPLECLICK9_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_TRIPLECLICK9_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_TRIPLECLICK9_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_TRIPLECLICK9_BORDER; break; @@ -1758,6 +2168,12 @@ have_event: key = KEYC_TRIPLECLICK10_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_TRIPLECLICK10_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_TRIPLECLICK10_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_TRIPLECLICK10_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_TRIPLECLICK10_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_TRIPLECLICK10_BORDER; break; @@ -1772,6 +2188,12 @@ have_event: key = KEYC_TRIPLECLICK11_STATUS_RIGHT; if (where == STATUS_DEFAULT) key = KEYC_TRIPLECLICK11_STATUS_DEFAULT; + if (where == SCROLLBAR_UP) + key = KEYC_TRIPLECLICK11_SCROLLBAR_UP; + if (where == SCROLLBAR_SLIDER) + key = KEYC_TRIPLECLICK11_SCROLLBAR_SLIDER; + if (where == SCROLLBAR_DOWN) + key = KEYC_TRIPLECLICK11_SCROLLBAR_DOWN; if (where == BORDER) key = KEYC_TRIPLECLICK11_BORDER; break; @@ -1806,7 +2228,7 @@ server_client_is_bracket_paste(struct client *c, key_code key) } if (key == KEYC_PASTE_END) { - c->flags &= ~CLIENT_BRACKETPASTING; + c->flags &= ~CLIENT_BRACKETPASTING; log_debug("%s: bracket paste off", c->name); return (0); } @@ -2226,7 +2648,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); } @@ -2685,7 +3107,7 @@ server_client_check_redraw(struct client *c) needed = 1; else { TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->flags & PANE_REDRAW) { + if (wp->flags & (PANE_REDRAW|PANE_REDRAWSCROLLBAR)) { needed = 1; break; } @@ -2704,7 +3126,7 @@ 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|PANE_REDRAWSCROLLBAR)) { log_debug("%s: pane %%%u needs redraw", c->name, wp->id); c->redraw_panes |= (1 << bit); @@ -2737,7 +3159,7 @@ server_client_check_redraw(struct client *c) */ TAILQ_FOREACH(wp, &w->panes, entry) { redraw = 0; - if (wp->flags & PANE_REDRAW) + if (wp->flags & (PANE_REDRAW)) redraw = 1; else if (c->flags & CLIENT_REDRAWPANES) redraw = !!(c->redraw_panes & (1 << bit)); @@ -3261,7 +3683,7 @@ const char * server_client_get_flags(struct client *c) { static char s[256]; - char tmp[32]; + char tmp[32]; *s = '\0'; if (c->flags & CLIENT_ATTACHED) diff --git a/tmux.1 b/tmux.1 index 285f7651..51f351e7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2402,22 +2402,31 @@ The synopsis for the command is: .Bl -tag -width Ds .It Xo Ic copy-mode -.Op Fl deHMqu +.Op Fl deHMquS .Op Fl s Ar src-pane .Op Fl t Ar target-pane .Xc Enter copy mode. +.Pp .Fl u -also scrolls one page up after entering and +enters copy mode and scrolls one page up and .Fl d -one page down if already in copy mode. -.Fl M -begins a mouse drag (only valid if bound to a mouse key binding, see -.Sx MOUSE SUPPORT ) . +one page down. .Fl H hides the position indicator in the top right. .Fl q cancels copy mode and any other modes. +.Pp +.Fl M +begins a mouse drag (only valid if bound to a mouse key binding, see +.Sx MOUSE SUPPORT ) . +.Fl S +scrolls when bound to a mouse drag event; for example, +.Ic copy-mode -Se +is bound to +.Ar MouseDrag1ScrollbarSlider +by default. +.Pp .Fl s copies from .Ar src-pane @@ -5028,6 +5037,55 @@ 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. +By default dragging the scrollbar slider up will enter copy mode; in copy +mode dragging the slider will scroll the pane. +.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 +When the +.Ic mouse +option is on, clicking above and below the slider pages up and down and dragging +the slider scrolls the pane. +.Pp +See also +.Xr pane-scrollbar-style +and the scrollbar mouse events in the +.Sx MOUSE SUPPORT +section. +.Pp +.It Ic pane-scrollbar-style Ar style +Set the pane scrollbar style for the currently active pane. +For how to specify +.Ar style , +see the +.Sx STYLES +section. +Attributes are ignored. +.Pp +.It Xo Ic pane-scrollbars-position +.Op Ic left | right +.Xc +Sets which side of the pane to display the pane scrollbars on. The +default is right. +.Pp .It Ic window-status-activity-style Ar style Set status line style for windows with an activity alert. For how to specify @@ -5400,6 +5458,9 @@ and a location suffix, one of the following: .It Li "StatusLeft" Ta "the left part of the status line" .It Li "StatusRight" Ta "the right part of the status line" .It Li "StatusDefault" Ta "any other part of the status line" +.It Li "ScrollbarSlider" Ta "the scrollbar slider" +.It Li "ScrollbarUp" Ta "above the scrollbar slider" +.It Li "ScrollbarDown" Ta "below the scrollbar slider" .El .Pp The following mouse events are available: diff --git a/tmux.h b/tmux.h index 86392052..7130f78c 100644 --- a/tmux.h +++ b/tmux.h @@ -184,13 +184,19 @@ struct winlink; KEYC_ ## name ## _STATUS_LEFT, \ KEYC_ ## name ## _STATUS_RIGHT, \ KEYC_ ## name ## _STATUS_DEFAULT, \ + KEYC_ ## name ## _SCROLLBAR_UP, \ + KEYC_ ## name ## _SCROLLBAR_SLIDER, \ + KEYC_ ## name ## _SCROLLBAR_DOWN, \ KEYC_ ## name ## _BORDER -#define KEYC_MOUSE_STRING(name, s) \ - { #s "Pane", KEYC_ ## name ## _PANE }, \ - { #s "Status", KEYC_ ## name ## _STATUS }, \ - { #s "StatusLeft", KEYC_ ## name ## _STATUS_LEFT }, \ - { #s "StatusRight", KEYC_ ## name ## _STATUS_RIGHT }, \ - { #s "StatusDefault", KEYC_ ## name ## _STATUS_DEFAULT }, \ +#define KEYC_MOUSE_STRING(name, s) \ + { #s "Pane", KEYC_ ## name ## _PANE }, \ + { #s "Status", KEYC_ ## name ## _STATUS }, \ + { #s "StatusLeft", KEYC_ ## name ## _STATUS_LEFT }, \ + { #s "StatusRight", KEYC_ ## name ## _STATUS_RIGHT }, \ + { #s "StatusDefault", KEYC_ ## name ## _STATUS_DEFAULT }, \ + { #s "ScrollbarUp", KEYC_ ## name ## _SCROLLBAR_UP }, \ + { #s "ScrollbarSlider", KEYC_ ## name ## _SCROLLBAR_SLIDER }, \ + { #s "ScrollbarDown", KEYC_ ## name ## _SCROLLBAR_DOWN }, \ { #s "Border", KEYC_ ## name ## _BORDER } /* @@ -747,6 +753,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~" @@ -1015,6 +1022,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; @@ -1133,6 +1143,10 @@ struct window_pane { #define PANE_EMPTY 0x800 #define PANE_STYLECHANGED 0x1000 #define PANE_UNSEENCHANGES 0x2000 +#define PANE_REDRAWSCROLLBAR 0x4000 + + u_int sb_slider_y; + u_int sb_slider_h; int argc; char **argv; @@ -1275,6 +1289,17 @@ TAILQ_HEAD(winlink_stack, winlink); #define PANE_STATUS_TOP 1 #define PANE_STATUS_BOTTOM 2 +/* Pane scrollbars options. */ +#define PANE_SCROLLBARS_OFF 0 +#define PANE_SCROLLBARS_MODAL 1 +#define PANE_SCROLLBARS_ALWAYS 2 +#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, @@ -1524,6 +1549,9 @@ struct tty { u_int mouse_last_y; u_int mouse_last_b; int mouse_drag_flag; + int mouse_scrolling_flag; + int mouse_slider_mpos; + void (*mouse_drag_update)(struct client *, struct mouse_event *); void (*mouse_drag_release)(struct client *, @@ -3288,6 +3316,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_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 b271d5bb..6438f267 100644 --- a/window-copy.c +++ b/window-copy.c @@ -40,6 +40,8 @@ static void window_copy_free(struct window_mode_entry *); static void window_copy_resize(struct window_mode_entry *, u_int, u_int); static void window_copy_formats(struct window_mode_entry *, struct format_tree *); +static void window_copy_scroll1(struct window_mode_entry *, + struct window_pane *wp, 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 *); @@ -274,7 +276,7 @@ struct window_copy_mode_data { u_int cx; u_int cy; - u_int lastcx; /* position in last line w/ content */ + u_int lastcx; /* position in last line w/ content */ u_int lastsx; /* size of last line w/ content */ u_int mx; /* mark position */ @@ -546,7 +548,7 @@ window_copy_vadd(struct window_pane *wp, int parse, const char *fmt, va_list ap) struct window_copy_mode_data *data = wme->data; struct screen *backing = data->backing; struct screen *writing = data->writing; - struct screen_write_ctx writing_ctx, backing_ctx, ctx; + struct screen_write_ctx writing_ctx, backing_ctx, ctx; struct grid_cell gc; u_int old_hsize, old_cy; u_int sx = screen_size_x(backing); @@ -598,6 +600,122 @@ window_copy_vadd(struct window_pane *wp, int parse, const char *fmt, va_list ap) screen_write_stop(&ctx); } +void +window_copy_scroll(struct window_pane *wp, int sl_mpos, u_int my, + int scroll_exit) +{ + struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes); + + window_set_active_pane(wp->window, wp, 0); + + if (wme != NULL) { + window_copy_scroll1(wme, wp, sl_mpos, my, 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) +{ + struct window_copy_mode_data *data = wme->data; + u_int ox, oy, px, py, n, offset, size; + u_int new_offset, slider_y = wp->sb_slider_y; + 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); + int new_slider_y, delta; + + log_debug("%s: slider %u mouse %u", __func__, slider_y, my); + + /* + * sl_mpos is where in the slider the user is dragging, mouse + * is dragging this y point relative to top of slider. + */ + if (my <= sb_top + sl_mpos) { + /* Slider banged into top. */ + new_slider_y = sb_top - wp->yoff; + } else if (my - 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 + 1; + } + + log_debug("%s: new slider %u mouse %u", __func__, new_slider_y, my); + + if (TAILQ_FIRST(&wp->modes) == NULL || + window_copy_get_current_offset(wp, &offset, &size) == 0) + return; + + /* + * See screen_redraw_draw_pane_scrollbar(), this is the inverse of the + * formula used there. + */ + new_offset = new_slider_y * ((float)(size + sb_height) / sb_height); + delta = (int)offset - new_offset; + + log_debug("%s: delta %d mouse %u", __func__, delta, my); + + /* + * Move pane view around based on delta relative to the cursor, + * maintaining the selection. + */ + oy = screen_hsize(data->backing) + data->cy - data->oy; + ox = window_copy_find_length(wme, oy); + + if (data->cx != ox) { + data->lastcx = data->cx; + data->lastsx = ox; + } + data->cx = data->lastcx; + + if (delta >= 0) { + n = (u_int)delta; + if (data->oy + n > screen_hsize(data->backing)) { + data->oy = screen_hsize(data->backing); + if (data->cy < n) + data->cy = 0; + else + data->cy -= n; + } else + data->oy += n; + } else { + n = (u_int)-delta; + if (data->oy < n) { + data->oy = 0; + if (data->cy + (n - data->oy) >= sy) + data->cy = sy - 1; + else + data->cy += n - data->oy; + } else + data->oy -= n; + } + + /* Don't also drag tail when dragging a scrollbar, it looks weird. */ + data->cursordrag = CURSORDRAG_NONE; + + if (data->screen.sel == NULL || !data->rectflag) { + py = screen_hsize(data->backing) + data->cy - data->oy; + px = window_copy_find_length(wme, py); + if ((data->cx >= data->lastsx && data->cx != px) || + data->cx > px) + window_copy_cursor_end_of_line(wme); + } + + if (scroll_exit && data->oy == 0) { + window_pane_reset_mode(wp); + return; + } + + if (data->searchmark != NULL && !data->timeout) + window_copy_search_marks(wme, NULL, data->searchregex, 1); + window_copy_update_selection(wme, 1, 0); + window_copy_redraw_screen(wme); + + return; +} + void window_copy_pageup(struct window_pane *wp, int half_page) { @@ -3803,12 +3921,12 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex) * beginning of the mark. */ if (window_copy_search_mark_at(data, fx, fy, - &start) == 0) { + &start) == 0) { while (window_copy_search_mark_at(data, fx, fy, - &at) == 0 && + &at) == 0 && data->searchmark != NULL && data->searchmark[at] == - data->searchmark[start]) { + data->searchmark[start]) { data->cx = fx; data->cy = fy - screen_hsize(data->backing) + @@ -4077,7 +4195,7 @@ window_copy_match_at_cursor(struct window_copy_mode_data *data) /* * Cells will not be set in the marked array unless they are valid text * and wrapping will be taken care of, so we can just copy. - */ + */ for (at = start; at <= end; at++) { py = at / sx; px = at - (py * sx); @@ -4175,7 +4293,7 @@ window_copy_write_one(struct window_mode_entry *wme, struct window_copy_mode_data *data = wme->data; struct grid *gd = data->backing->grid; struct grid_cell gc; - u_int fx; + u_int fx; screen_write_cursormove(ctx, 0, py, 0); for (fx = 0; fx < nx; fx++) { @@ -4256,10 +4374,13 @@ static void window_copy_write_lines(struct window_mode_entry *wme, struct screen_write_ctx *ctx, u_int py, u_int ny) { - u_int yy; + u_int yy; + struct window_pane *wp = wme->wp; for (yy = py; yy < py + ny; yy++) window_copy_write_line(wme, ctx, py); + + wp->flags |= PANE_REDRAWSCROLLBAR; } static void @@ -4295,7 +4416,7 @@ window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny) { struct window_pane *wp = wme->wp; struct window_copy_mode_data *data = wme->data; - struct screen_write_ctx ctx; + struct screen_write_ctx ctx; u_int i; screen_write_start_pane(&ctx, wp, NULL); @@ -4303,6 +4424,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 @@ -4445,7 +4568,7 @@ window_copy_adjust_selection(struct window_mode_entry *wme, u_int *selx, { struct window_copy_mode_data *data = wme->data; struct screen *s = &data->screen; - u_int sx, sy, ty; + u_int sx, sy, ty; int relpos; sx = *selx; @@ -5348,8 +5471,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; @@ -5462,6 +5584,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 @@ -5495,6 +5618,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/window.c b/window.c index 0e08444c..98e9cff9 100644 --- a/window.c +++ b/window.c @@ -591,11 +591,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; @@ -1096,6 +1116,8 @@ 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; + u_int pane_scrollbars; if (!TAILQ_EMPTY(&wp->modes) && TAILQ_FIRST(&wp->modes)->mode == mode) return (1); @@ -1120,6 +1142,10 @@ window_pane_set_mode(struct window_pane *wp, struct window_pane *swp, wp->screen = wme->screen; wp->flags |= (PANE_REDRAW|PANE_CHANGED); + pane_scrollbars = options_get_number(w->options, "pane-scrollbars"); + if (pane_scrollbars == PANE_SCROLLBARS_MODAL) + layout_fix_panes(w, NULL); + server_redraw_window_borders(wp->window); server_status_window(wp->window); notify_pane("pane-mode-changed", wp); @@ -1131,6 +1157,8 @@ void window_pane_reset_mode(struct window_pane *wp) { struct window_mode_entry *wme, *next; + struct window *w = wp->window; + u_int pane_scrollbars; if (TAILQ_EMPTY(&wp->modes)) return; @@ -1151,7 +1179,11 @@ 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); + + pane_scrollbars = options_get_number(w->options, "pane-scrollbars"); + if (pane_scrollbars != PANE_SCROLLBARS_OFF) + layout_fix_panes(w, NULL); server_redraw_window_borders(wp->window); server_status_window(wp->window); @@ -1168,7 +1200,7 @@ window_pane_reset_mode_all(struct window_pane *wp) static void window_pane_copy_paste(struct window_pane *wp, char *buf, size_t len) { - struct window_pane *loop; + struct window_pane *loop; TAILQ_FOREACH(loop, &wp->window->panes, entry) { if (loop != wp && @@ -1186,7 +1218,7 @@ window_pane_copy_paste(struct window_pane *wp, char *buf, size_t len) static void window_pane_copy_key(struct window_pane *wp, key_code key) { - struct window_pane *loop; + struct window_pane *loop; TAILQ_FOREACH(loop, &wp->window->panes, entry) { if (loop != wp &&