Implemented new "Autoplay" parameter to start the player in the
playback mode. Positioning during playback is now allowed. The desktop
contents is now being updated correctly on startup and after
positioning in the paused mode. Also a number of minor cleanups.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2520 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/java/src/com/tightvnc/rfbplayer/ButtonPanel.java b/java/src/com/tightvnc/rfbplayer/ButtonPanel.java
index 3b2d52f..8b062e8 100644
--- a/java/src/com/tightvnc/rfbplayer/ButtonPanel.java
+++ b/java/src/com/tightvnc/rfbplayer/ButtonPanel.java
@@ -56,10 +56,8 @@
   {
     if (paused) {
       playButton.setLabel("Play");
-      posText.setEditable(true);
     } else {
       playButton.setLabel("Pause");
-      posText.setEditable(false);
     }
     playButton.setEnabled(true);
   }
diff --git a/java/src/com/tightvnc/rfbplayer/FbsInputStream.java b/java/src/com/tightvnc/rfbplayer/FbsInputStream.java
index 7baa145..4057aca 100644
--- a/java/src/com/tightvnc/rfbplayer/FbsInputStream.java
+++ b/java/src/com/tightvnc/rfbplayer/FbsInputStream.java
@@ -22,6 +22,7 @@
 //
 
 import java.io.*;
+import java.util.*;
 
 class FbsInputStream extends InputStream {
 
@@ -36,6 +37,8 @@
   protected int bufferSize;
   protected int bufferPos;
 
+  protected Observer obs;
+
   //
   // Constructors.
   //
@@ -108,6 +111,8 @@
     buffer = null;
     bufferSize = 0;
     bufferPos = 0;
+
+    obs = null;
   }
 
   //
@@ -116,21 +121,21 @@
 
   public synchronized long getTimeOffset()
   {
-    return (long)(timeOffset * playbackSpeed);
+    long off = Math.max(seekOffset, timeOffset);
+    return (long)(off * playbackSpeed);
   }
 
   public synchronized void setTimeOffset(long pos)
   {
-    // FIXME: Seeking works only in paused mode.
-    paused = true;
     seekOffset = (long)(pos / playbackSpeed);
     notify();
   }
 
   public synchronized void setSpeed(double newSpeed)
   {
-    timeOffset = (long)(timeOffset * playbackSpeed / newSpeed);
-    startTime = System.currentTimeMillis() - timeOffset;
+    long newOffset = (long)(timeOffset * playbackSpeed / newSpeed);
+    startTime += timeOffset - newOffset;
+    timeOffset = newOffset;
     if (isSeeking()) {
       seekOffset = (long)(seekOffset * playbackSpeed / newSpeed);
     }
@@ -155,6 +160,11 @@
     notify();
   }
 
+  public void addObserver(Observer target)
+  {
+    obs = target;
+  }
+
   //
   // Methods for internal use.
   //
