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 (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) { - *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 (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; + goto out; - if (cmd_string_parse(cmd, &cmdlist, cdata->file, cdata->line, - &cause) != 0) { - if (cause != NULL) { - cmdq_error(cmdq, "%s", cause); - free(cause); - } - return; + 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; + if (new_cmdq != NULL) { + if (cdata->cmdq == NULL) + cmdq_append(c, new_cmdq); + else + cmdq_insert_after(cdata->cmdq, new_cmdq); + } - 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); - - 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 (""); + 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, *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; cmdq = xcalloc(1, sizeof *cmdq); - cmdq->references = 1; + cmdq->type = CMD_Q_CALLBACK; + cmdq->group = 0; cmdq->flags = 0; - cmdq->client = c; - cmdq->client_exit = -1; - - TAILQ_INIT(&cmdq->queue); - cmdq->item = NULL; - cmdq->cmd = NULL; - - 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)); +} - if (--cmdq->references != 0) { - if (cmdq->flags & CMD_Q_DEAD) - return (1); +/* 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 (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 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. */ @@ -140,175 +409,3 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) 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; -} - diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index be652b56..3360bd6b 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -60,12 +60,12 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) int x, y; 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); if (c == NULL || c->session != s) return (CMD_RETURN_NORMAL); 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); } diff --git a/cmd-run-shell.c b/cmd-run-shell.c index c81c76f8..ad2d4c2f 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -51,7 +51,6 @@ const struct cmd_entry cmd_run_shell_entry = { struct cmd_run_shell_data { char *cmd; struct cmd_q *cmdq; - int bflag; int wp_id; }; @@ -92,6 +91,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq) cwd = s->cwd; else cwd = NULL; + ft = format_create(cmdq, 0); format_defaults(ft, cmdq->state.c, s, wl, wp); 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->cmd = shellcmd; - cdata->bflag = args_has(args, 'b'); if (args_has(args, 't') && wp != NULL) cdata->wp_id = wp->id; else cdata->wp_id = -1; - cdata->cmdq = cmdq; - cmdq->references++; + if (args_has(args, 't') && wp != NULL) + 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, cdata); - if (cdata->bflag) + if (args_has(args, 'b')) return (CMD_RETURN_NORMAL); return (CMD_RETURN_WAIT); } @@ -121,16 +125,11 @@ static void cmd_run_shell_callback(struct job *job) { struct cmd_run_shell_data *cdata = job->data; - struct cmd_q *cmdq = cdata->cmdq; - char *cmd, *msg, *line; + char *cmd = cdata->cmd, *msg, *line; size_t size; int retcode; u_int lines; - if (cmdq->flags & CMD_Q_DEAD) - return; - cmd = cdata->cmd; - lines = 0; do { if ((line = evbuffer_readline(job->event->input)) != NULL) { @@ -163,16 +162,15 @@ cmd_run_shell_callback(struct job *job) if (msg != NULL) cmd_run_shell_print(job, msg); free(msg); + + if (cdata->cmdq != NULL) + cdata->cmdq->flags &= ~CMD_Q_WAITING; } static void cmd_run_shell_free(void *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); diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 062a13d7..94316834 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -62,7 +62,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) struct client *c = cmdq->state.c; struct window_pane *wp = cmdq->state.tflag.wp; struct session *s = cmdq->state.tflag.s; - struct mouse_event *m = &cmdq->item->mouse; + struct mouse_event *m = &cmdq->mouse; const u_char *keystr; int i, literal; key_code key; diff --git a/cmd-source-file.c b/cmd-source-file.c index 336a79e6..6f9c4451 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -28,7 +28,7 @@ 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 = { .name = "source-file", @@ -45,53 +45,31 @@ static enum cmd_retval cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - struct cmd_q *cmdq1; + struct client *c = cmdq->client; int quiet; - - cmdq1 = cmdq_new(cmdq->client); - cmdq1->emptyfn = cmd_source_file_done; - cmdq1->data = cmdq; + struct cmd_q *new_cmdq; quiet = args_has(args, 'q'); - switch (load_cfg(args->argv[0], cmdq1, quiet)) { + switch (load_cfg(args->argv[0], c, cmdq, quiet)) { case -1: - cmdq_free(cmdq1); - if (cfg_references == 0) { + if (cfg_finished) cfg_print_causes(cmdq); - return (CMD_RETURN_ERROR); - } - return (CMD_RETURN_NORMAL); + return (CMD_RETURN_ERROR); case 0: - cmdq_free(cmdq1); - if (cfg_references == 0) + if (cfg_finished) cfg_print_causes(cmdq); return (CMD_RETURN_NORMAL); } - - log_debug("%s: cmdq %p, parent %p", __func__, cmdq1, cmdq); - - cmdq->references++; - cfg_references++; - - cmdq_continue(cmdq1); - return (CMD_RETURN_WAIT); + if (cfg_finished) { + new_cmdq = cmdq_get_callback(cmd_source_file_done, NULL); + cmdq_insert_after(cmdq, new_cmdq); + } + return (CMD_RETURN_NORMAL); } -static void -cmd_source_file_done(struct cmd_q *cmdq1) +static enum cmd_retval +cmd_source_file_done(struct cmd_q *cmdq, __unused void *data) { - struct cmd_q *cmdq = cmdq1->data; - - 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); + cfg_print_causes(cmdq); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-split-window.c b/cmd-split-window.c index 41a53c63..ec2ea8cc 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -188,8 +188,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) fs.w = w; fs.wp = new_wp; cmd_find_log_state(__func__, &fs); - if (hooks_wait(s->hooks, cmdq, &fs, "after-split-window") == 0) - return (CMD_RETURN_WAIT); + hooks_insert(s->hooks, cmdq, &fs, "after-split-window"); + return (CMD_RETURN_NORMAL); error: diff --git a/cmd-wait-for.c b/cmd-wait-for.c index fb2fb699..505e4d63 100644 --- a/cmd-wait-for.c +++ b/cmd-wait-for.c @@ -41,13 +41,18 @@ const struct cmd_entry cmd_wait_for_entry = { .exec = cmd_wait_for_exec }; +struct wait_item { + struct cmd_q *cmdq; + TAILQ_ENTRY(wait_item) entry; +}; + struct wait_channel { const char *name; int locked; int woken; - TAILQ_HEAD(, cmd_q) waiters; - TAILQ_HEAD(, cmd_q) lockers; + TAILQ_HEAD(, wait_item) waiters; + TAILQ_HEAD(, wait_item) lockers; 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, struct wait_channel *wc) { - struct cmd_q *wq, *wq1; + struct wait_item *wi, *wi1; if (wc == NULL) 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); - TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) { - TAILQ_REMOVE(&wc->waiters, wq, waitentry); - if (!cmdq_free(wq)) - cmdq_continue(wq); + TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) { + wi->cmdq->flags &= ~CMD_Q_WAITING; + + TAILQ_REMOVE(&wc->waiters, wi, entry); + free(wi); } 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 -cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, - struct wait_channel *wc) +cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, struct wait_channel *wc) { - struct client *c = cmdq->client; + struct client *c = cmdq->client; + struct wait_item *wi; if (c == NULL || c->session != NULL) { 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); - TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry); - cmdq->references++; + wi = xcalloc(1, sizeof *wi); + wi->cmdq = cmdq; + TAILQ_INSERT_TAIL(&wc->waiters, wi, entry); return (CMD_RETURN_WAIT); } static enum cmd_retval -cmd_wait_for_lock(struct cmd_q *cmdq, const char *name, - struct wait_channel *wc) +cmd_wait_for_lock(struct cmd_q *cmdq, const char *name, struct wait_channel *wc) { + struct wait_item *wi; + if (cmdq->client == NULL || cmdq->client->session != NULL) { cmdq_error(cmdq, "not able to lock"); 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); if (wc->locked) { - TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry); - cmdq->references++; + wi = xcalloc(1, sizeof *wi); + wi->cmdq = cmdq; + TAILQ_INSERT_TAIL(&wc->lockers, wi, entry); return (CMD_RETURN_WAIT); } wc->locked = 1; @@ -210,17 +219,17 @@ static enum cmd_retval cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name, struct wait_channel *wc) { - struct cmd_q *wq; + struct wait_item *wi; if (wc == NULL || !wc->locked) { cmdq_error(cmdq, "channel %s not locked", name); return (CMD_RETURN_ERROR); } - if ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) { - TAILQ_REMOVE(&wc->lockers, wq, waitentry); - if (!cmdq_free(wq)) - cmdq_continue(wq); + if ((wi = TAILQ_FIRST(&wc->lockers)) != NULL) { + wi->cmdq->flags &= ~CMD_Q_WAITING; + TAILQ_REMOVE(&wc->lockers, wi, entry); + free(wi); } else { wc->locked = 0; cmd_wait_for_remove(wc); @@ -233,19 +242,19 @@ void cmd_wait_for_flush(void) { struct wait_channel *wc, *wc1; - struct cmd_q *wq, *wq1; + struct wait_item *wi, *wi1; RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) { - TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) { - TAILQ_REMOVE(&wc->waiters, wq, waitentry); - if (!cmdq_free(wq)) - cmdq_continue(wq); + TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) { + wi->cmdq->flags &= ~CMD_Q_WAITING; + TAILQ_REMOVE(&wc->waiters, wi, entry); + free(wi); } wc->woken = 1; - TAILQ_FOREACH_SAFE(wq, &wc->lockers, waitentry, wq1) { - TAILQ_REMOVE(&wc->lockers, wq, waitentry); - if (!cmdq_free(wq)) - cmdq_continue(wq); + TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) { + wi->cmdq->flags &= ~CMD_Q_WAITING; + TAILQ_REMOVE(&wc->lockers, wi, entry); + free(wi); } wc->locked = 0; cmd_wait_for_remove(wc); diff --git a/cmd.c b/cmd.c index 7964f654..9c37b849 100644 --- a/cmd.c +++ b/cmd.c @@ -390,12 +390,11 @@ usage: static int 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; struct cmd_find_state *fs = NULL; - struct cmd_find_state *current = NULL; - struct cmd_find_state tmp; + struct cmd_find_state current; if (flag == CMD_NONE || flag == CMD_CLIENT || @@ -449,21 +448,12 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, default: fatalx("unknown %cflag %d", c, flag); } - log_debug("%s: flag %c %d %#x", __func__, c, flag, targetflags); - if (parent != NULL) { - if (c == 't') - current = &parent->state.tflag; - else if (c == 's') - current = &parent->state.sflag; - } - 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)) + + error = cmd_find_current(¤t, cmdq, targetflags); + if (error != 0 && ~targetflags & CMD_FIND_QUIET) + return (-1); + if (!cmd_find_empty_state(¤t) && !cmd_find_valid_state(¤t)) fatalx("invalid current state"); switch (flag) { @@ -475,13 +465,13 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, case CMD_SESSION_CANFAIL: case CMD_SESSION_PREFERUNATTACHED: case CMD_SESSION_WITHPANE: - error = cmd_find_target(fs, current, cmdq, target, + error = cmd_find_target(fs, ¤t, cmdq, target, CMD_FIND_SESSION, targetflags); if (error != 0 && ~targetflags & CMD_FIND_QUIET) return (-1); break; case CMD_MOVEW_R: - error = cmd_find_target(fs, current, cmdq, target, + error = cmd_find_target(fs, ¤t, cmdq, target, CMD_FIND_SESSION, CMD_FIND_QUIET); if (error == 0) break; @@ -490,7 +480,7 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, case CMD_WINDOW_CANFAIL: case CMD_WINDOW_MARKED: case CMD_WINDOW_INDEX: - error = cmd_find_target(fs, current, cmdq, target, + error = cmd_find_target(fs, ¤t, cmdq, target, CMD_FIND_WINDOW, targetflags); if (error != 0 && ~targetflags & CMD_FIND_QUIET) return (-1); @@ -498,7 +488,7 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, case CMD_PANE: case CMD_PANE_CANFAIL: case CMD_PANE_MARKED: - error = cmd_find_target(fs, current, cmdq, target, + error = cmd_find_target(fs, ¤t, cmdq, target, CMD_FIND_PANE, targetflags); if (error != 0 && ~targetflags & CMD_FIND_QUIET) return (-1); @@ -510,14 +500,14 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, } 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; - struct cmd_state *state = &cmdq->state; - char *tmp; - enum cmd_entry_flag flag; - const char *s; - int error; + const struct cmd_entry *entry = cmd->entry; + struct cmd_state *state = &cmdq->state; + char *tmp; + enum cmd_entry_flag flag; + const char *s; + int error; tmp = cmd_print(cmd); log_debug("preparing state for %s (client %p)", tmp, cmdq->client); @@ -546,18 +536,19 @@ cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq, struct cmd_q *parent) state->c = cmd_find_client(cmdq, s, 1); break; } + log_debug("using client %p", state->c); s = args_get(cmd->args, 't'); 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) return (error); s = args_get(cmd->args, '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) return (error); diff --git a/control.c b/control.c index f6dedca8..cd605f4f 100644 --- a/control.c +++ b/control.c @@ -49,6 +49,21 @@ control_write_buffer(struct client *c, struct evbuffer *buffer) 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. */ void 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; struct cmd_list *cmdlist; struct cmd *cmd; + struct cmd_q *cmdq; if (closed) 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) { - c->cmdq->time = time(NULL); - c->cmdq->number++; - - cmdq_guard(c->cmdq, "begin", 1); - control_write(c, "parse error: %s", cause); - cmdq_guard(c->cmdq, "error", 1); - - free(cause); + cmdq = cmdq_get_callback(control_error, cause); + cmdq_append(c, cmdq); } else { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) 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); } diff --git a/format.c b/format.c index ed6f2cab..f9128f01 100644 --- a/format.c +++ b/format.c @@ -473,7 +473,6 @@ struct format_tree * format_create(struct cmd_q *cmdq, int flags) { struct format_tree *ft; - struct cmd *cmd; if (!event_initialized(&format_job_event)) { evtimer_set(&format_job_event, format_job_timer, NULL); @@ -491,11 +490,9 @@ format_create(struct cmd_q *cmdq, int flags) format_add_tv(ft, "start_time", &start_time); if (cmdq != NULL && cmdq->cmd != NULL) - format_add(ft, "command_name", "%s", cmdq->cmd->entry->name); - if (cmdq != NULL && cmdq->parent != NULL) { - cmd = cmdq->parent->cmd; - format_add(ft, "command_hooked", "%s", cmd->entry->name); - } + format_add(ft, "command", "%s", cmdq->cmd->entry->name); + if (cmdq != NULL && cmdq->hook != NULL) + format_add(ft, "hook", "%s", cmdq->hook); return (ft); } diff --git a/hooks.c b/hooks.c index 2e0126b7..cdd2cf45 100644 --- a/hooks.c +++ b/hooks.c @@ -33,7 +33,6 @@ RB_GENERATE_STATIC(hooks_tree, hook, entry, hooks_cmp); static struct hook *hooks_find1(struct hooks *, const char *); static void hooks_free1(struct hooks *, struct hook *); -static void hooks_emptyfn(struct cmd_q *); static int hooks_cmp(struct hook *hook1, struct hook *hook2) @@ -140,28 +139,14 @@ hooks_find(struct hooks *hooks, const char *name) return (hook); } -static 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 +void hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs, const char *fmt, ...) { struct hook *hook; - struct cmd_q *hooks_cmdq; va_list ap; char *name; + struct cmd_q *new_cmdq, *loop; va_start(ap, fmt); 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); if (hook == NULL) { free(name); - return (-1); + return; } 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); - hooks_cmdq = cmdq_new(c); - 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); + cmdq_append(c, new_cmdq); } -int -hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs, +void +hooks_insert(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs, const char *fmt, ...) { struct hook *hook; - struct cmd_q *hooks_cmdq; va_list ap; char *name; + struct cmd_q *new_cmdq, *loop; if (cmdq->flags & CMD_Q_NOHOOKS) - return (-1); + return; va_start(ap, fmt); 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); if (hook == NULL) { free(name); - return (-1); + return; } 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); - 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) - cmdq->references++; - cmdq_run(hooks_cmdq, hook->cmdlist, NULL); - return (0); + cmdq_insert_after(cmdq, new_cmdq); + else + cmdq_append(NULL, new_cmdq); } diff --git a/key-bindings.c b/key-bindings.c index b464c199..af53720c 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -377,18 +377,22 @@ key_bindings_init(void) struct cmd_list *cmdlist; char *cause; int error; - struct cmd_q *cmdq; - cmdq = cmdq_new(NULL); for (i = 0; i < nitems(defaults); i++) { error = cmd_string_parse(defaults[i], &cmdlist, "", i, &cause); if (error != 0) fatalx("bad default key"); - cmdq_run(cmdq, cmdlist, NULL); + cmdq_append(NULL, cmdq_get_command(cmdlist, NULL, NULL, 0)); 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 @@ -403,10 +407,8 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c, if (!(cmd->entry->flags & CMD_READONLY)) readonly = 0; } - if (!readonly && (c->flags & CLIENT_READONLY)) { - cmdq_error(c->cmdq, "client is read-only"); - return; - } - - cmdq_run(c->cmdq, bd->cmdlist, m); + if (!readonly && (c->flags & CLIENT_READONLY)) + cmdq_append(c, cmdq_get_callback(key_bindings_read_only, NULL)); + else + cmdq_append(c, cmdq_get_command(bd->cmdlist, NULL, m, 0)); } diff --git a/notify.c b/notify.c index 416b81f6..a75b3182 100644 --- a/notify.c +++ b/notify.c @@ -66,7 +66,7 @@ notify_hook(struct notify_entry *ne) const char *name; struct cmd_find_state fs; struct hook *hook; - struct cmd_q *hooks_cmdq; + struct cmd_q *new_cmdq, *loop; name = notify_hooks[ne->type]; if (name == NULL) @@ -87,14 +87,12 @@ notify_hook(struct notify_entry *ne) return; log_debug("notify hook %s", name); - hooks_cmdq = cmdq_new(NULL); - hooks_cmdq->flags |= CMD_Q_NOHOOKS; + new_cmdq = cmdq_get_command(hook->cmdlist, &fs, NULL, CMD_Q_NOHOOKS); - cmd_find_copy_state(&hooks_cmdq->current, &fs); - hooks_cmdq->parent = NULL; + for (loop = new_cmdq; loop != NULL; loop = loop->next) + loop->hook = xstrdup(name); - cmdq_run(hooks_cmdq, hook->cmdlist, NULL); - cmdq_free(hooks_cmdq); + cmdq_append(NULL, new_cmdq); } static void diff --git a/server-client.c b/server-client.c index 7e4d1ee4..7ad87cd1 100644 --- a/server-client.c +++ b/server-client.c @@ -126,8 +126,7 @@ server_client_create(int fd) c->fd = -1; c->cwd = NULL; - c->cmdq = cmdq_new(c); - c->cmdq->client_exit = 1; + TAILQ_INIT(&c->queue); c->stdin_data = evbuffer_new(); c->stdout_data = evbuffer_new(); @@ -244,10 +243,6 @@ server_client_lost(struct client *c) free(c->prompt_string); free(c->prompt_buffer); - c->cmdq->flags |= CMD_Q_DEAD; - cmdq_free(c->cmdq); - c->cmdq = NULL; - environ_free(c->environ); proc_remove_peer(c->peer); @@ -281,6 +276,9 @@ server_client_free(__unused int fd, __unused short events, void *arg) log_debug("free client %p (%d references)", c, c->references); + if (!TAILQ_EMPTY(&c->queue)) + fatalx("queue not empty"); + if (c->references == 0) free(c); } @@ -1254,6 +1252,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. */ static void server_client_dispatch_command(struct client *c, struct imsg *imsg) @@ -1276,7 +1297,7 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) argc = data.argc; if (cmd_unpack_argv(buf, len, argc, &argv) != 0) { - cmdq_error(c->cmdq, "command too long"); + cause = xstrdup("command too long"); goto error; } @@ -1287,20 +1308,19 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) } if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) { - cmdq_error(c->cmdq, "%s", cause); cmd_free_argv(argc, argv); goto error; } cmd_free_argv(argc, argv); - if (c != cfg_client || cfg_finished) - cmdq_run(c->cmdq, cmdlist, NULL); - else - cmdq_append(c->cmdq, cmdlist, NULL); + cmdq_append(c, cmdq_get_command(cmdlist, NULL, NULL, 0)); + cmdq_append(c, cmdq_get_callback(server_client_command_done, NULL)); cmd_list_free(cmdlist); return; error: + cmdq_append(c, cmdq_get_callback(server_client_command_error, cause)); + if (cmdlist != NULL) cmd_list_free(cmdlist); diff --git a/server.c b/server.c index e6d1c09f..15fd5546 100644 --- a/server.c +++ b/server.c @@ -190,9 +190,17 @@ static int server_loop(void) { 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(); - notify_drain(); if (!options_get_number(global_options, "exit-unattached")) { if (!RB_EMPTY(&sessions)) diff --git a/tmux.1 b/tmux.1 index a07b5e6c..88697bcf 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3456,8 +3456,7 @@ The following variables are available, where appropriate: .It Li "client_tty" Ta "" Ta "Pseudo terminal of client" .It Li "client_utf8" Ta "" Ta "1 if client supports utf8" .It Li "client_width" Ta "" Ta "Width of client" -.It Li "command_hooked" Ta "" Ta "Name of command hooked, if any" -.It Li "command_name" Ta "" Ta "Name of command in use, if any" +.It Li "command" 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_alias" Ta "" Ta "Command alias if listing commands" .It Li "command_list_usage" Ta "" Ta "Command usage if listing commands" @@ -3467,6 +3466,7 @@ The following variables are available, where appropriate: .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_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_short" Ta "#h" Ta "Hostname of local host (no domain name)" .It Li "insert_flag" Ta "" Ta "Pane insert flag" diff --git a/tmux.h b/tmux.h index bbb345b3..b5e5d96c 100644 --- a/tmux.h +++ b/tmux.h @@ -40,6 +40,8 @@ extern char **environ; struct args; struct client; +struct cmd_q; +struct cmd_q_list; struct environ; struct input_ctx; struct mode_key_cmdstr; @@ -631,7 +633,6 @@ struct grid { struct hook { const char *name; - struct cmd_q *cmdq; struct cmd_list *cmdlist; RB_ENTRY(hook) entry; @@ -1160,101 +1161,6 @@ struct message_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. */ struct args_entry; RB_HEAD(args_tree, args_entry); @@ -1324,42 +1230,46 @@ enum cmd_retval { CMD_RETURN_STOP }; -/* Command queue entry. */ -struct cmd_q_item { - struct cmd_list *cmdlist; - - struct mouse_event mouse; - - TAILQ_ENTRY(cmd_q_item) qentry; +/* Command queue item type. */ +enum cmd_q_type { + CMD_Q_COMMAND, + CMD_Q_CALLBACK, }; -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 { - int references; - int flags; -#define CMD_Q_DEAD 0x1 -#define CMD_Q_NOHOOKS 0x2 + struct cmd_q_list *queue; + struct cmd_q *next; struct client *client; - int client_exit; - struct cmd_q_items queue; - struct cmd_q_item *item; + enum cmd_q_type type; + 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_q *parent; + + cmd_q_cb cb; + void *data; struct cmd_find_state current; struct cmd_state state; - time_t time; - u_int number; + struct mouse_event mouse; - void (*emptyfn)(struct cmd_q *); - void *data; - - TAILQ_ENTRY(cmd_q) waitentry; + TAILQ_ENTRY(cmd_q) entry; }; +TAILQ_HEAD(cmd_q_list, cmd_q); /* Command -c, -t or -s flags. */ enum cmd_entry_flag { @@ -1409,6 +1319,101 @@ struct cmd_entry { 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. */ struct key_binding { key_code key; @@ -1504,10 +1509,9 @@ void proc_kill_peer(struct tmuxpeer *); /* cfg.c */ extern int cfg_finished; -extern int cfg_references; extern struct client *cfg_client; 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 printflike(1, 2) cfg_add_cause(const char *, ...); void cfg_print_causes(struct cmd_q *); @@ -1557,9 +1561,9 @@ void hooks_add(struct hooks *, const char *, struct cmd_list *); void hooks_copy(struct hooks *, struct hooks *); void hooks_remove(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 *, ...); -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 *, ...); /* mode-key.c */ @@ -1755,8 +1759,7 @@ char **cmd_copy_argv(int, char **); void cmd_free_argv(int, char **); char *cmd_stringify_argv(int, char **); struct cmd *cmd_parse(int, char **, const char *, u_int, char **); -int cmd_prepare_state(struct cmd *, struct cmd_q *, - struct cmd_q *); +int cmd_prepare_state(struct cmd *, struct cmd_q *); char *cmd_print(struct cmd *); int cmd_mouse_at(struct window_pane *, struct mouse_event *, u_int *, u_int *, int); @@ -1776,16 +1779,15 @@ void cmd_list_free(struct cmd_list *); char *cmd_list_print(struct cmd_list *); /* cmd-queue.c */ -struct cmd_q *cmdq_new(struct client *); -int cmdq_free(struct cmd_q *); +struct cmd_q *cmdq_get_command(struct cmd_list *, struct cmd_find_state *, + 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_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 */ int cmd_string_parse(const char *, struct cmd_list **, const char *, diff --git a/window-choose.c b/window-choose.c index 25dc77d1..b7720e8d 100644 --- a/window-choose.c +++ b/window-choose.c @@ -246,6 +246,7 @@ window_choose_data_run(struct window_choose_data *cdata) { struct cmd_list *cmdlist; char *cause; + struct cmd_q *cmdq; /* * 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; } - 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); }