Merge branch 'master' into sixel

This commit is contained in:
Nicholas Marriott 2022-04-01 10:14:15 +01:00
commit 742c063473
49 changed files with 1880 additions and 379 deletions

40
CHANGES
View File

@ -1,5 +1,45 @@
CHANGES FROM 3.2a TO 3.3 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 * Change so that {} is converted to tmux commands immediately when parsed. This
means it must contain valid tmux commands. For commands which expand %% and means it must contain valid tmux commands. For commands which expand %% and
%%%, this now only happens within string arguments. Use of nested aliases %%%, this now only happens within string arguments. Use of nested aliases

View File

@ -206,6 +206,11 @@ if NEED_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif endif
# Add compat file for systemd.
if HAVE_SYSTEMD
nodist_tmux_SOURCES += compat/systemd.c
endif
# Add compat file for utf8proc. # Add compat file for utf8proc.
if HAVE_UTF8PROC if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c nodist_tmux_SOURCES += compat/utf8proc.c

View File

@ -131,8 +131,9 @@ args_parse(const struct args_parse *parse, struct args_value *values,
u_int i; u_int i;
enum args_parse_type type; enum args_parse_type type;
struct args_value *value, *new; struct args_value *value, *new;
u_char flag, argument; u_char flag;
const char *found, *string, *s; const char *found, *string, *s;
int optional_argument;
if (count == 0) if (count == 0)
return (args_create()); return (args_create());
@ -169,18 +170,27 @@ args_parse(const struct args_parse *parse, struct args_value *values,
args_free(args); args_free(args);
return (NULL); return (NULL);
} }
argument = *++found; if (*++found != ':') {
if (argument != ':') {
log_debug("%s: -%c", __func__, flag); log_debug("%s: -%c", __func__, flag);
args_set(args, flag, NULL); args_set(args, flag, NULL);
continue; continue;
} }
if (*found == ':') {
optional_argument = 1;
found++;
}
new = xcalloc(1, sizeof *new); new = xcalloc(1, sizeof *new);
if (*string != '\0') { if (*string != '\0') {
new->type = ARGS_STRING; new->type = ARGS_STRING;
new->string = xstrdup(string); new->string = xstrdup(string);
} else { } else {
if (i == count) { if (i == count) {
if (optional_argument) {
log_debug("%s: -%c", __func__,
flag);
args_set(args, flag, NULL);
continue;
}
xasprintf(cause, xasprintf(cause,
"-%c expects an argument", "-%c expects an argument",
flag); flag);

View File

@ -531,7 +531,7 @@ client_signal(int sig)
if (sig == SIGCHLD) if (sig == SIGCHLD)
waitpid(WAIT_ANY, &status, WNOHANG); waitpid(WAIT_ANY, &status, WNOHANG);
else if (!client_attached) { else if (!client_attached) {
if (sig == SIGTERM) if (sig == SIGTERM || sig == SIGHUP)
proc_exit(client_proc); proc_exit(client_proc);
} else { } else {
switch (sig) { switch (sig) {

View File

@ -31,6 +31,8 @@
#define LIST_CLIENTS_TEMPLATE \ #define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \ "#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}] " \ "[#{client_width}x#{client_height} #{client_termname}] " \
"#{?#{!=:#{client_uid},#{uid}}," \
"[user #{?client_user,#{client_user},#{client_uid},}] ,}" \
"#{?client_flags,(,}#{client_flags}#{?client_flags,),}" "#{?client_flags,(,}#{client_flags}#{?client_flags,),}"
static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *); static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);

View File

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

View File

@ -60,7 +60,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
const char *errstr; const char *errstr;
char *cause; char *cause;
u_int adjust; u_int adjust;
int x, y; int x, y, status;
struct grid *gd = wp->base.grid; struct grid *gd = wp->base.grid;
if (args_has(args, 'T')) { if (args_has(args, 'T')) {
@ -121,6 +121,17 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
free(cause); free(cause);
return (CMD_RETURN_ERROR); 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); layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
} }

View File

@ -102,7 +102,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
name = options_match(argument, &idx, &ambiguous); name = options_match(argument, &idx, &ambiguous);
if (name == NULL) { if (name == NULL) {
if (args_has(args, 'q')) if (args_has(args, 'q'))
goto fail; goto out;
if (ambiguous) if (ambiguous)
cmdq_error(item, "ambiguous option: %s", argument); cmdq_error(item, "ambiguous option: %s", argument);
else else
@ -113,7 +113,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
&cause); &cause);
if (scope == OPTIONS_TABLE_NONE) { if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q')) if (args_has(args, 'q'))
goto fail; goto out;
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
goto fail; 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); cmd_show_options_print(self, item, o, idx, parent);
else if (*name == '@') { else if (*name == '@') {
if (args_has(args, 'q')) if (args_has(args, 'q'))
goto fail; goto out;
cmdq_error(item, "invalid option: %s", argument); cmdq_error(item, "invalid option: %s", argument);
goto fail; goto fail;
} }
out:
free(name); free(name);
free(argument); free(argument);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@ -60,6 +60,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s; struct session *s = target->s;
struct winlink *wl = target->wl; struct winlink *wl = target->wl;
struct window *w = wl->window;
struct window_pane *wp = target->wp, *new_wp; struct window_pane *wp = target->wp, *new_wp;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; 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); cmdq_error(item, "percentage %s", errstr);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
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) if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100; size = (wp->sy * percentage) / 100;
else else
size = (wp->sx * percentage) / 100; size = (wp->sx * percentage) / 100;
}
} else { } else {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause); size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) { if (cause != NULL) {
@ -105,10 +113,17 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
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) if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100; size = (wp->sy * percentage) / 100;
else else
size = (wp->sx * percentage) / 100; size = (wp->sx * percentage) / 100;
}
} else } else
size = -1; size = -1;

View File

@ -128,7 +128,7 @@ colour_tostring(int c)
u_char r, g, b; u_char r, g, b;
if (c == -1) if (c == -1)
return ("invalid"); return ("none");
if (c & COLOUR_FLAG_RGB) { if (c & COLOUR_FLAG_RGB) {
colour_split_rgb(c, &r, &g, &b); colour_split_rgb(c, &r, &g, &b);

View File

@ -334,6 +334,11 @@ char *strndup(const char *, size_t);
void *memmem(const void *, size_t, const void *, size_t); void *memmem(const void *, size_t, const void *, size_t);
#endif #endif
#ifndef HAVE_GETPEEREID
/* getpeereid.c */
int getpeereid(int, uid_t *, gid_t *);
#endif
#ifndef HAVE_DAEMON #ifndef HAVE_DAEMON
/* daemon.c */ /* daemon.c */
int daemon(int, int); int daemon(int, int);
@ -416,6 +421,11 @@ void *reallocarray(void *, size_t, size_t);
void *recallocarray(void *, size_t, size_t, size_t); void *recallocarray(void *, size_t, size_t, size_t);
#endif #endif
#ifdef HAVE_SYSTEMD
/* systemd.c */
int systemd_create_socket(int, char **);
#endif
#ifdef HAVE_UTF8PROC #ifdef HAVE_UTF8PROC
/* utf8proc.c */ /* utf8proc.c */
int utf8proc_wcwidth(wchar_t); int utf8proc_wcwidth(wchar_t);

59
compat/getpeereid.c Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2022 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* 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 <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#ifdef HAVE_UCRED_H
#include <ucred.h>
#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
}

58
compat/systemd.c Normal file
View File

@ -0,0 +1,58 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2022 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* 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 <sys/types.h>
#include <sys/un.h>
#include <systemd/sd-daemon.h>
#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);
}

View File

