Do not call event_del() for signals after fork(), just use sigaction()
[tmux-openbsd.git] / server-fn.c
blob03c89cf589aac259432958bcb0587208c4fb7f5e
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <string.h>
22 #include <time.h>
23 #include <unistd.h>
25 #include "tmux.h"
27 struct session *server_next_session(struct session *);
28 void server_callback_identify(int, short, void *);
30 void
31 server_fill_environ(struct session *s, struct environ *env)
33 char tmuxvar[MAXPATHLEN], *term;
34 u_int idx;
36 if (session_index(s, &idx) != 0)
37 fatalx("session not found");
38 xsnprintf(tmuxvar, sizeof tmuxvar,
39 "%s,%ld,%u", socket_path, (long) getpid(), idx);
40 environ_set(env, "TMUX", tmuxvar);
42 term = options_get_string(&s->options, "default-terminal");
43 environ_set(env, "TERM", term);
46 void
47 server_write_client(
48 struct client *c, enum msgtype type, const void *buf, size_t len)
50 struct imsgbuf *ibuf = &c->ibuf;
52 if (c->flags & CLIENT_BAD)
53 return;
54 log_debug("writing %d to client %d", type, c->ibuf.fd);
55 imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len);
56 server_update_event(c);
59 void
60 server_write_session(
61 struct session *s, enum msgtype type, const void *buf, size_t len)
63 struct client *c;
64 u_int i;
66 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
67 c = ARRAY_ITEM(&clients, i);
68 if (c == NULL || c->session == NULL)
69 continue;
70 if (c->session == s)
71 server_write_client(c, type, buf, len);
75 void
76 server_redraw_client(struct client *c)
78 c->flags |= CLIENT_REDRAW;
81 void
82 server_status_client(struct client *c)
84 c->flags |= CLIENT_STATUS;
87 void
88 server_redraw_session(struct session *s)
90 struct client *c;
91 u_int i;
93 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
94 c = ARRAY_ITEM(&clients, i);
95 if (c == NULL || c->session == NULL)
96 continue;
97 if (c->session == s)
98 server_redraw_client(c);
102 void
103 server_redraw_session_group(struct session *s)
105 struct session_group *sg;
107 if ((sg = session_group_find(s)) == NULL)
108 server_redraw_session(s);
109 else {
110 TAILQ_FOREACH(s, &sg->sessions, gentry)
111 server_redraw_session(s);
115 void
116 server_status_session(struct session *s)
118 struct client *c;
119 u_int i;
121 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
122 c = ARRAY_ITEM(&clients, i);
123 if (c == NULL || c->session == NULL)
124 continue;
125 if (c->session == s)
126 server_status_client(c);
130 void
131 server_status_session_group(struct session *s)
133 struct session_group *sg;
135 if ((sg = session_group_find(s)) == NULL)
136 server_status_session(s);
137 else {
138 TAILQ_FOREACH(s, &sg->sessions, gentry)
139 server_status_session(s);
143 void
144 server_redraw_window(struct window *w)
146 struct client *c;
147 u_int i;
149 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
150 c = ARRAY_ITEM(&clients, i);
151 if (c == NULL || c->session == NULL)
152 continue;
153 if (c->session->curw->window == w)
154 server_redraw_client(c);
156 w->flags |= WINDOW_REDRAW;
159 void
160 server_redraw_window_borders(struct window *w)
162 struct client *c;
163 u_int i;
165 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
166 c = ARRAY_ITEM(&clients, i);
167 if (c == NULL || c->session == NULL)
168 continue;
169 if (c->session->curw->window == w)
170 c->flags |= CLIENT_BORDERS;
174 void
175 server_status_window(struct window *w)
177 struct session *s;
178 u_int i;
181 * This is slightly different. We want to redraw the status line of any
182 * clients containing this window rather than any where it is the
183 * current window.
186 for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
187 s = ARRAY_ITEM(&sessions, i);
188 if (s != NULL && session_has(s, w) != NULL)
189 server_status_session(s);
193 void
194 server_lock(void)
196 struct client *c;
197 u_int i;
199 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
200 c = ARRAY_ITEM(&clients, i);
201 if (c == NULL || c->session == NULL)
202 continue;
203 server_lock_client(c);
207 void
208 server_lock_session(struct session *s)
210 struct client *c;
211 u_int i;
213 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
214 c = ARRAY_ITEM(&clients, i);
215 if (c == NULL || c->session == NULL || c->session != s)
216 continue;
217 server_lock_client(c);
221 void
222 server_lock_client(struct client *c)
224 const char *cmd;
225 size_t cmdlen;
226 struct msg_lock_data lockdata;
228 if (c->flags & CLIENT_SUSPENDED)
229 return;
231 cmd = options_get_string(&c->session->options, "lock-command");
232 cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd);
233 if (cmdlen >= sizeof lockdata.cmd)
234 return;
236 tty_stop_tty(&c->tty);
237 tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP));
238 tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR));
240 c->flags |= CLIENT_SUSPENDED;
241 server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata);
244 void
245 server_kill_window(struct window *w)
247 struct session *s;
248 struct winlink *wl;
249 u_int i;
251 for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
252 s = ARRAY_ITEM(&sessions, i);
253 if (s == NULL || session_has(s, w) == NULL)
254 continue;
255 while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) {
256 if (session_detach(s, wl)) {
257 server_destroy_session_group(s);
258 break;
259 } else
260 server_redraw_session_group(s);
266 server_link_window(struct session *src, struct winlink *srcwl,
267 struct session *dst, int dstidx, int killflag, int selectflag, char **cause)
269 struct winlink *dstwl;
270 struct session_group *srcsg, *dstsg;
272 srcsg = session_group_find(src);
273 dstsg = session_group_find(dst);
274 if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) {
275 xasprintf(cause, "sessions are grouped");
276 return (-1);
279 dstwl = NULL;
280 if (dstidx != -1)
281 dstwl = winlink_find_by_index(&dst->windows, dstidx);
282 if (dstwl != NULL) {
283 if (dstwl->window == srcwl->window)
284 return (-1);
285 if (killflag) {
287 * Can't use session_detach as it will destroy session
288 * if this makes it empty.
290 dstwl->flags &= ~WINLINK_ALERTFLAGS;
291 winlink_stack_remove(&dst->lastw, dstwl);
292 winlink_remove(&dst->windows, dstwl);
294 /* Force select/redraw if current. */
295 if (dstwl == dst->curw) {
296 selectflag = 1;
297 dst->curw = NULL;
302 if (dstidx == -1)
303 dstidx = -1 - options_get_number(&dst->options, "base-index");
304 dstwl = session_attach(dst, srcwl->window, dstidx, cause);
305 if (dstwl == NULL)
306 return (-1);
308 if (selectflag)
309 session_select(dst, dstwl->idx);
310 server_redraw_session_group(dst);
312 return (0);
315 void
316 server_unlink_window(struct session *s, struct winlink *wl)
318 if (session_detach(s, wl))
319 server_destroy_session_group(s);
320 else
321 server_redraw_session_group(s);
324 void
325 server_destroy_pane(struct window_pane *wp)
327 struct window *w = wp->window;
329 if (wp->fd != -1) {
330 close(wp->fd);
331 bufferevent_free(wp->event);
332 wp->fd = -1;
335 if (options_get_number(&w->options, "remain-on-exit"))
336 return;
338 layout_close_pane(wp);
339 window_remove_pane(w, wp);
341 if (TAILQ_EMPTY(&w->panes))
342 server_kill_window(w);
343 else
344 server_redraw_window(w);
347 void
348 server_destroy_session_group(struct session *s)
350 struct session_group *sg;
352 if ((sg = session_group_find(s)) == NULL)
353 server_destroy_session(s);
354 else {
355 TAILQ_FOREACH(s, &sg->sessions, gentry)
356 server_destroy_session(s);
357 TAILQ_REMOVE(&session_groups, sg, entry);
358 xfree(sg);
362 struct session *
363 server_next_session(struct session *s)
365 struct session *s_loop, *s_out;
366 u_int i;
368 s_out = NULL;
369 for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
370 s_loop = ARRAY_ITEM(&sessions, i);
371 if (s_loop == s)
372 continue;
373 if (s_out == NULL ||
374 timercmp(&s_loop->activity_time, &s_out->activity_time, <))
375 s_out = s_loop;
377 return (s_out);
380 void
381 server_destroy_session(struct session *s)
383 struct client *c;
384 struct session *s_new;
385 u_int i;
387 if (!options_get_number(&s->options, "detach-on-destroy"))
388 s_new = server_next_session(s);
389 else
390 s_new = NULL;
392 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
393 c = ARRAY_ITEM(&clients, i);
394 if (c == NULL || c->session != s)
395 continue;
396 if (s_new == NULL) {
397 c->session = NULL;
398 c->flags |= CLIENT_EXIT;
399 } else {
400 c->session = s_new;
401 server_redraw_client(c);
404 recalculate_sizes();
407 void
408 server_set_identify(struct client *c)
410 struct timeval tv;
411 int delay;
413 delay = options_get_number(&c->session->options, "display-panes-time");
414 tv.tv_sec = delay / 1000;
415 tv.tv_usec = (delay % 1000) * 1000L;
417 evtimer_del(&c->identify_timer);
418 evtimer_set(&c->identify_timer, server_callback_identify, c);
419 evtimer_add(&c->identify_timer, &tv);
421 c->flags |= CLIENT_IDENTIFY;
422 c->tty.flags |= (TTY_FREEZE|TTY_NOCURSOR);
423 server_redraw_client(c);
426 void
427 server_clear_identify(struct client *c)
429 if (c->flags & CLIENT_IDENTIFY) {
430 c->flags &= ~CLIENT_IDENTIFY;
431 c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
432 server_redraw_client(c);
436 /* ARGSUSED */
437 void
438 server_callback_identify(unused int fd, unused short events, void *data)
440 struct client *c = data;
442 server_clear_identify(c);
445 void
446 server_update_event(struct client *c)
448 short events;
450 events = 0;
451 if (!(c->flags & CLIENT_BAD))
452 events |= EV_READ;
453 if (c->ibuf.w.queued > 0)
454 events |= EV_WRITE;
455 event_del(&c->event);
456 event_set(&c->event, c->ibuf.fd, events, server_client_callback, c);
457 event_add(&c->event, NULL);