1
0
mirror of https://github.com/tmux/tmux.git synced 2025-03-24 06:48:48 +00:00

Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam 2016-10-16 20:01:10 +01:00
commit c67b702588
29 changed files with 817 additions and 702 deletions

70
cfg.c
View File

@ -28,14 +28,25 @@
#include "tmux.h" #include "tmux.h"
char *cfg_file; char *cfg_file;
static struct cmd_q *cfg_cmd_q;
int cfg_finished; int cfg_finished;
int cfg_references;
static char **cfg_causes; static char **cfg_causes;
static u_int cfg_ncauses; static u_int cfg_ncauses;
struct client *cfg_client; struct client *cfg_client;
static void cfg_default_done(struct cmd_q *); static enum cmd_retval
cfg_done(__unused struct cmd_q *cmdq, __unused void *data)
{
if (cfg_finished)
return (CMD_RETURN_NORMAL);
cfg_finished = 1;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_client != NULL)
server_client_unref(cfg_client);
return (CMD_RETURN_NORMAL);
}
void void
set_cfg_file(const char *path) set_cfg_file(const char *path)
@ -50,30 +61,24 @@ start_cfg(void)
const char *home; const char *home;
int quiet = 0; int quiet = 0;
cfg_cmd_q = cmdq_new(NULL);
cfg_cmd_q->emptyfn = cfg_default_done;
cfg_finished = 0;
cfg_references = 1;
cfg_client = TAILQ_FIRST(&clients); cfg_client = TAILQ_FIRST(&clients);
if (cfg_client != NULL) if (cfg_client != NULL)
cfg_client->references++; cfg_client->references++;
load_cfg(TMUX_CONF, cfg_cmd_q, 1); load_cfg(TMUX_CONF, cfg_client, NULL, 1);
if (cfg_file == NULL && (home = find_home()) != NULL) { if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home); xasprintf(&cfg_file, "%s/.tmux.conf", home);
quiet = 1; quiet = 1;
} }
if (cfg_file != NULL) if (cfg_file != NULL)
load_cfg(cfg_file, cfg_cmd_q, quiet); load_cfg(cfg_file, cfg_client, NULL, quiet);
cmdq_continue(cfg_cmd_q); cmdq_append(cfg_client, cmdq_get_callback(cfg_done, NULL));
} }
int int
load_cfg(const char *path, struct cmd_q *cmdq, int quiet) load_cfg(const char *path, struct client *c, struct cmd_q *cmdq, int quiet)
{ {
FILE *f; FILE *f;
char delim[3] = { '\\', '\\', '\0' }; char delim[3] = { '\\', '\\', '\0' };
@ -81,6 +86,7 @@ load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
size_t line = 0; size_t line = 0;
char *buf, *cause1, *p; char *buf, *cause1, *p;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
log_debug("loading %s", path); log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) { if ((f = fopen(path, "rb")) == NULL) {
@ -116,8 +122,13 @@ load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
if (cmdlist == NULL) if (cmdlist == NULL)
continue; continue;
cmdq_append(cmdq, cmdlist, NULL); new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
if (cmdq != NULL)
cmdq_insert_after(cmdq, new_cmdq);
else
cmdq_append(c, new_cmdq);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
found++; found++;
} }
fclose(f); fclose(f);
@ -125,37 +136,6 @@ load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
return (found); return (found);
} }
static void
cfg_default_done(__unused struct cmd_q *cmdq)
{
log_debug("%s: %u references%s", __func__, cfg_references,
cfg_finished ? " (finished)" : "");
if (cfg_finished || --cfg_references != 0)
return;
cfg_finished = 1;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
cmdq_free(cfg_cmd_q);
cfg_cmd_q = NULL;
if (cfg_client != NULL) {
/*
* The client command queue starts with client_exit set to 1 so
* only continue if not empty (that is, we have been delayed
* during configuration parsing for long enough that the
* MSG_COMMAND has arrived), else the client will exit before
* the MSG_COMMAND which might tell it not to.
*/
if (!TAILQ_EMPTY(&cfg_client->cmdq->queue))
cmdq_continue(cfg_client->cmdq);
server_client_unref(cfg_client);
cfg_client = NULL;
}
}
void void
cfg_add_cause(const char *fmt, ...) cfg_add_cause(const char *fmt, ...)
{ {

View File

@ -145,7 +145,7 @@ cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag,
if (~c->flags & CLIENT_CONTROL) if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0); proc_send(c->peer, MSG_READY, -1, NULL, 0);
hooks_run(c->session->hooks, c, NULL, "client-attached"); hooks_run(c->session->hooks, c, NULL, "client-attached");
cmdq->client_exit = 0; c->flags |= CLIENT_ATTACHED;
} }
recalculate_sizes(); recalculate_sizes();
alerts_check_session(s); alerts_check_session(s);

View File

@ -121,12 +121,24 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
static enum cmd_retval
cmd_command_prompt_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static int static int
cmd_command_prompt_callback(void *data, const char *s) cmd_command_prompt_callback(void *data, const char *s)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
struct client *c = cdata->c; struct client *c = cdata->c;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
char *cause, *new_template, *prompt, *ptr; char *cause, *new_template, *prompt, *ptr;
char *input = NULL; char *input = NULL;
@ -153,17 +165,19 @@ cmd_command_prompt_callback(void *data, const char *s)
if (cmd_string_parse(new_template, &cmdlist, NULL, 0, &cause) != 0) { if (cmd_string_parse(new_template, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) { if (cause != NULL) {
*cause = toupper((u_char) *cause); new_cmdq = cmdq_get_callback(cmd_command_prompt_error,
status_message_set(c, "%s", cause); cause);
free(cause); } else
} new_cmdq = NULL;
return (0); } else {
new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
} }
cmdq_run(c->cmdq, cmdlist, NULL); if (new_cmdq != NULL)
cmd_list_free(cmdlist); cmdq_append(c, new_cmdq);
if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback) if (c->prompt_callbackfn != (void *)&cmd_command_prompt_callback)
return (1); return (1);
return (0); return (0);
} }

View File

@ -83,12 +83,24 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
static enum cmd_retval
cmd_confirm_before_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static int static int
cmd_confirm_before_callback(void *data, const char *s) cmd_confirm_before_callback(void *data, const char *s)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client; struct client *c = cdata->client;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
char *cause; char *cause;
if (c->flags & CLIENT_DEAD) if (c->flags & CLIENT_DEAD)
@ -101,14 +113,17 @@ cmd_confirm_before_callback(void *data, const char *s)
if (cmd_string_parse(cdata->cmd, &cmdlist, NULL, 0, &cause) != 0) { if (cmd_string_parse(cdata->cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) { if (cause != NULL) {
cmdq_error(c->cmdq, "%s", cause); new_cmdq = cmdq_get_callback(cmd_confirm_before_error,
free(cause); cause);
} } else
return (0); new_cmdq = NULL;
} else {
new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
} }
cmdq_run(c->cmdq, cmdlist, NULL); if (new_cmdq != NULL)
cmd_list_free(cmdlist); cmdq_append(c, new_cmdq);
return (0); return (0);
} }

View File

