....phew, mind twisting TAILQ_* macros..but it works now. The problem you described is gone with this, and also this patch allows for complex mouse click patterns (like kill window on triple middle button click then shift left click within one second).. that needs a config syntax though. and yet the coolest thing to try: ncurses mousemask() mode, so the mouse works without xorg - and nested programs in tmux receive input too (finally)... Nicholas can you take a peek at http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/mouse.html ?

...and now: the bed x)
#regards|marcel.
--- input.c.orig	2011-10-24 19:46:41.526436392 +0200
+++ input.c	2011-12-05 20:43:32.997082068 +0100
@@ -723,7 +723,7 @@
 	/* Parse the input. */
 	while (off < len) {
 		ictx->ch = buf[off++];
-		log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
+		//log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
 
 		/* Find the transition. */
 		itr = ictx->state->transitions;
@@ -899,7 +899,7 @@
 	struct window_pane	*wp = ictx->wp;
 	struct screen		*s = sctx->s;
 
-	log_debug("%s: '%c", __func__, ictx->ch);
+	//log_debug("%s: '%c", __func__, ictx->ch);
 
 	switch (ictx->ch) {
 	case '\000':	/* NUL */
@@ -937,7 +937,7 @@
 		ictx->cell.attr &= ~GRID_ATTR_CHARSET;
 		break;
 	default:
-		log_debug("%s: unknown '%c'", __func__, ictx->ch);
+		//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 		break;
 	}
 
@@ -954,12 +954,12 @@
 
 	if (ictx->flags & INPUT_DISCARD)
 		return (0);
-	log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
+	//log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
 
 	entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
 	    sizeof input_esc_table[0], input_table_compare);
 	if (entry == NULL) {
-		log_debug("%s: unknown '%c'", __func__, ictx->ch);
+		//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 		return (0);
 	}
 
@@ -1044,13 +1044,13 @@
 		return (0);
 	if (input_split(ictx) != 0)
 		return (0);
-	log_debug("%s: '%c' \"%s\" \"%s\"",
-	    __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
+	//log_debug("%s: '%c' \"%s\" \"%s\"",
+	 //   __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
 
 	entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
 	    sizeof input_csi_table[0], input_table_compare);
 	if (entry == NULL) {
-		log_debug("%s: unknown '%c'", __func__, ictx->ch);
+		//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 		return (0);
 	}
 
@@ -1087,7 +1087,7 @@
 			input_reply(ictx, "\033[?1;2c");
 			break;
 		default:
-			log_debug("%s: unknown '%c'", __func__, ictx->ch);
+			//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
 		}
 		break;
@@ -1111,7 +1111,7 @@
 			input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
 			break;
 		default:
-			log_debug("%s: unknown '%c'", __func__, ictx->ch);
+			//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
 		}
 		break;
@@ -1138,7 +1138,7 @@
 			}
 			break;
 		default:
-			log_debug("%s: unknown '%c'", __func__, ictx->ch);
+			//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
 		}
 		break;
@@ -1154,7 +1154,7 @@
 			screen_write_clearline(sctx);
 			break;
 		default:
-			log_debug("%s: unknown '%c'", __func__, ictx->ch);
+			//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
 		}
 		break;
@@ -1174,7 +1174,7 @@
 			screen_write_insertmode(&ictx->ctx, 0);
 			break;
 		default:
-			log_debug("%s: unknown '%c'", __func__, ictx->ch);
+			//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
 		}
 		break;
@@ -1203,7 +1203,7 @@
 			window_pane_alternate_off(wp, &ictx->cell);
 			break;
 		default:
-			log_debug("%s: unknown '%c'", __func__, ictx->ch);
+			//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
 		}
 		break;
@@ -1216,7 +1216,7 @@
 			screen_write_insertmode(&ictx->ctx, 1);
 			break;
 		default:
-			log_debug("%s: unknown '%c'", __func__, ictx->ch);
+			//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
 		}
 		break;
@@ -1250,7 +1250,7 @@
 			window_pane_alternate_on(wp, &ictx->cell);
 			break;
 		default:
-			log_debug("%s: unknown '%c'", __func__, ictx->ch);
+			//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
 		}
 		break;
@@ -1264,7 +1264,7 @@
 			bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
 			break;
 		default:
-			log_debug("%s: unknown '%c'", __func__, ictx->ch);
+			//log_debug("%s: unknown '%c'", __func__, ictx->ch);
 			break;
 		}
 		break;
@@ -1437,7 +1437,7 @@
 	if (ictx->flags & INPUT_DISCARD)
 		return (0);
 
