From 921be619303fdad6db3c46662fc0cde2903c9535 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 3 Feb 2022 11:06:11 +0000 Subject: [PATCH 01/40] Adjust size given to resize-pane for pane status line, GitHub issue 3050. --- cmd-resize-pane.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 81744f72..c9439441 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -60,7 +60,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) const char *errstr; char *cause; u_int adjust; - int x, y; + int x, y, status; struct grid *gd = wp->base.grid; if (args_has(args, 'T')) { @@ -121,6 +121,17 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) free(cause); return (CMD_RETURN_ERROR); } + status = options_get_number(w->options, "pane-border-status"); + switch (status) { + case PANE_STATUS_TOP: + if (y != INT_MAX && wp->yoff == 1) + y++; + break; + case PANE_STATUS_BOTTOM: + if (y != INT_MAX && wp->yoff + wp->sy == w->sy - 1) + y++; + break; + } layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y); } From 9efa4199554b4b5613a19bf5b4d9036869978b4c Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 4 Feb 2022 11:57:22 +0000 Subject: [PATCH 02/40] Use ACS for pane border indicators so they work with different line types, from Thomas Adam. --- screen-redraw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/screen-redraw.c b/screen-redraw.c index 8dd75f40..ef79d9aa 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -727,8 +727,10 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) border == SCREEN_REDRAW_BORDER_RIGHT) || (cell_type == CELL_RIGHTJOIN && border == SCREEN_REDRAW_BORDER_LEFT)))) && - screen_redraw_check_is(x, y, pane_status, active)) + screen_redraw_check_is(x, y, pane_status, active)) { + gc.attr |= GRID_ATTR_CHARSET; utf8_set(&gc.data, BORDER_MARKERS[border]); + } } tty_cell(tty, &gc, &grid_default_cell, NULL); From 2adbe3ec1606806e31c74507cfa0225327e27225 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 14 Feb 2022 09:10:48 +0000 Subject: [PATCH 03/40] Do not return error with -q, GitHub issue 3065. --- cmd-show-options.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd-show-options.c b/cmd-show-options.c index 90226ad3..252a33c6 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -102,7 +102,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) name = options_match(argument, &idx, &ambiguous); if (name == NULL) { if (args_has(args, 'q')) - goto fail; + goto out; if (ambiguous) cmdq_error(item, "ambiguous option: %s", argument); else @@ -113,7 +113,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) &cause); if (scope == OPTIONS_TABLE_NONE) { if (args_has(args, 'q')) - goto fail; + goto out; cmdq_error(item, "%s", cause); free(cause); goto fail; @@ -128,11 +128,12 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) cmd_show_options_print(self, item, o, idx, parent); else if (*name == '@') { if (args_has(args, 'q')) - goto fail; + goto out; cmdq_error(item, "invalid option: %s", argument); goto fail; } +out: free(name); free(argument); return (CMD_RETURN_NORMAL); From 190b88fcabc413485584bffed6d8ed8b61db1b1f Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 15 Feb 2022 13:03:02 +0000 Subject: [PATCH 04/40] Do not create a buffer from an OSC 52 response if we have not sent a query. --- cmd-refresh-client.c | 2 +- tmux.h | 4 +++- tty-keys.c | 5 +++++ tty.c | 27 ++++++++++++++++++++++++++- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 821558ae..2af9cb46 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -225,7 +225,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) } if (args_has(args, 'l')) { - tty_putcode_ptr2(&tc->tty, TTYC_MS, "", "?"); + tty_send_osc52_query(&tc->tty); return (CMD_RETURN_NORMAL); } diff --git a/tmux.h b/tmux.h index a4f484eb..313432e0 100644 --- a/tmux.h +++ b/tmux.h @@ -1278,6 +1278,7 @@ LIST_HEAD(tty_terms, tty_term); struct tty { struct client *client; struct event start_timer; + struct event query_timer; u_int sx; u_int sy; @@ -1321,7 +1322,7 @@ struct tty { #define TTY_NOBLOCK 0x8 #define TTY_STARTED 0x10 #define TTY_OPENED 0x20 -/* 0x40 unused */ +#define TTY_OSC52QUERY 0x40 #define TTY_BLOCK 0x80 #define TTY_HAVEDA 0x100 #define TTY_HAVEXDA 0x200 @@ -2174,6 +2175,7 @@ void tty_reset(struct tty *); void tty_region_off(struct tty *); void tty_margin_off(struct tty *); void tty_cursor(struct tty *, u_int, u_int); +void tty_send_osc52_query(struct tty *); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int); diff --git a/tty-keys.c b/tty-keys.c index 65b600c0..5d950078 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1217,6 +1217,11 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len, buf++; end--; + /* If we did not request this, ignore it. */ + if (~tty->flags & TTY_OSC52QUERY) + return (0); + tty->flags &= ~TTY_OSC52QUERY; + /* It has to be a string so copy it. */ copy = xmalloc(end + 1); memcpy(copy, buf, end); diff --git a/tty.c b/tty.c index 8410a64c..06b1bfb2 100644 --- a/tty.c +++ b/tty.c @@ -83,6 +83,8 @@ static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int, #define TTY_BLOCK_START(tty) (1 + ((tty)->sx * (tty)->sy) * 8) #define TTY_BLOCK_STOP(tty) (1 + ((tty)->sx * (tty)->sy) / 8) +#define TTY_QUERY_TIMEOUT 5 + void tty_create_log(void) { @@ -307,7 +309,7 @@ tty_start_tty(struct tty *tty) { struct client *c = tty->client; struct termios tio; - struct timeval tv = { .tv_sec = 3 }; + struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; setblocking(c->fd, 0); event_add(&tty->event_in, NULL); @@ -2917,3 +2919,26 @@ tty_default_attributes(struct tty *tty, const struct grid_cell *defaults, gc.bg = bg; tty_attributes(tty, &gc, defaults, palette); } + +static void +tty_query_timer_callback(__unused int fd, __unused short events, void *data) +{ + struct tty *tty = data; + + tty->flags &= ~TTY_OSC52QUERY; +} + +void +tty_send_osc52_query(struct tty *tty) +{ + struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; + + if ((~tty->flags & TTY_STARTED) || (tty->flags & TTY_OSC52QUERY)) + return; + tty_putcode_ptr2(tty, TTYC_MS, "", "?"); + tty->flags |= TTY_OSC52QUERY; + + evtimer_set(&tty->query_timer, tty_query_timer_callback, tty); + evtimer_add(&tty->query_timer, &tv); +} + From eabbc80b75ef8e02653c2728d7f646fc6a8f558f Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 15 Feb 2022 13:11:29 +0000 Subject: [PATCH 05/40] Add an option (default off) to control the passthrough escape sequence. Like set-clipboard and allow-rename it is safer to forbid this by default. --- input.c | 6 +++++- options-table.c | 20 ++++++++++++++------ tmux.1 | 7 +++++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/input.c b/input.c index 16f31ad7..5adc694d 100644 --- a/input.c +++ b/input.c @@ -2235,15 +2235,19 @@ input_enter_dcs(struct input_ctx *ictx) static int input_dcs_dispatch(struct input_ctx *ictx) { + struct window_pane *wp = ictx->wp; struct screen_write_ctx *sctx = &ictx->ctx; u_char *buf = ictx->input_buf; size_t len = ictx->input_len; const char prefix[] = "tmux;"; const u_int prefixlen = (sizeof prefix) - 1; + if (wp == NULL) + return (0); if (ictx->flags & INPUT_DISCARD) return (0); - + if (!options_get_number(ictx->wp->options, "allow-passthrough")) + return (0); log_debug("%s: \"%s\"", __func__, buf); if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0) diff --git a/options-table.c b/options-table.c index 94f8701e..c8ae046e 100644 --- a/options-table.c +++ b/options-table.c @@ -301,7 +301,7 @@ const struct options_table_entry options_table[] = { .choices = options_table_extended_keys_list, .default_num = 0, .text = "Whether to request extended key sequences from terminals " - "that support it." + "that support it." }, { .name = "focus-events", @@ -800,6 +800,14 @@ const struct options_table_entry options_table[] = { "linked to ('off')." }, + { .name = "allow-passthrough", + .type = OPTIONS_TABLE_FLAG, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .default_num = 0, + .text = "Whether applications are allowed to use the escape sequence " + "to bypass tmux." + }, + { .name = "allow-rename", .type = OPTIONS_TABLE_FLAG, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, @@ -988,7 +996,7 @@ const struct options_table_entry options_table[] = { .choices = options_table_pane_border_lines_list, .default_num = PANE_LINES_SINGLE, .text = "Type of characters used to draw pane border lines. Some of " - "these are only supported on terminals with UTF-8 support." + "these are only supported on terminals with UTF-8 support." }, { .name = "pane-border-status", @@ -1040,7 +1048,7 @@ const struct options_table_entry options_table[] = { .choices = options_table_popup_border_lines_list, .default_num = BOX_LINES_SINGLE, .text = "Type of characters used to draw popup border lines. Some of " - "these are only supported on terminals with UTF-8 support." + "these are only supported on terminals with UTF-8 support." }, { .name = "remain-on-exit", @@ -1170,7 +1178,7 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_WINDOW, .default_num = 1, .text = "Whether xterm-style function key sequences should be sent. " - "This option is no longer used." + "This option is no longer used." }, /* Hook options. */ @@ -1218,8 +1226,8 @@ const struct options_table_entry options_table[] = { OPTIONS_TABLE_HOOK("client-active", ""), OPTIONS_TABLE_HOOK("client-attached", ""), OPTIONS_TABLE_HOOK("client-detached", ""), - OPTIONS_TABLE_HOOK("client-focus-in", ""), - OPTIONS_TABLE_HOOK("client-focus-out", ""), + OPTIONS_TABLE_HOOK("client-focus-in", ""), + OPTIONS_TABLE_HOOK("client-focus-out", ""), OPTIONS_TABLE_HOOK("client-resized", ""), OPTIONS_TABLE_HOOK("client-session-changed", ""), OPTIONS_TABLE_PANE_HOOK("pane-died", ""), diff --git a/tmux.1 b/tmux.1 index 638c3232..2128f81a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4406,6 +4406,13 @@ The default is on. Available pane options are: .Pp .Bl -tag -width Ds -compact +.It Xo Ic allow-passthrough +.Op Ic on | off +.Xc +Allow programs in the pane to bypass +.Nm +using a terminal escape sequence (\eePtmux;...\ee\e\e). +.Pp .It Xo Ic allow-rename .Op Ic on | off .Xc From 7f40c5b647241e0ac3c71c3c95a8cc33790e707e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 16 Feb 2022 12:26:23 +0000 Subject: [PATCH 06/40] No not allow static linking on macOS. --- configure.ac | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index c71a54b0..fb0ee239 100644 --- a/configure.ac +++ b/configure.ac @@ -69,6 +69,11 @@ AC_ARG_ENABLE( AS_HELP_STRING(--enable-static, create a static build) ) if test "x$enable_static" = xyes; then + case "$host_os" in + *darwin*) + AC_MSG_ERROR([static linking is not supported on macOS]) + ;; + esac test "x$PKG_CONFIG" != x && PKG_CONFIG="$PKG_CONFIG --static" AM_LDFLAGS="-static $AM_LDFLAGS" LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS" From 6a0a783c268b00df165b115d915b628e36a0f69b Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 16 Feb 2022 18:55:05 +0000 Subject: [PATCH 07/40] Support more mouse buttons when the terminal sends them, GitHub issue 3055. --- input-keys.c | 6 +- key-string.c | 42 ++++ menu.c | 6 +- popup.c | 8 +- server-client.c | 640 ++++++++++++++++++++++++++++++++++++++++++++++-- tmux.h | 66 ++++- tty-keys.c | 4 +- 7 files changed, 728 insertions(+), 44 deletions(-) diff --git a/input-keys.c b/input-keys.c index b4770808..47614aa0 100644 --- a/input-keys.c +++ b/input-keys.c @@ -577,13 +577,13 @@ input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y, */ if (m->sgr_type != ' ') { if (MOUSE_DRAG(m->sgr_b) && - MOUSE_BUTTONS(m->sgr_b) == 3 && + MOUSE_RELEASE(m->sgr_b) && (~s->mode & MODE_MOUSE_ALL)) return (0); } else { if (MOUSE_DRAG(m->b) && - MOUSE_BUTTONS(m->b) == 3 && - MOUSE_BUTTONS(m->lb) == 3 && + MOUSE_RELEASE(m->b) && + MOUSE_RELEASE(m->lb) && (~s->mode & MODE_MOUSE_ALL)) return (0); } diff --git a/key-string.c b/key-string.c index 4f7be858..0ca91306 100644 --- a/key-string.c +++ b/key-string.c @@ -91,26 +91,68 @@ static const struct { KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1), KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2), KEYC_MOUSE_STRING(MOUSEDOWN3, MouseDown3), + KEYC_MOUSE_STRING(MOUSEDOWN6, MouseDown6), + KEYC_MOUSE_STRING(MOUSEDOWN7, MouseDown7), + KEYC_MOUSE_STRING(MOUSEDOWN8, MouseDown8), + KEYC_MOUSE_STRING(MOUSEDOWN9, MouseDown9), + KEYC_MOUSE_STRING(MOUSEDOWN10, MouseDown10), + KEYC_MOUSE_STRING(MOUSEDOWN11, MouseDown11), KEYC_MOUSE_STRING(MOUSEUP1, MouseUp1), KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2), KEYC_MOUSE_STRING(MOUSEUP3, MouseUp3), + KEYC_MOUSE_STRING(MOUSEUP6, MouseUp6), + KEYC_MOUSE_STRING(MOUSEUP7, MouseUp7), + KEYC_MOUSE_STRING(MOUSEUP8, MouseUp8), + KEYC_MOUSE_STRING(MOUSEUP9, MouseUp9), + KEYC_MOUSE_STRING(MOUSEUP10, MouseUp10), + KEYC_MOUSE_STRING(MOUSEUP11, MouseUp11), KEYC_MOUSE_STRING(MOUSEDRAG1, MouseDrag1), KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2), KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3), + KEYC_MOUSE_STRING(MOUSEDRAG6, MouseDrag6), + KEYC_MOUSE_STRING(MOUSEDRAG7, MouseDrag7), + KEYC_MOUSE_STRING(MOUSEDRAG8, MouseDrag8), + KEYC_MOUSE_STRING(MOUSEDRAG9, MouseDrag9), + KEYC_MOUSE_STRING(MOUSEDRAG10, MouseDrag10), + KEYC_MOUSE_STRING(MOUSEDRAG11, MouseDrag11), KEYC_MOUSE_STRING(MOUSEDRAGEND1, MouseDragEnd1), KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2), KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3), + KEYC_MOUSE_STRING(MOUSEDRAGEND6, MouseDragEnd6), + KEYC_MOUSE_STRING(MOUSEDRAGEND7, MouseDragEnd7), + KEYC_MOUSE_STRING(MOUSEDRAGEND8, MouseDragEnd8), + KEYC_MOUSE_STRING(MOUSEDRAGEND9, MouseDragEnd9), + KEYC_MOUSE_STRING(MOUSEDRAGEND10, MouseDragEnd10), + KEYC_MOUSE_STRING(MOUSEDRAGEND11, MouseDragEnd11), KEYC_MOUSE_STRING(WHEELUP, WheelUp), KEYC_MOUSE_STRING(WHEELDOWN, WheelDown), KEYC_MOUSE_STRING(SECONDCLICK1, SecondClick1), KEYC_MOUSE_STRING(SECONDCLICK2, SecondClick2), KEYC_MOUSE_STRING(SECONDCLICK3, SecondClick3), + KEYC_MOUSE_STRING(SECONDCLICK6, SecondClick6), + KEYC_MOUSE_STRING(SECONDCLICK7, SecondClick7), + KEYC_MOUSE_STRING(SECONDCLICK8, SecondClick8), + KEYC_MOUSE_STRING(SECONDCLICK9, SecondClick9), + KEYC_MOUSE_STRING(SECONDCLICK10, SecondClick10), + KEYC_MOUSE_STRING(SECONDCLICK11, SecondClick11), KEYC_MOUSE_STRING(DOUBLECLICK1, DoubleClick1), KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2), KEYC_MOUSE_STRING(DOUBLECLICK3, DoubleClick3), + KEYC_MOUSE_STRING(DOUBLECLICK6, DoubleClick6), + KEYC_MOUSE_STRING(DOUBLECLICK7, DoubleClick7), + KEYC_MOUSE_STRING(DOUBLECLICK8, DoubleClick8), + KEYC_MOUSE_STRING(DOUBLECLICK9, DoubleClick9), + KEYC_MOUSE_STRING(DOUBLECLICK10, DoubleClick10), + KEYC_MOUSE_STRING(DOUBLECLICK11, DoubleClick11), KEYC_MOUSE_STRING(TRIPLECLICK1, TripleClick1), KEYC_MOUSE_STRING(TRIPLECLICK2, TripleClick2), KEYC_MOUSE_STRING(TRIPLECLICK3, TripleClick3), + KEYC_MOUSE_STRING(TRIPLECLICK6, TripleClick6), + KEYC_MOUSE_STRING(TRIPLECLICK7, TripleClick7), + KEYC_MOUSE_STRING(TRIPLECLICK8, TripleClick8), + KEYC_MOUSE_STRING(TRIPLECLICK9, TripleClick9), + KEYC_MOUSE_STRING(TRIPLECLICK10, TripleClick10), + KEYC_MOUSE_STRING(TRIPLECLICK11, TripleClick11) }; /* Find key string in table. */ diff --git a/menu.c b/menu.c index aaa1287e..c17d10b1 100644 --- a/menu.c +++ b/menu.c @@ -235,7 +235,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) if (KEYC_IS_MOUSE(event->key)) { if (md->flags & MENU_NOMOUSE) { - if (MOUSE_BUTTONS(m->b) != 0) + if (MOUSE_BUTTONS(m->b) != MOUSE_BUTTON_1) return (1); return (0); } @@ -248,7 +248,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) return (1); } else { if (!MOUSE_RELEASE(m->b) && - MOUSE_WHEEL(m->b) == 0 && + !MOUSE_WHEEL(m->b) && !MOUSE_DRAG(m->b)) return (1); } @@ -262,7 +262,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event) if (MOUSE_RELEASE(m->b)) goto chosen; } else { - if (MOUSE_WHEEL(m->b) == 0 && !MOUSE_DRAG(m->b)) + if (!MOUSE_WHEEL(m->b) && !MOUSE_DRAG(m->b)) goto chosen; } md->choice = m->y - (md->py + 1); diff --git a/popup.c b/popup.c index 1048af60..5522df3e 100644 --- a/popup.c +++ b/popup.c @@ -508,7 +508,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) m->x > pd->px + pd->sx - 1 || m->y < pd->py || m->y > pd->py + pd->sy - 1) { - if (MOUSE_BUTTONS(m->b) == 2) + if (MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3) goto menu; return (0); } @@ -523,16 +523,16 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) border = BOTTOM; } if ((m->b & MOUSE_MASK_MODIFIERS) == 0 && - MOUSE_BUTTONS(m->b) == 2 && + MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3 && (border == LEFT || border == TOP)) goto menu; if (((m->b & MOUSE_MASK_MODIFIERS) == MOUSE_MASK_META) || border != NONE) { if (!MOUSE_DRAG(m->b)) goto out; - if (MOUSE_BUTTONS(m->lb) == 0) + if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_1) pd->dragging = MOVE; - else if (MOUSE_BUTTONS(m->lb) == 2) + else if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_3) pd->dragging = SIZE; pd->dx = m->lx - pd->px; pd->dy = m->ly - pd->py; diff --git a/server-client.c b/server-client.c index 06154be7..0f043796 100644 --- a/server-client.c +++ b/server-client.c @@ -593,11 +593,11 @@ server_client_check_mouse(struct client *c, struct key_event *event) log_debug("double-click at %u,%u", x, y); } else if ((m->sgr_type != ' ' && MOUSE_DRAG(m->sgr_b) && - MOUSE_BUTTONS(m->sgr_b) == 3) || + MOUSE_RELEASE(m->sgr_b)) || (m->sgr_type == ' ' && MOUSE_DRAG(m->b) && - MOUSE_BUTTONS(m->b) == 3 && - MOUSE_BUTTONS(m->lb) == 3)) { + MOUSE_RELEASE(m->b) && + MOUSE_RELEASE(m->lb))) { type = MOVE; x = m->x, y = m->y, b = 0; log_debug("move at %u,%u", x, y); @@ -750,7 +750,7 @@ have_event: m->wp = -1; /* Stop dragging if needed. */ - if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag) { + if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag != 0) { if (c->tty.mouse_drag_release != NULL) c->tty.mouse_drag_release(c, m); @@ -761,8 +761,8 @@ have_event: * End a mouse drag by passing a MouseDragEnd key corresponding * to the button that started the drag. */ - switch (c->tty.mouse_drag_flag) { - case 1: + switch (c->tty.mouse_drag_flag - 1) { + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_MOUSEDRAGEND1_PANE; if (where == STATUS) @@ -776,7 +776,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAGEND1_BORDER; break; - case 2: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_MOUSEDRAGEND2_PANE; if (where == STATUS) @@ -790,7 +790,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAGEND2_BORDER; break; - case 3: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_MOUSEDRAGEND3_PANE; if (where == STATUS) @@ -804,6 +804,90 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAGEND3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_MOUSEDRAGEND6_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_MOUSEDRAGEND7_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_MOUSEDRAGEND8_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_MOUSEDRAGEND9_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_MOUSEDRAGEND10_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_MOUSEDRAGEND11_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAGEND11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAGEND11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAGEND11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAGEND11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAGEND11_BORDER; + break; default: key = KEYC_MOUSE; break; @@ -836,7 +920,7 @@ have_event: key = KEYC_DRAGGING; else { switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_MOUSEDRAG1_PANE; if (where == STATUS) @@ -850,7 +934,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAG1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_MOUSEDRAG2_PANE; if (where == STATUS) @@ -864,7 +948,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAG2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_MOUSEDRAG3_PANE; if (where == STATUS) @@ -878,6 +962,90 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDRAG3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_MOUSEDRAG6_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_MOUSEDRAG7_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_MOUSEDRAG8_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_MOUSEDRAG9_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_MOUSEDRAG10_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_MOUSEDRAG11_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDRAG11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDRAG11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDRAG11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDRAG11_BORDER; + break; } } @@ -918,7 +1086,7 @@ have_event: break; case UP: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_MOUSEUP1_PANE; if (where == STATUS) @@ -932,7 +1100,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEUP1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_MOUSEUP2_PANE; if (where == STATUS) @@ -946,7 +1114,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEUP2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_MOUSEUP3_PANE; if (where == STATUS) @@ -960,11 +1128,95 @@ have_event: if (where == BORDER) key = KEYC_MOUSEUP3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_MOUSEUP6_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_MOUSEUP7_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_MOUSEUP8_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_MOUSEUP9_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_MOUSEUP1_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP1_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP1_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP1_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP1_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP1_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_MOUSEUP11_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEUP11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEUP11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEUP11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEUP11_BORDER; + break; } break; case DOWN: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_MOUSEDOWN1_PANE; if (where == STATUS) @@ -978,7 +1230,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDOWN1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_MOUSEDOWN2_PANE; if (where == STATUS) @@ -992,7 +1244,7 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDOWN2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_MOUSEDOWN3_PANE; if (where == STATUS) @@ -1006,11 +1258,95 @@ have_event: if (where == BORDER) key = KEYC_MOUSEDOWN3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_MOUSEDOWN6_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_MOUSEDOWN7_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_MOUSEDOWN8_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_MOUSEDOWN9_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_MOUSEDOWN10_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_MOUSEDOWN11_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_MOUSEDOWN11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_MOUSEDOWN11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_MOUSEDOWN11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_MOUSEDOWN11_BORDER; + break; } break; case SECOND: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_SECONDCLICK1_PANE; if (where == STATUS) @@ -1024,7 +1360,7 @@ have_event: if (where == BORDER) key = KEYC_SECONDCLICK1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_SECONDCLICK2_PANE; if (where == STATUS) @@ -1038,7 +1374,7 @@ have_event: if (where == BORDER) key = KEYC_SECONDCLICK2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_SECONDCLICK3_PANE; if (where == STATUS) @@ -1052,11 +1388,95 @@ have_event: if (where == BORDER) key = KEYC_SECONDCLICK3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_SECONDCLICK6_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_SECONDCLICK7_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_SECONDCLICK8_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_SECONDCLICK9_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_SECONDCLICK10_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_SECONDCLICK11_PANE; + if (where == STATUS) + key = KEYC_SECONDCLICK11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_SECONDCLICK11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_SECONDCLICK11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_SECONDCLICK11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_SECONDCLICK11_BORDER; + break; } break; case DOUBLE: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_DOUBLECLICK1_PANE; if (where == STATUS) @@ -1070,7 +1490,7 @@ have_event: if (where == BORDER) key = KEYC_DOUBLECLICK1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_DOUBLECLICK2_PANE; if (where == STATUS) @@ -1084,7 +1504,7 @@ have_event: if (where == BORDER) key = KEYC_DOUBLECLICK2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_DOUBLECLICK3_PANE; if (where == STATUS) @@ -1098,11 +1518,95 @@ have_event: if (where == BORDER) key = KEYC_DOUBLECLICK3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_DOUBLECLICK6_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_DOUBLECLICK7_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_DOUBLECLICK8_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_DOUBLECLICK9_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_DOUBLECLICK10_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_DOUBLECLICK11_PANE; + if (where == STATUS) + key = KEYC_DOUBLECLICK11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_DOUBLECLICK11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_DOUBLECLICK11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_DOUBLECLICK11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_DOUBLECLICK11_BORDER; + break; } break; case TRIPLE: switch (MOUSE_BUTTONS(b)) { - case 0: + case MOUSE_BUTTON_1: if (where == PANE) key = KEYC_TRIPLECLICK1_PANE; if (where == STATUS) @@ -1116,7 +1620,7 @@ have_event: if (where == BORDER) key = KEYC_TRIPLECLICK1_BORDER; break; - case 1: + case MOUSE_BUTTON_2: if (where == PANE) key = KEYC_TRIPLECLICK2_PANE; if (where == STATUS) @@ -1130,7 +1634,7 @@ have_event: if (where == BORDER) key = KEYC_TRIPLECLICK2_BORDER; break; - case 2: + case MOUSE_BUTTON_3: if (where == PANE) key = KEYC_TRIPLECLICK3_PANE; if (where == STATUS) @@ -1144,6 +1648,90 @@ have_event: if (where == BORDER) key = KEYC_TRIPLECLICK3_BORDER; break; + case MOUSE_BUTTON_6: + if (where == PANE) + key = KEYC_TRIPLECLICK6_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK6_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK6_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK6_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK6_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK6_BORDER; + break; + case MOUSE_BUTTON_7: + if (where == PANE) + key = KEYC_TRIPLECLICK7_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK7_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK7_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK7_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK7_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK7_BORDER; + break; + case MOUSE_BUTTON_8: + if (where == PANE) + key = KEYC_TRIPLECLICK8_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK8_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK8_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK8_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK8_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK8_BORDER; + break; + case MOUSE_BUTTON_9: + if (where == PANE) + key = KEYC_TRIPLECLICK9_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK9_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK9_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK9_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK9_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK9_BORDER; + break; + case MOUSE_BUTTON_10: + if (where == PANE) + key = KEYC_TRIPLECLICK10_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK10_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK10_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK10_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK10_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK10_BORDER; + break; + case MOUSE_BUTTON_11: + if (where == PANE) + key = KEYC_TRIPLECLICK11_PANE; + if (where == STATUS) + key = KEYC_TRIPLECLICK11_STATUS; + if (where == STATUS_LEFT) + key = KEYC_TRIPLECLICK11_STATUS_LEFT; + if (where == STATUS_RIGHT) + key = KEYC_TRIPLECLICK11_STATUS_RIGHT; + if (where == STATUS_DEFAULT) + key = KEYC_TRIPLECLICK11_STATUS_DEFAULT; + if (where == BORDER) + key = KEYC_TRIPLECLICK11_BORDER; + break; } break; } diff --git a/tmux.h b/tmux.h index 313432e0..f172ba1a 100644 --- a/tmux.h +++ b/tmux.h @@ -202,26 +202,68 @@ enum { KEYC_MOUSE_KEY(MOUSEDOWN1), KEYC_MOUSE_KEY(MOUSEDOWN2), KEYC_MOUSE_KEY(MOUSEDOWN3), + KEYC_MOUSE_KEY(MOUSEDOWN6), + KEYC_MOUSE_KEY(MOUSEDOWN7), + KEYC_MOUSE_KEY(MOUSEDOWN8), + KEYC_MOUSE_KEY(MOUSEDOWN9), + KEYC_MOUSE_KEY(MOUSEDOWN10), + KEYC_MOUSE_KEY(MOUSEDOWN11), KEYC_MOUSE_KEY(MOUSEUP1), KEYC_MOUSE_KEY(MOUSEUP2), KEYC_MOUSE_KEY(MOUSEUP3), + KEYC_MOUSE_KEY(MOUSEUP6), + KEYC_MOUSE_KEY(MOUSEUP7), + KEYC_MOUSE_KEY(MOUSEUP8), + KEYC_MOUSE_KEY(MOUSEUP9), + KEYC_MOUSE_KEY(MOUSEUP10), + KEYC_MOUSE_KEY(MOUSEUP11), KEYC_MOUSE_KEY(MOUSEDRAG1), KEYC_MOUSE_KEY(MOUSEDRAG2), KEYC_MOUSE_KEY(MOUSEDRAG3), + KEYC_MOUSE_KEY(MOUSEDRAG6), + KEYC_MOUSE_KEY(MOUSEDRAG7), + KEYC_MOUSE_KEY(MOUSEDRAG8), + KEYC_MOUSE_KEY(MOUSEDRAG9), + KEYC_MOUSE_KEY(MOUSEDRAG10), + KEYC_MOUSE_KEY(MOUSEDRAG11), KEYC_MOUSE_KEY(MOUSEDRAGEND1), KEYC_MOUSE_KEY(MOUSEDRAGEND2), KEYC_MOUSE_KEY(MOUSEDRAGEND3), + KEYC_MOUSE_KEY(MOUSEDRAGEND6), + KEYC_MOUSE_KEY(MOUSEDRAGEND7), + KEYC_MOUSE_KEY(MOUSEDRAGEND8), + KEYC_MOUSE_KEY(MOUSEDRAGEND9), + KEYC_MOUSE_KEY(MOUSEDRAGEND10), + KEYC_MOUSE_KEY(MOUSEDRAGEND11), KEYC_MOUSE_KEY(WHEELUP), KEYC_MOUSE_KEY(WHEELDOWN), KEYC_MOUSE_KEY(SECONDCLICK1), KEYC_MOUSE_KEY(SECONDCLICK2), KEYC_MOUSE_KEY(SECONDCLICK3), + KEYC_MOUSE_KEY(SECONDCLICK6), + KEYC_MOUSE_KEY(SECONDCLICK7), + KEYC_MOUSE_KEY(SECONDCLICK8), + KEYC_MOUSE_KEY(SECONDCLICK9), + KEYC_MOUSE_KEY(SECONDCLICK10), + KEYC_MOUSE_KEY(SECONDCLICK11), KEYC_MOUSE_KEY(DOUBLECLICK1), KEYC_MOUSE_KEY(DOUBLECLICK2), KEYC_MOUSE_KEY(DOUBLECLICK3), + KEYC_MOUSE_KEY(DOUBLECLICK6), + KEYC_MOUSE_KEY(DOUBLECLICK7), + KEYC_MOUSE_KEY(DOUBLECLICK8), + KEYC_MOUSE_KEY(DOUBLECLICK9), + KEYC_MOUSE_KEY(DOUBLECLICK10), + KEYC_MOUSE_KEY(DOUBLECLICK11), KEYC_MOUSE_KEY(TRIPLECLICK1), KEYC_MOUSE_KEY(TRIPLECLICK2), KEYC_MOUSE_KEY(TRIPLECLICK3), + KEYC_MOUSE_KEY(TRIPLECLICK6), + KEYC_MOUSE_KEY(TRIPLECLICK7), + KEYC_MOUSE_KEY(TRIPLECLICK8), + KEYC_MOUSE_KEY(TRIPLECLICK9), + KEYC_MOUSE_KEY(TRIPLECLICK10), + KEYC_MOUSE_KEY(TRIPLECLICK11), /* Backspace key. */ KEYC_BSPACE, @@ -1199,21 +1241,33 @@ struct session { RB_HEAD(sessions, session); /* Mouse button masks. */ -#define MOUSE_MASK_BUTTONS 3 +#define MOUSE_MASK_BUTTONS 195 #define MOUSE_MASK_SHIFT 4 #define MOUSE_MASK_META 8 #define MOUSE_MASK_CTRL 16 #define MOUSE_MASK_DRAG 32 -#define MOUSE_MASK_WHEEL 64 #define MOUSE_MASK_MODIFIERS (MOUSE_MASK_SHIFT|MOUSE_MASK_META|MOUSE_MASK_CTRL) -/* Mouse wheel states. */ -#define MOUSE_WHEEL_UP 0 -#define MOUSE_WHEEL_DOWN 1 +/* Mouse wheel type. */ +#define MOUSE_WHEEL_UP 64 +#define MOUSE_WHEEL_DOWN 65 + +/* Mouse button type. */ +#define MOUSE_BUTTON_1 0 +#define MOUSE_BUTTON_2 1 +#define MOUSE_BUTTON_3 2 +#define MOUSE_BUTTON_6 66 +#define MOUSE_BUTTON_7 67 +#define MOUSE_BUTTON_8 128 +#define MOUSE_BUTTON_9 129 +#define MOUSE_BUTTON_10 130 +#define MOUSE_BUTTON_11 131 /* Mouse helpers. */ #define MOUSE_BUTTONS(b) ((b) & MOUSE_MASK_BUTTONS) -#define MOUSE_WHEEL(b) ((b) & MOUSE_MASK_WHEEL) +#define MOUSE_WHEEL(b) \ + (((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_UP || \ + ((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_DOWN) #define MOUSE_DRAG(b) ((b) & MOUSE_MASK_DRAG) #define MOUSE_RELEASE(b) (((b) & MOUSE_MASK_BUTTONS) == 3) diff --git a/tty-keys.c b/tty-keys.c index 5d950078..30717af3 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1118,7 +1118,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, /* Type is M for press, m for release. */ sgr_type = ch; if (sgr_type == 'm') - b |= 3; + b = 3; /* * Some terminals (like PuTTY 0.63) mistakenly send @@ -1126,7 +1126,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, * Discard it before it reaches any program running inside * tmux. */ - if (sgr_type == 'm' && (sgr_b & 64)) + if (sgr_type == 'm' && MOUSE_WHEEL(sgr_b)) return (-2); } else return (-1); From 4893edd5d67e80e8d4323f6cae02495a7164e3f0 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 17 Feb 2022 09:58:47 +0000 Subject: [PATCH 08/40] Add a window-resized hook which is fired when the window is actually resized which may be later than the client resize, GitHub issue 2995. --- options-table.c | 1 + resize.c | 1 + 2 files changed, 2 insertions(+) diff --git a/options-table.c b/options-table.c index c8ae046e..b8a5ccbb 100644 --- a/options-table.c +++ b/options-table.c @@ -1245,6 +1245,7 @@ const struct options_table_entry options_table[] = { OPTIONS_TABLE_HOOK("window-linked", ""), OPTIONS_TABLE_WINDOW_HOOK("window-pane-changed", ""), OPTIONS_TABLE_WINDOW_HOOK("window-renamed", ""), + OPTIONS_TABLE_WINDOW_HOOK("window-resized", ""), OPTIONS_TABLE_HOOK("window-unlinked", ""), { .name = NULL } diff --git a/resize.c b/resize.c index 18a02adb..457fee0a 100644 --- a/resize.c +++ b/resize.c @@ -61,6 +61,7 @@ resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel) tty_update_window_offset(w); server_redraw_window(w); notify_window("window-layout-changed", w); + notify_window("window-resized", w); w->flags &= ~WINDOW_RESIZE; } From f74a98cd077c301b27c18a0a98620f7eda003489 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 22 Feb 2022 11:01:57 +0000 Subject: [PATCH 09/40] Use correct size for screen when popup is created without borders. --- popup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/popup.c b/popup.c index 5522df3e..2e57153d 100644 --- a/popup.c +++ b/popup.c @@ -689,7 +689,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, } pd->border_cell.attr = 0; - screen_init(&pd->s, sx - 2, sy - 2, 0); + screen_init(&pd->s, jx, jy, 0); colour_palette_init(&pd->palette); colour_palette_from_option(&pd->palette, global_w_options); From 92a26a8b8c4b32223fb81d7bde93c986ff4f7f6b Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 22 Feb 2022 11:07:25 +0000 Subject: [PATCH 10/40] Initialize copy_width before adjusting it, GitHub issue 3079. --- format-draw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/format-draw.c b/format-draw.c index 1110535f..1a7e60b3 100644 --- a/format-draw.c +++ b/format-draw.c @@ -1154,13 +1154,13 @@ format_trim_right(const char *expanded, u_int limit) while (*cp != '\0') { if (*cp == '#') { end = format_leading_hashes(cp, &n, &leading_width); + copy_width = leading_width; if (width <= skip) { - if (skip - width >= leading_width) + if (skip - width >= copy_width) copy_width = 0; else copy_width -= (skip - width); - } else - copy_width = leading_width; + } if (copy_width != 0) { if (n == 1) *out++ = '#'; From a26ebccd421e53ce1e3fcad6f1db9759cb58b043 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 22 Feb 2022 11:10:41 +0000 Subject: [PATCH 11/40] Add next_session_id format with the next session ID, GitHub issue 3078. --- format.c | 10 ++++++++++ session.c | 2 +- tmux.1 | 6 ++++++ tmux.h | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/format.c b/format.c index 2fc0961e..5c6eed36 100644 --- a/format.c +++ b/format.c @@ -1650,6 +1650,13 @@ format_cb_mouse_y(struct format_tree *ft) return (NULL); } +/* Callback for next_session_id. */ +static void * +format_cb_next_session_id(__unused struct format_tree *ft) +{ + return (format_printf("$%u", next_session_id)); +} + /* Callback for origin_flag. */ static void * format_cb_origin_flag(struct format_tree *ft) @@ -2707,6 +2714,9 @@ static const struct format_table_entry format_table[] = { { "mouse_y", FORMAT_TABLE_STRING, format_cb_mouse_y }, + { "next_session_id", FORMAT_TABLE_STRING, + format_cb_next_session_id + }, { "origin_flag", FORMAT_TABLE_STRING, format_cb_origin_flag }, diff --git a/session.c b/session.c index f30f6a61..d9d9c486 100644 --- a/session.c +++ b/session.c @@ -27,7 +27,7 @@ #include "tmux.h" struct sessions sessions; -static u_int next_session_id; +u_int next_session_id; struct session_groups session_groups = RB_INITIALIZER(&session_groups); static void session_free(int, short, void *); diff --git a/tmux.1 b/tmux.1 index 2128f81a..1837e248 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4592,6 +4592,11 @@ Run when a session is renamed. Run when a window is linked into a session. .It window-renamed Run when a window is renamed. +.It window-resized +Run when a window is resized. +This may be after the +.Ar client-resized +hook is run. .It window-unlinked Run when a window is unlinked from a session. .El @@ -5096,6 +5101,7 @@ The following variables are available, where appropriate: .It Li "mouse_word" Ta "" Ta "Word under mouse, if any" .It Li "mouse_x" Ta "" Ta "Mouse X position, if any" .It Li "mouse_y" Ta "" Ta "Mouse Y position, if any" +.It Li "next_session_id" Ta "" Ta "Unique session ID for next new session" .It Li "origin_flag" Ta "" Ta "Pane origin flag" .It Li "pane_active" Ta "" Ta "1 if active pane" .It Li "pane_at_bottom" Ta "" Ta "1 if pane is at the bottom of window" diff --git a/tmux.h b/tmux.h index f172ba1a..7eccaa55 100644 --- a/tmux.h +++ b/tmux.h @@ -3119,6 +3119,7 @@ void control_notify_session_window_changed(struct session *); /* session.c */ extern struct sessions sessions; +extern u_int next_session_id; int session_cmp(struct session *, struct session *); RB_PROTOTYPE(sessions, session, entry, session_cmp); int session_alive(struct session *); From 046530878b351dc5d99347179f9598d0b40fa268 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 22 Feb 2022 13:31:18 +0000 Subject: [PATCH 12/40] Do not attempt to update focus (and crash) when there is no previous window. --- session.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/session.c b/session.c index d9d9c486..75028882 100644 --- a/session.c +++ b/session.c @@ -501,7 +501,8 @@ session_set_current(struct session *s, struct winlink *wl) winlink_stack_push(&s->lastw, s->curw); s->curw = wl; if (options_get_number(global_options, "focus-events")) { - window_update_focus(old->window); + if (old != NULL) + window_update_focus(old->window); window_update_focus(wl->window); } winlink_clear_flags(wl); From c030d6fe362eec41ccd5a5cb21321ef8cf07314b Mon Sep 17 00:00:00 2001 From: deraadt Date: Tue, 22 Feb 2022 17:35:01 +0000 Subject: [PATCH 13/40] MAXCOMLEN is no longer needed in these programs, so remove the annotation from sys/param.h include lines, or remove the include lines entirely if it this was the least requirement. ok millert --- osdep-openbsd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/osdep-openbsd.c b/osdep-openbsd.c index 54464753..1fc087d3 100644 --- a/osdep-openbsd.c +++ b/osdep-openbsd.c @@ -16,7 +16,6 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include /* MAXCOMLEN */ #include #include #include From 9947f7416a3e43c30abcfbc5092c7e3e7b122dcb Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 28 Feb 2022 09:24:22 +0000 Subject: [PATCH 14/40] Map control keys back to an ASCII uppercase letter when passing them on as extended keys. --- input-keys.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/input-keys.c b/input-keys.c index 47614aa0..f478cb95 100644 --- a/input-keys.c +++ b/input-keys.c @@ -417,7 +417,7 @@ int input_key(struct screen *s, struct bufferevent *bev, key_code key) { struct input_key_entry *ike; - key_code justkey, newkey, outkey; + key_code justkey, newkey, outkey, modifiers; struct utf8_data ud; char tmp[64], modifier; @@ -518,7 +518,12 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) return (input_key(s, bev, key & ~KEYC_CTRL)); } outkey = (key & KEYC_MASK_KEY); - switch (key & KEYC_MASK_MODIFIERS) { + modifiers = (key & KEYC_MASK_MODIFIERS); + if (outkey < ' ') { + outkey = 64 + outkey; + modifiers |= KEYC_CTRL; + } + switch (modifiers) { case KEYC_SHIFT: modifier = '2'; break; From 42e795933625dbda27e3c0a453fc7d0fbf4bb758 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 28 Feb 2022 09:34:57 +0000 Subject: [PATCH 15/40] Exit on SIGHUP before attach also, GitHub issue 3084. --- client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.c b/client.c index 8ca08524..08708c21 100644 --- a/client.c +++ b/client.c @@ -531,7 +531,7 @@ client_signal(int sig) if (sig == SIGCHLD) waitpid(WAIT_ANY, &status, WNOHANG); else if (!client_attached) { - if (sig == SIGTERM) + if (sig == SIGTERM || sig == SIGHUP) proc_exit(client_proc); } else { switch (sig) { From 141a823ea421171d10466eccf0b2d03c0417667e Mon Sep 17 00:00:00 2001 From: topcat001 Date: Mon, 28 Feb 2022 13:11:28 -0800 Subject: [PATCH 16/40] Use PATH_MAX instead of MAXPATHLEN. --- osdep-openbsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osdep-openbsd.c b/osdep-openbsd.c index 1fc087d3..b4c8fc56 100644 --- a/osdep-openbsd.c +++ b/osdep-openbsd.c @@ -141,7 +141,7 @@ char * osdep_get_cwd(int fd) { int name[] = { CTL_KERN, KERN_PROC_CWD, 0 }; - static char path[MAXPATHLEN]; + static char path[PATH_MAX]; size_t pathlen = sizeof path; if ((name[2] = tcgetpgrp(fd)) == -1) From bc0bd8213d26d7b85cdf2c26fbd68942291b5994 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Mar 2022 15:20:22 +0000 Subject: [PATCH 17/40] Don't convert codes for special keys (Tab, Enter, Escape). --- input-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input-keys.c b/input-keys.c index f478cb95..feb62f6d 100644 --- a/input-keys.c +++ b/input-keys.c @@ -519,7 +519,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) } outkey = (key & KEYC_MASK_KEY); modifiers = (key & KEYC_MASK_MODIFIERS); - if (outkey < ' ') { + if (outkey < 32 && outkey != 9 && outkey != 13 && outkey != 27) { outkey = 64 + outkey; modifiers |= KEYC_CTRL; } From 355ced93cc219897bf3c660e481808c006ffab6a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 3 Mar 2022 08:24:12 +0000 Subject: [PATCH 18/40] Allow optional arguments. --- arguments.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/arguments.c b/arguments.c index a27d8e0a..91c470e2 100644 --- a/arguments.c +++ b/arguments.c @@ -131,8 +131,9 @@ args_parse(const struct args_parse *parse, struct args_value *values, u_int i; enum args_parse_type type; struct args_value *value, *new; - u_char flag, argument; + u_char flag; const char *found, *string, *s; + int optional_argument; if (count == 0) return (args_create()); @@ -169,18 +170,27 @@ args_parse(const struct args_parse *parse, struct args_value *values, args_free(args); return (NULL); } - argument = *++found; - if (argument != ':') { + if (*++found != ':') { log_debug("%s: -%c", __func__, flag); args_set(args, flag, NULL); continue; } + if (*found == ':') { + optional_argument = 1; + found++; + } new = xcalloc(1, sizeof *new); if (*string != '\0') { new->type = ARGS_STRING; new->string = xstrdup(string); } else { if (i == count) { + if (optional_argument) { + log_debug("%s: -%c", __func__, + flag); + args_set(args, flag, NULL); + continue; + } xasprintf(cause, "-%c expects an argument", flag); From d5a84de84293798438989d7894e8001bec8c19f1 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 7 Mar 2022 11:52:09 +0000 Subject: [PATCH 19/40] Pass client when adding menu item, GitHub issue 3103. --- status.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.c b/status.c index 79033242..8d702de1 100644 --- a/status.c +++ b/status.c @@ -1798,7 +1798,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s, item.name = tmp; item.key = '0' + size - 1; item.command = NULL; - menu_add_item(menu, &item, NULL, NULL, NULL); + menu_add_item(menu, &item, NULL, c, NULL); free(tmp); if (size == height) From 367ee79df08f80f0ae28a967ed3d9922e4ccfb22 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 7 Mar 2022 15:21:39 +0000 Subject: [PATCH 20/40] Remove unnecessary declarations. --- osdep-netbsd.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/osdep-netbsd.c b/osdep-netbsd.c index b473e017..6003c035 100644 --- a/osdep-netbsd.c +++ b/osdep-netbsd.c @@ -35,9 +35,6 @@ ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB) struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *); -char *osdep_get_name(int, char *); -char *osdep_get_cwd(int); -struct event_base *osdep_event_init(void); struct kinfo_proc2 * cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2) From f1d87241987e4b46ae839395c06d9eb48e630fa7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 8 Mar 2022 11:02:17 +0000 Subject: [PATCH 21/40] Add getpeerid compat. --- compat/getpeereid.c | 40 ++++++++++++++++++++++++++++++++++++++++ configure.ac | 11 ++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 compat/getpeereid.c diff --git a/compat/getpeereid.c b/compat/getpeereid.c new file mode 100644 index 00000000..722f14a2 --- /dev/null +++ b/compat/getpeereid.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include + +#include "compat.h" + +int +getpeereid(int s, uid_t *uid, gid_t *gid) +{ +#ifdef HAVE_SO_PEERCRED + struct ucred uc; + int len = sizeof uc; + + if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &uc, &len) == -1) + return (-1); + *uid = uc.uid; + *gid = uc.gid; + return (0); +#else + errno = EOPNOTSUPP; + return (-1); +#endif +} diff --git a/configure.ac b/configure.ac index fb0ee239..6f607b0b 100644 --- a/configure.ac +++ b/configure.ac @@ -160,6 +160,7 @@ AC_REPLACE_FUNCS([ \ freezero \ getdtablecount \ getdtablesize \ + getpeereid \ getline \ getprogname \ memmem \ @@ -169,7 +170,7 @@ AC_REPLACE_FUNCS([ \ strlcat \ strlcpy \ strndup \ - strsep \ + strsep ]) AC_FUNC_STRNLEN @@ -684,6 +685,14 @@ AC_CHECK_DECL( [#include ] ) +# Look for setsockopt(SO_PEERCRED). +AC_CHECK_DECL( + SO_PEERCRED, + AC_DEFINE(HAVE_SO_PEERCRED), + , + [#include ] +) + # Look for fcntl(F_CLOSEM). AC_CHECK_DECL( F_CLOSEM, From 759f94965454a043285813cf4fd8b83944587973 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 8 Mar 2022 11:04:15 +0000 Subject: [PATCH 22/40] Need a declaration for getpeereid also. --- compat.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compat.h b/compat.h index 13334ad7..be726831 100644 --- a/compat.h +++ b/compat.h @@ -334,6 +334,11 @@ char *strndup(const char *, size_t); void *memmem(const void *, size_t, const void *, size_t); #endif +#ifndef HAVE_GETPEEREID +/* getpeereid.c */ +int getpeereid(int, uid_t *, gid_t *); +#endif + #ifndef HAVE_DAEMON /* daemon.c */ int daemon(int, int); From f97d784f172a10e0444ad93bb536ee0428613aa7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 8 Mar 2022 11:35:06 +0000 Subject: [PATCH 23/40] Use getpeerucred if available (not tested). --- compat/getpeereid.c | 19 +++++++++++++++++++ configure.ac | 6 ++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/compat/getpeereid.c b/compat/getpeereid.c index 722f14a2..5a593c07 100644 --- a/compat/getpeereid.c +++ b/compat/getpeereid.c @@ -19,6 +19,10 @@ #include +#ifdef HAVE_UCRED_H +#include +#endif + #include "compat.h" int @@ -33,6 +37,21 @@ getpeereid(int s, uid_t *uid, gid_t *gid) *uid = uc.uid; *gid = uc.gid; return (0); +#elif defined(HAVE_GETPEERUCRED) +int +getpeereid(int s, uid_t *uid, gid_t *gid) +{ + ucred_t *ucred = NULL; + + if (getpeerucred(s, &ucred) == -1) + return (-1); + if ((*uid = ucred_geteuid(ucred)) == -1) + return (-1); + if ((*gid = ucred_getrgid(ucred)) == -1) + return (-1); + ucred_free(ucred); + return (0); +} #else errno = EOPNOTSUPP; return (-1); diff --git a/configure.ac b/configure.ac index 6f607b0b..a9c035d7 100644 --- a/configure.ac +++ b/configure.ac @@ -128,6 +128,7 @@ AC_CHECK_HEADERS([ \ sys/dir.h \ sys/ndir.h \ sys/tree.h \ + ucred.h \ util.h \ ]) @@ -146,7 +147,8 @@ AC_CHECK_FUNCS([ \ flock \ prctl \ proc_pidinfo \ - sysconf + getpeerucred \ + sysconf \ ]) # Check for functions with a compatibility implementation. @@ -170,7 +172,7 @@ AC_REPLACE_FUNCS([ \ strlcat \ strlcpy \ strndup \ - strsep + strsep \ ]) AC_FUNC_STRNLEN From 8aed44420152b87e08f8f120ffbe4a888ee5d951 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 8 Mar 2022 11:28:40 +0000 Subject: [PATCH 24/40] Add formats for client and server UID and user (for multiuser setups). --- cmd-list-clients.c | 2 ++ format.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ proc.c | 11 +++++++++ 3 files changed, 73 insertions(+) diff --git a/cmd-list-clients.c b/cmd-list-clients.c index a5b7d147..53a99178 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -31,6 +31,8 @@ #define LIST_CLIENTS_TEMPLATE \ "#{client_name}: #{session_name} " \ "[#{client_width}x#{client_height} #{client_termname}] " \ + "#{?#{!=:#{client_uid},#{uid}}," \ + "[user #{?client_user,#{client_user},#{client_uid},}] ,}" \ "#{?client_flags,(,}#{client_flags}#{?client_flags,),}" static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *); diff --git a/format.c b/format.c index 5c6eed36..52eb4642 100644 --- a/format.c +++ b/format.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1387,6 +1388,35 @@ format_cb_client_tty(struct format_tree *ft) return (NULL); } +/* Callback for client_uid. */ +static void * +format_cb_client_uid(struct format_tree *ft) +{ + uid_t uid; + + if (ft->c != NULL) { + uid = proc_get_peer_uid(ft->c->peer); + if (uid != (uid_t)-1) + return (format_printf("%ld", (long)uid)); + } + return (NULL); +} + +/* Callback for client_user. */ +static void * +format_cb_client_user(struct format_tree *ft) +{ + uid_t uid; + struct passwd *pw; + + if (ft->c != NULL) { + uid = proc_get_peer_uid(ft->c->peer); + if (uid != (uid_t)-1 && (pw = getpwuid(uid)) != NULL) + return (xstrdup(pw->pw_name)); + } + return (NULL); +} + /* Callback for client_utf8. */ static void * format_cb_client_utf8(struct format_tree *ft) @@ -2521,6 +2551,24 @@ format_cb_tree_mode_format(__unused struct format_tree *ft) return (xstrdup(window_tree_mode.default_format)); } +/* Callback for uid. */ +static void * +format_cb_uid(__unused struct format_tree *ft) +{ + return (format_printf("%ld", (long)getuid())); +} + +/* Callback for user. */ +static void * +format_cb_user(__unused struct format_tree *ft) +{ + struct passwd *pw; + + if ((pw = getpwuid(getuid())) != NULL) + return (xstrdup(pw->pw_name)); + return NULL; +} + /* Format table type. */ enum format_table_type { FORMAT_TABLE_STRING, @@ -2627,6 +2675,12 @@ static const struct format_table_entry format_table[] = { { "client_tty", FORMAT_TABLE_STRING, format_cb_client_tty }, + { "client_uid", FORMAT_TABLE_STRING, + format_cb_client_uid + }, + { "client_user", FORMAT_TABLE_STRING, + format_cb_client_user + }, { "client_utf8", FORMAT_TABLE_STRING, format_cb_client_utf8 }, @@ -2906,6 +2960,12 @@ static const struct format_table_entry format_table[] = { { "tree_mode_format", FORMAT_TABLE_STRING, format_cb_tree_mode_format }, + { "uid", FORMAT_TABLE_STRING, + format_cb_uid + }, + { "user", FORMAT_TABLE_STRING, + format_cb_user + }, { "version", FORMAT_TABLE_STRING, format_cb_version }, diff --git a/proc.c b/proc.c index 958a9483..a9b1473e 100644 --- a/proc.c +++ b/proc.c @@ -56,6 +56,7 @@ struct tmuxpeer { struct imsgbuf ibuf; struct event event; + uid_t uid; int flags; #define PEER_BAD 0x1 @@ -308,6 +309,7 @@ proc_add_peer(struct tmuxproc *tp, int fd, void (*dispatchcb)(struct imsg *, void *), void *arg) { struct tmuxpeer *peer; + gid_t gid; peer = xcalloc(1, sizeof *peer); peer->parent = tp; @@ -318,6 +320,9 @@ proc_add_peer(struct tmuxproc *tp, int fd, imsg_init(&peer->ibuf, fd); event_set(&peer->event, fd, EV_READ, proc_event_cb, peer); + if (getpeereid(fd, &peer->uid, &gid) != 0) + peer->uid = (uid_t)-1; + log_debug("add peer %p: %d (%p)", peer, fd, arg); TAILQ_INSERT_TAIL(&tp->peers, peer, entry); @@ -373,3 +378,9 @@ proc_fork_and_daemon(int *fd) return (pid); } } + +uid_t +proc_get_peer_uid(struct tmuxpeer *peer) +{ + return (peer->uid); +} From 57f331438a1eb67d6f1d3380278c8df7c9003dc1 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 8 Mar 2022 12:01:19 +0000 Subject: [PATCH 25/40] Add argument to refresh-client -l to forward clipboard to a pane. GitHub issue 3068. --- cmd-refresh-client.c | 39 +++++++++-- input.c | 47 +++++++------ server-client.c | 1 + tmux.1 | 15 +++- tmux.h | 158 +++++++++++++++++++++++-------------------- tty-keys.c | 28 ++++++-- tty.c | 17 +++-- 7 files changed, 191 insertions(+), 114 deletions(-) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 2af9cb46..b2665ad9 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -34,7 +34,7 @@ const struct cmd_entry cmd_refresh_client_entry = { .name = "refresh-client", .alias = "refresh", - .args = { "A:B:cC:Df:F:lLRSt:U", 0, 1, NULL }, + .args = { "A:B:cC:Df:F:l::LRSt:U", 0, 1, NULL }, .usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] " "[-C XxY] [-f flags] " CMD_TARGET_CLIENT_USAGE " [adjustment]", @@ -162,6 +162,37 @@ out: free(copy); } +static enum cmd_retval +cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item) +{ + struct args *args = cmd_get_args(self); + struct client *tc = cmdq_get_target_client(item); + const char *p; + u_int i; + struct cmd_find_state fs; + + p = args_get(args, 'l'); + if (p == NULL) { + if (tc->flags & CLIENT_CLIPBOARDBUFFER) + return (CMD_RETURN_NORMAL); + tc->flags |= CLIENT_CLIPBOARDBUFFER; + } else { + if (cmd_find_target(&fs, item, p, CMD_FIND_PANE, 0) != 0) + return (CMD_RETURN_ERROR); + for (i = 0; i < tc->clipboard_npanes; i++) { + if (tc->clipboard_panes[i] == fs.wp->id) + break; + } + if (i != tc->clipboard_npanes) + return (CMD_RETURN_NORMAL); + tc->clipboard_panes = xreallocarray (tc->clipboard_panes, + tc->clipboard_npanes + 1, sizeof *tc->clipboard_panes); + tc->clipboard_panes[tc->clipboard_npanes++] = fs.wp->id; + } + tty_clipboard_query(&tc->tty); + return (CMD_RETURN_NORMAL); +} + static enum cmd_retval cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) { @@ -224,10 +255,8 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); } - if (args_has(args, 'l')) { - tty_send_osc52_query(&tc->tty); - return (CMD_RETURN_NORMAL); - } + if (args_has(args, 'l')) + return (cmd_refresh_client_clipboard(self, item)); if (args_has(args, 'F')) /* -F is an alias for -f */ server_client_set_flags(tc, args_get(args, 'F')); diff --git a/input.c b/input.c index 5adc694d..b1856538 100644 --- a/input.c +++ b/input.c @@ -2682,8 +2682,8 @@ input_osc_52(struct input_ctx *ictx, const char *p) { struct window_pane *wp = ictx->wp; char *end; - const char *buf; - size_t len; + const char *buf = NULL; + size_t len = 0; u_char *out; int outlen, state; struct screen_write_ctx ctx; @@ -2703,26 +2703,12 @@ input_osc_52(struct input_ctx *ictx, const char *p) log_debug("%s: %s", __func__, end); if (strcmp(end, "?") == 0) { - if ((pb = paste_get_top(NULL)) != NULL) { + if ((pb = paste_get_top(NULL)) != NULL) buf = paste_buffer_data(pb, &len); - outlen = 4 * ((len + 2) / 3) + 1; - out = xmalloc(outlen); - if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) { - free(out); - return; - } - } else { - outlen = 0; - out = NULL; - } - bufferevent_write(ictx->event, "\033]52;;", 6); - if (outlen != 0) - bufferevent_write(ictx->event, out, outlen); if (ictx->input_end == INPUT_END_BEL) - bufferevent_write(ictx->event, "\007", 1); + input_reply_clipboard(ictx->event, buf, len, "\007"); else - bufferevent_write(ictx->event, "\033\\", 2); - free(out); + input_reply_clipboard(ictx->event, buf, len, "\033\\"); return; } @@ -2780,3 +2766,26 @@ input_osc_104(struct input_ctx *ictx, const char *p) screen_write_fullredraw(&ictx->ctx); free(copy); } + +void +input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len, + const char *end) +{ + char *out = NULL; + size_t outlen = 0; + + if (buf != NULL && len != 0) { + outlen = 4 * ((len + 2) / 3) + 1; + out = xmalloc(outlen); + if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) { + free(out); + return; + } + } + + bufferevent_write(bev, "\033]52;;", 6); + if (outlen != 0) + bufferevent_write(bev, out, outlen); + bufferevent_write(bev, end, strlen(end)); + free(out); +} diff --git a/server-client.c b/server-client.c index 0f043796..3b888d01 100644 --- a/server-client.c +++ b/server-client.c @@ -422,6 +422,7 @@ server_client_lost(struct client *c) if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); free(c->ttyname); + free(c->clipboard_panes); free(c->term_name); free(c->term_type); diff --git a/tmux.1 b/tmux.1 index 1837e248..475ddfbb 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1341,11 +1341,12 @@ and sets an environment variable for the newly created session; it may be specified multiple times. .Tg refresh .It Xo Ic refresh-client -.Op Fl cDlLRSU +.Op Fl cDLRSU .Op Fl A Ar pane:state .Op Fl B Ar name:what:format .Op Fl C Ar size .Op Fl f Ar flags +.Op Fl l Op Ar target-pane .Op Fl t Ar target-client .Op Ar adjustment .Xc @@ -1459,7 +1460,11 @@ sets a comma-separated list of client flags, see .Fl l requests the clipboard from the client using the .Xr xterm 1 -escape sequence and stores it in a new paste buffer. +escape sequence. +If +Ar target-pane +is given, the clipboard is sent (in encoded form), otherwise it is stored in a +new paste buffer. .Pp .Fl L , .Fl R , @@ -5057,6 +5062,8 @@ The following variables are available, where appropriate: .It Li "client_termname" Ta "" Ta "Terminal name of client" .It Li "client_termtype" Ta "" Ta "Terminal type of client, if available" .It Li "client_tty" Ta "" Ta "Pseudo terminal of client" +.It Li "client_uid" Ta "" Ta "UID of client process" +.It Li "client_user" Ta "" Ta "User of client process" .It Li "client_utf8" Ta "" Ta "1 if client supports UTF-8" .It Li "client_width" Ta "" Ta "Width of client" .It Li "client_written" Ta "" Ta "Bytes written to client" @@ -5174,6 +5181,8 @@ The following variables are available, where appropriate: .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" +.It Li "uid" Ta "" Ta "Server UID" +.It Li "user" Ta "" Ta "Server user" .It Li "version" Ta "" Ta "Server version" .It Li "window_active" Ta "" Ta "1 if window active" .It Li "window_active_clients" Ta "" Ta "Number of clients viewing this window" @@ -5188,7 +5197,6 @@ The following variables are available, where appropriate: .It Li "window_cell_width" Ta "" Ta "Width of each cell in pixels" .It Li "window_end_flag" Ta "" Ta "1 if window has the highest index" .It Li "window_flags" Ta "#F" Ta "Window flags with # escaped as ##" -.It Li "window_raw_flags" Ta "" Ta "Window flags with nothing escaped" .It Li "window_format" Ta "" Ta "1 if format is for a window" .It Li "window_height" Ta "" Ta "Height of window" .It Li "window_id" Ta "" Ta "Unique window ID" @@ -5203,6 +5211,7 @@ The following variables are available, where appropriate: .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_raw_flags" Ta "" Ta "Window flags with nothing escaped" .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" .It Li "window_start_flag" Ta "" Ta "1 if window has the lowest index" diff --git a/tmux.h b/tmux.h index 7eccaa55..78283aa2 100644 --- a/tmux.h +++ b/tmux.h @@ -1332,7 +1332,7 @@ LIST_HEAD(tty_terms, tty_term); struct tty { struct client *client; struct event start_timer; - struct event query_timer; + struct event clipboard_timer; u_int sx; u_int sy; @@ -1685,50 +1685,50 @@ typedef int (*overlay_key_cb)(struct client *, void *, struct key_event *); typedef void (*overlay_free_cb)(struct client *, void *); typedef void (*overlay_resize_cb)(struct client *, void *); struct client { - const char *name; - struct tmuxpeer *peer; - struct cmdq_list *queue; + const char *name; + struct tmuxpeer *peer; + struct cmdq_list *queue; - struct client_windows windows; + struct client_windows windows; - struct control_state *control_state; - u_int pause_age; + struct control_state *control_state; + u_int pause_age; - pid_t pid; - int fd; - int out_fd; - struct event event; - int retval; + pid_t pid; + int fd; + int out_fd; + struct event event; + int retval; - struct timeval creation_time; - struct timeval activity_time; + struct timeval creation_time; + struct timeval activity_time; - struct environ *environ; + struct environ *environ; struct format_job_tree *jobs; - char *title; - const char *cwd; + char *title; + const char *cwd; - char *term_name; - int term_features; - char *term_type; - char **term_caps; - u_int term_ncaps; + char *term_name; + int term_features; + char *term_type; + char **term_caps; + u_int term_ncaps; - char *ttyname; - struct tty tty; + char *ttyname; + struct tty tty; - size_t written; - size_t discarded; - size_t redraw; + size_t written; + size_t discarded; + size_t redraw; - struct event repeat_timer; + struct event repeat_timer; - struct event click_timer; - u_int click_button; - struct mouse_event click_event; + struct event click_timer; + u_int click_button; + struct mouse_event click_event; - struct status_line status; + struct status_line status; #define CLIENT_TERMINAL 0x1 #define CLIENT_LOGIN 0x2 @@ -1765,6 +1765,7 @@ struct client { #define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL #define CLIENT_CONTROL_WAITEXIT 0x200000000ULL #define CLIENT_WINDOWSIZECHANGED 0x400000000ULL +#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL #define CLIENT_ALLREDRAWFLAGS \ (CLIENT_REDRAWWINDOW| \ CLIENT_REDRAWSTATUS| \ @@ -1776,73 +1777,79 @@ struct client { (CLIENT_DEAD| \ CLIENT_SUSPENDED| \ CLIENT_EXIT) -#define CLIENT_NODETACHFLAGS \ +#define CLIENT_NODETACHFLAGS \ (CLIENT_DEAD| \ CLIENT_EXIT) #define CLIENT_NOSIZEFLAGS \ (CLIENT_DEAD| \ CLIENT_SUSPENDED| \ CLIENT_EXIT) - uint64_t flags; + uint64_t flags; enum { CLIENT_EXIT_RETURN, CLIENT_EXIT_SHUTDOWN, CLIENT_EXIT_DETACH - } exit_type; - enum msgtype exit_msgtype; - char *exit_session; - char *exit_message; + } exit_type; + enum msgtype exit_msgtype; + char *exit_session; + char *exit_message; - struct key_table *keytable; + struct key_table *keytable; - uint64_t redraw_panes; + uint64_t redraw_panes; - int message_ignore_keys; - int message_ignore_styles; - char *message_string; - struct event message_timer; + int message_ignore_keys; + int message_ignore_styles; + char *message_string; + struct event message_timer; - char *prompt_string; - struct utf8_data *prompt_buffer; - char *prompt_last; - size_t prompt_index; - prompt_input_cb prompt_inputcb; - prompt_free_cb prompt_freecb; - void *prompt_data; - u_int prompt_hindex[PROMPT_NTYPES]; - enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode; - struct utf8_data *prompt_saved; + char *prompt_string; + struct utf8_data *prompt_buffer; + char *prompt_last; + size_t prompt_index; + prompt_input_cb prompt_inputcb; + prompt_free_cb prompt_freecb; + void *prompt_data; + u_int prompt_hindex[PROMPT_NTYPES]; + enum { + PROMPT_ENTRY, + PROMPT_COMMAND + } prompt_mode; + struct utf8_data *prompt_saved; #define PROMPT_SINGLE 0x1 #define PROMPT_NUMERIC 0x2 #define PROMPT_INCREMENTAL 0x4 #define PROMPT_NOFORMAT 0x8 #define PROMPT_KEY 0x10 - int prompt_flags; - enum prompt_type prompt_type; - int prompt_cursor; + int prompt_flags; + enum prompt_type prompt_type; + int prompt_cursor; - struct session *session; - struct session *last_session; + struct session *session; + struct session *last_session; - int references; + int references; - void *pan_window; - u_int pan_ox; - u_int pan_oy; + void *pan_window; + u_int pan_ox; + u_int pan_oy; - overlay_check_cb overlay_check; - overlay_mode_cb overlay_mode; - overlay_draw_cb overlay_draw; - overlay_key_cb overlay_key; - overlay_free_cb overlay_free; - overlay_resize_cb overlay_resize; - void *overlay_data; - struct event overlay_timer; + overlay_check_cb overlay_check; + overlay_mode_cb overlay_mode; + overlay_draw_cb overlay_draw; + overlay_key_cb overlay_key; + overlay_free_cb overlay_free; + overlay_resize_cb overlay_resize; + void *overlay_data; + struct event overlay_timer; - struct client_files files; + struct client_files files; - TAILQ_ENTRY(client) entry; + u_int *clipboard_panes; + u_int clipboard_npanes; + + TAILQ_ENTRY(client) entry; }; TAILQ_HEAD(clients, client); @@ -2016,6 +2023,7 @@ void proc_remove_peer(struct tmuxpeer *); void proc_kill_peer(struct tmuxpeer *); void proc_toggle_log(struct tmuxproc *); pid_t proc_fork_and_daemon(int *); +uid_t proc_get_peer_uid(struct tmuxpeer *); /* cfg.c */ extern int cfg_finished; @@ -2229,7 +2237,7 @@ void tty_reset(struct tty *); void tty_region_off(struct tty *); void tty_margin_off(struct tty *); void tty_cursor(struct tty *, u_int, u_int); -void tty_send_osc52_query(struct tty *); +void tty_clipboard_query(struct tty *); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int); @@ -2675,6 +2683,8 @@ 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 *, screen_write_init_ctx_cb, void *, u_char *, size_t); +void input_reply_clipboard(struct bufferevent *, const char *, size_t, + const char *); /* input-key.c */ void input_key_build(void); diff --git a/tty-keys.c b/tty-keys.c index 30717af3..8538e74b 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1154,12 +1154,14 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, * partial. */ static int -tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len, - size_t *size) +tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) { - size_t end, terminator, needed; - char *copy, *out; - int outlen; + struct client *c = tty->client; + struct window_pane *wp; + size_t end, terminator, needed; + char *copy, *out; + int outlen; + u_int i; *size = 0; @@ -1221,6 +1223,7 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len, if (~tty->flags & TTY_OSC52QUERY) return (0); tty->flags &= ~TTY_OSC52QUERY; + evtimer_del(&tty->clipboard_timer); /* It has to be a string so copy it. */ copy = xmalloc(end + 1); @@ -1237,9 +1240,20 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len, } free(copy); - /* Create a new paste buffer. */ + /* Create a new paste buffer and forward to panes. */ log_debug("%s: %.*s", __func__, outlen, out); - paste_add(NULL, out, outlen); + if (c->flags & CLIENT_CLIPBOARDBUFFER) { + paste_add(NULL, out, outlen); + c->flags &= ~CLIENT_CLIPBOARDBUFFER; + } + for (i = 0; i < c->clipboard_npanes; i++) { + wp = window_pane_find_by_id(c->clipboard_panes[i]); + if (wp != NULL) + input_reply_clipboard(wp->event, out, outlen, "\033\\"); + } + free(c->clipboard_panes); + c->clipboard_panes = NULL; + c->clipboard_npanes = 0; return (0); } diff --git a/tty.c b/tty.c index 06b1bfb2..40735ceb 100644 --- a/tty.c +++ b/tty.c @@ -2921,24 +2921,29 @@ tty_default_attributes(struct tty *tty, const struct grid_cell *defaults, } static void -tty_query_timer_callback(__unused int fd, __unused short events, void *data) +tty_clipboard_query_callback(__unused int fd, __unused short events, void *data) { struct tty *tty = data; + struct client *c = tty->client; + + c->flags &= ~CLIENT_CLIPBOARDBUFFER; + free(c->clipboard_panes); + c->clipboard_panes = NULL; + c->clipboard_npanes = 0; tty->flags &= ~TTY_OSC52QUERY; } void -tty_send_osc52_query(struct tty *tty) +tty_clipboard_query(struct tty *tty) { struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; if ((~tty->flags & TTY_STARTED) || (tty->flags & TTY_OSC52QUERY)) return; tty_putcode_ptr2(tty, TTYC_MS, "", "?"); + tty->flags |= TTY_OSC52QUERY; - - evtimer_set(&tty->query_timer, tty_query_timer_callback, tty); - evtimer_add(&tty->query_timer, &tv); + evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); + evtimer_add(&tty->clipboard_timer, &tv); } - From 98b92c0525f7cd5878122815cbe9adb4e292ce2c Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 8 Mar 2022 18:31:46 +0000 Subject: [PATCH 26/40] Add remain-on-exit-format to set text shown when pane is dead. --- format.c | 37 +++++++++++++++++++++++++++++++++++++ options-table.c | 13 +++++++++++++ server-fn.c | 38 +++++++++++++++++--------------------- tmux.1 | 7 +++++++ tmux.h | 1 + 5 files changed, 75 insertions(+), 21 deletions(-) diff --git a/format.c b/format.c index 52eb4642..2e4bceb5 100644 --- a/format.c +++ b/format.c @@ -1756,6 +1756,23 @@ format_cb_pane_dead(struct format_tree *ft) return (NULL); } +/* Callback for pane_dead_signal. */ +static void * +format_cb_pane_dead_signal(struct format_tree *ft) +{ + struct window_pane *wp = ft->wp; + const char *name; + + if (wp != NULL) { + if ((wp->flags & PANE_STATUSREADY) && WIFSIGNALED(wp->status)) { + name = sig2name(WTERMSIG(wp->status)); + return (format_printf("%s", name)); + } + return (NULL); + } + return (NULL); +} + /* Callback for pane_dead_status. */ static void * format_cb_pane_dead_status(struct format_tree *ft) @@ -1770,6 +1787,20 @@ format_cb_pane_dead_status(struct format_tree *ft) return (NULL); } +/* Callback for pane_dead_time. */ +static void * +format_cb_pane_dead_time(struct format_tree *ft) +{ + struct window_pane *wp = ft->wp; + + if (wp != NULL) { + if (wp->flags & PANE_STATUSDRAWN) + return (&wp->dead_time); + return (NULL); + } + return (NULL); +} + /* Callback for pane_format. */ static void * format_cb_pane_format(struct format_tree *ft) @@ -2804,9 +2835,15 @@ static const struct format_table_entry format_table[] = { { "pane_dead", FORMAT_TABLE_STRING, format_cb_pane_dead }, + { "pane_dead_signal", FORMAT_TABLE_STRING, + format_cb_pane_dead_signal + }, { "pane_dead_status", FORMAT_TABLE_STRING, format_cb_pane_dead_status }, + { "pane_dead_time", FORMAT_TABLE_TIME, + format_cb_pane_dead_time + }, { "pane_fg", FORMAT_TABLE_STRING, format_cb_pane_fg }, diff --git a/options-table.c b/options-table.c index b8a5ccbb..31b0e372 100644 --- a/options-table.c +++ b/options-table.c @@ -1060,6 +1060,19 @@ const struct options_table_entry options_table[] = { "killed ('off' or 'failed') when the program inside exits." }, + { .name = "remain-on-exit-format", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .default_str = "Pane is dead (" + "#{?#{!=:#{pane_dead_status},}," + "status #{pane_dead_status},}" + "#{?#{!=:#{pane_dead_signal},}," + "signal #{pane_dead_signal},}, " + "#{t:pane_dead_time})", + .text = "Message shown after the program in a pane has exited, if " + "remain-on-exit is enabled." + }, + { .name = "synchronize-panes", .type = OPTIONS_TABLE_FLAG, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, diff --git a/server-fn.c b/server-fn.c index 92793093..2a79f3e3 100644 --- a/server-fn.c +++ b/server-fn.c @@ -310,9 +310,11 @@ server_destroy_pane(struct window_pane *wp, int notify) struct window *w = wp->window; struct screen_write_ctx ctx; struct grid_cell gc; - time_t t; - char tim[26]; int remain_on_exit; + const char *s; + char *expanded; + u_int sx = screen_size_x(&wp->base); + u_int sy = screen_size_y(&wp->base); if (wp->fd != -1) { #ifdef HAVE_UTEMPTER @@ -339,32 +341,26 @@ server_destroy_pane(struct window_pane *wp, int notify) return; wp->flags |= PANE_STATUSDRAWN; + gettimeofday(&wp->dead_time, NULL); if (notify) notify_pane("pane-died", wp); - screen_write_start_pane(&ctx, wp, &wp->base); - screen_write_scrollregion(&ctx, 0, screen_size_y(ctx.s) - 1); - screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1, 0); - screen_write_linefeed(&ctx, 1, 8); - memcpy(&gc, &grid_default_cell, sizeof gc); + s = options_get_string(wp->options, "remain-on-exit-format"); + if (*s != '\0') { + screen_write_start_pane(&ctx, wp, &wp->base); + screen_write_scrollregion(&ctx, 0, sy - 1); + screen_write_cursormove(&ctx, 0, sy - 1, 0); + screen_write_linefeed(&ctx, 1, 8); + memcpy(&gc, &grid_default_cell, sizeof gc); - time(&t); - ctime_r(&t, tim); - tim[strcspn(tim, "\n")] = '\0'; + expanded = format_single(NULL, s, NULL, NULL, NULL, wp); + format_draw(&ctx, &gc, sx, expanded, NULL, 0); + free(expanded); - if (WIFEXITED(wp->status)) { - screen_write_nputs(&ctx, -1, &gc, - "Pane is dead (status %d, %s)", - WEXITSTATUS(wp->status), - tim); - } else if (WIFSIGNALED(wp->status)) { - screen_write_nputs(&ctx, -1, &gc, - "Pane is dead (signal %s, %s)", - sig2name(WTERMSIG(wp->status)), - tim); + screen_write_stop(&ctx); } + wp->base.mode &= ~MODE_CURSOR; - screen_write_stop(&ctx); wp->flags |= PANE_REDRAW; return; } diff --git a/tmux.1 b/tmux.1 index 475ddfbb..a7a6846f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4471,6 +4471,11 @@ The pane may be reactivated with the .Ic respawn-pane command. .Pp +.It Ic remain-on-exit-format Ar string +Set the text shown at the bottom of exited panes when +.Ic remain-on-exit +is enabled. +.Pp .It Xo Ic synchronize-panes .Op Ic on | off .Xc @@ -5120,7 +5125,9 @@ The following variables are available, where appropriate: .It Li "pane_current_command" Ta "" Ta "Current command if available" .It Li "pane_current_path" Ta "" Ta "Current path if available" .It Li "pane_dead" Ta "" Ta "1 if pane is dead" +.It Li "pane_dead_signal" Ta "" Ta "Exit signal of process in dead pane" .It Li "pane_dead_status" Ta "" Ta "Exit status of process in dead pane" +.It Li "pane_dead_time" Ta "" Ta "Exit time of process in dead pane" .It Li "pane_fg" Ta "" Ta "Pane foreground colour" .It Li "pane_format" Ta "" Ta "1 if format is for a pane" .It Li "pane_height" Ta "" Ta "Height of pane" diff --git a/tmux.h b/tmux.h index 78283aa2..8a8535dd 100644 --- a/tmux.h +++ b/tmux.h @@ -1027,6 +1027,7 @@ struct window_pane { pid_t pid; char tty[TTY_NAME_MAX]; int status; + struct timeval dead_time; int fd; struct bufferevent *event; From 23e613fcf5a1f3dc6f27f52d523bff17528f4b52 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 8 Mar 2022 21:58:37 +0000 Subject: [PATCH 27/40] Fix user hooks (which are strings not arrays). --- notify.c | 67 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/notify.c b/notify.c index 9c55d0b8..baeb0600 100644 --- a/notify.c +++ b/notify.c @@ -34,18 +34,37 @@ struct notify_entry { int pane; }; +static struct cmdq_item * +notify_insert_one_hook(struct cmdq_item *item, struct notify_entry *ne, + struct cmd_list *cmdlist, struct cmdq_state *state) +{ + struct cmdq_item *new_item; + char *s; + + if (cmdlist == NULL) + return (item); + if (log_get_level() != 0) { + s = cmd_list_print(cmdlist, 0); + log_debug("%s: hook %s is: %s", __func__, ne->name, s); + free (s); + } + new_item = cmdq_get_command(cmdlist, state); + return (cmdq_insert_after(item, new_item)); +} + static void notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne) { struct cmd_find_state fs; struct options *oo; - struct cmdq_item *new_item; - struct cmdq_state *new_state; + struct cmdq_state *state; struct options_entry *o; struct options_array_item *a; struct cmd_list *cmdlist; + const char *value; + struct cmd_parse_result *pr; - log_debug("%s: %s", __func__, ne->name); + log_debug("%s: inserting hook %s", __func__, ne->name); cmd_find_clear_state(&fs, 0); if (cmd_find_empty_state(&ne->fs) || !cmd_find_valid_state(&ne->fs)) @@ -66,23 +85,37 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne) oo = fs.wl->window->options; o = options_get(oo, ne->name); } - if (o == NULL) + if (o == NULL) { + log_debug("%s: hook %s not found", __func__, ne->name); return; - - new_state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS); - cmdq_add_formats(new_state, ne->formats); - - a = options_array_first(o); - while (a != NULL) { - cmdlist = options_array_item_value(a)->cmdlist; - if (cmdlist != NULL) { - new_item = cmdq_get_command(cmdlist, new_state); - item = cmdq_insert_after(item, new_item); - } - a = options_array_next(a); } - cmdq_free_state(new_state); + state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS); + cmdq_add_formats(state, ne->formats); + + if (*ne->name == '@') { + value = options_get_string(oo, ne->name); + pr = cmd_parse_from_string(value, NULL); + switch (pr->status) { + case CMD_PARSE_ERROR: + log_debug("%s: can't parse hook %s: %s", __func__, + ne->name, pr->error); + free(pr->error); + break; + case CMD_PARSE_SUCCESS: + notify_insert_one_hook(item, ne, pr->cmdlist, state); + break; + } + } else { + a = options_array_first(o); + while (a != NULL) { + cmdlist = options_array_item_value(a)->cmdlist; + item = notify_insert_one_hook(item, ne, cmdlist, state); + a = options_array_next(a); + } + } + + cmdq_free_state(state); } static enum cmd_retval From ad7113e0dbf2e5f5b6b33fd34824c5cf16e9053c Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 8 Mar 2022 22:14:25 +0000 Subject: [PATCH 28/40] With -f use percentages of window size not pane size, GitHub issue 2866. --- cmd-split-window.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/cmd-split-window.c b/cmd-split-window.c index 888d4106..9947dfd3 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -60,6 +60,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) struct client *tc = cmdq_get_target_client(item); struct session *s = target->s; struct winlink *wl = target->wl; + struct window *w = wl->window; struct window_pane *wp = target->wp, *new_wp; enum layout_type type; struct layout_cell *lc; @@ -86,10 +87,17 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) cmdq_error(item, "percentage %s", errstr); return (CMD_RETURN_ERROR); } - if (type == LAYOUT_TOPBOTTOM) - size = (wp->sy * percentage) / 100; - else - size = (wp->sx * percentage) / 100; + if (args_has(args, 'f')) { + if (type == LAYOUT_TOPBOTTOM) + size = (w->sy * percentage) / 100; + else + size = (w->sx * percentage) / 100; + } else { + if (type == LAYOUT_TOPBOTTOM) + size = (wp->sy * percentage) / 100; + else + size = (wp->sx * percentage) / 100; + } } else { size = args_strtonum(args, 'l', 0, INT_MAX, &cause); if (cause != NULL) { @@ -105,10 +113,17 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) free(cause); return (CMD_RETURN_ERROR); } - if (type == LAYOUT_TOPBOTTOM) - size = (wp->sy * percentage) / 100; - else - size = (wp->sx * percentage) / 100; + if (args_has(args, 'f')) { + if (type == LAYOUT_TOPBOTTOM) + size = (w->sy * percentage) / 100; + else + size = (w->sx * percentage) / 100; + } else { + if (type == LAYOUT_TOPBOTTOM) + size = (wp->sy * percentage) / 100; + else + size = (wp->sx * percentage) / 100; + } } else size = -1; From fe44b105e4a2d1d7baa12b37d0b84d8c6be9addc Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 16 Mar 2022 17:00:17 +0000 Subject: [PATCH 29/40] Add an option to set the character used for unused areas of the terminal, GitHub issue 3110. --- options-table.c | 7 ++++++ options.c | 6 +++++ screen-redraw.c | 13 +++++++--- tmux.1 | 3 +++ tmux.h | 66 +++++++++++++++++++++++++------------------------ window.c | 19 ++++++++++++++ 6 files changed, 78 insertions(+), 36 deletions(-) diff --git a/options-table.c b/options-table.c index 31b0e372..3aa72e78 100644 --- a/options-table.c +++ b/options-table.c @@ -881,6 +881,13 @@ const struct options_table_entry options_table[] = { .text = "Style of the marked line in copy mode." }, + { .name = "fill-character", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW, + .default_str = "", + .text = "Character used to fill unused parts of window." + }, + { .name = "main-pane-height", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, diff --git a/options.c b/options.c index 865ab01f..f9cf2afd 100644 --- a/options.c +++ b/options.c @@ -1108,6 +1108,8 @@ options_push_changes(const char *name) struct window_pane *wp; int c; + log_debug("%s: %s", __func__, name); + if (strcmp(name, "automatic-rename") == 0) { RB_FOREACH(w, windows, &windows) { if (w->active == NULL) @@ -1130,6 +1132,10 @@ options_push_changes(const char *name) &wp->screen->default_mode); } } + if (strcmp(name, "fill-character") == 0) { + RB_FOREACH(w, windows, &windows) + window_set_fill_character(w); + } if (strcmp(name, "key-table") == 0) { TAILQ_FOREACH(loop, &clients, entry) server_client_set_key_table(loop, NULL); diff --git a/screen-redraw.c b/screen-redraw.c index ef79d9aa..c4906ab8 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -47,11 +47,16 @@ enum screen_redraw_border_type { /* Get cell border character. */ static void -screen_redraw_border_set(struct window_pane *wp, enum pane_lines pane_lines, - int cell_type, struct grid_cell *gc) +screen_redraw_border_set(struct window *w, struct window_pane *wp, + enum pane_lines pane_lines, int cell_type, struct grid_cell *gc) { u_int idx; + if (cell_type == CELL_OUTSIDE && w->fill_character != NULL) { + utf8_copy(&gc->data, &w->fill_character[0]); + return; + } + switch (pane_lines) { case PANE_LINES_NUMBER: if (cell_type == CELL_OUTSIDE) { @@ -409,7 +414,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, else py = wp->yoff + wp->sy; cell_type = screen_redraw_type_of_cell(c, px, py, pane_status); - screen_redraw_border_set(wp, pane_lines, cell_type, &gc); + screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc); screen_write_cell(&ctx, &gc); } gc.attr &= ~GRID_ATTR_CHARSET; @@ -690,7 +695,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) screen_redraw_check_is(x, y, pane_status, marked_pane.wp)) gc.attr ^= GRID_ATTR_REVERSE; } - screen_redraw_border_set(wp, ctx->pane_lines, cell_type, &gc); + screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc); if (cell_type == CELL_TOPBOTTOM && (c->flags & CLIENT_UTF8) && diff --git a/tmux.1 b/tmux.1 index a7a6846f..a3a37e1e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4117,6 +4117,9 @@ Set clock colour. .Xc Set clock hour format. .Pp +.It Ic fill-character Ar character +Set the character used to fill areas of the terminal unused by a window. +.Pp .It Ic main-pane-height Ar height .It Ic main-pane-width Ar width Set the width or height of the main (left or top) pane in the diff --git a/tmux.h b/tmux.h index 8a8535dd..e23ad3a1 100644 --- a/tmux.h +++ b/tmux.h @@ -1070,40 +1070,41 @@ RB_HEAD(window_pane_tree, window_pane); /* Window structure. */ struct window { - u_int id; - void *latest; + u_int id; + void *latest; - char *name; - struct event name_event; - struct timeval name_time; + char *name; + struct event name_event; + struct timeval name_time; - struct event alerts_timer; - struct event offset_timer; + struct event alerts_timer; + struct event offset_timer; - struct timeval activity_time; + struct timeval activity_time; - struct window_pane *active; - struct window_pane *last; - struct window_panes panes; + struct window_pane *active; + struct window_pane *last; + struct window_panes panes; - int lastlayout; - struct layout_cell *layout_root; - struct layout_cell *saved_layout_root; - char *old_layout; + int lastlayout; + struct layout_cell *layout_root; + struct layout_cell *saved_layout_root; + char *old_layout; - u_int sx; - u_int sy; - u_int manual_sx; - u_int manual_sy; - u_int xpixel; - u_int ypixel; + u_int sx; + u_int sy; + u_int manual_sx; + u_int manual_sy; + u_int xpixel; + u_int ypixel; - u_int new_sx; - u_int new_sy; - u_int new_xpixel; - u_int new_ypixel; + u_int new_sx; + u_int new_sy; + u_int new_xpixel; + u_int new_ypixel; - int flags; + struct utf8_data *fill_character; + int flags; #define WINDOW_BELL 0x1 #define WINDOW_ACTIVITY 0x2 #define WINDOW_SILENCE 0x4 @@ -1112,15 +1113,15 @@ struct window { #define WINDOW_RESIZE 0x20 #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) - int alerts_queued; - TAILQ_ENTRY(window) alerts_entry; + int alerts_queued; + TAILQ_ENTRY(window) alerts_entry; - struct options *options; + struct options *options; - u_int references; - TAILQ_HEAD(, winlink) winlinks; + u_int references; + TAILQ_HEAD(, winlink) winlinks; - RB_ENTRY(window) entry; + RB_ENTRY(window) entry; }; RB_HEAD(windows, window); @@ -2977,6 +2978,7 @@ void *window_pane_get_new_data(struct window_pane *, struct window_pane_offset *, size_t *); void window_pane_update_used_data(struct window_pane *, struct window_pane_offset *, size_t); +void window_set_fill_character(struct window *); /* layout.c */ u_int layout_count_cells(struct layout_cell *); diff --git a/window.c b/window.c index fcc61c2a..bce8913a 100644 --- a/window.c +++ b/window.c @@ -329,6 +329,7 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) w->id = next_window_id++; RB_INSERT(windows, &windows, w); + window_set_fill_character(w); window_update_activity(w); log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy, @@ -360,6 +361,7 @@ window_destroy(struct window *w) event_del(&w->offset_timer); options_free(w->options); + free(w->fill_character); free(w->name); free(w); @@ -1599,3 +1601,20 @@ window_pane_update_used_data(struct window_pane *wp, size = EVBUFFER_LENGTH(wp->event->input) - used; wpo->used += size; } + +void +window_set_fill_character(struct window *w) +{ + const char *value; + struct utf8_data *ud; + + free(w->fill_character); + w->fill_character = NULL; + + value = options_get_string(w->options, "fill-character"); + if (*value != '\0' && utf8_isvalid(value)) { + ud = utf8_fromcstr(value); + if (ud != NULL && ud[0].width == 1) + w->fill_character = ud; + } +} From c0508c9321d2bd3b94a850d953db9532854b45cd Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 17 Mar 2022 11:35:37 +0000 Subject: [PATCH 30/40] Add an option (scroll-on-clear) to control if tmux scrolls into history on clear, from Robert Lange in GitHub issue 3121. --- options-table.c | 8 ++++++++ screen-write.c | 6 +++++- tmux.1 | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index 3aa72e78..a816f6ac 100644 --- a/options-table.c +++ b/options-table.c @@ -1080,6 +1080,14 @@ const struct options_table_entry options_table[] = { "remain-on-exit is enabled." }, + { .name = "scroll-on-clear", + .type = OPTIONS_TABLE_FLAG, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .default_num = 1, + .text = "Whether the contents of the screen should be scrolled into" + "history when clearing the whole screen." + }, + { .name = "synchronize-panes", .type = OPTIONS_TABLE_FLAG, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, diff --git a/screen-write.c b/screen-write.c index 0d70f668..aa898f78 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1427,7 +1427,11 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) ttyctx.bg = bg; /* Scroll into history if it is enabled and clearing entire screen. */ - if (s->cx == 0 && s->cy == 0 && (gd->flags & GRID_HISTORY)) + if (s->cx == 0 && + s->cy == 0 && + (gd->flags & GRID_HISTORY) && + ctx->wp != NULL && + options_get_number(ctx->wp->options, "scroll-on-clear")) grid_view_clear_history(gd, bg); else { if (s->cx <= sx - 1) diff --git a/tmux.1 b/tmux.1 index a3a37e1e..abaeb49c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4479,6 +4479,12 @@ Set the text shown at the bottom of exited panes when .Ic remain-on-exit is enabled. .Pp +.It Xo Ic scroll-on-clear +.Op Ic on | off +.Xc +When the entire screen is cleared and this option is on, scroll the contents of +the screen into history before clearing it. +.Pp .It Xo Ic synchronize-panes .Op Ic on | off .Xc From 60a0a904e007390b8fba484eea9461bf095bff7a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 17 Mar 2022 13:39:13 +0000 Subject: [PATCH 31/40] Check scroll-on-clear for ED also. --- screen-write.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/screen-write.c b/screen-write.c index aa898f78..6b6a750e 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1479,7 +1479,9 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg) ttyctx.bg = bg; /* Scroll into history if it is enabled. */ - if (s->grid->flags & GRID_HISTORY) + if ((s->grid->flags & GRID_HISTORY) && + ctx->wp != NULL && + options_get_number(ctx->wp->options, "scroll-on-clear")) grid_view_clear_history(s->grid, bg); else grid_view_clear(s->grid, 0, 0, sx, sy, bg); From 89a0046ad360d7a499732e327bae69b7e4b2536e Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 24 Mar 2022 09:05:57 +0000 Subject: [PATCH 32/40] Add a capability for OSC 7 and use it similarly to how the title is set (and controlled by the same set-titles option). GitHub issue 3127. --- server-client.c | 25 ++++++++++++++++++++++++- tmux.1 | 7 +++++++ tmux.h | 3 +++ tty-features.c | 13 +++++++++++++ tty-term.c | 1 + tty.c | 12 ++++++++++++ 6 files changed, 60 insertions(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index 3b888d01..2350a982 100644 --- a/server-client.c +++ b/server-client.c @@ -40,6 +40,7 @@ static void server_client_check_exit(struct client *); static void server_client_check_redraw(struct client *); static void server_client_check_modes(struct client *); static void server_client_set_title(struct client *); +static void server_client_set_path(struct client *); static void server_client_reset_state(struct client *); static int server_client_assume_paste(struct session *); static void server_client_update_latest(struct client *); @@ -2600,8 +2601,10 @@ server_client_check_redraw(struct client *c) } if (c->flags & CLIENT_ALLREDRAWFLAGS) { - if (options_get_number(s->options, "set-titles")) + if (options_get_number(s->options, "set-titles")) { server_client_set_title(c); + server_client_set_path(c); + } screen_redraw_screen(c); } @@ -2647,6 +2650,26 @@ server_client_set_title(struct client *c) format_free(ft); } +/* Set client path. */ +static void +server_client_set_path(struct client *c) +{ + struct session *s = c->session; + const char *path; + + if (s->curw == NULL) + return; + if (s->curw->window->active->base.path == NULL) + path = ""; + else + path = s->curw->window->active->base.path; + if (c->path == NULL || strcmp(path, c->path) != 0) { + free(c->path); + c->path = xstrdup(path); + tty_set_path(&c->tty, c->path); + } +} + /* Dispatch message from client. */ static void server_client_dispatch(struct imsg *imsg, void *arg) diff --git a/tmux.1 b/tmux.1 index abaeb49c..3503242c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3627,6 +3627,8 @@ Supports DECSLRM margins. Supports .Xr xterm 1 mouse sequences. +.It osc7 +Supports the OSC 7 working directory extension. .It overline Supports the overline SGR attribute. .It rectfill @@ -6394,6 +6396,11 @@ $ printf '\e033[4 q' If .Em Se is not set, \&Ss with argument 0 will be used to reset the cursor style instead. +.It Em \&Swd +Set the opening sequence for the working directory notification. +The sequence is terminated using the standard +.Em fsl +capability. .It Em \&Sync Start (parameter is 1) or end (parameter is 2) a synchronized update. .It Em \&Tc diff --git a/tmux.h b/tmux.h index e23ad3a1..370c7773 100644 --- a/tmux.h +++ b/tmux.h @@ -540,6 +540,7 @@ enum tty_code_code { TTYC_SMULX, TTYC_SMXX, TTYC_SS, + TTYC_SWD, TTYC_SYNC, TTYC_TC, TTYC_TSL, @@ -1709,6 +1710,7 @@ struct client { struct format_job_tree *jobs; char *title; + char *path; const char *cwd; char *term_name; @@ -2259,6 +2261,7 @@ void tty_start_tty(struct tty *); void tty_send_requests(struct tty *); void tty_stop_tty(struct tty *); void tty_set_title(struct tty *, const char *); +void tty_set_path(struct tty *, const char *); void tty_update_mode(struct tty *, int, struct screen *); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int, u_int, u_int, const struct grid_cell *, struct colour_palette *); diff --git a/tty-features.c b/tty-features.c index 3aca2520..4d83a465 100644 --- a/tty-features.c +++ b/tty-features.c @@ -53,6 +53,18 @@ static const struct tty_feature tty_feature_title = { 0 }; +/* Terminal has OSC 7 working directory. */ +static const char *tty_feature_osc7_capabilities[] = { + "Swd=\\E]7;", + "fsl=\\a", + NULL +}; +static const struct tty_feature tty_feature_osc7 = { + "osc7", + tty_feature_osc7_capabilities, + 0 +}; + /* Terminal has mouse support. */ static const char *tty_feature_mouse_capabilities[] = { "kmous=\\E[M", @@ -249,6 +261,7 @@ static const struct tty_feature *tty_features[] = { &tty_feature_focus, &tty_feature_margins, &tty_feature_mouse, + &tty_feature_osc7, &tty_feature_overline, &tty_feature_rectfill, &tty_feature_rgb, diff --git a/tty-term.c b/tty-term.c index 8e07da05..fdf0c4fa 100644 --- a/tty-term.c +++ b/tty-term.c @@ -277,6 +277,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { [TTYC_SMUL] = { TTYCODE_STRING, "smul" }, [TTYC_SMXX] = { TTYCODE_STRING, "smxx" }, [TTYC_SS] = { TTYCODE_STRING, "Ss" }, + [TTYC_SWD] = { TTYCODE_STRING, "Swd" }, [TTYC_SYNC] = { TTYCODE_STRING, "Sync" }, [TTYC_TC] = { TTYCODE_FLAG, "Tc" }, [TTYC_TSL] = { TTYCODE_STRING, "tsl" }, diff --git a/tty.c b/tty.c index 40735ceb..ea10e61e 100644 --- a/tty.c +++ b/tty.c @@ -655,6 +655,18 @@ tty_set_title(struct tty *tty, const char *title) tty_putcode(tty, TTYC_FSL); } +void +tty_set_path(struct tty *tty, const char *title) +{ + if (!tty_term_has(tty->term, TTYC_SWD) || + !tty_term_has(tty->term, TTYC_FSL)) + return; + + tty_putcode(tty, TTYC_SWD); + tty_puts(tty, title); + tty_putcode(tty, TTYC_FSL); +} + static void tty_force_cursor_colour(struct tty *tty, int c) { From d4eda7f9e5d33c613bb22770a677779ffbe9b363 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 24 Mar 2022 12:07:25 +0000 Subject: [PATCH 33/40] Add unit (milliseconds) to escape-time, show unset colours as "none" rather than "invalid" and don't show the same text twice for user options in customize mode. --- colour.c | 2 +- options-table.c | 1 + window-customize.c | 4 +--- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/colour.c b/colour.c index 6ede25da..a282d182 100644 --- a/colour.c +++ b/colour.c @@ -128,7 +128,7 @@ colour_tostring(int c) u_char r, g, b; if (c == -1) - return ("invalid"); + return ("none"); if (c & COLOUR_FLAG_RGB) { colour_split_rgb(c, &r, &g, &b); diff --git a/options-table.c b/options-table.c index a816f6ac..17be7ec4 100644 --- a/options-table.c +++ b/options-table.c @@ -277,6 +277,7 @@ const struct options_table_entry options_table[] = { .minimum = 0, .maximum = INT_MAX, .default_num = 500, + .unit = "milliseconds", .text = "Time to wait before assuming a key is Escape." }, diff --git a/window-customize.c b/window-customize.c index 98387e50..4a16e90c 100644 --- a/window-customize.c +++ b/window-customize.c @@ -680,9 +680,7 @@ window_customize_draw_option(struct window_customize_modedata *data, } ft = format_create_from_state(NULL, NULL, &fs); - if (oe == NULL) - text = "This is a user option."; - else if (oe->text == NULL) + if (oe == NULL || oe->text == NULL) text = "This option doesn't have a description."; else text = oe->text; From 98de5784a0a35681b736dc11bb6758a08d428562 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 25 Mar 2022 06:14:42 +0000 Subject: [PATCH 34/40] Fix exit message if creating socket fails. --- server.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server.c b/server.c index 29bcf88a..2db5a8d8 100644 --- a/server.c +++ b/server.c @@ -230,10 +230,10 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base, if (cause != NULL) { if (c != NULL) { - cmdq_append(c, cmdq_get_error(cause)); + c->exit_message = cause; c->flags |= CLIENT_EXIT; - } - free(cause); + } else + free(cause); } evtimer_set(&server_ev_tidy, server_tidy_event, NULL); From 1c69a91c25654339a0e670ed5a1495d52b37eb8e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 28 Mar 2022 08:42:13 +0100 Subject: [PATCH 35/40] Add support for systemd socket activation (where systemd creates the Unix domain socket for tmux rather than tmux creating it). Build with --enable-systemd. From Julien Moutinho in GitHub issue 3119. --- Makefile.am | 5 +++++ compat.h | 5 +++++ compat/systemd.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 25 +++++++++++++++++++++ server.c | 6 ++++- tmux.h | 1 + 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 compat/systemd.c diff --git a/Makefile.am b/Makefile.am index 68494932..5bdd9d5f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -204,6 +204,11 @@ if NEED_FORKPTY nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c endif +# Add compat file for systemd. +if HAVE_SYSTEMD +nodist_tmux_SOURCES += compat/systemd.c +endif + # Add compat file for utf8proc. if HAVE_UTF8PROC nodist_tmux_SOURCES += compat/utf8proc.c diff --git a/compat.h b/compat.h index be726831..6eb97619 100644 --- a/compat.h +++ b/compat.h @@ -421,6 +421,11 @@ void *reallocarray(void *, size_t, size_t); void *recallocarray(void *, size_t, size_t, size_t); #endif +#ifdef HAVE_SYSTEMD +/* systemd.c */ +int systemd_create_socket(int, char **); +#endif + #ifdef HAVE_UTF8PROC /* utf8proc.c */ int utf8proc_wcwidth(wchar_t); diff --git a/compat/systemd.c b/compat/systemd.c new file mode 100644 index 00000000..7317e43a --- /dev/null +++ b/compat/systemd.c @@ -0,0 +1,58 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2022 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include + +#include "tmux.h" + +int +systemd_create_socket(int flags, char **cause) +{ + int fds; + int fd; + struct sockaddr_un sa; + int addrlen = sizeof sa; + + fds = sd_listen_fds(0); + if (fds > 1) { /* too many file descriptors */ + errno = E2BIG; + goto fail; + } + + if (fds == 1) { /* socket-activated */ + fd = SD_LISTEN_FDS_START; + if (!sd_is_socket_unix(fd, SOCK_STREAM, 1, NULL, 0)) { + errno = EPFNOSUPPORT; + goto fail; + } + if (getsockname(fd, (struct sockaddr *)&sa, &addrlen) == -1) + goto fail; + socket_path = xstrdup(sa.sun_path); + return (fd); + } + + return (server_create_socket(flags, cause)); + +fail: + if (cause != NULL) + xasprintf(cause, "systemd socket error (%s)", strerror(errno)); + return (-1); +} diff --git a/configure.ac b/configure.ac index a9c035d7..20199515 100644 --- a/configure.ac +++ b/configure.ac @@ -390,6 +390,31 @@ if test "x$enable_utf8proc" = xyes; then fi AM_CONDITIONAL(HAVE_UTF8PROC, [test "x$enable_utf8proc" = xyes]) +# Check for systemd support. +AC_ARG_ENABLE( + systemd, + AS_HELP_STRING(--enable-systemd, enable systemd integration) +) +if test x"$enable_systemd" = xyes; then + PKG_CHECK_MODULES( + SYSTEMD, + libsystemd, + [ + AM_CPPFLAGS="$SYSTEMD_CFLAGS $AM_CPPFLAGS" + CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS" + LIBS="$SYSTEMD_LIBS $LIBS" + found_systemd=yes + ], + found_systemd=no + ) + if test "x$found_systemd" = xyes; then + AC_DEFINE(HAVE_SYSTEMD) + else + AC_MSG_ERROR("systemd not found") + fi +fi +AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$found_systemd" = xyes]) + # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. AC_MSG_CHECKING(for b64_ntop) AC_LINK_IFELSE([AC_LANG_PROGRAM( diff --git a/server.c b/server.c index 2db5a8d8..bf3a8361 100644 --- a/server.c +++ b/server.c @@ -100,7 +100,7 @@ server_check_marked(void) } /* Create server socket. */ -static int +int server_create_socket(int flags, char **cause) { struct sockaddr_un sa; @@ -214,7 +214,11 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base, gettimeofday(&start_time, NULL); +#ifdef HAVE_SYSTEMD + server_fd = systemd_create_socket(flags, &cause); +#else server_fd = server_create_socket(flags, &cause); +#endif if (server_fd != -1) server_update_socket(); if (~flags & CLIENT_NOFORK) diff --git a/tmux.h b/tmux.h index 370c7773..f16b5250 100644 --- a/tmux.h +++ b/tmux.h @@ -2583,6 +2583,7 @@ int server_start(struct tmuxproc *, int, struct event_base *, int, char *); void server_update_socket(void); void server_add_accept(int); void printflike(1, 2) server_add_message(const char *, ...); +int server_create_socket(int, char **); /* server-client.c */ RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp); From 880abd0ec2d4ce5c79645d59a6ba0fe08c0734aa Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 28 Mar 2022 07:40:57 +0000 Subject: [PATCH 36/40] Report error if creating socket fails with -D. --- server.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server.c b/server.c index bf3a8361..5b70dcd0 100644 --- a/server.c +++ b/server.c @@ -236,8 +236,10 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base, if (c != NULL) { c->exit_message = cause; c->flags |= CLIENT_EXIT; - } else - free(cause); + } else { + fprintf(stderr, "%s\n", cause); + exit(1); + } } evtimer_set(&server_ev_tidy, server_tidy_event, NULL); From 2df7bc14fa43def1e4bb334f25bdb2191a4af799 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 30 Mar 2022 07:05:26 +0000 Subject: [PATCH 37/40] Capture up to used size not available size for each line. --- grid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid.c b/grid.c index 91dc8f42..1109ac58 100644 --- a/grid.c +++ b/grid.c @@ -1003,7 +1003,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, gl = grid_peek_line(gd, py); for (xx = px; xx < px + nx; xx++) { - if (gl == NULL || xx >= gl->cellsize) + if (gl == NULL || xx >= gl->cellused) break; grid_get_cell(gd, xx, py, &gc); if (gc.flags & GRID_FLAG_PADDING) From fc6580574e88d27e481b9fa70eadc443f59ef1b5 Mon Sep 17 00:00:00 2001 From: naddy Date: Thu, 31 Mar 2022 17:27:27 +0000 Subject: [PATCH 38/40] man pages: add missing commas between subordinate and main clauses jmc@ dislikes a comma before "then" in a conditional, so leave those untouched. ok jmc@ --- tmux.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 3503242c..ae6b6fb8 100644 --- a/tmux.1 +++ b/tmux.1 @@ -43,7 +43,7 @@ then later reattached. .Pp When .Nm -is started it creates a new +is started, it creates a new .Em session with a single .Em window @@ -5918,7 +5918,7 @@ does not surround the popup by a border. sets the type of border line for the popup. When .Fl B -is specified the +is specified, the .Fl b option is ignored. See @@ -6639,7 +6639,7 @@ are replaced with underscores For input, .Nm always runs with a UTF-8 locale. -If en_US.UTF-8 is provided by the operating system it is used and +If en_US.UTF-8 is provided by the operating system, it is used and .Ev LC_CTYPE is ignored for input. Otherwise, From 1e9c3b3c63b9fb98bcf02eb8b09d1cefb0b72d26 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 1 Apr 2022 10:11:59 +0000 Subject: [PATCH 39/40] Preserve CRLF flag when respawning. --- screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen.c b/screen.c index 7046e098..62cf4765 100644 --- a/screen.c +++ b/screen.c @@ -103,7 +103,7 @@ screen_reinit(struct screen *s) s->rupper = 0; s->rlower = screen_size_y(s) - 1; - s->mode = MODE_CURSOR|MODE_WRAP; + s->mode = MODE_CURSOR|MODE_WRAP|(s->mode & MODE_CRLF); if (options_get_number(global_options, "extended-keys") == 2) s->mode |= MODE_KEXTENDED; From 39b1e96b453a535a8f7b5542dbb49f82c729f24c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 6 Apr 2022 14:24:17 +0100 Subject: [PATCH 40/40] Add to CHANGES. --- CHANGES | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CHANGES b/CHANGES index 159ab905..3c682e5f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,35 @@ CHANGES FROM 3.2a TO 3.3 +* Add an option (default off) to control the passthrough escape sequence. + +* Support more mouse buttons when the terminal sends them. + +* Add a window-resized hook which is fired when the window is actually resized + which may be later than the client resize. + +* Add next_session_id format with the next session ID. + +* Add formats for client and server UID and user. + +* Add argument to refresh-client -l to forward clipboard to a pane. + +* Add remain-on-exit-format to set text shown when pane is dead. + +* With split-window -f use percentages of window size not pane size. + +* Add an option (fill-character) to set the character used for unused areas of + a client. + +* Add an option (scroll-on-clear) to control if tmux scrolls into history on + clear. + +* Add a capability for OSC 7 and use it similarly to how the title is set (and + controlled by the same set-titles option). + +* Add support for systemd socket activation (where systemd creates the Unix + domain socket for tmux rather than tmux creating it). Build with + --enable-systemd. + * Add an option (pane-border-indicators) to select how the active pane is shown on the pane border (colour, arrows or both).