@ -61,7 +61,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp = cmdq->state.tflag.wp; struct window_pane *wp = cmdq->state.tflag.wp;
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&cmdq->item->mouse, &s, NULL)) == NULL) if ((wp = cmd_mouse_pane(&cmdq->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@ -80,7 +80,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if (wp->mode != NULL && wp->mode != &window_copy_mode) if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &cmdq->item->mouse); window_copy_start_drag(c, &cmdq->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, 0); window_copy_pageup(wp, 0);

View File

@ -65,32 +65,48 @@ cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
static enum cmd_retval
cmd_display_panes_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void static void
cmd_display_panes_callback(struct client *c, struct window_pane *wp) cmd_display_panes_callback(struct client *c, struct window_pane *wp)
{ {
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
char *template, *cmd, *expanded, *cause; char *template, *cmd, *expanded, *cause;
template = c->identify_callback_data; template = c->identify_callback_data;
if (wp != NULL) { if (wp == NULL)
xasprintf(&expanded, "%%%u", wp->id); goto out;
cmd = cmd_template_replace(template, expanded, 1); xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) { if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) { if (cause != NULL) {
*cause = toupper((u_char) *cause); new_cmdq = cmdq_get_callback(cmd_display_panes_error,
status_message_set(c, "%s", cause); cause);
free(cause); } else
} new_cmdq = NULL;
} else { } else {
cmdq_run(c->cmdq, cmdlist, NULL); new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
}
free(cmd);
free(expanded);
} }
if (new_cmdq != NULL)
cmdq_append(c, new_cmdq);
free(cmd);
free(expanded);
out:
free(c->identify_callback_data); free(c->identify_callback_data);
c->identify_callback_data = NULL; c->identify_callback_data = NULL;
c->identify_callback = NULL; c->identify_callback = NULL;

View File

@ -1005,7 +1005,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* Mouse target is a plain = or {mouse}. */ /* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) { if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &cmdq->item->mouse; m = &cmdq->mouse;
switch (type) { switch (type) {
case CMD_FIND_PANE: case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl); fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);

View File

@ -31,9 +31,9 @@
static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *);
static void cmd_if_shell_callback(struct job *); static enum cmd_retval cmd_if_shell_error(struct cmd_q *, void *);
static void cmd_if_shell_done(struct cmd_q *); static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_free(void *); static void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = { const struct cmd_entry cmd_if_shell_entry = {
.name = "if-shell", .name = "if-shell",
@ -56,11 +56,9 @@ struct cmd_if_shell_data {
char *cmd_if; char *cmd_if;
char *cmd_else; char *cmd_else;
struct client *client;
struct cmd_q *cmdq; struct cmd_q *cmdq;
struct mouse_event mouse; struct mouse_event mouse;
int bflag;
int references;
}; };
static enum cmd_retval static enum cmd_retval
@ -70,6 +68,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
struct cmd_if_shell_data *cdata; struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause; char *shellcmd, *cmd, *cause;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
struct session *s = cmdq->state.tflag.s; struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl; struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *wp = cmdq->state.tflag.wp; struct window_pane *wp = cmdq->state.tflag.wp;
@ -104,7 +103,8 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
} }
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
cmdq_run(cmdq, cmdlist, &cmdq->item->mouse); new_cmdq = cmdq_get_command(cmdlist, NULL, &cmdq->mouse, 0);
cmdq_insert_after(cmdq, new_cmdq);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@ -121,92 +121,80 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
else else
cdata->cmd_else = NULL; cdata->cmd_else = NULL;
cdata->bflag = args_has(args, 'b'); cdata->client = cmdq->client;
cdata->client->references++;
cdata->cmdq = cmdq; if (!args_has(args, 'b'))
memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse); cdata->cmdq = cmdq;
cmdq->references++; else
cdata->cmdq = NULL;
memcpy(&cdata->mouse, &cmdq->mouse, sizeof cdata->mouse);
cdata->references = 1;
job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free, job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
cdata); cdata);
free(shellcmd); free(shellcmd);
if (cdata->bflag) if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
static enum cmd_retval
cmd_if_shell_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void static void
cmd_if_shell_callback(struct job *job) cmd_if_shell_callback(struct job *job)
{ {
struct cmd_if_shell_data *cdata = job->data; struct cmd_if_shell_data *cdata = job->data;
struct cmd_q *cmdq = cdata->cmdq, *cmdq1; struct client *c = cdata->client;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
char *cause, *cmd; struct cmd_q *new_cmdq;
char *cause, *cmd, *file = cdata->file;
if (cmdq->flags & CMD_Q_DEAD) u_int line = cdata->line;
return;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
cmd = cdata->cmd_else; cmd = cdata->cmd_else;
else else
cmd = cdata->cmd_if; cmd = cdata->cmd_if;
if (cmd == NULL) if (cmd == NULL)
return; goto out;
if (cmd_string_parse(cmd, &cmdlist, cdata->file, cdata->line, if (cmd_string_parse(cmd, &cmdlist, file, line, &cause) != 0) {
&cause) != 0) { if (cause != NULL)
if (cause != NULL) { new_cmdq = cmdq_get_callback(cmd_if_shell_error, cause);
cmdq_error(cmdq, "%s", cause); else
free(cause); new_cmdq = NULL;
} } else {
return; new_cmdq = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
cmd_list_free(cmdlist);
} }
cmdq1 = cmdq_new(cmdq->client); if (new_cmdq != NULL) {
cmdq1->emptyfn = cmd_if_shell_done; if (cdata->cmdq == NULL)
cmdq1->data = cdata; cmdq_append(c, new_cmdq);
else
cmdq_insert_after(cdata->cmdq, new_cmdq);
}
cdata->references++; out:
cmdq_run(cmdq1, cmdlist, &cdata->mouse); if (cdata->cmdq != NULL)
cmd_list_free(cmdlist); cdata->cmdq->flags &= ~CMD_Q_WAITING;
}
static void
cmd_if_shell_done(struct cmd_q *cmdq1)
{
struct cmd_if_shell_data *cdata = cmdq1->data;
struct cmd_q *cmdq = cdata->cmdq;
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
if (--cdata->references != 0)
return;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata->file);
free(cdata);
} }
static void static void
cmd_if_shell_free(void *data) 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;
if (--cdata->references != 0) server_client_unref(cdata->client);
return;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd_else); free(cdata->cmd_else);
free(cdata->cmd_if); free(cdata->cmd_if);

View File

@ -46,17 +46,24 @@ const struct cmd_entry cmd_load_buffer_entry = {
.exec = cmd_load_buffer_exec .exec = cmd_load_buffer_exec
}; };
struct cmd_load_buffer_data {
struct cmd_q *cmdq;
char *bufname;
};
static enum cmd_retval static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct client *c = cmdq->client; struct cmd_load_buffer_data *cdata;
struct session *s; struct client *c = cmdq->client;
FILE *f; struct session *s;
const char *path, *bufname, *cwd; FILE *f;
char *pdata, *new_pdata, *cause, *file, resolved[PATH_MAX]; const char *path, *bufname, *cwd;
size_t psize; char *pdata, *new_pdata, *cause, *file;
int ch, error; char resolved[PATH_MAX];
size_t psize;
int ch, error;
bufname = NULL; bufname = NULL;
if (args_has(args, 'b')) if (args_has(args, 'b'))
@ -64,8 +71,12 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
path = args->argv[0]; path = args->argv[0];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
cdata = xcalloc(1, sizeof *cdata);
cdata->cmdq = cmdq;
cdata->bufname = xstrdup(bufname);
error = server_set_stdin_callback(c, cmd_load_buffer_callback, error = server_set_stdin_callback(c, cmd_load_buffer_callback,
(void *)bufname, &cause); cdata, &cause);
if (error != 0) { if (error != 0) {
cmdq_error(cmdq, "%s: %s", path, cause); cmdq_error(cmdq, "%s: %s", path, cause);
free(cause); free(cause);
@ -136,9 +147,9 @@ error:
static void static void
cmd_load_buffer_callback(struct client *c, int closed, void *data) cmd_load_buffer_callback(struct client *c, int closed, void *data)
{ {
const char *bufname = data; struct cmd_load_buffer_data *cdata = data;
char *pdata, *cause, *saved; char *pdata, *cause, *saved;
size_t psize; size_t psize;
if (!closed) if (!closed)
return; return;
@ -146,7 +157,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
server_client_unref(c); server_client_unref(c);
if (c->flags & CLIENT_DEAD) if (c->flags & CLIENT_DEAD)
return; goto out;
psize = EVBUFFER_LENGTH(c->stdin_data); psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
@ -156,7 +167,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
pdata[psize] = '\0'; pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize); evbuffer_drain(c->stdin_data, psize);
if (paste_set(pdata, psize, bufname, &cause) != 0) { if (paste_set(pdata, psize, cdata->bufname, &cause) != 0) {
/* No context so can't use server_client_msg_error. */ /* No context so can't use server_client_msg_error. */
if (~c->flags & CLIENT_UTF8) { if (~c->flags & CLIENT_UTF8) {
saved = cause; saved = cause;
@ -168,7 +179,9 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
free(pdata); free(pdata);
free(cause); free(cause);
} }
out: out:
cmdq_continue(c->cmdq); cdata->cmdq->flags &= ~CMD_Q_WAITING;
free(cdata->bufname);
free(cdata);
} }

View File

@ -312,14 +312,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
} }
if (!detached) if (!detached)
cmdq->client_exit = 0; c->flags |= CLIENT_ATTACHED;
if (to_free != NULL) if (to_free != NULL)
free((void *)to_free); free((void *)to_free);
cmd_find_from_session(&fs, s); cmd_find_from_session(&fs, s);
if (hooks_wait(s->hooks, cmdq, &fs, "after-new-session") == 0) hooks_insert(s->hooks, cmdq, &fs, "after-new-session");
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: error:

View File

@ -157,8 +157,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
free((void *)to_free); free((void *)to_free);
cmd_find_from_winlink(&fs, s, wl); cmd_find_from_winlink(&fs, s, wl);
if (hooks_wait(s->hooks, cmdq, &fs, "after-new-window") == 0) hooks_insert(s->hooks, cmdq, &fs, "after-new-window");
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: error:

View File