@ -69,6 +69,11 @@ AC_ARG_ENABLE(
AS_HELP_STRING(--enable-static, create a static build) AS_HELP_STRING(--enable-static, create a static build)
) )
if test "x$enable_static" = xyes; then 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" test "x$PKG_CONFIG" != x && PKG_CONFIG="$PKG_CONFIG --static"
AM_LDFLAGS="-static $AM_LDFLAGS" AM_LDFLAGS="-static $AM_LDFLAGS"
LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS" LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS"
@ -123,6 +128,7 @@ AC_CHECK_HEADERS([ \
sys/dir.h \ sys/dir.h \
sys/ndir.h \ sys/ndir.h \
sys/tree.h \ sys/tree.h \
ucred.h \
util.h \ util.h \
]) ])
@ -141,7 +147,8 @@ AC_CHECK_FUNCS([ \
flock \ flock \
prctl \ prctl \
proc_pidinfo \ proc_pidinfo \
sysconf getpeerucred \
sysconf \
]) ])
# Check for functions with a compatibility implementation. # Check for functions with a compatibility implementation.
@ -155,6 +162,7 @@ AC_REPLACE_FUNCS([ \
freezero \ freezero \
getdtablecount \ getdtablecount \
getdtablesize \ getdtablesize \
getpeereid \
getline \ getline \
getprogname \ getprogname \
memmem \ memmem \
@ -382,6 +390,31 @@ if test "x$enable_utf8proc" = xyes; then
fi fi
AM_CONDITIONAL(HAVE_UTF8PROC, [test "x$enable_utf8proc" = xyes]) 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. # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well.
AC_MSG_CHECKING(for b64_ntop) AC_MSG_CHECKING(for b64_ntop)
AC_LINK_IFELSE([AC_LANG_PROGRAM( AC_LINK_IFELSE([AC_LANG_PROGRAM(
@ -679,6 +712,14 @@ AC_CHECK_DECL(
[#include <sys/prctl.h>] [#include <sys/prctl.h>]
) )
# Look for setsockopt(SO_PEERCRED).
AC_CHECK_DECL(
SO_PEERCRED,
AC_DEFINE(HAVE_SO_PEERCRED),
,
[#include <sys/socket.h>]
)
# Look for fcntl(F_CLOSEM). # Look for fcntl(F_CLOSEM).
AC_CHECK_DECL( AC_CHECK_DECL(
F_CLOSEM, F_CLOSEM,

View File

@ -1154,13 +1154,13 @@ format_trim_right(const char *expanded, u_int limit)
while (*cp != '\0') { while (*cp != '\0') {
if (*cp == '#') { if (*cp == '#') {
end = format_leading_hashes(cp, &n, &leading_width); end = format_leading_hashes(cp, &n, &leading_width);
copy_width = leading_width;
if (width <= skip) { if (width <= skip) {
if (skip - width >= leading_width) if (skip - width >= copy_width)
copy_width = 0; copy_width = 0;
else else
copy_width -= (skip - width); copy_width -= (skip - width);
} else }
copy_width = leading_width;
if (copy_width != 0) { if (copy_width != 0) {
if (n == 1) if (n == 1)
*out++ = '#'; *out++ = '#';

107
format.c
View File

@ -24,6 +24,7 @@
#include <fnmatch.h> #include <fnmatch.h>
#include <libgen.h> #include <libgen.h>
#include <math.h> #include <math.h>
#include <pwd.h>
#include <regex.h> #include <regex.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
@ -1387,6 +1388,35 @@ format_cb_client_tty(struct format_tree *ft)
return (NULL); 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. */ /* Callback for client_utf8. */
static void * static void *
format_cb_client_utf8(struct format_tree *ft) format_cb_client_utf8(struct format_tree *ft)
@ -1650,6 +1680,13 @@ format_cb_mouse_y(struct format_tree *ft)
return (NULL); 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. */ /* Callback for origin_flag. */
static void * static void *
format_cb_origin_flag(struct format_tree *ft) format_cb_origin_flag(struct format_tree *ft)
@ -1719,6 +1756,23 @@ format_cb_pane_dead(struct format_tree *ft)
return (NULL); 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. */ /* Callback for pane_dead_status. */
static void * static void *
format_cb_pane_dead_status(struct format_tree *ft) format_cb_pane_dead_status(struct format_tree *ft)
@ -1733,6 +1787,20 @@ format_cb_pane_dead_status(struct format_tree *ft)
return (NULL); 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. */ /* Callback for pane_format. */
static void * static void *
format_cb_pane_format(struct format_tree *ft) 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)); 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. */ /* Format table type. */
enum format_table_type { enum format_table_type {
FORMAT_TABLE_STRING, FORMAT_TABLE_STRING,
@ -2620,6 +2706,12 @@ static const struct format_table_entry format_table[] = {
{ "client_tty", FORMAT_TABLE_STRING, { "client_tty", FORMAT_TABLE_STRING,
format_cb_client_tty 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, { "client_utf8", FORMAT_TABLE_STRING,
format_cb_client_utf8 format_cb_client_utf8
}, },
@ -2707,6 +2799,9 @@ static const struct format_table_entry format_table[] = {
{ "mouse_y", FORMAT_TABLE_STRING, { "mouse_y", FORMAT_TABLE_STRING,
format_cb_mouse_y format_cb_mouse_y
}, },
{ "next_session_id", FORMAT_TABLE_STRING,
format_cb_next_session_id
},
{ "origin_flag", FORMAT_TABLE_STRING, { "origin_flag", FORMAT_TABLE_STRING,
format_cb_origin_flag format_cb_origin_flag
}, },
@ -2740,9 +2835,15 @@ static const struct format_table_entry format_table[] = {
{ "pane_dead", FORMAT_TABLE_STRING, { "pane_dead", FORMAT_TABLE_STRING,
format_cb_pane_dead format_cb_pane_dead
}, },
{ "pane_dead_signal", FORMAT_TABLE_STRING,
format_cb_pane_dead_signal
},
{ "pane_dead_status", FORMAT_TABLE_STRING, { "pane_dead_status", FORMAT_TABLE_STRING,
format_cb_pane_dead_status format_cb_pane_dead_status
}, },
{ "pane_dead_time", FORMAT_TABLE_TIME,
format_cb_pane_dead_time
},
{ "pane_fg", FORMAT_TABLE_STRING, { "pane_fg", FORMAT_TABLE_STRING,
format_cb_pane_fg format_cb_pane_fg
}, },
@ -2896,6 +2997,12 @@ static const struct format_table_entry format_table[] = {
{ "tree_mode_format", FORMAT_TABLE_STRING, { "tree_mode_format", FORMAT_TABLE_STRING,
format_cb_tree_mode_format format_cb_tree_mode_format
}, },
{ "uid", FORMAT_TABLE_STRING,
format_cb_uid
},
{ "user", FORMAT_TABLE_STRING,
format_cb_user
},
{ "version", FORMAT_TABLE_STRING, { "version", FORMAT_TABLE_STRING,
format_cb_version format_cb_version
}, },

98
grid.c
View File

@ -826,6 +826,56 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values)
return (n); 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) * Returns ANSI code to set particular attributes (colour, bold and so on)
* given a current state. * 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. */ /* If any attribute is removed, begin with 0. */
for (i = 0; i < nitems(attrs); i++) { 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; s[n++] = 0;
lastattr &= GRID_ATTR_CHARSET; lastattr &= GRID_ATTR_CHARSET;
break; break;
@ -897,42 +949,20 @@ grid_string_cells_code(const struct grid_cell *lastgc,
/* If the foreground colour changed, write its parameters. */ /* If the foreground colour changed, write its parameters. */
nnewc = grid_string_cells_fg(gc, newc); nnewc = grid_string_cells_fg(gc, newc);
noldc = grid_string_cells_fg(lastgc, oldc); noldc = grid_string_cells_fg(lastgc, oldc);
if (nnewc != noldc || grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 || escape_c0);
(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);
}
/* If the background colour changed, append its parameters. */ /* If the background colour changed, append its parameters. */
nnewc = grid_string_cells_bg(gc, newc); nnewc = grid_string_cells_bg(gc, newc);
noldc = grid_string_cells_bg(lastgc, oldc); noldc = grid_string_cells_bg(lastgc, oldc);
if (nnewc != noldc || grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 || escape_c0);
(n != 0 && s[0] == 0)) {
if (escape_c0) /* If the underscore colour changed, append its parameters. */
strlcat(buf, "\\033[", len); nnewc = grid_string_cells_us(gc, newc);
else noldc = grid_string_cells_us(lastgc, oldc);
strlcat(buf, "\033[", len); grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
for (i = 0; i < nnewc; i++) { escape_c0);
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);
}
/* Append shift in/shift out if needed. */ /* Append shift in/shift out if needed. */
if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) { 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); gl = grid_peek_line(gd, py);
for (xx = px; xx < px + nx; xx++) { for (xx = px; xx < px + nx; xx++) {
if (gl == NULL || xx >= gl->cellsize) if (gl == NULL || xx >= gl->cellused)
break; break;
grid_get_cell(gd, xx, py, &gc); grid_get_cell(gd, xx, py, &gc);
if (gc.flags & GRID_FLAG_PADDING) if (gc.flags & GRID_FLAG_PADDING)

View File

@ -417,7 +417,7 @@ int
input_key(struct screen *s, struct bufferevent *bev, key_code key) input_key(struct screen *s, struct bufferevent *bev, key_code key)
{ {
struct input_key_entry *ike; struct input_key_entry *ike;
key_code justkey, newkey, outkey; key_code justkey, newkey, outkey, modifiers;
struct utf8_data ud; struct utf8_data ud;
char tmp[64], modifier; 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)); return (input_key(s, bev, key & ~KEYC_CTRL));
} }
outkey = (key & KEYC_MASK_KEY); 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: case KEYC_SHIFT:
modifier = '2'; modifier = '2';
break; 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 (m->sgr_type != ' ') {
if (MOUSE_DRAG(m->sgr_b) && if (MOUSE_DRAG(m->sgr_b) &&
MOUSE_BUTTONS(m->sgr_b) == 3 && MOUSE_RELEASE(m->sgr_b) &&
(~s->mode & MODE_MOUSE_ALL)) (~s->mode & MODE_MOUSE_ALL))
return (0); return (0);
} else { } else {
if (MOUSE_DRAG(m->b) && if (MOUSE_DRAG(m->b) &&
MOUSE_BUTTONS(m->b) == 3 && MOUSE_RELEASE(m->b) &&
MOUSE_BUTTONS(m->lb) == 3 && MOUSE_RELEASE(m->lb) &&
(~s->mode & MODE_MOUSE_ALL)) (~s->mode & MODE_MOUSE_ALL))
return (0); return (0);
} }

55
input.c
View File

@ -2244,11 +2244,13 @@ input_dcs_dispatch(struct input_ctx *ictx)
const u_int prefixlen = (sizeof prefix) - 1; const u_int prefixlen = (sizeof prefix) - 1;
struct sixel_image *si; struct sixel_image *si;
if (wp == NULL)
return (0);
if (ictx->flags & INPUT_DISCARD) if (ictx->flags & INPUT_DISCARD)
return (0); return (0);
if (!options_get_number(ictx->wp->options, "allow-passthrough"))
log_debug("%s: \"%s\" \"%s\" \"%s\"", __func__, buf, ictx->interm_buf, return (0);
ictx->param_buf); log_debug("%s: \"%s\"", __func__, buf);
if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0) if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0)
screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen); 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; struct window_pane *wp = ictx->wp;
char *end; char *end;
const char *buf; const char *buf = NULL;
size_t len; size_t len = 0;
u_char *out; u_char *out;
int outlen, state; int outlen, state;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
@ -2711,26 +2713,12 @@ input_osc_52(struct input_ctx *ictx, const char *p)
log_debug("%s: %s", __func__, end); log_debug("%s: %s", __func__, end);
if (strcmp(end, "?") == 0) { if (strcmp(end, "?") == 0) {
if ((pb = paste_get_top(NULL)) != NULL) { if ((pb = paste_get_top(NULL)) != NULL)
buf = paste_buffer_data(pb, &len); 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) if (ictx->input_end == INPUT_END_BEL)
bufferevent_write(ictx->event, "\007", 1); input_reply_clipboard(ictx->event, buf, len, "\007");
else else
bufferevent_write(ictx->event, "\033\\", 2); input_reply_clipboard(ictx->event, buf, len, "\033\\");
free(out);
return; return;
} }
@ -2788,3 +2776,26 @@ input_osc_104(struct input_ctx *ictx, const char *p)
screen_write_fullredraw(&ictx->ctx); screen_write_fullredraw(&ictx->ctx);
free(copy); 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);
}

3
job.c
View File

@ -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. * if-shell to decide on default-terminal based on outside TERM.
*/ */
env = environ_for_session(s, !cfg_finished); env = environ_for_session(s, !cfg_finished);
if (e != NULL) { if (e != NULL)
environ_copy(e, env); environ_copy(e, env);
}
sigfillset(&set); sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset); sigprocmask(SIG_BLOCK, &set, &oldset);

View File

@ -492,6 +492,7 @@ key_bindings_init(void)
"bind -Tcopy-mode \\; { send -X jump-again }", "bind -Tcopy-mode \\; { send -X jump-again }",
"bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }", "bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }",
"bind -Tcopy-mode N { send -X search-reverse }", "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 R { send -X rectangle-toggle }",
"bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }", "bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }",
"bind -Tcopy-mode X { send -X set-mark }", "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 L { send -X bottom-line }",
"bind -Tcopy-mode-vi M { send -X middle-line }", "bind -Tcopy-mode-vi M { send -X middle-line }",
"bind -Tcopy-mode-vi N { send -X search-reverse }", "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 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 V { send -X select-line }",
"bind -Tcopy-mode-vi W { send -X next-space }", "bind -Tcopy-mode-vi W { send -X next-space }",

View File

@ -91,26 +91,68 @@ static const struct {
KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1), KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1),
KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2), KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2),
KEYC_MOUSE_STRING(MOUSEDOWN3, MouseDown3), 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(MOUSEUP1, MouseUp1),
KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2), KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2),
KEYC_MOUSE_STRING(MOUSEUP3, MouseUp3), 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(MOUSEDRAG1, MouseDrag1),
KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2), KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2),
KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3), 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(MOUSEDRAGEND1, MouseDragEnd1),
KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2), KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2),
KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3), 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(WHEELUP, WheelUp),
KEYC_MOUSE_STRING(WHEELDOWN, WheelDown), KEYC_MOUSE_STRING(WHEELDOWN, WheelDown),
KEYC_MOUSE_STRING(SECONDCLICK1, SecondClick1), KEYC_MOUSE_STRING(SECONDCLICK1, SecondClick1),
KEYC_MOUSE_STRING(SECONDCLICK2, SecondClick2), KEYC_MOUSE_STRING(SECONDCLICK2, SecondClick2),
KEYC_MOUSE_STRING(SECONDCLICK3, SecondClick3), 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(DOUBLECLICK1, DoubleClick1),
KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2), KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2),
KEYC_MOUSE_STRING(DOUBLECLICK3, DoubleClick3), 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(TRIPLECLICK1, TripleClick1),
KEYC_MOUSE_STRING(TRIPLECLICK2, TripleClick2), KEYC_MOUSE_STRING(TRIPLECLICK2, TripleClick2),
KEYC_MOUSE_STRING(TRIPLECLICK3, TripleClick3), 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. */ /* Find key string in table. */

