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