@ -25,47 +25,316 @@
#include "tmux.h" #include "tmux.h"
static enum cmd_retval cmdq_continue_one(struct cmd_q *); /* Global command queue. */
static void cmdq_flush(struct cmd_q *); static struct cmd_q_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
/* Create new command queue. */ /* Get command queue name. */
static const char *
cmdq_name(struct client *c)
{
static char s[32];
if (c == NULL)
return ("<global>");
xsnprintf(s, sizeof s, "<%p>", c);
return (s);
}
/* Get command queue from client. */
static struct cmd_q_list *
cmdq_get(struct client *c)
{
if (c == NULL)
return (&global_queue);
return (&c->queue);
}
/* Append an item. */
void
cmdq_append(struct client *c, struct cmd_q *cmdq)
{
struct cmd_q_list *queue = cmdq_get(c);
struct cmd_q *next;
do {
next = cmdq->next;
cmdq->next = NULL;
if (c != NULL)
c->references++;
cmdq->client = c;
cmdq->queue = queue;
TAILQ_INSERT_TAIL(queue, cmdq, entry);
cmdq = next;
} while (cmdq != NULL);
}
/* Insert an item. */
void
cmdq_insert_after(struct cmd_q *after, struct cmd_q *cmdq)
{
struct client *c = after->client;
struct cmd_q_list *queue = after->queue;
struct cmd_q *next;
do {
next = cmdq->next;
cmdq->next = NULL;
if (c != NULL)
c->references++;
cmdq->client = c;
cmdq->queue = queue;
if (after->next != NULL)
TAILQ_INSERT_AFTER(queue, after->next, cmdq, entry);
else
TAILQ_INSERT_AFTER(queue, after, cmdq, entry);
after->next = cmdq;
cmdq = next;
} while (cmdq != NULL);
}
/* Remove an item. */
static void
cmdq_remove(struct cmd_q *cmdq)
{
free((void *)cmdq->hook);
if (cmdq->client != NULL)
server_client_unref(cmdq->client);
if (cmdq->type == CMD_Q_COMMAND)
cmd_list_free(cmdq->cmdlist);
TAILQ_REMOVE(cmdq->queue, cmdq, entry);
free(cmdq);
}
/* Set command group. */
static u_int
cmdq_next_group(void)
{
static u_int group;
return (++group);
}
/* Remove all subsequent items that match this item's group. */
static void
cmdq_remove_group(struct cmd_q *cmdq)
{
struct cmd_q *this, *next;
this = TAILQ_NEXT(cmdq, entry);
while (this != NULL) {
next = TAILQ_NEXT(this, entry);
if (this->group == cmdq->group)
cmdq_remove(this);
this = next;
}
}
/* Get a command for the command queue. */
struct cmd_q * struct cmd_q *
cmdq_new(struct client *c) cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct mouse_event *m, int flags)
{
struct cmd_q *cmdq, *first = NULL, *last = NULL;
struct cmd *cmd;
u_int group = cmdq_next_group();
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
cmdq = xcalloc(1, sizeof *cmdq);
cmdq->type = CMD_Q_COMMAND;
cmdq->group = group;
cmdq->flags = flags;
cmdq->cmdlist = cmdlist;
cmdq->cmd = cmd;
if (current != NULL)
cmd_find_copy_state(&cmdq->current, current);
if (m != NULL)
memcpy(&cmdq->mouse, m, sizeof cmdq->mouse);
cmdlist->references++;
if (first == NULL)
first = cmdq;
if (last != NULL)
last->next = cmdq;
last = cmdq;
}
return (first);
}
/* Fire command on command queue. */
static enum cmd_retval
cmdq_fire_command(struct cmd_q *cmdq)
{
struct client *c = cmdq->client;
struct cmd *cmd = cmdq->cmd;
enum cmd_retval retval;
const char *name;
struct cmd_find_state *fsp, fs;
int flags;
flags = !!(cmd->flags & CMD_CONTROL);
cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq) != 0) {
retval = CMD_RETURN_ERROR;
goto out;
}
if (cmdq->client == NULL)
cmdq->client = cmd_find_client(cmdq, NULL, CMD_FIND_QUIET);
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
goto out;
if (cmd->entry->flags & CMD_AFTERHOOK) {
name = cmd->entry->name;
if (cmd_find_valid_state(&cmdq->state.tflag))
fsp = &cmdq->state.tflag;
else {
if (cmd_find_current(&fs, cmdq, CMD_FIND_QUIET) != 0)
goto out;
fsp = &fs;
}
hooks_insert(fsp->s->hooks, cmdq, fsp, "after-%s", name);
}
out:
cmdq->client = c;
if (retval == CMD_RETURN_ERROR)
cmdq_guard(cmdq, "error", flags);
else
cmdq_guard(cmdq, "end", flags);
return (retval);
}
/* Get a callback for the command queue. */
struct cmd_q *
cmdq_get_callback(cmd_q_cb cb, void *data)
{ {
struct cmd_q *cmdq; struct cmd_q *cmdq;
cmdq = xcalloc(1, sizeof *cmdq); cmdq = xcalloc(1, sizeof *cmdq);
cmdq->references = 1; cmdq->type = CMD_Q_CALLBACK;
cmdq->group = 0;
cmdq->flags = 0; cmdq->flags = 0;
cmdq->client = c; cmdq->cb = cb;
cmdq->client_exit = -1; cmdq->data = data;
TAILQ_INIT(&cmdq->queue);
cmdq->item = NULL;
cmdq->cmd = NULL;
cmd_find_clear_state(&cmdq->current, NULL, 0);
cmdq->parent = NULL;
return (cmdq); return (cmdq);
} }
/* Free command queue */ /* Fire callback on callback queue. */
int static enum cmd_retval
cmdq_free(struct cmd_q *cmdq) cmdq_fire_callback(struct cmd_q *cmdq)
{ {
log_debug("cmdq %p free: %u references", cmdq, cmdq->references); return (cmdq->cb(cmdq, cmdq->data));
}
if (--cmdq->references != 0) { /* Process next item on command queue. */
if (cmdq->flags & CMD_Q_DEAD) u_int
return (1); cmdq_next(struct client *c)
{
struct cmd_q_list *queue = cmdq_get(c);
const char *name = cmdq_name(c);
struct cmd_q *cmdq;
enum cmd_retval retval;
u_int items = 0;
static u_int number;
if (TAILQ_EMPTY(queue)) {
log_debug("%s %s: empty", __func__, name);
return (0);
}
if (TAILQ_FIRST(queue)->flags & CMD_Q_WAITING) {
log_debug("%s %s: waiting", __func__, name);
return (0); return (0);
} }
cmdq_flush(cmdq); log_debug("%s %s: enter", __func__, name);
free(cmdq); for (;;) {
return (1); cmdq = TAILQ_FIRST(queue);
if (cmdq == NULL)
break;
log_debug("%s %s: type %d, flags %x", __func__, name,
cmdq->type, cmdq->flags);
/*
* Any item with the waiting flag set waits until an external
* event clears the flag (for example, a job - look at
* run-shell).
*/
if (cmdq->flags & CMD_Q_WAITING)
goto waiting;
/*
* Items are only fired once, once the fired flag is set, a
* waiting flag can only be cleared by an external event.
*/
if (~cmdq->flags & CMD_Q_FIRED) {
cmdq->time = time(NULL);
cmdq->number = ++number;
switch (cmdq->type)
{
case CMD_Q_COMMAND:
retval = cmdq_fire_command(cmdq);
/*
* If a command returns an error, remove any
* subsequent commands in the same group.
*/
if (retval == CMD_RETURN_ERROR)
cmdq_remove_group(cmdq);
break;
case CMD_Q_CALLBACK:
retval = cmdq_fire_callback(cmdq);
break;
default:
retval = CMD_RETURN_ERROR;
break;
}
cmdq->flags |= CMD_Q_FIRED;
if (retval == CMD_RETURN_WAIT) {
cmdq->flags |= CMD_Q_WAITING;
goto waiting;
}
items++;
}
cmdq_remove(cmdq);
}
log_debug("%s %s: exit (empty)", __func__, name);
return (items);
waiting:
log_debug("%s %s: exit (wait)", __func__, name);
return (items);
}
/* Print a guard line. */
void
cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
{
struct client *c = cmdq->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long)cmdq->time, cmdq->number, flags);
server_client_push_stdout(c);
} }
/* Show message from command. */ /* Show message from command. */
@ -140,175 +409,3 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
free(msg); free(msg);
} }
/* Print a guard line. */
void
cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
{
struct client *c = cmdq->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long) cmdq->time, cmdq->number, flags);
server_client_push_stdout(c);
}
/* Add command list to queue and begin processing if needed. */
void
cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{
cmdq_append(cmdq, cmdlist, m);
if (cmdq->item == NULL) {
cmdq->cmd = NULL;
cmdq_continue(cmdq);
}
}
/* Add command list to queue. */
void
cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{
struct cmd_q_item *item;
item = xcalloc(1, sizeof *item);
item->cmdlist = cmdlist;
TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
cmdlist->references++;
if (m != NULL)
memcpy(&item->mouse, m, sizeof item->mouse);
else
item->mouse.valid = 0;
}
/* Process one command. */
static enum cmd_retval
cmdq_continue_one(struct cmd_q *cmdq)
{
struct cmd_list *cmdlist = cmdq->item->cmdlist;
struct cmd *cmd = cmdq->cmd;
enum cmd_retval retval;
char *tmp;
int flags = !!(cmd->flags & CMD_CONTROL);
const char *name;
struct cmd_find_state *fsp, fs;
cmdlist->references++;
tmp = cmd_print(cmd);
log_debug("cmdq %p: %s", cmdq, tmp);
free(tmp);
cmdq->time = time(NULL);
cmdq->number++;
cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error;
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
goto error;
if (~cmd->entry->flags & CMD_AFTERHOOK)
goto end;
if (cmd_find_valid_state(&cmdq->state.tflag))
fsp = &cmdq->state.tflag;
else {
if (cmd_find_current(&fs, cmdq, CMD_FIND_QUIET) != 0)
goto end;
fsp = &fs;
}
name = cmd->entry->name;
if (hooks_wait(fsp->s->hooks, cmdq, fsp, "after-%s", name) == 0)
retval = CMD_RETURN_WAIT;
end:
cmdq_guard(cmdq, "end", flags);
cmd_list_free(cmdlist);
return (retval);
error:
cmdq_guard(cmdq, "error", flags);
cmd_list_free(cmdlist);
return (CMD_RETURN_ERROR);
}
/* Continue processing command queue. Returns 1 if finishes empty. */
int
cmdq_continue(struct cmd_q *cmdq)
{
struct client *c = cmdq->client;
struct cmd_q_item *next;
enum cmd_retval retval;
int empty;
log_debug("continuing cmdq %p: flags %#x (%p)", cmdq, cmdq->flags, c);
cmdq->references++;
empty = TAILQ_EMPTY(&cmdq->queue);
if (empty)
goto empty;
if (cmdq->item == NULL) {
cmdq->item = TAILQ_FIRST(&cmdq->queue);
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} else
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
do {
while (cmdq->cmd != NULL) {
retval = cmdq_continue_one(cmdq);
if (retval == CMD_RETURN_ERROR)
break;
if (retval == CMD_RETURN_WAIT)
goto out;
if (retval == CMD_RETURN_STOP) {
cmdq_flush(cmdq);
goto empty;
}
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
next = TAILQ_NEXT(cmdq->item, qentry);
TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
cmd_list_free(cmdq->item->cmdlist);
free(cmdq->item);
cmdq->item = next;
if (cmdq->item != NULL)
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} while (cmdq->item != NULL);
empty:
log_debug("cmdq %p empty", cmdq);
if (cmdq->client_exit > 0)
cmdq->client->flags |= CLIENT_EXIT;
if (cmdq->emptyfn != NULL)
cmdq->emptyfn(cmdq);
empty = 1;
out:
cmdq_free(cmdq);
return (empty);
}
/* Flush command queue. */
static void
cmdq_flush(struct cmd_q *cmdq)
{
struct cmd_q_item *item, *item1;
TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {
TAILQ_REMOVE(&cmdq->queue, item, qentry);
cmd_list_free(item->cmdlist);
free(item);
}
cmdq->item = NULL;
}

View File

@ -60,12 +60,12 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
int x, y; int x, y;
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if (cmd_mouse_window(&cmdq->item->mouse, &s) == NULL) if (cmd_mouse_window(&cmdq->mouse, &s) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update; c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &cmdq->item->mouse); cmd_resize_pane_mouse_update(c, &cmdq->mouse);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -51,7 +51,6 @@ const struct cmd_entry cmd_run_shell_entry = {
struct cmd_run_shell_data { struct cmd_run_shell_data {
char *cmd; char *cmd;
struct cmd_q *cmdq; struct cmd_q *cmdq;
int bflag;
int wp_id; int wp_id;
}; };
@ -92,6 +91,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
cwd = s->cwd; cwd = s->cwd;
else else
cwd = NULL; cwd = NULL;
ft = format_create(cmdq, 0); ft = format_create(cmdq, 0);
format_defaults(ft, cmdq->state.c, s, wl, wp); format_defaults(ft, cmdq->state.c, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]); shellcmd = format_expand(ft, args->argv[0]);
@ -99,20 +99,24 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
cdata = xcalloc(1, sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
cdata->cmd = shellcmd; cdata->cmd = shellcmd;
cdata->bflag = args_has(args, 'b');
if (args_has(args, 't') && wp != NULL) if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id; cdata->wp_id = wp->id;
else else
cdata->wp_id = -1; cdata->wp_id = -1;
cdata->cmdq = cmdq; if (args_has(args, 't') && wp != NULL)
cmdq->references++; cdata->wp_id = wp->id;
else
cdata->wp_id = -1;
if (!args_has(args, 'b'))
cdata->cmdq = cmdq;
job_run(shellcmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free, job_run(shellcmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
cdata); cdata);
if (cdata->bflag) if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
@ -121,16 +125,11 @@ static void
cmd_run_shell_callback(struct job *job) cmd_run_shell_callback(struct job *job)
{ {
struct cmd_run_shell_data *cdata = job->data; struct cmd_run_shell_data *cdata = job->data;
struct cmd_q *cmdq = cdata->cmdq; char *cmd = cdata->cmd, *msg, *line;
char *cmd, *msg, *line;
size_t size; size_t size;
int retcode; int retcode;
u_int lines; u_int lines;
if (cmdq->flags & CMD_Q_DEAD)
return;
cmd = cdata->cmd;
lines = 0; lines = 0;
do { do {
if ((line = evbuffer_readline(job->event->input)) != NULL) { if ((line = evbuffer_readline(job->event->input)) != NULL) {
@ -163,16 +162,15 @@ cmd_run_shell_callback(struct job *job)
if (msg != NULL) if (msg != NULL)
cmd_run_shell_print(job, msg); cmd_run_shell_print(job, msg);
free(msg); free(msg);
if (cdata->cmdq != NULL)
cdata->cmdq->flags &= ~CMD_Q_WAITING;
} }
static void static void
cmd_run_shell_free(void *data) cmd_run_shell_free(void *data)
{ {
struct cmd_run_shell_data *cdata = data; struct cmd_run_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd); free(cdata->cmd);
free(cdata); free(cdata);

View File

@ -62,7 +62,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->state.c; struct client *c = cmdq->state.c;
struct window_pane *wp = cmdq->state.tflag.wp; struct window_pane *wp = cmdq->state.tflag.wp;
struct session *s = cmdq->state.tflag.s; struct session *s = cmdq->state.tflag.s;
struct mouse_event *m = &cmdq->item->mouse; struct mouse_event *m = &cmdq->mouse;
const u_char *keystr; const u_char *keystr;
int i, literal; int i, literal;
key_code key; key_code key;

View File

@ -28,7 +28,7 @@
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_q *); static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_q *);
static void cmd_source_file_done(struct cmd_q *); static enum cmd_retval cmd_source_file_done(struct cmd_q *, void *);
const struct cmd_entry cmd_source_file_entry = { const struct cmd_entry cmd_source_file_entry = {
.name = "source-file", .name = "source-file",
@ -45,53 +45,31 @@ static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq) cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
struct cmd_q *cmdq1; struct client *c = cmdq->client;
int quiet; int quiet;
struct cmd_q *new_cmdq;
cmdq1 = cmdq_new(cmdq->client);
cmdq1->emptyfn = cmd_source_file_done;
cmdq1->data = cmdq;
quiet = args_has(args, 'q'); quiet = args_has(args, 'q');
switch (load_cfg(args->argv[0], cmdq1, quiet)) { switch (load_cfg(args->argv[0], c, cmdq, quiet)) {
case -1: case -1:
cmdq_free(cmdq1); if (cfg_finished)
if (cfg_references == 0) {
cfg_print_causes(cmdq); cfg_print_causes(cmdq);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
case 0: case 0:
cmdq_free(cmdq1); if (cfg_finished)
if (cfg_references == 0)
cfg_print_causes(cmdq); cfg_print_causes(cmdq);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cfg_finished) {
log_debug("%s: cmdq %p, parent %p", __func__, cmdq1, cmdq); new_cmdq = cmdq_get_callback(cmd_source_file_done, NULL);
cmdq_insert_after(cmdq, new_cmdq);
cmdq->references++; }
cfg_references++; return (CMD_RETURN_NORMAL);
cmdq_continue(cmdq1);
return (CMD_RETURN_WAIT);
} }
static void static enum cmd_retval
cmd_source_file_done(struct cmd_q *cmdq1) cmd_source_file_done(struct cmd_q *cmdq, __unused void *data)
{ {
struct cmd_q *cmdq = cmdq1->data; cfg_print_causes(cmdq);
return (CMD_RETURN_NORMAL);
log_debug("%s: cmdq %p, parent %p", __func__, cmdq1, cmdq);
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
cfg_references--;
if (cmdq_free(cmdq))
return;
if (cfg_references == 0)
cfg_print_causes(cmdq);
cmdq_continue(cmdq);
} }

View File

@ -187,8 +187,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
fs.w = w; fs.w = w;
fs.wp = new_wp; fs.wp = new_wp;
cmd_find_log_state(__func__, &fs); cmd_find_log_state(__func__, &fs);
if (hooks_wait(s->hooks, cmdq, &fs, "after-split-window") == 0) hooks_insert(s->hooks, cmdq, &fs, "after-split-window");
return (CMD_RETURN_WAIT);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
error: error:

View File

@ -41,13 +41,18 @@ const struct cmd_entry cmd_wait_for_entry = {
.exec = cmd_wait_for_exec .exec = cmd_wait_for_exec
}; };
struct wait_item {
struct cmd_q *cmdq;
TAILQ_ENTRY(wait_item) entry;
};
struct wait_channel { struct wait_channel {
const char *name; const char *name;
int locked; int locked;
int woken; int woken;
TAILQ_HEAD(, cmd_q) waiters; TAILQ_HEAD(, wait_item) waiters;
TAILQ_HEAD(, cmd_q) lockers; TAILQ_HEAD(, wait_item) lockers;
RB_ENTRY(wait_channel) entry; RB_ENTRY(wait_channel) entry;
}; };
@ -135,7 +140,7 @@ static enum cmd_retval
cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name, cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
struct cmd_q *wq, *wq1; struct wait_item *wi, *wi1;
if (wc == NULL) if (wc == NULL)
wc = cmd_wait_for_add(name); wc = cmd_wait_for_add(name);
@ -147,10 +152,11 @@ cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name,
} }
log_debug("signal wait channel %s, with waiters", wc->name); log_debug("signal wait channel %s, with waiters", wc->name);
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) { TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry); wi->cmdq->flags &= ~CMD_Q_WAITING;
if (!cmdq_free(wq))
cmdq_continue(wq); TAILQ_REMOVE(&wc->waiters, wi, entry);
free(wi);
} }
cmd_wait_for_remove(wc); cmd_wait_for_remove(wc);
@ -158,10 +164,10 @@ cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name,
} }
static enum cmd_retval static enum cmd_retval
cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, struct wait_channel *wc)
struct wait_channel *wc)
{ {
struct client *c = cmdq->client; struct client *c = cmdq->client;
struct wait_item *wi;
if (c == NULL || c->session != NULL) { if (c == NULL || c->session != NULL) {
cmdq_error(cmdq, "not able to wait"); cmdq_error(cmdq, "not able to wait");
@ -178,16 +184,18 @@ cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
} }
log_debug("wait channel %s not woken (%p)", wc->name, c); log_debug("wait channel %s not woken (%p)", wc->name, c);
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry); wi = xcalloc(1, sizeof *wi);
cmdq->references++; wi->cmdq = cmdq;
TAILQ_INSERT_TAIL(&wc->waiters, wi, entry);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
static enum cmd_retval static enum cmd_retval
cmd_wait_for_lock(struct cmd_q *cmdq, const char *name, cmd_wait_for_lock(struct cmd_q *cmdq, const char *name, struct wait_channel *wc)
struct wait_channel *wc)
{ {
struct wait_item *wi;
if (cmdq->client == NULL || cmdq->client->session != NULL) { if (cmdq->client == NULL || cmdq->client->session != NULL) {
cmdq_error(cmdq, "not able to lock"); cmdq_error(cmdq, "not able to lock");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@ -197,8 +205,9 @@ cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
wc = cmd_wait_for_add(name); wc = cmd_wait_for_add(name);
if (wc->locked) { if (wc->locked) {
TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry); wi = xcalloc(1, sizeof *wi);
cmdq->references++; wi->cmdq = cmdq;
TAILQ_INSERT_TAIL(&wc->lockers, wi, entry);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
wc->locked = 1; wc->locked = 1;
@ -210,17 +219,17 @@ static enum cmd_retval
cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name, cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
struct cmd_q *wq; struct wait_item *wi;
if (wc == NULL || !wc->locked) { if (wc == NULL || !wc->locked) {
cmdq_error(cmdq, "channel %s not locked", name); cmdq_error(cmdq, "channel %s not locked", name);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) { if ((wi = TAILQ_FIRST(&wc->lockers)) != NULL) {
TAILQ_REMOVE(&wc->lockers, wq, waitentry); wi->cmdq->flags &= ~CMD_Q_WAITING;
if (!cmdq_free(wq)) TAILQ_REMOVE(&wc->lockers, wi, entry);
cmdq_continue(wq); free(wi);
} else { } else {
wc->locked = 0; wc->locked = 0;
cmd_wait_for_remove(wc); cmd_wait_for_remove(wc);
@ -233,19 +242,19 @@ void
cmd_wait_for_flush(void) cmd_wait_for_flush(void)
{ {
struct wait_channel *wc, *wc1; struct wait_channel *wc, *wc1;
struct cmd_q *wq, *wq1; struct wait_item *wi, *wi1;
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) { RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) { TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry); wi->cmdq->flags &= ~CMD_Q_WAITING;
if (!cmdq_free(wq)) TAILQ_REMOVE(&wc->waiters, wi, entry);
cmdq_continue(wq); free(wi);
} }
wc->woken = 1; wc->woken = 1;
TAILQ_FOREACH_SAFE(wq, &wc->lockers, waitentry, wq1) { TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) {
TAILQ_REMOVE(&wc->lockers, wq, waitentry); wi->cmdq->flags &= ~CMD_Q_WAITING;
if (!cmdq_free(wq)) TAILQ_REMOVE(&wc->lockers, wi, entry);
cmdq_continue(wq); free(wi);
} }
wc->locked = 0; wc->locked = 0;
cmd_wait_for_remove(wc); cmd_wait_for_remove(wc);

51
cmd.c
View File

@ -389,12 +389,11 @@ usage:
static int static int
cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
struct cmd_q *cmdq, struct cmd_q *parent) struct cmd_q *cmdq)
{ {
int targetflags, error; int targetflags, error;
struct cmd_find_state *fs = NULL; struct cmd_find_state *fs = NULL;
struct cmd_find_state *current = NULL; struct cmd_find_state current;
struct cmd_find_state tmp;
if (flag == CMD_NONE || if (flag == CMD_NONE ||
flag == CMD_CLIENT || flag == CMD_CLIENT ||
@ -448,21 +447,12 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
default: default:
fatalx("unknown %cflag %d", c, flag); fatalx("unknown %cflag %d", c, flag);
} }
log_debug("%s: flag %c %d %#x", __func__, c, flag, targetflags); log_debug("%s: flag %c %d %#x", __func__, c, flag, targetflags);
if (parent != NULL) {
if (c == 't') error = cmd_find_current(&current, cmdq, targetflags);
current = &parent->state.tflag; if (error != 0 && ~targetflags & CMD_FIND_QUIET)
else if (c == 's') return (-1);
current = &parent->state.sflag; if (!cmd_find_empty_state(&current) && !cmd_find_valid_state(&current))
}
if (current == NULL || !cmd_find_valid_state(current)) {
error = cmd_find_current(&tmp, cmdq, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
current = &tmp;
}
if (!cmd_find_empty_state(current) && !cmd_find_valid_state(current))
fatalx("invalid current state"); fatalx("invalid current state");
switch (flag) { switch (flag) {
@ -474,13 +464,13 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
case CMD_SESSION_CANFAIL: case CMD_SESSION_CANFAIL:
case CMD_SESSION_PREFERUNATTACHED: case CMD_SESSION_PREFERUNATTACHED:
case CMD_SESSION_WITHPANE: case CMD_SESSION_WITHPANE:
error = cmd_find_target(fs, current, cmdq, target, error = cmd_find_target(fs, &current, cmdq, target,
CMD_FIND_SESSION, targetflags); CMD_FIND_SESSION, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET) if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1); return (-1);
break; break;
case CMD_MOVEW_R: case CMD_MOVEW_R:
error = cmd_find_target(fs, current, cmdq, target, error = cmd_find_target(fs, &current, cmdq, target,
CMD_FIND_SESSION, CMD_FIND_QUIET); CMD_FIND_SESSION, CMD_FIND_QUIET);
if (error == 0) if (error == 0)
break; break;
@ -489,7 +479,7 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
case CMD_WINDOW_CANFAIL: case CMD_WINDOW_CANFAIL:
case CMD_WINDOW_MARKED: case CMD_WINDOW_MARKED:
case CMD_WINDOW_INDEX: case CMD_WINDOW_INDEX:
error = cmd_find_target(fs, current, cmdq, target, error = cmd_find_target(fs, &current, cmdq, target,
CMD_FIND_WINDOW, targetflags); CMD_FIND_WINDOW, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET) if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1); return (-1);
@ -497,7 +487,7 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
case CMD_PANE: case CMD_PANE:
case CMD_PANE_CANFAIL: case CMD_PANE_CANFAIL:
case CMD_PANE_MARKED: case CMD_PANE_MARKED:
error = cmd_find_target(fs, current, cmdq, target, error = cmd_find_target(fs, &current, cmdq, target,
CMD_FIND_PANE, targetflags); CMD_FIND_PANE, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET) if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1); return (-1);
@ -509,14 +499,14 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
} }
int int
cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq, struct cmd_q *parent) cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq)
{ {
const struct cmd_entry *entry = cmd->entry; const struct cmd_entry *entry = cmd->entry;
struct cmd_state *state = &cmdq->state; struct cmd_state *state = &cmdq->state;
char *tmp; char *tmp;
enum cmd_entry_flag flag; enum cmd_entry_flag flag;
const char *s; const char *s;
int error; int error;
tmp = cmd_print(cmd); tmp = cmd_print(cmd);
log_debug("preparing state for %s (client %p)", tmp, cmdq->client); log_debug("preparing state for %s (client %p)", tmp, cmdq->client);
@ -545,18 +535,19 @@ cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq, struct cmd_q *parent)
state->c = cmd_find_client(cmdq, s, 1); state->c = cmd_find_client(cmdq, s, 1);
break; break;
} }
log_debug("using client %p", state->c);
s = args_get(cmd->args, 't'); s = args_get(cmd->args, 't');
log_debug("preparing -t state: target %s", s == NULL ? "none" : s); log_debug("preparing -t state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('t', s, entry->tflag, cmdq, parent); error = cmd_prepare_state_flag('t', s, entry->tflag, cmdq);
if (error != 0) if (error != 0)
return (error); return (error);
s = args_get(cmd->args, 's'); s = args_get(cmd->args, 's');
log_debug("preparing -s state: target %s", s == NULL ? "none" : s); log_debug("preparing -s state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('s', s, entry->sflag, cmdq, parent); error = cmd_prepare_state_flag('s', s, entry->sflag, cmdq);
if (error != 0) if (error != 0)
return (error); return (error);

View File

@ -49,6 +49,21 @@ control_write_buffer(struct client *c, struct evbuffer *buffer)
server_client_push_stdout(c); server_client_push_stdout(c);
} }
/* Control error callback. */
static enum cmd_retval
control_error(struct cmd_q *cmdq, void *data)
{
struct client *c = cmdq->client;
char *error = data;
cmdq_guard(cmdq, "begin", 1);
control_write(c, "parse error: %s", error);
cmdq_guard(cmdq, "error", 1);
free(error);
return (CMD_RETURN_NORMAL);
}
/* Control input callback. Read lines and fire commands. */ /* Control input callback. Read lines and fire commands. */
void void
control_callback(struct client *c, int closed, __unused void *data) control_callback(struct client *c, int closed, __unused void *data)
@ -56,6 +71,7 @@ control_callback(struct client *c, int closed, __unused void *data)
char *line, *cause; char *line, *cause;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd *cmd; struct cmd *cmd;
struct cmd_q *cmdq;
if (closed) if (closed)
c->flags |= CLIENT_EXIT; c->flags |= CLIENT_EXIT;
@ -70,18 +86,13 @@ control_callback(struct client *c, int closed, __unused void *data)
} }
if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) { if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) {
c->cmdq->time = time(NULL); cmdq = cmdq_get_callback(control_error, cause);
c->cmdq->number++; cmdq_append(c, cmdq);
cmdq_guard(c->cmdq, "begin", 1);
control_write(c, "parse error: %s", cause);
cmdq_guard(c->cmdq, "error", 1);
free(cause);
} else { } else {
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) TAILQ_FOREACH(cmd, &cmdlist->list, qentry)
cmd->flags |= CMD_CONTROL; cmd->flags |= CMD_CONTROL;
cmdq_run(c->cmdq, cmdlist, NULL); cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmdq_append(c, cmdq);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
} }

