mirror of
https://github.com/tmux/tmux.git
synced 2026-08-03 14:08:59 +00:00
200 lines
4.7 KiB
C
200 lines
4.7 KiB
C
/* $OpenBSD$ */
|
|
|
|
/*
|
|
* 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
|
|
* 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 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"
|
|
|
|
/* Event sink. */
|
|
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;
|
|
|
|
/* Free an event sink. */
|
|
static void
|
|
events_free_sink(struct events_sink *es)
|
|
{
|
|
TAILQ_REMOVE(&events_sinks, es, entry);
|
|
free(es->name);
|
|
free(es);
|
|
}
|
|
|
|
/* Free dead event sinks. */
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* Add an event sink. */
|
|
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);
|
|
}
|
|
|
|
/* Remove an event sink. */
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* Fire an event. */
|
|
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);
|
|
}
|
|
|
|
/* Fire a client event. */
|
|
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);
|
|
}
|
|
|
|
/* Fire a session event. */
|
|
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);
|
|
}
|
|
|
|
/* Fire a window event. */
|
|
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);
|
|
}
|
|
|
|
/* Fire a pane event. */
|
|
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);
|
|
}
|
|
|
|
/* Fire a winlink event. */
|
|
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);
|
|
}
|