tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

alerts.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2015 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 MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <stdlib.h>
22 
23 #include "tmux.h"
24 
25 static int alerts_fired;
26 
27 static void alerts_timer(int, short, void *);
28 static int alerts_enabled(struct window *, int);
29 static void alerts_callback(int, short, void *);
30 static void alerts_reset(struct window *);
31 
32 static int alerts_action_applies(struct winlink *, const char *);
33 static int alerts_check_all(struct window *);
34 static int alerts_check_bell(struct window *);
35 static int alerts_check_activity(struct window *);
36 static int alerts_check_silence(struct window *);
37 static void alerts_set_message(struct winlink *, const char *,
38  const char *);
39 
40 static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
41 
42 static void
43 alerts_timer(__unused int fd, __unused short events, void *arg)
44 {
45  struct window *w = arg;
46 
47  log_debug("@%u alerts timer expired", w->id);
49 }
50 
51 static void
52 alerts_callback(__unused int fd, __unused short events, __unused void *arg)
53 {
54  struct window *w, *w1;
55  int alerts;
56 
57  TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
58  alerts = alerts_check_all(w);
59  log_debug("@%u alerts check, alerts %#x", w->id, alerts);
60 
61  w->alerts_queued = 0;
62  TAILQ_REMOVE(&alerts_list, w, alerts_entry);
63 
64  w->flags &= ~~WINDOW_ALERTFLAGS;
65  window_remove_ref(w, __func__);
66  }
67  alerts_fired = 0;
68 }
69 
70 static int
71 alerts_action_applies(struct winlink *wl, const char *name)
72 {
73  int action;
74 
75  /*
76  * {bell,activity,silence}-action determines when to alert: none means
77  * nothing happens, current means only do something for the current
78  * window and other means only for windows other than the current.
79  */
80 
81  action = options_get_number(wl->session->options, name);
82  if (action == ALERT_ANY)
83  return (1);
84  if (action == ALERT_CURRENT)
85  return (wl == wl->session->curw);
86  if (action == ALERT_OTHER)
87  return (wl != wl->session->curw);
88  return (0);
89 }
90 
91 static int
93 {
94  int alerts;
95 
96  alerts = alerts_check_bell(w);
97  alerts |= alerts_check_activity(w);
98  alerts |= alerts_check_silence(w);
99  return (alerts);
100 }
101 
102 void
104 {
105  struct winlink *wl;
106 
107  RB_FOREACH(wl, winlinks, &s->windows)
109 }
110 
111 static int
112 alerts_enabled(struct window *w, int flags)
113 {
114  if (flags & WINDOW_BELL) {
115  if (options_get_number(w->options, "monitor-bell"))
116  return (1);
117  }
118  if (flags & WINDOW_ACTIVITY) {
119  if (options_get_number(w->options, "monitor-activity"))
120  return (1);
121  }
122  if (flags & WINDOW_SILENCE) {
123  if (options_get_number(w->options, "monitor-silence") != 0)
124  return (1);
125  }
126  return (0);
127 }
128 
129 void
131 {
132  struct window *w;
133 
134  RB_FOREACH(w, windows, &windows)
135  alerts_reset(w);
136 }
137 
138 static void
140 {
141  struct timeval tv;
142 
143  if (!event_initialized(&w->alerts_timer))
144  evtimer_set(&w->alerts_timer, alerts_timer, w);
145 
146  w->flags &= ~~WINDOW_SILENCE;
147  event_del(&w->alerts_timer);
148 
149  timerclear(&tv);
150  tv.tv_sec = options_get_number(w->options, "monitor-silence");
151 
152  log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
153  if (tv.tv_sec != 0)
154  event_add(&w->alerts_timer, &tv);
155 }
156 
157 void
158 alerts_queue(struct window *w, int flags)
159 {
160  alerts_reset(w);
161 
162  if ((w->flags & flags) != flags) {
163  w->flags |= flags;
164  log_debug("@%u alerts flags added %#x", w->id, flags);
165  }
166 
167  if (alerts_enabled(w, flags)) {
168  if (!w->alerts_queued) {
169  w->alerts_queued = 1;
170  TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
171  window_add_ref(w, __func__);
172  }
173 
174  if (!alerts_fired) {
175  log_debug("alerts check queued (by @%u)", w->id);
176  event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
177  alerts_fired = 1;
178  }
179  }
180 }
181 
182 static int
184 {
185  struct winlink *wl;
186  struct session *s;
187 
188  if (~w->flags & WINDOW_BELL)
189  return (0);
190  if (!options_get_number(w->options, "monitor-bell"))
191  return (0);
192 
193  TAILQ_FOREACH(wl, &w->winlinks, wentry)
194  wl->session->flags &= ~~SESSION_ALERTED;
195 
196  TAILQ_FOREACH(wl, &w->winlinks, wentry) {
197  /*
198  * Bells are allowed even if there is an existing bell (so do
199  * not check WINLINK_BELL).
200  */
201  s = wl->session;
202  if (s->curw != wl || s->attached == 0) {
203  wl->flags |= WINLINK_BELL;
205  }
206  if (!alerts_action_applies(wl, "bell-action"))
207  continue;
208  notify_winlink("alert-bell", wl);
209 
210  if (s->flags & SESSION_ALERTED)
211  continue;
212  s->flags |= SESSION_ALERTED;
213 
214  alerts_set_message(wl, "Bell", "visual-bell");
215  }
216 
217  return (WINDOW_BELL);
218 }
219 
220 static int
222 {
223  struct winlink *wl;
224  struct session *s;
225 
226  if (~w->flags & WINDOW_ACTIVITY)
227  return (0);
228  if (!options_get_number(w->options, "monitor-activity"))
229  return (0);
230 
231  TAILQ_FOREACH(wl, &w->winlinks, wentry)
232  wl->session->flags &= ~~SESSION_ALERTED;
233 
234  TAILQ_FOREACH(wl, &w->winlinks, wentry) {
235  if (wl->flags & WINLINK_ACTIVITY)
236  continue;
237  s = wl->session;
238  if (s->curw != wl || s->attached == 0) {
239  wl->flags |= WINLINK_ACTIVITY;
241  }
242  if (!alerts_action_applies(wl, "activity-action"))
243  continue;
244  notify_winlink("alert-activity", wl);
245 
246  if (s->flags & SESSION_ALERTED)
247  continue;
248  s->flags |= SESSION_ALERTED;
249 
250  alerts_set_message(wl, "Activity", "visual-activity");
251  }
252 
253  return (WINDOW_ACTIVITY);
254 }
255 
256 static int
258 {
259  struct winlink *wl;
260  struct session *s;
261 
262  if (~w->flags & WINDOW_SILENCE)
263  return (0);
264  if (options_get_number(w->options, "monitor-silence") == 0)
265  return (0);
266 
267  TAILQ_FOREACH(wl, &w->winlinks, wentry)
268  wl->session->flags &= ~~SESSION_ALERTED;
269 
270  TAILQ_FOREACH(wl, &w->winlinks, wentry) {
271  if (wl->flags & WINLINK_SILENCE)
272  continue;
273  s = wl->session;
274  if (s->curw != wl || s->attached == 0) {
275  wl->flags |= WINLINK_SILENCE;
277  }
278  if (!alerts_action_applies(wl, "silence-action"))
279  continue;
280  notify_winlink("alert-silence", wl);
281 
282  if (s->flags & SESSION_ALERTED)
283  continue;
284  s->flags |= SESSION_ALERTED;
285 
286  alerts_set_message(wl, "Silence", "visual-silence");
287  }
288 
289  return (WINDOW_SILENCE);
290 }
291 
292 static void
293 alerts_set_message(struct winlink *wl, const char *type, const char *option)
294 {
295  struct client *c;
296  int visual;
297 
298  /*
299  * We have found an alert (bell, activity or silence), so we need to
300  * pass it on to the user. For each client attached to this session,
301  * decide whether a bell, message or both is needed.
302  *
303  * If visual-{bell,activity,silence} is on, then a message is
304  * substituted for a bell; if it is off, a bell is sent as normal; both
305  * mean both a bell and message is sent.
306  */
307 
308  visual = options_get_number(wl->session->options, option);
309  TAILQ_FOREACH(c, &clients, entry) {
310  if (c->session != wl->session || c->flags & CLIENT_CONTROL)
311  continue;
312 
313  if (visual == VISUAL_OFF || visual == VISUAL_BOTH)
314  tty_putcode(&c->tty, TTYC_BEL);
315  if (visual == VISUAL_OFF)
316  continue;
317  if (c->session->curw == wl) {
318  status_message_set(c, -1, 1, 0, "%s in current window",
319  type);
320  } else {
321  status_message_set(c, -1, 1, 0, "%s in window %d", type,
322  wl->idx);
323  }
324  }
325 }
static void alerts_set_message(struct winlink *, const char *, const char *)
Definition: alerts.c:293
static int alerts_fired
Definition: alerts.c:25
static void alerts_reset(struct window *)
Definition: alerts.c:139
static int alerts_check_bell(struct window *)
Definition: alerts.c:183
static void alerts_timer(int, short, void *)
static TAILQ_HEAD(window)
Definition: alerts.c:40
static int alerts_check_silence(struct window *)
Definition: alerts.c:257
static int alerts_check_activity(struct window *)
Definition: alerts.c:221
static int alerts_enabled(struct window *, int)
Definition: alerts.c:112
void alerts_queue(struct window *w, int flags)
Definition: alerts.c:158
static void alerts_callback(int, short, void *)
Definition: alerts.c:52
static int alerts_check_all(struct window *)
Definition: alerts.c:92
void alerts_reset_all(void)
Definition: alerts.c:130
static int alerts_action_applies(struct winlink *, const char *)
Definition: alerts.c:71
void alerts_check_session(struct session *s)
Definition: alerts.c:103
#define __unused
Definition: compat.h:60
const char * name
Definition: layout-set.c:38
void log_debug(const char *msg,...)
Definition: log.c:130
void notify_winlink(const char *name, struct winlink *wl)
Definition: notify.c:235
long long options_get_number(struct options *oo, const char *name)
Definition: options.c:699
void server_status_session(struct session *s)
Definition: server-fn.c:70
struct clients clients
Definition: server.c:42
void status_message_set(struct client *c, int delay, int ignore_styles, int ignore_keys, const char *fmt,...)
Definition: status.c:428
Definition: tmux.h:1608
struct tty tty
Definition: tmux.h:1640
struct session * session
Definition: tmux.h:1743
uint64_t flags
Definition: tmux.h:1703
Definition: tmux.h:1179
struct winlinks windows
Definition: tmux.h:1194
struct winlink * curw
Definition: tmux.h:1192
struct options * options
Definition: tmux.h:1199
u_int attached
Definition: tmux.h:1205
int flags
Definition: tmux.h:1203
Definition: tmux.h:1041
struct event alerts_timer
Definition: tmux.h:1049
u_int id
Definition: tmux.h:1042
int flags
Definition: tmux.h:1073
struct options * options
Definition: tmux.h:1085
int alerts_queued
Definition: tmux.h:1082
@ TTYC_BEL
Definition: tmux.h:279
void tty_putcode(struct tty *, enum tty_code_code)
Definition: tty.c:491
void window_remove_ref(struct window *, const char *)
Definition: window.c:391
#define WINLINK_SILENCE
Definition: tmux.h:1103
#define WINLINK_BELL
Definition: tmux.h:1101
#define WINDOW_SILENCE
Definition: tmux.h:1076
#define SESSION_ALERTED
Definition: tmux.h:1202
#define WINDOW_BELL
Definition: tmux.h:1074
#define VISUAL_BOTH
Definition: tmux.h:110
#define ALERT_CURRENT
Definition: tmux.h:104
#define WINLINK_ACTIVITY
Definition: tmux.h:1102
#define VISUAL_OFF
Definition: tmux.h:108
#define CLIENT_CONTROL
Definition: tmux.h:1667
void window_add_ref(struct window *, const char *)
Definition: window.c:384
#define ALERT_ANY
Definition: tmux.h:103
struct windows windows
Definition: window.c:56
#define ALERT_OTHER
Definition: tmux.h:105
#define WINDOW_ACTIVITY
Definition: tmux.h:1075