diff --git a/Makefile.am b/Makefile.am index b59ca9e9..279fe144 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,17 +20,23 @@ LDADD = $(LIBOBJS) # Set flags for gcc. if IS_GCC -AM_CFLAGS += -std=gnu99 -O2 +AM_CFLAGS += -std=gnu99 +if IS_OPTIMIZED +AM_CFLAGS += -O2 +else +AM_CFLAGS += -O0 +endif if IS_DEBUG AM_CFLAGS += -g -AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2 +AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2 -Wno-use-after-free AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare -AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align +AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wno-cast-align AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes -AM_CFLAGS += -Wno-unused-result -Wno-format-y2k +AM_CFLAGS += -Wno-unused-result -Wno-format-y2k -Wno-unknown-warning-option +AM_CFLAGS += -Wno-maybe-uninitialized if IS_DARWIN -AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align -Wno-macro-redefined +AM_CFLAGS += -Wno-deprecated-declarations -Wno-macro-redefined endif AM_CPPFLAGS += -DDEBUG endif diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 85a1bf8a..e5c2b12c 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -42,8 +42,8 @@ const struct cmd_entry cmd_command_prompt_entry = { .name = "command-prompt", .alias = NULL, - .args = { "1bFkliI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse }, - .usage = "[-1bFkliN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE + .args = { "1beFiklI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse }, + .usage = "[-1beFiklN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [-T prompt-type] [template]", .flags = CMD_CLIENT_TFLAG, @@ -84,7 +84,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) struct client *tc = cmdq_get_target_client(item); struct cmd_find_state *target = cmdq_get_target(item); const char *type, *s, *input; - struct cmd_command_prompt_cdata *cdata; + struct cmd_command_prompt_cdata *cdata; char *tmp, *prompts, *prompt, *next_prompt; char *inputs = NULL, *next_input; u_int count = args_count(args); @@ -163,6 +163,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) cdata->flags |= PROMPT_INCREMENTAL; else if (args_has(args, 'k')) cdata->flags |= PROMPT_KEY; + else if (args_has(args, 'e')) + cdata->flags |= PROMPT_BSPACE_EXIT; status_prompt_set(tc, target, cdata->prompts[0].prompt, cdata->prompts[0].input, cmd_command_prompt_callback, cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type); @@ -234,7 +236,7 @@ out: static void cmd_command_prompt_free(void *data) { - struct cmd_command_prompt_cdata *cdata = data; + struct cmd_command_prompt_cdata *cdata = data; u_int i; for (i = 0; i < cdata->count; i++) { diff --git a/configure.ac b/configure.ac index e6d4b548..fa474825 100644 --- a/configure.ac +++ b/configure.ac @@ -64,6 +64,15 @@ AC_ARG_ENABLE( ) AM_CONDITIONAL(IS_DEBUG, test "x$enable_debug" = xyes) +# Is this --enable-optimizations? +AC_ARG_ENABLE( + optimizations, + AS_HELP_STRING(--enable-optimizations, enable optimization build flags), + , + enable_optimizations=yes +) +AM_CONDITIONAL(IS_OPTIMIZED, test "x$enable_optimizations" = xyes) + # Is this a static build? AC_ARG_ENABLE( static, diff --git a/format.c b/format.c index 9d60c3f7..10602ed4 100644 --- a/format.c +++ b/format.c @@ -454,6 +454,20 @@ format_job_tidy(struct format_job_tree *jobs, int force) } } +/* Work around needless -Wformat-nonliteral gcc warning. */ +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif +static size_t +format_strftime(char *s, size_t max, const char *fmt, const struct tm *tm) +{ + return (strftime(s, max, fmt, tm)); +} +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + /* Tidy old jobs for all clients. */ void format_tidy_jobs(void) @@ -3963,7 +3977,7 @@ found: else { if (time_format != NULL) { localtime_r(&t, &tm); - strftime(s, sizeof s, time_format, &tm); + format_strftime(s, sizeof s, time_format, &tm); } else { ctime_r(&t, s); s[strcspn(s, "\n")] = '\0'; @@ -5540,7 +5554,8 @@ format_expand1(struct format_expand_state *es, const char *fmt) es->time = time(NULL); localtime_r(&es->time, &es->tm); } - if (strftime(expanded, sizeof expanded, fmt, &es->tm) == 0) { + if (format_strftime(expanded, sizeof expanded, fmt, + &es->tm) == 0) { format_log(es, "format is too long"); return (xstrdup("")); } diff --git a/key-bindings.c b/key-bindings.c index de17c326..1fa568f3 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -49,6 +49,8 @@ " '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}' '<' {send -X history-top}" \ " '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}' '>' {send -X history-bottom}" \ " ''" \ + " '#{?#{&&:#{buffer_size},#{!:#{pane_in_mode}}},Paste #[underscore]#{=/9/...:buffer_sample},}' 'p' {paste-buffer}" \ + " ''" \ " '#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}' 'C-r' {if -F '#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}' 'copy-mode -t='; send -Xt= search-backward -- \"#{q:mouse_word}\"}" \ " '#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}' 'C-y' {copy-mode -q; send-keys -l -- \"#{q:mouse_word}\"}" \ " '#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}' 'c' {copy-mode -q; set-buffer -- \"#{q:mouse_word}\"}" \ diff --git a/regress/border-arrows.sh b/regress/border-arrows.sh new file mode 100644 index 00000000..7e7bffd0 --- /dev/null +++ b/regress/border-arrows.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# Test for GitHub issue #4780 - pane-border-indicators both arrows missing +# on second pane in a two-pane horizontal split. +# +# When pane-border-indicators is set to "both", arrow indicators should +# appear when EITHER pane is selected. Before the fix, arrows only appeared +# when the LEFT pane was selected. + +PATH=/bin:/usr/bin +TERM=screen + +[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) +TMUX="$TEST_TMUX -Ltest" +$TMUX kill-server 2>/dev/null +TMUX_OUTER="$TEST_TMUX -Ltest2" +$TMUX_OUTER kill-server 2>/dev/null + +trap "$TMUX kill-server 2>/dev/null; $TMUX_OUTER kill-server 2>/dev/null" 0 1 15 + +# Start outer tmux that will capture the inner tmux's rendering +$TMUX_OUTER -f/dev/null new -d -x80 -y24 "$TMUX -f/dev/null new -x78 -y22" || exit 1 +sleep 1 + +# Set pane-border-indicators to "both" in inner tmux +$TMUX set -g pane-border-indicators both || exit 1 + +# Create horizontal split (two panes side by side) +$TMUX splitw -h || exit 1 +sleep 1 + +# Helper to check for arrow characters in captured output +has_arrow() { + echo "$1" | grep -qE '(←|→|↑|↓)' +} + +# Test 1: Select left pane (pane 0) and check for arrows +$TMUX selectp -t 0 +sleep 1 +left_output=$($TMUX_OUTER capturep -Cep 2>/dev/null) +has_arrow "$left_output" || exit 1 + +# Test 2: Select right pane (pane 1) and check for arrows +# This is the case that failed before the fix +$TMUX selectp -t 1 +sleep 1 +right_output=$($TMUX_OUTER capturep -Cep 2>/dev/null) +has_arrow "$right_output" || exit 1 + +$TMUX kill-server 2>/dev/null +$TMUX_OUTER kill-server 2>/dev/null +exit 0 diff --git a/screen-redraw.c b/screen-redraw.c index 96f7b915..ea232830 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -98,7 +98,7 @@ screen_redraw_border_set(struct window *w, struct window_pane *wp, } } -/* Return if window has only two panes. */ +/* Return 1 if window has only two panes. */ static int screen_redraw_two_panes(struct window *w, enum layout_type *type) { @@ -196,7 +196,7 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp, if ((int)px == wp->xoff + (int)wp->sx + sb_w - 1) return (SCREEN_REDRAW_BORDER_RIGHT); } - } else { /* sb_pos == PANE_SCROLLBARS_RIGHT or none. */ + } else { /* sb_pos == PANE_SCROLLBARS_RIGHT or disabled */ if (wp->xoff == 0 && px == wp->sx + sb_w) if (!hsplit || (hsplit && py <= wp->sy / 2)) return (SCREEN_REDRAW_BORDER_RIGHT); @@ -900,6 +900,79 @@ screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x, return (&wp->border_gc); } +/* Draw arrow indicator if enabled. */ +static void +screen_redraw_draw_border_arrows(struct screen_redraw_ctx *ctx, u_int i, + u_int j, u_int cell_type, struct window_pane *wp, + struct window_pane *active, struct grid_cell *gc) +{ + struct client *c = ctx->c; + struct session *s = c->session; + struct window *w = s->curw->window; + struct options *oo = w->options; + u_int x = ctx->ox + i, y = ctx->oy + j; + int value, arrows = 0, border; + enum layout_type type; + + if (wp == NULL) + return; + if ((int)i != wp->xoff + 1 && (int)j != wp->yoff + 1) + return; + + value = options_get_number(oo, "pane-border-indicators"); + if (value != PANE_BORDER_ARROWS && value != PANE_BORDER_BOTH) + return; + + border = screen_redraw_pane_border(ctx, active, x, y); + if (border == SCREEN_REDRAW_INSIDE) + return; + + if ((int)i == wp->xoff + 1) { + if (border == SCREEN_REDRAW_OUTSIDE) { + if (screen_redraw_two_panes(wp->window, &type)) { + if (active == TAILQ_FIRST(&w->panes)) + border = SCREEN_REDRAW_BORDER_BOTTOM; + else + border = SCREEN_REDRAW_BORDER_TOP; + arrows = 1; + } + } else { + if (cell_type == CELL_LEFTRIGHT) + arrows = 1; + else if (cell_type == CELL_TOPJOIN && + border == SCREEN_REDRAW_BORDER_BOTTOM) + arrows = 1; + else if (cell_type == CELL_BOTTOMJOIN && + border == SCREEN_REDRAW_BORDER_TOP) + arrows = 1; + } + } + if ((int)j == wp->yoff + 1) { + if (border == SCREEN_REDRAW_OUTSIDE) { + if (screen_redraw_two_panes(wp->window, 0)) { + if (active == TAILQ_FIRST(&w->panes)) + border = SCREEN_REDRAW_BORDER_RIGHT; + else + border = SCREEN_REDRAW_BORDER_LEFT; + arrows = 1; + } + } else { + if (cell_type == CELL_TOPBOTTOM) + arrows = 1; + else if (cell_type == CELL_LEFTJOIN && + border == SCREEN_REDRAW_BORDER_RIGHT) + arrows = 1; + else if (cell_type == CELL_RIGHTJOIN && + border == SCREEN_REDRAW_BORDER_LEFT) + arrows = 1; + } + } + if (arrows) { + gc->attr |= GRID_ATTR_CHARSET; + utf8_set(&gc->data, BORDER_MARKERS[border]); + } +} + /* Draw a border cell. */ static void screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) @@ -915,7 +988,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) const struct grid_cell *tmp; struct overlay_ranges r; u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; - int arrows = 0, border, isolates; + int isolates; if (c->overlay_check != NULL) { c->overlay_check(c, c->overlay_data, x, y, 1, &r); @@ -963,32 +1036,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) if (isolates) tty_puts(tty, END_ISOLATE); - switch (options_get_number(oo, "pane-border-indicators")) { - case PANE_BORDER_ARROWS: - case PANE_BORDER_BOTH: - arrows = 1; - break; - } - - if (wp != NULL && arrows) { - border = screen_redraw_pane_border(ctx, active, x, y); - if ((((int)i == wp->xoff + 1 && - (cell_type == CELL_LEFTRIGHT || - (cell_type == CELL_TOPJOIN && - border == SCREEN_REDRAW_BORDER_BOTTOM) || - (cell_type == CELL_BOTTOMJOIN && - border == SCREEN_REDRAW_BORDER_TOP))) || - ((int)j == wp->yoff + 1 && - (cell_type == CELL_TOPBOTTOM || - (cell_type == CELL_LEFTJOIN && - border == SCREEN_REDRAW_BORDER_RIGHT) || - (cell_type == CELL_RIGHTJOIN && - border == SCREEN_REDRAW_BORDER_LEFT)))) && - screen_redraw_check_is(ctx, x, y, active)) { - gc.attr |= GRID_ATTR_CHARSET; - utf8_set(&gc.data, BORDER_MARKERS[border]); - } - } + screen_redraw_draw_border_arrows(ctx, i, j, cell_type, wp, active, &gc); tty_cell(tty, &gc, &grid_default_cell, NULL, NULL); if (isolates) diff --git a/screen-write.c b/screen-write.c index 9762f6dd..22d1874a 100644 --- a/screen-write.c +++ b/screen-write.c @@ -25,6 +25,8 @@ static struct screen_write_citem *screen_write_collect_trim( struct screen_write_ctx *, u_int, u_int, u_int, int *); +static void screen_write_collect_insert(struct screen_write_ctx *, + struct screen_write_citem *); static void screen_write_collect_clear(struct screen_write_ctx *, u_int, u_int); static void screen_write_collect_scroll(struct screen_write_ctx *, u_int); @@ -1334,7 +1336,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg) struct screen *s = ctx->s; struct grid_line *gl; u_int sx = screen_size_x(s); - struct screen_write_citem *ci = ctx->item, *before; + struct screen_write_citem *ci = ctx->item; if (s->cx == 0) { screen_write_clearline(ctx, bg); @@ -1352,16 +1354,11 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg) grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg); - before = screen_write_collect_trim(ctx, s->cy, s->cx, sx - s->cx, NULL); ci->x = s->cx; ci->used = sx - s->cx; ci->type = CLEAR; ci->bg = bg; - if (before == NULL) - TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); - else - TAILQ_INSERT_BEFORE(before, ci, entry); - ctx->item = screen_write_get_citem(); + screen_write_collect_insert(ctx, ci); } /* Clear to start of line from cursor. */ @@ -1370,7 +1367,7 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg) { struct screen *s = ctx->s; u_int sx = screen_size_x(s); - struct screen_write_citem *ci = ctx->item, *before; + struct screen_write_citem *ci = ctx->item; if (s->cx >= sx - 1) { screen_write_clearline(ctx, bg); @@ -1387,16 +1384,11 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg) else grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); - before = screen_write_collect_trim(ctx, s->cy, 0, s->cx + 1, NULL); ci->x = 0; ci->used = s->cx + 1; ci->type = CLEAR; ci->bg = bg; - if (before == NULL) - TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); - else - TAILQ_INSERT_BEFORE(before, ci, entry); - ctx->item = screen_write_get_citem(); + screen_write_collect_insert(ctx, ci); } /* Move cursor to px,py. */ @@ -1892,6 +1884,8 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, last = UINT_MAX; TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { + log_debug("collect list: x=%u (last %u), y=%u, used=%u", + ci->x, last, y, ci->used); if (last != UINT_MAX && ci->x <= last) { fatalx("collect list not in order: %u <= %u", ci->x, last); @@ -1948,29 +1942,39 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, log_debug("%s: flushed %u items (%s)", __func__, items, from); } -/* Finish and store collected cells. */ +/* Insert an item on current line. */ void -screen_write_collect_end(struct screen_write_ctx *ctx) +screen_write_collect_insert(struct screen_write_ctx *ctx, + struct screen_write_citem *ci) { struct screen *s = ctx->s; - struct screen_write_citem *ci = ctx->item, *nci, *before; struct screen_write_cline *cl = &s->write_list[s->cy]; - struct grid_cell gc; - u_int xx; - int wrapped = ci->wrapped; + struct screen_write_citem *before; - if (ci->used == 0) - return; - - before = screen_write_collect_trim(ctx, s->cy, s->cx, ci->used, - &wrapped); - ci->x = s->cx; - ci->wrapped = wrapped; + before = screen_write_collect_trim(ctx, s->cy, ci->x, ci->used, + &ci->wrapped); if (before == NULL) TAILQ_INSERT_TAIL(&cl->items, ci, entry); else TAILQ_INSERT_BEFORE(before, ci, entry); ctx->item = screen_write_get_citem(); +} + +/* Finish and store collected cells. */ +void +screen_write_collect_end(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + struct screen_write_citem *ci = ctx->item, *bci = NULL, *aci; + struct screen_write_cline *cl = &s->write_list[s->cy]; + struct grid_cell gc; + u_int xx; + + if (ci->used == 0) + return; + + ci->x = s->cx; + screen_write_collect_insert(ctx, ci); log_debug("%s: %u %.*s (at %u,%u)", __func__, ci->used, (int)ci->used, cl->data + ci->x, s->cx, s->cy); @@ -1982,27 +1986,28 @@ screen_write_collect_end(struct screen_write_ctx *ctx) break; grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); - log_debug("%s: padding erased (before) at %u", - __func__, xx); + log_debug("%s: padding erased (before) at %u (cx %u)", + __func__, xx, s->cx); } if (xx != s->cx) { if (xx == 0) grid_view_get_cell(s->grid, 0, s->cy, &gc); - if (gc.data.width > 1) { + if (gc.data.width > 1 || + (gc.flags & GRID_FLAG_PADDING)) { grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); - log_debug("%s: padding erased (before) at %u", - __func__, xx); + log_debug("%s: padding erased (before) at %u " + "(cx %u)", __func__, xx, s->cx); } } if (xx != s->cx) { - nci = ctx->item; - nci->type = CLEAR; - nci->x = xx; - nci->bg = 8; - nci->used = s->cx - xx; - TAILQ_INSERT_BEFORE(ci, nci, entry); - ctx->item = screen_write_get_citem(); + bci = ctx->item; + bci->type = CLEAR; + bci->x = xx; + bci->bg = 8; + bci->used = s->cx - xx; + log_debug("%s: padding erased (before): from %u, " + "size %u", __func__, bci->x, bci->used); } } @@ -2013,6 +2018,8 @@ screen_write_collect_end(struct screen_write_ctx *ctx) grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x, ci->used); + if (bci != NULL) + screen_write_collect_insert(ctx, bci); screen_write_set_cursor(ctx, s->cx + ci->used, -1); for (xx = s->cx; xx < screen_size_x(s); xx++) { @@ -2020,16 +2027,18 @@ screen_write_collect_end(struct screen_write_ctx *ctx) if (~gc.flags & GRID_FLAG_PADDING) break; grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); - log_debug("%s: padding erased (after) at %u", __func__, xx); + log_debug("%s: padding erased (after) at %u (cx %u)", + __func__, xx, s->cx); } if (xx != s->cx) { - nci = ctx->item; - nci->type = CLEAR; - nci->x = s->cx; - nci->bg = 8; - nci->used = xx - s->cx; - TAILQ_INSERT_AFTER(&cl->items, ci, nci, entry); - ctx->item = screen_write_get_citem(); + aci = ctx->item; + aci->type = CLEAR; + aci->x = s->cx; + aci->bg = 8; + aci->used = xx - s->cx; + log_debug("%s: padding erased (after): from %u, size %u", + __func__, aci->x, aci->used); + screen_write_collect_insert(ctx, aci); } } diff --git a/server-client.c b/server-client.c index ccd35c36..6c1a3273 100644 --- a/server-client.c +++ b/server-client.c @@ -311,6 +311,8 @@ server_client_create(int fd) evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); evtimer_set(&c->click_timer, server_client_click_timer, c); + c->click_wp = -1; + TAILQ_INIT(&c->input_requests); TAILQ_INSERT_TAIL(&clients, c, entry); @@ -759,21 +761,17 @@ server_client_check_mouse(struct client *c, struct key_event *event) if (c->flags & CLIENT_DOUBLECLICK) { evtimer_del(&c->click_timer); c->flags &= ~CLIENT_DOUBLECLICK; - if (m->b == c->click_button) { - type = SECOND; - x = m->x, y = m->y, b = m->b; - log_debug("second-click at %u,%u", x, y); - c->flags |= CLIENT_TRIPLECLICK; - } + type = SECOND; + x = m->x, y = m->y, b = m->b; + log_debug("second-click at %u,%u", x, y); + c->flags |= CLIENT_TRIPLECLICK; } else if (c->flags & CLIENT_TRIPLECLICK) { evtimer_del(&c->click_timer); c->flags &= ~CLIENT_TRIPLECLICK; - if (m->b == c->click_button) { - type = TRIPLE; - x = m->x, y = m->y, b = m->b; - log_debug("triple-click at %u,%u", x, y); - goto have_event; - } + type = TRIPLE; + x = m->x, y = m->y, b = m->b; + log_debug("triple-click at %u,%u", x, y); + goto have_event; } /* DOWN is the only remaining event type. */ @@ -783,17 +781,6 @@ server_client_check_mouse(struct client *c, struct key_event *event) log_debug("down at %u,%u", x, y); c->flags |= CLIENT_DOUBLECLICK; } - - if (KEYC_CLICK_TIMEOUT != 0) { - memcpy(&c->click_event, m, sizeof c->click_event); - c->click_button = m->b; - - log_debug("click timer started"); - tv.tv_sec = KEYC_CLICK_TIMEOUT / 1000; - tv.tv_usec = (KEYC_CLICK_TIMEOUT % 1000) * 1000L; - evtimer_del(&c->click_timer); - evtimer_add(&c->click_timer, &tv); - } } have_event: @@ -914,6 +901,34 @@ have_event: } } + /* Reset click type or add a click timer if needed. */ + if (type == DOWN || + type == SECOND || + type == TRIPLE) { + if (type != DOWN && + (m->b != c->click_button || + where != (enum mouse_where)c->click_where || + m->wp != c->click_wp)) { + type = DOWN; + log_debug("click sequence reset at %u,%u", x, y); + c->flags &= ~CLIENT_TRIPLECLICK; + c->flags |= CLIENT_DOUBLECLICK; + } + + if (type != TRIPLE && KEYC_CLICK_TIMEOUT != 0) { + memcpy(&c->click_event, m, sizeof c->click_event); + c->click_button = m->b; + c->click_where = where; + c->click_wp = m->wp; + + log_debug("click timer started"); + tv.tv_sec = KEYC_CLICK_TIMEOUT / 1000; + tv.tv_usec = (KEYC_CLICK_TIMEOUT % 1000) * 1000L; + evtimer_del(&c->click_timer); + evtimer_add(&c->click_timer, &tv); + } + } + /* Stop dragging if needed. */ if (type != DRAG && type != WHEEL && diff --git a/status.c b/status.c index 79ce9cad..edbb04ad 100644 --- a/status.c +++ b/status.c @@ -1383,6 +1383,11 @@ process_key: break; case KEYC_BSPACE: case 'h'|KEYC_CTRL: + if (c->prompt_flags & PROMPT_BSPACE_EXIT && size == 0) { + if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0) + status_prompt_clear(c); + break; + } if (c->prompt_index != 0) { if (c->prompt_index == size) c->prompt_buffer[--c->prompt_index].size = 0; diff --git a/tmux.1 b/tmux.1 index b8acaa38..d27a8ec9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6718,7 +6718,7 @@ See for possible values for .Ar prompt-type . .It Xo Ic command-prompt -.Op Fl 1bFiklN +.Op Fl 1beFiklN .Op Fl I Ar inputs .Op Fl p Ar prompts .Op Fl t Ar target-client @@ -6791,6 +6791,10 @@ makes the prompt only accept numeric key presses. .Fl i executes the command every time the prompt input changes instead of when the user exits the command prompt. +.Fl e +makes +.Em BSpace +cancel an empty prompt. .Pp .Fl T tells diff --git a/tmux.h b/tmux.h index 336b7b22..5b75043b 100644 --- a/tmux.h +++ b/tmux.h @@ -1984,6 +1984,8 @@ struct client { struct event repeat_timer; struct event click_timer; + int click_where; + int click_wp; u_int click_button; struct mouse_event click_event; @@ -2094,6 +2096,7 @@ struct client { #define PROMPT_KEY 0x10 #define PROMPT_ACCEPT 0x20 #define PROMPT_QUOTENEXT 0x40 +#define PROMPT_BSPACE_EXIT 0x80 int prompt_flags; enum prompt_type prompt_type; int prompt_cursor; diff --git a/window-clock.c b/window-clock.c index 81d33858..ecac43ec 100644 --- a/window-clock.c +++ b/window-clock.c @@ -228,7 +228,6 @@ window_clock_draw_screen(struct window_mode_entry *wme) struct screen *s = &data->screen; struct grid_cell gc; char tim[64], *ptr; - const char *timeformat; time_t t; struct tm *tm; u_int i, j, x, y, idx; @@ -242,20 +241,18 @@ window_clock_draw_screen(struct window_mode_entry *wme) tm = localtime(&t); if (style == 0 || style == 2) { if (style == 2) - timeformat = "%l:%M:%S "; + strftime(tim, sizeof tim, "%l:%M:%S ", localtime(&t)); else - timeformat = "%l:%M "; - strftime(tim, sizeof tim, timeformat, localtime(&t)); + strftime(tim, sizeof tim, "%l:%M ", localtime(&t)); if (tm->tm_hour >= 12) strlcat(tim, "PM", sizeof tim); else strlcat(tim, "AM", sizeof tim); } else { if (style == 3) - timeformat = "%H:%M:%S"; + strftime(tim, sizeof tim, "%H:%M:%S", tm); else - timeformat = "%H:%M"; - strftime(tim, sizeof tim, timeformat, tm); + strftime(tim, sizeof tim, "%H:%M", tm); } screen_write_clearscreen(&ctx, 8); diff --git a/window-copy.c b/window-copy.c index 81d84091..a47c9d4d 100644 --- a/window-copy.c +++ b/window-copy.c @@ -3237,6 +3237,15 @@ window_copy_command(struct window_mode_entry *wme, struct client *c, window_pane_reset_mode(wp); else if (action == WINDOW_COPY_CMD_REDRAW) window_copy_redraw_screen(wme); + else if (action == WINDOW_COPY_CMD_NOTHING) { + /* + * Nothing is not actually nothing - most commands at least + * move the cursor (what would be the point of a command that + * literally does nothing?) and in that case we need to redraw + * the first line to update the indicator. + */ + window_copy_redraw_lines(wme, 0, 1); + } } static void