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