diff --git a/input.c b/input.c index bf6cb48a..f56f90c2 100644 --- a/input.c +++ b/input.c @@ -59,11 +59,12 @@ struct input_request { enum input_request_type type; int idx; time_t t; + void *data; TAILQ_ENTRY(input_request) entry; TAILQ_ENTRY(input_request) centry; }; -#define INPUT_REQUEST_TIMEOUT 5 +#define INPUT_REQUEST_TIMEOUT 2 /* Input parser cell. */ struct input_cell { @@ -131,7 +132,7 @@ struct input_ctx { #define INPUT_DISCARD 0x1 #define INPUT_LAST 0x2 - struct input_requests requests[INPUT_REQUEST_TYPES]; + struct input_requests requests; u_int request_count; struct event request_timer; @@ -147,11 +148,13 @@ struct input_ctx { struct input_transition; static void input_request_timer_callback(int, short, void *); static void input_start_request_timer(struct input_ctx *); +static struct input_request *input_make_request(struct input_ctx *, + enum input_request_type); +static void input_free_request(struct input_request *); static int input_add_request(struct input_ctx *, enum input_request_type, int); static int input_split(struct input_ctx *); static int input_get(struct input_ctx *, u_int, int, int); -static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...); static void input_set_state(struct input_ctx *, const struct input_transition *); static void input_reset_cell(struct input_ctx *); @@ -852,7 +855,6 @@ input_init(struct window_pane *wp, struct bufferevent *bev, struct colour_palette *palette) { struct input_ctx *ictx; - u_int i; ictx = xcalloc(1, sizeof *ictx); ictx->wp = wp; @@ -867,8 +869,7 @@ input_init(struct window_pane *wp, struct bufferevent *bev, fatalx("out of memory"); evtimer_set(&ictx->ground_timer, input_ground_timer_callback, ictx); - for (i = 0; i < INPUT_REQUEST_TYPES; i++) - TAILQ_INIT(&ictx->requests[i]); + TAILQ_INIT(&ictx->requests); evtimer_set(&ictx->request_timer, input_request_timer_callback, ictx); input_reset(ictx, 0); @@ -879,25 +880,16 @@ input_init(struct window_pane *wp, struct bufferevent *bev, void input_free(struct input_ctx *ictx) { - struct input_request_list *irl; - struct input_request *ir, *ir1; - u_int i; + struct input_request *ir, *ir1; + u_int i; for (i = 0; i < ictx->param_list_len; i++) { if (ictx->param_list[i].type == INPUT_STRING) free(ictx->param_list[i].str); } - for (i = 0; i < INPUT_REQUEST_TYPES; i++) { - TAILQ_FOREACH_SAFE(ir, &ictx->requests[i], entry, ir1) { - log_debug("%s: req %p: client %s, pane %%%u, type %d", - __func__, ir, ir->c->name, ictx->wp->id, i); - irl = &ir->c->input_requests[i]; - TAILQ_REMOVE(&ictx->requests[i], ir, entry); - TAILQ_REMOVE(&irl->requests, ir, centry); - free(ir); - } - } + TAILQ_FOREACH_SAFE(ir, &ictx->requests, entry, ir1) + input_free_request(ir); event_del(&ictx->request_timer); free(ictx->input_buf); @@ -1137,24 +1129,37 @@ input_get(struct input_ctx *ictx, u_int validx, int minval, int defval) return (retval); } -/* Reply to terminal query. */ +/* Send reply. */ static void -input_reply(struct input_ctx *ictx, const char *fmt, ...) +input_send_reply(struct input_ctx *ictx, const char *reply) { struct bufferevent *bev = ictx->event; + + if (bev != NULL) { + log_debug("%s: %s", __func__, reply); + bufferevent_write(bev, reply, strlen(reply)); + } +} + +/* Reply to terminal query. */ +static void printflike(3, 4) +input_reply(struct input_ctx *ictx, int add, const char *fmt, ...) +{ + struct input_request *ir; va_list ap; char *reply; - if (bev == NULL) - return; - va_start(ap, fmt); xvasprintf(&reply, fmt, ap); va_end(ap); - log_debug("%s: %s", __func__, reply); - bufferevent_write(bev, reply, strlen(reply)); - free(reply); + if (add && !TAILQ_EMPTY(&ictx->requests)) { + ir = input_make_request(ictx, INPUT_REQUEST_QUEUE); + ir->data = reply; + } else { + input_send_reply(ictx, reply); + free(reply); + } } /* Clear saved state. */ @@ -1547,7 +1552,7 @@ input_csi_dispatch(struct input_ctx *ictx) case -1: break; case 0: - input_reply(ictx, "\033[?1;2c"); + input_reply(ictx, 1, "\033[?1;2c"); break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); @@ -1559,7 +1564,7 @@ input_csi_dispatch(struct input_ctx *ictx) case -1: break; case 0: - input_reply(ictx, "\033[>84;0;0c"); + input_reply(ictx, 1, "\033[>84;0;0c"); break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); @@ -1610,22 +1615,22 @@ input_csi_dispatch(struct input_ctx *ictx) /* blink for 1,3,5; steady for 0,2,4,6 */ n = (p == 1 || p == 3 || p == 5) ? 1 : 2; } - input_reply(ictx, "\033[?12;%d$y", n); + input_reply(ictx, 1, "\033[?12;%d$y", n); break; case 2004: /* bracketed paste */ n = (s->mode & MODE_BRACKETPASTE) ? 1 : 2; - input_reply(ictx, "\033[?2004;%d$y", n); + input_reply(ictx, 1, "\033[?2004;%d$y", n); break; case 1004: /* focus reporting */ n = (s->mode & MODE_FOCUSON) ? 1 : 2; - input_reply(ictx, "\033[?1004;%d$y", n); + input_reply(ictx, 1, "\033[?1004;%d$y", n); break; case 1006: /* SGR mouse */ n = (s->mode & MODE_MOUSE_SGR) ? 1 : 2; - input_reply(ictx, "\033[?1006;%d$y", n); + input_reply(ictx, 1, "\033[?1006;%d$y", n); break; case 2031: - input_reply(ictx, "\033[?2031;2$y"); + input_reply(ictx, 1, "\033[?2031;2$y"); break; } break; @@ -1634,10 +1639,11 @@ input_csi_dispatch(struct input_ctx *ictx) case -1: break; case 5: - input_reply(ictx, "\033[0n"); + input_reply(ictx, 1, "\033[0n"); break; case 6: - input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1); + input_reply(ictx, 1, "\033[%u;%uR", s->cy + 1, + s->cx + 1); break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); @@ -1792,8 +1798,10 @@ input_csi_dispatch(struct input_ctx *ictx) break; case INPUT_CSI_XDA: n = input_get(ictx, 0, 0, 0); - if (n == 0) - input_reply(ictx, "\033P>|tmux %s\033\\", getversion()); + if (n == 0) { + input_reply(ictx, 1, "\033P>|tmux %s\033\\", + getversion()); + } break; } @@ -2042,26 +2050,26 @@ input_csi_dispatch_winops(struct input_ctx *ictx) case 14: if (w == NULL) break; - input_reply(ictx, "\033[4;%u;%ut", y * w->ypixel, + input_reply(ictx, 1, "\033[4;%u;%ut", y * w->ypixel, x * w->xpixel); break; case 15: if (w == NULL) break; - input_reply(ictx, "\033[5;%u;%ut", y * w->ypixel, + input_reply(ictx, 1, "\033[5;%u;%ut", y * w->ypixel, x * w->xpixel); break; case 16: if (w == NULL) break; - input_reply(ictx, "\033[6;%u;%ut", w->ypixel, + input_reply(ictx, 1, "\033[6;%u;%ut", w->ypixel, w->xpixel); break; case 18: - input_reply(ictx, "\033[8;%u;%ut", y, x); + input_reply(ictx, 1, "\033[8;%u;%ut", y, x); break; case 19: - input_reply(ictx, "\033[9;%u;%ut", y, x); + input_reply(ictx, 1, "\033[9;%u;%ut", y, x); break; case 22: m++; @@ -2485,12 +2493,12 @@ input_handle_decrqss(struct input_ctx *ictx) log_debug("%s: DECRQSS cursor -> Ps=%d (cstyle=%d mode=%#x)", __func__, ps, s->cstyle, s->mode); - input_reply(ictx, "\033P1$r q%d q\033\\", ps); + input_reply(ictx, 1, "\033P1$r q%d q\033\\", ps); return (0); not_recognized: /* Unrecognized DECRQSS: send DCS 0 $ r Pt ST. */ - input_reply(ictx, "\033P0$r\033\\"); + input_reply(ictx, 1, "\033P0$r\033\\"); return (0); } @@ -2755,7 +2763,7 @@ input_top_bit_set(struct input_ctx *ictx) /* Reply to a colour request. */ static void -input_osc_colour_reply(struct input_ctx *ictx, u_int n, int idx, int c) +input_osc_colour_reply(struct input_ctx *ictx, int add, u_int n, int idx, int c) { u_char r, g, b; const char *end; @@ -2772,11 +2780,11 @@ input_osc_colour_reply(struct input_ctx *ictx, u_int n, int idx, int c) end = "\033\\"; if (n == 4) { - input_reply(ictx, + input_reply(ictx, add, "\033]%u;%d;rgb:%02hhx%02hhx/%02hhx%02hhx/%02hhx%02hhx%s", n, idx, r, r, g, g, b, b, end); } else { - input_reply(ictx, + input_reply(ictx, add, "\033]%u;rgb:%02hhx%02hhx/%02hhx%02hhx/%02hhx%02hhx%s", n, r, r, g, g, b, b, end); } @@ -2807,7 +2815,7 @@ input_osc_4(struct input_ctx *ictx, const char *p) if (strcmp(s, "?") == 0) { c = colour_palette_get(palette, idx|COLOUR_FLAG_256); if (c != -1) { - input_osc_colour_reply(ictx, 4, idx, c); + input_osc_colour_reply(ictx, 1, 4, idx, c); s = next; continue; } @@ -2891,7 +2899,7 @@ input_osc_10(struct input_ctx *ictx, const char *p) else c = defaults.fg; } - input_osc_colour_reply(ictx, 10, 0, c); + input_osc_colour_reply(ictx, 1, 10, 0, c); return; } @@ -2934,7 +2942,7 @@ input_osc_11(struct input_ctx *ictx, const char *p) if (wp == NULL) return; c = window_pane_get_bg(wp); - input_osc_colour_reply(ictx, 11, 0, c); + input_osc_colour_reply(ictx, 1, 11, 0, c); return; } @@ -2978,7 +2986,7 @@ input_osc_12(struct input_ctx *ictx, const char *p) c = ictx->ctx.s->ccolour; if (c == -1) c = ictx->ctx.s->default_ccolour; - input_osc_colour_reply(ictx, 12, 0, c); + input_osc_colour_reply(ictx, 1, 12, 0, c); } return; } @@ -3157,24 +3165,16 @@ input_set_buffer_size(size_t buffer_size) static void input_request_timer_callback(__unused int fd, __unused short events, void *arg) { - struct input_ctx *ictx = arg; - struct input_request *ir, *ir1; - struct input_request_list *irl; - u_int i; - time_t t = time(NULL); + struct input_ctx *ictx = arg; + struct input_request *ir, *ir1; + time_t t = time(NULL); - for (i = 0; i < INPUT_REQUEST_TYPES; i++) { - TAILQ_FOREACH_SAFE(ir, &ictx->requests[i], entry, ir1) { - if (ir->t >= t - INPUT_REQUEST_TIMEOUT) - continue; - log_debug("%s: req %p: client %s, pane %%%u, type %d", - __func__, ir, ir->c->name, ictx->wp->id, ir->type); - irl = &ir->c->input_requests[i]; - TAILQ_REMOVE(&ictx->requests[i], ir, entry); - TAILQ_REMOVE(&irl->requests, ir, centry); - ictx->request_count--; - free(ir); - } + TAILQ_FOREACH_SAFE(ir, &ictx->requests, entry, ir1) { + if (ir->t >= t - INPUT_REQUEST_TIMEOUT) + continue; + if (ir->type == INPUT_REQUEST_QUEUE) + input_send_reply(ir->ictx, ir->data); + input_free_request(ir); } if (ictx->request_count != 0) input_start_request_timer(ictx); @@ -3184,12 +3184,46 @@ input_request_timer_callback(__unused int fd, __unused short events, void *arg) static void input_start_request_timer(struct input_ctx *ictx) { - struct timeval tv = { .tv_sec = 1, .tv_usec = 0 }; + struct timeval tv = { .tv_sec = 0, .tv_usec = 500000 }; event_del(&ictx->request_timer); event_add(&ictx->request_timer, &tv); } +/* Create a request. */ +static struct input_request * +input_make_request(struct input_ctx *ictx, enum input_request_type type) +{ + struct input_request *ir; + + ir = xcalloc (1, sizeof *ir); + ir->type = type; + ir->ictx = ictx; + ir->t = time(NULL); + + if (++ictx->request_count == 1) + input_start_request_timer(ictx); + TAILQ_INSERT_TAIL(&ictx->requests, ir, entry); + + return (ir); +} + +/* Free a request. */ +static void +input_free_request(struct input_request *ir) +{ + struct input_ctx *ictx = ir->ictx; + + if (ir->c != NULL) + TAILQ_REMOVE(&ir->c->input_requests, ir, centry); + + ictx->request_count--; + TAILQ_REMOVE(&ictx->requests, ir, entry); + + free(ir->data); + free(ir); +} + /* Add a request. */ static int input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx) @@ -3219,24 +3253,18 @@ input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx) if (c == NULL) return (-1); - ir = xcalloc (1, sizeof *ir); + ir = input_make_request(ictx, type); ir->c = c; - ir->ictx = ictx; - ir->type = type; ir->idx = idx; - ir->t = time(NULL); - TAILQ_INSERT_TAIL(&ictx->requests[type], ir, entry); - TAILQ_INSERT_TAIL(&c->input_requests[type].requests, ir, centry); - if (++ictx->request_count == 1) - input_start_request_timer(ictx); - log_debug("%s: req %p: client %s, pane %%%u, type %d", __func__, ir, - c->name, wp->id, type); + TAILQ_INSERT_TAIL(&c->input_requests, ir, centry); switch (type) { case INPUT_REQUEST_PALETTE: xsnprintf(s, sizeof s, "\033]4;%d;?\033\\", idx); tty_puts(&c->tty, s); break; + case INPUT_REQUEST_QUEUE: + break; } return (0); @@ -3246,25 +3274,30 @@ input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx) void input_request_reply(struct client *c, enum input_request_type type, void *data) { - struct input_request_list *irl = &c->input_requests[type]; - struct input_request *ir, *ir1; + struct input_request *ir, *ir1, *found = NULL; struct input_request_palette_data *pd = data; + int complete = 0; - TAILQ_FOREACH_SAFE(ir, &irl->requests, centry, ir1) { - log_debug("%s: req %p: client %s, pane %%%u, type %d", - __func__, ir, c->name, ir->ictx->wp->id, ir->type); - switch (type) { - case INPUT_REQUEST_PALETTE: - if (pd->idx != ir->idx) - continue; - input_osc_colour_reply(ir->ictx, 4, pd->idx, pd->c); + TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1) { + if (ir->type == type && pd->idx == ir->idx) { + found = ir; break; } - TAILQ_REMOVE(&ir->ictx->requests[type], ir, entry); - TAILQ_REMOVE(&irl->requests, ir, centry); - ir->ictx->request_count--; - free(ir); - break; + input_free_request(ir); + } + if (found == NULL) + return; + + TAILQ_FOREACH_SAFE(ir, &found->ictx->requests, entry, ir1) { + if (complete && ir->type != INPUT_REQUEST_QUEUE) + break; + if (ir->type == INPUT_REQUEST_QUEUE) + input_send_reply(ir->ictx, ir->data); + else if (ir == found && ir->type == INPUT_REQUEST_PALETTE) { + input_osc_colour_reply(ir->ictx, 0, 4, pd->idx, pd->c); + complete = 1; + } + input_free_request(ir); } } @@ -3272,21 +3305,10 @@ input_request_reply(struct client *c, enum input_request_type type, void *data) void input_cancel_requests(struct client *c) { - struct input_request_list *irl; - struct input_request *ir, *ir1; - u_int i; + struct input_request *ir, *ir1; - for (i = 0; i < INPUT_REQUEST_TYPES; i++) { - irl = &c->input_requests[i]; - TAILQ_FOREACH_SAFE(ir, &irl->requests, entry, ir1) { - log_debug("%s: req %p: client %s, pane %%%u, type %d", - __func__, ir, c->name, ir->ictx->wp->id, ir->type); - TAILQ_REMOVE(&ir->ictx->requests[i], ir, entry); - TAILQ_REMOVE(&irl->requests, ir, centry); - ir->ictx->request_count--; - free(ir); - } - } + TAILQ_FOREACH_SAFE(ir, &c->input_requests, entry, ir1) + input_free_request(ir); } /* Report current theme. */ @@ -3295,10 +3317,10 @@ input_report_current_theme(struct input_ctx *ictx) { switch (window_pane_get_theme(ictx->wp)) { case THEME_DARK: - input_reply(ictx, "\033[?997;1n"); + input_reply(ictx, 0, "\033[?997;1n"); break; case THEME_LIGHT: - input_reply(ictx, "\033[?997;2n"); + input_reply(ictx, 0, "\033[?997;2n"); break; case THEME_UNKNOWN: break; diff --git a/server-client.c b/server-client.c index d2a5a80c..14ebe5fb 100644 --- a/server-client.c +++ b/server-client.c @@ -282,7 +282,6 @@ struct client * server_client_create(int fd) { struct client *c; - u_int i; setblocking(fd, 0); @@ -316,11 +315,7 @@ server_client_create(int fd) evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); evtimer_set(&c->click_timer, server_client_click_timer, c); - for (i = 0; i < INPUT_REQUEST_TYPES; i++) { - c->input_requests[i].c = c; - c->input_requests[i].type = i; - TAILQ_INIT(&c->input_requests[i].requests); - } + TAILQ_INIT(&c->input_requests); TAILQ_INSERT_TAIL(&clients, c, entry); log_debug("new client %p", c); diff --git a/tmux.h b/tmux.h index 736d0f55..6aa9bc57 100644 --- a/tmux.h +++ b/tmux.h @@ -1096,9 +1096,9 @@ struct window_mode_entry { /* Type of request to client. */ enum input_request_type { - INPUT_REQUEST_PALETTE + INPUT_REQUEST_PALETTE, + INPUT_REQUEST_QUEUE }; -#define INPUT_REQUEST_TYPES (1) /* Palette request reply data. */ struct input_request_palette_data { @@ -1108,11 +1108,6 @@ struct input_request_palette_data { /* Request sent to client on behalf of pane. */ TAILQ_HEAD(input_requests, input_request); -struct input_request_list { - struct client *c; - enum input_request_type type; - struct input_requests requests; -}; /* Offsets into pane buffer. */ struct window_pane_offset { @@ -1942,7 +1937,7 @@ struct client { struct status_line status; enum client_theme theme; - struct input_request_list input_requests[INPUT_REQUEST_TYPES]; + struct input_requests input_requests; #define CLIENT_TERMINAL 0x1 #define CLIENT_LOGIN 0x2