View File

@ -492,7 +492,6 @@ struct format_tree *
format_create(struct cmd_q *cmdq, int flags) format_create(struct cmd_q *cmdq, int flags)
{ {
struct format_tree *ft; struct format_tree *ft;
struct cmd *cmd;
if (!event_initialized(&format_job_event)) { if (!event_initialized(&format_job_event)) {
evtimer_set(&format_job_event, format_job_timer, NULL); evtimer_set(&format_job_event, format_job_timer, NULL);
@ -510,11 +509,9 @@ format_create(struct cmd_q *cmdq, int flags)
format_add_tv(ft, "start_time", &start_time); format_add_tv(ft, "start_time", &start_time);
if (cmdq != NULL && cmdq->cmd != NULL) if (cmdq != NULL && cmdq->cmd != NULL)
format_add(ft, "command_name", "%s", cmdq->cmd->entry->name); format_add(ft, "command", "%s", cmdq->cmd->entry->name);
if (cmdq != NULL && cmdq->parent != NULL) { if (cmdq != NULL && cmdq->hook != NULL)
cmd = cmdq->parent->cmd; format_add(ft, "hook", "%s", cmdq->hook);
format_add(ft, "command_hooked", "%s", cmd->entry->name);
}
return (ft); return (ft);
} }

68
hooks.c
View File

@ -33,7 +33,6 @@ RB_GENERATE_STATIC(hooks_tree, hook, entry, hooks_cmp);
static struct hook *hooks_find1(struct hooks *, const char *); static struct hook *hooks_find1(struct hooks *, const char *);
static void hooks_free1(struct hooks *, struct hook *); static void hooks_free1(struct hooks *, struct hook *);
static void hooks_emptyfn(struct cmd_q *);
static int static int
hooks_cmp(struct hook *hook1, struct hook *hook2) hooks_cmp(struct hook *hook1, struct hook *hook2)
@ -140,28 +139,14 @@ hooks_find(struct hooks *hooks, const char *name)
return (hook); return (hook);
} }
static void void
hooks_emptyfn(struct cmd_q *hooks_cmdq)
{
struct cmd_q *cmdq = hooks_cmdq->data;
if (cmdq != NULL) {
if (hooks_cmdq->client_exit >= 0)
cmdq->client_exit = hooks_cmdq->client_exit;
if (!cmdq_free(cmdq))
cmdq_continue(cmdq);
}
cmdq_free(hooks_cmdq);
}
int
hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs, hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs,
const char *fmt, ...) const char *fmt, ...)
{ {
struct hook *hook; struct hook *hook;
struct cmd_q *hooks_cmdq;
va_list ap; va_list ap;
char *name; char *name;
struct cmd_q *new_cmdq, *loop;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&name, fmt, ap); xvasprintf(&name, fmt, ap);
@ -170,34 +155,30 @@ hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs,
hook = hooks_find(hooks, name); hook = hooks_find(hooks, name);
if (hook == NULL) { if (hook == NULL) {
free(name); free(name);
return (-1); return;
} }
log_debug("running hook %s", name); log_debug("running hook %s", name);
new_cmdq = cmdq_get_command(hook->cmdlist, fs, NULL, CMD_Q_NOHOOKS);
for (loop = new_cmdq; loop != NULL; loop = loop->next)
loop->hook = xstrdup(name);
free(name); free(name);
hooks_cmdq = cmdq_new(c); cmdq_append(c, new_cmdq);
hooks_cmdq->flags |= CMD_Q_NOHOOKS;
if (fs != NULL)
cmd_find_copy_state(&hooks_cmdq->current, fs);
hooks_cmdq->parent = NULL;
cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
cmdq_free(hooks_cmdq);
return (0);
} }
int void
hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs, hooks_insert(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs,
const char *fmt, ...) const char *fmt, ...)
{ {
struct hook *hook; struct hook *hook;
struct cmd_q *hooks_cmdq;
va_list ap; va_list ap;
char *name; char *name;
struct cmd_q *new_cmdq, *loop;
if (cmdq->flags & CMD_Q_NOHOOKS) if (cmdq->flags & CMD_Q_NOHOOKS)
return (-1); return;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&name, fmt, ap); xvasprintf(&name, fmt, ap);
@ -206,23 +187,18 @@ hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs,
hook = hooks_find(hooks, name); hook = hooks_find(hooks, name);
if (hook == NULL) { if (hook == NULL) {
free(name); free(name);
return (-1); return;
} }
log_debug("running hook %s (parent %p)", name, cmdq); log_debug("running hook %s (parent %p)", name, cmdq);
new_cmdq = cmdq_get_command(hook->cmdlist, fs, NULL, CMD_Q_NOHOOKS);
for (loop = new_cmdq; loop != NULL; loop = loop->next)
loop->hook = xstrdup(name);
free(name); free(name);
hooks_cmdq = cmdq_new(cmdq->client);
hooks_cmdq->flags |= CMD_Q_NOHOOKS;
if (fs != NULL)
cmd_find_copy_state(&hooks_cmdq->current, fs);
hooks_cmdq->parent = cmdq;
hooks_cmdq->emptyfn = hooks_emptyfn;
hooks_cmdq->data = cmdq;
if (cmdq != NULL) if (cmdq != NULL)
cmdq->references++; cmdq_insert_after(cmdq, new_cmdq);
cmdq_run(hooks_cmdq, hook->cmdlist, NULL); else
return (0); cmdq_append(NULL, new_cmdq);
} }

