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>
27 struct session
*server_next_session(struct session
*);
28 void server_callback_identify(int, short, void *);
31 server_fill_environ(struct session
*s
, struct environ
*env
)
33 char var
[MAXPATHLEN
], *term
;
38 term
= options_get_string(&s
->options
, "default-terminal");
39 environ_set(env
, "TERM", term
);
45 xsnprintf(var
, sizeof var
, "%s,%ld,%d", socket_path
, pid
, idx
);
46 environ_set(env
, "TMUX", var
);
51 struct client
*c
, enum msgtype type
, const void *buf
, size_t len
)
53 struct imsgbuf
*ibuf
= &c
->ibuf
;
55 if (c
->flags
& CLIENT_BAD
)
57 log_debug("writing %d to client %d", type
, c
->ibuf
.fd
);
58 imsg_compose(ibuf
, type
, PROTOCOL_VERSION
, -1, -1, (void *) buf
, len
);
59 server_update_event(c
);
64 struct session
*s
, enum msgtype type
, const void *buf
, size_t len
)
69 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
70 c
= ARRAY_ITEM(&clients
, i
);
71 if (c
== NULL
|| c
->session
== NULL
)
74 server_write_client(c
, type
, buf
, len
);
79 server_redraw_client(struct client
*c
)
81 c
->flags
|= CLIENT_REDRAW
;
85 server_status_client(struct client
*c
)
87 c
->flags
|= CLIENT_STATUS
;
91 server_redraw_session(struct session
*s
)
96 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
97 c
= ARRAY_ITEM(&clients
, i
);
98 if (c
== NULL
|| c
->session
== NULL
)
101 server_redraw_client(c
);
106 server_redraw_session_group(struct session
*s
)
108 struct session_group
*sg
;
110 if ((sg
= session_group_find(s
)) == NULL
)
111 server_redraw_session(s
);
113 TAILQ_FOREACH(s
, &sg
->sessions
, gentry
)
114 server_redraw_session(s
);
119 server_status_session(struct session
*s
)
124 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
125 c
= ARRAY_ITEM(&clients
, i
);
126 if (c
== NULL
|| c
->session
== NULL
)
129 server_status_client(c
);
134 server_status_session_group(struct session
*s
)
136 struct session_group
*sg
;
138 if ((sg
= session_group_find(s
)) == NULL
)
139 server_status_session(s
);
141 TAILQ_FOREACH(s
, &sg
->sessions
, gentry
)
142 server_status_session(s
);
147 server_redraw_window(struct window
*w
)
152 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
153 c
= ARRAY_ITEM(&clients
, i
);
154 if (c
== NULL
|| c
->session
== NULL
)
156 if (c
->session
->curw
->window
== w
)
157 server_redraw_client(c
);
159 w
->flags
|= WINDOW_REDRAW
;
163 server_redraw_window_borders(struct window
*w
)
168 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
169 c
= ARRAY_ITEM(&clients
, i
);
170 if (c
== NULL
|| c
->session
== NULL
)
172 if (c
->session
->curw
->window
== w
)
173 c
->flags
|= CLIENT_BORDERS
;
178 server_status_window(struct window
*w
)
183 * This is slightly different. We want to redraw the status line of any
184 * clients containing this window rather than any where it is the
188 RB_FOREACH(s
, sessions
, &sessions
) {
189 if (session_has(s
, w
) != NULL
)
190 server_status_session(s
);
200 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
201 c
= ARRAY_ITEM(&clients
, i
);
202 if (c
== NULL
|| c
->session
== NULL
)
204 server_lock_client(c
);
209 server_lock_session(struct session
*s
)
214 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
215 c
= ARRAY_ITEM(&clients
, i
);
216 if (c
== NULL
|| c
->session
== NULL
|| c
->session
!= s
)
218 server_lock_client(c
);
223 server_lock_client(struct client
*c
)
227 struct msg_lock_data lockdata
;
229 if (c
->flags
& CLIENT_SUSPENDED
)
232 cmd
= options_get_string(&c
->session
->options
, "lock-command");
233 cmdlen
= strlcpy(lockdata
.cmd
, cmd
, sizeof lockdata
.cmd
);
234 if (cmdlen
>= sizeof lockdata
.cmd
)
237 tty_stop_tty(&c
->tty
);
238 tty_raw(&c
->tty
, tty_term_string(c
->tty
.term
, TTYC_SMCUP
));
239 tty_raw(&c
->tty
, tty_term_string(c
->tty
.term
, TTYC_CLEAR
));
241 c
->flags
|= CLIENT_SUSPENDED
;
242 server_write_client(c
, MSG_LOCK
, &lockdata
, sizeof lockdata
);
246 server_kill_window(struct window
*w
)
248 struct session
*s
, *next_s
;
251 next_s
= RB_MIN(sessions
, &sessions
);
252 while (next_s
!= NULL
) {
254 next_s
= RB_NEXT(sessions
, &sessions
, s
);
256 if (session_has(s
, w
) == NULL
)
258 while ((wl
= winlink_find_by_window(&s
->windows
, w
)) != NULL
) {
259 if (session_detach(s
, wl
)) {
260 server_destroy_session_group(s
);
263 server_redraw_session_group(s
);
269 server_link_window(struct session
*src
, struct winlink
*srcwl
,
270 struct session
*dst
, int dstidx
, int killflag
, int selectflag
, char **cause
)
272 struct winlink
*dstwl
;
273 struct session_group
*srcsg
, *dstsg
;
275 srcsg
= session_group_find(src
);
276 dstsg
= session_group_find(dst
);
277 if (src
!= dst
&& srcsg
!= NULL
&& dstsg
!= NULL
&& srcsg
== dstsg
) {
278 xasprintf(cause
, "sessions are grouped");
284 dstwl
= winlink_find_by_index(&dst
->windows
, dstidx
);
286 if (dstwl
->window
== srcwl
->window
) {
287 xasprintf(cause
, "same index: %d", dstidx
);
292 * Can't use session_detach as it will destroy session
293 * if this makes it empty.
295 dstwl
->flags
&= ~WINLINK_ALERTFLAGS
;
296 winlink_stack_remove(&dst
->lastw
, dstwl
);
297 winlink_remove(&dst
->windows
, dstwl
);
299 /* Force select/redraw if current. */
300 if (dstwl
== dst
->curw
) {
308 dstidx
= -1 - options_get_number(&dst
->options
, "base-index");
309 dstwl
= session_attach(dst
, srcwl
->window
, dstidx
, cause
);
314 session_select(dst
, dstwl
->idx
);
315 server_redraw_session_group(dst
);
321 server_unlink_window(struct session
*s
, struct winlink
*wl
)
323 if (session_detach(s
, wl
))
324 server_destroy_session_group(s
);
326 server_redraw_session_group(s
);
330 server_destroy_pane(struct window_pane
*wp
)
332 struct window
*w
= wp
->window
;
336 bufferevent_free(wp
->event
);
340 if (options_get_number(&w
->options
, "remain-on-exit"))
343 layout_close_pane(wp
);
344 window_remove_pane(w
, wp
);
346 if (TAILQ_EMPTY(&w
->panes
))
347 server_kill_window(w
);
349 server_redraw_window(w
);
353 server_destroy_session_group(struct session
*s
)
355 struct session_group
*sg
;
357 if ((sg
= session_group_find(s
)) == NULL
)
358 server_destroy_session(s
);
360 TAILQ_FOREACH(s
, &sg
->sessions
, gentry
)
361 server_destroy_session(s
);
362 TAILQ_REMOVE(&session_groups
, sg
, entry
);
368 server_next_session(struct session
*s
)
370 struct session
*s_loop
, *s_out
;
373 RB_FOREACH(s_loop
, sessions
, &sessions
) {
377 timercmp(&s_loop
->activity_time
, &s_out
->activity_time
, <))
384 server_destroy_session(struct session
*s
)
387 struct session
*s_new
;
390 if (!options_get_number(&s
->options
, "detach-on-destroy"))
391 s_new
= server_next_session(s
);
395 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
396 c
= ARRAY_ITEM(&clients
, i
);
397 if (c
== NULL
|| c
->session
!= s
)
401 c
->flags
|= CLIENT_EXIT
;
403 c
->last_session
= NULL
;
405 session_update_activity(s_new
);
406 server_redraw_client(c
);
413 server_check_unattached (void)
418 * If any sessions are no longer attached and have destroy-unattached
421 RB_FOREACH(s
, sessions
, &sessions
) {
422 if (!(s
->flags
& SESSION_UNATTACHED
))
424 if (options_get_number (&s
->options
, "destroy-unattached"))
430 server_set_identify(struct client
*c
)
435 delay
= options_get_number(&c
->session
->options
, "display-panes-time");
436 tv
.tv_sec
= delay
/ 1000;
437 tv
.tv_usec
= (delay
% 1000) * 1000L;
439 evtimer_del(&c
->identify_timer
);
440 evtimer_set(&c
->identify_timer
, server_callback_identify
, c
);
441 evtimer_add(&c
->identify_timer
, &tv
);
443 c
->flags
|= CLIENT_IDENTIFY
;
444 c
->tty
.flags
|= (TTY_FREEZE
|TTY_NOCURSOR
);
445 server_redraw_client(c
);
449 server_clear_identify(struct client
*c
)
451 if (c
->flags
& CLIENT_IDENTIFY
) {
452 c
->flags
&= ~CLIENT_IDENTIFY
;
453 c
->tty
.flags
&= ~(TTY_FREEZE
|TTY_NOCURSOR
);
454 server_redraw_client(c
);
460 server_callback_identify(unused
int fd
, unused
short events
, void *data
)
462 struct client
*c
= data
;
464 server_clear_identify(c
);
468 server_update_event(struct client
*c
)
473 if (!(c
->flags
& CLIENT_BAD
))
475 if (c
->ibuf
.w
.queued
> 0)
477 event_del(&c
->event
);
478 event_set(&c
->event
, c
->ibuf
.fd
, events
, server_client_callback
, c
);
479 event_add(&c
->event
, NULL
);