mirror of
https://github.com/tmux/tmux.git
synced 2026-07-11 11:59:32 +00:00
Merge branch 'obsd-master'
This commit is contained in:
@@ -31,6 +31,8 @@ static enum args_parse_type cmd_set_option_args_parse(struct args *,
|
||||
u_int, char **);
|
||||
static enum cmd_retval cmd_set_option_exec(struct cmd *,
|
||||
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 *,
|
||||
struct args *, int);
|
||||
|
||||
@@ -64,8 +66,8 @@ const struct cmd_entry cmd_set_hook_entry = {
|
||||
.name = "set-hook",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "agpRt:uB:w", 0, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpRuw] [-B name:what:format] " CMD_TARGET_PANE_USAGE " "
|
||||
.args = { "agpERTt:uB:w", 0, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpERTuw] [-B name:what:format] " CMD_TARGET_PANE_USAGE " "
|
||||
"[hook] [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
@@ -85,17 +87,63 @@ cmd_set_option_args_parse(struct args *args, u_int idx,
|
||||
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
|
||||
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 options *oo;
|
||||
struct options_entry *o;
|
||||
struct session *s = NULL;
|
||||
char *cause = NULL, *name = NULL, *format = NULL;
|
||||
char *expanded = NULL, *newvalue = NULL;
|
||||
const char *value, *old;
|
||||
enum monitor_type type;
|
||||
int id, scope;
|
||||
int id, scope, flags = 0;
|
||||
|
||||
if (args_count(args) > 1) {
|
||||
cmdq_error(item, "too many arguments");
|
||||
@@ -130,7 +178,7 @@ cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
|
||||
cmd_find_copy_state(&fs, target);
|
||||
|
||||
if (args_has(args, 'u')) {
|
||||
notify_monitor_remove(oo, name);
|
||||
hooks_monitor_remove(oo, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -152,7 +200,13 @@ cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
|
||||
}
|
||||
}
|
||||
|
||||
notify_monitor_add(item, oo, name, type, id, format, &fs, target->s);
|
||||
if (oo != global_options &&
|
||||
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:
|
||||
free(newvalue);
|
||||
@@ -185,6 +239,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
int scope;
|
||||
|
||||
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'))
|
||||
return (cmd_set_hook_monitor_exec(item, args, window));
|
||||
if (args_count(args) == 0) {
|
||||
@@ -197,7 +253,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
/* If set-hook -R, fire the hook straight away. */
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) {
|
||||
notify_hook(item, argument);
|
||||
hooks_run(item, argument);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
@@ -289,6 +345,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
goto fail;
|
||||
}
|
||||
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)) {
|
||||
error = options_from_string(oo, options_table_entry(parent),
|
||||
options_table_entry(parent)->name, value,
|
||||
|
||||
121
format.c
121
format.c
@@ -2187,6 +2187,106 @@ format_cb_pane_dead_time(struct format_tree *ft)
|
||||
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. */
|
||||
static void *
|
||||
format_cb_pane_format(struct format_tree *ft)
|
||||
@@ -3503,6 +3603,21 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_bottom", FORMAT_TABLE_STRING,
|
||||
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,
|
||||
format_cb_current_command
|
||||
},
|
||||
@@ -3554,6 +3669,12 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_last", FORMAT_TABLE_STRING,
|
||||
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,
|
||||
format_cb_pane_left
|
||||
},
|
||||
|
||||
461
hooks.c
Normal file
461
hooks.c
Normal file
@@ -0,0 +1,461 @@
|
||||
/* $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
110
input.c
@@ -174,6 +174,8 @@ static void input_osc_110(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_133(struct input_ctx *, const char *);
|
||||
static void input_fire_pane_title_changed(struct window_pane *,
|
||||
const char *);
|
||||
|
||||
/* Transition entry/exit handlers. */
|
||||
static void input_clear(struct input_ctx *);
|
||||
@@ -210,6 +212,21 @@ static int input_end_bel(struct input_ctx *);
|
||||
/* Command table comparison function. */
|
||||
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. */
|
||||
struct input_table_entry {
|
||||
int ch;
|
||||
@@ -1017,6 +1034,8 @@ input_parse_pane(struct window_pane *wp)
|
||||
size_t 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);
|
||||
window_pane_update_used_data(wp, &wp->offset, new_size);
|
||||
}
|
||||
@@ -2180,7 +2199,7 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
|
||||
screen_pop_title(sctx->s);
|
||||
if (wp == NULL)
|
||||
break;
|
||||
notify_pane("pane-title-changed", wp);
|
||||
events_fire_pane("pane-title-changed", wp);
|
||||
server_redraw_window_borders(w);
|
||||
server_status_window(w);
|
||||
break;
|
||||
@@ -2700,7 +2719,7 @@ input_exit_osc(struct input_ctx *ictx)
|
||||
if (wp != NULL &&
|
||||
options_get_number(wp->options, "allow-set-title") &&
|
||||
screen_set_title(sctx->s, p, 1)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
input_fire_pane_title_changed(wp, p);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@@ -2778,7 +2797,7 @@ input_exit_apc(struct input_ctx *ictx)
|
||||
if (wp != NULL &&
|
||||
options_get_number(wp->options, "allow-set-title") &&
|
||||
screen_set_title(sctx->s, ictx->input_buf, 1)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
input_fire_pane_title_changed(wp, ictx->input_buf);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@@ -3146,7 +3165,8 @@ input_osc_12(struct input_ctx *ictx, const char *p)
|
||||
c = ictx->ctx.s->ccolour;
|
||||
if (c == -1)
|
||||
c = ictx->ctx.s->default_ccolour;
|
||||
input_osc_colour_reply(ictx, 1, 12, 0, c, ictx->input_end);
|
||||
input_osc_colour_reply(ictx, 1, 12, 0, c,
|
||||
ictx->input_end);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3166,24 +3186,92 @@ input_osc_112(struct input_ctx *ictx, const char *p)
|
||||
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. */
|
||||
static void
|
||||
input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
struct grid *gd = ictx->ctx.s->grid;
|
||||
u_int line = ictx->ctx.s->cy + gd->hsize;
|
||||
struct grid_line *gl;
|
||||
struct grid_line *gl = NULL;
|
||||
const char *errstr;
|
||||
int status;
|
||||
|
||||
if (line > gd->hsize + gd->sy - 1)
|
||||
return;
|
||||
gl = grid_get_line(gd, line);
|
||||
if (line <= gd->hsize + gd->sy - 1)
|
||||
gl = grid_get_line(gd, line);
|
||||
|
||||
switch (*p) {
|
||||
case 'A':
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
if (gl != NULL)
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
if (wp != NULL) {
|
||||
wp->last_prompt_time = time(NULL);
|
||||
events_fire_pane("pane-shell-prompt", wp);
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
gl->flags |= GRID_LINE_START_OUTPUT;
|
||||
if (gl != NULL)
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -3289,7 +3377,7 @@ input_osc_52(struct input_ctx *ictx, const char *p)
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
screen_write_setselection(&ctx, clip, out, outlen);
|
||||
screen_write_stop(&ctx);
|
||||
notify_pane("pane-set-clipboard", wp);
|
||||
events_fire_pane("pane-set-clipboard", wp);
|
||||
paste_add(NULL, out, outlen);
|
||||
}
|
||||
}
|
||||
|
||||
13
monitor.c
13
monitor.c
@@ -1,7 +1,7 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -53,7 +53,7 @@ struct monitor_item {
|
||||
|
||||
enum monitor_type type;
|
||||
u_int id;
|
||||
u_int flags;
|
||||
int flags;
|
||||
|
||||
char *last;
|
||||
struct monitor_panes panes;
|
||||
@@ -198,7 +198,9 @@ monitor_check_value(struct monitor_set *ms, struct monitor_item *me,
|
||||
{
|
||||
if (*last == NULL) {
|
||||
*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);
|
||||
return;
|
||||
}
|
||||
@@ -208,7 +210,8 @@ monitor_check_value(struct monitor_set *ms, struct monitor_item *me,
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_report(ms, me, s, wl, wp, value, *last);
|
||||
if ((~me->flags & MONITOR_NOTIFY_TRUE) || format_true(value))
|
||||
monitor_report(ms, me, s, wl, wp, value, *last);
|
||||
free(*last);
|
||||
*last = value;
|
||||
}
|
||||
@@ -621,7 +624,7 @@ fail:
|
||||
/* Add a subscription. */
|
||||
void
|
||||
monitor_add(struct monitor_set *ms, const char *name, enum monitor_type type,
|
||||
int id, const char *format, u_int flags)
|
||||
int id, const char *format, int flags)
|
||||
{
|
||||
struct monitor_item *me, find = { .name = (char *)name };
|
||||
struct timeval tv = { .tv_sec = 1 };
|
||||
|
||||
@@ -1932,12 +1932,22 @@ 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-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-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-shell-prompt", ""),
|
||||
OPTIONS_TABLE_PANE_HOOK("pane-title-changed", ""),
|
||||
OPTIONS_TABLE_HOOK("session-closed", ""),
|
||||
OPTIONS_TABLE_HOOK("session-created", ""),
|
||||
@@ -1948,6 +1958,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 }
|
||||
|
||||
122
tmux.1
122
tmux.1
@@ -6325,11 +6325,7 @@ 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\\""
|
||||
.Ed
|
||||
.Pp
|
||||
All the notifications listed in the
|
||||
.Sx CONTROL MODE
|
||||
section are hooks (without any arguments), except
|
||||
.Ic %exit .
|
||||
The following additional hooks are available:
|
||||
The following hooks are available in addition to after hooks:
|
||||
.Bl -tag -width "XXXXXXXXXXXXXXXXXXXXXX"
|
||||
.It alert\-activity
|
||||
Run when a window has activity.
|
||||
@@ -6348,11 +6344,11 @@ Run when a client becomes the latest active client of its session.
|
||||
.It client\-attached
|
||||
Run when a client is attached.
|
||||
.It client\-detached
|
||||
Run when a client is detached
|
||||
Run when a client is detached.
|
||||
.It client\-focus\-in
|
||||
Run when focus enters a client
|
||||
Run when focus enters a client.
|
||||
.It client\-focus\-out
|
||||
Run when focus exits a client
|
||||
Run when focus exits a client.
|
||||
.It client\-resized
|
||||
Run when a client is resized.
|
||||
.It client\-session\-changed
|
||||
@@ -6363,6 +6359,21 @@ 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\-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
|
||||
Run when the program running in a pane exits, but
|
||||
.Ic remain\-on\-exit
|
||||
@@ -6377,20 +6388,40 @@ option is on.
|
||||
Run when the focus exits a pane, if the
|
||||
.Ic focus\-events
|
||||
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
|
||||
Run when the terminal clipboard is set using the
|
||||
.Xr xterm 1
|
||||
escape sequence.
|
||||
.It session\-created
|
||||
Run when a new session created.
|
||||
.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 closed.
|
||||
Run when a session is closed.
|
||||
.It session\-created
|
||||
Run when a new session is created.
|
||||
.It session\-renamed
|
||||
Run when a session is renamed.
|
||||
.It session\-window\-changed
|
||||
Run when a session changes its active window.
|
||||
.It window\-layout\-changed
|
||||
Run when a window layout is changed.
|
||||
.It window\-linked
|
||||
Run when a window is linked into a session.
|
||||
.It window\-pane\-changed
|
||||
Run when a window changes its active pane.
|
||||
.It window\-renamed
|
||||
Run when a window is renamed.
|
||||
.It window\-resized
|
||||
@@ -6398,6 +6429,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
|
||||
@@ -6405,13 +6440,15 @@ Run when a window is unlinked from a session.
|
||||
Hooks are managed with these commands:
|
||||
.Bl -tag -width Ds
|
||||
.It Xo Ic set\-hook
|
||||
.Op Fl agpRuw
|
||||
.Op Fl agpERTuw
|
||||
.Op Fl B Ar name:what:format
|
||||
.Op Fl t Ar target\-pane
|
||||
.Ar hook\-name
|
||||
.Op Ar command
|
||||
.Xc
|
||||
Without
|
||||
.Fl E
|
||||
or
|
||||
.Fl R ,
|
||||
sets (or with
|
||||
.Fl u
|
||||
@@ -6434,6 +6471,11 @@ is the hook to run,
|
||||
selects the session, pane, all panes, window, or all windows, and
|
||||
.Ar format
|
||||
is expanded once a second.
|
||||
With
|
||||
.Fl T ,
|
||||
the hook is run only when
|
||||
.Ar format
|
||||
is true.
|
||||
For monitor hooks,
|
||||
.Ar name
|
||||
must begin with
|
||||
@@ -6452,6 +6494,14 @@ the subscription named by
|
||||
is removed.
|
||||
.Pp
|
||||
With
|
||||
.Fl E ,
|
||||
fire the user event named
|
||||
.Ar hook\-name .
|
||||
.Ar hook\-name
|
||||
must begin with
|
||||
.Ql @ .
|
||||
.Pp
|
||||
With
|
||||
.Fl R ,
|
||||
run
|
||||
.Ar hook\-name
|
||||
@@ -7161,6 +7211,11 @@ 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_bg" Ta "" Ta "Pane background colour"
|
||||
.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_path" Ta "" Ta "Current path if available"
|
||||
.It Li "pane_dead" Ta "" Ta "1 if pane is dead"
|
||||
@@ -7178,6 +7233,8 @@ The following variables are available, where appropriate:
|
||||
.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_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_marked" Ta "" Ta "1 if this is the marked pane"
|
||||
.It Li "pane_marked_set" Ta "" Ta "1 if a marked pane is set"
|
||||
@@ -8562,8 +8619,10 @@ or the current pane if omitted) after the command finishes.
|
||||
If the command fails, the exit status is also displayed.
|
||||
.Tg wait
|
||||
.It Xo Ic wait\-for
|
||||
.Op Fl L | S | U
|
||||
.Ar channel
|
||||
.Op Fl ELSUlv
|
||||
.Op Fl F Ar format
|
||||
.Op Fl w Ar waiter
|
||||
.Ar name
|
||||
.Xc
|
||||
.D1 Pq alias: Ic wait
|
||||
When used without options, prevents the client from exiting until woken using
|
||||
@@ -8576,6 +8635,41 @@ 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
|
||||
.Ic wait\-for
|
||||
.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
|
||||
.Sh EXIT MESSAGES
|
||||
When a
|
||||
|
||||
136
tmux.h
136
tmux.h
@@ -49,6 +49,9 @@ struct cmdq_state;
|
||||
struct cmds;
|
||||
struct control_state;
|
||||
struct environ;
|
||||
struct event_payload;
|
||||
struct event_payload_item;
|
||||
struct events_sink;
|
||||
struct format_job_tree;
|
||||
struct format_tree;
|
||||
struct hyperlinks_uri;
|
||||
@@ -1298,6 +1301,7 @@ struct window_pane {
|
||||
#define PANE_UNSEENCHANGES 0x4000
|
||||
#define PANE_REDRAWSCROLLBAR 0x8000
|
||||
#define PANE_DESTROYED 0x10000
|
||||
#define PANE_CMDRUNNING 0x20000
|
||||
|
||||
bitstr_t *sync_dirty;
|
||||
u_int sync_dirty_size;
|
||||
@@ -1320,6 +1324,12 @@ struct window_pane {
|
||||
struct cmdq_item *wait_item; /* new-pane -W: waiting for pane exit */
|
||||
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;
|
||||
struct bufferevent *event;
|
||||
|
||||
@@ -2331,6 +2341,7 @@ enum monitor_type {
|
||||
MONITOR_ALL_WINDOWS
|
||||
};
|
||||
#define MONITOR_NOTIFY_INITIAL 0x1
|
||||
#define MONITOR_NOTIFY_TRUE 0x2
|
||||
struct monitor_change {
|
||||
const char *name;
|
||||
const char *value;
|
||||
@@ -2343,6 +2354,23 @@ struct monitor_change {
|
||||
};
|
||||
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. */
|
||||
struct key_binding {
|
||||
key_code key;
|
||||
@@ -2652,29 +2680,78 @@ char *format_grid_hyperlink(struct grid *, u_int, u_int,
|
||||
struct screen *);
|
||||
char *format_grid_line(struct grid *, u_int);
|
||||
|
||||
/* format-draw.c */
|
||||
void format_draw(struct screen_write_ctx *,
|
||||
const struct grid_cell *, u_int, const char *,
|
||||
struct style_ranges *, int);
|
||||
u_int format_width(const char *);
|
||||
char *format_trim_left(const char *, u_int);
|
||||
char *format_trim_right(const char *, 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 *);
|
||||
|
||||
/* notify.c */
|
||||
void notify_hook(struct cmdq_item *, const char *);
|
||||
void notify_monitor_add(struct cmdq_item *, struct options *,
|
||||
/* 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 */
|
||||
void format_draw(struct screen_write_ctx *, const struct grid_cell *,
|
||||
u_int, const char *, struct style_ranges *, int);
|
||||
u_int format_width(const char *);
|
||||
char *format_trim_left(const char *, u_int);
|
||||
char *format_trim_right(const char *, u_int);
|
||||
|
||||
/* hooks.c */
|
||||
void hooks_add_event(const char *);
|
||||
int hooks_valid_event_name(const char *);
|
||||
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 *,
|
||||
struct cmd_find_state *, struct session *);
|
||||
void notify_monitor_remove(struct options *, const char *);
|
||||
void notify_monitor_free(void *);
|
||||
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);
|
||||
int, struct cmd_find_state *, struct session *);
|
||||
void hooks_monitor_remove(struct options *, const char *);
|
||||
void hooks_monitor_free(void *);
|
||||
char *hooks_monitor_to_string(struct options_entry *);
|
||||
|
||||
/* options.c */
|
||||
struct options *options_create(struct options *);
|
||||
@@ -3882,7 +3959,7 @@ void monitor_destroy(struct monitor_set *);
|
||||
int monitor_parse(const char *, char **, enum monitor_type *, int *,
|
||||
char **);
|
||||
void monitor_add(struct monitor_set *, const char *, enum monitor_type, int,
|
||||
const char *, u_int);
|
||||
const char *, int);
|
||||
void monitor_remove(struct monitor_set *, const char *);
|
||||
|
||||
/* control.c */
|
||||
@@ -3905,20 +3982,7 @@ void control_add_sub(struct client *, const char *, enum monitor_type, int,
|
||||
void control_remove_sub(struct client *, const char *);
|
||||
|
||||
/* control-notify.c */
|
||||
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 *);
|
||||
void control_build_events(void);
|
||||
|
||||
/* session.c */
|
||||
extern struct sessions sessions;
|
||||
|
||||
157
window.c
157
window.c
@@ -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_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_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);
|
||||
@@ -86,6 +86,7 @@ struct window_pane_prompt {
|
||||
status_prompt_input_cb inputcb;
|
||||
prompt_free_cb freecb;
|
||||
void *data;
|
||||
enum prompt_type type;
|
||||
};
|
||||
|
||||
int
|
||||
@@ -94,6 +95,78 @@ window_cmp(struct window *w1, struct window *w2)
|
||||
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
|
||||
winlink_cmp(struct winlink *wl1, struct winlink *wl2)
|
||||
{
|
||||
@@ -444,13 +517,15 @@ window_pane_remove_ref(struct window_pane *wp, const char *from)
|
||||
void
|
||||
window_set_name(struct window *w, const char *new_name, int untrusted)
|
||||
{
|
||||
char *name;
|
||||
char *last, *name;
|
||||
|
||||
name = clean_name(new_name, untrusted);
|
||||
if (name != NULL) {
|
||||
last = xstrdup(w->name);
|
||||
free(w->name);
|
||||
w->name = name;
|
||||
notify_window("window-renamed", w);
|
||||
window_fire_renamed(w, last);
|
||||
free(last);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,13 +635,13 @@ window_pane_update_focus(struct window_pane *wp)
|
||||
log_debug("%s: %%%u focus out", __func__, wp->id);
|
||||
if (wp->base.mode & MODE_FOCUSON)
|
||||
bufferevent_write(wp->event, "\033[O", 3);
|
||||
notify_pane("pane-focus-out", wp);
|
||||
events_fire_pane("pane-focus-out", wp);
|
||||
wp->flags &= ~PANE_FOCUSED;
|
||||
} else if (focused && (~wp->flags & PANE_FOCUSED)) {
|
||||
log_debug("%s: %%%u focus in", __func__, wp->id);
|
||||
if (wp->base.mode & MODE_FOCUSON)
|
||||
bufferevent_write(wp->event, "\033[I", 3);
|
||||
notify_pane("pane-focus-in", wp);
|
||||
events_fire_pane("pane-focus-in", wp);
|
||||
wp->flags |= PANE_FOCUSED;
|
||||
} else
|
||||
log_debug("%s: %%%u focus unchanged", __func__, wp->id);
|
||||
@@ -602,7 +677,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
|
||||
server_redraw_window(w);
|
||||
|
||||
if (notify)
|
||||
notify_window("window-pane-changed", w);
|
||||
window_fire_pane_changed(w, w->active, lastwp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
@@ -792,7 +867,8 @@ window_zoom(struct window_pane *wp)
|
||||
w->saved_layout_root = w->layout_root;
|
||||
layout_init(w, wp);
|
||||
w->flags |= WINDOW_ZOOMED;
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-zoomed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
|
||||
redraw_invalidate_scene(w);
|
||||
return (0);
|
||||
@@ -818,8 +894,10 @@ window_unzoom(struct window *w, int notify)
|
||||
}
|
||||
layout_fix_panes(w, NULL);
|
||||
|
||||
if (notify)
|
||||
notify_window("window-layout-changed", w);
|
||||
if (notify) {
|
||||
events_fire_window("window-unzoomed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
}
|
||||
|
||||
redraw_invalidate_scene(w);
|
||||
return (0);
|
||||
@@ -901,7 +979,7 @@ window_lost_pane(struct window *w, struct window_pane *wp)
|
||||
if (w->active != NULL) {
|
||||
window_pane_stack_remove(&w->last_panes, w->active);
|
||||
w->active->flags |= PANE_CHANGED;
|
||||
notify_window("window-pane-changed", w);
|
||||
events_fire_window("window-pane-changed", w);
|
||||
window_update_focus(w);
|
||||
}
|
||||
}
|
||||
@@ -1106,6 +1184,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
|
||||
wp->window = w;
|
||||
wp->options = options_create(w->options);
|
||||
wp->flags = PANE_STYLECHANGED;
|
||||
wp->cmd_status = -1;
|
||||
|
||||
wp->id = next_window_pane_id++;
|
||||
RB_INSERT(window_pane_tree, &all_window_panes, wp);
|
||||
@@ -1230,9 +1309,9 @@ window_pane_destroy(struct window_pane *wp)
|
||||
window_pane_wait_finish(wp);
|
||||
spawn_editor_finish(wp);
|
||||
|
||||
window_pane_clear_prompt(wp);
|
||||
RB_REMOVE(window_pane_tree, &all_window_panes, wp);
|
||||
wp->flags |= PANE_DESTROYED;
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
window_pane_free_modes(wp);
|
||||
screen_write_clear_dirty(wp);
|
||||
@@ -1363,6 +1442,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;
|
||||
@@ -1385,6 +1466,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
|
||||
@@ -1394,9 +1486,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)
|
||||
@@ -1422,7 +1518,9 @@ window_pane_set_mode(struct window_pane *wp, struct window_pane *swp,
|
||||
|
||||
server_redraw_window_borders(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);
|
||||
}
|
||||
@@ -1433,11 +1531,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);
|
||||
@@ -1454,13 +1554,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);
|
||||
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)
|
||||
server_kill_pane(wp);
|
||||
@@ -1523,6 +1626,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);
|
||||
@@ -1540,19 +1644,28 @@ 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;
|
||||
|
||||
if (~wp->flags & PANE_DESTROYED)
|
||||
window_fire_pane_prompt("pane-prompt-closed", wp, type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Does this pane have an open prompt? */
|
||||
|
||||
Reference in New Issue
Block a user