34 Commits
3.2 ... 3.2a

Author SHA1 Message Date
Nicholas Marriott
3b929f332a Update CHANGES. 2021-06-10 09:24:57 +01:00
Nicholas Marriott
c827f5092d Do not clear region based on current cursor position, this is not necessary
anymore and causes problems, GitHub issue 2735.
2021-06-10 09:23:54 +01:00
Nicholas Marriott
d8feffd2bf Feature for the mouse since FreeBSD termcap does not have kmous. 2021-06-10 09:23:48 +01:00
Nicholas Marriott
f48c46a76a Fix rectangle selection, from Anindya Mukherjee, GitHub issue 2709. 2021-06-10 09:23:43 +01:00
Nicholas Marriott
f06ee2b87b Bump FORMAT_LOOOP_LIMIT and add a log message when hit, GitHub issue 2715. 2021-06-10 09:23:34 +01:00
Nicholas Marriott
9b4c05b6b9 Er, fix it properly. 2021-06-10 09:23:30 +01:00
Nicholas Marriott
3b9b823df5 Fix <= operator. 2021-06-10 09:23:25 +01:00
Nicholas Marriott
8aa34f616f Do not use NULL client when source-file finishes, GitHub issue 2707. 2021-06-10 09:23:15 +01:00
Nicholas Marriott
5ea6ccbb7f Do not expand the file given with -f so it can contain :s. 2021-06-10 09:23:07 +01:00
Nicholas Marriott
434ac8734a Looks like evports on SunOS are broken also, disable them. GitHub issue 2702. 2021-06-10 09:23:03 +01:00
Nicholas Marriott
47af583a50 Remove old shift function keys which interfere with xterm keys now. GitHub
issue 2696.
2021-06-10 09:22:51 +01:00
Nicholas Marriott
aaf87abfb4 Fire check callback after cleaning up event so it does not get stuck, from
Jeongho Jang in GitHub issue 2695.
2021-06-10 09:22:47 +01:00
Nicholas Marriott
bacb4d1b4d Fix warnings, from Jan Tache in GitHub issue 2692. 2021-06-10 09:22:39 +01:00
Nicholas Marriott
ad2f7642f2 Ctrl keys are < 0x7f, not Unicode. 2021-06-10 09:22:13 +01:00
Nicholas Marriott
059580e0f7 Move "special" keys into the Unicode PUA rather than making them high a top bit
set, some compilers cannot handle enums that are larger than int. GitHub issue
2673.
2021-06-10 09:22:07 +01:00
Nicholas Marriott
cb2943faab Change resize timers and flags into one timer and a queue to fix problems with
vim when resized multiple times. GitHub issue 2677.
2021-06-10 09:21:55 +01:00
Nicholas Marriott
7c28597e0f Mention S- for Shift, GitHub issue 2683. 2021-06-10 09:21:42 +01:00
Nicholas Marriott
fb52921a86 Do not count client if no window. 2021-06-10 09:21:34 +01:00
Nicholas Marriott
ddc67152a5 Three changes to fix problems with xterm in VT340 mode, reported by Thomas
Sattler.

1) Do not include the DECSLRM or DECFRA features for xterm; they will be added
   instead if secondary DA responds as VT420 (this happens already).

2) Set or reset the individual flags after terminal-overrides is applied, so
   the user can properly disable them.

3) Add a capability for DECFRA ("Rect").
2021-06-10 09:21:26 +01:00
Nicholas Marriott
4cf595a402 Include current client in size calcultion for new sessions, GitHub issue 2662. 2021-06-10 09:21:16 +01:00
Nicholas Marriott
5107e84897 Add an "always" value to the extended-keys option to always forward these keys
to applications inside tmux.
2021-06-10 09:21:09 +01:00
Nicholas Marriott
736a276cc9 Minor CHANGES and tmux.1 fixed, from Daniel Hahler, GitHub issue 2664. 2021-06-10 09:21:05 +01:00
Nicholas Marriott
825feac9f8 Add another couple of keys needed for extended keys, GitHub issue 2658. 2021-06-10 09:20:56 +01:00
Nicholas Marriott
d8c0069254 Use = not ==, from Leonardo Taccari. 2021-06-10 09:20:51 +01:00
Nicholas Marriott
33d4f854c0 back-to-indentation fixes, from Anindya Mukherjee. 2021-06-10 09:20:42 +01:00
Nicholas Marriott
9865ad27a5 Fix display-menu -xR, from Alexis Hildebrandt. 2021-06-10 09:20:33 +01:00
Nicholas Marriott
16b497e12b Apple have broken strtonum so check it works, from Teubel Gyorgy. 2021-06-10 09:20:28 +01:00
Nicholas Marriott
a25af7d0f3 Adjust latest client when a client detaches, GitHub issue 2657. 2021-06-10 09:20:22 +01:00
Nicholas Marriott
a11aa870b3 Handle modifier 9 as Meta, GitHub issue 2647. 2021-06-10 09:20:15 +01:00
Nicholas Marriott
0431d4d639 Add crosscompiling fallbacks, from Hasso Tepper. 2021-06-10 09:20:07 +01:00
nicm
d863978464 %begin now has three arguments, not two. GitHubs issue 2646. 2021-06-10 09:20:02 +01:00
nicm
57d5f67552 Include modifiers when looking up an individual key. 2021-06-10 09:19:56 +01:00
nicm
bab7a9a085 Change how extended ctrl keys are processed to fix C-S-Tab and C-;. 2021-06-10 09:19:49 +01:00
Nicholas Marriott
2ab53d30d0 3.2a version. 2021-06-10 09:17:46 +01:00
30 changed files with 482 additions and 274 deletions

23
CHANGES
View File

