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