mirror of
https://github.com/tmux/tmux.git
synced 2026-07-07 09:59:30 +00:00
Add set-hook -B install a subscription like in control mode.
Subscriptions are formats which are checked once a second and if changed invoke a hook. show-hooks -B lists.
This commit is contained in:
@@ -46,36 +46,17 @@ const struct cmd_entry cmd_refresh_client_entry = {
|
||||
static void
|
||||
cmd_refresh_client_update_subscription(struct client *tc, const char *value)
|
||||
{
|
||||
char *copy, *split, *name, *what;
|
||||
enum monitor_type subtype;
|
||||
int subid = -1;
|
||||
char *name, *format;
|
||||
enum monitor_type type;
|
||||
int id;
|
||||
|
||||
copy = name = xstrdup(value);
|
||||
if ((split = strchr(copy, ':')) == NULL) {
|
||||
control_remove_sub(tc, copy);
|
||||
goto out;
|
||||
if (monitor_parse(value, &name, &type, &id, &format) != 0) {
|
||||
control_remove_sub(tc, value);
|
||||
return;
|
||||
}
|
||||
*split++ = '\0';
|
||||
|
||||
what = split;
|
||||
if ((split = strchr(what, ':')) == NULL)
|
||||
goto out;
|
||||
*split++ = '\0';
|
||||
|
||||
if (strcmp(what, "%*") == 0)
|
||||
subtype = MONITOR_ALL_PANES;
|
||||
else if (sscanf(what, "%%%d", &subid) == 1 && subid >= 0)
|
||||
subtype = MONITOR_PANE;
|
||||
else if (strcmp(what, "@*") == 0)
|
||||
subtype = MONITOR_ALL_WINDOWS;
|
||||
else if (sscanf(what, "@%d", &subid) == 1 && subid >= 0)
|
||||
subtype = MONITOR_WINDOW;
|
||||
else
|
||||
subtype = MONITOR_SESSION;
|
||||
control_add_sub(tc, name, subtype, subid, split);
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
control_add_sub(tc, name, type, id, format);
|
||||
free(name);
|
||||
free(format);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
|
||||
101
cmd-set-option.c
101
cmd-set-option.c
@@ -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_monitor_exec(struct cmdq_item *,
|
||||
struct args *, int);
|
||||
|
||||
const struct cmd_entry cmd_set_option_entry = {
|
||||
.name = "set-option",
|
||||
@@ -62,8 +64,9 @@ const struct cmd_entry cmd_set_hook_entry = {
|
||||
.name = "set-hook",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "agpRt:uw", 1, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpRuw] " CMD_TARGET_PANE_USAGE " hook [command]",
|
||||
.args = { "agpRt:uB:w", 0, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpRuw] [-B name:what:format] " CMD_TARGET_PANE_USAGE " "
|
||||
"[hook] [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -72,14 +75,100 @@ const struct cmd_entry cmd_set_hook_entry = {
|
||||
};
|
||||
|
||||
static enum args_parse_type
|
||||
cmd_set_option_args_parse(__unused struct args *args, u_int idx,
|
||||
cmd_set_option_args_parse(struct args *args, u_int idx,
|
||||
__unused char **cause)
|
||||
{
|
||||
if (args_has(args, 'B'))
|
||||
return (ARGS_PARSE_COMMANDS_OR_STRING);
|
||||
if (idx == 1)
|
||||
return (ARGS_PARSE_COMMANDS_OR_STRING);
|
||||
return (ARGS_PARSE_STRING);
|
||||
}
|
||||
|
||||
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;
|
||||
char *cause = NULL, *name = NULL, *format = NULL;
|
||||
char *expanded = NULL, *newvalue = NULL;
|
||||
const char *value, *old;
|
||||
enum monitor_type type;
|
||||
int id, scope;
|
||||
|
||||
if (args_count(args) > 1) {
|
||||
cmdq_error(item, "too many arguments");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
value = args_get(args, 'B');
|
||||
if (args_has(args, 'u')) {
|
||||
if (monitor_parse(value, &name, &type, &id, &format) != 0)
|
||||
name = xstrdup(value);
|
||||
free(format);
|
||||
format = NULL;
|
||||
} else {
|
||||
if (monitor_parse(value, &name, &type, &id, &format) != 0) {
|
||||
cmdq_error(item, "invalid subscription: %s", value);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (*name != '@') {
|
||||
cmdq_error(item, "monitor hook name must start with @");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
scope = options_scope_from_name(args, window, name, target, &oo,
|
||||
&cause);
|
||||
if (scope == OPTIONS_TABLE_NONE) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
cmd_find_copy_state(&fs, target);
|
||||
|
||||
if (args_has(args, 'u')) {
|
||||
notify_monitor_remove(oo, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (args_count(args) != 0) {
|
||||
value = args_string(args, 0);
|
||||
if (args_has(args, 'F')) {
|
||||
expanded = format_single_from_target(item, value);
|
||||
value = expanded;
|
||||
}
|
||||
o = options_get_only(oo, name);
|
||||
if (!args_has(args, 'o') || o == NULL) {
|
||||
if (args_has(args, 'a') && o != NULL) {
|
||||
old = options_get_string(oo, name);
|
||||
xasprintf(&newvalue, "%s%s", old, value);
|
||||
value = newvalue;
|
||||
}
|
||||
options_set_string(oo, name, 0, "%s", value);
|
||||
options_push_changes(name);
|
||||
}
|
||||
}
|
||||
|
||||
notify_monitor_add(item, oo, name, type, id, format, &fs, target->s);
|
||||
|
||||
out:
|
||||
free(newvalue);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(format);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(newvalue);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(format);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -96,6 +185,12 @@ 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, 'B'))
|
||||
return (cmd_set_hook_monitor_exec(item, args, window));
|
||||
if (args_count(args) == 0) {
|
||||
cmdq_error(item, "missing argument");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
/* Expand argument. */
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
|
||||
@@ -32,6 +32,10 @@ static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
|
||||
struct options_entry *, int, int);
|
||||
static void cmd_show_hooks_print_monitor(struct cmdq_item *,
|
||||
struct options_entry *);
|
||||
static enum cmd_retval cmd_show_hooks_monitor(struct cmd *, struct cmdq_item *,
|
||||
int, struct options *);
|
||||
static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
|
||||
int, struct options *);
|
||||
|
||||
@@ -65,8 +69,8 @@ const struct cmd_entry cmd_show_hooks_entry = {
|
||||
.name = "show-hooks",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "gpt:w", 0, 1, NULL },
|
||||
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE " [hook]",
|
||||
.args = { "Bgpt:w", 0, 1, NULL },
|
||||
.usage = "[-Bgpw] " CMD_TARGET_PANE_USAGE " [hook]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
|
||||
@@ -96,6 +100,9 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (cmd_get_entry(self) == &cmd_show_hooks_entry &&
|
||||
args_has(args, 'B'))
|
||||
return (cmd_show_hooks_monitor(self, item, scope, oo));
|
||||
return (cmd_show_options_all(self, item, scope, oo));
|
||||
}
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
@@ -125,8 +132,13 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
parent = 1;
|
||||
} else
|
||||
parent = 0;
|
||||
if (o != NULL)
|
||||
cmd_show_options_print(self, item, o, idx, parent);
|
||||
if (o != NULL) {
|
||||
if (cmd_get_entry(self) == &cmd_show_hooks_entry &&
|
||||
args_has(args, 'B'))
|
||||
cmd_show_hooks_print_monitor(item, o);
|
||||
else
|
||||
cmd_show_options_print(self, item, o, idx, parent);
|
||||
}
|
||||
else if (*name == '@') {
|
||||
if (args_has(args, 'q'))
|
||||
goto out;
|
||||
@@ -196,6 +208,33 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_show_hooks_print_monitor(struct cmdq_item *item, struct options_entry *o)
|
||||
{
|
||||
char *value;
|
||||
|
||||
value = notify_monitor_to_string(o);
|
||||
if (value == NULL)
|
||||
return;
|
||||
cmdq_print(item, "%s", value);
|
||||
free(value);
|
||||
}
|
||||
|
||||
/* Show all hook monitors. */
|
||||
static enum cmd_retval
|
||||
cmd_show_hooks_monitor(__unused struct cmd *self, struct cmdq_item *item,
|
||||
__unused int scope, struct options *oo)
|
||||
{
|
||||
struct options_entry *o;
|
||||
|
||||
o = options_first(oo);
|
||||
while (o != NULL) {
|
||||
cmd_show_hooks_print_monitor(item, o);
|
||||
o = options_next(o);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
struct options *oo)
|
||||
|
||||
@@ -702,7 +702,7 @@ control_start(struct client *c)
|
||||
RB_INIT(&cs->panes);
|
||||
TAILQ_INIT(&cs->pending_list);
|
||||
TAILQ_INIT(&cs->all_blocks);
|
||||
cs->subs = monitor_create(c, control_sub_change, NULL);
|
||||
cs->subs = monitor_create_client(c, control_sub_change, NULL);
|
||||
|
||||
cs->read_event = bufferevent_new(c->fd, control_read_callback,
|
||||
control_write_callback, control_error_callback, c);
|
||||
@@ -776,7 +776,7 @@ control_add_sub(struct client *c, const char *name, enum monitor_type type,
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
|
||||
monitor_add(cs->subs, name, type, id, format);
|
||||
monitor_add(cs->subs, name, type, id, format, MONITOR_NOTIFY_INITIAL);
|
||||
}
|
||||
|
||||
/* Remove a subscription. */
|
||||
|
||||
244
monitor.c
244
monitor.c
@@ -29,6 +29,7 @@ struct monitor_pane {
|
||||
u_int pane;
|
||||
u_int idx;
|
||||
char *last;
|
||||
u_int generation;
|
||||
|
||||
RB_ENTRY(monitor_pane) entry;
|
||||
};
|
||||
@@ -39,6 +40,7 @@ struct monitor_window {
|
||||
u_int window;
|
||||
u_int idx;
|
||||
char *last;
|
||||
u_int generation;
|
||||
|
||||
RB_ENTRY(monitor_window) entry;
|
||||
};
|
||||
@@ -51,6 +53,7 @@ struct monitor_item {
|
||||
|
||||
enum monitor_type type;
|
||||
u_int id;
|
||||
u_int flags;
|
||||
|
||||
char *last;
|
||||
struct monitor_panes panes;
|
||||
@@ -63,15 +66,33 @@ RB_HEAD(monitor_items, monitor_item);
|
||||
/* Monitored subscription set. */
|
||||
struct monitor_set {
|
||||
struct client *client;
|
||||
struct session *session;
|
||||
monitor_cb cb;
|
||||
void *data;
|
||||
|
||||
struct monitor_items items;
|
||||
struct event timer;
|
||||
u_int generation;
|
||||
};
|
||||
|
||||
static void monitor_timer(__unused int, __unused short, void *);
|
||||
|
||||
/* Get the session for this monitor set. */
|
||||
static struct session *
|
||||
monitor_get_session(struct monitor_set *ms)
|
||||
{
|
||||
struct session *s;
|
||||
|
||||
if (ms->client != NULL)
|
||||
return (ms->client->session);
|
||||
s = ms->session;
|
||||
if (s == NULL)
|
||||
return (RB_MIN(sessions, &sessions));
|
||||
if (session_find_by_id(s->id) != s)
|
||||
return (NULL);
|
||||
return (s);
|
||||
}
|
||||
|
||||
/* Compare subscriptions. */
|
||||
static int
|
||||
monitor_item_cmp(struct monitor_item *m1, struct monitor_item *m2)
|
||||
@@ -141,38 +162,56 @@ monitor_free_item(struct monitor_set *ms, struct monitor_item *me)
|
||||
static void
|
||||
monitor_report(struct monitor_set *ms, struct monitor_item *me,
|
||||
struct session *s, struct winlink *wl, struct window_pane *wp,
|
||||
const char *value)
|
||||
const char *value, const char *last)
|
||||
{
|
||||
struct monitor_change change;
|
||||
struct monitor_change change = { 0 };
|
||||
|
||||
log_debug("%s: %s changed to %s", __func__, me->name, value);
|
||||
|
||||
change.name = me->name;
|
||||
change.value = value;
|
||||
change.last = last;
|
||||
change.c = ms->client;
|
||||
change.s = s;
|
||||
change.wl = wl;
|
||||
change.wp = wp;
|
||||
log_debug("%s: %s changed to %s", __func__, me->name, value);
|
||||
ms->cb(&change, ms->data);
|
||||
}
|
||||
|
||||
/* Check a value against its last value and report if changed. */
|
||||
static void
|
||||
monitor_check_value(struct monitor_set *ms, struct monitor_item *me,
|
||||
struct session *s, struct winlink *wl, struct window_pane *wp,
|
||||
char *value, char **last)
|
||||
{
|
||||
if (*last == NULL) {
|
||||
*last = value;
|
||||
if (me->flags & MONITOR_NOTIFY_INITIAL)
|
||||
monitor_report(ms, me, s, wl, wp, value, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(value, *last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_report(ms, me, s, wl, wp, value, *last);
|
||||
free(*last);
|
||||
*last = value;
|
||||
}
|
||||
|
||||
/* Check session subscription. */
|
||||
static void
|
||||
monitor_check_session(struct monitor_set *ms, struct monitor_item *me,
|
||||
struct format_tree *ft)
|
||||
{
|
||||
struct session *s = ms->client->session;
|
||||
struct session *s = monitor_get_session(ms);
|
||||
char *value;
|
||||
|
||||
value = format_expand(ft, me->format);
|
||||
|
||||
if (me->last != NULL && strcmp(value, me->last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_report(ms, me, s, NULL, NULL, value);
|
||||
free(me->last);
|
||||
me->last = value;
|
||||
monitor_check_value(ms, me, s, NULL, NULL, value, &me->last);
|
||||
}
|
||||
|
||||
/* Check pane subscription. */
|
||||
@@ -180,7 +219,7 @@ static void
|
||||
monitor_check_pane(struct monitor_set *ms, struct monitor_item *me)
|
||||
{
|
||||
struct client *c = ms->client;
|
||||
struct session *s = c->session;
|
||||
struct session *s = monitor_get_session(ms);
|
||||
struct window_pane *wp;
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
@@ -211,14 +250,7 @@ monitor_check_pane(struct monitor_set *ms, struct monitor_item *me)
|
||||
RB_INSERT(monitor_panes, &me->panes, mp);
|
||||
}
|
||||
|
||||
if (mp->last != NULL && strcmp(value, mp->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
monitor_report(ms, me, s, wl, wp, value);
|
||||
free(mp->last);
|
||||
mp->last = value;
|
||||
monitor_check_value(ms, me, s, wl, wp, value, &mp->last);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +259,7 @@ static void
|
||||
monitor_check_all_panes_one(struct monitor_set *ms, struct monitor_item *me,
|
||||
struct format_tree *ft, struct winlink *wl, struct window_pane *wp)
|
||||
{
|
||||
struct session *s = ms->client->session;
|
||||
struct session *s = monitor_get_session(ms);
|
||||
char *value;
|
||||
struct monitor_pane *mp, find;
|
||||
|
||||
@@ -242,15 +274,24 @@ monitor_check_all_panes_one(struct monitor_set *ms, struct monitor_item *me,
|
||||
mp->idx = wl->idx;
|
||||
RB_INSERT(monitor_panes, &me->panes, mp);
|
||||
}
|
||||
mp->generation = ms->generation;
|
||||
|
||||
if (mp->last != NULL && strcmp(value, mp->last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
monitor_check_value(ms, me, s, wl, wp, value, &mp->last);
|
||||
}
|
||||
|
||||
/* Remove all-panes entries not seen during the current scan. */
|
||||
static void
|
||||
monitor_sweep_all_panes(struct monitor_item *me, u_int generation)
|
||||
{
|
||||
struct monitor_pane *mp, *mp1;
|
||||
|
||||
RB_FOREACH_SAFE(mp, monitor_panes, &me->panes, mp1) {
|
||||
if (mp->generation == generation)
|
||||
continue;
|
||||
RB_REMOVE(monitor_panes, &me->panes, mp);
|
||||
free(mp->last);
|
||||
free(mp);
|
||||
}
|
||||
|
||||
monitor_report(ms, me, s, wl, wp, value);
|
||||
free(mp->last);
|
||||
mp->last = value;
|
||||
}
|
||||
|
||||
/* Check window subscription. */
|
||||
@@ -258,7 +299,7 @@ static void
|
||||
monitor_check_window(struct monitor_set *ms, struct monitor_item *me)
|
||||
{
|
||||
struct client *c = ms->client;
|
||||
struct session *s = c->session;
|
||||
struct session *s = monitor_get_session(ms);
|
||||
struct window *w;
|
||||
struct winlink *wl;
|
||||
struct format_tree *ft;
|
||||
@@ -287,14 +328,7 @@ monitor_check_window(struct monitor_set *ms, struct monitor_item *me)
|
||||
RB_INSERT(monitor_windows, &me->windows, mw);
|
||||
}
|
||||
|
||||
if (mw->last != NULL && strcmp(value, mw->last) == 0) {
|
||||
free(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
monitor_report(ms, me, s, wl, NULL, value);
|
||||
free(mw->last);
|
||||
mw->last = value;
|
||||
monitor_check_value(ms, me, s, wl, NULL, value, &mw->last);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +337,7 @@ static void
|
||||
monitor_check_all_windows_one(struct monitor_set *ms, struct monitor_item *me,
|
||||
struct format_tree *ft, struct winlink *wl)
|
||||
{
|
||||
struct session *s = ms->client->session;
|
||||
struct session *s = monitor_get_session(ms);
|
||||
struct window *w = wl->window;
|
||||
char *value;
|
||||
struct monitor_window *mw, find;
|
||||
@@ -319,15 +353,24 @@ monitor_check_all_windows_one(struct monitor_set *ms, struct monitor_item *me,
|
||||
mw->idx = wl->idx;
|
||||
RB_INSERT(monitor_windows, &me->windows, mw);
|
||||
}
|
||||
mw->generation = ms->generation;
|
||||
|
||||
if (mw->last != NULL && strcmp(value, mw->last) == 0) {
|
||||
free(value);
|
||||
return;
|
||||
monitor_check_value(ms, me, s, wl, NULL, value, &mw->last);
|
||||
}
|
||||
|
||||
/* Remove all-windows entries not seen during the current scan. */
|
||||
static void
|
||||
monitor_sweep_all_windows(struct monitor_item *me, u_int generation)
|
||||
{
|
||||
struct monitor_window *mw, *mw1;
|
||||
|
||||
RB_FOREACH_SAFE(mw, monitor_windows, &me->windows, mw1) {
|
||||
if (mw->generation == generation)
|
||||
continue;
|
||||
RB_REMOVE(monitor_windows, &me->windows, mw);
|
||||
free(mw->last);
|
||||
free(mw);
|
||||
}
|
||||
|
||||
monitor_report(ms, me, s, wl, NULL, value);
|
||||
free(mw->last);
|
||||
mw->last = value;
|
||||
}
|
||||
|
||||
/* Check session subscriptions. */
|
||||
@@ -335,7 +378,7 @@ static void
|
||||
monitor_check_sessions(struct monitor_set *ms)
|
||||
{
|
||||
struct client *c = ms->client;
|
||||
struct session *s = c->session;
|
||||
struct session *s = monitor_get_session(ms);
|
||||
struct monitor_item *me, *me1;
|
||||
struct format_tree *ft;
|
||||
|
||||
@@ -374,12 +417,14 @@ static void
|
||||
monitor_check_all_panes(struct monitor_set *ms)
|
||||
{
|
||||
struct client *c = ms->client;
|
||||
struct session *s = c->session;
|
||||
struct session *s = monitor_get_session(ms);
|
||||
struct monitor_item *me, *me1;
|
||||
struct window_pane *wp;
|
||||
struct format_tree *ft;
|
||||
struct winlink *wl;
|
||||
|
||||
if (++ms->generation == 0)
|
||||
ms->generation = 1;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||
@@ -391,6 +436,10 @@ monitor_check_all_panes(struct monitor_set *ms)
|
||||
format_free(ft);
|
||||
}
|
||||
}
|
||||
RB_FOREACH_SAFE(me, monitor_items, &ms->items, me1) {
|
||||
if (me->type == MONITOR_ALL_PANES)
|
||||
monitor_sweep_all_panes(me, ms->generation);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all-windows subscriptions. */
|
||||
@@ -398,11 +447,13 @@ static void
|
||||
monitor_check_all_windows(struct monitor_set *ms)
|
||||
{
|
||||
struct client *c = ms->client;
|
||||
struct session *s = c->session;
|
||||
struct session *s = monitor_get_session(ms);
|
||||
struct monitor_item *me, *me1;
|
||||
struct format_tree *ft;
|
||||
struct winlink *wl;
|
||||
|
||||
if (++ms->generation == 0)
|
||||
ms->generation = 1;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||
RB_FOREACH_SAFE(me, monitor_items, &ms->items, me1) {
|
||||
@@ -412,6 +463,10 @@ monitor_check_all_windows(struct monitor_set *ms)
|
||||
}
|
||||
format_free(ft);
|
||||
}
|
||||
RB_FOREACH_SAFE(me, monitor_items, &ms->items, me1) {
|
||||
if (me->type == MONITOR_ALL_WINDOWS)
|
||||
monitor_sweep_all_windows(me, ms->generation);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check subscriptions. */
|
||||
@@ -419,7 +474,6 @@ static void
|
||||
monitor_timer(__unused int fd, __unused short events, void *data)
|
||||
{
|
||||
struct monitor_set *ms = data;
|
||||
struct client *c = ms->client;
|
||||
struct monitor_item *me;
|
||||
struct timeval tv = { .tv_sec = 1 };
|
||||
int have_session = 0, have_all_panes = 0;
|
||||
@@ -428,7 +482,7 @@ monitor_timer(__unused int fd, __unused short events, void *data)
|
||||
log_debug("%s: timer fired", __func__);
|
||||
evtimer_add(&ms->timer, &tv);
|
||||
|
||||
if (c->session == NULL)
|
||||
if (monitor_get_session(ms) == NULL)
|
||||
return;
|
||||
|
||||
RB_FOREACH(me, monitor_items, &ms->items) {
|
||||
@@ -458,39 +512,104 @@ monitor_timer(__unused int fd, __unused short events, void *data)
|
||||
}
|
||||
|
||||
/* Create a monitor set. */
|
||||
struct monitor_set *
|
||||
monitor_create(struct client *c, monitor_cb cb, void *data)
|
||||
static struct monitor_set *
|
||||
monitor_create(monitor_cb cb, void *data)
|
||||
{
|
||||
struct monitor_set *ms;
|
||||
|
||||
ms = xcalloc(1, sizeof *ms);
|
||||
ms->client = c;
|
||||
ms->cb = cb;
|
||||
ms->data = data;
|
||||
RB_INIT(&ms->items);
|
||||
return (ms);
|
||||
}
|
||||
|
||||
/* Create a client monitor set. */
|
||||
struct monitor_set *
|
||||
monitor_create_client(struct client *c, monitor_cb cb, void *data)
|
||||
{
|
||||
struct monitor_set *ms;
|
||||
|
||||
ms = monitor_create(cb, data);
|
||||
ms->client = c;
|
||||
return (ms);
|
||||
}
|
||||
|
||||
/* Create a monitor set for a session. */
|
||||
struct monitor_set *
|
||||
monitor_create_session(struct session *s, monitor_cb cb, void *data)
|
||||
{
|
||||
struct monitor_set *ms;
|
||||
|
||||
ms = monitor_create(cb, data);
|
||||
ms->session = s;
|
||||
if (s != NULL)
|
||||
session_add_ref(s, __func__);
|
||||
return (ms);
|
||||
}
|
||||
|
||||
/* Destroy a monitor set. */
|
||||
void
|
||||
monitor_destroy(struct monitor_set *ms)
|
||||
{
|
||||
struct monitor_item *me, *me1;
|
||||
|
||||
if (ms == NULL)
|
||||
return;
|
||||
if (ms != NULL) {
|
||||
if (evtimer_initialized(&ms->timer))
|
||||
evtimer_del(&ms->timer);
|
||||
RB_FOREACH_SAFE(me, monitor_items, &ms->items, me1)
|
||||
monitor_free_item(ms, me);
|
||||
if (ms->session != NULL)
|
||||
session_remove_ref(ms->session, __func__);
|
||||
free(ms);
|
||||
}
|
||||
}
|
||||
|
||||
if (evtimer_initialized(&ms->timer))
|
||||
evtimer_del(&ms->timer);
|
||||
RB_FOREACH_SAFE(me, monitor_items, &ms->items, me1)
|
||||
monitor_free_item(ms, me);
|
||||
free(ms);
|
||||
/* Parse a subscription. */
|
||||
int
|
||||
monitor_parse(const char *value, char **name, enum monitor_type *type, int *id,
|
||||
char **format)
|
||||
{
|
||||
char *copy, *what, *split;
|
||||
|
||||
copy = xstrdup(value);
|
||||
*id = -1;
|
||||
|
||||
what = strchr(copy, ':');
|
||||
if (what == NULL)
|
||||
goto fail;
|
||||
*what++ = '\0';
|
||||
|
||||
split = strchr(what, ':');
|
||||
if (split == NULL)
|
||||
goto fail;
|
||||
*split++ = '\0';
|
||||
|
||||
if (strcmp(what, "%*") == 0)
|
||||
*type = MONITOR_ALL_PANES;
|
||||
else if (sscanf(what, "%%%d", id) == 1 && *id >= 0)
|
||||
*type = MONITOR_PANE;
|
||||
else if (strcmp(what, "@*") == 0)
|
||||
*type = MONITOR_ALL_WINDOWS;
|
||||
else if (sscanf(what, "@%d", id) == 1 && *id >= 0)
|
||||
*type = MONITOR_WINDOW;
|
||||
else
|
||||
*type = MONITOR_SESSION;
|
||||
*name = xstrdup(copy);
|
||||
*format = xstrdup(split);
|
||||
|
||||
free(copy);
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
free(copy);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Add a subscription. */
|
||||
void
|
||||
monitor_add(struct monitor_set *ms, const char *name, enum monitor_type type,
|
||||
int id, const char *format)
|
||||
int id, const char *format, u_int flags)
|
||||
{
|
||||
struct monitor_item *me, find = { .name = (char *)name };
|
||||
struct timeval tv = { .tv_sec = 1 };
|
||||
@@ -503,6 +622,7 @@ monitor_add(struct monitor_set *ms, const char *name, enum monitor_type type,
|
||||
me->format = xstrdup(format);
|
||||
me->type = type;
|
||||
me->id = id;
|
||||
me->flags = flags;
|
||||
RB_INIT(&me->panes);
|
||||
RB_INIT(&me->windows);
|
||||
RB_INSERT(monitor_items, &ms->items, me);
|
||||
|
||||
218
notify.c
218
notify.c
@@ -28,12 +28,25 @@ struct notify_entry {
|
||||
const char *name;
|
||||
struct cmd_find_state fs;
|
||||
struct format_tree *formats;
|
||||
struct options *oo;
|
||||
|
||||
struct client *client;
|
||||
struct session *session;
|
||||
struct window *window;
|
||||
int pane;
|
||||
const char *pbname;
|
||||
int expand;
|
||||
};
|
||||
|
||||
struct notify_monitor {
|
||||
struct options *oo;
|
||||
|
||||
struct monitor_set *set;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
enum monitor_type type;
|
||||
int id;
|
||||
char *format;
|
||||
};
|
||||
|
||||
static struct cmdq_item *
|
||||
@@ -51,7 +64,31 @@ notify_insert_one_hook(struct cmdq_item *item, struct notify_entry *ne,
|
||||
free(s);
|
||||
}
|
||||
new_item = cmdq_get_command(cmdlist, state);
|
||||
return (cmdq_insert_after(item, new_item));
|
||||
if (item != NULL)
|
||||
return (cmdq_insert_after(item, new_item));
|
||||
return (cmdq_append(NULL, new_item));
|
||||
}
|
||||
|
||||
static struct cmd_parse_result *
|
||||
notify_parse_hook(struct notify_entry *ne, struct cmd_find_state *fs,
|
||||
const char *value)
|
||||
{
|
||||
struct cmd_parse_result *pr;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
|
||||
if (!ne->expand)
|
||||
return (cmd_parse_from_string(value, NULL));
|
||||
|
||||
ft = format_create_defaults(NULL, ne->client, fs->s, fs->wl, fs->wp);
|
||||
if (ne->formats != NULL)
|
||||
format_merge(ft, ne->formats);
|
||||
expanded = format_expand(ft, value);
|
||||
format_free(ft);
|
||||
|
||||
pr = cmd_parse_from_string(expanded, NULL);
|
||||
free(expanded);
|
||||
return (pr);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -74,18 +111,23 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
|
||||
else
|
||||
cmd_find_copy_state(&fs, &ne->fs);
|
||||
|
||||
if (fs.s == NULL)
|
||||
oo = global_s_options;
|
||||
else
|
||||
oo = fs.s->options;
|
||||
o = options_get(oo, ne->name);
|
||||
if (o == NULL && fs.wp != NULL) {
|
||||
oo = fs.wp->options;
|
||||
o = options_get(oo, ne->name);
|
||||
}
|
||||
if (o == NULL && fs.wl != NULL) {
|
||||
oo = fs.wl->window->options;
|
||||
if (ne->oo != NULL) {
|
||||
oo = ne->oo;
|
||||
o = options_get_only(oo, ne->name);
|
||||
} else {
|
||||
if (fs.s == NULL)
|
||||
oo = global_s_options;
|
||||
else
|
||||
oo = fs.s->options;
|
||||
o = options_get(oo, ne->name);
|
||||
if (o == NULL && fs.wp != NULL) {
|
||||
oo = fs.wp->options;
|
||||
o = options_get(oo, ne->name);
|
||||
}
|
||||
if (o == NULL && fs.wl != NULL) {
|
||||
oo = fs.wl->window->options;
|
||||
o = options_get(oo, ne->name);
|
||||
}
|
||||
}
|
||||
if (o == NULL) {
|
||||
log_debug("%s: hook %s not found", __func__, ne->name);
|
||||
@@ -97,7 +139,7 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
|
||||
|
||||
if (*ne->name == '@') {
|
||||
value = options_get_string(oo, ne->name);
|
||||
pr = cmd_parse_from_string(value, NULL);
|
||||
pr = notify_parse_hook(ne, &fs, value);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_ERROR:
|
||||
log_debug("%s: can't parse hook %s: %s", __func__,
|
||||
@@ -111,8 +153,24 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
|
||||
} else {
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
cmdlist = options_array_item_value(a)->cmdlist;
|
||||
item = notify_insert_one_hook(item, ne, cmdlist, state);
|
||||
if (ne->expand) {
|
||||
value = options_array_item_value(a)->string;
|
||||
pr = notify_parse_hook(ne, &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 = notify_insert_one_hook(item, ne,
|
||||
pr->cmdlist, state);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cmdlist = options_array_item_value(a)->cmdlist;
|
||||
item = notify_insert_one_hook(item, ne, cmdlist,
|
||||
state);
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
}
|
||||
@@ -176,6 +234,136 @@ notify_callback(struct cmdq_item *item, void *data)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
notify_monitor_free(void *data)
|
||||
{
|
||||
struct notify_monitor *nhm = data;
|
||||
|
||||
monitor_destroy(nhm->set);
|
||||
free(nhm->format);
|
||||
free(nhm);
|
||||
}
|
||||
|
||||
void
|
||||
notify_monitor_remove(struct options *oo, const char *name)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct notify_monitor *nhm;
|
||||
|
||||
o = options_get_only(oo, name);
|
||||
if (o == NULL)
|
||||
return;
|
||||
|
||||
nhm = options_get_monitor_data(o);
|
||||
if (nhm != NULL) {
|
||||
options_set_monitor_data(o, NULL);
|
||||
notify_monitor_free(nhm);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
notify_monitor_cb(struct monitor_change *change, void *data)
|
||||
{
|
||||
struct notify_monitor *nhm = data;
|
||||
struct notify_entry ne;
|
||||
struct cmdq_item *item;
|
||||
struct window *w;
|
||||
|
||||
item = cmdq_running(NULL);
|
||||
if (item != NULL && (cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
|
||||
return;
|
||||
|
||||
memset(&ne, 0, sizeof ne);
|
||||
ne.name = change->name;
|
||||
ne.oo = nhm->oo;
|
||||
ne.client = change->c;
|
||||
ne.expand = 1;
|
||||
if (change->wp != NULL && change->wl != NULL)
|
||||
cmd_find_from_winlink_pane(&ne.fs, change->wl, change->wp, 0);
|
||||
else if (change->wl != NULL)
|
||||
cmd_find_from_winlink(&ne.fs, change->wl, 0);
|
||||
else if (change->s != NULL)
|
||||
cmd_find_from_session(&ne.fs, change->s, 0);
|
||||
else
|
||||
cmd_find_copy_state(&ne.fs, &nhm->fs);
|
||||
ne.formats = format_create(change->c, item, FORMAT_NONE, FORMAT_NOJOBS);
|
||||
format_add(ne.formats, "hook", "%s", change->name);
|
||||
format_add(ne.formats, "hook_value", "%s", change->value);
|
||||
format_add(ne.formats, "hook_last", "%s",
|
||||
change->last == NULL ? "" : change->last);
|
||||
if (change->s != NULL) {
|
||||
format_add(ne.formats, "hook_session", "$%u", change->s->id);
|
||||
format_add(ne.formats, "hook_session_name", "%s", change->s->name);
|
||||
}
|
||||
if (change->wl != NULL) {
|
||||
w = change->wl->window;
|
||||
format_add(ne.formats, "hook_window", "@%u", w->id);
|
||||
format_add(ne.formats, "hook_window_name", "%s", w->name);
|
||||
format_add(ne.formats, "hook_window_index", "%d", change->wl->idx);
|
||||
}
|
||||
if (change->wp != NULL) {
|
||||
format_add(ne.formats, "hook_pane", "%%%u", change->wp->id);
|
||||
}
|
||||
|
||||
notify_insert_hook(item, &ne);
|
||||
format_free(ne.formats);
|
||||
}
|
||||
|
||||
void
|
||||
notify_monitor_add(__unused struct cmdq_item *item, struct options *oo,
|
||||
const char *name, enum monitor_type type, int id, const char *format,
|
||||
struct cmd_find_state *fs, struct session *s)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct notify_monitor *nhm;
|
||||
|
||||
notify_monitor_remove(oo, name);
|
||||
o = options_get_only(oo, name);
|
||||
if (o == NULL)
|
||||
o = options_set_string(oo, name, 0, "%s", "");
|
||||
|
||||
nhm = xcalloc(1, sizeof *nhm);
|
||||
nhm->oo = oo;
|
||||
cmd_find_copy_state(&nhm->fs, fs);
|
||||
nhm->type = type;
|
||||
nhm->id = id;
|
||||
nhm->format = xstrdup(format);
|
||||
nhm->set = monitor_create_session(s, notify_monitor_cb, nhm);
|
||||
options_set_monitor_data(o, nhm);
|
||||
monitor_add(nhm->set, name, type, id, format, 0);
|
||||
}
|
||||
|
||||
/* Convert a hook monitor to its value. */
|
||||
char *
|
||||
notify_monitor_to_string(struct options_entry *o)
|
||||
{
|
||||
struct notify_monitor *nhm = options_get_monitor_data(o);
|
||||
const char *name = options_name(o);
|
||||
char *s;
|
||||
|
||||
if (nhm == NULL)
|
||||
return (NULL);
|
||||
|
||||
switch (nhm->type) {
|
||||
case MONITOR_SESSION:
|
||||
xasprintf(&s, "%s::%s", name, nhm->format);
|
||||
break;
|
||||
case MONITOR_PANE:
|
||||
xasprintf(&s, "%s:%%%d:%s", name, nhm->id, nhm->format);
|
||||
break;
|
||||
case MONITOR_ALL_PANES:
|
||||
xasprintf(&s, "%s:%%*:%s", name, nhm->format);
|
||||
break;
|
||||
case MONITOR_WINDOW:
|
||||
xasprintf(&s, "%s:@%d:%s", name, nhm->id, nhm->format);
|
||||
break;
|
||||
case MONITOR_ALL_WINDOWS:
|
||||
xasprintf(&s, "%s:@*:%s", name, nhm->format);
|
||||
break;
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
|
||||
struct session *s, struct window *w, struct window_pane *wp,
|
||||
|
||||
15
options.c
15
options.c
@@ -56,6 +56,7 @@ struct options_entry {
|
||||
|
||||
int cached;
|
||||
struct style style;
|
||||
void *monitor_data;
|
||||
|
||||
RB_ENTRY(options_entry) entry;
|
||||
};
|
||||
@@ -354,6 +355,8 @@ options_remove(struct options_entry *o)
|
||||
options_array_clear(o);
|
||||
else
|
||||
options_value_free(o, &o->value);
|
||||
if (o->monitor_data != NULL)
|
||||
notify_monitor_free(o->monitor_data);
|
||||
RB_REMOVE(options_tree, &oo->tree, o);
|
||||
free((void *)o->name);
|
||||
free(o);
|
||||
@@ -371,6 +374,18 @@ options_owner(struct options_entry *o)
|
||||
return (o->owner);
|
||||
}
|
||||
|
||||
void *
|
||||
options_get_monitor_data(struct options_entry *o)
|
||||
{
|
||||
return (o->monitor_data);
|
||||
}
|
||||
|
||||
void
|
||||
options_set_monitor_data(struct options_entry *o, void *data)
|
||||
{
|
||||
o->monitor_data = data;
|
||||
}
|
||||
|
||||
const struct options_table_entry *
|
||||
options_table_entry(struct options_entry *o)
|
||||
{
|
||||
|
||||
41
tmux.1
41
tmux.1
@@ -6395,6 +6395,7 @@ Hooks are managed with these commands:
|
||||
.Bl -tag -width Ds
|
||||
.It Xo Ic set\-hook
|
||||
.Op Fl agpRuw
|
||||
.Op Fl B Ar name:what:format
|
||||
.Op Fl t Ar target\-pane
|
||||
.Ar hook\-name
|
||||
.Op Ar command
|
||||
@@ -6411,18 +6412,53 @@ The flags are the same as for
|
||||
.Ic set\-option .
|
||||
.Pp
|
||||
With
|
||||
.Fl B ,
|
||||
.Ar name:what:format
|
||||
uses the same subscription syntax as
|
||||
.Ic refresh\-client
|
||||
.Fl B :
|
||||
.Ar name
|
||||
is the hook to run,
|
||||
.Ar what
|
||||
selects the session, pane, all panes, window, or all windows, and
|
||||
.Ar format
|
||||
is expanded once a second.
|
||||
For monitor hooks,
|
||||
.Ar name
|
||||
must begin with
|
||||
.Ql @ .
|
||||
If
|
||||
.Ar command
|
||||
is given, it is stored as the
|
||||
.Ql @
|
||||
hook command; otherwise only the monitor is created or replaced.
|
||||
Note that monitor hooks are not inherited, the hook is only run from
|
||||
the scope where it is created.
|
||||
With
|
||||
.Fl u ,
|
||||
the subscription named by
|
||||
.Fl B
|
||||
is removed.
|
||||
.Pp
|
||||
With
|
||||
.Fl R ,
|
||||
run
|
||||
.Ar hook\-name
|
||||
immediately.
|
||||
.It Xo Ic show\-hooks
|
||||
.Op Fl gpw
|
||||
.Op Fl Bgpw
|
||||
.Op Fl t Ar target\-pane
|
||||
.Op Ar hook
|
||||
.Xc
|
||||
Shows hooks.
|
||||
The flags are the same as for
|
||||
.Ic show\-options .
|
||||
.Pp
|
||||
With
|
||||
.Fl B ,
|
||||
shows the subscriptions installed with
|
||||
.Em set\-hook
|
||||
.Fl B .
|
||||
.El
|
||||
.Sh MOUSE SUPPORT
|
||||
If the
|
||||
@@ -7060,10 +7096,13 @@ The following variables are available, where appropriate:
|
||||
.It Li "history_size" Ta "" Ta "Size of history in lines"
|
||||
.It Li "hook" Ta "" Ta "Name of running hook, if any"
|
||||
.It Li "hook_client" Ta "" Ta "Name of client where hook was run, if any"
|
||||
.It Li "hook_last" Ta "" Ta "Previous value for a monitor hook"
|
||||
.It Li "hook_pane" Ta "" Ta "ID of pane where hook was run, if any"
|
||||
.It Li "hook_session" Ta "" Ta "ID of session where hook was run, if any"
|
||||
.It Li "hook_session_name" Ta "" Ta "Name of session where hook was run, if any"
|
||||
.It Li "hook_value" Ta "" Ta "New value for a monitor hook"
|
||||
.It Li "hook_window" Ta "" Ta "ID of window where hook was run, if any"
|
||||
.It Li "hook_window_index" Ta "" Ta "Index of window where hook was run, if any"
|
||||
.It Li "hook_window_name" Ta "" Ta "Name of window where hook was run, if any"
|
||||
.It Li "host" Ta "#H" Ta "Hostname of local host"
|
||||
.It Li "host_short" Ta "#h" Ta "Hostname of local host (no domain name)"
|
||||
|
||||
17
tmux.h
17
tmux.h
@@ -2282,9 +2282,11 @@ enum monitor_type {
|
||||
MONITOR_WINDOW,
|
||||
MONITOR_ALL_WINDOWS
|
||||
};
|
||||
#define MONITOR_NOTIFY_INITIAL 0x1
|
||||
struct monitor_change {
|
||||
const char *name;
|
||||
const char *value;
|
||||
const char *last;
|
||||
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
@@ -2612,6 +2614,12 @@ char *format_trim_right(const char *, u_int);
|
||||
|
||||
/* notify.c */
|
||||
void notify_hook(struct cmdq_item *, const char *);
|
||||
void notify_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 *);
|
||||
@@ -2634,6 +2642,8 @@ struct options_entry *options_default(struct options *,
|
||||
char *options_default_to_string(const struct options_table_entry *);
|
||||
const char *options_name(struct options_entry *);
|
||||
struct options *options_owner(struct options_entry *);
|
||||
void *options_get_monitor_data(struct options_entry *);
|
||||
void options_set_monitor_data(struct options_entry *, void *);
|
||||
const struct options_table_entry *options_table_entry(struct options_entry *);
|
||||
struct options_entry *options_get_only(struct options *, const char *);
|
||||
struct options_entry *options_get(struct options *, const char *);
|
||||
@@ -3805,10 +3815,13 @@ char *default_window_name(struct window *);
|
||||
char *parse_window_name(const char *);
|
||||
|
||||
/* monitor.c */
|
||||
struct monitor_set *monitor_create(struct client *, monitor_cb, void *);
|
||||
struct monitor_set *monitor_create_client(struct client *, monitor_cb, void *);
|
||||
struct monitor_set *monitor_create_session(struct session *, monitor_cb, void *);
|
||||
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 *);
|
||||
const char *, u_int);
|
||||
void monitor_remove(struct monitor_set *, const char *);
|
||||
|
||||
/* control.c */
|
||||
|
||||
Reference in New Issue
Block a user