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
* Add an option (pane-border-indicators) to select how the active pane is shown
on the pane border (colour, arrows or both).
* Support underscore styles with capture-pane -e.
* Make pane-border-format a pane option rather than window.
* Respond to OSC 4 queries
* Fix g/G keys in modes to do the same thing as copy mode (and vi).
* Bump the time terminals have to respond to device attributes queries to three
seconds.
* If automatic-rename is off, allow the rename escape sequence to set an empty
name.
* Trim menu item text more intelligently.
* Add cursor-style and cursor-colour options to set the default cursor style
and colour.
* Accept some useful and non-conflicting emacs keys in vi normal mode at the
command prompt.
* Add a format modifier (c) to force a colour to RGB.
* Add -s and -S to display-popup to set styles, -b to set lines and -T to set
popup title. New popup-border-lines, popup-border-style and popup-style
options set the defaults.
* Add -e flag to set an environment variable for a popup.
* Make send-keys without arguments send the key it is bound to (if bound to a
key).
* Try to leave terminal cursor at the right position even when tmux is drawing
its own cursor or selection (such as at the command prompt and in choose
mode) for people using screen readers and similar which can make use of it.
* Change so that {} is converted to tmux commands immediately when parsed. This
means it must contain valid tmux commands. For commands which expand %% and
%%%, this now only happens within string arguments. Use of nested aliases

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -60,7 +60,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
const char *errstr;
char *cause;
u_int adjust;
int x, y;
int x, y, status;
struct grid *gd = wp->base.grid;
if (args_has(args, 'T')) {
@ -121,6 +121,17 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
free(cause);
return (CMD_RETURN_ERROR);
}
status = options_get_number(w->options, "pane-border-status");
switch (status) {
case PANE_STATUS_TOP:
if (y != INT_MAX && wp->yoff == 1)
y++;
break;
case PANE_STATUS_BOTTOM:
if (y != INT_MAX && wp->yoff + wp->sy == w->sy - 1)
y++;
break;
}
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}

View File

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

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

View File

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

