Revert "Add formats and events for OSC 133 commmands, as well as a -T flag to"

This reverts commit f3c6b4f1a3.
This commit is contained in:
Nicholas Marriott
2026-07-11 04:37:04 +01:00
parent 8f27092756
commit 6fd9987632
9 changed files with 93 additions and 1107 deletions

View File

@@ -31,8 +31,6 @@ static enum args_parse_type cmd_set_option_args_parse(struct args *,
u_int, char **); u_int, char **);
static enum cmd_retval cmd_set_option_exec(struct cmd *, static enum cmd_retval cmd_set_option_exec(struct cmd *,
struct cmdq_item *); struct cmdq_item *);
static enum cmd_retval cmd_set_hook_event_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_set_hook_monitor_exec(struct cmdq_item *, static enum cmd_retval cmd_set_hook_monitor_exec(struct cmdq_item *,
struct args *, int); struct args *, int);
@@ -66,8 +64,8 @@ const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook", .name = "set-hook",
.alias = NULL, .alias = NULL,
.args = { "agpERTt:uB:w", 0, 2, cmd_set_option_args_parse }, .args = { "agpRt:uB:w", 0, 2, cmd_set_option_args_parse },
.usage = "[-agpERTuw] [-B name:what:format] " CMD_TARGET_PANE_USAGE " " .usage = "[-agpRuw] [-B name:what:format] " CMD_TARGET_PANE_USAGE " "
"[hook] [command]", "[hook] [command]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -87,63 +85,17 @@ cmd_set_option_args_parse(struct args *args, u_int idx,
return (ARGS_PARSE_STRING); return (ARGS_PARSE_STRING);
} }
static enum cmd_retval
cmd_set_hook_event_exec(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 client *c;
char *argument;
if (args_count(args) == 0) {
cmdq_error(item, "missing argument");
return (CMD_RETURN_ERROR);
}
if (args_count(args) != 1) {
cmdq_error(item, "too many arguments");
return (CMD_RETURN_ERROR);
}
argument = format_single_from_target(item, args_string(args, 0));
if (*argument != '@') {
cmdq_error(item, "event name must start with @");
free(argument);
return (CMD_RETURN_ERROR);
}
ep = event_payload_create();
event_payload_set_target(ep, target);
c = cmdq_get_client(item);
if (c != NULL)
event_payload_set_client(ep, "client", c);
if (target->s != NULL)
event_payload_set_session(ep, "session", target->s);
if (target->w != NULL)
event_payload_set_window(ep, "window", target->w);
if (target->wl != NULL)
event_payload_set_int(ep, "window_index", target->wl->idx);
else if (target->idx != -1)
event_payload_set_int(ep, "window_index", target->idx);
if (target->wp != NULL)
event_payload_set_pane(ep, "pane", target->wp);
events_fire(argument, ep);
free(argument);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval static enum cmd_retval
cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window) cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
{ {
struct cmd_find_state *target = cmdq_get_target(item), fs; struct cmd_find_state *target = cmdq_get_target(item), fs;
struct options *oo; struct options *oo;
struct options_entry *o; struct options_entry *o;
struct session *s = NULL;
char *cause = NULL, *name = NULL, *format = NULL; char *cause = NULL, *name = NULL, *format = NULL;
char *expanded = NULL, *newvalue = NULL; char *expanded = NULL, *newvalue = NULL;
const char *value, *old; const char *value, *old;
enum monitor_type type; enum monitor_type type;
int id, scope, flags = 0; int id, scope;
if (args_count(args) > 1) { if (args_count(args) > 1) {
cmdq_error(item, "too many arguments"); cmdq_error(item, "too many arguments");
@@ -178,7 +130,7 @@ cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
cmd_find_copy_state(&fs, target); cmd_find_copy_state(&fs, target);
if (args_has(args, 'u')) { if (args_has(args, 'u')) {
hooks_monitor_remove(oo, name); notify_monitor_remove(oo, name);
goto out; goto out;
} }
@@ -200,13 +152,7 @@ cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
} }
} }
if (oo != global_options && notify_monitor_add(item, oo, name, type, id, format, &fs, target->s);
oo != global_s_options &&
oo != global_w_options)
s = target->s;
if (args_has(args, 'T'))
flags |= MONITOR_NOTIFY_TRUE;
hooks_monitor_add(item, oo, name, type, id, format, flags, &fs, s);
out: out:
free(newvalue); free(newvalue);
@@ -239,8 +185,6 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
int scope; int scope;
window = (cmd_get_entry(self) == &cmd_set_window_option_entry); window = (cmd_get_entry(self) == &cmd_set_window_option_entry);
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'E'))
return (cmd_set_hook_event_exec(self, item));
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'B')) if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'B'))
return (cmd_set_hook_monitor_exec(item, args, window)); return (cmd_set_hook_monitor_exec(item, args, window));
if (args_count(args) == 0) { if (args_count(args) == 0) {
@@ -253,7 +197,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
/* If set-hook -R, fire the hook straight away. */ /* If set-hook -R, fire the hook straight away. */
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) { if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) {
hooks_run(item, argument); notify_hook(item, argument);
free(argument); free(argument);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -345,8 +289,6 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
goto fail; goto fail;
} }
options_set_string(oo, name, append, "%s", value); options_set_string(oo, name, append, "%s", value);
if (cmd_get_entry(self) == &cmd_set_hook_entry)
hooks_add_event(name);
} else if (array_key == NULL && !options_is_array(parent)) { } else if (array_key == NULL && !options_is_array(parent)) {
error = options_from_string(oo, options_table_entry(parent), error = options_from_string(oo, options_table_entry(parent),
options_table_entry(parent)->name, value, options_table_entry(parent)->name, value,

121
format.c
View File

@@ -2187,106 +2187,6 @@ format_cb_pane_dead_time(struct format_tree *ft)
return (NULL); return (NULL);
} }
/* Callback for pane_last_output_time. */
static void *
format_cb_pane_last_output_time(struct format_tree *ft)
{
struct window_pane *wp = ft->wp;
static struct timeval tv;
if (wp != NULL && wp->last_output_time != 0) {
tv.tv_sec = wp->last_output_time;
tv.tv_usec = 0;
return (&tv);
}
return (NULL);
}
/* Callback for pane_last_prompt_time. */
static void *
format_cb_pane_last_prompt_time(struct format_tree *ft)
{
struct window_pane *wp = ft->wp;
static struct timeval tv;
if (wp != NULL && wp->last_prompt_time != 0) {
tv.tv_sec = wp->last_prompt_time;
tv.tv_usec = 0;
return (&tv);
}
return (NULL);
}
/* Callback for pane_command_start_time. */
static void *
format_cb_pane_command_start_time(struct format_tree *ft)
{
struct window_pane *wp = ft->wp;
static struct timeval tv;
if (wp != NULL && wp->cmd_start_time != 0) {
tv.tv_sec = wp->cmd_start_time;
tv.tv_usec = 0;
return (&tv);
}
return (NULL);
}
/* Callback for pane_command_end_time. */
static void *
format_cb_pane_command_end_time(struct format_tree *ft)
{
struct window_pane *wp = ft->wp;
static struct timeval tv;
if (wp != NULL && wp->cmd_end_time != 0) {
tv.tv_sec = wp->cmd_end_time;
tv.tv_usec = 0;
return (&tv);
}
return (NULL);
}
/* Callback for pane_command_running. */
static void *
format_cb_pane_command_running(struct format_tree *ft)
{
struct window_pane *wp = ft->wp;
if (wp != NULL)
return (format_printf("%d", !!(wp->flags & PANE_CMDRUNNING)));
return (NULL);
}
/* Callback for pane_command_duration. */
static void *
format_cb_pane_command_duration(struct format_tree *ft)
{
struct window_pane *wp = ft->wp;
time_t end;
if (wp == NULL || wp->cmd_start_time == 0)
return (NULL);
if (wp->flags & PANE_CMDRUNNING)
end = time(NULL);
else
end = wp->cmd_end_time;
if (end < wp->cmd_start_time)
end = wp->cmd_start_time;
return (format_printf("%lld", (long long)(end - wp->cmd_start_time)));
}
/* Callback for pane_command_status. */
static void *
format_cb_pane_command_status(struct format_tree *ft)
{
struct window_pane *wp = ft->wp;
if (wp != NULL && wp->cmd_status != -1)
return (format_printf("%d", wp->cmd_status));
return (NULL);
}
/* Callback for pane_format. */ /* Callback for pane_format. */
static void * static void *
format_cb_pane_format(struct format_tree *ft) format_cb_pane_format(struct format_tree *ft)
@@ -3603,21 +3503,6 @@ static const struct format_table_entry format_table[] = {
{ "pane_bottom", FORMAT_TABLE_STRING, { "pane_bottom", FORMAT_TABLE_STRING,
format_cb_pane_bottom format_cb_pane_bottom
}, },
{ "pane_command_duration", FORMAT_TABLE_STRING,
format_cb_pane_command_duration
},
{ "pane_command_end_time", FORMAT_TABLE_TIME,
format_cb_pane_command_end_time
},
{ "pane_command_running", FORMAT_TABLE_STRING,
format_cb_pane_command_running
},
{ "pane_command_start_time", FORMAT_TABLE_TIME,
format_cb_pane_command_start_time
},
{ "pane_command_status", FORMAT_TABLE_STRING,
format_cb_pane_command_status
},
{ "pane_current_command", FORMAT_TABLE_STRING, { "pane_current_command", FORMAT_TABLE_STRING,
format_cb_current_command format_cb_current_command
}, },
@@ -3669,12 +3554,6 @@ static const struct format_table_entry format_table[] = {
{ "pane_last", FORMAT_TABLE_STRING, { "pane_last", FORMAT_TABLE_STRING,
format_cb_pane_last format_cb_pane_last
}, },
{ "pane_last_output_time", FORMAT_TABLE_TIME,
format_cb_pane_last_output_time
},
{ "pane_last_prompt_time", FORMAT_TABLE_TIME,
format_cb_pane_last_prompt_time
},
{ "pane_left", FORMAT_TABLE_STRING, { "pane_left", FORMAT_TABLE_STRING,
format_cb_pane_left format_cb_pane_left
}, },

461
hooks.c
View File

@@ -1,461 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
* Copyright (c) 2012 George Nachman <tmux@georgester.com>
*
* 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"
/* Hook monitor state owned by an option entry. */
struct hook_monitor {
struct options *oo;
struct monitor_set *set;
struct events_sink *sink;
struct cmd_find_state fs;
enum monitor_type type;
int id;
char *format;
};
/* Hook command data built from an event payload. */
struct hooks_data {
const char *name;
struct cmd_find_state fs;
struct format_tree *formats;
struct options *oo;
struct client *client;
int expand;
};
/* Hook event sink registered for a notify event name. */
struct hooks_event {
char *name;
struct events_sink *sink;
TAILQ_ENTRY(hooks_event) entry;
};
TAILQ_HEAD(hooks_events, hooks_event);
static struct hooks_events hooks_events = TAILQ_HEAD_INITIALIZER(hooks_events);
/* Insert one hook command list. */
static struct cmdq_item *
hooks_insert_one(struct cmdq_item *item, struct hooks_data *hd,
struct cmd_list *cmdlist, struct cmdq_state *state)
{
struct cmdq_item *new_item;
char *s;
if (cmdlist == NULL)
return (item);
if (log_get_level() != 0) {
s = cmd_list_print(cmdlist, 0);
log_debug("%s: hook %s is: %s", __func__, hd->name, s);
free(s);
}
new_item = cmdq_get_command(cmdlist, state);
if (item != NULL)
return (cmdq_insert_after(item, new_item));
return (cmdq_append(NULL, new_item));
}
/* Parse a hook command. */
static struct cmd_parse_result *
hooks_parse(struct hooks_data *hd, struct cmd_find_state *fs,
const char *value)
{
struct cmd_parse_result *pr;
struct format_tree *ft;
char *expanded;
if (!hd->expand)
return (cmd_parse_from_string(value, NULL));
ft = format_create_defaults(NULL, hd->client, fs->s, fs->wl, fs->wp);
if (hd->formats != NULL)
format_merge(ft, hd->formats);
expanded = format_expand(ft, value);
format_free(ft);
pr = cmd_parse_from_string(expanded, NULL);
free(expanded);
return (pr);
}
/* Insert commands for a hook. */
static void
hooks_insert(struct cmdq_item *item, struct hooks_data *hd)
{
struct cmd_find_state fs;
struct options *oo;
struct cmdq_state *state;
struct options_entry *o;
struct options_array_item *a;
struct cmd_list *cmdlist;
const char *value;
struct cmd_parse_result *pr;
log_debug("%s: inserting hook %s", __func__, hd->name);
cmd_find_clear_state(&fs, 0);
if (cmd_find_empty_state(&hd->fs) || !cmd_find_valid_state(&hd->fs))
cmd_find_from_nothing(&fs, 0);
else
cmd_find_copy_state(&fs, &hd->fs);
if (hd->oo != NULL) {
oo = hd->oo;
o = options_get_only(oo, hd->name);
} else {
if (fs.s == NULL)
oo = global_s_options;
else
oo = fs.s->options;
o = options_get(oo, hd->name);
if (o == NULL && fs.wp != NULL) {
oo = fs.wp->options;
o = options_get(oo, hd->name);
}
if (o == NULL && fs.wl != NULL) {
oo = fs.wl->window->options;
o = options_get(oo, hd->name);
}
}
if (o == NULL) {
log_debug("%s: hook %s not found", __func__, hd->name);
return;
}
if (item == NULL)
state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS);
else {
state = cmdq_new_state(&fs, cmdq_get_event(item),
CMDQ_STATE_NOHOOKS);
}
cmdq_add_formats(state, hd->formats);
if (*hd->name == '@') {
value = options_get_string(oo, hd->name);
pr = hooks_parse(hd, &fs, value);
switch (pr->status) {
case CMD_PARSE_ERROR:
log_debug("%s: can't parse hook %s: %s", __func__,
hd->name, pr->error);
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
hooks_insert_one(item, hd, pr->cmdlist, state);
break;
}
} else {
a = options_array_first(o);
while (a != NULL) {
if (hd->expand) {
value = options_array_item_value(a)->string;
pr = hooks_parse(hd, &fs, value);
switch (pr->status) {
case CMD_PARSE_ERROR:
if (pr->error != NULL) {
cmdq_error(item, "%s",
pr->error);
}
break;
case CMD_PARSE_SUCCESS:
item = hooks_insert_one(item, hd,
pr->cmdlist, state);
break;
}
} else {
cmdlist = options_array_item_value(a)->cmdlist;
item = hooks_insert_one(item, hd, cmdlist,
state);
}
a = options_array_next(a);
}
}
cmdq_free_state(state);
}
/* Insert commands for a hook event. */
static void
hooks_insert_event(struct cmdq_item *item, const char *name,
struct event_payload *ep, struct options *oo, int expand)
{
struct hooks_data hd;
struct format_tree *ft;
struct client *c;
if (item != NULL && (cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
return;
c = event_payload_get_client(ep, "client");
ft = format_create(c, item, FORMAT_NONE, FORMAT_NOJOBS);
event_payload_add_formats(ep, ft, "hook_");
format_add(ft, "hook", "%s", name);
format_log_debug(ft, __func__);
memset(&hd, 0, sizeof hd);
hd.name = name;
cmd_find_clear_state(&hd.fs, 0);
event_payload_get_target(ep, &hd.fs);
hd.formats = ft;
hd.oo = oo;
hd.client = c;
hd.expand = expand;
hooks_insert(item, &hd);
format_free(ft);
}
/* Handle an event for hooks. */
static void
hooks_event_cb(const char *name, struct event_payload *ep,
__unused void *sink_data)
{
struct cmdq_item *item;
if (event_payload_get_pointer(ep, "_hook_monitor") != NULL)
return;
item = event_payload_get_pointer(ep, "_cmdq_item");
if (item != NULL) {
hooks_insert_event(item, name, ep, NULL, 0);
return;
}
item = cmdq_running(NULL);
if (item == NULL || (~cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
hooks_insert_event(NULL, name, ep, NULL, 0);
}
/* Add a hook event sink. */
void
hooks_add_event(const char *name)
{
struct hooks_event *he;
TAILQ_FOREACH(he, &hooks_events, entry) {
if (strcmp(he->name, name) == 0)
return;
}
he = xcalloc(1, sizeof *he);
he->name = xstrdup(name);
he->sink = events_add_sink(name, hooks_event_cb, NULL);
TAILQ_INSERT_TAIL(&hooks_events, he, entry);
}
/* Return if an event name can be fired through the hooks path. */
int
hooks_valid_event_name(const char *name)
{
const struct options_table_entry *oe;
if (*name == '@')
return (1);
oe = options_search(name);
return (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK));
}
/* Add hook event sinks for all built-in hooks. */
void
hooks_build_events(void)
{
const struct options_table_entry *oe;
for (oe = options_table; oe->name != NULL; oe++) {
if (oe->flags & OPTIONS_TABLE_IS_HOOK)
hooks_add_event(oe->name);
}
}
/* Run a hook immediately. */
void
hooks_run(struct cmdq_item *item, const char *name)
{
struct cmd_find_state *target = cmdq_get_target(item);
struct hooks_data hd = { 0 };
hd.name = name;
cmd_find_copy_state(&hd.fs, target);
hd.client = cmdq_get_client(item);
hd.formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
format_add(hd.formats, "hook", "%s", name);
format_log_debug(hd.formats, __func__);
hooks_insert(item, &hd);
format_free(hd.formats);
}
/* Free a hook monitor. */
void
hooks_monitor_free(void *data)
{
struct hook_monitor *hm = data;
events_remove_sink(hm->sink);
monitor_destroy(hm->set);
free(hm->format);
free(hm);
}
/* Remove a hook monitor. */
void
hooks_monitor_remove(struct options *oo, const char *name)
{
struct options_entry *o;
struct hook_monitor *hm;
o = options_get_only(oo, name);
if (o == NULL)
return;
hm = options_get_monitor_data(o);
if (hm != NULL) {
options_set_monitor_data(o, NULL);
hooks_monitor_free(hm);
}
}
/* Handle a hook monitor event. */
static void
hooks_monitor_hook_cb(const char *name, struct event_payload *ep,
void *sink_data)
{
struct hook_monitor *hm = sink_data;
if (event_payload_get_pointer(ep, "_hook_monitor") == hm)
hooks_insert_event(cmdq_running(NULL), name, ep, hm->oo, 1);
}
/* Fire a hook monitor event. */
static void
hooks_monitor_cb(struct monitor_change *change, void *data)
{
struct hook_monitor *hm = data;
struct event_payload *ep;
struct winlink *wl = change->wl;
struct window_pane *wp = change->wp;
struct cmd_find_state fs;
ep = event_payload_create();
event_payload_set_pointer(ep, "_hook_monitor", data, NULL, NULL);
cmd_find_clear_state(&fs, 0);
if (wl != NULL && wp != NULL && wp->window == wl->window)
cmd_find_from_winlink_pane(&fs, wl, wp, 0);
else if (wl != NULL)
cmd_find_from_winlink(&fs, wl, 0);
else if (wp != NULL)
cmd_find_from_pane(&fs, wp, 0);
else if (change->s != NULL)
cmd_find_from_session(&fs, change->s, 0);
else
cmd_find_copy_state(&fs, &hm->fs);
event_payload_set_target(ep, &fs);
if (change->value != NULL)
event_payload_set_string(ep, "value", "%s", change->value);
else
event_payload_set_string(ep, "value", "%s", "");
if (change->last != NULL)
event_payload_set_string(ep, "last", "%s", change->last);
else
event_payload_set_string(ep, "last", "%s", "");
if (change->c != NULL)
event_payload_set_client(ep, "client", change->c);
if (change->s != NULL)
event_payload_set_session(ep, "session", change->s);
if (wl != NULL) {
if (change->s == NULL)
event_payload_set_session(ep, "session",
wl->session);
event_payload_set_window(ep, "window", wl->window);
event_payload_set_int(ep, "window_index", wl->idx);
}
if (wp != NULL) {
event_payload_set_pane(ep, "pane", wp);
if (wl == NULL)
event_payload_set_window(ep, "window", wp->window);
}
events_fire(change->name, ep);
}
/* Add a hook monitor. */
void
hooks_monitor_add(__unused struct cmdq_item *item, struct options *oo,
const char *name, enum monitor_type type, int id, const char *format,
int flags, struct cmd_find_state *fs, struct session *s)
{
struct options_entry *o;
struct hook_monitor *hm;
hooks_monitor_remove(oo, name);
o = options_get_only(oo, name);
if (o == NULL)
o = options_set_string(oo, name, 0, "%s", "");
hm = xcalloc(1, sizeof *hm);
hm->oo = oo;
cmd_find_copy_state(&hm->fs, fs);
hm->type = type;
hm->id = id;
hm->format = xstrdup(format);
hm->set = monitor_create_session(s, hooks_monitor_cb, hm);
hm->sink = events_add_sink(name, hooks_monitor_hook_cb, hm);
options_set_monitor_data(o, hm);
monitor_add(hm->set, name, type, id, format, flags);
}
/* Convert a hook monitor to its value. */
char *
hooks_monitor_to_string(struct options_entry *o)
{
struct hook_monitor *hm = options_get_monitor_data(o);
const char *name = options_name(o);
char *s;
if (hm == NULL)
return (NULL);
switch (hm->type) {
case MONITOR_SESSION:
xasprintf(&s, "%s::%s", name, hm->format);
break;
case MONITOR_PANE:
xasprintf(&s, "%s:%%%d:%s", name, hm->id, hm->format);
break;
case MONITOR_ALL_PANES:
xasprintf(&s, "%s:%%*:%s", name, hm->format);
break;
case MONITOR_WINDOW:
xasprintf(&s, "%s:@%d:%s", name, hm->id, hm->format);
break;
case MONITOR_ALL_WINDOWS:
xasprintf(&s, "%s:@*:%s", name, hm->format);
break;
}
return (s);
}

110
input.c
View File

@@ -174,8 +174,6 @@ static void input_osc_110(struct input_ctx *, const char *);
static void input_osc_111(struct input_ctx *, const char *); static void input_osc_111(struct input_ctx *, const char *);
static void input_osc_112(struct input_ctx *, const char *); static void input_osc_112(struct input_ctx *, const char *);
static void input_osc_133(struct input_ctx *, const char *); static void input_osc_133(struct input_ctx *, const char *);
static void input_fire_pane_title_changed(struct window_pane *,
const char *);
/* Transition entry/exit handlers. */ /* Transition entry/exit handlers. */
static void input_clear(struct input_ctx *); static void input_clear(struct input_ctx *);
@@ -212,21 +210,6 @@ static int input_end_bel(struct input_ctx *);
/* Command table comparison function. */ /* Command table comparison function. */
static int input_table_compare(const void *, const void *); static int input_table_compare(const void *, const void *);
static void
input_fire_pane_title_changed(struct window_pane *wp, const char *title)
{
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);
event_payload_set_string(ep, "new_title", "%s", title);
events_fire("pane-title-changed", ep);
}
/* Command table entry. */ /* Command table entry. */
struct input_table_entry { struct input_table_entry {
int ch; int ch;
@@ -1034,8 +1017,6 @@ input_parse_pane(struct window_pane *wp)
size_t new_size; size_t new_size;
new_data = window_pane_get_new_data(wp, &wp->offset, &new_size); new_data = window_pane_get_new_data(wp, &wp->offset, &new_size);
if (new_size != 0)
wp->last_output_time = time(NULL);
input_parse_buffer(wp, new_data, new_size); input_parse_buffer(wp, new_data, new_size);
window_pane_update_used_data(wp, &wp->offset, new_size); window_pane_update_used_data(wp, &wp->offset, new_size);
} }
@@ -2199,7 +2180,7 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
screen_pop_title(sctx->s); screen_pop_title(sctx->s);
if (wp == NULL) if (wp == NULL)
break; break;
events_fire_pane("pane-title-changed", wp); notify_pane("pane-title-changed", wp);
server_redraw_window_borders(w); server_redraw_window_borders(w);
server_status_window(w); server_status_window(w);
break; break;
@@ -2719,7 +2700,7 @@ input_exit_osc(struct input_ctx *ictx)
if (wp != NULL && if (wp != NULL &&
options_get_number(wp->options, "allow-set-title") && options_get_number(wp->options, "allow-set-title") &&
screen_set_title(sctx->s, p, 1)) { screen_set_title(sctx->s, p, 1)) {
input_fire_pane_title_changed(wp, p); notify_pane("pane-title-changed", wp);
server_redraw_window_borders(wp->window); server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
} }
@@ -2797,7 +2778,7 @@ input_exit_apc(struct input_ctx *ictx)
if (wp != NULL && if (wp != NULL &&
options_get_number(wp->options, "allow-set-title") && options_get_number(wp->options, "allow-set-title") &&
screen_set_title(sctx->s, ictx->input_buf, 1)) { screen_set_title(sctx->s, ictx->input_buf, 1)) {
input_fire_pane_title_changed(wp, ictx->input_buf); notify_pane("pane-title-changed", wp);
server_redraw_window_borders(wp->window); server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
} }
@@ -3165,8 +3146,7 @@ input_osc_12(struct input_ctx *ictx, const char *p)
c = ictx->ctx.s->ccolour; c = ictx->ctx.s->ccolour;
if (c == -1) if (c == -1)
c = ictx->ctx.s->default_ccolour; c = ictx->ctx.s->default_ccolour;
input_osc_colour_reply(ictx, 1, 12, 0, c, input_osc_colour_reply(ictx, 1, 12, 0, c, ictx->input_end);
ictx->input_end);
} }
return; return;
} }
@@ -3186,92 +3166,24 @@ input_osc_112(struct input_ctx *ictx, const char *p)
screen_set_cursor_colour(ictx->ctx.s, -1); screen_set_cursor_colour(ictx->ctx.s, -1);
} }
/* Fire an OSC 133 command event. */
static void
input_fire_command_event(struct window_pane *wp, const char *name)
{
struct event_payload *ep;
struct cmd_find_state fs;
time_t tstart = wp->cmd_start_time, end;
time_t tend = wp->cmd_end_time;
ep = event_payload_create();
cmd_find_from_pane(&fs, wp, 0);
event_payload_set_target(ep, &fs);
if (fs.s != NULL)
event_payload_set_session(ep, "session", fs.s);
if (fs.wl != NULL)
event_payload_set_int(ep, "window_index", fs.wl->idx);
event_payload_set_window(ep, "window", wp->window);
event_payload_set_pane(ep, "pane", wp);
if (wp->cmd_status != -1)
event_payload_set_int(ep, "command_status", wp->cmd_status);
if (tstart != 0)
event_payload_set_time(ep, "command_start_time", tstart);
if (tend != 0)
event_payload_set_time(ep, "command_end_time", tend);
if (tstart != 0) {
if (wp->flags & PANE_CMDRUNNING)
end = time(NULL);
else
end = tend;
if (end < tstart)
end = tstart;
end -= tstart;
event_payload_set_uint(ep, "command_duration", end);
}
events_fire(name, ep);
}
/* Handle the OSC 133 sequence. */ /* Handle the OSC 133 sequence. */
static void static void
input_osc_133(struct input_ctx *ictx, const char *p) input_osc_133(struct input_ctx *ictx, const char *p)
{ {
struct window_pane *wp = ictx->wp;
struct grid *gd = ictx->ctx.s->grid; struct grid *gd = ictx->ctx.s->grid;
u_int line = ictx->ctx.s->cy + gd->hsize; u_int line = ictx->ctx.s->cy + gd->hsize;
struct grid_line *gl = NULL; struct grid_line *gl;
const char *errstr;
int status;
if (line <= gd->hsize + gd->sy - 1) if (line > gd->hsize + gd->sy - 1)
gl = grid_get_line(gd, line); return;
gl = grid_get_line(gd, line);
switch (*p) { switch (*p) {
case 'A': case 'A':
if (gl != NULL) gl->flags |= GRID_LINE_START_PROMPT;
gl->flags |= GRID_LINE_START_PROMPT;
if (wp != NULL) {
wp->last_prompt_time = time(NULL);
events_fire_pane("pane-shell-prompt", wp);
}
break; break;
case 'C': case 'C':
if (gl != NULL) gl->flags |= GRID_LINE_START_OUTPUT;
gl->flags |= GRID_LINE_START_OUTPUT;
if (wp != NULL) {
wp->cmd_start_time = time(NULL);
wp->cmd_end_time = 0;
wp->flags |= PANE_CMDRUNNING;
wp->cmd_status = -1;
input_fire_command_event(wp, "pane-command-started");
}
break;
case 'D':
if (wp != NULL) {
wp->cmd_end_time = time(NULL);
wp->flags &= ~PANE_CMDRUNNING;
wp->cmd_status = -1;
if (p[1] == ';' && p[2] != '\0') {
status = strtonum(p + 2, 0, INT_MAX, &errstr);
if (errstr == NULL)
wp->cmd_status = status;
}
input_fire_command_event(wp, "pane-command-finished");
}
break; break;
} }
} }
@@ -3377,7 +3289,7 @@ input_osc_52(struct input_ctx *ictx, const char *p)
screen_write_start_pane(&ctx, wp, NULL); screen_write_start_pane(&ctx, wp, NULL);
screen_write_setselection(&ctx, clip, out, outlen); screen_write_setselection(&ctx, clip, out, outlen);
screen_write_stop(&ctx); screen_write_stop(&ctx);
events_fire_pane("pane-set-clipboard", wp); notify_pane("pane-set-clipboard", wp);
paste_add(NULL, out, outlen); paste_add(NULL, out, outlen);
} }
} }

