From d210d99ccecfaa2ef23a65609dc8cbb26bcfe236 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 26 Oct 2012 14:35:42 +0000 Subject: [PATCH] Make mouse event structure clearer by defining events (up, click, drag) and simplifying how buttons and wheels are represented, from Ailin Nemui. Should be no functional changes. --- input-keys.c | 12 ++++----- layout.c | 41 ++++++++++++++-------------- server-client.c | 68 +++++++++++++++++++++------------------------- tmux.h | 72 ++++++++++++++++++++++++++++++------------------- tty-keys.c | 56 +++++++++++++++++++++++++++++++------- window-choose.c | 2 +- window-copy.c | 10 +++---- window.c | 2 +- 8 files changed, 155 insertions(+), 108 deletions(-) diff --git a/input-keys.c b/input-keys.c index bd1c6157..eee469e8 100644 --- a/input-keys.c +++ b/input-keys.c @@ -200,7 +200,7 @@ input_key(struct window_pane *wp, int key) /* Translate mouse and output. */ void -input_mouse(struct window_pane *wp, struct mouse_event *m) +input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m) { char buf[10]; size_t len; @@ -208,14 +208,14 @@ input_mouse(struct window_pane *wp, struct mouse_event *m) if (wp->screen->mode & ALL_MOUSE_MODES) { 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(m->xb + 32, &buf[len]); len += utf8_split2(m->x + 33, &buf[len]); len += utf8_split2(m->y + 33, &buf[len]); } else { - if (m->b > 223 || m->x >= 222 || m->y > 222) + if (m->xb > 223 || m->x >= 222 || m->y > 222) return; len = xsnprintf(buf, sizeof buf, "\033[M"); - buf[len++] = m->b + 32; + buf[len++] = m->xb + 32; buf[len++] = m->x + 33; buf[len++] = m->y + 33; } @@ -223,12 +223,12 @@ input_mouse(struct window_pane *wp, struct mouse_event *m) return; } - if ((m->b & 3) != 1 && + if ((m->xb & 3) != 1 && options_get_number(&wp->window->options, "mode-mouse") == 1) { 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, NULL, m); + wp->mode->mouse(wp, s, m); } return; } diff --git a/layout.c b/layout.c index a0e624fb..adae0ec3 100644 --- a/layout.c +++ b/layout.c @@ -488,50 +488,51 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change) } void -layout_resize_pane_mouse(struct client *c, struct mouse_event *mouse) +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 ((c->last_mouse.b & MOUSE_BUTTON) != MOUSE_UP && - (c->last_mouse.b & MOUSE_RESIZE_PANE)) { + if (m->event & MOUSE_EVENT_DRAG && m->flags & MOUSE_RESIZE_PANE) { TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->xoff + wp->sx == c->last_mouse.x && - wp->yoff <= 1 + c->last_mouse.y && - wp->yoff + wp->sy >= c->last_mouse.y) { + if (wp->xoff + wp->sx == m->lx && + wp->yoff <= 1 + m->ly && + wp->yoff + wp->sy >= m->ly) { layout_resize_pane(wp, LAYOUT_LEFTRIGHT, - mouse->x - c->last_mouse.x); + m->x - m->lx); pane_border = 1; } - if (wp->yoff + wp->sy == c->last_mouse.y && - wp->xoff <= 1 + c->last_mouse.x && - wp->xoff + wp->sx >= c->last_mouse.x) { + if (wp->yoff + wp->sy == m->ly && + wp->xoff <= 1 + m->lx && + wp->xoff + wp->sx >= m->lx) { layout_resize_pane(wp, LAYOUT_TOPBOTTOM, - mouse->y - c->last_mouse.y); + m->y - m->ly); pane_border = 1; } } if (pane_border) server_redraw_window(w); - } else if (mouse->b != MOUSE_UP && - mouse->b == (mouse->b & MOUSE_BUTTON)) { + } else if (~m->event & MOUSE_EVENT_UP) { TAILQ_FOREACH(wp, &w->panes, entry) { - if ((wp->xoff + wp->sx == mouse->x && - wp->yoff <= 1 + mouse->y && - wp->yoff + wp->sy >= mouse->y) || - (wp->yoff + wp->sy == mouse->y && - wp->xoff <= 1 + mouse->x && - wp->xoff + wp->sx >= mouse->x)) { + 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) - mouse->b |= MOUSE_RESIZE_PANE; + m->flags |= MOUSE_RESIZE_PANE; + else + m->flags &= ~MOUSE_RESIZE_PANE; } int diff --git a/server-client.c b/server-client.c index 7f5bfe13..3db11ecb 100644 --- a/server-client.c +++ b/server-client.c @@ -28,8 +28,7 @@ #include "tmux.h" -void server_client_check_mouse(struct client *, struct window_pane *, - struct mouse_event *); +void server_client_check_mouse(struct client *, struct window_pane *); void server_client_repeat_timer(int, short, void *); void server_client_check_exit(struct client *); void server_client_check_redraw(struct client *); @@ -87,8 +86,12 @@ server_client_create(int fd) c->prompt_buffer = NULL; c->prompt_index = 0; - c->last_mouse.b = MOUSE_UP; - c->last_mouse.x = c->last_mouse.y = -1; + 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; evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); @@ -271,37 +274,28 @@ server_client_status_timer(void) /* Check for mouse keys. */ void -server_client_check_mouse( - struct client *c, struct window_pane *wp, struct mouse_event *mouse) +server_client_check_mouse(struct client *c, struct window_pane *wp) { - struct session *s = c->session; - struct options *oo = &s->options; - int statusat; + 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 && mouse->y == (u_int)statusat && + if (statusat != -1 && m->y == (u_int)statusat && options_get_number(oo, "mouse-select-window")) { - if (mouse->b == MOUSE_UP && c->last_mouse.b != MOUSE_UP) { - status_set_window_at(c, mouse->x); - recalculate_sizes(); - return; - } - if (mouse->b & MOUSE_45) { - if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { + 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); - server_redraw_session(s); - recalculate_sizes(); - } - if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { + else if (m->wheel == MOUSE_WHEEL_DOWN) session_next(c->session, 0); - server_redraw_session(s); - recalculate_sizes(); - } - return; + server_redraw_session(s); } - memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); + recalculate_sizes(); return; } @@ -310,27 +304,25 @@ server_client_check_mouse( * top and limit if at the bottom. From here on a struct mouse * represents the offset onto the window itself. */ - if (statusat == 0 &&mouse->y > 0) - mouse->y--; - else if (statusat > 0 && mouse->y >= (u_int)statusat) - mouse->y = statusat - 1; + 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? Allow down only in copy mode. */ if (options_get_number(oo, "mouse-select-pane") && - ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || - wp->mode != &window_copy_mode)) { - window_set_active_at(wp->window, mouse->x, mouse->y); + (m->event == MOUSE_EVENT_DOWN || wp->mode != &window_copy_mode)) { + window_set_active_at(wp->window, m->x, m->y); server_redraw_window_borders(wp->window); wp = wp->window->active; /* may have changed */ } /* Check if trying to resize pane. */ if (options_get_number(oo, "mouse-resize-pane")) - layout_resize_pane_mouse(c, mouse); + layout_resize_pane_mouse(c); /* Update last and pass through to client. */ - memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); - window_pane_mouse(wp, c->session, mouse); + window_pane_mouse(wp, c->session, m); } /* Handle data key input from client. */ @@ -385,7 +377,7 @@ 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, &c->tty.mouse); + server_client_check_mouse(c, wp); return; } @@ -524,7 +516,7 @@ server_client_reset_state(struct client *c) * a smooth appearance. */ mode = s->mode; - if ((c->last_mouse.b & MOUSE_RESIZE_PANE) && + if ((c->tty.mouse.flags & MOUSE_RESIZE_PANE) && !(mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ANY))) mode |= MODE_MOUSE_BUTTON; diff --git a/tmux.h b/tmux.h index e5ad1718..2e2d982f 100644 --- a/tmux.h +++ b/tmux.h @@ -1119,29 +1119,6 @@ struct session { RB_HEAD(sessions, session); ARRAY_DECL(sessionslist, struct session *); -/* - * Mouse input. xterm mouse mode is fairly silly. Buttons are in the bottom two - * bits: 0 = button 1; 1 = button 2; 2 = button 3; 3 = buttons released. Bits - * 3, 4 and 5 are for keys. Bit 6 is set for dragging and 7 for mouse buttons 4 - * and 5. - */ -struct mouse_event { - u_int b; -#define MOUSE_1 0 -#define MOUSE_2 1 -#define MOUSE_3 2 -#define MOUSE_UP 3 -#define MOUSE_BUTTON 3 -#define MOUSE_SHIFT 4 -#define MOUSE_ESCAPE 8 -#define MOUSE_CTRL 16 -#define MOUSE_DRAG 32 -#define MOUSE_45 64 -#define MOUSE_RESIZE_PANE 128 /* marker for resizing */ - u_int x; - u_int y; -}; - /* TTY information. */ struct tty_key { char ch; @@ -1170,6 +1147,47 @@ struct tty_term { }; LIST_HEAD(tty_terms, tty_term); +/* Mouse wheel states. */ +#define MOUSE_WHEEL_UP 0 +#define MOUSE_WHEEL_DOWN 1 + +/* Mouse events. */ +#define MOUSE_EVENT_DOWN (1 << 0) +#define MOUSE_EVENT_DRAG (1 << 1) +#define MOUSE_EVENT_UP (1 << 2) +#define MOUSE_EVENT_CLICK (1 << 3) +#define MOUSE_EVENT_WHEEL (1 << 4) + +/* Mouse flags. */ +#define MOUSE_RESIZE_PANE (1 << 0) + +/* + * Mouse input. When sent by xterm: + * + * - buttons are in the bottom two bits: 0 = b1; 1 = b2; 2 = b3; 3 = released + * - bits 3, 4 and 5 are for keys + * - bit 6 is set for dragging + * - bit 7 for buttons 4 and 5 + */ +struct mouse_event { + u_int xb; + + u_int x; + u_int lx; + u_int sx; + + u_int y; + u_int ly; + u_int sy; + + u_int button; + u_int clicks; + + int wheel; + int event; + int flags; +}; + struct tty { struct client *client; @@ -1330,8 +1348,6 @@ struct client { struct session *session; struct session *last_session; - struct mouse_event last_mouse; - int wlmouse; int references; @@ -1926,7 +1942,8 @@ void input_parse(struct window_pane *); /* input-key.c */ void input_key(struct window_pane *, int); -void input_mouse(struct window_pane *, struct mouse_event *); +void input_mouse(struct window_pane *, struct session *, + struct mouse_event *); /* xterm-keys.c */ char *xterm_keys_lookup(int); @@ -2170,8 +2187,7 @@ void layout_free(struct window *); void layout_resize(struct window *, u_int, u_int); void layout_resize_pane( struct window_pane *, enum layout_type, int); -void layout_resize_pane_mouse( - struct client *c, struct mouse_event *mouse); +void layout_resize_pane_mouse(struct client *c); void layout_assign_pane(struct layout_cell *, struct window_pane *); struct layout_cell *layout_split_pane( struct window_pane *, enum layout_type, int, int); diff --git a/tty-keys.c b/tty-keys.c index f375a07b..6d18d791 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -611,7 +611,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) { struct mouse_event *m = &tty->mouse; struct utf8_data utf8data; - u_int i, value; + u_int i, value, x, y, b; /* * Standard mouse sequences are \033[M followed by three characters @@ -622,6 +622,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) */ *size = 0; + x = y = b = 0; /* First three bytes are always \033[M. */ if (buf[0] != '\033') @@ -661,21 +662,58 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) } if (i == 0) - m->b = value; + b = value; else if (i == 1) - m->x = value; + x = value; else - m->y = value; + y = value; } log_debug("mouse input: %.*s", (int) *size, buf); /* Check and return the mouse input. */ - if (m->b < 32 || m->x < 33 || m->y < 33) + if (b < 32 || x < 33 || y < 33) return (-1); - m->b -= 32; - m->x -= 33; - m->y -= 33; - log_debug("mouse position: x=%u y=%u b=%u", m->x, m->y, m->b); + b -= 32; + x -= 33; + y -= 33; + log_debug("mouse position: x=%u y=%u b=%u", x, y, b); + + /* Fill in mouse structure. */ + if (~m->event & MOUSE_EVENT_WHEEL) { + m->lx = m->x; + m->ly = m->y; + } + m->xb = b; + if (b & 64) { /* wheel button */ + b &= 3; + if (b == 0) + m->wheel = MOUSE_WHEEL_UP; + else if (b == 1) + m->wheel = MOUSE_WHEEL_DOWN; + m->event = MOUSE_EVENT_WHEEL; + } else if ((b & 3) == 3) { + if (~m->event & MOUSE_EVENT_DRAG && x == m->x && y == m->y) { + m->event = MOUSE_EVENT_CLICK; + } else + m->event = MOUSE_EVENT_DRAG; + m->event |= MOUSE_EVENT_UP; + } else { + if (b & 32) /* drag motion */ + m->event = MOUSE_EVENT_DRAG; + else { + if (m->event & MOUSE_EVENT_UP && x == m->x && y == m->y) + m->clicks = (m->clicks + 1) % 3; + else + m->clicks = 0; + m->sx = x; + m->sy = y; + m->event = MOUSE_EVENT_DOWN; + } + m->button = (b & 3); + } + m->x = x; + m->y = y; + return (0); } diff --git a/window-choose.c b/window-choose.c index 019f4125..ab0d803b 100644 --- a/window-choose.c +++ b/window-choose.c @@ -623,7 +623,7 @@ window_choose_mouse( struct window_choose_mode_item *item; u_int idx; - if ((m->b & 3) == 3) + if (~m->event & MOUSE_EVENT_CLICK) return; if (m->x >= screen_size_x(s)) return; diff --git a/window-copy.c b/window-copy.c index bed645f0..97899595 100644 --- a/window-copy.c +++ b/window-copy.c @@ -829,11 +829,11 @@ window_copy_mouse( return; /* If mouse wheel (buttons 4 and 5), scroll. */ - if ((m->b & MOUSE_45)) { - if ((m->b & MOUSE_BUTTON) == MOUSE_1) { + if (m->event == MOUSE_EVENT_WHEEL) { + if (m->wheel == MOUSE_WHEEL_UP) { for (i = 0; i < 5; i++) window_copy_cursor_up(wp, 0); - } else if ((m->b & MOUSE_BUTTON) == MOUSE_2) { + } else if (m->wheel == MOUSE_WHEEL_DOWN) { for (i = 0; i < 5; i++) window_copy_cursor_down(wp, 0); if (data->oy == 0) @@ -847,7 +847,7 @@ window_copy_mouse( * pressed, or stop the selection on their release. */ if (s->mode & MODE_MOUSE_BUTTON) { - if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { + if (~m->event & MOUSE_EVENT_UP) { window_copy_update_cursor(wp, m->x, m->y); if (window_copy_update_selection(wp)) window_copy_redraw_screen(wp); @@ -857,7 +857,7 @@ window_copy_mouse( } /* Otherwise if other buttons pressed, start selection and motion. */ - if ((m->b & MOUSE_BUTTON) != MOUSE_UP) { + if (~m->event & MOUSE_EVENT_UP) { s->mode &= ~MODE_MOUSE_STANDARD; s->mode |= MODE_MOUSE_BUTTON; diff --git a/window.c b/window.c index 07e6ae1b..fc9fa5f3 100644 --- a/window.c +++ b/window.c @@ -1011,7 +1011,7 @@ window_pane_mouse( options_get_number(&wp->window->options, "mode-mouse")) wp->mode->mouse(wp, sess, m); } else if (wp->fd != -1) - input_mouse(wp, m); + input_mouse(wp, sess, m); } int