Coverage Report

Created: 2026-10-17 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/events.c
Line
Count
Source
1
/* $OpenBSD: events.c,v 1.1 2026/07/10 13:38:45 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
21
#include <stdlib.h>
22
#include <string.h>
23
24
#include "tmux.h"
25
26
/* Event sink. */
27
struct events_sink {
28
  char        *name;
29
  events_cb      cb;
30
  void        *data;
31
  int        dead;
32
  u_int        generation;
33
34
  TAILQ_ENTRY(events_sink)   entry;
35
};
36
37
TAILQ_HEAD(events_sinks, events_sink);
38
static struct events_sinks events_sinks = TAILQ_HEAD_INITIALIZER(events_sinks);
39
40
static u_int events_dispatching;
41
static u_int events_generation;
42
43
/* Free an event sink. */
44
static void
45
events_free_sink(struct events_sink *es)
46
0
{
47
0
  TAILQ_REMOVE(&events_sinks, es, entry);
48
0
  free(es->name);
49
0
  free(es);
50
0
}
51
52
/* Free dead event sinks. */
53
static void
54
events_free_dead(void)
55
42.6k
{
56
42.6k
  struct events_sink  *es, *es1;
57
58
42.6k
  TAILQ_FOREACH_SAFE(es, &events_sinks, entry, es1) {
59
0
    if (es->dead)
60
0
      events_free_sink(es);
61
0
  }
62
42.6k
}
63
64
/* Add an event sink. */
65
struct events_sink *
66
events_add_sink(const char *name, events_cb cb, void *data)
67
0
{
68
0
  struct events_sink  *es;
69
70
0
  es = xcalloc(1, sizeof *es);
71
0
  es->name = xstrdup(name);
72
0
  es->cb = cb;
73
0
  es->data = data;
74
0
  es->generation = ++events_generation;
75
76
0
  TAILQ_INSERT_TAIL(&events_sinks, es, entry);
77
0
  return (es);
78
0
}
79
80
/* Remove an event sink. */
81
void
82
events_remove_sink(struct events_sink *es)
83
0
{
84
0
  if (es != NULL && !es->dead) {
85
0
    if (events_dispatching != 0)
86
0
      es->dead = 1;
87
0
    else
88
0
      events_free_sink(es);
89
0
  }
90
0
}
91
92
/* Fire an event. */
93
void
94
events_fire(const char *name, struct event_payload *ep)
95
42.6k
{
96
42.6k
  struct events_sink  *es;
97
42.6k
  u_int      generation = events_generation;
98
99
42.6k
  event_payload_set_string(ep, "event", "%s", name);
100
101
42.6k
  if (log_get_level() != 0)
102
0
    event_payload_log(ep, "%s: %s: ", __func__, name);
103
104
42.6k
  events_dispatching++;
105
42.6k
  TAILQ_FOREACH(es, &events_sinks, entry) {
106
0
    if (es->dead || es->generation > generation)
107
0
      continue;
108
0
    if (strcmp(es->name, name) == 0)
109
0
      es->cb(name, ep, es->data);
110
0
  }
111
42.6k
  if (--events_dispatching == 0)
112
42.6k
    events_free_dead();
113
42.6k
  event_payload_free(ep);
114
42.6k
}
115
116
/* Fire a client event. */
117
void
118
events_fire_client(const char *name, struct client *c)
119
0
{
120
0
  struct event_payload  *ep;
121
0
  struct cmd_find_state  fs;
122
123
0
  ep = event_payload_create();
124
0
  cmd_find_from_client(&fs, c, 0);
125
0
  event_payload_set_target(ep, &fs);
126
0
  event_payload_set_client(ep, "client", c);
127
0
  if (fs.s != NULL)
128
0
    event_payload_set_session(ep, "session", fs.s);
129
0
  if (fs.w != NULL)
130
0
    event_payload_set_window(ep, "window", fs.w);
131
0
  if (fs.wl != NULL)
132
0
    event_payload_set_int(ep, "window_index", fs.wl->idx);
133
0
  else if (fs.idx != -1)
134
0
    event_payload_set_int(ep, "window_index", fs.idx);
135
0
  if (fs.wp != NULL)
136
0
    event_payload_set_pane(ep, "pane", fs.wp);
137
0
  events_fire(name, ep);
138
0
}
139
140
/* Fire a session event. */
141
void
142
events_fire_session(const char *name, struct session *s)
143
0
{
144
0
  struct event_payload  *ep;
145
0
  struct cmd_find_state  fs;
146
147
0
  ep = event_payload_create();
148
0
  if (session_alive(s)) {
149
0
    cmd_find_from_session(&fs, s, 0);
150
0
    event_payload_set_target(ep, &fs);
151
0
  }
152
0
  event_payload_set_session(ep, "session", s);
153
0
  events_fire(name, ep);
154
0
}
155
156
/* Fire a window event. */
157
void
158
events_fire_window(const char *name, struct window *w)
159
16.3k
{
160
16.3k
  struct event_payload  *ep;
161
16.3k
  struct cmd_find_state  fs;
162
163
16.3k
  ep = event_payload_create();
164
16.3k
  cmd_find_from_window(&fs, w, 0);
165
16.3k
  event_payload_set_target(ep, &fs);
166
16.3k
  event_payload_set_window(ep, "window", w);
167
16.3k
  events_fire(name, ep);
168
16.3k
}
169
170
/* Fire a pane event. */
171
void
172
events_fire_pane(const char *name, struct window_pane *wp)
173
19.6k
{
174
19.6k
  struct event_payload  *ep;
175
19.6k
  struct cmd_find_state  fs;
176
177
19.6k
  ep = event_payload_create();
178
19.6k
  cmd_find_from_pane(&fs, wp, 0);
179
19.6k
  event_payload_set_target(ep, &fs);
180
19.6k
  event_payload_set_pane(ep, "pane", wp);
181
19.6k
  event_payload_set_window(ep, "window", wp->window);
182
19.6k
  events_fire(name, ep);
183
19.6k
}
184
185
/* Fire a winlink event. */
186
void
187
events_fire_winlink(const char *name, struct winlink *wl)
188
0
{
189
0
  struct event_payload  *ep;
190
0
  struct cmd_find_state  fs;
191
192
0
  ep = event_payload_create();
193
0
  cmd_find_from_winlink(&fs, wl, 0);
194
0
  event_payload_set_target(ep, &fs);
195
0
  event_payload_set_session(ep, "session", wl->session);
196
0
  event_payload_set_window(ep, "window", wl->window);
197
0
  event_payload_set_int(ep, "window_index", wl->idx);
198
0
  events_fire(name, ep);
199
0
}