blob: e696d95f62cade376daedb18dc893751a6470933 [file] [log] [blame]
//
// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
// This is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this software; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
package com.tightvnc.rfbplayer;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class RfbPlayer extends java.applet.Applet
implements java.lang.Runnable, WindowListener {
boolean inAnApplet = true;
boolean inSeparateFrame = false;
/** current applet width */
int dispW = 300;
/** current applet height */
int dispH = 200;
//
// main() is called when run as a java program from the command line.
// It simply runs the applet inside a newly-created frame.
//
public static void main(String[] argv) {
RfbPlayer p = new RfbPlayer();
p.mainArgs = argv;
p.inAnApplet = false;
p.inSeparateFrame = true;
p.init();
p.start();
}
String[] mainArgs;
FbsInputStream fbs;
RfbProto rfb;
Thread rfbThread;
Frame vncFrame;
Container vncContainer;
//ScrollPane desktopScrollPane;
LWScrollPane desktopScrollPane;
GridBagLayout gridbag;
ButtonPanel buttonPanel;
VncCanvas vc;
String sessionURL;
String idxPrefix;
long initialTimeOffset;
double playbackSpeed;
boolean autoPlay;
boolean showControls;
boolean isQuitting = false;
int deferScreenUpdates;
//
// init()
//
public void init() {
// LiveConnect work-a-round
RfbSharedStatic.refApplet = this;
readParameters();
if (inSeparateFrame) {
vncFrame = new Frame("RFB Session Player");
if (!inAnApplet) {
vncFrame.add("Center", this);
}
vncContainer = vncFrame;
} else {
vncContainer = this;
}
if (inSeparateFrame)
vncFrame.addWindowListener(this);
rfbThread = new Thread(this, "RfbThread");
rfbThread.start();
}
public void update(Graphics g) {
}
//
// run() - executed by the rfbThread to read RFB data.
//
public void run() {
gridbag = new GridBagLayout();
vncContainer.setLayout(gridbag);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.NORTHWEST;
if (showControls) {
buttonPanel = new ButtonPanel(this);
buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
gridbag.setConstraints(buttonPanel, gbc);
vncContainer.add(buttonPanel);
}
if (inSeparateFrame) {
vncFrame.pack();
vncFrame.setVisible(true);
} else {
validate();
}
try {
java.applet.Applet applet = (inAnApplet) ? this : null;
FbsConnection conn = new FbsConnection(sessionURL, idxPrefix, applet);
fbs = conn.connect(initialTimeOffset);
rfb = new RfbProto(fbs);
vc = new VncCanvas(this);
gbc.weightx = 1.0;
gbc.weighty = 1.0;
// Create a panel which itself is resizeable and can hold
// non-resizeable VncCanvas component at the top left corner.
//Panel canvasPanel = new Panel();
//canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
//canvasPanel.add(vc);
// Create a ScrollPane which will hold a panel with VncCanvas
// inside.
//desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
desktopScrollPane = new LWScrollPane();
gbc.fill = GridBagConstraints.BOTH;
gridbag.setConstraints(vc, gbc);
//gridbag.setConstraints(canvasPanel, gbc);
desktopScrollPane.addComp(vc);
desktopScrollPane.setSize(dispW, dispH);
//desktopScrollPane.add(canvasPanel);
// Now add the scroll bar to the container.
if (inSeparateFrame) {
gridbag.setConstraints(desktopScrollPane, gbc);
vncFrame.add(desktopScrollPane);
vncFrame.setTitle(rfb.desktopName);
vc.resizeDesktopFrame();
} else {
// Size the scroll pane to display size.
desktopScrollPane.setSize(dispW, dispH);
// Just add the VncCanvas component to the Applet.
gbc.fill = GridBagConstraints.NONE;
gridbag.setConstraints(desktopScrollPane, gbc);
add(desktopScrollPane);
validate();
vc.resizeEmbeddedApplet();
}
while (!isQuitting) {
try {
setPaused(!autoPlay);
fbs.setSpeed(playbackSpeed);
vc.processNormalProtocol();
} catch (EOFException e) {
long newTimeOffset;
if (e.getMessage() != null && e.getMessage().equals("[JUMP]")) {
// A special type of EOFException allowing us to close FBS stream
// and then re-open it for jumping to a different time offset.
newTimeOffset = fbs.getSeekOffset();
autoPlay = !fbs.isPaused();
} else {
// Return to the beginning after the playback is finished.
newTimeOffset = 0;
autoPlay = false;
}
fbs.close();
fbs = conn.connect(newTimeOffset);
rfb.newSession(fbs);
vc.updateFramebufferSize();
} catch (NullPointerException e) {
// catching this causes a hang with 1.4.1 JVM's under Win32 IE
throw e;
}
}
} catch (FileNotFoundException e) {
fatalError(e.toString());
} catch (Exception e) {
e.printStackTrace();
fatalError(e.toString());
}
}
public void setPausedInt(String paused) {
// default to true (pause)
int pause = 1;
try {
pause = Integer.parseInt(paused);
} catch (NumberFormatException e) {
}
if (pause == 0) {
setPaused(false);
} else {
setPaused(true);
}
}
public void setPaused(boolean paused) {
if (showControls)
buttonPanel.setPaused(paused);
if (paused) {
fbs.pausePlayback();
} else {
fbs.resumePlayback();
}
}
public double getSpeed() {
return playbackSpeed;
}
public void setSpeed(double speed) {
playbackSpeed = speed;
fbs.setSpeed(speed);
}
public void jumpTo(long pos) {
long diff = Math.abs(pos - fbs.getTimeOffset());
// Current threshold is 5 seconds
if (diff > 5000) {
fbs.pausePlayback();
setPos(pos);
fbs.resumePlayback();
}
}
public void setPos(long pos) {
fbs.setTimeOffset(pos, true);
}
public void updatePos() {
if (showControls && buttonPanel != null)
buttonPanel.setPos(fbs.getTimeOffset());
}
//
// readParameters() - read parameters from the html source or from the
// command line. On the command line, the arguments are just a sequence of
// param_name/param_value pairs where the names and values correspond to
// those expected in the html applet tag source.
//
public void readParameters() {
sessionURL = readParameter("URL", true);
idxPrefix = readParameter("Index", false);
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;
str = readParameter("Show_Controls", false);
if (str != null && str.equalsIgnoreCase("No"))
showControls = false;
if (inAnApplet) {
str = readParameter("Open_New_Window", false);
if (str != null && str.equalsIgnoreCase("Yes"))
inSeparateFrame = true;
}
// Fine tuning options.
deferScreenUpdates = (int)readLongParameter("Defer_screen_updates", 20);
if (deferScreenUpdates < 0)
deferScreenUpdates = 0; // Just in case.
// Display width and height.
dispW = readIntParameter("DISPLAY_WIDTH", dispW);
dispH = readIntParameter("DISPLAY_HEIGHT", dispH);
}
public String readParameter(String name, boolean required) {
if (inAnApplet) {
String s = getParameter(name);
if ((s == null) && required) {
fatalError(name + " parameter not specified");
}
return s;
}
for (int i = 0; i < mainArgs.length; i += 2) {
if (mainArgs[i].equalsIgnoreCase(name)) {
try {
return mainArgs[i + 1];
} catch (Exception e) {
if (required) {
fatalError(name + " parameter not specified");
}
return null;
}
}
}
if (required) {
fatalError(name + " parameter not specified");
}
return null;
}
long readLongParameter(String name, long defaultValue) {
String str = readParameter(name, false);
long result = defaultValue;
if (str != null) {
try {
result = Long.parseLong(str);
} catch (NumberFormatException e) {
}
}
return result;
}
double readDoubleParameter(String name, double defaultValue) {
String str = readParameter(name, false);
double result = defaultValue;
if (str != null) {
try {
result = Double.valueOf(str).doubleValue();
} catch (NumberFormatException e) {
}
}
return result;
}
int readIntParameter(String name, int defaultValue) {
String str = readParameter(name, false);
int result = defaultValue;
if (str != null) {
try {
result = Integer.parseInt(str);
} catch (NumberFormatException e) {
}
}
return result;
}
//
// fatalError() - print out a fatal error message.
//
public void fatalError(String str) {
System.err.println(str);
if (inAnApplet) {
vncContainer.removeAll();
if (rfb != null) {
rfb = null;
}
Label errLabel = new Label(str);
errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
vncContainer.add(errLabel);
if (inSeparateFrame) {
vncFrame.pack();
} else {
validate();
}
Thread.currentThread().stop();
} else {
System.exit(1);
}
}
//
// This method is called before the applet is destroyed.
//
public void destroy() {
isQuitting = true;
vncContainer.removeAll();
if (fbs != null) {
fbs.quit();
try {
fbs.close();
} catch (IOException e) {
}
}
try {
rfbThread.join();
} catch (InterruptedException e) {
}
if (inSeparateFrame) {
vncFrame.removeWindowListener(this);
vncFrame.dispose();
}
}
//
// Set the new width and height of the applet. Call when browser is resized to
// resize the viewer.
//
public void displaySize(int width, int height) {
dispW = width;
dispH = height;
if (!inSeparateFrame) {
vc.resizeEmbeddedApplet();
}
}
//
// Close application properly on window close event.
//
public void windowClosing(WindowEvent evt) {
vncContainer.removeAll();
if (rfb != null)
rfb = null;
vncFrame.dispose();
if (!inAnApplet) {
System.exit(0);
}
}
//
// Ignore window events we're not interested in.
//
public void windowActivated(WindowEvent evt) {
}
public void windowDeactivated(WindowEvent evt) {
}
public void windowOpened(WindowEvent evt) {
}
public void windowClosed(WindowEvent evt) {
}
public void windowIconified(WindowEvent evt) {
}
public void windowDeiconified(WindowEvent evt) {
}
}