mirror of
https://github.com/tmux/tmux.git
synced 2026-08-03 14:08:59 +00:00
Convert notify.c to events.
This commit is contained in:
@@ -86,7 +86,7 @@ static enum cmd_retval cmd_wait_for_unlock(struct cmdq_item *, const char *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_event(struct cmdq_item *, const char *);
|
||||
static void cmd_wait_for_event_cb(const char *, void *,
|
||||
const struct events_type *, void *);
|
||||
struct events_type *, void *);
|
||||
|
||||
static struct wait_channel *cmd_wait_for_add(const char *);
|
||||
static void cmd_wait_for_remove(struct wait_channel *);
|
||||
@@ -159,7 +159,7 @@ cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_cb(__unused const char *name, __unused void *data,
|
||||
__unused const struct events_type *type, void *item_data)
|
||||
__unused struct events_type *type, void *item_data)
|
||||
{
|
||||
struct wait_event_item *wei = item_data;
|
||||
|
||||
|
||||
31
events.c
31
events.c
@@ -28,6 +28,7 @@ struct events_type {
|
||||
char *name;
|
||||
events_add_formats_cb add_formats_cb;
|
||||
events_find_state_cb find_state_cb;
|
||||
events_get_client_cb get_client_cb;
|
||||
|
||||
RB_ENTRY(events_type) entry;
|
||||
};
|
||||
@@ -96,13 +97,14 @@ events_free_dead(void)
|
||||
/* Add an event type. */
|
||||
int
|
||||
events_add_event(const char *name, events_add_formats_cb add_formats_cb,
|
||||
events_find_state_cb find_state_cb)
|
||||
events_find_state_cb find_state_cb, events_get_client_cb get_client_cb)
|
||||
{
|
||||
struct events_type *et;
|
||||
|
||||
if ((et = events_find_type(name)) != NULL) {
|
||||
et->add_formats_cb = add_formats_cb;
|
||||
et->find_state_cb = find_state_cb;
|
||||
et->get_client_cb = get_client_cb;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -110,6 +112,7 @@ events_add_event(const char *name, events_add_formats_cb add_formats_cb,
|
||||
et->name = xstrdup(name);
|
||||
et->add_formats_cb = add_formats_cb;
|
||||
et->find_state_cb = find_state_cb;
|
||||
et->get_client_cb = get_client_cb;
|
||||
RB_INSERT(events_types, &events_types, et);
|
||||
return (0);
|
||||
}
|
||||
@@ -160,3 +163,29 @@ events_fire(const char *name, void *data)
|
||||
if (--events_dispatching == 0)
|
||||
events_free_dead();
|
||||
}
|
||||
|
||||
/* Add event formats. */
|
||||
void
|
||||
events_add_formats(struct events_type *et, void *data, struct format_tree *ft)
|
||||
{
|
||||
if (et != NULL && et->add_formats_cb != NULL)
|
||||
et->add_formats_cb(data, ft);
|
||||
}
|
||||
|
||||
/* Find event state. */
|
||||
int
|
||||
events_find_state(struct events_type *et, void *data, struct cmd_find_state *fs)
|
||||
{
|
||||
if (et == NULL || et->find_state_cb == NULL)
|
||||
return (0);
|
||||
return (et->find_state_cb(data, fs));
|
||||
}
|
||||
|
||||
/* Get event client. */
|
||||
struct client *
|
||||
events_get_client(struct events_type *et, void *data)
|
||||
{
|
||||
if (et == NULL || et->get_client_cb == NULL)
|
||||
return (NULL);
|
||||
return (et->get_client_cb(data));
|
||||
}
|
||||
|
||||
365
notify.c
365
notify.c
@@ -54,6 +54,17 @@ struct notify_monitor_event {
|
||||
struct monitor_change *change;
|
||||
};
|
||||
|
||||
struct notify_event_entry {
|
||||
const char *name;
|
||||
void (*control_cb)(struct notify_entry *);
|
||||
};
|
||||
|
||||
static void notify_event_hook_cb(const char *, void *, struct events_type *,
|
||||
void *);
|
||||
static void notify_event_control_cb(const char *, void *,
|
||||
struct events_type *, void *);
|
||||
static void notify_register_events(void);
|
||||
|
||||
static struct cmdq_item *
|
||||
notify_insert_one_hook(struct cmdq_item *item, struct notify_entry *ne,
|
||||
struct cmd_list *cmdlist, struct cmdq_state *state)
|
||||
@@ -183,43 +194,285 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
|
||||
cmdq_free_state(state);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_event_insert_hook(struct cmdq_item *item, const char *name,
|
||||
struct events_type *type, void *data, struct options *oo, int expand)
|
||||
{
|
||||
struct cmd_find_state fs;
|
||||
struct notify_entry ne;
|
||||
struct format_tree *ft;
|
||||
struct client *c;
|
||||
|
||||
if (item != NULL && (cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
|
||||
return;
|
||||
|
||||
cmd_find_clear_state(&fs, 0);
|
||||
if (!events_find_state(type, data, &fs) ||
|
||||
cmd_find_empty_state(&fs) || !cmd_find_valid_state(&fs))
|
||||
cmd_find_from_nothing(&fs, 0);
|
||||
|
||||
c = events_get_client(type, data);
|
||||
ft = format_create(c, item, FORMAT_NONE, FORMAT_NOJOBS);
|
||||
events_add_formats(type, data, ft);
|
||||
|
||||
memset(&ne, 0, sizeof ne);
|
||||
ne.name = name;
|
||||
cmd_find_copy_state(&ne.fs, &fs);
|
||||
ne.formats = ft;
|
||||
ne.oo = oo;
|
||||
ne.client = c;
|
||||
ne.expand = expand;
|
||||
|
||||
notify_insert_hook(item, &ne);
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_event_add_formats(void *data, struct format_tree *ft)
|
||||
{
|
||||
struct notify_entry *ne = data;
|
||||
|
||||
if (ne->formats != NULL)
|
||||
format_merge(ft, ne->formats);
|
||||
}
|
||||
|
||||
static int
|
||||
notify_event_find_state(void *data, struct cmd_find_state *fs)
|
||||
{
|
||||
struct notify_entry *ne = data;
|
||||
|
||||
if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs))
|
||||
return (0);
|
||||
cmd_find_copy_state(fs, &ne->fs);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static struct client *
|
||||
notify_event_get_client(void *data)
|
||||
{
|
||||
struct notify_entry *ne = data;
|
||||
|
||||
return (ne->client);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_monitor_event_add_formats(void *data, struct format_tree *ft)
|
||||
{
|
||||
struct notify_monitor_event *nme = data;
|
||||
struct monitor_change *change = nme->change;
|
||||
struct window *w;
|
||||
|
||||
format_add(ft, "hook", "%s", change->name);
|
||||
format_add(ft, "hook_value", "%s",
|
||||
change->value == NULL ? "" : change->value);
|
||||
format_add(ft, "hook_last", "%s",
|
||||
change->last == NULL ? "" : change->last);
|
||||
if (change->s != NULL) {
|
||||
format_add(ft, "hook_session", "$%u", change->s->id);
|
||||
format_add(ft, "hook_session_name", "%s", change->s->name);
|
||||
}
|
||||
if (change->wl != NULL) {
|
||||
w = change->wl->window;
|
||||
format_add(ft, "hook_window", "@%u", w->id);
|
||||
format_add(ft, "hook_window_name", "%s", w->name);
|
||||
format_add(ft, "hook_window_index", "%d", change->wl->idx);
|
||||
}
|
||||
if (change->wp != NULL)
|
||||
format_add(ft, "hook_pane", "%%%u", change->wp->id);
|
||||
}
|
||||
|
||||
static int
|
||||
notify_monitor_event_find_state(void *data, struct cmd_find_state *fs)
|
||||
{
|
||||
struct notify_monitor_event *nme = data;
|
||||
struct notify_monitor *nhm = nme->nhm;
|
||||
struct monitor_change *change = nme->change;
|
||||
|
||||
if (change->wp != NULL && change->wl != NULL)
|
||||
cmd_find_from_winlink_pane(fs, change->wl, change->wp, 0);
|
||||
else if (change->wl != NULL)
|
||||
cmd_find_from_winlink(fs, change->wl, 0);
|
||||
else if (change->s != NULL)
|
||||
cmd_find_from_session(fs, change->s, 0);
|
||||
else
|
||||
cmd_find_copy_state(fs, &nhm->fs);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static struct client *
|
||||
notify_monitor_event_get_client(void *data)
|
||||
{
|
||||
struct notify_monitor_event *nme = data;
|
||||
struct monitor_change *change = nme->change;
|
||||
|
||||
return (change->c);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_pane_mode_changed(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_pane_mode_changed(ne->pane);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_window_layout_changed(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_window_layout_changed(ne->window);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_window_pane_changed(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_window_pane_changed(ne->window);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_window_unlinked(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_window_unlinked(ne->session, ne->window);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_window_linked(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_window_linked(ne->session, ne->window);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_window_renamed(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_window_renamed(ne->window);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_client_session_changed(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_client_session_changed(ne->client);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_client_detached(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_client_detached(ne->client);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_session_renamed(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_session_renamed(ne->session);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_session_created(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_session_created(ne->session);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_session_closed(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_session_closed(ne->session);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_session_window_changed(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_session_window_changed(ne->session);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_paste_buffer_changed(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_paste_buffer_changed(ne->pbname);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_control_paste_buffer_deleted(struct notify_entry *ne)
|
||||
{
|
||||
control_notify_paste_buffer_deleted(ne->pbname);
|
||||
}
|
||||
|
||||
static struct notify_event_entry notify_events[] = {
|
||||
{ "alert-activity", NULL },
|
||||
{ "alert-bell", NULL },
|
||||
{ "alert-silence", NULL },
|
||||
{ "client-active", NULL },
|
||||
{ "client-attached", NULL },
|
||||
{ "client-dark-theme", NULL },
|
||||
{ "client-focus-in", NULL },
|
||||
{ "client-focus-out", NULL },
|
||||
{ "client-light-theme", NULL },
|
||||
{ "client-resized", NULL },
|
||||
{ "pane-mode-changed", notify_control_pane_mode_changed },
|
||||
{ "pane-died", NULL },
|
||||
{ "pane-exited", NULL },
|
||||
{ "pane-focus-in", NULL },
|
||||
{ "pane-focus-out", NULL },
|
||||
{ "pane-set-clipboard", NULL },
|
||||
{ "pane-title-changed", NULL },
|
||||
{ "window-layout-changed", notify_control_window_layout_changed },
|
||||
{ "window-pane-changed", notify_control_window_pane_changed },
|
||||
{ "window-resized", NULL },
|
||||
{ "window-unlinked", notify_control_window_unlinked },
|
||||
{ "window-linked", notify_control_window_linked },
|
||||
{ "window-renamed", notify_control_window_renamed },
|
||||
{ "client-session-changed", notify_control_client_session_changed },
|
||||
{ "client-detached", notify_control_client_detached },
|
||||
{ "session-renamed", notify_control_session_renamed },
|
||||
{ "session-created", notify_control_session_created },
|
||||
{ "session-closed", notify_control_session_closed },
|
||||
{ "session-window-changed", notify_control_session_window_changed },
|
||||
{ "paste-buffer-changed", notify_control_paste_buffer_changed },
|
||||
{ "paste-buffer-deleted", notify_control_paste_buffer_deleted }
|
||||
};
|
||||
|
||||
static void
|
||||
notify_event_hook_cb(const char *name, void *data, struct events_type *type,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
notify_event_insert_hook(cmdq_running(NULL), name, type, data, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_event_control_cb(__unused const char *name, void *data,
|
||||
__unused struct events_type *type, void *sink_data)
|
||||
{
|
||||
struct notify_event_entry *nee = sink_data;
|
||||
|
||||
nee->control_cb(data);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_register_events(void)
|
||||
{
|
||||
static int done;
|
||||
u_int i;
|
||||
|
||||
if (done)
|
||||
return;
|
||||
done = 1;
|
||||
|
||||
for (i = 0; i < nitems(notify_events); i++) {
|
||||
events_add_event(notify_events[i].name, notify_event_add_formats,
|
||||
notify_event_find_state, notify_event_get_client);
|
||||
events_add_sink(notify_events[i].name, notify_event_hook_cb,
|
||||
NULL);
|
||||
if (notify_events[i].control_cb != NULL) {
|
||||
events_add_sink(notify_events[i].name,
|
||||
notify_event_control_cb, ¬ify_events[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
notify_callback(struct cmdq_item *item, void *data)
|
||||
notify_callback(__unused struct cmdq_item *item, void *data)
|
||||
{
|
||||
struct notify_entry *ne = data;
|
||||
|
||||
log_debug("%s: %s", __func__, ne->name);
|
||||
|
||||
if (strcmp(ne->name, "pane-mode-changed") == 0)
|
||||
control_notify_pane_mode_changed(ne->pane);
|
||||
if (strcmp(ne->name, "window-layout-changed") == 0)
|
||||
control_notify_window_layout_changed(ne->window);
|
||||
if (strcmp(ne->name, "window-pane-changed") == 0)
|
||||
control_notify_window_pane_changed(ne->window);
|
||||
if (strcmp(ne->name, "window-unlinked") == 0)
|
||||
control_notify_window_unlinked(ne->session, ne->window);
|
||||
if (strcmp(ne->name, "window-linked") == 0)
|
||||
control_notify_window_linked(ne->session, ne->window);
|
||||
if (strcmp(ne->name, "window-renamed") == 0)
|
||||
control_notify_window_renamed(ne->window);
|
||||
if (strcmp(ne->name, "client-session-changed") == 0)
|
||||
control_notify_client_session_changed(ne->client);
|
||||
if (strcmp(ne->name, "client-detached") == 0)
|
||||
control_notify_client_detached(ne->client);
|
||||
if (strcmp(ne->name, "session-renamed") == 0)
|
||||
control_notify_session_renamed(ne->session);
|
||||
if (strcmp(ne->name, "session-created") == 0)
|
||||
control_notify_session_created(ne->session);
|
||||
if (strcmp(ne->name, "session-closed") == 0)
|
||||
control_notify_session_closed(ne->session);
|
||||
if (strcmp(ne->name, "session-window-changed") == 0)
|
||||
control_notify_session_window_changed(ne->session);
|
||||
if (strcmp(ne->name, "paste-buffer-changed") == 0)
|
||||
control_notify_paste_buffer_changed(ne->pbname);
|
||||
if (strcmp(ne->name, "paste-buffer-deleted") == 0)
|
||||
control_notify_paste_buffer_deleted(ne->pbname);
|
||||
|
||||
notify_insert_hook(item, ne);
|
||||
notify_register_events();
|
||||
events_fire(ne->name, ne);
|
||||
|
||||
if (ne->client != NULL)
|
||||
server_client_unref(ne->client);
|
||||
@@ -268,57 +521,16 @@ notify_monitor_remove(struct options *oo, const char *name)
|
||||
}
|
||||
|
||||
static void
|
||||
notify_monitor_hook_cb(__unused const char *name, void *data,
|
||||
__unused const struct events_type *type, void *sink_data)
|
||||
notify_monitor_hook_cb(const char *name, void *data, struct events_type *type,
|
||||
void *sink_data)
|
||||
{
|
||||
struct notify_monitor_event *nme = data;
|
||||
struct notify_monitor *nhm = sink_data;
|
||||
struct monitor_change *change = nme->change;
|
||||
struct notify_entry ne;
|
||||
struct cmdq_item *item;
|
||||
struct window *w;
|
||||
|
||||
if (nme->nhm != nhm)
|
||||
return;
|
||||
|
||||
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);
|
||||
notify_event_insert_hook(cmdq_running(NULL), name, type, data, nhm->oo, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -351,7 +563,8 @@ notify_monitor_add(__unused struct cmdq_item *item, struct options *oo,
|
||||
nhm->id = id;
|
||||
nhm->format = xstrdup(format);
|
||||
nhm->set = monitor_create_session(s, notify_monitor_cb, nhm);
|
||||
events_add_event(name, NULL, NULL);
|
||||
events_add_event(name, notify_monitor_event_add_formats,
|
||||
notify_monitor_event_find_state, notify_monitor_event_get_client);
|
||||
nhm->sink = events_add_sink(name, notify_monitor_hook_cb, nhm);
|
||||
options_set_monitor_data(o, nhm);
|
||||
monitor_add(nhm->set, name, type, id, format, 0);
|
||||
|
||||
@@ -94,4 +94,20 @@ $TMUX set -g @wf_value 2 || fail "set @wf_value 2 failed"
|
||||
wait_channel wf-late
|
||||
wait "$late_pid" || fail "late wait-for -E command failed"
|
||||
|
||||
$TMUX new -d -s wf2 || fail "new-session wf2 failed"
|
||||
|
||||
$TMUX wait-for -E window-renamed \; wait-for -S wf-renamed &
|
||||
renamed_pid=$!
|
||||
|
||||
sleep 0.5
|
||||
$TMUX rename-window -t wf2:0 renamed || fail "rename-window failed"
|
||||
wait_channel wf-renamed
|
||||
wait "$renamed_pid" || fail "wait-for -E window-renamed failed"
|
||||
|
||||
$TMUX set-hook -g window-renamed 'wait-for -S wf-hook-renamed' ||
|
||||
fail "set-hook window-renamed failed"
|
||||
$TMUX rename-window -t wf2:0 renamed-again ||
|
||||
fail "rename-window renamed-again failed"
|
||||
wait_channel wf-hook-renamed
|
||||
|
||||
exit 0
|
||||
|
||||
5
tmux.1
5
tmux.1
@@ -8562,6 +8562,11 @@ When
|
||||
is used,
|
||||
.Nm
|
||||
waits for the next event with the given name.
|
||||
Events include hook and notification names, and user
|
||||
.Ql @
|
||||
events generated by
|
||||
.Ic set-hook
|
||||
.Fl B .
|
||||
When
|
||||
.Fl L
|
||||
is used, the channel is locked and any clients that try to lock the same
|
||||
|
||||
11
tmux.h
11
tmux.h
@@ -2339,10 +2339,10 @@ struct monitor_change {
|
||||
typedef void (*monitor_cb)(struct monitor_change *, void *);
|
||||
|
||||
/* Events. */
|
||||
typedef void (*events_cb)(const char *, void *, const struct events_type *,
|
||||
void *);
|
||||
typedef void (*events_cb)(const char *, void *, struct events_type *, void *);
|
||||
typedef void (*events_add_formats_cb)(void *, struct format_tree *);
|
||||
typedef int (*events_find_state_cb)(void *, struct cmd_find_state *);
|
||||
typedef struct client *(*events_get_client_cb)(void *);
|
||||
|
||||
/* Key binding and key table. */
|
||||
struct key_binding {
|
||||
@@ -2655,10 +2655,15 @@ char *format_grid_line(struct grid *, u_int);
|
||||
|
||||
/* events.c */
|
||||
int events_add_event(const char *, events_add_formats_cb,
|
||||
events_find_state_cb);
|
||||
events_find_state_cb, events_get_client_cb);
|
||||
struct events_sink *events_add_sink(const char *, events_cb, void *);
|
||||
void events_remove_sink(struct events_sink *);
|
||||
void events_fire(const char *, void *);
|
||||
void events_add_formats(struct events_type *, void *,
|
||||
struct format_tree *);
|
||||
int events_find_state(struct events_type *, void *,
|
||||
struct cmd_find_state *);
|
||||
struct client *events_get_client(struct events_type *, void *);
|
||||
|
||||
/* format-draw.c */
|
||||
void format_draw(struct screen_write_ctx *,
|
||||
|
||||
Reference in New Issue
Block a user