xref: /minix/external/bsd/tmux/dist/server-window.c (revision 0a6a1f1d)
1 /* Id */
2 
3 /*
4  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
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 <event.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 
25 #include "tmux.h"
26 
27 int	server_window_check_bell(struct session *, struct winlink *);
28 int	server_window_check_activity(struct session *, struct winlink *);
29 int	server_window_check_silence(struct session *, struct winlink *);
30 int	server_window_check_content(
31 	    struct session *, struct winlink *, struct window_pane *);
32 void	ring_bell(struct session *);
33 
34 /* Window functions that need to happen every loop. */
35 void
server_window_loop(void)36 server_window_loop(void)
37 {
38 	struct window		*w;
39 	struct winlink		*wl;
40 	struct window_pane	*wp;
41 	struct session		*s;
42 	u_int		 	 i;
43 
44 	for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
45 		w = ARRAY_ITEM(&windows, i);
46 		if (w == NULL)
47 			continue;
48 
49 		RB_FOREACH(s, sessions, &sessions) {
50 			wl = session_has(s, w);
51 			if (wl == NULL)
52 				continue;
53 
54 			if (server_window_check_bell(s, wl) ||
55 			    server_window_check_activity(s, wl) ||
56 			    server_window_check_silence(s, wl))
57 				server_status_session(s);
58 			TAILQ_FOREACH(wp, &w->panes, entry)
59 				server_window_check_content(s, wl, wp);
60 		}
61 	}
62 }
63 
64 /* Check for bell in window. */
65 int
server_window_check_bell(struct session * s,struct winlink * wl)66 server_window_check_bell(struct session *s, struct winlink *wl)
67 {
68 	struct client	*c;
69 	struct window	*w = wl->window;
70 	u_int		 i;
71 	int		 action, visual;
72 
73 	if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL)
74 		return (0);
75 	if (s->curw != wl || s->flags & SESSION_UNATTACHED)
76 		wl->flags |= WINLINK_BELL;
77 	if (s->flags & SESSION_UNATTACHED)
78 		return (0);
79 	if (s->curw->window == w)
80 		w->flags &= ~WINDOW_BELL;
81 
82 	visual = options_get_number(&s->options, "visual-bell");
83 	action = options_get_number(&s->options, "bell-action");
84 	if (action == BELL_NONE)
85 		return (0);
86 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
87 		c = ARRAY_ITEM(&clients, i);
88 		if (c == NULL || c->session != s || (c->flags & CLIENT_CONTROL))
89 			continue;
90 		if (!visual) {
91 			tty_bell(&c->tty);
92 			continue;
93 		}
94 		if (c->session->curw->window == w)
95 			status_message_set(c, "Bell in current window");
96 		else if (action == BELL_ANY)
97 			status_message_set(c, "Bell in window %u", wl->idx);
98 	}
99 
100 	return (1);
101 }
102 
103 /* Check for activity in window. */
104 int
server_window_check_activity(struct session * s,struct winlink * wl)105 server_window_check_activity(struct session *s, struct winlink *wl)
106 {
107 	struct client	*c;
108 	struct window	*w = wl->window;
109 	u_int		 i;
110 
111 	if (s->curw->window == w)
112 		w->flags &= ~WINDOW_ACTIVITY;
113 
114 	if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
115 		return (0);
116 	if (s->curw == wl && !(s->flags & SESSION_UNATTACHED))
117 		return (0);
118 
119 	if (!options_get_number(&w->options, "monitor-activity"))
120 		return (0);
121 
122 	if (options_get_number(&s->options, "bell-on-alert"))
123 		ring_bell(s);
124 	wl->flags |= WINLINK_ACTIVITY;
125 
126 	if (options_get_number(&s->options, "visual-activity")) {
127 		for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
128 			c = ARRAY_ITEM(&clients, i);
129 			if (c == NULL || c->session != s)
130 				continue;
131 			status_message_set(c, "Activity in window %u", wl->idx);
132 		}
133 	}
134 
135 	return (1);
136 }
137 
138 /* Check for silence in window. */
139 int
server_window_check_silence(struct session * s,struct winlink * wl)140 server_window_check_silence(struct session *s, struct winlink *wl)
141 {
142 	struct client	*c;
143 	struct window	*w = wl->window;
144 	struct timeval	 timer;
145 	u_int		 i;
146 	int		 silence_interval, timer_difference;
147 
148 	if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
149 		return (0);
150 
151 	if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) {
152 		/*
153 		 * Reset the timer for this window if we've focused it.  We
154 		 * don't want the timer tripping as soon as we've switched away
155 		 * from this window.
156 		 */
157 		if (gettimeofday(&w->silence_timer, NULL) != 0)
158 			fatal("gettimeofday failed.");
159 
160 		return (0);
161 	}
162 
163 	silence_interval = options_get_number(&w->options, "monitor-silence");
164 	if (silence_interval == 0)
165 		return (0);
166 
167 	if (gettimeofday(&timer, NULL) != 0)
168 		fatal("gettimeofday");
169 	timer_difference = timer.tv_sec - w->silence_timer.tv_sec;
170 	if (timer_difference <= silence_interval)
171 		return (0);
172 
173 	if (options_get_number(&s->options, "bell-on-alert"))
174 		ring_bell(s);
175 	wl->flags |= WINLINK_SILENCE;
176 
177 	if (options_get_number(&s->options, "visual-silence")) {
178 		for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
179 			c = ARRAY_ITEM(&clients, i);
180 			if (c == NULL || c->session != s)
181 				continue;
182 			status_message_set(c, "Silence in window %u", wl->idx);
183 		}
184 	}
185 
186 	return (1);
187 }
188 
189 /* Check for content change in window. */
190 int
server_window_check_content(struct session * s,struct winlink * wl,struct window_pane * wp)191 server_window_check_content(
192     struct session *s, struct winlink *wl, struct window_pane *wp)
193 {
194 	struct client	*c;
195 	struct window	*w = wl->window;
196 	u_int		 i;
197 	char		*found, *ptr;
198 
199 	/* Activity flag must be set for new content. */
200 	if (s->curw->window == w)
201 		w->flags &= ~WINDOW_ACTIVITY;
202 
203 	if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT)
204 		return (0);
205 	if (s->curw == wl && !(s->flags & SESSION_UNATTACHED))
206 		return (0);
207 
208 	ptr = options_get_string(&w->options, "monitor-content");
209 	if (ptr == NULL || *ptr == '\0')
210 		return (0);
211 	if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
212 		return (0);
213 	free(found);
214 
215 	if (options_get_number(&s->options, "bell-on-alert"))
216 		ring_bell(s);
217 	wl->flags |= WINLINK_CONTENT;
218 
219 	if (options_get_number(&s->options, "visual-content")) {
220 		for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
221 			c = ARRAY_ITEM(&clients, i);
222 			if (c == NULL || c->session != s)
223 				continue;
224 			status_message_set(c, "Content in window %u", wl->idx);
225 		}
226 	}
227 
228 	return (1);
229 }
230 
231 /* Ring terminal bell. */
232 void
ring_bell(struct session * s)233 ring_bell(struct session *s)
234 {
235 	struct client	*c;
236 	u_int		 i;
237 
238 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
239 		c = ARRAY_ITEM(&clients, i);
240 		if (c != NULL && c->session == s && !(c->flags & CLIENT_CONTROL))
241 			tty_bell(&c->tty);
242 	}
243 }
244