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