blob: a47220a230ab355d6e1937a5725a879eac2156f5 [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
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000052 FbsInputStream fbsStream;
53
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000054 Frame vncFrame;
55 Container vncContainer;
56 ScrollPane desktopScrollPane;
57 GridBagLayout gridbag;
58 ButtonPanel buttonPanel;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000059 VncCanvas vc;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000060
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +000061 String sessionURL;
Constantin Kaplinsky972c2572002-05-30 14:19:02 +000062 long initialTimeOffset;
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +000063 double playbackSpeed;
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 Kaplinsky5d99c952002-05-25 09:49:23 +0000123 URL url = new URL(sessionURL);
124 fbsStream = new FbsInputStream(url.openStream());
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000125 rfb = new RfbProto(fbsStream);
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
133 // 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);
138
139 // 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);
145
146 // Finally, add our ScrollPane to the Frame window.
147 vncFrame.add(desktopScrollPane);
148 vncFrame.setTitle(rfb.desktopName);
149 vncFrame.pack();
150 vc.resizeDesktopFrame();
151
152 } else {
153
154 // Just add the VncCanvas component to the Applet.
155 gridbag.setConstraints(vc, gbc);
156 add(vc);
157 validate();
158
159 }
160
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000161 while (true) {
162 try {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000163 setPaused(true);
164 fbsStream.setTimeOffset(initialTimeOffset);
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000165 fbsStream.setSpeed(playbackSpeed);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000166 vc.processNormalProtocol();
167 } catch (EOFException e) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000168 initialTimeOffset = 0;
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000169 fbsStream.close();
170 fbsStream = new FbsInputStream(url.openStream());
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000171 rfb.newInputStream(fbsStream);
172 }
173 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000174
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000175 } catch (FileNotFoundException e) {
176 fatalError(e.toString());
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000177 } catch (Exception e) {
178 e.printStackTrace();
179 fatalError(e.toString());
180 }
181
182 }
183
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000184 public void setPaused(boolean paused) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000185 if (showControls)
186 buttonPanel.setPaused(paused);
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000187 if (fbsStream != null) {
188 if (paused) {
189 fbsStream.pausePlayback();
190 } else {
191 fbsStream.resumePlayback();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000192 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000193 }
194 }
195
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000196 public double getSpeed() {
197 return playbackSpeed;
198 }
199
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000200 public void setSpeed(double speed) {
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000201 playbackSpeed = speed;
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000202 fbsStream.setSpeed(speed);
203 }
204
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000205 public void setPos(int pos) {
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000206 fbsStream.setTimeOffset(pos * 1000);
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000207 }
208
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000209
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000210 public void updatePos() {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000211 if (showControls)
212 buttonPanel.setPos((int)(fbsStream.getTimeOffset() / 1000));
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000213 }
214
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000215 //
216 // readParameters() - read parameters from the html source or from the
217 // command line. On the command line, the arguments are just a sequence of
218 // param_name/param_value pairs where the names and values correspond to
219 // those expected in the html applet tag source.
220 //
221
222 public void readParameters() {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000223
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000224 sessionURL = readParameter("URL", true);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000225 initialTimeOffset = readLongParameter("Position", 0);
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000226 if (initialTimeOffset < 0)
227 initialTimeOffset = 0;
228 playbackSpeed = readDoubleParameter("Speed", 1.0);
229 if (playbackSpeed <= 0.0)
230 playbackSpeed = 1.0;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000231
232 showControls = true;
233 String str = readParameter("Show Controls", false);
234 if (str != null && str.equalsIgnoreCase("No"))
235 showControls = false;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000236
237 if (inAnApplet) {
238 str = readParameter("Open New Window", false);
239 if (str != null && str.equalsIgnoreCase("Yes"))
240 inSeparateFrame = true;
241 }
242
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000243 // Fine tuning options.
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000244 deferScreenUpdates = (int)readLongParameter("Defer screen updates", 20);
245 if (deferScreenUpdates < 0)
246 deferScreenUpdates = 0; // Just in case.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000247 }
248
249 public String readParameter(String name, boolean required) {
250 if (inAnApplet) {
251 String s = getParameter(name);
252 if ((s == null) && required) {
253 fatalError(name + " parameter not specified");
254 }
255 return s;
256 }
257
258 for (int i = 0; i < mainArgs.length; i += 2) {
259 if (mainArgs[i].equalsIgnoreCase(name)) {
260 try {
261 return mainArgs[i+1];
262 } catch (Exception e) {
263 if (required) {
264 fatalError(name + " parameter not specified");
265 }
266 return null;
267 }
268 }
269 }
270 if (required) {
271 fatalError(name + " parameter not specified");
272 }
273 return null;
274 }
275
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000276 long readLongParameter(String name, long defaultValue) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000277 String str = readParameter(name, false);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000278 long result = defaultValue;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000279 if (str != null) {
280 try {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000281 result = Long.parseLong(str);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000282 } catch (NumberFormatException e) { }
283 }
284 return result;
285 }
286
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000287 double readDoubleParameter(String name, double defaultValue) {
288 String str = readParameter(name, false);
289 double result = defaultValue;
290 if (str != null) {
291 try {
292 result = Double.parseDouble(str);
293 } catch (NumberFormatException e) { }
294 }
295 return result;
296 }
297
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000298 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000299 // fatalError() - print out a fatal error message.
300 //
301
302 public void fatalError(String str) {
303 System.out.println(str);
304
305 if (inAnApplet) {
306 vncContainer.removeAll();
307 if (rfb != null) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000308 rfb = null;
309 }
310 Label errLabel = new Label(str);
311 errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
312 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
313 vncContainer.add(errLabel);
314 if (inSeparateFrame) {
315 vncFrame.pack();
316 } else {
317 validate();
318 }
319 Thread.currentThread().stop();
320 } else {
321 System.exit(1);
322 }
323 }
324
325
326 //
327 // This method is called before the applet is destroyed.
328 //
329
330 public void destroy() {
331 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000332 if (rfb != null) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000333 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000334 }
335 if (inSeparateFrame) {
336 vncFrame.dispose();
337 }
338 }
339
340
341 //
342 // Close application properly on window close event.
343 //
344
345 public void windowClosing(WindowEvent evt) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000346 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000347 if (rfb != null)
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000348 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000349
350 vncFrame.dispose();
351 if (!inAnApplet) {
352 System.exit(0);
353 }
354 }
355
356 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000357 // Ignore window events we're not interested in.
358 //
359
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000360 public void windowActivated (WindowEvent evt) {}
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000361 public void windowDeactivated (WindowEvent evt) {}
362 public void windowOpened(WindowEvent evt) {}
363 public void windowClosed(WindowEvent evt) {}
364 public void windowIconified(WindowEvent evt) {}
365 public void windowDeiconified(WindowEvent evt) {}
366}