Annotation of src/usr.bin/tmux/server-window.c, Revision 1.7
1.7 ! nicm 1: /* $OpenBSD: server-window.c,v 1.6 2009/11/04 20:59:22 nicm Exp $ */
1.1 nicm 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:
1.5 nicm 21: #include <event.h>
1.1 nicm 22: #include <unistd.h>
23:
24: #include "tmux.h"
25:
1.3 nicm 26: int server_window_backoff(struct window_pane *);
1.1 nicm 27: int server_window_check_bell(struct session *, struct window *);
28: int server_window_check_activity(struct session *, struct window *);
29: int server_window_check_content(
30: struct session *, struct window *, struct window_pane *);
31: void server_window_check_alive(struct window *);
1.2 nicm 32:
33: /* Register windows for poll. */
34: void
35: server_window_prepare(void)
36: {
37: struct window *w;
38: struct window_pane *wp;
39: u_int i;
40: int events;
41:
42: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
43: if ((w = ARRAY_ITEM(&windows, i)) == NULL)
44: continue;
45:
46: TAILQ_FOREACH(wp, &w->panes, entry) {
47: if (wp->fd == -1)
48: continue;
1.3 nicm 49: events = 0;
50: if (!server_window_backoff(wp))
1.6 nicm 51: events |= EV_READ;
1.2 nicm 52: if (BUFFER_USED(wp->out) > 0)
1.5 nicm 53: events |= EV_WRITE;
54: event_del(&wp->event);
55: event_set(&wp->event,
1.2 nicm 56: wp->fd, events, server_window_callback, wp);
1.5 nicm 57: event_add(&wp->event, NULL);
1.2 nicm 58:
59: if (wp->pipe_fd == -1)
60: continue;
61: events = 0;
62: if (BUFFER_USED(wp->pipe_buf) > 0)
1.5 nicm 63: events |= EV_WRITE;
64: event_del(&wp->pipe_event);
65: event_set(&wp->pipe_event,
1.2 nicm 66: wp->pipe_fd, events, server_window_callback, wp);
1.5 nicm 67: event_add(&wp->pipe_event, NULL);
1.2 nicm 68: }
69: }
1.3 nicm 70: }
71:
72: /* Check if this window should suspend reading. */
73: int
74: server_window_backoff(struct window_pane *wp)
75: {
76: struct client *c;
77: u_int i;
78:
79: if (!window_pane_visible(wp))
80: return (0);
81:
82: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
83: c = ARRAY_ITEM(&clients, i);
84: if (c == NULL || c->session == NULL)
1.4 nicm 85: continue;
86: if ((c->flags & (CLIENT_SUSPENDED|CLIENT_DEAD)) != 0)
1.3 nicm 87: continue;
88: if (c->session->curw->window != wp->window)
89: continue;
1.7 ! nicm 90:
! 91: if (EVBUFFER_LENGTH(c->tty.event->output) > BACKOFF_THRESHOLD)
1.3 nicm 92: return (1);
93: }
94: return (0);
1.2 nicm 95: }
1.1 nicm 96:
97: /* Process a single window pane event. */
98: void
1.5 nicm 99: server_window_callback(int fd, short events, void *data)
1.1 nicm 100: {
101: struct window_pane *wp = data;
102:
103: if (wp->fd == -1)
104: return;
105:
106: if (fd == wp->fd) {
107: if (buffer_poll(fd, events, wp->in, wp->out) != 0) {
108: close(wp->fd);
109: wp->fd = -1;
110: } else
111: window_pane_parse(wp);
112: }
113:
114: if (fd == wp->pipe_fd) {
115: if (buffer_poll(fd, events, NULL, wp->pipe_buf) != 0) {
116: buffer_destroy(wp->pipe_buf);
117: close(wp->pipe_fd);
118: wp->pipe_fd = -1;
119: }
120: }
121: }
122:
123: /* Window functions that need to happen every loop. */
124: void
125: server_window_loop(void)
126: {
127: struct window *w;
128: struct window_pane *wp;
129: struct session *s;
130: u_int i, j;
131:
132: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
133: w = ARRAY_ITEM(&windows, i);
134: if (w == NULL)
135: continue;
136:
137: for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
138: s = ARRAY_ITEM(&sessions, j);
139: if (s == NULL || !session_has(s, w))
140: continue;
141:
142: if (server_window_check_bell(s, w) ||
143: server_window_check_activity(s, w))
144: server_status_session(s);
145: TAILQ_FOREACH(wp, &w->panes, entry)
146: server_window_check_content(s, w, wp);
147: }
148: w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
149:
150: server_window_check_alive(w);
151: }
152:
153: set_window_names();
154: }
155:
156: /* Check for bell in window. */
157: int
158: server_window_check_bell(struct session *s, struct window *w)
159: {
160: struct client *c;
161: u_int i;
162: int action, visual;
163:
164: if (!(w->flags & WINDOW_BELL))
165: return (0);
166:
167: if (session_alert_has_window(s, w, WINDOW_BELL))
168: return (0);
169: session_alert_add(s, w, WINDOW_BELL);
170:
171: action = options_get_number(&s->options, "bell-action");
172: switch (action) {
173: case BELL_ANY:
174: if (s->flags & SESSION_UNATTACHED)
175: break;
176: visual = options_get_number(&s->options, "visual-bell");
177: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
178: c = ARRAY_ITEM(&clients, i);
179: if (c == NULL || c->session != s)
180: continue;
181: if (!visual) {
182: tty_putcode(&c->tty, TTYC_BEL);
183: continue;
184: }
185: if (c->session->curw->window == w) {
186: status_message_set(c, "Bell in current window");
187: continue;
188: }
189: status_message_set(c, "Bell in window %u",
190: winlink_find_by_window(&s->windows, w)->idx);
191: }
192: break;
193: case BELL_CURRENT:
194: if (s->flags & SESSION_UNATTACHED)
195: break;
196: visual = options_get_number(&s->options, "visual-bell");
197: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
198: c = ARRAY_ITEM(&clients, i);
199: if (c == NULL || c->session != s)
200: continue;
201: if (c->session->curw->window != w)
202: continue;
203: if (!visual) {
204: tty_putcode(&c->tty, TTYC_BEL);
205: continue;
206: }
207: status_message_set(c, "Bell in current window");
208: }
209: break;
210: }
211:
212: return (1);
213: }
214:
215: /* Check for activity in window. */
216: int
217: server_window_check_activity(struct session *s, struct window *w)
218: {
219: struct client *c;
220: u_int i;
221:
222: if (!(w->flags & WINDOW_ACTIVITY))
223: return (0);
224: if (s->curw->window == w)
225: return (0);
226:
227: if (!options_get_number(&w->options, "monitor-activity"))
228: return (0);
229:
230: if (session_alert_has_window(s, w, WINDOW_ACTIVITY))
231: return (0);
232: session_alert_add(s, w, WINDOW_ACTIVITY);
233:
234: if (s->flags & SESSION_UNATTACHED)
235: return (0);
236: if (options_get_number(&s->options, "visual-activity")) {
237: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
238: c = ARRAY_ITEM(&clients, i);
239: if (c == NULL || c->session != s)
240: continue;
241: status_message_set(c, "Activity in window %u",
242: winlink_find_by_window(&s->windows, w)->idx);
243: }
244: }
245:
246: return (1);
247: }
248:
249: /* Check for content change in window. */
250: int
251: server_window_check_content(
252: struct session *s, struct window *w, struct window_pane *wp)
253: {
254: struct client *c;
255: u_int i;
256: char *found, *ptr;
257:
258: if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */
259: return (0);
260: if (s->curw->window == w)
261: return (0);
262:
263: ptr = options_get_string(&w->options, "monitor-content");
264: if (ptr == NULL || *ptr == '\0')
265: return (0);
266:
267: if (session_alert_has_window(s, w, WINDOW_CONTENT))
268: return (0);
269:
270: if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
271: return (0);
272: xfree(found);
273:
274: session_alert_add(s, w, WINDOW_CONTENT);
275: if (s->flags & SESSION_UNATTACHED)
276: return (0);
277: if (options_get_number(&s->options, "visual-content")) {
278: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
279: c = ARRAY_ITEM(&clients, i);
280: if (c == NULL || c->session != s)
281: continue;
282: status_message_set(c, "Content in window %u",
283: winlink_find_by_window(&s->windows, w)->idx);
284: }
285: }
286:
287: return (1);
288: }
289:
290: /* Check if window still exists. */
291: void
292: server_window_check_alive(struct window *w)
293: {
294: struct window_pane *wp, *wq;
295: struct options *oo = &w->options;
296: struct session *s;
297: struct winlink *wl;
298: u_int i;
299: int destroyed;
300:
301: destroyed = 1;
302:
303: wp = TAILQ_FIRST(&w->panes);
304: while (wp != NULL) {
305: wq = TAILQ_NEXT(wp, entry);
306: /*
307: * If the pane has died and the remain-on-exit flag is not set,
308: * remove the pane; otherwise, if the flag is set, don't allow
309: * the window to be destroyed (or it'll close when the last
310: * pane dies).
311: */
312: if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) {
313: layout_close_pane(wp);
314: window_remove_pane(w, wp);
315: server_redraw_window(w);
316: } else
317: destroyed = 0;
318: wp = wq;
319: }
320:
321: if (!destroyed)
322: return;
323:
324: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
325: s = ARRAY_ITEM(&sessions, i);
326: if (s == NULL)
327: continue;
328: if (!session_has(s, w))
329: continue;
330:
331: restart:
332: /* Detach window and either redraw or kill clients. */
333: RB_FOREACH(wl, winlinks, &s->windows) {
334: if (wl->window != w)
335: continue;
336: if (session_detach(s, wl)) {
337: server_destroy_session_group(s);
338: break;
339: }
340: server_redraw_session(s);
341: server_status_session_group(s);
342: goto restart;
343: }
344: }
345:
346: recalculate_sizes();
347: }