View File

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

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)
)
if test "x$enable_static" = xyes; then
case "$host_os" in
*darwin*)
AC_MSG_ERROR([static linking is not supported on macOS])
;;
esac
test "x$PKG_CONFIG" != x && PKG_CONFIG="$PKG_CONFIG --static"
AM_LDFLAGS="-static $AM_LDFLAGS"
LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS"
@ -123,6 +128,7 @@ AC_CHECK_HEADERS([ \
sys/dir.h \
sys/ndir.h \
sys/tree.h \
ucred.h \
util.h \
])
@ -141,7 +147,8 @@ AC_CHECK_FUNCS([ \
flock \
prctl \
proc_pidinfo \
sysconf
getpeerucred \
sysconf \
])
# Check for functions with a compatibility implementation.
@ -155,6 +162,7 @@ AC_REPLACE_FUNCS([ \
freezero \
getdtablecount \
getdtablesize \
getpeereid \
getline \
getprogname \
memmem \
@ -382,6 +390,31 @@ if test "x$enable_utf8proc" = xyes; then
fi
AM_CONDITIONAL(HAVE_UTF8PROC, [test "x$enable_utf8proc" = xyes])
# Check for systemd support.
AC_ARG_ENABLE(
systemd,
AS_HELP_STRING(--enable-systemd, enable systemd integration)
)
if test x"$enable_systemd" = xyes; then
PKG_CHECK_MODULES(
SYSTEMD,
libsystemd,
[
AM_CPPFLAGS="$SYSTEMD_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
LIBS="$SYSTEMD_LIBS $LIBS"
found_systemd=yes
],
found_systemd=no
)
if test "x$found_systemd" = xyes; then
AC_DEFINE(HAVE_SYSTEMD)
else
AC_MSG_ERROR("systemd not found")
fi
fi
AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$found_systemd" = xyes])
# Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well.
AC_MSG_CHECKING(for b64_ntop)
AC_LINK_IFELSE([AC_LANG_PROGRAM(
@ -679,6 +712,14 @@ AC_CHECK_DECL(
[#include <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).
AC_CHECK_DECL(
F_CLOSEM,

View File

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

107
format.c
View File

@ -24,6 +24,7 @@
#include <fnmatch.h>
#include <libgen.h>
#include <math.h>
#include <pwd.h>
#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
@ -1387,6 +1388,35 @@ format_cb_client_tty(struct format_tree *ft)
return (NULL);
}
/* Callback for client_uid. */
static void *
format_cb_client_uid(struct format_tree *ft)
{
uid_t uid;
if (ft->c != NULL) {
uid = proc_get_peer_uid(ft->c->peer);
if (uid != (uid_t)-1)
return (format_printf("%ld", (long)uid));
}
return (NULL);
}
/* Callback for client_user. */
static void *
format_cb_client_user(struct format_tree *ft)
{
uid_t uid;
struct passwd *pw;
if (ft->c != NULL) {
uid = proc_get_peer_uid(ft->c->peer);
if (uid != (uid_t)-1 && (pw = getpwuid(uid)) != NULL)
return (xstrdup(pw->pw_name));
}
return (NULL);
}
/* Callback for client_utf8. */
static void *
format_cb_client_utf8(struct format_tree *ft)
@ -1650,6 +1680,13 @@ format_cb_mouse_y(struct format_tree *ft)
return (NULL);
}
/* Callback for next_session_id. */
static void *
format_cb_next_session_id(__unused struct format_tree *ft)
{
return (format_printf("$%u", next_session_id));
}
/* Callback for origin_flag. */
static void *
format_cb_origin_flag(struct format_tree *ft)
@ -1719,6 +1756,23 @@ format_cb_pane_dead(struct format_tree *ft)
return (NULL);
}
/* Callback for pane_dead_signal. */
static void *
format_cb_pane_dead_signal(struct format_tree *ft)
{
struct window_pane *wp = ft->wp;
const char *name;
if (wp != NULL) {
if ((wp->flags & PANE_STATUSREADY) && WIFSIGNALED(wp->status)) {
name = sig2name(WTERMSIG(wp->status));
return (format_printf("%s", name));
}
return (NULL);
}
return (NULL);
}
/* Callback for pane_dead_status. */
static void *
format_cb_pane_dead_status(struct format_tree *ft)
@ -1733,6 +1787,20 @@ format_cb_pane_dead_status(struct format_tree *ft)
return (NULL);
}
/* Callback for pane_dead_time. */
static void *
format_cb_pane_dead_time(struct format_tree *ft)
{
struct window_pane *wp = ft->wp;
if (wp != NULL) {
if (wp->flags & PANE_STATUSDRAWN)
return (&wp->dead_time);
return (NULL);
}
return (NULL);
}
/* Callback for pane_format. */
static void *
format_cb_pane_format(struct format_tree *ft)
@ -2514,6 +2582,24 @@ format_cb_tree_mode_format(__unused struct format_tree *ft)
return (xstrdup(window_tree_mode.default_format));
}
/* Callback for uid. */
static void *
format_cb_uid(__unused struct format_tree *ft)
{
return (format_printf("%ld", (long)getuid()));
}
/* Callback for user. */
static void *
format_cb_user(__unused struct format_tree *ft)
{
struct passwd *pw;
if ((pw = getpwuid(getuid())) != NULL)
return (xstrdup(pw->pw_name));
return NULL;
}
/* Format table type. */
enum format_table_type {
FORMAT_TABLE_STRING,
@ -2620,6 +2706,12 @@ static const struct format_table_entry format_table[] = {
{ "client_tty", FORMAT_TABLE_STRING,
format_cb_client_tty
},
{ "client_uid", FORMAT_TABLE_STRING,
format_cb_client_uid
},
{ "client_user", FORMAT_TABLE_STRING,
format_cb_client_user
},
{ "client_utf8", FORMAT_TABLE_STRING,
format_cb_client_utf8
},
@ -2707,6 +2799,9 @@ static const struct format_table_entry format_table[] = {
{ "mouse_y", FORMAT_TABLE_STRING,
format_cb_mouse_y
},
{ "next_session_id", FORMAT_TABLE_STRING,
format_cb_next_session_id
},
{ "origin_flag", FORMAT_TABLE_STRING,
format_cb_origin_flag
},
@ -2740,9 +2835,15 @@ static const struct format_table_entry format_table[] = {
{ "pane_dead", FORMAT_TABLE_STRING,
format_cb_pane_dead
},
{ "pane_dead_signal", FORMAT_TABLE_STRING,
format_cb_pane_dead_signal
},
{ "pane_dead_status", FORMAT_TABLE_STRING,
format_cb_pane_dead_status
},
{ "pane_dead_time", FORMAT_TABLE_TIME,
format_cb_pane_dead_time
},
{ "pane_fg", FORMAT_TABLE_STRING,
format_cb_pane_fg
},
@ -2896,6 +2997,12 @@ static const struct format_table_entry format_table[] = {
{ "tree_mode_format", FORMAT_TABLE_STRING,
format_cb_tree_mode_format
},
{ "uid", FORMAT_TABLE_STRING,
format_cb_uid
},
{ "user", FORMAT_TABLE_STRING,
format_cb_user
},
{ "version", FORMAT_TABLE_STRING,
format_cb_version
},

98
grid.c
View File

@ -826,6 +826,56 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values)
return (n);
}
/* Get underscore colour sequence. */
static size_t
grid_string_cells_us(const struct grid_cell *gc, int *values)
{
size_t n;
u_char r, g, b;
n = 0;
if (gc->us & COLOUR_FLAG_256) {
values[n++] = 58;
values[n++] = 5;
values[n++] = gc->us & 0xff;
} else if (gc->us & COLOUR_FLAG_RGB) {
values[n++] = 58;
values[n++] = 2;
colour_split_rgb(gc->us, &r, &g, &b);
values[n++] = r;
values[n++] = g;
values[n++] = b;
}
return (n);
}
/* Add on SGR code. */
static void
grid_string_cells_add_code(char *buf, size_t len, u_int n, int *s, int *newc,
int *oldc, size_t nnewc, size_t noldc, int escape_c0)
{
u_int i;
char tmp[64];
if (nnewc != 0 &&
(nnewc != noldc ||
memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 ||
(n != 0 && s[0] == 0))) {
if (escape_c0)
strlcat(buf, "\\033[", len);
else
strlcat(buf, "\033[", len);
for (i = 0; i < nnewc; i++) {
if (i + 1 < nnewc)
xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
else
xsnprintf(tmp, sizeof tmp, "%d", newc[i]);
strlcat(buf, tmp, len);
}
strlcat(buf, "m", len);
}
}
/*
* Returns ANSI code to set particular attributes (colour, bold and so on)
* given a current state.
@ -861,7 +911,9 @@ grid_string_cells_code(const struct grid_cell *lastgc,
/* If any attribute is removed, begin with 0. */
for (i = 0; i < nitems(attrs); i++) {
if (!(attr & attrs[i].mask) && (lastattr & attrs[i].mask)) {
if (((~attr & attrs[i].mask) &&
(lastattr & attrs[i].mask)) ||
(lastgc->us != 0 && gc->us == 0)) {
s[n++] = 0;
lastattr &= GRID_ATTR_CHARSET;
break;
@ -897,42 +949,20 @@ grid_string_cells_code(const struct grid_cell *lastgc,
/* If the foreground colour changed, write its parameters. */
nnewc = grid_string_cells_fg(gc, newc);
noldc = grid_string_cells_fg(lastgc, oldc);
if (nnewc != noldc ||
memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 ||
(n != 0 && s[0] == 0)) {
if (escape_c0)
strlcat(buf, "\\033[", len);
else
strlcat(buf, "\033[", len);
for (i = 0; i < nnewc; i++) {
if (i + 1 < nnewc)
xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
else
xsnprintf(tmp, sizeof tmp, "%d", newc[i]);
strlcat(buf, tmp, len);
}
strlcat(buf, "m", len);
}
grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
escape_c0);
/* If the background colour changed, append its parameters. */
nnewc = grid_string_cells_bg(gc, newc);
noldc = grid_string_cells_bg(lastgc, oldc);
if (nnewc != noldc ||
memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 ||
(n != 0 && s[0] == 0)) {
if (escape_c0)
strlcat(buf, "\\033[", len);
else
strlcat(buf, "\033[", len);
for (i = 0; i < nnewc; i++) {
if (i + 1 < nnewc)
xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
else
xsnprintf(tmp, sizeof tmp, "%d", newc[i]);
strlcat(buf, tmp, len);
}
strlcat(buf, "m", len);
}
grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
escape_c0);
/* If the underscore colour changed, append its parameters. */
nnewc = grid_string_cells_us(gc, newc);
noldc = grid_string_cells_us(lastgc, oldc);
grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
escape_c0);
/* Append shift in/shift out if needed. */
if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) {
@ -973,7 +1003,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
gl = grid_peek_line(gd, py);
for (xx = px; xx < px + nx; xx++) {
if (gl == NULL || xx >= gl->cellsize)
if (gl == NULL || xx >= gl->cellused)
break;
grid_get_cell(gd, xx, py, &gc);
if (gc.flags & GRID_FLAG_PADDING)

View File

@ -417,7 +417,7 @@ int
input_key(struct screen *s, struct bufferevent *bev, key_code key)
{
struct input_key_entry *ike;
key_code justkey, newkey, outkey;
key_code justkey, newkey, outkey, modifiers;
struct utf8_data ud;
char tmp[64], modifier;
@ -518,7 +518,12 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
return (input_key(s, bev, key & ~KEYC_CTRL));
}
outkey = (key & KEYC_MASK_KEY);
switch (key & KEYC_MASK_MODIFIERS) {
modifiers = (key & KEYC_MASK_MODIFIERS);
if (outkey < 32 && outkey != 9 && outkey != 13 && outkey != 27) {
outkey = 64 + outkey;
modifiers |= KEYC_CTRL;
}
switch (modifiers) {
case KEYC_SHIFT:
modifier = '2';
break;
@ -577,13 +582,13 @@ input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,
*/
if (m->sgr_type != ' ') {
if (MOUSE_DRAG(m->sgr_b) &&
MOUSE_BUTTONS(m->sgr_b) == 3 &&
MOUSE_RELEASE(m->sgr_b) &&
(~s->mode & MODE_MOUSE_ALL))
return (0);
} else {
if (MOUSE_DRAG(m->b) &&
MOUSE_BUTTONS(m->b) == 3 &&
MOUSE_BUTTONS(m->lb) == 3 &&
MOUSE_RELEASE(m->b) &&
MOUSE_RELEASE(m->lb) &&
(~s->mode & MODE_MOUSE_ALL))
return (0);
}

55
input.c
View File

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

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.
*/
env = environ_for_session(s, !cfg_finished);
if (e != NULL) {
if (e != NULL)
environ_copy(e, env);
}
sigfillset(&set);
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 F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }",
"bind -Tcopy-mode N { send -X search-reverse }",
"bind -Tcopy-mode P { send -X toggle-position }",
"bind -Tcopy-mode R { send -X rectangle-toggle }",
"bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }",
"bind -Tcopy-mode X { send -X set-mark }",
@ -588,6 +589,7 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi L { send -X bottom-line }",
"bind -Tcopy-mode-vi M { send -X middle-line }",
"bind -Tcopy-mode-vi N { send -X search-reverse }",
"bind -Tcopy-mode-vi P { send -X toggle-position }",
"bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }",
"bind -Tcopy-mode-vi V { send -X select-line }",
"bind -Tcopy-mode-vi W { send -X next-space }",

View File

@ -91,26 +91,68 @@ static const struct {
KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1),
KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2),
KEYC_MOUSE_STRING(MOUSEDOWN3, MouseDown3),
KEYC_MOUSE_STRING(MOUSEDOWN6, MouseDown6),
KEYC_MOUSE_STRING(MOUSEDOWN7, MouseDown7),
KEYC_MOUSE_STRING(MOUSEDOWN8, MouseDown8),
KEYC_MOUSE_STRING(MOUSEDOWN9, MouseDown9),
KEYC_MOUSE_STRING(MOUSEDOWN10, MouseDown10),
KEYC_MOUSE_STRING(MOUSEDOWN11, MouseDown11),
KEYC_MOUSE_STRING(MOUSEUP1, MouseUp1),
KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2),
KEYC_MOUSE_STRING(MOUSEUP3, MouseUp3),
KEYC_MOUSE_STRING(MOUSEUP6, MouseUp6),
KEYC_MOUSE_STRING(MOUSEUP7, MouseUp7),
KEYC_MOUSE_STRING(MOUSEUP8, MouseUp8),
KEYC_MOUSE_STRING(MOUSEUP9, MouseUp9),
KEYC_MOUSE_STRING(MOUSEUP10, MouseUp10),
KEYC_MOUSE_STRING(MOUSEUP11, MouseUp11),
KEYC_MOUSE_STRING(MOUSEDRAG1, MouseDrag1),
KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2),
KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3),
KEYC_MOUSE_STRING(MOUSEDRAG6, MouseDrag6),
KEYC_MOUSE_STRING(MOUSEDRAG7, MouseDrag7),
KEYC_MOUSE_STRING(MOUSEDRAG8, MouseDrag8),
KEYC_MOUSE_STRING(MOUSEDRAG9, MouseDrag9),
KEYC_MOUSE_STRING(MOUSEDRAG10, MouseDrag10),
KEYC_MOUSE_STRING(MOUSEDRAG11, MouseDrag11),
KEYC_MOUSE_STRING(MOUSEDRAGEND1, MouseDragEnd1),
KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2),
KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3),
KEYC_MOUSE_STRING(MOUSEDRAGEND6, MouseDragEnd6),
KEYC_MOUSE_STRING(MOUSEDRAGEND7, MouseDragEnd7),
KEYC_MOUSE_STRING(MOUSEDRAGEND8, MouseDragEnd8),
KEYC_MOUSE_STRING(MOUSEDRAGEND9, MouseDragEnd9),
KEYC_MOUSE_STRING(MOUSEDRAGEND10, MouseDragEnd10),
KEYC_MOUSE_STRING(MOUSEDRAGEND11, MouseDragEnd11),
KEYC_MOUSE_STRING(WHEELUP, WheelUp),
KEYC_MOUSE_STRING(WHEELDOWN, WheelDown),
KEYC_MOUSE_STRING(SECONDCLICK1, SecondClick1),
KEYC_MOUSE_STRING(SECONDCLICK2, SecondClick2),
KEYC_MOUSE_STRING(SECONDCLICK3, SecondClick3),
KEYC_MOUSE_STRING(SECONDCLICK6, SecondClick6),
KEYC_MOUSE_STRING(SECONDCLICK7, SecondClick7),
KEYC_MOUSE_STRING(SECONDCLICK8, SecondClick8),
KEYC_MOUSE_STRING(SECONDCLICK9, SecondClick9),
KEYC_MOUSE_STRING(SECONDCLICK10, SecondClick10),
KEYC_MOUSE_STRING(SECONDCLICK11, SecondClick11),
KEYC_MOUSE_STRING(DOUBLECLICK1, DoubleClick1),
KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2),
KEYC_MOUSE_STRING(DOUBLECLICK3, DoubleClick3),
KEYC_MOUSE_STRING(DOUBLECLICK6, DoubleClick6),
KEYC_MOUSE_STRING(DOUBLECLICK7, DoubleClick7),
KEYC_MOUSE_STRING(DOUBLECLICK8, DoubleClick8),
KEYC_MOUSE_STRING(DOUBLECLICK9, DoubleClick9),
KEYC_MOUSE_STRING(DOUBLECLICK10, DoubleClick10),
KEYC_MOUSE_STRING(DOUBLECLICK11, DoubleClick11),
KEYC_MOUSE_STRING(TRIPLECLICK1, TripleClick1),
KEYC_MOUSE_STRING(TRIPLECLICK2, TripleClick2),
KEYC_MOUSE_STRING(TRIPLECLICK3, TripleClick3),
KEYC_MOUSE_STRING(TRIPLECLICK6, TripleClick6),
KEYC_MOUSE_STRING(TRIPLECLICK7, TripleClick7),
KEYC_MOUSE_STRING(TRIPLECLICK8, TripleClick8),
KEYC_MOUSE_STRING(TRIPLECLICK9, TripleClick9),
KEYC_MOUSE_STRING(TRIPLECLICK10, TripleClick10),
KEYC_MOUSE_STRING(TRIPLECLICK11, TripleClick11)
};
/* Find key string in table. */

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

View File

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

View File

@ -34,18 +34,37 @@ struct notify_entry {
int pane;
};
static struct cmdq_item *
notify_insert_one_hook(struct cmdq_item *item, struct notify_entry *ne,
struct cmd_list *cmdlist, struct cmdq_state *state)
{
struct cmdq_item *new_item;
char *s;
if (cmdlist == NULL)
return (item);
if (log_get_level() != 0) {
s = cmd_list_print(cmdlist, 0);
log_debug("%s: hook %s is: %s", __func__, ne->name, s);
free (s);
}
new_item = cmdq_get_command(cmdlist, state);
return (cmdq_insert_after(item, new_item));
}
static void
notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
{
struct cmd_find_state fs;
struct options *oo;
struct cmdq_item *new_item;
struct cmdq_state *new_state;
struct cmdq_state *state;
struct options_entry *o;
struct options_array_item *a;
struct cmd_list *cmdlist;
const char *value;
struct cmd_parse_result *pr;
log_debug("%s: %s", __func__, ne->name);
log_debug("%s: inserting hook %s", __func__, ne->name);
cmd_find_clear_state(&fs, 0);
if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs))
@ -66,23 +85,37 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
oo = fs.wl->window->options;
o = options_get(oo, ne->name);
}
if (o == NULL)
if (o == NULL) {
log_debug("%s: hook %s not found", __func__, ne->name);
return;
}
new_state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS);
cmdq_add_formats(new_state, ne->formats);
state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS);
cmdq_add_formats(state, ne->formats);
if (*ne->name == '@') {
value = options_get_string(oo, ne->name);
pr = cmd_parse_from_string(value, NULL);
switch (pr->status) {
case CMD_PARSE_ERROR:
log_debug("%s: can't parse hook %s: %s", __func__,
ne->name, pr->error);
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
notify_insert_one_hook(item, ne, pr->cmdlist, state);
break;
}
} else {
a = options_array_first(o);
while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist;
if (cmdlist != NULL) {
new_item = cmdq_get_command(cmdlist, new_state);
item = cmdq_insert_after(item, new_item);
}
item = notify_insert_one_hook(item, ne, cmdlist, state);
a = options_array_next(a);
}
}
cmdq_free_state(new_state);
cmdq_free_state(state);
}
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[] = {
"off", "top", "bottom", NULL
};
static const char *options_table_pane_border_indicators_list[] = {
"off", "colour", "arrows", "both", NULL
};
static const char *options_table_pane_border_lines_list[] = {
"single", "double", "heavy", "simple", "number", NULL
};
@ -274,6 +277,7 @@ const struct options_table_entry options_table[] = {
.minimum = 0,
.maximum = INT_MAX,
.default_num = 500,
.unit = "milliseconds",
.text = "Time to wait before assuming a key is Escape."
},
@ -797,6 +801,14 @@ const struct options_table_entry options_table[] = {
"linked to ('off')."
},
{ .name = "allow-passthrough",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 0,
.text = "Whether applications are allowed to use the escape sequence "
"to bypass tmux."
},
{ .name = "allow-rename",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
@ -870,6 +882,13 @@ const struct options_table_entry options_table[] = {
.text = "Style of the marked line in copy mode."
},
{ .name = "fill-character",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "",
.text = "Character used to fill unused parts of window."
},
{ .name = "main-pane-height",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
@ -964,12 +983,21 @@ const struct options_table_entry options_table[] = {
{ .name = "pane-border-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] "
"\"#{pane_title}\"",
.text = "Format of text in the pane status lines."
},
{ .name = "pane-border-indicators",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_pane_border_indicators_list,
.default_num = PANE_BORDER_COLOUR,
.text = "Whether to indicate the active pane by colouring border or "
"displaying arrow markers."
},
{ .name = "pane-border-lines",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
@ -1040,6 +1068,27 @@ const struct options_table_entry options_table[] = {
"killed ('off' or 'failed') when the program inside exits."
},
{ .name = "remain-on-exit-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "Pane is dead ("
"#{?#{!=:#{pane_dead_status},},"
"status #{pane_dead_status},}"
"#{?#{!=:#{pane_dead_signal},},"
"signal #{pane_dead_signal},}, "
"#{t:pane_dead_time})",
.text = "Message shown after the program in a pane has exited, if "
"remain-on-exit is enabled."
},
{ .name = "scroll-on-clear",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 1,
.text = "Whether the contents of the screen should be scrolled into"
"history when clearing the whole screen."
},
{ .name = "synchronize-panes",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
@ -1225,6 +1274,7 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_HOOK("window-linked", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-pane-changed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-renamed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-resized", ""),
OPTIONS_TABLE_HOOK("window-unlinked", ""),
{ .name = NULL }

View File

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

View File

@ -35,9 +35,6 @@
((p)->p_stat == SSTOP || (p)->p_stat == SZOMB)
struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *);
char *osdep_get_name(int, char *);
char *osdep_get_cwd(int);
struct event_base *osdep_event_init(void);
struct kinfo_proc2 *
cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2)

View File

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

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

11
proc.c
View File

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

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

View File

@ -34,19 +34,29 @@ static void screen_redraw_set_context(struct client *,
#define START_ISOLATE "\342\201\246"
#define END_ISOLATE "\342\201\251"
/* Border in relation to a pane. */
enum screen_redraw_border_type {
SCREEN_REDRAW_OUTSIDE,
SCREEN_REDRAW_INSIDE,
SCREEN_REDRAW_BORDER
SCREEN_REDRAW_BORDER_LEFT,
SCREEN_REDRAW_BORDER_RIGHT,
SCREEN_REDRAW_BORDER_TOP,
SCREEN_REDRAW_BORDER_BOTTOM
};
#define BORDER_MARKERS " +,.-"
/* Get cell border character. */
static void
screen_redraw_border_set(struct window_pane *wp, enum pane_lines pane_lines,
int cell_type, struct grid_cell *gc)
screen_redraw_border_set(struct window *w, struct window_pane *wp,
enum pane_lines pane_lines, int cell_type, struct grid_cell *gc)
{
u_int idx;
if (cell_type == CELL_OUTSIDE && w->fill_character != NULL) {
utf8_copy(&gc->data, &w->fill_character[0]);
return;
}
switch (pane_lines) {
case PANE_LINES_NUMBER:
if (cell_type == CELL_OUTSIDE) {
@ -102,64 +112,74 @@ static enum screen_redraw_border_type
screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py,
int pane_status)
{
struct options *oo = wp->window->options;
int split = 0;
u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
/* Inside pane. */
if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
return (SCREEN_REDRAW_INSIDE);
/* Get pane indicator. */
switch (options_get_number(oo, "pane-border-indicators")) {
case PANE_BORDER_COLOUR:
case PANE_BORDER_BOTH:
split = 1;
break;
}
/* Left/right borders. */
if (pane_status == PANE_STATUS_OFF) {
if (screen_redraw_two_panes(wp->window, 0)) {
if (screen_redraw_two_panes(wp->window, 0) && split) {
if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_RIGHT);
if (wp->xoff != 0 &&
px == wp->xoff - 1 &&
py > wp->sy / 2)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_LEFT);
} else {
if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
if (wp->xoff != 0 && px == wp->xoff - 1)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_LEFT);
if (px == ex)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_RIGHT);
}
}
} else {
if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
if (wp->xoff != 0 && px == wp->xoff - 1)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_LEFT);
if (px == ex)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_RIGHT);
}
}
/* Top/bottom borders. */
if (pane_status == PANE_STATUS_OFF) {
if (screen_redraw_two_panes(wp->window, 1)) {
if (screen_redraw_two_panes(wp->window, 1) && split) {
if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_BOTTOM);
if (wp->yoff != 0 &&
py == wp->yoff - 1 &&
px > wp->sx / 2)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_TOP);
} else {
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
if (wp->yoff != 0 && py == wp->yoff - 1)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_TOP);
if (py == ey)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_BOTTOM);
}
}
} else if (pane_status == PANE_STATUS_TOP) {
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
if (wp->yoff != 0 && py == wp->yoff - 1)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_TOP);
}
} else {
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
if (py == ey)
return (SCREEN_REDRAW_BORDER);
return (SCREEN_REDRAW_BORDER_BOTTOM);
}
}
@ -189,10 +209,10 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status)
switch (screen_redraw_pane_border(wp, px, py, pane_status)) {
case SCREEN_REDRAW_INSIDE:
return (0);
case SCREEN_REDRAW_BORDER:
return (1);
case SCREEN_REDRAW_OUTSIDE:
break;
default:
return (1);
}
}
@ -346,7 +366,7 @@ screen_redraw_check_is(u_int px, u_int py, int pane_status,
enum screen_redraw_border_type border;
border = screen_redraw_pane_border(wp, px, py, pane_status);
if (border == SCREEN_REDRAW_BORDER)
if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE)
return (1);
return (0);
}
@ -373,7 +393,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
style_apply(&gc, w->options, "pane-active-border-style", ft);
else
style_apply(&gc, w->options, "pane-border-style", ft);
fmt = options_get_string(w->options, "pane-border-format");
fmt = options_get_string(wp->options, "pane-border-format");
expanded = format_expand_time(ft, fmt);
if (wp->sx < 4)
@ -394,7 +414,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
else
py = wp->yoff + wp->sy;
cell_type = screen_redraw_type_of_cell(c, px, py, pane_status);
screen_redraw_border_set(wp, pane_lines, cell_type, &gc);
screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc);
screen_write_cell(&ctx, &gc);
}
gc.attr &= ~GRID_ATTR_CHARSET;
@ -637,11 +657,12 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
struct options *oo = w->options;
struct tty *tty = &c->tty;
struct format_tree *ft;
struct window_pane *wp;
struct window_pane *wp, *active = server_client_get_pane(c);
struct grid_cell gc;
const struct grid_cell *tmp;
struct overlay_ranges r;
u_int cell_type, x = ctx->ox + i, y = ctx->oy + j;
int arrows = 0, border;
int pane_status = ctx->pane_status, isolates;
if (c->overlay_check != NULL) {
@ -674,7 +695,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
screen_redraw_check_is(x, y, pane_status, marked_pane.wp))
gc.attr ^= GRID_ATTR_REVERSE;
}
screen_redraw_border_set(wp, ctx->pane_lines, cell_type, &gc);
screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc);
if (cell_type == CELL_TOPBOTTOM &&
(c->flags & CLIENT_UTF8) &&
@ -689,6 +710,34 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
tty_cursor(tty, i, j);
if (isolates)
tty_puts(tty, END_ISOLATE);
switch (options_get_number(oo, "pane-border-indicators")) {
case PANE_BORDER_ARROWS:
case PANE_BORDER_BOTH:
arrows = 1;
break;
}
if (wp != NULL && arrows) {
border = screen_redraw_pane_border(active, x, y, pane_status);
if (((i == wp->xoff + 1 &&
(cell_type == CELL_LEFTRIGHT ||
(cell_type == CELL_TOPJOIN &&
border == SCREEN_REDRAW_BORDER_BOTTOM) ||
(cell_type == CELL_BOTTOMJOIN &&
border == SCREEN_REDRAW_BORDER_TOP))) ||
(j == wp->yoff + 1 &&
(cell_type == CELL_TOPBOTTOM ||
(cell_type == CELL_LEFTJOIN &&
border == SCREEN_REDRAW_BORDER_RIGHT) ||
(cell_type == CELL_RIGHTJOIN &&
border == SCREEN_REDRAW_BORDER_LEFT)))) &&
screen_redraw_check_is(x, y, pane_status, active)) {
gc.attr |= GRID_ATTR_CHARSET;
utf8_set(&gc.data, BORDER_MARKERS[border]);
}
}
tty_cell(tty, &gc, &grid_default_cell, NULL);
if (isolates)
tty_puts(tty, START_ISOLATE);

View File

@ -1476,7 +1476,11 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
ttyctx.bg = bg;
/* Scroll into history if it is enabled and clearing entire screen. */
if (s->cx == 0 && s->cy == 0 && (gd->flags & GRID_HISTORY))
if (s->cx == 0 &&
s->cy == 0 &&
(gd->flags & GRID_HISTORY) &&
ctx->wp != NULL &&
options_get_number(ctx->wp->options, "scroll-on-clear"))
grid_view_clear_history(gd, bg);
else {
if (s->cx <= sx - 1)
@ -1530,7 +1534,9 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
ttyctx.bg = bg;
/* Scroll into history if it is enabled. */
if (s->grid->flags & GRID_HISTORY)
if ((s->grid->flags & GRID_HISTORY) &&
ctx->wp != NULL &&
options_get_number(ctx->wp->options, "scroll-on-clear"))
grid_view_clear_history(s->grid, bg);
else
grid_view_clear(s->grid, 0, 0, sx, sy, bg);

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_modes(struct client *);
static void server_client_set_title(struct client *);
static void server_client_set_path(struct client *);
static void server_client_reset_state(struct client *);
static int server_client_assume_paste(struct session *);
static void server_client_update_latest(struct client *);
@ -422,6 +423,7 @@ server_client_lost(struct client *c)
if (c->flags & CLIENT_TERMINAL)
tty_free(&c->tty);
free(c->ttyname);
free(c->clipboard_panes);
free(c->term_name);
free(c->term_type);
@ -593,11 +595,11 @@ server_client_check_mouse(struct client *c, struct key_event *event)
log_debug("double-click at %u,%u", x, y);
} else if ((m->sgr_type != ' ' &&
MOUSE_DRAG(m->sgr_b) &&
MOUSE_BUTTONS(m->sgr_b) == 3) ||
MOUSE_RELEASE(m->sgr_b)) ||
(m->sgr_type == ' ' &&
MOUSE_DRAG(m->b) &&
MOUSE_BUTTONS(m->b) == 3 &&
MOUSE_BUTTONS(m->lb) == 3)) {
MOUSE_RELEASE(m->b) &&
MOUSE_RELEASE(m->lb))) {
type = MOVE;
x = m->x, y = m->y, b = 0;
log_debug("move at %u,%u", x, y);
@ -750,7 +752,7 @@ have_event:
m->wp = -1;
/* Stop dragging if needed. */
if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag) {
if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag != 0) {
if (c->tty.mouse_drag_release != NULL)
c->tty.mouse_drag_release(c, m);
@ -761,8 +763,8 @@ have_event:
* End a mouse drag by passing a MouseDragEnd key corresponding
* to the button that started the drag.
*/
switch (c->tty.mouse_drag_flag) {
case 1:
switch (c->tty.mouse_drag_flag - 1) {
case MOUSE_BUTTON_1:
if (where == PANE)
key = KEYC_MOUSEDRAGEND1_PANE;
if (where == STATUS)
@ -776,7 +778,7 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEDRAGEND1_BORDER;
break;
case 2:
case MOUSE_BUTTON_2:
if (where == PANE)
key = KEYC_MOUSEDRAGEND2_PANE;
if (where == STATUS)
@ -790,7 +792,7 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEDRAGEND2_BORDER;
break;
case 3:
case MOUSE_BUTTON_3:
if (where == PANE)
key = KEYC_MOUSEDRAGEND3_PANE;
if (where == STATUS)
@ -804,6 +806,90 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEDRAGEND3_BORDER;
break;
case MOUSE_BUTTON_6:
if (where == PANE)
key = KEYC_MOUSEDRAGEND6_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAGEND6_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAGEND6_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAGEND6_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAGEND6_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAGEND6_BORDER;
break;
case MOUSE_BUTTON_7:
if (where == PANE)
key = KEYC_MOUSEDRAGEND7_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAGEND7_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAGEND7_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAGEND7_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAGEND7_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAGEND7_BORDER;
break;
case MOUSE_BUTTON_8:
if (where == PANE)
key = KEYC_MOUSEDRAGEND8_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAGEND8_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAGEND8_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAGEND8_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAGEND8_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAGEND8_BORDER;
break;
case MOUSE_BUTTON_9:
if (where == PANE)
key = KEYC_MOUSEDRAGEND9_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAGEND9_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAGEND9_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAGEND9_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAGEND9_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAGEND9_BORDER;
break;
case MOUSE_BUTTON_10:
if (where == PANE)
key = KEYC_MOUSEDRAGEND10_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAGEND10_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAGEND10_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAGEND10_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAGEND10_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAGEND10_BORDER;
break;
case MOUSE_BUTTON_11:
if (where == PANE)
key = KEYC_MOUSEDRAGEND11_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAGEND11_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAGEND11_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAGEND11_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAGEND11_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAGEND11_BORDER;
break;
default:
key = KEYC_MOUSE;
break;
@ -836,7 +922,7 @@ have_event:
key = KEYC_DRAGGING;
else {
switch (MOUSE_BUTTONS(b)) {
case 0:
case MOUSE_BUTTON_1:
if (where == PANE)
key = KEYC_MOUSEDRAG1_PANE;
if (where == STATUS)
@ -850,7 +936,7 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEDRAG1_BORDER;
break;
case 1:
case MOUSE_BUTTON_2:
if (where == PANE)
key = KEYC_MOUSEDRAG2_PANE;
if (where == STATUS)
@ -864,7 +950,7 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEDRAG2_BORDER;
break;
case 2:
case MOUSE_BUTTON_3:
if (where == PANE)
key = KEYC_MOUSEDRAG3_PANE;
if (where == STATUS)
@ -878,6 +964,90 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEDRAG3_BORDER;
break;
case MOUSE_BUTTON_6:
if (where == PANE)
key = KEYC_MOUSEDRAG6_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAG6_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAG6_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAG6_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAG6_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAG6_BORDER;
break;
case MOUSE_BUTTON_7:
if (where == PANE)
key = KEYC_MOUSEDRAG7_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAG7_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAG7_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAG7_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAG7_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAG7_BORDER;
break;
case MOUSE_BUTTON_8:
if (where == PANE)
key = KEYC_MOUSEDRAG8_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAG8_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAG8_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAG8_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAG8_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAG8_BORDER;
break;
case MOUSE_BUTTON_9:
if (where == PANE)
key = KEYC_MOUSEDRAG9_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAG9_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAG9_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAG9_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAG9_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAG9_BORDER;
break;
case MOUSE_BUTTON_10:
if (where == PANE)
key = KEYC_MOUSEDRAG10_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAG10_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAG10_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAG10_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAG10_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAG10_BORDER;
break;
case MOUSE_BUTTON_11:
if (where == PANE)
key = KEYC_MOUSEDRAG11_PANE;
if (where == STATUS)
key = KEYC_MOUSEDRAG11_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDRAG11_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDRAG11_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDRAG11_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDRAG11_BORDER;
break;
}
}
@ -918,7 +1088,7 @@ have_event:
break;
case UP:
switch (MOUSE_BUTTONS(b)) {
case 0:
case MOUSE_BUTTON_1:
if (where == PANE)
key = KEYC_MOUSEUP1_PANE;
if (where == STATUS)
@ -932,7 +1102,7 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEUP1_BORDER;
break;
case 1:
case MOUSE_BUTTON_2:
if (where == PANE)
key = KEYC_MOUSEUP2_PANE;
if (where == STATUS)
@ -946,7 +1116,7 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEUP2_BORDER;
break;
case 2:
case MOUSE_BUTTON_3:
if (where == PANE)
key = KEYC_MOUSEUP3_PANE;
if (where == STATUS)
@ -960,11 +1130,95 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEUP3_BORDER;
break;
case MOUSE_BUTTON_6:
if (where == PANE)
key = KEYC_MOUSEUP6_PANE;
if (where == STATUS)
key = KEYC_MOUSEUP6_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEUP6_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEUP6_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEUP6_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEUP6_BORDER;
break;
case MOUSE_BUTTON_7:
if (where == PANE)
key = KEYC_MOUSEUP7_PANE;
if (where == STATUS)
key = KEYC_MOUSEUP7_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEUP7_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEUP7_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEUP7_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEUP7_BORDER;
break;
case MOUSE_BUTTON_8:
if (where == PANE)
key = KEYC_MOUSEUP8_PANE;
if (where == STATUS)
key = KEYC_MOUSEUP8_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEUP8_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEUP8_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEUP8_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEUP8_BORDER;
break;
case MOUSE_BUTTON_9:
if (where == PANE)
key = KEYC_MOUSEUP9_PANE;
if (where == STATUS)
key = KEYC_MOUSEUP9_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEUP9_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEUP9_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEUP9_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEUP9_BORDER;
break;
case MOUSE_BUTTON_10:
if (where == PANE)
key = KEYC_MOUSEUP1_PANE;
if (where == STATUS)
key = KEYC_MOUSEUP1_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEUP1_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEUP1_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEUP1_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEUP1_BORDER;
break;
case MOUSE_BUTTON_11:
if (where == PANE)
key = KEYC_MOUSEUP11_PANE;
if (where == STATUS)
key = KEYC_MOUSEUP11_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEUP11_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEUP11_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEUP11_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEUP11_BORDER;
break;
}
break;
case DOWN:
switch (MOUSE_BUTTONS(b)) {
case 0:
case MOUSE_BUTTON_1:
if (where == PANE)
key = KEYC_MOUSEDOWN1_PANE;
if (where == STATUS)
@ -978,7 +1232,7 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEDOWN1_BORDER;
break;
case 1:
case MOUSE_BUTTON_2:
if (where == PANE)
key = KEYC_MOUSEDOWN2_PANE;
if (where == STATUS)
@ -992,7 +1246,7 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEDOWN2_BORDER;
break;
case 2:
case MOUSE_BUTTON_3:
if (where == PANE)
key = KEYC_MOUSEDOWN3_PANE;
if (where == STATUS)
@ -1006,11 +1260,95 @@ have_event:
if (where == BORDER)
key = KEYC_MOUSEDOWN3_BORDER;
break;
case MOUSE_BUTTON_6:
if (where == PANE)
key = KEYC_MOUSEDOWN6_PANE;
if (where == STATUS)
key = KEYC_MOUSEDOWN6_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDOWN6_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDOWN6_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDOWN6_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDOWN6_BORDER;
break;
case MOUSE_BUTTON_7:
if (where == PANE)
key = KEYC_MOUSEDOWN7_PANE;
if (where == STATUS)
key = KEYC_MOUSEDOWN7_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDOWN7_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDOWN7_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDOWN7_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDOWN7_BORDER;
break;
case MOUSE_BUTTON_8:
if (where == PANE)
key = KEYC_MOUSEDOWN8_PANE;
if (where == STATUS)
key = KEYC_MOUSEDOWN8_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDOWN8_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDOWN8_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDOWN8_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDOWN8_BORDER;
break;
case MOUSE_BUTTON_9:
if (where == PANE)
key = KEYC_MOUSEDOWN9_PANE;
if (where == STATUS)
key = KEYC_MOUSEDOWN9_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDOWN9_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDOWN9_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDOWN9_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDOWN9_BORDER;
break;
case MOUSE_BUTTON_10:
if (where == PANE)
key = KEYC_MOUSEDOWN10_PANE;
if (where == STATUS)
key = KEYC_MOUSEDOWN10_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDOWN10_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDOWN10_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDOWN10_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDOWN10_BORDER;
break;
case MOUSE_BUTTON_11:
if (where == PANE)
key = KEYC_MOUSEDOWN11_PANE;
if (where == STATUS)
key = KEYC_MOUSEDOWN11_STATUS;
if (where == STATUS_LEFT)
key = KEYC_MOUSEDOWN11_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_MOUSEDOWN11_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_MOUSEDOWN11_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_MOUSEDOWN11_BORDER;
break;
}
break;
case SECOND:
switch (MOUSE_BUTTONS(b)) {
case 0:
case MOUSE_BUTTON_1:
if (where == PANE)
key = KEYC_SECONDCLICK1_PANE;
if (where == STATUS)
@ -1024,7 +1362,7 @@ have_event:
if (where == BORDER)
key = KEYC_SECONDCLICK1_BORDER;
break;
case 1:
case MOUSE_BUTTON_2:
if (where == PANE)
key = KEYC_SECONDCLICK2_PANE;
if (where == STATUS)
@ -1038,7 +1376,7 @@ have_event:
if (where == BORDER)
key = KEYC_SECONDCLICK2_BORDER;
break;
case 2:
case MOUSE_BUTTON_3:
if (where == PANE)
key = KEYC_SECONDCLICK3_PANE;
if (where == STATUS)
@ -1052,11 +1390,95 @@ have_event:
if (where == BORDER)
key = KEYC_SECONDCLICK3_BORDER;
break;
case MOUSE_BUTTON_6:
if (where == PANE)
key = KEYC_SECONDCLICK6_PANE;
if (where == STATUS)
key = KEYC_SECONDCLICK6_STATUS;
if (where == STATUS_LEFT)
key = KEYC_SECONDCLICK6_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_SECONDCLICK6_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_SECONDCLICK6_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_SECONDCLICK6_BORDER;
break;
case MOUSE_BUTTON_7:
if (where == PANE)
key = KEYC_SECONDCLICK7_PANE;
if (where == STATUS)
key = KEYC_SECONDCLICK7_STATUS;
if (where == STATUS_LEFT)
key = KEYC_SECONDCLICK7_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_SECONDCLICK7_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_SECONDCLICK7_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_SECONDCLICK7_BORDER;
break;
case MOUSE_BUTTON_8:
if (where == PANE)
key = KEYC_SECONDCLICK8_PANE;
if (where == STATUS)
key = KEYC_SECONDCLICK8_STATUS;
if (where == STATUS_LEFT)
key = KEYC_SECONDCLICK8_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_SECONDCLICK8_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_SECONDCLICK8_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_SECONDCLICK8_BORDER;
break;
case MOUSE_BUTTON_9:
if (where == PANE)
key = KEYC_SECONDCLICK9_PANE;
if (where == STATUS)
key = KEYC_SECONDCLICK9_STATUS;
if (where == STATUS_LEFT)
key = KEYC_SECONDCLICK9_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_SECONDCLICK9_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_SECONDCLICK9_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_SECONDCLICK9_BORDER;
break;
case MOUSE_BUTTON_10:
if (where == PANE)
key = KEYC_SECONDCLICK10_PANE;
if (where == STATUS)
key = KEYC_SECONDCLICK10_STATUS;
if (where == STATUS_LEFT)
key = KEYC_SECONDCLICK10_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_SECONDCLICK10_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_SECONDCLICK10_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_SECONDCLICK10_BORDER;
break;
case MOUSE_BUTTON_11:
if (where == PANE)
key = KEYC_SECONDCLICK11_PANE;
if (where == STATUS)
key = KEYC_SECONDCLICK11_STATUS;
if (where == STATUS_LEFT)
key = KEYC_SECONDCLICK11_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_SECONDCLICK11_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_SECONDCLICK11_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_SECONDCLICK11_BORDER;
break;
}
break;
case DOUBLE:
switch (MOUSE_BUTTONS(b)) {
case 0:
case MOUSE_BUTTON_1:
if (where == PANE)
key = KEYC_DOUBLECLICK1_PANE;
if (where == STATUS)
@ -1070,7 +1492,7 @@ have_event:
if (where == BORDER)
key = KEYC_DOUBLECLICK1_BORDER;
break;
case 1:
case MOUSE_BUTTON_2:
if (where == PANE)
key = KEYC_DOUBLECLICK2_PANE;
if (where == STATUS)
@ -1084,7 +1506,7 @@ have_event:
if (where == BORDER)
key = KEYC_DOUBLECLICK2_BORDER;
break;
case 2:
case MOUSE_BUTTON_3:
if (where == PANE)
key = KEYC_DOUBLECLICK3_PANE;
if (where == STATUS)
@ -1098,11 +1520,95 @@ have_event:
if (where == BORDER)
key = KEYC_DOUBLECLICK3_BORDER;
break;
case MOUSE_BUTTON_6:
if (where == PANE)
key = KEYC_DOUBLECLICK6_PANE;
if (where == STATUS)
key = KEYC_DOUBLECLICK6_STATUS;
if (where == STATUS_LEFT)
key = KEYC_DOUBLECLICK6_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_DOUBLECLICK6_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_DOUBLECLICK6_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_DOUBLECLICK6_BORDER;
break;
case MOUSE_BUTTON_7:
if (where == PANE)
key = KEYC_DOUBLECLICK7_PANE;
if (where == STATUS)
key = KEYC_DOUBLECLICK7_STATUS;
if (where == STATUS_LEFT)
key = KEYC_DOUBLECLICK7_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_DOUBLECLICK7_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_DOUBLECLICK7_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_DOUBLECLICK7_BORDER;
break;
case MOUSE_BUTTON_8:
if (where == PANE)
key = KEYC_DOUBLECLICK8_PANE;
if (where == STATUS)
key = KEYC_DOUBLECLICK8_STATUS;
if (where == STATUS_LEFT)
key = KEYC_DOUBLECLICK8_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_DOUBLECLICK8_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_DOUBLECLICK8_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_DOUBLECLICK8_BORDER;
break;
case MOUSE_BUTTON_9:
if (where == PANE)
key = KEYC_DOUBLECLICK9_PANE;
if (where == STATUS)
key = KEYC_DOUBLECLICK9_STATUS;
if (where == STATUS_LEFT)
key = KEYC_DOUBLECLICK9_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_DOUBLECLICK9_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_DOUBLECLICK9_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_DOUBLECLICK9_BORDER;
break;
case MOUSE_BUTTON_10:
if (where == PANE)
key = KEYC_DOUBLECLICK10_PANE;
if (where == STATUS)
key = KEYC_DOUBLECLICK10_STATUS;
if (where == STATUS_LEFT)
key = KEYC_DOUBLECLICK10_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_DOUBLECLICK10_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_DOUBLECLICK10_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_DOUBLECLICK10_BORDER;
break;
case MOUSE_BUTTON_11:
if (where == PANE)
key = KEYC_DOUBLECLICK11_PANE;
if (where == STATUS)
key = KEYC_DOUBLECLICK11_STATUS;
if (where == STATUS_LEFT)
key = KEYC_DOUBLECLICK11_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_DOUBLECLICK11_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_DOUBLECLICK11_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_DOUBLECLICK11_BORDER;
break;
}
break;
case TRIPLE:
switch (MOUSE_BUTTONS(b)) {
case 0:
case MOUSE_BUTTON_1:
if (where == PANE)
key = KEYC_TRIPLECLICK1_PANE;
if (where == STATUS)
@ -1116,7 +1622,7 @@ have_event:
if (where == BORDER)
key = KEYC_TRIPLECLICK1_BORDER;
break;
case 1:
case MOUSE_BUTTON_2:
if (where == PANE)
key = KEYC_TRIPLECLICK2_PANE;
if (where == STATUS)
@ -1130,7 +1636,7 @@ have_event:
if (where == BORDER)
key = KEYC_TRIPLECLICK2_BORDER;
break;
case 2:
case MOUSE_BUTTON_3:
if (where == PANE)
key = KEYC_TRIPLECLICK3_PANE;
if (where == STATUS)
@ -1144,6 +1650,90 @@ have_event:
if (where == BORDER)
key = KEYC_TRIPLECLICK3_BORDER;
break;
case MOUSE_BUTTON_6:
if (where == PANE)
key = KEYC_TRIPLECLICK6_PANE;
if (where == STATUS)
key = KEYC_TRIPLECLICK6_STATUS;
if (where == STATUS_LEFT)
key = KEYC_TRIPLECLICK6_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_TRIPLECLICK6_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_TRIPLECLICK6_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_TRIPLECLICK6_BORDER;
break;
case MOUSE_BUTTON_7:
if (where == PANE)
key = KEYC_TRIPLECLICK7_PANE;
if (where == STATUS)
key = KEYC_TRIPLECLICK7_STATUS;
if (where == STATUS_LEFT)
key = KEYC_TRIPLECLICK7_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_TRIPLECLICK7_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_TRIPLECLICK7_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_TRIPLECLICK7_BORDER;
break;
case MOUSE_BUTTON_8:
if (where == PANE)
key = KEYC_TRIPLECLICK8_PANE;
if (where == STATUS)
key = KEYC_TRIPLECLICK8_STATUS;
if (where == STATUS_LEFT)
key = KEYC_TRIPLECLICK8_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_TRIPLECLICK8_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_TRIPLECLICK8_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_TRIPLECLICK8_BORDER;
break;
case MOUSE_BUTTON_9:
if (where == PANE)
key = KEYC_TRIPLECLICK9_PANE;
if (where == STATUS)
key = KEYC_TRIPLECLICK9_STATUS;
if (where == STATUS_LEFT)
key = KEYC_TRIPLECLICK9_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_TRIPLECLICK9_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_TRIPLECLICK9_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_TRIPLECLICK9_BORDER;
break;
case MOUSE_BUTTON_10:
if (where == PANE)
key = KEYC_TRIPLECLICK10_PANE;
if (where == STATUS)
key = KEYC_TRIPLECLICK10_STATUS;
if (where == STATUS_LEFT)
key = KEYC_TRIPLECLICK10_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_TRIPLECLICK10_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_TRIPLECLICK10_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_TRIPLECLICK10_BORDER;
break;
case MOUSE_BUTTON_11:
if (where == PANE)
key = KEYC_TRIPLECLICK11_PANE;
if (where == STATUS)
key = KEYC_TRIPLECLICK11_STATUS;
if (where == STATUS_LEFT)
key = KEYC_TRIPLECLICK11_STATUS_LEFT;
if (where == STATUS_RIGHT)
key = KEYC_TRIPLECLICK11_STATUS_RIGHT;
if (where == STATUS_DEFAULT)
key = KEYC_TRIPLECLICK11_STATUS_DEFAULT;
if (where == BORDER)
key = KEYC_TRIPLECLICK11_BORDER;
break;
}
break;
}
@ -2011,8 +2601,10 @@ server_client_check_redraw(struct client *c)
}
if (c->flags & CLIENT_ALLREDRAWFLAGS) {
if (options_get_number(s->options, "set-titles"))
if (options_get_number(s->options, "set-titles")) {
server_client_set_title(c);
server_client_set_path(c);
}
screen_redraw_screen(c);
}
@ -2058,6 +2650,26 @@ server_client_set_title(struct client *c)
format_free(ft);
}
/* Set client path. */
static void
server_client_set_path(struct client *c)
{
struct session *s = c->session;
const char *path;
if (s->curw == NULL)
return;
if (s->curw->window->active->base.path == NULL)
path = "";
else
path = s->curw->window->active->base.path;
if (c->path == NULL || strcmp(path, c->path) != 0) {
free(c->path);
c->path = xstrdup(path);
tty_set_path(&c->tty, c->path);
}
}
/* Dispatch message from client. */
static void
server_client_dispatch(struct imsg *imsg, void *arg)