@@ -181,9 +191,11 @@
 
     if (seekOffset >= 0) {
       if (timeOffset >= seekOffset) {
+	startTime = System.currentTimeMillis() - seekOffset;
 	seekOffset = -1;
+      } else {
+	return true;
       }
-      return true;
     }
 
     while (true) {
@@ -210,6 +222,9 @@
     while (paused && !isSeeking()) {
       synchronized(this) {
 	try {
+	  // Note: we call Observer.update(Observable,Object) method
+	  // directly instead of maintaining an Observable object.
+	  obs.update(null, null);
 	  wait();
 	} catch (InterruptedException e) {
 	}
diff --git a/java/src/com/tightvnc/rfbplayer/README b/java/src/com/tightvnc/rfbplayer/README
index 67a28d2..21352e2 100644
--- a/java/src/com/tightvnc/rfbplayer/README
+++ b/java/src/com/tightvnc/rfbplayer/README
@@ -29,6 +29,14 @@
 
     Set initial time position in the session file, in milliseconds.
 
+--> "Autoplay"
+
+    Values: "Yes", "No".
+    Default: "No".
+
+    If set to "Yes", then start in the playback mode. By default, the
+    player starts in the paused state.
+
 --> "Open new window" (applicable only in the applet mode)
 
     Values: "Yes", "No".
diff --git a/java/src/com/tightvnc/rfbplayer/RfbPlayer.java b/java/src/com/tightvnc/rfbplayer/RfbPlayer.java
index 1da501c..c2fa6f6 100644
--- a/java/src/com/tightvnc/rfbplayer/RfbPlayer.java
+++ b/java/src/com/tightvnc/rfbplayer/RfbPlayer.java
@@ -60,6 +60,7 @@
   URL url;
   long initialTimeOffset;
   double playbackSpeed;
+  boolean autoPlay;
   boolean showControls;
   int deferScreenUpdates;
 
@@ -158,12 +159,13 @@
 
       while (true) {
 	try {
-	  setPaused(true);
-	  setPos(initialTimeOffset);
+	  setPaused(!autoPlay);
 	  rfb.fbs.setSpeed(playbackSpeed);
+          setPos(initialTimeOffset);
 	  vc.processNormalProtocol();
 	} catch (EOFException e) {
 	  initialTimeOffset = 0;
+	  autoPlay = false;
 	  rfb.newSession(url);
 	}
       }
@@ -216,15 +218,22 @@
   public void readParameters() {
 
     sessionURL = readParameter("URL", true);
+
     initialTimeOffset = readLongParameter("Position", 0);
     if (initialTimeOffset < 0)
       initialTimeOffset = 0;
+
     playbackSpeed = readDoubleParameter("Speed", 1.0);
     if (playbackSpeed <= 0.0)
       playbackSpeed = 1.0;
 
+    autoPlay = false;
+    String str = readParameter("Autoplay", false);
+    if (str != null && str.equalsIgnoreCase("Yes"))
+      autoPlay = true;
+
     showControls = true;
-    String str = readParameter("Show Controls", false);
+    str = readParameter("Show Controls", false);
     if (str != null && str.equalsIgnoreCase("No"))
       showControls = false;
 
diff --git a/java/src/com/tightvnc/rfbplayer/VncCanvas.java b/java/src/com/tightvnc/rfbplayer/VncCanvas.java
index 953e61d..8272016 100644
--- a/java/src/com/tightvnc/rfbplayer/VncCanvas.java
+++ b/java/src/com/tightvnc/rfbplayer/VncCanvas.java
@@ -25,6 +25,7 @@
 import java.awt.image.*;
 import java.io.*;
 import java.lang.*;
+import java.util.*;
 import java.util.zip.*;
 
 
@@ -32,7 +33,7 @@
 // VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
 //
 
-class VncCanvas extends Canvas {
+class VncCanvas extends Canvas implements Observer {
 
   RfbPlayer player;
   RfbProto rfb;
@@ -214,8 +215,13 @@
     zlibInflater = new Inflater();
     tightInflaters = new Inflater[4];
 
+    // Show current time position in the control panel.
     player.updatePos();
 
+    // Tell our FbsInputStream object to notify us when it goes to the
+    // `paused' mode.
+    rfb.fbs.addObserver(this);
+
     // Main dispatch loop.
 
     while (true) {
@@ -820,14 +826,27 @@
       seekMode = true;
     } else {
       if (seekMode) {
-	// Full-screen immediate repaint after seeking.
+	// Immediate repaint of the whole desktop after seeking.
 	repaint();
       } else {
-	// Usual incremental repaint in playback mode.
+	// Usual incremental repaint.
 	repaint(player.deferScreenUpdates, x, y, w, h);
       }
       seekMode = false;
     }
   }
 
+  //
+  // We are observing our FbsInputStream object to get notified on
+  // switching to the `paused' mode. In such cases we want to repaint
+  // our desktop if we were seeking.
+  //
+
+  public void update(Observable o, Object arg) {
+    // Immediate repaint of the whole desktop after seeking.
+    repaint();
+    // Let next scheduleRepaint() call invoke incremental drawing.
+    seekMode = false;
+  }
+
 }