Merge branch 'master' into feature-floating-window-panes

This commit is contained in:
Michael Grant 2025-12-06 21:14:38 +00:00 committed by GitHub
commit ac01f15bfe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 249 additions and 151 deletions

26
CHANGES
View File

@ -1,3 +1,29 @@
CHANGES FROM 3.6 TO 3.6a
* Fix a buffer overread and an infinite loop in format processing (reported by
Giorgi Kobakhia, issue 4735).
* Allow drag in alternate screen again (issue 4743 reported by Brad King).
* Fix y offset of mouse if status at top (issue 4738 from Michael Grant).
* Add a missing skin tone (from Jake Stewart, issue 4736).
* Allow characters to be combined in either order (issue 4726, reported by Jake
Stewart).
* Fix horizontal mouse resizing when pane status lines are on (from Michael
Grant, issue 4720).
* Fix noattr so it does not delete attributes set in the style itself (issue
4713).
* Newer libevents do not allow event_del on a zero'd event (issue 4706).
* Place cursor on correct line if message-line is not 0 (issue 4707).
* Fix compile error on FreeBSD (from Yasuhiro Kimura, issue 4701).
CHANGES FROM 3.5a TO 3.6 CHANGES FROM 3.5a TO 3.6
* Add seconds options for clock mode (issue 4697). * Add seconds options for clock mode (issue 4697).

View File

@ -31,7 +31,7 @@ attributes_tostring(int attr)
if (attr == 0) if (attr == 0)
return ("none"); return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(attr & GRID_ATTR_CHARSET) ? "acs," : "", (attr & GRID_ATTR_CHARSET) ? "acs," : "",
(attr & GRID_ATTR_BRIGHT) ? "bright," : "", (attr & GRID_ATTR_BRIGHT) ? "bright," : "",
(attr & GRID_ATTR_DIM) ? "dim," : "", (attr & GRID_ATTR_DIM) ? "dim," : "",
@ -45,7 +45,8 @@ attributes_tostring(int attr)
(attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "",
(attr & GRID_ATTR_OVERLINE) ? "overline," : ""); (attr & GRID_ATTR_OVERLINE) ? "overline," : "",
(attr & GRID_ATTR_NOATTR) ? "noattr," : "");
if (len > 0) if (len > 0)
buf[len - 1] = '\0'; buf[len - 1] = '\0';

View File

@ -34,7 +34,7 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client", .name = "refresh-client",
.alias = "refresh", .alias = "refresh",
.args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL }, .args = { "A:B:cC:Df:r:F:lLRSt:U", 0, 1, NULL },
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] " .usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
"[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE "[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE
" [adjustment]", " [adjustment]",
@ -163,37 +163,6 @@ out:
free(copy); free(copy);
} }
static enum cmd_retval
cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
const char *p;
u_int i;
struct cmd_find_state fs;
p = args_get(args, 'l');
if (p == NULL) {
if (tc->flags & CLIENT_CLIPBOARDBUFFER)
return (CMD_RETURN_NORMAL);
tc->flags |= CLIENT_CLIPBOARDBUFFER;
} else {
if (cmd_find_target(&fs, item, p, CMD_FIND_PANE, 0) != 0)
return (CMD_RETURN_ERROR);
for (i = 0; i < tc->clipboard_npanes; i++) {
if (tc->clipboard_panes[i] == fs.wp->id)
break;
}
if (i != tc->clipboard_npanes)
return (CMD_RETURN_NORMAL);
tc->clipboard_panes = xreallocarray(tc->clipboard_panes,
tc->clipboard_npanes + 1, sizeof *tc->clipboard_panes);
tc->clipboard_panes[tc->clipboard_npanes++] = fs.wp->id;
}
tty_clipboard_query(&tc->tty);
return (CMD_RETURN_NORMAL);
}
static void static void
cmd_refresh_report(struct tty *tty, const char *value) cmd_refresh_report(struct tty *tty, const char *value)
{ {
@ -284,8 +253,10 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'l')) if (args_has(args, 'l')) {
return (cmd_refresh_client_clipboard(self, item)); tty_clipboard_query(&tc->tty);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'F')) /* -F is an alias for -f */ if (args_has(args, 'F')) /* -F is an alias for -f */
server_client_set_flags(tc, args_get(args, 'F')); server_client_set_flags(tc, args_get(args, 'F'));

