Add some more events.

This commit is contained in:
Nicholas Marriott
2026-07-08 11:53:45 +01:00
parent fcf27f942c
commit 172801a40e
5 changed files with 220 additions and 50 deletions

View File

@@ -80,6 +80,69 @@ cmd_select_pane_redraw(struct window *w)
}
}
static enum cmd_retval
cmd_select_pane_marked_pane(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct event_payload *ep;
struct cmd_find_state fs;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp, *lwp = NULL, *mwp;
struct session *s = target->s;
if (args_has(args, 'm') && !window_pane_is_visible(wp))
return (CMD_RETURN_NORMAL);
if (server_check_marked())
lwp = marked_pane.wp;
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
server_clear_marked();
else
server_set_marked(s, wl, wp);
mwp = marked_pane.wp;
ep = event_payload_create();
if (mwp != NULL)
cmd_find_from_pane(&fs, mwp, 0);
else if (lwp != NULL)
cmd_find_from_pane(&fs, lwp, 0);
else
cmd_find_from_pane(&fs, wp, 0);
event_payload_set_target(ep, &fs);
if (mwp != NULL) {
event_payload_set_pane(ep, "pane", mwp);
event_payload_set_pane(ep, "new_pane", mwp);
event_payload_set_window(ep, "window", mwp->window);
} else if (lwp != NULL) {
event_payload_set_pane(ep, "pane", lwp);
event_payload_set_window(ep, "window", lwp->window);
} else {
event_payload_set_pane(ep, "pane", wp);
event_payload_set_window(ep, "window", wp->window);
}
if (lwp != NULL)
event_payload_set_pane(ep, "old_pane", lwp);
event_payload_set_int(ep, "marked", mwp != NULL);
events_fire("marked-pane-changed", ep);
if (lwp != NULL) {
lwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
server_redraw_window_borders(lwp->window);
server_status_window(lwp->window);
}
if (mwp != NULL) {
mwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
server_redraw_window_borders(mwp->window);
server_status_window(mwp->window);
}
if (window_pane_is_floating(wp)) {
window_redraw_active_switch(wp->window, wp);
window_set_active_pane(wp->window, wp, 1);
}
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{
@@ -93,7 +156,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct session *s = target->s;
struct window_pane *wp = target->wp, *activewp, *lastwp, *markedwp;
struct window_pane *wp = target->wp, *activewp, *lastwp;
struct options *oo = wp->options;
char *title;
const char *style;
@@ -136,38 +199,8 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'm') || args_has(args, 'M')) {
if (args_has(args, 'm') && !window_pane_is_visible(wp))
return (CMD_RETURN_NORMAL);
if (server_check_marked())
lastwp = marked_pane.wp;
else
lastwp = NULL;
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
server_clear_marked();
else
server_set_marked(s, wl, wp);
markedwp = marked_pane.wp;
if (lastwp != NULL) {
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
PANE_THEMECHANGED);
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
}
if (markedwp != NULL) {
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
PANE_THEMECHANGED);
server_redraw_window_borders(markedwp->window);
server_status_window(markedwp->window);
}
if (window_pane_is_floating(wp)) {
window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'm') || args_has(args, 'M'))
return (cmd_select_pane_marked_pane(self, item));
style = args_get(args, 'P');
if (style != NULL) {

View File

@@ -1932,11 +1932,18 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_HOOK("client-light-theme", ""),
OPTIONS_TABLE_HOOK("client-dark-theme", ""),
OPTIONS_TABLE_HOOK("command-error", ""),
OPTIONS_TABLE_HOOK("marked-pane-changed", ""),
OPTIONS_TABLE_PANE_HOOK("pane-created", ""),
OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
OPTIONS_TABLE_PANE_HOOK("pane-focus-in", ""),
OPTIONS_TABLE_PANE_HOOK("pane-focus-out", ""),
OPTIONS_TABLE_PANE_HOOK("pane-mode-changed", ""),
OPTIONS_TABLE_PANE_HOOK("pane-mode-entered", ""),
OPTIONS_TABLE_PANE_HOOK("pane-mode-exited", ""),
OPTIONS_TABLE_PANE_HOOK("pane-prompt-closed", ""),
OPTIONS_TABLE_PANE_HOOK("pane-prompt-opened", ""),
OPTIONS_TABLE_PANE_HOOK("pane-resized", ""),
OPTIONS_TABLE_PANE_HOOK("pane-set-clipboard", ""),
OPTIONS_TABLE_PANE_HOOK("pane-title-changed", ""),
OPTIONS_TABLE_HOOK("session-closed", ""),
@@ -1948,6 +1955,8 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_WINDOW_HOOK("window-pane-changed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-renamed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-resized", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-unzoomed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-zoomed", ""),
OPTIONS_TABLE_HOOK("window-unlinked", ""),
{ .name = NULL }

41
spawn.c
View File

@@ -71,6 +71,45 @@ spawn_log(const char *from, struct spawn_context *sc)
log_debug("%s: s=$%u %s idx=%d", from, s->id, tmp, sc->idx);
}
static void
spawn_fire_pane_created(struct spawn_context *sc, struct window_pane *wp)
{
struct event_payload *ep;
struct cmd_find_state fs;
char *cmd = NULL;
const char *cwd = wp->cwd;
ep = event_payload_create();
cmd_find_from_winlink_pane(&fs, sc->wl, wp, 0);
event_payload_set_target(ep, &fs);
event_payload_set_session(ep, "session", sc->s);
event_payload_set_window(ep, "window", wp->window);
event_payload_set_int(ep, "window_index", sc->wl->idx);
event_payload_set_pane(ep, "pane", wp);
if (wp->argc != 0)
cmd = cmd_stringify_argv(wp->argc, wp->argv);
if (cmd != NULL && *cmd != '\0')
event_payload_set_string(ep, "pane_command", "%s", cmd);
else if (wp->shell != NULL)
event_payload_set_string(ep, "pane_command", "%s", wp->shell);
free(cmd);
if (cwd != NULL)
event_payload_set_string(ep, "pane_current_path", "%s", cwd);
if (sc->flags & SPAWN_EMPTY)
event_payload_set_int(ep, "created_empty", 1);
else
event_payload_set_int(ep, "created_empty", 0);
if (sc->flags & SPAWN_RESPAWN)
event_payload_set_int(ep, "created_respawn", 1);
else
event_payload_set_int(ep, "created_respawn", 0);
events_fire("pane-created", ep);
}
struct winlink *
spawn_window(struct spawn_context *sc, char **cause)
{
@@ -519,8 +558,8 @@ complete:
sigprocmask(SIG_SETMASK, &oldset, NULL);
window_pane_set_event(new_wp);
environ_free(child);
spawn_fire_pane_created(sc, new_wp);
if (sc->flags & SPAWN_RESPAWN)
return (new_wp);

18
tmux.1
View File

@@ -6361,6 +6361,10 @@ Run when a client switches to a light theme.
Run when a client switches to a dark theme.
.It command\-error
Run when a command fails.
.It marked\-pane\-changed
Run when the marked pane is set or cleared.
.It pane\-created
Run when a pane is created or respawned.
.It pane\-died
Run when the program running in a pane exits, but
.Ic remain\-on\-exit
@@ -6375,6 +6379,16 @@ option is on.
Run when the focus exits a pane, if the
.Ic focus\-events
option is on.
.It pane\-mode\-entered
Run when a pane enters a mode.
.It pane\-mode\-exited
Run when a pane exits a mode.
.It pane\-prompt\-closed
Run when a prompt in a pane is closed.
.It pane\-prompt\-opened
Run when a prompt is opened in a pane.
.It pane\-resized
Run when a pane is resized.
.It pane\-set\-clipboard
Run when the terminal clipboard is set using the
.Xr xterm 1
@@ -6396,6 +6410,10 @@ Run when a window is resized.
This may be after the
.Ar client\-resized
hook is run.
.It window\-unzoomed
Run when a window is unzoomed.
.It window\-zoomed
Run when a window is zoomed.
.It window\-unlinked
Run when a window is unlinked from a session.
.El

103
window.c
View File

@@ -73,11 +73,8 @@ static struct window_pane *window_pane_create(struct window *, u_int, u_int,
static void window_pane_destroy(struct window_pane *);
static void window_pane_free(struct window_pane *);
static void window_pane_scrollbar_timer(int, short, void *);
static void window_pane_full_size_offset(struct window_pane *wp,
int *xoff, int *yoff, u_int *sx, u_int *sy);
static void window_fire_renamed(struct window *, const char *);
static void window_fire_pane_changed(struct window *, struct window_pane *,
struct window_pane *);
static void window_pane_full_size_offset(struct window_pane *, int *, int *,
u_int *, u_int *);
RB_GENERATE(windows, window, entry, window_cmp);
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
@@ -89,6 +86,7 @@ struct window_pane_prompt {
status_prompt_input_cb inputcb;
prompt_free_cb freecb;
void *data;
enum prompt_type type;
};
int
@@ -130,6 +128,45 @@ window_fire_pane_changed(struct window *w, struct window_pane *wp,
events_fire("window-pane-changed", ep);
}
static void
window_fire_pane_mode_changed(const char *name, struct window_pane *wp,
const char *previous, const char *current, int entered)
{
struct event_payload *ep;
struct cmd_find_state fs;
ep = event_payload_create();
cmd_find_from_pane(&fs, wp, 0);
event_payload_set_target(ep, &fs);
event_payload_set_pane(ep, "pane", wp);
event_payload_set_window(ep, "window", wp->window);
if (current != NULL)
event_payload_set_string(ep, "current_mode", "%s", current);
if (previous != NULL)
event_payload_set_string(ep, "previous_mode", "%s", previous);
event_payload_set_int(ep, "mode_entered", entered);
events_fire(name, ep);
}
static void
window_fire_pane_prompt(const char *name, struct window_pane *wp,
enum prompt_type type)
{
struct event_payload *ep;
struct cmd_find_state fs;
const char *type_string = prompt_type_string(type);
ep = event_payload_create();
cmd_find_from_pane(&fs, wp, 0);
event_payload_set_target(ep, &fs);
event_payload_set_pane(ep, "pane", wp);
event_payload_set_window(ep, "window", wp->window);
event_payload_set_string(ep, "prompt_type", "%s", type_string);
events_fire(name, ep);
}
int
winlink_cmp(struct winlink *wl1, struct winlink *wl2)
{
@@ -830,6 +867,7 @@ window_zoom(struct window_pane *wp)
w->saved_layout_root = w->layout_root;
layout_init(w, wp);
w->flags |= WINDOW_ZOOMED;
events_fire_window("window-zoomed", w);
events_fire_window("window-layout-changed", w);
redraw_invalidate_scene(w);
@@ -856,8 +894,10 @@ window_unzoom(struct window *w, int notify)
}
layout_fix_panes(w, NULL);
if (notify)
if (notify) {
events_fire_window("window-unzoomed", w);
events_fire_window("window-layout-changed", w);
}
redraw_invalidate_scene(w);
return (0);
@@ -1401,6 +1441,8 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_mode_entry *wme;
struct window_pane_resize *r;
struct event_payload *ep;
struct cmd_find_state fs;
if (sx == wp->sx && sy == wp->sy)
return;
@@ -1423,6 +1465,17 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->resize != NULL)
wme->mode->resize(wme, sx, sy);
ep = event_payload_create();
cmd_find_from_pane(&fs, wp, 0);
event_payload_set_target(ep, &fs);
event_payload_set_pane(ep, "pane", wp);
event_payload_set_window(ep, "window", wp->window);
event_payload_set_uint(ep, "width", sx);
event_payload_set_uint(ep, "height", sy);
event_payload_set_uint(ep, "old_width", r->osx);
event_payload_set_uint(ep, "old_height", r->osy);
events_fire("pane-resized", ep);
}
int
@@ -1432,9 +1485,13 @@ window_pane_set_mode(struct window_pane *wp, struct window_pane *swp,
{
struct window_mode_entry *wme;
struct window *w = wp->window;
const char *name = mode->name, *p = NULL;
if (!TAILQ_EMPTY(&wp->modes) && TAILQ_FIRST(&wp->modes)->mode == mode)
return (1);
if (!TAILQ_EMPTY(&wp->modes)) {
if (TAILQ_FIRST(&wp->modes)->mode == mode)
return (1);
p = TAILQ_FIRST(&wp->modes)->mode->name;
}
TAILQ_FOREACH(wme, &wp->modes, entry) {
if (wme->mode == mode)
@@ -1460,7 +1517,9 @@ window_pane_set_mode(struct window_pane *wp, struct window_pane *swp,
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
events_fire_pane("pane-mode-changed", wp);
window_fire_pane_mode_changed("pane-mode-entered", wp, p, name, 1);
window_fire_pane_mode_changed("pane-mode-changed", wp, p, name, 1);
return (0);
}
@@ -1471,11 +1530,13 @@ window_pane_reset_mode(struct window_pane *wp)
struct window_mode_entry *wme, *next;
struct window *w = wp->window;
int kill;
const char *name, *p;
if (TAILQ_EMPTY(&wp->modes))
return;
wme = TAILQ_FIRST(&wp->modes);
p = wme->mode->name;
kill = wme->kill;
TAILQ_REMOVE(&wp->modes, wme, entry);
wme->mode->free(wme);
@@ -1492,13 +1553,16 @@ window_pane_reset_mode(struct window_pane *wp)
if (next->mode->resize != NULL)
next->mode->resize(next, wp->sx, wp->sy);
}
name = (next == NULL ? NULL : next->mode->name);
wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR|PANE_CHANGED);
layout_fix_panes(w, NULL);
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
events_fire_pane("pane-mode-changed", wp);
window_fire_pane_mode_changed("pane-mode-exited", wp, p, name, 0);
window_fire_pane_mode_changed("pane-mode-changed", wp, p, name, 0);
if (kill)
server_kill_pane(wp);
@@ -1561,6 +1625,7 @@ window_pane_set_prompt(struct window_pane *wp, struct client *c,
wpp->inputcb = inputcb;
wpp->freecb = freecb;
wpp->data = data;
wpp->type = type;
memset(&pd, 0, sizeof pd);
prompt_set_options(&pd, s);
@@ -1578,19 +1643,25 @@ window_pane_set_prompt(struct window_pane *wp, struct client *c,
wp->flags |= PANE_REDRAW;
prompt_incremental_start(wp->prompt);
window_fire_pane_prompt("pane-prompt-opened", wp, type);
}
/* Close a pane prompt. */
void
window_pane_clear_prompt(struct window_pane *wp)
{
struct prompt *prompt = wp->prompt;
struct prompt *prompt = wp->prompt;
struct window_pane_prompt *wpp = wp->prompt_data;
enum prompt_type type = PROMPT_TYPE_INVALID;
if (prompt == NULL)
return;
wp->prompt = NULL;
prompt_free(prompt);
wp->flags |= PANE_REDRAW;
if (prompt != NULL) {
if (wpp != NULL)
type = wpp->type;
wp->prompt = NULL;
prompt_free(prompt);
wp->flags |= PANE_REDRAW;
window_fire_pane_prompt("pane-prompt-closed", wp, type);
}
}
/* Does this pane have an open prompt? */