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 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 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 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 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 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 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