-	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
+	//log_debug("%s: \"%s\"", __func__, ictx->input_buf);
 
 	/* Check for tmux prefix. */
 	if (ictx->input_len >= prefix_len &&
@@ -1453,7 +1453,7 @@
 void
 input_enter_osc(struct input_ctx *ictx)
 {
-	log_debug("%s", __func__);
+	//log_debug("%s", __func__);
 
 	input_clear(ictx);
 }
@@ -1470,7 +1470,7 @@
 	if (ictx->input_len < 1 || *p < '0' || *p > '9')
 		return;
 
-	log_debug("%s: \"%s\"", __func__, p);
+	//log_debug("%s: \"%s\"", __func__, p);
 
 	option = 0;
 	while (*p >= '0' && *p <= '9')
@@ -1492,7 +1492,7 @@
 			screen_set_cursor_colour(ictx->ctx.s, "");
 		break;
 	default:
-		log_debug("%s: unknown '%u'", __func__, option);
+		//log_debug("%s: unknown '%u'", __func__, option);
 		break;
 	}
 }
@@ -1501,7 +1501,7 @@
 void
 input_enter_apc(struct input_ctx *ictx)
 {
-	log_debug("%s", __func__);
+	//log_debug("%s", __func__);
 
 	input_clear(ictx);
 }
