diff options
Diffstat (limited to 'server-client.c')
-rw-r--r-- | server-client.c | 77 |
1 files changed, 71 insertions, 6 deletions
diff --git a/server-client.c b/server-client.c index 3c63a9d5..e42ad8e0 100644 --- a/server-client.c +++ b/server-client.c @@ -47,7 +47,7 @@ static void server_client_dispatch_command(struct client *, struct imsg *); static void server_client_dispatch_identify(struct client *, struct imsg *); static void server_client_dispatch_shell(struct client *); -/* Idenfity mode callback. */ +/* Identify mode callback. */ static void server_client_callback_identify(__unused int fd, __unused short events, void *data) { @@ -323,15 +323,30 @@ server_client_free(__unused int fd, __unused short events, void *arg) } } +/* Suspend a client. */ +void +server_client_suspend(struct client *c) +{ + struct session *s = c->session; + + if (s == NULL || (c->flags & CLIENT_DETACHING)) + return; + + tty_stop_tty(&c->tty); + c->flags |= CLIENT_SUSPENDED; + proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0); +} + /* Detach a client. */ void server_client_detach(struct client *c, enum msgtype msgtype) { - struct session *s = c->session; + struct session *s = c->session; - if (s == NULL) + if (s == NULL || (c->flags & CLIENT_DETACHING)) return; + c->flags |= CLIENT_DETACHING; notify_client("client-detached", c); proc_send_s(c->peer, msgtype, s->name); } @@ -1209,6 +1224,14 @@ server_client_check_exit(struct client *c) c->flags &= ~CLIENT_EXIT; } +/* Redraw timer callback. */ +static void +server_client_redraw_timer(__unused int fd, __unused short events, + __unused void* data) +{ + log_debug("redraw timer fired"); +} + /* Check for client redraws. */ static void server_client_check_redraw(struct client *c) @@ -1216,19 +1239,61 @@ server_client_check_redraw(struct client *c) struct session *s = c->session; struct tty *tty = &c->tty; struct window_pane *wp; - int flags, masked; + int needed, flags, masked; + struct timeval tv = { .tv_usec = 1000 }; + static struct event ev; + size_t left; if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) return; + /* + * If there is outstanding data, defer the redraw until it has been + * consumed. We can just add a timer to get out of the event loop and + * end up back here. + */ + needed = 0; + if (c->flags & CLIENT_REDRAW) + needed = 1; + else { + TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { + if (wp->flags & PANE_REDRAW) { + needed = 1; + break; + } + } + } + if (needed) { + left = EVBUFFER_LENGTH(tty->out); + if (left != 0) { + log_debug("%s: redraw deferred (%zu left)", c->name, left); + if (evtimer_initialized(&ev) && evtimer_pending(&ev, NULL)) + return; + log_debug("redraw timer started"); + evtimer_set(&ev, server_client_redraw_timer, NULL); + evtimer_add(&ev, &tv); + + /* + * We may have got here for a single pane redraw, but + * force a full redraw next time in case other panes + * have been updated. + */ + c->flags |= CLIENT_REDRAW; + return; + } + if (evtimer_initialized(&ev)) + evtimer_del(&ev); + log_debug("%s: redraw needed", c->name); + } + if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { if (options_get_number(s->options, "set-titles")) server_client_set_title(c); screen_redraw_update(c); /* will adjust flags */ } - flags = tty->flags & (TTY_FREEZE|TTY_NOCURSOR); - tty->flags = (tty->flags & ~TTY_FREEZE) | TTY_NOCURSOR; + flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR); + tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE)) | TTY_NOCURSOR; if (c->flags & CLIENT_REDRAW) { tty_update_mode(tty, tty->mode, NULL); |