diff --git a/CHANGES b/CHANGES index 5e0db208..bcd1e1c6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,242 @@ +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 + +* Add seconds options for clock mode (issue 4697). + +* Add a resize callback for menus so that they are correctly moved on resize + (issue 4696). + +* Make -v to source-file pass through to subsequent source-file commands (issue + 4216). + +* If display-popup is used inside a popup, modify that popup (issue 4678). + +* Add selection-mode command to expilcitly set the selection mode in copy mode + (issue 3842). + +* Save and restore images in alternate screen (issue 3732). + +* Ignore Hangul filler character (issue 3998). + +* Improve handling of regional indicators and emoji modifiers (issue 3998). + +* Preserve marked pane with swap-window and move-window (issue 3443). + +* Set and check COLORTERM as a hint for RGB colour. + +* If tmux receives a palette request (OSC 4) in a pane and the palette entry + has not been set, send a request to the most recently used client and + forward any response instead (based on change from Tim Culverhouse, issue + 4665). + +* Add -l flag to command-prompt to disable splitting into multiple prompts + (issue 4483). + +* Don't enter copy mode on mouse wheel in alternate screen (issue 3705). + +* Add commands to centre the cursor in copy mode (issue 4662). + +* Support case insensitive search in modes in the same way as copy mode + (like emacs, so all-lowercase means case insensitive) (issue 4396). + +* Fix the logic of the no-detached case for the detach-on-destroy option (from + Martin Louazel, issue 4649). + +* Add buffer_full format variable (from Mohammad AlSaleh, issue 4630). + +* Introduce a new window option, tiled-layout-max-columns, which configures the + maximum number of columns in the tiled layout. + +* Add support for DECRQSS SP q (report cursor style), DECRQM ?12 (report cursor + blink state) and DECRQM ?2004, ?1004, ?1006 (report mouse state) ( rom + Andrea Alberti, issue 4618). + +* Fix missing argument from OSC 4 reply (issue 4596). + +* Add -k flag to display-popup which allows any key to dismiss the popup once + the command has exited (from Meriel Luna Mittelbach, issue 4612). + +* Add nicer default second and third status lines (from Michael Grant, issue + 4490). + +* Add a pane-border-lines "spaces" value to use spaces for pane borders (issue + 4587). + +* Replace invalid UTF-8 characters with the placeholder instead of ignoring + them (issue 4514). + +* Fix incorrect handling of Korean Hangul Jamo characters (from Roy Jung, issue + 4546). + +* Allow uppercase letters in gray/grey color names (from Pavel Roskin, issue + 4560). + +* Add sorting to W, P, L loop operators (from Michael Grant, issue 4516). + +* Detect support for OSC 52 using the device attributes report (from James + Holderness, issue 4539). + +* Add noattr for styles and use in mode-style to allow whether attributes are + ignored or used to be configured (issue 4498). + +* Add a set-default style attribute which replaces the current default colours + and attributes completely. + +* Add -E to run-shell to forward stderr as well as stdout (issue 4246). + +* Add an option variation-selector-always-wide to instruct tmux not to + always interpret VS16 as a wide character and assume the terminal does + likewise. + +* Switch to getopt_long from OpenSSH (from Koichi Murase, issue 4492). + +* Add more features for boolean expressions in formats: 1) extend && and || to + support arbitrarily many arguments and 2) add ! and !! for not and not-not + (from David Mandelberg). + +* Do not mistake other DCS sequences for SIXEL sequences (from James + Holderness, issue 4488). + +* Improve #? conditional expression in formats: add support for else if and + default empty string if no else value (from David Mandelberg, issue 4451). + +* Add default-client-command to set the command used if tmux is run without a + command; the default stays new-session (from David Mandelberg, issue + 4422). + +* Add S-Up and S-Down to move windows in tree mode (from David Mandelberg, + issue 4415). + +* Add mode 2031 support to automatically report dark or light theme. tmux will + guess the theme from the background colour on terminals which do not + themselves support the escape sequence (from Jonathan Slenders, issue 4353). + +* Add -M flag to capture-pane to use the copy mode screen (issue 4358). + +* Align index numbers in trees (from David Mandelberg, issue 4360). + +* Add display-message -C flag to update pane while message is displayed (from + Vitaly Ostrosablin, issue 4363). + +* Make list-commands command show only one command if an argument is given + (from Ilya Grigoriev, issue 4352). + +* Count line numbers correctly inside strings in configuration files (reported + by Pedro Navarro, issue 4325). + +* Map bright black (colour 8) to white (7) if the background is black on + terminals with only eight colours so the text is not invisible (from Dmytro + Bagrii, issue 4322). + +* New codepoint-widths option allowing users to override the width of + individual Unicode codepoints. + +* Add a nesting limit to source-file (from Fadi Afani, issue 4223). + +* Add copy-mode-position-style and copy-mode-selection-style options for copy + mode. + +* Add no-detach-on-destroy client option (issue 4242). + +* Add input-buffer-size option (from Ken Lau). + +* Add support for a scrollbar at the side of each pane. New options + pane-scrollbars turn them on or off, pane-scrollbars-position sets the + position (left or right), and pane-scrollbars-style to set the colours (from + Michael Grant, issue 4221). + +* Allow control characters to be entered at the command prompt by prefixing + with C-v (from Alexander Arch, issue 4206). + +* Do not attempt to search for zero length strings (from Alexander Arch, issue + 4209). + +* Preserve tabs for copying and capture-pane (from Alexander Arch, issue + 4201). + +* Increase the maximum for repeat-time. + +* Adjust how Ctrl and Meta keys are sent to use standard representation if + available in mode 1 (from Stanislav Kljuhhin, issue 4188). + +* Allow attributes in menu style (from Japin Li, issue 4194). + +* Add a sixel_support format variable which is 1 if SIXEL is supported, always + 0 on OpenBSD (requested by Misaki Masa, issue 4177). + +* Add prompt-cursor-colour and prompt-cursor-style to set the style of the + cursor in the command prompt and remove the emulated cursor (from Alexander + Arch, issue 4170). + +* Add initial-repeat-time option to allow the first repeat time to be increased + and later reduced (from David le Blanc, issue 4164). + +* Send focus events to pane when entering or leaving popup (issue 3991). + +* Add copy-mode-position-format to configure the position indicator. + +* Add -y flag to disable confirmation prompts in modes (issue 4152). + +* Add -C and -P flags to the copy commands in copy mode: -C prevents the + commands from sending the text to the clipboard and -P prevents them from + adding the text as a paste buffer (issue 4153). + +* Preserve transparency and raster attribute dimensions when sending a SIXEL + image, and avoid collapsing empty lines (issue 4149). + +* Bypass permission check for Cygwin (based on a change by Yuya Adachi via + Rafael Kitover, issue 4148). + +* Add MSYSTEM to default update-environment (for Cgywin). + +* Set client stdout file descriptor also for Cgywin (from Michael Wild via Rafael + Kitover, issue 4148). + +* Use global cursor style and colour options for modes instead of default + (issue 4117). + +* Fix pasting so it does not interpret keys but instead copies the input + without interpretation (reported by Mark Kelly). + +* Try to query window pixel size from the outside terminal if the values + returned by TIOCGWINSZ are zero (Dmitry Galchinsky, issue 4099). + +CHANGES FROM 3.5 TO 3.5a + +* Do not translate BSpace as Unicode with extended keys. + +* Fix so that keys with Shift are represented correctly with extended keys. + +* Revert to using /bin/sh for #() and run-shell and if-shell; the change to use + default-shell only applies now to popups. + +* Fix grey colour without a number suffix in styles. + CHANGES FROM 3.4 TO 3.5 * Revamp extended keys support to more closely match xterm and support mode 2 diff --git a/attributes.c b/attributes.c index b839f06d..8eaa8897 100644 --- a/attributes.c +++ b/attributes.c @@ -31,7 +31,7 @@ attributes_tostring(int attr) if (attr == 0) 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_BRIGHT) ? "bright," : "", (attr & GRID_ATTR_DIM) ? "dim," : "", @@ -45,7 +45,8 @@ attributes_tostring(int attr) (attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-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) buf[len - 1] = '\0'; diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 399c83de..cb30749e 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -34,7 +34,7 @@ const struct cmd_entry cmd_refresh_client_entry = { .name = "refresh-client", .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] " "[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE " [adjustment]", @@ -163,37 +163,6 @@ out: 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 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); } - if (args_has(args, 'l')) - return (cmd_refresh_client_clipboard(self, item)); + if (args_has(args, 'l')) { + tty_clipboard_query(&tc->tty); + return (CMD_RETURN_NORMAL); + } if (args_has(args, 'F')) /* -F is an alias for -f */ server_client_set_flags(tc, args_get(args, 'F')); diff --git a/colour.c b/colour.c index 791c5fd5..88198e96 100644 --- a/colour.c +++ b/colour.c @@ -1082,22 +1082,22 @@ colour_palette_free(struct colour_palette *p) /* Get a colour from a palette. */ int -colour_palette_get(struct colour_palette *p, int c) +colour_palette_get(struct colour_palette *p, int n) { if (p == NULL) return (-1); - if (c >= 90 && c <= 97) - c = 8 + c - 90; - else if (c & COLOUR_FLAG_256) - c &= ~COLOUR_FLAG_256; - else if (c >= 8) + if (n >= 90 && n <= 97) + n = 8 + n - 90; + else if (n & COLOUR_FLAG_256) + n &= ~COLOUR_FLAG_256; + else if (n >= 8) return (-1); - if (p->palette != NULL && p->palette[c] != -1) - return (p->palette[c]); - if (p->default_palette != NULL && p->default_palette[c] != -1) - return (p->default_palette[c]); + if (p->palette != NULL && p->palette[n] != -1) + return (p->palette[n]); + if (p->default_palette != NULL && p->default_palette[n] != -1) + return (p->default_palette[n]); return (-1); } @@ -1107,15 +1107,14 @@ colour_palette_set(struct colour_palette *p, int n, int c) { u_int i; - if (p == NULL || n > 255) + if (p == NULL || n < 0 || n > 255) return (0); if (c == -1 && p->palette == NULL) return (0); - if (c != -1 && p->palette == NULL) { - if (p->palette == NULL) - p->palette = xcalloc(256, sizeof *p->palette); + if (p->palette == NULL) { + p->palette = xcalloc(256, sizeof *p->palette); for (i = 0; i < 256; i++) p->palette[i] = -1; } diff --git a/configure.ac b/configure.ac index 3b23febe..e6d4b548 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT([tmux], next-3.6) +AC_INIT([tmux], next-3.7) AC_PREREQ([2.60]) AC_CONFIG_AUX_DIR(etc) diff --git a/environ.c b/environ.c index 63d47946..039d3a4a 100644 --- a/environ.c +++ b/environ.c @@ -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_VERSION", 0, "%s", getversion()); 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 diff --git a/format-draw.c b/format-draw.c index efc6ab1a..c8cb74b6 100644 --- a/format-draw.c +++ b/format-draw.c @@ -1104,8 +1104,6 @@ format_width(const char *expanded) more = utf8_append(&ud, *cp); if (more == UTF8_DONE) width += ud.width; - else - cp -= ud.have; } else if (*cp > 0x1f && *cp < 0x7f) { width++; cp++; diff --git a/format.c b/format.c index 36799d27..17654c30 100644 --- a/format.c +++ b/format.c @@ -5545,7 +5545,8 @@ format_expand1(struct format_expand_state *es, const char *fmt) buf[off++] = *fmt++; continue; } - fmt++; + if (*fmt++ == '\0') + break; ch = (u_char)*fmt++; switch (ch) { diff --git a/input.c b/input.c index 3a61ec26..58a1b091 100644 --- a/input.c +++ b/input.c @@ -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. */ static void input_osc_52(struct input_ctx *ictx, const char *p) { struct window_pane *wp = ictx->wp; + size_t len; char *end; - const char *buf = NULL; - size_t len = 0; u_char *out; int outlen, state; struct screen_write_ctx ctx; - struct paste_buffer *pb; const char* allow = "cpqs01234567"; char flags[sizeof "cpqs01234567"] = ""; 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); if (strcmp(end, "?") == 0) { - if ((pb = paste_get_top(NULL)) != NULL) - 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\\"); + input_osc_52_reply(ictx); return; } @@ -3169,6 +3187,7 @@ input_osc_104(struct input_ctx *ictx, const char *p) free(copy); } +/* Send a clipboard reply. */ void input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len, 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); tty_puts(&c->tty, s); break; + case INPUT_REQUEST_CLIPBOARD: + tty_putcode_ss(&c->tty, TTYC_MS, "", "?"); + break; case INPUT_REQUEST_QUEUE: break; } @@ -3312,6 +3334,39 @@ input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx) 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. */ void 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; 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; break; } - input_free_request(ir); } if (found == NULL) return; @@ -3335,8 +3397,11 @@ input_request_reply(struct client *c, enum input_request_type type, void *data) break; if (ir->type == INPUT_REQUEST_QUEUE) input_send_reply(ir->ictx, ir->data); - else if (ir == found && ir->type == INPUT_REQUEST_PALETTE) { - input_osc_colour_reply(ir->ictx, 0, 4, pd->idx, pd->c, ir->end); + else if (ir == found) { + 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; } input_free_request(ir); diff --git a/key-bindings.c b/key-bindings.c index de7cef04..436bf032 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -442,7 +442,7 @@ key_bindings_init(void) "bind -n MouseDown1Pane { select-pane -t=; send -M }", /* 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. */ "bind -n WheelUpPane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e } }", diff --git a/layout.c b/layout.c index b3d83622..885398a7 100644 --- a/layout.c +++ b/layout.c @@ -1159,9 +1159,8 @@ int layout_spread_cell(struct window *w, struct layout_cell *parent) { struct layout_cell *lc; - struct style *sb_style = &w->active->scrollbar_style; u_int number, each, size, this, remainder; - int change, changed, status, scrollbars; + int change, changed, status; number = 0; TAILQ_FOREACH (lc, &parent->cells, entry) @@ -1169,14 +1168,9 @@ 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"); - if (parent->type == LAYOUT_LEFTRIGHT) { - if (scrollbars) - size = parent->sx - sb_style->width + sb_style->pad; - else - size = parent->sx; - } + if (parent->type == LAYOUT_LEFTRIGHT) + size = parent->sx; else if (parent->type == LAYOUT_TOPBOTTOM) { if (layout_add_horizontal_border(w, parent, status)) size = parent->sy - 1; diff --git a/menu.c b/menu.c index fd3a9fe4..7449d88d 100644 --- a/menu.c +++ b/menu.c @@ -438,6 +438,38 @@ chosen: return (1); } +static void +menu_resize_cb(struct client *c, void *data) +{ + struct menu_data *md = data; + u_int nx, ny, w, h; + + if (md == NULL) + return; + + nx = md->px; + ny = md->py; + + w = md->menu->width + 4; + h = md->menu->count + 2; + + if (nx + w > c->tty.sx) { + if (c->tty.sx <= w) + nx = 0; + else + nx = c->tty.sx - w; + } + + if (ny + h > c->tty.sy) { + if (c->tty.sy <= h) + ny = 0; + else + ny = c->tty.sy - h; + } + md->px = nx; + md->py = ny; +} + static void menu_set_style(struct client *c, struct grid_cell *gc, const char *style, const char *option) @@ -551,6 +583,6 @@ menu_display(struct menu *menu, int flags, int starting_choice, if (md == NULL) return (-1); server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb, - menu_key_cb, menu_free_cb, NULL, md); + menu_key_cb, menu_free_cb, menu_resize_cb, md); return (0); } diff --git a/options-table.c b/options-table.c index 6946a085..447fb52e 100644 --- a/options-table.c +++ b/options-table.c @@ -36,7 +36,7 @@ static const char *options_table_mode_keys_list[] = { "emacs", "vi", NULL }; static const char *options_table_clock_mode_style_list[] = { - "12", "24", NULL + "12", "24", "12-with-seconds", "24-with-seconds", NULL }; static const char *options_table_status_list[] = { "off", "on", "2", "3", "4", "5", NULL @@ -84,6 +84,9 @@ static const char *options_table_popup_border_lines_list[] = { static const char *options_table_set_clipboard_list[] = { "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[] = { "largest", "smallest", "manual", "latest", NULL }; @@ -405,6 +408,18 @@ const struct options_table_entry options_table[] = { .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", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, diff --git a/regress/combine-test.result b/regress/combine-test.result index 0d2afb5e..a08539fb 100644 --- a/regress/combine-test.result +++ b/regress/combine-test.result @@ -4,7 +4,7 @@ Λ̊1 🏻2 👍🏻3 -👍🏻 👍🏻4 +👍🏻 👍🏻4 🤷‍♂️5 ♂️7 🤷‍♂️8 diff --git a/screen-redraw.c b/screen-redraw.c index 9244348f..82dcb4c9 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1313,8 +1313,10 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx, int yoff = wp->yoff; struct visible_ranges *vr; - if (ctx->statustop) + if (ctx->statustop) { + sb_y += ctx->statuslines; sy += ctx->statuslines; + } /* Set up style for slider. */ gc = sb_style->gc; diff --git a/screen-write.c b/screen-write.c index 48ee3d15..c7ab21bd 100644 --- a/screen-write.c +++ b/screen-write.c @@ -2206,6 +2206,8 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) case HANGULJAMO_STATE_NOT_HANGULJAMO: if (utf8_should_combine(&last.data, ud)) force_wide = 1; + else if (utf8_should_combine(ud, &last.data)) + force_wide = 1; else if (!utf8_has_zwj(&last.data)) return (0); break; diff --git a/screen.c b/screen.c index a7a13af2..d82784c5 100644 --- a/screen.c +++ b/screen.c @@ -594,8 +594,12 @@ screen_select_cell(struct screen *s, struct grid_cell *dst, if (COLOUR_DEFAULT(dst->bg)) dst->bg = src->bg; utf8_copy(&dst->data, &src->data); - dst->attr = src->attr; 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. */ diff --git a/server-client.c b/server-client.c index 6c6e1930..820e306a 100644 --- a/server-client.c +++ b/server-client.c @@ -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 */ /* 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) || ((int)py >= wp->yoff && py < wp->yoff + wp->sy)) && ((sb_pos == PANE_SCROLLBARS_RIGHT && @@ -1307,7 +1308,11 @@ have_event: if (c->tty.mouse_scrolling_flag == 0 && where == SCROLLBAR_SLIDER) { 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; case WHEEL: @@ -2938,8 +2943,8 @@ server_client_reset_state(struct client *c) struct window_pane *wp = server_client_get_pane(c), *loop; struct screen *s = NULL; struct options *oo = c->session->options; - int mode = 0, cursor, flags, n; - u_int cx = 0, cy = 0, ox, oy, sx, sy; + int mode = 0, cursor, flags; + u_int cx = 0, cy = 0, ox, oy, sx, sy, n; if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) return; @@ -2971,13 +2976,13 @@ server_client_reset_state(struct client *c) if (c->prompt_string != NULL) { n = options_get_number(oo, "status-position"); if (n == 0) - cy = 0; + cy = status_prompt_line_at(c); else { - n = status_line_size(c); - if (n == 0) - cy = tty->sy - 1; - else + n = status_line_size(c) - status_prompt_line_at(c); + if (n <= tty->sy) cy = tty->sy - n; + else + cy = tty->sy - 1; } cx = c->prompt_cursor; } else if (c->overlay_draw == NULL) { diff --git a/server-fn.c b/server-fn.c index 6ab7fa48..29802a60 100644 --- a/server-fn.c +++ b/server-fn.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include diff --git a/status.c b/status.c index 2786db7e..0551b547 100644 --- a/status.c +++ b/status.c @@ -264,14 +264,19 @@ status_line_size(struct client *c) } /* Get the prompt line number for client's session. 1 means at the bottom. */ -static u_int +u_int status_prompt_line_at(struct client *c) { struct session *s = c->session; + u_int line, lines; - if (c->flags & (CLIENT_STATUSOFF|CLIENT_CONTROL)) - return (1); - return (options_get_number(s->options, "message-line")); + lines = status_line_size(c); + if (lines == 0) + return (0); + line = options_get_number(s->options, "message-line"); + if (line >= lines) + return (lines - 1); + return (line); } /* Get window at window list position. */ diff --git a/style.c b/style.c index ef3bb225..4acc17dd 100644 --- a/style.c +++ b/style.c @@ -218,20 +218,23 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) sy->gc.attr = 0; else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { if (strcmp(tmp + 2, "attr") == 0) - value = 0xffff & ~GRID_ATTR_CHARSET; - else if ((value = attributes_fromstring(tmp + 2)) == -1) - goto error; - sy->gc.attr &= ~value; + sy->gc.attr |= GRID_ATTR_NOATTR; + else { + value = attributes_fromstring(tmp + 2); + if (value == -1) + goto error; + sy->gc.attr &= ~value; + } } else if (end > 6 && strncasecmp(tmp, "width=", 6) == 0) { - n = strtonum(tmp + 6, 0, UINT_MAX, &errstr); - if (errstr != NULL) - goto error; - sy->width = (int)n; + n = strtonum(tmp + 6, 0, UINT_MAX, &errstr); + if (errstr != NULL) + goto error; + sy->width = (int)n; } else if (end > 4 && strncasecmp(tmp, "pad=", 4) == 0) { - n = strtonum(tmp + 4, 0, UINT_MAX, &errstr); - if (errstr != NULL) - goto error; - sy->pad = (int)n; + n = strtonum(tmp + 4, 0, UINT_MAX, &errstr); + if (errstr != NULL) + goto error; + sy->pad = (int)n; } else { if ((value = attributes_fromstring(tmp)) == -1) goto error; @@ -344,13 +347,13 @@ style_tostring(struct style *sy) attributes_tostring(gc->attr)); comma = ","; } - if (sy->width >= 0) { - xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma, + if (sy->width >= 0) { + xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma, sy->width); comma = ","; } - if (sy->pad >= 0) { - xsnprintf(s + off, sizeof s - off, "%spad=%u", comma, + if (sy->pad >= 0) { + xsnprintf(s + off, sizeof s - off, "%spad=%u", comma, sy->pad); comma = ","; } diff --git a/tmux.1 b/tmux.1 index a25da1fb..404909bd 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1363,12 +1363,11 @@ and sets an environment variable for the newly created session; it may be specified multiple times. .Tg refresh .It Xo Ic refresh-client -.Op Fl cDLRSU +.Op Fl cDlLRSU .Op Fl A Ar pane:state .Op Fl B Ar name:what:format .Op Fl C Ar size .Op Fl f Ar flags -.Op Fl l Op Ar target-pane .Op Fl r Ar pane:report .Op Fl t Ar target-client .Op Ar adjustment @@ -1489,11 +1488,7 @@ a colon, then a report escape sequence. .Fl l requests the clipboard from the client using the .Xr xterm 1 -escape sequence. -If -.Ar target-pane -is given, the clipboard is sent (in encoded form), otherwise it is stored in a -new paste buffer. +escape sequence and stores it in a new paste buffer. .Pp .Fl L , .Fl R , @@ -4241,6 +4236,32 @@ passed through to applications running in .Nm . Attached clients should be detached and attached again after changing this 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 If not empty, a file to which .Nm @@ -4927,7 +4948,7 @@ option is enabled. Set clock colour. .Pp .It Xo Ic clock-mode-style -.Op Ic 12 | 24 +.Op Ic 12 | 24 | 12-with-seconds | 24-with-seconds .Xc Set clock hour format. .Pp @@ -6135,7 +6156,6 @@ The following variables are available, where appropriate: .It Li "insert_flag" Ta "" Ta "Pane insert flag" .It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor 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 "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" @@ -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_grouped" Ta "" Ta "1 if session in a group" .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_many_attached" Ta "" Ta "1 if multiple clients attached" .It Li "session_marked" Ta "" Ta "1 if this session contains the marked pane" diff --git a/tmux.h b/tmux.h index eaeb6eeb..48e7af87 100644 --- a/tmux.h +++ b/tmux.h @@ -727,6 +727,7 @@ struct colour_palette { #define GRID_ATTR_UNDERSCORE_4 0x800 #define GRID_ATTR_UNDERSCORE_5 0x1000 #define GRID_ATTR_OVERLINE 0x2000 +#define GRID_ATTR_NOATTR 0x4000 /* All underscore attributes. */ #define GRID_ATTR_ALL_UNDERSCORE \ @@ -1129,6 +1130,7 @@ struct window_mode_entry { /* Type of request to client. */ enum input_request_type { INPUT_REQUEST_PALETTE, + INPUT_REQUEST_CLIPBOARD, INPUT_REQUEST_QUEUE }; @@ -1138,6 +1140,12 @@ struct input_request_palette_data { int c; }; +/* Clipboard request reply data. */ +struct input_request_clipboard_data { + char *buf; + size_t len; +}; + /* Request sent to client on behalf of pane. */ TAILQ_HEAD(input_requests, input_request); @@ -2016,7 +2024,7 @@ struct client { #define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL #define CLIENT_CONTROL_WAITEXIT 0x200000000ULL #define CLIENT_WINDOWSIZECHANGED 0x400000000ULL -#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL +/* 0x800000000ULL unused */ #define CLIENT_BRACKETPASTING 0x1000000000ULL #define CLIENT_ASSUMEPASTING 0x2000000000ULL #define CLIENT_REDRAWSCROLLBARS 0x4000000000ULL @@ -2959,6 +2967,7 @@ extern u_int status_prompt_hsize[]; void status_timer_start(struct client *); void status_timer_start_all(void); void status_update_cache(struct session *); +u_int status_prompt_line_at(struct client *); int status_at_line(struct client *); u_int status_line_size(struct client *); struct style_range *status_get_range(struct client *, u_int, u_int); diff --git a/tty-keys.c b/tty-keys.c index 77254591..7474621c 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1301,12 +1301,11 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, static int tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) { - struct client *c = tty->client; - struct window_pane *wp; - size_t end, terminator = 0, needed; - char *copy, *out; - int outlen; - u_int i; + struct client *c = tty->client; + size_t end, terminator = 0, needed; + char *copy, *out; + int outlen; + struct input_request_clipboard_data cd; *size = 0; @@ -1364,12 +1363,6 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) buf++; 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. */ copy = xmalloc(end + 1); 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); } free(copy); - - /* Create a new paste buffer and forward to panes. */ 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); } diff --git a/tty.c b/tty.c index 26752a9a..eda897d8 100644 --- a/tty.c +++ b/tty.c @@ -35,6 +35,8 @@ static int tty_log_fd = -1; +static void tty_start_timer_callback(int, short, void *); +static void tty_clipboard_query_callback(int, short, void *); static void tty_set_italics(struct tty *); static int tty_try_colour(struct tty *, int, const char *); static void tty_force_cursor_colour(struct tty *, int); @@ -296,6 +298,8 @@ tty_open(struct tty *tty, char **cause) if (tty->out == NULL) fatal("out of memory"); + evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); + evtimer_set(&tty->start_timer, tty_start_timer_callback, tty); evtimer_set(&tty->timer, tty_timer_callback, tty); tty_start_tty(tty); @@ -327,7 +331,6 @@ tty_start_start_timer(struct tty *tty) log_debug("%s: start timer started", c->name); evtimer_del(&tty->start_timer); - evtimer_set(&tty->start_timer, tty_start_timer_callback, tty); evtimer_add(&tty->start_timer, &tv); } @@ -445,6 +448,7 @@ tty_stop_tty(struct tty *tty) tty->flags &= ~TTY_STARTED; evtimer_del(&tty->start_timer); + evtimer_del(&tty->clipboard_timer); event_del(&tty->timer); tty->flags &= ~TTY_BLOCK; @@ -3296,12 +3300,6 @@ static void tty_clipboard_query_callback(__unused int fd, __unused short events, void *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; } @@ -3311,11 +3309,9 @@ tty_clipboard_query(struct tty *tty) { struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; - if ((~tty->flags & TTY_STARTED) || (tty->flags & TTY_OSC52QUERY)) - return; - tty_putcode_ss(tty, TTYC_MS, "", "?"); - - tty->flags |= TTY_OSC52QUERY; - evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); - evtimer_add(&tty->clipboard_timer, &tv); + if ((tty->flags & TTY_STARTED) && (~tty->flags & TTY_OSC52QUERY)) { + tty_putcode_ss(tty, TTYC_MS, "", "?"); + tty->flags |= TTY_OSC52QUERY; + evtimer_add(&tty->clipboard_timer, &tv); + } } diff --git a/utf8-combined.c b/utf8-combined.c index 635ae92c..1eee3b82 100644 --- a/utf8-combined.c +++ b/utf8-combined.c @@ -122,6 +122,7 @@ utf8_should_combine(const struct utf8_data *with, const struct utf8_data *add) case 0x1F47C: case 0x1F481: case 0x1F482: + case 0x1F483: case 0x1F485: case 0x1F486: case 0x1F487: diff --git a/window-clock.c b/window-clock.c index 8cef3f9a..51620d4a 100644 --- a/window-clock.c +++ b/window-clock.c @@ -45,7 +45,7 @@ const struct window_mode window_clock_mode = { }; struct window_clock_mode_data { - struct screen screen; + struct screen screen; time_t tim; struct event timer; }; @@ -142,7 +142,7 @@ window_clock_timer_callback(__unused int fd, __unused short events, void *arg) t = time(NULL); gmtime_r(&t, &now); gmtime_r(&data->tim, &then); - if (now.tm_min == then.tm_min) + if (now.tm_sec == then.tm_sec) return; data->tim = t; @@ -207,11 +207,12 @@ window_clock_draw_screen(struct window_mode_entry *wme) { struct window_pane *wp = wme->wp; struct window_clock_mode_data *data = wme->data; - struct screen_write_ctx ctx; + struct screen_write_ctx ctx; int colour, style; struct screen *s = &data->screen; struct grid_cell gc; char tim[64], *ptr; + const char *timeformat; time_t t; struct tm *tm; u_int i, j, x, y, idx; @@ -223,14 +224,23 @@ window_clock_draw_screen(struct window_mode_entry *wme) t = time(NULL); tm = localtime(&t); - if (style == 0) { - strftime(tim, sizeof tim, "%l:%M ", localtime(&t)); + if (style == 0 || style == 2) { + if (style == 2) + timeformat = "%l:%M:%S "; + else + timeformat = "%l:%M "; + strftime(tim, sizeof tim, timeformat, localtime(&t)); if (tm->tm_hour >= 12) strlcat(tim, "PM", sizeof tim); else strlcat(tim, "AM", sizeof tim); - } else - strftime(tim, sizeof tim, "%H:%M", tm); + } else { + if (style == 3) + timeformat = "%H:%M:%S"; + else + timeformat = "%H:%M"; + strftime(tim, sizeof tim, timeformat, tm); + } screen_write_clearscreen(&ctx, 8); diff --git a/window-copy.c b/window-copy.c index f8d2fb7e..313e08a1 100644 --- a/window-copy.c +++ b/window-copy.c @@ -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); } else { /* 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 || diff --git a/window.c b/window.c index aaa22ce1..a6cf9457 100644 --- a/window.c +++ b/window.c @@ -1851,7 +1851,7 @@ window_pane_mode(struct window_pane *wp) int 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); if (sb_option == PANE_SCROLLBARS_ALWAYS || (sb_option == PANE_SCROLLBARS_MODAL &&