blob: 4b748890b36d9253cb1b71da44c05b9ec4ac9342 [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;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000071 int deferScreenUpdates;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000072
73 //
74 // init()
75 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000076 public void init() {
77
wimba.comc23aeb02004-09-16 00:00:00 +000078 // LiveConnect work-a-round
79 RfbSharedStatic.refApplet = this;
80
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000081 readParameters();
82
83 if (inSeparateFrame) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000084 vncFrame = new Frame("RFB Session Player");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000085 if (!inAnApplet) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000086 vncFrame.add("Center", this);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000087 }
88 vncContainer = vncFrame;
89 } else {
90 vncContainer = this;
91 }
92
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000093 if (inSeparateFrame)
94 vncFrame.addWindowListener(this);
95
96 rfbThread = new Thread(this);
97 rfbThread.start();
98 }
99
100 public void update(Graphics g) {
101 }
102
103 //
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000104 // run() - executed by the rfbThread to read RFB data.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000105 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000106 public void run() {
107
108 gridbag = new GridBagLayout();
109 vncContainer.setLayout(gridbag);
110
111 GridBagConstraints gbc = new GridBagConstraints();
112 gbc.gridwidth = GridBagConstraints.REMAINDER;
113 gbc.anchor = GridBagConstraints.NORTHWEST;
114
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000115 if (showControls) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000116 buttonPanel = new ButtonPanel(this);
117 buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
118 gridbag.setConstraints(buttonPanel, gbc);
119 vncContainer.add(buttonPanel);
120 }
121
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000122 if (inSeparateFrame) {
123 vncFrame.pack();
124 vncFrame.show();
125 } else {
126 validate();
127 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000128
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000129 try {
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000130 if (inAnApplet) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000131 url = new URL(getCodeBase(), sessionURL);
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000132 } else {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000133 url = new URL(sessionURL);
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000134 }
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000135 rfb = new RfbProto(url);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000136
137 vc = new VncCanvas(this);
138 gbc.weightx = 1.0;
139 gbc.weighty = 1.0;
140
wimba.com252eb3b2004-09-21 21:27:54 +0000141 // Create a panel which itself is resizeable and can hold
142 // non-resizeable VncCanvas component at the top left corner.
143 Panel canvasPanel = new Panel();
144 canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
145 canvasPanel.add(vc);
146
147 // Create a ScrollPane which will hold a panel with VncCanvas
148 // inside.
149 desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
150 gbc.fill = GridBagConstraints.BOTH;
151 gridbag.setConstraints(canvasPanel, gbc);
152 desktopScrollPane.add(canvasPanel);
153
154 // Now add the scroll bar to the container.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000155 if (inSeparateFrame) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000156 gridbag.setConstraints(desktopScrollPane, gbc);
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000157 vncFrame.add(desktopScrollPane);
158 vncFrame.setTitle(rfb.desktopName);
159 vncFrame.pack();
160 vc.resizeDesktopFrame();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000161 } else {
wimba.com252eb3b2004-09-21 21:27:54 +0000162 // Size the scroll pane to display size.
163 desktopScrollPane.setSize(dispW, dispH);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000164
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000165 // Just add the VncCanvas component to the Applet.
wimba.com252eb3b2004-09-21 21:27:54 +0000166 gbc.fill = GridBagConstraints.NONE;
167 gridbag.setConstraints(desktopScrollPane, gbc);
168 add(desktopScrollPane);
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000169 validate();
wimba.com252eb3b2004-09-21 21:27:54 +0000170 vc.resizeEmbeddedApplet();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000171 }
172
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000173 while (true) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000174 try {
175 setPaused(!autoPlay);
176 rfb.fbs.setSpeed(playbackSpeed);
177 if (initialTimeOffset > rfb.fbs.getTimeOffset())
178 setPos(initialTimeOffset); // don't seek backwards here
179 vc.processNormalProtocol();
180 } catch (EOFException e) {
181 if (e.getMessage() != null && e.getMessage().equals("[REWIND]")) {
182 // A special type of EOFException allowing us to seek backwards.
183 initialTimeOffset = rfb.fbs.getSeekOffset();
184 autoPlay = !rfb.fbs.isPaused();
185 } else {
186 // Return to the beginning after the playback is finished.
187 initialTimeOffset = 0;
188 autoPlay = false;
189 }
Constantin Kaplinsky282aaa12002-09-22 11:33:22 +0000190 rfb.newSession(url);
191 vc.updateFramebufferSize();
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000192 }
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000193 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000194
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000195 } catch (FileNotFoundException e) {
196 fatalError(e.toString());
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000197 } catch (Exception e) {
198 e.printStackTrace();
199 fatalError(e.toString());
200 }
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000201
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000202 }
203
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000204 public void setPaused(boolean paused) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000205 if (showControls)
206 buttonPanel.setPaused(paused);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000207 if (paused) {
208 rfb.fbs.pausePlayback();
209 } else {
210 rfb.fbs.resumePlayback();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000211 }
212 }
213
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000214 public double getSpeed() {
215 return playbackSpeed;
216 }
217
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000218 public void setSpeed(double speed) {
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000219 playbackSpeed = speed;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000220 rfb.fbs.setSpeed(speed);
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000221 }
222
wimba.comc23aeb02004-09-16 00:00:00 +0000223 public void jumpTo(long pos) {
224 long diff = Math.abs(pos - rfb.fbs.getTimeOffset());
225
226 // Current threshold is 5 seconds
227 if (diff > 5000) {
228 rfb.fbs.pausePlayback();
229 setPos(pos);
230 rfb.fbs.resumePlayback();
231 }
232 }
233
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000234 public void setPos(long pos) {
Constantin Kaplinsky5b1b92a2002-05-30 18:02:34 +0000235 rfb.fbs.setTimeOffset(pos);
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000236 }
237
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000238 public void updatePos() {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000239 if (showControls)
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000240 buttonPanel.setPos(rfb.fbs.getTimeOffset());
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000241 }
242
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000243 //
244 // readParameters() - read parameters from the html source or from the
245 // command line. On the command line, the arguments are just a sequence of
246 // param_name/param_value pairs where the names and values correspond to
247 // those expected in the html applet tag source.
248 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000249 public void readParameters() {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000250
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000251 sessionURL = readParameter("URL", true);
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000252
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000253 initialTimeOffset = readLongParameter("Position", 0);
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000254 if (initialTimeOffset < 0)
255 initialTimeOffset = 0;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000256
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000257 playbackSpeed = readDoubleParameter("Speed", 1.0);
258 if (playbackSpeed <= 0.0)
259 playbackSpeed = 1.0;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000260
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000261 autoPlay = false;
262 String str = readParameter("Autoplay", false);
263 if (str != null && str.equalsIgnoreCase("Yes"))
264 autoPlay = true;
265
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000266 showControls = true;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000267 str = readParameter("Show Controls", false);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000268 if (str != null && str.equalsIgnoreCase("No"))
269 showControls = false;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000270
271 if (inAnApplet) {
272 str = readParameter("Open New Window", false);
273 if (str != null && str.equalsIgnoreCase("Yes"))
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000274 inSeparateFrame = true;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000275 }
276
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000277 // Fine tuning options.
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000278 deferScreenUpdates = (int)readLongParameter("Defer screen updates", 20);
279 if (deferScreenUpdates < 0)
280 deferScreenUpdates = 0; // Just in case.
wimba.com252eb3b2004-09-21 21:27:54 +0000281
282 // Display width and height.
283 dispW = readIntParameter("DISPLAY_WIDTH", dispW);
284 dispH = readIntParameter("DISPLAY_HEIGHT", dispH);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000285 }
286
287 public String readParameter(String name, boolean required) {
288 if (inAnApplet) {
289 String s = getParameter(name);
290 if ((s == null) && required) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000291 fatalError(name + " parameter not specified");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000292 }
293 return s;
294 }
295
296 for (int i = 0; i < mainArgs.length; i += 2) {
297 if (mainArgs[i].equalsIgnoreCase(name)) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000298 try {
299 return mainArgs[i + 1];
300 } catch (Exception e) {
301 if (required) {
302 fatalError(name + " parameter not specified");
303 }
304 return null;
305 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000306 }
307 }
308 if (required) {
309 fatalError(name + " parameter not specified");
310 }
311 return null;
312 }
313
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000314 long readLongParameter(String name, long defaultValue) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000315 String str = readParameter(name, false);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000316 long result = defaultValue;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000317 if (str != null) {
318 try {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000319 result = Long.parseLong(str);
320 } catch (NumberFormatException e) {
321 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000322 }
323 return result;
324 }
325
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000326 double readDoubleParameter(String name, double defaultValue) {
327 String str = readParameter(name, false);
328 double result = defaultValue;
329 if (str != null) {
330 try {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000331 result = Double.valueOf(str).doubleValue();
332 } catch (NumberFormatException e) {
333 }
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000334 }
335 return result;
336 }
337
wimba.com252eb3b2004-09-21 21:27:54 +0000338 int readIntParameter(String name, int defaultValue) {
339 String str = readParameter(name, false);
340 int result = defaultValue;
341 if (str != null) {
342 try {
343 result = Integer.parseInt(str);
344 } catch (NumberFormatException e) {
345 }
346 }
347 return result;
348 }
349
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000350 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000351 // fatalError() - print out a fatal error message.
352 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000353 public void fatalError(String str) {
354 System.out.println(str);
355
356 if (inAnApplet) {
357 vncContainer.removeAll();
358 if (rfb != null) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000359 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000360 }
361 Label errLabel = new Label(str);
362 errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
363 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
364 vncContainer.add(errLabel);
365 if (inSeparateFrame) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000366 vncFrame.pack();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000367 } else {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000368 validate();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000369 }
370 Thread.currentThread().stop();
371 } else {
372 System.exit(1);
373 }
374 }
375
376
377 //
378 // This method is called before the applet is destroyed.
379 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000380 public void destroy() {
381 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000382 if (rfb != null) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000383 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000384 }
385 if (inSeparateFrame) {
386 vncFrame.dispose();
387 }
388 }
389
wimba.com252eb3b2004-09-21 21:27:54 +0000390 //
391 // Set the new width and height of the applet. Call when browser is resized to
392 // resize the viewer.
393 //
394 public void displaySize(int width, int height) {
395 dispW = width;
396 dispH = height;
397 if (!inSeparateFrame) {
398 vc.resizeEmbeddedApplet();
399 }
400 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000401
402 //
403 // Close application properly on window close event.
404 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000405 public void windowClosing(WindowEvent evt) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000406 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000407 if (rfb != null)
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000408 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000409
410 vncFrame.dispose();
411 if (!inAnApplet) {
412 System.exit(0);
413 }
414 }
415
416 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000417 // Ignore window events we're not interested in.
418 //
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000419 public void windowActivated(WindowEvent evt) {
420 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000421
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000422 public void windowDeactivated(WindowEvent evt) {
423 }
424
425 public void windowOpened(WindowEvent evt) {
426 }
427
428 public void windowClosed(WindowEvent evt) {
429 }
430
431 public void windowIconified(WindowEvent evt) {
432 }
433
434 public void windowDeiconified(WindowEvent evt) {
435 }
436
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000437}