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