Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam
2026-04-03 16:01:08 +01:00
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

@@ -1321,6 +1321,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

@@ -604,7 +604,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");
@@ -617,35 +618,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 */
@@ -654,19 +658,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);
@@ -683,7 +698,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;
@@ -821,8 +836,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;
}
}
}
@@ -861,9 +882,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

@@ -179,6 +179,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 */
};
@@ -224,7 +234,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), \
@@ -249,7 +269,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
@@ -875,7 +905,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;
@@ -889,6 +920,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
@@ -1212,7 +1249,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
@@ -1254,6 +1291,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;
@@ -1882,10 +1920,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;
@@ -1894,7 +1928,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. */
@@ -3417,6 +3451,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 *);
@@ -3734,6 +3770,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

@@ -596,16 +596,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);
@@ -666,6 +674,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;
@@ -696,6 +705,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);
@@ -966,6 +976,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);
@@ -1018,6 +1029,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);
}
@@ -1969,3 +1981,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));
}