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. --- server-client.c | 331 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 244 insertions(+), 87 deletions(-) (limited to 'server-client.c') 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; -- cgit v1.2.3