#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
struct events_sink {
char *name;
events_cb cb;
void *data;
int dead;
u_int generation;
TAILQ_ENTRY(events_sink) entry;
};
TAILQ_HEAD(events_sinks, events_sink);
static struct events_sinks events_sinks = TAILQ_HEAD_INITIALIZER(events_sinks);
static u_int events_dispatching;
static u_int events_generation;
static void
events_free_sink(struct events_sink *es)
{
TAILQ_REMOVE(&events_sinks, es, entry);
free(es->name);
free(es);
}
static void
events_free_dead(void)
{
struct events_sink *es, *es1;
TAILQ_FOREACH_SAFE(es, &events_sinks, entry, es1) {
if (es->dead)
events_free_sink(es);
}
}
struct events_sink *
events_add_sink(const char *name, events_cb cb, void *data)
{
struct events_sink *es;
es = xcalloc(1, sizeof *es);
es->name = xstrdup(name);
es->cb = cb;
es->data = data;
es->generation = ++events_generation;
TAILQ_INSERT_TAIL(&events_sinks, es, entry);
return (es);
}
void
events_remove_sink(struct events_sink *es)
{
if (es != NULL && !es->dead) {
if (events_dispatching != 0)
es->dead = 1;
else
events_free_sink(es);
}
}
void
events_fire(const char *name, struct event_payload *ep)
{
struct events_sink *es;
u_int generation = events_generation;
event_payload_set_string(ep, "event", "%s", name);
if (log_get_level() != 0)
event_payload_log(ep, "%s: %s: ", __func__, name);
events_dispatching++;
TAILQ_FOREACH(es, &events_sinks, entry) {
if (es->dead || es->generation > generation)
continue;
if (strcmp(es->name, name) == 0)
es->cb(name, ep, es->data);
}
if (--events_dispatching == 0)
events_free_dead();
event_payload_free(ep);
}
void
events_fire_client(const char *name, struct client *c)
{
struct event_payload *ep;
struct cmd_find_state fs;
ep = event_payload_create();
cmd_find_from_client(&fs, c, 0);
event_payload_set_target(ep, &fs);
event_payload_set_client(ep, "client", c);
if (fs.s != NULL)
event_payload_set_session(ep, "session", fs.s);
if (fs.w != NULL)
event_payload_set_window(ep, "window", fs.w);
if (fs.wl != NULL)
event_payload_set_int(ep, "window_index", fs.wl->idx);
else if (fs.idx != -1)
event_payload_set_int(ep, "window_index", fs.idx);
if (fs.wp != NULL)
event_payload_set_pane(ep, "pane", fs.wp);
events_fire(name, ep);
}
void
events_fire_session(const char *name, struct session *s)
{
struct event_payload *ep;
struct cmd_find_state fs;
ep = event_payload_create();
if (session_alive(s)) {
cmd_find_from_session(&fs, s, 0);
event_payload_set_target(ep, &fs);
}
event_payload_set_session(ep, "session", s);
events_fire(name, ep);
}
void
events_fire_window(const char *name, struct window *w)
{
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);
events_fire(name, ep);
}
void
events_fire_pane(const char *name, struct window_pane *wp)
{
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);
events_fire(name, ep);
}
void
events_fire_winlink(const char *name, struct winlink *wl)
{
struct event_payload *ep;
struct cmd_find_state fs;
ep = event_payload_create();
cmd_find_from_winlink(&fs, wl, 0);
event_payload_set_target(ep, &fs);
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);
events_fire(name, ep);
}