summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cfg.c70
-rw-r--r--cmd-attach-session.c2
-rw-r--r--cmd-command-prompt.c30
-rw-r--r--cmd-confirm-before.c27
-rw-r--r--cmd-copy-mode.c4
-rw-r--r--cmd-display-panes.c50
-rw-r--r--cmd-find.c2
-rw-r--r--cmd-if-shell.c112
-rw-r--r--cmd-load-buffer.c45
-rw-r--r--cmd-new-session.c6
-rw-r--r--cmd-new-window.c4
-rw-r--r--cmd-queue.c489
-rw-r--r--cmd-resize-pane.c4
-rw-r--r--cmd-run-shell.c28
-rw-r--r--cmd-send-keys.c2
-rw-r--r--cmd-source-file.c54
-rw-r--r--cmd-split-window.c4
-rw-r--r--cmd-wait-for.c69
-rw-r--r--cmd.c51
-rw-r--r--control.c29
-rw-r--r--format.c9
-rw-r--r--hooks.c64
-rw-r--r--key-bindings.c22
-rw-r--r--notify.c12
-rw-r--r--server-client.c44
-rw-r--r--server.c10
-rw-r--r--tmux.14
-rw-r--r--tmux.h268
-rw-r--r--window-choose.c4
29 files changed, 817 insertions, 702 deletions
diff --git a/cfg.c b/cfg.c
index 801056db..62cca179 100644
--- a/cfg.c
+++ b/cfg.c
@@ -29,14 +29,25 @@
#include "tmux.h"
char *cfg_file;
-static struct cmd_q *cfg_cmd_q;
int cfg_finished;
-int cfg_references;
static char **cfg_causes;
static u_int cfg_ncauses;
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
set_cfg_file(const char *path)
@@ -51,30 +62,24 @@ start_cfg(void)
const char *home;
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);
if (cfg_client != NULL)
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) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
quiet = 1;
}
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
-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;
char delim[3] = { '\\', '\\', '\0' };
@@ -82,6 +87,7 @@ load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
size_t line = 0;
char *buf, *cause1, *p;
struct cmd_list *cmdlist;
+ struct cmd_q *new_cmdq;
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
@@ -117,8 +123,13 @@ load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
if (cmdlist == NULL)
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);
+
found++;
}
fclose(f);
@@ -126,37 +137,6 @@ load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
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
cfg_add_cause(const char *fmt, ...)
{
diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index daab428f..f0e860f9 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -145,7 +145,7 @@ cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag,
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
hooks_run(c->session->hooks, c, NULL, "client-attached");
- cmdq->client_exit = 0;
+ c->flags |= CLIENT_ATTACHED;
}
recalculate_sizes();
alerts_check_session(s);
diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c
index 12ecb493..5e21b2bc 100644
--- a/cmd-command-prompt.c
+++ b/cmd-command-prompt.c
@@ -121,12 +121,24 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
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
cmd_command_prompt_callback(void *data, const char *s)
{
struct cmd_command_prompt_cdata *cdata = data;
struct client *c = cdata->c;
struct cmd_list *cmdlist;
+ struct cmd_q *new_cmdq;
char *cause, *new_template, *prompt, *ptr;
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 (cause != NULL) {
- *cause = toupper((u_char) *cause);
- status_message_set(c, "%s", cause);
- free(cause);
- }
- return (0);
+ new_cmdq = cmdq_get_callback(cmd_command_prompt_error,
+ cause);
+ } else
+ new_cmdq = NULL;
+ } else {
+ new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
+ cmd_list_free(cmdlist);
}
- cmdq_run(c->cmdq, cmdlist, NULL);
- cmd_list_free(cmdlist);
+ if (new_cmdq != NULL)
+ 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 (0);
}
diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c
index 4241aefb..2dd52c81 100644
--- a/cmd-confirm-before.c
+++ b/cmd-confirm-before.c
@@ -83,12 +83,24 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
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
cmd_confirm_before_callback(void *data, const char *s)
{
struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
struct cmd_list *cmdlist;
+ struct cmd_q *new_cmdq;
char *cause;
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 (cause != NULL) {
- cmdq_error(c->cmdq, "%s", cause);
- free(cause);
- }
- return (0);
+ new_cmdq = cmdq_get_callback(cmd_confirm_before_error,
+ cause);
+ } else
+ new_cmdq = NULL;
+ } else {
+ new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
+ cmd_list_free(cmdlist);
}
- cmdq_run(c->cmdq, cmdlist, NULL);
- cmd_list_free(cmdlist);
+ if (new_cmdq != NULL)
+ cmdq_append(c, new_cmdq);
return (0);
}
diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c
index 4591a37d..dc880d56 100644
--- a/cmd-copy-mode.c
+++ b/cmd-copy-mode.c
@@ -61,7 +61,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp = cmdq->state.tflag.wp;
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);
if (c == NULL || c->session != s)
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 (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->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp, 0);
diff --git a/cmd-display-panes.c b/cmd-display-panes.c
index 2edb2eb3..471bec02 100644
--- a/cmd-display-panes.c
+++ b/cmd-display-panes.c
@@ -65,32 +65,48 @@ cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq)
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
cmd_display_panes_callback(struct client *c, struct window_pane *wp)
{
struct cmd_list *cmdlist;
+ struct cmd_q *new_cmdq;
char *template, *cmd, *expanded, *cause;
template = c->identify_callback_data;
- if (wp != NULL) {
- xasprintf(&expanded, "%%%u", wp->id);
- cmd = cmd_template_replace(template, expanded, 1);
-
- if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
- if (cause != NULL) {
- *cause = toupper((u_char) *cause);
- status_message_set(c, "%s", cause);
- free(cause);
- }
- } else {
- cmdq_run(c->cmdq, cmdlist, NULL);
- cmd_list_free(cmdlist);
- }
-
- free(cmd);
- free(expanded);
+ if (wp == NULL)
+ goto out;
+ xasprintf(&expanded, "%%%u", wp->id);
+ cmd = cmd_template_replace(template, expanded, 1);
+
+ if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
+ if (cause != NULL) {
+ new_cmdq = cmdq_get_callback(cmd_display_panes_error,
+ cause);
+ } else
+ new_cmdq = NULL;
+ } else {
+ new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
+ cmd_list_free(cmdlist);
}
+ if (new_cmdq != NULL)
+ cmdq_append(c, new_cmdq);
+
+ free(cmd);
+ free(expanded);
+
+out:
free(c->identify_callback_data);
c->identify_callback_data = NULL;
c->identify_callback = NULL;
diff --git a/cmd-find.c b/cmd-find.c
index 21691f67..f9cbe442 100644
--- a/cmd-find.c
+++ b/cmd-find.c
@@ -1006,7 +1006,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
- m = &cmdq->item->mouse;
+ m = &cmdq->mouse;
switch (type) {
case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 2a8cbff2..7192b204 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -31,9 +31,9 @@
static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *);
-static void cmd_if_shell_callback(struct job *);
-static void cmd_if_shell_done(struct cmd_q *);
-static void cmd_if_shell_free(void *);
+static enum cmd_retval cmd_if_shell_error(struct cmd_q *, void *);
+static void cmd_if_shell_callback(struct job *);
+static void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = {
.name = "if-shell",
@@ -56,11 +56,9 @@ struct cmd_if_shell_data {
char *cmd_if;
char *cmd_else;
+ struct client *client;
struct cmd_q *cmdq;
struct mouse_event mouse;
-
- int bflag;
- int references;
};
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;
char *shellcmd, *cmd, *cause;
struct cmd_list *cmdlist;
+ struct cmd_q *new_cmdq;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
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);
}
- 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);
return (CMD_RETURN_NORMAL);
}
@@ -121,92 +121,80 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
else
cdata->cmd_else = NULL;
- cdata->bflag = args_has(args, 'b');
+ cdata->client = cmdq->client;
+ cdata->client->references++;
- cdata->cmdq = cmdq;
- memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse);
- cmdq->references++;
+ if (!args_has(args, 'b'))
+ cdata->cmdq = cmdq;
+ 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,
cdata);
free(shellcmd);
- if (cdata->bflag)
+ if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
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
cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job->data;
- struct cmd_q *cmdq = cdata->cmdq, *cmdq1;
+ struct client *c = cdata->client;
struct cmd_list *cmdlist;
- char *cause, *cmd;
-
- if (cmdq->flags & CMD_Q_DEAD)
- return;
+ struct cmd_q *new_cmdq;
+ char *cause, *cmd, *file = cdata->file;
+ u_int line = cdata->line;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
cmd = cdata->cmd_else;
else
cmd = cdata->cmd_if;
if (cmd == NULL)
- return;
-
- if (cmd_string_parse(cmd, &cmdlist, cdata->file, cdata->line,
- &cause) != 0) {
- if (cause != NULL) {
- cmdq_error(cmdq, "%s", cause);
- free(cause);
- }
- return;
+ goto out;
+
+ if (cmd_string_parse(cmd, &cmdlist, file, line, &cause) != 0) {
+ if (cause != NULL)
+ new_cmdq = cmdq_get_callback(cmd_if_shell_error, cause);
+ else
+ new_cmdq = NULL;
+ } else {
+ new_cmdq = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
+ cmd_list_free(cmdlist);
}
- cmdq1 = cmdq_new(cmdq->client);
- cmdq1->emptyfn = cmd_if_shell_done;
- cmdq1->data = cdata;
-
- cdata->references++;
- cmdq_run(cmdq1, cmdlist, &cdata->mouse);
- cmd_list_free(cmdlist);
-}
-
-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);
+ if (new_cmdq != NULL) {
+ if (cdata->cmdq == NULL)
+ cmdq_append(c, new_cmdq);
+ else
+ cmdq_insert_after(cdata->cmdq, new_cmdq);
+ }
- free(cdata->file);
- free(cdata);
+out:
+ if (cdata->cmdq != NULL)
+ cdata->cmdq->flags &= ~CMD_Q_WAITING;
}
static void
cmd_if_shell_free(void *data)
{
struct cmd_if_shell_data *cdata = data;
- struct cmd_q *cmdq = cdata->cmdq;
-
- if (--cdata->references != 0)
- return;
- if (!cmdq_free(cmdq) && !cdata->bflag)
- cmdq_continue(cmdq);
+ server_client_unref(cdata->client);
free(cdata->cmd_else);
free(cdata->cmd_if);
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index ca886d69..ae071968 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -46,17 +46,24 @@ const struct cmd_entry cmd_load_buffer_entry = {
.exec = cmd_load_buffer_exec
};
+struct cmd_load_buffer_data {
+ struct cmd_q *cmdq;
+ char *bufname;
+};
+
static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
- struct client *c = cmdq->client;
- struct session *s;
- FILE *f;
- const char *path, *bufname, *cwd;
- char *pdata, *new_pdata, *cause, *file, resolved[PATH_MAX];
- size_t psize;
- int ch, error;
+ struct args *args = self->args;
+ struct cmd_load_buffer_data *cdata;
+ struct client *c = cmdq->client;
+ struct session *s;
+ FILE *f;
+ const char *path, *bufname, *cwd;
+ char *pdata, *new_pdata, *cause, *file;
+ char resolved[PATH_MAX];
+ size_t psize;
+ int ch, error;
bufname = NULL;
if (args_has(args, 'b'))
@@ -64,8 +71,12 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
path = args->argv[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,
- (void *)bufname, &cause);
+ cdata, &cause);
if (error != 0) {
cmdq_error(cmdq, "%s: %s", path, cause);
free(cause);
@@ -136,9 +147,9 @@ error:
static void
cmd_load_buffer_callback(struct client *c, int closed, void *data)
{
- const char *bufname = data;
- char *pdata, *cause, *saved;
- size_t psize;
+ struct cmd_load_buffer_data *cdata = data;
+ char *pdata, *cause, *saved;
+ size_t psize;
if (!closed)
return;
@@ -146,7 +157,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
server_client_unref(c);
if (c->flags & CLIENT_DEAD)
- return;
+ goto out;
psize = EVBUFFER_LENGTH(c->stdin_data);
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';
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. */
if (~c->flags & CLIENT_UTF8) {
saved = cause;
@@ -168,7 +179,9 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
free(pdata);
free(cause);
}
-
out:
- cmdq_continue(c->cmdq);
+ cdata->cmdq->flags &= ~CMD_Q_WAITING;
+
+ free(cdata->bufname);
+ free(cdata);
}
diff --git a/cmd-new-session.c b/cmd-new-session.c
index 5924b793..e587e5ee 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -312,14 +312,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
}
if (!detached)
- cmdq->client_exit = 0;
+ c->flags |= CLIENT_ATTACHED;
if (to_free != NULL)
free((void *)to_free);
cmd_find_from_session(&fs, s);
- if (hooks_wait(s->hooks, cmdq, &fs, "after-new-session") == 0)
- return (CMD_RETURN_WAIT);
+ hooks_insert(s->hooks, cmdq, &fs, "after-new-session");
+
return (CMD_RETURN_NORMAL);
error:
diff --git a/cmd-new-window.c b/cmd-new-window.c
index 4d0e0057..af476913 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -157,8 +157,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
free((void *)to_free);
cmd_find_from_winlink(&fs, s, wl);
- if (hooks_wait(s->hooks, cmdq, &fs, "after-new-window") == 0)
- return (CMD_RETURN_WAIT);
+ hooks_insert(s->hooks, cmdq, &fs, "after-new-window");
+
return (CMD_RETURN_NORMAL);
error:
diff --git a/cmd-queue.c b/cmd-queue.c
index 2012e871..fca3bf04 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -25,47 +25,316 @@
#include "tmux.h"
-static enum cmd_retval cmdq_continue_one(struct cmd_q *);
-static void cmdq_flush(struct cmd_q *);
+/* Global command queue. */
+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 *
-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;
+ 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);
+}
- cmdq = xcalloc(1, sizeof *cmdq);
- cmdq->references = 1;
- cmdq->flags = 0;
+/* 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;
- cmdq->client_exit = -1;
+ if (retval == CMD_RETURN_ERROR)
+ cmdq_guard(cmdq, "error", flags);
+ else
+ cmdq_guard(cmdq, "end", flags);
+ return (retval);
+}
- TAILQ_INIT(&cmdq->queue);
- cmdq->item = NULL;
- cmdq->cmd = NULL;
+/* Get a callback for the command queue. */
+struct cmd_q *
+cmdq_get_callback(cmd_q_cb cb, void *data)
+{
+ struct cmd_q *cmdq;
+
+ cmdq = xcalloc(1, sizeof *cmdq);
+ cmdq->type = CMD_Q_CALLBACK;
+ cmdq->group = 0;
+ cmdq->flags = 0;
- cmd_find_clear_state(&cmdq->current, NULL, 0);
- cmdq->parent = NULL;
+ cmdq->cb = cb;
+ cmdq->data = data;
return (cmdq);
}
-/* Free command queue */
-int
-cmdq_free(struct cmd_q *cmdq)
+/* Fire callback on callback queue. */
+static enum cmd_retval
+cmdq_fire_callback(struct cmd_q *cmdq)
{
- log_debug("cmdq %p free: %u references", cmdq, cmdq->references);
+ return (cmdq->cb(cmdq, cmdq->data));
+}
+
+/* Process next item on command queue. */
+u_int
+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 (--cmdq->references != 0) {
- if (cmdq->flags & CMD_Q_DEAD)
- return (1);
+ 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);
}
- cmdq_flush(cmdq);
- free(cmdq);
- return (1);
+ log_debug("%s %s: enter", __func__, name);
+ for (;;) {
+ 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 sam