mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Add hooks infrastructure, basic commands (set-hook, show-hooks) and a
couple of not very useful client hooks. This will eventually let commands be run at various points and on notifications. Joint work with Thomas Adam.
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							@@ -56,6 +56,7 @@ SRCS=	alerts.c \
 | 
				
			|||||||
	cmd-send-keys.c \
 | 
						cmd-send-keys.c \
 | 
				
			||||||
	cmd-set-buffer.c \
 | 
						cmd-set-buffer.c \
 | 
				
			||||||
	cmd-set-environment.c \
 | 
						cmd-set-environment.c \
 | 
				
			||||||
 | 
						cmd-set-hook.c \
 | 
				
			||||||
	cmd-set-option.c \
 | 
						cmd-set-option.c \
 | 
				
			||||||
	cmd-show-environment.c \
 | 
						cmd-show-environment.c \
 | 
				
			||||||
	cmd-show-messages.c \
 | 
						cmd-show-messages.c \
 | 
				
			||||||
@@ -78,6 +79,7 @@ SRCS=	alerts.c \
 | 
				
			|||||||
	format.c \
 | 
						format.c \
 | 
				
			||||||
	grid-view.c \
 | 
						grid-view.c \
 | 
				
			||||||
	grid.c \
 | 
						grid.c \
 | 
				
			||||||
 | 
						hooks.c \
 | 
				
			||||||
	input-keys.c \
 | 
						input-keys.c \
 | 
				
			||||||
	input.c \
 | 
						input.c \
 | 
				
			||||||
	job.c \
 | 
						job.c \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,7 +108,7 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
 | 
				
			|||||||
			TAILQ_FOREACH(c_loop, &clients, entry) {
 | 
								TAILQ_FOREACH(c_loop, &clients, entry) {
 | 
				
			||||||
				if (c_loop->session != s || c == c_loop)
 | 
									if (c_loop->session != s || c == c_loop)
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				proc_send_s(c_loop->peer, MSG_DETACH, s->name);
 | 
									server_client_detach(c, MSG_DETACH);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -139,7 +139,7 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
 | 
				
			|||||||
			TAILQ_FOREACH(c_loop, &clients, entry) {
 | 
								TAILQ_FOREACH(c_loop, &clients, entry) {
 | 
				
			||||||
				if (c_loop->session != s || c == c_loop)
 | 
									if (c_loop->session != s || c == c_loop)
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				proc_send_s(c_loop->peer, MSG_DETACH, s->name);
 | 
									server_client_detach(c_loop, MSG_DETACH);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -159,6 +159,7 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		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, "client-attached", c);
 | 
				
			||||||
		cmdq->client_exit = 0;
 | 
							cmdq->client_exit = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	recalculate_sizes();
 | 
						recalculate_sizes();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,9 +72,8 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
				
			|||||||
			return (CMD_RETURN_ERROR);
 | 
								return (CMD_RETURN_ERROR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		TAILQ_FOREACH(cloop, &clients, entry) {
 | 
							TAILQ_FOREACH(cloop, &clients, entry) {
 | 
				
			||||||
			if (cloop->session != s)
 | 
								if (cloop->session == s)
 | 
				
			||||||
				continue;
 | 
									server_client_detach(cloop, msgtype);
 | 
				
			||||||
			proc_send_s(cloop->peer, msgtype, cloop->session->name);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return (CMD_RETURN_STOP);
 | 
							return (CMD_RETURN_STOP);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -85,13 +84,12 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (args_has(args, 'a')) {
 | 
						if (args_has(args, 'a')) {
 | 
				
			||||||
		TAILQ_FOREACH(cloop, &clients, entry) {
 | 
							TAILQ_FOREACH(cloop, &clients, entry) {
 | 
				
			||||||
			if (cloop->session == NULL || cloop == c)
 | 
								if (cloop->session != NULL && cloop != c)
 | 
				
			||||||
				continue;
 | 
									server_client_detach(cloop, msgtype);
 | 
				
			||||||
			proc_send_s(cloop->peer, msgtype, cloop->session->name);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return (CMD_RETURN_NORMAL);
 | 
							return (CMD_RETURN_NORMAL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	proc_send_s(c->peer, msgtype, c->session->name);
 | 
						server_client_detach(c, msgtype);
 | 
				
			||||||
	return (CMD_RETURN_STOP);
 | 
						return (CMD_RETURN_STOP);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										116
									
								
								cmd-set-hook.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								cmd-set-hook.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
				
			|||||||
 | 
					/* $OpenBSD$ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
 | 
				
			||||||
 | 
					 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 | 
				
			||||||
 | 
					 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "tmux.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Set or show global or session hooks.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmd_q *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct cmd_entry cmd_set_hook_entry = {
 | 
				
			||||||
 | 
						"set-hook", NULL,
 | 
				
			||||||
 | 
						"gt:u", 1, 2,
 | 
				
			||||||
 | 
						"[-gu] " CMD_TARGET_SESSION_USAGE " hook-name [command]",
 | 
				
			||||||
 | 
						0,
 | 
				
			||||||
 | 
						cmd_set_hook_exec
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct cmd_entry cmd_show_hooks_entry = {
 | 
				
			||||||
 | 
						"show-hooks", NULL,
 | 
				
			||||||
 | 
						"gt:", 0, 1,
 | 
				
			||||||
 | 
						"[-g] " CMD_TARGET_SESSION_USAGE,
 | 
				
			||||||
 | 
						0,
 | 
				
			||||||
 | 
						cmd_set_hook_exec
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum cmd_retval
 | 
				
			||||||
 | 
					cmd_set_hook_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct args	*args = self->args;
 | 
				
			||||||
 | 
						struct session	*s;
 | 
				
			||||||
 | 
						struct cmd_list	*cmdlist;
 | 
				
			||||||
 | 
						struct hooks	*hooks;
 | 
				
			||||||
 | 
						struct hook	*hook;
 | 
				
			||||||
 | 
						char		*cause, *tmp;
 | 
				
			||||||
 | 
						const char	*name, *cmd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (args_has(args, 'g'))
 | 
				
			||||||
 | 
							hooks = global_hooks;
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							s = cmd_find_session(cmdq, args_get(args, 't'), 0);
 | 
				
			||||||
 | 
							if (s == NULL)
 | 
				
			||||||
 | 
								return (CMD_RETURN_ERROR);
 | 
				
			||||||
 | 
							hooks = s->hooks;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (self->entry == &cmd_show_hooks_entry) {
 | 
				
			||||||
 | 
							hook = hooks_first(hooks);
 | 
				
			||||||
 | 
							while (hook != NULL) {
 | 
				
			||||||
 | 
								tmp = cmd_list_print(hook->cmdlist);
 | 
				
			||||||
 | 
								cmdq_print(cmdq, "%s -> %s", hook->name, tmp);
 | 
				
			||||||
 | 
								free(tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								hook = hooks_next(hook);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return (CMD_RETURN_NORMAL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						name = args->argv[0];
 | 
				
			||||||
 | 
						if (*name == '\0') {
 | 
				
			||||||
 | 
							cmdq_error(cmdq, "invalid hook name");
 | 
				
			||||||
 | 
							return (CMD_RETURN_ERROR);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (args->argc < 2)
 | 
				
			||||||
 | 
							cmd = NULL;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							cmd = args->argv[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (args_has(args, 'u')) {
 | 
				
			||||||
 | 
							if (cmd != NULL) {
 | 
				
			||||||
 | 
								cmdq_error(cmdq, "command passed to unset hook: %s",
 | 
				
			||||||
 | 
								    name);
 | 
				
			||||||
 | 
								return (CMD_RETURN_ERROR);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ((hook = hooks_find(hooks, name)) != NULL)
 | 
				
			||||||
 | 
								hooks_remove(hooks, hook);
 | 
				
			||||||
 | 
							return (CMD_RETURN_NORMAL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cmd == NULL) {
 | 
				
			||||||
 | 
							cmdq_error(cmdq, "no command to set hook: %s", name);
 | 
				
			||||||
 | 
							return (CMD_RETURN_ERROR);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
 | 
				
			||||||
 | 
							if (cause != NULL) {
 | 
				
			||||||
 | 
								cmdq_error(cmdq, "%s", cause);
 | 
				
			||||||
 | 
								free(cause);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return (CMD_RETURN_ERROR);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						hooks_add(hooks, name, cmdlist);
 | 
				
			||||||
 | 
						cmd_list_free(cmdlist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (CMD_RETURN_NORMAL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										4
									
								
								cmd.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								cmd.c
									
									
									
									
									
								
							@@ -96,10 +96,12 @@ extern const struct cmd_entry cmd_send_prefix_entry;
 | 
				
			|||||||
extern const struct cmd_entry cmd_server_info_entry;
 | 
					extern const struct cmd_entry cmd_server_info_entry;
 | 
				
			||||||
extern const struct cmd_entry cmd_set_buffer_entry;
 | 
					extern const struct cmd_entry cmd_set_buffer_entry;
 | 
				
			||||||
extern const struct cmd_entry cmd_set_environment_entry;
 | 
					extern const struct cmd_entry cmd_set_environment_entry;
 | 
				
			||||||
 | 
					extern const struct cmd_entry cmd_set_hook_entry;
 | 
				
			||||||
extern const struct cmd_entry cmd_set_option_entry;
 | 
					extern const struct cmd_entry cmd_set_option_entry;
 | 
				
			||||||
extern const struct cmd_entry cmd_set_window_option_entry;
 | 
					extern const struct cmd_entry cmd_set_window_option_entry;
 | 
				
			||||||
extern const struct cmd_entry cmd_show_buffer_entry;
 | 
					extern const struct cmd_entry cmd_show_buffer_entry;
 | 
				
			||||||
extern const struct cmd_entry cmd_show_environment_entry;
 | 
					extern const struct cmd_entry cmd_show_environment_entry;
 | 
				
			||||||
 | 
					extern const struct cmd_entry cmd_show_hooks_entry;
 | 
				
			||||||
extern const struct cmd_entry cmd_show_messages_entry;
 | 
					extern const struct cmd_entry cmd_show_messages_entry;
 | 
				
			||||||
extern const struct cmd_entry cmd_show_options_entry;
 | 
					extern const struct cmd_entry cmd_show_options_entry;
 | 
				
			||||||
extern const struct cmd_entry cmd_show_window_options_entry;
 | 
					extern const struct cmd_entry cmd_show_window_options_entry;
 | 
				
			||||||
@@ -183,10 +185,12 @@ const struct cmd_entry *cmd_table[] = {
 | 
				
			|||||||
	&cmd_server_info_entry,
 | 
						&cmd_server_info_entry,
 | 
				
			||||||
	&cmd_set_buffer_entry,
 | 
						&cmd_set_buffer_entry,
 | 
				
			||||||
	&cmd_set_environment_entry,
 | 
						&cmd_set_environment_entry,
 | 
				
			||||||
 | 
						&cmd_set_hook_entry,
 | 
				
			||||||
	&cmd_set_option_entry,
 | 
						&cmd_set_option_entry,
 | 
				
			||||||
	&cmd_set_window_option_entry,
 | 
						&cmd_set_window_option_entry,
 | 
				
			||||||
	&cmd_show_buffer_entry,
 | 
						&cmd_show_buffer_entry,
 | 
				
			||||||
	&cmd_show_environment_entry,
 | 
						&cmd_show_environment_entry,
 | 
				
			||||||
 | 
						&cmd_show_hooks_entry,
 | 
				
			||||||
	&cmd_show_messages_entry,
 | 
						&cmd_show_messages_entry,
 | 
				
			||||||
	&cmd_show_options_entry,
 | 
						&cmd_show_options_entry,
 | 
				
			||||||
	&cmd_show_window_options_entry,
 | 
						&cmd_show_window_options_entry,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										139
									
								
								hooks.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								hooks.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
				
			|||||||
 | 
					/* $OpenBSD$ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
 | 
				
			||||||
 | 
					 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 | 
				
			||||||
 | 
					 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "tmux.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hooks {
 | 
				
			||||||
 | 
						RB_HEAD(hooks_tree, hook) tree;
 | 
				
			||||||
 | 
						struct hooks	*parent;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int	hooks_cmp(struct hook *, struct hook *);
 | 
				
			||||||
 | 
					RB_PROTOTYPE(hooks_tree, hook, entry, hooks_cmp);
 | 
				
			||||||
 | 
					RB_GENERATE(hooks_tree, hook, entry, hooks_cmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hook	*hooks_find1(struct hooks *, const char *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					hooks_cmp(struct hook *hook1, struct hook *hook2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (strcmp(hook1->name, hook2->name));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hooks *
 | 
				
			||||||
 | 
					hooks_create(struct hooks *parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hooks	*hooks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hooks = xcalloc(1, sizeof *hooks);
 | 
				
			||||||
 | 
						RB_INIT(&hooks->tree);
 | 
				
			||||||
 | 
						hooks->parent = parent;
 | 
				
			||||||
 | 
						return (hooks);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					hooks_free(struct hooks *hooks)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hook	*hook, *hook1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RB_FOREACH_SAFE(hook, hooks_tree, &hooks->tree, hook1)
 | 
				
			||||||
 | 
							hooks_remove(hooks, hook);
 | 
				
			||||||
 | 
						free(hooks);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hook *
 | 
				
			||||||
 | 
					hooks_first(struct hooks *hooks)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (RB_MIN(hooks_tree, &hooks->tree));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hook *
 | 
				
			||||||
 | 
					hooks_next(struct hook *hook)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (RB_NEXT(hooks_tree, &hooks->tree, hook));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hook	*hook;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((hook = hooks_find1(hooks, name)) != NULL)
 | 
				
			||||||
 | 
							hooks_remove(hooks, hook);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hook = xcalloc(1, sizeof *hook);
 | 
				
			||||||
 | 
						hook->name = xstrdup(name);
 | 
				
			||||||
 | 
						hook->cmdlist = cmdlist;
 | 
				
			||||||
 | 
						hook->cmdlist->references++;
 | 
				
			||||||
 | 
						RB_INSERT(hooks_tree, &hooks->tree, hook);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					hooks_remove(struct hooks *hooks, struct hook *hook)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						RB_REMOVE(hooks_tree, &hooks->tree, hook);
 | 
				
			||||||
 | 
						cmd_list_free(hook->cmdlist);
 | 
				
			||||||
 | 
						free((char *) hook->name);
 | 
				
			||||||
 | 
						free(hook);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hook *
 | 
				
			||||||
 | 
					hooks_find1(struct hooks *hooks, const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hook	hook;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hook.name = name;
 | 
				
			||||||
 | 
						return (RB_FIND(hooks_tree, &hooks->tree, &hook));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hook *
 | 
				
			||||||
 | 
					hooks_find(struct hooks *hooks, const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hook	 hook0, *hook;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hook0.name = name;
 | 
				
			||||||
 | 
						hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
 | 
				
			||||||
 | 
						while (hook == NULL) {
 | 
				
			||||||
 | 
							hooks = hooks->parent;
 | 
				
			||||||
 | 
							if (hooks == NULL)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return (hook);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					hooks_run(struct hooks *hooks, const char *name, struct client *c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hook	*hook;
 | 
				
			||||||
 | 
						struct cmd_q	*cmdq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hook = hooks_find(hooks, name);
 | 
				
			||||||
 | 
						if (hook == NULL)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						log_debug("running hook %s", name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmdq = cmdq_new(c);
 | 
				
			||||||
 | 
						cmdq_run(cmdq, hook->cmdlist, NULL);
 | 
				
			||||||
 | 
						cmdq_free(cmdq);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -256,6 +256,19 @@ server_client_free(__unused int fd, __unused short events, void *arg)
 | 
				
			|||||||
		free(c);
 | 
							free(c);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Detach a client. */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					server_client_detach(struct client *c, enum msgtype msgtype)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct session	*s = c->session;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (s == NULL)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hooks_run(c->session->hooks, "client-detached", c);
 | 
				
			||||||
 | 
						proc_send_s(c->peer, msgtype, s->name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check for mouse keys. */
 | 
					/* Check for mouse keys. */
 | 
				
			||||||
key_code
 | 
					key_code
 | 
				
			||||||
server_client_check_mouse(struct client *c)
 | 
					server_client_check_mouse(struct client *c)
 | 
				
			||||||
@@ -995,6 +1008,8 @@ server_client_dispatch(struct imsg *imsg, void *arg)
 | 
				
			|||||||
			recalculate_sizes();
 | 
								recalculate_sizes();
 | 
				
			||||||
			server_redraw_client(c);
 | 
								server_redraw_client(c);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (c->session != NULL)
 | 
				
			||||||
 | 
								hooks_run(c->session->hooks, "client-resized", c);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MSG_EXITING:
 | 
						case MSG_EXITING:
 | 
				
			||||||
		if (datalen != 0)
 | 
							if (datalen != 0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -123,7 +123,9 @@ session_create(const char *name, int argc, char **argv, const char *path,
 | 
				
			|||||||
	s->environ = environ_create();
 | 
						s->environ = environ_create();
 | 
				
			||||||
	if (env != NULL)
 | 
						if (env != NULL)
 | 
				
			||||||
		environ_copy(env, s->environ);
 | 
							environ_copy(env, s->environ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s->options = options_create(global_s_options);
 | 
						s->options = options_create(global_s_options);
 | 
				
			||||||
 | 
						s->hooks = hooks_create(global_hooks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s->tio = NULL;
 | 
						s->tio = NULL;
 | 
				
			||||||
	if (tio != NULL) {
 | 
						if (tio != NULL) {
 | 
				
			||||||
@@ -189,7 +191,9 @@ session_free(__unused int fd, __unused short events, void *arg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (s->references == 0) {
 | 
						if (s->references == 0) {
 | 
				
			||||||
		environ_free(s->environ);
 | 
							environ_free(s->environ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		options_free(s->options);
 | 
							options_free(s->options);
 | 
				
			||||||
 | 
							hooks_free(s->hooks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		free(s->name);
 | 
							free(s->name);
 | 
				
			||||||
		free(s);
 | 
							free(s);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										46
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								tmux.1
									
									
									
									
									
								
							@@ -3193,6 +3193,52 @@ is used.
 | 
				
			|||||||
.Fl v
 | 
					.Fl v
 | 
				
			||||||
shows only the option value, not the name.
 | 
					shows only the option value, not the name.
 | 
				
			||||||
.El
 | 
					.El
 | 
				
			||||||
 | 
					.Sh HOOKS
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					allows commands to run on various triggers, called
 | 
				
			||||||
 | 
					.Em hooks .
 | 
				
			||||||
 | 
					Each hook has a
 | 
				
			||||||
 | 
					.Em name .
 | 
				
			||||||
 | 
					The following hooks are available:
 | 
				
			||||||
 | 
					.Bl -tag -width "XXXXXXXXXXXXXXXX"
 | 
				
			||||||
 | 
					.It client-attached
 | 
				
			||||||
 | 
					Run when a client is attached.
 | 
				
			||||||
 | 
					.It client-detached
 | 
				
			||||||
 | 
					Run when a client is detached
 | 
				
			||||||
 | 
					.It client-resized
 | 
				
			||||||
 | 
					Run when a client is resized.
 | 
				
			||||||
 | 
					.El
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					Hooks are managed with these commands:
 | 
				
			||||||
 | 
					.Bl -tag -width Ds
 | 
				
			||||||
 | 
					.It Xo Ic set-hook
 | 
				
			||||||
 | 
					.Op Fl g
 | 
				
			||||||
 | 
					.Op Fl t Ar target-session
 | 
				
			||||||
 | 
					.Ar hook-name
 | 
				
			||||||
 | 
					.Ar command
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Sets hook
 | 
				
			||||||
 | 
					.Ar hook-name
 | 
				
			||||||
 | 
					to
 | 
				
			||||||
 | 
					.Ar command .
 | 
				
			||||||
 | 
					If
 | 
				
			||||||
 | 
					.Fl g
 | 
				
			||||||
 | 
					is given,
 | 
				
			||||||
 | 
					.Em hook-name
 | 
				
			||||||
 | 
					is added to the global list of hooks, otherwise it is added to the session
 | 
				
			||||||
 | 
					hooks (for
 | 
				
			||||||
 | 
					.Ar target-session
 | 
				
			||||||
 | 
					with
 | 
				
			||||||
 | 
					.Fl t ) .
 | 
				
			||||||
 | 
					Like options, session hooks inherit from the global ones.
 | 
				
			||||||
 | 
					.It Xo Ic show-hooks
 | 
				
			||||||
 | 
					.Op Fl g
 | 
				
			||||||
 | 
					.Op Fl t Ar target-session
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Shows the global list of hooks with
 | 
				
			||||||
 | 
					.Fl g ,
 | 
				
			||||||
 | 
					otherwise the session hooks.
 | 
				
			||||||
 | 
					.Ed
 | 
				
			||||||
.Sh MOUSE SUPPORT
 | 
					.Sh MOUSE SUPPORT
 | 
				
			||||||
If the
 | 
					If the
 | 
				
			||||||
.Ic mouse
 | 
					.Ic mouse
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								tmux.c
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								tmux.c
									
									
									
									
									
								
							@@ -38,6 +38,7 @@ struct options	*global_options;	/* server options */
 | 
				
			|||||||
struct options	*global_s_options;	/* session options */
 | 
					struct options	*global_s_options;	/* session options */
 | 
				
			||||||
struct options	*global_w_options;	/* window options */
 | 
					struct options	*global_w_options;	/* window options */
 | 
				
			||||||
struct environ	*global_environ;
 | 
					struct environ	*global_environ;
 | 
				
			||||||
 | 
					struct hooks	*global_hooks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct timeval	 start_time;
 | 
					struct timeval	 start_time;
 | 
				
			||||||
const char	*socket_path;
 | 
					const char	*socket_path;
 | 
				
			||||||
@@ -269,6 +270,8 @@ main(int argc, char **argv)
 | 
				
			|||||||
			flags |= CLIENT_UTF8;
 | 
								flags |= CLIENT_UTF8;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						global_hooks = hooks_create(NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	global_environ = environ_create();
 | 
						global_environ = environ_create();
 | 
				
			||||||
	for (var = environ; *var != NULL; var++)
 | 
						for (var = environ; *var != NULL; var++)
 | 
				
			||||||
		environ_put(global_environ, *var);
 | 
							environ_put(global_environ, *var);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								tmux.h
									
									
									
									
									
								
							@@ -691,6 +691,14 @@ struct grid {
 | 
				
			|||||||
	struct grid_line	*linedata;
 | 
						struct grid_line	*linedata;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Hook data structures. */
 | 
				
			||||||
 | 
					struct hook {
 | 
				
			||||||
 | 
						const char      *name;
 | 
				
			||||||
 | 
						struct cmd_q    *cmdq;
 | 
				
			||||||
 | 
						struct cmd_list *cmdlist;
 | 
				
			||||||
 | 
						RB_ENTRY(hook)   entry;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Option data structures. */
 | 
					/* Option data structures. */
 | 
				
			||||||
struct options_entry {
 | 
					struct options_entry {
 | 
				
			||||||
	char		*name;
 | 
						char		*name;
 | 
				
			||||||
@@ -1011,6 +1019,7 @@ struct session {
 | 
				
			|||||||
	struct winlink_stack lastw;
 | 
						struct winlink_stack lastw;
 | 
				
			||||||
	struct winlinks	 windows;
 | 
						struct winlinks	 windows;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct hooks	*hooks;
 | 
				
			||||||
	struct options	*options;
 | 
						struct options	*options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SESSION_UNATTACHED 0x1	/* not attached to any clients */
 | 
					#define SESSION_UNATTACHED 0x1	/* not attached to any clients */
 | 
				
			||||||
@@ -1427,10 +1436,11 @@ struct options_table_entry {
 | 
				
			|||||||
#define CMD_BUFFER_USAGE "[-b buffer-name]"
 | 
					#define CMD_BUFFER_USAGE "[-b buffer-name]"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* tmux.c */
 | 
					/* tmux.c */
 | 
				
			||||||
extern struct options *global_options;
 | 
					extern struct hooks	*global_hooks;
 | 
				
			||||||
extern struct options *global_s_options;
 | 
					extern struct options	*global_options;
 | 
				
			||||||
extern struct options *global_w_options;
 | 
					extern struct options	*global_s_options;
 | 
				
			||||||
extern struct environ *global_environ;
 | 
					extern struct options	*global_w_options;
 | 
				
			||||||
 | 
					extern struct environ	*global_environ;
 | 
				
			||||||
extern struct timeval	 start_time;
 | 
					extern struct timeval	 start_time;
 | 
				
			||||||
extern const char	*socket_path;
 | 
					extern const char	*socket_path;
 | 
				
			||||||
const char	*getshell(void);
 | 
					const char	*getshell(void);
 | 
				
			||||||
@@ -1495,6 +1505,18 @@ void		 format_defaults_pane(struct format_tree *,
 | 
				
			|||||||
void		 format_defaults_paste_buffer(struct format_tree *,
 | 
					void		 format_defaults_paste_buffer(struct format_tree *,
 | 
				
			||||||
		     struct paste_buffer *);
 | 
							     struct paste_buffer *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* hooks.c */
 | 
				
			||||||
 | 
					struct hook;
 | 
				
			||||||
 | 
					struct hooks	*hooks_create(struct hooks *);
 | 
				
			||||||
 | 
					void		 hooks_free(struct hooks *);
 | 
				
			||||||
 | 
					struct hook	*hooks_first(struct hooks *);
 | 
				
			||||||
 | 
					struct hook	*hooks_next(struct hook *);
 | 
				
			||||||
 | 
					void		 hooks_add(struct hooks *, const char *, struct cmd_list *);
 | 
				
			||||||
 | 
					void		 hooks_copy(struct hooks *, struct hooks *);
 | 
				
			||||||
 | 
					void		 hooks_remove(struct hooks *, struct hook *);
 | 
				
			||||||
 | 
					struct hook	*hooks_find(struct hooks *, const char *);
 | 
				
			||||||
 | 
					void		 hooks_run(struct hooks *, const char *, struct client *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* mode-key.c */
 | 
					/* mode-key.c */
 | 
				
			||||||
extern const struct mode_key_table mode_key_tables[];
 | 
					extern const struct mode_key_table mode_key_tables[];
 | 
				
			||||||
extern struct mode_key_tree mode_key_tree_vi_edit;
 | 
					extern struct mode_key_tree mode_key_tree_vi_edit;
 | 
				
			||||||
@@ -1782,6 +1804,7 @@ void	 server_client_create(int);
 | 
				
			|||||||
int	 server_client_open(struct client *, char **);
 | 
					int	 server_client_open(struct client *, char **);
 | 
				
			||||||
void	 server_client_unref(struct client *);
 | 
					void	 server_client_unref(struct client *);
 | 
				
			||||||
void	 server_client_lost(struct client *);
 | 
					void	 server_client_lost(struct client *);
 | 
				
			||||||
 | 
					void	 server_client_detach(struct client *, enum msgtype);
 | 
				
			||||||
void	 server_client_loop(void);
 | 
					void	 server_client_loop(void);
 | 
				
			||||||
void	 server_client_push_stdout(struct client *);
 | 
					void	 server_client_push_stdout(struct client *);
 | 
				
			||||||
void	 server_client_push_stderr(struct client *);
 | 
					void	 server_client_push_stderr(struct client *);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user