summaryrefslogtreecommitdiffstats
path: root/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'server.c')
-rw-r--r--server.c994
1 files changed, 119 insertions, 875 deletions
diff --git a/server.c b/server.c
index 6fdcf940..e1ec4eb8 100644
--- a/server.c
+++ b/server.c
@@ -47,80 +47,70 @@ struct clients dead_clients;
/* Mapping of a pollfd to an fd independent of its position in the array. */
struct poll_item {
- struct pollfd pfd;
+ int fd;
+ int events;
+
+ void (*fn)(int, int, void *);
+ void *data;
RB_ENTRY(poll_item) entry;
};
RB_HEAD(poll_items, poll_item) poll_items;
int server_poll_cmp(struct poll_item *, struct poll_item *);
-struct pollfd *server_poll_lookup(int);
-void server_poll_add(int, int);
+struct poll_item*server_poll_lookup(int);
+void server_poll_add(int, int, void (*)(int, int, void *), void *);
struct pollfd *server_poll_flatten(int *);
-void server_poll_parse(struct pollfd *);
+void server_poll_dispatch(struct pollfd *, int);
void server_poll_reset(void);
RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp);
RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp);
-void server_create_client(int);
int server_create_socket(void);
+void server_callback(int, int, void *);
int server_main(int);
void server_shutdown(void);
int server_should_shutdown(void);
void server_child_signal(void);
void server_fill_windows(void);
-void server_handle_windows(void);
void server_fill_clients(void);
-void server_handle_clients(void);
void server_fill_jobs(void);
-void server_handle_jobs(void);
-void server_accept_client(int);
-void server_handle_client(struct client *);
-void server_handle_window(struct window *, struct window_pane *);
-int server_check_window_bell(struct session *, struct window *);
-int server_check_window_activity(struct session *,
- struct window *);
-int server_check_window_content(struct session *, struct window *,
- struct window_pane *);
void server_clean_dead(void);
-void server_lost_client(struct client *);
-void server_check_window(struct window *);
-void server_check_redraw(struct client *);
-void server_set_title(struct client *);
-void server_check_timers(struct client *);
-void server_check_jobs(void);
+void server_second_timers(void);
void server_lock_server(void);
void server_lock_sessions(void);
-void server_check_clients(void);
-void server_second_timers(void);
int server_update_socket(void);
int
server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2)
{
- return (pitem1->pfd.fd - pitem2->pfd.fd);
-}
-
-struct pollfd *
-server_poll_lookup(int fd)
-{
- struct poll_item pitem;
-
- pitem.pfd.fd = fd;
- return (&RB_FIND(poll_items, &poll_items, &pitem)->pfd);
+ return (pitem1->fd - pitem2->fd);
}
void
-server_poll_add(int fd, int events)
+server_poll_add(int fd, int events, void (*fn)(int, int, void *), void *data)
{
struct poll_item *pitem;
pitem = xmalloc(sizeof *pitem);
- pitem->pfd.fd = fd;
- pitem->pfd.events = events;
+ pitem->fd = fd;
+ pitem->events = events;
+
+ pitem->fn = fn;
+ pitem->data = data;
+
RB_INSERT(poll_items, &poll_items, pitem);
}
+struct poll_item *
+server_poll_lookup(int fd)
+{
+ struct poll_item pitem;
+
+ pitem.fd = fd;
+ return (RB_FIND(poll_items, &poll_items, &pitem));
+}
+
struct pollfd *
server_poll_flatten(int *nfds)
{
@@ -131,23 +121,25 @@ server_poll_flatten(int *nfds)
*nfds = 0;
RB_FOREACH(pitem, poll_items, &poll_items) {
pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds);
- pfds[*nfds].fd = pitem->pfd.fd;
- pfds[*nfds].events = pitem->pfd.events;
+ pfds[*nfds].fd = pitem->fd;
+ pfds[*nfds].events = pitem->events;
(*nfds)++;
}
return (pfds);
}
void
-server_poll_parse(struct pollfd *pfds)
+server_poll_dispatch(struct pollfd *pfds, int nfds)
{
struct poll_item *pitem;
- int nfds;
+ struct pollfd *pfd;
- nfds = 0;
- RB_FOREACH(pitem, poll_items, &poll_items) {
- pitem->pfd.revents = pfds[nfds].revents;
- nfds++;
+ while (nfds > 0) {
+ pfd = &pfds[--nfds];
+ if (pfd->revents != 0) {
+ pitem = server_poll_lookup(pfd->fd);
+ pitem->fn(pitem->fd, pfd->revents, pitem->data);
+ }
}
xfree(pfds);
}
@@ -164,13 +156,34 @@ server_poll_reset(void)
}
}
-/* Create a new client. */
-void
-server_create_client(int fd)
+/* Create server socket. */
+int
+server_create_socket(void)
{
- struct client *c;
- int mode;
- u_int i;
+ struct sockaddr_un sa;
+ size_t size;
+ mode_t mask;
+ int fd, mode;
+
+ memset(&sa, 0, sizeof sa);
+ sa.sun_family = AF_UNIX;
+ size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
+ if (size >= sizeof sa.sun_path) {
+ errno = ENAMETOOLONG;
+ fatal("socket failed");
+ }
+ unlink(sa.sun_path);
+
+ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ fatal("socket failed");
+
+ mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
+ if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
+ fatal("bind failed");
+ umask(mask);
+
+ if (listen(fd, 16) == -1)
+ fatal("listen failed");
if ((mode = fcntl(fd, F_GETFL)) == -1)
fatal("fcntl failed");
@@ -179,39 +192,33 @@ server_create_client(int fd)
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
- c = xcalloc(1, sizeof *c);
- c->references = 0;
- imsg_init(&c->ibuf, fd);
-
- if (gettimeofday(&c->tv, NULL) != 0)
- fatal("gettimeofday failed");
-
- ARRAY_INIT(&c->prompt_hdata);
-
- c->tty.fd = -1;
- c->title = NULL;
-
- c->session = NULL;
- c->tty.sx = 80;
- c->tty.sy = 24;
-
- screen_init(&c->status, c->tty.sx, 1, 0);
- job_tree_init(&c->status_jobs);
+ return (fd);
+}
- c->message_string = NULL;
+/* Callback for server socket. */
+void
+server_callback(int fd, int events, unused void *data)
+{
+ struct sockaddr_storage sa;
+ socklen_t slen = sizeof sa;
+ int newfd;
- c->prompt_string = NULL;
- c->prompt_buffer = NULL;
- c->prompt_index = 0;
+ if (events & (POLLERR|POLLNVAL|POLLHUP))
+ fatalx("lost server socket");
+ if (!(events & POLLIN))
+ return;
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- if (ARRAY_ITEM(&clients, i) == NULL) {
- ARRAY_SET(&clients, i, c);
+ newfd = accept(fd, (struct sockaddr *) &sa, &slen);
+ if (newfd == -1) {
+ if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
return;
- }
+ fatal("accept failed");
}
- ARRAY_ADD(&clients, c);
- log_debug("new client %d", fd);
+ if (sigterm) {
+ close(newfd);
+ return;
+ }
+ server_client_create(newfd);
}
/* Fork new server. */
@@ -267,7 +274,7 @@ server_start(char *path)
setproctitle("server (%s)", rpathbuf);
srv_fd = server_create_socket();
- server_create_client(pair[1]);
+ server_client_create(pair[1]);
if (access(SYSTEM_CFG, R_OK) != 0) {
if (errno != ENOENT) {
@@ -295,50 +302,11 @@ error:
exit(server_main(srv_fd));
}
-/* Create server socket. */
-int
-server_create_socket(void)
-{
- struct sockaddr_un sa;
- size_t size;
- mode_t mask;
- int fd, mode;
-
- memset(&sa, 0, sizeof sa);
- sa.sun_family = AF_UNIX;
- size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
- if (size >= sizeof sa.sun_path) {
- errno = ENAMETOOLONG;
- fatal("socket failed");
- }
- unlink(sa.sun_path);
-
- if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
- fatal("socket failed");
-
- mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
- if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
- fatal("bind failed");
- umask(mask);
-
- if (listen(fd, 16) == -1)
- fatal("listen failed");
-
- if ((mode = fcntl(fd, F_GETFL)) == -1)
- fatal("fcntl failed");
- if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
- fatal("fcntl failed");
- if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
- fatal("fcntl failed");
-
- return (fd);
-}
-
/* Main server loop. */
int
server_main(int srv_fd)
{
- struct pollfd *pfds, *pfd;
+ struct pollfd *pfds;
int nfds, xtimeout;
u_int i;
time_t now, last;
@@ -371,13 +339,9 @@ server_main(int srv_fd)
sigusr1 = 0;
}
- /* Collect any jobs that have died and process clients. */
- server_check_jobs();
- server_check_clients();
-
/* Initialise pollfd array and add server socket. */
server_poll_reset();
- server_poll_add(srv_fd, POLLIN);
+ server_poll_add(srv_fd, POLLIN, server_callback, NULL);
/* Fill window and client sockets. */
server_fill_jobs();
@@ -396,16 +360,7 @@ server_main(int srv_fd)
continue;
fatal("poll failed");
}
- server_poll_parse(pfds);
-
- /* Handle server socket. */
- pfd = server_poll_lookup(srv_fd);
- if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP))
- fatalx("lost server socket");
- if (pfd->revents & POLLIN) {
- server_accept_client(srv_fd);
- continue;
- }
+ server_poll_dispatch(pfds, nfds);
/* Call second-based timers. */
now = time(NULL);
@@ -414,13 +369,10 @@ server_main(int srv_fd)
server_second_timers();
}
- /* Set window names. */
- set_window_names();
-
- /* Handle window and client sockets. */
- server_handle_jobs();
- server_handle_windows();
- server_handle_clients();
+ /* Run once-per-loop events. */
+ server_job_loop();
+ server_window_loop();
+ server_client_loop();
/* Collect any unset key bindings. */
key_bindings_clean();
@@ -438,7 +390,7 @@ server_main(int srv_fd)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (ARRAY_ITEM(&clients, i) != NULL)
- server_lost_client(ARRAY_ITEM(&clients, i));
+ server_client_lost(ARRAY_ITEM(&clients, i));
}
ARRAY_FREE(&clients);
@@ -468,7 +420,7 @@ server_shutdown(void)
c = ARRAY_ITEM(&clients, i);
if (c != NULL) {
if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED))
- server_lost_client(c);
+ server_client_lost(c);
else
server_write_client(c, MSG_SHUTDOWN, NULL, 0);
}
@@ -571,193 +523,18 @@ server_fill_windows(void)
events = POLLIN;
if (BUFFER_USED(wp->out) > 0)
events |= POLLOUT;
- server_poll_add(wp->fd, events);
+ server_poll_add(
+ wp->fd, events, server_window_callback, wp);
if (wp->pipe_fd == -1)
continue;
events = 0;
if (BUFFER_USED(wp->pipe_buf) > 0)
events |= POLLOUT;
- server_poll_add(wp->pipe_fd, events);
- }
- }
-}
-
-/* Handle window pollfds. */
-void
-server_handle_windows(void)
-{
- struct window *w;
- struct window_pane *wp;
- struct pollfd *pfd;
- u_int i;
-
- for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
- w = ARRAY_ITEM(&windows, i);
- if (w == NULL)
- continue;
-
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if (wp->fd == -1)
- continue;
- if ((pfd = server_poll_lookup(wp->fd)) == NULL)
- continue;
- if (buffer_poll(pfd, wp->in, wp->out) != 0) {
- close(wp->fd);
- wp->fd = -1;
- } else
- server_handle_window(w, wp);
-
- if (wp->pipe_fd == -1)
- continue;
- if ((pfd = server_poll_lookup(wp->pipe_fd)) == NULL)
- continue;
- if (buffer_poll(pfd, NULL, wp->pipe_buf) != 0) {
- buffer_destroy(wp->pipe_buf);
- close(wp->pipe_fd);
- wp->pipe_fd = -1;
- }
- }
-
- server_check_window(w);
- }
-}
-
-/* Check clients for redraw and timers. */
-void
-server_check_clients(void)
-{
- struct client *c;
- struct window *w;
- struct window_pane *wp;
- u_int i;
-
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session == NULL)
- continue;
-
- server_check_timers(c);
- server_check_redraw(c);
- }
-
- /*
- * Clear any window redraw flags (will have been redrawn as part of
- * client).
- */
- for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
- w = ARRAY_ITEM(&windows, i);
- if (w == NULL)
- continue;
-
- w->flags &= ~WINDOW_REDRAW;
- TAILQ_FOREACH(wp, &w->panes, entry)
- wp->flags &= ~PANE_REDRAW;
- }
-}
-
-/* Check for general redraw on client. */
-void
-server_check_redraw(struct client *c)
-{
- struct session *s = c->session;
- struct window_pane *wp;
- int flags, redraw;
-
- flags = c->tty.flags & TTY_FREEZE;
- c->tty.flags &= ~TTY_FREEZE;
-
- if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
- if (options_get_number(&s->options, "set-titles"))
- server_set_title(c);
-
- if (c->message_string != NULL)
- redraw = status_message_redraw(c);
- else if (c->prompt_string != NULL)
- redraw = status_prompt_redraw(c);
- else
- redraw = status_redraw(c);
- if (!redraw)
- c->flags &= ~CLIENT_STATUS;
- }
-
- if (c->flags & CLIENT_REDRAW) {
- screen_redraw_screen(c, 0);
- c->flags &= ~CLIENT_STATUS;
- } else {
- TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
- if (wp->flags & PANE_REDRAW)
- screen_redraw_pane(c, wp);
+ server_poll_add(
+ wp->pipe_fd, events, server_window_callback, wp);
}
}
-
- if (c->flags & CLIENT_STATUS)
- screen_redraw_screen(c, 1);
-
- c->tty.flags |= flags;
-
- c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS);
-}
-
-/* Set client title. */
-void
-server_set_title(struct client *c)
-{
- struct session *s = c->session;
- const char *template;
- char *title;
-
- template = options_get_string(&s->options, "set-titles-string");
-
- title = status_replace(c, template, time(NULL));
- if (c->title == NULL || strcmp(title, c->title) != 0) {
- if (c->title != NULL)
- xfree(c->title);
- c->title = xstrdup(title);
- tty_set_title(&c->tty, c->title);
- }
- xfree(title);
-}
-
-/* Check for timers on client. */
-void
-server_check_timers(struct client *c)
-{
- struct session *s = c->session;
- struct job *job;
- struct timeval tv;
- u_int interval;
-
- if (gettimeofday(&tv, NULL) != 0)
- fatal("gettimeofday failed");
-
- if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >))
- server_clear_identify(c);
-
- if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >))
- status_message_clear(c);
-
- if (c->message_string != NULL || c->prompt_string != NULL) {
- /*
- * Don't need timed redraw for messages/prompts so bail now.
- * The status timer isn't reset when they are redrawn anyway.
- */
- return;
- }
- if (!options_get_number(&s->options, "status"))
- return;
-
- /* Check timer; resolution is only a second so don't be too clever. */
- interval = options_get_number(&s->options, "status-interval");
- if (interval == 0)
- return;
- if (tv.tv_sec < c->status_timer.tv_sec ||
- ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) {
- /* Run the jobs for this client and schedule for redraw. */
- RB_FOREACH(job, jobs, &c->status_jobs)
- job_run(job);
- c->flags |= CLIENT_STATUS;
- }
}
/* Fill client pollfds. */
@@ -777,7 +554,8 @@ server_fill_clients(void)
events |= POLLIN;
if (c->ibuf.w.queued > 0)
events |= POLLOUT;
- server_poll_add(c->ibuf.fd, events);
+ server_poll_add(
+ c->ibuf.fd, events, server_client_callback, c);
}
if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
@@ -785,7 +563,8 @@ server_fill_clients(void)
events = POLLIN;
if (BUFFER_USED(c->tty.out) > 0)
events |= POLLOUT;
- server_poll_add(c->tty.fd, events);
+ server_poll_add(
+ c->tty.fd, events, server_client_callback, c);
}
}
}
@@ -799,328 +578,10 @@ server_fill_jobs(void)
SLIST_FOREACH(job, &all_jobs, lentry) {
if (job->fd == -1)
continue;
- server_poll_add(job->fd, POLLIN);
+ server_poll_add(job->fd, POLLIN, server_job_callback, job);
}
}
-/* Handle job fds. */
-void
-server_handle_jobs(void)
-{
- struct job *job;
- struct pollfd *pfd;
-
- SLIST_FOREACH(job, &all_jobs, lentry) {
- if (job->fd == -1)
- continue;
- if ((pfd = server_poll_lookup(job->fd)) == NULL)
- continue;
- if (buffer_poll(pfd, job->out, NULL) != 0) {
- close(job->fd);
- job->fd = -1;
- }
- }
-}
-
-/* Handle job fds. */
-void
-server_check_jobs(void)
-{
- struct job *job;
-
-restart:
- SLIST_FOREACH(job, &all_jobs, lentry) {
- if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1)
- continue;
- job->flags |= JOB_DONE;
-
- if (job->callbackfn != NULL) {
- job->callbackfn(job);
- goto restart; /* could be freed by callback */
- }
- }
-}
-
-/* Handle client pollfds. */
-void
-server_handle_clients(void)
-{
- struct client *c;
- struct pollfd *pfd;
- u_int i;
-
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- c = ARRAY_ITEM(&clients, i);
-
- if (c != NULL) {
- if ((pfd = server_poll_lookup(c->ibuf.fd)) == NULL)
- continue;
- if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) {
- server_lost_client(c);
- continue;
- }
-
- if (pfd->revents & POLLOUT) {
- if (msgbuf_write(&c->ibuf.w) < 0) {
- server_lost_client(c);
- continue;
- }
- }
-
- if (c->flags & CLIENT_BAD) {
- if (c->ibuf.w.queued == 0)
- server_lost_client(c);
- continue;
- } else if (pfd->revents & POLLIN) {
- if (server_msg_dispatch(c) != 0) {
- server_lost_client(c);
- continue;
- }
- }
- }
-
- if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
- c->tty.fd != -1 && c->session != NULL) {
- if ((pfd = server_poll_lookup(c->tty.fd)) == NULL)
- continue;
- if (buffer_poll(pfd, c->tty.in, c->tty.out) != 0)
- server_lost_client(c);
- else
- server_handle_client(c);
- }
- }
-}
-
-/* accept(2) and create new client. */
-void
-server_accept_client(int srv_fd)
-{
- struct sockaddr_storage sa;
- socklen_t slen = sizeof sa;
- int fd;
-
- fd = accept(srv_fd, (struct sockaddr *) &sa, &slen);
- if (fd == -1) {
- if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
- return;
- fatal("accept failed");
- }
- if (sigterm) {
- close(fd);
- return;
- }
- server_create_client(fd);
-}
-
-/* Input data from client. */
-void
-server_handle_client(struct client *c)
-{
- struct window *w;
- struct window_pane *wp;
- struct screen *s;
- struct options *oo;
- struct timeval tv;
- struct key_binding *bd;
- struct keylist *keylist;
- struct mouse_event mouse;
- int key, status, xtimeout, mode, isprefix;
- u_int i;
-
- xtimeout = options_get_number(&c->session->options, "repeat-time");
- if (xtimeout != 0 && c->flags & CLIENT_REPEAT) {
- if (gettimeofday(&tv, NULL) != 0)
- fatal("gettimeofday failed");
- if (timercmp(&tv, &c->repeat_timer, >))
- c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
- }
-
- /* Process keys. */
- keylist = options_get_data(&c->session->options, "prefix");
- while (tty_keys_next(&c->tty, &key, &mouse) == 0) {
- if (c->session == NULL)
- return;
-
- c->session->activity = time(NULL);
- w = c->session->curw->window;
- wp = w->active; /* could die */
- oo = &c->session->options;
-
- /* Special case: number keys jump to pane in identify mode. */
- if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
- wp = window_pane_at_index(w, key - '0');
- if (wp != NULL && window_pane_visible(wp))
- window_set_active_pane(w, wp);
- server_clear_identify(c);
- continue;
- }
-
- status_message_clear(c);
- server_clear_identify(c);
- if (c->prompt_string != NULL) {
- status_prompt_key(c, key);
- continue;
- }
-
- /* Check for mouse keys. */
- if (key == KEYC_MOUSE) {
- if (options_get_number(oo, "mouse-select-pane")) {
- window_set_active_at(w, mouse.x, mouse.y);
- wp = w->active;
- }
- window_pane_mouse(wp, c, &mouse);
- continue;
- }
-
- /* Is this a prefix key? */
- isprefix = 0;
- for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
- if (key == ARRAY_ITEM(keylist, i)) {
- isprefix = 1;
- break;
- }
- }
-
- /* No previous prefix key. */
- if (!(c->flags & CLIENT_PREFIX)) {
- if (isprefix)
- c->flags |= CLIENT_PREFIX;
- else {
- /* Try as a non-prefix key binding. */
- if ((bd = key_bindings_lookup(key)) == NULL)
- window_pane_key(wp, c, key);
- else
- key_bindings_dispatch(bd, c);
- }
- continue;
- }
-
- /* Prefix key already pressed. Reset prefix and lookup key. */
- c->flags &= ~CLIENT_PREFIX;
- if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
- /* If repeating, treat this as a key, else ignore. */
- if (c->flags & CLIENT_REPEAT) {
- c->flags &= ~CLIENT_REPEAT;
- if (isprefix)
- c->flags |= CLIENT_PREFIX;
- else
- window_pane_key(wp, c, key);
- }
- continue;
- }
-
- /* If already repeating, but this key can't repeat, skip it. */
- if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
- c->flags &= ~CLIENT_REPEAT;
- if (isprefix)
- c->flags |= CLIENT_PREFIX;
- else
- window_pane_key(wp, c, key);
- continue;
- }
-
- /* If this key can repeat, reset the repeat flags and timer. */
- if (xtimeout != 0 && bd->can_repeat) {
- c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
-
- tv.tv_sec = xtimeout / 1000;
- tv.tv_usec = (xtimeout % 1000) * 1000L;
- if (gettimeofday(&c->repeat_timer, NULL) != 0)
- fatal("gettimeofday failed");
- timeradd(&c->repeat_timer, &tv, &c->repeat_timer);
- }
-
- /* Dispatch the command. */
- key_bindings_dispatch(bd, c);
- }
- if (c->session == NULL)
- return;
- w = c->session->curw->window;
- wp = w->active;
- oo = &c->session->options;
- s = wp->screen;
-
- /*
- * Update cursor position and mode settings. The scroll region and
- * attributes are cleared across poll(2) as this is the most likely
- * time a user may interrupt tmux, for example with ~^Z in ssh(1). This
- * is a compromise between excessive resets and likelihood of an
- * interrupt.
- *
- * tty_region/tty_reset/tty_update_mode already take care of not
- * resetting things that are already in their default state.
- */
- tty_region(&c->tty, 0, c->tty.sy - 1);
-
- status = options_get_number(oo, "status");
- if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
- tty_cursor(&c->tty, 0, 0);
- else
- tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy);
-
- mode = s->mode;
- if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
- options_get_number(oo, "mouse-select-pane"))
- mode |= MODE_MOUSE;
- tty_update_mode(&c->tty, mode);
- tty_reset(&c->tty);
-}
-
-/* Lost a client. */
-void
-server_lost_client(struct client *c)
-{
- u_int i;
-
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- if (ARRAY_ITEM(&clients, i) == c)
- ARRAY_SET(&clients, i, NULL);
- }
- log_debug("lost client %d", c->ibuf.fd);
-
- /*
- * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
- * and tty_free might close an unrelated fd.
- */
- if (c->flags & CLIENT_TERMINAL)
- tty_free(&c->tty);
-
- screen_free(&c->status);
- job_tree_free(&c->status_jobs);
-
- if (c->title != NULL)
- xfree(c->title);
-
- if (c->message_string != NULL)
- xfree(c->message_string);
-
- if (c->prompt_string != NULL)
- xfree(c->prompt_string);
- if (c->prompt_buffer != NULL)
- xfree(c->prompt_buffer);
- for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
- xfree(ARRAY_ITEM(&c->prompt_hdata, i));
- ARRAY_FREE(&c->prompt_hdata);
-
- if (c->cwd != NULL)
- xfree(c->cwd);
-
- close(c->ibuf.fd);
- imsg_clear(&c->ibuf);
-
- for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
- if (ARRAY_ITEM(&dead_clients, i) == NULL) {
- ARRAY_SET(&dead_clients, i, c);
- break;
- }
- }
- if (i == ARRAY_LENGTH(&dead_clients))
- ARRAY_ADD(&dead_clients, c);
- c->flags |= CLIENT_DEAD;
-
- recalculate_sizes();
-}
-
/* Free dead, unreferenced clients and sessions. */
void
server_clean_dead(void)
@@ -1146,221 +607,29 @@ server_clean_dead(void)
}
}
-/* Handle window data. */
-void
-server_handle_window(struct window *w, struct window_pane *wp)
-{
- struct session *s;
- u_int i;
- int update;
-
- window_pane_parse(wp);
-
- if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0)
- return;
-
- update = 0;
- for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
- s = ARRAY_ITEM(&sessions, i);
- if (s == NULL || !session_has(s, w))
- continue;
-
- update += server_check_window_bell(s, w);
- update += server_check_window_activity(s, w);
- update += server_check_window_content(s, w, wp);
- }
- if (update)
- server_status_window(w);
-
- w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
-}
-
-int
-server_check_window_bell(struct session *s, struct window *w)
-{
- struct client *c;
- u_int i;
- int action, visual;
-
- if (!(w->flags & WINDOW_BELL))
- return (0);
- if (session_alert_has_window(s, w, WINDOW_BELL))
- return (0);
- session_alert_add(s, w, WINDOW_BELL);
-
- action = options_get_number(&s->options, "bell-action");
- switch (action) {
- case BELL_ANY:
- if (s->flags & SESSION_UNATTACHED)
- break;
- visual = options_get_number(&s->options, "visual-bell");
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session != s)
- continue;
- if (!visual) {
- tty_putcode(&c->tty, TTYC_BEL);
- continue;
- }
- if (c->session->curw->window == w) {
- status_message_set(c, "Bell in current window");
- continue;
- }
- status_message_set(c, "Bell in window %u",
- winlink_find_by_window(&s->windows, w)->idx);
- }
- break;
- case BELL_CURRENT:
- if (s->flags & SESSION_UNATTACHED)
- break;
- visual = options_get_number(&s->options, "visual-bell");
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session != s)
- continue;
- if (c->session->curw->window != w)
- continue;
- if (!visual) {
- tty_putcode(&c->tty, TTYC_BEL);
- continue;
- }
- status_message_set(c, "Bell in current window");
- }
- break;
- }
- return (1);
-}
-
-int
-server_check_window_activity(struct session *s, struct window *w)
-{
- struct client *c;
- u_int i;
-
- if (!(w->flags & WINDOW_ACTIVITY))
- return (0);
-
- if (!options_get_number(&w->options, "monitor-activity"))
- return (0);
-
- if (session_alert_has_window(s, w, WINDOW_ACTIVITY))
- return (0);
- if (s->curw->window == w)
- return (0);
-
- session_alert_add(s, w, WINDOW_ACTIVITY);
- if (s->flags & SESSION_UNATTACHED)
- return (0);
- if (options_get_number(&s->options, "visual-activity")) {
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session != s)
- continue;
- status_message_set(c, "Activity in window %u",
- winlink_find_by_window(&s->windows, w)->idx);
- }
- }
-
- return (1);
-}
-
-int
-server_check_window_content(
- struct session *s, struct window *w, struct window_pane *wp)
-{
- struct client *c;
- u_int i;
- char *found, *ptr;
-
- if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */
- return (0);
-
- ptr = options_get_string(&w->options, "monitor-content");
- if (ptr == NULL || *ptr == '\0')
- return (0);
-
- if (session_alert_has_window(s, w, WINDOW_CONTENT))
- return (0);
- if (s->curw->window == w)
- return (0);
-
- if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
- return (0);
- xfree(found);
-
- session_alert_add(s, w, WINDOW_CONTENT);
- if (s->flags & SESSION_UNATTACHED)
- return (0);
- if (options_get_number(&s->options, "visual-content")) {
- for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session != s)
- continue;
- status_message_set(c, "Content in window %u",
- winlink_find_by_window(&s->windows, w)->idx);
- }
- }
-
- return (1);
-}
-
-/* Check if window still exists. */
+/* Call any once-per-second timers. */
void
-server_check_window(struct window *w)
+server_second_timers(void)
{
- struct window_pane *wp, *wq;
- struct options *oo = &w->options;
- struct session *s;
- struct winlink *wl;
+ struct window *w;
+ struct window_pane *wp;
u_int i;
- int destroyed;
-
- destroyed = 1;
-
- wp = TAILQ_FIRST(&w->panes);
- while (wp != NULL) {
- wq = TAILQ_NEXT(wp, entry);
- /*
- * If the pane has died and the remain-on-exit flag is not set,
- * remove the pane; otherwise, if the flag is set, don't allow
- * the window to be destroyed (or it'll close when the last
- * pane dies).
- */
- if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) {
- layout_close_pane(wp);
- window_remove_pane(w, wp);
- server_redraw_window(w);
- } else
- destroyed = 0;
- wp = wq;
- }
- if (!destroyed)
- return;
+ if (options_get_number(&global_s_options, "lock-server"))
+ server_lock_server();
+ else
+ server_lock_sessions();
- for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
- s = ARRAY_ITEM(&sessions, i);
- if (s == NULL)
- continue;
- if (!session_has(s, w))
+ for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
+ w = ARRAY_ITEM(&windows, i);
+ if (w == NULL)
continue;
- restart:
- /* Detach window and either redraw or kill clients. */
- RB_FOREACH(wl, winlinks, &s->windows) {
- if (wl->window != w)
- continue;
- if (session_detach(s, wl)) {
- server_destroy_session_group(s);
- break;
- }
- server_redraw_session(s);
- server_status_session_group(s);
- goto restart;
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (wp->mode != NULL && wp->mode->timer != NULL)
+ wp->mode->timer(wp);
}
}
-
- recalculate_sizes();
}
/* Lock the server if ALL sessions have hit the time limit. */
@@ -1418,31 +687,6 @@ server_lock_sessions(void)
}
}
-/* Call any once-per-second timers. */
-void
-server_second_timers(void)
-{
- struct window *w;
- struct window_pane *wp;
- u_int i;
-
- if (options_get_number(&global_s_options, "lock-server"))
- server_lock_server();
- else
- server_lock_sessions();
-
- for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
- w = ARRAY_ITEM(&windows, i);
- if (w == NULL)
- continue;
-
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if (wp->mode != NULL && wp->mode->timer != NULL)
- wp->mode->timer(wp);
- }
- }
-}
-
/* Update socket execute permissions based on whether sessions are attached. */
int
server_update_socket(void)