mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Add infrastructure to work out the best target given a pane or window
alone and use it to add pane_died and pane_exited hooks.
This commit is contained in:
		@@ -144,7 +144,7 @@ cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (~c->flags & CLIENT_CONTROL)
 | 
							if (~c->flags & CLIENT_CONTROL)
 | 
				
			||||||
			proc_send(c->peer, MSG_READY, -1, NULL, 0);
 | 
								proc_send(c->peer, MSG_READY, -1, NULL, 0);
 | 
				
			||||||
		hooks_run(c->session->hooks, c, "client-attached");
 | 
							hooks_run(c->session->hooks, c, NULL, "client-attached");
 | 
				
			||||||
		cmdq->client_exit = 0;
 | 
							cmdq->client_exit = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	recalculate_sizes();
 | 
						recalculate_sizes();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										53
									
								
								cmd-find.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								cmd-find.c
									
									
									
									
									
								
							@@ -190,7 +190,7 @@ cmd_find_best_session_with_window(struct cmd_find_state *fs)
 | 
				
			|||||||
	u_int		  ssize;
 | 
						u_int		  ssize;
 | 
				
			||||||
	struct session	 *s;
 | 
						struct session	 *s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fs->cmdq->client != NULL) {
 | 
						if (fs->cmdq != NULL && fs->cmdq->client != NULL) {
 | 
				
			||||||
		fs->s = cmd_find_try_TMUX(fs->cmdq->client, fs->w);
 | 
							fs->s = cmd_find_try_TMUX(fs->cmdq->client, fs->w);
 | 
				
			||||||
		if (fs->s != NULL)
 | 
							if (fs->s != NULL)
 | 
				
			||||||
			return (cmd_find_best_winlink_with_window(fs));
 | 
								return (cmd_find_best_winlink_with_window(fs));
 | 
				
			||||||
@@ -254,7 +254,7 @@ cmd_find_current_session_with_client(struct cmd_find_state *fs)
 | 
				
			|||||||
	 * sessions to those containing that pane (we still use the current
 | 
						 * sessions to those containing that pane (we still use the current
 | 
				
			||||||
	 * window in the best session).
 | 
						 * window in the best session).
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (fs->cmdq->client->tty.path != NULL) {
 | 
						if (fs->cmdq != NULL && fs->cmdq->client->tty.path != NULL) {
 | 
				
			||||||
		RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
 | 
							RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
 | 
				
			||||||
			if (strcmp(wp->tty, fs->cmdq->client->tty.path) == 0)
 | 
								if (strcmp(wp->tty, fs->cmdq->client->tty.path) == 0)
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
@@ -289,7 +289,9 @@ cmd_find_current_session_with_client(struct cmd_find_state *fs)
 | 
				
			|||||||
	return (0);
 | 
						return (0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unknown_pane:
 | 
					unknown_pane:
 | 
				
			||||||
	fs->s = cmd_find_try_TMUX(fs->cmdq->client, NULL);
 | 
						fs->s = NULL;
 | 
				
			||||||
 | 
						if (fs->cmdq != NULL)
 | 
				
			||||||
 | 
							fs->s = cmd_find_try_TMUX(fs->cmdq->client, NULL);
 | 
				
			||||||
	if (fs->s == NULL)
 | 
						if (fs->s == NULL)
 | 
				
			||||||
		fs->s = cmd_find_best_session(NULL, 0, fs->flags);
 | 
							fs->s = cmd_find_best_session(NULL, 0, fs->flags);
 | 
				
			||||||
	if (fs->s == NULL)
 | 
						if (fs->s == NULL)
 | 
				
			||||||
@@ -310,7 +312,7 @@ int
 | 
				
			|||||||
cmd_find_current_session(struct cmd_find_state *fs)
 | 
					cmd_find_current_session(struct cmd_find_state *fs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* If we know the current client, use it. */
 | 
						/* If we know the current client, use it. */
 | 
				
			||||||
	if (fs->cmdq->client != NULL) {
 | 
						if (fs->cmdq != NULL && fs->cmdq->client != NULL) {
 | 
				
			||||||
		log_debug("%s: have client %p%s", __func__, fs->cmdq->client,
 | 
							log_debug("%s: have client %p%s", __func__, fs->cmdq->client,
 | 
				
			||||||
		    fs->cmdq->client->session == NULL ? "" : " (with session)");
 | 
							    fs->cmdq->client->session == NULL ? "" : " (with session)");
 | 
				
			||||||
		if (fs->cmdq->client->session == NULL)
 | 
							if (fs->cmdq->client->session == NULL)
 | 
				
			||||||
@@ -862,6 +864,49 @@ cmd_find_log_state(const char *prefix, struct cmd_find_state *fs)
 | 
				
			|||||||
		log_debug("%s: idx=none", prefix);
 | 
							log_debug("%s: idx=none", prefix);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Find state from a session. */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					cmd_find_from_session(struct cmd_find_state *fs, struct session *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cmd_find_clear_state(fs, NULL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fs->s = s;
 | 
				
			||||||
 | 
						fs->wl = fs->s->curw;
 | 
				
			||||||
 | 
						fs->w = fs->wl->window;
 | 
				
			||||||
 | 
						fs->wp = fs->w->active;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd_find_log_state(__func__, fs);
 | 
				
			||||||
 | 
						return (0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Find state from a window. */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					cmd_find_from_window(struct cmd_find_state *fs, struct window *w)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cmd_find_clear_state(fs, NULL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fs->w = w;
 | 
				
			||||||
 | 
						if (cmd_find_best_session_with_window(fs) != 0)
 | 
				
			||||||
 | 
							return (-1);
 | 
				
			||||||
 | 
						if (cmd_find_best_winlink_with_window(fs) != 0)
 | 
				
			||||||
 | 
							return (-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd_find_log_state(__func__, fs);
 | 
				
			||||||
 | 
						return (0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Find state from a pane. */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (cmd_find_from_window(fs, wp->window) != 0)
 | 
				
			||||||
 | 
							return (-1);
 | 
				
			||||||
 | 
						fs->wp = wp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd_find_log_state(__func__, fs);
 | 
				
			||||||
 | 
						return (0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Split target into pieces and resolve for the given type. Fills in the given
 | 
					 * Split target into pieces and resolve for the given type. Fills in the given
 | 
				
			||||||
 * state. Returns 0 on success or -1 on error.
 | 
					 * state. Returns 0 on success or -1 on error.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,9 @@ cmdq_new(struct client *c)
 | 
				
			|||||||
	cmdq->item = NULL;
 | 
						cmdq->item = NULL;
 | 
				
			||||||
	cmdq->cmd = NULL;
 | 
						cmdq->cmd = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd_find_clear_state(&cmdq->current, NULL, 0);
 | 
				
			||||||
 | 
						cmdq->parent = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (cmdq);
 | 
						return (cmdq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -286,3 +289,4 @@ cmdq_flush(struct cmd_q *cmdq)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	cmdq->item = NULL;
 | 
						cmdq->item = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,7 +90,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
				
			|||||||
		cmdq_error(cmdq, "respawn window failed: %s", cause);
 | 
							cmdq_error(cmdq, "respawn window failed: %s", cause);
 | 
				
			||||||
		free(cause);
 | 
							free(cause);
 | 
				
			||||||
		environ_free(env);
 | 
							environ_free(env);
 | 
				
			||||||
		server_destroy_pane(wp);
 | 
							server_destroy_pane(wp, 0);
 | 
				
			||||||
		return (CMD_RETURN_ERROR);
 | 
							return (CMD_RETURN_ERROR);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	layout_init(w, wp);
 | 
						layout_init(w, wp);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								hooks.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								hooks.c
									
									
									
									
									
								
							@@ -42,6 +42,14 @@ hooks_cmp(struct hook *hook1, struct hook *hook2)
 | 
				
			|||||||
	return (strcmp(hook1->name, hook2->name));
 | 
						return (strcmp(hook1->name, hook2->name));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hooks *
 | 
				
			||||||
 | 
					hooks_get(struct session *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (s != NULL)
 | 
				
			||||||
 | 
							return (s->hooks);
 | 
				
			||||||
 | 
						return (global_hooks);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct hooks *
 | 
					struct hooks *
 | 
				
			||||||
hooks_create(struct hooks *parent)
 | 
					hooks_create(struct hooks *parent)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -148,7 +156,8 @@ hooks_emptyfn(struct cmd_q *hooks_cmdq)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
hooks_run(struct hooks *hooks, struct client *c, const char *fmt, ...)
 | 
					hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs,
 | 
				
			||||||
 | 
					    const char *fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hook	*hook;
 | 
						struct hook	*hook;
 | 
				
			||||||
	struct cmd_q	*hooks_cmdq;
 | 
						struct cmd_q	*hooks_cmdq;
 | 
				
			||||||
@@ -169,6 +178,9 @@ hooks_run(struct hooks *hooks, struct client *c, const char *fmt, ...)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	hooks_cmdq = cmdq_new(c);
 | 
						hooks_cmdq = cmdq_new(c);
 | 
				
			||||||
	hooks_cmdq->flags |= CMD_Q_NOHOOKS;
 | 
						hooks_cmdq->flags |= CMD_Q_NOHOOKS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fs != NULL)
 | 
				
			||||||
 | 
							cmd_find_copy_state(&hooks_cmdq->current, fs);
 | 
				
			||||||
	hooks_cmdq->parent = NULL;
 | 
						hooks_cmdq->parent = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
 | 
						cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
 | 
				
			||||||
@@ -177,7 +189,8 @@ hooks_run(struct hooks *hooks, struct client *c, const char *fmt, ...)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, const char *fmt, ...)
 | 
					hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs,
 | 
				
			||||||
 | 
					    const char *fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hook	*hook;
 | 
						struct hook	*hook;
 | 
				
			||||||
	struct cmd_q	*hooks_cmdq;
 | 
						struct cmd_q	*hooks_cmdq;
 | 
				
			||||||
@@ -198,6 +211,9 @@ hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, const char *fmt, ...)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	hooks_cmdq = cmdq_new(cmdq->client);
 | 
						hooks_cmdq = cmdq_new(cmdq->client);
 | 
				
			||||||
	hooks_cmdq->flags |= CMD_Q_NOHOOKS;
 | 
						hooks_cmdq->flags |= CMD_Q_NOHOOKS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fs != NULL)
 | 
				
			||||||
 | 
							cmd_find_copy_state(&hooks_cmdq->current, fs);
 | 
				
			||||||
	hooks_cmdq->parent = cmdq;
 | 
						hooks_cmdq->parent = cmdq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hooks_cmdq->emptyfn = hooks_emptyfn;
 | 
						hooks_cmdq->emptyfn = hooks_emptyfn;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -283,7 +283,7 @@ server_client_detach(struct client *c, enum msgtype msgtype)
 | 
				
			|||||||
	if (s == NULL)
 | 
						if (s == NULL)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hooks_run(c->session->hooks, c, "client-detached");
 | 
						hooks_run(c->session->hooks, c, NULL, "client-detached");
 | 
				
			||||||
	proc_send_s(c->peer, msgtype, s->name);
 | 
						proc_send_s(c->peer, msgtype, s->name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1027,7 +1027,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
 | 
				
			|||||||
			server_redraw_client(c);
 | 
								server_redraw_client(c);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (c->session != NULL)
 | 
							if (c->session != NULL)
 | 
				
			||||||
			hooks_run(c->session->hooks, c, "client-resized");
 | 
								hooks_run(c->session->hooks, c, NULL, "client-resized");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MSG_EXITING:
 | 
						case MSG_EXITING:
 | 
				
			||||||
		if (datalen != 0)
 | 
							if (datalen != 0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -293,12 +293,13 @@ server_unlink_window(struct session *s, struct winlink *wl)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
server_destroy_pane(struct window_pane *wp)
 | 
					server_destroy_pane(struct window_pane *wp, int hooks)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct window		*w = wp->window;
 | 
						struct window		*w = wp->window;
 | 
				
			||||||
	int			 old_fd;
 | 
						int			 old_fd;
 | 
				
			||||||
	struct screen_write_ctx	 ctx;
 | 
						struct screen_write_ctx	 ctx;
 | 
				
			||||||
	struct grid_cell	 gc;
 | 
						struct grid_cell	 gc;
 | 
				
			||||||
 | 
						struct cmd_find_state	 fs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	old_fd = wp->fd;
 | 
						old_fd = wp->fd;
 | 
				
			||||||
	if (wp->fd != -1) {
 | 
						if (wp->fd != -1) {
 | 
				
			||||||
@@ -319,6 +320,9 @@ server_destroy_pane(struct window_pane *wp)
 | 
				
			|||||||
		screen_write_puts(&ctx, &gc, "Pane is dead");
 | 
							screen_write_puts(&ctx, &gc, "Pane is dead");
 | 
				
			||||||
		screen_write_stop(&ctx);
 | 
							screen_write_stop(&ctx);
 | 
				
			||||||
		wp->flags |= PANE_REDRAW;
 | 
							wp->flags |= PANE_REDRAW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (hooks && cmd_find_from_pane(&fs, wp) == 0)
 | 
				
			||||||
 | 
								hooks_run(hooks_get(fs.s), NULL, &fs, "pane-died");
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -326,6 +330,9 @@ server_destroy_pane(struct window_pane *wp)
 | 
				
			|||||||
	layout_close_pane(wp);
 | 
						layout_close_pane(wp);
 | 
				
			||||||
	window_remove_pane(w, wp);
 | 
						window_remove_pane(w, wp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (hooks && cmd_find_from_window(&fs, w) == 0)
 | 
				
			||||||
 | 
							hooks_run(hooks_get(fs.s), NULL, &fs, "pane-exited");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (TAILQ_EMPTY(&w->panes))
 | 
						if (TAILQ_EMPTY(&w->panes))
 | 
				
			||||||
		server_kill_window(w);
 | 
							server_kill_window(w);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								server.c
									
									
									
									
									
								
							@@ -387,7 +387,7 @@ server_child_exited(pid_t pid, int status)
 | 
				
			|||||||
		TAILQ_FOREACH(wp, &w->panes, entry) {
 | 
							TAILQ_FOREACH(wp, &w->panes, entry) {
 | 
				
			||||||
			if (wp->pid == pid) {
 | 
								if (wp->pid == pid) {
 | 
				
			||||||
				wp->status = status;
 | 
									wp->status = status;
 | 
				
			||||||
				server_destroy_pane(wp);
 | 
									server_destroy_pane(wp, 1);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								tmux.1
									
									
									
									
									
								
							@@ -3230,6 +3230,12 @@ Run when a client is attached.
 | 
				
			|||||||
Run when a client is detached
 | 
					Run when a client is detached
 | 
				
			||||||
.It client-resized
 | 
					.It client-resized
 | 
				
			||||||
Run when a client is resized.
 | 
					Run when a client is resized.
 | 
				
			||||||
 | 
					.It pane-died
 | 
				
			||||||
 | 
					Run when the program running in a pane exits, but
 | 
				
			||||||
 | 
					.Ic remain-on-exit
 | 
				
			||||||
 | 
					is on so the pane has not closed.
 | 
				
			||||||
 | 
					.It pane-exited
 | 
				
			||||||
 | 
					Run when the program running in a pane exits.
 | 
				
			||||||
.El
 | 
					.El
 | 
				
			||||||
.Pp
 | 
					.Pp
 | 
				
			||||||
Hooks are managed with these commands:
 | 
					Hooks are managed with these commands:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user