View File

@ -1082,22 +1082,22 @@ colour_palette_free(struct colour_palette *p)
/* Get a colour from a palette. */ /* Get a colour from a palette. */
int int
colour_palette_get(struct colour_palette *p, int c) colour_palette_get(struct colour_palette *p, int n)
{ {
if (p == NULL) if (p == NULL)
return (-1); return (-1);
if (c >= 90 && c <= 97) if (n >= 90 && n <= 97)
c = 8 + c - 90; n = 8 + n - 90;
else if (c & COLOUR_FLAG_256) else if (n & COLOUR_FLAG_256)
c &= ~COLOUR_FLAG_256; n &= ~COLOUR_FLAG_256;
else if (c >= 8) else if (n >= 8)
return (-1); return (-1);
if (p->palette != NULL && p->palette[c] != -1) if (p->palette != NULL && p->palette[n] != -1)
return (p->palette[c]); return (p->palette[n]);
if (p->default_palette != NULL && p->default_palette[c] != -1) if (p->default_palette != NULL && p->default_palette[n] != -1)
return (p->default_palette[c]); return (p->default_palette[n]);
return (-1); return (-1);
} }
@ -1107,15 +1107,14 @@ colour_palette_set(struct colour_palette *p, int n, int c)
{ {
u_int i; u_int i;
if (p == NULL || n > 255) if (p == NULL || n < 0 || n > 255)
return (0); return (0);
if (c == -1 && p->palette == NULL) if (c == -1 && p->palette == NULL)
return (0); return (0);
if (c != -1 && p->palette == NULL) { if (p->palette == NULL) {
if (p->palette == NULL) p->palette = xcalloc(256, sizeof *p->palette);
p->palette = xcalloc(256, sizeof *p->palette);
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
p->palette[i] = -1; p->palette[i] = -1;
} }

View File

@ -263,11 +263,6 @@ environ_for_session(struct session *s, int no_TERM)
environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux"); environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux");
environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion()); environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
environ_set(env, "COLORTERM", 0, "truecolor"); environ_set(env, "COLORTERM", 0, "truecolor");
} else {
environ_unset(env, "TERM");
environ_unset(env, "TERM_PROGRAM");
environ_unset(env, "TERM_PROGRAM_VERSION");
environ_unset(env, "COLORTERM");
} }
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD

View File

