blob: 1d725f92645a016d3343880a2425b8f4e299a0a8 [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 Kaplinsky903009e2002-05-20 10:55:47 +000063 boolean showControls;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000064 int deferScreenUpdates;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000065
66 //
67 // init()
68 //
69
70 public void init() {
71
72 readParameters();
73
74 if (inSeparateFrame) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000075 vncFrame = new Frame("RFB Session Player");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000076 if (!inAnApplet) {
77 vncFrame.add("Center", this);
78 }
79 vncContainer = vncFrame;
80 } else {
81 vncContainer = this;
82 }
83
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000084 if (inSeparateFrame)
85 vncFrame.addWindowListener(this);
86
87 rfbThread = new Thread(this);
88 rfbThread.start();
89 }
90
91 public void update(Graphics g) {
92 }
93
94 //
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000095 // run() - executed by the rfbThread to read RFB data.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000096 //
97
98 public void run() {
99
100 gridbag = new GridBagLayout();
101 vncContainer.setLayout(gridbag);
102
103 GridBagConstraints gbc = new GridBagConstraints();
104 gbc.gridwidth = GridBagConstraints.REMAINDER;
105 gbc.anchor = GridBagConstraints.NORTHWEST;
106
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000107 if (showControls) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000108 buttonPanel = new ButtonPanel(this);
109 buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
110 gridbag.setConstraints(buttonPanel, gbc);
111 vncContainer.add(buttonPanel);
112 }
113
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000114 if (inSeparateFrame) {
115 vncFrame.pack();
116 vncFrame.show();
117 } else {
118 validate();
119 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000120
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000121 try {
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000122 url = new URL(sessionURL);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000123 rfb = new RfbProto(url);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000124
125 vc = new VncCanvas(this);
126 gbc.weightx = 1.0;
127 gbc.weighty = 1.0;
128
129 if (inSeparateFrame) {
130
131 // Create a panel which itself is resizeable and can hold
132 // non-resizeable VncCanvas component at the top left corner.
133 Panel canvasPanel = new Panel();
134 canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
135 canvasPanel.add(vc);
136
137 // Create a ScrollPane which will hold a panel with VncCanvas
138 // inside.
139 desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
140 gbc.fill = GridBagConstraints.BOTH;
141 gridbag.setConstraints(desktopScrollPane, gbc);
142 desktopScrollPane.add(canvasPanel);
143
144 // Finally, add our ScrollPane to the Frame window.
145 vncFrame.add(desktopScrollPane);
146 vncFrame.setTitle(rfb.desktopName);
147 vncFrame.pack();
148 vc.resizeDesktopFrame();
149
150 } else {
151
152 // Just add the VncCanvas component to the Applet.
153 gridbag.setConstraints(vc, gbc);
154 add(vc);
155 validate();
156
157 }
158
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000159 while (true) {
160 try {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000161 setPaused(true);
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000162 setPos(initialTimeOffset);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000163 rfb.fbs.setSpeed(playbackSpeed);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000164 vc.processNormalProtocol();
165 } catch (EOFException e) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000166 initialTimeOffset = 0;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000167 rfb.newSession(url);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000168 }
169 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000170
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000171 } catch (FileNotFoundException e) {
172 fatalError(e.toString());
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000173 } catch (Exception e) {
174 e.printStackTrace();
175 fatalError(e.toString());
176 }
177
178 }
179
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000180 public void setPaused(boolean paused) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000181 if (showControls)
182 buttonPanel.setPaused(paused);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000183 if (paused) {
184 rfb.fbs.pausePlayback();
185 } else {
186 rfb.fbs.resumePlayback();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000187 }
188 }
189
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000190 public double getSpeed() {
191 return playbackSpeed;
192 }
193
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000194 public void setSpeed(double speed) {
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000195 playbackSpeed = speed;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000196 rfb.fbs.setSpeed(speed);
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000197 }
198
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000199 public void setPos(long pos) {
200 if (pos > rfb.fbs.getTimeOffset()) {
201 rfb.fbs.setTimeOffset(pos);
202 } else {
203 System.out.println("Seeking backwards is not implemented yet.");
204 }
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000205 }
206
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000207
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000208 public void updatePos() {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000209 if (showControls)
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000210 buttonPanel.setPos(rfb.fbs.getTimeOffset());
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000211 }
212
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000213 //
214 // readParameters() - read parameters from the html source or from the
215 // command line. On the command line, the arguments are just a sequence of
216 // param_name/param_value pairs where the names and values correspond to
217 // those expected in the html applet tag source.
218 //
219
220 public void readParameters() {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000221
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000222 sessionURL = readParameter("URL", true);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000223 initialTimeOffset = readLongParameter("Position", 0);
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000224 if (initialTimeOffset < 0)
225 initialTimeOffset = 0;
226 playbackSpeed = readDoubleParameter("Speed", 1.0);
227 if (playbackSpeed <= 0.0)
228 playbackSpeed = 1.0;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000229
230 showControls = true;
231 String str = readParameter("Show Controls", false);
232 if (str != null && str.equalsIgnoreCase("No"))
233 showControls = false;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000234
235 if (inAnApplet) {
236 str = readParameter("Open New Window", false);
237 if (str != null && str.equalsIgnoreCase("Yes"))
238 inSeparateFrame = true;
239 }
240
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000241 // Fine tuning options.
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000242 deferScreenUpdates = (int)readLongParameter("Defer screen updates", 20);
243 if (deferScreenUpdates < 0)
244 deferScreenUpdates = 0; // Just in case.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000245 }
246
247 public String readParameter(String name, boolean required) {
248 if (inAnApplet) {
249 String s = getParameter(name);
250 if ((s == null) && required) {
251 fatalError(name + " parameter not specified");
252 }
253 return s;
254 }
255
256 for (int i = 0; i < mainArgs.length; i += 2) {
257 if (mainArgs[i].equalsIgnoreCase(name)) {
258 try {
259 return mainArgs[i+1];
260 } catch (Exception e) {
261 if (required) {
262 fatalError(name + " parameter not specified");
263 }
264 return null;
265 }
266 }
267 }
268 if (required) {
269 fatalError(name + " parameter not specified");
270 }
271 return null;
272 }
273
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000274 long readLongParameter(String name, long defaultValue) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000275 String str = readParameter(name, false);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000276 long result = defaultValue;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000277 if (str != null) {
278 try {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000279 result = Long.parseLong(str);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000280 } catch (NumberFormatException e) { }
281 }
282 return result;
283 }
284
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000285 double readDoubleParameter(String name, double defaultValue) {
286 String str = readParameter(name, false);
287 double result = defaultValue;
288 if (str != null) {
289 try {
290 result = Double.parseDouble(str);
291 } catch (NumberFormatException e) { }
292 }
293 return result;
294 }
295
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000296 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000297 // fatalError() - print out a fatal error message.
298 //
299
300 public void fatalError(String str) {
301 System.out.println(str);
302
303 if (inAnApplet) {
304 vncContainer.removeAll();
305 if (rfb != null) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000306 rfb = null;
307 }
308 Label errLabel = new Label(str);
309 errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
310 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
311 vncContainer.add(errLabel);
312 if (inSeparateFrame) {
313 vncFrame.pack();
314 } else {
315 validate();
316 }
317 Thread.currentThread().stop();
318 } else {
319 System.exit(1);
320 }
321 }
322
323
324 //
325 // This method is called before the applet is destroyed.
326 //
327
328 public void destroy() {
329 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000330 if (rfb != null) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000331 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000332 }
333 if (inSeparateFrame) {
334 vncFrame.dispose();
335 }
336 }
337
338
339 //
340 // Close application properly on window close event.
341 //
342
343 public void windowClosing(WindowEvent evt) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000344 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000345 if (rfb != null)
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000346 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000347
348 vncFrame.dispose();
349 if (!inAnApplet) {
350 System.exit(0);
351 }
352 }
353
354 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000355 // Ignore window events we're not interested in.
356 //
357
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000358 public void windowActivated (WindowEvent evt) {}
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000359 public void windowDeactivated (WindowEvent evt) {}
360 public void windowOpened(WindowEvent evt) {}
361 public void windowClosed(WindowEvent evt) {}
362 public void windowIconified(WindowEvent evt) {}
363 public void windowDeiconified(WindowEvent evt) {}
364}