From 9ef5bdc7c058854f902dd42f79b6b7454331a98e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 19 Jun 2008 18:27:55 +0000 Subject: [PATCH] Show status messages without blocking the server. --- TODO | 6 +++-- server-fn.c | 66 +++++++++++++++++++++++------------------------------ server.c | 57 ++++++++++++++++++++++++++++++--------------- status.c | 60 ++++++++++++++++++++++++++++++++++++++++++++---- tmux.h | 15 +++++++++--- 5 files changed, 139 insertions(+), 65 deletions(-) diff --git a/TODO b/TODO index 55e52fd1..fcbba555 100644 --- a/TODO +++ b/TODO @@ -37,8 +37,6 @@ - function groups, bind-key ^W { select-window 0; send-key ^W } etc *** - allow fnmatch for -c, so that you can, eg, detach all clients - bind non prefix keys -- stuff like rename would be nice to be able to do in-client like screen, if - it could be implemented in a non-icky way - there is too much redrawing. use flags? - command mode (! + type tmux command) - garbage collect window history (100 lines at a time?) if it hasn't been used @@ -86,3 +84,7 @@ option to pass through to xterm window when switching window session not being watched? - document status-left/status-right/status-interval/set-titles - enhance paste buffers. per-session buffers, lots of command love +- stuff like rename would be nice to be able to do in-client like screen, if + it could be implemented in a non-icky way (we have control over the tty fd + now in the server so should be easier...) +- tidy up window modes diff --git a/server-fn.c b/server-fn.c index 8547fbf7..9893d409 100644 --- a/server-fn.c +++ b/server-fn.c @@ -1,4 +1,4 @@ -/* $Id: server-fn.c,v 1.42 2008-06-16 17:35:40 nicm Exp $ */ +/* $Id: server-fn.c,v 1.43 2008-06-19 18:27:55 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -23,6 +23,31 @@ #include "tmux.h" +void +server_set_client_message(struct client *c, const char *msg) +{ + struct timespec ts = { 0, 750000000L }; + + c->message_string = xstrdup(msg); + if (clock_gettime(CLOCK_REALTIME, &c->message_timer) != 0) + fatal("clock_gettime"); + timespecadd(&c->message_timer, &ts, &c->message_timer); + + c->flags |= CLIENT_STATUS; +} + +void +server_clear_client_message(struct client *c) +{ + if (c->message_string == NULL) + return; + + xfree(c->message_string); + c->message_string = NULL; + + c->flags |= CLIENT_STATUS; +} + void server_write_client( struct client *c, enum hdrtype type, const void *buf, size_t len) @@ -150,47 +175,14 @@ server_status_window(struct window *w) void printflike2 server_write_message(struct client *c, const char *fmt, ...) { - struct screen_redraw_ctx ctx; - va_list ap; - char *msg; - size_t size; - u_int slines; - - slines = options_get_number(&c->session->options, "status-lines"); - - screen_redraw_start_client(&ctx, c); + va_list ap; + char *msg; va_start(ap, fmt); xvasprintf(&msg, fmt, ap); va_end(ap); - msg = xrealloc(msg, 1, c->sx + 1); - msg[c->sx] = '\0'; - - size = strlen(msg); - if (size < c->sx) - memset(msg + size, ' ', c->sx - size); - - screen_redraw_move_cursor(&ctx, 0, c->sy - 1); - screen_redraw_set_attributes(&ctx, ATTR_REVERSE, 0x88); - screen_redraw_write_string(&ctx, "%s", msg); - - buffer_flush(c->tty.fd, c->tty.in, c->tty.out); - usleep(750000); - - memset(msg, ' ', c->sx); - - screen_redraw_move_cursor(&ctx, 0, c->sy - 1); - screen_redraw_set_attributes(&ctx, 0, 0x88); - screen_redraw_write_string(&ctx, "%s", msg); + server_set_client_message(c, msg); xfree(msg); - - if (slines == 0) { - screen_redraw_lines(&ctx, c->sy - 1, 1); - screen_redraw_stop(&ctx); - } else { - screen_redraw_stop(&ctx); - server_status_client(c); - } } diff --git a/server.c b/server.c index 3b63b69b..b10cf476 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.68 2008-06-18 22:21:51 nicm Exp $ */ +/* $Id: server.c,v 1.69 2008-06-19 18:27:55 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -54,7 +54,7 @@ void server_handle_window(struct window *); void server_lost_client(struct client *); void server_lost_window(struct window *); void server_check_redraw(struct client *); -void server_check_status(struct client *); +void server_check_timers(struct client *); void server_update_socket(const char *); /* Fork new server. */ @@ -322,7 +322,7 @@ server_check_redraw(struct client *c) } xx = c->sx; - yy = c->sy - options_get_number(&s->options, "status-lines"); + yy = c->sy - 1; //options_get_number(&s->options, "status-lines"); if (c->flags & CLIENT_REDRAW) { sx = screen_size_x(s->curw->window->screen); sy = screen_size_y(s->curw->window->screen); @@ -351,33 +351,47 @@ server_check_redraw(struct client *c) screen_redraw_lines(&ctx, 0, screen_size_y(ctx.s)); screen_redraw_stop(&ctx); - status_redraw(c); - } else if (c->flags & CLIENT_STATUS) - status_redraw(c); + c->flags |= CLIENT_STATUS; + } - c->flags &= ~(CLIENT_CLEAR|CLIENT_REDRAW|CLIENT_STATUS); + if (c->flags & CLIENT_STATUS) { + if (c->message_string != NULL) + status_message_redraw(c); + else + status_redraw(c); + } + + c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); } -/* Check for status line redraw on client. */ +/* Check for timers on client. */ void -server_check_status(struct client *c) +server_check_timers(struct client *c) { - struct timespec ts; + struct session *s; + struct timespec ts, ts2; u_int nlines, interval; if (c == NULL || c->session == NULL) return; - - nlines = options_get_number(&c->session->options, "status-lines"); - interval = options_get_number(&c->session->options, "status-interval"); - if (nlines == 0 || interval == 0) - return; + s = c->session; if (clock_gettime(CLOCK_REALTIME, &ts) != 0) fatal("clock_gettime"); - ts.tv_sec -= interval; + + if (c->message_string != NULL && timespeccmp(&ts, &c->message_timer, >)) + server_clear_client_message(c); - if (timespeccmp(&c->status_ts, &ts, <)) + nlines = options_get_number(&s->options, "status-lines"); + if (nlines == 0) + return; + interval = options_get_number(&s->options, "status-interval"); + if (interval == 0) + return; + + memcpy(&ts2, &ts, sizeof ts2); + ts2.tv_sec -= interval; + if (timespeccmp(&c->status_timer, &ts2, <)) c->flags |= CLIENT_STATUS; } @@ -391,8 +405,8 @@ server_fill_clients(struct pollfd **pfd) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); + server_check_timers(c); server_check_redraw(c); - server_check_status(c); if (c == NULL) (*pfd)->fd = -1; @@ -483,6 +497,12 @@ server_accept_client(int srv_fd) c->sx = 80; c->sy = 25; + c->message_string = NULL; + + c->prompt_string = NULL; + c->prompt_buffer = NULL; + c->prompt_size = 0; + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) == NULL) { ARRAY_SET(&clients, i, c); @@ -502,6 +522,7 @@ server_handle_client(struct client *c) prefix = options_get_key(&c->session->options, "prefix-key"); while (tty_keys_next(&c->tty, &key) == 0) { + server_clear_client_message(c); if (c->flags & CLIENT_PREFIX) { key_bindings_dispatch(key, c); c->flags &= ~CLIENT_PREFIX; diff --git a/status.c b/status.c index a9dbfb5e..20e3282c 100644 --- a/status.c +++ b/status.c @@ -1,4 +1,4 @@ -/* $Id: status.c,v 1.30 2008-06-18 22:21:51 nicm Exp $ */ +/* $Id: status.c,v 1.31 2008-06-19 18:27:55 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -39,14 +39,15 @@ status_redraw(struct client *c) size_t llen, rlen, offset, xx, yy; size_t size, start, width; u_char attr, colr; + struct tm *tm; int larrow, rarrow; yy = options_get_number(&s->options, "status-lines"); if (c->sy == 0 || yy == 0) - return; + goto off; larrow = rarrow = 0; - if (clock_gettime(CLOCK_REALTIME, &c->status_ts) != 0) + if (clock_gettime(CLOCK_REALTIME, &c->status_timer) != 0) fatal("clock_gettime failed"); colr = options_get_colours(&s->options, "status-colour"); @@ -54,11 +55,12 @@ status_redraw(struct client *c) if (yy == 0) goto blank; + tm = localtime(&(c->status_timer.tv_sec)); left = options_get_string(&s->options, "status-left"); - strftime(lbuf, sizeof lbuf, left, localtime(&(c->status_ts.tv_sec))); + strftime(lbuf, sizeof lbuf, left, tm); llen = strlen(lbuf); right = options_get_string(&s->options, "status-right"); - strftime(rbuf, sizeof rbuf, right, localtime(&(c->status_ts.tv_sec))); + strftime(rbuf, sizeof rbuf, right, tm); rlen = strlen(rbuf); /* @@ -229,6 +231,26 @@ blank: for (offset = 0; offset < c->sx; offset++) ctx.write(ctx.data, TTY_CHARACTER, ' '); screen_redraw_stop(&ctx); + + return; + +off: + /* + * Draw the real window last line. Necessary to wipe over message if + * status is off. Not sure this is the right place for this. + */ + screen_redraw_start_client(&ctx, c); + /* If the screen is too small, use blank. */ + if (screen_size_y(c->session->curw->window->screen) < c->sy) { + screen_redraw_move_cursor(&ctx, 0, c->sy - 1); + screen_redraw_set_attributes(&ctx, 0, 0x88); + for (offset = 0; offset < c->sx; offset++) + ctx.write(ctx.data, TTY_CHARACTER, ' '); + } else + screen_redraw_lines(&ctx, c->sy - 1, 1); + screen_redraw_stop(&ctx); + + return; } size_t @@ -261,3 +283,31 @@ status_print(struct session *s, struct winlink *wl, u_char *attr) xasprintf(&text, "%d:%s%c", wl->idx, wl->window->name, flag); return (text); } + +/* Draw client message on status line of present else on last line. */ +void +status_message_redraw(struct client *c) +{ + struct screen_redraw_ctx ctx; + size_t xx, yy; + + if (c->sx == 0 || c->sy == 0) + return; + + xx = strlen(c->message_string); + if (xx > c->sx) + xx = c->sx; + yy = c->sy - 1; + + screen_redraw_start_client(&ctx, c); + screen_redraw_set_attributes(&ctx, ATTR_REVERSE, 0x88); + + screen_redraw_move_cursor(&ctx, 0, yy); + screen_redraw_write_string(&ctx, "%.*s", (int) xx, c->message_string); + for (; xx < c->sx; xx++) + ctx.write(ctx.data, TTY_CHARACTER, ' '); + screen_redraw_stop(&ctx); + + /* Force cursor off. */ + tty_write_client(c, TTY_CURSOROFF); +} diff --git a/tmux.h b/tmux.h index 5038d84b..83e0f643 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.151 2008-06-18 20:58:03 nicm Exp $ */ +/* $Id: tmux.h,v 1.152 2008-06-19 18:27:55 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -664,7 +664,7 @@ struct client { char *title; struct tty tty; - struct timespec status_ts; + struct timespec status_timer; u_int sx; u_int sy; @@ -674,9 +674,15 @@ struct client { #define CLIENT_MOUSE 0x4 #define CLIENT_REDRAW 0x8 #define CLIENT_STATUS 0x10 -#define CLIENT_CLEAR 0x20 int flags; + char *message_string; + struct timespec message_timer; + + char *prompt_string; + char *prompt_buffer; + size_t prompt_size; + struct session *session; }; ARRAY_DECL(clients, struct client *); @@ -949,6 +955,8 @@ int server_start(const char *); int server_msg_dispatch(struct client *); /* server-fn.c */ +void server_set_client_message(struct client *, const char *); +void server_clear_client_message(struct client *); struct session *server_extract_session( struct msg_command_data *, char *, char **); void server_write_client( @@ -967,6 +975,7 @@ void printflike2 server_write_message(struct client *, const char *, ...); /* status.c */ void status_redraw(struct client *c); +void status_message_redraw(struct client *c); /* resize.c */ void recalculate_sizes(void);