@@ -1,3 +1,16 @@
CHANGES FROM 3.2 TO 3.2a
* Add an "always" value for the "extended-keys" option; if set then tmux will
forward extended keys to applications even if they do not request them.
* Add a "mouse" terminal feature so tmux can enable the mouse on terminals
where it is known to be supported even if terminfo(5) says otherwise.
* Do not expand the filename given to -f so it can contain colons.
* Fixes for problems with extended keys and modifiers, scroll region,
source-file, crosscompiling, format modifiers and other minor issues.
CHANGES FROM 3.1c TO 3.2
* Add a flag to disable keys to close a message.
@@ -29,7 +42,7 @@ CHANGES FROM 3.1c TO 3.2
* Add a -S flag to new-window to make it select the existing window if one
with the given name already exists rather than failing with an error.
* Addd a format modifier to check if a window or session name exists (N/w or
* Add a format modifier to check if a window or session name exists (N/w or
N/s).
* Add compat clock_gettime for older macOS.
@@ -61,7 +74,7 @@ CHANGES FROM 3.1c TO 3.2
an option on all panes.
* Make replacement of ##s consistent when drawing formats, whether followed by
[ or not. Add a flag (e) to the q: format modifier to double up #s
[ or not. Add a flag (e) to the q: format modifier to double up #s.
* Add -N flag to display-panes to ignore keys.
@@ -265,7 +278,7 @@ CHANGES FROM 3.1c TO 3.2
* Wait until the initial command sequence is done before sending a device
attributes request and other bits that prompt a reply from the terminal. This
means that stray relies are not left on the terminal if the command has
means that stray replies are not left on the terminal if the command has
attached and then immediately detached and tmux will not be around to receive
them.
@@ -280,7 +293,7 @@ CHANGES FROM 3.1c TO 3.2
window-renamed
window-unlinked
And these now pane options:
And these are now pane options:
pane-died
pane-exited
@@ -355,7 +368,7 @@ CHANGES FROM 3.1c TO 3.2
* Add a default binding for button 2 to paste.
* Add -d flag to run-shell to delay before running the command and allow it to
run without a command so it just delays.
be used without a command so it just delays.
* Add C-g to cancel command prompt with vi keys as well as emacs, and q in
command mode.

View File

@@ -205,7 +205,7 @@ cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item,
if (xp == NULL || strcmp(xp, "C") == 0)
xp = "#{popup_centre_x}";
else if (strcmp(xp, "R") == 0)
xp = "#{popup_right}";
xp = "#{popup_pane_right}";
else if (strcmp(xp, "P") == 0)
xp = "#{popup_pane_left}";
else if (strcmp(xp, "M") == 0)

View File

@@ -165,7 +165,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "invalid key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
only &= KEYC_MASK_KEY;
only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
}
tablename = args_get(args, 'T');

View File

@@ -269,6 +269,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
memset(&sc, 0, sizeof sc);
sc.item = item;
sc.s = s;
sc.tc = c;
sc.name = args_get(args, 'n');
sc.argc = args->argc;

View File

@@ -67,7 +67,9 @@ cmd_source_file_complete(struct client *c, struct cmd_source_file_data *cdata)
struct cmdq_item *new_item;
if (cfg_finished) {
if (cdata->retval == CMD_RETURN_ERROR && c->session == NULL)
if (cdata->retval == CMD_RETURN_ERROR &&
c != NULL &&
c->session == NULL)
c->retval = 1;
new_item = cmdq_get_callback(cmd_source_file_complete_cb, NULL);
cmdq_insert_after(cdata->after, new_item);

View File

@@ -1,6 +1,6 @@
# configure.ac
AC_INIT([tmux], 3.2)
AC_INIT([tmux], 3.2a)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
@@ -34,10 +34,10 @@ AC_ARG_VAR(
# Set up convenient fuzzing defaults before initializing compiler.
if test "x$enable_fuzzing" = xyes; then
AC_DEFINE(NEED_FUZZING)
test "x$CC" == x && CC=clang
test "x$FUZZING_LIBS" == x && \
test "x$CC" = x && CC=clang
test "x$FUZZING_LIBS" = x && \
FUZZING_LIBS="-fsanitize=fuzzer"
test "x$SAVED_CFLAGS" == x && \
test "x$SAVED_CFLAGS" = x && \
AM_CFLAGS="-g -fsanitize=fuzzer-no-link,address"
fi
@@ -150,10 +150,19 @@ AC_REPLACE_FUNCS([ \
strlcpy \
strndup \
strsep \
strtonum \
])
AC_FUNC_STRNLEN
# Check if strtonum works.
AC_MSG_CHECKING([for working strtonum])
AC_RUN_IFELSE([AC_LANG_PROGRAM(
[#include <stdlib.h>],
[return (strtonum("0", 0, 1, NULL) == 0 ? 0 : 1);]
)],
[AC_DEFINE(HAVE_STRTONUM) AC_MSG_RESULT(yes)],
[AC_LIBOBJ(strtonum) AC_MSG_RESULT(no)]
)
# Clang sanitizers wrap reallocarray even if it isn't available on the target
# system. When compiled it always returns NULL and crashes the program. To
# detect this we need a more complicated test.
@@ -163,6 +172,7 @@ AC_RUN_IFELSE([AC_LANG_PROGRAM(
[return (reallocarray(NULL, 1, 1) == NULL);]
)],
AC_MSG_RESULT(yes),
[AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])],
[AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])]
)
AC_MSG_CHECKING([for working recallocarray])
@@ -171,6 +181,7 @@ AC_RUN_IFELSE([AC_LANG_PROGRAM(
[return (recallocarray(NULL, 1, 1, 1) == NULL);]
)],
AC_MSG_RESULT(yes),
[AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])],
[AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])]
)

6
file.c
View File

@@ -503,14 +503,14 @@ file_write_error_callback(__unused struct bufferevent *bev, __unused short what,
log_debug("write error file %d", cf->stream);
if (cf->cb != NULL)
cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
bufferevent_free(cf->event);
cf->event = NULL;
close(cf->fd);
cf->fd = -1;
if (cf->cb != NULL)
cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
}
/* Client file write callback. */

View File