6
menu.c
View File

@ -235,7 +235,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
if (KEYC_IS_MOUSE(event->key)) { if (KEYC_IS_MOUSE(event->key)) {
if (md->flags & MENU_NOMOUSE) { if (md->flags & MENU_NOMOUSE) {
if (MOUSE_BUTTONS(m->b) != 0) if (MOUSE_BUTTONS(m->b) != MOUSE_BUTTON_1)
return (1); return (1);
return (0); return (0);
} }
@ -248,7 +248,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
return (1); return (1);
} else { } else {
if (!MOUSE_RELEASE(m->b) && if (!MOUSE_RELEASE(m->b) &&
MOUSE_WHEEL(m->b) == 0 && !MOUSE_WHEEL(m->b) &&
!MOUSE_DRAG(m->b)) !MOUSE_DRAG(m->b))
return (1); return (1);
} }
@ -262,7 +262,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
if (MOUSE_RELEASE(m->b)) if (MOUSE_RELEASE(m->b))
goto chosen; goto chosen;
} else { } else {
if (MOUSE_WHEEL(m->b) == 0 && !MOUSE_DRAG(m->b)) if (!MOUSE_WHEEL(m->b) && !MOUSE_DRAG(m->b))
goto chosen; goto chosen;
} }
md->choice = m->y - (md->py + 1); md->choice = m->y - (md->py + 1);

View File

@ -104,7 +104,6 @@ struct mode_tree_menu {
struct mode_tree_data *data; struct mode_tree_data *data;
struct client *c; struct client *c;
u_int line; u_int line;
void *itemdata;
}; };
static void mode_tree_free_items(struct mode_tree_list *); static void mode_tree_free_items(struct mode_tree_list *);
@ -911,16 +910,12 @@ mode_tree_menu_callback(__unused struct menu *menu, __unused u_int idx,
{ {
struct mode_tree_menu *mtm = data; struct mode_tree_menu *mtm = data;
struct mode_tree_data *mtd = mtm->data; struct mode_tree_data *mtd = mtm->data;
struct mode_tree_item *mti;
if (mtd->dead || key == KEYC_NONE) if (mtd->dead || key == KEYC_NONE)
goto out; goto out;
if (mtm->line >= mtd->line_size) if (mtm->line >= mtd->line_size)
goto out; goto out;
mti = mtd->line_list[mtm->line].item;
if (mti->itemdata != mtm->itemdata)
goto out;
mtd->current = mtm->line; mtd->current = mtm->line;
mtd->menucb(mtd->modedata, mtm->c, key); 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(""); title = xstrdup("");
} }
menu = menu_create(title); menu = menu_create(title);
menu_add_items(menu, items, NULL, NULL, NULL); menu_add_items(menu, items, NULL, c, NULL);
free(title); free(title);
mtm = xmalloc(sizeof *mtm); mtm = xmalloc(sizeof *mtm);
mtm->data = mtd; mtm->data = mtd;
mtm->c = c; mtm->c = c;
mtm->line = line; mtm->line = line;
mtm->itemdata = mti->itemdata;
mtd->references++; mtd->references++;
if (x >= (menu->width + 4) / 2) if (x >= (menu->width + 4) / 2)

View File

@ -34,18 +34,37 @@ struct notify_entry {
int pane; 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 static void
notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne) notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
{ {
struct cmd_find_state fs; struct cmd_find_state fs;
struct options *oo; struct options *oo;
struct cmdq_item *new_item; struct cmdq_state *state;
struct cmdq_state *new_state;
struct options_entry *o; struct options_entry *o;
struct options_array_item *a; struct options_array_item *a;
struct cmd_list *cmdlist; 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); cmd_find_clear_state(&fs, 0);
if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs)) 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; oo = fs.wl->window->options;
o = options_get(oo, ne->name); o = options_get(oo, ne->name);
} }
if (o == NULL) if (o == NULL) {
log_debug("%s: hook %s not found", __func__, ne->name);
return; return;
}
new_state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS); state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS);
cmdq_add_formats(new_state, ne->formats); 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); a = options_array_first(o);
while (a != NULL) { while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist; cmdlist = options_array_item_value(a)->cmdlist;
if (cmdlist != NULL) { item = notify_insert_one_hook(item, ne, cmdlist, state);
new_item = cmdq_get_command(cmdlist, new_state);
item = cmdq_insert_after(item, new_item);
}
a = options_array_next(a); a = options_array_next(a);
} }
}
cmdq_free_state(new_state); cmdq_free_state(state);
} }
static enum cmd_retval static enum cmd_retval

View File

@ -63,6 +63,9 @@ static const char *options_table_cursor_style_list[] = {
static const char *options_table_pane_status_list[] = { static const char *options_table_pane_status_list[] = {
"off", "top", "bottom", NULL "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[] = { static const char *options_table_pane_border_lines_list[] = {
"single", "double", "heavy", "simple", "number", NULL "single", "double", "heavy", "simple", "number", NULL
}; };
@ -274,6 +277,7 @@ const struct options_table_entry options_table[] = {
.minimum = 0, .minimum = 0,
.maximum = INT_MAX, .maximum = INT_MAX,
.default_num = 500, .default_num = 500,
.unit = "milliseconds",
.text = "Time to wait before assuming a key is Escape." .text = "Time to wait before assuming a key is Escape."
}, },
@ -797,6 +801,14 @@ const struct options_table_entry options_table[] = {
"linked to ('off')." "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", { .name = "allow-rename",
.type = OPTIONS_TABLE_FLAG, .type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .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." .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", { .name = "main-pane-height",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@ -964,12 +983,21 @@ const struct options_table_entry options_table[] = {
{ .name = "pane-border-format", { .name = "pane-border-format",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] " .default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] "
"\"#{pane_title}\"", "\"#{pane_title}\"",
.text = "Format of text in the pane status lines." .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", { .name = "pane-border-lines",
.type = OPTIONS_TABLE_CHOICE, .type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@ -1040,6 +1068,27 @@ const struct options_table_entry options_table[] = {
"killed ('off' or 'failed') when the program inside exits." "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", { .name = "synchronize-panes",
.type = OPTIONS_TABLE_FLAG, .type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
@ -1225,6 +1274,7 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_HOOK("window-linked", ""), OPTIONS_TABLE_HOOK("window-linked", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-pane-changed", ""), OPTIONS_TABLE_WINDOW_HOOK("window-pane-changed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-renamed", ""), OPTIONS_TABLE_WINDOW_HOOK("window-renamed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-resized", ""),
OPTIONS_TABLE_HOOK("window-unlinked", ""), OPTIONS_TABLE_HOOK("window-unlinked", ""),
{ .name = NULL } { .name = NULL }

View File

@ -1108,6 +1108,8 @@ options_push_changes(const char *name)
struct window_pane *wp; struct window_pane *wp;
int c; int c;
log_debug("%s: %s", __func__, name);
if (strcmp(name, "automatic-rename") == 0) { if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) { RB_FOREACH(w, windows, &windows) {
if (w->active == NULL) if (w->active == NULL)
@ -1130,6 +1132,10 @@ options_push_changes(const char *name)
&wp->screen->default_mode); &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) { if (strcmp(name, "key-table") == 0) {
TAILQ_FOREACH(loop, &clients, entry) TAILQ_FOREACH(loop, &clients, entry)
server_client_set_key_table(loop, NULL); server_client_set_key_table(loop, NULL);

View File

@ -35,9 +35,6 @@
((p)->p_stat == SSTOP || (p)->p_stat == SZOMB) ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB)
struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *); 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 * struct kinfo_proc2 *
cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2) cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2)

View File

@ -16,7 +16,6 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <sys/param.h> /* MAXCOMLEN */
#include <sys/types.h> #include <sys/types.h>
#include <sys/signal.h> #include <sys/signal.h>
#include <sys/proc.h> #include <sys/proc.h>
@ -142,7 +141,7 @@ char *
osdep_get_cwd(int fd) osdep_get_cwd(int fd)
{ {
int name[] = { CTL_KERN, KERN_PROC_CWD, 0 }; int name[] = { CTL_KERN, KERN_PROC_CWD, 0 };
static char path[MAXPATHLEN]; static char path[PATH_MAX];
size_t pathlen = sizeof path; size_t pathlen = sizeof path;
if ((name[2] = tcgetpgrp(fd)) == -1) if ((name[2] = tcgetpgrp(fd)) == -1)

15
popup.c
View File

@ -508,7 +508,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
m->x > pd->px + pd->sx - 1 || m->x > pd->px + pd->sx - 1 ||
m->y < pd->py || m->y < pd->py ||
m->y > pd->py + pd->sy - 1) { m->y > pd->py + pd->sy - 1) {
if (MOUSE_BUTTONS(m->b) == 2) if (MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3)
goto menu; goto menu;
return (0); return (0);
} }
@ -523,16 +523,16 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
border = BOTTOM; border = BOTTOM;
} }
if ((m->b & MOUSE_MASK_MODIFIERS) == 0 && if ((m->b & MOUSE_MASK_MODIFIERS) == 0 &&
MOUSE_BUTTONS(m->b) == 2 && MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3 &&
(border == LEFT || border == TOP)) (border == LEFT || border == TOP))
goto menu; goto menu;
if (((m->b & MOUSE_MASK_MODIFIERS) == MOUSE_MASK_META) || if (((m->b & MOUSE_MASK_MODIFIERS) == MOUSE_MASK_META) ||
border != NONE) { border != NONE) {
if (!MOUSE_DRAG(m->b)) if (!MOUSE_DRAG(m->b))
goto out; goto out;
if (MOUSE_BUTTONS(m->lb) == 0) if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_1)
pd->dragging = MOVE; pd->dragging = MOVE;
else if (MOUSE_BUTTONS(m->lb) == 2) else if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_3)
pd->dragging = SIZE; pd->dragging = SIZE;
pd->dx = m->lx - pd->px; pd->dx = m->lx - pd->px;
pd->dy = m->ly - pd->py; pd->dy = m->ly - pd->py;
@ -565,10 +565,10 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
menu: menu:
pd->menu = menu_create(""); pd->menu = menu_create("");
if (pd->flags & POPUP_INTERNAL) { 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); NULL);
} else } 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) if (m->x >= (pd->menu->width + 4) / 2)
x = m->x - (pd->menu->width + 4) / 2; x = m->x - (pd->menu->width + 4) / 2;
else else
@ -667,6 +667,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
pd = xcalloc(1, sizeof *pd); pd = xcalloc(1, sizeof *pd);
pd->item = item; pd->item = item;
pd->flags = flags; pd->flags = flags;
if (title != NULL)
pd->title = xstrdup(title); pd->title = xstrdup(title);
pd->c = c; pd->c = c;
@ -688,7 +689,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
} }
pd->border_cell.attr = 0; 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_init(&pd->palette);
colour_palette_from_option(&pd->palette, global_w_options); colour_palette_from_option(&pd->palette, global_w_options);