View File

@ -377,18 +377,22 @@ key_bindings_init(void)
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
char *cause; char *cause;
int error; int error;
struct cmd_q *cmdq;
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,
"<default-keys>", i, &cause); "<default-keys>", i, &cause);
if (error != 0) if (error != 0)
fatalx("bad default key"); fatalx("bad default key");
cmdq_run(cmdq, cmdlist, NULL); cmdq_append(NULL, cmdq_get_command(cmdlist, NULL, NULL, 0));
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
} }
cmdq_free(cmdq); }
static enum cmd_retval
key_bindings_read_only(struct cmd_q *cmdq, __unused void *data)
{
cmdq_error(cmdq, "client is read-only");
return (CMD_RETURN_ERROR);
} }
void void
@ -403,10 +407,8 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c,
if (!(cmd->entry->flags & CMD_READONLY)) if (!(cmd->entry->flags & CMD_READONLY))
readonly = 0; readonly = 0;
} }
if (!readonly && (c->flags & CLIENT_READONLY)) { if (!readonly && (c->flags & CLIENT_READONLY))
cmdq_error(c->cmdq, "client is read-only"); cmdq_append(c, cmdq_get_callback(key_bindings_read_only, NULL));
return; else
} cmdq_append(c, cmdq_get_command(bd->cmdlist, NULL, m, 0));
cmdq_run(c->cmdq, bd->cmdlist, m);
} }

