diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 18be3f77..2c8dd920 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -80,7 +80,7 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp, size_t linelen; u_int i; - pending = input_pending(wp); + pending = input_pending(wp->ictx); if (pending == NULL) return (xstrdup("")); diff --git a/cmd-send-keys.c b/cmd-send-keys.c index cc04a73f..5770572a 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -192,7 +192,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) if (args_has(args, 'R')) { window_pane_reset_palette(wp); - input_reset(wp, 1); + input_reset(wp->ictx, 1); } for (; np != 0; np--) { diff --git a/input-keys.c b/input-keys.c index d09bf8fb..9d4043ef 100644 --- a/input-keys.c +++ b/input-keys.c @@ -149,9 +149,25 @@ input_split2(u_int c, u_char *dst) return (1); } +/* Translate a key code into an output key sequence for a pane. */ +int +input_key_pane(struct window_pane *wp, key_code key, struct mouse_event *m) +{ + log_debug("writing key 0x%llx (%s) to %%%u", key, + key_string_lookup_key(key), wp->id); + + if (KEYC_IS_MOUSE(key)) { + if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) + input_key_mouse(wp, m); + return (0); + } + return (input_key(wp, wp->screen, wp->event, key)); +} + /* Translate a key code into an output key sequence. */ int -input_key(struct window_pane *wp, key_code key, struct mouse_event *m) +input_key(struct window_pane *wp, struct screen *s, struct bufferevent *bev, + key_code key) { const struct input_key_ent *ike; u_int i; @@ -160,20 +176,14 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) key_code justkey, newkey; struct utf8_data ud; - log_debug("writing key 0x%llx (%s) to %%%u", key, - key_string_lookup_key(key), wp->id); - - /* If this is a mouse key, pass off to mouse function. */ - if (KEYC_IS_MOUSE(key)) { - if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) - input_key_mouse(wp, m); + /* Mouse keys need a pane. */ + if (KEYC_IS_MOUSE(key)) return (0); - } /* Literal keys go as themselves (can't be more than eight bits). */ if (key & KEYC_LITERAL) { ud.data[0] = (u_char)key; - bufferevent_write(wp->event, &ud.data[0], 1); + bufferevent_write(bev, &ud.data[0], 1); return (0); } @@ -192,17 +202,17 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) justkey = (key & ~(KEYC_XTERM|KEYC_ESCAPE)); if (justkey <= 0x7f) { if (key & KEYC_ESCAPE) - bufferevent_write(wp->event, "\033", 1); + bufferevent_write(bev, "\033", 1); ud.data[0] = justkey; - bufferevent_write(wp->event, &ud.data[0], 1); + bufferevent_write(bev, &ud.data[0], 1); return (0); } if (justkey > 0x7f && justkey < KEYC_BASE) { if (utf8_split(justkey, &ud) != UTF8_DONE) return (-1); if (key & KEYC_ESCAPE) - bufferevent_write(wp->event, "\033", 1); - bufferevent_write(wp->event, ud.data, ud.size); + bufferevent_write(bev, "\033", 1); + bufferevent_write(bev, ud.data, ud.size); return (0); } @@ -210,9 +220,9 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) * Then try to look this up as an xterm key, if the flag to output them * is set. */ - if (options_get_number(wp->window->options, "xterm-keys")) { + if (wp == NULL || options_get_number(wp->window->options, "xterm-keys")) { if ((out = xterm_keys_lookup(key)) != NULL) { - bufferevent_write(wp->event, out, strlen(out)); + bufferevent_write(bev, out, strlen(out)); free(out); return (0); } @@ -223,11 +233,9 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) for (i = 0; i < nitems(input_keys); i++) { ike = &input_keys[i]; - if ((ike->flags & INPUTKEY_KEYPAD) && - !(wp->screen->mode & MODE_KKEYPAD)) + if ((ike->flags & INPUTKEY_KEYPAD) && (~s->mode & MODE_KKEYPAD)) continue; - if ((ike->flags & INPUTKEY_CURSOR) && - !(wp->screen->mode & MODE_KCURSOR)) + if ((ike->flags & INPUTKEY_CURSOR) && (~s->mode & MODE_KCURSOR)) continue; if ((key & KEYC_ESCAPE) && (ike->key | KEYC_ESCAPE) == key) @@ -244,8 +252,8 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m) /* Prefix a \033 for escape. */ if (key & KEYC_ESCAPE) - bufferevent_write(wp->event, "\033", 1); - bufferevent_write(wp->event, ike->data, dlen); + bufferevent_write(bev, "\033", 1); + bufferevent_write(bev, ike->data, dlen); return (0); } diff --git a/input.c b/input.c index 82d2b398..c7d67b82 100644 --- a/input.c +++ b/input.c @@ -128,7 +128,7 @@ struct input_transition; 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 window_pane *, +static void input_set_state(struct input_ctx *, const struct input_transition *); static void input_reset_cell(struct input_ctx *); @@ -731,10 +731,9 @@ static void input_timer_callback(__unused int fd, __unused short events, void *arg) { struct input_ctx *ictx = arg; - struct window_pane *wp = ictx->wp; - log_debug("%s: %%%u %s expired" , __func__, wp->id, ictx->state->name); - input_reset(wp, 0); + log_debug("%s: %s expired" , __func__, ictx->state->name); + input_reset(ictx, 0); } /* Start the timer. */ @@ -788,12 +787,13 @@ input_restore_state(struct input_ctx *ictx) } /* Initialise input parser. */ -void +struct input_ctx * input_init(struct window_pane *wp) { struct input_ctx *ictx; - ictx = wp->ictx = xcalloc(1, sizeof *ictx); + ictx = xcalloc(1, sizeof *ictx); + ictx->wp = wp; ictx->input_space = INPUT_BUF_START; ictx->input_buf = xmalloc(INPUT_BUF_START); @@ -804,15 +804,15 @@ input_init(struct window_pane *wp) evtimer_set(&ictx->timer, input_timer_callback, ictx); - input_reset(wp, 0); + input_reset(ictx, 0); + return (ictx); } /* Destroy input parser. */ void -input_free(struct window_pane *wp) +input_free(struct input_ctx *ictx) { - struct input_ctx *ictx = wp->ictx; - u_int i; + u_int i; for (i = 0; i < ictx->param_list_len; i++) { if (ictx->param_list[i].type == INPUT_STRING) @@ -825,19 +825,18 @@ input_free(struct window_pane *wp) evbuffer_free(ictx->since_ground); free(ictx); - wp->ictx = NULL; } /* Reset input state and clear screen. */ void -input_reset(struct window_pane *wp, int clear) +input_reset(struct input_ctx *ictx, int clear) { - struct input_ctx *ictx = wp->ictx; struct screen_write_ctx *sctx = &ictx->ctx; + struct window_pane *wp = ictx->wp; input_reset_cell(ictx); - if (clear) { + if (clear && wp != NULL) { if (TAILQ_EMPTY(&wp->modes)) screen_write_start(sctx, wp, &wp->base); else @@ -856,17 +855,15 @@ input_reset(struct window_pane *wp, int clear) /* Return pending data. */ struct evbuffer * -input_pending(struct window_pane *wp) +input_pending(struct input_ctx *ictx) { - return (wp->ictx->since_ground); + return (ictx->since_ground); } /* Change input state. */ static void -input_set_state(struct window_pane *wp, const struct input_transition *itr) +input_set_state(struct input_ctx *ictx, const struct input_transition *itr) { - struct input_ctx *ictx = wp->ictx; - if (ictx->state->exit != NULL) ictx->state->exit(ictx); ictx->state = itr->state; @@ -874,46 +871,15 @@ input_set_state(struct window_pane *wp, const struct input_transition *itr) ictx->state->enter(ictx); } -/* Parse input. */ -void -input_parse(struct window_pane *wp) +/* Parse data. */ +static void +input_parse(struct input_ctx *ictx, u_char *buf, size_t len) { - struct evbuffer *evb = wp->event->input; - - input_parse_buffer(wp, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb)); - evbuffer_drain(evb, EVBUFFER_LENGTH(evb)); -} - -/* Parse given input. */ -void -input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len) -{ - struct input_ctx *ictx = wp->ictx; struct screen_write_ctx *sctx = &ictx->ctx; const struct input_state *state = NULL; const struct input_transition *itr = NULL; size_t off = 0; - if (len == 0) - return; - - window_update_activity(wp->window); - wp->flags |= PANE_CHANGED; - notify_input(wp, buf, len); - - /* - * Open the screen. Use NULL wp if there is a mode set as don't want to - * update the tty. - */ - if (TAILQ_EMPTY(&wp->modes)) - screen_write_start(sctx, wp, &wp->base); - else - screen_write_start(sctx, NULL, &wp->base); - ictx->wp = wp; - - log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id, - ictx->state->name, len, (int)len, buf); - /* Parse the input. */ while (off < len) { ictx->ch = buf[off++]; @@ -956,14 +922,63 @@ input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len) /* And switch state, if necessary. */ if (itr->state != NULL) - input_set_state(wp, itr); + input_set_state(ictx, itr); /* If not in ground state, save input. */ if (ictx->state != &input_state_ground) evbuffer_add(ictx->since_ground, &ictx->ch, 1); } +} - /* Close the screen. */ +/* Parse input from pane. */ +void +input_parse_pane(struct window_pane *wp) +{ + struct evbuffer *evb = wp->event->input; + + input_parse_buffer(wp, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb)); + evbuffer_drain(evb, EVBUFFER_LENGTH(evb)); +} + +/* Parse given input. */ +void +input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len) +{ + struct input_ctx *ictx = wp->ictx; + struct screen_write_ctx *sctx = &ictx->ctx; + + if (len == 0) + return; + + window_update_activity(wp->window); + wp->flags |= PANE_CHANGED; + notify_input(wp, buf, len); + + /* NULL wp if there is a mode set as don't want to update the tty. */ + if (TAILQ_EMPTY(&wp->modes)) + screen_write_start(sctx, wp, &wp->base); + else + screen_write_start(sctx, NULL, &wp->base); + + log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id, + ictx->state->name, len, (int)len, buf); + + input_parse(ictx, buf, len); + screen_write_stop(sctx); +} + +/* Parse given input for screen. */ +void +input_parse_screen(struct input_ctx *ictx, struct screen *s, u_char *buf, + size_t len) +{ + struct screen_write_ctx *sctx = &ictx->ctx; + + if (len == 0) + return; + + screen_write_start(sctx, NULL, s); + input_parse(ictx, buf, len); screen_write_stop(sctx); } @@ -1043,14 +1058,18 @@ input_get(struct input_ctx *ictx, u_int validx, int minval, int defval) static void input_reply(struct input_ctx *ictx, const char *fmt, ...) { - va_list ap; - char *reply; + struct window_pane *wp = ictx->wp; + va_list ap; + char *reply; + + if (wp == NULL) + return; va_start(ap, fmt); xvasprintf(&reply, fmt, ap); va_end(ap); - bufferevent_write(ictx->wp->event, reply, strlen(reply)); + bufferevent_write(wp->event, reply, strlen(reply)); free(reply); } @@ -1177,7 +1196,8 @@ input_c0_dispatch(struct input_ctx *ictx) case '\000': /* NUL */ break; case '\007': /* BEL */ - alerts_queue(wp->window, WINDOW_BELL); + if (wp != NULL) + alerts_queue(wp->window, WINDOW_BELL); break; case '\010': /* BS */ screen_write_backspace(sctx); @@ -1224,6 +1244,7 @@ static int input_esc_dispatch(struct input_ctx *ictx) { struct screen_write_ctx *sctx = &ictx->ctx; + struct window_pane *wp = ictx->wp; struct screen *s = sctx->s; struct input_table_entry *entry; @@ -1240,7 +1261,8 @@ input_esc_dispatch(struct input_ctx *ictx) switch (entry->type) { case INPUT_ESC_RIS: - window_pane_reset_palette(ictx->wp); + if (wp != NULL) + window_pane_reset_palette(wp); input_reset_cell(ictx); screen_write_reset(sctx); break; @@ -1612,6 +1634,7 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx) { struct screen_write_ctx *sctx = &ictx->ctx; struct window_pane *wp = ictx->wp; + struct grid_cell *gc = &ictx->cell.cell; u_int i; for (i = 0; i < ictx->param_list_len; i++) { @@ -1623,7 +1646,7 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx) break; case 3: /* DECCOLM */ screen_write_cursormove(sctx, 0, 0, 1); - screen_write_clearscreen(sctx, ictx->cell.cell.bg); + screen_write_clearscreen(sctx, gc->bg); break; case 6: /* DECOM */ screen_write_mode_clear(sctx, MODE_ORIGIN); @@ -1655,10 +1678,12 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx) break; case 47: case 1047: - window_pane_alternate_off(wp, &ictx->cell.cell, 0); + if (wp != NULL) + window_pane_alternate_off(wp, gc, 0); break; case 1049: - window_pane_alternate_off(wp, &ictx->cell.cell, 1); + if (wp != NULL) + window_pane_alternate_off(wp, gc, 1); break; case 2004: screen_write_mode_clear(sctx, MODE_BRACKETPASTE); @@ -1700,6 +1725,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx) { struct screen_write_ctx *sctx = &ictx->ctx; struct window_pane *wp = ictx->wp; + struct grid_cell *gc = &ictx->cell.cell; u_int i; for (i = 0; i < ictx->param_list_len; i++) { @@ -1742,7 +1768,8 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx) if (sctx->s->mode & MODE_FOCUSON) break; screen_write_mode_set(sctx, MODE_FOCUSON); - wp->flags |= PANE_FOCUSPUSH; /* force update */ + if (wp != NULL) + wp->flags |= PANE_FOCUSPUSH; /* force update */ break; case 1005: screen_write_mode_set(sctx, MODE_MOUSE_UTF8); @@ -1752,10 +1779,12 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx) break; case 47: case 1047: - window_pane_alternate_on(wp, &ictx->cell.cell, 0); + if (wp != NULL) + window_pane_alternate_on(wp, gc, 0); break; case 1049: - window_pane_alternate_on(wp, &ictx->cell.cell, 1); + if (wp != NULL) + window_pane_alternate_on(wp, gc, 1); break; case 2004: screen_write_mode_set(sctx, MODE_BRACKETPASTE); @@ -1823,12 +1852,16 @@ input_csi_dispatch_winops(struct input_ctx *ictx) case 0: case 2: screen_pop_title(sctx->s); - server_status_window(ictx->wp->window); + if (wp != NULL) + server_status_window(wp->window); break; } break; case 18: - input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx); + if (wp != NULL) { + input_reply(ictx, "\033[8;%u;%ut", wp->sy, + wp->sx); + } break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); @@ -2193,6 +2226,7 @@ static void input_exit_osc(struct input_ctx *ictx) { struct screen_write_ctx *sctx = &ictx->ctx; + struct window_pane *wp = ictx->wp; u_char *p = ictx->input_buf; u_int option; @@ -2213,7 +2247,7 @@ input_exit_osc(struct input_ctx *ictx) switch (option) { case 0: case 2: - if (screen_set_title(sctx->s, p)) + if (screen_set_title(sctx->s, p) && wp != NULL) server_status_window(ictx->wp->window); break; case 4: @@ -2222,7 +2256,8 @@ input_exit_osc(struct input_ctx *ictx) case 7: if (utf8_isvalid(p)) { screen_set_path(sctx->s, p); - server_status_window(ictx->wp->window); + if (wp != NULL) + server_status_window(wp->window); } break; case 10: @@ -2267,13 +2302,14 @@ static void input_exit_apc(struct input_ctx *ictx) { struct screen_write_ctx *sctx = &ictx->ctx; + struct window_pane *wp = ictx->wp; if (ictx->flags & INPUT_DISCARD) return; log_debug("%s: \"%s\"", __func__, ictx->input_buf); - if (screen_set_title(sctx->s, ictx->input_buf)) - server_status_window(ictx->wp->window); + if (screen_set_title(sctx->s, ictx->input_buf) && wp != NULL) + server_status_window(wp->window); } /* Rename string started. */ @@ -2294,6 +2330,8 @@ input_exit_rename(struct input_ctx *ictx) struct window_pane *wp = ictx->wp; struct options_entry *oe; + if (wp == NULL) + return; if (ictx->flags & INPUT_DISCARD) return; if (!options_get_number(ictx->wp->options, "allow-rename")) @@ -2309,9 +2347,9 @@ input_exit_rename(struct input_ctx *ictx) options_remove(oe); return; } - window_set_name(ictx->wp->window, ictx->input_buf); - options_set_number(ictx->wp->window->options, "automatic-rename", 0); - server_status_window(ictx->wp->window); + window_set_name(wp->window, ictx->input_buf); + options_set_number(wp->window->options, "automatic-rename", 0); + server_status_window(wp->window); } /* Open UTF-8 character. */ @@ -2407,6 +2445,9 @@ input_osc_4(struct input_ctx *ictx, const char *p) long idx; u_int r, g, b; + if (wp == NULL) + return; + copy = s = xstrdup(p); while (s != NULL && *s != '\0') { idx = strtol(s, &next, 10); @@ -2441,6 +2482,8 @@ input_osc_10(struct input_ctx *ictx, const char *p) u_int r, g, b; char tmp[16]; + if (wp == NULL) + return; if (strcmp(p, "?") == 0) return; @@ -2465,6 +2508,8 @@ input_osc_11(struct input_ctx *ictx, const char *p) u_int r, g, b; char tmp[16]; + if (wp == NULL) + return; if (strcmp(p, "?") == 0) return; @@ -2494,6 +2539,8 @@ input_osc_52(struct input_ctx *ictx, const char *p) struct screen_write_ctx ctx; struct paste_buffer *pb; + if (wp == NULL) + return; state = options_get_number(global_options, "set-clipboard"); if (state != 2) return; @@ -2555,6 +2602,9 @@ input_osc_104(struct input_ctx *ictx, const char *p) char *copy, *s; long idx; + if (wp == NULL) + return; + if (*p == '\0') { window_pane_reset_palette(wp); return; diff --git a/spawn.c b/spawn.c index 9d2ccdf1..660ee47d 100644 --- a/spawn.c +++ b/spawn.c @@ -255,7 +255,8 @@ spawn_pane(struct spawn_context *sc, char **cause) } window_pane_reset_mode_all(sc->wp0); screen_reinit(&sc->wp0->base); - input_init(sc->wp0); + input_free(sc->wp0->ictx); + sc->wp0->ictx = input_init(sc->wp0); new_wp = sc->wp0; new_wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN); } else if (sc->lc == NULL) { diff --git a/tmux.h b/tmux.h index 043cb070..53372cfe 100644 --- a/tmux.h +++ b/tmux.h @@ -810,7 +810,6 @@ struct menu { u_int width; }; typedef void (*menu_choice_cb)(struct menu *, u_int, key_code, void *); -#define MENU_NOMOUSE 0x1 /* * Window mode. Windows can be in several modes and this is used to call the @@ -2288,15 +2287,19 @@ void recalculate_size(struct window *); void recalculate_sizes(void); /* input.c */ -void input_init(struct window_pane *); -void input_free(struct window_pane *); -void input_reset(struct window_pane *, int); -struct evbuffer *input_pending(struct window_pane *); -void input_parse(struct window_pane *); +struct input_ctx *input_init(struct window_pane *); +void input_free(struct input_ctx *); +void input_reset(struct input_ctx *, int); +struct evbuffer *input_pending(struct input_ctx *); +void input_parse_pane(struct window_pane *); void input_parse_buffer(struct window_pane *, u_char *, size_t); +void input_parse_screen(struct input_ctx *, struct screen *, u_char *, + size_t); /* input-key.c */ -int input_key(struct window_pane *, key_code, struct mouse_event *); +int input_key_pane(struct window_pane *, key_code, struct mouse_event *); +int input_key(struct window_pane *, struct screen *, struct bufferevent *, + key_code); /* xterm-keys.c */ char *xterm_keys_lookup(key_code); @@ -2731,6 +2734,7 @@ __dead void printflike(1, 2) fatal(const char *, ...); __dead void printflike(1, 2) fatalx(const char *, ...); /* menu.c */ +#define MENU_NOMOUSE 0x1 struct menu *menu_create(const char *); void menu_add_items(struct menu *, const struct menu_item *, struct cmdq_item *, struct client *, @@ -2738,7 +2742,6 @@ void menu_add_items(struct menu *, const struct menu_item *, void menu_add_item(struct menu *, const struct menu_item *, struct cmdq_item *, struct client *, struct cmd_find_state *); - void menu_free(struct menu *); int menu_display(struct menu *, int, struct cmdq_item *, u_int, u_int, struct client *, struct cmd_find_state *, diff --git a/window.c b/window.c index ab1d9217..754b9e59 100644 --- a/window.c +++ b/window.c @@ -891,7 +891,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) if (gethostname(host, sizeof host) == 0) screen_set_title(&wp->base, host); - input_init(wp); + wp->ictx = input_init(wp); return (wp); } @@ -907,7 +907,7 @@ window_pane_destroy(struct window_pane *wp) close(wp->fd); } - input_free(wp); + input_free(wp->ictx); screen_free(&wp->status_screen); @@ -949,7 +949,7 @@ window_pane_read_callback(__unused struct bufferevent *bufev, void *data) } log_debug("%%%u has %zu bytes", wp->id, size); - input_parse(wp); + input_parse_pane(wp); wp->pipe_off = EVBUFFER_LENGTH(evb); } @@ -1257,7 +1257,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s, if (wp->fd == -1 || wp->flags & PANE_INPUTOFF) return (0); - if (input_key(wp, key, m) != 0) + if (input_key_pane(wp, key, m) != 0) return (-1); if (KEYC_IS_MOUSE(key)) @@ -1269,7 +1269,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s, wp2->fd != -1 && (~wp2->flags & PANE_INPUTOFF) && window_pane_visible(wp2)) - input_key(wp2, key, NULL); + input_key_pane(wp2, key, NULL); } } return (0);