diff --git a/Makefile.am b/Makefile.am index 9bbd21d4..874e51a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,6 +14,7 @@ dist_EXTRA_tmux_SOURCES = compat/*.[ch] AM_CPPFLAGS += @XOPEN_DEFINES@ \ -DTMUX_VERSION='"@VERSION@"' \ -DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' \ + -DTMUX_LOCK_CMD='"@DEFAULT_LOCK_CMD@"' \ -DTMUX_TERM='"@DEFAULT_TERM@"' # Additional object files. diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index ce8c95e0..485e6e65 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -41,8 +41,9 @@ const struct cmd_entry cmd_confirm_before_entry = { .name = "confirm-before", .alias = "confirm", - .args = { "bp:t:", 1, 1, cmd_confirm_before_args_parse }, - .usage = "[-b] [-p prompt] " CMD_TARGET_CLIENT_USAGE " command", + .args = { "bc:p:t:y", 1, 1, cmd_confirm_before_args_parse }, + .usage = "[-by] [-c confirm_key] [-p prompt] " CMD_TARGET_CLIENT_USAGE + " command", .flags = CMD_CLIENT_TFLAG, .exec = cmd_confirm_before_exec @@ -51,6 +52,8 @@ const struct cmd_entry cmd_confirm_before_entry = { struct cmd_confirm_before_data { struct cmdq_item *item; struct cmd_list *cmdlist; + u_char confirm_key; + int default_yes; }; static enum args_parse_type @@ -68,7 +71,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) struct client *tc = cmdq_get_target_client(item); struct cmd_find_state *target = cmdq_get_target(item); char *new_prompt; - const char *prompt, *cmd; + const char *confirm_key, *prompt, *cmd; int wait = !args_has(args, 'b'); cdata = xcalloc(1, sizeof *cdata); @@ -79,11 +82,26 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) if (wait) cdata->item = item; + cdata->default_yes = args_has(args, 'y'); + if ((confirm_key = args_get(args, 'c')) != NULL) { + if (confirm_key[1] == '\0' && + confirm_key[0] > 31 && + confirm_key[0] < 127) + cdata->confirm_key = confirm_key[0]; + else { + cmdq_error(item, "invalid confirm key"); + return (CMD_RETURN_ERROR); + } + } + else + cdata->confirm_key = 'y'; + if ((prompt = args_get(args, 'p')) != NULL) xasprintf(&new_prompt, "%s ", prompt); else { cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name; - xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd); + xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", + cmd, cdata->confirm_key); } status_prompt_set(tc, target, new_prompt, NULL, @@ -107,9 +125,9 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s, if (c->flags & CLIENT_DEAD) goto out; - if (s == NULL || *s == '\0') + if (s == NULL) goto out; - if (tolower((u_char)s[0]) != 'y' || s[1] != '\0') + if (s[0] != cdata->confirm_key && (s[0] != '\0' || !cdata->default_yes)) goto out; retcode = 0; @@ -123,12 +141,12 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s, } out: - if (item != NULL) { - if (cmdq_get_client(item) != NULL && - cmdq_get_client(item)->session == NULL) - cmdq_get_client(item)->retval = retcode; - cmdq_continue(item); - } + if (item != NULL) { + if (cmdq_get_client(item) != NULL && + cmdq_get_client(item)->session == NULL) + cmdq_get_client(item)->retval = retcode; + cmdq_continue(item); + } return (0); } diff --git a/compat.h b/compat.h index aefc0d38..cabdf3ad 100644 --- a/compat.h +++ b/compat.h @@ -425,6 +425,7 @@ void *recallocarray(void *, size_t, size_t, size_t); /* systemd.c */ int systemd_activated(void); int systemd_create_socket(int, char **); +int systemd_move_pid_to_new_cgroup(pid_t, char **); #endif #ifdef HAVE_UTF8PROC diff --git a/compat/systemd.c b/compat/systemd.c index cce42ed4..6f790a32 100644 --- a/compat/systemd.c +++ b/compat/systemd.c @@ -19,7 +19,10 @@ #include #include +#include #include +#include +#include #include @@ -64,3 +67,149 @@ fail: xasprintf(cause, "systemd socket error (%s)", strerror(errno)); return (-1); } + +int +systemd_move_pid_to_new_cgroup(pid_t pid, char **cause) +{ + sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus_message *m = NULL, *reply = NULL; + sd_bus *bus = NULL; + char *name, *desc, *slice; + sd_id128_t uuid; + int r; + pid_t parent_pid; + + /* Connect to the session bus. */ + r = sd_bus_default_user(&bus); + if (r < 0) { + xasprintf(cause, "failed to connect to session bus: %s", + strerror(-r)); + goto finish; + } + + /* Start building the method call. */ + r = sd_bus_message_new_method_call(bus, &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartTransientUnit"); + if (r < 0) { + xasprintf(cause, "failed to create bus message: %s", + strerror(-r)); + goto finish; + } + + /* Generate a unique name for the new scope, to avoid collisions. */ + r = sd_id128_randomize(&uuid); + if (r < 0) { + xasprintf(cause, "failed to generate uuid: %s", strerror(-r)); + goto finish; + } + xasprintf(&name, "tmux-spawn-" SD_ID128_UUID_FORMAT_STR ".scope", + SD_ID128_FORMAT_VAL(uuid)); + r = sd_bus_message_append(m, "s", name); + free(name); + if (r < 0) { + xasprintf(cause, "failed to append to bus message: %s", + strerror(-r)); + goto finish; + } + + /* Mode: fail if there's a queued unit with the same name. */ + r = sd_bus_message_append(m, "s", "fail"); + if (r < 0) { + xasprintf(cause, "failed to append to bus message: %s", + strerror(-r)); + goto finish; + } + + /* Start properties array. */ + r = sd_bus_message_open_container(m, 'a', "(sv)"); + if (r < 0) { + xasprintf(cause, "failed to start properties array: %s", + strerror(-r)); + goto finish; + } + + parent_pid = getpid(); + xasprintf(&desc, "tmux child pane %ld launched by process %ld", + (long)pid, (long)parent_pid); + r = sd_bus_message_append(m, "(sv)", "Description", "s", desc); + free(desc); + if (r < 0) { + xasprintf(cause, "failed to append to properties: %s", + strerror(-r)); + goto finish; + } + + /* + * Inherit the slice from the parent process, or default to + * "app-tmux.slice" if that fails. + */ + r = sd_pid_get_user_slice(parent_pid, &slice); + if (r < 0) { + slice = xstrdup("app-tmux.slice"); + } + r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); + free(slice); + if (r < 0) { + xasprintf(cause, "failed to append to properties: %s", + strerror(-r)); + goto finish; + } + + /* PIDs to add to the scope: length - 1 array of uint32_t. */ + r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid); + if (r < 0) { + xasprintf(cause, "failed to append to properties: %s", + strerror(-r)); + goto finish; + } + + /* Clean up the scope even if it fails. */ + r = sd_bus_message_append(m, "(sv)", "CollectMode", "s", + "inactive-or-failed"); + if (r < 0) { + xasprintf(cause, "failed to append to properties: %s", + strerror(-r)); + goto finish; + } + + /* End properties array. */ + r = sd_bus_message_close_container(m); + if (r < 0) { + xasprintf(cause, "failed to end properties array: %s", + strerror(-r)); + goto finish; + } + + /* aux is currently unused and should be passed an empty array. */ + r = sd_bus_message_append(m, "a(sa(sv))", 0); + if (r < 0) { + xasprintf(cause, "failed to append to bus message: %s", + strerror(-r)); + goto finish; + } + + /* Call the method with a timeout of 1 second = 1e6 us. */ + r = sd_bus_call(bus, m, 1000000, &error, &reply); + if (r < 0) { + if (error.message != NULL) { + /* We have a specific error message from sd-bus. */ + xasprintf(cause, "StartTransientUnit call failed: %s", + error.message); + } else { + xasprintf(cause, "StartTransientUnit call failed: %s", + strerror(-r)); + } + goto finish; + } + +finish: + sd_bus_error_free(&error); + sd_bus_message_unref(m); + sd_bus_message_unref(reply); + sd_bus_unref(bus); + + return (r); +} diff --git a/configure.ac b/configure.ac index 8e846042..1ccd0481 100644 --- a/configure.ac +++ b/configure.ac @@ -350,6 +350,10 @@ else AC_MSG_ERROR("curses not found") fi fi +AC_CHECK_FUNCS([ \ + tiparm \ + tiparm_s \ +]) # Look for utempter. AC_ARG_ENABLE( @@ -420,6 +424,21 @@ if test x"$enable_systemd" = xyes; then fi fi AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$found_systemd" = xyes]) +AC_ARG_ENABLE( + cgroups, + AS_HELP_STRING(--disable-cgroups, disable adding panes to new cgroups with systemd) +) +if test "x$enable_cgroups" = x; then + # Default to the same as $enable_systemd. + enable_cgroups=$enable_systemd +fi +if test "x$enable_cgroups" = xyes; then + if test "x$found_systemd" = xyes; then + AC_DEFINE(ENABLE_CGROUPS) + else + AC_MSG_ERROR("cgroups requires systemd to be enabled") + fi +fi # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. AC_MSG_CHECKING(for b64_ntop) @@ -921,6 +940,19 @@ AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux) AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku) AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown) +# Set the default lock command +DEFAULT_LOCK_CMD="lock -np" +AC_MSG_CHECKING(lock-command) +if test "x$PLATFORM" = xlinux; then + AC_CHECK_PROG(found_vlock, vlock, yes, no) + if test "x$found_vlock" = xyes; then + DEFAULT_LOCK_CMD="vlock" + fi +fi +AC_MSG_RESULT($DEFAULT_LOCK_CMD) +AC_SUBST(DEFAULT_LOCK_CMD) + + # Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user # variables. AC_SUBST(AM_CPPFLAGS) diff --git a/file.c b/file.c index 3c1096be..9bea5179 100644 --- a/file.c +++ b/file.c @@ -174,9 +174,9 @@ file_fire_read(struct client_file *cf) int file_can_print(struct client *c) { - if (c == NULL) - return (0); - if (c->session != NULL && (~c->flags & CLIENT_CONTROL)) + if (c == NULL || + (c->flags & CLIENT_ATTACHED) || + (c->flags & CLIENT_CONTROL)) return (0); return (1); } diff --git a/format.c b/format.c index 547f4e1a..275d5218 100644 --- a/format.c +++ b/format.c @@ -1885,6 +1885,18 @@ format_cb_pane_input_off(struct format_tree *ft) return (NULL); } +/* Callback for pane_unseen_changes. */ +static void * +format_cb_pane_unseen_changes(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->flags & PANE_UNSEENCHANGES) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + /* Callback for pane_last. */ static void * format_cb_pane_last(struct format_tree *ft) @@ -2953,6 +2965,9 @@ static const struct format_table_entry format_table[] = { { "pane_tty", FORMAT_TABLE_STRING, format_cb_pane_tty }, + { "pane_unseen_changes", FORMAT_TABLE_STRING, + format_cb_pane_unseen_changes + }, { "pane_width", FORMAT_TABLE_STRING, format_cb_pane_width }, diff --git a/input.c b/input.c index 42862d8f..41d1a266 100644 --- a/input.c +++ b/input.c @@ -971,6 +971,10 @@ input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len) window_update_activity(wp->window); wp->flags |= PANE_CHANGED; + /* Flag new input while in a mode. */ + if (!TAILQ_EMPTY(&wp->modes)) + wp->flags |= PANE_UNSEENCHANGES; + /* NULL wp if there is a mode set as don't want to update the tty. */ if (TAILQ_EMPTY(&wp->modes)) screen_write_start_pane(sctx, wp, &wp->base); diff --git a/options-table.c b/options-table.c index d4e7b204..6cb724cc 100644 --- a/options-table.c +++ b/options-table.c @@ -530,7 +530,7 @@ const struct options_table_entry options_table[] = { { .name = "lock-command", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SESSION, - .default_str = "lock -np", + .default_str = TMUX_LOCK_CMD, .text = "Shell command to run to lock a client." }, diff --git a/proc.c b/proc.c index 67ec214a..30eedadb 100644 --- a/proc.c +++ b/proc.c @@ -193,18 +193,13 @@ proc_start(const char *name) log_debug("%s started (%ld): version %s, socket %s, protocol %d", name, (long)getpid(), getversion(), socket_path, PROTOCOL_VERSION); log_debug("on %s %s %s", u.sysname, u.release, u.version); - log_debug("using libevent %s (%s)" + log_debug("using libevent %s %s", event_get_version(), event_get_method()); #ifdef HAVE_UTF8PROC - "; utf8proc %s" + log_debug("using utf8proc %s", utf8proc_version()); #endif #ifdef NCURSES_VERSION - "; ncurses " NCURSES_VERSION + log_debug("using ncurses %s %06u", NCURSES_VERSION, NCURSES_VERSION_PATCH); #endif - , event_get_version(), event_get_method() -#ifdef HAVE_UTF8PROC - , utf8proc_version() -#endif - ); tp = xcalloc(1, sizeof *tp); tp->name = xstrdup(name); diff --git a/screen-write.c b/screen-write.c index 0718df87..99e63ae9 100644 --- a/screen-write.c +++ b/screen-write.c @@ -132,6 +132,12 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c) { struct window_pane *wp = ttyctx->arg; + if (ttyctx->allow_invisible_panes) { + if (session_has(c->session, wp->window)) + return (1); + return (0); + } + if (c->session->curw->window != wp->window) return (0); if (wp->layout_cell == NULL) diff --git a/spawn.c b/spawn.c index e63133fe..10604028 100644 --- a/spawn.c +++ b/spawn.c @@ -380,8 +380,20 @@ spawn_pane(struct spawn_context *sc, char **cause) } /* In the parent process, everything is done now. */ - if (new_wp->pid != 0) + if (new_wp->pid != 0) { +#if defined(HAVE_SYSTEMD) && defined(ENABLE_CGROUPS) + /* + * Move the child process into a new cgroup for systemd-oomd + * isolation. + */ + if (systemd_move_pid_to_new_cgroup(new_wp->pid, cause) < 0) { + log_debug("%s: moving pane to new cgroup failed: %s", + __func__, *cause); + free (*cause); + } +#endif goto complete; + } /* * Child process. Change to the working directory or home if that diff --git a/status.c b/status.c index 08952f58..2bb42c0c 100644 --- a/status.c +++ b/status.c @@ -1471,8 +1471,6 @@ process_key: return (0); append_key: - if (key <= 0x1f || (key >= KEYC_BASE && key < KEYC_BASE_END)) - return (0); if (key <= 0x7f) utf8_set(&tmp, key); else if (KEYC_IS_UNICODE(key)) diff --git a/tmux.1 b/tmux.1 index 2009924f..92e2915f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1281,7 +1281,10 @@ behave like .Ic attach-session if .Ar session-name -already exists; in this case, +already exists; +if +.Fl A +is given, .Fl D behaves like .Fl d @@ -5260,6 +5263,7 @@ The following variables are available, where appropriate: .It Li "pane_title" Ta "#T" Ta "Title of pane (can be set by application)" .It Li "pane_top" Ta "" Ta "Top of pane" .It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane" +.It Li "pane_unseen_changes" Ta "" Ta "1 if there were changes in pane while in mode" .It Li "pane_width" Ta "" Ta "Width of pane" .It Li "pid" Ta "" Ta "Server PID" .It Li "rectangle_toggle" Ta "" Ta "1 if rectangle selection is activated" @@ -5806,7 +5810,8 @@ the prompt is shown in the background and the invoking client does not exit until it is dismissed. .Tg confirm .It Xo Ic confirm-before -.Op Fl b +.Op Fl by +.Op Fl c Ar confirm-key .Op Fl p Ar prompt .Op Fl t Ar target-client .Ar command @@ -5827,6 +5832,14 @@ With .Fl b , the prompt is shown in the background and the invoking client does not exit until it is dismissed. +.Fl y +changes the default behaviour (if Enter alone is pressed) of the prompt to +run the command. +.Fl c +changes the confirmation key to +.Ar confirm-key ; +the default is +.Ql y . .Tg menu .It Xo Ic display-menu .Op Fl O diff --git a/tmux.c b/tmux.c index ef78e7b4..a01ed423 100644 --- a/tmux.c +++ b/tmux.c @@ -391,7 +391,7 @@ main(int argc, char **argv) cfg_quiet = 0; break; case 'V': - printf("%s %s\n", getprogname(), getversion()); + printf("tmux %s\n", getversion()); exit(0); case 'l': flags |= CLIENT_LOGIN; diff --git a/tmux.h b/tmux.h index 251d826d..bc12ab09 100644 --- a/tmux.h +++ b/tmux.h @@ -82,6 +82,9 @@ struct winlink; #ifndef TMUX_TERM #define TMUX_TERM "screen" #endif +#ifndef TMUX_LOCK_CMD +#define TMUX_LOCK_CMD "lock -np" +#endif /* Minimum layout cell size, NOT including border lines. */ #define PANE_MINIMUM 1 @@ -159,7 +162,9 @@ struct winlink; #define KEYC_IS_UNICODE(key) \ (((key) & KEYC_MASK_KEY) > 0x7f && \ (((key) & KEYC_MASK_KEY) < KEYC_BASE || \ - ((key) & KEYC_MASK_KEY) >= KEYC_BASE_END)) + ((key) & KEYC_MASK_KEY) >= KEYC_BASE_END) && \ + (((key) & KEYC_MASK_KEY) < KEYC_USER || \ + ((key) & KEYC_MASK_KEY) >= KEYC_USER + KEYC_NUSER)) /* Multiple click timeout. */ #define KEYC_CLICK_TIMEOUT 300 @@ -1063,6 +1068,7 @@ struct window_pane { #define PANE_STATUSDRAWN 0x400 #define PANE_EMPTY 0x800 #define PANE_STYLECHANGED 0x1000 +#define PANE_UNSEENCHANGES 0x2000 int argc; char **argv; @@ -2312,12 +2318,12 @@ void tty_margin_off(struct tty *); void tty_cursor(struct tty *, u_int, u_int); void tty_clipboard_query(struct tty *); void tty_putcode(struct tty *, enum tty_code_code); -void tty_putcode1(struct tty *, enum tty_code_code, int); -void tty_putcode2(struct tty *, enum tty_code_code, int, int); -void tty_putcode3(struct tty *, enum tty_code_code, int, int, int); -void tty_putcode_ptr1(struct tty *, enum tty_code_code, const void *); -void tty_putcode_ptr2(struct tty *, enum tty_code_code, const void *, - const void *); +void tty_putcode_i(struct tty *, enum tty_code_code, int); +void tty_putcode_ii(struct tty *, enum tty_code_code, int, int); +void tty_putcode_iii(struct tty *, enum tty_code_code, int, int, int); +void tty_putcode_s(struct tty *, enum tty_code_code, const char *); +void tty_putcode_ss(struct tty *, enum tty_code_code, const char *, + const char *); void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, u_char); void tty_putn(struct tty *, const void *, size_t, u_int); @@ -2383,15 +2389,15 @@ int tty_term_read_list(const char *, int, char ***, u_int *, void tty_term_free_list(char **, u_int); int tty_term_has(struct tty_term *, enum tty_code_code); const char *tty_term_string(struct tty_term *, enum tty_code_code); -const char *tty_term_string1(struct tty_term *, enum tty_code_code, int); -const char *tty_term_string2(struct tty_term *, enum tty_code_code, int, +const char *tty_term_string_i(struct tty_term *, enum tty_code_code, int); +const char *tty_term_string_ii(struct tty_term *, enum tty_code_code, int, int); -const char *tty_term_string3(struct tty_term *, enum tty_code_code, int, +const char *tty_term_string_iii(struct tty_term *, enum tty_code_code, int, int, int); -const char *tty_term_ptr1(struct tty_term *, enum tty_code_code, - const void *); -const char *tty_term_ptr2(struct tty_term *, enum tty_code_code, - const void *, const void *); +const char *tty_term_string_s(struct tty_term *, enum tty_code_code, + const char *); +const char *tty_term_string_ss(struct tty_term *, enum tty_code_code, + const char *, const char *); int tty_term_number(struct tty_term *, enum tty_code_code); int tty_term_flag(struct tty_term *, enum tty_code_code); const char *tty_term_describe(struct tty_term *, enum tty_code_code); diff --git a/tty-keys.c b/tty-keys.c index 03e91f96..2801914f 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1008,7 +1008,8 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, /* * Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial - * (probably a mouse sequence but need more data). + * (probably a mouse sequence but need more data), -2 if an invalid mouse + * sequence. */ static int tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, @@ -1069,7 +1070,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, if (b < MOUSE_PARAM_BTN_OFF || x < MOUSE_PARAM_POS_OFF || y < MOUSE_PARAM_POS_OFF) - return (-1); + return (-2); b -= MOUSE_PARAM_BTN_OFF; x -= MOUSE_PARAM_POS_OFF; y -= MOUSE_PARAM_POS_OFF; @@ -1111,7 +1112,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, /* Check and return the mouse input. */ if (x < 1 || y < 1) - return (-1); + return (-2); x--; y--; b = sgr_b; diff --git a/tty-term.c b/tty-term.c index 4e9b7799..7dbcfee7 100644 --- a/tty-term.c +++ b/tty-term.c @@ -766,35 +766,100 @@ tty_term_string(struct tty_term *term, enum tty_code_code code) } const char * -tty_term_string1(struct tty_term *term, enum tty_code_code code, int a) +tty_term_string_i(struct tty_term *term, enum tty_code_code code, int a) { - return (tparm((char *) tty_term_string(term, code), a, 0, 0, 0, 0, 0, 0, 0, 0)); + const char *x = tty_term_string(term, code), *s; + +#if defined(HAVE_TIPARM_S) + s = tiparm_s(1, 0, x, a); +#elif defined(HAVE_TIPARM) + s = tiparm(x, a); +#else + s = tparm((char *)x, a, 0, 0, 0, 0, 0, 0, 0, 0); +#endif + if (s == NULL) { + log_debug("could not expand %s", tty_term_codes[code].name); + return (""); + } + return (s); } const char * -tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b) +tty_term_string_ii(struct tty_term *term, enum tty_code_code code, int a, int b) { - return (tparm((char *) tty_term_string(term, code), a, b, 0, 0, 0, 0, 0, 0, 0)); + const char *x = tty_term_string(term, code), *s; + +#if defined(HAVE_TIPARM_S) + s = tiparm_s(2, 0, x, a, b); +#elif defined(HAVE_TIPARM) + s = tiparm(x, a, b); +#else + s = tparm((char *)x, a, b, 0, 0, 0, 0, 0, 0, 0); +#endif + if (s == NULL) { + log_debug("could not expand %s", tty_term_codes[code].name); + return (""); + } + return (s); } const char * -tty_term_string3(struct tty_term *term, enum tty_code_code code, int a, int b, - int c) +tty_term_string_iii(struct tty_term *term, enum tty_code_code code, int a, + int b, int c) { - return (tparm((char *) tty_term_string(term, code), a, b, c, 0, 0, 0, 0, 0, 0)); + const char *x = tty_term_string(term, code), *s; + +#if defined(HAVE_TIPARM_S) + s = tiparm_s(3, 0, x, a, b, c); +#elif defined(HAVE_TIPARM) + s = tiparm(x, a, b, c); +#else + s = tparm((char *)x, a, b, c, 0, 0, 0, 0, 0, 0); +#endif + if (s == NULL) { + log_debug("could not expand %s", tty_term_codes[code].name); + return (""); + } + return (s); } const char * -tty_term_ptr1(struct tty_term *term, enum tty_code_code code, const void *a) +tty_term_string_s(struct tty_term *term, enum tty_code_code code, const char *a) { - return (tparm((char *) tty_term_string(term, code), (long)a, 0, 0, 0, 0, 0, 0, 0, 0)); + const char *x = tty_term_string(term, code), *s; + +#if defined(HAVE_TIPARM_S) + s = tiparm_s(1, 1, x, a); +#elif defined(HAVE_TIPARM) + s = tiparm(x, a); +#else + s = tparm((char *)x, (long)a, 0, 0, 0, 0, 0, 0, 0, 0); +#endif + if (s == NULL) { + log_debug("could not expand %s", tty_term_codes[code].name); + return (""); + } + return (s); } const char * -tty_term_ptr2(struct tty_term *term, enum tty_code_code code, const void *a, - const void *b) +tty_term_string_ss(struct tty_term *term, enum tty_code_code code, + const char *a, const char *b) { - return (tparm((char *) tty_term_string(term, code), (long)a, (long)b, 0, 0, 0, 0, 0, 0, 0)); + const char *x = tty_term_string(term, code), *s; + +#if defined(HAVE_TIPARM_S) + s = tiparm_s(2, 3, x, a, b); +#elif defined(HAVE_TIPARM) + s = tiparm(x, a, b); +#else + s = tparm((char *)x, (long)a, (long)b, 0, 0, 0, 0, 0, 0, 0); +#endif + if (s == NULL) { + log_debug("could not expand %s", tty_term_codes[code].name); + return (""); + } + return (s); } int diff --git a/tty.c b/tty.c index 0428f4ae..4c5c43b3 100644 --- a/tty.c +++ b/tty.c @@ -34,8 +34,6 @@ static int tty_log_fd = -1; -static int tty_client_ready(struct client *); - 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); @@ -407,7 +405,7 @@ tty_stop_tty(struct tty *tty) if (tcsetattr(c->fd, TCSANOW, &tty->tio) == -1) return; - tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); + tty_raw(tty, tty_term_string_ii(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); if (tty_acs_needed(tty)) tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); @@ -417,7 +415,7 @@ tty_stop_tty(struct tty *tty) if (tty_term_has(tty->term, TTYC_SE)) tty_raw(tty, tty_term_string(tty->term, TTYC_SE)); else if (tty_term_has(tty->term, TTYC_SS)) - tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0)); + tty_raw(tty, tty_term_string_i(tty->term, TTYC_SS, 0)); } if (tty->ccolour != -1) tty_raw(tty, tty_term_string(tty->term, TTYC_CR)); @@ -484,6 +482,8 @@ tty_update_features(struct tty *tty) tty_puts(tty, tty_term_string(tty->term, TTYC_ENFCS)); if (tty->term->flags & TERM_VT100LIKE) tty_puts(tty, "\033[?7727h"); + + tty_invalidate(tty); } void @@ -514,42 +514,42 @@ tty_putcode(struct tty *tty, enum tty_code_code code) } void -tty_putcode1(struct tty *tty, enum tty_code_code code, int a) +tty_putcode_i(struct tty *tty, enum tty_code_code code, int a) { if (a < 0) return; - tty_puts(tty, tty_term_string1(tty->term, code, a)); + tty_puts(tty, tty_term_string_i(tty->term, code, a)); } void -tty_putcode2(struct tty *tty, enum tty_code_code code, int a, int b) +tty_putcode_ii(struct tty *tty, enum tty_code_code code, int a, int b) { if (a < 0 || b < 0) return; - tty_puts(tty, tty_term_string2(tty->term, code, a, b)); + tty_puts(tty, tty_term_string_ii(tty->term, code, a, b)); } void -tty_putcode3(struct tty *tty, enum tty_code_code code, int a, int b, int c) +tty_putcode_iii(struct tty *tty, enum tty_code_code code, int a, int b, int c) { if (a < 0 || b < 0 || c < 0) return; - tty_puts(tty, tty_term_string3(tty->term, code, a, b, c)); + tty_puts(tty, tty_term_string_iii(tty->term, code, a, b, c)); } void -tty_putcode_ptr1(struct tty *tty, enum tty_code_code code, const void *a) +tty_putcode_s(struct tty *tty, enum tty_code_code code, const char *a) { if (a != NULL) - tty_puts(tty, tty_term_ptr1(tty->term, code, a)); + tty_puts(tty, tty_term_string_s(tty->term, code, a)); } void -tty_putcode_ptr2(struct tty *tty, enum tty_code_code code, const void *a, - const void *b) +tty_putcode_ss(struct tty *tty, enum tty_code_code code, const char *a, + const char *b) { if (a != NULL && b != NULL) - tty_puts(tty, tty_term_ptr2(tty->term, code, a, b)); + tty_puts(tty, tty_term_string_ss(tty->term, code, a, b)); } static void @@ -611,7 +611,7 @@ tty_putc(struct tty *tty, u_char ch) * it works on sensible terminals as well. */ if (tty->term->flags & TERM_NOAM) - tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx); + tty_putcode_ii(tty, TTYC_CUP, tty->cy, tty->cx); } else tty->cx++; } @@ -690,7 +690,7 @@ tty_force_cursor_colour(struct tty *tty, int c) else { colour_split_rgb(c, &r, &g, &b); xsnprintf(s, sizeof s, "rgb:%02hhx/%02hhx/%02hhx", r, g, b); - tty_putcode_ptr1(tty, TTYC_CS, s); + tty_putcode_s(tty, TTYC_CS, s); } tty->ccolour = c; } @@ -751,7 +751,7 @@ tty_update_cursor(struct tty *tty, int mode, struct screen *s) if (tty_term_has(tty->term, TTYC_SE)) tty_putcode(tty, TTYC_SE); else - tty_putcode1(tty, TTYC_SS, 0); + tty_putcode_i(tty, TTYC_SS, 0); } if (cmode & (MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)) tty_putcode(tty, TTYC_CVVIS); @@ -759,27 +759,27 @@ tty_update_cursor(struct tty *tty, int mode, struct screen *s) case SCREEN_CURSOR_BLOCK: if (tty_term_has(tty->term, TTYC_SS)) { if (cmode & MODE_CURSOR_BLINKING) - tty_putcode1(tty, TTYC_SS, 1); + tty_putcode_i(tty, TTYC_SS, 1); else - tty_putcode1(tty, TTYC_SS, 2); + tty_putcode_i(tty, TTYC_SS, 2); } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; case SCREEN_CURSOR_UNDERLINE: if (tty_term_has(tty->term, TTYC_SS)) { if (cmode & MODE_CURSOR_BLINKING) - tty_putcode1(tty, TTYC_SS, 3); + tty_putcode_i(tty, TTYC_SS, 3); else - tty_putcode1(tty, TTYC_SS, 4); + tty_putcode_i(tty, TTYC_SS, 4); } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; case SCREEN_CURSOR_BAR: if (tty_term_has(tty->term, TTYC_SS)) { if (cmode & MODE_CURSOR_BLINKING) - tty_putcode1(tty, TTYC_SS, 5); + tty_putcode_i(tty, TTYC_SS, 5); else - tty_putcode1(tty, TTYC_SS, 6); + tty_putcode_i(tty, TTYC_SS, 6); } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; @@ -835,7 +835,7 @@ tty_emulate_repeat(struct tty *tty, enum tty_code_code code, enum tty_code_code code1, u_int n) { if (tty_term_has(tty->term, code)) - tty_putcode1(tty, code, n); + tty_putcode_i(tty, code, n); else { while (n-- > 0) tty_putcode(tty, code1); @@ -1124,7 +1124,7 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py, /* Section of line. Use ECH if possible. */ if (tty_term_has(tty->term, TTYC_ECH)) { tty_cursor(tty, px, py); - tty_putcode1(tty, TTYC_ECH, nx); + tty_putcode_i(tty, TTYC_ECH, nx); return; } } @@ -1265,7 +1265,7 @@ tty_clear_area(struct tty *tty, const struct grid_cell *defaults, u_int py, tty_term_has(tty->term, TTYC_INDN)) { tty_region(tty, py, py + ny - 1); tty_margin_off(tty); - tty_putcode1(tty, TTYC_INDN, ny); + tty_putcode_i(tty, TTYC_INDN, ny); return; } @@ -1280,7 +1280,7 @@ tty_clear_area(struct tty *tty, const struct grid_cell *defaults, u_int py, tty_term_has(tty->term, TTYC_INDN)) { tty_region(tty, py, py + ny - 1); tty_margin(tty, px, px + nx - 1); - tty_putcode1(tty, TTYC_INDN, ny); + tty_putcode_i(tty, TTYC_INDN, ny); return; } } @@ -1619,7 +1619,7 @@ tty_sync_start(struct tty *tty) if (tty_term_has(tty->term, TTYC_SYNC)) { log_debug("%s sync start", tty->client->name); - tty_putcode1(tty, TTYC_SYNC, 1); + tty_putcode_i(tty, TTYC_SYNC, 1); } } @@ -1634,16 +1634,26 @@ tty_sync_end(struct tty *tty) if (tty_term_has(tty->term, TTYC_SYNC)) { log_debug("%s sync end", tty->client->name); - tty_putcode1(tty, TTYC_SYNC, 2); + tty_putcode_i(tty, TTYC_SYNC, 2); } } static int -tty_client_ready(struct client *c) +tty_client_ready(const struct tty_ctx *ctx, struct client *c) { if (c->session == NULL || c->tty.term == NULL) return (0); - if (c->flags & (CLIENT_REDRAWWINDOW|CLIENT_SUSPENDED)) + if (c->flags & CLIENT_SUSPENDED) + return (0); + + /* + * If invisible panes are allowed (used for passthrough), don't care if + * redrawing or frozen. + */ + if (ctx->allow_invisible_panes) + return (1); + + if (c->flags & CLIENT_REDRAWWINDOW) return (0); if (c->tty.flags & TTY_FREEZE) return (0); @@ -1660,21 +1670,14 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *), if (ctx->set_client_cb == NULL) return; TAILQ_FOREACH(c, &clients, entry) { - if (ctx->allow_invisible_panes) { - if (c->session == NULL || - c->tty.term == NULL || - c->flags & CLIENT_SUSPENDED) - continue; - } else { - if (!tty_client_ready(c)) - continue; + if (tty_client_ready(ctx, c)) { state = ctx->set_client_cb(ctx, c); if (state == -1) break; if (state == 0) continue; + cmdfn(&c->tty, ctx); } - cmdfn(&c->tty, ctx); } } @@ -1849,7 +1852,7 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) if (tty_term_has(tty->term, TTYC_RI)) tty_putcode(tty, TTYC_RI); else - tty_putcode1(tty, TTYC_RIN, 1); + tty_putcode_i(tty, TTYC_RIN, 1); } void @@ -1930,7 +1933,7 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) tty_cursor(tty, 0, 0); else tty_cursor(tty, 0, tty->cy); - tty_putcode1(tty, TTYC_INDN, ctx->num); + tty_putcode_i(tty, TTYC_INDN, ctx->num); } } @@ -1961,7 +1964,7 @@ tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx) tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper); if (tty_term_has(tty->term, TTYC_RIN)) - tty_putcode1(tty, TTYC_RIN, ctx->num); + tty_putcode_i(tty, TTYC_RIN, ctx->num); else { for (i = 0; i < ctx->num; i++) tty_putcode(tty, TTYC_RI); @@ -2166,7 +2169,7 @@ tty_set_selection(struct tty *tty, const char *flags, const char *buf, b64_ntop(buf, len, encoded, size); tty->flags |= TTY_NOBLOCK; - tty_putcode_ptr2(tty, TTYC_MS, flags, encoded); + tty_putcode_ss(tty, TTYC_MS, flags, encoded); free(encoded); } @@ -2280,7 +2283,7 @@ tty_reset(struct tty *tty) if (!grid_cells_equal(gc, &grid_default_cell)) { if (gc->link != 0) - tty_putcode_ptr2(tty, TTYC_HLS, "", ""); + tty_putcode_ss(tty, TTYC_HLS, "", ""); if ((gc->attr & GRID_ATTR_CHARSET) && tty_acs_needed(tty)) tty_putcode(tty, TTYC_RMACS); tty_putcode(tty, TTYC_SGR0); @@ -2355,7 +2358,7 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower) tty_cursor(tty, 0, tty->cy); } - tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); + tty_putcode_ii(tty, TTYC_CSR, tty->rupper, tty->rlower); tty->cx = tty->cy = UINT_MAX; } @@ -2383,7 +2386,7 @@ tty_margin(struct tty *tty, u_int rleft, u_int rright) if (tty->rleft == rleft && tty->rright == rright) return; - tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); + tty_putcode_ii(tty, TTYC_CSR, tty->rupper, tty->rlower); tty->rleft = rleft; tty->rright = rright; @@ -2391,7 +2394,7 @@ tty_margin(struct tty *tty, u_int rleft, u_int rright) if (rleft == 0 && rright == tty->sx - 1) tty_putcode(tty, TTYC_CLMG); else - tty_putcode2(tty, TTYC_CMG, rleft, rright); + tty_putcode_ii(tty, TTYC_CMG, rleft, rright); tty->cx = tty->cy = UINT_MAX; } @@ -2501,7 +2504,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) * the cursor with CUB/CUF. */ if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) { - tty_putcode1(tty, TTYC_HPA, cx); + tty_putcode_i(tty, TTYC_HPA, cx); goto out; } else if (change > 0 && tty_term_has(term, TTYC_CUB) && @@ -2511,12 +2514,12 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) tty_putcode(tty, TTYC_CUB1); goto out; } - tty_putcode1(tty, TTYC_CUB, change); + tty_putcode_i(tty, TTYC_CUB, change); goto out; } else if (change < 0 && tty_term_has(term, TTYC_CUF) && !tty_use_margin(tty)) { - tty_putcode1(tty, TTYC_CUF, -change); + tty_putcode_i(tty, TTYC_CUF, -change); goto out; } } else if (cx == thisx) { @@ -2549,21 +2552,21 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) (change < 0 && cy - change > tty->rlower) || (change > 0 && cy - change < tty->rupper)) { if (tty_term_has(term, TTYC_VPA)) { - tty_putcode1(tty, TTYC_VPA, cy); + tty_putcode_i(tty, TTYC_VPA, cy); goto out; } } else if (change > 0 && tty_term_has(term, TTYC_CUU)) { - tty_putcode1(tty, TTYC_CUU, change); + tty_putcode_i(tty, TTYC_CUU, change); goto out; } else if (change < 0 && tty_term_has(term, TTYC_CUD)) { - tty_putcode1(tty, TTYC_CUD, -change); + tty_putcode_i(tty, TTYC_CUD, -change); goto out; } } absolute: /* Absolute movement. */ - tty_putcode2(tty, TTYC_CUP, cy, cx); + tty_putcode_ii(tty, TTYC_CUP, cy, cx); out: tty->cx = cx; @@ -2584,9 +2587,9 @@ tty_hyperlink(struct tty *tty, const struct grid_cell *gc, return; if (gc->link == 0 || !hyperlinks_get(hl, gc->link, &uri, NULL, &id)) - tty_putcode_ptr2(tty, TTYC_HLS, "", ""); + tty_putcode_ss(tty, TTYC_HLS, "", ""); else - tty_putcode_ptr2(tty, TTYC_HLS, id, uri); + tty_putcode_ss(tty, TTYC_HLS, id, uri); } void @@ -2663,13 +2666,13 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, !tty_term_has(tty->term, TTYC_SMULX)) tty_putcode(tty, TTYC_SMUL); else if (changed & GRID_ATTR_UNDERSCORE_2) - tty_putcode1(tty, TTYC_SMULX, 2); + tty_putcode_i(tty, TTYC_SMULX, 2); else if (changed & GRID_ATTR_UNDERSCORE_3) - tty_putcode1(tty, TTYC_SMULX, 3); + tty_putcode_i(tty, TTYC_SMULX, 3); else if (changed & GRID_ATTR_UNDERSCORE_4) - tty_putcode1(tty, TTYC_SMULX, 4); + tty_putcode_i(tty, TTYC_SMULX, 4); else if (changed & GRID_ATTR_UNDERSCORE_5) - tty_putcode1(tty, TTYC_SMULX, 5); + tty_putcode_i(tty, TTYC_SMULX, 5); } if (changed & GRID_ATTR_BLINK) tty_putcode(tty, TTYC_BLINK); @@ -2726,14 +2729,14 @@ tty_colours(struct tty *tty, const struct grid_cell *gc) if (have_ax) tty_puts(tty, "\033[39m"); else if (tc->fg != 7) - tty_putcode1(tty, TTYC_SETAF, 7); + tty_putcode_i(tty, TTYC_SETAF, 7); tc->fg = gc->fg; } if (COLOUR_DEFAULT(gc->bg) && !COLOUR_DEFAULT(tc->bg)) { if (have_ax) tty_puts(tty, "\033[49m"); else if (tc->bg != 0) - tty_putcode1(tty, TTYC_SETAB, 0); + tty_putcode_i(tty, TTYC_SETAB, 0); tc->bg = gc->bg; } } @@ -2903,12 +2906,12 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc) xsnprintf(s, sizeof s, "\033[%dm", gc->fg); tty_puts(tty, s); } else - tty_putcode1(tty, TTYC_SETAF, gc->fg - 90 + 8); + tty_putcode_i(tty, TTYC_SETAF, gc->fg - 90 + 8); goto save; } /* Otherwise set the foreground colour. */ - tty_putcode1(tty, TTYC_SETAF, gc->fg); + tty_putcode_i(tty, TTYC_SETAF, gc->fg); save: /* Save the new values in the terminal current cell. */ @@ -2935,12 +2938,12 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10); tty_puts(tty, s); } else - tty_putcode1(tty, TTYC_SETAB, gc->bg - 90 + 8); + tty_putcode_i(tty, TTYC_SETAB, gc->bg - 90 + 8); goto save; } /* Otherwise set the background colour. */ - tty_putcode1(tty, TTYC_SETAB, gc->bg); + tty_putcode_i(tty, TTYC_SETAB, gc->bg); save: /* Save the new values in the terminal current cell. */ @@ -2976,10 +2979,10 @@ tty_colours_us(struct tty *tty, const struct grid_cell *gc) * non-RGB version may be wrong. */ if (tty_term_has(tty->term, TTYC_SETULC)) - tty_putcode1(tty, TTYC_SETULC, c); + tty_putcode_i(tty, TTYC_SETULC, c); else if (tty_term_has(tty->term, TTYC_SETAL) && tty_term_has(tty->term, TTYC_RGB)) - tty_putcode1(tty, TTYC_SETAL, c); + tty_putcode_i(tty, TTYC_SETAL, c); save: /* Save the new values in the terminal current cell. */ @@ -2993,18 +2996,18 @@ tty_try_colour(struct tty *tty, int colour, const char *type) if (colour & COLOUR_FLAG_256) { if (*type == '3' && tty_term_has(tty->term, TTYC_SETAF)) - tty_putcode1(tty, TTYC_SETAF, colour & 0xff); + tty_putcode_i(tty, TTYC_SETAF, colour & 0xff); else if (tty_term_has(tty->term, TTYC_SETAB)) - tty_putcode1(tty, TTYC_SETAB, colour & 0xff); + tty_putcode_i(tty, TTYC_SETAB, colour & 0xff); return (0); } if (colour & COLOUR_FLAG_RGB) { colour_split_rgb(colour & 0xffffff, &r, &g, &b); if (*type == '3' && tty_term_has(tty->term, TTYC_SETRGBF)) - tty_putcode3(tty, TTYC_SETRGBF, r, g, b); + tty_putcode_iii(tty, TTYC_SETRGBF, r, g, b); else if (tty_term_has(tty->term, TTYC_SETRGBB)) - tty_putcode3(tty, TTYC_SETRGBB, r, g, b); + tty_putcode_iii(tty, TTYC_SETRGBB, r, g, b); return (0); } @@ -3088,7 +3091,7 @@ tty_clipboard_query(struct tty *tty) if ((~tty->flags & TTY_STARTED) || (tty->flags & TTY_OSC52QUERY)) return; - tty_putcode_ptr2(tty, TTYC_MS, "", "?"); + tty_putcode_ss(tty, TTYC_MS, "", "?"); tty->flags |= TTY_OSC52QUERY; evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); diff --git a/window.c b/window.c index 60a21a58..3af71d66 100644 --- a/window.c +++ b/window.c @@ -1130,6 +1130,7 @@ window_pane_reset_mode(struct window_pane *wp) next = TAILQ_FIRST(&wp->modes); if (next == NULL) { + wp->flags &= ~PANE_UNSEENCHANGES; log_debug("%s: no next mode", __func__); wp->screen = &wp->base; } else {