From 36181297d07b25c82c3764c6ae8f0fcfca6c29a7 Mon Sep 17 00:00:00 2001
From: runge <runge>
Date: Thu, 23 Dec 2004 04:05:08 +0000
Subject:  x11vnc: minor tweaks for x11vnc 0.7 file release

---
 prepare_x11vnc_dist.sh |   2 +-
 x11vnc/ChangeLog       |   4 ++
 x11vnc/README          |  30 ++------
 x11vnc/tkx11vnc        |  93 ++++++++++++++++++++++---
 x11vnc/tkx11vnc.h      |  93 ++++++++++++++++++++++---
 x11vnc/x11vnc.1        |   2 +-
 x11vnc/x11vnc.c        | 184 ++++++++++++++++++++++++++++++++++++++++++++++---
 7 files changed, 359 insertions(+), 49 deletions(-)

diff --git a/prepare_x11vnc_dist.sh b/prepare_x11vnc_dist.sh
index 9c1ff03..a2e7bbf 100644
--- a/prepare_x11vnc_dist.sh
+++ b/prepare_x11vnc_dist.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-VERSION="0.6.3pre"
+VERSION="0.7pre"
 
 cd "$(dirname "$0")"
 
diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog
index ee31689..42b6aef 100644
--- a/x11vnc/ChangeLog
+++ b/x11vnc/ChangeLog
@@ -1,3 +1,7 @@
+2004-12-22  Karl Runge <runge@karlrunge.com>
+	* final polishing for 0.7 release, tkx11vnc tweaks
+	* more careful rfbPE in pick_window, start check_user_input4()
+
 2004-12-19  Karl Runge <runge@karlrunge.com>
 	* cleanup putenv, snprint, other string manip.
 	* add -sync mode to remote control for better control
diff --git a/x11vnc/README b/x11vnc/README
index 8e9a89b..b424684 100644
--- a/x11vnc/README
+++ b/x11vnc/README
@@ -1,5 +1,5 @@
 
-x11vnc README file                         Date: Mon Dec 20 11:34:56 EST 2004
+x11vnc README file                         Date: Wed Dec 22 23:18:56 EST 2004
 
 The following information is taken from these URLs:
 
@@ -895,31 +895,15 @@ int srandom(unsigned int seed);
 #undef LIBVNCSERVER_HAVE_LIBPTHREAD
 #define SHUT_RDWR 2
 typedef unsigned int in_addr_t;
-#define XConvertCase(sym, lower, upper) \
-*(lower) = sym; \
-*(upper) = sym; \
-if (sym >> 8 == 0) { \
-    if ((sym >= XK_A) && (sym <= XK_Z)) \
-        *(lower) += (XK_a - XK_A); \
-    else if ((sym >= XK_a) && (sym <= XK_z)) \
-        *(upper) -= (XK_a - XK_A); \
-    else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) \
-        *(lower) += (XK_agrave - XK_Agrave); \
-    else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) \
-        *(upper) -= (XK_agrave - XK_Agrave); \
-    else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) \
-        *(lower) += (XK_oslash - XK_Ooblique); \
-    else if ((sym >= XK_oslash) && (sym <= XK_thorn)) \
-        *(upper) -= (XK_oslash - XK_Ooblique); \
-}
-
-   You will also have to change all the snprint() references to sprintf()
-   calls x11vnc.c (sorry I don't know how to do this in a macro since
-   snprint() is varargs).
+#ifndef snprintf
+#define snprintf(a, n, args...) sprintf((a), ## args)
+#endif
 
    Then run make with the Solaris build script environment, everything
    should compile without problems, and the resulting x11vnc binary
-   should work OK (but note the above XConvertCase only covers Latin 1).
+   should work OK (but note the workaround for XConvertCase in x11vnc.c
+   only covers Latin 1). If some non-x11vnc related programs fail (e.g.
+   test programs) and the x11vnc binary is not created try "make -k".
    Similar sorts of kludges can be done on other older OS (Solaris,
    Linux, ...) releases.
 
diff --git a/x11vnc/tkx11vnc b/x11vnc/tkx11vnc
index b32598f..d2e3782 100755
--- a/x11vnc/tkx11vnc
+++ b/x11vnc/tkx11vnc
@@ -73,6 +73,7 @@ Actions
 	=RA update-all
 	=GA clear-all
 	--
+	=RA stop+quit 
 	=GA Quit 
 
 Help
