diff --git a/format-draw.c b/format-draw.c index 03fad05f..510f28e0 100644 --- a/format-draw.c +++ b/format-draw.c @@ -49,6 +49,7 @@ format_is_type(struct format_range *fr, struct style *sy) case STYLE_RANGE_NONE: case STYLE_RANGE_LEFT: case STYLE_RANGE_RIGHT: + case STYLE_RANGE_CONTROL: return (1); case STYLE_RANGE_PANE: case STYLE_RANGE_WINDOW: @@ -1065,6 +1066,10 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, log_debug("%s: range user|%u at %u-%u", __func__, sr->argument, sr->start, sr->end); break; + case STYLE_RANGE_CONTROL: + log_debug("%s: range control|%u at %u-%u", __func__, + sr->argument, sr->start, sr->end); + break; } format_free_range(&frs, fr); } diff --git a/format.c b/format.c index 9feb0f46..a9310ff4 100644 --- a/format.c +++ b/format.c @@ -1307,6 +1307,8 @@ format_cb_mouse_status_range(struct format_tree *ft) return (xstrdup("session")); case STYLE_RANGE_USER: return (xstrdup(sr->string)); + case STYLE_RANGE_CONTROL: + return (xstrdup("control")); } return (NULL); } diff --git a/screen-redraw.c b/screen-redraw.c index 88653f34..8b77564a 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -450,6 +450,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, struct grid_cell gc; const char *fmt; struct format_tree *ft; + struct style_line_entry *sle = &wp->border_status_line; char *expanded; int pane_status = rctx->pane_status, sb_w = 0; int pane_scrollbars = rctx->pane_scrollbars; @@ -494,12 +495,15 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, gc.attr &= ~GRID_ATTR_CHARSET; screen_write_cursormove(&ctx, 0, 0, 0); - format_draw(&ctx, &gc, width, expanded, NULL, 0); - screen_write_stop(&ctx); + style_ranges_free(&sle->ranges); + format_draw(&ctx, &gc, width, expanded, &sle->ranges, 0); - free(expanded); + screen_write_stop(&ctx); format_free(ft); + free(sle->expanded); + sle->expanded = expanded; + if (grid_compare(wp->status_screen.grid, old.grid) == 0) { screen_free(&old); return (0); diff --git a/server-client.c b/server-client.c index 8a4fe491..ca57d397 100644 --- a/server-client.c +++ b/server-client.c @@ -608,7 +608,8 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py, struct options *wo = w->options; struct window_pane *fwp; int pane_status, sb, sb_pos, sb_w, sb_pad; - u_int line, sl_top, sl_bottom; + int pane_status_line, sl_top, sl_bottom; + int bdr_bottom, bdr_top, bdr_right; sb = options_get_number(wo, "pane-scrollbars"); sb_pos = options_get_number(wo, "pane-scrollbars-position"); @@ -621,35 +622,38 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py, sb_w = 0; sb_pad = 0; } + if (pane_status == PANE_STATUS_TOP) - line = wp->yoff - 1; + pane_status_line = wp->yoff - 1; else if (pane_status == PANE_STATUS_BOTTOM) - line = wp->yoff + wp->sy; + pane_status_line = wp->yoff + wp->sy; + else + pane_status_line = -1; /* not used */ /* Check if point is within the pane or scrollbar. */ if (((pane_status != PANE_STATUS_OFF && - py != line && py != wp->yoff + wp->sy) || + (int)py != pane_status_line && py != wp->yoff + wp->sy) || (wp->yoff == 0 && py < wp->sy) || (py >= wp->yoff && py < wp->yoff + wp->sy)) && ((sb_pos == PANE_SCROLLBARS_RIGHT && - px < wp->xoff + wp->sx + sb_pad + sb_w) || + (int)px < (int)wp->xoff + (int)wp->sx + sb_pad + sb_w) || (sb_pos == PANE_SCROLLBARS_LEFT && - px < wp->xoff + wp->sx - sb_pad - sb_w))) { + (int)px < (int)wp->xoff + (int)wp->sx - sb_pad - sb_w))) { /* Check if in the scrollbar. */ if ((sb_pos == PANE_SCROLLBARS_RIGHT && - (px >= wp->xoff + wp->sx + sb_pad && - px < wp->xoff + wp->sx + sb_pad + sb_w)) || + ((int)px >= (int)wp->xoff + (int)wp->sx + sb_pad && + (int)px < (int)wp->xoff + (int)wp->sx + sb_pad + sb_w)) || (sb_pos == PANE_SCROLLBARS_LEFT && - (px >= wp->xoff - sb_pad - sb_w && - px < wp->xoff - sb_pad))) { + ((int)px >= (int)wp->xoff - sb_pad - sb_w && + (int)px < (int)wp->xoff - sb_pad))) { /* Check where inside the scrollbar. */ sl_top = wp->yoff + wp->sb_slider_y; sl_bottom = (wp->yoff + wp->sb_slider_y + wp->sb_slider_h - 1); - if (py < sl_top) + if ((int)py < sl_top) return (KEYC_MOUSE_LOCATION_SCROLLBAR_UP); - else if (py >= sl_top && - py <= sl_bottom) { + else if ((int)py >= sl_top && + (int)py <= sl_bottom) { *sl_mpos = (py - wp->sb_slider_y - wp->yoff); return (KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER); } else /* py > sl_bottom */ @@ -658,19 +662,30 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py, /* Must be inside the pane. */ return (KEYC_MOUSE_LOCATION_PANE); } - } else if (~w->flags & WINDOW_ZOOMED) { - /* Try the pane borders if not zoomed. */ + } else { + /* Try the pane borders. */ TAILQ_FOREACH(fwp, &w->panes, entry) { - if ((((sb_pos == PANE_SCROLLBARS_RIGHT && - fwp->xoff + fwp->sx + sb_pad + sb_w == px) || - (sb_pos == PANE_SCROLLBARS_LEFT && - fwp->xoff + fwp->sx == px)) && - fwp->yoff <= 1 + py && - fwp->yoff + fwp->sy >= py) || - (fwp->yoff + fwp->sy == py && - fwp->xoff <= 1 + px && - fwp->xoff + fwp->sx >= px)) - break; + if ((w->flags & WINDOW_ZOOMED) && + (~fwp->flags & PANE_ZOOMED)) + continue; + bdr_top = fwp->yoff - 1; + bdr_bottom = fwp->yoff + (int)fwp->sy; + if (sb_pos == PANE_SCROLLBARS_LEFT) + bdr_right = fwp->xoff + (int)fwp->sx; + else + /* PANE_SCROLLBARS_RIGHT or none. */ + bdr_right = fwp->xoff + (int)fwp->sx + + sb_pad + sb_w; + if ((int)py >= (int)fwp->yoff - 1 && + py <= fwp->yoff + fwp->sy) { + if ((int)px == bdr_right) + break; + } + if ((int)px >= (int)fwp->xoff - 1 && + px <= fwp->xoff + fwp->sx) { + if ((int)py == bdr_bottom || (int)py == bdr_top) + break; + } } if (fwp != NULL) return (KEYC_MOUSE_LOCATION_BORDER); @@ -687,7 +702,7 @@ server_client_check_mouse(struct client *c, struct key_event *event) struct window *w = s->curw->window; struct winlink *fwl; struct window_pane *wp, *fwp; - u_int x, y, sx, sy, px, py, sl_mpos = 0; + u_int x, y, sx, sy, px, py, n, sl_mpos = 0; u_int b, bn; int ignore = 0; key_code key; @@ -825,8 +840,14 @@ have_event: loc = KEYC_MOUSE_LOCATION_STATUS; break; case STYLE_RANGE_USER: + log_debug("mouse range: user"); loc = KEYC_MOUSE_LOCATION_STATUS; break; + case STYLE_RANGE_CONTROL: + n = sr->argument; /* parsing keeps this < 10 */ + log_debug("mouse range: control %u", n); + loc = KEYC_MOUSE_LOCATION_CONTROL0 + n; + break; } } } @@ -865,9 +886,15 @@ have_event: if (loc == KEYC_MOUSE_LOCATION_PANE) { log_debug("mouse %u,%u on pane %%%u", x, y, wp->id); - } else if (loc == KEYC_MOUSE_LOCATION_BORDER) + } else if (loc == KEYC_MOUSE_LOCATION_BORDER) { + sr = window_pane_border_status_get_range(wp, px, + py); + if (sr != NULL) { + n = sr->argument; + loc = KEYC_MOUSE_LOCATION_CONTROL0 + n; + } log_debug("mouse on pane %%%u border", wp->id); - else if (loc == KEYC_MOUSE_LOCATION_SCROLLBAR_UP || + } else if (loc == KEYC_MOUSE_LOCATION_SCROLLBAR_UP || loc == KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER || loc == KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN) { log_debug("mouse on pane %%%u scrollbar", diff --git a/status.c b/status.c index cd8c62be..c39d0d8f 100644 --- a/status.c +++ b/status.c @@ -284,27 +284,10 @@ struct style_range * status_get_range(struct client *c, u_int x, u_int y) { struct status_line *sl = &c->status; - struct style_range *sr; if (y >= nitems(sl->entries)) return (NULL); - TAILQ_FOREACH(sr, &sl->entries[y].ranges, entry) { - if (x >= sr->start && x < sr->end) - return (sr); - } - return (NULL); -} - -/* Free all ranges. */ -static void -status_free_ranges(struct style_ranges *srs) -{ - struct style_range *sr, *sr1; - - TAILQ_FOREACH_SAFE(sr, srs, entry, sr1) { - TAILQ_REMOVE(srs, sr, entry); - free(sr); - } + return (style_ranges_get_range(&sl->entries[y].ranges, x)); } /* Save old status line. */ @@ -341,7 +324,7 @@ status_init(struct client *c) u_int i; for (i = 0; i < nitems(sl->entries); i++) - TAILQ_INIT(&sl->entries[i].ranges); + style_ranges_init(&sl->entries[i].ranges); screen_init(&sl->screen, c->tty.sx, 1, 0); sl->active = &sl->screen; @@ -355,7 +338,7 @@ status_free(struct client *c) u_int i; for (i = 0; i < nitems(sl->entries); i++) { - status_free_ranges(&sl->entries[i].ranges); + style_ranges_free(&sl->entries[i].ranges); free((void *)sl->entries[i].expanded); } @@ -374,7 +357,7 @@ int status_redraw(struct client *c) { struct status_line *sl = &c->status; - struct status_line_entry *sle; + struct style_line_entry *sle; struct session *s = c->session; struct screen_write_ctx ctx; struct grid_cell gc; @@ -454,7 +437,7 @@ status_redraw(struct client *c) screen_write_putc(&ctx, &gc, ' '); screen_write_cursormove(&ctx, 0, i, 0); - status_free_ranges(&sle->ranges); + style_ranges_free(&sle->ranges); format_draw(&ctx, &gc, width, expanded, &sle->ranges, 0); diff --git a/style.c b/style.c index 394eaf32..586e9f93 100644 --- a/style.c +++ b/style.c @@ -137,6 +137,15 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) sy->range_type = STYLE_RANGE_RIGHT; sy->range_argument = 0; style_set_range_string(sy, ""); + } else if (strcasecmp(tmp + 6, "control") == 0) { + if (found == NULL) + goto error; + n = strtonum(found, 0, 9, &errstr); + if (errstr != NULL) + goto error; + sy->range_type = STYLE_RANGE_CONTROL; + sy->range_argument = n; + style_set_range_string(sy, ""); } else if (strcasecmp(tmp + 6, "pane") == 0) { if (found == NULL) goto error; @@ -426,8 +435,10 @@ style_copy(struct style *dst, struct style *src) memcpy(dst, src, sizeof *dst); } +/* Set scrollbar style from an option. */ void -style_set_scrollbar_style_from_option(struct style *sb_style, struct options *oo) +style_set_scrollbar_style_from_option(struct style *sb_style, + struct options *oo) { struct style *sy; @@ -446,3 +457,37 @@ style_set_scrollbar_style_from_option(struct style *sb_style, struct options *oo utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER); } } + +/* Initialize style ranges. */ +void +style_ranges_init(struct style_ranges *srs) +{ + TAILQ_INIT(srs); +} + +/* Free style ranges. */ +void +style_ranges_free(struct style_ranges *srs) +{ + struct style_range *sr, *sr1; + + TAILQ_FOREACH_SAFE(sr, srs, entry, sr1) { + TAILQ_REMOVE(srs, sr, entry); + free(sr); + } +} + +/* Get range for position from style ranges. */ +struct style_range * +style_ranges_get_range(struct style_ranges *srs, u_int x) +{ + struct style_range *sr; + + if (srs == NULL) + return (NULL); + TAILQ_FOREACH(sr, srs, entry) { + if (x >= sr->start && x < sr->end) + return (sr); + } + return (NULL); +} diff --git a/tmux.h b/tmux.h index cab5b694..3f55c30f 100644 --- a/tmux.h +++ b/tmux.h @@ -170,6 +170,16 @@ enum key_code_mouse_location { KEYC_MOUSE_LOCATION_SCROLLBAR_UP, KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER, KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN, + KEYC_MOUSE_LOCATION_CONTROL0, /* keep order */ + KEYC_MOUSE_LOCATION_CONTROL1, + KEYC_MOUSE_LOCATION_CONTROL2, + KEYC_MOUSE_LOCATION_CONTROL3, + KEYC_MOUSE_LOCATION_CONTROL4, + KEYC_MOUSE_LOCATION_CONTROL5, + KEYC_MOUSE_LOCATION_CONTROL6, + KEYC_MOUSE_LOCATION_CONTROL7, + KEYC_MOUSE_LOCATION_CONTROL8, + KEYC_MOUSE_LOCATION_CONTROL9, KEYC_MOUSE_LOCATION_NOWHERE /* end */ }; @@ -215,7 +225,17 @@ enum key_code_mouse_location { KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, BORDER), \ KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_UP), \ KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_SLIDER), \ - KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_DOWN) + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_DOWN), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL0), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL1), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL2), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL3), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL4), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL5), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL6), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL7), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL8), \ + KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL9) #define KEYC_MOUSE_KEY(p, t, l) \ p ## _ ## l = KEYC_MAKE_MOUSE_KEY(t, 0, KEYC_MOUSE_LOCATION_ ## l), \ p ## 1_ ## l = KEYC_MAKE_MOUSE_KEY(t, 1, KEYC_MOUSE_LOCATION_ ## l), \ @@ -240,7 +260,17 @@ enum key_code_mouse_location { { #s "ScrollbarUp", KEYC_ ## name ## _SCROLLBAR_UP }, \ { #s "ScrollbarSlider", KEYC_ ## name ## _SCROLLBAR_SLIDER }, \ { #s "ScrollbarDown", KEYC_ ## name ## _SCROLLBAR_DOWN }, \ - { #s "Border", KEYC_ ## name ## _BORDER } + { #s "Border", KEYC_ ## name ## _BORDER }, \ + { #s "Control0", KEYC_ ## name ## _CONTROL0 }, \ + { #s "Control1", KEYC_ ## name ## _CONTROL1 }, \ + { #s "Control2", KEYC_ ## name ## _CONTROL2 }, \ + { #s "Control3", KEYC_ ## name ## _CONTROL3 }, \ + { #s "Control4", KEYC_ ## name ## _CONTROL4 }, \ + { #s "Control5", KEYC_ ## name ## _CONTROL5 }, \ + { #s "Control6", KEYC_ ## name ## _CONTROL6 }, \ + { #s "Control7", KEYC_ ## name ## _CONTROL7 }, \ + { #s "Control8", KEYC_ ## name ## _CONTROL8 }, \ + { #s "Control9", KEYC_ ## name ## _CONTROL9 } /* * A single key. This can be ASCII or Unicode or one of the keys between @@ -866,7 +896,8 @@ enum style_range_type { STYLE_RANGE_PANE, STYLE_RANGE_WINDOW, STYLE_RANGE_SESSION, - STYLE_RANGE_USER + STYLE_RANGE_USER, + STYLE_RANGE_CONTROL }; struct style_range { enum style_range_type type; @@ -880,6 +911,12 @@ struct style_range { }; TAILQ_HEAD(style_ranges, style_range); +/* Ranges connected with a status line. */ +struct style_line_entry { + char *expanded; + struct style_ranges ranges; +}; + /* Default style width and pad. */ #define STYLE_WIDTH_DEFAULT -1 #define STYLE_PAD_DEFAULT -1 @@ -1180,7 +1217,7 @@ struct window_pane { #define PANE_DROP 0x2 #define PANE_FOCUSED 0x4 #define PANE_VISITED 0x8 -/* 0x10 unused */ +#define PANE_ZOOMED 0x10 /* 0x20 unused */ #define PANE_INPUTOFF 0x40 #define PANE_CHANGED 0x80 @@ -1222,6 +1259,7 @@ struct window_pane { struct grid_cell cached_active_gc; struct colour_palette palette; enum client_theme last_theme; + struct style_line_entry border_status_line; int pipe_fd; pid_t pipe_pid; @@ -1847,10 +1885,6 @@ struct cmd_entry { /* Status line. */ #define STATUS_LINES_LIMIT 5 -struct status_line_entry { - char *expanded; - struct style_ranges ranges; -}; struct status_line { struct event timer; @@ -1859,7 +1893,7 @@ struct status_line { int references; struct grid_cell style; - struct status_line_entry entries[STATUS_LINES_LIMIT]; + struct style_line_entry entries[STATUS_LINES_LIMIT]; }; /* Prompt type. */ @@ -3368,6 +3402,8 @@ int window_pane_get_bg_control_client(struct window_pane *); int window_get_bg_client(struct window_pane *); enum client_theme window_pane_get_theme(struct window_pane *); void window_pane_send_theme_update(struct window_pane *); +struct style_range *window_pane_border_status_get_range(struct window_pane *, + u_int, u_int); /* layout.c */ u_int layout_count_cells(struct layout_cell *); @@ -3684,6 +3720,9 @@ void style_set(struct style *, const struct grid_cell *); void style_copy(struct style *, struct style *); void style_set_scrollbar_style_from_option(struct style *, struct options *); +void style_ranges_init(struct style_ranges *); +void style_ranges_free(struct style_ranges *); +struct style_range *style_ranges_get_range(struct style_ranges *, u_int); /* spawn.c */ struct winlink *spawn_window(struct spawn_context *, char **); diff --git a/window.c b/window.c index 60f2204a..7a70205e 100644 --- a/window.c +++ b/window.c @@ -589,16 +589,24 @@ struct window_pane * window_get_active_at(struct window *w, u_int x, u_int y) { struct window_pane *wp; - u_int xoff, yoff, sx, sy; + int pane_status, xoff, yoff; + u_int sx, sy; + + pane_status = options_get_number(w->options, "pane-border-status"); TAILQ_FOREACH(wp, &w->panes, entry) { if (!window_pane_visible(wp)) continue; window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); - if (x < xoff || x > xoff + sx) - continue; - if (y < yoff || y > yoff + sy) + if ((int)x < xoff || x > xoff + sx) continue; + if (pane_status == PANE_STATUS_TOP) { + if ((int)y <= yoff - 2 || y > yoff + sy - 1) + continue; + } else { + if ((int)y < yoff || y > yoff + sy) + continue; + } return (wp); } return (NULL); @@ -659,6 +667,7 @@ window_zoom(struct window_pane *wp) if (w->active != wp) window_set_active_pane(w, wp, 1); + wp->flags |= PANE_ZOOMED; TAILQ_FOREACH(wp1, &w->panes, entry) { wp1->saved_layout_cell = wp1->layout_cell; @@ -689,6 +698,7 @@ window_unzoom(struct window *w, int notify) TAILQ_FOREACH(wp, &w->panes, entry) { wp->layout_cell = wp->saved_layout_cell; wp->saved_layout_cell = NULL; + wp->flags ^= PANE_ZOOMED; } layout_fix_panes(w, NULL); @@ -959,6 +969,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) window_pane_default_cursor(wp); screen_init(&wp->status_screen, 1, 1, 0); + style_ranges_init(&wp->border_status_line.ranges); if (gethostname(host, sizeof host) == 0) screen_set_title(&wp->base, host); @@ -1007,6 +1018,7 @@ window_pane_destroy(struct window_pane *wp) free(wp->shell); cmd_free_argv(wp->argc, wp->argv); colour_palette_free(&wp->palette); + style_ranges_free(&wp->border_status_line.ranges); free(wp); } @@ -1958,3 +1970,31 @@ window_pane_send_theme_update(struct window_pane *wp) break; } } + +struct style_range * +window_pane_border_status_get_range(struct window_pane *wp, u_int x, u_int y) +{ + struct style_ranges *srs; + struct window *w = wp->window; + struct options *wo = w->options; + u_int line; + int pane_status; + + if (wp == NULL) + return (NULL); + srs = &wp->border_status_line.ranges; + + 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; + if (pane_status == PANE_STATUS_OFF || line != y) + return (NULL); + + /* + * The border formats start 2 off but that isn't reflected in + * the stored bounds of the range. + */ + return (style_ranges_get_range(srs, x - wp->xoff - 2)); +}