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