blob: 0918bef1d72472ddf4c37a18c3b45c33257f5e9e [file] [log] [blame]
Constantin Kaplinsky1215b992008-04-18 09:51:44 +00001//
2// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
3// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
4//
5// This is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//
10// This software is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this software; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18// USA.
19//
20
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000021import java.awt.*;
22import java.awt.event.*;
23import java.io.*;
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +000024import java.net.*;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000025
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000026public class RfbPlayer extends java.applet.Applet
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000027 implements java.lang.Runnable, WindowListener {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000028
29 boolean inAnApplet = true;
30 boolean inSeparateFrame = false;
31
32 //
33 // main() is called when run as a java program from the command line.
34 // It simply runs the applet inside a newly-created frame.
35 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000036 public static void main(String[] argv) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000037 RfbPlayer p = new RfbPlayer();
38 p.mainArgs = argv;
39 p.inAnApplet = false;
40 p.inSeparateFrame = true;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000041
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000042 p.init();
43 p.start();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000044 }
45
46 String[] mainArgs;
47
48 RfbProto rfb;
49 Thread rfbThread;
50
51 Frame vncFrame;
52 Container vncContainer;
53 ScrollPane desktopScrollPane;
54 GridBagLayout gridbag;
55 ButtonPanel buttonPanel;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000056 VncCanvas vc;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000057
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +000058 String sessionURL;
Constantin Kaplinskyc833e012002-05-30 17:59:22 +000059 URL url;
Constantin Kaplinsky972c2572002-05-30 14:19:02 +000060 long initialTimeOffset;
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +000061 double playbackSpeed;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +000062 boolean autoPlay;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000063 boolean showControls;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000064 int deferScreenUpdates;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000065
66 //
67 // init()
68 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000069 public void init() {
70
71 readParameters();
72
73 if (inSeparateFrame) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000074 vncFrame = new Frame("RFB Session Player");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000075 if (!inAnApplet) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000076 vncFrame.add("Center", this);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000077 }
78 vncContainer = vncFrame;
79 } else {
80 vncContainer = this;
81 }
82
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000083 if (inSeparateFrame)
84 vncFrame.addWindowListener(this);
85
86 rfbThread = new Thread(this);
87 rfbThread.start();
88 }
89
90 public void update(Graphics g) {
91 }
92
93 //
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000094 // run() - executed by the rfbThread to read RFB data.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000095 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000096 public void run() {
97
98 gridbag = new GridBagLayout();
99 vncContainer.setLayout(gridbag);
100
101 GridBagConstraints gbc = new GridBagConstraints();
102 gbc.gridwidth = GridBagConstraints.REMAINDER;
103 gbc.anchor = GridBagConstraints.NORTHWEST;
104
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000105 if (showControls) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000106 buttonPanel = new ButtonPanel(this);
107 buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
108 gridbag.setConstraints(buttonPanel, gbc);
109 vncContainer.add(buttonPanel);
110 }
111
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000112 if (inSeparateFrame) {
113 vncFrame.pack();
114 vncFrame.show();
115 } else {
116 validate();
117 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000118
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000119 try {
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000120 if (inAnApplet) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000121 url = new URL(getCodeBase(), sessionURL);
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000122 } else {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000123 url = new URL(sessionURL);
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000124 }
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000125 rfb = new RfbProto(url);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000126
127 vc = new VncCanvas(this);
128 gbc.weightx = 1.0;
129 gbc.weighty = 1.0;
130
131 if (inSeparateFrame) {
132
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000133 // Create a panel which itself is resizeable and can hold
134 // non-resizeable VncCanvas component at the top left corner.
135 Panel canvasPanel = new Panel();
136 canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
137 canvasPanel.add(vc);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000138
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000139 // Create a ScrollPane which will hold a panel with VncCanvas
140 // inside.
141 desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
142 gbc.fill = GridBagConstraints.BOTH;
143 gridbag.setConstraints(desktopScrollPane, gbc);
144 desktopScrollPane.add(canvasPanel);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000145
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000146 // Finally, add our ScrollPane to the Frame window.
147 vncFrame.add(desktopScrollPane);
148 vncFrame.setTitle(rfb.desktopName);
149 vncFrame.pack();
150 vc.resizeDesktopFrame();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000151
152 } else {
153
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000154 // Just add the VncCanvas component to the Applet.
155 gridbag.setConstraints(vc, gbc);
156 add(vc);
157 validate();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000158
159 }
160
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000161 while (true) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000162 try {
163 setPaused(!autoPlay);
164 rfb.fbs.setSpeed(playbackSpeed);
165 if (initialTimeOffset > rfb.fbs.getTimeOffset())
166 setPos(initialTimeOffset); // don't seek backwards here
167 vc.processNormalProtocol();
168 } catch (EOFException e) {
169 if (e.getMessage() != null && e.getMessage().equals("[REWIND]")) {
170 // A special type of EOFException allowing us to seek backwards.
171 initialTimeOffset = rfb.fbs.getSeekOffset();
172 autoPlay = !rfb.fbs.isPaused();
173 } else {
174 // Return to the beginning after the playback is finished.
175 initialTimeOffset = 0;
176 autoPlay = false;
177 }
Constantin Kaplinsky282aaa12002-09-22 11:33:22 +0000178 rfb.newSession(url);
179 vc.updateFramebufferSize();
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000180 }
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000181 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000182
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000183 } catch (FileNotFoundException e) {
184 fatalError(e.toString());
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000185 } catch (Exception e) {
186 e.printStackTrace();
187 fatalError(e.toString());
188 }
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000189
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000190 }
191
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000192 public void setPaused(boolean paused) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000193 if (showControls)
194 buttonPanel.setPaused(paused);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000195 if (paused) {
196 rfb.fbs.pausePlayback();
197 } else {
198 rfb.fbs.resumePlayback();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000199 }
200 }
201
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000202 public double getSpeed() {
203 return playbackSpeed;
204 }
205
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000206 public void setSpeed(double speed) {
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000207 playbackSpeed = speed;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000208 rfb.fbs.setSpeed(speed);
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000209 }
210
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000211 public void setPos(long pos) {
Constantin Kaplinsky5b1b92a2002-05-30 18:02:34 +0000212 rfb.fbs.setTimeOffset(pos);
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000213 }
214
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000215 public void updatePos() {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000216 if (showControls)
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000217 buttonPanel.setPos(rfb.fbs.getTimeOffset());
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000218 }
219
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000220 //
221 // readParameters() - read parameters from the html source or from the
222 // command line. On the command line, the arguments are just a sequence of
223 // param_name/param_value pairs where the names and values correspond to
224 // those expected in the html applet tag source.
225 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000226 public void readParameters() {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000227
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000228 sessionURL = readParameter("URL", true);
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000229
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000230 initialTimeOffset = readLongParameter("Position", 0);
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000231 if (initialTimeOffset < 0)
232 initialTimeOffset = 0;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000233
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000234 playbackSpeed = readDoubleParameter("Speed", 1.0);
235 if (playbackSpeed <= 0.0)
236 playbackSpeed = 1.0;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000237
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000238 autoPlay = false;
239 String str = readParameter("Autoplay", false);
240 if (str != null && str.equalsIgnoreCase("Yes"))
241 autoPlay = true;
242
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000243 showControls = true;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000244 str = readParameter("Show Controls", false);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000245 if (str != null && str.equalsIgnoreCase("No"))
246 showControls = false;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000247
248 if (inAnApplet) {
249 str = readParameter("Open New Window", false);
250 if (str != null && str.equalsIgnoreCase("Yes"))
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000251 inSeparateFrame = true;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000252 }
253
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000254 // Fine tuning options.
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000255 deferScreenUpdates = (int)readLongParameter("Defer screen updates", 20);
256 if (deferScreenUpdates < 0)
257 deferScreenUpdates = 0; // Just in case.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000258 }
259
260 public String readParameter(String name, boolean required) {
261 if (inAnApplet) {
262 String s = getParameter(name);
263 if ((s == null) && required) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000264 fatalError(name + " parameter not specified");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000265 }
266 return s;
267 }
268
269 for (int i = 0; i < mainArgs.length; i += 2) {
270 if (mainArgs[i].equalsIgnoreCase(name)) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000271 try {
272 return mainArgs[i + 1];
273 } catch (Exception e) {
274 if (required) {
275 fatalError(name + " parameter not specified");
276 }
277 return null;
278 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000279 }
280 }
281 if (required) {
282 fatalError(name + " parameter not specified");
283 }
284 return null;
285 }
286
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000287 long readLongParameter(String name, long defaultValue) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000288 String str = readParameter(name, false);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000289 long result = defaultValue;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000290 if (str != null) {
291 try {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000292 result = Long.parseLong(str);
293 } catch (NumberFormatException e) {
294 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000295 }
296 return result;
297 }
298
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000299 double readDoubleParameter(String name, double defaultValue) {
300 String str = readParameter(name, false);
301 double result = defaultValue;
302 if (str != null) {
303 try {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000304 result = Double.valueOf(str).doubleValue();
305 } catch (NumberFormatException e) {
306 }
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000307 }
308 return result;
309 }
310
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000311 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000312 // fatalError() - print out a fatal error message.
313 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000314 public void fatalError(String str) {
315 System.out.println(str);
316
317 if (inAnApplet) {
318 vncContainer.removeAll();
319 if (rfb != null) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000320 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000321 }
322 Label errLabel = new Label(str);
323 errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
324 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
325 vncContainer.add(errLabel);
326 if (inSeparateFrame) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000327 vncFrame.pack();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000328 } else {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000329 validate();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000330 }
331 Thread.currentThread().stop();
332 } else {
333 System.exit(1);
334 }
335 }
336
337
338 //
339 // This method is called before the applet is destroyed.
340 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000341 public void destroy() {
342 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000343 if (rfb != null) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000344 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000345 }
346 if (inSeparateFrame) {
347 vncFrame.dispose();
348 }
349 }
350
351
352 //
353 // Close application properly on window close event.
354 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000355 public void windowClosing(WindowEvent evt) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000356 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000357 if (rfb != null)
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000358 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000359
360 vncFrame.dispose();
361 if (!inAnApplet) {
362 System.exit(0);
363 }
364 }
365
366 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000367 // Ignore window events we're not interested in.
368 //
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000369 public void windowActivated(WindowEvent evt) {
370 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000371
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000372 public void windowDeactivated(WindowEvent evt) {
373 }
374
375 public void windowOpened(WindowEvent evt) {
376 }
377
378 public void windowClosed(WindowEvent evt) {
379 }
380
381 public void windowIconified(WindowEvent evt) {
382 }
383
384 public void windowDeiconified(WindowEvent evt) {
385 }
386
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000387}