@@ -284,6 +285,10 @@ remote commands are not on a menu, but for those few you can
 run the command directly this way.  Just enter the command into
 the Entry box when prompted.  Use the prefix \"Q:\" to indicate
 a -Q query.  Examples: \"zero:20,20,100,100\", \"Q:ext_xfixes\"  
+"
+
+	set helptext(stop+quit) "
+Send the stop command to the x11vnc server, then terminate the tkx11vnc gui.
 "
 
 	set helptext(Quit) "
@@ -778,10 +783,16 @@ proc menus_state {state} {
 }
 
 proc menus_enable {} {
+	global menus_disabled
+
 	menus_state "normal"
+	set menus_disabled 0
 }
 
 proc menus_disable {} {
+	global menus_disabled
+
+	set menus_disabled 1
 	menus_state "disabled"
 }
 
@@ -1183,6 +1194,8 @@ proc see_if_ok {query item expected} {
 	set query_result_list [split_query $query]
 
 	foreach q $query_result_list {
+		# XXX following will crash if $item is not a good regexp
+		# need to protect it \Q$item\E style...
 #		if {[regexp "^$item:" $q]} {
 #			set found $q
 #		}
@@ -1409,6 +1422,12 @@ proc do_action {item} {
 	} elseif {$item == "all-settings"} {
 		show_all_settings
 		return
+	} elseif {$item == "stop+quit"} {
+		push_new_value "stop" "stop" 1 0
+		set_connected no
+		update
+		after 500
+		destroy .
 	}
 
 	if {[value_is_string $item]} {
@@ -1656,12 +1675,45 @@ proc disconnect_dialog {client} {
 	}
 }
 
+proc update_clients_and_repost {} {
+	global item_cascade menu_m menu_b
+
+	append_text "Refreshing connected clients list... "
+	query_all 1
+	update
+
+	set saw 0
+	set casc $item_cascade(current)
+	set last [$casc index end]
+	for {set i 0} {$i <= $last} {incr i} {
+		if {[$casc type $i] == "separator"} {
+			continue
+		}
+		set name [$casc entrycget $i -label]
+		if {[regexp {^#} $name]} {
+			continue
+		}
+		if {[regexp {^refresh-list} $name]} {
+			continue
+		}
+		if {! $saw} {
+			append_text "\n"
+		}
+		set saw 1
+		append_text "client: $name\n"
+	}
+	if {! $saw} {
+		append_text "done.\n"
+	}
+}
+
 proc update_clients_menu {list} {
 	global item_cascade
 	set subm $item_cascade(current);
 	catch {destroy $subm}
 	menu $subm -tearoff 0
 	$subm add command
+	$subm add command -label "refresh-list" -command "update_clients_and_repost"
 	$subm add separator
 	set count 0
 	foreach client [split $list ","] {
@@ -1762,7 +1814,16 @@ set v 0
 			set menu "$colf.menu$case.menu";
 			set menu_b($case) $menub
 			set menu_m($case) $menu
-			menubutton $menub -text "$case" -underline 0 \
+			set ul 0
+			foreach char [split $case ""] {
+				set char [string tolower $char]
+				if {![info exists underlined($char)]} {
+					set underlined($char) 1
+					break
+				}
+				incr ul
+			}
+			menubutton $menub -text "$case" -underline $ul \
 				-anchor w -menu $menu -background $fbg \
 				-font $bfont
 			pack $menub -side top -fill x
@@ -2036,16 +2097,31 @@ MenuSelect>>
 }
 
 proc key_bindings {} {
-	global env
+	global env menus_disabled
 	if {[info exists env(USER)] && $env(USER) == "runge"} {
 		# quick restart
 		bind . <Control-KeyPress-c> {exec $argv0 $argv &; destroy .}
 	}
-	bind . <Control-KeyPress-p> {try_connect_and_query_all}
-	bind . <Control-KeyPress-u> {query_all 0}
-	bind . <Control-KeyPress-r> {query_all 0}
-	bind . <Control-KeyPress-d> {detach_from_display}
-	bind . <Control-KeyPress-a> {try_connect_and_query_all}
+	bind . <Control-KeyPress-p> { \
+		global menus_disabled; \
+		if {!$menus_disabled} {try_connect_and_query_all} \
+	}
+	bind . <Control-KeyPress-u> { \
+		global menus_disabled; \
+		if {!$menus_disabled} {query_all 0} \
+	}
+	bind . <Control-KeyPress-r> { \
+		global menus_disabled; \
+		if {!$menus_disabled} {query_all 0} \
+	}
+	bind . <Control-KeyPress-d> { \
+		global menus_disabled; \
+		if {!$menus_disabled} {detach_from_display} \
+	}
+	bind . <Control-KeyPress-a> { \
+		global menus_disabled; \
+		if {!$menus_disabled} {try_connect_and_query_all} \
+	}
 }
 
 proc stop_watch {onoff} {
@@ -2337,7 +2413,7 @@ global env x11vnc_prog x11vnc_cmdline x11vnc_xdisplay x11vnc_connect;
 global helpall helptext helpremote helplabel hostname;
 global all_settings reply_xdisplay always_update
 global max_text_height max_text_width
-global menu_var unset_str
+global menu_var unset_str menus_disabled
 global bfont
 global connected_to_x11vnc
 global delay_sleep extra_sleep extra_sleep_split
@@ -2345,6 +2421,7 @@ global cache_all_query_vars
 
 set unset_str "(unset)"
 set connected_to_x11vnc 0
+set menus_disabled 0
 set max_text_height 40
 set max_text_width 90
 set bfont -adobe-helvetica-bold-r-*-*-*-120-*-*-*-*-*-*;
diff --git a/x11vnc/tkx11vnc.h b/x11vnc/tkx11vnc.h
index 0f442a2..ddd5f23 100644
--- a/x11vnc/tkx11vnc.h
+++ b/x11vnc/tkx11vnc.h
@@ -79,6 +79,7 @@
 "	=RA update-all\n"
 "	=GA clear-all\n"
 "	--\n"
+"	=RA stop+quit \n"
 "	=GA Quit \n"
 "\n"
 "Help\n"
@@ -292,6 +293,10 @@
 "a -Q query.  Examples: \\\"zero:20,20,100,100\\\", \\\"Q:ext_xfixes\\\"  \n"
 "\"\n"
 "\n"
+"	set helptext(stop+quit) \"\n"
+"Send the stop command to the x11vnc server, then terminate the tkx11vnc gui.\n"
+"\"\n"
+"\n"
 "	set helptext(Quit) \"\n"
 "Terminate the tkx11vnc gui.  Any x11vnc servers will be left running.\n"
 "\"\n"
@@ -784,10 +789,16 @@
 "}\n"
 "\n"
 "proc menus_enable {} {\n"
+"	global menus_disabled\n"
+"\n"
 "	menus_state \"normal\"\n"
+"	set menus_disabled 0\n"
 "}\n"
 "\n"
 "proc menus_disable {} {\n"
+"	global menus_disabled\n"
+"\n"
+"	set menus_disabled 1\n"
 "	menus_state \"disabled\"\n"
 "}\n"
 "\n"
@@ -1189,6 +1200,8 @@
 "	set query_result_list [split_query $query]\n"
 "\n"
 "	foreach q $query_result_list {\n"
+"		# XXX following will crash if $item is not a good regexp\n"
+"		# need to protect it \\Q$item\\E style...\n"
 "#		if {[regexp \"^$item:\" $q]} {\n"
 "#			set found $q\n"
 "#		}\n"
@@ -1415,6 +1428,12 @@
 "	} elseif {$item == \"all-settings\"} {\n"
 "		show_all_settings\n"
 "		return\n"
+"	} elseif {$item == \"stop+quit\"} {\n"
+"		push_new_value \"stop\" \"stop\" 1 0\n"
+"		set_connected no\n"
+"		update\n"
+"		after 500\n"
+"		destroy .\n"
 "	}\n"
 "\n"
 "	if {[value_is_string $item]} {\n"
@@ -1662,12 +1681,45 @@
 "	}\n"
 "}\n"
 "\n"
+"proc update_clients_and_repost {} {\n"
+"	global item_cascade menu_m menu_b\n"
+"\n"
+"	append_text \"Refreshing connected clients list... \"\n"
+"	query_all 1\n"
+"	update\n"
+"\n"
+"	set saw 0\n"
+"	set casc $item_cascade(current)\n"
+"	set last [$casc index end]\n"
+"	for {set i 0} {$i <= $last} {incr i} {\n"
+"		if {[$casc type $i] == \"separator\"} {\n"
+"			continue\n"
+"		}\n"
+"		set name [$casc entrycget $i -label]\n"
+"		if {[regexp {^#} $name]} {\n"
+"			continue\n"
+"		}\n"
+"		if {[regexp {^refresh-list} $name]} {\n"
+"			continue\n"
+"		}\n"
+"		if {! $saw} {\n"
+"			append_text \"\\n\"\n"
+"		}\n"
+"		set saw 1\n"
+"		append_text \"client: $name\\n\"\n"
+"	}\n"
+"	if {! $saw} {\n"
+"		append_text \"done.\\n\"\n"
+"	}\n"
+"}\n"
+"\n"
 "proc update_clients_menu {list} {\n"
 "	global item_cascade\n"
 "	set subm $item_cascade(current);\n"
 "	catch {destroy $subm}\n"
 "	menu $subm -tearoff 0\n"
 "	$subm add command\n"
+"	$subm add command -label \"refresh-list\" -command \"update_clients_and_repost\"\n"
 "	$subm add separator\n"
 "	set count 0\n"
 "	foreach client [split $list \",\"] {\n"
@@ -1768,7 +1820,16 @@
 "			set menu \"$colf.menu$case.menu\";\n"
 "			set menu_b($case) $menub\n"
 "			set menu_m($case) $menu\n"
-"			menubutton $menub -text \"$case\" -underline 0 \\\n"
+"			set ul 0\n"
+"			foreach char [split $case \"\"] {\n"
+"				set char [string tolower $char]\n"
+"				if {![info exists underlined($char)]} {\n"
+"					set underlined($char) 1\n"
+"					break\n"
+"				}\n"
+"				incr ul\n"
+"			}\n"
+"			menubutton $menub -text \"$case\" -underline $ul \\\n"
 "				-anchor w -menu $menu -background $fbg \\\n"
 "				-font $bfont\n"
 "			pack $menub -side top -fill x\n"
@@ -2042,16 +2103,31 @@
 "}\n"
 "\n"
 "proc key_bindings {} {\n"
-"	global env\n"
+"	global env menus_disabled\n"
 "	if {[info exists env(USER)] && $env(USER) == \"runge\"} {\n"
 "		# quick restart\n"
 "		bind . <Control-KeyPress-c> {exec $argv0 $argv &; destroy .}\n"
 "	}\n"
-"	bind . <Control-KeyPress-p> {try_connect_and_query_all}\n"
-"	bind . <Control-KeyPress-u> {query_all 0}\n"
-"	bind . <Control-KeyPress-r> {query_all 0}\n"
-"	bind . <Control-KeyPress-d> {detach_from_display}\n"
-"	bind . <Control-KeyPress-a> {try_connect_and_query_all}\n"
+"	bind . <Control-KeyPress-p> { \\\n"
+"		global menus_disabled; \\\n"
+"		if {!$menus_disabled} {try_connect_and_query_all} \\\n"
+"	}\n"
+"	bind . <Control-KeyPress-u> { \\\n"
+"		global menus_disabled; \\\n"
+"		if {!$menus_disabled} {query_all 0} \\\n"
+"	}\n"
+"	bind . <Control-KeyPress-r> { \\\n"
+"		global menus_disabled; \\\n"
+"		if {!$menus_disabled} {query_all 0} \\\n"
+"	}\n"
+"	bind . <Control-KeyPress-d> { \\\n"
+"		global menus_disabled; \\\n"
+"		if {!$menus_disabled} {detach_from_display} \\\n"
+"	}\n"
+"	bind . <Control-KeyPress-a> { \\\n"
+"		global menus_disabled; \\\n"
+"		if {!$menus_disabled} {try_connect_and_query_all} \\\n"
+"	}\n"
 "}\n"
 "\n"
 "proc stop_watch {onoff} {\n"
@@ -2343,7 +2419,7 @@
 "global helpall helptext helpremote helplabel hostname;\n"
 "global all_settings reply_xdisplay always_update\n"
 "global max_text_height max_text_width\n"
-"global menu_var unset_str\n"
+"global menu_var unset_str menus_disabled\n"
 "global bfont\n"
 "global connected_to_x11vnc\n"
 "global delay_sleep extra_sleep extra_sleep_split\n"
@@ -2351,6 +2427,7 @@
 "\n"
 "set unset_str \"(unset)\"\n"
 "set connected_to_x11vnc 0\n"
+"set menus_disabled 0\n"
 "set max_text_height 40\n"
 "set max_text_width 90\n"
 "set bfont -adobe-helvetica-bold-r-*-*-*-120-*-*-*-*-*-*;\n"
diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1
index abf7273..2f15efc 100644
--- a/x11vnc/x11vnc.1
+++ b/x11vnc/x11vnc.1
@@ -2,7 +2,7 @@
 .TH X11VNC "1" "December 2004" "x11vnc " "User Commands"
 .SH NAME
 x11vnc - allow VNC connections to real X11 displays
-         version: 0.7pre, lastmod: 2004-12-20
+         version: 0.7pre, lastmod: 2004-12-23
 .SH SYNOPSIS
 .B x11vnc
 [OPTION]...
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index 0a23219..96781a5 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -256,7 +256,7 @@ static int xdamage_base_event_type;
 #endif
 
 /*               date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.7pre lastmod: 2004-12-20";
+char lastmod[] = "0.7pre lastmod: 2004-12-23";
 
 /* X display info */
 
@@ -732,13 +732,21 @@ int pick_windowid(unsigned long *num) {
 
 		if (screen && screen->clientHead) {
 			/* they may be doing the pointer-pick thru vnc: */
+			int nfds;
 			tv.tv_sec = 0;
 			tv.tv_usec = msec * 1000;
 			FD_ZERO(&set);
 			FD_SET(fileno(p), &set);
-			if (select(fileno(p)+1, &set, NULL, NULL, &tv) == 0) {
-				/* note that rfbPE takes about 30ms too */
+
+			nfds = select(fileno(p)+1, &set, NULL, NULL, &tv);
+			
+			if (nfds == 0 || nfds < 0) {
+				/* 
+				 * select timedout or error.
+				 * note this rfbPE takes about 30ms too:
+				 */
 				rfbPE(screen, -1);
+				XFlush(dpy);
 				continue;
 			}
 		}
@@ -12585,7 +12593,7 @@ static void check_user_input3(double dt, int tile_diffs) {
 		int spun_out, missed_out, allowed_misses, g, g_in;
 		double spin, spin_max, tm, to, dtm, rpe_last;
 		static int rfb_wait_ms = 2;
-		static double grind_spin_time = 0.30, dt_min = 0.075;
+		static double grind_spin_time = 0.30, dt_cut = 0.075;
 		static double quick_spin_fac = 0.65, spin_max_fac = 2.0;
 		static double rpe_wait = 0.15;
 		int grinding, gcnt, ms, split = 200;
@@ -12593,12 +12601,13 @@ static void check_user_input3(double dt, int tile_diffs) {
 		if (first) {
 			char *p = getenv("SPIN");
 			if (p) {
-				sscanf(p, "%lf,%lf,%lf", &grind_spin_time, &dt_min, &quick_spin_fac);
+				sscanf(p, "%lf,%lf,%lf", &grind_spin_time, &dt_cut, &quick_spin_fac);
 			}
 			first = 0;
 		}
 
 
+
 		/*
 		 * Try for some "quick" pointer input processing.
 		 *
@@ -12615,8 +12624,8 @@ static void check_user_input3(double dt, int tile_diffs) {
 		 * should continue, if we do so we say we are "grinding"
 		 */
 
-		if (dt < dt_min) {
-			dt = dt_min;	/* this is to try to avoid early exit */
+		if (dt < dt_cut) {
+			dt = dt_cut;	/* this is to try to avoid early exit */
 		}
 		/* max spin time in 1st pass, comparable to last dt */
 		spin_max = quick_spin_fac * dt;
@@ -12723,8 +12732,167 @@ static void check_user_input3(double dt, int tile_diffs) {
 	drag_in_progress = 0;
 }
 
+/* quick-n-dirty copy of check_user_input3, merge later... */
+
 static void check_user_input4(double dt, int tile_diffs) {
-	return;
+
+	int spun_out, missed_out, allowed_misses, g, g_in;
+	double spin, spin_max, tm, to, dtm, rpe_last;
+	static int rfb_wait_ms = 2;
+	static double grind_spin_time = 0.30, dt_cut = 0.075;
+	static double quick_spin_fac = 0.65, spin_max_fac = 2.0;
+	static double rpe_wait = 0.15;
+	int grinding, gcnt, ms, split = 200;
+	static int first = 1;
+
+	int Btile = tile_x * tile_y * bpp/8; 
+	double Ttile;
+	double screen_rate = 5000000.;    /* 5 MB/sec */
+	double client_rate = 80 * 100000.; /* 20 KB/sec @ 80X compression */
+	static double Tfac = 1.0;
+	static double dt_min = -1.0, dt_max = -1.0;
+
+	if (first) {
+		char *p = getenv("SPIN");
+		if (p) {
+			sscanf(p, "%lf,%lf,%lf,%lf", &grind_spin_time,
+			    &dt_cut, &quick_spin_fac, &Tfac);
+		}
+		first = 0;
+	}
+
+	if (dt_min < 0 || dt < dt_min) {
+		dt_min = dt;
+	}
+	if (dt_max < 0 || dt > dt_max) {
+		dt_max = dt;
+	}
+
+	/*
+	 * when we first enter we require some pointer input
+	 */
+	if (!got_pointer_input) {
+		drag_in_progress = 0;
+		return;
+	}
+
+	Ttile = Btile * (1.0/screen_rate + 1.0/client_rate);
+	Ttile = Tfac * Ttile;
+
+	if (dt < dt_cut) {
+		dt = dt_cut;	/* this is to try to avoid early exit */
+	}
+
+	/* max spin time in 1st pass, comparable to last dt */
+	spin_max = quick_spin_fac * dt;
+
+	grinding = 0;		/* 1st pass is "not grinding" */
+	spin = 0.0;		/* amount of time spinning */
+	spun_out = 0;		/* whether we spun out of time */
+	missed_out = 0;		/* whether we received no ptr input */
+	allowed_misses = 3;	/* number of ptr inputs we can miss */
+	gcnt = 0;
+
+	tm = 0.0;		/* timer variable */
+	dtime(&tm);
+	rpe_last = to = tm;	/* last time we did rfbPE() */
+	g = g_in = got_pointer_input;
+
+
+	while (1) {
+		int got_input = 0;
+
+		gcnt++;
+		if (grinding) {
+			if (gcnt >= split) {
+				break;
+			}
+			usleep(ms * 1000);
+		}
+
+		if (button_mask) {
+			drag_in_progress = 1;
+		}
+
+		if (show_multiple_cursors && tm > rpe_last + rpe_wait) {
+			rfbPE(screen, rfb_wait_ms * 1000);
+			rpe_last = tm;
+		} else {
+			rfbCFD(screen, rfb_wait_ms * 1000);
+		}
+
+		dtm = dtime(&tm);
+		spin += dtm;
+
+		if (spin > spin_max) {
+			/* get out if spin time over limit */
+			spun_out = 1;
+
+		} else if (tile_diffs > 200 && spin > Ttile * tile_diffs) {
+			/* XXX not finished. */
+			/* we think we can push the frame */
+			break;
+
+		} else if (got_pointer_input > g) {
+			/* received some input, flush to display. */
+			got_input = 1;
+			g = got_pointer_input;
+			XFlush(dpy);
+
+		} else if (--allowed_misses <= 0) {
+			/* too many misses */
+			missed_out = 1;
+
+		} else {
+			/* these are misses */
+			int wms = 0;
+			if (! grinding && gcnt == 1 && button_mask) {
+				/*
+				 * missed our first input, wait for
+				 * a defer time. (e.g. on slow link)
+				 * hopefully client will batch them.
+				 */
+				wms = 1000 * (0.5 * (spin_max - spin));
+
+			} else if (button_mask) {
+				wms = 10;
+			}
+			if (wms) {
+				usleep(wms * 1000);
+			}
+		}
+		if (spun_out && ! grinding) {
+			/* set parameters for grinding mode. */
+
+			grinding = 1;
+
+			if (spin > grind_spin_time || button_mask) {
+				spin_max = spin +
+				    grind_spin_time * spin_max_fac;
+			} else {
+				spin_max = spin + dt * spin_max_fac;
+			}
+			ms = (int) (1000 * ((spin_max - spin)/split));
+			if (ms < 1) {
+				ms = 1;
+			}
+
+			/* reset for second pass */
+			spun_out = 0;
+			missed_out = 0;
+			allowed_misses = 3;
+			g = got_pointer_input;
+			gcnt = 0;
+
+		} else if (spun_out && grinding) {
+			/* done in 2nd pass */
+			break;
+		} else if (missed_out) {
+			/* done in either pass */
+			break;
+		}
+	}
+	drag_in_progress = 0;
 }
 
 static int check_user_input(double dt, int tile_diffs, int *cnt) {
-- 
cgit v1.2.3

