mirror of
https://github.com/tmate-io/tmate-ssh-server.git
synced 2020-11-18 19:53:51 -08:00
Merge branch 'obsd-master'
This commit is contained in:
commit
0a88377086
9
client.c
9
client.c
@ -261,8 +261,13 @@ client_main(int argc, char **argv, int flags)
|
|||||||
/* Initialize the client socket and start the server. */
|
/* Initialize the client socket and start the server. */
|
||||||
fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
|
fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
fprintf(stderr, "failed to connect to server: %s\n",
|
if (errno == ECONNREFUSED) {
|
||||||
strerror(errno));
|
fprintf(stderr, "no server running on %s\n",
|
||||||
|
socket_path);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "error connecting to %s (%s)\n",
|
||||||
|
socket_path, strerror(errno));
|
||||||
|
}
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ enum cmd_retval cmd_bind_key_mode_table(struct cmd *, struct cmd_q *, int);
|
|||||||
|
|
||||||
const struct cmd_entry cmd_bind_key_entry = {
|
const struct cmd_entry cmd_bind_key_entry = {
|
||||||
"bind-key", "bind",
|
"bind-key", "bind",
|
||||||
"cnrt:", 1, -1,
|
"cnrt:T:", 1, -1,
|
||||||
"[-cnr] [-t mode-table] key command [arguments]",
|
"[-cnr] [-t mode-table] [-T key-table] key command [arguments]",
|
||||||
0,
|
0,
|
||||||
cmd_bind_key_exec
|
cmd_bind_key_exec
|
||||||
};
|
};
|
||||||
@ -46,6 +46,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
char *cause;
|
char *cause;
|
||||||
struct cmd_list *cmdlist;
|
struct cmd_list *cmdlist;
|
||||||
int key;
|
int key;
|
||||||
|
const char *tablename;
|
||||||
|
|
||||||
if (args_has(args, 't')) {
|
if (args_has(args, 't')) {
|
||||||
if (args->argc != 2 && args->argc != 3) {
|
if (args->argc != 2 && args->argc != 3) {
|
||||||
@ -68,6 +69,13 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
if (args_has(args, 't'))
|
if (args_has(args, 't'))
|
||||||
return (cmd_bind_key_mode_table(self, cmdq, key));
|
return (cmd_bind_key_mode_table(self, cmdq, key));
|
||||||
|
|
||||||
|
if (args_has(args, 'T'))
|
||||||
|
tablename = args_get(args, 'T');
|
||||||
|
else if (args_has(args, 'n'))
|
||||||
|
tablename = "root";
|
||||||
|
else
|
||||||
|
tablename = "prefix";
|
||||||
|
|
||||||
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0,
|
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0,
|
||||||
&cause);
|
&cause);
|
||||||
if (cmdlist == NULL) {
|
if (cmdlist == NULL) {
|
||||||
@ -76,9 +84,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args_has(args, 'n'))
|
key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist);
|
||||||
key |= KEYC_PREFIX;
|
|
||||||
key_bindings_add(key, args_has(args, 'r'), cmdlist);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,8 +68,11 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
window_copy_init_from_pane(wp);
|
window_copy_init_from_pane(wp);
|
||||||
}
|
}
|
||||||
if (args_has(args, 'M'))
|
if (args_has(args, 'M')) {
|
||||||
|
if (wp->mode != NULL && wp->mode != &window_copy_mode)
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
window_copy_start_drag(c, &cmdq->item->mouse);
|
window_copy_start_drag(c, &cmdq->item->mouse);
|
||||||
|
}
|
||||||
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
|
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
|
||||||
window_copy_pageup(wp);
|
window_copy_pageup(wp);
|
||||||
|
|
||||||
|
@ -44,11 +44,14 @@ const struct cmd_entry cmd_if_shell_entry = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct cmd_if_shell_data {
|
struct cmd_if_shell_data {
|
||||||
char *cmd_if;
|
char *cmd_if;
|
||||||
char *cmd_else;
|
char *cmd_else;
|
||||||
struct cmd_q *cmdq;
|
|
||||||
int bflag;
|
struct cmd_q *cmdq;
|
||||||
int started;
|
struct mouse_event mouse;
|
||||||
|
|
||||||
|
int bflag;
|
||||||
|
int references;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum cmd_retval
|
enum cmd_retval
|
||||||
@ -95,23 +98,26 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
}
|
}
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
cmdq_run(cmdq, cmdlist, NULL);
|
cmdq_run(cmdq, cmdlist, &cmdq->item->mouse);
|
||||||
cmd_list_free(cmdlist);
|
cmd_list_free(cmdlist);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
cdata = xmalloc(sizeof *cdata);
|
cdata = xmalloc(sizeof *cdata);
|
||||||
|
|
||||||
cdata->cmd_if = xstrdup(args->argv[1]);
|
cdata->cmd_if = xstrdup(args->argv[1]);
|
||||||
if (args->argc == 3)
|
if (args->argc == 3)
|
||||||
cdata->cmd_else = xstrdup(args->argv[2]);
|
cdata->cmd_else = xstrdup(args->argv[2]);
|
||||||
else
|
else
|
||||||
cdata->cmd_else = NULL;
|
cdata->cmd_else = NULL;
|
||||||
|
|
||||||
cdata->bflag = args_has(args, 'b');
|
cdata->bflag = args_has(args, 'b');
|
||||||
|
|
||||||
cdata->started = 0;
|
|
||||||
cdata->cmdq = cmdq;
|
cdata->cmdq = cmdq;
|
||||||
|
memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse);
|
||||||
cmdq->references++;
|
cmdq->references++;
|
||||||
|
|
||||||
|
cdata->references = 1;
|
||||||
job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata);
|
job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata);
|
||||||
free(shellcmd);
|
free(shellcmd);
|
||||||
|
|
||||||
@ -146,13 +152,12 @@ cmd_if_shell_callback(struct job *job)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cdata->started = 1;
|
|
||||||
|
|
||||||
cmdq1 = cmdq_new(cmdq->client);
|
cmdq1 = cmdq_new(cmdq->client);
|
||||||
cmdq1->emptyfn = cmd_if_shell_done;
|
cmdq1->emptyfn = cmd_if_shell_done;
|
||||||
cmdq1->data = cdata;
|
cmdq1->data = cdata;
|
||||||
|
|
||||||
cmdq_run(cmdq1, cmdlist, NULL);
|
cdata->references++;
|
||||||
|
cmdq_run(cmdq1, cmdlist, &cdata->mouse);
|
||||||
cmd_list_free(cmdlist);
|
cmd_list_free(cmdlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,12 +169,14 @@ cmd_if_shell_done(struct cmd_q *cmdq1)
|
|||||||
|
|
||||||
if (cmdq1->client_exit >= 0)
|
if (cmdq1->client_exit >= 0)
|
||||||
cmdq->client_exit = cmdq1->client_exit;
|
cmdq->client_exit = cmdq1->client_exit;
|
||||||
|
cmdq_free(cmdq1);
|
||||||
|
|
||||||
|
if (--cdata->references != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!cmdq_free(cmdq) && !cdata->bflag)
|
if (!cmdq_free(cmdq) && !cdata->bflag)
|
||||||
cmdq_continue(cmdq);
|
cmdq_continue(cmdq);
|
||||||
|
|
||||||
cmdq_free(cmdq1);
|
|
||||||
|
|
||||||
free(cdata->cmd_else);
|
free(cdata->cmd_else);
|
||||||
free(cdata->cmd_if);
|
free(cdata->cmd_if);
|
||||||
free(cdata);
|
free(cdata);
|
||||||
@ -181,7 +188,7 @@ cmd_if_shell_free(void *data)
|
|||||||
struct cmd_if_shell_data *cdata = data;
|
struct cmd_if_shell_data *cdata = data;
|
||||||
struct cmd_q *cmdq = cdata->cmdq;
|
struct cmd_q *cmdq = cdata->cmdq;
|
||||||
|
|
||||||
if (cdata->started)
|
if (--cdata->references != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!cmdq_free(cmdq) && !cdata->bflag)
|
if (!cmdq_free(cmdq) && !cdata->bflag)
|
||||||
|
@ -33,8 +33,8 @@ enum cmd_retval cmd_list_keys_commands(struct cmd *, struct cmd_q *);
|
|||||||
|
|
||||||
const struct cmd_entry cmd_list_keys_entry = {
|
const struct cmd_entry cmd_list_keys_entry = {
|
||||||
"list-keys", "lsk",
|
"list-keys", "lsk",
|
||||||
"t:", 0, 0,
|
"t:T:", 0, 0,
|
||||||
"[-t key-table]",
|
"[-t mode-table] [-T key-table]",
|
||||||
0,
|
0,
|
||||||
cmd_list_keys_exec
|
cmd_list_keys_exec
|
||||||
};
|
};
|
||||||
@ -51,11 +51,12 @@ enum cmd_retval
|
|||||||
cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
|
cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
|
struct key_table *table;
|
||||||
struct key_binding *bd;
|
struct key_binding *bd;
|
||||||
const char *key;
|
const char *key, *tablename, *r;
|
||||||
char tmp[BUFSIZ], flags[8];
|
char tmp[BUFSIZ];
|
||||||
size_t used;
|
size_t used;
|
||||||
int width, keywidth;
|
int repeat, width, tablewidth, keywidth;
|
||||||
|
|
||||||
if (self->entry == &cmd_list_commands_entry)
|
if (self->entry == &cmd_list_commands_entry)
|
||||||
return (cmd_list_keys_commands(self, cmdq));
|
return (cmd_list_keys_commands(self, cmdq));
|
||||||
@ -63,46 +64,57 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
if (args_has(args, 't'))
|
if (args_has(args, 't'))
|
||||||
return (cmd_list_keys_table(self, cmdq));
|
return (cmd_list_keys_table(self, cmdq));
|
||||||
|
|
||||||
width = 0;
|
tablename = args_get(args, 'T');
|
||||||
|
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
|
||||||
RB_FOREACH(bd, key_bindings, &key_bindings) {
|
cmdq_error(cmdq, "table %s doesn't exist", tablename);
|
||||||
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
|
return (CMD_RETURN_ERROR);
|
||||||
if (key == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
keywidth = strlen(key);
|
|
||||||
if (!(bd->key & KEYC_PREFIX)) {
|
|
||||||
if (bd->can_repeat)
|
|
||||||
keywidth += 4;
|
|
||||||
else
|
|
||||||
keywidth += 3;
|
|
||||||
} else if (bd->can_repeat)
|
|
||||||
keywidth += 3;
|
|
||||||
if (keywidth > width)
|
|
||||||
width = keywidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RB_FOREACH(bd, key_bindings, &key_bindings) {
|
repeat = 0;
|
||||||
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
|
tablewidth = keywidth = 0;
|
||||||
if (key == NULL)
|
RB_FOREACH(table, key_tables, &key_tables) {
|
||||||
|
if (tablename != NULL && strcmp(table->name, tablename) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
|
||||||
|
key = key_string_lookup_key(bd->key);
|
||||||
|
if (key == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
*flags = '\0';
|
|
||||||
if (!(bd->key & KEYC_PREFIX)) {
|
|
||||||
if (bd->can_repeat)
|
if (bd->can_repeat)
|
||||||
xsnprintf(flags, sizeof flags, "-rn ");
|
repeat = 1;
|
||||||
else
|
|
||||||
xsnprintf(flags, sizeof flags, "-n ");
|
|
||||||
} else if (bd->can_repeat)
|
|
||||||
xsnprintf(flags, sizeof flags, "-r ");
|
|
||||||
|
|
||||||
used = xsnprintf(tmp, sizeof tmp, "%s%*s ",
|
width = strlen(table->name);
|
||||||
flags, (int) (width - strlen(flags)), key);
|
if (width > tablewidth)
|
||||||
if (used >= sizeof tmp)
|
tablewidth =width;
|
||||||
|
width = strlen(key);
|
||||||
|
if (width > keywidth)
|
||||||
|
keywidth = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RB_FOREACH(table, key_tables, &key_tables) {
|
||||||
|
if (tablename != NULL && strcmp(table->name, tablename) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
|
||||||
|
key = key_string_lookup_key(bd->key);
|
||||||
|
if (key == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
|
if (!repeat)
|
||||||
cmdq_print(cmdq, "bind-key %s", tmp);
|
r = "";
|
||||||
|
else if (bd->can_repeat)
|
||||||
|
r = "-r ";
|
||||||
|
else
|
||||||
|
r = " ";
|
||||||
|
used = xsnprintf(tmp, sizeof tmp, "%s-T %-*s %-*s ", r,
|
||||||
|
(int)tablewidth, table->name, (int)keywidth, key);
|
||||||
|
if (used < sizeof tmp) {
|
||||||
|
cmd_list_print(bd->cmdlist, tmp + used,
|
||||||
|
(sizeof tmp) - used);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdq_print(cmdq, "bind-key %s", tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
@ -51,7 +51,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
struct session *src, *dst, *s;
|
struct session *src, *dst, *s;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
char *cause;
|
char *cause;
|
||||||
int idx, kflag, dflag;
|
int idx, kflag, dflag, sflag;
|
||||||
|
|
||||||
if (args_has(args, 'r')) {
|
if (args_has(args, 'r')) {
|
||||||
s = cmd_find_session(cmdq, args_get(args, 't'), 0);
|
s = cmd_find_session(cmdq, args_get(args, 't'), 0);
|
||||||
@ -71,6 +71,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
|
|
||||||
kflag = args_has(self->args, 'k');
|
kflag = args_has(self->args, 'k');
|
||||||
dflag = args_has(self->args, 'd');
|
dflag = args_has(self->args, 'd');
|
||||||
|
sflag = args_has(self->args, 's');
|
||||||
if (server_link_window(src, wl, dst, idx, kflag, !dflag,
|
if (server_link_window(src, wl, dst, idx, kflag, !dflag,
|
||||||
&cause) != 0) {
|
&cause) != 0) {
|
||||||
cmdq_error(cmdq, "can't link window: %s", cause);
|
cmdq_error(cmdq, "can't link window: %s", cause);
|
||||||
@ -79,6 +80,15 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
}
|
}
|
||||||
if (self->entry == &cmd_move_window_entry)
|
if (self->entry == &cmd_move_window_entry)
|
||||||
server_unlink_window(src, wl);
|
server_unlink_window(src, wl);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Renumber the winlinks in the src session only, the destination
|
||||||
|
* session already has the correct winlink id to us, either
|
||||||
|
* automatically or specified by -s.
|
||||||
|
*/
|
||||||
|
if (!sflag && options_get_number(&src->options, "renumber-windows"))
|
||||||
|
session_renumber_windows(src);
|
||||||
|
|
||||||
recalculate_sizes();
|
recalculate_sizes();
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
@ -31,8 +31,8 @@ enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *);
|
|||||||
|
|
||||||
const struct cmd_entry cmd_switch_client_entry = {
|
const struct cmd_entry cmd_switch_client_entry = {
|
||||||
"switch-client", "switchc",
|
"switch-client", "switchc",
|
||||||
"lc:npt:r", 0, 0,
|
"lc:npt:rT:", 0, 0,
|
||||||
"[-lnpr] [-c target-client] [-t target-session]",
|
"[-lnpr] [-c target-client] [-t target-session] [-T key-table]",
|
||||||
CMD_READONLY,
|
CMD_READONLY,
|
||||||
cmd_switch_client_exec
|
cmd_switch_client_exec
|
||||||
};
|
};
|
||||||
@ -46,7 +46,8 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
struct winlink *wl = NULL;
|
struct winlink *wl = NULL;
|
||||||
struct window *w = NULL;
|
struct window *w = NULL;
|
||||||
struct window_pane *wp = NULL;
|
struct window_pane *wp = NULL;
|
||||||
const char *tflag;
|
const char *tflag, *tablename;
|
||||||
|
struct key_table *table;
|
||||||
|
|
||||||
if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL)
|
if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL)
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
@ -58,6 +59,18 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
c->flags |= CLIENT_READONLY;
|
c->flags |= CLIENT_READONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tablename = args_get(args, 'T');
|
||||||
|
if (tablename != NULL) {
|
||||||
|
table = key_bindings_get_table(tablename, 0);
|
||||||
|
if (table == NULL) {
|
||||||
|
cmdq_error(cmdq, "table %s doesn't exist", tablename);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
table->references++;
|
||||||
|
key_bindings_unref_table(c->keytable);
|
||||||
|
c->keytable = table;
|
||||||
|
}
|
||||||
|
|
||||||
tflag = args_get(args, 't');
|
tflag = args_get(args, 't');
|
||||||
if (args_has(args, 'n')) {
|
if (args_has(args, 'n')) {
|
||||||
if ((s = session_next_session(c->session)) == NULL) {
|
if ((s = session_next_session(c->session)) == NULL) {
|
||||||
|
@ -31,8 +31,8 @@ enum cmd_retval cmd_unbind_key_mode_table(struct cmd *, struct cmd_q *, int);
|
|||||||
|
|
||||||
const struct cmd_entry cmd_unbind_key_entry = {
|
const struct cmd_entry cmd_unbind_key_entry = {
|
||||||
"unbind-key", "unbind",
|
"unbind-key", "unbind",
|
||||||
"acnt:", 0, 1,
|
"acnt:T:", 0, 1,
|
||||||
"[-acn] [-t mode-table] key",
|
"[-acn] [-t mode-table] [-T key-table] key",
|
||||||
0,
|
0,
|
||||||
cmd_unbind_key_exec
|
cmd_unbind_key_exec
|
||||||
};
|
};
|
||||||
@ -40,9 +40,9 @@ const struct cmd_entry cmd_unbind_key_entry = {
|
|||||||
enum cmd_retval
|
enum cmd_retval
|
||||||
cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
|
cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct key_binding *bd;
|
int key;
|
||||||
int key;
|
const char *tablename;
|
||||||
|
|
||||||
if (!args_has(args, 'a')) {
|
if (!args_has(args, 'a')) {
|
||||||
if (args->argc != 1) {
|
if (args->argc != 1) {
|
||||||
@ -66,16 +66,31 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
return (cmd_unbind_key_mode_table(self, cmdq, key));
|
return (cmd_unbind_key_mode_table(self, cmdq, key));
|
||||||
|
|
||||||
if (key == KEYC_NONE) {
|
if (key == KEYC_NONE) {
|
||||||
while (!RB_EMPTY(&key_bindings)) {
|
tablename = args_get(args, 'T');
|
||||||
bd = RB_ROOT(&key_bindings);
|
if (tablename == NULL) {
|
||||||
key_bindings_remove(bd->key);
|
key_bindings_remove_table("root");
|
||||||
|
key_bindings_remove_table("prefix");
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
if (key_bindings_get_table(tablename, 0) == NULL) {
|
||||||
|
cmdq_error(cmdq, "table %s doesn't exist", tablename);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
key_bindings_remove_table(tablename);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args_has(args, 'n'))
|
if (args_has(args, 'T')) {
|
||||||
key |= KEYC_PREFIX;
|
tablename = args_get(args, 'T');
|
||||||
key_bindings_remove(key);
|
if (key_bindings_get_table(tablename, 0) == NULL) {
|
||||||
|
cmdq_error(cmdq, "table %s doesn't exist", tablename);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
} else if (args_has(args, 'n'))
|
||||||
|
tablename = "root";
|
||||||
|
else
|
||||||
|
tablename = "prefix";
|
||||||
|
key_bindings_remove(tablename, key);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
cmd.c
8
cmd.c
@ -780,15 +780,15 @@ cmd_lookup_index(struct session *s, const char *name, int *ambiguous)
|
|||||||
const char *errstr;
|
const char *errstr;
|
||||||
u_int idx;
|
u_int idx;
|
||||||
|
|
||||||
|
idx = strtonum(name, 0, INT_MAX, &errstr);
|
||||||
|
if (errstr == NULL)
|
||||||
|
return (idx);
|
||||||
|
|
||||||
if ((wl = cmd_lookup_window(s, name, ambiguous)) != NULL)
|
if ((wl = cmd_lookup_window(s, name, ambiguous)) != NULL)
|
||||||
return (wl->idx);
|
return (wl->idx);
|
||||||
if (*ambiguous)
|
if (*ambiguous)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
idx = strtonum(name, 0, INT_MAX, &errstr);
|
|
||||||
if (errstr == NULL)
|
|
||||||
return (idx);
|
|
||||||
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
format.c
13
format.c
@ -546,7 +546,11 @@ format_defaults_client(struct format_tree *ft, struct client *c)
|
|||||||
format_add(ft, "client_activity", "%lld", (long long) t);
|
format_add(ft, "client_activity", "%lld", (long long) t);
|
||||||
format_add(ft, "client_activity_string", "%s", format_time_string(t));
|
format_add(ft, "client_activity_string", "%s", format_time_string(t));
|
||||||
|
|
||||||
format_add(ft, "client_prefix", "%d", !!(c->flags & CLIENT_PREFIX));
|
if (strcmp(c->keytable->name, "root") == 0)
|
||||||
|
format_add(ft, "client_prefix", "%d", 0);
|
||||||
|
else
|
||||||
|
format_add(ft, "client_prefix", "%d", 1);
|
||||||
|
format_add(ft, "client_key_table", "%s", c->keytable->name);
|
||||||
|
|
||||||
if (c->tty.flags & TTY_UTF8)
|
if (c->tty.flags & TTY_UTF8)
|
||||||
format_add(ft, "client_utf8", "%d", 1);
|
format_add(ft, "client_utf8", "%d", 1);
|
||||||
@ -574,7 +578,10 @@ format_defaults_window(struct format_tree *ft, struct window *w)
|
|||||||
|
|
||||||
ft->w = w;
|
ft->w = w;
|
||||||
|
|
||||||
layout = layout_dump(w);
|
if (w->saved_layout_root != NULL)
|
||||||
|
layout = layout_dump(w->saved_layout_root);
|
||||||
|
else
|
||||||
|
layout = layout_dump(w->layout_root);
|
||||||
|
|
||||||
format_add(ft, "window_id", "@%u", w->id);
|
format_add(ft, "window_id", "@%u", w->id);
|
||||||
format_add(ft, "window_name", "%s", w->name);
|
format_add(ft, "window_name", "%s", w->name);
|
||||||
@ -728,6 +735,8 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
|
|||||||
format_add(ft, "wrap_flag", "%d",
|
format_add(ft, "wrap_flag", "%d",
|
||||||
!!(wp->base.mode & MODE_WRAP));
|
!!(wp->base.mode & MODE_WRAP));
|
||||||
|
|
||||||
|
format_add(ft, "mouse_any_flag", "%d",
|
||||||
|
!!(wp->base.mode & (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON)));
|
||||||
format_add(ft, "mouse_standard_flag", "%d",
|
format_add(ft, "mouse_standard_flag", "%d",
|
||||||
!!(wp->base.mode & MODE_MOUSE_STANDARD));
|
!!(wp->base.mode & MODE_MOUSE_STANDARD));
|
||||||
format_add(ft, "mouse_button_flag", "%d",
|
format_add(ft, "mouse_button_flag", "%d",
|
||||||
|
@ -250,5 +250,6 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
|
|||||||
buf[len++] = x + 33;
|
buf[len++] = x + 33;
|
||||||
buf[len++] = y + 33;
|
buf[len++] = y + 33;
|
||||||
}
|
}
|
||||||
|
log_debug("writing mouse %.*s", (int)len, buf);
|
||||||
bufferevent_write(wp->event, buf, len);
|
bufferevent_write(wp->event, buf, len);
|
||||||
}
|
}
|
||||||
|
114
key-bindings.c
114
key-bindings.c
@ -25,60 +25,120 @@
|
|||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
|
RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||||
|
RB_GENERATE(key_tables, key_table, entry, key_table_cmp);
|
||||||
|
struct key_tables key_tables = RB_INITIALIZER(&key_tables);
|
||||||
|
|
||||||
struct key_bindings key_bindings;
|
int
|
||||||
|
key_table_cmp(struct key_table *e1, struct key_table *e2)
|
||||||
|
{
|
||||||
|
return (strcmp(e1->name, e2->name));
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
|
key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
|
||||||
{
|
{
|
||||||
int key1, key2;
|
return (bd1->key - bd2->key);
|
||||||
|
|
||||||
key1 = bd1->key & ~KEYC_PREFIX;
|
|
||||||
key2 = bd2->key & ~KEYC_PREFIX;
|
|
||||||
if (key1 != key2)
|
|
||||||
return (key1 - key2);
|
|
||||||
|
|
||||||
if (bd1->key & KEYC_PREFIX && !(bd2->key & KEYC_PREFIX))
|
|
||||||
return (-1);
|
|
||||||
if (bd2->key & KEYC_PREFIX && !(bd1->key & KEYC_PREFIX))
|
|
||||||
return (1);
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct key_binding *
|
struct key_table *
|
||||||
key_bindings_lookup(int key)
|
key_bindings_get_table(const char *name, int create)
|
||||||
{
|
{
|
||||||
struct key_binding bd;
|
struct key_table table_find, *table;
|
||||||
|
|
||||||
bd.key = key;
|
table_find.name = name;
|
||||||
return (RB_FIND(key_bindings, &key_bindings, &bd));
|
table = RB_FIND(key_tables, &key_tables, &table_find);
|
||||||
|
if (table != NULL || !create)
|
||||||
|
return (table);
|
||||||
|
|
||||||
|
table = xmalloc(sizeof *table);
|
||||||
|
table->name = xstrdup(name);
|
||||||
|
RB_INIT(&table->key_bindings);
|
||||||
|
|
||||||
|
table->references = 1; /* one reference in key_tables */
|
||||||
|
RB_INSERT(key_tables, &key_tables, table);
|
||||||
|
|
||||||
|
return (table);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist)
|
key_bindings_unref_table(struct key_table *table)
|
||||||
{
|
{
|
||||||
struct key_binding *bd;
|
struct key_binding *bd;
|
||||||
|
|
||||||
key_bindings_remove(key);
|
if (--table->references != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (!RB_EMPTY(&table->key_bindings)) {
|
||||||
|
bd = RB_ROOT(&table->key_bindings);
|
||||||
|
RB_REMOVE(key_bindings, &table->key_bindings, bd);
|
||||||
|
cmd_list_free(bd->cmdlist);
|
||||||
|
free(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
free((void *)table->name);
|
||||||
|
free(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
key_bindings_add(const char *name, int key, int can_repeat,
|
||||||
|
struct cmd_list *cmdlist)
|
||||||
|
{
|
||||||
|
struct key_table *table;
|
||||||
|
struct key_binding bd_find, *bd;
|
||||||
|
|
||||||
|
table = key_bindings_get_table(name, 1);
|
||||||
|
|
||||||
|
bd_find.key = key;
|
||||||
|
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
|
||||||
|
if (bd != NULL) {
|
||||||
|
RB_REMOVE(key_bindings, &table->key_bindings, bd);
|
||||||
|
cmd_list_free(bd->cmdlist);
|
||||||
|
free(bd);
|
||||||
|
}
|
||||||
|
|
||||||
bd = xmalloc(sizeof *bd);
|
bd = xmalloc(sizeof *bd);
|
||||||
bd->key = key;
|
bd->key = key;
|
||||||
RB_INSERT(key_bindings, &key_bindings, bd);
|
RB_INSERT(key_bindings, &table->key_bindings, bd);
|
||||||
|
|
||||||
bd->can_repeat = can_repeat;
|
bd->can_repeat = can_repeat;
|
||||||
bd->cmdlist = cmdlist;
|
bd->cmdlist = cmdlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
key_bindings_remove(int key)
|
key_bindings_remove(const char *name, int key)
|
||||||
{
|
{
|
||||||
struct key_binding *bd;
|
struct key_table *table;
|
||||||
|
struct key_binding bd_find, *bd;
|
||||||
|
|
||||||
if ((bd = key_bindings_lookup(key)) == NULL)
|
table = key_bindings_get_table(name, 0);
|
||||||
|
if (table == NULL)
|
||||||
return;
|
return;
|
||||||
RB_REMOVE(key_bindings, &key_bindings, bd);
|
|
||||||
|
bd_find.key = key;
|
||||||
|
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
|
||||||
|
if (bd == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RB_REMOVE(key_bindings, &table->key_bindings, bd);
|
||||||
cmd_list_free(bd->cmdlist);
|
cmd_list_free(bd->cmdlist);
|
||||||
free(bd);
|
free(bd);
|
||||||
|
|
||||||
|
if (RB_EMPTY(&table->key_bindings)) {
|
||||||
|
RB_REMOVE(key_tables, &key_tables, table);
|
||||||
|
key_bindings_unref_table(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
key_bindings_remove_table(const char *name)
|
||||||
|
{
|
||||||
|
struct key_table *table;
|
||||||
|
|
||||||
|
table = key_bindings_get_table(name, 0);
|
||||||
|
if (table != NULL) {
|
||||||
|
RB_REMOVE(key_tables, &key_tables, table);
|
||||||
|
key_bindings_unref_table(table);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -161,7 +221,7 @@ key_bindings_init(void)
|
|||||||
"bind -n MouseDown1Pane select-pane -t=\\; send-keys -M",
|
"bind -n MouseDown1Pane select-pane -t=\\; send-keys -M",
|
||||||
"bind -n MouseDrag1Border resize-pane -M",
|
"bind -n MouseDrag1Border resize-pane -M",
|
||||||
"bind -n MouseDown1Status select-window -t=",
|
"bind -n MouseDown1Status select-window -t=",
|
||||||
"bind -n MouseDrag1Pane copy-mode -M",
|
"bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'",
|
||||||
};
|
};
|
||||||
u_int i;
|
u_int i;
|
||||||
struct cmd_list *cmdlist;
|
struct cmd_list *cmdlist;
|
||||||
@ -169,8 +229,6 @@ key_bindings_init(void)
|
|||||||
int error;
|
int error;
|
||||||
struct cmd_q *cmdq;
|
struct cmd_q *cmdq;
|
||||||
|
|
||||||
RB_INIT(&key_bindings);
|
|
||||||
|
|
||||||
cmdq = cmdq_new(NULL);
|
cmdq = cmdq_new(NULL);
|
||||||
for (i = 0; i < nitems(defaults); i++) {
|
for (i = 0; i < nitems(defaults); i++) {
|
||||||
error = cmd_string_parse(defaults[i], &cmdlist,
|
error = cmd_string_parse(defaults[i], &cmdlist,
|
||||||
|
@ -55,12 +55,12 @@ layout_checksum(const char *layout)
|
|||||||
|
|
||||||
/* Dump layout as a string. */
|
/* Dump layout as a string. */
|
||||||
char *
|
char *
|
||||||
layout_dump(struct window *w)
|
layout_dump(struct layout_cell *root)
|
||||||
{
|
{
|
||||||
char layout[BUFSIZ], *out;
|
char layout[BUFSIZ], *out;
|
||||||
|
|
||||||
*layout = '\0';
|
*layout = '\0';
|
||||||
if (layout_append(w->layout_root, layout, sizeof layout) != 0)
|
if (layout_append(root, layout, sizeof layout) != 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
xasprintf(&out, "%04x,%s", layout_checksum(layout), layout);
|
xasprintf(&out, "%04x,%s", layout_checksum(layout), layout);
|
||||||
|
172
server-client.c
172
server-client.c
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
|
void server_client_key_table(struct client *, const char *);
|
||||||
void server_client_check_focus(struct window_pane *);
|
void server_client_check_focus(struct window_pane *);
|
||||||
void server_client_check_resize(struct window_pane *);
|
void server_client_check_resize(struct window_pane *);
|
||||||
int server_client_check_mouse(struct client *);
|
int server_client_check_mouse(struct client *);
|
||||||
@ -44,6 +45,15 @@ void server_client_msg_command(struct client *, struct imsg *);
|
|||||||
void server_client_msg_identify(struct client *, struct imsg *);
|
void server_client_msg_identify(struct client *, struct imsg *);
|
||||||
void server_client_msg_shell(struct client *);
|
void server_client_msg_shell(struct client *);
|
||||||
|
|
||||||
|
/* Set client key table. */
|
||||||
|
void
|
||||||
|
server_client_key_table(struct client *c, const char *name)
|
||||||
|
{
|
||||||
|
key_bindings_unref_table(c->keytable);
|
||||||
|
c->keytable = key_bindings_get_table(name, 1);
|
||||||
|
c->keytable->references++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a new client. */
|
/* Create a new client. */
|
||||||
void
|
void
|
||||||
server_client_create(int fd)
|
server_client_create(int fd)
|
||||||
@ -92,6 +102,9 @@ server_client_create(int fd)
|
|||||||
|
|
||||||
c->flags |= CLIENT_FOCUSED;
|
c->flags |= CLIENT_FOCUSED;
|
||||||
|
|
||||||
|
c->keytable = key_bindings_get_table("root", 1);
|
||||||
|
c->keytable->references++;
|
||||||
|
|
||||||
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
|
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||||
@ -163,6 +176,8 @@ server_client_lost(struct client *c)
|
|||||||
|
|
||||||
evtimer_del(&c->repeat_timer);
|
evtimer_del(&c->repeat_timer);
|
||||||
|
|
||||||
|
key_bindings_unref_table(c->keytable);
|
||||||
|
|
||||||
if (event_initialized(&c->identify_timer))
|
if (event_initialized(&c->identify_timer))
|
||||||
evtimer_del(&c->identify_timer);
|
evtimer_del(&c->identify_timer);
|
||||||
|
|
||||||
@ -375,7 +390,7 @@ server_client_check_mouse(struct client *c)
|
|||||||
c->tty.mouse_drag_release = NULL;
|
c->tty.mouse_drag_release = NULL;
|
||||||
|
|
||||||
c->tty.mouse_drag_flag = 0;
|
c->tty.mouse_drag_flag = 0;
|
||||||
return (KEYC_NONE);
|
return (KEYC_MOUSE); /* not a key, but still may want to pass */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert to a key binding. */
|
/* Convert to a key binding. */
|
||||||
@ -526,16 +541,19 @@ void
|
|||||||
server_client_handle_key(struct client *c, int key)
|
server_client_handle_key(struct client *c, int key)
|
||||||
{
|
{
|
||||||
struct mouse_event *m = &c->tty.mouse;
|
struct mouse_event *m = &c->tty.mouse;
|
||||||
struct session *s;
|
struct session *s = c->session;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
struct key_binding *bd;
|
struct key_table *table = c->keytable;
|
||||||
int xtimeout, isprefix, ispaste;
|
struct key_binding bd_find, *bd;
|
||||||
|
int xtimeout;
|
||||||
|
|
||||||
/* Check the client is good to accept input. */
|
/* Check the client is good to accept input. */
|
||||||
if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
|
if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
|
||||||
return;
|
return;
|
||||||
|
w = s->curw->window;
|
||||||
|
wp = w->active;
|
||||||
|
|
||||||
/* No session, do nothing. */
|
/* No session, do nothing. */
|
||||||
if (c->session == NULL)
|
if (c->session == NULL)
|
||||||
@ -551,7 +569,7 @@ server_client_handle_key(struct client *c, int key)
|
|||||||
sizeof s->last_activity_time);
|
sizeof s->last_activity_time);
|
||||||
memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
|
memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
|
||||||
|
|
||||||
/* Special case: number keys jump to pane in identify mode. */
|
/* Number keys jump to pane in identify mode. */
|
||||||
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
|
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
|
||||||
if (c->flags & CLIENT_READONLY)
|
if (c->flags & CLIENT_READONLY)
|
||||||
return;
|
return;
|
||||||
@ -592,74 +610,88 @@ server_client_handle_key(struct client *c, int key)
|
|||||||
} else
|
} else
|
||||||
m->valid = 0;
|
m->valid = 0;
|
||||||
|
|
||||||
/* Is this a prefix key? */
|
/* Treat everything as a regular key when pasting is detected. */
|
||||||
if (key == options_get_number(&s->options, "prefix"))
|
if (server_client_assume_paste(s)) {
|
||||||
isprefix = 1;
|
if (!(c->flags & CLIENT_READONLY))
|
||||||
else if (key == options_get_number(&s->options, "prefix2"))
|
|
||||||
isprefix = 1;
|
|
||||||
else
|
|
||||||
isprefix = 0;
|
|
||||||
|
|
||||||
/* Treat prefix as a regular key when pasting is detected. */
|
|
||||||
ispaste = server_client_assume_paste(s);
|
|
||||||
if (ispaste)
|
|
||||||
isprefix = 0;
|
|
||||||
|
|
||||||
/* No previous prefix key. */
|
|
||||||
if (!(c->flags & CLIENT_PREFIX)) {
|
|
||||||
if (isprefix) {
|
|
||||||
c->flags |= CLIENT_PREFIX;
|
|
||||||
server_status_client(c);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try as a non-prefix key binding. */
|
|
||||||
if (ispaste || (bd = key_bindings_lookup(key)) == NULL) {
|
|
||||||
if (!(c->flags & CLIENT_READONLY))
|
|
||||||
window_pane_key(wp, c, s, key, m);
|
|
||||||
} else
|
|
||||||
key_bindings_dispatch(bd, c, m);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prefix key already pressed. Reset prefix and lookup key. */
|
|
||||||
c->flags &= ~CLIENT_PREFIX;
|
|
||||||
server_status_client(c);
|
|
||||||
if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
|
|
||||||
/* If repeating, treat this as a key, else ignore. */
|
|
||||||
if (c->flags & CLIENT_REPEAT) {
|
|
||||||
c->flags &= ~CLIENT_REPEAT;
|
|
||||||
if (isprefix)
|
|
||||||
c->flags |= CLIENT_PREFIX;
|
|
||||||
else if (!(c->flags & CLIENT_READONLY))
|
|
||||||
window_pane_key(wp, c, s, key, m);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If already repeating, but this key can't repeat, skip it. */
|
|
||||||
if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
|
|
||||||
c->flags &= ~CLIENT_REPEAT;
|
|
||||||
if (isprefix)
|
|
||||||
c->flags |= CLIENT_PREFIX;
|
|
||||||
else if (!(c->flags & CLIENT_READONLY))
|
|
||||||
window_pane_key(wp, c, s, key, m);
|
window_pane_key(wp, c, s, key, m);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this key can repeat, reset the repeat flags and timer. */
|
retry:
|
||||||
xtimeout = options_get_number(&s->options, "repeat-time");
|
/* Try to see if there is a key binding in the current table. */
|
||||||
if (xtimeout != 0 && bd->can_repeat) {
|
bd_find.key = key;
|
||||||
c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
|
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
|
||||||
|
if (bd != NULL) {
|
||||||
|
/*
|
||||||
|
* Key was matched in this table. If currently repeating but a
|
||||||
|
* non-repeating binding was found, stop repeating and try
|
||||||
|
* again in the root table.
|
||||||
|
*/
|
||||||
|
if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) {
|
||||||
|
server_client_key_table(c, "root");
|
||||||
|
c->flags &= ~CLIENT_REPEAT;
|
||||||
|
server_status_client(c);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
tv.tv_sec = xtimeout / 1000;
|
/*
|
||||||
tv.tv_usec = (xtimeout % 1000) * 1000L;
|
* Take a reference to this table to make sure the key binding
|
||||||
evtimer_del(&c->repeat_timer);
|
* doesn't disappear.
|
||||||
evtimer_add(&c->repeat_timer, &tv);
|
*/
|
||||||
|
table->references++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is a repeating key, start the timer. Otherwise reset
|
||||||
|
* the client back to the root table.
|
||||||
|
*/
|
||||||
|
xtimeout = options_get_number(&s->options, "repeat-time");
|
||||||
|
if (xtimeout != 0 && bd->can_repeat) {
|
||||||
|
c->flags |= CLIENT_REPEAT;
|
||||||
|
|
||||||
|
tv.tv_sec = xtimeout / 1000;
|
||||||
|
tv.tv_usec = (xtimeout % 1000) * 1000L;
|
||||||
|
evtimer_del(&c->repeat_timer);
|
||||||
|
evtimer_add(&c->repeat_timer, &tv);
|
||||||
|
} else {
|
||||||
|
c->flags &= ~CLIENT_REPEAT;
|
||||||
|
server_client_key_table(c, "root");
|
||||||
|
}
|
||||||
|
server_status_client(c);
|
||||||
|
|
||||||
|
/* Dispatch the key binding. */
|
||||||
|
key_bindings_dispatch(bd, c, m);
|
||||||
|
key_bindings_unref_table(table);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dispatch the command. */
|
/*
|
||||||
key_bindings_dispatch(bd, c, m);
|
* No match in this table. If repeating, switch the client back to the
|
||||||
|
* root table and try again.
|
||||||
|
*/
|
||||||
|
if (c->flags & CLIENT_REPEAT) {
|
||||||
|
server_client_key_table(c, "root");
|
||||||
|
c->flags &= ~CLIENT_REPEAT;
|
||||||
|
server_status_client(c);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no match and we're not in the root table, that's it. */
|
||||||
|
if (strcmp(c->keytable->name, "root") != 0) {
|
||||||
|
server_client_key_table(c, "root");
|
||||||
|
server_status_client(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No match, but in the root table. Prefix switches to the prefix table
|
||||||
|
* and everything else is passed through.
|
||||||
|
*/
|
||||||
|
if (key == options_get_number(&s->options, "prefix") ||
|
||||||
|
key == options_get_number(&s->options, "prefix2")) {
|
||||||
|
server_client_key_table(c, "prefix");
|
||||||
|
server_status_client(c);
|
||||||
|
} else if (!(c->flags & CLIENT_READONLY))
|
||||||
|
window_pane_key(wp, c, s, key, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Client functions that need to happen every loop. */
|
/* Client functions that need to happen every loop. */
|
||||||
@ -857,9 +889,9 @@ server_client_repeat_timer(unused int fd, unused short events, void *data)
|
|||||||
struct client *c = data;
|
struct client *c = data;
|
||||||
|
|
||||||
if (c->flags & CLIENT_REPEAT) {
|
if (c->flags & CLIENT_REPEAT) {
|
||||||
if (c->flags & CLIENT_PREFIX)
|
server_client_key_table(c, "root");
|
||||||
server_status_client(c);
|
c->flags &= ~CLIENT_REPEAT;
|
||||||
c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
|
server_status_client(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +351,6 @@ server_unlink_window(struct session *s, struct winlink *wl)
|
|||||||
server_destroy_session_group(s);
|
server_destroy_session_group(s);
|
||||||
else
|
else
|
||||||
server_redraw_session_group(s);
|
server_redraw_session_group(s);
|
||||||
session_renumber_windows(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
22
server.c
22
server.c
@ -78,24 +78,22 @@ server_create_socket(void)
|
|||||||
size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
|
size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
|
||||||
if (size >= sizeof sa.sun_path) {
|
if (size >= sizeof sa.sun_path) {
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
fatal("socket failed");
|
return (-1);
|
||||||
}
|
}
|
||||||
unlink(sa.sun_path);
|
unlink(sa.sun_path);
|
||||||
|
|
||||||
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||||
fatal("socket failed");
|
return (-1);
|
||||||
|
|
||||||
mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
|
mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
|
||||||
if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
|
if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
|
||||||
fatal("bind failed");
|
return (-1);
|
||||||
umask(mask);
|
umask(mask);
|
||||||
|
|
||||||
if (listen(fd, 16) == -1)
|
if (listen(fd, 16) == -1)
|
||||||
fatal("listen failed");
|
return (-1);
|
||||||
setblocking(fd, 0);
|
setblocking(fd, 0);
|
||||||
|
|
||||||
server_update_socket();
|
|
||||||
|
|
||||||
return (fd);
|
return (fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +154,9 @@ server_start(int lockfd, char *lockfile)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
server_fd = server_create_socket();
|
server_fd = server_create_socket();
|
||||||
|
if (server_fd == -1)
|
||||||
|
fatal("couldn't create socket");
|
||||||
|
server_update_socket();
|
||||||
server_client_create(pair[1]);
|
server_client_create(pair[1]);
|
||||||
|
|
||||||
unlink(lockfile);
|
unlink(lockfile);
|
||||||
@ -388,6 +389,7 @@ server_add_accept(int timeout)
|
|||||||
void
|
void
|
||||||
server_signal_callback(int sig, unused short events, unused void *data)
|
server_signal_callback(int sig, unused short events, unused void *data)
|
||||||
{
|
{
|
||||||
|
int fd;
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
server_shutdown = 1;
|
server_shutdown = 1;
|
||||||
@ -398,8 +400,12 @@ server_signal_callback(int sig, unused short events, unused void *data)
|
|||||||
break;
|
break;
|
||||||
case SIGUSR1:
|
case SIGUSR1:
|
||||||
event_del(&server_ev_accept);
|
event_del(&server_ev_accept);
|
||||||
close(server_fd);
|
fd = server_create_socket();
|
||||||
server_fd = server_create_socket();
|
if (fd != -1) {
|
||||||
|
close(server_fd);
|
||||||
|
server_fd = fd;
|
||||||
|
server_update_socket();
|
||||||
|
}
|
||||||
server_add_accept(0);
|
server_add_accept(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
108
tmux.1
108
tmux.1
@ -163,7 +163,8 @@ If the socket is accidentally removed, the
|
|||||||
.Dv SIGUSR1
|
.Dv SIGUSR1
|
||||||
signal may be sent to the
|
signal may be sent to the
|
||||||
.Nm
|
.Nm
|
||||||
server process to recreate it.
|
server process to recreate it (note that this will fail if any parent
|
||||||
|
directories are missing).
|
||||||
.It Fl l
|
.It Fl l
|
||||||
Behave as a login shell.
|
Behave as a login shell.
|
||||||
This flag currently has no effect and is for compatibility with other shells
|
This flag currently has no effect and is for compatibility with other shells
|
||||||
@ -842,6 +843,7 @@ Suspend a client by sending
|
|||||||
.Op Fl lnpr
|
.Op Fl lnpr
|
||||||
.Op Fl c Ar target-client
|
.Op Fl c Ar target-client
|
||||||
.Op Fl t Ar target-session
|
.Op Fl t Ar target-session
|
||||||
|
.Op Fl T Ar key-table
|
||||||
.Xc
|
.Xc
|
||||||
.D1 (alias: Ic switchc )
|
.D1 (alias: Ic switchc )
|
||||||
Switch the current session for client
|
Switch the current session for client
|
||||||
@ -859,6 +861,22 @@ respectively.
|
|||||||
toggles whether a client is read-only (see the
|
toggles whether a client is read-only (see the
|
||||||
.Ic attach-session
|
.Ic attach-session
|
||||||
command).
|
command).
|
||||||
|
.Pp
|
||||||
|
.Fl T
|
||||||
|
sets the client's key table; the next key from the client will be interpreted from
|
||||||
|
.Ar key-table .
|
||||||
|
This may be used to configure multiple prefix keys, or to bind commands to
|
||||||
|
sequences of keys.
|
||||||
|
For example, to make typing
|
||||||
|
.Ql abc
|
||||||
|
run the
|
||||||
|
.Ic list-keys
|
||||||
|
command:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
bind-key -Ttable2 c list-keys
|
||||||
|
bind-key -Ttable1 b switch-client -Ttable2
|
||||||
|
bind-key -Troot a switch-client -Ttable1
|
||||||
|
.Ed
|
||||||
.El
|
.El
|
||||||
.Sh WINDOWS AND PANES
|
.Sh WINDOWS AND PANES
|
||||||
A
|
A
|
||||||
@ -1935,6 +1953,7 @@ Commands related to key bindings are as follows:
|
|||||||
.It Xo Ic bind-key
|
.It Xo Ic bind-key
|
||||||
.Op Fl cnr
|
.Op Fl cnr
|
||||||
.Op Fl t Ar mode-table
|
.Op Fl t Ar mode-table
|
||||||
|
.Op Fl T Ar key-table
|
||||||
.Ar key Ar command Op Ar arguments
|
.Ar key Ar command Op Ar arguments
|
||||||
.Xc
|
.Xc
|
||||||
.D1 (alias: Ic bind )
|
.D1 (alias: Ic bind )
|
||||||
@ -1942,16 +1961,40 @@ Bind key
|
|||||||
.Ar key
|
.Ar key
|
||||||
to
|
to
|
||||||
.Ar command .
|
.Ar command .
|
||||||
By default (without
|
Keys are bound in a key table.
|
||||||
.Fl t )
|
By default (without -T), the key is bound in
|
||||||
the primary key bindings are modified (those normally activated with the prefix
|
the
|
||||||
key); in this case, if
|
.Em prefix
|
||||||
.Fl n
|
key table.
|
||||||
is specified, it is not necessary to use the prefix key,
|
This table is used for keys pressed after the prefix key (for example,
|
||||||
.Ar command
|
by default
|
||||||
|
.Ql c
|
||||||
is bound to
|
is bound to
|
||||||
.Ar key
|
.Ic new-window
|
||||||
alone.
|
in the
|
||||||
|
.Em prefix
|
||||||
|
table, so
|
||||||
|
.Ql C-b c
|
||||||
|
creates a new window).
|
||||||
|
The
|
||||||
|
.Em root
|
||||||
|
table is used for keys pressed without the prefix key: binding
|
||||||
|
.Ql c
|
||||||
|
to
|
||||||
|
.Ic new-window
|
||||||
|
in the
|
||||||
|
.Em root
|
||||||
|
table (not recommended) means a plain
|
||||||
|
.Ql c
|
||||||
|
will create a new window.
|
||||||
|
.Fl n
|
||||||
|
is an alias
|
||||||
|
for
|
||||||
|
.Fl T Ar root .
|
||||||
|
Keys may also be bound in custom key tables and the
|
||||||
|
.Ic switch-client
|
||||||
|
.Fl T
|
||||||
|
command used to switch to them from a key binding.
|
||||||
The
|
The
|
||||||
.Fl r
|
.Fl r
|
||||||
flag indicates this key may repeat, see the
|
flag indicates this key may repeat, see the
|
||||||
@ -1967,21 +2010,33 @@ is bound in
|
|||||||
the binding for command mode with
|
the binding for command mode with
|
||||||
.Fl c
|
.Fl c
|
||||||
or for normal mode without.
|
or for normal mode without.
|
||||||
|
See the
|
||||||
|
.Sx WINDOWS AND PANES
|
||||||
|
section and the
|
||||||
|
.Ic list-keys
|
||||||
|
command for information on mode key bindings.
|
||||||
|
.Pp
|
||||||
To view the default bindings and possible commands, see the
|
To view the default bindings and possible commands, see the
|
||||||
.Ic list-keys
|
.Ic list-keys
|
||||||
command.
|
command.
|
||||||
.It Ic list-keys Op Fl t Ar key-table
|
.It Xo Ic list-keys
|
||||||
|
.Op Fl t Ar mode-table
|
||||||
|
.Op Fl T Ar key-table
|
||||||
|
.Xc
|
||||||
.D1 (alias: Ic lsk )
|
.D1 (alias: Ic lsk )
|
||||||
List all key bindings.
|
List all key bindings.
|
||||||
Without
|
Without
|
||||||
.Fl t
|
.Fl T
|
||||||
the primary key bindings - those executed when preceded by the prefix key -
|
all key tables are printed.
|
||||||
are printed.
|
With
|
||||||
|
.Fl T
|
||||||
|
only
|
||||||
|
.Ar key-table .
|
||||||
.Pp
|
.Pp
|
||||||
With
|
With
|
||||||
.Fl t ,
|
.Fl t ,
|
||||||
the key bindings in
|
the key bindings in
|
||||||
.Ar key-table
|
.Ar mode-table
|
||||||
are listed; this may be one of:
|
are listed; this may be one of:
|
||||||
.Em vi-edit ,
|
.Em vi-edit ,
|
||||||
.Em emacs-edit ,
|
.Em emacs-edit ,
|
||||||
@ -2026,31 +2081,22 @@ the secondary prefix key, to a window as if it was pressed.
|
|||||||
.It Xo Ic unbind-key
|
.It Xo Ic unbind-key
|
||||||
.Op Fl acn
|
.Op Fl acn
|
||||||
.Op Fl t Ar mode-table
|
.Op Fl t Ar mode-table
|
||||||
|
.Op Fl T Ar key-table
|
||||||
.Ar key
|
.Ar key
|
||||||
.Xc
|
.Xc
|
||||||
.D1 (alias: Ic unbind )
|
.D1 (alias: Ic unbind )
|
||||||
Unbind the command bound to
|
Unbind the command bound to
|
||||||
.Ar key .
|
.Ar key .
|
||||||
Without
|
.Fl c ,
|
||||||
|
.Fl n ,
|
||||||
|
.Fl T
|
||||||
|
and
|
||||||
.Fl t
|
.Fl t
|
||||||
the primary key bindings are modified; in this case, if
|
are the same as for
|
||||||
.Fl n
|
.Ic bind-key .
|
||||||
is specified, the command bound to
|
|
||||||
.Ar key
|
|
||||||
without a prefix (if any) is removed.
|
|
||||||
If
|
If
|
||||||
.Fl a
|
.Fl a
|
||||||
is present, all key bindings are removed.
|
is present, all key bindings are removed.
|
||||||
.Pp
|
|
||||||
If
|
|
||||||
.Fl t
|
|
||||||
is present,
|
|
||||||
.Ar key
|
|
||||||
in
|
|
||||||
.Ar mode-table
|
|
||||||
is unbound: the binding for command mode with
|
|
||||||
.Fl c
|
|
||||||
or for normal mode without.
|
|
||||||
.El
|
.El
|
||||||
.Sh OPTIONS
|
.Sh OPTIONS
|
||||||
The appearance and behaviour of
|
The appearance and behaviour of
|
||||||
|
41
tmux.h
41
tmux.h
@ -87,10 +87,9 @@ extern char **environ;
|
|||||||
#define KEYC_ESCAPE 0x2000
|
#define KEYC_ESCAPE 0x2000
|
||||||
#define KEYC_CTRL 0x4000
|
#define KEYC_CTRL 0x4000
|
||||||
#define KEYC_SHIFT 0x8000
|
#define KEYC_SHIFT 0x8000
|
||||||
#define KEYC_PREFIX 0x10000
|
|
||||||
|
|
||||||
/* Mask to obtain key w/o modifiers. */
|
/* Mask to obtain key w/o modifiers. */
|
||||||
#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX)
|
#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT)
|
||||||
#define KEYC_MASK_KEY (~KEYC_MASK_MOD)
|
#define KEYC_MASK_KEY (~KEYC_MASK_MOD)
|
||||||
|
|
||||||
/* Is this a mouse key? */
|
/* Is this a mouse key? */
|
||||||
@ -1299,7 +1298,7 @@ struct client {
|
|||||||
struct screen status;
|
struct screen status;
|
||||||
|
|
||||||
#define CLIENT_TERMINAL 0x1
|
#define CLIENT_TERMINAL 0x1
|
||||||
#define CLIENT_PREFIX 0x2
|
/* 0x2 unused */
|
||||||
#define CLIENT_EXIT 0x4
|
#define CLIENT_EXIT 0x4
|
||||||
#define CLIENT_REDRAW 0x8
|
#define CLIENT_REDRAW 0x8
|
||||||
#define CLIENT_STATUS 0x10
|
#define CLIENT_STATUS 0x10
|
||||||
@ -1318,6 +1317,7 @@ struct client {
|
|||||||
#define CLIENT_256COLOURS 0x20000
|
#define CLIENT_256COLOURS 0x20000
|
||||||
#define CLIENT_IDENTIFIED 0x40000
|
#define CLIENT_IDENTIFIED 0x40000
|
||||||
int flags;
|
int flags;
|
||||||
|
struct key_table *keytable;
|
||||||
|
|
||||||
struct event identify_timer;
|
struct event identify_timer;
|
||||||
|
|
||||||
@ -1438,15 +1438,24 @@ struct cmd_entry {
|
|||||||
enum cmd_retval (*exec)(struct cmd *, struct cmd_q *);
|
enum cmd_retval (*exec)(struct cmd *, struct cmd_q *);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Key binding. */
|
/* Key binding and key table. */
|
||||||
struct key_binding {
|
struct key_binding {
|
||||||
int key;
|
int key;
|
||||||
struct cmd_list *cmdlist;
|
struct cmd_list *cmdlist;
|
||||||
int can_repeat;
|
int can_repeat;
|
||||||
|
|
||||||
RB_ENTRY(key_binding) entry;
|
RB_ENTRY(key_binding) entry;
|
||||||
};
|
};
|
||||||
RB_HEAD(key_bindings, key_binding);
|
RB_HEAD(key_bindings, key_binding);
|
||||||
|
struct key_table {
|
||||||
|
const char *name;
|
||||||
|
struct key_bindings key_bindings;
|
||||||
|
|
||||||
|
u_int references;
|
||||||
|
|
||||||
|
RB_ENTRY(key_table) entry;
|
||||||
|
};
|
||||||
|
RB_HEAD(key_tables, key_table);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Option table entries. The option table is the user-visible part of the
|
* Option table entries. The option table is the user-visible part of the
|
||||||
@ -1874,12 +1883,16 @@ void cmd_wait_for_flush(void);
|
|||||||
int client_main(int, char **, int);
|
int client_main(int, char **, int);
|
||||||
|
|
||||||
/* key-bindings.c */
|
/* key-bindings.c */
|
||||||
extern struct key_bindings key_bindings;
|
|
||||||
int key_bindings_cmp(struct key_binding *, struct key_binding *);
|
|
||||||
RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp);
|
RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||||
struct key_binding *key_bindings_lookup(int);
|
RB_PROTOTYPE(key_tables, key_table, entry, key_table_cmp);
|
||||||
void key_bindings_add(int, int, struct cmd_list *);
|
extern struct key_tables key_tables;
|
||||||
void key_bindings_remove(int);
|
int key_table_cmp(struct key_table *, struct key_table *);
|
||||||
|
int key_bindings_cmp(struct key_binding *, struct key_binding *);
|
||||||
|
struct key_table *key_bindings_get_table(const char *, int);
|
||||||
|
void key_bindings_unref_table(struct key_table *);
|
||||||
|
void key_bindings_add(const char *, int, int, struct cmd_list *);
|
||||||
|
void key_bindings_remove(const char *, int);
|
||||||
|
void key_bindings_remove_table(const char *);
|
||||||
void key_bindings_init(void);
|
void key_bindings_init(void);
|
||||||
void key_bindings_dispatch(struct key_binding *, struct client *,
|
void key_bindings_dispatch(struct key_binding *, struct client *,
|
||||||
struct mouse_event *);
|
struct mouse_event *);
|
||||||
@ -2210,7 +2223,7 @@ struct layout_cell *layout_split_pane(
|
|||||||
void layout_close_pane(struct window_pane *);
|
void layout_close_pane(struct window_pane *);
|
||||||
|
|
||||||
/* layout-custom.c */
|
/* layout-custom.c */
|
||||||
char *layout_dump(struct window *);
|
char *layout_dump(struct layout_cell *);
|
||||||
int layout_parse(struct window *, const char *);
|
int layout_parse(struct window *, const char *);
|
||||||
|
|
||||||
/* layout-set.c */
|
/* layout-set.c */
|
||||||
|
4
utf8.c
4
utf8.c
@ -291,9 +291,9 @@ utf8_build(void)
|
|||||||
while (*ptr != NULL) {
|
while (*ptr != NULL) {
|
||||||
node = *ptr;
|
node = *ptr;
|
||||||
if (item->last < node->first)
|
if (item->last < node->first)
|
||||||
ptr = &(node->left);
|
ptr = &node->left;
|
||||||
else if (item->first > node->last)
|
else if (item->first > node->last)
|
||||||
ptr = &(node->right);
|
ptr = &node->right;
|
||||||
}
|
}
|
||||||
*ptr = item;
|
*ptr = item;
|
||||||
}
|
}
|
||||||
|
@ -2216,14 +2216,12 @@ window_copy_rectangle_toggle(struct window_pane *wp)
|
|||||||
void
|
void
|
||||||
window_copy_start_drag(struct client *c, unused struct mouse_event *m)
|
window_copy_start_drag(struct client *c, unused struct mouse_event *m)
|
||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct window_copy_mode_data *data;
|
u_int x, y;
|
||||||
u_int x, y;
|
|
||||||
|
|
||||||
wp = cmd_mouse_pane(m, NULL, NULL);
|
wp = cmd_mouse_pane(m, NULL, NULL);
|
||||||
if (wp->mode != &window_copy_mode)
|
if (wp == NULL || wp->mode != &window_copy_mode)
|
||||||
return;
|
return;
|
||||||
data = wp->modedata;
|
|
||||||
|
|
||||||
if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
|
if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
|
||||||
return;
|
return;
|
||||||
@ -2244,7 +2242,7 @@ window_copy_drag_update(unused struct client *c, struct mouse_event *m)
|
|||||||
u_int x, y, old_cy;
|
u_int x, y, old_cy;
|
||||||
|
|
||||||
wp = cmd_mouse_pane(m, NULL, NULL);
|
wp = cmd_mouse_pane(m, NULL, NULL);
|
||||||
if (wp->mode != &window_copy_mode)
|
if (wp == NULL || wp->mode != &window_copy_mode)
|
||||||
return;
|
return;
|
||||||
data = wp->modedata;
|
data = wp->modedata;
|
||||||
|
|
||||||
@ -2260,13 +2258,11 @@ window_copy_drag_update(unused struct client *c, struct mouse_event *m)
|
|||||||
void
|
void
|
||||||
window_copy_drag_release(unused struct client *c, struct mouse_event *m)
|
window_copy_drag_release(unused struct client *c, struct mouse_event *m)
|
||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct window_copy_mode_data *data;
|
|
||||||
|
|
||||||
wp = cmd_mouse_pane(m, NULL, NULL);
|
wp = cmd_mouse_pane(m, NULL, NULL);
|
||||||
if (wp->mode != &window_copy_mode)
|
if (wp == NULL || wp->mode != &window_copy_mode)
|
||||||
return;
|
return;
|
||||||
data = wp->modedata;
|
|
||||||
|
|
||||||
window_copy_copy_selection(wp, NULL);
|
window_copy_copy_selection(wp, NULL);
|
||||||
window_pane_reset_mode(wp);
|
window_pane_reset_mode(wp);
|
||||||
|
1
window.c
1
window.c
@ -518,6 +518,7 @@ window_unzoom(struct window *w)
|
|||||||
w->flags &= ~WINDOW_ZOOMED;
|
w->flags &= ~WINDOW_ZOOMED;
|
||||||
layout_free(w);
|
layout_free(w);
|
||||||
w->layout_root = w->saved_layout_root;
|
w->layout_root = w->saved_layout_root;
|
||||||
|
w->saved_layout_root = NULL;
|
||||||
|
|
||||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||||
wp->layout_cell = wp->saved_layout_cell;
|
wp->layout_cell = wp->saved_layout_cell;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user