View File

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

View File

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

View File

@ -27,7 +27,7 @@
#include "tmux.h"
struct sessions sessions;
static u_int next_session_id;
u_int next_session_id;
struct session_groups session_groups = RB_INITIALIZER(&session_groups);
static void session_free(int, short, void *);
@ -501,6 +501,7 @@ session_set_current(struct session *s, struct winlink *wl)
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
if (options_get_number(global_options, "focus-events")) {
if (old != NULL)
window_update_focus(old->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);
}
} else {
screen_write_box(&ctx, sx, sy);
screen_write_box(&ctx, sx, sy, BOX_LINES_DEFAULT, NULL, NULL);
for (y = 1; y < sy - 1; y++) {
for (x = 1; x < sx - 1; x++)
grid_view_set_cell(s->grid, x, y, &gc);

View File

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

92
tmux.1
View File

@ -43,7 +43,7 @@ then later reattached.
.Pp
When
.Nm
is started it creates a new
is started, it creates a new
.Em session
with a single
.Em window
@ -140,7 +140,10 @@ By default,
loads the system configuration file from
.Pa @SYSCONFDIR@/tmux.conf ,
if present, then looks for a user configuration file at
.Pa ~/.tmux.conf .
.Pa ~/.tmux.conf,
.Pa $XDG_CONFIG_HOME/tmux/tmux.conf
or
.Pa ~/.config/tmux/tmux.conf .
.Pp
The configuration file is a set of
.Nm
@ -1338,11 +1341,12 @@ and sets an environment variable for the newly created session; it may be
specified multiple times.
.Tg refresh
.It Xo Ic refresh-client
.Op Fl cDlLRSU
.Op Fl cDLRSU
.Op Fl A Ar pane:state
.Op Fl B Ar name:what:format
.Op Fl C Ar size
.Op Fl f Ar flags
.Op Fl l Op Ar target-pane
.Op Fl t Ar target-client
.Op Ar adjustment
.Xc
@ -1456,7 +1460,11 @@ sets a comma-separated list of client flags, see
.Fl l
requests the clipboard from the client using the
.Xr xterm 1
escape sequence and stores it in a new paste buffer.
escape sequence.
If
Ar target-pane
is given, the clipboard is sent (in encoded form), otherwise it is stored in a
new paste buffer.
.Pp
.Fl L ,
.Fl R ,
@ -1773,6 +1781,7 @@ The following commands are supported in copy mode:
.It Li "set-mark" Ta "X" Ta "X"
.It Li "start-of-line" Ta "0" Ta "C-a"
.It Li "stop-selection" Ta "" Ta ""
.It Li "toggle-position" Ta "P" Ta "P"
.It Li "top-line" Ta "H" Ta "M-R"
.El
.Pp
@ -3618,6 +3627,8 @@ Supports DECSLRM margins.
Supports
.Xr xterm 1
mouse sequences.
.It osc7
Supports the OSC 7 working directory extension.
.It overline
Supports the overline SGR attribute.
.It rectfill
@ -4108,6 +4119,9 @@ Set clock colour.
.Xc
Set clock hour format.
.Pp
.It Ic fill-character Ar character
Set the character used to fill areas of the terminal unused by a window.
.Pp
.It Ic main-pane-height Ar height
.It Ic main-pane-width Ar width
Set the width or height of the main (left or top) pane in the
@ -4223,6 +4237,12 @@ but set the starting index for pane numbers.
.It Ic pane-border-format Ar format
Set the text shown in pane border status lines.
.Pp
.It Xo Ic pane-border-indicators
.Op Ic off | colour | arrows | both
.Xc
Indicate active pane by colouring only half of the border in windows with
exactly two panes, by displaying arrow markers, by drawing both or neither.
.Pp
.It Ic pane-border-lines Ar type
Set the type of characters used for drawing pane borders.
.Ar type
@ -4396,6 +4416,13 @@ The default is on.
Available pane options are:
.Pp
.Bl -tag -width Ds -compact
.It Xo Ic allow-passthrough
.Op Ic on | off
.Xc
Allow programs in the pane to bypass
.Nm
using a terminal escape sequence (\eePtmux;...\ee\e\e).
.Pp
.It Xo Ic allow-rename
.Op Ic on | off
.Xc
@ -4449,6 +4476,17 @@ The pane may be reactivated with the
.Ic respawn-pane
command.
.Pp
.It Ic remain-on-exit-format Ar string
Set the text shown at the bottom of exited panes when
.Ic remain-on-exit
is enabled.
.Pp
.It Xo Ic scroll-on-clear
.Op Ic on | off
.Xc
When the entire screen is cleared and this option is on, scroll the contents of
the screen into history before clearing it.
.Pp
.It Xo Ic synchronize-panes
.Op Ic on | off
.Xc
@ -4575,6 +4613,11 @@ Run when a session is renamed.
Run when a window is linked into a session.
.It window-renamed
Run when a window is renamed.
.It window-resized
Run when a window is resized.
This may be after the
.Ar client-resized
hook is run.
.It window-unlinked
Run when a window is unlinked from a session.
.El
@ -4989,7 +5032,9 @@ commands to finish; instead, the previous result from running the same command i
or a placeholder if the command has not been run before.
If the command hasn't exited, the most recent line of output will be used, but the status
line will not be updated more than once a second.
Commands are executed with the
Commands are executed using
.Pa /bin/sh
and with the
.Nm
global environment set (see the
.Sx GLOBAL AND SESSION ENVIRONMENT
@ -5033,6 +5078,8 @@ The following variables are available, where appropriate:
.It Li "client_termname" Ta "" Ta "Terminal name of client"
.It Li "client_termtype" Ta "" Ta "Terminal type of client, if available"
.It Li "client_tty" Ta "" Ta "Pseudo terminal of client"
.It Li "client_uid" Ta "" Ta "UID of client process"
.It Li "client_user" Ta "" Ta "User of client process"
.It Li "client_utf8" Ta "" Ta "1 if client supports UTF-8"
.It Li "client_width" Ta "" Ta "Width of client"
.It Li "client_written" Ta "" Ta "Bytes written to client"
@ -5077,6 +5124,7 @@ The following variables are available, where appropriate:
.It Li "mouse_word" Ta "" Ta "Word under mouse, if any"
.It Li "mouse_x" Ta "" Ta "Mouse X position, if any"
.It Li "mouse_y" Ta "" Ta "Mouse Y position, if any"
.It Li "next_session_id" Ta "" Ta "Unique session ID for next new session"
.It Li "origin_flag" Ta "" Ta "Pane origin flag"
.It Li "pane_active" Ta "" Ta "1 if active pane"
.It Li "pane_at_bottom" Ta "" Ta "1 if pane is at the bottom of window"
@ -5088,7 +5136,9 @@ The following variables are available, where appropriate:
.It Li "pane_current_command" Ta "" Ta "Current command if available"
.It Li "pane_current_path" Ta "" Ta "Current path if available"
.It Li "pane_dead" Ta "" Ta "1 if pane is dead"
.It Li "pane_dead_signal" Ta "" Ta "Exit signal of process in dead pane"
.It Li "pane_dead_status" Ta "" Ta "Exit status of process in dead pane"
.It Li "pane_dead_time" Ta "" Ta "Exit time of process in dead pane"
.It Li "pane_fg" Ta "" Ta "Pane foreground colour"
.It Li "pane_format" Ta "" Ta "1 if format is for a pane"
.It Li "pane_height" Ta "" Ta "Height of pane"
@ -5149,6 +5199,8 @@ The following variables are available, where appropriate:
.It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "socket_path" Ta "" Ta "Server socket path"
.It Li "start_time" Ta "" Ta "Server start time"
.It Li "uid" Ta "" Ta "Server UID"
.It Li "user" Ta "" Ta "Server user"
.It Li "version" Ta "" Ta "Server version"
.It Li "window_active" Ta "" Ta "1 if window active"
.It Li "window_active_clients" Ta "" Ta "Number of clients viewing this window"
@ -5163,7 +5215,6 @@ The following variables are available, where appropriate:
.It Li "window_cell_width" Ta "" Ta "Width of each cell in pixels"
.It Li "window_end_flag" Ta "" Ta "1 if window has the highest index"
.It Li "window_flags" Ta "#F" Ta "Window flags with # escaped as ##"
.It Li "window_raw_flags" Ta "" Ta "Window flags with nothing escaped"
.It Li "window_format" Ta "" Ta "1 if format is for a window"
.It Li "window_height" Ta "" Ta "Height of window"
.It Li "window_id" Ta "" Ta "Unique window ID"
@ -5178,6 +5229,7 @@ The following variables are available, where appropriate:
.It Li "window_offset_x" Ta "" Ta "X offset into window if larger than client"
.It Li "window_offset_y" Ta "" Ta "Y offset into window if larger than client"
.It Li "window_panes" Ta "" Ta "Number of panes in window"
.It Li "window_raw_flags" Ta "" Ta "Window flags with nothing escaped"
.It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert"
.It Li "window_stack_index" Ta "" Ta "Index in session most recent stack"
.It Li "window_start_flag" Ta "" Ta "1 if window has the lowest index"
@ -5866,7 +5918,7 @@ does not surround the popup by a border.
sets the type of border line for the popup.
When
.Fl B
is specified the
is specified, the
.Fl b
option is ignored.
See
@ -6155,6 +6207,8 @@ Execute the first
.Ar command
if
.Ar shell-command
(run with
.Pa /bin/sh )
returns success or the second
.Ar command
otherwise.
@ -6191,6 +6245,8 @@ option.
.D1 Pq alias: Ic run
Execute
.Ar shell-command
using
.Pa /bin/sh
or (with
.Fl C )
a
@ -6292,6 +6348,11 @@ to change the cursor colour from inside
.Bd -literal -offset indent
$ printf '\e033]12;red\e033\e\e'
.Ed
.Pp
The colour is an
.Xr X 7
colour, see
.Xr XParseColor 3 .
.It Em \&Cmg, \&Clmg, \&Dsmg , \&Enmg
Set, clear, disable or enable DECSLRM margins.
These are set automatically if the terminal reports it is
@ -6335,6 +6396,11 @@ $ printf '\e033[4 q'
If
.Em Se
is not set, \&Ss with argument 0 will be used to reset the cursor style instead.
.It Em \&Swd
Set the opening sequence for the working directory notification.
The sequence is terminated using the standard
.Em fsl
capability.
.It Em \&Sxl
Indicates that the terminal supports SIXEL.
.It Em \&Sync
@ -6509,6 +6575,14 @@ are for future use and should be ignored.
The window with ID
.Ar window-id
was created but is not linked to the current session.
.It Ic %unlinked-window-close Ar window-id
The window with ID
.Ar window-id ,
which is not linked to the current session, was closed.
.It Ic %unlinked-window-renamed Ar window-id
The window with ID
.Ar window-id ,
which is not linked to the current session, was renamed.
.It Ic %window-add Ar window-id
The window with ID
.Ar window-id
@ -6567,7 +6641,7 @@ are replaced with underscores
For input,
.Nm
always runs with a UTF-8 locale.
If en_US.UTF-8 is provided by the operating system it is used and
If en_US.UTF-8 is provided by the operating system, it is used and
.Ev LC_CTYPE
is ignored for input.
Otherwise,
@ -6616,6 +6690,8 @@ options.
.Sh FILES
.Bl -tag -width "@SYSCONFDIR@/tmux.confXXX" -compact
.It Pa ~/.tmux.conf
.It Pa $XDG_CONFIG_HOME/tmux/tmux.conf
.It Pa ~/.config/tmux/tmux.conf
Default
.Nm
configuration file.

106
tmux.h
View File

@ -203,26 +203,68 @@ enum {
KEYC_MOUSE_KEY(MOUSEDOWN1),
KEYC_MOUSE_KEY(MOUSEDOWN2),
KEYC_MOUSE_KEY(MOUSEDOWN3),
KEYC_MOUSE_KEY(MOUSEDOWN6),
KEYC_MOUSE_KEY(MOUSEDOWN7),
KEYC_MOUSE_KEY(MOUSEDOWN8),
KEYC_MOUSE_KEY(MOUSEDOWN9),
KEYC_MOUSE_KEY(MOUSEDOWN10),
KEYC_MOUSE_KEY(MOUSEDOWN11),
KEYC_MOUSE_KEY(MOUSEUP1),
KEYC_MOUSE_KEY(MOUSEUP2),
KEYC_MOUSE_KEY(MOUSEUP3),
KEYC_MOUSE_KEY(MOUSEUP6),
KEYC_MOUSE_KEY(MOUSEUP7),
KEYC_MOUSE_KEY(MOUSEUP8),
KEYC_MOUSE_KEY(MOUSEUP9),
KEYC_MOUSE_KEY(MOUSEUP10),
KEYC_MOUSE_KEY(MOUSEUP11),
KEYC_MOUSE_KEY(MOUSEDRAG1),
KEYC_MOUSE_KEY(MOUSEDRAG2),
KEYC_MOUSE_KEY(MOUSEDRAG3),
KEYC_MOUSE_KEY(MOUSEDRAG6),
KEYC_MOUSE_KEY(MOUSEDRAG7),
KEYC_MOUSE_KEY(MOUSEDRAG8),
KEYC_MOUSE_KEY(MOUSEDRAG9),
KEYC_MOUSE_KEY(MOUSEDRAG10),
KEYC_MOUSE_KEY(MOUSEDRAG11),
KEYC_MOUSE_KEY(MOUSEDRAGEND1),
KEYC_MOUSE_KEY(MOUSEDRAGEND2),
KEYC_MOUSE_KEY(MOUSEDRAGEND3),
KEYC_MOUSE_KEY(MOUSEDRAGEND6),
KEYC_MOUSE_KEY(MOUSEDRAGEND7),
KEYC_MOUSE_KEY(MOUSEDRAGEND8),
KEYC_MOUSE_KEY(MOUSEDRAGEND9),
KEYC_MOUSE_KEY(MOUSEDRAGEND10),
KEYC_MOUSE_KEY(MOUSEDRAGEND11),
KEYC_MOUSE_KEY(WHEELUP),
KEYC_MOUSE_KEY(WHEELDOWN),
KEYC_MOUSE_KEY(SECONDCLICK1),
KEYC_MOUSE_KEY(SECONDCLICK2),
KEYC_MOUSE_KEY(SECONDCLICK3),
KEYC_MOUSE_KEY(SECONDCLICK6),
KEYC_MOUSE_KEY(SECONDCLICK7),
KEYC_MOUSE_KEY(SECONDCLICK8),
KEYC_MOUSE_KEY(SECONDCLICK9),
KEYC_MOUSE_KEY(SECONDCLICK10),
KEYC_MOUSE_KEY(SECONDCLICK11),
KEYC_MOUSE_KEY(DOUBLECLICK1),
KEYC_MOUSE_KEY(DOUBLECLICK2),
KEYC_MOUSE_KEY(DOUBLECLICK3),
KEYC_MOUSE_KEY(DOUBLECLICK6),
KEYC_MOUSE_KEY(DOUBLECLICK7),
KEYC_MOUSE_KEY(DOUBLECLICK8),
KEYC_MOUSE_KEY(DOUBLECLICK9),
KEYC_MOUSE_KEY(DOUBLECLICK10),
KEYC_MOUSE_KEY(DOUBLECLICK11),
KEYC_MOUSE_KEY(TRIPLECLICK1),
KEYC_MOUSE_KEY(TRIPLECLICK2),
KEYC_MOUSE_KEY(TRIPLECLICK3),
KEYC_MOUSE_KEY(TRIPLECLICK6),
KEYC_MOUSE_KEY(TRIPLECLICK7),
KEYC_MOUSE_KEY(TRIPLECLICK8),
KEYC_MOUSE_KEY(TRIPLECLICK9),
KEYC_MOUSE_KEY(TRIPLECLICK10),
KEYC_MOUSE_KEY(TRIPLECLICK11),
/* Backspace key. */
KEYC_BSPACE,
@ -500,6 +542,7 @@ enum tty_code_code {
TTYC_SMXX,
TTYC_SXL,
TTYC_SS,
TTYC_SWD,
TTYC_SYNC,
TTYC_TC,
TTYC_TSL,
@ -671,15 +714,15 @@ struct grid_cell_entry {
/* Grid line. */
struct grid_line {
struct grid_cell_entry *celldata;
u_int cellused;
u_int cellsize;
struct grid_cell_entry *celldata;
u_int extdsize;
struct grid_extd_entry *extddata;
u_int extdsize;
int flags;
} __packed;
};
/* Entire grid of cells. */
struct grid {
@ -814,7 +857,6 @@ struct screen {
struct grid_cell saved_cell;
int saved_flags;
int mode;
bitstr_t *tabs;
struct screen_sel *sel;
struct images images;
@ -862,6 +904,12 @@ enum pane_lines {
PANE_LINES_NUMBER
};
/* Pane border indicator option. */
#define PANE_BORDER_OFF 0
#define PANE_BORDER_COLOUR 1
#define PANE_BORDER_ARROWS 2
#define PANE_BORDER_BOTH 3
/* Screen redraw context. */
struct screen_redraw_ctx {
struct client *c;
@ -998,6 +1046,7 @@ struct window_pane {
pid_t pid;
char tty[TTY_NAME_MAX];
int status;
struct timeval dead_time;
int fd;
struct bufferevent *event;
@ -1073,6 +1122,7 @@ struct window {
u_int new_xpixel;
u_int new_ypixel;
struct utf8_data *fill_character;
int flags;
#define WINDOW_BELL 0x1
#define WINDOW_ACTIVITY 0x2
@ -1212,21 +1262,33 @@ struct session {
RB_HEAD(sessions, session);
/* Mouse button masks. */
#define MOUSE_MASK_BUTTONS 3
#define MOUSE_MASK_BUTTONS 195
#define MOUSE_MASK_SHIFT 4
#define MOUSE_MASK_META 8
#define MOUSE_MASK_CTRL 16
#define MOUSE_MASK_DRAG 32
#define MOUSE_MASK_WHEEL 64
#define MOUSE_MASK_MODIFIERS (MOUSE_MASK_SHIFT|MOUSE_MASK_META|MOUSE_MASK_CTRL)
/* Mouse wheel states. */
#define MOUSE_WHEEL_UP 0
#define MOUSE_WHEEL_DOWN 1
/* Mouse wheel type. */
#define MOUSE_WHEEL_UP 64
#define MOUSE_WHEEL_DOWN 65
/* Mouse button type. */
#define MOUSE_BUTTON_1 0
#define MOUSE_BUTTON_2 1
#define MOUSE_BUTTON_3 2
#define MOUSE_BUTTON_6 66
#define MOUSE_BUTTON_7 67
#define MOUSE_BUTTON_8 128
#define MOUSE_BUTTON_9 129
#define MOUSE_BUTTON_10 130
#define MOUSE_BUTTON_11 131
/* Mouse helpers. */
#define MOUSE_BUTTONS(b) ((b) & MOUSE_MASK_BUTTONS)
#define MOUSE_WHEEL(b) ((b) & MOUSE_MASK_WHEEL)
#define MOUSE_WHEEL(b) \
(((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_UP || \
((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_DOWN)
#define MOUSE_DRAG(b) ((b) & MOUSE_MASK_DRAG)
#define MOUSE_RELEASE(b) (((b) & MOUSE_MASK_BUTTONS) == 3)
@ -1292,6 +1354,7 @@ LIST_HEAD(tty_terms, tty_term);
struct tty {
struct client *client;
struct event start_timer;
struct event clipboard_timer;
u_int sx;
u_int sy;
@ -1332,15 +1395,14 @@ struct tty {
#define TTY_NOCURSOR 0x1
#define TTY_FREEZE 0x2
#define TTY_TIMER 0x4
/* 0x8 unused */
#define TTY_NOBLOCK 0x8
#define TTY_STARTED 0x10
#define TTY_OPENED 0x20
/* 0x40 unused */
#define TTY_OSC52QUERY 0x40
#define TTY_BLOCK 0x80
#define TTY_HAVEDA 0x100
#define TTY_HAVEXDA 0x200
#define TTY_SYNCING 0x400
#define TTY_NOBLOCK 0x800
int flags;
struct tty_term *term;
@ -1668,6 +1730,7 @@ struct client {
struct format_job_tree *jobs;
char *title;
char *path;
const char *cwd;
char *term_name;
@ -1726,6 +1789,7 @@ struct client {
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL
#define CLIENT_ALLREDRAWFLAGS \
(CLIENT_REDRAWWINDOW| \
CLIENT_REDRAWSTATUS| \
@ -1772,7 +1836,10 @@ struct client {
prompt_free_cb prompt_freecb;
void *prompt_data;
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;
#define PROMPT_SINGLE 0x1
#define PROMPT_NUMERIC 0x2
@ -1803,6 +1870,9 @@ struct client {
struct client_files files;
u_int *clipboard_panes;
u_int clipboard_npanes;
TAILQ_ENTRY(client) entry;
};
TAILQ_HEAD(clients, client);
@ -1977,6 +2047,7 @@ void proc_remove_peer(struct tmuxpeer *);
void proc_kill_peer(struct tmuxpeer *);
void proc_toggle_log(struct tmuxproc *);
pid_t proc_fork_and_daemon(int *);
uid_t proc_get_peer_uid(struct tmuxpeer *);
/* cfg.c */
extern int cfg_finished;
@ -2190,6 +2261,7 @@ void tty_reset(struct tty *);
void tty_region_off(struct tty *);
void tty_margin_off(struct tty *);
void tty_cursor(struct tty *, u_int, u_int);
void tty_clipboard_query(struct tty *);
void tty_putcode(struct tty *, enum tty_code_code);
void tty_putcode1(struct tty *, enum tty_code_code, int);
void tty_putcode2(struct tty *, enum tty_code_code, int, int);
@ -2209,6 +2281,7 @@ void tty_start_tty(struct tty *);
void tty_send_requests(struct tty *);
void tty_stop_tty(struct tty *);
void tty_set_title(struct tty *, const char *);
void tty_set_path(struct tty *, const char *);
void tty_update_mode(struct tty *, int, struct screen *);
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
u_int, u_int, const struct grid_cell *, struct colour_palette *);
@ -2532,6 +2605,7 @@ int server_start(struct tmuxproc *, int, struct event_base *, int, char *);
void server_update_socket(void);
void server_add_accept(int);
void printflike(1, 2) server_add_message(const char *, ...);
int server_create_socket(int, char **);
/* server-client.c */
RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp);
@ -2637,6 +2711,8 @@ void input_parse_pane(struct window_pane *);
void input_parse_buffer(struct window_pane *, u_char *, size_t);
void input_parse_screen(struct input_ctx *, struct screen *,
screen_write_init_ctx_cb, void *, u_char *, size_t);
void input_reply_clipboard(struct bufferevent *, const char *, size_t,
const char *);
/* input-key.c */
void input_key_build(void);
@ -2930,6 +3006,7 @@ void *window_pane_get_new_data(struct window_pane *,
struct window_pane_offset *, size_t *);
void window_pane_update_used_data(struct window_pane *,
struct window_pane_offset *, size_t);
void window_set_fill_character(struct window *);
/* layout.c */
u_int layout_count_cells(struct layout_cell *);
@ -3083,6 +3160,7 @@ void control_notify_session_window_changed(struct session *);
/* session.c */
extern struct sessions sessions;
extern u_int next_session_id;
int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_alive(struct session *);

View File

@ -53,6 +53,18 @@ static const struct tty_feature tty_feature_title = {
0
};
/* Terminal has OSC 7 working directory. */
static const char *tty_feature_osc7_capabilities[] = {
"Swd=\\E]7;",
"fsl=\\a",
NULL
};
static const struct tty_feature tty_feature_osc7 = {
"osc7",
tty_feature_osc7_capabilities,
0
};
/* Terminal has mouse support. */
static const char *tty_feature_mouse_capabilities[] = {
"kmous=\\E[M",
@ -249,6 +261,7 @@ static const struct tty_feature *tty_features[] = {
&tty_feature_focus,
&tty_feature_margins,
&tty_feature_mouse,
&tty_feature_osc7,
&tty_feature_overline,
&tty_feature_rectfill,
&tty_feature_rgb,
@ -363,7 +376,7 @@ tty_default_features(int *feat, const char *name, u_int version)
},
{ .name = "iTerm2",
.features = TTY_FEATURES_BASE_MODERN_XTERM
",cstyle,extkeys,margins,sync"
",cstyle,extkeys,margins,usstyle,sync"
},
{ .name = "XTerm",
/*

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

View File

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

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

View File

@ -1272,6 +1272,16 @@ window_copy_cmd_halfpage_up(struct window_copy_cmd_state *cs)
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action
window_copy_cmd_toggle_position(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
struct window_copy_mode_data *data = wme->data;
data->hide_position = !data->hide_position;
return (WINDOW_COPY_CMD_REDRAW);
}
static enum window_copy_cmd_action
window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
{
@ -2817,6 +2827,12 @@ static const struct {
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_stop_selection
},
{ .command = "toggle-position",
.minargs = 0,
.maxargs = 0,
.clear = WINDOW_COPY_CMD_CLEAR_NEVER,
.f = window_copy_cmd_toggle_position
},
{ .command = "top-line",
.minargs = 0,
.maxargs = 0,
@ -3148,6 +3164,11 @@ window_copy_cellstring(const struct grid_line *gl, u_int px, size_t *size,
}
utf8_to_data(gl->extddata[gce->offset].data, &ud);
if (ud.size == 0) {
*size = 0;
*allocated = 0;
return (NULL);
}
*size = ud.size;
*allocated = 1;

View File

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

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++;
RB_INSERT(windows, &windows, w);
window_set_fill_character(w);
window_update_activity(w);
log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy,
@ -360,6 +361,7 @@ window_destroy(struct window *w)
event_del(&w->offset_timer);
options_free(w->options);
free(w->fill_character);
free(w->name);
free(w);
@ -761,6 +763,7 @@ window_lost_pane(struct window *w, struct window_pane *wp)
if (w->active != NULL) {
w->active->flags |= PANE_CHANGED;
notify_window("window-pane-changed", w);
window_update_focus(w);
}
} else if (wp == w->last)
w->last = NULL;
@ -1598,3 +1601,20 @@ window_pane_update_used_data(struct window_pane *wp,
size = EVBUFFER_LENGTH(wp->event->input) - used;
wpo->used += size;
}
void
window_set_fill_character(struct window *w)
{
const char *value;
struct utf8_data *ud;
free(w->fill_character);
w->fill_character = NULL;
value = options_get_string(w->options, "fill-character");
if (*value != '\0' && utf8_isvalid(value)) {
ud = utf8_fromcstr(value);
if (ud != NULL && ud[0].width == 1)
w->fill_character = ud;
}
}