@ -1104,8 +1104,6 @@ format_width(const char *expanded)
more = utf8_append(&ud, *cp); more = utf8_append(&ud, *cp);
if (more == UTF8_DONE) if (more == UTF8_DONE)
width += ud.width; width += ud.width;
else
cp -= ud.have;
} else if (*cp > 0x1f && *cp < 0x7f) { } else if (*cp > 0x1f && *cp < 0x7f) {
width++; width++;
cp++; cp++;

View File

@ -5545,7 +5545,8 @@ format_expand1(struct format_expand_state *es, const char *fmt)
buf[off++] = *fmt++; buf[off++] = *fmt++;
continue; continue;
} }
fmt++; if (*fmt++ == '\0')
break;
ch = (u_char)*fmt++; ch = (u_char)*fmt++;
switch (ch) { switch (ch) {

91
input.c
View File

@ -3069,18 +3069,41 @@ input_osc_133(struct input_ctx *ictx, const char *p)
} }
} }
/* Handle OSC 52 reply. */
static void
input_osc_52_reply(struct input_ctx *ictx)
{
struct paste_buffer *pb;
int state;
const char *buf;
size_t len;
state = options_get_number(global_options, "get-clipboard");
if (state == 0)
return;
if (state == 1) {
if ((pb = paste_get_top(NULL)) == NULL)
return;
buf = paste_buffer_data(pb, &len);
if (ictx->input_end == INPUT_END_BEL)
input_reply_clipboard(ictx->event, buf, len, "\007");
else
input_reply_clipboard(ictx->event, buf, len, "\033\\");
return;
}
input_add_request(ictx, INPUT_REQUEST_CLIPBOARD, ictx->input_end);
}
/* Handle the OSC 52 sequence for setting the clipboard. */ /* Handle the OSC 52 sequence for setting the clipboard. */
static void static void
input_osc_52(struct input_ctx *ictx, const char *p) input_osc_52(struct input_ctx *ictx, const char *p)
{ {
struct window_pane *wp = ictx->wp; struct window_pane *wp = ictx->wp;
size_t len;
char *end; char *end;
const char *buf = NULL;
size_t len = 0;
u_char *out; u_char *out;
int outlen, state; int outlen, state;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct paste_buffer *pb;
const char* allow = "cpqs01234567"; const char* allow = "cpqs01234567";
char flags[sizeof "cpqs01234567"] = ""; char flags[sizeof "cpqs01234567"] = "";
u_int i, j = 0; u_int i, j = 0;
@ -3105,12 +3128,7 @@ input_osc_52(struct input_ctx *ictx, const char *p)
log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, flags); log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, flags);
if (strcmp(end, "?") == 0) { if (strcmp(end, "?") == 0) {
if ((pb = paste_get_top(NULL)) != NULL) input_osc_52_reply(ictx);
buf = paste_buffer_data(pb, &len);
if (ictx->input_end == INPUT_END_BEL)
input_reply_clipboard(ictx->event, buf, len, "\007");
else
input_reply_clipboard(ictx->event, buf, len, "\033\\");
return; return;
} }
@ -3169,6 +3187,7 @@ input_osc_104(struct input_ctx *ictx, const char *p)
free(copy); free(copy);
} }
/* Send a clipboard reply. */
void void
input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len, input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
const char *end) const char *end)
@ -3305,6 +3324,9 @@ input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx)
xsnprintf(s, sizeof s, "\033]4;%d;?\033\\", idx); xsnprintf(s, sizeof s, "\033]4;%d;?\033\\", idx);
tty_puts(&c->tty, s); tty_puts(&c->tty, s);
break; break;
case INPUT_REQUEST_CLIPBOARD:
tty_putcode_ss(&c->tty, TTYC_MS, "", "?");
break;
case INPUT_REQUEST_QUEUE: case INPUT_REQUEST_QUEUE:
break; break;
} }
@ -3312,6 +3334,39 @@ input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx)
return (0); return (0);
} }
/* Handle a palette reply. */
static void
input_request_palette_reply(struct input_request *ir, void *data)
{
struct input_request_palette_data *pd = data;
input_osc_colour_reply(ir->ictx, 0, 4, pd->idx, pd->c, ir->end);
}
/* Handle a clipboard reply. */
static void
input_request_clipboard_reply(struct input_request *ir, void *data)
{
struct input_ctx *ictx = ir->ictx;
struct input_request_clipboard_data *cd = data;
int state;
char *copy;
state = options_get_number(global_options, "get-clipboard");
if (state == 0 || state == 1)
return;
if (state == 3) {
copy = xmalloc(cd->len);
memcpy(copy, cd->buf, cd->len);
paste_add(NULL, copy, cd->len);
}
if (ir->idx == INPUT_END_BEL)
input_reply_clipboard(ictx->event, cd->buf, cd->len, "\007");
else
input_reply_clipboard(ictx->event, cd->buf, cd->len, "\033\\");
}
/* Handle a reply to a request. */ /* Handle a reply to a request. */
void void
input_request_reply(struct client *c, enum input_request_type type, void *data) input_request_reply(struct client *c, enum input_request_type type, void *data)
@ -3321,11 +3376,18 @@ input_request_reply(struct client *c, enum input_request_type type, void *data)
int complete = 0; int complete = 0;
TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1) { TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1) {
if (ir->type == type && pd->idx == ir->idx) { if (ir->type != type) {
input_free_request(ir);
continue;
}
if (type == INPUT_REQUEST_PALETTE && pd->idx == ir->idx) {
found = ir;
break;
}
if (type == INPUT_REQUEST_CLIPBOARD) {
found = ir; found = ir;
break; break;
} }
input_free_request(ir);
} }
if (found == NULL) if (found == NULL)
return; return;
@ -3335,8 +3397,11 @@ input_request_reply(struct client *c, enum input_request_type type, void *data)
break; break;
if (ir->type == INPUT_REQUEST_QUEUE) if (ir->type == INPUT_REQUEST_QUEUE)
input_send_reply(ir->ictx, ir->data); input_send_reply(ir->ictx, ir->data);
else if (ir == found && ir->type == INPUT_REQUEST_PALETTE) { else if (ir == found) {
input_osc_colour_reply(ir->ictx, 0, 4, pd->idx, pd->c, ir->end); if (ir->type == INPUT_REQUEST_PALETTE)
input_request_palette_reply(ir, data);
else if (ir->type == INPUT_REQUEST_CLIPBOARD)
input_request_clipboard_reply(ir, data);
complete = 1; complete = 1;
} }
input_free_request(ir); input_free_request(ir);