11
proc.c
View File

@ -56,6 +56,7 @@ struct tmuxpeer {
struct imsgbuf ibuf; struct imsgbuf ibuf;
struct event event; struct event event;
uid_t uid;
int flags; int flags;
#define PEER_BAD 0x1 #define PEER_BAD 0x1
@ -308,6 +309,7 @@ proc_add_peer(struct tmuxproc *tp, int fd,
void (*dispatchcb)(struct imsg *, void *), void *arg) void (*dispatchcb)(struct imsg *, void *), void *arg)
{ {
struct tmuxpeer *peer; struct tmuxpeer *peer;
gid_t gid;
peer = xcalloc(1, sizeof *peer); peer = xcalloc(1, sizeof *peer);
peer->parent = tp; peer->parent = tp;
@ -318,6 +320,9 @@ proc_add_peer(struct tmuxproc *tp, int fd,
imsg_init(&peer->ibuf, fd); imsg_init(&peer->ibuf, fd);
event_set(&peer->event, fd, EV_READ, proc_event_cb, peer); 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); log_debug("add peer %p: %d (%p)", peer, fd, arg);
TAILQ_INSERT_TAIL(&tp->peers, peer, entry); TAILQ_INSERT_TAIL(&tp->peers, peer, entry);
@ -373,3 +378,9 @@ proc_fork_and_daemon(int *fd)
return (pid); return (pid);
} }
} }
uid_t
proc_get_peer_uid(struct tmuxpeer *peer)
{
return (peer->uid);
}

View File

@ -61,6 +61,7 @@ resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
tty_update_window_offset(w); tty_update_window_offset(w);
server_redraw_window(w); server_redraw_window(w);
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
notify_window("window-resized", w);
w->flags &= ~WINDOW_RESIZE; w->flags &= ~WINDOW_RESIZE;
} }
@ -178,7 +179,7 @@ clients_calculate_size(int type, int current, struct client *c,
cw = NULL; cw = NULL;
/* Work out this client's size. */ /* Work out this client's size. */
if (cw != NULL) { if (cw != NULL && cw->sx != 0 && cw->sy != 0) {
cx = cw->sx; cx = cw->sx;
cy = cw->sy; cy = cw->sy;
} else { } else {

View File

@ -34,19 +34,29 @@ static void screen_redraw_set_context(struct client *,
#define START_ISOLATE "\342\201\246" #define START_ISOLATE "\342\201\246"
#define END_ISOLATE "\342\201\251" #define END_ISOLATE "\342\201\251"
/* Border in relation to a pane. */
enum screen_redraw_border_type { enum screen_redraw_border_type {
SCREEN_REDRAW_OUTSIDE, SCREEN_REDRAW_OUTSIDE,
SCREEN_REDRAW_INSIDE, 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. */ /* Get cell border character. */
static void static void
screen_redraw_border_set(struct window_pane *wp, enum pane_lines pane_lines, screen_redraw_border_set(struct window *w, struct window_pane *wp,
int cell_type, struct grid_cell *gc) enum pane_lines pane_lines, int cell_type, struct grid_cell *gc)
{ {
u_int idx; u_int idx;
if (cell_type == CELL_OUTSIDE && w->fill_character != NULL) {
utf8_copy(&gc->data, &w->fill_character[0]);
return;
}
switch (pane_lines) { switch (pane_lines) {
case PANE_LINES_NUMBER: case PANE_LINES_NUMBER:
if (cell_type == CELL_OUTSIDE) { 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, screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py,
int pane_status) int pane_status)
{ {
struct options *oo = wp->window->options;
int split = 0;
u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy; u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
/* Inside pane. */ /* Inside pane. */
if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey) if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
return (SCREEN_REDRAW_INSIDE); 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. */ /* Left/right borders. */
if (pane_status == PANE_STATUS_OFF) { 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) if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_RIGHT);
if (wp->xoff != 0 && if (wp->xoff != 0 &&
px == wp->xoff - 1 && px == wp->xoff - 1 &&
py > wp->sy / 2) py > wp->sy / 2)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_LEFT);
} else { } else {
if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
if (wp->xoff != 0 && px == wp->xoff - 1) if (wp->xoff != 0 && px == wp->xoff - 1)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_LEFT);
if (px == ex) if (px == ex)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_RIGHT);
} }
} }
} else { } else {
if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) { if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
if (wp->xoff != 0 && px == wp->xoff - 1) if (wp->xoff != 0 && px == wp->xoff - 1)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_LEFT);
if (px == ex) if (px == ex)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_RIGHT);
} }
} }
/* Top/bottom borders. */ /* Top/bottom borders. */
if (pane_status == PANE_STATUS_OFF) { 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) if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_BOTTOM);
if (wp->yoff != 0 && if (wp->yoff != 0 &&
py == wp->yoff - 1 && py == wp->yoff - 1 &&
px > wp->sx / 2) px > wp->sx / 2)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_TOP);
} else { } else {
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
if (wp->yoff != 0 && py == wp->yoff - 1) if (wp->yoff != 0 && py == wp->yoff - 1)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_TOP);
if (py == ey) if (py == ey)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_BOTTOM);
} }
} }
} else if (pane_status == PANE_STATUS_TOP) { } else if (pane_status == PANE_STATUS_TOP) {
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
if (wp->yoff != 0 && py == wp->yoff - 1) if (wp->yoff != 0 && py == wp->yoff - 1)
return (SCREEN_REDRAW_BORDER); return (SCREEN_REDRAW_BORDER_TOP);
} }
} else { } else {
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) { if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
if (py == ey) 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)) { switch (screen_redraw_pane_border(wp, px, py, pane_status)) {
case SCREEN_REDRAW_INSIDE: case SCREEN_REDRAW_INSIDE:
return (0); return (0);
case SCREEN_REDRAW_BORDER:
return (1);
case SCREEN_REDRAW_OUTSIDE: case SCREEN_REDRAW_OUTSIDE:
break; 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; enum screen_redraw_border_type border;
border = screen_redraw_pane_border(wp, px, py, pane_status); 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 (1);
return (0); 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); style_apply(&gc, w->options, "pane-active-border-style", ft);
else else
style_apply(&gc, w->options, "pane-border-style", ft); 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); expanded = format_expand_time(ft, fmt);
if (wp->sx < 4) if (wp->sx < 4)
@ -394,7 +414,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
else else
py = wp->yoff + wp->sy; py = wp->yoff + wp->sy;
cell_type = screen_redraw_type_of_cell(c, px, py, pane_status); 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); screen_write_cell(&ctx, &gc);
} }
gc.attr &= ~GRID_ATTR_CHARSET; 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 options *oo = w->options;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct format_tree *ft; struct format_tree *ft;
struct window_pane *wp; struct window_pane *wp, *active = server_client_get_pane(c);
struct grid_cell gc; struct grid_cell gc;
const struct grid_cell *tmp; const struct grid_cell *tmp;
struct overlay_ranges r; struct overlay_ranges r;
u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; u_int cell_type, x = ctx->ox + i, y = ctx->oy + j;
int arrows = 0, border;
int pane_status = ctx->pane_status, isolates; int pane_status = ctx->pane_status, isolates;
if (c->overlay_check != NULL) { 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)) screen_redraw_check_is(x, y, pane_status, marked_pane.wp))
gc.attr ^= GRID_ATTR_REVERSE; 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 && if (cell_type == CELL_TOPBOTTOM &&
(c->flags & CLIENT_UTF8) && (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); tty_cursor(tty, i, j);
if (isolates) if (isolates)
tty_puts(tty, END_ISOLATE); 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); tty_cell(tty, &gc, &grid_default_cell, NULL);
if (isolates) if (isolates)
tty_puts(tty, START_ISOLATE); tty_puts(tty, START_ISOLATE);

View File

