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>
28 struct session
*server_next_session(struct session
*);
29 void server_callback_identify(int, short, void *);
32 server_fill_environ(struct session
*s
, struct environ
*env
)
34 char var
[MAXPATHLEN
], *term
;
39 term
= options_get_string(&s
->options
, "default-terminal");
40 environ_set(env
, "TERM", term
);
46 xsnprintf(var
, sizeof var
, "%s,%ld,%d", socket_path
, pid
, idx
);
47 environ_set(env
, "TMUX", var
);
51 server_write_ready(struct client
*c
)
53 if (c
->flags
& CLIENT_CONTROL
)
55 server_write_client(c
, MSG_READY
, NULL
, 0);
59 server_write_client(struct client
*c
, enum msgtype type
, const void *buf
,
62 struct imsgbuf
*ibuf
= &c
->ibuf
;
65 if (c
->flags
& CLIENT_BAD
)
67 log_debug("writing %d to client %d", type
, c
->ibuf
.fd
);
68 error
= imsg_compose(ibuf
, type
, PROTOCOL_VERSION
, -1, -1,
71 server_update_event(c
);
72 return (error
== 1 ? 0 : -1);
76 server_write_session(struct session
*s
, enum msgtype type
, const void *buf
,
82 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
83 c
= ARRAY_ITEM(&clients
, i
);
84 if (c
== NULL
|| c
->session
== NULL
)
87 server_write_client(c
, type
, buf
, len
);
92 server_redraw_client(struct client
*c
)
94 c
->flags
|= CLIENT_REDRAW
;
98 server_status_client(struct client
*c
)
100 c
->flags
|= CLIENT_STATUS
;
104 server_redraw_session(struct session
*s
)
109 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
110 c
= ARRAY_ITEM(&clients
, i
);
111 if (c
== NULL
|| c
->session
== NULL
)
114 server_redraw_client(c
);
119 server_redraw_session_group(struct session
*s
)
121 struct session_group
*sg
;
123 if ((sg
= session_group_find(s
)) == NULL
)
124 server_redraw_session(s
);
126 TAILQ_FOREACH(s
, &sg
->sessions
, gentry
)
127 server_redraw_session(s
);
132 server_status_session(struct session
*s
)
137 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
138 c
= ARRAY_ITEM(&clients
, i
);
139 if (c
== NULL
|| c
->session
== NULL
)
142 server_status_client(c
);
147 server_status_session_group(struct session
*s
)
149 struct session_group
*sg
;
151 if ((sg
= session_group_find(s
)) == NULL
)
152 server_status_session(s
);
154 TAILQ_FOREACH(s
, &sg
->sessions
, gentry
)
155 server_status_session(s
);
160 server_redraw_window(struct window
*w
)
165 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
166 c
= ARRAY_ITEM(&clients
, i
);
167 if (c
== NULL
|| c
->session
== NULL
)
169 if (c
->session
->curw
->window
== w
)
170 server_redraw_client(c
);
172 w
->flags
|= WINDOW_REDRAW
;
176 server_redraw_window_borders(struct window
*w
)
181 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
182 c
= ARRAY_ITEM(&clients
, i
);
183 if (c
== NULL
|| c
->session
== NULL
)
185 if (c
->session
->curw
->window
== w
)
186 c
->flags
|= CLIENT_BORDERS
;
191 server_status_window(struct window
*w
)
196 * This is slightly different. We want to redraw the status line of any
197 * clients containing this window rather than anywhere it is the
201 RB_FOREACH(s
, sessions
, &sessions
) {
202 if (session_has(s
, w
) != NULL
)
203 server_status_session(s
);
213 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
214 c
= ARRAY_ITEM(&clients
, i
);
215 if (c
== NULL
|| c
->session
== NULL
)
217 server_lock_client(c
);
222 server_lock_session(struct session
*s
)
227 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
228 c
= ARRAY_ITEM(&clients
, i
);
229 if (c
== NULL
|| c
->session
== NULL
|| c
->session
!= s
)
231 server_lock_client(c
);
236 server_lock_client(struct client
*c
)
240 if (c
->flags
& CLIENT_CONTROL
)
243 if (c
->flags
& CLIENT_SUSPENDED
)
246 cmd
= options_get_string(&c
->session
->options
, "lock-command");
247 if (strlen(cmd
) + 1 > MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
250 tty_stop_tty(&c
->tty
);
251 tty_raw(&c
->tty
, tty_term_string(c
->tty
.term
, TTYC_SMCUP
));
252 tty_raw(&c
->tty
, tty_term_string(c
->tty
.term
, TTYC_CLEAR
));
253 tty_raw(&c
->tty
, tty_term_string(c
->tty
.term
, TTYC_E3
));
255 c
->flags
|= CLIENT_SUSPENDED
;
256 server_write_client(c
, MSG_LOCK
, cmd
, strlen(cmd
) + 1);
260 server_kill_window(struct window
*w
)
262 struct session
*s
, *next_s
, *target_s
;
263 struct session_group
*sg
;
266 next_s
= RB_MIN(sessions
, &sessions
);
267 while (next_s
!= NULL
) {
269 next_s
= RB_NEXT(sessions
, &sessions
, s
);
271 if (session_has(s
, w
) == NULL
)
273 while ((wl
= winlink_find_by_window(&s
->windows
, w
)) != NULL
) {
274 if (session_detach(s
, wl
)) {
275 server_destroy_session_group(s
);
278 server_redraw_session_group(s
);
281 if (options_get_number(&s
->options
, "renumber-windows")) {
282 if ((sg
= session_group_find(s
)) != NULL
) {
283 TAILQ_FOREACH(target_s
, &sg
->sessions
, gentry
)
284 session_renumber_windows(target_s
);
286 session_renumber_windows(s
);
293 server_link_window(struct session
*src
, struct winlink
*srcwl
,
294 struct session
*dst
, int dstidx
, int killflag
, int selectflag
, char **cause
)
296 struct winlink
*dstwl
;
297 struct session_group
*srcsg
, *dstsg
;
299 srcsg
= session_group_find(src
);
300 dstsg
= session_group_find(dst
);
301 if (src
!= dst
&& srcsg
!= NULL
&& dstsg
!= NULL
&& srcsg
== dstsg
) {
302 xasprintf(cause
, "sessions are grouped");
308 dstwl
= winlink_find_by_index(&dst
->windows
, dstidx
);
310 if (dstwl
->window
== srcwl
->window
) {
311 xasprintf(cause
, "same index: %d", dstidx
);
316 * Can't use session_detach as it will destroy session
317 * if this makes it empty.
319 notify_window_unlinked(dst
, dstwl
->window
);
320 dstwl
->flags
&= ~WINLINK_ALERTFLAGS
;
321 winlink_stack_remove(&dst
->lastw
, dstwl
);
322 winlink_remove(&dst
->windows
, dstwl
);
324 /* Force select/redraw if current. */
325 if (dstwl
== dst
->curw
) {
333 dstidx
= -1 - options_get_number(&dst
->options
, "base-index");
334 dstwl
= session_attach(dst
, srcwl
->window
, dstidx
, cause
);
339 session_select(dst
, dstwl
->idx
);
340 server_redraw_session_group(dst
);
346 server_unlink_window(struct session
*s
, struct winlink
*wl
)
348 if (session_detach(s
, wl
))
349 server_destroy_session_group(s
);
351 server_redraw_session_group(s
);
355 server_destroy_pane(struct window_pane
*wp
)
357 struct window
*w
= wp
->window
;
359 struct screen_write_ctx ctx
;
364 bufferevent_free(wp
->event
);
369 if (options_get_number(&w
->options
, "remain-on-exit")) {
372 screen_write_start(&ctx
, wp
, &wp
->base
);
373 screen_write_scrollregion(&ctx
, 0, screen_size_y(ctx
.s
) - 1);
374 screen_write_cursormove(&ctx
, 0, screen_size_y(ctx
.s
) - 1);
375 screen_write_linefeed(&ctx
, 1);
376 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
377 gc
.attr
|= GRID_ATTR_BRIGHT
;
378 screen_write_puts(&ctx
, &gc
, "Pane is dead");
379 screen_write_stop(&ctx
);
380 wp
->flags
|= PANE_REDRAW
;
384 server_unzoom_window(w
);
385 layout_close_pane(wp
);
386 window_remove_pane(w
, wp
);
388 if (TAILQ_EMPTY(&w
->panes
))
389 server_kill_window(w
);
391 server_redraw_window(w
);
395 server_destroy_session_group(struct session
*s
)
397 struct session_group
*sg
;
400 if ((sg
= session_group_find(s
)) == NULL
)
401 server_destroy_session(s
);
403 TAILQ_FOREACH_SAFE(s
, &sg
->sessions
, gentry
, s1
) {
404 server_destroy_session(s
);
411 server_next_session(struct session
*s
)
413 struct session
*s_loop
, *s_out
;
416 RB_FOREACH(s_loop
, sessions
, &sessions
) {
420 timercmp(&s_loop
->activity_time
, &s_out
->activity_time
, <))
427 server_destroy_session(struct session
*s
)
430 struct session
*s_new
;
433 if (!options_get_number(&s
->options
, "detach-on-destroy"))
434 s_new
= server_next_session(s
);
438 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
439 c
= ARRAY_ITEM(&clients
, i
);
440 if (c
== NULL
|| c
->session
!= s
)
444 c
->flags
|= CLIENT_EXIT
;
446 c
->last_session
= NULL
;
448 notify_attached_session_changed(c
);
449 session_update_activity(s_new
);
450 server_redraw_client(c
);
457 server_check_unattached (void)
462 * If any sessions are no longer attached and have destroy-unattached
465 RB_FOREACH(s
, sessions
, &sessions
) {
466 if (!(s
->flags
& SESSION_UNATTACHED
))
468 if (options_get_number (&s
->options
, "destroy-unattached"))
474 server_set_identify(struct client
*c
)
479 delay
= options_get_number(&c
->session
->options
, "display-panes-time");
480 tv
.tv_sec
= delay
/ 1000;
481 tv
.tv_usec
= (delay
% 1000) * 1000L;
483 if (event_initialized (&c
->identify_timer
))
484 evtimer_del(&c
->identify_timer
);
485 evtimer_set(&c
->identify_timer
, server_callback_identify
, c
);
486 evtimer_add(&c
->identify_timer
, &tv
);
488 c
->flags
|= CLIENT_IDENTIFY
;
489 c
->tty
.flags
|= (TTY_FREEZE
|TTY_NOCURSOR
);
490 server_redraw_client(c
);
494 server_clear_identify(struct client
*c
)
496 if (c
->flags
& CLIENT_IDENTIFY
) {
497 c
->flags
&= ~CLIENT_IDENTIFY
;
498 c
->tty
.flags
&= ~(TTY_FREEZE
|TTY_NOCURSOR
);
499 server_redraw_client(c
);
504 server_callback_identify(unused
int fd
, unused
short events
, void *data
)
506 struct client
*c
= data
;
508 server_clear_identify(c
);
512 server_update_event(struct client
*c
)
517 if (!(c
->flags
& CLIENT_BAD
))
519 if (c
->ibuf
.w
.queued
> 0)
521 if (event_initialized(&c
->event
))
522 event_del(&c
->event
);
523 event_set(&c
->event
, c
->ibuf
.fd
, events
, server_client_callback
, c
);
524 event_add(&c
->event
, NULL
);
527 /* Push stdout to client if possible. */
529 server_push_stdout(struct client
*c
)
531 struct msg_stdout_data data
;
534 size
= EVBUFFER_LENGTH(c
->stdout_data
);
537 if (size
> sizeof data
.data
)
538 size
= sizeof data
.data
;
540 memcpy(data
.data
, EVBUFFER_DATA(c
->stdout_data
), size
);
543 if (server_write_client(c
, MSG_STDOUT
, &data
, sizeof data
) == 0)
544 evbuffer_drain(c
->stdout_data
, size
);
547 /* Push stderr to client if possible. */
549 server_push_stderr(struct client
*c
)
551 struct msg_stderr_data data
;
554 if (c
->stderr_data
== c
->stdout_data
) {
555 server_push_stdout(c
);
558 size
= EVBUFFER_LENGTH(c
->stderr_data
);
561 if (size
> sizeof data
.data
)
562 size
= sizeof data
.data
;
564 memcpy(data
.data
, EVBUFFER_DATA(c
->stderr_data
), size
);
567 if (server_write_client(c
, MSG_STDERR
, &data
, sizeof data
) == 0)
568 evbuffer_drain(c
->stderr_data
, size
);
571 /* Set stdin callback. */
573 server_set_stdin_callback(struct client
*c
, void (*cb
)(struct client
*, int,
574 void *), void *cb_data
, char **cause
)
576 if (c
== NULL
|| c
->session
!= NULL
) {
577 *cause
= xstrdup("no client with stdin");
580 if (c
->flags
& CLIENT_TERMINAL
) {
581 *cause
= xstrdup("stdin is a tty");
584 if (c
->stdin_callback
!= NULL
) {
585 *cause
= xstrdup("stdin in use");
589 c
->stdin_callback_data
= cb_data
;
590 c
->stdin_callback
= cb
;
595 c
->stdin_callback (c
, 1, c
->stdin_callback_data
);
597 server_write_client(c
, MSG_STDIN
, NULL
, 0);
603 server_unzoom_window(struct window
*w
)
606 server_redraw_window(w
);
607 server_status_window(w
);