blob: c46c769c17d058e3da4daf69806e246c5addbcd1 [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
34 //
35 // main() is called when run as a java program from the command line.
36 // It simply runs the applet inside a newly-created frame.
37 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000038 public static void main(String[] argv) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000039 RfbPlayer p = new RfbPlayer();
40 p.mainArgs = argv;
41 p.inAnApplet = false;
42 p.inSeparateFrame = true;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000043
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000044 p.init();
45 p.start();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000046 }
47
48 String[] mainArgs;
49
50 RfbProto rfb;
51 Thread rfbThread;
52
53 Frame vncFrame;
54 Container vncContainer;
55 ScrollPane desktopScrollPane;
56 GridBagLayout gridbag;
57 ButtonPanel buttonPanel;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000058 VncCanvas vc;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000059
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +000060 String sessionURL;
Constantin Kaplinskyc833e012002-05-30 17:59:22 +000061 URL url;
Constantin Kaplinsky972c2572002-05-30 14:19:02 +000062 long initialTimeOffset;
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +000063 double playbackSpeed;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +000064 boolean autoPlay;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000065 boolean showControls;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000066 int deferScreenUpdates;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000067
68 //
69 // init()
70 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000071 public void init() {
72
wimba.comc23aeb02004-09-16 00:00:00 +000073 // LiveConnect work-a-round
74 RfbSharedStatic.refApplet = this;
75
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000076 readParameters();
77
78 if (inSeparateFrame) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000079 vncFrame = new Frame("RFB Session Player");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000080 if (!inAnApplet) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000081 vncFrame.add("Center", this);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000082 }
83 vncContainer = vncFrame;
84 } else {
85 vncContainer = this;
86 }
87
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000088 if (inSeparateFrame)
89 vncFrame.addWindowListener(this);
90
91 rfbThread = new Thread(this);
92 rfbThread.start();
93 }
94
95 public void update(Graphics g) {
96 }
97
98 //
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000099 // run() - executed by the rfbThread to read RFB data.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000100 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000101 public void run() {
102
103 gridbag = new GridBagLayout();
104 vncContainer.setLayout(gridbag);
105
106 GridBagConstraints gbc = new GridBagConstraints();
107 gbc.gridwidth = GridBagConstraints.REMAINDER;
108 gbc.anchor = GridBagConstraints.NORTHWEST;
109
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000110 if (showControls) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000111 buttonPanel = new ButtonPanel(this);
112 buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
113 gridbag.setConstraints(buttonPanel, gbc);
114 vncContainer.add(buttonPanel);
115 }
116
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000117 if (inSeparateFrame) {
118 vncFrame.pack();
119 vncFrame.show();
120 } else {
121 validate();
122 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000123
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000124 try {
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000125 if (inAnApplet) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000126 url = new URL(getCodeBase(), sessionURL);
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000127 } else {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000128 url = new URL(sessionURL);
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000129 }
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000130 rfb = new RfbProto(url);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000131
132 vc = new VncCanvas(this);
133 gbc.weightx = 1.0;
134 gbc.weighty = 1.0;
135
136 if (inSeparateFrame) {
137
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000138 // Create a panel which itself is resizeable and can hold
139 // non-resizeable VncCanvas component at the top left corner.
140 Panel canvasPanel = new Panel();
141 canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
142 canvasPanel.add(vc);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000143
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000144 // Create a ScrollPane which will hold a panel with VncCanvas
145 // inside.
146 desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
147 gbc.fill = GridBagConstraints.BOTH;
148 gridbag.setConstraints(desktopScrollPane, gbc);
149 desktopScrollPane.add(canvasPanel);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000150
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000151 // Finally, add our ScrollPane to the Frame window.
152 vncFrame.add(desktopScrollPane);
153 vncFrame.setTitle(rfb.desktopName);
154 vncFrame.pack();
155 vc.resizeDesktopFrame();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000156
157 } else {
158
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000159 // Just add the VncCanvas component to the Applet.
160 gridbag.setConstraints(vc, gbc);
161 add(vc);
162 validate();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000163
164 }
165
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000166 while (true) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000167 try {
168 setPaused(!autoPlay);
169 rfb.fbs.setSpeed(playbackSpeed);
170 if (initialTimeOffset > rfb.fbs.getTimeOffset())
171 setPos(initialTimeOffset); // don't seek backwards here
172 vc.processNormalProtocol();
173 } catch (EOFException e) {
174 if (e.getMessage() != null && e.getMessage().equals("[REWIND]")) {
175 // A special type of EOFException allowing us to seek backwards.
176 initialTimeOffset = rfb.fbs.getSeekOffset();
177 autoPlay = !rfb.fbs.isPaused();
178 } else {
179 // Return to the beginning after the playback is finished.
180 initialTimeOffset = 0;
181 autoPlay = false;
182 }
Constantin Kaplinsky282aaa12002-09-22 11:33:22 +0000183 rfb.newSession(url);
184 vc.updateFramebufferSize();
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000185 }
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000186 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000187
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000188 } catch (FileNotFoundException e) {
189 fatalError(e.toString());
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000190 } catch (Exception e) {
191 e.printStackTrace();
192 fatalError(e.toString());
193 }
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000194
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000195 }
196
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000197 public void setPaused(boolean paused) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000198 if (showControls)
199 buttonPanel.setPaused(paused);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000200 if (paused) {
201 rfb.fbs.pausePlayback();
202 } else {
203 rfb.fbs.resumePlayback();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000204 }
205 }
206
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000207 public double getSpeed() {
208 return playbackSpeed;
209 }
210
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000211 public void setSpeed(double speed) {
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000212 playbackSpeed = speed;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000213 rfb.fbs.setSpeed(speed);
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000214 }
215
wimba.comc23aeb02004-09-16 00:00:00 +0000216 public void jumpTo(long pos) {
217 long diff = Math.abs(pos - rfb.fbs.getTimeOffset());
218
219 // Current threshold is 5 seconds
220 if (diff > 5000) {
221 rfb.fbs.pausePlayback();
222 setPos(pos);
223 rfb.fbs.resumePlayback();
224 }
225 }
226
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000227 public void setPos(long pos) {
Constantin Kaplinsky5b1b92a2002-05-30 18:02:34 +0000228 rfb.fbs.setTimeOffset(pos);
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000229 }
230
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000231 public void updatePos() {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000232 if (showControls)
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000233 buttonPanel.setPos(rfb.fbs.getTimeOffset());
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000234 }
235
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000236 //
237 // readParameters() - read parameters from the html source or from the
238 // command line. On the command line, the arguments are just a sequence of
239 // param_name/param_value pairs where the names and values correspond to
240 // those expected in the html applet tag source.
241 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000242 public void readParameters() {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000243
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000244 sessionURL = readParameter("URL", true);
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000245
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000246 initialTimeOffset = readLongParameter("Position", 0);
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000247 if (initialTimeOffset < 0)
248 initialTimeOffset = 0;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000249
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000250 playbackSpeed = readDoubleParameter("Speed", 1.0);
251 if (playbackSpeed <= 0.0)
252 playbackSpeed = 1.0;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000253
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000254 autoPlay = false;
255 String str = readParameter("Autoplay", false);
256 if (str != null && str.equalsIgnoreCase("Yes"))
257 autoPlay = true;
258
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000259 showControls = true;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000260 str = readParameter("Show Controls", false);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000261 if (str != null && str.equalsIgnoreCase("No"))
262 showControls = false;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000263
264 if (inAnApplet) {
265 str = readParameter("Open New Window", false);
266 if (str != null && str.equalsIgnoreCase("Yes"))
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000267 inSeparateFrame = true;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000268 }
269
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000270 // Fine tuning options.
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000271 deferScreenUpdates = (int)readLongParameter("Defer screen updates", 20);
272 if (deferScreenUpdates < 0)
273 deferScreenUpdates = 0; // Just in case.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000274 }
275
276 public String readParameter(String name, boolean required) {
277 if (inAnApplet) {
278 String s = getParameter(name);
279 if ((s == null) && required) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000280 fatalError(name + " parameter not specified");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000281 }
282 return s;
283 }
284
285 for (int i = 0; i < mainArgs.length; i += 2) {
286 if (mainArgs[i].equalsIgnoreCase(name)) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000287 try {
288 return mainArgs[i + 1];
289 } catch (Exception e) {
290 if (required) {
291 fatalError(name + " parameter not specified");
292 }
293 return null;
294 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000295 }
296 }
297 if (required) {
298 fatalError(name + " parameter not specified");
299 }
300 return null;
301 }
302
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000303 long readLongParameter(String name, long defaultValue) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000304 String str = readParameter(name, false);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000305 long result = defaultValue;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000306 if (str != null) {
307 try {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000308 result = Long.parseLong(str);
309 } catch (NumberFormatException e) {
310 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000311 }
312 return result;
313 }
314
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000315 double readDoubleParameter(String name, double defaultValue) {
316 String str = readParameter(name, false);
317 double result = defaultValue;
318 if (str != null) {
319 try {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000320 result = Double.valueOf(str).doubleValue();
321 } catch (NumberFormatException e) {
322 }
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000323 }
324 return result;
325 }
326
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000327 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000328 // fatalError() - print out a fatal error message.
329 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000330 public void fatalError(String str) {
331 System.out.println(str);
332
333 if (inAnApplet) {
334 vncContainer.removeAll();
335 if (rfb != null) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000336 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000337 }
338 Label errLabel = new Label(str);
339 errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
340 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
341 vncContainer.add(errLabel);
342 if (inSeparateFrame) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000343 vncFrame.pack();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000344 } else {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000345 validate();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000346 }
347 Thread.currentThread().stop();
348 } else {
349 System.exit(1);
350 }
351 }
352
353
354 //
355 // This method is called before the applet is destroyed.
356 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000357 public void destroy() {
358 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000359 if (rfb != null) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000360 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000361 }
362 if (inSeparateFrame) {
363 vncFrame.dispose();
364 }
365 }
366
367
368 //
369 // Close application properly on window close event.
370 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000371 public void windowClosing(WindowEvent evt) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000372 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000373 if (rfb != null)
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000374 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000375
376 vncFrame.dispose();
377 if (!inAnApplet) {
378 System.exit(0);
379 }
380 }
381
382 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000383 // Ignore window events we're not interested in.
384 //
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000385 public void windowActivated(WindowEvent evt) {
386 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000387
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000388 public void windowDeactivated(WindowEvent evt) {
389 }
390
391 public void windowOpened(WindowEvent evt) {
392 }
393
394 public void windowClosed(WindowEvent evt) {
395 }
396
397 public void windowIconified(WindowEvent evt) {
398 }
399
400 public void windowDeiconified(WindowEvent evt) {
401 }
402
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000403}