Add some new mouse ranges called "control0" to "control9", will be used

for controls on floating panes, from Dane Jensen, with some bits from
Michael Grant.
This commit is contained in:
nicm
2026-04-03 10:13:20 +00:00
parent 0917cd7010
commit 6b056eb53f
8 changed files with 212 additions and 67 deletions

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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",

View File

@@ -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);

47
style.c
View File

@@ -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);
}

57
tmux.h
View File

@@ -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 **);

View File

@@ -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));
}