From 5d9e591ae8ebf60bdabd9535877af96ce1ca9980 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 2 May 2019 20:12:40 +0000 Subject: [PATCH 1/4] Fix up some bits about window-size that seem to have got lost. --- tmux.1 | 107 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 81 insertions(+), 26 deletions(-) diff --git a/tmux.1 b/tmux.1 index 80e51a69..5990c0c7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -206,7 +206,6 @@ and files in the current directory, where .Em PID is the PID of the server or client process. -.Pp If .Fl v is specified twice, an additional @@ -847,13 +846,22 @@ and are the name of and shell command to execute in the initial window. With .Fl d , -the initial size is 80 x 24; +the initial size comes from the global +.Ic default-size +option; .Fl x and .Fl y can be used to specify a different size. .Ql - uses the size of the current client if any. +If +.Fl x +or +.Fl y +is given, the +.Ic default-size +option is set for the session. .Pp If run from a terminal, any .Xr termios 4 @@ -931,6 +939,36 @@ If .Fl S is specified, only update the client's status line. .Pp +The +.Fl U , +.Fl D , +.Fl L +.Fl R , +and +.Fl c +flags allow the visible portion of a window which is larger than the client +to be changed. +.Fl U +moves the visible part up by +.Ar adjustment +rows and +.Fl D +down, +.Fl L +left by +.Ar adjustment +columns and +.Fl R +right. +.Fl c +returns to tracking the cursor automatically. +If +.Ar adjustment +is omitted, 1 is used. +Note that the visible position is a property of the client not of the +window, changing the current window in the attached session will reset +it. +.Pp .Fl C sets the width and height of a control client. .Fl l @@ -2783,9 +2821,15 @@ This option should be configured when .Nm is used as a login shell. .It Ic default-size Ar XxY -Set the default size of windows when the size is not set or the -.Ic window-size -option is manual. +Set the default size of new windows when the +.Ar window-size +option is set to manual or when a session is created with +.Ic new-session +.Fl d . +The value is the width and height separated by an +.Ql x +character. +The default is 80x24. .It Xo Ic destroy-unattached .Op Ic on | off .Xc @@ -3120,10 +3164,13 @@ Supported window options are: Aggressively resize the chosen window. This means that .Nm -will resize the window to the size of the smallest session for which it is the -current window, rather than the smallest session to which it is attached. -The window may resize when the current window is changed on another sessions; -this option is good for full-screen programs which support +will resize the window to the size of the smallest or largest session +(see the +.Ic window-size +option) for which it is the current window, rather than the session to +which it is attached. +The window may resize when the current window is changed on another +session; this option is good for full-screen programs which support .Dv SIGWINCH and poor for interactive programs such as shells. .Pp @@ -3365,6 +3412,28 @@ see the .Sx STYLES section. .Pp +.It Xo Ic window-size +.Ar largest | Ar smallest | Ar manual +.Xc +Configure how +.Nm +determines the window size. +If set to +.Ar largest , +the size of the largest attached session is used; if +.Ar smallest , +the size of the smallest. +If +.Ar manual , +the size of a new window is set from the +.Ic default-size +option and windows are resized automatically. +See also the +.Ic resize-window +command and the +.Ic aggressive-resize +option. +.Pp .It Ic window-style Ar style Set the default window style. For how to specify @@ -3373,21 +3442,6 @@ see the .Sx STYLES section. .Pp -.It Xo Ic window-size -.Op Ic smallest | largest | manual -.Xc -Tell -.Nm -how to automatically size windows either the size of the smallest session -containing the window, the size of the largest, or manual size. -See also the -.Ic resize-window -command and the -.Ic default-size -and -.Ic aggressive-resize -options. -.Pp .It Xo Ic wrap-search .Op Ic on | off .Xc @@ -3936,12 +3990,10 @@ The following variables are available, where appropriate: .It Li "session_group_size" Ta "" Ta "Size of session group" .It Li "session_group_list" Ta "" Ta "List of sessions in group" .It Li "session_grouped" Ta "" Ta "1 if session in a group" -.It Li "session_height" Ta "" Ta "Height of session" .It Li "session_id" Ta "" Ta "Unique session ID" .It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached" .It Li "session_name" Ta "#S" Ta "Name of session" .It Li "session_stack" Ta "" Ta "Window indexes in most recent order" -.It Li "session_width" Ta "" Ta "Width of session" .It Li "session_windows" Ta "" Ta "Number of windows in session" .It Li "socket_path" Ta "" Ta "Server socket path" .It Li "start_time" Ta "" Ta "Server start time" @@ -3949,6 +4001,7 @@ The following variables are available, where appropriate: .It Li "window_activity_flag" Ta "" Ta "1 if window has activity" .It Li "window_active" Ta "" Ta "1 if window active" .It Li "window_bell_flag" Ta "" Ta "1 if window has bell" +.It Li "window_bigger" Ta "" Ta "1 if window is larger than client" .It Li "window_end_flag" Ta "" Ta "1 if window has the highest index" .It Li "window_flags" Ta "#F" Ta "Window flags" .It Li "window_format" Ta "" Ta "1 if format is for a window (not assuming the current)" @@ -3959,6 +4012,8 @@ The following variables are available, where appropriate: .It Li "window_layout" Ta "" Ta "Window layout description, ignoring zoomed window panes" .It Li "window_linked" Ta "" Ta "1 if window is linked across sessions" .It Li "window_name" Ta "#W" Ta "Name of window" +.It Li "window_offset_x" Ta "" Ta "X offset into window if larger than client" +.It Li "window_offset_y" Ta "" Ta "Y offset into window if larger than client" .It Li "window_panes" Ta "" Ta "Number of panes in window" .It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert" .It Li "window_stack_index" Ta "" Ta "Index in session most recent stack" From 4bb48998e075017707b0fd8d61499409bd144c6d Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 3 May 2019 10:00:48 +0000 Subject: [PATCH 2/4] Fix reverse attribute in status line, GitHub issue 1709. --- status.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/status.c b/status.c index 89912114..332f8fd6 100644 --- a/status.c +++ b/status.c @@ -320,7 +320,7 @@ status_redraw(struct client *c) struct session *s = c->session; struct screen_write_ctx ctx; struct grid_cell gc; - u_int lines, i, width = c->tty.sx; + u_int lines, i, n, width = c->tty.sx; int flags, force = 0, changed = 0; struct options_entry *o; union options_value *ov; @@ -364,15 +364,17 @@ status_redraw(struct client *c) /* Write the status lines. */ o = options_get(s->options, "status-format"); - if (o == NULL) - screen_write_clearscreen(&ctx, gc.bg); - else { + if (o == NULL) { + for (n = 0; n < width * lines; n++) + screen_write_putc(&ctx, &gc, ' '); + } else { for (i = 0; i < lines; i++) { screen_write_cursormove(&ctx, 0, i, 0); ov = options_array_get(o, i); if (ov == NULL) { - screen_write_clearline(&ctx, gc.bg); + for (n = 0; n < width; n++) + screen_write_putc(&ctx, &gc, ' '); continue; } sle = &sl->entries[i]; @@ -386,7 +388,10 @@ status_redraw(struct client *c) } changed = 1; - screen_write_clearline(&ctx, gc.bg); + for (n = 0; n < width; n++) + screen_write_putc(&ctx, &gc, ' '); + screen_write_cursormove(&ctx, 0, i, 0); + status_free_ranges(&sle->ranges); format_draw(&ctx, &gc, width, expanded, &sle->ranges); From 33298d6df67e2ba3d90abdc94250eeaa963c3730 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 3 May 2019 14:51:30 +0000 Subject: [PATCH 3/4] Instead of processing keys all together, put them up on the client command queue so they are ordered correctly with the commands that they execute. --- server-client.c | 63 ++++++++++++++++++++++++++++++------------------- tmux.h | 13 +++++++--- tty-keys.c | 60 +++++++++++++++++++++++++++------------------- 3 files changed, 85 insertions(+), 51 deletions(-) diff --git a/server-client.c b/server-client.c index 4cd5be74..a3d6aebf 100644 --- a/server-client.c +++ b/server-client.c @@ -35,7 +35,7 @@ static void server_client_free(int, short, void *); static void server_client_check_focus(struct window_pane *); static void server_client_check_resize(struct window_pane *); -static key_code server_client_check_mouse(struct client *); +static key_code server_client_check_mouse(struct client *, struct key_event *); static void server_client_repeat_timer(int, short, void *); static void server_client_click_timer(int, short, void *); static void server_client_check_exit(struct client *); @@ -407,10 +407,10 @@ server_client_exec(struct client *c, const char *cmd) /* Check for mouse keys. */ static key_code -server_client_check_mouse(struct client *c) +server_client_check_mouse(struct client *c, struct key_event *event) { + struct mouse_event *m = &event->m; struct session *s = c->session; - struct mouse_event *m = &c->tty.mouse; struct winlink *wl; struct window_pane *wp; u_int x, y, b, sx, sy, px, py; @@ -419,7 +419,13 @@ server_client_check_mouse(struct client *c) struct timeval tv; struct style_range *sr; enum { NOTYPE, MOVE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type; - enum { NOWHERE, PANE, STATUS, STATUS_LEFT, STATUS_RIGHT, STATUS_DEFAULT, BORDER } where; + enum { NOWHERE, + PANE, + STATUS, + STATUS_LEFT, + STATUS_RIGHT, + STATUS_DEFAULT, + BORDER } where; type = NOTYPE; where = NOWHERE; @@ -976,11 +982,17 @@ server_client_assume_paste(struct session *s) return (0); } -/* Handle data key input from client. */ -void -server_client_handle_key(struct client *c, key_code key) +/* + * Handle data key input from client. This owns and can modify the key event it + * is given and is responsible for freeing it. + */ +enum cmd_retval +server_client_key_callback(struct cmdq_item *item, void *data) { - struct mouse_event *m = &c->tty.mouse; + struct client *c = item->client; + struct key_event *event = data; + key_code key = event->key; + struct mouse_event *m = &event->m; struct session *s = c->session; struct winlink *wl; struct window *w; @@ -995,7 +1007,7 @@ server_client_handle_key(struct client *c, key_code key) /* Check the client is good to accept input. */ if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) - return; + goto out; wl = s->curw; w = wl->window; @@ -1007,11 +1019,11 @@ server_client_handle_key(struct client *c, key_code key) /* Number keys jump to pane in identify mode. */ if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { if (c->flags & CLIENT_READONLY) - return; + goto out; window_unzoom(w); wp = window_pane_at_index(w, key - '0'); server_client_clear_identify(c, wp); - return; + goto out; } /* Handle status line. */ @@ -1021,19 +1033,19 @@ server_client_handle_key(struct client *c, key_code key) } if (c->prompt_string != NULL) { if (c->flags & CLIENT_READONLY) - return; + goto out; if (status_prompt_key(c, key) == 0) - return; + goto out; } /* Check for mouse keys. */ m->valid = 0; if (key == KEYC_MOUSE) { if (c->flags & CLIENT_READONLY) - return; - key = server_client_check_mouse(c); + goto out; + key = server_client_check_mouse(c, event); if (key == KEYC_UNKNOWN) - return; + goto out; m->valid = 1; m->key = key; @@ -1044,10 +1056,9 @@ server_client_handle_key(struct client *c, key_code key) */ if (key == KEYC_DRAGGING) { c->tty.mouse_drag_update(c, m); - return; + goto out; } - } else - m->valid = 0; + } /* Find affected pane. */ if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0) @@ -1086,7 +1097,7 @@ table_changed: strcmp(table->name, "prefix") != 0) { server_client_set_key_table(c, "prefix"); server_status_client(c); - return; + goto out; } flags = c->flags; @@ -1144,9 +1155,9 @@ try_again: server_status_client(c); /* Execute the key binding. */ - key_bindings_dispatch(bd, NULL, c, m, &fs); + key_bindings_dispatch(bd, item, c, m, &fs); key_bindings_unref_table(table); - return; + goto out; } /* @@ -1181,14 +1192,18 @@ try_again: if (first != table && (~flags & CLIENT_REPEAT)) { server_client_set_key_table(c, NULL); server_status_client(c); - return; + goto out; } forward_key: if (c->flags & CLIENT_READONLY) - return; + goto out; if (wp != NULL) window_pane_key(wp, c, s, wl, key, m); + +out: + free(event); + return (CMD_RETURN_NORMAL); } /* Client functions that need to happen every loop. */ diff --git a/tmux.h b/tmux.h index 0e79d429..4f69301f 100644 --- a/tmux.h +++ b/tmux.h @@ -1052,6 +1052,12 @@ struct mouse_event { u_int sgr_b; }; +/* Key event. */ +struct key_event { + key_code key; + struct mouse_event m; +}; + /* TTY information. */ struct tty_key { char ch; @@ -1143,7 +1149,8 @@ struct tty { TTY_UNKNOWN } term_type; - struct mouse_event mouse; + u_int mouse_last_x; + u_int mouse_last_y; int mouse_drag_flag; void (*mouse_drag_update)(struct client *, struct mouse_event *); @@ -1864,7 +1871,7 @@ const char *tty_acs_get(struct tty *, u_char); /* tty-keys.c */ void tty_keys_build(struct tty *); void tty_keys_free(struct tty *); -key_code tty_keys_next(struct tty *); +int tty_keys_next(struct tty *); /* arguments.c */ void args_set(struct args *, u_char, const char *); @@ -2002,7 +2009,7 @@ void server_client_set_identify(struct client *, u_int); void server_client_set_key_table(struct client *, const char *); const char *server_client_get_key_table(struct client *); int server_client_check_nested(struct client *); -void server_client_handle_key(struct client *, key_code); +enum cmd_retval server_client_key_callback(struct cmdq_item *, void *); struct client *server_client_create(int); int server_client_open(struct client *, char **); void server_client_unref(struct client *); diff --git a/tty-keys.c b/tty-keys.c index 850c9119..1aecbcb2 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -46,7 +46,8 @@ static struct tty_key *tty_keys_find(struct tty *, const char *, size_t, static int tty_keys_next1(struct tty *, const char *, size_t, key_code *, size_t *, int); static void tty_keys_callback(int, short, void *); -static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); +static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *, + struct mouse_event *); static int tty_keys_clipboard(struct tty *, const char *, size_t, size_t *); static int tty_keys_device_attributes(struct tty *, const char *, size_t, @@ -560,25 +561,26 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key, return (-1); } -/* - * Process at least one key in the buffer and invoke tty->key_callback. Return - * 0 if there are no further keys, or 1 if there could be more in the buffer. - */ -key_code +/* Process at least one key in the buffer. Return 0 if no keys present. */ +int tty_keys_next(struct tty *tty) { - struct client *c = tty->client; - struct timeval tv; - const char *buf; - size_t len, size; - cc_t bspace; - int delay, expired = 0, n; - key_code key; + struct client *c = tty->client; + struct timeval tv; + const char *buf; + size_t len, size; + cc_t bspace; + int delay, expired = 0, n; + key_code key; + struct cmdq_item *item; + struct mouse_event m = { 0 }; + struct key_event *event; + + gettimeofday(&tv, NULL); /* Get key buffer. */ buf = EVBUFFER_DATA(tty->in); len = EVBUFFER_LENGTH(tty->in); - if (len == 0) return (0); log_debug("%s: keys are %zu (%.*s)", c->name, len, (int)len, buf); @@ -606,7 +608,7 @@ tty_keys_next(struct tty *tty) } /* Is this a mouse key press? */ - switch (tty_keys_mouse(tty, buf, len, &size)) { + switch (tty_keys_mouse(tty, buf, len, &size, &m)) { case 0: /* yes */ key = KEYC_MOUSE; goto complete_key; @@ -725,8 +727,14 @@ complete_key: } /* Fire the key. */ - if (key != KEYC_UNKNOWN) - server_client_handle_key(tty->client, key); + if (key != KEYC_UNKNOWN) { + event = xmalloc(sizeof *event); + event->key = key; + memcpy(&event->m, &m, sizeof event->m); + + item = cmdq_get_callback(server_client_key_callback, event); + cmdq_append(c, item); + } return (1); @@ -756,12 +764,12 @@ tty_keys_callback(__unused int fd, __unused short events, void *data) * (probably a mouse sequence but need more data). */ static int -tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) +tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, + struct mouse_event *m) { - struct client *c = tty->client; - struct mouse_event *m = &tty->mouse; - u_int i, x, y, b, sgr_b; - u_char sgr_type, ch; + struct client *c = tty->client; + u_int i, x, y, b, sgr_b; + u_char sgr_type, ch; /* * Standard mouse sequences are \033[M followed by three characters @@ -882,15 +890,19 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) return (-1); /* Fill mouse event. */ - m->lx = m->x; + m->lx = tty->mouse_last_x; m->x = x; - m->ly = m->y; + m->ly = tty->mouse_last_y; m->y = y; m->lb = m->b; m->b = b; m->sgr_type = sgr_type; m->sgr_b = sgr_b; + /* Update last mouse state. */ + tty->mouse_last_x = x; + tty->mouse_last_y = y; + return (0); } From cf6075fb29fcd86f11a1f2cc6e906c62f39d4032 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 3 May 2019 15:43:01 +0000 Subject: [PATCH 4/4] Correct ordering when adding after an existing item. --- cmd-queue.c | 24 +++++++++--------------- tmux.h | 2 +- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/cmd-queue.c b/cmd-queue.c index 9ce25f5f..14d6a824 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -66,6 +66,7 @@ cmdq_append(struct client *c, struct cmdq_item *item) item->queue = queue; TAILQ_INSERT_TAIL(queue, item, entry); + log_debug("%s %s: %s", __func__, cmdq_name(c), item->name); item = next; } while (item != NULL); @@ -81,18 +82,17 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item) do { next = item->next; - item->next = NULL; + item->next = after->next; + after->next = item; if (c != NULL) c->references++; item->client = c; item->queue = queue; - if (after->next != NULL) - TAILQ_INSERT_AFTER(queue, after->next, item, entry); - else - TAILQ_INSERT_AFTER(queue, after, item, entry); - after->next = item; + TAILQ_INSERT_AFTER(queue, after, item, entry); + log_debug("%s %s: %s after %s", __func__, cmdq_name(c), + item->name, after->name); item = next; } while (item != NULL); @@ -170,7 +170,7 @@ cmdq_remove(struct cmdq_item *item) TAILQ_REMOVE(item->queue, item, entry); - free((void *)item->name); + free(item->name); free(item); } @@ -206,7 +206,6 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current, struct cmdq_item *item, *first = NULL, *last = NULL; struct cmd *cmd; u_int group = cmdq_next_group(); - char *tmp; struct cmdq_shared *shared; shared = xcalloc(1, sizeof *shared); @@ -218,10 +217,8 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current, memcpy(&shared->mouse, m, sizeof shared->mouse); TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { - xasprintf(&tmp, "command[%s]", cmd->entry->name); - item = xcalloc(1, sizeof *item); - item->name = tmp; + xasprintf(&item->name, "[%s/%p]", cmd->entry->name, item); item->type = CMDQ_COMMAND; item->group = group; @@ -316,12 +313,9 @@ struct cmdq_item * cmdq_get_callback1(const char *name, cmdq_cb cb, void *data) { struct cmdq_item *item; - char *tmp; - - xasprintf(&tmp, "callback[%s]", name); item = xcalloc(1, sizeof *item); - item->name = tmp; + xasprintf(&item->name, "[%s/%p]", name, item); item->type = CMDQ_CALLBACK; item->group = 0; diff --git a/tmux.h b/tmux.h index 4f69301f..e8d03c4b 100644 --- a/tmux.h +++ b/tmux.h @@ -1291,7 +1291,7 @@ struct cmdq_shared { /* Command queue item. */ typedef enum cmd_retval (*cmdq_cb) (struct cmdq_item *, void *); struct cmdq_item { - const char *name; + char *name; struct cmdq_list *queue; struct cmdq_item *next;