@@ -1512,7 +1512,7 @@
 {
 	if (ictx->flags & INPUT_DISCARD)
 		return;
-	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
+	//log_debug("%s: \"%s\"", __func__, ictx->input_buf);
 
 	screen_set_title(ictx->ctx.s, ictx->input_buf);
 	server_status_window(ictx->wp->window);
@@ -1522,7 +1522,7 @@
 void
 input_enter_rename(struct input_ctx *ictx)
 {
-	log_debug("%s", __func__);
+	//log_debug("%s", __func__);
 
 	input_clear(ictx);
 }
@@ -1533,7 +1533,7 @@
 {
 	if (ictx->flags & INPUT_DISCARD)
 		return;
-	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
+	//log_debug("%s: \"%s\"", __func__, ictx->input_buf);
 
 	xfree(ictx->wp->window->name);
 	ictx->wp->window->name = xstrdup(ictx->input_buf);
@@ -1551,7 +1551,7 @@
 		input_print(ictx);
 		return (-1);
 	}
-	log_debug("%s", __func__);
+	//log_debug("%s", __func__);
 
 	utf8_open(&ictx->utf8data, ictx->ch);
 	return (0);
@@ -1561,7 +1561,7 @@
 int
 input_utf8_add(struct input_ctx *ictx)
 {
-	log_debug("%s", __func__);
+	//log_debug("%s", __func__);
 
 	utf8_append(&ictx->utf8data, ictx->ch);
 	return (0);
@@ -1571,7 +1571,7 @@
 int
 input_utf8_close(struct input_ctx *ictx)
 {
-	log_debug("%s", __func__);
+	//log_debug("%s", __func__);
 
 	utf8_append(&ictx->utf8data, ictx->ch);
 
--- server-client.c.orig	2011-08-31 21:13:19.912686029 +0200
+++ server-client.c	2011-12-06 02:22:54.380602287 +0100
@@ -88,8 +88,7 @@
 	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 +260,149 @@
 	}
 }
 
+    char *
+    format_binary(unsigned int x)
+    { //panic.cc !!!
+    	#define MAXLEN 8 // width of format
+    	#define MAXCNT 4 // count per printf
+    	static char fmtbuf[(MAXLEN+1)*MAXCNT];
+    	static int count = 0;
+    	char *b;
+    	count = count % MAXCNT + 1;
+    	b = &fmtbuf[(MAXLEN+1)*count];	
+    	b[MAXLEN] = '\0';
+    	for (int z = 0; z < MAXLEN; z++) { b[MAXLEN-1-z] = ((x>>z) & 0x1) ? '1' : '0'; }
+    	return b;
+    }
+
+u_int usec_diff(struct timeval tv1, struct timeval tv2)
+{
+	u_int	diff_usec; //tv1 - tv2
+
+	diff_usec  = tv1.tv_usec - tv2.tv_usec;
+	diff_usec += (tv1.tv_sec - tv2.tv_sec) * 1000000;
+	return diff_usec;
+}
+
+char *
+server_client_mouse_button_string(int b) {
+	static char buf[200];
+//	for (int i = 32; i < 33; i++)
+//		log_debug("mouse event (%u & %u) = %u = (%s & %s) = %s", b, i, (b & i), format_binary(b), format_binary(i), format_binary(b & i));
+	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 ");
+
+/*
+#define MODE_CURSOR 0x1							#define MOUSE_1 0	0
+#define MODE_INSERT 0x2                                                 #define MOUSE_2 1	01
+#define MODE_KCURSOR 0x4                                                #define MOUSE_3 2	10
+#define MODE_KKEYPAD 0x8        // set = application, clear = number    #define MOUSE_UP 3	11
+#define MODE_WRAP 0x10          // whether lines wrap                   #define MOUSE_BUTTON 3	11
+#define MODE_MOUSE_STANDARD 0x20                                        #define MOUSE_SHIFT 4	100
+#define MODE_MOUSE_BUTTON 0x40                                          #define MOUSE_ALT 8	1000
+#define MODE_MOUSE_ANY 0x80                                             #define MOUSE_CTRL 16	10000
+#define MODE_MOUSE_UTF8 0x100                                           #define MOUSE_DRAG 32	100000
+#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD                            #define MOUSE_45 64	1000000
+	|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY)	                        #define MOUSE_RESIZE_PANE	?
+	}*/
+	return buf;
+}
+
+#define MAXMOUSEEVENTS 100
+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("%u elements in tail queue", 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			*button;
+	u_int			 tdiff, i = 0;
+
+	s = c->session;
+	w = s->curw->window;
+	wp = w->active;
+	oo = &s->options;
+
+	memset(m, 0, MAXMOUSEEVENTS * sizeof *m);
+	m[0] = xmalloc(sizeof(struct mouse_event));
+	memcpy(m[0], mouse, sizeof(struct mouse_event));
+
+	button = server_client_mouse_button_string(m[0]->b);
+	tdiff = TAILQ_EMPTY(&c->mouse_events) ? 0 : usec_diff(m[0]->time, TAILQ_FIRST(&c->mouse_events)->time);
+	log_debug("mouse event (%p): button=%u (%s), (x,y)=(%u,%u) @ %u.%u (+%.2fsec)", m[0], m[0]->b, button, m[0]->x, m[0]->y, (uint) m[0]->time.tv_sec, (uint) m[0]->time.tv_usec, tdiff/1000000.0);
+
+	TAILQ_INSERT_HEAD(&c->mouse_events, m[0], entry);
+	server_client_prune_mouse_stack(c);
+	TAILQ_FOREACH(mouse, &c->mouse_events, entry) {
+		m[i] = mouse;
+		i++;
+	}
+
+	if (options_get_number(oo, "mouse-select-pane") &&
+	    ((!(m[0]->b & MOUSE_DRAG) && m[0]->b != MOUSE_UP) || //is neither mouse drag nor button up
+	    wp->mode != &window_copy_mode)) {
+		/*
+		 * Allow pane switching in copy mode only by mouse down
+		 * (click).
+		 */
+		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);
+				server_redraw_session(s);
+			}
+			if ((m[0]->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, m[0]);
+	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 +429,7 @@
 	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,42 +461,8 @@
 	if (key == KEYC_MOUSE) {
 		if (c->flags & CLIENT_READONLY)
 			return;
-		if (options_get_number(oo, "mouse-select-pane") &&
-		    ((!(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? */
@@ -473,6 +582,7 @@
 	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)
@@ -491,7 +601,9 @@
 	 * 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-07-14 17:05:30.322902790 +0200
+++ layout.c	2011-12-06 02:13:16.110926213 +0100
@@ -490,26 +490,27 @@
 {
 	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-07-14 17:05:30.325902745 +0200
+++ tty-keys.c	2011-12-05 20:43:33.005082367 +0100
@@ -645,7 +645,7 @@
 			m->y = value;
 	}
 	log_debug("mouse input: %.*s", (int) *size, buf);
-
+	memset(&m->entry, 0, sizeof(m->entry));	
 	/* Check and return the mouse input. */
 	if (m->b < 32 || m->x < 33 || m->y < 33)
 		return (-1);
--- tmux.h.orig	2011-11-26 04:59:34.927771326 +0100
+++ tmux.h	2011-12-05 20:51:22.352676154 +0100
@@ -1097,12 +1097,18 @@
 #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 {
@@ -1191,7 +1197,7 @@
 	struct session	*session;
 	struct session	*last_session;
 
-	struct mouse_event last_mouse;
+	struct mouse_event_stack mouse_events;
 
 	int		 references;
 };
------------------------------------------------------------------------------
Cloud Services Checklist: Pricing and Packaging Optimization
This white paper is intended to serve as a reference, checklist and point of 
discussion for anyone considering optimizing the pricing and packaging model 
of a cloud services business. Read Now!
http://www.accelacomm.com/jaw/sfnl/114/51491232/
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to