@ -1476,7 +1476,11 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
ttyctx.bg = bg; ttyctx.bg = bg;
/* Scroll into history if it is enabled and clearing entire screen. */ /* 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); grid_view_clear_history(gd, bg);
else { else {
if (s->cx <= sx - 1) if (s->cx <= sx - 1)
@ -1530,7 +1534,9 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
ttyctx.bg = bg; ttyctx.bg = bg;
/* Scroll into history if it is enabled. */ /* 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); grid_view_clear_history(s->grid, bg);
else else
grid_view_clear(s->grid, 0, 0, sx, sy, bg); grid_view_clear(s->grid, 0, 0, sx, sy, bg);

View File

@ -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_redraw(struct client *);
static void server_client_check_modes(struct client *); static void server_client_check_modes(struct client *);
static void server_client_set_title(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 void server_client_reset_state(struct client *);
static int server_client_assume_paste(struct session *); static int server_client_assume_paste(struct session *);
static void server_client_update_latest(struct client *); static void server_client_update_latest(struct client *);
@ -422,6 +423,7 @@ server_client_lost(struct client *c)
if (c->flags & CLIENT_TERMINAL) if (c->flags & CLIENT_TERMINAL)
tty_free(&c->tty); tty_free(&c->tty);
free(c->ttyname); free(c->ttyname);
free(c->clipboard_panes);
free(c->term_name); free(c->term_name);
free(c->term_type); 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); log_debug("double-click at %u,%u", x, y);
} else if ((m->sgr_type != ' ' && } else if ((m->sgr_type != ' ' &&
MOUSE_DRAG(m->sgr_b) && MOUSE_DRAG(m->sgr_b) &&
MOUSE_BUTTONS(m->sgr_b) == 3) || MOUSE_RELEASE(m->sgr_b)) ||
(m->sgr_type == ' ' && (m->sgr_type == ' ' &&
MOUSE_DRAG(m->b) && MOUSE_DRAG(m->b) &&
MOUSE_BUTTONS(m->b) == 3 && MOUSE_RELEASE(m->b) &&
MOUSE_BUTTONS(m->lb) == 3)) { MOUSE_RELEASE(m->lb))) {
type = MOVE; type = MOVE;
x = m->x, y = m->y, b = 0; x = m->x, y = m->y, b = 0;
log_debug("move at %u,%u", x, y); log_debug("move at %u,%u", x, y);
@ -750,7 +752,7 @@ have_event:
m->wp = -1; m->wp = -1;
/* Stop dragging if needed. */ /* 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) if (c->tty.mouse_drag_release != NULL)
c->tty.mouse_drag_release(c, m); c->tty.mouse_drag_release(c, m);
@ -761,8 +763,8 @@ have_event:
* End a mouse drag by passing a MouseDragEnd key corresponding * End a mouse drag by passing a MouseDragEnd key corresponding
* to the button that started the drag. * to the button that started the drag.
*/ */
switch (c->tty.mouse_drag_flag) { switch (c->tty.mouse_drag_flag - 1) {
case 1: case MOUSE_BUTTON_1:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEDRAGEND1_PANE; key = KEYC_MOUSEDRAGEND1_PANE;
if (where == STATUS) if (where == STATUS)
@ -776,7 +778,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAGEND1_BORDER; key = KEYC_MOUSEDRAGEND1_BORDER;
break; break;
case 2: case MOUSE_BUTTON_2:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEDRAGEND2_PANE; key = KEYC_MOUSEDRAGEND2_PANE;
if (where == STATUS) if (where == STATUS)
@ -790,7 +792,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAGEND2_BORDER; key = KEYC_MOUSEDRAGEND2_BORDER;
break; break;
case 3: case MOUSE_BUTTON_3:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEDRAGEND3_PANE; key = KEYC_MOUSEDRAGEND3_PANE;
if (where == STATUS) if (where == STATUS)
@ -804,6 +806,90 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAGEND3_BORDER; key = KEYC_MOUSEDRAGEND3_BORDER;
break; 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: default:
key = KEYC_MOUSE; key = KEYC_MOUSE;
break; break;
@ -836,7 +922,7 @@ have_event:
key = KEYC_DRAGGING; key = KEYC_DRAGGING;
else { else {
switch (MOUSE_BUTTONS(b)) { switch (MOUSE_BUTTONS(b)) {
case 0: case MOUSE_BUTTON_1:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEDRAG1_PANE; key = KEYC_MOUSEDRAG1_PANE;
if (where == STATUS) if (where == STATUS)
@ -850,7 +936,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAG1_BORDER; key = KEYC_MOUSEDRAG1_BORDER;
break; break;
case 1: case MOUSE_BUTTON_2:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEDRAG2_PANE; key = KEYC_MOUSEDRAG2_PANE;
if (where == STATUS) if (where == STATUS)
@ -864,7 +950,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAG2_BORDER; key = KEYC_MOUSEDRAG2_BORDER;
break; break;
case 2: case MOUSE_BUTTON_3:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEDRAG3_PANE; key = KEYC_MOUSEDRAG3_PANE;
if (where == STATUS) if (where == STATUS)
@ -878,6 +964,90 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDRAG3_BORDER; key = KEYC_MOUSEDRAG3_BORDER;
break; 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; break;
case UP: case UP:
switch (MOUSE_BUTTONS(b)) { switch (MOUSE_BUTTONS(b)) {
case 0: case MOUSE_BUTTON_1:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEUP1_PANE; key = KEYC_MOUSEUP1_PANE;
if (where == STATUS) if (where == STATUS)
@ -932,7 +1102,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEUP1_BORDER; key = KEYC_MOUSEUP1_BORDER;
break; break;
case 1: case MOUSE_BUTTON_2:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEUP2_PANE; key = KEYC_MOUSEUP2_PANE;
if (where == STATUS) if (where == STATUS)
@ -946,7 +1116,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEUP2_BORDER; key = KEYC_MOUSEUP2_BORDER;
break; break;
case 2: case MOUSE_BUTTON_3:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEUP3_PANE; key = KEYC_MOUSEUP3_PANE;
if (where == STATUS) if (where == STATUS)
@ -960,11 +1130,95 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEUP3_BORDER; key = KEYC_MOUSEUP3_BORDER;
break; 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; break;
case DOWN: case DOWN:
switch (MOUSE_BUTTONS(b)) { switch (MOUSE_BUTTONS(b)) {
case 0: case MOUSE_BUTTON_1:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEDOWN1_PANE; key = KEYC_MOUSEDOWN1_PANE;
if (where == STATUS) if (where == STATUS)
@ -978,7 +1232,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDOWN1_BORDER; key = KEYC_MOUSEDOWN1_BORDER;
break; break;
case 1: case MOUSE_BUTTON_2:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEDOWN2_PANE; key = KEYC_MOUSEDOWN2_PANE;
if (where == STATUS) if (where == STATUS)
@ -992,7 +1246,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDOWN2_BORDER; key = KEYC_MOUSEDOWN2_BORDER;
break; break;
case 2: case MOUSE_BUTTON_3:
if (where == PANE) if (where == PANE)
key = KEYC_MOUSEDOWN3_PANE; key = KEYC_MOUSEDOWN3_PANE;
if (where == STATUS) if (where == STATUS)
@ -1006,11 +1260,95 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_MOUSEDOWN3_BORDER; key = KEYC_MOUSEDOWN3_BORDER;
break; 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; break;
case SECOND: case SECOND:
switch (MOUSE_BUTTONS(b)) { switch (MOUSE_BUTTONS(b)) {
case 0: case MOUSE_BUTTON_1:
if (where == PANE) if (where == PANE)
key = KEYC_SECONDCLICK1_PANE; key = KEYC_SECONDCLICK1_PANE;
if (where == STATUS) if (where == STATUS)
@ -1024,7 +1362,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_SECONDCLICK1_BORDER; key = KEYC_SECONDCLICK1_BORDER;
break; break;
case 1: case MOUSE_BUTTON_2:
if (where == PANE) if (where == PANE)
key = KEYC_SECONDCLICK2_PANE; key = KEYC_SECONDCLICK2_PANE;
if (where == STATUS) if (where == STATUS)
@ -1038,7 +1376,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_SECONDCLICK2_BORDER; key = KEYC_SECONDCLICK2_BORDER;
break; break;
case 2: case MOUSE_BUTTON_3:
if (where == PANE) if (where == PANE)
key = KEYC_SECONDCLICK3_PANE; key = KEYC_SECONDCLICK3_PANE;
if (where == STATUS) if (where == STATUS)
@ -1052,11 +1390,95 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_SECONDCLICK3_BORDER; key = KEYC_SECONDCLICK3_BORDER;
break; 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; break;
case DOUBLE: case DOUBLE:
switch (MOUSE_BUTTONS(b)) { switch (MOUSE_BUTTONS(b)) {
case 0: case MOUSE_BUTTON_1:
if (where == PANE) if (where == PANE)
key = KEYC_DOUBLECLICK1_PANE; key = KEYC_DOUBLECLICK1_PANE;
if (where == STATUS) if (where == STATUS)
@ -1070,7 +1492,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_DOUBLECLICK1_BORDER; key = KEYC_DOUBLECLICK1_BORDER;
break; break;
case 1: case MOUSE_BUTTON_2:
if (where == PANE) if (where == PANE)
key = KEYC_DOUBLECLICK2_PANE; key = KEYC_DOUBLECLICK2_PANE;
if (where == STATUS) if (where == STATUS)
@ -1084,7 +1506,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_DOUBLECLICK2_BORDER; key = KEYC_DOUBLECLICK2_BORDER;
break; break;
case 2: case MOUSE_BUTTON_3:
if (where == PANE) if (where == PANE)
key = KEYC_DOUBLECLICK3_PANE; key = KEYC_DOUBLECLICK3_PANE;
if (where == STATUS) if (where == STATUS)
@ -1098,11 +1520,95 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_DOUBLECLICK3_BORDER; key = KEYC_DOUBLECLICK3_BORDER;
break; 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; break;
case TRIPLE: case TRIPLE:
switch (MOUSE_BUTTONS(b)) { switch (MOUSE_BUTTONS(b)) {
case 0: case MOUSE_BUTTON_1:
if (where == PANE) if (where == PANE)
key = KEYC_TRIPLECLICK1_PANE; key = KEYC_TRIPLECLICK1_PANE;
if (where == STATUS) if (where == STATUS)
@ -1116,7 +1622,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_TRIPLECLICK1_BORDER; key = KEYC_TRIPLECLICK1_BORDER;
break; break;
case 1: case MOUSE_BUTTON_2:
if (where == PANE) if (where == PANE)
key = KEYC_TRIPLECLICK2_PANE; key = KEYC_TRIPLECLICK2_PANE;
if (where == STATUS) if (where == STATUS)
@ -1130,7 +1636,7 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_TRIPLECLICK2_BORDER; key = KEYC_TRIPLECLICK2_BORDER;
break; break;
case 2: case MOUSE_BUTTON_3:
if (where == PANE) if (where == PANE)
key = KEYC_TRIPLECLICK3_PANE; key = KEYC_TRIPLECLICK3_PANE;
if (where == STATUS) if (where == STATUS)
@ -1144,6 +1650,90 @@ have_event:
if (where == BORDER) if (where == BORDER)
key = KEYC_TRIPLECLICK3_BORDER; key = KEYC_TRIPLECLICK3_BORDER;
break; 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; break;
} }
@ -2011,8 +2601,10 @@ server_client_check_redraw(struct client *c)
} }
if (c->flags & CLIENT_ALLREDRAWFLAGS) { 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_title(c);
server_client_set_path(c);
}
screen_redraw_screen(c); screen_redraw_screen(c);
} }
@ -2058,6 +2650,26 @@ server_client_set_title(struct client *c)
format_free(ft); 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. */ /* Dispatch message from client. */
static void static void
server_client_dispatch(struct imsg *imsg, void *arg) server_client_dispatch(struct imsg *imsg, void *arg)

View File

@ -310,9 +310,11 @@ server_destroy_pane(struct window_pane *wp, int notify)
struct window *w = wp->window; struct window *w = wp->window;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct grid_cell gc; struct grid_cell gc;
time_t t;
char tim[26];
int remain_on_exit; 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) { if (wp->fd != -1) {
#ifdef HAVE_UTEMPTER #ifdef HAVE_UTEMPTER
@ -339,32 +341,26 @@ server_destroy_pane(struct window_pane *wp, int notify)
return; return;
wp->flags |= PANE_STATUSDRAWN; wp->flags |= PANE_STATUSDRAWN;
gettimeofday(&wp->dead_time, NULL);
if (notify) if (notify)
notify_pane("pane-died", wp); notify_pane("pane-died", wp);
s = options_get_string(wp->options, "remain-on-exit-format");
if (*s != '\0') {
screen_write_start_pane(&ctx, wp, &wp->base); screen_write_start_pane(&ctx, wp, &wp->base);
screen_write_scrollregion(&ctx, 0, screen_size_y(ctx.s) - 1); screen_write_scrollregion(&ctx, 0, sy - 1);
screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1, 0); screen_write_cursormove(&ctx, 0, sy - 1, 0);
screen_write_linefeed(&ctx, 1, 8); screen_write_linefeed(&ctx, 1, 8);
memcpy(&gc, &grid_default_cell, sizeof gc); memcpy(&gc, &grid_default_cell, sizeof gc);
time(&t); expanded = format_single(NULL, s, NULL, NULL, NULL, wp);
ctime_r(&t, tim); format_draw(&ctx, &gc, sx, expanded, NULL, 0);
tim[strcspn(tim, "\n")] = '\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); screen_write_stop(&ctx);
}
wp->base.mode &= ~MODE_CURSOR;
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
return; return;
} }

View File

@ -100,7 +100,7 @@ server_check_marked(void)
} }
/* Create server socket. */ /* Create server socket. */
static int int
server_create_socket(int flags, char **cause) server_create_socket(int flags, char **cause)
{ {
struct sockaddr_un sa; struct sockaddr_un sa;
@ -214,7 +214,11 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
gettimeofday(&start_time, NULL); gettimeofday(&start_time, NULL);
#ifdef HAVE_SYSTEMD
server_fd = systemd_create_socket(flags, &cause);
#else
server_fd = server_create_socket(flags, &cause); server_fd = server_create_socket(flags, &cause);
#endif
if (server_fd != -1) if (server_fd != -1)
server_update_socket(); server_update_socket();
if (~flags & CLIENT_NOFORK) if (~flags & CLIENT_NOFORK)
@ -230,10 +234,12 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
if (cause != NULL) { if (cause != NULL) {
if (c != NULL) { if (c != NULL) {
cmdq_append(c, cmdq_get_error(cause)); c->exit_message = cause;
c->flags |= CLIENT_EXIT; c->flags |= CLIENT_EXIT;
} else {
fprintf(stderr, "%s\n", cause);
exit(1);
} }
free(cause);
} }
evtimer_set(&server_ev_tidy, server_tidy_event, NULL); evtimer_set(&server_ev_tidy, server_tidy_event, NULL);

View File

@ -27,7 +27,7 @@
#include "tmux.h" #include "tmux.h"
struct sessions sessions; struct sessions sessions;
static u_int next_session_id; u_int next_session_id;
struct session_groups session_groups = RB_INITIALIZER(&session_groups); struct session_groups session_groups = RB_INITIALIZER(&session_groups);
static void session_free(int, short, void *); static void session_free(int, short, void *);
@ -501,6 +501,7 @@ session_set_current(struct session *s, struct winlink *wl)
winlink_stack_push(&s->lastw, s->curw); winlink_stack_push(&s->lastw, s->curw);
s->curw = wl; s->curw = wl;
if (options_get_number(global_options, "focus-events")) { if (options_get_number(global_options, "focus-events")) {
if (old != NULL)
window_update_focus(old->window); window_update_focus(old->window);
window_update_focus(wl->window); window_update_focus(wl->window);
} }

View File

@ -554,7 +554,7 @@ sixel_to_screen(struct sixel_image *si)
grid_view_set_cell(s->grid, x, y, &gc); grid_view_set_cell(s->grid, x, y, &gc);
} }
} else { } 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 (y = 1; y < sy - 1; y++) {
for (x = 1; x < sx - 1; x++) for (x = 1; x < sx - 1; x++)
grid_view_set_cell(s->grid, x, y, &gc); grid_view_set_cell(s->grid, x, y, &gc);

View File

@ -718,7 +718,7 @@ status_prompt_redraw(struct client *c)
memcpy(&cursorgc, &gc, sizeof cursorgc); memcpy(&cursorgc, &gc, sizeof cursorgc);
cursorgc.attr ^= GRID_ATTR_REVERSE; cursorgc.attr ^= GRID_ATTR_REVERSE;
start = screen_write_strlen("%s", c->prompt_string); start = format_width(c->prompt_string);
if (start > c->tty.sx) if (start > c->tty.sx)
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++) for (offset = 0; offset < c->tty.sx; offset++)
screen_write_putc(&ctx, &gc, ' '); screen_write_putc(&ctx, &gc, ' ');
screen_write_cursormove(&ctx, 0, lines - 1, 0); 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); screen_write_cursormove(&ctx, start, lines - 1, 0);
left = c->tty.sx - start; left = c->tty.sx - start;
@ -1798,7 +1798,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
item.name = tmp; item.name = tmp;
item.key = '0' + size - 1; item.key = '0' + size - 1;
item.command = NULL; item.command = NULL;
menu_add_item(menu, &item, NULL, NULL, NULL); menu_add_item(menu, &item, NULL, c, NULL);
free(tmp); free(tmp);
if (size == height) if (size == height)

92
tmux.1
View File

@ -43,7 +43,7 @@ then later reattached.
.Pp .Pp
When When
.Nm .Nm
is started it creates a new is started, it creates a new
.Em session .Em session
with a single with a single
.Em window .Em window
@ -140,7 +140,10 @@ By default,
loads the system configuration file from loads the system configuration file from
.Pa @SYSCONFDIR@/tmux.conf , .Pa @SYSCONFDIR@/tmux.conf ,
if present, then looks for a user configuration file at 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 .Pp
The configuration file is a set of The configuration file is a set of
.Nm .Nm
@ -1338,11 +1341,12 @@ and sets an environment variable for the newly created session; it may be
specified multiple times. specified multiple times.
.Tg refresh .Tg refresh
.It Xo Ic refresh-client .It Xo Ic refresh-client
.Op Fl cDlLRSU .Op Fl cDLRSU
.Op Fl A Ar pane:state .Op Fl A Ar pane:state
.Op Fl B Ar name:what:format .Op Fl B Ar name:what:format
.Op Fl C Ar size .Op Fl C Ar size
.Op Fl f Ar flags .Op Fl f Ar flags
.Op Fl l Op Ar target-pane
.Op Fl t Ar target-client .Op Fl t Ar target-client
.Op Ar adjustment .Op Ar adjustment
.Xc .Xc
@ -1456,7 +1460,11 @@ sets a comma-separated list of client flags, see
.Fl l .Fl l
requests the clipboard from the client using the requests the clipboard from the client using the
.Xr xterm 1 .Xr xterm 1
escape sequence 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 .Pp
.Fl L , .Fl L ,
.Fl R , .Fl R ,
@ -1773,6 +1781,7 @@ The following commands are supported in copy mode:
.It Li "set-mark" Ta "X" Ta "X" .It Li "set-mark" Ta "X" Ta "X"
.It Li "start-of-line" Ta "0" Ta "C-a" .It Li "start-of-line" Ta "0" Ta "C-a"
.It Li "stop-selection" Ta "" Ta "" .It Li "stop-selection" Ta "" Ta ""
.It Li "toggle-position" Ta "P" Ta "P"
.It Li "top-line" Ta "H" Ta "M-R" .It Li "top-line" Ta "H" Ta "M-R"
.El .El
.Pp .Pp
@ -3618,6 +3627,8 @@ Supports DECSLRM margins.
Supports Supports
.Xr xterm 1 .Xr xterm 1
mouse sequences. mouse sequences.
.It osc7
Supports the OSC 7 working directory extension.
.It overline .It overline
Supports the overline SGR attribute. Supports the overline SGR attribute.
.It rectfill .It rectfill
@ -4108,6 +4119,9 @@ Set clock colour.
.Xc .Xc
Set clock hour format. Set clock hour format.
.Pp .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-height Ar height
.It Ic main-pane-width Ar width .It Ic main-pane-width Ar width
Set the width or height of the main (left or top) pane in the 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 .It Ic pane-border-format Ar format
Set the text shown in pane border status lines. Set the text shown in pane border status lines.
.Pp .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 .It Ic pane-border-lines Ar type
Set the type of characters used for drawing pane borders. Set the type of characters used for drawing pane borders.
.Ar type .Ar type
@ -4396,6 +4416,13 @@ The default is on.
Available pane options are: Available pane options are:
.Pp .Pp
.Bl -tag -width Ds -compact .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 .It Xo Ic allow-rename
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@ -4449,6 +4476,17 @@ The pane may be reactivated with the
.Ic respawn-pane .Ic respawn-pane
command. command.
.Pp .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 .It Xo Ic synchronize-panes
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@ -4575,6 +4613,11 @@ Run when a session is renamed.
Run when a window is linked into a session. Run when a window is linked into a session.
.It window-renamed .It window-renamed
Run when a window is 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 .It window-unlinked
Run when a window is unlinked from a session. Run when a window is unlinked from a session.
.El .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. 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 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. 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 .Nm
global environment set (see the global environment set (see the
.Sx GLOBAL AND SESSION ENVIRONMENT .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_termname" Ta "" Ta "Terminal name of client"
.It Li "client_termtype" Ta "" Ta "Terminal type of client, if available" .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_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_utf8" Ta "" Ta "1 if client supports UTF-8"
.It Li "client_width" Ta "" Ta "Width of client" .It Li "client_width" Ta "" Ta "Width of client"
.It Li "client_written" Ta "" Ta "Bytes written to 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_word" Ta "" Ta "Word under mouse, if any"
.It Li "mouse_x" Ta "" Ta "Mouse X position, 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 "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 "origin_flag" Ta "" Ta "Pane origin flag"
.It Li "pane_active" Ta "" Ta "1 if active pane" .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" .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_command" Ta "" Ta "Current command if available"
.It Li "pane_current_path" Ta "" Ta "Current path 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" 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_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_fg" Ta "" Ta "Pane foreground colour"
.It Li "pane_format" Ta "" Ta "1 if format is for a pane" .It Li "pane_format" Ta "" Ta "1 if format is for a pane"
.It Li "pane_height" Ta "" Ta "Height of 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 "session_windows" Ta "" Ta "Number of windows in session"
.It Li "socket_path" Ta "" Ta "Server socket path" .It Li "socket_path" Ta "" Ta "Server socket path"
.It Li "start_time" Ta "" Ta "Server start time" .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 "version" Ta "" Ta "Server version"
.It Li "window_active" Ta "" Ta "1 if window active" .It Li "window_active" Ta "" Ta "1 if window active"
.It Li "window_active_clients" Ta "" Ta "Number of clients viewing this window" .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_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_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_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_format" Ta "" Ta "1 if format is for a window"
.It Li "window_height" Ta "" Ta "Height of window" .It Li "window_height" Ta "" Ta "Height of window"
.It Li "window_id" Ta "" Ta "Unique window ID" .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_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_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_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_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_stack_index" Ta "" Ta "Index in session most recent stack"
.It Li "window_start_flag" Ta "" Ta "1 if window has the lowest index" .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. sets the type of border line for the popup.
When When
.Fl B .Fl B
is specified the is specified, the
.Fl b .Fl b
option is ignored. option is ignored.
See See
@ -6155,6 +6207,8 @@ Execute the first
.Ar command .Ar command
if if
.Ar shell-command .Ar shell-command
(run with
.Pa /bin/sh )
returns success or the second returns success or the second
.Ar command .Ar command
otherwise. otherwise.
@ -6191,6 +6245,8 @@ option.
.D1 Pq alias: Ic run .D1 Pq alias: Ic run
Execute Execute
.Ar shell-command .Ar shell-command
using
.Pa /bin/sh
or (with or (with
.Fl C ) .Fl C )
a a
@ -6292,6 +6348,11 @@ to change the cursor colour from inside
.Bd -literal -offset indent .Bd -literal -offset indent
$ printf '\e033]12;red\e033\e\e' $ printf '\e033]12;red\e033\e\e'
.Ed .Ed
.Pp
The colour is an
.Xr X 7
colour, see
.Xr XParseColor 3 .
.It Em \&Cmg, \&Clmg, \&Dsmg , \&Enmg .It Em \&Cmg, \&Clmg, \&Dsmg , \&Enmg
Set, clear, disable or enable DECSLRM margins. Set, clear, disable or enable DECSLRM margins.
These are set automatically if the terminal reports it is These are set automatically if the terminal reports it is
@ -6335,6 +6396,11 @@ $ printf '\e033[4 q'
If If
.Em Se .Em Se
is not set, \&Ss with argument 0 will be used to reset the cursor style instead. 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 .It Em \&Sxl
Indicates that the terminal supports SIXEL. Indicates that the terminal supports SIXEL.
.It Em \&Sync .It Em \&Sync
@ -6509,6 +6575,14 @@ are for future use and should be ignored.
The window with ID The window with ID
.Ar window-id .Ar window-id
was created but is not linked to the current session. 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 .It Ic %window-add Ar window-id
The window with ID The window with ID
.Ar window-id .Ar window-id
@ -6567,7 +6641,7 @@ are replaced with underscores
For input, For input,
.Nm .Nm
always runs with a UTF-8 locale. 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 .Ev LC_CTYPE
is ignored for input. is ignored for input.
Otherwise, Otherwise,
@ -6616,6 +6690,8 @@ options.
.Sh FILES .Sh FILES
.Bl -tag -width "@SYSCONFDIR@/tmux.confXXX" -compact .Bl -tag -width "@SYSCONFDIR@/tmux.confXXX" -compact
.It Pa ~/.tmux.conf .It Pa ~/.tmux.conf
.It Pa $XDG_CONFIG_HOME/tmux/tmux.conf
.It Pa ~/.config/tmux/tmux.conf
Default Default
.Nm .Nm
configuration file. configuration file.

106
tmux.h
View File

@ -203,26 +203,68 @@ enum {
KEYC_MOUSE_KEY(MOUSEDOWN1), KEYC_MOUSE_KEY(MOUSEDOWN1),
KEYC_MOUSE_KEY(MOUSEDOWN2), KEYC_MOUSE_KEY(MOUSEDOWN2),
KEYC_MOUSE_KEY(MOUSEDOWN3), 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(MOUSEUP1),
KEYC_MOUSE_KEY(MOUSEUP2), KEYC_MOUSE_KEY(MOUSEUP2),
KEYC_MOUSE_KEY(MOUSEUP3), 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(MOUSEDRAG1),
KEYC_MOUSE_KEY(MOUSEDRAG2), KEYC_MOUSE_KEY(MOUSEDRAG2),
KEYC_MOUSE_KEY(MOUSEDRAG3), 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(MOUSEDRAGEND1),
KEYC_MOUSE_KEY(MOUSEDRAGEND2), KEYC_MOUSE_KEY(MOUSEDRAGEND2),
KEYC_MOUSE_KEY(MOUSEDRAGEND3), 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(WHEELUP),
KEYC_MOUSE_KEY(WHEELDOWN), KEYC_MOUSE_KEY(WHEELDOWN),
KEYC_MOUSE_KEY(SECONDCLICK1), KEYC_MOUSE_KEY(SECONDCLICK1),
KEYC_MOUSE_KEY(SECONDCLICK2), KEYC_MOUSE_KEY(SECONDCLICK2),
KEYC_MOUSE_KEY(SECONDCLICK3), 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(DOUBLECLICK1),
KEYC_MOUSE_KEY(DOUBLECLICK2), KEYC_MOUSE_KEY(DOUBLECLICK2),
KEYC_MOUSE_KEY(DOUBLECLICK3), 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(TRIPLECLICK1),
KEYC_MOUSE_KEY(TRIPLECLICK2), KEYC_MOUSE_KEY(TRIPLECLICK2),
KEYC_MOUSE_KEY(TRIPLECLICK3), 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. */ /* Backspace key. */
KEYC_BSPACE, KEYC_BSPACE,
@ -500,6 +542,7 @@ enum tty_code_code {
TTYC_SMXX, TTYC_SMXX,
TTYC_SXL, TTYC_SXL,
TTYC_SS, TTYC_SS,
TTYC_SWD,
TTYC_SYNC, TTYC_SYNC,
TTYC_TC, TTYC_TC,
TTYC_TSL, TTYC_TSL,
@ -671,15 +714,15 @@ struct grid_cell_entry {
/* Grid line. */ /* Grid line. */
struct grid_line { struct grid_line {
struct grid_cell_entry *celldata;
u_int cellused; u_int cellused;
u_int cellsize; u_int cellsize;
struct grid_cell_entry *celldata;
u_int extdsize;
struct grid_extd_entry *extddata; struct grid_extd_entry *extddata;
u_int extdsize;
int flags; int flags;
} __packed; };
/* Entire grid of cells. */ /* Entire grid of cells. */
struct grid { struct grid {
@ -814,7 +857,6 @@ struct screen {
struct grid_cell saved_cell; struct grid_cell saved_cell;
int saved_flags; int saved_flags;
int mode;
bitstr_t *tabs; bitstr_t *tabs;
struct screen_sel *sel; struct screen_sel *sel;
struct images images; struct images images;
@ -862,6 +904,12 @@ enum pane_lines {
PANE_LINES_NUMBER 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. */ /* Screen redraw context. */
struct screen_redraw_ctx { struct screen_redraw_ctx {
struct client *c; struct client *c;
@ -998,6 +1046,7 @@ struct window_pane {
pid_t pid; pid_t pid;
char tty[TTY_NAME_MAX]; char tty[TTY_NAME_MAX];
int status; int status;
struct timeval dead_time;
int fd; int fd;
struct bufferevent *event; struct bufferevent *event;
@ -1073,6 +1122,7 @@ struct window {
u_int new_xpixel; u_int new_xpixel;
u_int new_ypixel; u_int new_ypixel;
struct utf8_data *fill_character;
int flags; int flags;
#define WINDOW_BELL 0x1 #define WINDOW_BELL 0x1
#define WINDOW_ACTIVITY 0x2 #define WINDOW_ACTIVITY 0x2
@ -1212,21 +1262,33 @@ struct session {
RB_HEAD(sessions, session); RB_HEAD(sessions, session);
/* Mouse button masks. */ /* Mouse button masks. */
#define MOUSE_MASK_BUTTONS 3 #define MOUSE_MASK_BUTTONS 195
#define MOUSE_MASK_SHIFT 4 #define MOUSE_MASK_SHIFT 4
#define MOUSE_MASK_META 8 #define MOUSE_MASK_META 8
#define MOUSE_MASK_CTRL 16 #define MOUSE_MASK_CTRL 16
#define MOUSE_MASK_DRAG 32 #define MOUSE_MASK_DRAG 32
#define MOUSE_MASK_WHEEL 64
#define MOUSE_MASK_MODIFIERS (MOUSE_MASK_SHIFT|MOUSE_MASK_META|MOUSE_MASK_CTRL) #define MOUSE_MASK_MODIFIERS (MOUSE_MASK_SHIFT|MOUSE_MASK_META|MOUSE_MASK_CTRL)
/* Mouse wheel states. */ /* Mouse wheel type. */
#define MOUSE_WHEEL_UP 0 #define MOUSE_WHEEL_UP 64
#define MOUSE_WHEEL_DOWN 1 #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. */ /* Mouse helpers. */
#define MOUSE_BUTTONS(b) ((b) & MOUSE_MASK_BUTTONS) #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_DRAG(b) ((b) & MOUSE_MASK_DRAG)
#define MOUSE_RELEASE(b) (((b) & MOUSE_MASK_BUTTONS) == 3) #define MOUSE_RELEASE(b) (((b) & MOUSE_MASK_BUTTONS) == 3)
@ -1292,6 +1354,7 @@ LIST_HEAD(tty_terms, tty_term);
struct tty { struct tty {
struct client *client; struct client *client;
struct event start_timer; struct event start_timer;
struct event clipboard_timer;
u_int sx; u_int sx;
u_int sy; u_int sy;
@ -1332,15 +1395,14 @@ struct tty {
#define TTY_NOCURSOR 0x1 #define TTY_NOCURSOR 0x1
#define TTY_FREEZE 0x2 #define TTY_FREEZE 0x2
#define TTY_TIMER 0x4 #define TTY_TIMER 0x4
/* 0x8 unused */ #define TTY_NOBLOCK 0x8
#define TTY_STARTED 0x10 #define TTY_STARTED 0x10
#define TTY_OPENED 0x20 #define TTY_OPENED 0x20
/* 0x40 unused */ #define TTY_OSC52QUERY 0x40
#define TTY_BLOCK 0x80 #define TTY_BLOCK 0x80
#define TTY_HAVEDA 0x100 #define TTY_HAVEDA 0x100
#define TTY_HAVEXDA 0x200 #define TTY_HAVEXDA 0x200
#define TTY_SYNCING 0x400 #define TTY_SYNCING 0x400
#define TTY_NOBLOCK 0x800
int flags; int flags;
struct tty_term *term; struct tty_term *term;
@ -1668,6 +1730,7 @@ struct client {
struct format_job_tree *jobs; struct format_job_tree *jobs;
char *title; char *title;
char *path;
const char *cwd; const char *cwd;
char *term_name; char *term_name;
@ -1726,6 +1789,7 @@ struct client {
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL #define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL #define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL #define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL
#define CLIENT_ALLREDRAWFLAGS \ #define CLIENT_ALLREDRAWFLAGS \
(CLIENT_REDRAWWINDOW| \ (CLIENT_REDRAWWINDOW| \
CLIENT_REDRAWSTATUS| \ CLIENT_REDRAWSTATUS| \
@ -1772,7 +1836,10 @@ struct client {
prompt_free_cb prompt_freecb; prompt_free_cb prompt_freecb;
void *prompt_data; void *prompt_data;
u_int prompt_hindex[PROMPT_NTYPES]; u_int prompt_hindex[PROMPT_NTYPES];
enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode; enum {
PROMPT_ENTRY,
PROMPT_COMMAND
} prompt_mode;
struct utf8_data *prompt_saved; struct utf8_data *prompt_saved;
#define PROMPT_SINGLE 0x1 #define PROMPT_SINGLE 0x1
#define PROMPT_NUMERIC 0x2 #define PROMPT_NUMERIC 0x2
@ -1803,6 +1870,9 @@ struct client {
struct client_files files; struct client_files files;
u_int *clipboard_panes;
u_int clipboard_npanes;
TAILQ_ENTRY(client) entry; TAILQ_ENTRY(client) entry;
}; };
TAILQ_HEAD(clients, client); TAILQ_HEAD(clients, client);
@ -1977,6 +2047,7 @@ void proc_remove_peer(struct tmuxpeer *);
void proc_kill_peer(struct tmuxpeer *); void proc_kill_peer(struct tmuxpeer *);
void proc_toggle_log(struct tmuxproc *); void proc_toggle_log(struct tmuxproc *);
pid_t proc_fork_and_daemon(int *); pid_t proc_fork_and_daemon(int *);
uid_t proc_get_peer_uid(struct tmuxpeer *);
/* cfg.c */ /* cfg.c */
extern int cfg_finished; extern int cfg_finished;
@ -2190,6 +2261,7 @@ void tty_reset(struct tty *);
void tty_region_off(struct tty *); void tty_region_off(struct tty *);
void tty_margin_off(struct tty *); void tty_margin_off(struct tty *);
void tty_cursor(struct tty *, u_int, u_int); 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_putcode(struct tty *, enum tty_code_code);
void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode1(struct tty *, enum tty_code_code, int);
void tty_putcode2(struct tty *, enum tty_code_code, int, 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_send_requests(struct tty *);
void tty_stop_tty(struct tty *); void tty_stop_tty(struct tty *);
void tty_set_title(struct tty *, const char *); 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_update_mode(struct tty *, int, struct screen *);
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int, 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 *); 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_update_socket(void);
void server_add_accept(int); void server_add_accept(int);
void printflike(1, 2) server_add_message(const char *, ...); void printflike(1, 2) server_add_message(const char *, ...);
int server_create_socket(int, char **);
/* server-client.c */ /* server-client.c */
RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp); 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_buffer(struct window_pane *, u_char *, size_t);
void input_parse_screen(struct input_ctx *, struct screen *, void input_parse_screen(struct input_ctx *, struct screen *,
screen_write_init_ctx_cb, void *, u_char *, size_t); 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 */ /* input-key.c */
void input_key_build(void); void input_key_build(void);
@ -2930,6 +3006,7 @@ void *window_pane_get_new_data(struct window_pane *,
struct window_pane_offset *, size_t *); struct window_pane_offset *, size_t *);
void window_pane_update_used_data(struct window_pane *, void window_pane_update_used_data(struct window_pane *,
struct window_pane_offset *, size_t); struct window_pane_offset *, size_t);
void window_set_fill_character(struct window *);
/* layout.c */ /* layout.c */
u_int layout_count_cells(struct layout_cell *); u_int layout_count_cells(struct layout_cell *);
@ -3083,6 +3160,7 @@ void control_notify_session_window_changed(struct session *);
/* session.c */ /* session.c */
extern struct sessions sessions; extern struct sessions sessions;
extern u_int next_session_id;
int session_cmp(struct session *, struct session *); int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp); RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_alive(struct session *); int session_alive(struct session *);

View File

@ -53,6 +53,18 @@ static const struct tty_feature tty_feature_title = {
0 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. */ /* Terminal has mouse support. */
static const char *tty_feature_mouse_capabilities[] = { static const char *tty_feature_mouse_capabilities[] = {
"kmous=\\E[M", "kmous=\\E[M",
@ -249,6 +261,7 @@ static const struct tty_feature *tty_features[] = {
&tty_feature_focus, &tty_feature_focus,
&tty_feature_margins, &tty_feature_margins,
&tty_feature_mouse, &tty_feature_mouse,
&tty_feature_osc7,
&tty_feature_overline, &tty_feature_overline,
&tty_feature_rectfill, &tty_feature_rectfill,
&tty_feature_rgb, &tty_feature_rgb,
@ -363,7 +376,7 @@ tty_default_features(int *feat, const char *name, u_int version)
}, },
{ .name = "iTerm2", { .name = "iTerm2",
.features = TTY_FEATURES_BASE_MODERN_XTERM .features = TTY_FEATURES_BASE_MODERN_XTERM
",cstyle,extkeys,margins,sync" ",cstyle,extkeys,margins,usstyle,sync"
}, },
{ .name = "XTerm", { .name = "XTerm",
/* /*

View File

@ -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. */ /* Type is M for press, m for release. */
sgr_type = ch; sgr_type = ch;
if (sgr_type == 'm') if (sgr_type == 'm')
b |= 3; b = 3;
/* /*
* Some terminals (like PuTTY 0.63) mistakenly send * 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 * Discard it before it reaches any program running inside
* tmux. * tmux.
*/ */
if (sgr_type == 'm' && (sgr_b & 64)) if (sgr_type == 'm' && MOUSE_WHEEL(sgr_b))
return (-2); return (-2);
} else } else
return (-1); return (-1);
@ -1154,12 +1154,14 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size,
* partial. * partial.
*/ */
static int static int
tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len, tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
size_t *size)
{ {
struct client *c = tty->client;
struct window_pane *wp;
size_t end, terminator, needed; size_t end, terminator, needed;
char *copy, *out; char *copy, *out;
int outlen; int outlen;
u_int i;
*size = 0; *size = 0;
@ -1217,6 +1219,12 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len,
buf++; buf++;
end--; end--;
/* If we did not request this, ignore it. */
if (~tty->flags & TTY_OSC52QUERY)
return (0);
tty->flags &= ~TTY_OSC52QUERY;
evtimer_del(&tty->clipboard_timer);
/* It has to be a string so copy it. */ /* It has to be a string so copy it. */
copy = xmalloc(end + 1); copy = xmalloc(end + 1);
memcpy(copy, buf, end); memcpy(copy, buf, end);
@ -1232,9 +1240,20 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len,
} }
free(copy); free(copy);
/* Create a new paste buffer. */ /* Create a new paste buffer and forward to panes. */
log_debug("%s: %.*s", __func__, outlen, out); log_debug("%s: %.*s", __func__, outlen, out);
if (c->flags & CLIENT_CLIPBOARDBUFFER) {
paste_add(NULL, out, outlen); 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); return (0);
} }

View File

@ -278,6 +278,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_SMUL] = { TTYCODE_STRING, "smul" }, [TTYC_SMUL] = { TTYCODE_STRING, "smul" },
[TTYC_SMXX] = { TTYCODE_STRING, "smxx" }, [TTYC_SMXX] = { TTYCODE_STRING, "smxx" },
[TTYC_SS] = { TTYCODE_STRING, "Ss" }, [TTYC_SS] = { TTYCODE_STRING, "Ss" },
[TTYC_SWD] = { TTYCODE_STRING, "Swd" },
[TTYC_SYNC] = { TTYCODE_STRING, "Sync" }, [TTYC_SYNC] = { TTYCODE_STRING, "Sync" },
[TTYC_TC] = { TTYCODE_FLAG, "Tc" }, [TTYC_TC] = { TTYCODE_FLAG, "Tc" },
[TTYC_TSL] = { TTYCODE_STRING, "tsl" }, [TTYC_TSL] = { TTYCODE_STRING, "tsl" },

72
tty.c
View File

@ -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_START(tty) (1 + ((tty)->sx * (tty)->sy) * 8)
#define TTY_BLOCK_STOP(tty) (1 + ((tty)->sx * (tty)->sy) / 8) #define TTY_BLOCK_STOP(tty) (1 + ((tty)->sx * (tty)->sy) / 8)
#define TTY_QUERY_TIMEOUT 5
void void
tty_create_log(void) tty_create_log(void)
{ {
@ -307,7 +309,7 @@ tty_start_tty(struct tty *tty)
{ {
struct client *c = tty->client; struct client *c = tty->client;
struct termios tio; struct termios tio;
struct timeval tv = { .tv_sec = 3 }; struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT };
setblocking(c->fd, 0); setblocking(c->fd, 0);
event_add(&tty->event_in, NULL); event_add(&tty->event_in, NULL);
@ -653,6 +655,18 @@ tty_set_title(struct tty *tty, const char *title)
tty_putcode(tty, TTYC_FSL); 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 static void
tty_force_cursor_colour(struct tty *tty, int c) 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 ((changed & ALL_MOUSE_MODES) && tty_term_has(term, TTYC_KMOUS)) {
/* /*
* If the mouse modes have changed, clear any that are set and * If the mouse modes have changed, clear then all and apply
* apply again. There are differences in how terminals track * again. There are differences in how terminals track the
* the various bits. * various bits.
*/ */
if (tty->mode & MODE_MOUSE_SGR) tty_puts(tty, "\033[?1006l\033[?1000l\033[?1002l\033[?1003l");
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");
if (mode & ALL_MOUSE_MODES) if (mode & ALL_MOUSE_MODES)
tty_puts(tty, "\033[?1006h"); 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) 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 (changed & MODE_BRACKETPASTE) {
if (mode & 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); encoded = xmalloc(size);
b64_ntop(buf, len, encoded, size); b64_ntop(buf, len, encoded, size);
tty->flags |= TTY_NOBLOCK;
tty_putcode_ptr2(tty, TTYC_MS, "", encoded); tty_putcode_ptr2(tty, TTYC_MS, "", encoded);
tty->client->redraw = EVBUFFER_LENGTH(tty->out);
free(encoded); free(encoded);
} }
@ -2134,6 +2141,7 @@ tty_set_selection(struct tty *tty, const char *buf, size_t len)
void void
tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx)
{ {
tty->flags |= TTY_NOBLOCK;
tty_add(tty, ctx->ptr, ctx->num); tty_add(tty, ctx->ptr, ctx->num);
tty_invalidate(tty); tty_invalidate(tty);
} }
@ -2996,3 +3004,31 @@ tty_default_attributes(struct tty *tty, const struct grid_cell *defaults,
gc.bg = bg; gc.bg = bg;
tty_attributes(tty, &gc, defaults, palette); 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);
}

View File

@ -1272,6 +1272,16 @@ window_copy_cmd_halfpage_up(struct window_copy_cmd_state *cs)
return (WINDOW_COPY_CMD_NOTHING); 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 static enum window_copy_cmd_action
window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs) window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
{ {
@ -2817,6 +2827,12 @@ static const struct {
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_stop_selection .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", { .command = "top-line",
.minargs = 0, .minargs = 0,
.maxargs = 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); utf8_to_data(gl->extddata[gce->offset].data, &ud);
if (ud.size == 0) {
*size = 0;
*allocated = 0;
return (NULL);
}
*size = ud.size; *size = ud.size;
*allocated = 1; *allocated = 1;

View File

@ -680,9 +680,7 @@ window_customize_draw_option(struct window_customize_modedata *data,
} }
ft = format_create_from_state(NULL, NULL, &fs); ft = format_create_from_state(NULL, NULL, &fs);
if (oe == NULL) if (oe == NULL || oe->text == NULL)
text = "This is a user option.";
else if (oe->text == NULL)
text = "This option doesn't have a description."; text = "This option doesn't have a description.";
else else
text = oe->text; text = oe->text;

View File

@ -329,6 +329,7 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel)
w->id = next_window_id++; w->id = next_window_id++;
RB_INSERT(windows, &windows, w); RB_INSERT(windows, &windows, w);
window_set_fill_character(w);
window_update_activity(w); window_update_activity(w);
log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy, 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); event_del(&w->offset_timer);
options_free(w->options); options_free(w->options);
free(w->fill_character);
free(w->name); free(w->name);
free(w); free(w);
@ -761,6 +763,7 @@ window_lost_pane(struct window *w, struct window_pane *wp)
if (w->active != NULL) { if (w->active != NULL) {
w->active->flags |= PANE_CHANGED; w->active->flags |= PANE_CHANGED;
notify_window("window-pane-changed", w); notify_window("window-pane-changed", w);
window_update_focus(w);
} }
} else if (wp == w->last) } else if (wp == w->last)
w->last = NULL; w->last = NULL;
@ -1598,3 +1601,20 @@ window_pane_update_used_data(struct window_pane *wp,
size = EVBUFFER_LENGTH(wp->event->input) - used; size = EVBUFFER_LENGTH(wp->event->input) - used;
wpo->used += size; 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;
}
}