blob: 7a767f17c8df61e4e07b72b388b9a51e35321052 [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
wimba.comc23aeb02004-09-16 00:00:00 +000021package com.HorizonLive.RfbPlayer;
22
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000023import java.awt.*;
24import java.awt.event.*;
25import java.io.*;
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +000026import java.net.*;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000027
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000028public class RfbPlayer extends java.applet.Applet
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000029 implements java.lang.Runnable, WindowListener {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000030
31 boolean inAnApplet = true;
32 boolean inSeparateFrame = false;
33
wimba.com252eb3b2004-09-21 21:27:54 +000034 /** current applet width */
35 int dispW = 300;
36 /** current applet height */
37 int dispH = 200;
38
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000039 //
40 // main() is called when run as a java program from the command line.
41 // It simply runs the applet inside a newly-created frame.
42 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000043 public static void main(String[] argv) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000044 RfbPlayer p = new RfbPlayer();
45 p.mainArgs = argv;
46 p.inAnApplet = false;
47 p.inSeparateFrame = true;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000048
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000049 p.init();
50 p.start();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000051 }
52
53 String[] mainArgs;
54
55 RfbProto rfb;
56 Thread rfbThread;
57
58 Frame vncFrame;
59 Container vncContainer;
60 ScrollPane desktopScrollPane;
61 GridBagLayout gridbag;
62 ButtonPanel buttonPanel;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000063 VncCanvas vc;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000064
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +000065 String sessionURL;
Constantin Kaplinskyc833e012002-05-30 17:59:22 +000066 URL url;
Constantin Kaplinsky972c2572002-05-30 14:19:02 +000067 long initialTimeOffset;
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +000068 double playbackSpeed;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +000069 boolean autoPlay;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000070 boolean showControls;
wimba.comd1f56df2004-11-01 16:18:54 +000071 boolean isQuitting = false;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000072 int deferScreenUpdates;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000073
74 //
75 // init()
76 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000077 public void init() {
78
wimba.comc23aeb02004-09-16 00:00:00 +000079 // LiveConnect work-a-round
80 RfbSharedStatic.refApplet = this;
81
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000082 readParameters();
83
84 if (inSeparateFrame) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000085 vncFrame = new Frame("RFB Session Player");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000086 if (!inAnApplet) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000087 vncFrame.add("Center", this);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000088 }
89 vncContainer = vncFrame;
90 } else {
91 vncContainer = this;
92 }
93
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000094 if (inSeparateFrame)
95 vncFrame.addWindowListener(this);
96
wimba.comd1f56df2004-11-01 16:18:54 +000097 rfbThread = new Thread(this, "RfbThread");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000098 rfbThread.start();
99 }
100
101 public void update(Graphics g) {
102 }
103
104 //
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000105 // run() - executed by the rfbThread to read RFB data.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000106 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000107 public void run() {
108
109 gridbag = new GridBagLayout();
110 vncContainer.setLayout(gridbag);
111
112 GridBagConstraints gbc = new GridBagConstraints();
113 gbc.gridwidth = GridBagConstraints.REMAINDER;
114 gbc.anchor = GridBagConstraints.NORTHWEST;
115
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000116 if (showControls) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000117 buttonPanel = new ButtonPanel(this);
118 buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
119 gridbag.setConstraints(buttonPanel, gbc);
120 vncContainer.add(buttonPanel);
121 }
122
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000123 if (inSeparateFrame) {
124 vncFrame.pack();
125 vncFrame.show();
126 } else {
127 validate();
128 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000129
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000130 try {
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000131 if (inAnApplet) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000132 url = new URL(getCodeBase(), sessionURL);
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000133 } else {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000134 url = new URL(sessionURL);
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000135 }
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000136 rfb = new RfbProto(url);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000137
138 vc = new VncCanvas(this);
139 gbc.weightx = 1.0;
140 gbc.weighty = 1.0;
141
wimba.com252eb3b2004-09-21 21:27:54 +0000142 // Create a panel which itself is resizeable and can hold
143 // non-resizeable VncCanvas component at the top left corner.
144 Panel canvasPanel = new Panel();
145 canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
146 canvasPanel.add(vc);
147
148 // Create a ScrollPane which will hold a panel with VncCanvas
149 // inside.
150 desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
151 gbc.fill = GridBagConstraints.BOTH;
152 gridbag.setConstraints(canvasPanel, gbc);
153 desktopScrollPane.add(canvasPanel);
154
155 // Now add the scroll bar to the container.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000156 if (inSeparateFrame) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000157 gridbag.setConstraints(desktopScrollPane, gbc);
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000158 vncFrame.add(desktopScrollPane);
159 vncFrame.setTitle(rfb.desktopName);
160 vncFrame.pack();
161 vc.resizeDesktopFrame();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000162 } else {
wimba.com252eb3b2004-09-21 21:27:54 +0000163 // Size the scroll pane to display size.
164 desktopScrollPane.setSize(dispW, dispH);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000165
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000166 // Just add the VncCanvas component to the Applet.
wimba.com252eb3b2004-09-21 21:27:54 +0000167 gbc.fill = GridBagConstraints.NONE;
168 gridbag.setConstraints(desktopScrollPane, gbc);
169 add(desktopScrollPane);
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000170 validate();
wimba.com252eb3b2004-09-21 21:27:54 +0000171 vc.resizeEmbeddedApplet();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000172 }
173
wimba.comd1f56df2004-11-01 16:18:54 +0000174 while (!isQuitting) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000175 try {
176 setPaused(!autoPlay);
177 rfb.fbs.setSpeed(playbackSpeed);
178 if (initialTimeOffset > rfb.fbs.getTimeOffset())
179 setPos(initialTimeOffset); // don't seek backwards here
180 vc.processNormalProtocol();
181 } catch (EOFException e) {
182 if (e.getMessage() != null && e.getMessage().equals("[REWIND]")) {
183 // A special type of EOFException allowing us to seek backwards.
184 initialTimeOffset = rfb.fbs.getSeekOffset();
185 autoPlay = !rfb.fbs.isPaused();
186 } else {
187 // Return to the beginning after the playback is finished.
188 initialTimeOffset = 0;
189 autoPlay = false;
190 }
Constantin Kaplinsky282aaa12002-09-22 11:33:22 +0000191 rfb.newSession(url);
192 vc.updateFramebufferSize();
wimba.com30ff9ed2004-11-01 20:54:08 +0000193 } catch (NullPointerException e) {
194 // catching this causes a hang with 1.4.1 JVM's under Win32 IE
195 throw e;
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000196 }
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000197 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000198
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000199 } catch (FileNotFoundException e) {
200 fatalError(e.toString());
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000201 } catch (Exception e) {
202 e.printStackTrace();
203 fatalError(e.toString());
204 }
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000205
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000206 }
207
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000208 public void setPaused(boolean paused) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000209 if (showControls)
210 buttonPanel.setPaused(paused);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000211 if (paused) {
212 rfb.fbs.pausePlayback();
213 } else {
214 rfb.fbs.resumePlayback();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000215 }
216 }
217
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000218 public double getSpeed() {
219 return playbackSpeed;
220 }
221
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000222 public void setSpeed(double speed) {
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000223 playbackSpeed = speed;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000224 rfb.fbs.setSpeed(speed);
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000225 }
226
wimba.comc23aeb02004-09-16 00:00:00 +0000227 public void jumpTo(long pos) {
228 long diff = Math.abs(pos - rfb.fbs.getTimeOffset());
229
230 // Current threshold is 5 seconds
231 if (diff > 5000) {
232 rfb.fbs.pausePlayback();
233 setPos(pos);
234 rfb.fbs.resumePlayback();
235 }
236 }
237
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000238 public void setPos(long pos) {
Constantin Kaplinsky5b1b92a2002-05-30 18:02:34 +0000239 rfb.fbs.setTimeOffset(pos);
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000240 }
241
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000242 public void updatePos() {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000243 if (showControls)
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000244 buttonPanel.setPos(rfb.fbs.getTimeOffset());
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000245 }
246
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000247 //
248 // readParameters() - read parameters from the html source or from the
249 // command line. On the command line, the arguments are just a sequence of
250 // param_name/param_value pairs where the names and values correspond to
251 // those expected in the html applet tag source.
252 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000253 public void readParameters() {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000254
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000255 sessionURL = readParameter("URL", true);
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000256
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000257 initialTimeOffset = readLongParameter("Position", 0);
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000258 if (initialTimeOffset < 0)
259 initialTimeOffset = 0;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000260
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000261 playbackSpeed = readDoubleParameter("Speed", 1.0);
262 if (playbackSpeed <= 0.0)
263 playbackSpeed = 1.0;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000264
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000265 autoPlay = false;
266 String str = readParameter("Autoplay", false);
267 if (str != null && str.equalsIgnoreCase("Yes"))
268 autoPlay = true;
269
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000270 showControls = true;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000271 str = readParameter("Show Controls", false);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000272 if (str != null && str.equalsIgnoreCase("No"))
273 showControls = false;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000274
275 if (inAnApplet) {
276 str = readParameter("Open New Window", false);
277 if (str != null && str.equalsIgnoreCase("Yes"))
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000278 inSeparateFrame = true;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000279 }
280
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000281 // Fine tuning options.
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000282 deferScreenUpdates = (int)readLongParameter("Defer screen updates", 20);
283 if (deferScreenUpdates < 0)
284 deferScreenUpdates = 0; // Just in case.
wimba.com252eb3b2004-09-21 21:27:54 +0000285
286 // Display width and height.
287 dispW = readIntParameter("DISPLAY_WIDTH", dispW);
288 dispH = readIntParameter("DISPLAY_HEIGHT", dispH);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000289 }
290
291 public String readParameter(String name, boolean required) {
292 if (inAnApplet) {
293 String s = getParameter(name);
294 if ((s == null) && required) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000295 fatalError(name + " parameter not specified");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000296 }
297 return s;
298 }
299
300 for (int i = 0; i < mainArgs.length; i += 2) {
301 if (mainArgs[i].equalsIgnoreCase(name)) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000302 try {
303 return mainArgs[i + 1];
304 } catch (Exception e) {
305 if (required) {
306 fatalError(name + " parameter not specified");
307 }
308 return null;
309 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000310 }
311 }
312 if (required) {
313 fatalError(name + " parameter not specified");
314 }
315 return null;
316 }
317
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000318 long readLongParameter(String name, long defaultValue) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000319 String str = readParameter(name, false);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000320 long result = defaultValue;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000321 if (str != null) {
322 try {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000323 result = Long.parseLong(str);
324 } catch (NumberFormatException e) {
325 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000326 }
327 return result;
328 }
329
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000330 double readDoubleParameter(String name, double defaultValue) {
331 String str = readParameter(name, false);
332 double result = defaultValue;
333 if (str != null) {
334 try {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000335 result = Double.valueOf(str).doubleValue();
336 } catch (NumberFormatException e) {
337 }
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000338 }
339 return result;
340 }
341
wimba.com252eb3b2004-09-21 21:27:54 +0000342 int readIntParameter(String name, int defaultValue) {
343 String str = readParameter(name, false);
344 int result = defaultValue;
345 if (str != null) {
346 try {
347 result = Integer.parseInt(str);
348 } catch (NumberFormatException e) {
349 }
350 }
351 return result;
352 }
353
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000354 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000355 // fatalError() - print out a fatal error message.
356 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000357 public void fatalError(String str) {
358 System.out.println(str);
359
360 if (inAnApplet) {
361 vncContainer.removeAll();
362 if (rfb != null) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000363 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000364 }
365 Label errLabel = new Label(str);
366 errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
367 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
368 vncContainer.add(errLabel);
369 if (inSeparateFrame) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000370 vncFrame.pack();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000371 } else {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000372 validate();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000373 }
374 Thread.currentThread().stop();
375 } else {
376 System.exit(1);
377 }
378 }
379
380
381 //
382 // This method is called before the applet is destroyed.
383 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000384 public void destroy() {
wimba.comd1f56df2004-11-01 16:18:54 +0000385 isQuitting = true;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000386 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000387 if (rfb != null) {
wimba.comd1f56df2004-11-01 16:18:54 +0000388 rfb.quit();
389 }
390 try {
391 rfbThread.join();
392 } catch (InterruptedException e) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000393 }
394 if (inSeparateFrame) {
wimba.com30ff9ed2004-11-01 20:54:08 +0000395 vncFrame.removeWindowListener(this);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000396 vncFrame.dispose();
397 }
398 }
399
wimba.com252eb3b2004-09-21 21:27:54 +0000400 //
401 // Set the new width and height of the applet. Call when browser is resized to
402 // resize the viewer.
403 //
404 public void displaySize(int width, int height) {
405 dispW = width;
406 dispH = height;
407 if (!inSeparateFrame) {
408 vc.resizeEmbeddedApplet();
409 }
410 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000411
412 //
413 // Close application properly on window close event.
414 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000415 public void windowClosing(WindowEvent evt) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000416 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000417 if (rfb != null)
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000418 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000419
420 vncFrame.dispose();
421 if (!inAnApplet) {
422 System.exit(0);
423 }
424 }
425
426 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000427 // Ignore window events we're not interested in.
428 //
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000429 public void windowActivated(WindowEvent evt) {
430 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000431
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000432 public void windowDeactivated(WindowEvent evt) {
433 }
434
435 public void windowOpened(WindowEvent evt) {
436 }
437
438 public void windowClosed(WindowEvent evt) {
439 }
440
441 public void windowIconified(WindowEvent evt) {
442 }
443
444 public void windowDeiconified(WindowEvent evt) {
445 }
446
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000447}