blob: 4a600169be9adc45482763011f02e2443d0b5684 [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 Kaplinsky972c2572002-05-30 14:19:02 +000060 long initialTimeOffset;
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +000061 double playbackSpeed;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000062 boolean showControls;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000063 int deferScreenUpdates;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000064
65 //
66 // init()
67 //
68
69 public void init() {
70
71 readParameters();
72
73 if (inSeparateFrame) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000074 vncFrame = new Frame("RFB Session Player");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000075 if (!inAnApplet) {
76 vncFrame.add("Center", this);
77 }
78 vncContainer = vncFrame;
79 } else {
80 vncContainer = this;
81 }
82
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000083 if (inSeparateFrame)
84 vncFrame.addWindowListener(this);
85
86 rfbThread = new Thread(this);
87 rfbThread.start();
88 }
89
90 public void update(Graphics g) {
91 }
92
93 //
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000094 // run() - executed by the rfbThread to read RFB data.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000095 //
96
97 public void run() {
98
99 gridbag = new GridBagLayout();
100 vncContainer.setLayout(gridbag);
101
102 GridBagConstraints gbc = new GridBagConstraints();
103 gbc.gridwidth = GridBagConstraints.REMAINDER;
104 gbc.anchor = GridBagConstraints.NORTHWEST;
105
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000106 if (showControls) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000107 buttonPanel = new ButtonPanel(this);
108 buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
109 gridbag.setConstraints(buttonPanel, gbc);
110 vncContainer.add(buttonPanel);
111 }
112
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000113 if (inSeparateFrame) {
114 vncFrame.pack();
115 vncFrame.show();
116 } else {
117 validate();
118 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000119
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000120 try {
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000121 URL url = new URL(sessionURL);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000122 rfb = new RfbProto(url);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000123
124 vc = new VncCanvas(this);
125 gbc.weightx = 1.0;
126 gbc.weighty = 1.0;
127
128 if (inSeparateFrame) {
129
130 // Create a panel which itself is resizeable and can hold
131 // non-resizeable VncCanvas component at the top left corner.
132 Panel canvasPanel = new Panel();
133 canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
134 canvasPanel.add(vc);
135
136 // Create a ScrollPane which will hold a panel with VncCanvas
137 // inside.
138 desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
139 gbc.fill = GridBagConstraints.BOTH;
140 gridbag.setConstraints(desktopScrollPane, gbc);
141 desktopScrollPane.add(canvasPanel);
142
143 // Finally, add our ScrollPane to the Frame window.
144 vncFrame.add(desktopScrollPane);
145 vncFrame.setTitle(rfb.desktopName);
146 vncFrame.pack();
147 vc.resizeDesktopFrame();
148
149 } else {
150
151 // Just add the VncCanvas component to the Applet.
152 gridbag.setConstraints(vc, gbc);
153 add(vc);
154 validate();
155
156 }
157
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000158 while (true) {
159 try {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000160 setPaused(true);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000161 rfb.fbs.setTimeOffset(initialTimeOffset);
162 rfb.fbs.setSpeed(playbackSpeed);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000163 vc.processNormalProtocol();
164 } catch (EOFException e) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000165 initialTimeOffset = 0;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000166 rfb.newSession(url);
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000167 }
168 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000169
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000170 } catch (FileNotFoundException e) {
171 fatalError(e.toString());
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000172 } catch (Exception e) {
173 e.printStackTrace();
174 fatalError(e.toString());
175 }
176
177 }
178
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000179 public void setPaused(boolean paused) {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000180 if (showControls)
181 buttonPanel.setPaused(paused);
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000182 if (paused) {
183 rfb.fbs.pausePlayback();
184 } else {
185 rfb.fbs.resumePlayback();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000186 }
187 }
188
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000189 public double getSpeed() {
190 return playbackSpeed;
191 }
192
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000193 public void setSpeed(double speed) {
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000194 playbackSpeed = speed;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000195 rfb.fbs.setSpeed(speed);
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000196 }
197
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000198 public void setPos(int pos) {
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000199 rfb.fbs.setTimeOffset(pos * 1000);
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000200 }
201
Constantin Kaplinskyce39d3b2002-05-30 15:54:56 +0000202
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000203 public void updatePos() {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000204 if (showControls)
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000205 buttonPanel.setPos((int)(rfb.fbs.getTimeOffset() / 1000));
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000206 }
207
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000208 //
209 // readParameters() - read parameters from the html source or from the
210 // command line. On the command line, the arguments are just a sequence of
211 // param_name/param_value pairs where the names and values correspond to
212 // those expected in the html applet tag source.
213 //
214
215 public void readParameters() {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000216
Constantin Kaplinsky5d99c952002-05-25 09:49:23 +0000217 sessionURL = readParameter("URL", true);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000218 initialTimeOffset = readLongParameter("Position", 0);
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000219 if (initialTimeOffset < 0)
220 initialTimeOffset = 0;
221 playbackSpeed = readDoubleParameter("Speed", 1.0);
222 if (playbackSpeed <= 0.0)
223 playbackSpeed = 1.0;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000224
225 showControls = true;
226 String str = readParameter("Show Controls", false);
227 if (str != null && str.equalsIgnoreCase("No"))
228 showControls = false;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000229
230 if (inAnApplet) {
231 str = readParameter("Open New Window", false);
232 if (str != null && str.equalsIgnoreCase("Yes"))
233 inSeparateFrame = true;
234 }
235
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000236 // Fine tuning options.
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000237 deferScreenUpdates = (int)readLongParameter("Defer screen updates", 20);
238 if (deferScreenUpdates < 0)
239 deferScreenUpdates = 0; // Just in case.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000240 }
241
242 public String readParameter(String name, boolean required) {
243 if (inAnApplet) {
244 String s = getParameter(name);
245 if ((s == null) && required) {
246 fatalError(name + " parameter not specified");
247 }
248 return s;
249 }
250
251 for (int i = 0; i < mainArgs.length; i += 2) {
252 if (mainArgs[i].equalsIgnoreCase(name)) {
253 try {
254 return mainArgs[i+1];
255 } catch (Exception e) {
256 if (required) {
257 fatalError(name + " parameter not specified");
258 }
259 return null;
260 }
261 }
262 }
263 if (required) {
264 fatalError(name + " parameter not specified");
265 }
266 return null;
267 }
268
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000269 long readLongParameter(String name, long defaultValue) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000270 String str = readParameter(name, false);
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000271 long result = defaultValue;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000272 if (str != null) {
273 try {
Constantin Kaplinsky972c2572002-05-30 14:19:02 +0000274 result = Long.parseLong(str);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000275 } catch (NumberFormatException e) { }
276 }
277 return result;
278 }
279
Constantin Kaplinsky7957ca12002-05-30 16:19:11 +0000280 double readDoubleParameter(String name, double defaultValue) {
281 String str = readParameter(name, false);
282 double result = defaultValue;
283 if (str != null) {
284 try {
285 result = Double.parseDouble(str);
286 } catch (NumberFormatException e) { }
287 }
288 return result;
289 }
290
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000291 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000292 // fatalError() - print out a fatal error message.
293 //
294
295 public void fatalError(String str) {
296 System.out.println(str);
297
298 if (inAnApplet) {
299 vncContainer.removeAll();
300 if (rfb != null) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000301 rfb = null;
302 }
303 Label errLabel = new Label(str);
304 errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
305 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
306 vncContainer.add(errLabel);
307 if (inSeparateFrame) {
308 vncFrame.pack();
309 } else {
310 validate();
311 }
312 Thread.currentThread().stop();
313 } else {
314 System.exit(1);
315 }
316 }
317
318
319 //
320 // This method is called before the applet is destroyed.
321 //
322
323 public void destroy() {
324 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000325 if (rfb != null) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000326 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000327 }
328 if (inSeparateFrame) {
329 vncFrame.dispose();
330 }
331 }
332
333
334 //
335 // Close application properly on window close event.
336 //
337
338 public void windowClosing(WindowEvent evt) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000339 vncContainer.removeAll();
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000340 if (rfb != null)
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000341 rfb = null;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000342
343 vncFrame.dispose();
344 if (!inAnApplet) {
345 System.exit(0);
346 }
347 }
348
349 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000350 // Ignore window events we're not interested in.
351 //
352
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000353 public void windowActivated (WindowEvent evt) {}
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000354 public void windowDeactivated (WindowEvent evt) {}
355 public void windowOpened(WindowEvent evt) {}
356 public void windowClosed(WindowEvent evt) {}
357 public void windowIconified(WindowEvent evt) {}
358 public void windowDeiconified(WindowEvent evt) {}
359}