View File

@@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com> * Copyright (c) 2026 Nicholas Marriott <nicm@users.sourceforge.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -53,7 +53,7 @@ struct monitor_item {
enum monitor_type type; enum monitor_type type;
u_int id; u_int id;
int flags; u_int flags;
char *last; char *last;
struct monitor_panes panes; struct monitor_panes panes;
@@ -198,9 +198,7 @@ monitor_check_value(struct monitor_set *ms, struct monitor_item *me,
{ {
if (*last == NULL) { if (*last == NULL) {
*last = value; *last = value;
if ((me->flags & MONITOR_NOTIFY_INITIAL) && if (me->flags & MONITOR_NOTIFY_INITIAL)
((~me->flags & MONITOR_NOTIFY_TRUE) ||
format_true(value)))
monitor_report(ms, me, s, wl, wp, value, NULL); monitor_report(ms, me, s, wl, wp, value, NULL);
return; return;
} }
@@ -210,8 +208,7 @@ monitor_check_value(struct monitor_set *ms, struct monitor_item *me,
return; return;
} }
if ((~me->flags & MONITOR_NOTIFY_TRUE) || format_true(value)) monitor_report(ms, me, s, wl, wp, value, *last);
monitor_report(ms, me, s, wl, wp, value, *last);
free(*last); free(*last);
*last = value; *last = value;
} }
@@ -624,7 +621,7 @@ fail:
/* Add a subscription. */ /* Add a subscription. */
void void
monitor_add(struct monitor_set *ms, const char *name, enum monitor_type type, monitor_add(struct monitor_set *ms, const char *name, enum monitor_type type,
int id, const char *format, int flags) int id, const char *format, u_int flags)
{ {
struct monitor_item *me, find = { .name = (char *)name }; struct monitor_item *me, find = { .name = (char *)name };
struct timeval tv = { .tv_sec = 1 }; struct timeval tv = { .tv_sec = 1 };

View File

@@ -1932,22 +1932,12 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_HOOK("client-light-theme", ""), OPTIONS_TABLE_HOOK("client-light-theme", ""),
OPTIONS_TABLE_HOOK("client-dark-theme", ""), OPTIONS_TABLE_HOOK("client-dark-theme", ""),
OPTIONS_TABLE_HOOK("command-error", ""), OPTIONS_TABLE_HOOK("command-error", ""),
OPTIONS_TABLE_HOOK("marked-pane-changed", ""),
OPTIONS_TABLE_PANE_HOOK("pane-command-finished", ""),
OPTIONS_TABLE_PANE_HOOK("pane-command-started", ""),
OPTIONS_TABLE_PANE_HOOK("pane-created", ""),
OPTIONS_TABLE_PANE_HOOK("pane-died", ""), OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""), OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
OPTIONS_TABLE_PANE_HOOK("pane-focus-in", ""), OPTIONS_TABLE_PANE_HOOK("pane-focus-in", ""),
OPTIONS_TABLE_PANE_HOOK("pane-focus-out", ""), OPTIONS_TABLE_PANE_HOOK("pane-focus-out", ""),
OPTIONS_TABLE_PANE_HOOK("pane-mode-changed", ""), 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-set-clipboard", ""),
OPTIONS_TABLE_PANE_HOOK("pane-shell-prompt", ""),
OPTIONS_TABLE_PANE_HOOK("pane-title-changed", ""), OPTIONS_TABLE_PANE_HOOK("pane-title-changed", ""),
OPTIONS_TABLE_HOOK("session-closed", ""), OPTIONS_TABLE_HOOK("session-closed", ""),
OPTIONS_TABLE_HOOK("session-created", ""), OPTIONS_TABLE_HOOK("session-created", ""),
@@ -1958,8 +1948,6 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_WINDOW_HOOK("window-pane-changed", ""), OPTIONS_TABLE_WINDOW_HOOK("window-pane-changed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-renamed", ""), OPTIONS_TABLE_WINDOW_HOOK("window-renamed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-resized", ""), OPTIONS_TABLE_WINDOW_HOOK("window-resized", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-unzoomed", ""),
OPTIONS_TABLE_WINDOW_HOOK("window-zoomed", ""),
OPTIONS_TABLE_HOOK("window-unlinked", ""), OPTIONS_TABLE_HOOK("window-unlinked", ""),
{ .name = NULL } { .name = NULL }

122
tmux.1
View File

@@ -6325,7 +6325,11 @@ For example, this could be used to write to a log file:
set\-hook \-g command\-error "run\-shell \\"echo 'a tmux command failed' >>/tmp/log\\"" set\-hook \-g command\-error "run\-shell \\"echo 'a tmux command failed' >>/tmp/log\\""
.Ed .Ed
.Pp .Pp
The following hooks are available in addition to after hooks: All the notifications listed in the
.Sx CONTROL MODE
section are hooks (without any arguments), except
.Ic %exit .
The following additional hooks are available:
.Bl -tag -width "XXXXXXXXXXXXXXXXXXXXXX" .Bl -tag -width "XXXXXXXXXXXXXXXXXXXXXX"
.It alert\-activity .It alert\-activity
Run when a window has activity. Run when a window has activity.
@@ -6344,11 +6348,11 @@ Run when a client becomes the latest active client of its session.
.It client\-attached .It client\-attached
Run when a client is attached. Run when a client is attached.
.It client\-detached .It client\-detached
Run when a client is detached. Run when a client is detached
.It client\-focus\-in .It client\-focus\-in
Run when focus enters a client. Run when focus enters a client
.It client\-focus\-out .It client\-focus\-out
Run when focus exits a client. Run when focus exits a client
.It client\-resized .It client\-resized
Run when a client is resized. Run when a client is resized.
.It client\-session\-changed .It client\-session\-changed
@@ -6359,21 +6363,6 @@ Run when a client switches to a light theme.
Run when a client switches to a dark theme. Run when a client switches to a dark theme.
.It command\-error .It command\-error
Run when a command fails. Run when a command fails.
.It marked\-pane\-changed
Run when the marked pane is set or cleared.
.It pane\-command\-finished
Run when an OSC 133 command finishes in a pane.
The event payload includes
.Ql hook_command_start_time ,
.Ql hook_command_end_time ,
.Ql hook_command_duration
and
.Ql hook_command_status
if present.
.It pane\-command\-started
Run when an OSC 133 command starts in a pane.
.It pane\-created
Run when a pane is created or respawned.
.It pane\-died .It pane\-died
Run when the program running in a pane exits, but Run when the program running in a pane exits, but
.Ic remain\-on\-exit .Ic remain\-on\-exit
@@ -6388,40 +6377,20 @@ option is on.
Run when the focus exits a pane, if the Run when the focus exits a pane, if the
.Ic focus\-events .Ic focus\-events
option is on. option is on.
.It pane\-mode\-changed
Run when a pane changes mode.
.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 .It pane\-set\-clipboard
Run when the terminal clipboard is set using the Run when the terminal clipboard is set using the
.Xr xterm 1 .Xr xterm 1
escape sequence. escape sequence.
.It pane\-shell\-prompt
Run when an OSC 133 shell prompt starts in a pane.
.It pane\-title\-changed
Run when a pane title is changed.
.It session\-closed
Run when a session is closed.
.It session\-created .It session\-created
Run when a new session is created. Run when a new session created.
.It session\-closed
Run when a session closed.
.It session\-renamed .It session\-renamed
Run when a session is renamed. Run when a session is renamed.
.It session\-window\-changed
Run when a session changes its active window.
.It window\-layout\-changed .It window\-layout\-changed
Run when a window layout is changed. Run when a window layout is changed.
.It window\-linked .It window\-linked
Run when a window is linked into a session. Run when a window is linked into a session.
.It window\-pane\-changed
Run when a window changes its active pane.
.It window\-renamed .It window\-renamed
Run when a window is renamed. Run when a window is renamed.
.It window\-resized .It window\-resized
@@ -6429,10 +6398,6 @@ Run when a window is resized.
This may be after the This may be after the
.Ar client\-resized .Ar client\-resized
hook is run. hook is run.
.It window\-unzoomed
Run when a window is unzoomed.
.It window\-zoomed
Run when a window is zoomed.
.It window\-unlinked .It window\-unlinked
Run when a window is unlinked from a session. Run when a window is unlinked from a session.
.El .El
@@ -6440,15 +6405,13 @@ Run when a window is unlinked from a session.
Hooks are managed with these commands: Hooks are managed with these commands:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Xo Ic set\-hook .It Xo Ic set\-hook
.Op Fl agpERTuw .Op Fl agpRuw
.Op Fl B Ar name:what:format .Op Fl B Ar name:what:format
.Op Fl t Ar target\-pane .Op Fl t Ar target\-pane
.Ar hook\-name .Ar hook\-name
.Op Ar command .Op Ar command
.Xc .Xc
Without Without
.Fl E
or
.Fl R , .Fl R ,
sets (or with sets (or with
.Fl u .Fl u
@@ -6471,11 +6434,6 @@ is the hook to run,
selects the session, pane, all panes, window, or all windows, and selects the session, pane, all panes, window, or all windows, and
.Ar format .Ar format
is expanded once a second. is expanded once a second.
With
.Fl T ,
the hook is run only when
.Ar format
is true.
For monitor hooks, For monitor hooks,
.Ar name .Ar name
must begin with must begin with
@@ -6494,14 +6452,6 @@ the subscription named by
is removed. is removed.
.Pp .Pp
With With
.Fl E ,
fire the user event named
.Ar hook\-name .
.Ar hook\-name
must begin with
.Ql @ .
.Pp
With
.Fl R , .Fl R ,
run run
.Ar hook\-name .Ar hook\-name
@@ -7211,11 +7161,6 @@ The following variables are available, where appropriate:
.It Li "pane_at_top" Ta "" Ta "1 if pane is at the top of window" .It Li "pane_at_top" Ta "" Ta "1 if pane is at the top of window"
.It Li "pane_bg" Ta "" Ta "Pane background colour" .It Li "pane_bg" Ta "" Ta "Pane background colour"
.It Li "pane_bottom" Ta "" Ta "Bottom of pane" .It Li "pane_bottom" Ta "" Ta "Bottom of pane"
.It Li "pane_command_duration" Ta "" Ta "Current or most recent OSC 133 command duration in seconds"
.It Li "pane_command_end_time" Ta "" Ta "Time most recent OSC 133 command ended"
.It Li "pane_command_running" Ta "" Ta "1 if an OSC 133 command is running"
.It Li "pane_command_start_time" Ta "" Ta "Time current or most recent OSC 133 command started"
.It Li "pane_command_status" Ta "" Ta "Exit status from most recent OSC 133 command"
.It Li "pane_current_command" Ta "" Ta "Current command if available" .It Li "pane_current_command" Ta "" Ta "Current command if available"
.It Li "pane_current_path" Ta "" Ta "Current path if available" .It Li "pane_current_path" Ta "" Ta "Current path if available"
.It Li "pane_dead" Ta "" Ta "1 if pane is dead" .It Li "pane_dead" Ta "" Ta "1 if pane is dead"
@@ -7233,8 +7178,6 @@ The following variables are available, where appropriate:
.It Li "pane_input_off" Ta "" Ta "1 if input to pane is disabled" .It Li "pane_input_off" Ta "" Ta "1 if input to pane is disabled"
.It Li "pane_key_mode" Ta "" Ta "Extended key reporting mode in this pane" .It Li "pane_key_mode" Ta "" Ta "Extended key reporting mode in this pane"
.It Li "pane_last" Ta "" Ta "1 if last pane" .It Li "pane_last" Ta "" Ta "1 if last pane"
.It Li "pane_last_output_time" Ta "" Ta "Time pane last produced output"
.It Li "pane_last_prompt_time" Ta "" Ta "Time most recent OSC 133 prompt began"
.It Li "pane_left" Ta "" Ta "Left of pane" .It Li "pane_left" Ta "" Ta "Left of pane"
.It Li "pane_marked" Ta "" Ta "1 if this is the marked pane" .It Li "pane_marked" Ta "" Ta "1 if this is the marked pane"
.It Li "pane_marked_set" Ta "" Ta "1 if a marked pane is set" .It Li "pane_marked_set" Ta "" Ta "1 if a marked pane is set"
@@ -8619,10 +8562,8 @@ or the current pane if omitted) after the command finishes.
If the command fails, the exit status is also displayed. If the command fails, the exit status is also displayed.
.Tg wait .Tg wait
.It Xo Ic wait\-for .It Xo Ic wait\-for
.Op Fl ELSUlv .Op Fl L | S | U
.Op Fl F Ar format .Ar channel
.Op Fl w Ar waiter
.Ar name
.Xc .Xc
.D1 Pq alias: Ic wait .D1 Pq alias: Ic wait
When used without options, prevents the client from exiting until woken using When used without options, prevents the client from exiting until woken using
@@ -8635,41 +8576,6 @@ is used, the channel is locked and any clients that try to lock the same
channel are made to wait until the channel is unlocked with channel are made to wait until the channel is unlocked with
.Ic wait\-for .Ic wait\-for
.Fl U . .Fl U .
.Pp
With
.Fl E ,
.Nm
waits for the next event with
.Ar name .
Events include hook and notification names, and user
.Ql @
events generated by
.Ic set-hook
.Fl E
or
.Ic set-hook
.Fl B .
If
.Fl F
is given,
.Ar format
must also be true.
If
.Fl v
is given, event payload keys are printed (whether or not
.Ar format
is true).
.Pp
.Fl l
list the waiters for
.Ar name
and
.Fl w
wakes
.Ar waiter
on
.Ar name
immediately.
.El .El
.Sh EXIT MESSAGES .Sh EXIT MESSAGES
When a When a

134
tmux.h
View File

@@ -49,9 +49,6 @@ struct cmdq_state;
struct cmds; struct cmds;
struct control_state; struct control_state;
struct environ; struct environ;
struct event_payload;
struct event_payload_item;
struct events_sink;
struct format_job_tree; struct format_job_tree;
struct format_tree; struct format_tree;
struct hyperlinks_uri; struct hyperlinks_uri;
@@ -1301,7 +1298,6 @@ struct window_pane {
#define PANE_UNSEENCHANGES 0x4000 #define PANE_UNSEENCHANGES 0x4000
#define PANE_REDRAWSCROLLBAR 0x8000 #define PANE_REDRAWSCROLLBAR 0x8000
#define PANE_DESTROYED 0x10000 #define PANE_DESTROYED 0x10000
#define PANE_CMDRUNNING 0x20000
bitstr_t *sync_dirty; bitstr_t *sync_dirty;
u_int sync_dirty_size; u_int sync_dirty_size;
@@ -1324,12 +1320,6 @@ struct window_pane {
struct cmdq_item *wait_item; /* new-pane -W: waiting for pane exit */ struct cmdq_item *wait_item; /* new-pane -W: waiting for pane exit */
struct spawn_editor_state *editor; struct spawn_editor_state *editor;
time_t last_output_time;
time_t last_prompt_time;
time_t cmd_start_time;
time_t cmd_end_time;
int cmd_status;
int fd; int fd;
struct bufferevent *event; struct bufferevent *event;
@@ -2341,7 +2331,6 @@ enum monitor_type {
MONITOR_ALL_WINDOWS MONITOR_ALL_WINDOWS
}; };
#define MONITOR_NOTIFY_INITIAL 0x1 #define MONITOR_NOTIFY_INITIAL 0x1
#define MONITOR_NOTIFY_TRUE 0x2
struct monitor_change { struct monitor_change {
const char *name; const char *name;
const char *value; const char *value;
@@ -2354,23 +2343,6 @@ struct monitor_change {
}; };
typedef void (*monitor_cb)(struct monitor_change *, void *); typedef void (*monitor_cb)(struct monitor_change *, void *);
/* Event payload type. */
enum event_payload_type {
EVENT_PAYLOAD_STRING,
EVENT_PAYLOAD_TIME,
EVENT_PAYLOAD_INT,
EVENT_PAYLOAD_UINT,
EVENT_PAYLOAD_CLIENT,
EVENT_PAYLOAD_SESSION,
EVENT_PAYLOAD_WINDOW,
EVENT_PAYLOAD_PANE,
EVENT_PAYLOAD_POINTER
};
/* Event payload callbacks. */
typedef void (*event_payload_free_cb)(void *);
typedef void (*event_payload_print_cb)(void *, struct evbuffer *);
/* Key binding and key table. */ /* Key binding and key table. */
struct key_binding { struct key_binding {
key_code key; key_code key;
@@ -2680,78 +2652,29 @@ char *format_grid_hyperlink(struct grid *, u_int, u_int,
struct screen *); struct screen *);
char *format_grid_line(struct grid *, u_int); char *format_grid_line(struct grid *, u_int);
/* events-payload.c */
struct event_payload *event_payload_create(void);
void event_payload_free(struct event_payload *);
void printflike(2, 3) event_payload_log(struct event_payload *, const char *,
...);
char *event_payload_item_print(struct event_payload_item *);
void event_payload_set_target(struct event_payload *,
struct cmd_find_state *);
int event_payload_get_target(struct event_payload *,
struct cmd_find_state *);
void printflike(3, 4) event_payload_set_string(struct event_payload *,
const char *, const char *, ...);
void event_payload_set_time(struct event_payload *, const char *, time_t);
void event_payload_set_int(struct event_payload *, const char *, int);
void event_payload_set_uint(struct event_payload *, const char *, u_int);
void event_payload_set_client(struct event_payload *, const char *,
struct client *);
void event_payload_set_session(struct event_payload *, const char *,
struct session *);
void event_payload_set_window(struct event_payload *, const char *,
struct window *);
void event_payload_set_pane(struct event_payload *, const char *,
struct window_pane *);
void event_payload_set_pointer(struct event_payload *, const char *, void *,
event_payload_free_cb, event_payload_print_cb);
const char *event_payload_get_string(struct event_payload *, const char *);
char *event_payload_print(struct event_payload *, const char *);
void event_payload_add_formats(struct event_payload *,
struct format_tree *, const char *);
struct event_payload_item *event_payload_first(struct event_payload *);
struct event_payload_item *event_payload_next(struct event_payload_item *);
const char *event_payload_item_name(struct event_payload_item *);
enum event_payload_type event_payload_item_type(struct event_payload_item *);
time_t event_payload_get_time(struct event_payload *, const char *);
int event_payload_get_int(struct event_payload *, const char *, int *);
int event_payload_get_uint(struct event_payload *, const char *, u_int *);
struct client *event_payload_get_client(struct event_payload *, const char *);
struct session *event_payload_get_session(struct event_payload *, const char *);
struct window *event_payload_get_window(struct event_payload *, const char *);
struct window_pane *event_payload_get_pane(struct event_payload *,
const char *);
void *event_payload_get_pointer(struct event_payload *, const char *);
/* events.c */
typedef void (*events_cb)(const char *, struct event_payload *, void *);
struct events_sink *events_add_sink(const char *, events_cb, void *);
void events_remove_sink(struct events_sink *);
void events_fire(const char *, struct event_payload *);
void events_fire_client(const char *, struct client *);
void events_fire_session(const char *, struct session *);
void events_fire_window(const char *, struct window *);
void events_fire_pane(const char *, struct window_pane *);
void events_fire_winlink(const char *, struct winlink *);
/* format-draw.c */ /* format-draw.c */
void format_draw(struct screen_write_ctx *, const struct grid_cell *, void format_draw(struct screen_write_ctx *,
u_int, const char *, struct style_ranges *, int); const struct grid_cell *, u_int, const char *,
u_int format_width(const char *); struct style_ranges *, int);
char *format_trim_left(const char *, u_int); u_int format_width(const char *);
char *format_trim_right(const char *, u_int); char *format_trim_left(const char *, u_int);
char *format_trim_right(const char *, u_int);
/* hooks.c */ /* notify.c */
void hooks_add_event(const char *); void notify_hook(struct cmdq_item *, const char *);
int hooks_valid_event_name(const char *); void notify_monitor_add(struct cmdq_item *, struct options *,
void hooks_build_events(void);
void hooks_run(struct cmdq_item *, const char *);
void hooks_monitor_add(struct cmdq_item *, struct options *,
const char *, enum monitor_type, int, const char *, const char *, enum monitor_type, int, const char *,
int, struct cmd_find_state *, struct session *); struct cmd_find_state *, struct session *);
void hooks_monitor_remove(struct options *, const char *); void notify_monitor_remove(struct options *, const char *);
void hooks_monitor_free(void *); void notify_monitor_free(void *);
char *hooks_monitor_to_string(struct options_entry *); char *notify_monitor_to_string(struct options_entry *);
void notify_client(const char *, struct client *);
void notify_session(const char *, struct session *);
void notify_winlink(const char *, struct winlink *);
void notify_session_window(const char *, struct session *, struct window *);
void notify_window(const char *, struct window *);
void notify_pane(const char *, struct window_pane *);
void notify_paste_buffer(const char *, int);
/* options.c */ /* options.c */
struct options *options_create(struct options *); struct options *options_create(struct options *);
@@ -3959,7 +3882,7 @@ void monitor_destroy(struct monitor_set *);
int monitor_parse(const char *, char **, enum monitor_type *, int *, int monitor_parse(const char *, char **, enum monitor_type *, int *,
char **); char **);
void monitor_add(struct monitor_set *, const char *, enum monitor_type, int, void monitor_add(struct monitor_set *, const char *, enum monitor_type, int,
const char *, int); const char *, u_int);
void monitor_remove(struct monitor_set *, const char *); void monitor_remove(struct monitor_set *, const char *);
/* control.c */ /* control.c */
@@ -3983,7 +3906,20 @@ void control_add_sub(struct client *, const char *, enum monitor_type, int,
void control_remove_sub(struct client *, const char *); void control_remove_sub(struct client *, const char *);
/* control-notify.c */ /* control-notify.c */
void control_build_events(void); void control_notify_pane_mode_changed(int);
void control_notify_window_layout_changed(struct window *);
void control_notify_window_pane_changed(struct window *);
void control_notify_window_unlinked(struct session *, struct window *);
void control_notify_window_linked(struct session *, struct window *);
void control_notify_window_renamed(struct window *);
void control_notify_client_session_changed(struct client *);
void control_notify_client_detached(struct client *);
void control_notify_session_renamed(struct session *);
void control_notify_session_created(struct session *);
void control_notify_session_closed(struct session *);
void control_notify_session_window_changed(struct session *);
void control_notify_paste_buffer_changed(const char *);
void control_notify_paste_buffer_deleted(const char *);
/* session.c */ /* session.c */
extern struct sessions sessions; extern struct sessions sessions;

157
window.c
View File

@@ -73,8 +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_destroy(struct window_pane *);
static void window_pane_free(struct window_pane *); static void window_pane_free(struct window_pane *);
static void window_pane_scrollbar_timer(int, short, void *); static void window_pane_scrollbar_timer(int, short, void *);
static void window_pane_full_size_offset(struct window_pane *, int *, int *, static void window_pane_full_size_offset(struct window_pane *wp,
u_int *, u_int *); int *xoff, int *yoff, u_int *sx, u_int *sy);
RB_GENERATE(windows, window, entry, window_cmp); RB_GENERATE(windows, window, entry, window_cmp);
RB_GENERATE(winlinks, winlink, entry, winlink_cmp); RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
@@ -86,7 +86,6 @@ struct window_pane_prompt {
status_prompt_input_cb inputcb; status_prompt_input_cb inputcb;
prompt_free_cb freecb; prompt_free_cb freecb;
void *data; void *data;
enum prompt_type type;
}; };
int int
@@ -95,78 +94,6 @@ window_cmp(struct window *w1, struct window *w2)
return (w1->id - w2->id); return (w1->id - w2->id);
} }
static void
window_fire_renamed(struct window *w, const char *old_name)
{
struct event_payload *ep;
struct cmd_find_state fs;
ep = event_payload_create();
cmd_find_from_window(&fs, w, 0);
event_payload_set_target(ep, &fs);
event_payload_set_window(ep, "window", w);
event_payload_set_string(ep, "old_name", "%s", old_name);
event_payload_set_string(ep, "new_name", "%s", w->name);
events_fire("window-renamed", ep);
}
static void
window_fire_pane_changed(struct window *w, struct window_pane *wp,
struct window_pane *lastwp)
{
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_window(ep, "window", w);
event_payload_set_pane(ep, "pane", wp);
event_payload_set_pane(ep, "new_pane", wp);
if (lastwp != NULL)
event_payload_set_pane(ep, "old_pane", lastwp);
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 int
winlink_cmp(struct winlink *wl1, struct winlink *wl2) winlink_cmp(struct winlink *wl1, struct winlink *wl2)
{ {
@@ -517,15 +444,13 @@ window_pane_remove_ref(struct window_pane *wp, const char *from)
void void
window_set_name(struct window *w, const char *new_name, int untrusted) window_set_name(struct window *w, const char *new_name, int untrusted)
{ {
char *last, *name; char *name;
name = clean_name(new_name, untrusted); name = clean_name(new_name, untrusted);
if (name != NULL) { if (name != NULL) {
last = xstrdup(w->name);
free(w->name); free(w->name);
w->name = name; w->name = name;
window_fire_renamed(w, last); notify_window("window-renamed", w);
free(last);
} }
} }
@@ -635,13 +560,13 @@ window_pane_update_focus(struct window_pane *wp)
log_debug("%s: %%%u focus out", __func__, wp->id); log_debug("%s: %%%u focus out", __func__, wp->id);
if (wp->base.mode & MODE_FOCUSON) if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[O", 3); bufferevent_write(wp->event, "\033[O", 3);
events_fire_pane("pane-focus-out", wp); notify_pane("pane-focus-out", wp);
wp->flags &= ~PANE_FOCUSED; wp->flags &= ~PANE_FOCUSED;
} else if (focused && (~wp->flags & PANE_FOCUSED)) { } else if (focused && (~wp->flags & PANE_FOCUSED)) {
log_debug("%s: %%%u focus in", __func__, wp->id); log_debug("%s: %%%u focus in", __func__, wp->id);
if (wp->base.mode & MODE_FOCUSON) if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[I", 3); bufferevent_write(wp->event, "\033[I", 3);
events_fire_pane("pane-focus-in", wp); notify_pane("pane-focus-in", wp);
wp->flags |= PANE_FOCUSED; wp->flags |= PANE_FOCUSED;
} else } else
log_debug("%s: %%%u focus unchanged", __func__, wp->id); log_debug("%s: %%%u focus unchanged", __func__, wp->id);
@@ -677,7 +602,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
server_redraw_window(w); server_redraw_window(w);
if (notify) if (notify)
window_fire_pane_changed(w, w->active, lastwp); notify_window("window-pane-changed", w);
return (1); return (1);
} }
@@ -867,8 +792,7 @@ window_zoom(struct window_pane *wp)
w->saved_layout_root = w->layout_root; w->saved_layout_root = w->layout_root;
layout_init(w, wp); layout_init(w, wp);
w->flags |= WINDOW_ZOOMED; w->flags |= WINDOW_ZOOMED;
events_fire_window("window-zoomed", w); notify_window("window-layout-changed", w);
events_fire_window("window-layout-changed", w);
redraw_invalidate_scene(w); redraw_invalidate_scene(w);
return (0); return (0);
@@ -894,10 +818,8 @@ window_unzoom(struct window *w, int notify)
} }
layout_fix_panes(w, NULL); layout_fix_panes(w, NULL);
if (notify) { if (notify)
events_fire_window("window-unzoomed", w); notify_window("window-layout-changed", w);
events_fire_window("window-layout-changed", w);
}
redraw_invalidate_scene(w); redraw_invalidate_scene(w);
return (0); return (0);
@@ -979,7 +901,7 @@ window_lost_pane(struct window *w, struct window_pane *wp)
if (w->active != NULL) { if (w->active != NULL) {
window_pane_stack_remove(&w->last_panes, w->active); window_pane_stack_remove(&w->last_panes, w->active);
w->active->flags |= PANE_CHANGED; w->active->flags |= PANE_CHANGED;
events_fire_window("window-pane-changed", w); notify_window("window-pane-changed", w);
window_update_focus(w); window_update_focus(w);
} }
} }
@@ -1184,7 +1106,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->window = w; wp->window = w;
wp->options = options_create(w->options); wp->options = options_create(w->options);
wp->flags = PANE_STYLECHANGED; wp->flags = PANE_STYLECHANGED;
wp->cmd_status = -1;
wp->id = next_window_pane_id++; wp->id = next_window_pane_id++;
RB_INSERT(window_pane_tree, &all_window_panes, wp); RB_INSERT(window_pane_tree, &all_window_panes, wp);
@@ -1309,9 +1230,9 @@ window_pane_destroy(struct window_pane *wp)
window_pane_wait_finish(wp); window_pane_wait_finish(wp);
spawn_editor_finish(wp); spawn_editor_finish(wp);
window_pane_clear_prompt(wp);
RB_REMOVE(window_pane_tree, &all_window_panes, wp); RB_REMOVE(window_pane_tree, &all_window_panes, wp);
wp->flags |= PANE_DESTROYED; wp->flags |= PANE_DESTROYED;
window_pane_clear_prompt(wp);
window_pane_free_modes(wp); window_pane_free_modes(wp);
screen_write_clear_dirty(wp); screen_write_clear_dirty(wp);
@@ -1442,8 +1363,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
{ {
struct window_mode_entry *wme; struct window_mode_entry *wme;
struct window_pane_resize *r; struct window_pane_resize *r;
struct event_payload *ep;
struct cmd_find_state fs;
if (sx == wp->sx && sy == wp->sy) if (sx == wp->sx && sy == wp->sy)
return; return;
@@ -1466,17 +1385,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->resize != NULL) if (wme != NULL && wme->mode->resize != NULL)
wme->mode->resize(wme, sx, sy); 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 int
@@ -1486,13 +1394,9 @@ window_pane_set_mode(struct window_pane *wp, struct window_pane *swp,
{ {
struct window_mode_entry *wme; struct window_mode_entry *wme;
struct window *w = wp->window; struct window *w = wp->window;
const char *name = mode->name, *p = NULL;
if (!TAILQ_EMPTY(&wp->modes)) { if (!TAILQ_EMPTY(&wp->modes) && TAILQ_FIRST(&wp->modes)->mode == mode)
if (TAILQ_FIRST(&wp->modes)->mode == mode) return (1);
return (1);
p = TAILQ_FIRST(&wp->modes)->mode->name;
}
TAILQ_FOREACH(wme, &wp->modes, entry) { TAILQ_FOREACH(wme, &wp->modes, entry) {
if (wme->mode == mode) if (wme->mode == mode)
@@ -1518,9 +1422,7 @@ window_pane_set_mode(struct window_pane *wp, struct window_pane *swp,
server_redraw_window_borders(wp->window); server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
notify_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); return (0);
} }
@@ -1531,13 +1433,11 @@ window_pane_reset_mode(struct window_pane *wp)
struct window_mode_entry *wme, *next; struct window_mode_entry *wme, *next;
struct window *w = wp->window; struct window *w = wp->window;
int kill; int kill;
const char *name, *p;
if (TAILQ_EMPTY(&wp->modes)) if (TAILQ_EMPTY(&wp->modes))
return; return;
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
p = wme->mode->name;
kill = wme->kill; kill = wme->kill;
TAILQ_REMOVE(&wp->modes, wme, entry); TAILQ_REMOVE(&wp->modes, wme, entry);
wme->mode->free(wme); wme->mode->free(wme);
@@ -1554,16 +1454,13 @@ window_pane_reset_mode(struct window_pane *wp)
if (next->mode->resize != NULL) if (next->mode->resize != NULL)
next->mode->resize(next, wp->sx, wp->sy); next->mode->resize(next, wp->sx, wp->sy);
} }
name = (next == NULL ? NULL : next->mode->name);
wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR|PANE_CHANGED); wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR|PANE_CHANGED);
layout_fix_panes(w, NULL); layout_fix_panes(w, NULL);
server_redraw_window_borders(wp->window); server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
notify_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) if (kill)
server_kill_pane(wp); server_kill_pane(wp);
@@ -1626,7 +1523,6 @@ window_pane_set_prompt(struct window_pane *wp, struct client *c,
wpp->inputcb = inputcb; wpp->inputcb = inputcb;
wpp->freecb = freecb; wpp->freecb = freecb;
wpp->data = data; wpp->data = data;
wpp->type = type;
memset(&pd, 0, sizeof pd); memset(&pd, 0, sizeof pd);
prompt_set_options(&pd, s); prompt_set_options(&pd, s);
@@ -1644,28 +1540,19 @@ window_pane_set_prompt(struct window_pane *wp, struct client *c,
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
prompt_incremental_start(wp->prompt); prompt_incremental_start(wp->prompt);
window_fire_pane_prompt("pane-prompt-opened", wp, type);
} }
/* Close a pane prompt. */ /* Close a pane prompt. */
void void
window_pane_clear_prompt(struct window_pane *wp) 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) { if (prompt == NULL)
if (wpp != NULL) return;
type = wpp->type; wp->prompt = NULL;
prompt_free(prompt);
wp->prompt = NULL; wp->flags |= PANE_REDRAW;
prompt_free(prompt);
wp->flags |= PANE_REDRAW;
if (~wp->flags & PANE_DESTROYED)
window_fire_pane_prompt("pane-prompt-closed", wp, type);
}
} }
/* Does this pane have an open prompt? */ /* Does this pane have an open prompt? */