diff --git a/CHANGES b/CHANGES index d1dbb6ea..159ab905 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,45 @@ CHANGES FROM 3.2a TO 3.3 +* Add an option (pane-border-indicators) to select how the active pane is shown + on the pane border (colour, arrows or both). + +* Support underscore styles with capture-pane -e. + +* Make pane-border-format a pane option rather than window. + +* Respond to OSC 4 queries + +* Fix g/G keys in modes to do the same thing as copy mode (and vi). + +* Bump the time terminals have to respond to device attributes queries to three + seconds. + +* If automatic-rename is off, allow the rename escape sequence to set an empty + name. + +* Trim menu item text more intelligently. + +* Add cursor-style and cursor-colour options to set the default cursor style + and colour. + +* Accept some useful and non-conflicting emacs keys in vi normal mode at the + command prompt. + +* Add a format modifier (c) to force a colour to RGB. + +* Add -s and -S to display-popup to set styles, -b to set lines and -T to set + popup title. New popup-border-lines, popup-border-style and popup-style + options set the defaults. + +* Add -e flag to set an environment variable for a popup. + +* Make send-keys without arguments send the key it is bound to (if bound to a + key). + +* Try to leave terminal cursor at the right position even when tmux is drawing + its own cursor or selection (such as at the command prompt and in choose + mode) for people using screen readers and similar which can make use of it. + * Change so that {} is converted to tmux commands immediately when parsed. This means it must contain valid tmux commands. For commands which expand %% and %%%, this now only happens within string arguments. Use of nested aliases diff --git a/Makefile.am b/Makefile.am index 55bf150f..fdfc8d42 100644 --- a/Makefile.am +++ b/Makefile.am @@ -206,6 +206,11 @@ if NEED_FORKPTY nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c endif +# Add compat file for systemd. +if HAVE_SYSTEMD +nodist_tmux_SOURCES += compat/systemd.c +endif + # Add compat file for utf8proc. if HAVE_UTF8PROC nodist_tmux_SOURCES += compat/utf8proc.c diff --git a/arguments.c b/arguments.c index a27d8e0a..91c470e2 100644 --- a/arguments.c +++ b/arguments.c @@ -131,8 +131,9 @@ args_parse(const struct args_parse *parse, struct args_value *values, u_int i; enum args_parse_type type; struct args_value *value, *new; - u_char flag, argument; + u_char flag; const char *found, *string, *s; + int optional_argument; if (count == 0) return (args_create()); @@ -169,18 +170,27 @@ args_parse(const struct args_parse *parse, struct args_value *values, args_free(args); return (NULL); } - argument = *++found; - if (argument != ':') { + if (*++found != ':') { log_debug("%s: -%c", __func__, flag); args_set(args, flag, NULL); continue; } + if (*found == ':') { + optional_argument = 1; + found++; + } new = xcalloc(1, sizeof *new); if (*string != '\0') { new->type = ARGS_STRING; new->string = xstrdup(string); } else { if (i == count) { + if (optional_argument) { + log_debug("%s: -%c", __func__, + flag); + args_set(args, flag, NULL); + continue; + } xasprintf(cause, "-%c expects an argument", flag); diff --git a/client.c b/client.c index 8ca08524..08708c21 100644 --- a/client.c +++ b/client.c @@ -531,7 +531,7 @@ client_signal(int sig) if (sig == SIGCHLD) waitpid(WAIT_ANY, &status, WNOHANG); else if (!client_attached) { - if (sig == SIGTERM) + if (sig == SIGTERM || sig == SIGHUP) proc_exit(client_proc); } else { switch (sig) { diff --git a/cmd-list-clients.c b/cmd-list-clients.c index a5b7d147..53a99178 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -31,6 +31,8 @@ #define LIST_CLIENTS_TEMPLATE \ "#{client_name}: #{session_name} " \ "[#{client_width}x#{client_height} #{client_termname}] " \ + "#{?#{!=:#{client_uid},#{uid}}," \ + "[user #{?client_user,#{client_user},#{client_uid},}] ,}" \ "#{?client_flags,(,}#{client_flags}#{?client_flags,),}" static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *); diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 821558ae..b2665ad9 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:F:lLRSt:U", 0, 1, NULL }, + .args = { "A:B:cC:Df:F:l::LRSt:U", 0, 1, NULL }, .usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] " "[-C XxY] [-f flags] " CMD_TARGET_CLIENT_USAGE " [adjustment]", @@ -162,6 +162,37 @@ 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 enum cmd_retval cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) { @@ -224,10 +255,8 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); } - if (args_has(args, 'l')) { - tty_putcode_ptr2(&tc->tty, TTYC_MS, "", "?"); - return (CMD_RETURN_NORMAL); - } + if (args_has(args, 'l')) + return (cmd_refresh_client_clipboard(self, item)); if (args_has(args, 'F')) /* -F is an alias for -f */ server_client_set_flags(tc, args_get(args, 'F')); diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 81744f72..c9439441 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -60,7 +60,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) const char *errstr; char *cause; u_int adjust; - int x, y; + int x, y, status; struct grid *gd = wp->base.grid; if (args_has(args, 'T')) { @@ -121,6 +121,17 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) free(cause); return (CMD_RETURN_ERROR); } + status = options_get_number(w->options, "pane-border-status"); + switch (status) { + case PANE_STATUS_TOP: + if (y != INT_MAX && wp->yoff == 1) + y++; + break; + case PANE_STATUS_BOTTOM: + if (y != INT_MAX && wp->yoff + wp->sy == w->sy - 1) + y++; + break; + } layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y); } diff --git a/cmd-show-options.c b/cmd-show-options.c index 90226ad3..252a33c6 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -102,7 +102,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) name = options_match(argument, &idx, &ambiguous); if (name == NULL) { if (args_has(args, 'q')) - goto fail; + goto out; if (ambiguous) cmdq_error(item, "ambiguous option: %s", argument); else @@ -113,7 +113,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) &cause); if (scope == OPTIONS_TABLE_NONE) { if (args_has(args, 'q')) - goto fail; + goto out; cmdq_error(item, "%s", cause); free(cause); goto fail; @@ -128,11 +128,12 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) cmd_show_options_print(self, item, o, idx, parent); else if (*name == '@') { if (args_has(args, 'q')) - goto fail; + goto out; cmdq_error(item, "invalid option: %s", argument); goto fail; } +out: free(name); free(argument); return (CMD_RETURN_NORMAL); diff --git a/cmd-split-window.c b/cmd-split-window.c index 888d4106..9947dfd3 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -60,6 +60,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) struct client *tc = cmdq_get_target_client(item); struct session *s = target->s; struct winlink *wl = target->wl; + struct window *w = wl->window; struct window_pane *wp = target->wp, *new_wp; enum layout_type type; struct layout_cell *lc; @@ -86,10 +87,17 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) cmdq_error(item, "percentage %s", errstr); return (CMD_RETURN_ERROR); } - if (type == LAYOUT_TOPBOTTOM) - size = (wp->sy * percentage) / 100; - else - size = (wp->sx * percentage) / 100; + if (args_has(args, 'f')) { + if (type == LAYOUT_TOPBOTTOM) + size = (w->sy * percentage) / 100; + else + size = (w->sx * percentage) / 100; + } else { + if (type == LAYOUT_TOPBOTTOM) + size = (wp->sy * percentage) / 100; + else + size = (wp->sx * percentage) / 100; + } } else { size = args_strtonum(args, 'l', 0, INT_MAX, &cause); if (cause != NULL) { @@ -105,10 +113,17 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) free(cause); return (CMD_RETURN_ERROR); } - if (type == LAYOUT_TOPBOTTOM) - size = (wp->sy * percentage) / 100; - else - size = (wp->sx * percentage) / 100; + if (args_has(args, 'f')) { + if (type == LAYOUT_TOPBOTTOM) + size = (w->sy * percentage) / 100; + else + size = (w->sx * percentage) / 100; + } else { + if (type == LAYOUT_TOPBOTTOM) + size = (wp->sy * percentage) / 100; + else + size = (wp->sx * percentage) / 100; + } } else size = -1; diff --git a/colour.c b/colour.c index 6ede25da..a282d182 100644 --- a/colour.c +++ b/colour.c @@ -128,7 +128,7 @@ colour_tostring(int c) u_char r, g, b; if (c == -1) - return ("invalid"); + return ("none"); if (c & COLOUR_FLAG_RGB) { colour_split_rgb(c, &r, &g, &b); diff --git a/compat.h b/compat.h index 13334ad7..6eb97619 100644 --- a/compat.h +++ b/compat.h @@ -334,6 +334,11 @@ char *strndup(const char *, size_t); void *memmem(const void *, size_t, const void *, size_t); #endif +#ifndef HAVE_GETPEEREID +/* getpeereid.c */ +int getpeereid(int, uid_t *, gid_t *); +#endif + #ifndef HAVE_DAEMON /* daemon.c */ int daemon(int, int); @@ -416,6 +421,11 @@ void *reallocarray(void *, size_t, size_t); void *recallocarray(void *, size_t, size_t, size_t); #endif +#ifdef HAVE_SYSTEMD +/* systemd.c */ +int systemd_create_socket(int, char **); +#endif + #ifdef HAVE_UTF8PROC /* utf8proc.c */ int utf8proc_wcwidth(wchar_t); diff --git a/compat/getpeereid.c b/compat/getpeereid.c new file mode 100644 index 00000000..5a593c07 --- /dev/null +++ b/compat/getpeereid.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include + +#ifdef HAVE_UCRED_H +#include +#endif + +#include "compat.h" + +int +getpeereid(int s, uid_t *uid, gid_t *gid) +{ +#ifdef HAVE_SO_PEERCRED + struct ucred uc; + int len = sizeof uc; + + if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &uc, &len) == -1) + return (-1); + *uid = uc.uid; + *gid = uc.gid; + return (0); +#elif defined(HAVE_GETPEERUCRED) +int +getpeereid(int s, uid_t *uid, gid_t *gid) +{ + ucred_t *ucred = NULL; + + if (getpeerucred(s, &ucred) == -1) + return (-1); + if ((*uid = ucred_geteuid(ucred)) == -1) + return (-1); + if ((*gid = ucred_getrgid(ucred)) == -1) + return (-1); + ucred_free(ucred); + return (0); +} +#else + errno = EOPNOTSUPP; + return (-1); +#endif +} diff --git a/compat/systemd.c b/compat/systemd.c new file mode 100644 index 00000000..7317e43a --- /dev/null +++ b/compat/systemd.c @@ -0,0 +1,58 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2022 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include + +#include "tmux.h" + +int +systemd_create_socket(int flags, char **cause) +{ + int fds; + int fd; + struct sockaddr_un sa; + int addrlen = sizeof sa; + + fds = sd_listen_fds(0); + if (fds > 1) { /* too many file descriptors */ + errno = E2BIG; + goto fail; + } + + if (fds == 1) { /* socket-activated */ + fd = SD_LISTEN_FDS_START; + if (!sd_is_socket_unix(fd, SOCK_STREAM, 1, NULL, 0)) { + errno = EPFNOSUPPORT; + goto fail; + } + if (getsockname(fd, (struct sockaddr *)&sa, &addrlen) == -1) + goto fail; + socket_path = xstrdup(sa.sun_path); + return (fd); + } + + return (server_create_socket(flags, cause)); + +fail: + if (cause != NULL) + xasprintf(cause, "systemd socket error (%s)", strerror(errno)); + return (-1); +} diff --git a/configure.ac b/configure.ac index 26bd1a98..276f71c8 100644 --- a/configure.ac +++ b/configure.ac @@ -69,6 +69,11 @@ AC_ARG_ENABLE( AS_HELP_STRING(--enable-static, create a static build) ) if test "x$enable_static" = xyes; then + case "$host_os" in + *darwin*) + AC_MSG_ERROR([static linking is not supported on macOS]) + ;; + esac test "x$PKG_CONFIG" != x && PKG_CONFIG="$PKG_CONFIG --static" AM_LDFLAGS="-static $AM_LDFLAGS" LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS" @@ -123,6 +128,7 @@ AC_CHECK_HEADERS([ \ sys/dir.h \ sys/ndir.h \ sys/tree.h \ + ucred.h \ util.h \ ]) @@ -141,7 +147,8 @@ AC_CHECK_FUNCS([ \ flock \ prctl \ proc_pidinfo \ - sysconf + getpeerucred \ + sysconf \ ]) # Check for functions with a compatibility implementation. @@ -155,6 +162,7 @@ AC_REPLACE_FUNCS([ \ freezero \ getdtablecount \ getdtablesize \ + getpeereid \ getline \ getprogname \ memmem \ @@ -382,6 +390,31 @@ if test "x$enable_utf8proc" = xyes; then fi AM_CONDITIONAL(HAVE_UTF8PROC, [test "x$enable_utf8proc" = xyes]) +# Check for systemd support. +AC_ARG_ENABLE( + systemd, + AS_HELP_STRING(--enable-systemd, enable systemd integration) +) +if test x"$enable_systemd" = xyes; then + PKG_CHECK_MODULES( + SYSTEMD, + libsystemd, + [ + AM_CPPFLAGS="$SYSTEMD_CFLAGS $AM_CPPFLAGS" + CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS" + LIBS="$SYSTEMD_LIBS $LIBS" + found_systemd=yes + ], + found_systemd=no + ) + if test "x$found_systemd" = xyes; then + AC_DEFINE(HAVE_SYSTEMD) + else + AC_MSG_ERROR("systemd not found") + fi +fi +AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$found_systemd" = xyes]) + # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. AC_MSG_CHECKING(for b64_ntop) AC_LINK_IFELSE([AC_LANG_PROGRAM( @@ -679,6 +712,14 @@ AC_CHECK_DECL( [#include ] ) +# Look for setsockopt(SO_PEERCRED). +AC_CHECK_DECL( + SO_PEERCRED, + AC_DEFINE(HAVE_SO_PEERCRED), + , + [#include ] +) + # Look for fcntl(F_CLOSEM). AC_CHECK_DECL( F_CLOSEM, diff --git a/format-draw.c b/format-draw.c index 1110535f..1a7e60b3 100644 --- a/format-draw.c +++ b/format-draw.c @@ -1154,13 +1154,13 @@ format_trim_right(const char *expanded, u_int limit) while (*cp != '\0') { if (*cp == '#') { end = format_leading_hashes(cp, &n, &leading_width); + copy_width = leading_width; if (width <= skip) { - if (skip - width >= leading_width) + if (skip - width >= copy_width) copy_width = 0; else copy_width -= (skip - width); - } else - copy_width = leading_width; + } if (copy_width != 0) { if (n == 1) *out++ = '#'; diff --git a/format.c b/format.c index 2fc0961e..2e4bceb5 100644 --- a/format.c +++ b/format.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1387,6 +1388,35 @@ format_cb_client_tty(struct format_tree *ft) return (NULL); } +/* Callback for client_uid. */ +static void * +format_cb_client_uid(struct format_tree *ft) +{ + uid_t uid; + + if (ft->c != NULL) { + uid = proc_get_peer_uid(ft->c->peer); + if (uid != (uid_t)-1) + return (format_printf("%ld", (long)uid)); + } + return (NULL); +} + +/* Callback for client_user. */ +static void * +format_cb_client_user(struct format_tree *ft) +{ + uid_t uid; + struct passwd *pw; + + if (ft->c != NULL) { + uid = proc_get_peer_uid(ft->c->peer); + if (uid != (uid_t)-1 && (pw = getpwuid(uid)) != NULL) + return (xstrdup(pw->pw_name)); + } + return (NULL); +} + /* Callback for client_utf8. */ static void * format_cb_client_utf8(struct format_tree *ft) @@ -1650,6 +1680,13 @@ format_cb_mouse_y(struct format_tree *ft) return (NULL); } +/* Callback for next_session_id. */ +static void * +format_cb_next_session_id(__unused struct format_tree *ft) +{ + return (format_printf("$%u", next_session_id)); +} + /* Callback for origin_flag. */ static void * format_cb_origin_flag(struct format_tree *ft) @@ -1719,6 +1756,23 @@ format_cb_pane_dead(struct format_tree *ft) return (NULL); } +/* Callback for pane_dead_signal. */ +static void * +format_cb_pane_dead_signal(struct format_tree *ft) +{ + struct window_pane *wp = ft->wp; + const char *name; + + if (wp != NULL) { + if ((wp->flags & PANE_STATUSREADY) && WIFSIGNALED(wp->status)) { + name = sig2name(WTERMSIG(wp->status)); + return (format_printf("%s", name)); + } + return (NULL); + } + return (NULL); +} + /* Callback for pane_dead_status. */ static void * format_cb_pane_dead_status(struct format_tree *ft) @@ -1733,6 +1787,20 @@ format_cb_pane_dead_status(struct format_tree *ft) return (NULL); } +/* Callback for pane_dead_time. */ +static void * +format_cb_pane_dead_time(struct format_tree *ft) +{ + struct window_pane *wp = ft->wp; + + if (wp != NULL) { + if (wp->flags & PANE_STATUSDRAWN) + return (&wp->dead_time); + return (NULL); + } + return (NULL); +} + /* Callback for pane_format. */ static void * format_cb_pane_format(struct format_tree *ft) @@ -2514,6 +2582,24 @@ format_cb_tree_mode_format(__unused struct format_tree *ft) return (xstrdup(window_tree_mode.default_format)); } +/* Callback for uid. */ +static void * +format_cb_uid(__unused struct format_tree *ft) +{ + return (format_printf("%ld", (long)getuid())); +} + +/* Callback for user. */ +static void * +format_cb_user(__unused struct format_tree *ft) +{ + struct passwd *pw; + + if ((pw = getpwuid(getuid())) != NULL) + return (xstrdup(pw->pw_name)); + return NULL; +} + /* Format table type. */ enum format_table_type { FORMAT_TABLE_STRING, @@ -2620,6 +2706,12 @@ static const struct format_table_entry format_table[] = { { "client_tty", FORMAT_TABLE_STRING, format_cb_client_tty }, + { "client_uid", FORMAT_TABLE_STRING, + format_cb_client_uid + }, + { "client_user", FORMAT_TABLE_STRING, + format_cb_client_user + }, { "client_utf8", FORMAT_TABLE_STRING, format_cb_client_utf8 }, @@ -2707,6 +2799,9 @@ static const struct format_table_entry format_table[] = { { "mouse_y", FORMAT_TABLE_STRING, format_cb_mouse_y }, + { "next_session_id", FORMAT_TABLE_STRING, + format_cb_next_session_id + }, { "origin_flag", FORMAT_TABLE_STRING, format_cb_origin_flag }, @@ -2740,9 +2835,15 @@ static const struct format_table_entry format_table[] = { { "pane_dead", FORMAT_TABLE_STRING, format_cb_pane_dead }, + { "pane_dead_signal", FORMAT_TABLE_STRING, + format_cb_pane_dead_signal + }, { "pane_dead_status", FORMAT_TABLE_STRING, format_cb_pane_dead_status }, + { "pane_dead_time", FORMAT_TABLE_TIME, + format_cb_pane_dead_time + }, { "pane_fg", FORMAT_TABLE_STRING, format_cb_pane_fg }, @@ -2896,6 +2997,12 @@ static const struct format_table_entry format_table[] = { { "tree_mode_format", FORMAT_TABLE_STRING, format_cb_tree_mode_format }, + { "uid", FORMAT_TABLE_STRING, + format_cb_uid + }, + { "user", FORMAT_TABLE_STRING, + format_cb_user + }, { "version", FORMAT_TABLE_STRING, format_cb_version }, diff --git a/grid.c b/grid.c index 7744587a..1109ac58 100644 --- a/grid.c +++ b/grid.c @@ -826,6 +826,56 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values) return (n); } +/* Get underscore colour sequence. */ +static size_t +grid_string_cells_us(const struct grid_cell *gc, int *values) +{ + size_t n; + u_char r, g, b; + + n = 0; + if (gc->us & COLOUR_FLAG_256) { + values[n++] = 58; + values[n++] = 5; + values[n++] = gc->us & 0xff; + } else if (gc->us & COLOUR_FLAG_RGB) { + values[n++] = 58; + values[n++] = 2; + colour_split_rgb(gc->us, &r, &g, &b); + values[n++] = r; + values[n++] = g; + values[n++] = b; + } + return (n); +} + +/* Add on SGR code. */ +static void +grid_string_cells_add_code(char *buf, size_t len, u_int n, int *s, int *newc, + int *oldc, size_t nnewc, size_t noldc, int escape_c0) +{ + u_int i; + char tmp[64]; + + if (nnewc != 0 && + (nnewc != noldc || + memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 || + (n != 0 && s[0] == 0))) { + if (escape_c0) + strlcat(buf, "\\033[", len); + else + strlcat(buf, "\033[", len); + for (i = 0; i < nnewc; i++) { + if (i + 1 < nnewc) + xsnprintf(tmp, sizeof tmp, "%d;", newc[i]); + else + xsnprintf(tmp, sizeof tmp, "%d", newc[i]); + strlcat(buf, tmp, len); + } + strlcat(buf, "m", len); + } +} + /* * Returns ANSI code to set particular attributes (colour, bold and so on) * given a current state. @@ -861,7 +911,9 @@ grid_string_cells_code(const struct grid_cell *lastgc, /* If any attribute is removed, begin with 0. */ for (i = 0; i < nitems(attrs); i++) { - if (!(attr & attrs[i].mask) && (lastattr & attrs[i].mask)) { + if (((~attr & attrs[i].mask) && + (lastattr & attrs[i].mask)) || + (lastgc->us != 0 && gc->us == 0)) { s[n++] = 0; lastattr &= GRID_ATTR_CHARSET; break; @@ -897,42 +949,20 @@ grid_string_cells_code(const struct grid_cell *lastgc, /* If the foreground colour changed, write its parameters. */ nnewc = grid_string_cells_fg(gc, newc); noldc = grid_string_cells_fg(lastgc, oldc); - if (nnewc != noldc || - memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 || - (n != 0 && s[0] == 0)) { - if (escape_c0) - strlcat(buf, "\\033[", len); - else - strlcat(buf, "\033[", len); - for (i = 0; i < nnewc; i++) { - if (i + 1 < nnewc) - xsnprintf(tmp, sizeof tmp, "%d;", newc[i]); - else - xsnprintf(tmp, sizeof tmp, "%d", newc[i]); - strlcat(buf, tmp, len); - } - strlcat(buf, "m", len); - } + grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc, + escape_c0); /* If the background colour changed, append its parameters. */ nnewc = grid_string_cells_bg(gc, newc); noldc = grid_string_cells_bg(lastgc, oldc); - if (nnewc != noldc || - memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 || - (n != 0 && s[0] == 0)) { - if (escape_c0) - strlcat(buf, "\\033[", len); - else - strlcat(buf, "\033[", len); - for (i = 0; i < nnewc; i++) { - if (i + 1 < nnewc) - xsnprintf(tmp, sizeof tmp, "%d;", newc[i]); - else - xsnprintf(tmp, sizeof tmp, "%d", newc[i]); - strlcat(buf, tmp, len); - } - strlcat(buf, "m", len); - } + grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc, + escape_c0); + + /* If the underscore colour changed, append its parameters. */ + nnewc = grid_string_cells_us(gc, newc); + noldc = grid_string_cells_us(lastgc, oldc); + grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc, + escape_c0); /* Append shift in/shift out if needed. */ if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) { @@ -973,7 +1003,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, gl = grid_peek_line(gd, py); for (xx = px; xx < px + nx; xx++) { - if (gl == NULL || xx >= gl->cellsize) + if (gl == NULL || xx >= gl->cellused) break; grid_get_cell(gd, xx, py, &gc); if (gc.flags & GRID_FLAG_PADDING) diff --git a/input-keys.c b/input-keys.c index b4770808..feb62f6d 100644 --- a/input-keys.c +++ b/input-keys.c @@ -417,7 +417,7 @@ int input_key(struct screen *s, struct bufferevent *bev, key_code key) { struct input_key_entry *ike; - key_code justkey, newkey, outkey; + key_code justkey, newkey, outkey, modifiers; struct utf8_data ud; char tmp[64], modifier; @@ -518,7 +518,12 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) return (input_key(s, bev, key & ~KEYC_CTRL)); } outkey = (key & KEYC_MASK_KEY); - switch (key & KEYC_MASK_MODIFIERS) { + modifiers = (key & KEYC_MASK_MODIFIERS); + if (outkey < 32 && outkey != 9 && outkey != 13 && outkey != 27) { + outkey = 64 + outkey; + modifiers |= KEYC_CTRL; + } + switch (modifiers) { case KEYC_SHIFT: modifier = '2'; break; @@ -577,13 +582,13 @@ input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y, */ if (m->sgr_type != ' ') { if (MOUSE_DRAG(m->sgr_b) && - MOUSE_BUTTONS(m->sgr_b) == 3 && + MOUSE_RELEASE(m->sgr_b) && (~s->mode & MODE_MOUSE_ALL)) return (0); } else { if (MOUSE_DRAG(m->b) && - MOUSE_BUTTONS(m->b) == 3 && - MOUSE_BUTTONS(m->lb) == 3 && + MOUSE_RELEASE(m->b) && + MOUSE_RELEASE(m->lb) && (~s->mode & MODE_MOUSE_ALL)) return (0); } diff --git a/input.c b/input.c index faad5b59..39441dd1 100644 --- a/input.c +++ b/input.c @@ -2244,11 +2244,13 @@ input_dcs_dispatch(struct input_ctx *ictx) const u_int prefixlen = (sizeof prefix) - 1; struct sixel_image *si; + if (wp == NULL) + return (0); if (ictx->flags & INPUT_DISCARD) return (0); - - log_debug("%s: \"%s\" \"%s\" \"%s\"", __func__, buf, ictx->interm_buf, - ictx->param_buf); + if (!options_get_number(ictx->wp->options, "allow-passthrough")) + return (0); + log_debug("%s: \"%s\"", __func__, buf); if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0) screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen); @@ -2690,8 +2692,8 @@ input_osc_52(struct input_ctx *ictx, const char *p) { struct window_pane *wp = ictx->wp; char *end; - const char *buf; - size_t len; + const char *buf = NULL; + size_t len = 0; u_char *out; int outlen, state; struct screen_write_ctx ctx; @@ -2711,26 +2713,12 @@ input_osc_52(struct input_ctx *ictx, const char *p) log_debug("%s: %s", __func__, end); if (strcmp(end, "?") == 0) { - if ((pb = paste_get_top(NULL)) != NULL) { + if ((pb = paste_get_top(NULL)) != NULL) buf = paste_buffer_data(pb, &len); - outlen = 4 * ((len + 2) / 3) + 1; - out = xmalloc(outlen); - if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) { - free(out); - return; - } - } else { - outlen = 0; - out = NULL; - } - bufferevent_write(ictx->event, "\033]52;;", 6); - if (outlen != 0) - bufferevent_write(ictx->event, out, outlen); if (ictx->input_end == INPUT_END_BEL) - bufferevent_write(ictx->event, "\007", 1); + input_reply_clipboard(ictx->event, buf, len, "\007"); else - bufferevent_write(ictx->event, "\033\\", 2); - free(out); + input_reply_clipboard(ictx->event, buf, len, "\033\\"); return; } @@ -2788,3 +2776,26 @@ input_osc_104(struct input_ctx *ictx, const char *p) screen_write_fullredraw(&ictx->ctx); free(copy); } + +void +input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len, + const char *end) +{ + char *out = NULL; + size_t outlen = 0; + + if (buf != NULL && len != 0) { + outlen = 4 * ((len + 2) / 3) + 1; + out = xmalloc(outlen); + if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) { + free(out); + return; + } + } + + bufferevent_write(bev, "\033]52;;", 6); + if (outlen != 0) + bufferevent_write(bev, out, outlen); + bufferevent_write(bev, end, strlen(end)); + free(out); +} diff --git a/job.c b/job.c index b312fdc2..d2d9adbf 100644 --- a/job.c +++ b/job.c @@ -87,9 +87,8 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio * if-shell to decide on default-terminal based on outside TERM. */ env = environ_for_session(s, !cfg_finished); - if (e != NULL) { + if (e != NULL) environ_copy(e, env); - } sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); diff --git a/key-bindings.c b/key-bindings.c index 9f7e734a..95171966 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -492,6 +492,7 @@ key_bindings_init(void) "bind -Tcopy-mode \\; { send -X jump-again }", "bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }", "bind -Tcopy-mode N { send -X search-reverse }", + "bind -Tcopy-mode P { send -X toggle-position }", "bind -Tcopy-mode R { send -X rectangle-toggle }", "bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }", "bind -Tcopy-mode X { send -X set-mark }", @@ -588,6 +589,7 @@ key_bindings_init(void) "bind -Tcopy-mode-vi L { send -X bottom-line }", "bind -Tcopy-mode-vi M { send -X middle-line }", "bind -Tcopy-mode-vi N { send -X search-reverse }", + "bind -Tcopy-mode-vi P { send -X toggle-position }", "bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }", "bind -Tcopy-mode-vi V { send -X select-line }", "bind -Tcopy-mode-vi W { send -X next-space }", diff --git a/key-string.c b/key-string.c index 4f7be858..0ca91306 100644 --- a/key-string.c +++ b/key-string.c @@ -91,26 +91,68 @@ static const struct { KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1), KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2), KEYC_MOUSE_STRING(MOUSEDOWN3, MouseDown3), + KEYC_MOUSE_STRING(MOUSEDOWN6, MouseDown6), + KEYC_MOUSE_STRING(MOUSEDOWN7, MouseDown7), + KEYC_MOUSE_STRING(MOUSEDOWN8, MouseDown8), + KEYC_MOUSE_STRING(MOUSEDOWN9, MouseDown9), + KEYC_MOUSE_STRING(MOUSEDOWN10, MouseDown10), + KEYC_MOUSE_STRING(MOUSEDOWN11, MouseDown11), KEYC_MOUSE_STRING(MOUSEUP1, MouseUp1), KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2), KEYC_MOUSE_STRING(MOUSEUP3, MouseUp3), + KEYC_MOUSE_STRING(MOUSEUP6, MouseUp6), + KEYC_MOUSE_STRING(MOUSEUP7, MouseUp7), + KEYC_MOUSE_STRING(MOUSEUP8, MouseUp8), + KEYC_MOUSE_STRING(MOUSEUP9, MouseUp9), + KEYC_MOUSE_STRING(MOUSEUP10, MouseUp10), + KEYC_MOUSE_STRING(MOUSEUP11, MouseUp11), KEYC_MOUSE_STRING(MOUSEDRAG1, MouseDrag1), KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2), KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3), + KEYC_MOUSE_STRING(MOUSEDRAG6, MouseDrag6), + KEYC_MOUSE_STRING(MOUSEDRAG7, MouseDrag7), + KEYC_MOUSE_STRING(MOUSEDRAG8, MouseDrag8), + KEYC_MOUSE_STRING(MOUSEDRAG9, MouseDrag9), + KEYC_MOUSE_STRING(MOUSEDRAG10, MouseDrag10), + KEYC_MOUSE_STRING(MOUSEDRAG11, MouseDrag11), KEYC_MOUSE_STRING(MOUSEDRAGEND1, MouseDragEnd1), KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2), KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3), + KEYC_MOUSE_STRING(MOUSEDRAGEND6, MouseDragEnd6), + KEYC_MOUSE_STRING(MOUSEDRAGEND7, MouseDragEnd7), + KEYC_MOUSE_STRING(MOUSEDRAGEND8, MouseDragEnd8), + KEYC_MOUSE_STRING(MOUSEDRAGEND9, MouseDragEnd9), + KEYC_MOUSE_STRING(MOUSEDRAGEND10, MouseDragEnd10), + KEYC_MOUSE_STRING(MOUSEDRAGEND11, MouseDragEnd11), KEYC_MOUSE_STRING(WHEELUP, WheelUp), KEYC_MOUSE_STRING(WHEELDOWN, WheelDown), KEYC_MOUSE_STRING(SECONDCLICK1, SecondClick1), KEYC_MOUSE_STRING(SECONDCLICK2, SecondClick2), KEYC_MOUSE_STRING(SECONDCLICK3, SecondClick3), + KEYC_MOUSE_STRING(SECONDCLICK6, SecondClick6), + KEYC_MOUSE_STRING(SECONDCLICK7, SecondClick7), + KEYC_MOUSE_STRING(SECONDCLICK8, SecondClick8), + KEYC_MOUSE_STRING(SECONDCLICK9, SecondClick9), + KEYC_MOUSE_STRING(SECONDCLICK10, SecondClick10), + KEYC_MOUSE_STRING(SECONDCLICK11, SecondClick11), KEYC_MOUSE_STRING(DOUBLECLICK1, DoubleClick1), KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2), KEYC_MOUSE_STRING(DOUBLECLICK3, DoubleClick3), + KEYC_MOUSE_STRING(DOUBLECLICK6, DoubleClick6), + KEYC_MOUSE_STRING(DOUBLECLICK7, DoubleClick7), + KEYC_MOUSE_STRING(DOUBLECLICK8, DoubleClick8), + KEYC_MOUSE_STRING(DOUBLECLICK9, DoubleClick9), + KEYC_MOUSE_STRING(DOUBLECLICK10, DoubleClick10), + KEYC_MOUSE_STRING(DOUBLECLICK11, DoubleClick11), KEYC_MOUSE_STRING(TRIPLECLICK1, TripleClick1), KEYC_MOUSE_STRING(TRIPLECLICK2, TripleClick2), KEYC_MOUSE_STRING(TRIPLECLICK3, TripleClick3), + KEYC_MOUSE_STRING(TRIPLECLICK6, TripleClick6), + KEYC_MOUSE_STRING(TRIPLECLICK7, TripleClick7), + KEYC_MOUSE_STRING(TRIPLECLICK8, TripleClick8), + KEYC_MOUSE_STRING(TRIPLECLICK9, TripleClick9), + KEYC_MOUSE_STRING(TRIPLECLICK10, TripleClick10), + KEYC_MOUSE_STRING(TRIPLECLICK11, TripleClick11) }; /* Find key string in table. */ diff --git a/menu.c b/menu.c index aaa1287e..c17d10b1 100644 --- a/menu.c +++ b/menu.c @@ -235,7 +235,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) if (KEYC_IS_MOUSE(event->key)) { if (md->flags & MENU_NOMOUSE) { - if (MOUSE_BUTTONS(m->b) != 0) + if (MOUSE_BUTTONS(m->b) != MOUSE_BUTTON_1) return (1); return (0); } @@ -248,7 +248,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) return (1); } else { if (!MOUSE_RELEASE(m->b) && - MOUSE_WHEEL(m->b) == 0 && + !MOUSE_WHEEL(m->b) && !MOUSE_DRAG(m->b)) return (1); } @@ -262,7 +262,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) if (MOUSE_RELEASE(m->b)) goto chosen; } else { - if (MOUSE_WHEEL(m->b) == 0 && !MOUSE_DRAG(m->b)) + if (!MOUSE_WHEEL(m->b) && !MOUSE_DRAG(m->b)) goto chosen; } md->choice = m->y - (md->py + 1); diff --git a/mode-tree.c b/mode-tree.c index 1eb496fe..c007e27f 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -104,7 +104,6 @@ struct mode_tree_menu { struct mode_tree_data *data; struct client *c; u_int line; - void *itemdata; }; static void mode_tree_free_items(struct mode_tree_list *); @@ -909,18 +908,14 @@ static void mode_tree_menu_callback(__unused struct menu *menu, __unused u_int idx, key_code key, void *data) { - struct mode_tree_menu *mtm = data; - struct mode_tree_data *mtd = mtm->data; - struct mode_tree_item *mti; + struct mode_tree_menu *mtm = data; + struct mode_tree_data *mtd = mtm->data; if (mtd->dead || key == KEYC_NONE) goto out; if (mtm->line >= mtd->line_size) goto out; - mti = mtd->line_list[mtm->line].item; - if (mti->itemdata != mtm->itemdata) - goto out; mtd->current = mtm->line; mtd->menucb(mtd->modedata, mtm->c, key); @@ -954,14 +949,13 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x, title = xstrdup(""); } menu = menu_create(title); - menu_add_items(menu, items, NULL, NULL, NULL); + menu_add_items(menu, items, NULL, c, NULL); free(title); mtm = xmalloc(sizeof *mtm); mtm->data = mtd; mtm->c = c; mtm->line = line; - mtm->itemdata = mti->itemdata; mtd->references++; if (x >= (menu->width + 4) / 2) diff --git a/notify.c b/notify.c index 9c55d0b8..baeb0600 100644 --- a/notify.c +++ b/notify.c @@ -34,18 +34,37 @@ struct notify_entry { int pane; }; +static struct cmdq_item * +notify_insert_one_hook(struct cmdq_item *item, struct notify_entry *ne, + struct cmd_list *cmdlist, struct cmdq_state *state) +{ + struct cmdq_item *new_item; + char *s; + + if (cmdlist == NULL) + return (item); + if (log_get_level() != 0) { + s = cmd_list_print(cmdlist, 0); + log_debug("%s: hook %s is: %s", __func__, ne->name, s); + free (s); + } + new_item = cmdq_get_command(cmdlist, state); + return (cmdq_insert_after(item, new_item)); +} + static void notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne) { struct cmd_find_state fs; struct options *oo; - struct cmdq_item *new_item; - struct cmdq_state *new_state; + struct cmdq_state *state; struct options_entry *o; struct options_array_item *a; struct cmd_list *cmdlist; + const char *value; + struct cmd_parse_result *pr; - log_debug("%s: %s", __func__, ne->name); + log_debug("%s: inserting hook %s", __func__, ne->name); cmd_find_clear_state(&fs, 0); if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs)) @@ -66,23 +85,37 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne) oo = fs.wl->window->options; o = options_get(oo, ne->name); } - if (o == NULL) + if (o == NULL) { + log_debug("%s: hook %s not found", __func__, ne->name); return; - - new_state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS); - cmdq_add_formats(new_state, ne->formats); - - a = options_array_first(o); - while (a != NULL) { - cmdlist = options_array_item_value(a)->cmdlist; - if (cmdlist != NULL) { - new_item = cmdq_get_command(cmdlist, new_state); - item = cmdq_insert_after(item, new_item); - } - a = options_array_next(a); } - cmdq_free_state(new_state); + state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS); + cmdq_add_formats(state, ne->formats); + + if (*ne->name == '@') { + value = options_get_string(oo, ne->name); + pr = cmd_parse_from_string(value, NULL); + switch (pr->status) { + case CMD_PARSE_ERROR: + log_debug("%s: can't parse hook %s: %s", __func__, + ne->name, pr->error); + free(pr->error); + break; + case CMD_PARSE_SUCCESS: + notify_insert_one_hook(item, ne, pr->cmdlist, state); + break; + } + } else { + a = options_array_first(o); + while (a != NULL) { + cmdlist = options_array_item_value(a)->cmdlist; + item = notify_insert_one_hook(item, ne, cmdlist, state); + a = options_array_next(a); + } + } + + cmdq_free_state(state); } static enum cmd_retval diff --git a/options-table.c b/options-table.c index 3e0ff198..17be7ec4 100644 --- a/options-table.c +++ b/options-table.c @@ -63,6 +63,9 @@ static const char *options_table_cursor_style_list[] = { static const char *options_table_pane_status_list[] = { "off", "top", "bottom", NULL }; +static const char *options_table_pane_border_indicators_list[] = { + "off", "colour", "arrows", "both", NULL +}; static const char *options_table_pane_border_lines_list[] = { "single", "double", "heavy", "simple", "number", NULL }; @@ -274,6 +277,7 @@ const struct options_table_entry options_table[] = { .minimum = 0, .maximum = INT_MAX, .default_num = 500, + .unit = "milliseconds", .text = "Time to wait before assuming a key is Escape." }, @@ -298,7 +302,7 @@ const struct options_table_entry options_table[] = { .choices = options_table_extended_keys_list, .default_num = 0, .text = "Whether to request extended key sequences from terminals " - "that support it." + "that support it." }, { .name = "focus-events", @@ -797,6 +801,14 @@ const struct options_table_entry options_table[] = { "linked to ('off')." }, + { .name = "allow-passthrough", + .type = OPTIONS_TABLE_FLAG, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .default_num = 0, + .text = "Whether applications are allowed to use the escape sequence " + "to bypass tmux." + }, + { .name = "allow-rename", .type = OPTIONS_TABLE_FLAG, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, @@ -870,6 +882,13 @@ const struct options_table_entry options_table[] = { .text = "Style of the marked line in copy mode." }, + { .name = "fill-character", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW, + .default_str = "", + .text = "Character used to fill unused parts of window." + }, + { .name = "main-pane-height", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, @@ -964,19 +983,28 @@ const struct options_table_entry options_table[] = { { .name = "pane-border-format", .type = OPTIONS_TABLE_STRING, - .scope = OPTIONS_TABLE_WINDOW, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] " "\"#{pane_title}\"", .text = "Format of text in the pane status lines." }, + { .name = "pane-border-indicators", + .type = OPTIONS_TABLE_CHOICE, + .scope = OPTIONS_TABLE_WINDOW, + .choices = options_table_pane_border_indicators_list, + .default_num = PANE_BORDER_COLOUR, + .text = "Whether to indicate the active pane by colouring border or " + "displaying arrow markers." + }, + { .name = "pane-border-lines", .type = OPTIONS_TABLE_CHOICE, .scope = OPTIONS_TABLE_WINDOW, .choices = options_table_pane_border_lines_list, .default_num = PANE_LINES_SINGLE, .text = "Type of characters used to draw pane border lines. Some of " - "these are only supported on terminals with UTF-8 support." + "these are only supported on terminals with UTF-8 support." }, { .name = "pane-border-status", @@ -1028,7 +1056,7 @@ const struct options_table_entry options_table[] = { .choices = options_table_popup_border_lines_list, .default_num = BOX_LINES_SINGLE, .text = "Type of characters used to draw popup border lines. Some of " - "these are only supported on terminals with UTF-8 support." + "these are only supported on terminals with UTF-8 support." }, { .name = "remain-on-exit", @@ -1040,6 +1068,27 @@ const struct options_table_entry options_table[] = { "killed ('off' or 'failed') when the program inside exits." }, + { .name = "remain-on-exit-format", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .default_str = "Pane is dead (" + "#{?#{!=:#{pane_dead_status},}," + "status #{pane_dead_status},}" + "#{?#{!=:#{pane_dead_signal},}," + "signal #{pane_dead_signal},}, " + "#{t:pane_dead_time})", + .text = "Message shown after the program in a pane has exited, if " + "remain-on-exit is enabled." + }, + + { .name = "scroll-on-clear", + .type = OPTIONS_TABLE_FLAG, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .default_num = 1, + .text = "Whether the contents of the screen should be scrolled into" + "history when clearing the whole screen." + }, + { .name = "synchronize-panes", .type = OPTIONS_TABLE_FLAG, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, @@ -1158,7 +1207,7 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_WINDOW, .default_num = 1, .text = "Whether xterm-style function key sequences should be sent. " - "This option is no longer used." + "This option is no longer used." }, /* Hook options. */ @@ -1206,8 +1255,8 @@ const struct options_table_entry options_table[] = { OPTIONS_TABLE_HOOK("client-active", ""), OPTIONS_TABLE_HOOK("client-attached", ""), OPTIONS_TABLE_HOOK("client-detached", ""), - OPTIONS_TABLE_HOOK("client-focus-in", ""), - OPTIONS_TABLE_HOOK("client-focus-out", ""), + OPTIONS_TABLE_HOOK("client-focus-in", ""), + OPTIONS_TABLE_HOOK("client-focus-out", ""), OPTIONS_TABLE_HOOK("client-resized", ""), OPTIONS_TABLE_HOOK("client-session-changed", ""), OPTIONS_TABLE_PANE_HOOK("pane-died", ""), @@ -1225,6 +1274,7 @@ const struct options_table_entry options_table[] = { OPTIONS_TABLE_HOOK("window-linked", ""), OPTIONS_TABLE_WINDOW_HOOK("window-pane-changed", ""), OPTIONS_TABLE_WINDOW_HOOK("window-renamed", ""), + OPTIONS_TABLE_WINDOW_HOOK("window-resized", ""), OPTIONS_TABLE_HOOK("window-unlinked", ""), { .name = NULL } diff --git a/options.c b/options.c index 865ab01f..f9cf2afd 100644 --- a/options.c +++ b/options.c @@ -1108,6 +1108,8 @@ options_push_changes(const char *name) struct window_pane *wp; int c; + log_debug("%s: %s", __func__, name); + if (strcmp(name, "automatic-rename") == 0) { RB_FOREACH(w, windows, &windows) { if (w->active == NULL) @@ -1130,6 +1132,10 @@ options_push_changes(const char *name) &wp->screen->default_mode); } } + if (strcmp(name, "fill-character") == 0) { + RB_FOREACH(w, windows, &windows) + window_set_fill_character(w); + } if (strcmp(name, "key-table") == 0) { TAILQ_FOREACH(loop, &clients, entry) server_client_set_key_table(loop, NULL); diff --git a/osdep-netbsd.c b/osdep-netbsd.c index b473e017..6003c035 100644 --- a/osdep-netbsd.c +++ b/osdep-netbsd.c @@ -35,9 +35,6 @@ ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB) struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *); -char *osdep_get_name(int, char *); -char *osdep_get_cwd(int); -struct event_base *osdep_event_init(void); struct kinfo_proc2 * cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2) diff --git a/osdep-openbsd.c b/osdep-openbsd.c index 54464753..b4c8fc56 100644 --- a/osdep-openbsd.c +++ b/osdep-openbsd.c @@ -16,7 +16,6 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include /* MAXCOMLEN */ #include #include #include @@ -142,7 +141,7 @@ char * osdep_get_cwd(int fd) { int name[] = { CTL_KERN, KERN_PROC_CWD, 0 }; - static char path[MAXPATHLEN]; + static char path[PATH_MAX]; size_t pathlen = sizeof path; if ((name[2] = tcgetpgrp(fd)) == -1) diff --git a/popup.c b/popup.c index 0418ea7e..2e57153d 100644 --- a/popup.c +++ b/popup.c @@ -508,7 +508,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) m->x > pd->px + pd->sx - 1 || m->y < pd->py || m->y > pd->py + pd->sy - 1) { - if (MOUSE_BUTTONS(m->b) == 2) + if (MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3) goto menu; return (0); } @@ -523,16 +523,16 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) border = BOTTOM; } if ((m->b & MOUSE_MASK_MODIFIERS) == 0 && - MOUSE_BUTTONS(m->b) == 2 && + MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3 && (border == LEFT || border == TOP)) goto menu; if (((m->b & MOUSE_MASK_MODIFIERS) == MOUSE_MASK_META) || border != NONE) { if (!MOUSE_DRAG(m->b)) goto out; - if (MOUSE_BUTTONS(m->lb) == 0) + if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_1) pd->dragging = MOVE; - else if (MOUSE_BUTTONS(m->lb) == 2) + else if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_3) pd->dragging = SIZE; pd->dx = m->lx - pd->px; pd->dy = m->ly - pd->py; @@ -565,10 +565,10 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) menu: pd->menu = menu_create(""); if (pd->flags & POPUP_INTERNAL) { - menu_add_items(pd->menu, popup_internal_menu_items, NULL, NULL, + menu_add_items(pd->menu, popup_internal_menu_items, NULL, c, NULL); } else - menu_add_items(pd->menu, popup_menu_items, NULL, NULL, NULL); + menu_add_items(pd->menu, popup_menu_items, NULL, c, NULL); if (m->x >= (pd->menu->width + 4) / 2) x = m->x - (pd->menu->width + 4) / 2; else @@ -667,7 +667,8 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, pd = xcalloc(1, sizeof *pd); pd->item = item; pd->flags = flags; - pd->title = xstrdup(title); + if (title != NULL) + pd->title = xstrdup(title); pd->c = c; pd->c->references++; @@ -688,7 +689,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, } pd->border_cell.attr = 0; - screen_init(&pd->s, sx - 2, sy - 2, 0); + screen_init(&pd->s, jx, jy, 0); colour_palette_init(&pd->palette); colour_palette_from_option(&pd->palette, global_w_options); diff --git a/proc.c b/proc.c index 958a9483..a9b1473e 100644 --- a/proc.c +++ b/proc.c @@ -56,6 +56,7 @@ struct tmuxpeer { struct imsgbuf ibuf; struct event event; + uid_t uid; int flags; #define PEER_BAD 0x1 @@ -308,6 +309,7 @@ proc_add_peer(struct tmuxproc *tp, int fd, void (*dispatchcb)(struct imsg *, void *), void *arg) { struct tmuxpeer *peer; + gid_t gid; peer = xcalloc(1, sizeof *peer); peer->parent = tp; @@ -318,6 +320,9 @@ proc_add_peer(struct tmuxproc *tp, int fd, imsg_init(&peer->ibuf, fd); event_set(&peer->event, fd, EV_READ, proc_event_cb, peer); + if (getpeereid(fd, &peer->uid, &gid) != 0) + peer->uid = (uid_t)-1; + log_debug("add peer %p: %d (%p)", peer, fd, arg); TAILQ_INSERT_TAIL(&tp->peers, peer, entry); @@ -373,3 +378,9 @@ proc_fork_and_daemon(int *fd) return (pid); } } + +uid_t +proc_get_peer_uid(struct tmuxpeer *peer) +{ + return (peer->uid); +} diff --git a/resize.c b/resize.c index 175dd740..457fee0a 100644 --- a/resize.c +++ b/resize.c @@ -61,6 +61,7 @@ resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel) tty_update_window_offset(w); server_redraw_window(w); notify_window("window-layout-changed", w); + notify_window("window-resized", w); w->flags &= ~WINDOW_RESIZE; } @@ -178,7 +179,7 @@ clients_calculate_size(int type, int current, struct client *c, cw = NULL; /* Work out this client's size. */ - if (cw != NULL) { + if (cw != NULL && cw->sx != 0 && cw->sy != 0) { cx = cw->sx; cy = cw->sy; } else { diff --git a/screen-redraw.c b/screen-redraw.c index bffbe8b5..5e67f7c4 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -34,19 +34,29 @@ static void screen_redraw_set_context(struct client *, #define START_ISOLATE "\342\201\246" #define END_ISOLATE "\342\201\251" +/* Border in relation to a pane. */ enum screen_redraw_border_type { SCREEN_REDRAW_OUTSIDE, SCREEN_REDRAW_INSIDE, - SCREEN_REDRAW_BORDER + SCREEN_REDRAW_BORDER_LEFT, + SCREEN_REDRAW_BORDER_RIGHT, + SCREEN_REDRAW_BORDER_TOP, + SCREEN_REDRAW_BORDER_BOTTOM }; +#define BORDER_MARKERS " +,.-" /* Get cell border character. */ static void -screen_redraw_border_set(struct window_pane *wp, enum pane_lines pane_lines, - int cell_type, struct grid_cell *gc) +screen_redraw_border_set(struct window *w, struct window_pane *wp, + enum pane_lines pane_lines, int cell_type, struct grid_cell *gc) { u_int idx; + if (cell_type == CELL_OUTSIDE && w->fill_character != NULL) { + utf8_copy(&gc->data, &w->fill_character[0]); + return; + } + switch (pane_lines) { case PANE_LINES_NUMBER: if (cell_type == CELL_OUTSIDE) { @@ -102,64 +112,74 @@ static enum screen_redraw_border_type screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py, int pane_status) { - u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy; + struct options *oo = wp->window->options; + int split = 0; + u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy; /* Inside pane. */ if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey) return (SCREEN_REDRAW_INSIDE); + /* Get pane indicator. */ + switch (options_get_number(oo, "pane-border-indicators")) { + case PANE_BORDER_COLOUR: + case PANE_BORDER_BOTH: + split = 1; + break; + } + /* Left/right borders. */ if (pane_status == PANE_STATUS_OFF) { - if (screen_redraw_two_panes(wp->window, 0)) { + if (screen_redraw_two_panes(wp->window, 0) && split) { if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_RIGHT); if (wp->xoff != 0 && px == wp->xoff - 1 && py > wp->sy / 2) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_LEFT); } else { if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { if (wp->xoff != 0 && px == wp->xoff - 1) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_LEFT); if (px == ex) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_RIGHT); } } } else { if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { if (wp->xoff != 0 && px == wp->xoff - 1) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_LEFT); if (px == ex) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_RIGHT); } } /* Top/bottom borders. */ if (pane_status == PANE_STATUS_OFF) { - if (screen_redraw_two_panes(wp->window, 1)) { + if (screen_redraw_two_panes(wp->window, 1) && split) { if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_BOTTOM); if (wp->yoff != 0 && py == wp->yoff - 1 && px > wp->sx / 2) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_TOP); } else { if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { if (wp->yoff != 0 && py == wp->yoff - 1) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_TOP); if (py == ey) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_BOTTOM); } } } else if (pane_status == PANE_STATUS_TOP) { if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { if (wp->yoff != 0 && py == wp->yoff - 1) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_TOP); } } else { if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { if (py == ey) - return (SCREEN_REDRAW_BORDER); + return (SCREEN_REDRAW_BORDER_BOTTOM); } } @@ -189,10 +209,10 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status) switch (screen_redraw_pane_border(wp, px, py, pane_status)) { case SCREEN_REDRAW_INSIDE: return (0); - case SCREEN_REDRAW_BORDER: - return (1); case SCREEN_REDRAW_OUTSIDE: break; + default: + return (1); } } @@ -346,7 +366,7 @@ screen_redraw_check_is(u_int px, u_int py, int pane_status, enum screen_redraw_border_type border; border = screen_redraw_pane_border(wp, px, py, pane_status); - if (border == SCREEN_REDRAW_BORDER) + if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE) return (1); return (0); } @@ -373,7 +393,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, style_apply(&gc, w->options, "pane-active-border-style", ft); else style_apply(&gc, w->options, "pane-border-style", ft); - fmt = options_get_string(w->options, "pane-border-format"); + fmt = options_get_string(wp->options, "pane-border-format"); expanded = format_expand_time(ft, fmt); if (wp->sx < 4) @@ -394,7 +414,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, else py = wp->yoff + wp->sy; cell_type = screen_redraw_type_of_cell(c, px, py, pane_status); - screen_redraw_border_set(wp, pane_lines, cell_type, &gc); + screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc); screen_write_cell(&ctx, &gc); } gc.attr &= ~GRID_ATTR_CHARSET; @@ -637,11 +657,12 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) struct options *oo = w->options; struct tty *tty = &c->tty; struct format_tree *ft; - struct window_pane *wp; + struct window_pane *wp, *active = server_client_get_pane(c); struct grid_cell gc; const struct grid_cell *tmp; struct overlay_ranges r; u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; + int arrows = 0, border; int pane_status = ctx->pane_status, isolates; if (c->overlay_check != NULL) { @@ -674,7 +695,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) screen_redraw_check_is(x, y, pane_status, marked_pane.wp)) gc.attr ^= GRID_ATTR_REVERSE; } - screen_redraw_border_set(wp, ctx->pane_lines, cell_type, &gc); + screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc); if (cell_type == CELL_TOPBOTTOM && (c->flags & CLIENT_UTF8) && @@ -689,6 +710,34 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) tty_cursor(tty, i, j); if (isolates) tty_puts(tty, END_ISOLATE); + + switch (options_get_number(oo, "pane-border-indicators")) { + case PANE_BORDER_ARROWS: + case PANE_BORDER_BOTH: + arrows = 1; + break; + } + + if (wp != NULL && arrows) { + border = screen_redraw_pane_border(active, x, y, pane_status); + if (((i == wp->xoff + 1 && + (cell_type == CELL_LEFTRIGHT || + (cell_type == CELL_TOPJOIN && + border == SCREEN_REDRAW_BORDER_BOTTOM) || + (cell_type == CELL_BOTTOMJOIN && + border == SCREEN_REDRAW_BORDER_TOP))) || + (j == wp->yoff + 1 && + (cell_type == CELL_TOPBOTTOM || + (cell_type == CELL_LEFTJOIN && + border == SCREEN_REDRAW_BORDER_RIGHT) || + (cell_type == CELL_RIGHTJOIN && + border == SCREEN_REDRAW_BORDER_LEFT)))) && + screen_redraw_check_is(x, y, pane_status, active)) { + gc.attr |= GRID_ATTR_CHARSET; + utf8_set(&gc.data, BORDER_MARKERS[border]); + } + } + tty_cell(tty, &gc, &grid_default_cell, NULL); if (isolates) tty_puts(tty, START_ISOLATE); diff --git a/screen-write.c b/screen-write.c index 7bdba327..b517bbdd 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1476,7 +1476,11 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) ttyctx.bg = bg; /* Scroll into history if it is enabled and clearing entire screen. */ - if (s->cx == 0 && s->cy == 0 && (gd->flags & GRID_HISTORY)) + if (s->cx == 0 && + s->cy == 0 && + (gd->flags & GRID_HISTORY) && + ctx->wp != NULL && + options_get_number(ctx->wp->options, "scroll-on-clear")) grid_view_clear_history(gd, bg); else { if (s->cx <= sx - 1) @@ -1530,7 +1534,9 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg) ttyctx.bg = bg; /* Scroll into history if it is enabled. */ - if (s->grid->flags & GRID_HISTORY) + if ((s->grid->flags & GRID_HISTORY) && + ctx->wp != NULL && + options_get_number(ctx->wp->options, "scroll-on-clear")) grid_view_clear_history(s->grid, bg); else grid_view_clear(s->grid, 0, 0, sx, sy, bg); diff --git a/server-client.c b/server-client.c index 56848a15..cea2e691 100644 --- a/server-client.c +++ b/server-client.c @@ -40,6 +40,7 @@ static void server_client_check_exit(struct client *); static void server_client_check_redraw(struct client *); static void server_client_check_modes(struct client *); static void server_client_set_title(struct client *); +static void server_client_set_path(struct client *); static void server_client_reset_state(struct client *); static int server_client_assume_paste(struct session *); static void server_client_update_latest(struct client *); @@ -422,6 +423,7 @@ server_client_lost(struct client *c) if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); free(c->ttyname); + free(c->clipboard_panes); free(c->term_name); free(c->term_type); @@ -593,11 +595,11 @@ server_client_check_mouse(struct client *c, struct key_event *event) log_debug("double-click at %u,%u", x, y); } else if ((m->sgr_type != ' ' && MOUSE_DRAG(m->sgr_b) && - MOUSE_BUTTONS(m->sgr_b) == 3) || + MOUSE_RELEASE(m->sgr_b)) || (m->sgr_type == ' ' && MOUSE_DRAG(m->b) && - MOUSE_BUTTONS(m->b) == 3 && - MOUSE_BUTTONS(m->lb) == 3)) { + MOUSE_RELEASE(m->b) && + MOUSE_RELEASE(m->lb))) { type = MOVE; x = m->x, y = m->y, b = 0; log_debug("move at %u,%u", x, y); @@ -750,7 +752,7 @@ have_event: m->wp = -1; /* Stop dragging if needed. */ - if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag) { + if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag != 0) { if (c->tty.mouse_drag_release != NULL) c->tty.mouse_drag_release(c, m); @@ -761,8 +763,8 @@ have_event: * End a mouse drag by passing a MouseDragEnd key corresponding * to the button that started the drag. */ - switch (c->tty.mouse_drag_flag) { - case 1: + switch (c->tty.mouse_drag_flag - 1) { + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_MOUSEDRAGEND1_PANE; if (where == STATUS) @@ -776,7 +778,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAGEND1_BORDER; break; - case 2: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_MOUSEDRAGEND2_PANE; if (where == STATUS) @@ -790,7 +792,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAGEND2_BORDER; break; - case 3: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_MOUSEDRAGEND3_PANE; if (where == STATUS) @@ -804,6 +806,90 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAGEND3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_MOUSEDRAGEND6_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_MOUSEDRAGEND7_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_MOUSEDRAGEND8_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_MOUSEDRAGEND9_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_MOUSEDRAGEND10_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_MOUSEDRAGEND11_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND11_BORDER; + break; default: key = KEYC_MOUSE; break; @@ -836,7 +922,7 @@ have_event: key = KEYC_DRAGGING; else { switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_MOUSEDRAG1_PANE; if (where == STATUS) @@ -850,7 +936,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAG1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_MOUSEDRAG2_PANE; if (where == STATUS) @@ -864,7 +950,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAG2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_MOUSEDRAG3_PANE; if (where == STATUS) @@ -878,6 +964,90 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAG3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_MOUSEDRAG6_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_MOUSEDRAG7_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_MOUSEDRAG8_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_MOUSEDRAG9_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_MOUSEDRAG10_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_MOUSEDRAG11_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG11_BORDER; + break; } } @@ -918,7 +1088,7 @@ have_event: break; case UP: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_MOUSEUP1_PANE; if (where == STATUS) @@ -932,7 +1102,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEUP1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_MOUSEUP2_PANE; if (where == STATUS) @@ -946,7 +1116,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEUP2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_MOUSEUP3_PANE; if (where == STATUS) @@ -960,11 +1130,95 @@ have_event: if (where == BORDER) key = KEYC_MOUSEUP3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_MOUSEUP6_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_MOUSEUP7_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_MOUSEUP8_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_MOUSEUP9_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_MOUSEUP1_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP1_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP1_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP1_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP1_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP1_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_MOUSEUP11_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP11_BORDER; + break; } break; case DOWN: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_MOUSEDOWN1_PANE; if (where == STATUS) @@ -978,7 +1232,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDOWN1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_MOUSEDOWN2_PANE; if (where == STATUS) @@ -992,7 +1246,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDOWN2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_MOUSEDOWN3_PANE; if (where == STATUS) @@ -1006,11 +1260,95 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDOWN3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_MOUSEDOWN6_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_MOUSEDOWN7_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_MOUSEDOWN8_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_MOUSEDOWN9_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_MOUSEDOWN10_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_MOUSEDOWN11_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN11_BORDER; + break; } break; case SECOND: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_SECONDCLICK1_PANE; if (where == STATUS) @@ -1024,7 +1362,7 @@ have_event: if (where == BORDER) key = KEYC_SECONDCLICK1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_SECONDCLICK2_PANE; if (where == STATUS) @@ -1038,7 +1376,7 @@ have_event: if (where == BORDER) key = KEYC_SECONDCLICK2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_SECONDCLICK3_PANE; if (where == STATUS) @@ -1052,11 +1390,95 @@ have_event: if (where == BORDER) key = KEYC_SECONDCLICK3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_SECONDCLICK6_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_SECONDCLICK7_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_SECONDCLICK8_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_SECONDCLICK9_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_SECONDCLICK10_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_SECONDCLICK11_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK11_BORDER; + break; } break; case DOUBLE: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_DOUBLECLICK1_PANE; if (where == STATUS) @@ -1070,7 +1492,7 @@ have_event: if (where == BORDER) key = KEYC_DOUBLECLICK1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_DOUBLECLICK2_PANE; if (where == STATUS) @@ -1084,7 +1506,7 @@ have_event: if (where == BORDER) key = KEYC_DOUBLECLICK2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_DOUBLECLICK3_PANE; if (where == STATUS) @@ -1098,11 +1520,95 @@ have_event: if (where == BORDER) key = KEYC_DOUBLECLICK3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_DOUBLECLICK6_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_DOUBLECLICK7_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_DOUBLECLICK8_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_DOUBLECLICK9_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_DOUBLECLICK10_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_DOUBLECLICK11_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK11_BORDER; + break; } break; case TRIPLE: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_TRIPLECLICK1_PANE; if (where == STATUS) @@ -1116,7 +1622,7 @@ have_event: if (where == BORDER) key = KEYC_TRIPLECLICK1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_TRIPLECLICK2_PANE; if (where == STATUS) @@ -1130,7 +1636,7 @@ have_event: if (where == BORDER) key = KEYC_TRIPLECLICK2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_TRIPLECLICK3_PANE; if (where == STATUS) @@ -1144,6 +1650,90 @@ have_event: if (where == BORDER) key = KEYC_TRIPLECLICK3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_TRIPLECLICK6_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_TRIPLECLICK7_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_TRIPLECLICK8_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_TRIPLECLICK9_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_TRIPLECLICK10_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_TRIPLECLICK11_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK11_BORDER; + break; } break; } @@ -2011,8 +2601,10 @@ server_client_check_redraw(struct client *c) } if (c->flags & CLIENT_ALLREDRAWFLAGS) { - if (options_get_number(s->options, "set-titles")) + if (options_get_number(s->options, "set-titles")) { server_client_set_title(c); + server_client_set_path(c); + } screen_redraw_screen(c); } @@ -2058,6 +2650,26 @@ server_client_set_title(struct client *c) format_free(ft); } +/* Set client path. */ +static void +server_client_set_path(struct client *c) +{ + struct session *s = c->session; + const char *path; + + if (s->curw == NULL) + return; + if (s->curw->window->active->base.path == NULL) + path = ""; + else + path = s->curw->window->active->base.path; + if (c->path == NULL || strcmp(path, c->path) != 0) { + free(c->path); + c->path = xstrdup(path); + tty_set_path(&c->tty, c->path); + } +} + /* Dispatch message from client. */ static void server_client_dispatch(struct imsg *imsg, void *arg) diff --git a/server-fn.c b/server-fn.c index 92793093..2a79f3e3 100644 --- a/server-fn.c +++ b/server-fn.c @@ -310,9 +310,11 @@ server_destroy_pane(struct window_pane *wp, int notify) struct window *w = wp->window; struct screen_write_ctx ctx; struct grid_cell gc; - time_t t; - char tim[26]; int remain_on_exit; + const char *s; + char *expanded; + u_int sx = screen_size_x(&wp->base); + u_int sy = screen_size_y(&wp->base); if (wp->fd != -1) { #ifdef HAVE_UTEMPTER @@ -339,32 +341,26 @@ server_destroy_pane(struct window_pane *wp, int notify) return; wp->flags |= PANE_STATUSDRAWN; + gettimeofday(&wp->dead_time, NULL); if (notify) notify_pane("pane-died", wp); - screen_write_start_pane(&ctx, wp, &wp->base); - screen_write_scrollregion(&ctx, 0, screen_size_y(ctx.s) - 1); - screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1, 0); - screen_write_linefeed(&ctx, 1, 8); - memcpy(&gc, &grid_default_cell, sizeof gc); + s = options_get_string(wp->options, "remain-on-exit-format"); + if (*s != '\0') { + screen_write_start_pane(&ctx, wp, &wp->base); + screen_write_scrollregion(&ctx, 0, sy - 1); + screen_write_cursormove(&ctx, 0, sy - 1, 0); + screen_write_linefeed(&ctx, 1, 8); + memcpy(&gc, &grid_default_cell, sizeof gc); - time(&t); - ctime_r(&t, tim); - tim[strcspn(tim, "\n")] = '\0'; + expanded = format_single(NULL, s, NULL, NULL, NULL, wp); + format_draw(&ctx, &gc, sx, expanded, NULL, 0); + free(expanded); - if (WIFEXITED(wp->status)) { - screen_write_nputs(&ctx, -1, &gc, - "Pane is dead (status %d, %s)", - WEXITSTATUS(wp->status), - tim); - } else if (WIFSIGNALED(wp->status)) { - screen_write_nputs(&ctx, -1, &gc, - "Pane is dead (signal %s, %s)", - sig2name(WTERMSIG(wp->status)), - tim); + screen_write_stop(&ctx); } + wp->base.mode &= ~MODE_CURSOR; - screen_write_stop(&ctx); wp->flags |= PANE_REDRAW; return; } diff --git a/server.c b/server.c index 29bcf88a..5b70dcd0 100644 --- a/server.c +++ b/server.c @@ -100,7 +100,7 @@ server_check_marked(void) } /* Create server socket. */ -static int +int server_create_socket(int flags, char **cause) { struct sockaddr_un sa; @@ -214,7 +214,11 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base, gettimeofday(&start_time, NULL); +#ifdef HAVE_SYSTEMD + server_fd = systemd_create_socket(flags, &cause); +#else server_fd = server_create_socket(flags, &cause); +#endif if (server_fd != -1) server_update_socket(); if (~flags & CLIENT_NOFORK) @@ -230,10 +234,12 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base, if (cause != NULL) { if (c != NULL) { - cmdq_append(c, cmdq_get_error(cause)); + c->exit_message = cause; c->flags |= CLIENT_EXIT; + } else { + fprintf(stderr, "%s\n", cause); + exit(1); } - free(cause); } evtimer_set(&server_ev_tidy, server_tidy_event, NULL); diff --git a/session.c b/session.c index f30f6a61..75028882 100644 --- a/session.c +++ b/session.c @@ -27,7 +27,7 @@ #include "tmux.h" struct sessions sessions; -static u_int next_session_id; +u_int next_session_id; struct session_groups session_groups = RB_INITIALIZER(&session_groups); static void session_free(int, short, void *); @@ -501,7 +501,8 @@ session_set_current(struct session *s, struct winlink *wl) winlink_stack_push(&s->lastw, s->curw); s->curw = wl; if (options_get_number(global_options, "focus-events")) { - window_update_focus(old->window); + if (old != NULL) + window_update_focus(old->window); window_update_focus(wl->window); } winlink_clear_flags(wl); diff --git a/sixel.c b/sixel.c index a8cd5134..ad8f70df 100644 --- a/sixel.c +++ b/sixel.c @@ -554,7 +554,7 @@ sixel_to_screen(struct sixel_image *si) grid_view_set_cell(s->grid, x, y, &gc); } } else { - screen_write_box(&ctx, sx, sy); + screen_write_box(&ctx, sx, sy, BOX_LINES_DEFAULT, NULL, NULL); for (y = 1; y < sy - 1; y++) { for (x = 1; x < sx - 1; x++) grid_view_set_cell(s->grid, x, y, &gc); diff --git a/status.c b/status.c index bb57b3d6..8d702de1 100644 --- a/status.c +++ b/status.c @@ -718,7 +718,7 @@ status_prompt_redraw(struct client *c) memcpy(&cursorgc, &gc, sizeof cursorgc); cursorgc.attr ^= GRID_ATTR_REVERSE; - start = screen_write_strlen("%s", c->prompt_string); + start = format_width(c->prompt_string); if (start > c->tty.sx) start = c->tty.sx; @@ -728,7 +728,7 @@ status_prompt_redraw(struct client *c) for (offset = 0; offset < c->tty.sx; offset++) screen_write_putc(&ctx, &gc, ' '); screen_write_cursormove(&ctx, 0, lines - 1, 0); - screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string); + format_draw(&ctx, &gc, start, c->prompt_string, NULL, 0); screen_write_cursormove(&ctx, start, lines - 1, 0); left = c->tty.sx - start; @@ -1798,7 +1798,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s, item.name = tmp; item.key = '0' + size - 1; item.command = NULL; - menu_add_item(menu, &item, NULL, NULL, NULL); + menu_add_item(menu, &item, NULL, c, NULL); free(tmp); if (size == height) diff --git a/tmux.1 b/tmux.1 index 8433d9f2..b0ed13a3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -43,7 +43,7 @@ then later reattached. .Pp When .Nm -is started it creates a new +is started, it creates a new .Em session with a single .Em window @@ -140,7 +140,10 @@ By default, loads the system configuration file from .Pa @SYSCONFDIR@/tmux.conf , if present, then looks for a user configuration file at -.Pa ~/.tmux.conf . +.Pa ~/.tmux.conf, +.Pa $XDG_CONFIG_HOME/tmux/tmux.conf +or +.Pa ~/.config/tmux/tmux.conf . .Pp The configuration file is a set of .Nm @@ -1338,11 +1341,12 @@ 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 cDlLRSU +.Op Fl cDLRSU .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 t Ar target-client .Op Ar adjustment .Xc @@ -1456,7 +1460,11 @@ sets a comma-separated list of client flags, see .Fl l requests the clipboard from the client using the .Xr xterm 1 -escape sequence and stores it in a new paste buffer. +escape sequence. +If +Ar target-pane +is given, the clipboard is sent (in encoded form), otherwise it is stored in a +new paste buffer. .Pp .Fl L , .Fl R , @@ -1773,6 +1781,7 @@ The following commands are supported in copy mode: .It Li "set-mark" Ta "X" Ta "X" .It Li "start-of-line" Ta "0" Ta "C-a" .It Li "stop-selection" Ta "" Ta "" +.It Li "toggle-position" Ta "P" Ta "P" .It Li "top-line" Ta "H" Ta "M-R" .El .Pp @@ -3618,6 +3627,8 @@ Supports DECSLRM margins. Supports .Xr xterm 1 mouse sequences. +.It osc7 +Supports the OSC 7 working directory extension. .It overline Supports the overline SGR attribute. .It rectfill @@ -4108,6 +4119,9 @@ Set clock colour. .Xc Set clock hour format. .Pp +.It Ic fill-character Ar character +Set the character used to fill areas of the terminal unused by a window. +.Pp .It Ic main-pane-height Ar height .It Ic main-pane-width Ar width Set the width or height of the main (left or top) pane in the @@ -4223,6 +4237,12 @@ but set the starting index for pane numbers. .It Ic pane-border-format Ar format Set the text shown in pane border status lines. .Pp +.It Xo Ic pane-border-indicators +.Op Ic off | colour | arrows | both +.Xc +Indicate active pane by colouring only half of the border in windows with +exactly two panes, by displaying arrow markers, by drawing both or neither. +.Pp .It Ic pane-border-lines Ar type Set the type of characters used for drawing pane borders. .Ar type @@ -4396,6 +4416,13 @@ The default is on. Available pane options are: .Pp .Bl -tag -width Ds -compact +.It Xo Ic allow-passthrough +.Op Ic on | off +.Xc +Allow programs in the pane to bypass +.Nm +using a terminal escape sequence (\eePtmux;...\ee\e\e). +.Pp .It Xo Ic allow-rename .Op Ic on | off .Xc @@ -4449,6 +4476,17 @@ The pane may be reactivated with the .Ic respawn-pane command. .Pp +.It Ic remain-on-exit-format Ar string +Set the text shown at the bottom of exited panes when +.Ic remain-on-exit +is enabled. +.Pp +.It Xo Ic scroll-on-clear +.Op Ic on | off +.Xc +When the entire screen is cleared and this option is on, scroll the contents of +the screen into history before clearing it. +.Pp .It Xo Ic synchronize-panes .Op Ic on | off .Xc @@ -4575,6 +4613,11 @@ Run when a session is renamed. Run when a window is linked into a session. .It window-renamed Run when a window is renamed. +.It window-resized +Run when a window is resized. +This may be after the +.Ar client-resized +hook is run. .It window-unlinked Run when a window is unlinked from a session. .El @@ -4989,7 +5032,9 @@ commands to finish; instead, the previous result from running the same command i or a placeholder if the command has not been run before. If the command hasn't exited, the most recent line of output will be used, but the status line will not be updated more than once a second. -Commands are executed with the +Commands are executed using +.Pa /bin/sh +and with the .Nm global environment set (see the .Sx GLOBAL AND SESSION ENVIRONMENT @@ -5033,6 +5078,8 @@ The following variables are available, where appropriate: .It Li "client_termname" Ta "" Ta "Terminal name of client" .It Li "client_termtype" Ta "" Ta "Terminal type of client, if available" .It Li "client_tty" Ta "" Ta "Pseudo terminal of client" +.It Li "client_uid" Ta "" Ta "UID of client process" +.It Li "client_user" Ta "" Ta "User of client process" .It Li "client_utf8" Ta "" Ta "1 if client supports UTF-8" .It Li "client_width" Ta "" Ta "Width of client" .It Li "client_written" Ta "" Ta "Bytes written to client" @@ -5077,6 +5124,7 @@ The following variables are available, where appropriate: .It Li "mouse_word" Ta "" Ta "Word under mouse, if any" .It Li "mouse_x" Ta "" Ta "Mouse X position, if any" .It Li "mouse_y" Ta "" Ta "Mouse Y position, if any" +.It Li "next_session_id" Ta "" Ta "Unique session ID for next new session" .It Li "origin_flag" Ta "" Ta "Pane origin flag" .It Li "pane_active" Ta "" Ta "1 if active pane" .It Li "pane_at_bottom" Ta "" Ta "1 if pane is at the bottom of window" @@ -5088,7 +5136,9 @@ The following variables are available, where appropriate: .It Li "pane_current_command" Ta "" Ta "Current command if available" .It Li "pane_current_path" Ta "" Ta "Current path if available" .It Li "pane_dead" Ta "" Ta "1 if pane is dead" +.It Li "pane_dead_signal" Ta "" Ta "Exit signal of process in dead pane" .It Li "pane_dead_status" Ta "" Ta "Exit status of process in dead pane" +.It Li "pane_dead_time" Ta "" Ta "Exit time of process in dead pane" .It Li "pane_fg" Ta "" Ta "Pane foreground colour" .It Li "pane_format" Ta "" Ta "1 if format is for a pane" .It Li "pane_height" Ta "" Ta "Height of pane" @@ -5149,6 +5199,8 @@ The following variables are available, where appropriate: .It Li "session_windows" Ta "" Ta "Number of windows in session" .It Li "socket_path" Ta "" Ta "Server socket path" .It Li "start_time" Ta "" Ta "Server start time" +.It Li "uid" Ta "" Ta "Server UID" +.It Li "user" Ta "" Ta "Server user" .It Li "version" Ta "" Ta "Server version" .It Li "window_active" Ta "" Ta "1 if window active" .It Li "window_active_clients" Ta "" Ta "Number of clients viewing this window" @@ -5163,7 +5215,6 @@ The following variables are available, where appropriate: .It Li "window_cell_width" Ta "" Ta "Width of each cell in pixels" .It Li "window_end_flag" Ta "" Ta "1 if window has the highest index" .It Li "window_flags" Ta "#F" Ta "Window flags with # escaped as ##" -.It Li "window_raw_flags" Ta "" Ta "Window flags with nothing escaped" .It Li "window_format" Ta "" Ta "1 if format is for a window" .It Li "window_height" Ta "" Ta "Height of window" .It Li "window_id" Ta "" Ta "Unique window ID" @@ -5178,6 +5229,7 @@ The following variables are available, where appropriate: .It Li "window_offset_x" Ta "" Ta "X offset into window if larger than client" .It Li "window_offset_y" Ta "" Ta "Y offset into window if larger than client" .It Li "window_panes" Ta "" Ta "Number of panes in window" +.It Li "window_raw_flags" Ta "" Ta "Window flags with nothing escaped" .It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert" .It Li "window_stack_index" Ta "" Ta "Index in session most recent stack" .It Li "window_start_flag" Ta "" Ta "1 if window has the lowest index" @@ -5866,7 +5918,7 @@ does not surround the popup by a border. sets the type of border line for the popup. When .Fl B -is specified the +is specified, the .Fl b option is ignored. See @@ -6155,6 +6207,8 @@ Execute the first .Ar command if .Ar shell-command +(run with +.Pa /bin/sh ) returns success or the second .Ar command otherwise. @@ -6191,6 +6245,8 @@ option. .D1 Pq alias: Ic run Execute .Ar shell-command +using +.Pa /bin/sh or (with .Fl C ) a @@ -6292,6 +6348,11 @@ to change the cursor colour from inside .Bd -literal -offset indent $ printf '\e033]12;red\e033\e\e' .Ed +.Pp +The colour is an +.Xr X 7 +colour, see +.Xr XParseColor 3 . .It Em \&Cmg, \&Clmg, \&Dsmg , \&Enmg Set, clear, disable or enable DECSLRM margins. These are set automatically if the terminal reports it is @@ -6335,6 +6396,11 @@ $ printf '\e033[4 q' If .Em Se is not set, \&Ss with argument 0 will be used to reset the cursor style instead. +.It Em \&Swd +Set the opening sequence for the working directory notification. +The sequence is terminated using the standard +.Em fsl +capability. .It Em \&Sxl Indicates that the terminal supports SIXEL. .It Em \&Sync @@ -6509,6 +6575,14 @@ are for future use and should be ignored. The window with ID .Ar window-id was created but is not linked to the current session. +.It Ic %unlinked-window-close Ar window-id +The window with ID +.Ar window-id , +which is not linked to the current session, was closed. +.It Ic %unlinked-window-renamed Ar window-id +The window with ID +.Ar window-id , +which is not linked to the current session, was renamed. .It Ic %window-add Ar window-id The window with ID .Ar window-id @@ -6567,7 +6641,7 @@ are replaced with underscores For input, .Nm always runs with a UTF-8 locale. -If en_US.UTF-8 is provided by the operating system it is used and +If en_US.UTF-8 is provided by the operating system, it is used and .Ev LC_CTYPE is ignored for input. Otherwise, @@ -6616,6 +6690,8 @@ options. .Sh FILES .Bl -tag -width "@SYSCONFDIR@/tmux.confXXX" -compact .It Pa ~/.tmux.conf +.It Pa $XDG_CONFIG_HOME/tmux/tmux.conf +.It Pa ~/.config/tmux/tmux.conf Default .Nm configuration file. diff --git a/tmux.h b/tmux.h index 12d1d9d5..1f0bd726 100644 --- a/tmux.h +++ b/tmux.h @@ -203,26 +203,68 @@ enum { KEYC_MOUSE_KEY(MOUSEDOWN1), KEYC_MOUSE_KEY(MOUSEDOWN2), KEYC_MOUSE_KEY(MOUSEDOWN3), + KEYC_MOUSE_KEY(MOUSEDOWN6), + KEYC_MOUSE_KEY(MOUSEDOWN7), + KEYC_MOUSE_KEY(MOUSEDOWN8), + KEYC_MOUSE_KEY(MOUSEDOWN9), + KEYC_MOUSE_KEY(MOUSEDOWN10), + KEYC_MOUSE_KEY(MOUSEDOWN11), KEYC_MOUSE_KEY(MOUSEUP1), KEYC_MOUSE_KEY(MOUSEUP2), KEYC_MOUSE_KEY(MOUSEUP3), + KEYC_MOUSE_KEY(MOUSEUP6), + KEYC_MOUSE_KEY(MOUSEUP7), + KEYC_MOUSE_KEY(MOUSEUP8), + KEYC_MOUSE_KEY(MOUSEUP9), + KEYC_MOUSE_KEY(MOUSEUP10), + KEYC_MOUSE_KEY(MOUSEUP11), KEYC_MOUSE_KEY(MOUSEDRAG1), KEYC_MOUSE_KEY(MOUSEDRAG2), KEYC_MOUSE_KEY(MOUSEDRAG3), + KEYC_MOUSE_KEY(MOUSEDRAG6), + KEYC_MOUSE_KEY(MOUSEDRAG7), + KEYC_MOUSE_KEY(MOUSEDRAG8), + KEYC_MOUSE_KEY(MOUSEDRAG9), + KEYC_MOUSE_KEY(MOUSEDRAG10), + KEYC_MOUSE_KEY(MOUSEDRAG11), KEYC_MOUSE_KEY(MOUSEDRAGEND1), KEYC_MOUSE_KEY(MOUSEDRAGEND2), KEYC_MOUSE_KEY(MOUSEDRAGEND3), + KEYC_MOUSE_KEY(MOUSEDRAGEND6), + KEYC_MOUSE_KEY(MOUSEDRAGEND7), + KEYC_MOUSE_KEY(MOUSEDRAGEND8), + KEYC_MOUSE_KEY(MOUSEDRAGEND9), + KEYC_MOUSE_KEY(MOUSEDRAGEND10), + KEYC_MOUSE_KEY(MOUSEDRAGEND11), KEYC_MOUSE_KEY(WHEELUP), KEYC_MOUSE_KEY(WHEELDOWN), KEYC_MOUSE_KEY(SECONDCLICK1), KEYC_MOUSE_KEY(SECONDCLICK2), KEYC_MOUSE_KEY(SECONDCLICK3), + KEYC_MOUSE_KEY(SECONDCLICK6), + KEYC_MOUSE_KEY(SECONDCLICK7), + KEYC_MOUSE_KEY(SECONDCLICK8), + KEYC_MOUSE_KEY(SECONDCLICK9), + KEYC_MOUSE_KEY(SECONDCLICK10), + KEYC_MOUSE_KEY(SECONDCLICK11), KEYC_MOUSE_KEY(DOUBLECLICK1), KEYC_MOUSE_KEY(DOUBLECLICK2), KEYC_MOUSE_KEY(DOUBLECLICK3), + KEYC_MOUSE_KEY(DOUBLECLICK6), + KEYC_MOUSE_KEY(DOUBLECLICK7), + KEYC_MOUSE_KEY(DOUBLECLICK8), + KEYC_MOUSE_KEY(DOUBLECLICK9), + KEYC_MOUSE_KEY(DOUBLECLICK10), + KEYC_MOUSE_KEY(DOUBLECLICK11), KEYC_MOUSE_KEY(TRIPLECLICK1), KEYC_MOUSE_KEY(TRIPLECLICK2), KEYC_MOUSE_KEY(TRIPLECLICK3), + KEYC_MOUSE_KEY(TRIPLECLICK6), + KEYC_MOUSE_KEY(TRIPLECLICK7), + KEYC_MOUSE_KEY(TRIPLECLICK8), + KEYC_MOUSE_KEY(TRIPLECLICK9), + KEYC_MOUSE_KEY(TRIPLECLICK10), + KEYC_MOUSE_KEY(TRIPLECLICK11), /* Backspace key. */ KEYC_BSPACE, @@ -500,6 +542,7 @@ enum tty_code_code { TTYC_SMXX, TTYC_SXL, TTYC_SS, + TTYC_SWD, TTYC_SYNC, TTYC_TC, TTYC_TSL, @@ -671,15 +714,15 @@ struct grid_cell_entry { /* Grid line. */ struct grid_line { + struct grid_cell_entry *celldata; u_int cellused; u_int cellsize; - struct grid_cell_entry *celldata; - u_int extdsize; struct grid_extd_entry *extddata; + u_int extdsize; int flags; -} __packed; +}; /* Entire grid of cells. */ struct grid { @@ -814,7 +857,6 @@ struct screen { struct grid_cell saved_cell; int saved_flags; - int mode; bitstr_t *tabs; struct screen_sel *sel; struct images images; @@ -862,6 +904,12 @@ enum pane_lines { PANE_LINES_NUMBER }; +/* Pane border indicator option. */ +#define PANE_BORDER_OFF 0 +#define PANE_BORDER_COLOUR 1 +#define PANE_BORDER_ARROWS 2 +#define PANE_BORDER_BOTH 3 + /* Screen redraw context. */ struct screen_redraw_ctx { struct client *c; @@ -998,6 +1046,7 @@ struct window_pane { pid_t pid; char tty[TTY_NAME_MAX]; int status; + struct timeval dead_time; int fd; struct bufferevent *event; @@ -1040,40 +1089,41 @@ RB_HEAD(window_pane_tree, window_pane); /* Window structure. */ struct window { - u_int id; - void *latest; + u_int id; + void *latest; - char *name; - struct event name_event; - struct timeval name_time; + char *name; + struct event name_event; + struct timeval name_time; - struct event alerts_timer; - struct event offset_timer; + struct event alerts_timer; + struct event offset_timer; - struct timeval activity_time; + struct timeval activity_time; - struct window_pane *active; - struct window_pane *last; - struct window_panes panes; + struct window_pane *active; + struct window_pane *last; + struct window_panes panes; - int lastlayout; - struct layout_cell *layout_root; - struct layout_cell *saved_layout_root; - char *old_layout; + int lastlayout; + struct layout_cell *layout_root; + struct layout_cell *saved_layout_root; + char *old_layout; - u_int sx; - u_int sy; - u_int manual_sx; - u_int manual_sy; - u_int xpixel; - u_int ypixel; + u_int sx; + u_int sy; + u_int manual_sx; + u_int manual_sy; + u_int xpixel; + u_int ypixel; - u_int new_sx; - u_int new_sy; - u_int new_xpixel; - u_int new_ypixel; + u_int new_sx; + u_int new_sy; + u_int new_xpixel; + u_int new_ypixel; - int flags; + struct utf8_data *fill_character; + int flags; #define WINDOW_BELL 0x1 #define WINDOW_ACTIVITY 0x2 #define WINDOW_SILENCE 0x4 @@ -1082,15 +1132,15 @@ struct window { #define WINDOW_RESIZE 0x20 #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) - int alerts_queued; - TAILQ_ENTRY(window) alerts_entry; + int alerts_queued; + TAILQ_ENTRY(window) alerts_entry; - struct options *options; + struct options *options; - u_int references; - TAILQ_HEAD(, winlink) winlinks; + u_int references; + TAILQ_HEAD(, winlink) winlinks; - RB_ENTRY(window) entry; + RB_ENTRY(window) entry; }; RB_HEAD(windows, window); @@ -1212,21 +1262,33 @@ struct session { RB_HEAD(sessions, session); /* Mouse button masks. */ -#define MOUSE_MASK_BUTTONS 3 +#define MOUSE_MASK_BUTTONS 195 #define MOUSE_MASK_SHIFT 4 #define MOUSE_MASK_META 8 #define MOUSE_MASK_CTRL 16 #define MOUSE_MASK_DRAG 32 -#define MOUSE_MASK_WHEEL 64 #define MOUSE_MASK_MODIFIERS (MOUSE_MASK_SHIFT|MOUSE_MASK_META|MOUSE_MASK_CTRL) -/* Mouse wheel states. */ -#define MOUSE_WHEEL_UP 0 -#define MOUSE_WHEEL_DOWN 1 +/* Mouse wheel type. */ +#define MOUSE_WHEEL_UP 64 +#define MOUSE_WHEEL_DOWN 65 + +/* Mouse button type. */ +#define MOUSE_BUTTON_1 0 +#define MOUSE_BUTTON_2 1 +#define MOUSE_BUTTON_3 2 +#define MOUSE_BUTTON_6 66 +#define MOUSE_BUTTON_7 67 +#define MOUSE_BUTTON_8 128 +#define MOUSE_BUTTON_9 129 +#define MOUSE_BUTTON_10 130 +#define MOUSE_BUTTON_11 131 /* Mouse helpers. */ #define MOUSE_BUTTONS(b) ((b) & MOUSE_MASK_BUTTONS) -#define MOUSE_WHEEL(b) ((b) & MOUSE_MASK_WHEEL) +#define MOUSE_WHEEL(b) \ + (((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_UP || \ + ((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_DOWN) #define MOUSE_DRAG(b) ((b) & MOUSE_MASK_DRAG) #define MOUSE_RELEASE(b) (((b) & MOUSE_MASK_BUTTONS) == 3) @@ -1292,6 +1354,7 @@ LIST_HEAD(tty_terms, tty_term); struct tty { struct client *client; struct event start_timer; + struct event clipboard_timer; u_int sx; u_int sy; @@ -1332,15 +1395,14 @@ struct tty { #define TTY_NOCURSOR 0x1 #define TTY_FREEZE 0x2 #define TTY_TIMER 0x4 -/* 0x8 unused */ +#define TTY_NOBLOCK 0x8 #define TTY_STARTED 0x10 #define TTY_OPENED 0x20 -/* 0x40 unused */ +#define TTY_OSC52QUERY 0x40 #define TTY_BLOCK 0x80 #define TTY_HAVEDA 0x100 #define TTY_HAVEXDA 0x200 #define TTY_SYNCING 0x400 -#define TTY_NOBLOCK 0x800 int flags; struct tty_term *term; @@ -1646,50 +1708,51 @@ typedef int (*overlay_key_cb)(struct client *, void *, struct key_event *); typedef void (*overlay_free_cb)(struct client *, void *); typedef void (*overlay_resize_cb)(struct client *, void *); struct client { - const char *name; - struct tmuxpeer *peer; - struct cmdq_list *queue; + const char *name; + struct tmuxpeer *peer; + struct cmdq_list *queue; - struct client_windows windows; + struct client_windows windows; - struct control_state *control_state; - u_int pause_age; + struct control_state *control_state; + u_int pause_age; - pid_t pid; - int fd; - int out_fd; - struct event event; - int retval; + pid_t pid; + int fd; + int out_fd; + struct event event; + int retval; - struct timeval creation_time; - struct timeval activity_time; + struct timeval creation_time; + struct timeval activity_time; - struct environ *environ; + struct environ *environ; struct format_job_tree *jobs; - char *title; - const char *cwd; + char *title; + char *path; + const char *cwd; - char *term_name; - int term_features; - char *term_type; - char **term_caps; - u_int term_ncaps; + char *term_name; + int term_features; + char *term_type; + char **term_caps; + u_int term_ncaps; - char *ttyname; - struct tty tty; + char *ttyname; + struct tty tty; - size_t written; - size_t discarded; - size_t redraw; + size_t written; + size_t discarded; + size_t redraw; - struct event repeat_timer; + struct event repeat_timer; - struct event click_timer; - u_int click_button; - struct mouse_event click_event; + struct event click_timer; + u_int click_button; + struct mouse_event click_event; - struct status_line status; + struct status_line status; #define CLIENT_TERMINAL 0x1 #define CLIENT_LOGIN 0x2 @@ -1726,6 +1789,7 @@ struct client { #define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL #define CLIENT_CONTROL_WAITEXIT 0x200000000ULL #define CLIENT_WINDOWSIZECHANGED 0x400000000ULL +#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL #define CLIENT_ALLREDRAWFLAGS \ (CLIENT_REDRAWWINDOW| \ CLIENT_REDRAWSTATUS| \ @@ -1737,73 +1801,79 @@ struct client { (CLIENT_DEAD| \ CLIENT_SUSPENDED| \ CLIENT_EXIT) -#define CLIENT_NODETACHFLAGS \ +#define CLIENT_NODETACHFLAGS \ (CLIENT_DEAD| \ CLIENT_EXIT) #define CLIENT_NOSIZEFLAGS \ (CLIENT_DEAD| \ CLIENT_SUSPENDED| \ CLIENT_EXIT) - uint64_t flags; + uint64_t flags; enum { CLIENT_EXIT_RETURN, CLIENT_EXIT_SHUTDOWN, CLIENT_EXIT_DETACH - } exit_type; - enum msgtype exit_msgtype; - char *exit_session; - char *exit_message; + } exit_type; + enum msgtype exit_msgtype; + char *exit_session; + char *exit_message; - struct key_table *keytable; + struct key_table *keytable; - uint64_t redraw_panes; + uint64_t redraw_panes; - int message_ignore_keys; - int message_ignore_styles; - char *message_string; - struct event message_timer; + int message_ignore_keys; + int message_ignore_styles; + char *message_string; + struct event message_timer; - char *prompt_string; - struct utf8_data *prompt_buffer; - char *prompt_last; - size_t prompt_index; - prompt_input_cb prompt_inputcb; - prompt_free_cb prompt_freecb; - void *prompt_data; - u_int prompt_hindex[PROMPT_NTYPES]; - enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode; - struct utf8_data *prompt_saved; + char *prompt_string; + struct utf8_data *prompt_buffer; + char *prompt_last; + size_t prompt_index; + prompt_input_cb prompt_inputcb; + prompt_free_cb prompt_freecb; + void *prompt_data; + u_int prompt_hindex[PROMPT_NTYPES]; + enum { + PROMPT_ENTRY, + PROMPT_COMMAND + } prompt_mode; + struct utf8_data *prompt_saved; #define PROMPT_SINGLE 0x1 #define PROMPT_NUMERIC 0x2 #define PROMPT_INCREMENTAL 0x4 #define PROMPT_NOFORMAT 0x8 #define PROMPT_KEY 0x10 - int prompt_flags; - enum prompt_type prompt_type; - int prompt_cursor; + int prompt_flags; + enum prompt_type prompt_type; + int prompt_cursor; - struct session *session; - struct session *last_session; + struct session *session; + struct session *last_session; - int references; + int references; - void *pan_window; - u_int pan_ox; - u_int pan_oy; + void *pan_window; + u_int pan_ox; + u_int pan_oy; - overlay_check_cb overlay_check; - overlay_mode_cb overlay_mode; - overlay_draw_cb overlay_draw; - overlay_key_cb overlay_key; - overlay_free_cb overlay_free; - overlay_resize_cb overlay_resize; - void *overlay_data; - struct event overlay_timer; + overlay_check_cb overlay_check; + overlay_mode_cb overlay_mode; + overlay_draw_cb overlay_draw; + overlay_key_cb overlay_key; + overlay_free_cb overlay_free; + overlay_resize_cb overlay_resize; + void *overlay_data; + struct event overlay_timer; - struct client_files files; + struct client_files files; - TAILQ_ENTRY(client) entry; + u_int *clipboard_panes; + u_int clipboard_npanes; + + TAILQ_ENTRY(client) entry; }; TAILQ_HEAD(clients, client); @@ -1977,6 +2047,7 @@ void proc_remove_peer(struct tmuxpeer *); void proc_kill_peer(struct tmuxpeer *); void proc_toggle_log(struct tmuxproc *); pid_t proc_fork_and_daemon(int *); +uid_t proc_get_peer_uid(struct tmuxpeer *); /* cfg.c */ extern int cfg_finished; @@ -2190,6 +2261,7 @@ void tty_reset(struct tty *); void tty_region_off(struct tty *); 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); @@ -2209,6 +2281,7 @@ void tty_start_tty(struct tty *); void tty_send_requests(struct tty *); void tty_stop_tty(struct tty *); void tty_set_title(struct tty *, const char *); +void tty_set_path(struct tty *, const char *); void tty_update_mode(struct tty *, int, struct screen *); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int, u_int, u_int, const struct grid_cell *, struct colour_palette *); @@ -2532,6 +2605,7 @@ int server_start(struct tmuxproc *, int, struct event_base *, int, char *); void server_update_socket(void); void server_add_accept(int); void printflike(1, 2) server_add_message(const char *, ...); +int server_create_socket(int, char **); /* server-client.c */ RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp); @@ -2637,6 +2711,8 @@ void input_parse_pane(struct window_pane *); void input_parse_buffer(struct window_pane *, u_char *, size_t); void input_parse_screen(struct input_ctx *, struct screen *, screen_write_init_ctx_cb, void *, u_char *, size_t); +void input_reply_clipboard(struct bufferevent *, const char *, size_t, + const char *); /* input-key.c */ void input_key_build(void); @@ -2930,6 +3006,7 @@ void *window_pane_get_new_data(struct window_pane *, struct window_pane_offset *, size_t *); void window_pane_update_used_data(struct window_pane *, struct window_pane_offset *, size_t); +void window_set_fill_character(struct window *); /* layout.c */ u_int layout_count_cells(struct layout_cell *); @@ -3083,6 +3160,7 @@ void control_notify_session_window_changed(struct session *); /* session.c */ extern struct sessions sessions; +extern u_int next_session_id; int session_cmp(struct session *, struct session *); RB_PROTOTYPE(sessions, session, entry, session_cmp); int session_alive(struct session *); diff --git a/tty-features.c b/tty-features.c index 48ac51be..4d83a465 100644 --- a/tty-features.c +++ b/tty-features.c @@ -53,6 +53,18 @@ static const struct tty_feature tty_feature_title = { 0 }; +/* Terminal has OSC 7 working directory. */ +static const char *tty_feature_osc7_capabilities[] = { + "Swd=\\E]7;", + "fsl=\\a", + NULL +}; +static const struct tty_feature tty_feature_osc7 = { + "osc7", + tty_feature_osc7_capabilities, + 0 +}; + /* Terminal has mouse support. */ static const char *tty_feature_mouse_capabilities[] = { "kmous=\\E[M", @@ -249,6 +261,7 @@ static const struct tty_feature *tty_features[] = { &tty_feature_focus, &tty_feature_margins, &tty_feature_mouse, + &tty_feature_osc7, &tty_feature_overline, &tty_feature_rectfill, &tty_feature_rgb, @@ -363,7 +376,7 @@ tty_default_features(int *feat, const char *name, u_int version) }, { .name = "iTerm2", .features = TTY_FEATURES_BASE_MODERN_XTERM - ",cstyle,extkeys,margins,sync" + ",cstyle,extkeys,margins,usstyle,sync" }, { .name = "XTerm", /* diff --git a/tty-keys.c b/tty-keys.c index 22c64a5d..02372aa1 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1118,7 +1118,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, /* Type is M for press, m for release. */ sgr_type = ch; if (sgr_type == 'm') - b |= 3; + b = 3; /* * Some terminals (like PuTTY 0.63) mistakenly send @@ -1126,7 +1126,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, * Discard it before it reaches any program running inside * tmux. */ - if (sgr_type == 'm' && (sgr_b & 64)) + if (sgr_type == 'm' && MOUSE_WHEEL(sgr_b)) return (-2); } else return (-1); @@ -1154,12 +1154,14 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, * partial. */ static int -tty_keys_clipboard(__unused 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) { - size_t end, terminator, needed; - char *copy, *out; - int outlen; + struct client *c = tty->client; + struct window_pane *wp; + size_t end, terminator, needed; + char *copy, *out; + int outlen; + u_int i; *size = 0; @@ -1217,6 +1219,12 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len, 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); @@ -1232,9 +1240,20 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len, } free(copy); - /* Create a new paste buffer. */ + /* Create a new paste buffer and forward to panes. */ log_debug("%s: %.*s", __func__, outlen, out); - paste_add(NULL, out, outlen); + 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; return (0); } diff --git a/tty-term.c b/tty-term.c index d1060d65..1acd2dda 100644 --- a/tty-term.c +++ b/tty-term.c @@ -278,6 +278,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { [TTYC_SMUL] = { TTYCODE_STRING, "smul" }, [TTYC_SMXX] = { TTYCODE_STRING, "smxx" }, [TTYC_SS] = { TTYCODE_STRING, "Ss" }, + [TTYC_SWD] = { TTYCODE_STRING, "Swd" }, [TTYC_SYNC] = { TTYCODE_STRING, "Sync" }, [TTYC_TC] = { TTYCODE_FLAG, "Tc" }, [TTYC_TSL] = { TTYCODE_STRING, "tsl" }, diff --git a/tty.c b/tty.c index fb1276de..c631e5ad 100644 --- a/tty.c +++ b/tty.c @@ -83,6 +83,8 @@ static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int, #define TTY_BLOCK_START(tty) (1 + ((tty)->sx * (tty)->sy) * 8) #define TTY_BLOCK_STOP(tty) (1 + ((tty)->sx * (tty)->sy) / 8) +#define TTY_QUERY_TIMEOUT 5 + void tty_create_log(void) { @@ -307,7 +309,7 @@ tty_start_tty(struct tty *tty) { struct client *c = tty->client; struct termios tio; - struct timeval tv = { .tv_sec = 3 }; + struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; setblocking(c->fd, 0); event_add(&tty->event_in, NULL); @@ -653,6 +655,18 @@ tty_set_title(struct tty *tty, const char *title) tty_putcode(tty, TTYC_FSL); } +void +tty_set_path(struct tty *tty, const char *title) +{ + if (!tty_term_has(tty->term, TTYC_SWD) || + !tty_term_has(tty->term, TTYC_FSL)) + return; + + tty_putcode(tty, TTYC_SWD); + tty_puts(tty, title); + tty_putcode(tty, TTYC_FSL); +} + static void tty_force_cursor_colour(struct tty *tty, int c) { @@ -791,26 +805,19 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) if ((changed & ALL_MOUSE_MODES) && tty_term_has(term, TTYC_KMOUS)) { /* - * If the mouse modes have changed, clear any that are set and - * apply again. There are differences in how terminals track - * the various bits. + * If the mouse modes have changed, clear then all and apply + * again. There are differences in how terminals track the + * various bits. */ - if (tty->mode & MODE_MOUSE_SGR) - tty_puts(tty, "\033[?1006l"); - if (tty->mode & MODE_MOUSE_STANDARD) - tty_puts(tty, "\033[?1000l"); - if (tty->mode & MODE_MOUSE_BUTTON) - tty_puts(tty, "\033[?1002l"); - if (tty->mode & MODE_MOUSE_ALL) - tty_puts(tty, "\033[?1003l"); + tty_puts(tty, "\033[?1006l\033[?1000l\033[?1002l\033[?1003l"); if (mode & ALL_MOUSE_MODES) tty_puts(tty, "\033[?1006h"); - if (mode & MODE_MOUSE_STANDARD) - tty_puts(tty, "\033[?1000h"); - if (mode & MODE_MOUSE_BUTTON) - tty_puts(tty, "\033[?1002h"); if (mode & MODE_MOUSE_ALL) - tty_puts(tty, "\033[?1003h"); + tty_puts(tty, "\033[?1000h\033[?1002h\033[?1003h"); + if (mode & MODE_MOUSE_BUTTON) + tty_puts(tty, "\033[?1000h\033[?1002h"); + else if (mode & MODE_MOUSE_STANDARD) + tty_puts(tty, "\033[?1000h"); } if (changed & MODE_BRACKETPASTE) { if (mode & MODE_BRACKETPASTE) @@ -2125,8 +2132,8 @@ tty_set_selection(struct tty *tty, const char *buf, size_t len) encoded = xmalloc(size); b64_ntop(buf, len, encoded, size); + tty->flags |= TTY_NOBLOCK; tty_putcode_ptr2(tty, TTYC_MS, "", encoded); - tty->client->redraw = EVBUFFER_LENGTH(tty->out); free(encoded); } @@ -2134,6 +2141,7 @@ tty_set_selection(struct tty *tty, const char *buf, size_t len) void tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) { + tty->flags |= TTY_NOBLOCK; tty_add(tty, ctx->ptr, ctx->num); tty_invalidate(tty); } @@ -2996,3 +3004,31 @@ tty_default_attributes(struct tty *tty, const struct grid_cell *defaults, gc.bg = bg; tty_attributes(tty, &gc, defaults, palette); } + +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; +} + +void +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_ptr2(tty, TTYC_MS, "", "?"); + + tty->flags |= TTY_OSC52QUERY; + evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); + evtimer_add(&tty->clipboard_timer, &tv); +} diff --git a/window-copy.c b/window-copy.c index ec6a2f4e..7c55b0f2 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1272,6 +1272,16 @@ window_copy_cmd_halfpage_up(struct window_copy_cmd_state *cs) return (WINDOW_COPY_CMD_NOTHING); } +static enum window_copy_cmd_action +window_copy_cmd_toggle_position(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + struct window_copy_mode_data *data = wme->data; + + data->hide_position = !data->hide_position; + return (WINDOW_COPY_CMD_REDRAW); +} + static enum window_copy_cmd_action window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs) { @@ -2817,6 +2827,12 @@ static const struct { .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .f = window_copy_cmd_stop_selection }, + { .command = "toggle-position", + .minargs = 0, + .maxargs = 0, + .clear = WINDOW_COPY_CMD_CLEAR_NEVER, + .f = window_copy_cmd_toggle_position + }, { .command = "top-line", .minargs = 0, .maxargs = 0, @@ -3148,6 +3164,11 @@ window_copy_cellstring(const struct grid_line *gl, u_int px, size_t *size, } utf8_to_data(gl->extddata[gce->offset].data, &ud); + if (ud.size == 0) { + *size = 0; + *allocated = 0; + return (NULL); + } *size = ud.size; *allocated = 1; diff --git a/window-customize.c b/window-customize.c index 98387e50..4a16e90c 100644 --- a/window-customize.c +++ b/window-customize.c @@ -680,9 +680,7 @@ window_customize_draw_option(struct window_customize_modedata *data, } ft = format_create_from_state(NULL, NULL, &fs); - if (oe == NULL) - text = "This is a user option."; - else if (oe->text == NULL) + if (oe == NULL || oe->text == NULL) text = "This option doesn't have a description."; else text = oe->text; diff --git a/window.c b/window.c index d3e3f60f..bce8913a 100644 --- a/window.c +++ b/window.c @@ -329,6 +329,7 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) w->id = next_window_id++; RB_INSERT(windows, &windows, w); + window_set_fill_character(w); window_update_activity(w); log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy, @@ -360,6 +361,7 @@ window_destroy(struct window *w) event_del(&w->offset_timer); options_free(w->options); + free(w->fill_character); free(w->name); free(w); @@ -761,6 +763,7 @@ window_lost_pane(struct window *w, struct window_pane *wp) if (w->active != NULL) { w->active->flags |= PANE_CHANGED; notify_window("window-pane-changed", w); + window_update_focus(w); } } else if (wp == w->last) w->last = NULL; @@ -1598,3 +1601,20 @@ window_pane_update_used_data(struct window_pane *wp, size = EVBUFFER_LENGTH(wp->event->input) - used; wpo->used += size; } + +void +window_set_fill_character(struct window *w) +{ + const char *value; + struct utf8_data *ud; + + free(w->fill_character); + w->fill_character = NULL; + + value = options_get_string(w->options, "fill-character"); + if (*value != '\0' && utf8_isvalid(value)) { + ud = utf8_fromcstr(value); + if (ud != NULL && ud[0].width == 1) + w->fill_character = ud; + } +}