Coverage Report

Created: 2026-06-12 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/control-notify.c
Line
Count
Source
1
/* $OpenBSD$ */
2
3
/*
4
 * Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
5
 * Copyright (c) 2012 George Nachman <tmux@georgester.com>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
22
#include <stdlib.h>
23
24
#include "tmux.h"
25
26
#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
27
0
  ((c) != NULL && ((c)->flags & CLIENT_CONTROL) && \
28
0
   (c)->control_state != NULL)
29
30
void
31
control_notify_pane_mode_changed(int pane)
32
0
{
33
0
  struct client *c;
34
35
0
  TAILQ_FOREACH(c, &clients, entry) {
36
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
37
0
      continue;
38
39
0
    control_write(c, "%%pane-mode-changed %%%u", pane);
40
0
  }
41
0
}
42
43
void
44
control_notify_window_layout_changed(struct window *w)
45
0
{
46
0
  struct client *c;
47
0
  struct session  *s;
48
0
  struct winlink  *wl;
49
0
  const char  *template;
50
0
  char    *cp;
51
52
0
  template = "%layout-change #{window_id} #{window_layout} "
53
0
      "#{window_visible_layout} #{window_raw_flags}";
54
55
  /*
56
   * When the last pane in a window is closed it won't have a layout root
57
   * and we don't need to inform the client about the layout change
58
   * because the whole window will go away soon.
59
   */
60
0
  wl = TAILQ_FIRST(&w->winlinks);
61
0
  if (wl == NULL || w->layout_root == NULL)
62
0
    return;
63
0
  cp = format_single(NULL, template, NULL, NULL, wl, NULL);
64
65
0
  TAILQ_FOREACH(c, &clients, entry) {
66
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
67
0
      continue;
68
0
    s = c->session;
69
0
    if (winlink_find_by_window_id(&s->windows, w->id) != NULL)
70
0
      control_write(c, "%s", cp);
71
0
  }
72
0
  free(cp);
73
0
}
74
75
void
76
control_notify_window_pane_changed(struct window *w)
77
0
{
78
0
  struct client *c;
79
80
0
  if (w->active == NULL)
81
0
    return;
82
0
  TAILQ_FOREACH(c, &clients, entry) {
83
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
84
0
      continue;
85
86
0
    control_write(c, "%%window-pane-changed @%u %%%u", w->id,
87
0
        w->active->id);
88
0
  }
89
0
}
90
91
void
92
control_notify_window_unlinked(__unused struct session *s, struct window *w)
93
0
{
94
0
  struct client *c;
95
0
  struct session  *cs;
96
97
0
  TAILQ_FOREACH(c, &clients, entry) {
98
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
99
0
      continue;
100
0
    cs = c->session;
101
102
0
    if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
103
0
      control_write(c, "%%window-close @%u", w->id);
104
0
    else
105
0
      control_write(c, "%%unlinked-window-close @%u", w->id);
106
0
  }
107
0
}
108
109
void
110
control_notify_window_linked(__unused struct session *s, struct window *w)
111
0
{
112
0
  struct client *c;
113
0
  struct session  *cs;
114
115
0
  TAILQ_FOREACH(c, &clients, entry) {
116
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
117
0
      continue;
118
0
    cs = c->session;
119
120
0
    if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
121
0
      control_write(c, "%%window-add @%u", w->id);
122
0
    else
123
0
      control_write(c, "%%unlinked-window-add @%u", w->id);
124
0
  }
125
0
}
126
127
void
128
control_notify_window_renamed(struct window *w)
129
1.07k
{
130
1.07k
  struct client *c;
131
1.07k
  struct session  *cs;
132
133
1.07k
  TAILQ_FOREACH(c, &clients, entry) {
134
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
135
0
      continue;
136
0
    cs = c->session;
137
138
0
    if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) {
139
0
      control_write(c, "%%window-renamed @%u %s", w->id,
140
0
          w->name);
141
0
    } else {
142
0
      control_write(c, "%%unlinked-window-renamed @%u %s",
143
0
          w->id, w->name);
144
0
    }
145
0
  }
146
1.07k
}
147
148
void
149
control_notify_client_session_changed(struct client *cc)
150
0
{
151
0
  struct client *c;
152
0
  struct session  *s;
153
154
0
  if (cc->session == NULL)
155
0
    return;
156
0
  s = cc->session;
157
158
0
  TAILQ_FOREACH(c, &clients, entry) {
159
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
160
0
      continue;
161
162
0
    if (cc == c) {
163
0
      control_write(c, "%%session-changed $%u %s", s->id,
164
0
          s->name);
165
0
    } else {
166
0
      control_write(c, "%%client-session-changed %s $%u %s",
167
0
          cc->name, s->id, s->name);
168
0
    }
169
0
  }
170
0
}
171
172
void
173
control_notify_client_detached(struct client *cc)
174
0
{
175
0
  struct client *c;
176
177
0
  TAILQ_FOREACH(c, &clients, entry) {
178
0
    if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
179
0
      control_write(c, "%%client-detached %s", cc->name);
180
0
  }
181
0
}
182
183
void
184
control_notify_session_renamed(struct session *s)
185
0
{
186
0
  struct client *c;
187
188
0
  TAILQ_FOREACH(c, &clients, entry) {
189
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
190
0
      continue;
191
192
0
    control_write(c, "%%session-renamed $%u %s", s->id, s->name);
193
0
  }
194
0
}
195
196
void
197
control_notify_session_created(__unused struct session *s)
198
0
{
199
0
  struct client *c;
200
201
0
  TAILQ_FOREACH(c, &clients, entry) {
202
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
203
0
      continue;
204
205
0
    control_write(c, "%%sessions-changed");
206
0
  }
207
0
}
208
209
void
210
control_notify_session_closed(__unused struct session *s)
211
0
{
212
0
  struct client *c;
213
214
0
  TAILQ_FOREACH(c, &clients, entry) {
215
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
216
0
      continue;
217
218
0
    control_write(c, "%%sessions-changed");
219
0
  }
220
0
}
221
222
void
223
control_notify_session_window_changed(struct session *s)
224
0
{
225
0
  struct client *c;
226
227
0
  TAILQ_FOREACH(c, &clients, entry) {
228
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
229
0
      continue;
230
231
0
    control_write(c, "%%session-window-changed $%u @%u", s->id,
232
0
        s->curw->window->id);
233
0
  }
234
0
}
235
236
void
237
control_notify_paste_buffer_changed(const char *name)
238
783
{
239
783
  struct client *c;
240
241
783
  TAILQ_FOREACH(c, &clients, entry) {
242
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
243
0
      continue;
244
245
0
    control_write(c, "%%paste-buffer-changed %s", name);
246
0
  }
247
783
}
248
249
void
250
control_notify_paste_buffer_deleted(const char *name)
251
733
{
252
733
  struct client *c;
253
254
733
  TAILQ_FOREACH(c, &clients, entry) {
255
0
    if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
256
0
      continue;
257
258
0
    control_write(c, "%%paste-buffer-deleted %s", name);
259
0
  }
260
733
}