View File

@ -65,7 +65,7 @@ notify_hook(struct notify_entry *ne)
const char *name; const char *name;
struct cmd_find_state fs; struct cmd_find_state fs;
struct hook *hook; struct hook *hook;
struct cmd_q *hooks_cmdq; struct cmd_q *new_cmdq, *loop;
name = notify_hooks[ne->type]; name = notify_hooks[ne->type];
if (name == NULL) if (name == NULL)
@ -86,14 +86,12 @@ notify_hook(struct notify_entry *ne)
return; return;
log_debug("notify hook %s", name); log_debug("notify hook %s", name);
hooks_cmdq = cmdq_new(NULL); new_cmdq = cmdq_get_command(hook->cmdlist, &fs, NULL, CMD_Q_NOHOOKS);
hooks_cmdq->flags |= CMD_Q_NOHOOKS;
cmd_find_copy_state(&hooks_cmdq->current, &fs); for (loop = new_cmdq; loop != NULL; loop = loop->next)
hooks_cmdq->parent = NULL; loop->hook = xstrdup(name);
cmdq_run(hooks_cmdq, hook->cmdlist, NULL); cmdq_append(NULL, new_cmdq);
cmdq_free(hooks_cmdq);
} }
static void static void

View File

@ -124,8 +124,7 @@ server_client_create(int fd)
c->fd = -1; c->fd = -1;
c->cwd = NULL; c->cwd = NULL;
c->cmdq = cmdq_new(c); TAILQ_INIT(&c->queue);
c->cmdq->client_exit = 1;
c->stdin_data = evbuffer_new(); c->stdin_data = evbuffer_new();
c->stdout_data = evbuffer_new(); c->stdout_data = evbuffer_new();
@ -242,10 +241,6 @@ server_client_lost(struct client *c)
free(c->prompt_string); free(c->prompt_string);
free(c->prompt_buffer); free(c->prompt_buffer);
c->cmdq->flags |= CMD_Q_DEAD;
cmdq_free(c->cmdq);
c->cmdq = NULL;
environ_free(c->environ); environ_free(c->environ);
proc_remove_peer(c->peer); proc_remove_peer(c->peer);
@ -279,6 +274,9 @@ server_client_free(__unused int fd, __unused short events, void *arg)
log_debug("free client %p (%d references)", c, c->references); log_debug("free client %p (%d references)", c, c->references);
if (!TAILQ_EMPTY(&c->queue))
fatalx("queue not empty");
if (c->references == 0) if (c->references == 0)
free(c); free(c);
} }
@ -1262,6 +1260,29 @@ server_client_dispatch(struct imsg *imsg, void *arg)
} }
} }
/* Callback when command is done. */
static enum cmd_retval
server_client_command_done(struct cmd_q *cmdq, __unused void *data)
{
struct client *c = cmdq->client;
if (~c->flags & CLIENT_ATTACHED)
c->flags |= CLIENT_EXIT;
return (CMD_RETURN_NORMAL);
}
/* Show an error message. */
static enum cmd_retval
server_client_command_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
/* Handle command message. */ /* Handle command message. */
static void static void
server_client_dispatch_command(struct client *c, struct imsg *imsg) server_client_dispatch_command(struct client *c, struct imsg *imsg)
@ -1284,7 +1305,7 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
argc = data.argc; argc = data.argc;
if (cmd_unpack_argv(buf, len, argc, &argv) != 0) { if (cmd_unpack_argv(buf, len, argc, &argv) != 0) {
cmdq_error(c->cmdq, "command too long"); cause = xstrdup("command too long");
goto error; goto error;
} }
@ -1295,20 +1316,19 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
} }
if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) { if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) {
cmdq_error(c->cmdq, "%s", cause);
cmd_free_argv(argc, argv); cmd_free_argv(argc, argv);
goto error; goto error;
} }
cmd_free_argv(argc, argv); cmd_free_argv(argc, argv);
if (c != cfg_client || cfg_finished) cmdq_append(c, cmdq_get_command(cmdlist, NULL, NULL, 0));
cmdq_run(c->cmdq, cmdlist, NULL); cmdq_append(c, cmdq_get_callback(server_client_command_done, NULL));
else
cmdq_append(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
return; return;
error: error:
cmdq_append(c, cmdq_get_callback(server_client_command_error, cause));
if (cmdlist != NULL) if (cmdlist != NULL)
cmd_list_free(cmdlist); cmd_list_free(cmdlist);

View File

@ -192,9 +192,17 @@ static int
server_loop(void) server_loop(void)
{ {
struct client *c; struct client *c;
u_int items;
notify_drain();
do {
items = cmdq_next(NULL);
TAILQ_FOREACH(c, &clients, entry)
items += cmdq_next(c);
} while (items != 0);
server_client_loop(); server_client_loop();
notify_drain();
if (!options_get_number(global_options, "exit-unattached")) { if (!options_get_number(global_options, "exit-unattached")) {
if (!RB_EMPTY(&sessions)) if (!RB_EMPTY(&sessions))

4
tmux.1
View File

@ -3460,8 +3460,7 @@ The following variables are available, where appropriate:
.It Li "client_tty" Ta "" Ta "Pseudo terminal of client" .It Li "client_tty" Ta "" Ta "Pseudo terminal of client"
.It Li "client_utf8" Ta "" Ta "1 if client supports utf8" .It Li "client_utf8" Ta "" Ta "1 if client supports utf8"
.It Li "client_width" Ta "" Ta "Width of client" .It Li "client_width" Ta "" Ta "Width of client"
.It Li "command_hooked" Ta "" Ta "Name of command hooked, if any" .It Li "command" Ta "" Ta "Name of command in use, if any"
.It Li "command_name" Ta "" Ta "Name of command in use, if any"
.It Li "command_list_name" Ta "" Ta "Command name if listing commands" .It Li "command_list_name" Ta "" Ta "Command name if listing commands"
.It Li "command_list_alias" Ta "" Ta "Command alias if listing commands" .It Li "command_list_alias" Ta "" Ta "Command alias if listing commands"
.It Li "command_list_usage" Ta "" Ta "Command usage if listing commands" .It Li "command_list_usage" Ta "" Ta "Command usage if listing commands"
@ -3471,6 +3470,7 @@ The following variables are available, where appropriate:
.It Li "history_bytes" Ta "" Ta "Number of bytes in window history" .It Li "history_bytes" Ta "" Ta "Number of bytes in window history"
.It Li "history_limit" Ta "" Ta "Maximum window history lines" .It Li "history_limit" Ta "" Ta "Maximum window history lines"
.It Li "history_size" Ta "" Ta "Size of history in bytes" .It Li "history_size" Ta "" Ta "Size of history in bytes"
.It Li "hook" Ta "" Ta "Name of running hook, if any"
.It Li "host" Ta "#H" Ta "Hostname of local host" .It Li "host" Ta "#H" Ta "Hostname of local host"
.It Li "host_short" Ta "#h" Ta "Hostname of local host (no domain name)" .It Li "host_short" Ta "#h" Ta "Hostname of local host (no domain name)"
.It Li "insert_flag" Ta "" Ta "Pane insert flag" .It Li "insert_flag" Ta "" Ta "Pane insert flag"

268
tmux.h
View File

@ -42,6 +42,8 @@ extern char **environ;
struct args; struct args;
struct client; struct client;
struct cmd_q;
struct cmd_q_list;
struct environ; struct environ;
struct input_ctx; struct input_ctx;
struct mode_key_cmdstr; struct mode_key_cmdstr;
@ -633,7 +635,6 @@ struct grid {
struct hook { struct hook {
const char *name; const char *name;
struct cmd_q *cmdq;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
RB_ENTRY(hook) entry; RB_ENTRY(hook) entry;
@ -1162,101 +1163,6 @@ struct message_entry {
TAILQ_ENTRY(message_entry) entry; TAILQ_ENTRY(message_entry) entry;
}; };
/* Client connection. */
struct client {
struct tmuxpeer *peer;
pid_t pid;
int fd;
struct event event;
int retval;
struct timeval creation_time;
struct timeval activity_time;
struct environ *environ;
char *title;
const char *cwd;
char *term;
char *ttyname;
struct tty tty;
void (*stdin_callback)(struct client *, int, void *);
void *stdin_callback_data;
struct evbuffer *stdin_data;
int stdin_closed;
struct evbuffer *stdout_data;
struct evbuffer *stderr_data;
struct event repeat_timer;
struct event click_timer;
u_int click_button;
struct event status_timer;
struct screen status;
#define CLIENT_TERMINAL 0x1
#define CLIENT_LOGIN 0x2
#define CLIENT_EXIT 0x4
#define CLIENT_REDRAW 0x8
#define CLIENT_STATUS 0x10
#define CLIENT_REPEAT 0x20
#define CLIENT_SUSPENDED 0x40
/* 0x80 unused */
#define CLIENT_IDENTIFY 0x100
#define CLIENT_DEAD 0x200
#define CLIENT_BORDERS 0x400
#define CLIENT_READONLY 0x800
#define CLIENT_REDRAWWINDOW 0x1000
#define CLIENT_CONTROL 0x2000
#define CLIENT_CONTROLCONTROL 0x4000
#define CLIENT_FOCUSED 0x8000
#define CLIENT_UTF8 0x10000
#define CLIENT_256COLOURS 0x20000
#define CLIENT_IDENTIFIED 0x40000
#define CLIENT_STATUSFORCE 0x80000
#define CLIENT_DOUBLECLICK 0x100000
#define CLIENT_TRIPLECLICK 0x200000
int flags;
struct key_table *keytable;
struct event identify_timer;
void (*identify_callback)(struct client *, struct window_pane *);
void *identify_callback_data;
char *message_string;
struct event message_timer;
u_int message_next;
TAILQ_HEAD(, message_entry) message_log;
char *prompt_string;
struct utf8_data *prompt_buffer;
size_t prompt_index;
int (*prompt_callbackfn)(void *, const char *);
void (*prompt_freefn)(void *);
void *prompt_data;
u_int prompt_hindex;
enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode;
#define PROMPT_SINGLE 0x1
#define PROMPT_NUMERIC 0x2
int prompt_flags;
struct session *session;
struct session *last_session;
int wlmouse;
struct cmd_q *cmdq;
int references;
TAILQ_ENTRY(client) entry;
};
TAILQ_HEAD(clients, client);
/* Parsed arguments structures. */ /* Parsed arguments structures. */
struct args_entry; struct args_entry;
RB_HEAD(args_tree, args_entry); RB_HEAD(args_tree, args_entry);
@ -1326,42 +1232,46 @@ enum cmd_retval {
CMD_RETURN_STOP CMD_RETURN_STOP
}; };
/* Command queue entry. */ /* Command queue item type. */
struct cmd_q_item { enum cmd_q_type {
struct cmd_list *cmdlist; CMD_Q_COMMAND,
CMD_Q_CALLBACK,
struct mouse_event mouse;
TAILQ_ENTRY(cmd_q_item) qentry;
}; };
TAILQ_HEAD(cmd_q_items, cmd_q_item);
/* Command queue. */ /* Command queue item. */
typedef enum cmd_retval (*cmd_q_cb) (struct cmd_q *, void *);
struct cmd_q { struct cmd_q {
int references; struct cmd_q_list *queue;
int flags; struct cmd_q *next;
#define CMD_Q_DEAD 0x1
#define CMD_Q_NOHOOKS 0x2
struct client *client; struct client *client;
int client_exit;
struct cmd_q_items queue; enum cmd_q_type type;
struct cmd_q_item *item; u_int group;
u_int number;
time_t time;
const char *hook;
int flags;
#define CMD_Q_FIRED 0x1
#define CMD_Q_WAITING 0x2
#define CMD_Q_NOHOOKS 0x4
struct cmd_list *cmdlist;
struct cmd *cmd; struct cmd *cmd;
struct cmd_q *parent;
cmd_q_cb cb;
void *data;
struct cmd_find_state current; struct cmd_find_state current;
struct cmd_state state; struct cmd_state state;
time_t time; struct mouse_event mouse;
u_int number;
void (*emptyfn)(struct cmd_q *); TAILQ_ENTRY(cmd_q) entry;
void *data;
TAILQ_ENTRY(cmd_q) waitentry;
}; };
TAILQ_HEAD(cmd_q_list, cmd_q);
/* Command -c, -t or -s flags. */ /* Command -c, -t or -s flags. */
enum cmd_entry_flag { enum cmd_entry_flag {
@ -1411,6 +1321,101 @@ struct cmd_entry {
enum cmd_retval (*exec)(struct cmd *, struct cmd_q *); enum cmd_retval (*exec)(struct cmd *, struct cmd_q *);
}; };
/* Client connection. */
struct client {
struct tmuxpeer *peer;
struct cmd_q_list queue;
pid_t pid;
int fd;
struct event event;
int retval;
struct timeval creation_time;
struct timeval activity_time;
struct environ *environ;
char *title;
const char *cwd;
char *term;
char *ttyname;
struct tty tty;
void (*stdin_callback)(struct client *, int, void *);
void *stdin_callback_data;
struct evbuffer *stdin_data;
int stdin_closed;
struct evbuffer *stdout_data;
struct evbuffer *stderr_data;
struct event repeat_timer;
struct event click_timer;
u_int click_button;
struct event status_timer;
struct screen status;
#define CLIENT_TERMINAL 0x1
#define CLIENT_LOGIN 0x2
#define CLIENT_EXIT 0x4
#define CLIENT_REDRAW 0x8
#define CLIENT_STATUS 0x10
#define CLIENT_REPEAT 0x20
#define CLIENT_SUSPENDED 0x40
#define CLIENT_ATTACHED 0x80
#define CLIENT_IDENTIFY 0x100
#define CLIENT_DEAD 0x200
#define CLIENT_BORDERS 0x400
#define CLIENT_READONLY 0x800
#define CLIENT_REDRAWWINDOW 0x1000
#define CLIENT_CONTROL 0x2000
#define CLIENT_CONTROLCONTROL 0x4000
#define CLIENT_FOCUSED 0x8000
#define CLIENT_UTF8 0x10000
#define CLIENT_256COLOURS 0x20000
#define CLIENT_IDENTIFIED 0x40000
#define CLIENT_STATUSFORCE 0x80000
#define CLIENT_DOUBLECLICK 0x100000
#define CLIENT_TRIPLECLICK 0x200000
int flags;
struct key_table *keytable;
struct event identify_timer;
void (*identify_callback)(struct client *, struct window_pane *);
void *identify_callback_data;
char *message_string;
struct event message_timer;
u_int message_next;
TAILQ_HEAD(, message_entry) message_log;
char *prompt_string;
struct utf8_data *prompt_buffer;
size_t prompt_index;
int (*prompt_callbackfn)(void *, const char *);
void (*prompt_freefn)(void *);
void *prompt_data;
u_int prompt_hindex;
enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode;
#define PROMPT_SINGLE 0x1
#define PROMPT_NUMERIC 0x2
int prompt_flags;
struct session *session;
struct session *last_session;
int wlmouse;
int references;
TAILQ_ENTRY(client) entry;
};
TAILQ_HEAD(clients, client);
/* Key binding and key table. */ /* Key binding and key table. */
struct key_binding { struct key_binding {
key_code key; key_code key;
@ -1506,10 +1511,9 @@ void proc_kill_peer(struct tmuxpeer *);
/* cfg.c */ /* cfg.c */
extern int cfg_finished; extern int cfg_finished;
extern int cfg_references;
extern struct client *cfg_client; extern struct client *cfg_client;
void start_cfg(void); void start_cfg(void);
int load_cfg(const char *, struct cmd_q *, int); int load_cfg(const char *, struct client *, struct cmd_q *, int);
void set_cfg_file(const char *); void set_cfg_file(const char *);
void printflike(1, 2) cfg_add_cause(const char *, ...); void printflike(1, 2) cfg_add_cause(const char *, ...);
void cfg_print_causes(struct cmd_q *); void cfg_print_causes(struct cmd_q *);
@ -1559,9 +1563,9 @@ void hooks_add(struct hooks *, const char *, struct cmd_list *);
void hooks_copy(struct hooks *, struct hooks *); void hooks_copy(struct hooks *, struct hooks *);
void hooks_remove(struct hooks *, const char *); void hooks_remove(struct hooks *, const char *);
struct hook *hooks_find(struct hooks *, const char *); struct hook *hooks_find(struct hooks *, const char *);
int printflike(4, 5) hooks_run(struct hooks *, struct client *, void printflike(4, 5) hooks_run(struct hooks *, struct client *,
struct cmd_find_state *, const char *, ...); struct cmd_find_state *, const char *, ...);
int printflike(4, 5) hooks_wait(struct hooks *, struct cmd_q *, void printflike(4, 5) hooks_insert(struct hooks *, struct cmd_q *,
struct cmd_find_state *, const char *, ...); struct cmd_find_state *, const char *, ...);
/* mode-key.c */ /* mode-key.c */
@ -1757,8 +1761,7 @@ char **cmd_copy_argv(int, char **);
void cmd_free_argv(int, char **); void cmd_free_argv(int, char **);
char *cmd_stringify_argv(int, char **); char *cmd_stringify_argv(int, char **);
struct cmd *cmd_parse(int, char **, const char *, u_int, char **); struct cmd *cmd_parse(int, char **, const char *, u_int, char **);
int cmd_prepare_state(struct cmd *, struct cmd_q *, int cmd_prepare_state(struct cmd *, struct cmd_q *);
struct cmd_q *);
char *cmd_print(struct cmd *); char *cmd_print(struct cmd *);
int cmd_mouse_at(struct window_pane *, struct mouse_event *, int cmd_mouse_at(struct window_pane *, struct mouse_event *,
u_int *, u_int *, int); u_int *, u_int *, int);
@ -1778,16 +1781,15 @@ void cmd_list_free(struct cmd_list *);
char *cmd_list_print(struct cmd_list *); char *cmd_list_print(struct cmd_list *);
/* cmd-queue.c */ /* cmd-queue.c */
struct cmd_q *cmdq_new(struct client *); struct cmd_q *cmdq_get_command(struct cmd_list *, struct cmd_find_state *,
int cmdq_free(struct cmd_q *); struct mouse_event *, int);
struct cmd_q *cmdq_get_callback(cmd_q_cb, void *);
void cmdq_insert_after(struct cmd_q *, struct cmd_q *);
void cmdq_append(struct client *, struct cmd_q *);
u_int cmdq_next(struct client *);
void cmdq_guard(struct cmd_q *, const char *, int);
void printflike(2, 3) cmdq_print(struct cmd_q *, const char *, ...); void printflike(2, 3) cmdq_print(struct cmd_q *, const char *, ...);
void printflike(2, 3) cmdq_error(struct cmd_q *, const char *, ...); void printflike(2, 3) cmdq_error(struct cmd_q *, const char *, ...);
void cmdq_guard(struct cmd_q *, const char *, int);
void cmdq_run(struct cmd_q *, struct cmd_list *,
struct mouse_event *);
void cmdq_append(struct cmd_q *, struct cmd_list *,
struct mouse_event *);
int cmdq_continue(struct cmd_q *);
/* cmd-string.c */ /* cmd-string.c */
int cmd_string_parse(const char *, struct cmd_list **, const char *, int cmd_string_parse(const char *, struct cmd_list **, const char *,

View File

@ -246,6 +246,7 @@ window_choose_data_run(struct window_choose_data *cdata)
{ {
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
char *cause; char *cause;
struct cmd_q *cmdq;
/* /*
* The command template will have already been replaced. But if it's * The command template will have already been replaced. But if it's
@ -263,7 +264,8 @@ window_choose_data_run(struct window_choose_data *cdata)
return; return;
} }
cmdq_run(cdata->start_client->cmdq, cmdlist, NULL); cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmdq_append(cdata->start_client, cmdq);
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
} }