On 24/12/11 09:27, Nicholas Marriott wrote:
Uhhm.. well. Rerolled my previous patch (and converted the time_diff function into a #MACRO). Another one here, don't exit mouse-mode for mode-mouse=copy-mode when reaching bottom.Yes, not intended. Fix applied, thanks!
#regards/marcel.
--- input-keys.c.orig 2011-12-27 17:59:02.747319071 +0100 +++ input-keys.c 2011-12-27 18:36:46.075369931 +0100 @@ -203,7 +203,7 @@ input_mouse(struct window_pane *wp, stru { char buf[10]; size_t len; - int value; + int mode, i, lines; if (wp->screen->mode & ALL_MOUSE_MODES) { if (wp->screen->mode & MODE_MOUSE_UTF8) { @@ -220,13 +220,29 @@ input_mouse(struct window_pane *wp, stru buf[len++] = m->y + 33; } bufferevent_write(wp->event, buf, len); - } else if ((m->b & MOUSE_BUTTON) != MOUSE_2) { - value = options_get_number(&wp->window->options, "mode-mouse"); - if (value == 1 && + return; + } + if ((m->b & MOUSE_BUTTON) != MOUSE_2) { + mode = options_get_number(&wp->window->options, "mode-mouse"); + if (mode == 1 && 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); + return; } } + /* Emulate mouse wheel scrolling. */ + if (m->b & MOUSE_45) { + /* + * Wheel + shift: scroll 1 line + * Wheel + ctrl: scroll at triple speed + * */ + lines = (m->b & MOUSE_SHIFT) ? 1 : MOUSE_SCROLL_EMU_LINES; + if (m->b & MOUSE_CTRL) + lines *= 3; + + for (i=0; i < lines; i++) + input_key(wp, (m->b & MOUSE_BUTTON) == MOUSE_1 ? KEYC_UP : KEYC_DOWN); + } } --- server-client.c.orig 2011-12-27 17:59:02.823321926 +0100 +++ server-client.c 2011-12-27 19:27:27.319632742 +0100 @@ -26,6 +26,9 @@ #include "tmux.h" +char* server_client_mouse_button_string(int); +void server_client_prune_mouse_stack(struct client *); +void server_client_handle_mouse_event(struct client *, struct mouse_event *); void server_client_handle_key(int, struct mouse_event *, void *); void server_client_repeat_timer(int, short, void *); void server_client_check_exit(struct client *); @@ -88,8 +91,7 @@ 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; + TAILQ_INIT(&c->mouse_events); evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); @@ -261,6 +263,115 @@ server_client_status_timer(void) } } +char * +server_client_mouse_button_string(int b) { + static char buf[200]; + buf[0] = '\0'; + if (b & MOUSE_SHIFT) strcat(buf, "shift "); + if (b & MOUSE_ALT) strcat(buf, "alt "); + if (b & MOUSE_CTRL) strcat(buf, "ctrl "); + if (!(b & MOUSE_45) && ((b & MOUSE_BUTTON) == MOUSE_1)) strcat(buf, "left "); + if (!(b & MOUSE_45) && ((b & MOUSE_BUTTON) == MOUSE_2)) strcat(buf, "middle "); + if ((b & MOUSE_BUTTON) == MOUSE_3) strcat(buf, "right "); + if (!(b & MOUSE_45) && ((b & MOUSE_BUTTON) == MOUSE_BUTTON)) strcat(buf, "buttonup "); + if (b & MOUSE_DRAG) strcat(buf, "drag "); + if ((b & MOUSE_45) && (b & MOUSE_BUTTON) == MOUSE_1) strcat(buf, "wheelup "); + if ((b & MOUSE_45) && (b & MOUSE_BUTTON) == MOUSE_2) strcat(buf, "wheeldown "); + + return buf; +} + +#define MAXMOUSEEVENTS 10 +void +server_client_prune_mouse_stack(struct client *c) +{ + struct mouse_event *m = TAILQ_FIRST(&c->mouse_events); + int i = 0; + + while (m) { + if(++i == MAXMOUSEEVENTS) { + TAILQ_REMOVE(&c->mouse_events, m, entry); + xfree(m); + break; + } else + m = TAILQ_NEXT(m, entry); + } + log_debug("mouse: %u events in history", i); + +} + +void +server_client_handle_mouse_event(struct client *c, struct mouse_event *mouse) +{ + struct mouse_event *m[MAXMOUSEEVENTS]; + struct session *s; + struct window *w; + struct window_pane *wp; + struct options *oo; + char *btn_str; + u_int tdiff, i = 0; + + s = c->session; + w = s->curw->window; + wp = w->active; + oo = &s->options; + + btn_str = server_client_mouse_button_string(mouse->b); + tdiff = TAILQ_EMPTY(&c->mouse_events) ? 0 : TIME_DIFF(TAILQ_FIRST(&c->mouse_events)->time, mouse->time); + log_debug("mouse event: %s(button=%u), (x,y)=(%u,%u) (+%.2fsec)", + btn_str, mouse->b, mouse->x, mouse->y, tdiff/1000.0); + + memset(m, 0, MAXMOUSEEVENTS * sizeof *m); + m[0] = xmalloc(sizeof(struct mouse_event)); + memcpy(m[0], mouse, sizeof(struct mouse_event)); + + TAILQ_INSERT_HEAD(&c->mouse_events, m[0], entry); + server_client_prune_mouse_stack(c); + /* Map the mouse event history tail queue to an array for laziness benefit. */ + TAILQ_FOREACH(mouse, &c->mouse_events, entry) { + m[i] = mouse; + i++; + } + + if (options_get_number(oo, "mouse-select-pane") && + /* Make sure event is not over status line. */ + !(options_get_number(oo, "status") && m[0]->y + 1 == c->tty.sy) && + (wp->mode != &window_copy_mode || + /* Copy mode: check that event is neither mouse drag nor button up. */ + (!(m[0]->b & MOUSE_DRAG) && m[0]->b != MOUSE_UP))) { + window_set_active_at(w, m[0]->x, m[0]->y); + server_redraw_window_borders(w); + wp = w->active; + } + if (m[0]->y + 1 == c->tty.sy && + options_get_number(oo, "mouse-select-window") && + options_get_number(oo, "status")) { + if (m[0]->b == MOUSE_UP && m[1] && m[1]->b != MOUSE_UP) { + status_set_window_at(c, m[0]->x); + return; + } + if (m[0]->b & MOUSE_45) { + if ((m[0]->b & MOUSE_BUTTON) == MOUSE_1) { + session_previous(c->session, 0); + } + if ((m[0]->b & MOUSE_BUTTON) == MOUSE_2) { + session_next(c->session, 0); + } + recalculate_sizes(); + server_redraw_session(s); + return; + } + } + if (options_get_number(oo, "mouse-resize-pane")) + layout_resize_pane_mouse(c, m[0]); + /* + * TODO: Elaborate mouse click gesture matching on + * event history array goes here. Config syntax? + */ + window_pane_mouse(wp, c->session, m[0]); + return; +} + /* Handle data key input from client. */ void server_client_handle_key(int key, struct mouse_event *mouse, void *data) @@ -287,6 +398,7 @@ server_client_handle_key(int key, struct if (gettimeofday(&c->activity_time, NULL) != 0) fatal("gettimeofday failed"); memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); + memcpy(&mouse->time, &c->activity_time, sizeof mouse->time); w = c->session->curw->window; wp = w->active; @@ -318,44 +430,8 @@ server_client_handle_key(int key, struct if (key == KEYC_MOUSE) { if (c->flags & CLIENT_READONLY) return; - if (options_get_number(oo, "mouse-select-pane") && - (!(options_get_number(oo, "status") && - mouse->y + 1 == c->tty.sy)) && - ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || - wp->mode != &window_copy_mode)) { - /* - * Allow pane switching in copy mode only by mouse down - * (click). - */ - window_set_active_at(w, mouse->x, mouse->y); - server_redraw_window_borders(w); - wp = w->active; - } - if (mouse->y + 1 == c->tty.sy && - options_get_number(oo, "mouse-select-window") && - options_get_number(oo, "status")) { - if (mouse->b == MOUSE_UP && - c->last_mouse.b != MOUSE_UP) { - status_set_window_at(c, mouse->x); - return; - } - if (mouse->b & MOUSE_45) { - if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { - session_previous(c->session, 0); - server_redraw_session(s); - } - if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { - session_next(c->session, 0); - server_redraw_session(s); - } - return; - } - } - if (options_get_number(oo, "mouse-resize-pane")) - layout_resize_pane_mouse(c, mouse); - memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); - window_pane_mouse(wp, c->session, mouse); - return; + else + server_client_handle_mouse_event(c, mouse); } /* Is this a prefix key? */ @@ -475,6 +551,7 @@ server_client_reset_state(struct client struct screen *s = wp->screen; struct options *oo = &c->session->options; struct options *wo = &w->options; + struct mouse_event *lm; int status, mode; if (c->flags & CLIENT_SUSPENDED) @@ -493,7 +570,9 @@ server_client_reset_state(struct client * a smooth appearance. */ mode = s->mode; - if ((c->last_mouse.b & MOUSE_RESIZE_PANE) && + if (!TAILQ_EMPTY(&c->mouse_events) && + (lm = TAILQ_NEXT(TAILQ_FIRST(&c->mouse_events), entry)) != NULL && + lm->b & MOUSE_RESIZE_PANE && !(mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ANY))) mode |= MODE_MOUSE_BUTTON; --- layout.c.orig 2011-12-27 17:59:02.775320122 +0100 +++ layout.c 2011-12-27 18:36:46.091370533 +0100 @@ -490,26 +490,27 @@ layout_resize_pane_mouse(struct client * { struct window *w; struct window_pane *wp; + struct mouse_event *last_mouse = TAILQ_NEXT(mouse, entry); 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 (last_mouse != NULL && (last_mouse->b & MOUSE_BUTTON) != MOUSE_UP && + (last_mouse->b & 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 == last_mouse->x && + wp->yoff <= 1 + last_mouse->y && + wp->yoff + wp->sy >= last_mouse->y) { layout_resize_pane(wp, LAYOUT_LEFTRIGHT, - mouse->x - c->last_mouse.x); + mouse->x - last_mouse->x); 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 == last_mouse->y && + wp->xoff <= 1 + last_mouse->x && + wp->xoff + wp->sx >= last_mouse->x) { layout_resize_pane(wp, LAYOUT_TOPBOTTOM, - mouse->y - c->last_mouse.y); + mouse->y - last_mouse->y); pane_border = 1; } } --- tty-keys.c.orig 2011-12-27 17:59:02.876323918 +0100 +++ tty-keys.c 2011-12-27 18:36:46.095370685 +0100 @@ -633,6 +633,7 @@ tty_keys_mouse(struct tty *tty, value = (unsigned char)buf[*size]; (*size)++; } else { + /* FIXME: x > 160 = pointeger magic casting FAIL? */ value = (unsigned char)buf[*size]; (*size)++; } @@ -644,14 +645,12 @@ tty_keys_mouse(struct tty *tty, else m->y = value; } - log_debug("mouse input: %.*s", (int) *size, buf); - - /* Check and return the mouse input. */ + /* Fail on invalid mouse input. */ if (m->b < 32 || m->x < 33 || m->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); + memset(&m->entry, 0, sizeof(m->entry)); return (0); } --- tmux.h.orig 2011-12-27 17:59:02.875323880 +0100 +++ tmux.h 2011-12-27 19:18:23.015196400 +0100 @@ -86,6 +86,10 @@ extern char **environ; #define printflike4 __attribute__ ((format (printf, 4, 5))) #define printflike5 __attribute__ ((format (printf, 5, 6))) +/* Millisecond time difference (timeval) second - (timeval) first. */ +#define TIME_DIFF(first,second) ((second.tv_sec - first.tv_sec)*1000 + \ + (second.tv_usec - first.tv_usec)/1000) + /* Number of items in array. */ #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -569,6 +573,8 @@ struct mode_key_table { #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY) +#define MOUSE_SCROLL_EMU_LINES 3 + /* * A single UTF-8 character. * @@ -1099,12 +1105,18 @@ struct mouse_event { #define MOUSE_3 2 #define MOUSE_UP 3 #define MOUSE_BUTTON 3 +#define MOUSE_SHIFT 4 +#define MOUSE_ALT 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; + struct timeval time; + TAILQ_ENTRY(mouse_event) entry; }; +TAILQ_HEAD(mouse_event_stack, mouse_event); /* Saved message entry. */ struct message_entry { @@ -1193,7 +1205,7 @@ struct client { struct session *session; struct session *last_session; - struct mouse_event last_mouse; + struct mouse_event_stack mouse_events; int references; };
--- window-copy.c.orig 2011-12-25 13:00:13.090541316 +0100 +++ window-copy.c 2011-12-25 13:24:00.553528172 +0100 @@ -838,7 +838,8 @@ window_copy_mouse( old_cy = data->cy; for (i = 0; i < 5; i++) window_copy_cursor_down(wp, 0); - if (old_cy == data->cy) + if (old_cy == data->cy && + options_get_number(&wp->window->options, "mode-mouse") == 1) goto reset_mode; } return;
------------------------------------------------------------------------------ Write once. Port to many. Get the SDK and tools to simplify cross-platform app development. Create new or port existing apps to sell to consumers worldwide. Explore the Intel AppUpSM program developer opportunity. appdeveloper.intel.com/join http://p.sf.net/sfu/intel-appdev
_______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users