aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/lock.yml2
-rw-r--r--CHANGES23
-rw-r--r--client.c23
-rw-r--r--cmd-copy-mode.c4
-rw-r--r--cmd-run-shell.c62
-rw-r--r--cmd-set-option.c7
-rw-r--r--configure.ac5
-rw-r--r--format.c117
-rw-r--r--input-keys.c11
-rw-r--r--key-bindings.c58
-rw-r--r--server-client.c47
-rw-r--r--server.c17
-rw-r--r--spawn.c2
-rw-r--r--status.c4
-rw-r--r--tmux.152
-rw-r--r--tmux.c19
-rw-r--r--tmux.h11
-rw-r--r--tty.c50
-rw-r--r--window-copy.c22
-rw-r--r--window.c4
20 files changed, 426 insertions, 114 deletions
diff --git a/.github/lock.yml b/.github/lock.yml
index 89126482..08cf2fc0 100644
--- a/.github/lock.yml
+++ b/.github/lock.yml
@@ -1,4 +1,4 @@
-daysUntilLock: 180
+daysUntilLock: 30
skipCreatedBefore: false
exemptLabels: []
lockLabel: false
diff --git a/CHANGES b/CHANGES
index 728bac60..c938e28c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,26 @@
+CHANGES FROM 3.1 TO 3.2
+
+* Change double and triple click bindings so that only one is fired (previously
+ double click was fired on the way to triple click). Also add default double
+ and triple click bindings to copy the word or line under the cursor and
+ change the existing bindings in copy mode to do the same.
+
+* 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.
+
+* Add C-g to cancel command prompt with vi keys as well as emacs, and q in
+ command mode.
+
+* When the server socket is given with -S, create it with umask 177 instead of
+ 117 (because it may not be in a safe directory like the default directory in
+ /tmp).
+
+* Add a copy-mode -H flag to hide the position marker in the top right.
+
+* Add number operators for formats (+, -, *, / and m),
+
CHANGES FROM 3.0a TO 3.1
* Add selection_active format for when the selection is present but not moving
diff --git a/client.c b/client.c
index 91e084a5..52bf302c 100644
--- a/client.c
+++ b/client.c
@@ -97,7 +97,7 @@ client_get_lock(char *lockfile)
/* Connect client to server. */
static int
-client_connect(struct event_base *base, const char *path, int start_server)
+client_connect(struct event_base *base, const char *path, int flags)
{
struct sockaddr_un sa;
size_t size;
@@ -122,7 +122,7 @@ retry:
log_debug("connect failed: %s", strerror(errno));
if (errno != ECONNREFUSED && errno != ENOENT)
goto failed;
- if (!start_server)
+ if (~flags & CLIENT_STARTSERVER)
goto failed;
close(fd);
@@ -154,7 +154,7 @@ retry:
close(lockfd);
return (-1);
}
- fd = server_start(client_proc, base, lockfd, lockfile);
+ fd = server_start(client_proc, flags, base, lockfd, lockfile);
}
if (locked && lockfd >= 0) {
@@ -238,7 +238,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
struct cmd_parse_result *pr;
struct cmd *cmd;
struct msg_command *data;
- int cmdflags, fd, i;
+ int fd, i;
const char *ttynam, *cwd;
pid_t ppid;
enum msgtype msg;
@@ -248,17 +248,13 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN);
- /* Save the flags. */
- client_flags = flags;
-
/* Set up the initial command. */
- cmdflags = 0;
if (shell_command != NULL) {
msg = MSG_SHELL;
- cmdflags = CMD_STARTSERVER;
+ flags = CLIENT_STARTSERVER;
} else if (argc == 0) {
msg = MSG_COMMAND;
- cmdflags = CMD_STARTSERVER;
+ flags |= CLIENT_STARTSERVER;
} else {
msg = MSG_COMMAND;
@@ -271,19 +267,22 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
if (pr->status == CMD_PARSE_SUCCESS) {
TAILQ_FOREACH(cmd, &pr->cmdlist->list, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER)
- cmdflags |= CMD_STARTSERVER;
+ flags |= CLIENT_STARTSERVER;
}
cmd_list_free(pr->cmdlist);
} else
free(pr->error);
}
+ /* Save the flags. */
+ client_flags = flags;
+
/* Create client process structure (starts logging). */
client_proc = proc_start("client");
proc_set_signals(client_proc, client_signal);
/* Initialize the client socket and start the server. */
- fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
+ fd = client_connect(base, socket_path, client_flags);
if (fd == -1) {
if (errno == ECONNREFUSED) {
fprintf(stderr, "no server running on %s\n",
diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c
index b35d0af1..9c0015bf 100644
--- a/cmd-copy-mode.c
+++ b/cmd-copy-mode.c
@@ -30,8 +30,8 @@ const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode",
.alias = NULL,
- .args = { "Met:u", 0, 0 },
- .usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
+ .args = { "eHMt:u", 0, 0 },
+ .usage = "[-eHMu] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index 2f45f492..bc21cc9c 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -31,6 +31,7 @@
static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
+static void cmd_run_shell_timer(int, short, void *);
static void cmd_run_shell_callback(struct job *);
static void cmd_run_shell_free(void *);
static void cmd_run_shell_print(struct job *, const char *);
@@ -39,8 +40,8 @@ const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell",
.alias = "run",
- .args = { "bt:", 1, 1 },
- .usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
+ .args = { "bd:t:", 0, 1 },
+ .usage = "[-b] [-d delay] " CMD_TARGET_PANE_USAGE " [shell-command]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -50,8 +51,11 @@ const struct cmd_entry cmd_run_shell_entry = {
struct cmd_run_shell_data {
char *cmd;
+ char *cwd;
struct cmdq_item *item;
+ struct session *s;
int wp_id;
+ struct event timer;
};
static void
@@ -91,9 +95,14 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
+ const char *delay;
+ double d;
+ struct timeval tv;
+ char *end;
cdata = xcalloc(1, sizeof *cdata);
- cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
+ if (args->argc != 0)
+ cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id;
@@ -103,12 +112,26 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'b'))
cdata->item = item;
- if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
- cmd_run_shell_callback, cmd_run_shell_free, cdata, 0) == NULL) {
- cmdq_error(item, "failed to run command: %s", cdata->cmd);
- free(cdata);
- return (CMD_RETURN_ERROR);
- }
+ cdata->cwd = xstrdup(server_client_get_cwd(item->client, s));
+ cdata->s = s;
+ if (s != NULL)
+ session_add_ref(s, __func__);
+
+ evtimer_set(&cdata->timer, cmd_run_shell_timer, cdata);
+
+ if ((delay = args_get(args, 'd')) != NULL) {
+ d = strtod(delay, &end);
+ if (*end != '\0') {
+ cmdq_error(item, "invalid delay time: %s", delay);
+ cmd_run_shell_free(cdata);
+ return (CMD_RETURN_ERROR);
+ }
+ timerclear(&tv);
+ tv.tv_sec = (time_t)d;
+ tv.tv_usec = (d - (double)tv.tv_sec) * 1000000U;
+ evtimer_add(&cdata->timer, &tv);
+ } else
+ cmd_run_shell_timer(-1, 0, cdata);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
@@ -116,6 +139,23 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
}
static void
+cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
+{
+ struct cmd_run_shell_data *cdata = arg;
+
+ if (cdata->cmd != NULL) {
+ if (job_run(cdata->cmd, cdata->s, cdata->cwd, NULL,
+ cmd_run_shell_callback, cmd_run_shell_free, cdata,
+ 0) == NULL)
+ cmd_run_shell_free(cdata);
+ } else {
+ if (cdata->item != NULL)
+ cmdq_continue(cdata->item);
+ cmd_run_shell_free(cdata);
+ }
+}
+
+static void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job_get_data(job);
@@ -163,6 +203,10 @@ cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
+ evtimer_del(&cdata->timer);
+ if (cdata->s != NULL)
+ session_remove_ref(cdata->s, __func__);
+ free(cdata->cwd);
free(cdata->cmd);
free(cdata);
}
diff --git a/cmd-set-option.c b/cmd-set-option.c
index 23b45230..2709dcdc 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -309,6 +309,13 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
old = xstrdup(options_get_string(oo, oe->name));
options_set_string(oo, oe->name, append, "%s", value);
new = options_get_string(oo, oe->name);
+ if (strcmp(oe->name, "default-shell") == 0 &&
+ !checkshell(new)) {
+ options_set_string(oo, oe->name, 0, "%s", old);
+ free(old);
+ cmdq_error(item, "not a suitable shell: %s", value);
+ return (-1);
+ }
if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) {
options_set_string(oo, oe->name, 0, "%s", old);
free(old);
diff --git a/configure.ac b/configure.ac
index 947a0a2f..e29ebdc7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
# configure.ac
-AC_INIT([tmux], 3.1-rc2)
+AC_INIT([tmux], next-3.2)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
@@ -87,6 +87,9 @@ AC_CHECK_HEADERS([ \
util.h \
])
+# Look for fmod.
+AC_CHECK_LIB(m, fmod)
+
# Look for library needed for flock.
AC_SEARCH_LIBS(flock, bsd)
diff --git a/format.c b/format.c
index 79e99b61..e973d825 100644
--- a/format.c
+++ b/format.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <fnmatch.h>
#include <libgen.h>
+#include <math.h>
#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
@@ -49,7 +50,6 @@ static void format_add_tv(struct format_tree *, const char *,
struct timeval *);
static int format_replace(struct format_tree *, const char *, size_t,
char **, size_t *, size_t *);
-
static void format_defaults_session(struct format_tree *,
struct session *);
static void format_defaults_client(struct format_tree *, struct client *);
@@ -1543,7 +1543,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
}
/* Now try single character with arguments. */
- if (strchr("mCs=p", cp[0]) == NULL)
+ if (strchr("mCs=pe", cp[0]) == NULL)
break;
c = cp[0];
@@ -1799,6 +1799,108 @@ format_loop_panes(struct format_tree *ft, const char *fmt)
return (value);
}
+static char *
+format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,
+ const char *copy)
+{
+ int argc = mexp->argc;
+ const char *errstr;
+ char *endch, *value, *left = NULL, *right = NULL;
+ int use_fp = 0;
+ u_int prec = 0;
+ double mleft, mright, result;
+ enum { ADD, SUBTRACT, MULTIPLY, DIVIDE, MODULUS } operator;
+
+ if (strcmp(mexp->argv[0], "+") == 0)
+ operator = ADD;
+ else if (strcmp(mexp->argv[0], "-") == 0)
+ operator = SUBTRACT;
+ else if (strcmp(mexp->argv[0], "*") == 0)
+ operator = MULTIPLY;
+ else if (strcmp(mexp->argv[0], "/") == 0)
+ operator = DIVIDE;
+ else if (strcmp(mexp->argv[0], "%") == 0 ||
+ strcmp(mexp->argv[0], "m") == 0)
+ operator = MODULUS;
+ else {
+ format_log(ft, "expression has no valid operator: '%s'",
+ mexp->argv[0]);
+ goto fail;
+ }
+
+ /* The second argument may be flags. */
+ if (argc >= 2 && strchr(mexp->argv[1], 'f') != NULL) {
+ use_fp = 1;
+ prec = 2;
+ }
+
+ /* The third argument may be precision. */
+ if (argc >= 3) {
+ prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr);
+ if (errstr != NULL) {
+ format_log (ft, "expression precision %s: %s", errstr,
+ mexp->argv[2]);
+ goto fail;
+ }
+ }
+
+ if (format_choose(ft, copy, &left, &right, 1) != 0) {
+ format_log(ft, "expression syntax error");
+ goto fail;
+ }
+
+ mleft = strtod(left, &endch);
+ if (*endch != '\0') {
+ format_log(ft, "expression left side is invalid: %s", left);
+ goto fail;
+ }
+
+ mright = strtod(right, &endch);
+ if (*endch != '\0') {
+ format_log(ft, "expression right side is invalid: %s", right);
+ goto fail;
+ }
+
+ if (!use_fp) {
+ mleft = (long long)mleft;
+ mright = (long long)mright;
+ }
+ format_log(ft, "expression left side is: %.*f", prec, mleft);
+ format_log(ft, "expression right side is: %.*f", prec, mright);
+
+ switch (operator) {
+ case ADD:
+ result = mleft + mright;
+ break;
+ case SUBTRACT:
+ result = mleft - mright;
+ break;
+ case MULTIPLY:
+ result = mleft * mright;
+ break;
+ case DIVIDE:
+ result = mleft / mright;
+ break;
+ case MODULUS:
+ result = fmod(mleft, mright);
+ break;
+ }
+ if (use_fp)
+ xasprintf(&value, "%.*f", prec, result);
+ else
+ xasprintf(&value, "%.*f", prec, (double)(long long)result);
+ format_log(ft, "expression result is %s", value);
+
+ free(right);
+ free(left);
+ return value;
+
+fail:
+ free(right);
+ free(left);
+ return (NULL);
+}
+
/* Replace a key. */
static int
format_replace(struct format_tree *ft, const char *key, size_t keylen,
@@ -1811,7 +1913,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
size_t valuelen;
int modifiers = 0, limit = 0, width = 0, j;
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
- struct format_modifier **sub = NULL;
+ struct format_modifier **sub = NULL, *mexp = NULL;
u_int i, count, nsub = 0;
/* Make a copy of the key. */
@@ -1863,6 +1965,11 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
if (errptr != NULL)
width = 0;
break;
+ case 'e':
+ if (fm->argc < 1 || fm->argc > 3)
+ break;
+ mexp = fm;
+ break;
case 'l':
modifiers |= FORMAT_LITERAL;
break;
@@ -2039,6 +2146,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
free(condition);
free(found);
+ } else if (mexp != NULL) {
+ value = format_replace_expression(mexp, ft, copy);
+ if (value == NULL)
+ value = xstrdup("");
} else {
/* Neither: look up directly. */
value = format_find(ft, copy, modifiers);
diff --git a/input-keys.c b/input-keys.c
index 69c5199e..f415e3a7 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -253,12 +253,12 @@ static void
input_key_mouse(struct window_pane *wp, struct mouse_event *m)
{
struct screen *s = wp->screen;
- int mode = s->mode;
char buf[40];
size_t len;
u_int x, y;
- if ((mode & ALL_MOUSE_MODES) == 0)
+ /* Ignore events if no mouse mode or the pane is not visible. */
+ if (m->ignore || (s->mode & ALL_MOUSE_MODES) == 0)
return;
if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
return;
@@ -266,8 +266,7 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
return;
/* If this pane is not in button or all mode, discard motion events. */
- if (MOUSE_DRAG(m->b) &&
- (mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)) == 0)
+ if (MOUSE_DRAG(m->b) && (s->mode & MOTION_MOUSE_MODES) == 0)
return;
/*
@@ -279,13 +278,13 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
if (m->sgr_type != ' ') {
if (MOUSE_DRAG(m->sgr_b) &&
MOUSE_BUTTONS(m->sgr_b) == 3 &&
- (~mode & MODE_MOUSE_ALL))
+ (~s->mode & MODE_MOUSE_ALL))
return;
} else {
if (MOUSE_DRAG(m->b) &&
MOUSE_BUTTONS(m->b) == 3 &&
MOUSE_BUTTONS(m->lb) == 3 &&
- (~mode & MODE_MOUSE_ALL))
+ (~s->mode & MODE_MOUSE_ALL))
return;
}
diff --git a/key-bindings.c b/key-bindings.c
index 4387c011..57b71c0f 100644
--- a/key-bindings.c
+++ b/key-bindings.c
@@ -229,6 +229,7 @@ void
key_bindings_init(void)
{
static const char *defaults[] = {
+ /* Prefix keys. */
"bind -N 'Send the prefix key' C-b send-prefix",
"bind -N 'Rotate through the panes' C-o rotate-window",
"bind -N 'Suspend the current client' C-z suspend-client",
@@ -312,21 +313,51 @@ key_bindings_init(void)
"bind -N 'Resize the pane left' -r C-Left resize-pane -L",
"bind -N 'Resize the pane right' -r C-Right resize-pane -R",
- "bind -n MouseDown1Pane select-pane -t=\\; send-keys -M",
+ /* Menu keys */
+ "bind < display-menu -xW -yS -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU,
+ "bind > display-menu -xP -yP -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU,
+
+ /* Mouse button 1 down on pane. */
+ "bind -n MouseDown1Pane select-pane -t=\\; send -M",
+
+ /* Mouse button 1 drag on pane. */
+ "bind -n MouseDrag1Pane if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M }",
+
+ /* Mouse wheel up on pane. */
+ "bind -n WheelUpPane if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e }",
+
+ /* Mouse button 2 down on pane. */
+ "bind -n MouseDown2Pane select-pane -t=\\; if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { paste -p }",
+
+ /* Mouse button 1 double click on pane. */
+ "bind -n DoubleClick1Pane select-pane -t=\\; if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -H; send -X select-word; run -d0.3; send -X copy-selection-and-cancel }",
+
+ /* Mouse button 1 triple click on pane. */
+ "bind -n TripleClick1Pane select-pane -t=\\; if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -H; send -X select-line; run -d0.3; send -X copy-selection-and-cancel }",
+
+ /* Mouse button 1 drag on border. */
"bind -n MouseDrag1Border resize-pane -M",
+
+ /* Mouse button 1 down on status line. */
"bind -n MouseDown1Status select-window -t=",
+
+ /* Mouse wheel down on status line. */
"bind -n WheelDownStatus next-window",
+
+ /* Mouse wheel up on status line. */
"bind -n WheelUpStatus previous-window",
- "bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'",
- "bind -n WheelUpPane if -Ft= '#{mouse_any_flag}' 'send-keys -M' 'if -Ft= \"#{pane_in_mode}\" \"send-keys -M\" \"copy-mode -et=\"'",
- "bind -n MouseDown3StatusLeft display-menu -t= -xM -yS -T \"#[align=centre]#{session_name}\" " DEFAULT_SESSION_MENU,
- "bind -n MouseDown3Status display-menu -t= -xW -yS -T \"#[align=centre]#{window_index}:#{window_name}\" " DEFAULT_WINDOW_MENU,
- "bind < display-menu -xW -yS -T \"#[align=centre]#{window_index}:#{window_name}\" " DEFAULT_WINDOW_MENU,
- "bind -n MouseDown3Pane if -Ft= '#{||:#{mouse_any_flag},#{pane_in_mode}}' 'select-pane -t=; send-keys -M' {display-menu -t= -xM -yM -T \"#[align=centre]#{pane_index} (#{pane_id})\" " DEFAULT_PANE_MENU "}",
- "bind -n M-MouseDown3Pane display-menu -t= -xM -yM -T \"#[align=centre]#{pane_index} (#{pane_id})\" " DEFAULT_PANE_MENU,
- "bind > display-menu -xP -yP -T \"#[align=centre]#{pane_index} (#{pane_id})\" " DEFAULT_PANE_MENU,
+ /* Mouse button 3 down on status left. */
+ "bind -n MouseDown3StatusLeft display-menu -t= -xM -yS -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU,
+
+ /* Mouse button 3 down on status line. */
+ "bind -n MouseDown3Status display-menu -t= -xW -yS -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU,
+
+ /* Mouse button 3 down on pane. */
+ "bind -n MouseDown3Pane if -Ft= '#{||:#{mouse_any_flag},#{pane_in_mode}}' { select-pane -t=; send -M } { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
+ "bind -n M-MouseDown3Pane display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU,
+ /* Copy mode (emacs) keys. */
"bind -Tcopy-mode C-Space send -X begin-selection",
"bind -Tcopy-mode C-a send -X start-of-line",
"bind -Tcopy-mode C-c send -X cancel",
@@ -361,8 +392,8 @@ key_bindings_init(void)
"bind -Tcopy-mode MouseDragEnd1Pane send -X copy-selection-and-cancel",
"bind -Tcopy-mode WheelUpPane select-pane\\; send -N5 -X scroll-up",
"bind -Tcopy-mode WheelDownPane select-pane\\; send -N5 -X scroll-down",
- "bind -Tcopy-mode DoubleClick1Pane select-pane\\; send -X select-word",
- "bind -Tcopy-mode TripleClick1Pane select-pane\\; send -X select-line",
+ "bind -Tcopy-mode DoubleClick1Pane select-pane\\; send -X select-word\\; run -d0.3\\; send -X copy-selection-and-cancel",
+ "bind -Tcopy-mode TripleClick1Pane select-pane\\; send -X select-line\\; run -d0.3\\; send -X copy-selection-and-cancel",
"bind -Tcopy-mode NPage send -X page-down",
"bind -Tcopy-mode PPage send -X page-up",
"bind -Tcopy-mode Up send -X cursor-up",
@@ -396,6 +427,7 @@ key_bindings_init(void)
"bind -Tcopy-mode C-Up send -X scroll-up",
"bind -Tcopy-mode C-Down send -X scroll-down",
+ /* Copy mode (vi) keys. */
"bind -Tcopy-mode-vi '#' send -FX search-backward '#{copy_cursor_word}'",
"bind -Tcopy-mode-vi * send -FX search-forward '#{copy_cursor_word}'",
"bind -Tcopy-mode-vi C-c send -X cancel",
@@ -465,8 +497,8 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel",
"bind -Tcopy-mode-vi WheelUpPane select-pane\\; send -N5 -X scroll-up",
"bind -Tcopy-mode-vi WheelDownPane select-pane\\; send -N5 -X scroll-down",
- "bind -Tcopy-mode-vi DoubleClick1Pane select-pane\\; send -X select-word",
- "bind -Tcopy-mode-vi TripleClick1Pane select-pane\\; send -X select-line",
+ "bind -Tcopy-mode-vi DoubleClick1Pane select-pane\\; send -X select-word\\; run -d0.3\\; send -X copy-selection-and-cancel",
+ "bind -Tcopy-mode-vi TripleClick1Pane select-pane\\; send -X select-line\\; run -d0.3\\; send -X copy-selection-and-cancel",
"bind -Tcopy-mode-vi BSpace send -X cursor-left",
"bind -Tcopy-mode-vi NPage send -X page-down",
"bind -Tcopy-mode-vi PPage send -X page-up",
diff --git a/server-client.c b/server-client.c
index fe72317a..fd31eeee 100644
--- a/server-client.c
+++ b/server-client.c
@@ -398,6 +398,8 @@ server_client_exec(struct client *c, const char *cmd)
shell = options_get_string(s->options, "default-shell");
else
shell = options_get_string(global_s_options, "default-shell");
+ if (!checkshell(shell))
+ shell = _PATH_BSHELL;
shellsize = strlen(shell) + 1;
msg = xmalloc(cmdsize + shellsize);
@@ -417,7 +419,7 @@ server_client_check_mouse(struct client *c, struct key_event *event)
struct winlink *wl;
struct window_pane *wp;
u_int x, y, b, sx, sy, px, py;
- int flag;
+ int ignore = 0;
key_code key;
struct timeval tv;
struct style_range *sr;
@@ -441,7 +443,12 @@ server_client_check_mouse(struct client *c, struct key_event *event)
m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag);
/* What type of event is this? */
- if ((m->sgr_type != ' ' &&
+ if (event->key == KEYC_DOUBLECLICK) {
+ type = DOUBLE;
+ x = m->x, y = m->y, b = m->b;
+ ignore = 1;
+ 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) ||
(m->sgr_type == ' ' &&
@@ -475,10 +482,8 @@ server_client_check_mouse(struct client *c, struct key_event *event)
evtimer_del(&c->click_timer);
c->flags &= ~CLIENT_DOUBLECLICK;
if (m->b == c->click_button) {
- type = DOUBLE;
- x = m->x, y = m->y, b = m->b;
- log_debug("double-click at %u,%u", x, y);
- flag = CLIENT_TRIPLECLICK;
+ type = NOTYPE;
+ c->flags |= CLIENT_TRIPLECLICK;
goto add_timer;
}
} else if (c->flags & CLIENT_TRIPLECLICK) {
@@ -488,18 +493,19 @@ server_client_check_mouse(struct client *c, struct key_event *event)
type = TRIPLE;
x = m->x, y = m->y, b = m->b;
log_debug("triple-click at %u,%u", x, y);
+ ignore = 1;
goto have_event;
}
- }
+ } else
+ c->flags |= CLIENT_DOUBLECLICK;
+ add_timer:
type = DOWN;
x = m->x, y = m->y, b = m->b;
log_debug("down at %u,%u", x, y);
- flag = CLIENT_DOUBLECLICK;
- add_timer:
if (KEYC_CLICK_TIMEOUT != 0) {
- c->flags |= flag;
+ memcpy(&c->click_event, m, sizeof c->click_event);
c->click_button = m->b;
tv.tv_sec = KEYC_CLICK_TIMEOUT / 1000;
@@ -516,6 +522,7 @@ have_event:
/* Save the session. */
m->s = s->id;
m->w = -1;
+ m->ignore = ignore;
/* Is this on the status line? */
m->statusat = status_at_line(c);
@@ -1045,7 +1052,7 @@ server_client_key_callback(struct cmdq_item *item, void *data)
/* Check for mouse keys. */
m->valid = 0;
- if (key == KEYC_MOUSE) {
+ if (key == KEYC_MOUSE || key == KEYC_DOUBLECLICK) {
if (c->flags & CLIENT_READONLY)
goto out;
key = server_client_check_mouse(c, event);
@@ -1547,8 +1554,22 @@ server_client_repeat_timer(__unused int fd, __unused short events, void *data)
static void
server_client_click_timer(__unused int fd, __unused short events, void *data)
{
- struct client *c = data;
+ struct client *c = data;
+ struct key_event *event;
+
+ log_debug("click timer expired");
+ if (c->flags & CLIENT_TRIPLECLICK) {
+ /*
+ * Waiting for a third click that hasn't happened, so this must
+ * have been a double click.
+ */
+ event = xmalloc(sizeof *event);
+ event->key = KEYC_DOUBLECLICK;
+ memcpy(&event->m, &c->click_event, sizeof event->m);
+ if (!server_client_handle_key(c, event))
+ free(event);
+ }
c->flags &= ~(CLIENT_DOUBLECLICK|CLIENT_TRIPLECLICK);
}
@@ -1992,7 +2013,7 @@ server_client_dispatch_shell(struct client *c)
const char *shell;
shell = options_get_string(global_s_options, "default-shell");
- if (*shell == '\0' || areshell(shell))
+ if (!checkshell(shell))
shell = _PATH_BSHELL;
proc_send(c->peer, MSG_SHELL, -1, shell, strlen(shell) + 1);
diff --git a/server.c b/server.c
index a5d5e37f..bf8d0310 100644
--- a/server.c
+++ b/server.c
@@ -44,6 +44,7 @@ struct clients clients;
struct tmuxproc *server_proc;
static int server_fd = -1;
+static int server_client_flags;
static int server_exit;
static struct event server_ev_accept;
@@ -97,7 +98,7 @@ server_check_marked(void)
/* Create server socket. */
static int
-server_create_socket(char **cause)
+server_create_socket(int flags, char **cause)
{
struct sockaddr_un sa;
size_t size;
@@ -116,7 +117,10 @@ server_create_socket(char **cause)
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
goto fail;
- mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
+ if (flags & CLIENT_DEFAULTSOCKET)
+ mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
+ else
+ mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
if (bind(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
saved_errno = errno;
close(fd);
@@ -145,8 +149,8 @@ fail:
/* Fork new server. */
int
-server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
- char *lockfile)
+server_start(struct tmuxproc *client, int flags, struct event_base *base,
+ int lockfd, char *lockfile)
{
int pair[2];
sigset_t set, oldset;
@@ -155,6 +159,7 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
fatal("socketpair failed");
+ server_client_flags = flags;
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
@@ -192,7 +197,7 @@ server_start(struct tmuxproc *client, struct event_base *base, int lockfd,
gettimeofday(&start_time, NULL);
- server_fd = server_create_socket(&cause);
+ server_fd = server_create_socket(flags, &cause);
if (server_fd != -1)
server_update_socket();
c = server_client_create(pair[1]);
@@ -395,7 +400,7 @@ server_signal(int sig)
break;
case SIGUSR1:
event_del(&server_ev_accept);
- fd = server_create_socket(NULL);
+ fd = server_create_socket(server_client_flags, NULL);
if (fd != -1) {
close(server_fd);
server_fd = fd;
diff --git a/spawn.c b/spawn.c
index ee19cb9d..88c59100 100644
--- a/spawn.c
+++ b/spawn.c
@@ -318,7 +318,7 @@ spawn_pane(struct spawn_context *sc, char **cause)
/* Then the shell. If respawning, use the old one. */
if (~sc->flags & SPAWN_RESPAWN) {
tmp = options_get_string(s->options, "default-shell");
- if (*tmp == '\0' || areshell(tmp))
+ if (!checkshell(tmp))
tmp = _PATH_BSHELL;
free(new_wp->shell);
new_wp->shell = xstrdup(tmp);
diff --git a/status.c b/status.c
index 33f6c47a..6beadb81 100644
--- a/status.c
+++ b/status.c
@@ -733,6 +733,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
if (c->prompt_mode == PROMPT_ENTRY) {
switch (key) {
case '\003': /* C-c */
+ case '\007': /* C-g */
case '\010': /* C-h */
case '\011': /* Tab */
case '\025': /* C-u */
@@ -813,6 +814,9 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
case 'p':
*new_key = '\031'; /* C-y */
return (1);
+ case 'q':
+ *new_key = '\003'; /* C-c */
+ return (1);
case 's':
case KEYC_DC:
case 'x':
diff --git a/tmux.1 b/tmux.1
index dc78abdc..720b8254 100644
--- a/tmux.1
+++ b/tmux.1
@@ -1565,7 +1565,7 @@ The synopsis for the
command is:
.Bl -tag -width Ds
.It Xo Ic copy-mode
-.Op Fl Meu
+.Op Fl eHMu
.Op Fl t Ar target-pane
.Xc
Enter copy mode.
@@ -1575,6 +1575,9 @@ option scrolls one page up.
.Fl M
begins a mouse drag (only valid if bound to a mouse key binding, see
.Sx MOUSE SUPPORT ) .
+.Fl H
+hides the position indicator in the top right.
+.Pp
.Fl e
specifies that scrolling to the bottom of the history (to the visible screen)
should exit copy mode.
@@ -4107,7 +4110,7 @@ specifies an
.Xr fnmatch 3
or regular expression comparison.
The first argument is the pattern and the second the string to compare.
-An optional third argument specifies flags:
+An optional argument specifies flags:
.Ql r
means the pattern is a regular expression instead of the default
.Xr fnmatch 3
@@ -4134,6 +4137,38 @@ ignores case.
For example:
.Ql #{C/r:^Start}
.Pp
+Numeric operators may be performed by prefixing two comma-separated alternatives with an
+.Ql e
+and an operator.
+An optional
+.Ql f
+flag may be given after the operator to use floating point numbers, otherwise integers are used.
+This may be followed by a number giving the number of decimal places to use for the result.
+The available operators are:
+addition
+.Ql + ,
+subtraction
+.Ql - ,
+multiplication
+.Ql * ,
+division
+.Ql / ,
+and modulus
+.Ql m
+or
+.Ql %
+(note that
+.Ql %
+must be escaped as
+.Ql %%
+in formats which are also expanded by
+.Xr strftime 3 ) .
+For example,
+.Ql #{e|*|f|4:5.5,3}
+multiplies 5.5 by 3 for a result with four decimal places and
+.Ql #{e|%%:7,3}
+returns the modulus of 7 and 3.
+.Pp
A limit may be placed on the length of the resultant string by prefixing it
by an
.Ql = ,
@@ -4806,7 +4841,7 @@ on the value of the
option:
.Bl -column "FunctionXXXXXXXXXXXXXXXXXXXXXXXXX" "viXXXX" "emacsX" -offset indent
.It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
-.It Li "Cancel command prompt" Ta "Escape" Ta "Escape"
+.It Li "Cancel command prompt" Ta "q" Ta "Escape"
.It Li "Delete from cursor to start of word" Ta "" Ta "C-w"
.It Li "Delete entire command" Ta "d" Ta "C-u"
.It Li "Delete from cursor to end" Ta "D" Ta "C-k"
@@ -5168,8 +5203,9 @@ Lock each client individually by running the command specified by the
option.
.It Xo Ic run-shell
.Op Fl b
+.Op Fl d Ar delay
.Op Fl t Ar target-pane
-.Ar shell-command
+.Op Ar shell-command
.Xc
.D1 (alias: Ic run )
Execute
@@ -5182,8 +5218,12 @@ section.
With
.Fl b ,
the command is run in the background.
-After it finishes, any output to stdout is displayed in copy mode (in the pane
-specified by
+.Fl d
+waits for
+.Ar delay
+seconds before starting the command.
+After the command finishes, any output to stdout is displayed in view mode (in
+the pane specified by
.Fl t
or the current pane if omitted).
If the command doesn't return success, the exit status is also displayed.
diff --git a/tmux.c b/tmux.c
index 3c1feccc..46a9a656 100644
--- a/tmux.c
+++ b/tmux.c
@@ -46,8 +46,8 @@ const char *shell_command;
static __dead void usage(void);
static char *make_label(const char *, char **);
+static int areshell(const char *);
static const char *getshell(void);
-static int checkshell(const char *);
static __dead void
usage(void)
@@ -76,7 +76,7 @@ getshell(void)
return (_PATH_BSHELL);
}
-static int
+int
checkshell(const char *shell)
{
if (shell == NULL || *shell != '/')
@@ -88,7 +88,7 @@ checkshell(const char *shell)
return (1);
}
-int
+static int
areshell(const char *shell)
{
const char *progname, *ptr;
@@ -368,12 +368,15 @@ main(int argc, char **argv)
path[strcspn(path, ",")] = '\0';
}
}
- if (path == NULL && (path = make_label(label, &cause)) == NULL) {
- if (cause != NULL) {
- fprintf(stderr, "%s\n", cause);
- free(cause);
+ if (path == NULL) {
+ if ((path = make_label(label, &cause)) == NULL) {
+ if (cause != NULL) {
+ fprintf(stderr, "%s\n", cause);
+ free(cause);
+ }
+ exit(1);
}
- exit(1);
+ flags |= CLIENT_DEFAULTSOCKET;
}
socket_path = path;
free(label);
diff --git a/tmux.h b/tmux.h
index 222f7d43..633a101b 100644
--- a/tmux.h
+++ b/tmux.h
@@ -168,6 +168,7 @@ enum {
/* Mouse keys. */
KEYC_MOUSE, /* unclassified mouse event */
KEYC_DRAGGING, /* dragging in progress */
+ KEYC_DOUBLECLICK, /* double click complete */
KEYC_MOUSE_KEY(MOUSEMOVE),
KEYC_MOUSE_KEY(MOUSEDOWN1),
KEYC_MOUSE_KEY(MOUSEDOWN2),
@@ -562,6 +563,7 @@ struct msg_write_close {
#define ALL_MODES 0xffffff
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
+#define MOTION_MOUSE_MODES (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
/*
* A single UTF-8 character. UTF8_SIZE must be big enough to hold
@@ -1118,6 +1120,7 @@ RB_HEAD(sessions, session);
/* Mouse input. */
struct mouse_event {
int valid;
+ int ignore;
key_code key;
@@ -1549,6 +1552,7 @@ struct client {
struct event click_timer;
u_int click_button;
+ struct mouse_event click_event;
struct status_line status;
@@ -1579,6 +1583,8 @@ struct client {
#define CLIENT_REDRAWSTATUSALWAYS 0x1000000
#define CLIENT_REDRAWOVERLAY 0x2000000
#define CLIENT_CONTROL_NOOUTPUT 0x4000000
+#define CLIENT_DEFAULTSOCKET 0x8000000
+#define CLIENT_STARTSERVER 0x10000000
#define CLIENT_ALLREDRAWFLAGS \
(CLIENT_REDRAWWINDOW| \
CLIENT_REDRAWSTATUS| \
@@ -1767,7 +1773,7 @@ extern const char *socket_path;
extern const char *shell_command;
extern int ptm_fd;
extern const char *shell_command;
-int areshell(const char *);
+int checkshell(const char *);
void setblocking(int, int);
const char *find_cwd(void);
const char *find_home(void);
@@ -1824,6 +1830,7 @@ char *paste_make_sample(struct paste_buffer *);
#define FORMAT_PANE 0x80000000U
#define FORMAT_WINDOW 0x40000000U
struct format_tree;
+struct format_modifier;
const char *format_skip(const char *, const char *);
int format_true(const char *);
struct format_tree *format_create(struct client *, struct cmdq_item *, int,
@@ -2201,7 +2208,7 @@ void server_clear_marked(void);
int server_is_marked(struct session *, struct winlink *,
struct window_pane *);
int server_check_marked(void);
-int server_start(struct tmuxproc *, struct event_base *, int, char *);
+int server_start(struct tmuxproc *, int, struct event_base *, int, char *);
void server_update_socket(void);
void server_add_accept(int);
diff --git a/tty.c b/tty.c
index 8efe57b5..862a1266 100644
--- a/tty.c
+++ b/tty.c
@@ -658,7 +658,8 @@ tty_force_cursor_colour(struct tty *tty, const char *ccolour)
void
tty_update_mode(struct tty *tty, int mode, struct screen *s)
{
- int changed;
+ struct client *c = tty->client;
+ int changed;
if (s != NULL && strcmp(s->ccolour, tty->ccolour) != 0)
tty_force_cursor_colour(tty, s->ccolour);
@@ -667,6 +668,8 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
mode &= ~MODE_CURSOR;
changed = mode ^ tty->mode;
+ log_debug("%s: update mode %x to %x", c->name, tty->mode, mode);
+
if (changed & MODE_BLINKING) {
if (tty_term_has(tty->term, TTYC_CVVIS))
tty_putcode(tty, TTYC_CVVIS);
@@ -690,28 +693,31 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
}
tty->cstyle = s->cstyle;
}
- if (changed & ALL_MOUSE_MODES) {
- if (mode & ALL_MOUSE_MODES) {
- /*
- * Enable the SGR (1006) extension unconditionally, as
- * it is safe from misinterpretation.
- */
- tty_puts(tty, "\033[?1006h");
- if (mode & MODE_MOUSE_ALL)
- tty_puts(tty, "\033[?1003h");
- else if (mode & MODE_MOUSE_BUTTON)
- tty_puts(tty, "\033[?1002h");
- else if (mode & MODE_MOUSE_STANDARD)
- tty_puts(tty, "\033[?1000h");
- } else {
- if (tty->mode & MODE_MOUSE_ALL)
- tty_puts(tty, "\033[?1003l");
- else if (tty->mode & MODE_MOUSE_BUTTON)
- tty_puts(tty, "\033[?1002l");
- else if (tty->mode & MODE_MOUSE_STANDARD)
- tty_puts(tty, "\033[?1000l");
+ if ((changed & ALL_MOUSE_MODES) &&
+ tty_term_has(tty->term, TTYC_KMOUS)) {
+ if ((mode & ALL_MOUSE_MODES) == 0)
tty_puts(tty, "\033[?1006l");
- }
+ if ((changed & MODE_MOUSE_STANDARD) &&
+ (~mode & MODE_MOUSE_STANDARD))
+ tty_puts(tty, "\033[?1000l");
+ if ((changed & MODE_MOUSE_BUTTON) &&
+ (~mode & MODE_MOUSE_BUTTON))
+ tty_puts(tty, "\033[?1002l");
+ if ((changed & MODE_MOUSE_ALL) &&
+ (~mode & MODE_MOUSE_ALL))
+ tty_puts(tty, "\033[?1003l");
+
+ if (mode & ALL_MOUSE_MODES)
+ tty_puts(tty, "\033[?1006h");
+ if ((changed & MODE_MOUSE_STANDARD) &&
+ (mode & MODE_MOUSE_STANDARD))
+ tty_puts(tty, "\033[?1000h");
+ if ((changed & MODE_MOUSE_BUTTON) &&
+ (mode & MODE_MOUSE_BUTTON))
+ tty_puts(tty, "\033[?1002h");
+ if ((changed & MODE_MOUSE_ALL) &&
+ (mode & MODE_MOUSE_ALL))
+ tty_puts(tty, "\033[?1003h");
}
if (changed & MODE_BRACKETPASTE) {
if (mode & MODE_BRACKETPASTE)
diff --git a/window-copy.c b/window-copy.c
index 8e3f63d1..6864d8f9 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -230,6 +230,7 @@ struct window_copy_mode_data {
} lineflag; /* line selection mode */
int rectflag; /* in rectangle copy mode? */
int scroll_exit; /* exit on scroll to end? */
+ int hide_position; /* hide position marker */
enum {
SEL_CHAR, /* select one char at a time */
@@ -304,6 +305,7 @@ window_copy_common_init(struct window_mode_entry *wme)
data->cursordrag = CURSORDRAG_NONE;
data->lineflag = LINE_SEL_NONE;
+ data->selflag = SEL_CHAR;
if (wp->searchstr != NULL) {
data->searchtype = WINDOW_COPY_SEARCHUP;
@@ -345,6 +347,7 @@ window_copy_init(struct window_mode_entry *wme,
data->cy = data->backing->cy;
data->scroll_exit = args_has(args, 'e');
+ data->hide_position = args_has(args, 'H');
data->screen.cx = data->cx;
data->screen.cy = data->cy;
@@ -737,6 +740,7 @@ window_copy_cmd_stop_selection(struct window_copy_cmd_state *cs)
data->cursordrag = CURSORDRAG_NONE;
data->lineflag = LINE_SEL_NONE;
+ data->selflag = SEL_CHAR;
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -2774,7 +2778,7 @@ window_copy_write_line(struct window_mode_entry *wme,
style_apply(&gc, oo, "mode-style");
gc.flags |= GRID_FLAG_NOPALETTE;
- if (py == 0 && s->rupper < s->rlower) {
+ if (py == 0 && s->rupper < s->rlower && !data->hide_position) {
if (data->searchmark == NULL) {
size = xsnprintf(hdr, sizeof hdr,
"[%u/%u]", data->oy, screen_hsize(data->backing));
@@ -2873,15 +2877,15 @@ window_copy_redraw_screen(struct window_mode_entry *wme)
}
static void
-window_copy_synchronize_cursor_end(struct window_mode_entry *wme)
+window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin)
{
struct window_copy_mode_data *data = wme->data;
u_int xx, yy;
- int begin = 0;
yy = screen_hsize(data->backing) + data->cy - data->oy;
switch (data->selflag) {
case SEL_WORD:
+ begin = 0;
xx = data->cx;
if (data->ws == NULL)
break;
@@ -2907,6 +2911,7 @@ window_copy_synchronize_cursor_end(struct window_mode_entry *wme)
}
break;
case SEL_LINE:
+ begin = 0;
if (data->dy > yy) {
/* Right to left selection. */
xx = 0;
@@ -2944,11 +2949,10 @@ window_copy_synchronize_cursor(struct window_mode_entry *wme)
switch (data->cursordrag) {
case CURSORDRAG_ENDSEL:
- window_copy_synchronize_cursor_end(wme);
+ window_copy_synchronize_cursor_end(wme, 0);
break;
case CURSORDRAG_SEL:
- data->selx = data->cx;
- data->sely = screen_hsize(data->backing) + data->cy - data->oy;
+ window_copy_synchronize_cursor_end(wme, 1);
break;
case CURSORDRAG_NONE:
break;
@@ -3358,6 +3362,7 @@ window_copy_clear_selection(struct window_mode_entry *wme)
data->cursordrag = CURSORDRAG_NONE;
data->lineflag = LINE_SEL_NONE;
+ data->selflag = SEL_CHAR;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wme, py);
@@ -4122,7 +4127,7 @@ window_copy_start_drag(struct client *c, struct mouse_event *m)
struct window_pane *wp;
struct window_mode_entry *wme;
struct window_copy_mode_data *data;
- u_int x, y;
+ u_int x, y, yg;
if (c == NULL)
return;
@@ -4143,6 +4148,9 @@ window_copy_start_drag(struct client *c, struct mouse_event *m)
c->tty.mouse_drag_release = window_copy_drag_release;
data = wme->data;
+ yg = screen_hsize(data->backing) + y - data->oy;
+ if (x < data->selrx || x > data->endselrx || yg != data->selry)
+ data->selflag = SEL_CHAR;
switch (data->selflag) {
case SEL_WORD:
if (data->ws) {
diff --git a/window.c b/window.c
index f911f186..c0395287 100644
--- a/window.c
+++ b/window.c
@@ -423,8 +423,8 @@ window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
ypixel = DEFAULT_YPIXEL;
log_debug("%s: @%u resize %ux%u (%ux%u)", __func__, w->id, sx, sy,
- xpixel == -1 ? w->xpixel : xpixel,
- ypixel == -1 ? w->ypixel : ypixel);
+ xpixel == -1 ? w->xpixel : (u_int)xpixel,
+ ypixel == -1 ? w->ypixel : (u_int)ypixel);
w->sx = sx;
w->sy = sy;
if (xpixel != -1)