diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 3b3f9e68..586863aa 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -144,7 +144,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, "client-attached", c); + hooks_run(c->session->hooks, c, "client-attached"); cmdq->client_exit = 0; } recalculate_sizes(); diff --git a/hooks.c b/hooks.c index 6f548d23..424faf0c 100644 --- a/hooks.c +++ b/hooks.c @@ -34,6 +34,7 @@ RB_GENERATE(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) @@ -132,18 +133,78 @@ hooks_find(struct hooks *hooks, const char *name) return (hook); } -void -hooks_run(struct hooks *hooks, const char *name, struct client *c) +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 +hooks_run(struct hooks *hooks, struct client *c, const char *fmt, ...) { struct hook *hook; - struct cmd_q *cmdq; + struct cmd_q *hooks_cmdq; + va_list ap; + char *name; + + va_start(ap, fmt); + xvasprintf(&name, fmt, ap); + va_end(ap); hook = hooks_find(hooks, name); - if (hook == NULL) - return; + if (hook == NULL) { + free(name); + return (-1); + } log_debug("running hook %s", name); + free(name); - cmdq = cmdq_new(c); - cmdq_run(cmdq, hook->cmdlist, NULL); - cmdq_free(cmdq); + hooks_cmdq = cmdq_new(c); + hooks_cmdq->flags |= CMD_Q_NOHOOKS; + hooks_cmdq->parent = NULL; + + cmdq_run(hooks_cmdq, hook->cmdlist, NULL); + cmdq_free(hooks_cmdq); + return (0); +} + +int +hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, const char *fmt, ...) +{ + struct hook *hook; + struct cmd_q *hooks_cmdq; + va_list ap; + char *name; + + va_start(ap, fmt); + xvasprintf(&name, fmt, ap); + va_end(ap); + + hook = hooks_find(hooks, name); + if (hook == NULL) { + free(name); + return (-1); + } + log_debug("running hook %s (parent %p)", name, cmdq); + free(name); + + hooks_cmdq = cmdq_new(cmdq->client); + hooks_cmdq->flags |= CMD_Q_NOHOOKS; + 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); } diff --git a/server-client.c b/server-client.c index c2b43f38..ec16340b 100644 --- a/server-client.c +++ b/server-client.c @@ -283,7 +283,7 @@ server_client_detach(struct client *c, enum msgtype msgtype) if (s == NULL) return; - hooks_run(c->session->hooks, "client-detached", c); + hooks_run(c->session->hooks, c, "client-detached"); proc_send_s(c->peer, msgtype, s->name); } @@ -1027,7 +1027,7 @@ server_client_dispatch(struct imsg *imsg, void *arg) server_redraw_client(c); } if (c->session != NULL) - hooks_run(c->session->hooks, "client-resized", c); + hooks_run(c->session->hooks, c, "client-resized"); break; case MSG_EXITING: if (datalen != 0) diff --git a/tmux.h b/tmux.h index 651990f0..2b1b29b0 100644 --- a/tmux.h +++ b/tmux.h @@ -1368,6 +1368,8 @@ struct cmd_q { int references; int flags; #define CMD_Q_DEAD 0x1 +#define CMD_Q_REENTRY 0x2 +#define CMD_Q_NOHOOKS 0x4 struct client *client; int client_exit; @@ -1375,6 +1377,7 @@ struct cmd_q { struct cmd_q_items queue; struct cmd_q_item *item; struct cmd *cmd; + struct cmd_q *parent; struct cmd_state state; @@ -1581,7 +1584,10 @@ 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 *); -void hooks_run(struct hooks *, const char *, struct client *); +int printflike(3, 4) hooks_run(struct hooks *, struct client *, const char *, + ...); +int printflike(3, 4) hooks_wait(struct hooks *, struct cmd_q *, const char *, + ...); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[];