blob: 1cf16abe80d21fa7b9f201a0fa376bee3200c3b3 [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 Kaplinsky1215b992008-04-18 09:51:44 +000027 implements java.lang.Runnable, WindowListener {
28
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 //
36
37 public static void main(String[] argv) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000038 RfbPlayer p = new RfbPlayer();
39 p.mainArgs = argv;
40 p.inAnApplet = false;
41 p.inSeparateFrame = true;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000042
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000043 p.init();
44 p.start();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000045 }
46
47 String[] mainArgs;
48
49 RfbProto rfb;
50 Thread rfbThread;
51
52 Frame vncFrame;
53 Container vncContainer;
54 ScrollPane desktopScrollPane;
55 GridBagLayout gridbag;
56 ButtonPanel buttonPanel;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000057 VncCanvas vc;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000058
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +000059 String sessionURL;
Constantin Kaplinskyc833e012002-05-30 17:59:22 +000060 URL url;
Constantin Kaplinsky972c2572002-05-30 14:19:02 +000061 long initialTimeOffset;
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +000062 double playbackSpeed;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +000063 boolean autoPlay;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000064 boolean showControls;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000065 int deferScreenUpdates;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000066
67 //
68 // init()
69 //
70
71 public void init() {
72
73 readParameters();
74
75 if (inSeparateFrame) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000076 vncFrame = new Frame("RFB Session Player");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000077 if (!inAnApplet) {
78 vncFrame.add("Center", this);
79 }
80 vncContainer = vncFrame;
81 } else {
82 vncContainer = this;
83 }
84
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000085 if (inSeparateFrame)
86 vncFrame.addWindowListener(this);
87
88 rfbThread = new Thread(this);
89 rfbThread.start();
90 }
91
92 public void update(Graphics g) {
93 }
94
95 //
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000096 // run() - executed by the rfbThread to read RFB data.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000097 //
98
99 public void run() {
100
101 gridbag = new GridBagLayout();
102 vncContainer.setLayout(gridbag);
103
104 GridBagConstraints gbc = new GridBagConstraints();
105 gbc.gridwidth = GridBagConstraints.REMAINDER;
106 gbc.anchor = GridBagConstraints.NORTHWEST;
107
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000108 if (showControls) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000109 buttonPanel = new ButtonPanel(this);
110 buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
111 gridbag.setConstraints(buttonPanel, gbc);
112 vncContainer.add(buttonPanel);
113 }
114
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000115 if (inSeparateFrame) {
116 vncFrame.pack();
117 vncFrame.show();
118 } else {
119 validate();
120 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000121
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000122 try {
Constantin Kaplinsky40ad1712002-09-22 08:36:43 +0000123 if (inAnApplet) {
124 url = new URL(getCodeBase(), sessionURL);
125 } else {
126 url = new URL(sessionURL);
127 }
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000128 rfb = new RfbProto(url);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000129
130 vc = new VncCanvas(this);
131 gbc.weightx = 1.0;
132 gbc.weighty = 1.0;
133
134 if (inSeparateFrame) {
135
136 // Create a panel which itself is resizeable and can hold
137 // non-resizeable VncCanvas component at the top left corner.
138 Panel canvasPanel = new Panel();
139 canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
140 canvasPanel.add(vc);
141
142 // Create a ScrollPane which will hold a panel with VncCanvas
143 // inside.
144 desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
145 gbc.fill = GridBagConstraints.BOTH;
146 gridbag.setConstraints(desktopScrollPane, gbc);
147 desktopScrollPane.add(canvasPanel);
148
149 // Finally, add our ScrollPane to the Frame window.
150 vncFrame.add(desktopScrollPane);
151 vncFrame.setTitle(rfb.desktopName);
152 vncFrame.pack();
153 vc.resizeDesktopFrame();
154
155 } else {
156
157 // Just add the VncCanvas component to the Applet.
158 gridbag.setConstraints(vc, gbc);
159 add(vc);
160 validate();
161
162 }
163
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000164 while (true) {
165 try {
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000166 setPaused(!autoPlay);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000167 rfb.fbs.setSpeed(playbackSpeed);
Constantin Kaplinskyd8770f62002-08-16 16:01:37 +0000168 if (initialTimeOffset > rfb.fbs.getTimeOffset())
169 setPos(initialTimeOffset); // don't seek backwards here
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000170 vc.processNormalProtocol();
171 } catch (EOFException e) {
Constantin Kaplinskyd8770f62002-08-16 16:01:37 +0000172 if (e.getMessage() != null && e.getMessage().equals("[REWIND]")) {
173 // A special type of EOFException allowing us to seek backwards.
174 initialTimeOffset = rfb.fbs.getSeekOffset();
175 autoPlay = !rfb.fbs.isPaused();
Constantin Kaplinskyd8770f62002-08-16 16:01:37 +0000176 } else {
177 // Return to the beginning after the playback is finished.
178 initialTimeOffset = 0;
179 autoPlay = false;
Constantin Kaplinskyd8770f62002-08-16 16:01:37 +0000180 }
Constantin Kaplinsky282aaa12002-09-22 11:33:22 +0000181 rfb.newSession(url);
182 vc.updateFramebufferSize();
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000183 }
184 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000185
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000186 } catch (FileNotFoundException e) {
187 fatalError(e.toString());
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000188 } catch (Exception e) {
189 e.printStackTrace();
190 fatalError(e.toString());
191 }
192
193 }
194
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000195 public void setPaused(boolean paused) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000196 if (showControls)
197 buttonPanel.setPaused(paused);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000198 if (paused) {
199 rfb.fbs.pausePlayback();
200 } else {
201 rfb.fbs.resumePlayback();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000202 }
203 }
204
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000205 public double getSpeed() {
206 return playbackSpeed;
207 }
208
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000209 public void setSpeed(double speed) {
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000210 playbackSpeed = speed;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000211 rfb.fbs.setSpeed(speed);
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000212 }
213
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000214 public void setPos(long pos) {
Constantin Kaplinsky5b1b92a2002-05-30 18:02:34 +0000215 rfb.fbs.setTimeOffset(pos);
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000216 }
217
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000218
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000219 public void updatePos() {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000220 if (showControls)
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000221 buttonPanel.setPos(rfb.fbs.getTimeOffset());
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000222 }
223
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000224 //
225 // readParameters() - read parameters from the html source or from the
226 // command line. On the command line, the arguments are just a sequence of
227 // param_name/param_value pairs where the names and values correspond to
228 // those expected in the html applet tag source.
229 //
230
231 public void readParameters() {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000232
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000233 sessionURL = readParameter("URL", true);
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000234
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000235 initialTimeOffset = readLongParameter("Position", 0);
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000236 if (initialTimeOffset < 0)
237 initialTimeOffset = 0;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000238
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000239 playbackSpeed = readDoubleParameter("Speed", 1.0);
240 if (playbackSpeed <= 0.0)
241 playbackSpeed = 1.0;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000242
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000243 autoPlay = false;
244 String str = readParameter("Autoplay", false);
245 if (str != null && str.equalsIgnoreCase("Yes"))
246 autoPlay = true;
247
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000248 showControls = true;
Constantin Kaplinsky5a7133a2002-07-24 17:02:04 +0000249 str = readParameter("Show Controls", false);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000250 if (str != null && str.equalsIgnoreCase("No"))
251 showControls = false;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000252
253 if (inAnApplet) {
254 str = readParameter("Open New Window", false);
255 if (str != null && str.equalsIgnoreCase("Yes"))
256 inSeparateFrame = true;
257 }
258
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000259 // Fine tuning options.
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000260 deferScreenUpdates = (int)readLongParameter("Defer screen updates", 20);
261 if (deferScreenUpdates < 0)
262 deferScreenUpdates = 0; // Just in case.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000263 }
264
265 public String readParameter(String name, boolean required) {
266 if (inAnApplet) {
267 String s = getParameter(name);
268 if ((s == null) && required) {
269 fatalError(name + " parameter not specified");
270 }
271 return s;
272 }
273
274 for (int i = 0; i < mainArgs.length; i += 2) {
275 if (mainArgs[i].equalsIgnoreCase(name)) {
276 try {
277 return mainArgs[i+1];
278 } catch (Exception e) {
279 if (required) {
280 fatalError(name + " parameter not specified");
281 }
282 return null;
283 }
284 }
285 }
286 if (required) {
287 fatalError(name + " parameter not specified");
288 }
289 return null;
290 }
291
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000292 long readLongParameter(String name, long defaultValue) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000293 String str = readParameter(name, false);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000294 long result = defaultValue;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000295 if (str != null) {
296 try {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000297 result = Long.parseLong(str);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000298 } catch (NumberFormatException e) { }
299 }
300 return result;
301 }
302
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000303 double readDoubleParameter(String name, double defaultValue) {
304 String str = readParameter(name, false);
305 double result = defaultValue;
306 if (str != null) {
307 try {
Constantin Kaplinsky3044ecb2002-06-04 18:29:05 +0000308 result = Double.valueOf(str).doubleValue();
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000309 } catch (NumberFormatException e) { }
310 }
311 return result;
312 }
313
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000314 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000315 // fatalError() - print out a fatal error message.
316 //
317
318 public void fatalError(String str) {
319 System.out.println(str);
320
321 if (inAnApplet) {
322 vncContainer.removeAll();
323 if (rfb != null) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000324 rfb = null;
325 }
326 Label errLabel = new Label(str);
327 errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
328 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
329 vncContainer.add(errLabel);
330 if (inSeparateFrame) {
331 vncFrame.pack();
332 } else {
333 validate();
334 }
335 Thread.currentThread().stop();
336 } else {
337 System.exit(1);
338 }
339 }
340
341
342 //
343 // This method is called before the applet is destroyed.
344 //
345
346 public void destroy() {
347 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000348 if (rfb != null) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000349 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000350 }
351 if (inSeparateFrame) {
352 vncFrame.dispose();
353 }
354 }
355
356
357 //
358 // Close application properly on window close event.
359 //
360
361 public void windowClosing(WindowEvent evt) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000362 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000363 if (rfb != null)
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000364 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000365
366 vncFrame.dispose();
367 if (!inAnApplet) {
368 System.exit(0);
369 }
370 }
371
372 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000373 // Ignore window events we're not interested in.
374 //
375
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000376 public void windowActivated (WindowEvent evt) {}
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000377 public void windowDeactivated (WindowEvent evt) {}
378 public void windowOpened(WindowEvent evt) {}
379 public void windowClosed(WindowEvent evt) {}
380 public void windowIconified(WindowEvent evt) {}
381 public void windowDeiconified(WindowEvent evt) {}
382}