@@ -103,7 +103,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
#define FORMAT_CHARACTER 0x10000
/* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 10
#define FORMAT_LOOP_LIMIT 100
/* Format expand flags. */
#define FORMAT_EXPAND_TIME 0x1
@@ -3991,7 +3991,7 @@ format_replace_expression(struct format_modifier *mexp,
result = (mleft < mright);
break;
case LESS_THAN_EQUAL:
result = (mleft > mright);
result = (mleft <= mright);
break;
}
if (use_fp)
@@ -4199,7 +4199,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
value = xstrdup("0");
} else {
format_log(es, "search '%s' pane %%%u", new, wp->id);
value = format_search(fm, wp, new);
value = format_search(search, wp, new);
}
free(new);
} else if (cmp != NULL) {
@@ -4441,8 +4441,10 @@ format_expand1(struct format_expand_state *es, const char *fmt)
if (fmt == NULL || *fmt == '\0')
return (xstrdup(""));
if (es->loop == FORMAT_LOOP_LIMIT)
if (es->loop == FORMAT_LOOP_LIMIT) {
format_log(es, "reached loop limit (%u)", FORMAT_LOOP_LIMIT);
return (xstrdup(""));
}
es->loop++;
format_log(es, "expanding format: %s", fmt);

View File

@@ -371,19 +371,26 @@ void
grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
{
struct grid_cell gc;
u_int px, py, xx, yy;
u_int px, py, xx, yy, oldx, oldy;
yy = gr->gd->hsize + gr->gd->sy - 1;
oldx = gr->cx;
oldy = gr->cy;
grid_reader_cursor_start_of_line(gr, 1);
for (py = gr->cy; py <= yy; py++) {
xx = grid_line_length(gr->gd, py);
for (px = 0; px < xx; px++) {
grid_get_cell(gr->gd, px, py, &gc);
if (gc.data.size != 1 || *gc.data.data != ' ')
break;
if (gc.data.size != 1 || *gc.data.data != ' ') {
gr->cx = px;
gr->cy = py;
return;
}
}
if (~grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED)
break;
}
gr->cx = oldx;
gr->cy = oldy;
}

View File

@@ -94,30 +94,6 @@ static struct input_key_entry input_key_defaults[] = {
{ .key = KEYC_F12,
.data = "\033[24~"
},
{ .key = KEYC_F1|KEYC_SHIFT,
.data = "\033[25~"
},
{ .key = KEYC_F2|KEYC_SHIFT,
.data = "\033[26~"
},
{ .key = KEYC_F3|KEYC_SHIFT,
.data = "\033[28~"
},
{ .key = KEYC_F4|KEYC_SHIFT,
.data = "\033[29~"
},
{ .key = KEYC_F5|KEYC_SHIFT,
.data = "\033[31~"
},
{ .key = KEYC_F6|KEYC_SHIFT,
.data = "\033[32~"
},
{ .key = KEYC_F7|KEYC_SHIFT,
.data = "\033[33~"
},
{ .key = KEYC_F8|KEYC_SHIFT,
.data = "\033[34~"
},
{ .key = KEYC_IC,
.data = "\033[2~"
},
@@ -476,7 +452,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
if (justkey > 0x7f && justkey < KEYC_BASE) {
if (KEYC_IS_UNICODE(justkey)) {
if (key & KEYC_META)
input_key_write(__func__, bev, "\033", 1);
utf8_to_data(justkey, &ud);

View File

@@ -1390,6 +1390,8 @@ input_csi_dispatch(struct input_ctx *ictx)
case INPUT_CSI_MODSET:
n = input_get(ictx, 0, 0, 0);
m = input_get(ictx, 1, 0, 0);
if (options_get_number(global_options, "extended-keys") == 2)
break;
if (n == 0 || (n == 4 && m == 0))
screen_write_mode_clear(sctx, MODE_KEXTENDED);
else if (n == 4 && (m == 1 || m == 2))

View File

@@ -215,6 +215,9 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat,
if (repeat)
bd->flags |= KEY_BINDING_REPEAT;
bd->cmdlist = cmdlist;
log_debug("%s: %#llx %s = %s", __func__, bd->key,
key_string_lookup_key(bd->key, 1), cmd_list_print(bd->cmdlist, 0));
}
void
@@ -231,6 +234,9 @@ key_bindings_remove(const char *name, key_code key)
if (bd == NULL)
return;
log_debug("%s: %#llx %s", __func__, bd->key,
key_string_lookup_key(bd->key, 1));
RB_REMOVE(key_bindings, &table->key_bindings, bd);
key_bindings_free(bd);

View File

@@ -164,7 +164,7 @@ key_string_get_modifiers(const char **string)
key_code
key_string_lookup_string(const char *string)
{
static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177";
static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177`/";
key_code key, modifiers;
u_int u, i;
struct utf8_data ud, *udp;
@@ -238,8 +238,12 @@ key_string_lookup_string(const char *string)
}
/* Convert the standard control keys. */
if (key < KEYC_BASE && (modifiers & KEYC_CTRL) &&
strchr(other, key) == NULL) {
if (key <= 127 &&
(modifiers & KEYC_CTRL) &&
strchr(other, key) == NULL &&
key != 9 &&
key != 13 &&
key != 27) {
if (key >= 97 && key <= 122)
key -= 96;
else if (key >= 64 && key <= 95)
@@ -364,8 +368,8 @@ key_string_lookup_key(key_code key, int with_flags)
goto out;
}
/* Is this a UTF-8 key? */
if (key > 127 && key < KEYC_BASE) {
/* Is this a Unicode key? */
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key, &ud);
off = strlen(out);
memcpy(out + off, ud.data, ud.size);

View File

@@ -74,6 +74,9 @@ static const char *options_table_remain_on_exit_list[] = {
static const char *options_table_detach_on_destroy_list[] = {
"off", "on", "no-detached", NULL
};
static const char *options_table_extended_keys_list[] = {
"off", "on", "always", NULL
};
/* Status line format. */
#define OPTIONS_TABLE_STATUS_FORMAT1 \
@@ -266,8 +269,9 @@ const struct options_table_entry options_table[] = {
},
{ .name = "extended-keys",
.type = OPTIONS_TABLE_FLAG,
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SERVER,
.choices = options_table_extended_keys_list,
.default_num = 0,
.text = "Whether to request extended key sequences from terminals "
"that support it."

View File

@@ -96,5 +96,17 @@ osdep_get_cwd(int fd)
struct event_base *
osdep_event_init(void)
{
return (event_init());
struct event_base *base;
/*
* On Illumos, evports don't seem to work properly. It is not clear if
* this a problem in libevent, with the way tmux uses file descriptors,
* or with some types of file descriptor. But using poll instead is
* fine.
*/
setenv("EVENT_NOEVPORT", "1", 1);
base = event_init();
unsetenv("EVENT_NOEVPORT");
return (base);
}

View File

@@ -108,17 +108,19 @@ clients_with_window(struct window *w)
}
static int
clients_calculate_size(int type, int current, struct session *s,
struct window *w, int (*skip_client)(struct client *, int, int,
struct session *, struct window *), u_int *sx, u_int *sy, u_int *xpixel,
u_int *ypixel)
clients_calculate_size(int type, int current, struct client *c,
struct session *s, struct window *w, int (*skip_client)(struct client *,
int, int, struct session *, struct window *), u_int *sx, u_int *sy,
u_int *xpixel, u_int *ypixel)
{
struct client *loop;
u_int cx, cy, n = 0;
/* Manual windows do not have their size changed based on a client. */
if (type == WINDOW_SIZE_MANUAL)
if (type == WINDOW_SIZE_MANUAL) {
log_debug("%s: type is manual", __func__);
return (0);
}
/*
* Start comparing with 0 for largest and UINT_MAX for smallest or
@@ -134,23 +136,29 @@ clients_calculate_size(int type, int current, struct session *s,
* For latest, count the number of clients with this window. We only
* care if there is more than one.
*/
if (type == WINDOW_SIZE_LATEST)
if (type == WINDOW_SIZE_LATEST && w != NULL)
n = clients_with_window(w);
/* Loop over the clients and work out the size. */
TAILQ_FOREACH(loop, &clients, entry) {
if (ignore_client_size(loop))
if (loop != c && ignore_client_size(loop)) {
log_debug("%s: ignoring %s", __func__, loop->name);
continue;
if (skip_client(loop, type, current, s, w))
}
if (loop != c && skip_client(loop, type, current, s, w)) {
log_debug("%s: skipping %s", __func__, loop->name);
continue;
}
/*
* If there are multiple clients attached, only accept the
* latest client; otherwise let the only client be chosen as
* for smallest.
*/
if (type == WINDOW_SIZE_LATEST && n > 1 && loop != w->latest)
if (type == WINDOW_SIZE_LATEST && n > 1 && loop != w->latest) {
log_debug("%s: %s is not latest", __func__, loop->name);
continue;
}
/* Work out this client's size. */
cx = loop->tty.sx;
@@ -175,16 +183,24 @@ clients_calculate_size(int type, int current, struct session *s,
*xpixel = loop->tty.xpixel;
*ypixel = loop->tty.ypixel;
}
log_debug("%s: after %s (%ux%u), size is %ux%u", __func__,
loop->name, cx, cy, *sx, *sy);
}
/* Return whether a suitable size was found. */
if (type == WINDOW_SIZE_LARGEST)
if (type == WINDOW_SIZE_LARGEST) {
log_debug("%s: type is largest", __func__);
return (*sx != 0 && *sy != 0);
}
if (type == WINDOW_SIZE_LATEST)
log_debug("%s: type is latest", __func__);
else
log_debug("%s: type is smallest", __func__);
return (*sx != UINT_MAX && *sy != UINT_MAX);
}
static int
default_window_size_skip_client (struct client *loop, int type,
default_window_size_skip_client(struct client *loop, int type,
__unused int current, struct session *s, struct window *w)
{
/*
@@ -221,23 +237,25 @@ default_window_size(struct client *c, struct session *s, struct window *w,
*sy = c->tty.sy - status_line_size(c);
*xpixel = c->tty.xpixel;
*ypixel = c->tty.ypixel;
log_debug("%s: using %ux%u from %s", __func__, *sx, *sy,
c->name);
goto done;
}
if (w == NULL)
type = WINDOW_SIZE_MANUAL;
}
/*
* Look for a client to base the size on. If none exists (or the type
* is manual), use the default-size option.
*/
if (!clients_calculate_size(type, 0, s, w,
if (!clients_calculate_size(type, 0, c, s, w,
default_window_size_skip_client, sx, sy, xpixel, ypixel)) {
value = options_get_string(s->options, "default-size");
if (sscanf(value, "%ux%u", sx, sy) != 2) {
*sx = 80;
*sy = 24;
}
log_debug("%s: using %ux%u from default-size", __func__, *sx,
*sy);
}
done:
@@ -250,6 +268,7 @@ done:
*sy = WINDOW_MINIMUM;
if (*sy > WINDOW_MAXIMUM)
*sy = WINDOW_MAXIMUM;
log_debug("%s: resulting size is %ux%u", __func__, *sx, *sy);
}
static int
@@ -289,7 +308,7 @@ recalculate_size(struct window *w, int now)
current = options_get_number(w->options, "aggressive-resize");
/* Look for a suitable client and get the new size. */
changed = clients_calculate_size(type, current, NULL, w,
changed = clients_calculate_size(type, current, NULL, NULL, w,
recalculate_size_skip_client, &sx, &sy, &xpixel, &ypixel);
/*

View File

@@ -100,7 +100,9 @@ screen_reinit(struct screen *s)
s->rupper = 0;
s->rlower = screen_size_y(s) - 1;
s->mode = MODE_CURSOR | MODE_WRAP;
s->mode = MODE_CURSOR|MODE_WRAP;
if (options_get_number(global_options, "extended-keys") == 2)
s->mode |= MODE_KEXTENDED;
if (s->saved_grid != NULL)
screen_alternate_off(s, NULL, 0);

View File

@@ -43,6 +43,7 @@ static void server_client_check_modes(struct client *);
static void server_client_set_title(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 *);
static void server_client_dispatch(struct imsg *, void *);
static void server_client_dispatch_command(struct client *, struct imsg *);
@@ -271,6 +272,40 @@ server_client_open(struct client *c, char **cause)
return (0);
}
/* Lost an attached client. */
static void
server_client_attached_lost(struct client *c)
{
struct session *s = c->session;
struct window *w;
struct client *loop;
struct client *found;
log_debug("lost attached client %p", c);
/*
* By this point the session in the client has been cleared so walk all
* windows to find any with this client as the latest.
*/
RB_FOREACH(w, windows, &windows) {
if (w->latest != c)
continue;
found = NULL;
TAILQ_FOREACH(loop, &clients, entry) {
s = loop->session;
if (loop == c || s == NULL || s->curw->window != w)
continue;
if (found == NULL ||
timercmp(&loop->activity_time, &found->activity_time,
>))
found = loop;
}
if (found != NULL)
server_client_update_latest(found);
}
}
/* Lost a client. */
void
server_client_lost(struct client *c)
@@ -296,8 +331,10 @@ server_client_lost(struct client *c)
TAILQ_REMOVE(&clients, c, entry);
log_debug("lost client %p", c);
if (c->flags & CLIENT_ATTACHED)
if (c->flags & CLIENT_ATTACHED) {
server_client_attached_lost(c);
notify_client("client-detached", c);
}
if (c->flags & CLIENT_CONTROL)
control_stop(c);
@@ -1410,84 +1447,79 @@ server_client_resize_timer(__unused int fd, __unused short events, void *data)
evtimer_del(&wp->resize_timer);
}
/* Start the resize timer. */
static void
server_client_start_resize_timer(struct window_pane *wp)
{
struct timeval tv = { .tv_usec = 250000 };
log_debug("%s: %%%u resize timer started", __func__, wp->id);
evtimer_add(&wp->resize_timer, &tv);
}
/* Force timer event. */
static void
server_client_force_timer(__unused int fd, __unused short events, void *data)
{
struct window_pane *wp = data;
log_debug("%s: %%%u force timer expired", __func__, wp->id);
evtimer_del(&wp->force_timer);
wp->flags |= PANE_RESIZENOW;
}
/* Start the force timer. */
static void
server_client_start_force_timer(struct window_pane *wp)
{
struct timeval tv = { .tv_usec = 10000 };
log_debug("%s: %%%u force timer started", __func__, wp->id);
evtimer_add(&wp->force_timer, &tv);
}
/* Check if pane should be resized. */
static void
server_client_check_pane_resize(struct window_pane *wp)
{
struct window_pane_resize *r;
struct window_pane_resize *r1;
struct window_pane_resize *first;
struct window_pane_resize *last;
struct timeval tv = { .tv_usec = 250000 };
if (TAILQ_EMPTY(&wp->resize_queue))
return;
if (!event_initialized(&wp->resize_timer))
evtimer_set(&wp->resize_timer, server_client_resize_timer, wp);
if (!event_initialized(&wp->force_timer))
evtimer_set(&wp->force_timer, server_client_force_timer, wp);
if (~wp->flags & PANE_RESIZE)
if (evtimer_pending(&wp->resize_timer, NULL))
return;
log_debug("%s: %%%u needs to be resized", __func__, wp->id);
if (evtimer_pending(&wp->resize_timer, NULL)) {
log_debug("%s: %%%u resize timer is running", __func__, wp->id);
return;
TAILQ_FOREACH(r, &wp->resize_queue, entry) {
log_debug("queued resize: %ux%u -> %ux%u", r->osx, r->osy,
r->sx, r->sy);
}
server_client_start_resize_timer(wp);
if (~wp->flags & PANE_RESIZEFORCE) {
/*
* The timer is not running and we don't need to force a
* resize, so just resize immediately.
*/
log_debug("%s: resizing %%%u now", __func__, wp->id);
window_pane_send_resize(wp, 0);
wp->flags &= ~PANE_RESIZE;
/*
* There are three cases that matter:
*
* - Only one resize. It can just be applied.
*
* - Multiple resizes and the ending size is different from the
* starting size. We can discard all resizes except the most recent.
*
* - Multiple resizes and the ending size is the same as the starting
* size. We must resize at least twice to force the application to
* redraw. So apply the first and leave the last on the queue for
* next time.
*/
first = TAILQ_FIRST(&wp->resize_queue);
last = TAILQ_LAST(&wp->resize_queue, window_pane_resizes);
if (first == last) {
/* Only one resize. */
window_pane_send_resize(wp, first->sx, first->sy);
TAILQ_REMOVE(&wp->resize_queue, first, entry);
free(first);
} else if (last->sx != first->osx || last->sy != first->osy) {
/* Multiple resizes ending up with a different size. */
window_pane_send_resize(wp, last->sx, last->sy);
TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
TAILQ_REMOVE(&wp->resize_queue, r, entry);
free(r);
}
} else {
/*
* The timer is not running, but we need to force a resize. If
* the force timer has expired, resize to the real size now.
* Otherwise resize to the force size and start the timer.
* Multiple resizes ending up with the same size. There will
* not be more than one to the same size in succession so we
* can just use the last-but-one on the list and leave the last
* for later. We reduce the time until the next check to avoid
* a long delay between the resizes.
*/
if (wp->flags & PANE_RESIZENOW) {
log_debug("%s: resizing %%%u after forced resize",
__func__, wp->id);
window_pane_send_resize(wp, 0);
wp->flags &= ~(PANE_RESIZE|PANE_RESIZEFORCE|PANE_RESIZENOW);
} else if (!evtimer_pending(&wp->force_timer, NULL)) {
log_debug("%s: forcing resize of %%%u", __func__,
wp->id);
window_pane_send_resize(wp, 1);
server_client_start_force_timer(wp);
r = TAILQ_PREV(last, window_pane_resizes, entry);
window_pane_send_resize(wp, r->sx, r->sy);
TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
if (r == last)
break;
TAILQ_REMOVE(&wp->resize_queue, r, entry);
free(r);
}
tv.tv_usec = 10000;
}
evtimer_add(&wp->resize_timer, &tv);
}
/* Check pane buffer size. */
static void
server_client_check_pane_buffer(struct window_pane *wp)

View File

@@ -163,7 +163,8 @@ server_tidy_event(__unused int fd, __unused short events, __unused void *data)
malloc_trim(0);
#endif
log_debug("%s: took %llu milliseconds", __func__, get_timer() - t);
log_debug("%s: took %llu milliseconds", __func__,
(unsigned long long)(get_timer() - t));
evtimer_add(&server_ev_tidy, &tv);
}

View File

@@ -226,6 +226,8 @@ status_line_size(struct client *c)
if (c->flags & (CLIENT_STATUSOFF|CLIENT_CONTROL))
return (0);
if (s == NULL)
return (options_get_number(global_s_options, "status"));
return (s->statuslines);
}
@@ -1298,7 +1300,7 @@ process_key:
return (0);
append_key:
if (key <= 0x1f || key >= KEYC_BASE)
if (key <= 0x1f || (key >= KEYC_BASE && key < KEYC_BASE_END))
return (0);
if (key <= 0x7f)
utf8_set(&tmp, key);

42
tmux.1
View File

@@ -2953,6 +2953,8 @@ Ctrl keys may be prefixed with
.Ql C-
or
.Ql ^ ,
Shift keys with
.Ql S-
and Alt (meta) with
.Ql M- .
In addition, the following special key names are accepted:
@@ -3418,11 +3420,24 @@ sessions.
.Xc
If enabled, the server will exit when there are no attached clients.
.It Xo Ic extended-keys
.Op Ic on | off
.Op Ic on | off | always
.Xc
When enabled, extended keys are requested from the terminal and if supported
are recognised by
.Nm .
When
.Ic on
or
.Ic always ,
the escape sequence to enable extended keys is sent to the terminal, if
.Nm
knows that it is supported.
.Nm
always recognises extended keys itself.
If this option is
.Ic on ,
.Nm
will only forward extended keys to applications when they request them; if
.Ic always ,
.Nm
will always forward the keys.
.It Xo Ic focus-events
.Op Ic on | off
.Xc
@@ -3501,8 +3516,8 @@ capabilities to be set instead,
is intended for classes of functionality supported in a standard way but not
reported by
.Xr terminfo 5 .
Care must be taken only to configure this with features the terminal actually
support.
Care must be taken to configure this only with features the terminal actually
supports.
.Pp
This is an array option where each entry is a colon-separated string made up
of a terminal type pattern (matched using
@@ -3524,6 +3539,10 @@ Supports extended keys.
Supports focus reporting.
.It margins
Supports DECSLRM margins.
.It mouse
Supports
.Xr xterm 1
mouse sequences.
.It overline
Supports the overline SGR attribute.
.It rectfill
@@ -6036,6 +6055,10 @@ Disable and enable focus reporting.
These are set automatically if the
.Em XT
capability is present.
.It Em \&Rect
Tell
.Nm
that the terminal supports rectangle operations.
.It Em \&Smol
Enable the overline attribute.
.It Em \&Smulx
@@ -6116,12 +6139,13 @@ and matching
.Em %end
or
.Em %error
have two arguments: an integer time (as seconds from epoch) and command number.
have three arguments: an integer time (as seconds from epoch), command number and
flags (currently not used).
For example:
.Bd -literal -offset indent
%begin 1363006971 2
%begin 1363006971 2 1
0: ksh* (1 panes) [80x24] [layout b25f,80x24,0,0,2] @2 (active)
%end 1363006971 2
%end 1363006971 2 1
.Ed
.Pp
The

15
tmux.c
View File

@@ -328,7 +328,7 @@ main(int argc, char **argv)
char *path = NULL, *label = NULL;
char *cause, **var;
const char *s, *cwd;
int opt, keys, feat = 0;
int opt, keys, feat = 0, fflag = 0;
uint64_t flags = 0;
const struct options_table_entry *oe;
u_int i;
@@ -373,10 +373,15 @@ main(int argc, char **argv)
flags |= CLIENT_CONTROL;
break;
case 'f':
for (i = 0; i < cfg_nfiles; i++)
free(cfg_files[i]);
free(cfg_files);
expand_paths(optarg, &cfg_files, &cfg_nfiles, 0);
if (!fflag) {
fflag = 1;
for (i = 0; i < cfg_nfiles; i++)
free(cfg_files[i]);
cfg_nfiles = 0;
}
cfg_files = xreallocarray(cfg_files, cfg_nfiles + 1,
sizeof *cfg_files);
cfg_files[cfg_nfiles++] = xstrdup(optarg);
cfg_quiet = 0;
break;
case 'V':

59
tmux.h
View File

@@ -109,11 +109,16 @@ struct winlink;
#define VISUAL_ON 1
#define VISUAL_BOTH 2
/* Special key codes. */
#define KEYC_NONE 0x00ff000000000ULL
#define KEYC_UNKNOWN 0x00fe000000000ULL
#define KEYC_BASE 0x0001000000000ULL
#define KEYC_USER 0x0002000000000ULL
/* No key or unknown key. */
#define KEYC_NONE 0x000ff000000000ULL
#define KEYC_UNKNOWN 0x000fe000000000ULL
/*
* Base for special (that is, not Unicode) keys. An enum must be at most a
* signed int, so these are based in the highest Unicode PUA.
*/
#define KEYC_BASE 0x0000000010e000ULL
#define KEYC_USER 0x0000000010f000ULL
/* Key modifier bits. */
#define KEYC_META 0x00100000000000ULL
@@ -136,8 +141,15 @@ struct winlink;
#define KEYC_NUSER 1000
/* Is this a mouse key? */
#define KEYC_IS_MOUSE(key) (((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \
((key) & KEYC_MASK_KEY) < KEYC_BSPACE)
#define KEYC_IS_MOUSE(key) \
(((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \
((key) & KEYC_MASK_KEY) < KEYC_BSPACE)
/* Is this a Unicode key? */
#define KEYC_IS_UNICODE(key) \
(((key) & KEYC_MASK_KEY) > 0x7f && \
(((key) & KEYC_MASK_KEY) < KEYC_BASE || \
((key) & KEYC_MASK_KEY) >= KEYC_BASE_END))
/* Multiple click timeout. */
#define KEYC_CLICK_TIMEOUT 300
@@ -159,8 +171,8 @@ struct winlink;
{ #s "Border", KEYC_ ## name ## _BORDER }
/*
* A single key. This can be ASCII or Unicode or one of the keys starting at
* KEYC_BASE.
* A single key. This can be ASCII or Unicode or one of the keys between
* KEYC_BASE and KEYC_BASE_END.
*/
typedef unsigned long long key_code;
@@ -253,6 +265,9 @@ enum {
KEYC_KP_ENTER,
KEYC_KP_ZERO,
KEYC_KP_PERIOD,
/* End of special keys. */
KEYC_BASE_END
};
/* Termcap codes. */
@@ -452,6 +467,7 @@ enum tty_code_code {
TTYC_MS,
TTYC_OL,
TTYC_OP,
TTYC_RECT,
TTYC_REV,
TTYC_RGB,
TTYC_RI,
@@ -918,7 +934,7 @@ struct window_mode_entry {
struct screen *screen;
u_int prefix;
TAILQ_ENTRY (window_mode_entry) entry;
TAILQ_ENTRY(window_mode_entry) entry;
};
/* Offsets into pane buffer. */
@@ -926,6 +942,18 @@ struct window_pane_offset {
size_t used;
};
/* Queued pane resize. */
struct window_pane_resize {
u_int sx;
u_int sy;
u_int osx;
u_int osy;
TAILQ_ENTRY(window_pane_resize) entry;
};
TAILQ_HEAD(window_pane_resizes, window_pane_resize);
/* Child window structure. */
struct window_pane {
u_int id;
@@ -950,8 +978,8 @@ struct window_pane {
#define PANE_REDRAW 0x1
#define PANE_DROP 0x2
#define PANE_FOCUSED 0x4
#define PANE_RESIZE 0x8
#define PANE_RESIZEFORCE 0x10
/* 0x8 unused */
/* 0x10 unused */
#define PANE_FOCUSPUSH 0x20
#define PANE_INPUTOFF 0x40
#define PANE_CHANGED 0x80
@@ -960,7 +988,6 @@ struct window_pane {
#define PANE_STATUSDRAWN 0x400
#define PANE_EMPTY 0x800
#define PANE_STYLECHANGED 0x1000
#define PANE_RESIZENOW 0x2000
int argc;
char **argv;
@@ -977,8 +1004,8 @@ struct window_pane {
struct window_pane_offset offset;
size_t base_offset;
struct window_pane_resizes resize_queue;
struct event resize_timer;
struct event force_timer;
struct input_ctx *ictx;
@@ -996,7 +1023,7 @@ struct window_pane {
struct screen status_screen;
size_t status_size;
TAILQ_HEAD (, window_mode_entry) modes;
TAILQ_HEAD(, window_mode_entry) modes;
char *searchstr;
int searchregex;
@@ -2755,7 +2782,7 @@ void window_redraw_active_switch(struct window *,
struct window_pane *window_add_pane(struct window *, struct window_pane *,
u_int, int);
void window_resize(struct window *, u_int, u_int, int, int);
void window_pane_send_resize(struct window_pane *, int);
void window_pane_send_resize(struct window_pane *, u_int, u_int);
int window_zoom(struct window_pane *);
int window_unzoom(struct window *);
int window_push_zoom(struct window *, int, int);

View File

@@ -25,7 +25,6 @@
/*
* Still hardcoded:
* - mouse (under kmous capability);
* - default colours (under AX or op capabilities);
* - AIX colours (under colors >= 16);
* - alternate escape (if terminal is VT100-like).
@@ -54,6 +53,17 @@ static const struct tty_feature tty_feature_title = {
0
};
/* Terminal has mouse support. */
static const char *tty_feature_mouse_capabilities[] = {
"kmous=\\E[M",
NULL
};
static const struct tty_feature tty_feature_mouse = {
"mouse",
tty_feature_mouse_capabilities,
0
};
/* Terminal can set the clipboard with OSC 52. */
static const char *tty_feature_clipboard_capabilities[] = {
"Ms=\\E]52;%p1%s;%p2%s\\a",
@@ -218,9 +228,13 @@ static const struct tty_feature tty_feature_margins = {
};
/* Terminal supports DECFRA rectangle fill. */
static const char *tty_feature_rectfill_capabilities[] = {
"Rect",
NULL
};
static const struct tty_feature tty_feature_rectfill = {
"rectfill",
NULL,
tty_feature_rectfill_capabilities,
TERM_DECFRA
};
@@ -234,6 +248,7 @@ static const struct tty_feature *tty_features[] = {
&tty_feature_extkeys,
&tty_feature_focus,
&tty_feature_margins,
&tty_feature_mouse,
&tty_feature_overline,
&tty_feature_rectfill,
&tty_feature_rgb,
@@ -334,7 +349,7 @@ tty_default_features(int *feat, const char *name, u_int version)
const char *features;
} table[] = {
#define TTY_FEATURES_BASE_MODERN_XTERM \
"256,RGB,bpaste,clipboard,strikethrough,title"
"256,RGB,bpaste,clipboard,mouse,strikethrough,title"
{ .name = "mintty",
.features = TTY_FEATURES_BASE_MODERN_XTERM
",ccolour,cstyle,extkeys,margins,overline,usstyle"
@@ -344,15 +359,20 @@ tty_default_features(int *feat, const char *name, u_int version)
",ccolour,cstyle,focus,overline,usstyle"
},
{ .name = "rxvt-unicode",
.features = "256,bpaste,ccolour,cstyle,title"
.features = "256,bpaste,ccolour,cstyle,mouse,title"
},
{ .name = "iTerm2",
.features = TTY_FEATURES_BASE_MODERN_XTERM
",cstyle,extkeys,margins,sync"
},
{ .name = "XTerm",
/*
* xterm also supports DECSLRM and DECFRA, but they can be
* disabled so not set it here - they will be added if
* secondary DA shows VT420.
*/
.features = TTY_FEATURES_BASE_MODERN_XTERM
",ccolour,cstyle,extkeys,focus,margins,rectfill"
",ccolour,cstyle,extkeys,focus"
}
};
u_int i;

View File

@@ -252,7 +252,8 @@ static const key_code tty_default_xterm_modifiers[] = {
KEYC_CTRL,
KEYC_SHIFT|KEYC_CTRL,
KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL,
KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL
KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL,
KEYC_META|KEYC_IMPLIED_META
};
/*
@@ -944,6 +945,9 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
case 8:
nkey |= (KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL);
break;
case 9:
nkey |= (KEYC_META|KEYC_IMPLIED_META);
break;
default:
*key = KEYC_NONE;
break;
@@ -955,23 +959,22 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
*/
if (nkey & KEYC_CTRL) {
onlykey = (nkey & KEYC_MASK_KEY);
if (onlykey < 32) {
if (onlykey != 9)
onlykey = (nkey & ~KEYC_CTRL);
else
onlykey = (9|KEYC_CTRL);
} else {
if (onlykey >= 97 && onlykey <= 122)
onlykey -= 96;
else if (onlykey >= 64 && onlykey <= 95)
onlykey -= 64;
else if (onlykey == 32)
onlykey = 0;
else if (onlykey == 63)
onlykey = 127;
onlykey |= ((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL);
}
nkey = onlykey;
if (onlykey < 32 &&
onlykey != 9 &&
onlykey != 13 &&
onlykey != 27)
/* nothing */;
else if (onlykey >= 97 && onlykey <= 122)
onlykey -= 96;
else if (onlykey >= 64 && onlykey <= 95)
onlykey -= 64;
else if (onlykey == 32)
onlykey = 0;
else if (onlykey == 63)
onlykey = 127;
else
onlykey |= KEYC_CTRL;
nkey = onlykey|((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL);
}
if (log_get_level() != 0) {

View File

@@ -251,6 +251,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_MS] = { TTYCODE_STRING, "Ms" },
[TTYC_OL] = { TTYCODE_STRING, "ol" },
[TTYC_OP] = { TTYCODE_STRING, "op" },
[TTYC_RECT] = { TTYCODE_STRING, "Rect" },
[TTYC_REV] = { TTYCODE_STRING, "rev" },
[TTYC_RGB] = { TTYCODE_FLAG, "RGB" },
[TTYC_RIN] = { TTYCODE_STRING, "rin" },
@@ -434,10 +435,11 @@ tty_term_apply_overrides(struct tty_term *term)
struct options_entry *o;
struct options_array_item *a;
union options_value *ov;
const char *s;
const char *s, *acs;
size_t offset;
char *first;
/* Update capabilities from the option. */
o = options_get_only(global_options, "terminal-overrides");
a = options_array_first(o);
while (a != NULL) {
@@ -450,6 +452,64 @@ tty_term_apply_overrides(struct tty_term *term)
tty_term_apply(term, s + offset, 0);
a = options_array_next(a);
}
/* Update the RGB flag if the terminal has RGB colours. */
if (tty_term_has(term, TTYC_SETRGBF) &&
tty_term_has(term, TTYC_SETRGBB))
term->flags |= TERM_RGBCOLOURS;
else
term->flags &= ~TERM_RGBCOLOURS;
log_debug("RGBCOLOURS flag is %d", !!(term->flags & TERM_RGBCOLOURS));
/*
* Set or clear the DECSLRM flag if the terminal has the margin
* capabilities.
*/
if (tty_term_has(term, TTYC_CMG) && tty_term_has(term, TTYC_CLMG))
term->flags |= TERM_DECSLRM;
else
term->flags &= ~TERM_DECSLRM;
log_debug("DECSLRM flag is %d", !!(term->flags & TERM_DECSLRM));
/*
* Set or clear the DECFRA flag if the terminal has the rectangle
* capability.
*/
if (tty_term_has(term, TTYC_RECT))
term->flags |= TERM_DECFRA;
else
term->flags &= ~TERM_DECFRA;
log_debug("DECFRA flag is %d", !!(term->flags & TERM_DECFRA));
/*
* Terminals without am (auto right margin) wrap at at $COLUMNS - 1
* rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1).
*
* Terminals without xenl (eat newline glitch) ignore a newline beyond
* the right edge of the terminal, but tmux doesn't care about this -
* it always uses absolute only moves the cursor with a newline when
* also sending a linefeed.
*
* This is irritating, most notably because it is painful to write to
* the very bottom-right of the screen without scrolling.
*
* Flag the terminal here and apply some workarounds in other places to
* do the best possible.
*/
if (!tty_term_flag(term, TTYC_AM))
term->flags |= TERM_NOAM;
else
term->flags &= ~TERM_NOAM;
log_debug("NOAM flag is %d", !!(term->flags & TERM_NOAM));
/* Generate ACS table. If none is present, use nearest ASCII. */
memset(term->acs, 0, sizeof term->acs);
if (tty_term_has(term, TTYC_ACSC))
acs = tty_term_string(term, TTYC_ACSC);
else
acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y<z>~.";
for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2)
term->acs[(u_char) acs[0]][0] = acs[1];
}
struct tty_term *
@@ -463,7 +523,7 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
struct options_array_item *a;
union options_value *ov;
u_int i, j;
const char *s, *acs, *value;
const char *s, *value;
size_t offset, namelen;
char *first;
@@ -566,40 +626,10 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
(!tty_term_has(term, TTYC_SETRGBF) ||
!tty_term_has(term, TTYC_SETRGBB)))
tty_add_features(feat, "RGB", ",");
if (tty_term_has(term, TTYC_SETRGBF) &&
tty_term_has(term, TTYC_SETRGBB))
term->flags |= TERM_RGBCOLOURS;
/* Apply the features and overrides again. */
tty_apply_features(term, *feat);
tty_term_apply_overrides(term);
/*
* Terminals without am (auto right margin) wrap at at $COLUMNS - 1
* rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1).
*
* Terminals without xenl (eat newline glitch) ignore a newline beyond
* the right edge of the terminal, but tmux doesn't care about this -
* it always uses absolute only moves the cursor with a newline when
* also sending a linefeed.
*
* This is irritating, most notably because it is painful to write to
* the very bottom-right of the screen without scrolling.
*
* Flag the terminal here and apply some workarounds in other places to
* do the best possible.
*/
if (!tty_term_flag(term, TTYC_AM))
term->flags |= TERM_NOAM;
/* Generate ACS table. If none is present, use nearest ASCII. */
memset(term->acs, 0, sizeof term->acs);
if (tty_term_has(term, TTYC_ACSC))
acs = tty_term_string(term, TTYC_ACSC);
else
acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y<z>~.";
for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2)
term->acs[(u_char) acs[0]][0] = acs[1];
if (tty_apply_features(term, *feat))
tty_term_apply_overrides(term);
/* Log the capabilities. */
for (i = 0; i < tty_term_ncodes(); i++)
@@ -667,7 +697,7 @@ tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps,
ent = &tty_term_codes[i];
switch (ent->type) {
case TTYCODE_NONE:
break;
continue;
case TTYCODE_STRING:
s = tigetstr((char *)ent->name);
if (s == NULL || s == (char *)-1)

9
tty.c
View File

@@ -958,13 +958,8 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx)
return;
}
if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) {
for (i = ctx->ocy; i < ctx->sy; i++)
tty_draw_pane(tty, ctx, i);
} else {
for (i = ctx->orupper; i <= ctx->orlower; i++)
tty_draw_pane(tty, ctx, i);
}
for (i = ctx->orupper; i <= ctx->orlower; i++)
tty_draw_pane(tty, ctx, i);
}
/* Is this position visible in the pane? */

View File

@@ -294,9 +294,9 @@ window_buffer_get_key(void *modedata, void *itemdata, u_int line)
struct window_buffer_modedata *data = modedata;
struct window_buffer_itemdata *item = itemdata;
struct format_tree *ft;
struct session *s;
struct winlink *wl;
struct window_pane *wp;
struct session *s = NULL;
struct winlink *wl = NULL;
struct window_pane *wp = NULL;
struct paste_buffer *pb;
char *expanded;
key_code key;

View File

@@ -1102,10 +1102,13 @@ static enum window_copy_cmd_action
window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
struct window_copy_mode_data *data = wme->data;
u_int np = wme->prefix;
for (; np != 0; np--)
window_copy_cursor_right(wme, 0);
for (; np != 0; np--) {
window_copy_cursor_right(wme, data->screen.sel != NULL &&
data->rectflag);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -4425,10 +4428,12 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
struct window_copy_mode_data *data = wme->data;
struct screen *s = &data->screen;
u_int ox, oy, px, py;
int norectsel;
norectsel = data->screen.sel == NULL || !data->rectflag;
oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wme, oy);
if (data->cx != ox) {
if (norectsel && data->cx != ox) {
data->lastcx = data->cx;
data->lastsx = ox;
}
@@ -4437,7 +4442,8 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
window_copy_other_end(wme);
if (scroll_only || data->cy == 0) {
data->cx = data->lastcx;
if (norectsel)
data->cx = data->lastcx;
window_copy_scroll_down(wme, 1);
if (scroll_only) {
if (data->cy == screen_size_y(s) - 1)
@@ -4446,7 +4452,11 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
window_copy_redraw_lines(wme, data->cy, 2);
}
} else {
window_copy_update_cursor(wme, data->lastcx, data->cy - 1);
if (norectsel) {
window_copy_update_cursor(wme, data->lastcx,
data->cy - 1);
} else
window_copy_update_cursor(wme, data->cx, data->cy - 1);
if (window_copy_update_selection(wme, 1, 0)) {
if (data->cy == screen_size_y(s) - 1)
window_copy_redraw_lines(wme, data->cy, 1);
@@ -4455,7 +4465,7 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
}
}
if (data->screen.sel == NULL || !data->rectflag) {
if (norectsel) {
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wme, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -4492,10 +4502,12 @@ window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
struct window_copy_mode_data *data = wme->data;
struct screen *s = &data->screen;
u_int ox, oy, px, py;
int norectsel;
norectsel = data->screen.sel == NULL || !data->rectflag;
oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wme, oy);
if (data->cx != ox) {
if (norectsel && data->cx != ox) {
data->lastcx = data->cx;
data->lastsx = ox;
}
@@ -4504,17 +4516,22 @@ window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
window_copy_other_end(wme);
if (scroll_only || data->cy == screen_size_y(s) - 1) {
data->cx = data->lastcx;
if (norectsel)
data->cx = data->lastcx;
window_copy_scroll_up(wme, 1);
if (scroll_only && data->cy > 0)
window_copy_redraw_lines(wme, data->cy - 1, 2);
} else {
window_copy_update_cursor(wme, data->lastcx, data->cy + 1);
if (norectsel) {
window_copy_update_cursor(wme, data->lastcx,
data->cy + 1);
} else
window_copy_update_cursor(wme, data->cx, data->cy + 1);
if (window_copy_update_selection(wme, 1, 0))
window_copy_redraw_lines(wme, data->cy - 1, 2);
}
if (data->screen.sel == NULL || !data->rectflag) {
if (norectsel) {
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wme, py);
if ((data->cx >= data->lastsx && data->cx != px) ||

View File

@@ -329,6 +329,8 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel)
window_update_activity(w);
log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy,
w->xpixel, w->ypixel);
return (w);
}
@@ -423,25 +425,18 @@ window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
}
void
window_pane_send_resize(struct window_pane *wp, int force)
window_pane_send_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window *w = wp->window;
struct winsize ws;
u_int sy;
if (wp->fd == -1)
return;
if (!force)
sy = wp->sy;
else if (wp->sy <= 1)
sy = wp->sy + 1;
else
sy = wp->sy - 1;
log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, wp->sx, sy);
log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, sx, sy);
memset(&ws, 0, sizeof ws);
ws.ws_col = wp->sx;
ws.ws_col = sx;
ws.ws_row = sy;
ws.ws_xpixel = w->xpixel * ws.ws_col;
ws.ws_ypixel = w->ypixel * ws.ws_row;
@@ -865,29 +860,19 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->id = next_window_pane_id++;
RB_INSERT(window_pane_tree, &all_window_panes, wp);
wp->argc = 0;
wp->argv = NULL;
wp->shell = NULL;
wp->cwd = NULL;
wp->fd = -1;
wp->event = NULL;
wp->fg = 8;
wp->bg = 8;
TAILQ_INIT(&wp->modes);
wp->layout_cell = NULL;
wp->xoff = 0;
wp->yoff = 0;
TAILQ_INIT (&wp->resize_queue);
wp->sx = sx;
wp->sy = sy;
wp->pipe_fd = -1;
wp->pipe_event = NULL;
screen_init(&wp->base, sx, sy, hlimit);
wp->screen = &wp->base;
@@ -903,6 +888,9 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
static void
window_pane_destroy(struct window_pane *wp)
{
struct window_pane_resize *r;
struct window_pane_resize *r1;
window_pane_reset_mode_all(wp);
free(wp->searchstr);
@@ -927,8 +915,10 @@ window_pane_destroy(struct window_pane *wp)
if (event_initialized(&wp->resize_timer))
event_del(&wp->resize_timer);
if (event_initialized(&wp->force_timer))
event_del(&wp->force_timer);
TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
TAILQ_REMOVE(&wp->resize_queue, r, entry);
free(r);
}
RB_REMOVE(window_pane_tree, &all_window_panes, wp);
@@ -997,9 +987,18 @@ void
window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_mode_entry *wme;
struct window_pane_resize *r;
if (sx == wp->sx && sy == wp->sy)
return;
r = xmalloc (sizeof *r);
r->sx = sx;
r->sy = sy;
r->osx = wp->sx;
r->osy = wp->sy;
TAILQ_INSERT_TAIL (&wp->resize_queue, r, entry);
wp->sx = sx;
wp->sy = sy;
@@ -1009,14 +1008,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->resize != NULL)
wme->mode->resize(wme, sx, sy);
/*
* If the pane has already been resized, set the force flag and make
* the application resize twice to force it to redraw.
*/
if (wp->flags & PANE_RESIZE)
wp->flags |= PANE_RESIZEFORCE;
wp->flags |= PANE_RESIZE;
}
void