View File

@ -442,7 +442,7 @@ key_bindings_init(void)
"bind -n MouseDown1Pane { select-pane -t=; send -M }", "bind -n MouseDown1Pane { select-pane -t=; send -M }",
/* Mouse button 1 drag on pane. */ /* Mouse button 1 drag on pane. */
"bind -n MouseDrag1Pane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }", "bind -n MouseDrag1Pane { if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }",
/* Mouse wheel up on pane. */ /* Mouse wheel up on pane. */
"bind -n WheelUpPane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e } }", "bind -n WheelUpPane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e } }",

View File

@ -1103,9 +1103,8 @@ int
layout_spread_cell(struct window *w, struct layout_cell *parent) layout_spread_cell(struct window *w, struct layout_cell *parent)
{ {
struct layout_cell *lc; struct layout_cell *lc;
struct style *sb_style = &w->active->scrollbar_style;
u_int number, each, size, this, remainder; u_int number, each, size, this, remainder;
int change, changed, status, scrollbars; int change, changed, status;
number = 0; number = 0;
TAILQ_FOREACH (lc, &parent->cells, entry) TAILQ_FOREACH (lc, &parent->cells, entry)
@ -1113,14 +1112,9 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
if (number <= 1) if (number <= 1)
return (0); return (0);
status = options_get_number(w->options, "pane-border-status"); status = options_get_number(w->options, "pane-border-status");
scrollbars = options_get_number(w->options, "pane-scrollbars");
if (parent->type == LAYOUT_LEFTRIGHT) { if (parent->type == LAYOUT_LEFTRIGHT)
if (scrollbars) size = parent->sx;
size = parent->sx - sb_style->width + sb_style->pad;
else
size = parent->sx;
}
else if (parent->type == LAYOUT_TOPBOTTOM) { else if (parent->type == LAYOUT_TOPBOTTOM) {
if (layout_add_horizontal_border(w, parent, status)) if (layout_add_horizontal_border(w, parent, status))
size = parent->sy - 1; size = parent->sy - 1;

View File

@ -84,6 +84,9 @@ static const char *options_table_popup_border_lines_list[] = {
static const char *options_table_set_clipboard_list[] = { static const char *options_table_set_clipboard_list[] = {
"off", "external", "on", NULL "off", "external", "on", NULL
}; };
static const char *options_table_get_clipboard_list[] = {
"off", "buffer", "request", "both", NULL
};
static const char *options_table_window_size_list[] = { static const char *options_table_window_size_list[] = {
"largest", "smallest", "manual", "latest", NULL "largest", "smallest", "manual", "latest", NULL
}; };
@ -405,6 +408,18 @@ const struct options_table_entry options_table[] = {
.text = "Whether to send focus events to applications." .text = "Whether to send focus events to applications."
}, },
{ .name = "get-clipboard",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SERVER,
.choices = options_table_get_clipboard_list,
.default_num = 1,
.text = "When an application requests the clipboard, whether to "
"ignore the request ('off'); respond with the newest buffer "
"('buffer'); request the clipboard from the most recently "
"used terminal ('request'); or to request the clipboard, "
"create a buffer, and send it to the application ('both')."
},
{ .name = "history-file", { .name = "history-file",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,

View File

@ -4,7 +4,7 @@
Λ̊1 Λ̊1
🏻2 🏻2
👍🏻3 👍🏻3
👍🏻 👍🏻4 👍🏻 👍🏻4
🤷5 🤷5
7 7
🤷8 🤷8

View File

@ -1312,6 +1312,11 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx,
int yoff = wp->yoff; int yoff = wp->yoff;
struct visible_ranges *vr; struct visible_ranges *vr;
if (ctx->statustop) {
sb_y += ctx->statuslines;
sy += ctx->statuslines;
}
/* Set up style for slider. */ /* Set up style for slider. */
gc = sb_style->gc; gc = sb_style->gc;
memcpy(&slgc, &gc, sizeof slgc); memcpy(&slgc, &gc, sizeof slgc);

View File

@ -2207,6 +2207,8 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc)
case HANGULJAMO_STATE_NOT_HANGULJAMO: case HANGULJAMO_STATE_NOT_HANGULJAMO:
if (utf8_should_combine(&last.data, ud)) if (utf8_should_combine(&last.data, ud))
force_wide = 1; force_wide = 1;
else if (utf8_should_combine(ud, &last.data))
force_wide = 1;
else if (!utf8_has_zwj(&last.data)) else if (!utf8_has_zwj(&last.data))
return (0); return (0);
break; break;

View File

@ -594,8 +594,12 @@ screen_select_cell(struct screen *s, struct grid_cell *dst,
if (COLOUR_DEFAULT(dst->bg)) if (COLOUR_DEFAULT(dst->bg))
dst->bg = src->bg; dst->bg = src->bg;
utf8_copy(&dst->data, &src->data); utf8_copy(&dst->data, &src->data);
dst->attr = src->attr;
dst->flags = src->flags; dst->flags = src->flags;
if (dst->attr & GRID_ATTR_NOATTR)
dst->attr |= (src->attr & GRID_ATTR_CHARSET);
else
dst->attr |= src->attr;
} }
/* Reflow wrapped lines. */ /* Reflow wrapped lines. */

View File

@ -617,7 +617,8 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py,
pane_status_line = -1; /* not used */ pane_status_line = -1; /* not used */
/* Check if point is within the pane or scrollbar. */ /* Check if point is within the pane or scrollbar. */
if (((pane_status != PANE_STATUS_OFF && py != pane_status_line) || if (((pane_status != PANE_STATUS_OFF &&
py != pane_status_line && py != wp->yoff + wp->sy) ||
(wp->yoff == 0 && py < wp->sy) || (wp->yoff == 0 && py < wp->sy) ||
((int)py >= wp->yoff && py < wp->yoff + wp->sy)) && ((int)py >= wp->yoff && py < wp->yoff + wp->sy)) &&
((sb_pos == PANE_SCROLLBARS_RIGHT && ((sb_pos == PANE_SCROLLBARS_RIGHT &&
@ -1302,7 +1303,11 @@ have_event:
if (c->tty.mouse_scrolling_flag == 0 && if (c->tty.mouse_scrolling_flag == 0 &&
where == SCROLLBAR_SLIDER) { where == SCROLLBAR_SLIDER) {
c->tty.mouse_scrolling_flag = 1; c->tty.mouse_scrolling_flag = 1;
c->tty.mouse_slider_mpos = sl_mpos; if (m->statusat == 0) {
c->tty.mouse_slider_mpos = sl_mpos +
m->statuslines;
} else
c->tty.mouse_slider_mpos = sl_mpos;
} }
break; break;
case WHEEL: case WHEEL:

35
style.c
View File

@ -218,20 +218,23 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
sy->gc.attr = 0; sy->gc.attr = 0;
else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
if (strcmp(tmp + 2, "attr") == 0) if (strcmp(tmp + 2, "attr") == 0)
value = 0xffff & ~GRID_ATTR_CHARSET; sy->gc.attr |= GRID_ATTR_NOATTR;
else if ((value = attributes_fromstring(tmp + 2)) == -1) else {
goto error; value = attributes_fromstring(tmp + 2);
sy->gc.attr &= ~value; if (value == -1)
goto error;
sy->gc.attr &= ~value;
}
} else if (end > 6 && strncasecmp(tmp, "width=", 6) == 0) { } else if (end > 6 && strncasecmp(tmp, "width=", 6) == 0) {
n = strtonum(tmp + 6, 0, UINT_MAX, &errstr); n = strtonum(tmp + 6, 0, UINT_MAX, &errstr);
if (errstr != NULL) if (errstr != NULL)
goto error; goto error;
sy->width = (int)n; sy->width = (int)n;
} else if (end > 4 && strncasecmp(tmp, "pad=", 4) == 0) { } else if (end > 4 && strncasecmp(tmp, "pad=", 4) == 0) {
n = strtonum(tmp + 4, 0, UINT_MAX, &errstr); n = strtonum(tmp + 4, 0, UINT_MAX, &errstr);
if (errstr != NULL) if (errstr != NULL)
goto error; goto error;
sy->pad = (int)n; sy->pad = (int)n;
} else { } else {
if ((value = attributes_fromstring(tmp)) == -1) if ((value = attributes_fromstring(tmp)) == -1)
goto error; goto error;
@ -344,13 +347,13 @@ style_tostring(struct style *sy)
attributes_tostring(gc->attr)); attributes_tostring(gc->attr));
comma = ","; comma = ",";
} }
if (sy->width >= 0) { if (sy->width >= 0) {
xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma, xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma,
sy->width); sy->width);
comma = ","; comma = ",";
} }
if (sy->pad >= 0) { if (sy->pad >= 0) {
xsnprintf(s + off, sizeof s - off, "%spad=%u", comma, xsnprintf(s + off, sizeof s - off, "%spad=%u", comma,
sy->pad); sy->pad);
comma = ","; comma = ",";
} }

37
tmux.1
View File

@ -1363,12 +1363,11 @@ and sets an environment variable for the newly created session; it may be
specified multiple times. specified multiple times.
.Tg refresh .Tg refresh
.It Xo Ic refresh-client .It Xo Ic refresh-client
.Op Fl cDLRSU .Op Fl cDlLRSU
.Op Fl A Ar pane:state .Op Fl A Ar pane:state
.Op Fl B Ar name:what:format .Op Fl B Ar name:what:format
.Op Fl C Ar size .Op Fl C Ar size
.Op Fl f Ar flags .Op Fl f Ar flags
.Op Fl l Op Ar target-pane
.Op Fl r Ar pane:report .Op Fl r Ar pane:report
.Op Fl t Ar target-client .Op Fl t Ar target-client
.Op Ar adjustment .Op Ar adjustment
@ -1489,11 +1488,7 @@ a colon, then a report escape sequence.
.Fl l .Fl l
requests the clipboard from the client using the requests the clipboard from the client using the
.Xr xterm 1 .Xr xterm 1
escape sequence. escape sequence and stores it in a new paste buffer.
If
.Ar target-pane
is given, the clipboard is sent (in encoded form), otherwise it is stored in a
new paste buffer.
.Pp .Pp
.Fl L , .Fl L ,
.Fl R , .Fl R ,
@ -4241,6 +4236,32 @@ passed through to applications running in
.Nm . .Nm .
Attached clients should be detached and attached again after changing this Attached clients should be detached and attached again after changing this
option. option.
.It Xo Ic get-clipboard
.Op Ic both | request | buffer | off
.Xc
Controls the behaviour when an application requests the clipboard from
.Nm .
.Pp
If
.Ic off ,
the request is ignored;
if
.Ic buffer ,
.Nm
responds with the newest paste buffer;
.Ic request
causes
.Nm
to request the clipboard from the most recently used client (if possible) and
send the reply (if any) back to the application;
.Ic buffer
is the same as
.Ic request
but also creates a paste buffer.
.Pp
See also the
.Ic set-clipboard
option.
.It Ic history-file Ar path .It Ic history-file Ar path
If not empty, a file to which If not empty, a file to which
.Nm .Nm
@ -6135,7 +6156,6 @@ The following variables are available, where appropriate:
.It Li "insert_flag" Ta "" Ta "Pane insert flag" .It Li "insert_flag" Ta "" Ta "Pane insert flag"
.It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag" .It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag"
.It Li "keypad_flag" Ta "" Ta "Pane keypad flag" .It Li "keypad_flag" Ta "" Ta "Pane keypad flag"
.It Li "last_session_index" Ta "" Ta "Index of last session"
.It Li "last_window_index" Ta "" Ta "Index of last window in session" .It Li "last_window_index" Ta "" Ta "Index of last window in session"
.It Li "line" Ta "" Ta "Line number in the list" .It Li "line" Ta "" Ta "Line number in the list"
.It Li "loop_last_flag" Ta "" Ta "1 if last window, pane, session, client in the W:, P:, S:, or L: loop" .It Li "loop_last_flag" Ta "" Ta "1 if last window, pane, session, client in the W:, P:, S:, or L: loop"
@ -6227,7 +6247,6 @@ The following variables are available, where appropriate:
.It Li "session_group_size" Ta "" Ta "Size of session group" .It Li "session_group_size" Ta "" Ta "Size of session group"
.It Li "session_grouped" Ta "" Ta "1 if session in a group" .It Li "session_grouped" Ta "" Ta "1 if session in a group"
.It Li "session_id" Ta "" Ta "Unique session ID" .It Li "session_id" Ta "" Ta "Unique session ID"
.It Li "session_index" Ta "" Ta "Index of session"
.It Li "session_last_attached" Ta "" Ta "Time session last attached" .It Li "session_last_attached" Ta "" Ta "Time session last attached"
.It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached" .It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached"
.It Li "session_marked" Ta "" Ta "1 if this session contains the marked pane" .It Li "session_marked" Ta "" Ta "1 if this session contains the marked pane"

10
tmux.h
View File

@ -727,6 +727,7 @@ struct colour_palette {
#define GRID_ATTR_UNDERSCORE_4 0x800 #define GRID_ATTR_UNDERSCORE_4 0x800
#define GRID_ATTR_UNDERSCORE_5 0x1000 #define GRID_ATTR_UNDERSCORE_5 0x1000
#define GRID_ATTR_OVERLINE 0x2000 #define GRID_ATTR_OVERLINE 0x2000
#define GRID_ATTR_NOATTR 0x4000
/* All underscore attributes. */ /* All underscore attributes. */
#define GRID_ATTR_ALL_UNDERSCORE \ #define GRID_ATTR_ALL_UNDERSCORE \
@ -1129,6 +1130,7 @@ struct window_mode_entry {
/* Type of request to client. */ /* Type of request to client. */
enum input_request_type { enum input_request_type {
INPUT_REQUEST_PALETTE, INPUT_REQUEST_PALETTE,
INPUT_REQUEST_CLIPBOARD,
INPUT_REQUEST_QUEUE INPUT_REQUEST_QUEUE
}; };
@ -1138,6 +1140,12 @@ struct input_request_palette_data {
int c; int c;
}; };
/* Clipboard request reply data. */
struct input_request_clipboard_data {
char *buf;
size_t len;
};
/* Request sent to client on behalf of pane. */ /* Request sent to client on behalf of pane. */
TAILQ_HEAD(input_requests, input_request); TAILQ_HEAD(input_requests, input_request);
@ -2014,7 +2022,7 @@ struct client {
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL #define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL #define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL #define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL /* 0x800000000ULL unused */
#define CLIENT_BRACKETPASTING 0x1000000000ULL #define CLIENT_BRACKETPASTING 0x1000000000ULL
#define CLIENT_ASSUMEPASTING 0x2000000000ULL #define CLIENT_ASSUMEPASTING 0x2000000000ULL
#define CLIENT_REDRAWSCROLLBARS 0x4000000000ULL #define CLIENT_REDRAWSCROLLBARS 0x4000000000ULL

View File

@ -1301,12 +1301,11 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size,
static int static int
tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
{ {
struct client *c = tty->client; struct client *c = tty->client;
struct window_pane *wp; size_t end, terminator = 0, needed;
size_t end, terminator = 0, needed; char *copy, *out;
char *copy, *out; int outlen;
int outlen; struct input_request_clipboard_data cd;
u_int i;
*size = 0; *size = 0;
@ -1364,12 +1363,6 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
buf++; buf++;
end--; end--;
/* If we did not request this, ignore it. */
if (~tty->flags & TTY_OSC52QUERY)
return (0);
tty->flags &= ~TTY_OSC52QUERY;
evtimer_del(&tty->clipboard_timer);
/* It has to be a string so copy it. */ /* It has to be a string so copy it. */
copy = xmalloc(end + 1); copy = xmalloc(end + 1);
memcpy(copy, buf, end); memcpy(copy, buf, end);
@ -1384,22 +1377,22 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
return (0); return (0);
} }
free(copy); free(copy);
/* Create a new paste buffer and forward to panes. */
log_debug("%s: %.*s", __func__, outlen, out); log_debug("%s: %.*s", __func__, outlen, out);
if (c->flags & CLIENT_CLIPBOARDBUFFER) {
paste_add(NULL, out, outlen);
c->flags &= ~CLIENT_CLIPBOARDBUFFER;
}
for (i = 0; i < c->clipboard_npanes; i++) {
wp = window_pane_find_by_id(c->clipboard_panes[i]);
if (wp != NULL)
input_reply_clipboard(wp->event, out, outlen, "\033\\");
}
free(c->clipboard_panes);
c->clipboard_panes = NULL;
c->clipboard_npanes = 0;
/* Set reply if any. */
cd.buf = out;
cd.len = outlen;
input_request_reply(c, INPUT_REQUEST_CLIPBOARD, &cd);
/* Create a buffer if requested. */
if (tty->flags & TTY_OSC52QUERY) {
paste_add(NULL, out, outlen);
out = NULL;
evtimer_del(&tty->clipboard_timer);
tty->flags &= ~TTY_OSC52QUERY;
}
free(out);
return (0); return (0);
} }

17
tty.c
View File

@ -3300,12 +3300,6 @@ static void
tty_clipboard_query_callback(__unused int fd, __unused short events, void *data) tty_clipboard_query_callback(__unused int fd, __unused short events, void *data)
{ {
struct tty *tty = data; struct tty *tty = data;
struct client *c = tty->client;
c->flags &= ~CLIENT_CLIPBOARDBUFFER;
free(c->clipboard_panes);
c->clipboard_panes = NULL;
c->clipboard_npanes = 0;
tty->flags &= ~TTY_OSC52QUERY; tty->flags &= ~TTY_OSC52QUERY;
} }
@ -3315,10 +3309,9 @@ tty_clipboard_query(struct tty *tty)
{ {
struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT };
if ((~tty->flags & TTY_STARTED) || (tty->flags & TTY_OSC52QUERY)) if ((tty->flags & TTY_STARTED) && (~tty->flags & TTY_OSC52QUERY)) {
return; tty_putcode_ss(tty, TTYC_MS, "", "?");
tty_putcode_ss(tty, TTYC_MS, "", "?"); tty->flags |= TTY_OSC52QUERY;
evtimer_add(&tty->clipboard_timer, &tv);
tty->flags |= TTY_OSC52QUERY; }
evtimer_add(&tty->clipboard_timer, &tv);
} }

View File

@ -122,6 +122,7 @@ utf8_should_combine(const struct utf8_data *with, const struct utf8_data *add)
case 0x1F47C: case 0x1F47C:
case 0x1F481: case 0x1F481:
case 0x1F482: case 0x1F482:
case 0x1F483:
case 0x1F485: case 0x1F485:
case 0x1F486: case 0x1F486:
case 0x1F487: case 0x1F487:

View File

@ -627,7 +627,7 @@ window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp,
new_slider_y = sb_top - wp->yoff + (sb_height - slider_height); new_slider_y = sb_top - wp->yoff + (sb_height - slider_height);
} else { } else {
/* Slider is somewhere in the middle. */ /* Slider is somewhere in the middle. */
new_slider_y = my - wp->yoff - sl_mpos + 1; new_slider_y = my - wp->yoff - sl_mpos;
} }
if (TAILQ_FIRST(&wp->modes) == NULL || if (TAILQ_FIRST(&wp->modes) == NULL ||

View File

@ -1826,7 +1826,7 @@ window_pane_mode(struct window_pane *wp)
int int
window_pane_show_scrollbar(struct window_pane *wp, int sb_option) window_pane_show_scrollbar(struct window_pane *wp, int sb_option)
{ {
if (SCREEN_IS_ALTERNATE(wp->screen)) if (SCREEN_IS_ALTERNATE(&wp->base))
return (0); return (0);
if (sb_option == PANE_SCROLLBARS_ALWAYS || if (sb_option == PANE_SCROLLBARS_ALWAYS ||
(sb_option == PANE_SCROLLBARS_MODAL && (sb_option == PANE_SCROLLBARS_MODAL &&