Annotation of src/usr.bin/tmux/server-fn.c, Revision 1.37
1.37 ! nicm 1: /* $OpenBSD: server-fn.c,v 1.36 2010/04/17 23:25:16 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2007 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 <string.h>
1.5 nicm 22: #include <time.h>
1.1 nicm 23: #include <unistd.h>
24:
25: #include "tmux.h"
26:
1.28 nicm 27: void server_callback_identify(int, short, void *);
28:
1.13 nicm 29: void
30: server_fill_environ(struct session *s, struct environ *env)
1.1 nicm 31: {
1.13 nicm 32: char tmuxvar[MAXPATHLEN], *term;
33: u_int idx;
1.1 nicm 34:
35: if (session_index(s, &idx) != 0)
36: fatalx("session not found");
37: xsnprintf(tmuxvar, sizeof tmuxvar,
1.13 nicm 38: "%s,%ld,%u", socket_path, (long) getpid(), idx);
39: environ_set(env, "TMUX", tmuxvar);
1.1 nicm 40:
1.13 nicm 41: term = options_get_string(&s->options, "default-terminal");
42: environ_set(env, "TERM", term);
1.10 nicm 43: }
44:
45: void
1.1 nicm 46: server_write_client(
1.11 nicm 47: struct client *c, enum msgtype type, const void *buf, size_t len)
1.1 nicm 48: {
1.14 nicm 49: struct imsgbuf *ibuf = &c->ibuf;
1.1 nicm 50:
1.12 nicm 51: if (c->flags & CLIENT_BAD)
52: return;
1.14 nicm 53: log_debug("writing %d to client %d", type, c->ibuf.fd);
54: imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len);
1.31 nicm 55: server_update_event(c);
1.1 nicm 56: }
57:
58: void
59: server_write_session(
1.11 nicm 60: struct session *s, enum msgtype type, const void *buf, size_t len)
1.1 nicm 61: {
62: struct client *c;
63: u_int i;
64:
65: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
66: c = ARRAY_ITEM(&clients, i);
67: if (c == NULL || c->session == NULL)
68: continue;
69: if (c->session == s)
70: server_write_client(c, type, buf, len);
71: }
72: }
73:
74: void
75: server_redraw_client(struct client *c)
76: {
77: c->flags |= CLIENT_REDRAW;
78: }
79:
80: void
81: server_status_client(struct client *c)
82: {
83: c->flags |= CLIENT_STATUS;
84: }
85:
86: void
87: server_redraw_session(struct session *s)
88: {
89: struct client *c;
90: u_int i;
91:
92: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
93: c = ARRAY_ITEM(&clients, i);
94: if (c == NULL || c->session == NULL)
95: continue;
96: if (c->session == s)
97: server_redraw_client(c);
98: }
99: }
100:
101: void
1.25 nicm 102: server_redraw_session_group(struct session *s)
103: {
104: struct session_group *sg;
105:
106: if ((sg = session_group_find(s)) == NULL)
107: server_redraw_session(s);
108: else {
109: TAILQ_FOREACH(s, &sg->sessions, gentry)
110: server_redraw_session(s);
111: }
112: }
113:
114: void
1.1 nicm 115: server_status_session(struct session *s)
116: {
117: struct client *c;
118: u_int i;
119:
120: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
121: c = ARRAY_ITEM(&clients, i);
122: if (c == NULL || c->session == NULL)
123: continue;
124: if (c->session == s)
125: server_status_client(c);
126: }
127: }
128:
129: void
1.25 nicm 130: server_status_session_group(struct session *s)
131: {
132: struct session_group *sg;
133:
134: if ((sg = session_group_find(s)) == NULL)
135: server_status_session(s);
136: else {
137: TAILQ_FOREACH(s, &sg->sessions, gentry)
138: server_status_session(s);
139: }
140: }
141:
142: void
1.1 nicm 143: server_redraw_window(struct window *w)
144: {
145: struct client *c;
146: u_int i;
147:
148: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
149: c = ARRAY_ITEM(&clients, i);
150: if (c == NULL || c->session == NULL)
151: continue;
152: if (c->session->curw->window == w)
153: server_redraw_client(c);
154: }
155: w->flags |= WINDOW_REDRAW;
1.33 nicm 156: }
157:
158: void
159: server_redraw_window_borders(struct window *w)
160: {
161: struct client *c;
162: u_int i;
163:
164: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
165: c = ARRAY_ITEM(&clients, i);
166: if (c == NULL || c->session == NULL)
167: continue;
168: if (c->session->curw->window == w)
169: c->flags |= CLIENT_BORDERS;
170: }
1.1 nicm 171: }
172:
173: void
174: server_status_window(struct window *w)
175: {
176: struct session *s;
177: u_int i;
178:
179: /*
180: * This is slightly different. We want to redraw the status line of any
181: * clients containing this window rather than any where it is the
182: * current window.
183: */
184:
185: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
186: s = ARRAY_ITEM(&sessions, i);
1.37 ! nicm 187: if (s != NULL && session_has(s, w) != NULL)
1.1 nicm 188: server_status_session(s);
189: }
190: }
191:
192: void
193: server_lock(void)
194: {
1.23 nicm 195: struct client *c;
196: u_int i;
1.17 nicm 197:
1.1 nicm 198: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
199: c = ARRAY_ITEM(&clients, i);
200: if (c == NULL || c->session == NULL)
201: continue;
1.23 nicm 202: server_lock_client(c);
203: }
204: }
1.1 nicm 205:
1.23 nicm 206: void
207: server_lock_session(struct session *s)
208: {
209: struct client *c;
210: u_int i;
211:
212: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
213: c = ARRAY_ITEM(&clients, i);
214: if (c == NULL || c->session == NULL || c->session != s)
215: continue;
216: server_lock_client(c);
1.31 nicm 217: }
1.23 nicm 218: }
1.1 nicm 219:
1.23 nicm 220: void
221: server_lock_client(struct client *c)
222: {
223: const char *cmd;
224: size_t cmdlen;
225: struct msg_lock_data lockdata;
1.24 nicm 226:
227: if (c->flags & CLIENT_SUSPENDED)
228: return;
1.1 nicm 229:
1.23 nicm 230: cmd = options_get_string(&c->session->options, "lock-command");
231: cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd);
232: if (cmdlen >= sizeof lockdata.cmd)
233: return;
1.31 nicm 234:
1.23 nicm 235: tty_stop_tty(&c->tty);
236: tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP));
237: tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR));
238:
239: c->flags |= CLIENT_SUSPENDED;
240: server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata);
1.8 nicm 241: }
242:
243: void
244: server_kill_window(struct window *w)
245: {
246: struct session *s;
247: struct winlink *wl;
1.19 nicm 248: u_int i;
1.31 nicm 249:
1.8 nicm 250: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
251: s = ARRAY_ITEM(&sessions, i);
1.37 ! nicm 252: if (s == NULL || session_has(s, w) == NULL)
1.8 nicm 253: continue;
1.34 nicm 254: while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) {
255: if (session_detach(s, wl)) {
256: server_destroy_session_group(s);
257: break;
258: } else
259: server_redraw_session_group(s);
260: }
1.8 nicm 261: }
1.21 nicm 262: }
263:
264: int
1.25 nicm 265: server_link_window(struct session *src, struct winlink *srcwl,
266: struct session *dst, int dstidx, int killflag, int selectflag, char **cause)
1.21 nicm 267: {
1.25 nicm 268: struct winlink *dstwl;
269: struct session_group *srcsg, *dstsg;
270:
271: srcsg = session_group_find(src);
272: dstsg = session_group_find(dst);
273: if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) {
274: xasprintf(cause, "sessions are grouped");
275: return (-1);
276: }
1.21 nicm 277:
278: dstwl = NULL;
279: if (dstidx != -1)
280: dstwl = winlink_find_by_index(&dst->windows, dstidx);
281: if (dstwl != NULL) {
282: if (dstwl->window == srcwl->window)
283: return (0);
284: if (killflag) {
285: /*
286: * Can't use session_detach as it will destroy session
287: * if this makes it empty.
288: */
1.37 ! nicm 289: dstwl->flags &= ~WINLINK_ALERTFLAGS;
1.21 nicm 290: winlink_stack_remove(&dst->lastw, dstwl);
291: winlink_remove(&dst->windows, dstwl);
292:
293: /* Force select/redraw if current. */
1.26 nicm 294: if (dstwl == dst->curw) {
1.21 nicm 295: selectflag = 1;
1.26 nicm 296: dst->curw = NULL;
297: }
1.21 nicm 298: }
299: }
300:
301: if (dstidx == -1)
302: dstidx = -1 - options_get_number(&dst->options, "base-index");
303: dstwl = session_attach(dst, srcwl->window, dstidx, cause);
304: if (dstwl == NULL)
305: return (-1);
306:
1.25 nicm 307: if (selectflag)
1.21 nicm 308: session_select(dst, dstwl->idx);
1.25 nicm 309: server_redraw_session_group(dst);
1.21 nicm 310:
311: return (0);
312: }
313:
314: void
315: server_unlink_window(struct session *s, struct winlink *wl)
316: {
317: if (session_detach(s, wl))
1.25 nicm 318: server_destroy_session_group(s);
319: else
320: server_redraw_session_group(s);
1.29 nicm 321: }
322:
323: void
324: server_destroy_pane(struct window_pane *wp)
325: {
326: struct window *w = wp->window;
327:
1.36 nicm 328: if (wp->fd != -1) {
329: close(wp->fd);
330: bufferevent_free(wp->event);
331: wp->fd = -1;
332: }
1.29 nicm 333:
334: if (options_get_number(&w->options, "remain-on-exit"))
335: return;
336:
337: layout_close_pane(wp);
338: window_remove_pane(w, wp);
339:
340: if (TAILQ_EMPTY(&w->panes))
341: server_kill_window(w);
342: else
343: server_redraw_window(w);
1.25 nicm 344: }
345:
346: void
347: server_destroy_session_group(struct session *s)
348: {
349: struct session_group *sg;
350:
351: if ((sg = session_group_find(s)) == NULL)
1.21 nicm 352: server_destroy_session(s);
1.25 nicm 353: else {
354: TAILQ_FOREACH(s, &sg->sessions, gentry)
355: server_destroy_session(s);
356: TAILQ_REMOVE(&session_groups, sg, entry);
357: xfree(sg);
358: }
1.19 nicm 359: }
360:
361: void
362: server_destroy_session(struct session *s)
363: {
364: struct client *c;
365: u_int i;
1.31 nicm 366:
1.19 nicm 367: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
368: c = ARRAY_ITEM(&clients, i);
369: if (c == NULL || c->session != s)
370: continue;
371: c->session = NULL;
372: server_write_client(c, MSG_EXIT, NULL, 0);
373: }
1.15 nicm 374: }
375:
376: void
377: server_set_identify(struct client *c)
378: {
379: struct timeval tv;
380: int delay;
381:
382: delay = options_get_number(&c->session->options, "display-panes-time");
383: tv.tv_sec = delay / 1000;
384: tv.tv_usec = (delay % 1000) * 1000L;
1.31 nicm 385:
1.28 nicm 386: evtimer_del(&c->identify_timer);
387: evtimer_set(&c->identify_timer, server_callback_identify, c);
388: evtimer_add(&c->identify_timer, &tv);
1.15 nicm 389:
390: c->flags |= CLIENT_IDENTIFY;
391: c->tty.flags |= (TTY_FREEZE|TTY_NOCURSOR);
392: server_redraw_client(c);
393: }
394:
395: void
396: server_clear_identify(struct client *c)
397: {
398: if (c->flags & CLIENT_IDENTIFY) {
399: c->flags &= ~CLIENT_IDENTIFY;
400: c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
401: server_redraw_client(c);
402: }
1.28 nicm 403: }
404:
1.30 nicm 405: /* ARGSUSED */
1.28 nicm 406: void
407: server_callback_identify(unused int fd, unused short events, void *data)
408: {
409: struct client *c = data;
410:
411: server_clear_identify(c);
1.27 nicm 412: }
413:
414: void
415: server_update_event(struct client *c)
416: {
417: short events;
418:
419: events = 0;
420: if (!(c->flags & CLIENT_BAD))
421: events |= EV_READ;
422: if (c->ibuf.w.queued > 0)
423: events |= EV_WRITE;
424: event_del(&c->event);
425: event_set(&c->event, c->ibuf.fd, events, server_client_callback, c);
1.31 nicm 426: event_add(&c->event, NULL);
1.1 nicm 427: }