From ee123c248951450100475717f5bd45f292d9bb4d Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 19 Apr 2015 21:05:27 +0000 Subject: Support setting the default window and pane background colours (window and active pane via window-style and window-active-style options, an individual pane by a new select-pane -P flag). From J Raynor. --- cmd-select-pane.c | 20 ++++++- options-table.c | 10 ++++ screen-redraw.c | 20 +++---- server-client.c | 3 +- tmux.1 | 41 ++++++++++++- tmux.h | 11 +++- tty-term.c | 1 + tty.c | 170 +++++++++++++++++++++++++++++++++++++++--------------- window.c | 2 + 9 files changed, 212 insertions(+), 66 deletions(-) diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 5810eeab..c84b4149 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -28,8 +28,8 @@ enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_select_pane_entry = { "select-pane", "selectp", - "DdeLlRt:U", 0, 0, - "[-DdeLlRU] " CMD_TARGET_PANE_USAGE, + "DdegLlP:Rt:U", 0, 0, + "[-DdegLlRU] [-P style] " CMD_TARGET_PANE_USAGE, 0, cmd_select_pane_exec }; @@ -48,6 +48,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; struct winlink *wl; struct window_pane *wp; + const char *style; if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); @@ -82,6 +83,21 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } + if (args_has(self->args, 'P') || args_has(self->args, 'g')) { + if (args_has(args, 'P')) { + style = args_get(args, 'P'); + if (style_parse(&grid_default_cell, &wp->colgc, + style) == -1) { + cmdq_error(cmdq, "bad style: %s", style); + return (CMD_RETURN_ERROR); + } + wp->flags |= PANE_REDRAW; + } + if (args_has(self->args, 'g')) + cmdq_print(cmdq, "%s", style_tostring(&wp->colgc)); + return (CMD_RETURN_NORMAL); + } + if (args_has(self->args, 'L')) wp = window_pane_find_left(wp); else if (args_has(self->args, 'R')) diff --git a/options-table.c b/options-table.c index fb231f7d..5e72d14f 100644 --- a/options-table.c +++ b/options-table.c @@ -668,6 +668,16 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 /* overridden in main() */ }, + { .name = "window-active-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "default" + }, + + { .name = "window-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "default" + }, + { .name = "window-status-activity-attr", .type = OPTIONS_TABLE_ATTRIBUTES, .default_num = GRID_ATTR_REVERSE, diff --git a/screen-redraw.c b/screen-redraw.c index c2b2ece6..e3369b82 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -266,7 +266,7 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) yoff++; for (i = 0; i < wp->sy; i++) - tty_draw_line(&c->tty, wp->screen, i, wp->xoff, yoff); + tty_draw_pane(&c->tty, wp, i, wp->xoff, yoff); tty_reset(&c->tty); } @@ -323,9 +323,9 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top) small && i > msgx && j == msgy) continue; if (screen_redraw_check_active(i, j, type, w, wp)) - tty_attributes(tty, &active_gc); + tty_attributes(tty, &active_gc, NULL); else - tty_attributes(tty, &other_gc); + tty_attributes(tty, &other_gc, NULL); tty_cursor(tty, i, top + j); tty_putc(tty, CELL_BORDERS[type]); } @@ -333,7 +333,7 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top) if (small) { memcpy(&msg_gc, &grid_default_cell, sizeof msg_gc); - tty_attributes(tty, &msg_gc); + tty_attributes(tty, &msg_gc, NULL); tty_cursor(tty, msgx, msgy); tty_puts(tty, msg); } @@ -346,15 +346,13 @@ screen_redraw_draw_panes(struct client *c, u_int top) struct window *w = c->session->curw->window; struct tty *tty = &c->tty; struct window_pane *wp; - struct screen *s; u_int i; TAILQ_FOREACH(wp, &w->panes, entry) { if (!window_pane_visible(wp)) continue; - s = wp->screen; for (i = 0; i < wp->sy; i++) - tty_draw_line(tty, s, i, wp->xoff, top + wp->yoff); + tty_draw_pane(tty, wp, i, wp->xoff, top + wp->yoff); if (c->flags & CLIENT_IDENTIFY) screen_redraw_draw_number(c, wp); } @@ -367,9 +365,9 @@ screen_redraw_draw_status(struct client *c, u_int top) struct tty *tty = &c->tty; if (top) - tty_draw_line(tty, &c->status, 0, 0, 0); + tty_draw_line(tty, NULL, &c->status, 0, 0, 0); else - tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); + tty_draw_line(tty, NULL, &c->status, 0, 0, tty->sy - 1); } /* Draw number on a pane. */ @@ -411,7 +409,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) colour_set_bg(&gc, active_colour); else colour_set_bg(&gc, colour); - tty_attributes(tty, &gc); + tty_attributes(tty, &gc, wp); for (ptr = buf; *ptr != '\0'; ptr++) { if (*ptr < '0' || *ptr > '9') continue; @@ -438,7 +436,7 @@ draw_text: colour_set_fg(&gc, active_colour); else colour_set_fg(&gc, colour); - tty_attributes(tty, &gc); + tty_attributes(tty, &gc, wp); tty_puts(tty, buf); tty_cursor(tty, 0, 0); diff --git a/server-client.c b/server-client.c index 8373a0ef..352e8ab6 100644 --- a/server-client.c +++ b/server-client.c @@ -329,8 +329,7 @@ server_client_check_mouse(struct client *c, struct window_pane *wp) if (options_get_number(oo, "mouse-select-pane") && (m->event == MOUSE_EVENT_DOWN || m->event == MOUSE_EVENT_WHEEL)) { window_set_active_at(wp->window, m->x, m->y); - server_status_window(wp->window); - server_redraw_window_borders(wp->window); + server_redraw_window(wp->window); wp = wp->window->active; /* may have changed */ } diff --git a/tmux.1 b/tmux.1 index abdeba54..a3dac237 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1730,14 +1730,17 @@ and .Ic previous-layout commands. .It Xo Ic select-pane -.Op Fl DdeLlRU +.Op Fl DdegLlRU +.Op Fl P Ar style .Op Fl t Ar target-pane .Xc .D1 (alias: Ic selectp ) Make pane .Ar target-pane the active pane in window -.Ar target-window . +.Ar target-window , +or set it's style (with +.Fl P ) . If one of .Fl D , .Fl L , @@ -1754,6 +1757,22 @@ command. enables or .Fl d disables input to the pane. +.Pp +Each pane has a style: by default the +.Ic window-style +and +.Ic window-active-style +options are used, +.Ic select-pane +.Fl P +sets the style for a single pane. +For example, to set the pane 1 background to red: +.Bd -literal -offset indent +select-pane -t:.1 -P 'bg=red' +.Ed +.Pp +.Fl g +shows the current pane style. .It Xo Ic select-window .Op Fl lnpT .Op Fl t Ar target-window @@ -2070,7 +2089,7 @@ also supports user options which are prefixed with a User options may have any name, so long as they are prefixed with .Ql \&@ , and be set to any string. -For example +For example: .Bd -literal -offset indent $ tmux setw -q @foo "abc123" $ tmux showw -v @foo @@ -2936,6 +2955,14 @@ Instructs .Nm to expect UTF-8 sequences to appear in this window. .Pp +.It Ic window-active-style Ar style +Set the style for the window's active pane. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. +.Pp .It Ic window-status-activity-style Ar style Set status line style for windows with an activity alert. For how to specify @@ -2993,6 +3020,14 @@ see the .Ic message-command-style option. .Pp +.It Ic window-style Ar style +Set the default window style. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. +.Pp .It Xo Ic xterm-keys .Op Ic on | off .Xc diff --git a/tmux.h b/tmux.h index 4e1ee1b3..19a8aa3a 100644 --- a/tmux.h +++ b/tmux.h @@ -156,6 +156,7 @@ enum key_code { enum tty_code_code { TTYC_AX = 0, TTYC_ACSC, /* acs_chars, ac */ + TTYC_BCE, /* back_color_erase, ut */ TTYC_BEL, /* bell, bl */ TTYC_BLINK, /* enter_blink_mode, mb */ TTYC_BOLD, /* enter_bold_mode, md */ @@ -902,6 +903,8 @@ struct window_pane { struct input_ctx ictx; + struct grid_cell colgc; + int pipe_fd; struct bufferevent *pipe_event; size_t pipe_off; @@ -1606,7 +1609,8 @@ void environ_push(struct environ *); /* tty.c */ void tty_init_termios(int, struct termios *, struct bufferevent *); void tty_raw(struct tty *, const char *); -void tty_attributes(struct tty *, const struct grid_cell *); +void tty_attributes(struct tty *, const struct grid_cell *, + const struct window_pane *); void tty_reset(struct tty *); void tty_region_pane(struct tty *, const struct tty_ctx *, u_int, u_int); void tty_region(struct tty *, u_int, u_int); @@ -1630,7 +1634,10 @@ void tty_stop_tty(struct tty *); void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int, struct screen *); void tty_force_cursor_colour(struct tty *, const char *); -void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); +void tty_draw_pane(struct tty *, const struct window_pane *, u_int, u_int, + u_int); +void tty_draw_line(struct tty *, const struct window_pane *, struct screen *, + u_int, u_int, u_int); int tty_open(struct tty *, char **); void tty_close(struct tty *); void tty_free(struct tty *); diff --git a/tty-term.c b/tty-term.c index c8a6ba8b..f6f6b444 100644 --- a/tty-term.c +++ b/tty-term.c @@ -35,6 +35,7 @@ struct tty_terms tty_terms = LIST_HEAD_INITIALIZER(tty_terms); const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_ACSC, TTYCODE_STRING, "acsc" }, { TTYC_AX, TTYCODE_FLAG, "AX" }, + { TTYC_BCE, TTYCODE_FLAG, "bce" }, { TTYC_BEL, TTYCODE_STRING, "bel" }, { TTYC_BLINK, TTYCODE_STRING, "blink" }, { TTYC_BOLD, TTYCODE_STRING, "bold" }, diff --git a/tty.c b/tty.c index 83ae8282..59ed3bb8 100644 --- a/tty.c +++ b/tty.c @@ -43,11 +43,14 @@ void tty_colours_fg(struct tty *, const struct grid_cell *); void tty_colours_bg(struct tty *, const struct grid_cell *); int tty_large_region(struct tty *, const struct tty_ctx *); +int tty_fake_bce(const struct tty *, const struct window_pane *); void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( struct tty *, enum tty_code_code, enum tty_code_code, u_int); void tty_repeat_space(struct tty *, u_int); -void tty_cell(struct tty *, const struct grid_cell *); +void tty_cell(struct tty *, const struct grid_cell *, + const struct window_pane *); +void tty_default_colours(struct grid_cell *, const struct window_pane *); #define tty_use_acs(tty) \ (tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) @@ -581,6 +584,23 @@ tty_large_region(unused struct tty *tty, const struct tty_ctx *ctx) return (ctx->orlower - ctx->orupper >= screen_size_y(wp->screen) / 2); } +/* + * Return if BCE is needed but the terminal doesn't have it - it'll need to be + * emulated. + */ +int +tty_fake_bce(const struct tty *tty, const struct window_pane *wp) +{ + struct grid_cell gc; + + memcpy(&gc, &grid_default_cell, sizeof gc); + tty_default_colours(&gc, wp); + + if (gc.bg == 8 && !(gc.flags & GRID_FLAG_BG256)) + return (0); + return (!tty_term_flag(tty->term, TTYC_BCE)); +} + /* * Redraw scroll region using data from screen (already updated). Used when * CSR not supported, or window is a pane that doesn't take up the full @@ -604,15 +624,23 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) { for (i = ctx->ocy; i < screen_size_y(s); i++) - tty_draw_line(tty, s, i, ctx->xoff, ctx->yoff); + tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff); } else { for (i = ctx->orupper; i <= ctx->orlower; i++) - tty_draw_line(tty, s, i, ctx->xoff, ctx->yoff); + tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff); } } void -tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) +tty_draw_pane(struct tty *tty, const struct window_pane *wp, u_int py, u_int ox, + u_int oy) +{ + tty_draw_line(tty, wp, wp->screen, py, ox, oy); +} + +void +tty_draw_line(struct tty *tty, const struct window_pane *wp, + struct screen *s, u_int py, u_int ox, u_int oy) { const struct grid_cell *gc; struct grid_line *gl; @@ -650,20 +678,20 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int ox, u_int oy) ~(GRID_FLAG_FG256|GRID_FLAG_BG256); tmpgc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); - tty_cell(tty, &tmpgc); + tty_cell(tty, &tmpgc, wp); } else - tty_cell(tty, gc); + tty_cell(tty, gc, wp); } if (sx >= tty->sx) { tty_update_mode(tty, tty->mode, s); return; } - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_cursor(tty, ox + sx, oy + py); if (sx != screen_size_x(s) && ox + screen_size_x(s) >= tty->sx && - tty_term_has(tty->term, TTYC_EL)) + tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) tty_putcode(tty, TTYC_EL); else tty_repeat_space(tty, screen_size_x(s) - sx); @@ -713,19 +741,19 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; if (!tty_pane_full_width(tty, ctx)) { - tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); + tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff); return; } - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (tty_term_has(tty->term, TTYC_ICH) || - tty_term_has(tty->term, TTYC_ICH1)) + if (!tty_fake_bce(tty, wp) && (tty_term_has(tty->term, TTYC_ICH) || + tty_term_has(tty->term, TTYC_ICH1))) tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); else - tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); + tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff); } void @@ -733,14 +761,14 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - if (!tty_pane_full_width(tty, ctx) || + if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, wp) || (!tty_term_has(tty->term, TTYC_DCH) && !tty_term_has(tty->term, TTYC_DCH1))) { - tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); + tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff); return; } - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); @@ -754,11 +782,11 @@ tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx) { u_int i; - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, ctx->wp); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (tty_term_has(tty->term, TTYC_ECH)) + if (tty_term_has(tty->term, TTYC_ECH) && !tty_fake_bce(tty, ctx->wp)) tty_putcode1(tty, TTYC_ECH, ctx->num); else { for (i = 0; i < ctx->num; i++) @@ -769,14 +797,14 @@ tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) { - if (!tty_pane_full_width(tty, ctx) || + if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, ctx->wp) || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_IL1)) { tty_redraw_region(tty, ctx); return; } - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, ctx->wp); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); @@ -787,14 +815,14 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) { - if (!tty_pane_full_width(tty, ctx) || + if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, ctx->wp) || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_DL1)) { tty_redraw_region(tty, ctx); return; } - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, ctx->wp); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); @@ -808,11 +836,12 @@ tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_cursor_pane(tty, ctx, 0, ctx->ocy); - if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) + if (tty_pane_full_width(tty, ctx) && !tty_fake_bce(tty, wp) && + tty_term_has(tty->term, TTYC_EL)) tty_putcode(tty, TTYC_EL); else tty_repeat_space(tty, screen_size_x(s)); @@ -824,11 +853,12 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) struct window_pane *wp = ctx->wp; struct screen *s = wp->screen; - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) + if (tty_pane_full_width(tty, ctx) && + tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) tty_putcode(tty, TTYC_EL); else tty_repeat_space(tty, screen_size_x(s) - ctx->ocx); @@ -837,9 +867,10 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) { - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, ctx->wp); - if (ctx->xoff == 0 && tty_term_has(tty->term, TTYC_EL1)) { + if (ctx->xoff == 0 && tty_term_has(tty->term, TTYC_EL1) && + !tty_fake_bce(tty, ctx->wp)) { tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); tty_putcode(tty, TTYC_EL1); } else { @@ -854,14 +885,14 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy != ctx->orupper) return; - if (!tty_pane_full_width(tty, ctx) || + if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, ctx->wp) || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_RI)) { tty_redraw_region(tty, ctx); return; } - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, ctx->wp); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper); @@ -877,7 +908,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) if (ctx->ocy != ctx->orlower) return; - if (!tty_pane_full_width(tty, ctx) || + if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, wp) || !tty_term_has(tty->term, TTYC_CSR)) { if (tty_large_region(tty, ctx)) wp->flags |= PANE_REDRAW; @@ -894,7 +925,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) if (ctx->num && !(tty->term->flags & TERM_EARLYWRAP)) return; - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); @@ -909,12 +940,13 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) struct screen *s = wp->screen; u_int i, j; - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { + if (tty_pane_full_width(tty, ctx) && + tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) { tty_putcode(tty, TTYC_EL); if (ctx->ocy != screen_size_y(s) - 1) { tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); @@ -942,12 +974,13 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) struct screen *s = wp->screen; u_int i, j; - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); - if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { + if (tty_pane_full_width(tty, ctx) && + tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) { for (i = 0; i < ctx->ocy; i++) { tty_putcode(tty, TTYC_EL); tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); @@ -969,12 +1002,13 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) struct screen *s = wp->screen; u_int i, j; - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); tty_cursor_pane(tty, ctx, 0, 0); - if (tty_pane_full_width(tty, ctx) && tty_term_has(tty->term, TTYC_EL)) { + if (tty_pane_full_width(tty, ctx) && + tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) { for (i = 0; i < screen_size_y(s); i++) { tty_putcode(tty, TTYC_EL); if (i != screen_size_y(s) - 1) { @@ -997,7 +1031,7 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) struct screen *s = wp->screen; u_int i, j; - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, wp); tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); @@ -1038,12 +1072,12 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) */ cx = screen_size_x(s) - grid_cell_width(&ctx->last_cell); tty_cursor_pane(tty, ctx, cx, ctx->ocy); - tty_cell(tty, &ctx->last_cell); + tty_cell(tty, &ctx->last_cell, wp); } } else tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_cell(tty, ctx->cell); + tty_cell(tty, ctx->cell, wp); } void @@ -1055,7 +1089,7 @@ tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) * Cannot rely on not being a partial character, so just redraw the * whole line. */ - tty_draw_line(tty, wp->screen, ctx->ocy, ctx->xoff, ctx->yoff); + tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff); } void @@ -1088,12 +1122,13 @@ tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) tty->cx = tty->cy = UINT_MAX; tty->rupper = tty->rlower = UINT_MAX; - tty_reset(tty); + tty_attributes(tty, &grid_default_cell, ctx->wp); tty_cursor(tty, 0, 0); } void -tty_cell(struct tty *tty, const struct grid_cell *gc) +tty_cell(struct tty *tty, const struct grid_cell *gc, + const struct window_pane *wp) { struct utf8_data ud; u_int i; @@ -1108,7 +1143,7 @@ tty_cell(struct tty *tty, const struct grid_cell *gc) return; /* Set the attributes. */ - tty_attributes(tty, gc); + tty_attributes(tty, gc, wp); /* Get the cell and if ASCII write with putc to do ACS translation. */ grid_cell_get(gc, &ud); @@ -1312,12 +1347,14 @@ out: } void -tty_attributes(struct tty *tty, const struct grid_cell *gc) +tty_attributes(struct tty *tty, const struct grid_cell *gc, + const struct window_pane *wp) { struct grid_cell *tc = &tty->cell, gc2; u_char changed; memcpy(&gc2, gc, sizeof gc2); + tty_default_colours(&gc2, wp); /* * If no setab, try to use the reverse attribute as a best-effort for a @@ -1609,6 +1646,47 @@ tty_try_256(struct tty *tty, u_char colour, const char *type) return (-1); } +void +tty_default_colours(struct grid_cell *gc, const struct window_pane *wp) +{ + const struct grid_cell *agc, *pgc, *wgc; + + if (wp == NULL) + return; + + pgc = &wp->colgc; + agc = options_get_style(&wp->window->options, "window-active-style"); + wgc = options_get_style(&wp->window->options, "window-style"); + + if (gc->fg == 8 && !(gc->flags & GRID_FLAG_FG256)) { + if (pgc->fg != 8 || (pgc->flags & GRID_FLAG_FG256)) { + gc->fg = pgc->fg; + gc->flags |= (pgc->flags & GRID_FLAG_FG256); + } else if (wp == wp->window->active && + (agc->fg != 8 || (agc->flags & GRID_FLAG_FG256))) { + gc->fg = agc->fg; + gc->flags |= (agc->flags & GRID_FLAG_FG256); + } else { + gc->fg = wgc->fg; + gc->flags |= (wgc->flags & GRID_FLAG_FG256); + } + } + + if (gc->bg == 8 && !(gc->flags & GRID_FLAG_BG256)) { + if (pgc->bg != 8 || (pgc->flags & GRID_FLAG_BG256)) { + gc->bg = pgc->bg; + gc->flags |= (pgc->flags & GRID_FLAG_BG256); + } else if (wp == wp->window->active && + (agc->bg != 8 || (agc->flags & GRID_FLAG_BG256))) { + gc->bg = agc->bg; + gc->flags |= (agc->flags & GRID_FLAG_BG256); + } else { + gc->bg = wgc->bg; + gc->flags |= (wgc->flags & GRID_FLAG_BG256); + } + } +} + void tty_bell(struct tty *tty) { diff --git a/window.c b/window.c index 6a742a2e..4abcf495 100644 --- a/window.c +++ b/window.c @@ -705,6 +705,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->saved_grid = NULL; + memcpy(&wp->colgc, &grid_default_cell, sizeof wp->colgc); + screen_init(&wp->base, sx, sy, hlimit); wp->screen = &wp->base; -- cgit From bf635e7741f7b881f67ec7e4a5caa02f7ff3d786 Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 19 Apr 2015 21:34:21 +0000 Subject: Rewrite of tmux mouse support which was a mess. Instead of having options for "mouse-this" and "mouse-that", mouse events may be bound as keys and there is one option "mouse" that turns on mouse support entirely (set -g mouse on). See the new MOUSE SUPPORT section of the man page for description of the key names and new flags (-t= to specify the pane or window under mouse as a target, and send-keys -M to pass through a mouse event). The default builtin bindings for the mouse are: bind -n MouseDown1Pane select-pane -t=; send-keys -M bind -n MouseDown1Status select-window -t= bind -n MouseDrag1Pane copy-mode -M bind -n MouseDrag1Border resize-pane -M To get the effect of turning mode-mouse off, do: unbind -n MouseDrag1Pane unbind -temacs-copy MouseDrag1Pane The old mouse options are now gone, set-option -q may be used to suppress warnings if mixing configuration files. --- cfg.c | 2 +- cmd-command-prompt.c | 2 +- cmd-confirm-before.c | 2 +- cmd-copy-mode.c | 15 ++- cmd-if-shell.c | 4 +- cmd-queue.c | 12 +- cmd-resize-pane.c | 66 +++++++++- cmd-send-keys.c | 21 +++- cmd.c | 94 ++++++++++++++- control.c | 2 +- input-keys.c | 97 +++++++-------- key-bindings.c | 13 +- key-string.c | 17 ++- layout.c | 52 -------- mode-key.c | 14 +++ options-table.c | 21 +--- server-client.c | 331 +++++++++++++++++++++++++++++++++++++-------------- server-fn.c | 7 +- status.c | 13 +- tmux.1 | 99 ++++++++++----- tmux.h | 140 ++++++++++++---------- tty-keys.c | 81 ++++--------- tty.c | 4 + window-choose.c | 107 +++++++---------- window-clock.c | 8 +- window-copy.c | 198 +++++++++++++++--------------- window.c | 49 ++++---- 27 files changed, 883 insertions(+), 588 deletions(-) diff --git a/cfg.c b/cfg.c index 23828923..b4c9bff4 100644 --- a/cfg.c +++ b/cfg.c @@ -75,7 +75,7 @@ load_cfg(const char *path, struct cmd_q *cmdq, char **cause) if (cmdlist == NULL) continue; - cmdq_append(cmdq, cmdlist); + cmdq_append(cmdq, cmdlist, NULL); cmd_list_free(cmdlist); found++; } diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 22b1d84e..1622e0b7 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -151,7 +151,7 @@ cmd_command_prompt_callback(void *data, const char *s) return (0); } - cmdq_run(c->cmdq, cmdlist); + cmdq_run(c->cmdq, cmdlist, NULL); cmd_list_free(cmdlist); if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback) diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 0bf58449..5e4816ed 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -105,7 +105,7 @@ cmd_confirm_before_callback(void *data, const char *s) return (0); } - cmdq_run(c->cmdq, cmdlist); + cmdq_run(c->cmdq, cmdlist, NULL); cmd_list_free(cmdlist); return (0); diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index b46a5a46..19dca5ff 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -28,8 +28,8 @@ enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, - "t:u", 0, 0, - "[-u] " CMD_TARGET_PANE_USAGE, + "Mt:u", 0, 0, + "[-Mu] " CMD_TARGET_PANE_USAGE, 0, cmd_copy_mode_exec }; @@ -46,9 +46,16 @@ enum cmd_retval cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; + struct client *c = cmdq->client; + struct session *s; struct window_pane *wp; - if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) + if (args_has(args, 'M')) { + if ((wp = cmd_mouse_pane(&cmdq->item->mouse, &s, NULL)) == NULL) + return (CMD_RETURN_NORMAL); + if (c == NULL || c->session != s) + return (CMD_RETURN_NORMAL); + } else if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); if (self->entry == &cmd_clock_mode_entry) { @@ -61,6 +68,8 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_NORMAL); window_copy_init_from_pane(wp); } + if (args_has(args, 'M')) + window_copy_start_drag(c, &cmdq->item->mouse); if (wp->mode == &window_copy_mode && args_has(self->args, 'u')) window_copy_pageup(wp); diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 8c6620da..9659511e 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -95,7 +95,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) } return (CMD_RETURN_ERROR); } - cmdq_run(cmdq, cmdlist); + cmdq_run(cmdq, cmdlist, NULL); cmd_list_free(cmdlist); return (CMD_RETURN_NORMAL); } @@ -152,7 +152,7 @@ cmd_if_shell_callback(struct job *job) cmdq1->emptyfn = cmd_if_shell_done; cmdq1->data = cdata; - cmdq_run(cmdq1, cmdlist); + cmdq_run(cmdq1, cmdlist, NULL); cmd_list_free(cmdlist); } diff --git a/cmd-queue.c b/cmd-queue.c index 6be532a8..61b14147 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "tmux.h" @@ -132,9 +133,9 @@ cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags) /* Add command list to queue and begin processing if needed. */ void -cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist) +cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m) { - cmdq_append(cmdq, cmdlist); + cmdq_append(cmdq, cmdlist, m); if (cmdq->item == NULL) { cmdq->cmd = NULL; @@ -144,7 +145,7 @@ cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist) /* Add command list to queue. */ void -cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist) +cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m) { struct cmd_q_item *item; @@ -152,6 +153,11 @@ cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist) item->cmdlist = cmdlist; TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry); cmdlist->references++; + + if (m != NULL) + memcpy(&item->mouse, m, sizeof item->mouse); + else + item->mouse.valid = 0; } /* Continue processing command queue. Returns 1 if finishes empty. */ diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 42f0f39a..b342307d 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -28,10 +28,13 @@ enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_q *); +void cmd_resize_pane_mouse_update(struct client *, struct mouse_event *); + const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", - "DLRt:Ux:y:Z", 0, 1, - "[-DLRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]", + "DLMRt:Ux:y:Z", 0, 1, + "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE + " [adjustment]", 0, cmd_resize_pane_exec }; @@ -40,6 +43,8 @@ enum cmd_retval cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; + struct client *c = cmdq->client; + struct session *s; struct winlink *wl; struct window *w; const char *errstr; @@ -48,6 +53,16 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) u_int adjust; int x, y; + if (args_has(args, 'M')) { + if (cmd_mouse_window(&cmdq->item->mouse, &s) == NULL) + return (CMD_RETURN_NORMAL); + if (c == NULL || c->session != s) + return (CMD_RETURN_NORMAL); + c->tty.mouse_drag_update = cmd_resize_pane_mouse_update; + cmd_resize_pane_mouse_update(c, &cmdq->item->mouse); + return (CMD_RETURN_NORMAL); + } + if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) return (CMD_RETURN_ERROR); w = wl->window; @@ -106,3 +121,50 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_NORMAL); } + +void +cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m) +{ + struct winlink *wl; + struct window_pane *wp; + int found; + u_int y, ly; + + wl = cmd_mouse_window(m, NULL); + if (wl == NULL) { + c->tty.mouse_drag_update = NULL; + return; + } + + y = m->y; + if (m->statusat == 0 && y > 0) + y--; + else if (m->statusat > 0 && y >= (u_int)m->statusat) + y = m->statusat - 1; + ly = m->ly; + if (m->statusat == 0 && ly > 0) + ly--; + else if (m->statusat > 0 && ly >= (u_int)m->statusat) + ly = m->statusat - 1; + + found = 0; + TAILQ_FOREACH(wp, &wl->window->panes, entry) { + if (!window_pane_visible(wp)) + continue; + + if (wp->xoff + wp->sx == m->lx && + wp->yoff <= 1 + ly && wp->yoff + wp->sy >= ly) { + layout_resize_pane(wp, LAYOUT_LEFTRIGHT, m->x - m->lx); + found = 1; + } + if (wp->yoff + wp->sy == ly && + wp->xoff <= 1 + m->lx && wp->xoff + wp->sx >= m->lx) { + layout_resize_pane(wp, LAYOUT_TOPBOTTOM, y - ly); + found = 1; + } + } + if (found) + server_redraw_window(wl->window); + else + c->tty.mouse_drag_update = NULL; +} diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 7a4d97d5..27da410d 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_send_keys_entry = { "send-keys", "send", - "lRt:", 0, -1, - "[-lR] " CMD_TARGET_PANE_USAGE " key ...", + "lRMt:", 0, -1, + "[-lRM] " CMD_TARGET_PANE_USAGE " key ...", 0, cmd_send_keys_exec }; @@ -49,12 +49,23 @@ enum cmd_retval cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; + struct mouse_event *m = &cmdq->item->mouse; struct window_pane *wp; struct session *s; struct input_ctx *ictx; const u_char *str; int i, key; + if (args_has(args, 'M')) { + wp = cmd_mouse_pane(m, &s, NULL); + if (wp == NULL) { + cmdq_error(cmdq, "no mouse target"); + return (CMD_RETURN_ERROR); + } + window_pane_key(wp, NULL, s, m->key, m); + return (CMD_RETURN_NORMAL); + } + if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL) return (CMD_RETURN_ERROR); @@ -63,7 +74,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) key = options_get_number(&s->options, "prefix2"); else key = options_get_number(&s->options, "prefix"); - window_pane_key(wp, s, key); + window_pane_key(wp, NULL, s, key, NULL); return (CMD_RETURN_NORMAL); } @@ -88,10 +99,10 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) if (!args_has(args, 'l') && (key = key_string_lookup_string(str)) != KEYC_NONE) { - window_pane_key(wp, s, key); + window_pane_key(wp, NULL, s, key, NULL); } else { for (; *str != '\0'; str++) - window_pane_key(wp, s, *str); + window_pane_key(wp, NULL, s, *str, NULL); } } diff --git a/cmd.c b/cmd.c index 66ac58b8..dd1a0a7b 100644 --- a/cmd.c +++ b/cmd.c @@ -348,6 +348,7 @@ cmd_current_session(struct cmd_q *cmdq, int prefer_unattached) const char *path; int found; + /* Try the queue session. */ if (c != NULL && c->session != NULL) return (c->session); @@ -504,6 +505,74 @@ cmd_choose_client(struct clients *cc) return (cbest); } +/* Adjust current mouse position for a pane. */ +int +cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp, + u_int *yp, int last) +{ + u_int x, y; + + if (last) { + x = m->lx; + y = m->ly; + } else { + x = m->x; + y = m->y; + } + + if (m->statusat == 0 && y > 0) + y--; + else if (m->statusat > 0 && y >= (u_int)m->statusat) + y = m->statusat - 1; + + if (x < wp->xoff || x >= wp->xoff + wp->sx) + return (-1); + if (y < wp->yoff || y >= wp->yoff + wp->sy) + return (-1); + + *xp = x - wp->xoff; + *yp = y - wp->yoff; + return (0); +} + +/* Get current mouse window if any. */ +struct winlink * +cmd_mouse_window(struct mouse_event *m, struct session **sp) +{ + struct session *s; + struct window *w; + + if (!m->valid || m->s == -1 || m->w == -1) + return (NULL); + if ((s = session_find_by_id(m->s)) == NULL) + return (NULL); + if ((w = window_find_by_id(m->w)) == NULL) + return (NULL); + + if (sp != NULL) + *sp = s; + return (winlink_find_by_window(&s->windows, w)); +} + +/* Get current mouse pane if any. */ +struct window_pane * +cmd_mouse_pane(struct mouse_event *m, struct session **sp, struct winlink **wlp) +{ + struct winlink *wl; + struct window_pane *wp; + + if ((wl = cmd_mouse_window(m, sp)) == NULL) + return (NULL); + if ((wp = window_pane_find_by_id(m->wp)) == NULL) + return (NULL); + if (!window_has_pane(wl->window, wp)) + return (NULL); + + if (wlp != NULL) + *wlp = wl; + return (wp); +} + /* Find the target client or report an error and return NULL. */ struct client * cmd_find_client(struct cmd_q *cmdq, const char *arg, int quiet) @@ -928,7 +997,12 @@ no_colon: * No colon in the string, first try special cases, then as a window * and lastly as a session. */ - if (arg[0] == '!' && arg[1] == '\0') { + if (arg[0] == '=' && arg[1] == '\0') { + if ((wl = cmd_mouse_window(&cmdq->item->mouse, &s)) == NULL) { + cmdq_error(cmdq, "no mouse target"); + goto error; + } + } else if (arg[0] == '!' && arg[1] == '\0') { if ((wl = TAILQ_FIRST(&s->lastw)) == NULL) goto not_found; } else if (arg[0] == '+' || arg[0] == '-') { @@ -959,14 +1033,16 @@ no_session: cmdq_error(cmdq, "multiple sessions: %s", arg); else cmdq_error(cmdq, "session not found: %s", arg); - free(sessptr); - return (NULL); + goto error; not_found: if (ambiguous) cmdq_error(cmdq, "multiple windows: %s", arg); else cmdq_error(cmdq, "window not found: %s", arg); + goto error; + +error: free(sessptr); return (NULL); } @@ -1228,6 +1304,18 @@ lookup_string: return (wl); no_period: + /* Check mouse event. */ + if (arg[0] == '=' && arg[1] == '\0') { + *wpp = cmd_mouse_pane(&cmdq->item->mouse, &s, &wl); + if (*wpp == NULL) { + cmdq_error(cmdq, "no mouse target"); + return (NULL); + } + if (sp != NULL) + *sp = s; + return (wl); + } + /* Try as a pane number alone. */ idx = strtonum(arg, 0, INT_MAX, &errstr); if (errstr != NULL) diff --git a/control.c b/control.c index 0ace6c12..11fa2d80 100644 --- a/control.c +++ b/control.c @@ -81,7 +81,7 @@ control_callback(struct client *c, int closed, unused void *data) } else { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) cmd->flags |= CMD_CONTROL; - cmdq_run(c->cmdq, cmdlist); + cmdq_run(c->cmdq, cmdlist, NULL); cmd_list_free(cmdlist); } diff --git a/input-keys.c b/input-keys.c index f2d010d8..ae00e4a9 100644 --- a/input-keys.c +++ b/input-keys.c @@ -31,6 +31,8 @@ * direction with output). */ +void input_key_mouse(struct window_pane *, struct mouse_event *); + struct input_key_ent { int key; const char *data; @@ -135,7 +137,7 @@ const struct input_key_ent input_keys[] = { /* Translate a key code into an output key sequence. */ void -input_key(struct window_pane *wp, int key) +input_key(struct window_pane *wp, int key, struct mouse_event *m) { const struct input_key_ent *ike; u_int i; @@ -143,7 +145,14 @@ input_key(struct window_pane *wp, int key) char *out; u_char ch; - log_debug("writing key 0x%x", key); + log_debug("writing key 0x%x (%s)", key, key_string_lookup_key(key)); + + /* If this is a mouse key, pass off to mouse function. */ + if (KEYC_IS_MOUSE(key)) { + if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) + input_key_mouse(wp, m); + return; + } /* * If this is a normal 7-bit key, just send it, with a leading escape @@ -200,55 +209,47 @@ input_key(struct window_pane *wp, int key) /* Translate mouse and output. */ void -input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m) +input_key_mouse(struct window_pane *wp, struct mouse_event *m) { - char buf[40]; - size_t len; - struct paste_buffer *pb; - int event; - - if (wp->screen->mode & ALL_MOUSE_MODES) { - /* - * Use the SGR (1006) extension only if the application - * requested it and the underlying terminal also sent the event - * in this format (this is because an old style mouse release - * event cannot be converted into the new SGR format, since the - * released button is unknown). Otherwise pretend that tmux - * doesn't speak this extension, and fall back to the UTF-8 - * (1005) extension if the application requested, or to the - * legacy format. - */ - if (m->sgr && (wp->screen->mode & MODE_MOUSE_SGR)) { - len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c", - m->sgr_xb, m->x + 1, m->y + 1, - m->sgr_rel ? 'm' : 'M'); - } else if (wp->screen->mode & MODE_MOUSE_UTF8) { - len = xsnprintf(buf, sizeof buf, "\033[M"); - len += utf8_split2(m->xb + 32, &buf[len]); - len += utf8_split2(m->x + 33, &buf[len]); - len += utf8_split2(m->y + 33, &buf[len]); - } else { - if (m->xb > 223) - return; - len = xsnprintf(buf, sizeof buf, "\033[M"); - buf[len++] = m->xb + 32; - buf[len++] = m->x + 33; - buf[len++] = m->y + 33; - } - bufferevent_write(wp->event, buf, len); + char buf[40]; + size_t len; + u_int x, y; + + if ((wp->screen->mode & ALL_MOUSE_MODES) == 0) + return; + if (!window_pane_visible(wp)) + return; + if (cmd_mouse_at(wp, m, &x, &y, 0) != 0) return; - } - if (options_get_number(&wp->window->options, "mode-mouse") != 1) + /* If this pane is not in button mode, discard motion events. */ + if (!(wp->screen->mode & MODE_MOUSE_BUTTON) && (m->b & MOUSE_MASK_DRAG)) return; - event = m->event & (MOUSE_EVENT_CLICK|MOUSE_EVENT_WHEEL); - if (wp->mode == NULL && m->button == 1 && event == MOUSE_EVENT_CLICK) { - pb = paste_get_top(); - if (pb != NULL) - paste_send_pane(pb, wp, "\r", 1); - } else if (window_pane_set_mode(wp, &window_copy_mode) == 0) { - window_copy_init_from_pane(wp); - if (wp->mode->mouse != NULL) - wp->mode->mouse(wp, s, m); + + /* + * Use the SGR (1006) extension only if the application requested it + * and the underlying terminal also sent the event in this format (this + * is because an old style mouse release event cannot be converted into + * the new SGR format, since the released button is unknown). Otherwise + * pretend that tmux doesn't speak this extension, and fall back to the + * UTF-8 (1005) extension if the application requested, or to the + * legacy format. + */ + if (m->sgr_type != ' ' && (wp->screen->mode & MODE_MOUSE_SGR)) { + len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c", + m->sgr_b, x + 1, y + 1, m->sgr_type); + } else if (wp->screen->mode & MODE_MOUSE_UTF8) { + len = xsnprintf(buf, sizeof buf, "\033[M"); + len += utf8_split2(m->b + 32, &buf[len]); + len += utf8_split2(x + 33, &buf[len]); + len += utf8_split2(y + 33, &buf[len]); + } else { + if (m->b > 223) + return; + len = xsnprintf(buf, sizeof buf, "\033[M"); + buf[len++] = m->b + 32; + buf[len++] = x + 33; + buf[len++] = y + 33; } + bufferevent_write(wp->event, buf, len); } diff --git a/key-bindings.c b/key-bindings.c index 00f73d73..c6cdeeb7 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -158,6 +158,10 @@ key_bindings_init(void) "bind -r C-Down resize-pane -D", "bind -r C-Left resize-pane -L", "bind -r C-Right resize-pane -R", + "bind -n MouseDown1Pane select-pane -t=\\; send-keys -M", + "bind -n MouseDrag1Border resize-pane -M", + "bind -n MouseDown1Status select-window -t=", + "bind -n MouseDrag1Pane copy-mode -M", }; u_int i; struct cmd_list *cmdlist; @@ -173,14 +177,15 @@ key_bindings_init(void) "", i, &cause); if (error != 0) fatalx("bad default key"); - cmdq_run(cmdq, cmdlist); - cmd_list_free(cmdlist); + cmdq_run(cmdq, cmdlist, NULL); + cmd_list_free (cmdlist); } cmdq_free(cmdq); } void -key_bindings_dispatch(struct key_binding *bd, struct client *c) +key_bindings_dispatch(struct key_binding *bd, struct client *c, + struct mouse_event *m) { struct cmd *cmd; int readonly; @@ -195,5 +200,5 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c) return; } - cmdq_run(c->cmdq, bd->cmdlist); + cmdq_run(c->cmdq, bd->cmdlist, m); } diff --git a/key-string.c b/key-string.c index db968279..b6474c4f 100644 --- a/key-string.c +++ b/key-string.c @@ -82,6 +82,19 @@ const struct { { "KPEnter", KEYC_KP_ENTER }, { "KP0", KEYC_KP_ZERO }, { "KP.", KEYC_KP_PERIOD }, + + /* Mouse keys. */ + KEYC_MOUSE_STRING(MOUSEDOWN1, MouseDown1), + KEYC_MOUSE_STRING(MOUSEDOWN2, MouseDown2), + KEYC_MOUSE_STRING(MOUSEDOWN3, MouseDown3), + KEYC_MOUSE_STRING(MOUSEUP1, MouseUp1), + KEYC_MOUSE_STRING(MOUSEUP2, MouseUp2), + KEYC_MOUSE_STRING(MOUSEUP3, MouseUp3), + KEYC_MOUSE_STRING(MOUSEDRAG1, MouseDrag1), + KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2), + KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3), + KEYC_MOUSE_STRING(WHEELUP, WheelUp), + KEYC_MOUSE_STRING(WHEELDOWN, WheelDown), }; /* Find key string in table. */ @@ -192,7 +205,9 @@ key_string_lookup_key(int key) /* Handle no key. */ if (key == KEYC_NONE) - return ("none"); + return (""); + if (key == KEYC_MOUSE) + return (""); /* * Special case: display C-@ as C-Space. Could do this below in diff --git a/layout.c b/layout.c index b91b86cd..bb1bbf8d 100644 --- a/layout.c +++ b/layout.c @@ -519,58 +519,6 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change) notify_window_layout_changed(wp->window); } -/* Resize pane based on mouse events. */ -void -layout_resize_pane_mouse(struct client *c) -{ - struct window *w; - struct window_pane *wp; - struct mouse_event *m = &c->tty.mouse; - int pane_border; - - w = c->session->curw->window; - - pane_border = 0; - if (m->event & MOUSE_EVENT_DRAG && m->flags & MOUSE_RESIZE_PANE) { - TAILQ_FOREACH(wp, &w->panes, entry) { - if (!window_pane_visible(wp)) - continue; - - if (wp->xoff + wp->sx == m->lx && - wp->yoff <= 1 + m->ly && - wp->yoff + wp->sy >= m->ly) { - layout_resize_pane(wp, LAYOUT_LEFTRIGHT, - m->x - m->lx); - pane_border = 1; - } - if (wp->yoff + wp->sy == m->ly && - wp->xoff <= 1 + m->lx && - wp->xoff + wp->sx >= m->lx) { - layout_resize_pane(wp, LAYOUT_TOPBOTTOM, - m->y - m->ly); - pane_border = 1; - } - } - if (pane_border) - server_redraw_window(w); - } else if (m->event & MOUSE_EVENT_DOWN) { - TAILQ_FOREACH(wp, &w->panes, entry) { - if ((wp->xoff + wp->sx == m->x && - wp->yoff <= 1 + m->y && - wp->yoff + wp->sy >= m->y) || - (wp->yoff + wp->sy == m->y && - wp->xoff <= 1 + m->x && - wp->xoff + wp->sx >= m->x)) { - pane_border = 1; - } - } - } - if (pane_border) - m->flags |= MOUSE_RESIZE_PANE; - else - m->flags &= ~MOUSE_RESIZE_PANE; -} - /* Helper function to grow pane. */ int layout_resize_pane_grow( diff --git a/mode-key.c b/mode-key.c index 72d66f37..c06d7ed5 100644 --- a/mode-key.c +++ b/mode-key.c @@ -251,6 +251,10 @@ const struct mode_key_entry mode_key_vi_choice[] = { { KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND }, { KEYC_LEFT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_COLLAPSE_ALL }, { KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL }, + { KEYC_MOUSEDOWN1_PANE, 0, MODEKEYCHOICE_CHOOSE }, + { KEYC_MOUSEDOWN3_PANE, 0, MODEKEYCHOICE_TREE_TOGGLE }, + { KEYC_WHEELUP_PANE, 0, MODEKEYCHOICE_UP }, + { KEYC_WHEELDOWN_PANE, 0, MODEKEYCHOICE_DOWN }, { 0, -1, 0 } }; @@ -326,6 +330,9 @@ const struct mode_key_entry mode_key_vi_copy[] = { { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, + { KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP }, + { KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN }, + { KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION }, { 0, -1, 0 } }; @@ -405,6 +412,10 @@ const struct mode_key_entry mode_key_emacs_choice[] = { { KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND }, { KEYC_LEFT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_COLLAPSE_ALL }, { KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL }, + { KEYC_MOUSEDOWN1_PANE, 0, MODEKEYCHOICE_CHOOSE }, + { KEYC_MOUSEDOWN3_PANE, 0, MODEKEYCHOICE_TREE_TOGGLE }, + { KEYC_WHEELUP_PANE, 0, MODEKEYCHOICE_UP }, + { KEYC_WHEELDOWN_PANE, 0, MODEKEYCHOICE_DOWN }, { 0, -1, 0 } }; @@ -467,6 +478,9 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP }, { KEYC_UP, 0, MODEKEYCOPY_UP }, + { KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP }, + { KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN }, + { KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION }, { 0, -1, 0 } }; diff --git a/options-table.c b/options-table.c index 5e72d14f..5e21c692 100644 --- a/options-table.c +++ b/options-table.c @@ -36,9 +36,6 @@ const char *options_table_mode_keys_list[] = { "emacs", "vi", NULL }; -const char *options_table_mode_mouse_list[] = { - "off", "on", "copy-mode", NULL -}; const char *options_table_clock_mode_style_list[] = { "12", "24", NULL }; @@ -255,17 +252,7 @@ const struct options_table_entry session_options_table[] = { .default_str = "bg=yellow,fg=black" }, - { .name = "mouse-resize-pane", - .type = OPTIONS_TABLE_FLAG, - .default_num = 0 - }, - - { .name = "mouse-select-pane", - .type = OPTIONS_TABLE_FLAG, - .default_num = 0 - }, - - { .name = "mouse-select-window", + { .name = "mouse", .type = OPTIONS_TABLE_FLAG, .default_num = 0 }, @@ -575,12 +562,6 @@ const struct options_table_entry window_options_table[] = { .default_num = MODEKEY_EMACS }, - { .name = "mode-mouse", - .type = OPTIONS_TABLE_CHOICE, - .choices = options_table_mode_mouse_list, - .default_num = 0 - }, - { .name = "mode-style", .type = OPTIONS_TABLE_STYLE, .default_str = "bg=yellow,fg=black" diff --git a/server-client.c b/server-client.c index 352e8ab6..3968c50b 100644 --- a/server-client.c +++ b/server-client.c @@ -32,7 +32,7 @@ void server_client_check_focus(struct window_pane *); void server_client_check_resize(struct window_pane *); -void server_client_check_mouse(struct client *, struct window_pane *); +int server_client_check_mouse(struct client *); void server_client_repeat_timer(int, short, void *); void server_client_check_exit(struct client *); void server_client_check_redraw(struct client *); @@ -91,13 +91,6 @@ server_client_create(int fd) c->prompt_buffer = NULL; c->prompt_index = 0; - c->tty.mouse.xb = c->tty.mouse.button = 3; - c->tty.mouse.x = c->tty.mouse.y = -1; - c->tty.mouse.lx = c->tty.mouse.ly = -1; - c->tty.mouse.sx = c->tty.mouse.sy = -1; - c->tty.mouse.event = MOUSE_EVENT_UP; - c->tty.mouse.flags = 0; - c->flags |= CLIENT_FOCUSED; evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); @@ -289,56 +282,228 @@ server_client_status_timer(void) } /* Check for mouse keys. */ -void -server_client_check_mouse(struct client *c, struct window_pane *wp) +int +server_client_check_mouse(struct client *c) { - struct session *s = c->session; - struct options *oo = &s->options; - struct mouse_event *m = &c->tty.mouse; - int statusat; - - statusat = status_at_line(c); - - /* Is this a window selection click on the status line? */ - if (statusat != -1 && m->y == (u_int)statusat && - options_get_number(oo, "mouse-select-window")) { - if (m->event & MOUSE_EVENT_CLICK) { - status_set_window_at(c, m->x); - } else if (m->event == MOUSE_EVENT_WHEEL) { - if (m->wheel == MOUSE_WHEEL_UP) - session_previous(c->session, 0); - else if (m->wheel == MOUSE_WHEEL_DOWN) - session_next(c->session, 0); - server_redraw_session(s); + struct session *s = c->session; + struct mouse_event *m = &c->tty.mouse; + struct window *w; + struct window_pane *wp; + enum { NOTYPE, DOWN, UP, DRAG, WHEEL } type = NOTYPE; + enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE; + u_int x, y, b; + int key; + + log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y, + m->lx, m->ly, c->tty.mouse_drag_flag); + + /* What type of event is this? */ + if (MOUSE_DRAG(m->b)) { + type = DRAG; + if (c->tty.mouse_drag_flag) { + x = m->x, y = m->y, b = m->b; + log_debug("drag update at %u,%u", x, y); + } else { + x = m->lx, y = m->ly, b = m->lb; + log_debug("drag start at %u,%u", x, y); } - recalculate_sizes(); - return; + } else if (MOUSE_WHEEL(m->b)) { + type = WHEEL; + x = m->x, y = m->y, b = m->b; + log_debug("wheel at %u,%u", x, y); + } else if (MOUSE_BUTTONS(m->b) == 3) { + type = UP; + x = m->x, y = m->y, b = m->lb; + log_debug("up at %u,%u", x, y); + } else { + type = DOWN; + x = m->x, y = m->y, b = m->b; + log_debug("down at %u,%u", x, y); } + if (type == NOTYPE) + return (KEYC_NONE); - /* - * Not on status line - adjust mouse position if status line is at the - * top and limit if at the bottom. From here on a struct mouse - * represents the offset onto the window itself. - */ - if (statusat == 0 && m->y > 0) - m->y--; - else if (statusat > 0 && m->y >= (u_int)statusat) - m->y = statusat - 1; - - /* Is this a pane selection? */ - if (options_get_number(oo, "mouse-select-pane") && - (m->event == MOUSE_EVENT_DOWN || m->event == MOUSE_EVENT_WHEEL)) { - window_set_active_at(wp->window, m->x, m->y); - server_redraw_window(wp->window); - wp = wp->window->active; /* may have changed */ + /* Always save the session. */ + m->s = s->id; + + /* Is this on the status line? */ + m->statusat = status_at_line(c); + if (m->statusat != -1 && y == (u_int)m->statusat) { + w = status_get_window_at(c, x); + if (w == NULL) + return (KEYC_NONE); + m->w = w->id; + where = STATUS; + } else + m->w = -1; + + /* Not on status line. Adjust position and check for border or pane. */ + if (where == NOWHERE) { + if (m->statusat == 0 && y > 0) + y--; + else if (m->statusat > 0 && y >= (u_int)m->statusat) + y = m->statusat - 1; + + TAILQ_FOREACH(wp, &s->curw->window->panes, entry) { + if ((wp->xoff + wp->sx == x && + wp->yoff <= 1 + y && + wp->yoff + wp->sy >= y) || + (wp->yoff + wp->sy == y && + wp->xoff <= 1 + x && + wp->xoff + wp->sx >= x)) + break; + } + if (wp != NULL) + where = BORDER; + else { + wp = window_get_active_at(s->curw->window, x, y); + if (wp != NULL) + where = PANE; + } + if (where == NOWHERE) + return (KEYC_NONE); + m->wp = wp->id; + m->w = wp->window->id; + } else + m->wp = -1; + + /* Stop dragging if needed. */ + if (type != DRAG && c->tty.mouse_drag_flag) { + if (c->tty.mouse_drag_release != NULL) + c->tty.mouse_drag_release(c, m); + + c->tty.mouse_drag_update = NULL; + c->tty.mouse_drag_release = NULL; + + c->tty.mouse_drag_flag = 0; + return (KEYC_NONE); } - /* Check if trying to resize pane. */ - if (options_get_number(oo, "mouse-resize-pane")) - layout_resize_pane_mouse(c); + /* Convert to a key binding. */ + key = KEYC_NONE; + switch (type) { + case NOTYPE: + break; + case DRAG: + if (c->tty.mouse_drag_update != NULL) + c->tty.mouse_drag_update(c, m); + else { + switch (MOUSE_BUTTONS(b)) { + case 0: + if (where == PANE) + key = KEYC_MOUSEDRAG1_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG1_STATUS; + if (where == BORDER) + key = KEYC_MOUSEDRAG1_BORDER; + break; + case 1: + if (where == PANE) + key = KEYC_MOUSEDRAG2_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG2_STATUS; + if (where == BORDER) + key = KEYC_MOUSEDRAG2_BORDER; + break; + case 2: + if (where == PANE) + key = KEYC_MOUSEDRAG3_PANE; + if (where == STATUS) + key = KEYC_MOUSEDRAG3_STATUS; + if (where == BORDER) + key = KEYC_MOUSEDRAG3_BORDER; + break; + } + } - /* Update last and pass through to client. */ - window_pane_mouse(wp, c->session, m); + c->tty.mouse_drag_flag = 1; + break; + case WHEEL: + if (MOUSE_BUTTONS(b) == MOUSE_WHEEL_UP) { + if (where == PANE) + key = KEYC_WHEELUP_PANE; + if (where == STATUS) + key = KEYC_WHEELUP_STATUS; + if (where == BORDER) + key = KEYC_WHEELUP_BORDER; + } else { + if (where == PANE) + key = KEYC_WHEELDOWN_PANE; + if (where == STATUS) + key = KEYC_WHEELDOWN_STATUS; + if (where == BORDER) + key = KEYC_WHEELDOWN_BORDER; + } + break; + case UP: + switch (MOUSE_BUTTONS(b)) { + case 0: + if (where == PANE) + key = KEYC_MOUSEUP1_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP1_STATUS; + if (where == BORDER) + key = KEYC_MOUSEUP1_BORDER; + break; + case 1: + if (where == PANE) + key = KEYC_MOUSEUP2_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP2_STATUS; + if (where == BORDER) + key = KEYC_MOUSEUP2_BORDER; + break; + case 2: + if (where == PANE) + key = KEYC_MOUSEUP3_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP3_STATUS; + if (where == BORDER) + key = KEYC_MOUSEUP3_BORDER; + break; + } + break; + case DOWN: + switch (MOUSE_BUTTONS(b)) { + case 0: + if (where == PANE) + key = KEYC_MOUSEDOWN1_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN1_STATUS; + if (where == BORDER) + key = KEYC_MOUSEDOWN1_BORDER; + break; + case 1: + if (where == PANE) + key = KEYC_MOUSEDOWN2_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN2_STATUS; + if (where == BORDER) + key = KEYC_MOUSEDOWN2_BORDER; + break; + case 2: + if (where == PANE) + key = KEYC_MOUSEDOWN3_PANE; + if (where == STATUS) + key = KEYC_MOUSEDOWN3_STATUS; + if (where == BORDER) + key = KEYC_MOUSEDOWN3_BORDER; + break; + } + break; + } + if (key == KEYC_NONE) + return (KEYC_NONE); + + /* Apply modifiers if any. */ + if (b & MOUSE_MASK_META) + key |= KEYC_ESCAPE; + if (b & MOUSE_MASK_CTRL) + key |= KEYC_CTRL; + if (b & MOUSE_MASK_SHIFT) + key |= KEYC_SHIFT; + + return (key); } /* Is this fast enough to probably be a paste? */ @@ -361,6 +526,7 @@ server_client_assume_paste(struct session *s) void server_client_handle_key(struct client *c, int key) { + struct mouse_event *m = &c->tty.mouse; struct session *s; struct window *w; struct window_pane *wp; @@ -372,21 +538,20 @@ server_client_handle_key(struct client *c, int key) if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) return; + /* No session, do nothing. */ if (c->session == NULL) return; s = c->session; + w = c->session->curw->window; + wp = w->active; /* Update the activity timer. */ if (gettimeofday(&c->activity_time, NULL) != 0) fatal("gettimeofday failed"); - memcpy(&s->last_activity_time, &s->activity_time, sizeof s->last_activity_time); memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); - w = c->session->curw->window; - wp = w->active; - /* Special case: number keys jump to pane in identify mode. */ if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { if (c->flags & CLIENT_READONLY) @@ -414,9 +579,19 @@ server_client_handle_key(struct client *c, int key) if (key == KEYC_MOUSE) { if (c->flags & CLIENT_READONLY) return; - server_client_check_mouse(c, wp); - return; - } + key = server_client_check_mouse(c); + if (key == KEYC_NONE) + return; + + m->valid = 1; + m->key = key; + + if (!options_get_number(&s->options, "mouse")) { + window_pane_key(wp, c, s, key, m); + return; + } + } else + m->valid = 0; /* Is this a prefix key? */ if (key == options_get_number(&s->options, "prefix")) @@ -442,9 +617,9 @@ server_client_handle_key(struct client *c, int key) /* Try as a non-prefix key binding. */ if (ispaste || (bd = key_bindings_lookup(key)) == NULL) { if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, s, key); + window_pane_key(wp, c, s, key, m); } else - key_bindings_dispatch(bd, c); + key_bindings_dispatch(bd, c, m); return; } @@ -458,7 +633,7 @@ server_client_handle_key(struct client *c, int key) if (isprefix) c->flags |= CLIENT_PREFIX; else if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, s, key); + window_pane_key(wp, c, s, key, m); } return; } @@ -469,7 +644,7 @@ server_client_handle_key(struct client *c, int key) if (isprefix) c->flags |= CLIENT_PREFIX; else if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, s, key); + window_pane_key(wp, c, s, key, m); return; } @@ -485,7 +660,7 @@ server_client_handle_key(struct client *c, int key) } /* Dispatch the command. */ - key_bindings_dispatch(bd, c); + key_bindings_dispatch(bd, c, m); } /* Client functions that need to happen every loop. */ @@ -622,7 +797,6 @@ server_client_reset_state(struct client *c) struct window_pane *wp = w->active; struct screen *s = wp->screen; struct options *oo = &c->session->options; - struct options *wo = &w->options; int status, mode, o; if (c->flags & CLIENT_SUSPENDED) @@ -642,29 +816,12 @@ server_client_reset_state(struct client *c) } /* - * Resizing panes with the mouse requires at least button mode to give - * a smooth appearance. + * Set mouse mode if requested. To support dragging, always use button + * mode. */ mode = s->mode; - if ((c->tty.mouse.flags & MOUSE_RESIZE_PANE) && - !(mode & MODE_MOUSE_BUTTON)) - mode |= MODE_MOUSE_BUTTON; - - /* - * Any mode will do for mouse-select-pane, but set standard mode if - * none. - */ - if ((mode & ALL_MOUSE_MODES) == 0) { - if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && - options_get_number(oo, "mouse-select-pane")) - mode |= MODE_MOUSE_STANDARD; - else if (options_get_number(oo, "mouse-resize-pane")) - mode |= MODE_MOUSE_STANDARD; - else if (options_get_number(oo, "mouse-select-window")) - mode |= MODE_MOUSE_STANDARD; - else if (options_get_number(wo, "mode-mouse")) - mode |= MODE_MOUSE_STANDARD; - } + if (options_get_number(oo, "mouse")) + mode = (mode & ~ALL_MOUSE_MODES) | MODE_MOUSE_BUTTON; /* * Set UTF-8 mouse input if required. If the terminal is UTF-8, the @@ -945,9 +1102,9 @@ server_client_msg_command(struct client *c, struct imsg *imsg) cmd_free_argv(argc, argv); if (c != cfg_client || cfg_finished) - cmdq_run(c->cmdq, cmdlist); + cmdq_run(c->cmdq, cmdlist, NULL); else - cmdq_append(c->cmdq, cmdlist); + cmdq_append(c->cmdq, cmdlist, NULL); cmd_list_free(cmdlist); return; diff --git a/server-fn.c b/server-fn.c index f89eca8e..83ea9474 100644 --- a/server-fn.c +++ b/server-fn.c @@ -604,7 +604,8 @@ server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int, void server_unzoom_window(struct window *w) { - window_unzoom(w); - server_redraw_window(w); - server_status_window(w); + if (window_unzoom(w) == 0) { + server_redraw_window(w); + server_status_window(w); + } } diff --git a/status.c b/status.c index 5f8895fb..ae5d99ab 100644 --- a/status.c +++ b/status.c @@ -118,9 +118,9 @@ status_redraw_get_right(struct client *c, time_t t, int utf8flag, return (right); } -/* Set window at window list position. */ -void -status_set_window_at(struct client *c, u_int x) +/* Get window at window list position. */ +struct window * +status_get_window_at(struct client *c, u_int x) { struct session *s = c->session; struct winlink *wl; @@ -130,12 +130,13 @@ status_set_window_at(struct client *c, u_int x) x += c->wlmouse; RB_FOREACH(wl, winlinks, &s->windows) { oo = &wl->window->options; - len = strlen(options_get_string(oo, "window-status-separator")); - if (x < wl->status_width && session_select(s, wl->idx) == 0) - server_redraw_session(s); + + if (x < wl->status_width) + return (wl->window); x -= wl->status_width + len; } + return (NULL); } /* Draw status for client on the last lines of given context. */ diff --git a/tmux.1 b/tmux.1 index a3dac237..fb08ddc1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1019,13 +1019,16 @@ The synopsis for the command is: .Bl -tag -width Ds .It Xo Ic copy-mode -.Op Fl u +.Op Fl Mu .Op Fl t Ar target-pane .Xc Enter copy mode. The .Fl u option scrolls one page up. +.Fl M +begins a mouse drag (only valid if bound to a mouse key binding, see +.Sx MOUSE SUPPORT Ns ). .El .Pp Each window displayed by @@ -1643,7 +1646,7 @@ Rename the current window, or the window at if specified, to .Ar new-name . .It Xo Ic resize-pane -.Op Fl DLRUZ +.Op Fl DLMRUZ .Op Fl t Ar target-pane .Op Fl x Ar width .Op Fl y Ar height @@ -1672,6 +1675,10 @@ With .Fl Z , the active pane is toggled between zoomed (occupying the whole of the w