Annotation of src/usr.bin/tmux/session.c, Revision 1.4
1.4 ! nicm 1: /* $OpenBSD: session.c,v 1.3 2009/08/08 21:52:43 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: #include <sys/time.h>
21:
22: #include <string.h>
23: #include <stdlib.h>
24: #include <unistd.h>
25:
26: #include "tmux.h"
27:
28: /* Global session list. */
29: struct sessions sessions;
30:
31: struct winlink *session_next_activity(struct session *, struct winlink *);
32: struct winlink *session_previous_activity(struct session *, struct winlink *);
33:
34: void
35: session_alert_cancel(struct session *s, struct winlink *wl)
36: {
37: struct session_alert *sa, *sb;
38:
39: sa = SLIST_FIRST(&s->alerts);
40: while (sa != NULL) {
41: sb = sa;
42: sa = SLIST_NEXT(sa, entry);
43:
44: if (wl == NULL || sb->wl == wl) {
45: SLIST_REMOVE(&s->alerts, sb, session_alert, entry);
46: xfree(sb);
47: }
48: }
49: }
50:
51: void
52: session_alert_add(struct session *s, struct window *w, int type)
53: {
54: struct session_alert *sa;
55: struct winlink *wl;
56:
57: RB_FOREACH(wl, winlinks, &s->windows) {
58: if (wl == s->curw)
59: continue;
60:
61: if (wl->window == w &&
62: !session_alert_has(s, wl, type)) {
63: sa = xmalloc(sizeof *sa);
64: sa->wl = wl;
65: sa->type = type;
66: SLIST_INSERT_HEAD(&s->alerts, sa, entry);
67: }
68: }
69: }
70:
71: int
72: session_alert_has(struct session *s, struct winlink *wl, int type)
73: {
74: struct session_alert *sa;
75:
76: SLIST_FOREACH(sa, &s->alerts, entry) {
77: if (sa->wl == wl && sa->type == type)
78: return (1);
79: }
80:
81: return (0);
82: }
83:
84: int
85: session_alert_has_window(struct session *s, struct window *w, int type)
86: {
87: struct session_alert *sa;
88:
89: SLIST_FOREACH(sa, &s->alerts, entry) {
90: if (sa->wl->window == w && sa->type == type)
91: return (1);
92: }
93:
94: return (0);
95: }
96:
97: /* Find session by name. */
98: struct session *
99: session_find(const char *name)
100: {
101: struct session *s;
102: u_int i;
103:
104: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
105: s = ARRAY_ITEM(&sessions, i);
106: if (s != NULL && strcmp(s->name, name) == 0)
107: return (s);
108: }
109:
110: return (NULL);
111: }
112:
113: /* Create a new session. */
114: struct session *
1.3 nicm 115: session_create(const char *name, const char *cmd, const char *cwd,
1.4 ! nicm 116: struct environ *env, struct termios *tio, u_int sx, u_int sy, char **cause)
1.1 nicm 117: {
118: struct session *s;
119: u_int i;
120:
121: s = xmalloc(sizeof *s);
122: s->flags = 0;
123: if (gettimeofday(&s->tv, NULL) != 0)
124: fatal("gettimeofday");
125: s->curw = NULL;
126: SLIST_INIT(&s->lastw);
127: RB_INIT(&s->windows);
128: SLIST_INIT(&s->alerts);
129: paste_init_stack(&s->buffers);
1.2 nicm 130: options_init(&s->options, &global_s_options);
1.3 nicm 131: environ_init(&s->environ);
132: if (env != NULL)
133: environ_copy(env, &s->environ);
1.4 ! nicm 134: memcpy(&s->tio, tio, sizeof s->tio);
1.1 nicm 135:
136: s->sx = sx;
137: s->sy = sy;
138:
139: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
140: if (ARRAY_ITEM(&sessions, i) == NULL) {
141: ARRAY_SET(&sessions, i, s);
142: break;
143: }
144: }
145: if (i == ARRAY_LENGTH(&sessions))
146: ARRAY_ADD(&sessions, s);
147:
148: if (name != NULL)
149: s->name = xstrdup(name);
150: else
151: xasprintf(&s->name, "%u", i);
152: if (session_new(s, NULL, cmd, cwd, -1, cause) == NULL) {
153: session_destroy(s);
154: return (NULL);
155: }
156: session_select(s, 0);
157:
158: log_debug("session %s created", s->name);
159:
160: return (s);
161: }
162:
163: /* Destroy a session. */
164: void
165: session_destroy(struct session *s)
166: {
167: u_int i;
168:
169: log_debug("session %s destroyed", s->name);
170:
171: if (session_index(s, &i) != 0)
172: fatalx("session not found");
173: ARRAY_SET(&sessions, i, NULL);
174: while (!ARRAY_EMPTY(&sessions) && ARRAY_LAST(&sessions) == NULL)
175: ARRAY_TRUNC(&sessions, 1);
176:
177: session_alert_cancel(s, NULL);
1.3 nicm 178: environ_free(&s->environ);
1.1 nicm 179: options_free(&s->options);
180: paste_free_stack(&s->buffers);
181:
182: while (!SLIST_EMPTY(&s->lastw))
183: winlink_stack_remove(&s->lastw, SLIST_FIRST(&s->lastw));
184: while (!RB_EMPTY(&s->windows))
185: winlink_remove(&s->windows, RB_ROOT(&s->windows));
186:
187: xfree(s->name);
188: xfree(s);
189: }
190:
191: /* Find session index. */
192: int
193: session_index(struct session *s, u_int *i)
194: {
195: for (*i = 0; *i < ARRAY_LENGTH(&sessions); (*i)++) {
196: if (s == ARRAY_ITEM(&sessions, *i))
197: return (0);
198: }
199: return (-1);
200: }
201:
202: /* Create a new window on a session. */
203: struct winlink *
1.4 ! nicm 204: session_new(struct session *s,
1.1 nicm 205: const char *name, const char *cmd, const char *cwd, int idx, char **cause)
206: {
207: struct window *w;
1.3 nicm 208: struct environ env;
1.1 nicm 209: u_int hlimit;
210:
1.3 nicm 211: environ_init(&env);
212: environ_copy(&global_environ, &env);
213: environ_copy(&s->environ, &env);
214: server_fill_environ(s, &env);
1.1 nicm 215:
216: hlimit = options_get_number(&s->options, "history-limit");
1.4 ! nicm 217: w = window_create(
! 218: name, cmd, cwd, &env, &s->tio, s->sx, s->sy, hlimit, cause);
1.3 nicm 219: if (w == NULL) {
220: environ_free(&env);
1.1 nicm 221: return (NULL);
1.3 nicm 222: }
223: environ_free(&env);
1.1 nicm 224:
225: if (options_get_number(&s->options, "set-remain-on-exit"))
226: options_set_number(&w->options, "remain-on-exit", 1);
227:
228: return (session_attach(s, w, idx, cause));
229: }
230:
231: /* Attach a window to a session. */
232: struct winlink *
233: session_attach(struct session *s, struct window *w, int idx, char **cause)
234: {
235: struct winlink *wl;
236:
237: if ((wl = winlink_add(&s->windows, w, idx)) == NULL)
238: xasprintf(cause, "index in use: %d", idx);
239: return (wl);
240: }
241:
242: /* Detach a window from a session. */
243: int
244: session_detach(struct session *s, struct winlink *wl)
245: {
246: if (s->curw == wl &&
247: session_last(s) != 0 && session_previous(s, 0) != 0)
248: session_next(s, 0);
249:
250: session_alert_cancel(s, wl);
251: winlink_stack_remove(&s->lastw, wl);
252: winlink_remove(&s->windows, wl);
253: if (RB_EMPTY(&s->windows)) {
254: session_destroy(s);
255: return (1);
256: }
257: return (0);
258: }
259:
260: /* Return if session has window. */
261: int
262: session_has(struct session *s, struct window *w)
263: {
264: struct winlink *wl;
265:
266: RB_FOREACH(wl, winlinks, &s->windows) {
267: if (wl->window == w)
268: return (1);
269: }
270: return (0);
271: }
272:
273: struct winlink *
274: session_next_activity(struct session *s, struct winlink *wl)
275: {
276: while (wl != NULL) {
277: if (session_alert_has(s, wl, WINDOW_BELL))
278: break;
279: if (session_alert_has(s, wl, WINDOW_ACTIVITY))
280: break;
281: if (session_alert_has(s, wl, WINDOW_CONTENT))
282: break;
283: wl = winlink_next(&s->windows, wl);
284: }
285: return (wl);
286: }
287:
288: /* Move session to next window. */
289: int
290: session_next(struct session *s, int activity)
291: {
292: struct winlink *wl;
293:
294: if (s->curw == NULL)
295: return (-1);
296:
297: wl = winlink_next(&s->windows, s->curw);
298: if (activity)
299: wl = session_next_activity(s, wl);
300: if (wl == NULL) {
301: wl = RB_MIN(winlinks, &s->windows);
302: if (activity && ((wl = session_next_activity(s, wl)) == NULL))
303: return (-1);
304: }
305: if (wl == s->curw)
306: return (1);
307: winlink_stack_remove(&s->lastw, wl);
308: winlink_stack_push(&s->lastw, s->curw);
309: s->curw = wl;
310: session_alert_cancel(s, wl);
311: return (0);
312: }
313:
314: struct winlink *
315: session_previous_activity(struct session *s, struct winlink *wl)
316: {
317: while (wl != NULL) {
318: if (session_alert_has(s, wl, WINDOW_BELL))
319: break;
320: if (session_alert_has(s, wl, WINDOW_ACTIVITY))
321: break;
322: if (session_alert_has(s, wl, WINDOW_CONTENT))
323: break;
324: wl = winlink_previous(&s->windows, wl);
325: }
326: return (wl);
327: }
328:
329: /* Move session to previous window. */
330: int
331: session_previous(struct session *s, int activity)
332: {
333: struct winlink *wl;
334:
335: if (s->curw == NULL)
336: return (-1);
337:
338: wl = winlink_previous(&s->windows, s->curw);
339: if (activity)
340: wl = session_previous_activity(s, wl);
341: if (wl == NULL) {
342: wl = RB_MAX(winlinks, &s->windows);
343: if (activity && (wl = session_previous_activity(s, wl)) == NULL)
344: return (-1);
345: }
346: if (wl == s->curw)
347: return (1);
348: winlink_stack_remove(&s->lastw, wl);
349: winlink_stack_push(&s->lastw, s->curw);
350: s->curw = wl;
351: session_alert_cancel(s, wl);
352: return (0);
353: }
354:
355: /* Move session to specific window. */
356: int
357: session_select(struct session *s, int idx)
358: {
359: struct winlink *wl;
360:
361: wl = winlink_find_by_index(&s->windows, idx);
362: if (wl == NULL)
363: return (-1);
364: if (wl == s->curw)
365: return (1);
366: winlink_stack_remove(&s->lastw, wl);
367: winlink_stack_push(&s->lastw, s->curw);
368: s->curw = wl;
369: session_alert_cancel(s, wl);
370: return (0);
371: }
372:
373: /* Move session to last used window. */
374: int
375: session_last(struct session *s)
376: {
377: struct winlink *wl;
378:
379: wl = SLIST_FIRST(&s->lastw);
380: if (wl == NULL)
381: return (-1);
382: if (wl == s->curw)
383: return (1);
384:
385: winlink_stack_remove(&s->lastw, wl);
386: winlink_stack_push(&s->lastw, s->curw);
387: s->curw = wl;
388: session_alert_cancel(s, wl);
389: return (0);
390: }