aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/tightvnc/rfbplayer/RfbPlayer.java
blob: 9f7aa63c43065cd421802c9a959df8f97c9a42ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
//
//  Copyright (C) 2001,2002 HorizonLive.com, Inc.  All Rights Reserved.
//  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
//
//  This is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This software is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this software; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
//  USA.
//

package com.HorizonLive.RfbPlayer;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

public class RfbPlayer extends java.applet.Applet
    implements java.lang.Runnable, WindowListener {

  boolean inAnApplet = true;
  boolean inSeparateFrame = false;

  /** current applet width */
  int dispW = 300;
  /** current applet height */
  int dispH = 200;

  //
  // main() is called when run as a java program from the command line.
  // It simply runs the applet inside a newly-created frame.
  //
  public static void main(String[] argv) {
    RfbPlayer p = new RfbPlayer();
    p.mainArgs = argv;
    p.inAnApplet = false;
    p.inSeparateFrame = true;

    p.init();
    p.start();
  }

  String[] mainArgs;

  RfbProto rfb;
  Thread rfbThread;

  Frame vncFrame;
  Container vncContainer;
  //ScrollPane desktopScrollPane;
  LWScrollPane desktopScrollPane;
  GridBagLayout gridbag;
  ButtonPanel buttonPanel;
  VncCanvas vc;

  String sessionURL;
  URL url;
  long initialTimeOffset;
  double playbackSpeed;
  boolean autoPlay;
  boolean showControls;
  boolean isQuitting = false;
  int deferScreenUpdates;

  //
  // init()
  //
  public void init() {

    // LiveConnect work-a-round
    RfbSharedStatic.refApplet = this;

    readParameters();

    if (inSeparateFrame) {
      vncFrame = new Frame("RFB Session Player");
      if (!inAnApplet) {
        vncFrame.add("Center", this);
      }
      vncContainer = vncFrame;
    } else {
      vncContainer = this;
    }

    if (inSeparateFrame)
      vncFrame.addWindowListener(this);

    rfbThread = new Thread(this, "RfbThread");
    rfbThread.start();
  }

  public void update(Graphics g) {
  }

  //
  // run() - executed by the rfbThread to read RFB data.
  //
  public void run() {

    gridbag = new GridBagLayout();
    vncContainer.setLayout(gridbag);

    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridwidth = GridBagConstraints.REMAINDER;
    gbc.anchor = GridBagConstraints.NORTHWEST;

    if (showControls) {
      buttonPanel = new ButtonPanel(this);
      buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
      gridbag.setConstraints(buttonPanel, gbc);
      vncContainer.add(buttonPanel);
    }

    if (inSeparateFrame) {
      vncFrame.pack();
      vncFrame.show();
    } else {
      validate();
    }

    try {
      if (inAnApplet) {
        url = new URL(getCodeBase(), sessionURL);
      } else {
        url = new URL(sessionURL);
      }
      rfb = new RfbProto(url);

      vc = new VncCanvas(this);
      gbc.weightx = 1.0;
      gbc.weighty = 1.0;

      // Create a panel which itself is resizeable and can hold
      // non-resizeable VncCanvas component at the top left corner.
      //Panel canvasPanel = new Panel();
      //canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
      //canvasPanel.add(vc);

      // Create a ScrollPane which will hold a panel with VncCanvas
      // inside.
      //desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
      desktopScrollPane = new LWScrollPane();
      gbc.fill = GridBagConstraints.BOTH;
      gridbag.setConstraints(vc, gbc);
      //gridbag.setConstraints(canvasPanel, gbc);
      desktopScrollPane.addComp(vc);
      desktopScrollPane.setSize(dispW, dispH);
      //desktopScrollPane.add(canvasPanel);

      // Now add the scroll bar to the container.
      if (inSeparateFrame) {
        gridbag.setConstraints(desktopScrollPane, gbc);
        vncFrame.add(desktopScrollPane);
        vncFrame.setTitle(rfb.desktopName);
        vc.resizeDesktopFrame();
      } else {
        // Size the scroll pane to display size.
        desktopScrollPane.setSize(dispW, dispH);

        // Just add the VncCanvas component to the Applet.
        gbc.fill = GridBagConstraints.NONE;
        gridbag.setConstraints(desktopScrollPane, gbc);
        add(desktopScrollPane);
        validate();
        vc.resizeEmbeddedApplet();
      }

      while (!isQuitting) {
        try {
          setPaused(!autoPlay);
          rfb.fbs.setSpeed(playbackSpeed);
          if (initialTimeOffset > rfb.fbs.getTimeOffset())
            setPos(initialTimeOffset); // don't seek backwards here
          vc.processNormalProtocol();
        } catch (EOFException e) {
          if (e.getMessage() != null && e.getMessage().equals("[REWIND]")) {
            // A special type of EOFException allowing us to seek backwards.
            initialTimeOffset = rfb.fbs.getSeekOffset();
            autoPlay = !rfb.fbs.isPaused();
          } else {
            // Return to the beginning after the playback is finished.
            initialTimeOffset = 0;
            autoPlay = false;
          }
          rfb.newSession(url);
          vc.updateFramebufferSize();
        } catch (NullPointerException e) {
          // catching this causes a hang with 1.4.1 JVM's under Win32 IE
          throw e;
        }
      }

    } catch (FileNotFoundException e) {
      fatalError(e.toString());
    } catch (Exception e) {
      e.printStackTrace();
      fatalError(e.toString());
    }

  }

  public void setPaused(boolean paused) {
    if (showControls)
      buttonPanel.setPaused(paused);
    if (paused) {
      rfb.fbs.pausePlayback();
    } else {
      rfb.fbs.resumePlayback();
    }
  }

  public double getSpeed() {
    return playbackSpeed;
  }

  public void setSpeed(double speed) {
    playbackSpeed = speed;
    rfb.fbs.setSpeed(speed);
  }

  public void jumpTo(long pos) {
    long diff = Math.abs(pos - rfb.fbs.getTimeOffset());

    // Current threshold is 5 seconds
    if (diff > 5000) {
      rfb.fbs.pausePlayback();
      setPos(pos);
      rfb.fbs.resumePlayback();
    }
  }

  public void setPos(long pos) {
    rfb.fbs.setTimeOffset(pos);
  }

  public void updatePos() {
    if (showControls)
      buttonPanel.setPos(rfb.fbs.getTimeOffset());
  }

  //
  // readParameters() - read parameters from the html source or from the
  // command line.  On the command line, the arguments are just a sequence of
  // param_name/param_value pairs where the names and values correspond to
  // those expected in the html applet tag source.
  //
  public void readParameters() {

    sessionURL = readParameter("URL", true);

    initialTimeOffset = readLongParameter("Position", 0);
    if (initialTimeOffset < 0)
      initialTimeOffset = 0;

    playbackSpeed = readDoubleParameter("Speed", 1.0);
    if (playbackSpeed <= 0.0)
      playbackSpeed = 1.0;

    autoPlay = false;
    String str = readParameter("Autoplay", false);
    if (str != null && str.equalsIgnoreCase("Yes"))
      autoPlay = true;

    showControls = true;
    str = readParameter("Show Controls", false);
    if (str != null && str.equalsIgnoreCase("No"))
      showControls = false;

    if (inAnApplet) {
      str = readParameter("Open New Window", false);
      if (str != null && str.equalsIgnoreCase("Yes"))
        inSeparateFrame = true;
    }

    // Fine tuning options.
    deferScreenUpdates = (int)readLongParameter("Defer screen updates", 20);
    if (deferScreenUpdates < 0)
      deferScreenUpdates = 0;	// Just in case.

    // Display width and height.
    dispW = readIntParameter("DISPLAY_WIDTH", dispW);
    dispH = readIntParameter("DISPLAY_HEIGHT", dispH);
  }

  public String readParameter(String name, boolean required) {
    if (inAnApplet) {
      String s = getParameter(name);
      if ((s == null) && required) {
        fatalError(name + " parameter not specified");
      }
      return s;
    }

    for (int i = 0; i < mainArgs.length; i += 2) {
      if (mainArgs[i].equalsIgnoreCase(name)) {
        try {
          return mainArgs[i + 1];
        } catch (Exception e) {
          if (required) {
            fatalError(name + " parameter not specified");
          }
          return null;
        }
      }
    }
    if (required) {
      fatalError(name + " parameter not specified");
    }
    return null;
  }

  long readLongParameter(String name, long defaultValue) {
    String str = readParameter(name, false);
    long result = defaultValue;
    if (str != null) {
      try {
        result = Long.parseLong(str);
      } catch (NumberFormatException e) {
      }
    }
    return result;
  }

  double readDoubleParameter(String name, double defaultValue) {
    String str = readParameter(name, false);
    double result = defaultValue;
    if (str != null) {
      try {
        result = Double.valueOf(str).doubleValue();
      } catch (NumberFormatException e) {
      }
    }
    return result;
  }

  int readIntParameter(String name, int defaultValue) {
    String str = readParameter(name, false);
    int result = defaultValue;
    if (str != null) {
      try {
        result = Integer.parseInt(str);
      } catch (NumberFormatException e) {
      }
    }
    return result;
  }

  //
  // fatalError() - print out a fatal error message.
  //
  public void fatalError(String str) {
    System.out.println(str);

    if (inAnApplet) {
      vncContainer.removeAll();
      if (rfb != null) {
        rfb = null;
      }
      Label errLabel = new Label(str);
      errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
      vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
      vncContainer.add(errLabel);
      if (inSeparateFrame) {
        vncFrame.pack();
      } else {
        validate();
      }
      Thread.currentThread().stop();
    } else {
      System.exit(1);
    }
  }


  //
  // This method is called before the applet is destroyed.
  //
  public void destroy() {
    isQuitting = true;
    vncContainer.removeAll();
    if (rfb != null) {
      rfb.quit();
    }
    try {
      rfbThread.join();
    } catch (InterruptedException e) {
    }
    if (inSeparateFrame) {
      vncFrame.removeWindowListener(this);
      vncFrame.dispose();
    }
  }

  //
  // Set the new width and height of the applet. Call when browser is resized to 
  // resize the viewer.
  //
  public void displaySize(int width, int height) {
    dispW = width;
    dispH = height;
    if (!inSeparateFrame) {
      vc.resizeEmbeddedApplet();
    }
  }

  //
  // Close application properly on window close event.
  //
  public void windowClosing(WindowEvent evt) {
    vncContainer.removeAll();
    if (rfb != null)
      rfb = null;

    vncFrame.dispose();
    if (!inAnApplet) {
      System.exit(0);
    }
  }

  //
  // Ignore window events we're not interested in.
  //
  public void windowActivated(WindowEvent evt) {
  }

  public void windowDeactivated(WindowEvent evt) {
  }

  public void windowOpened(WindowEvent evt) {
  }

  public void windowClosed(WindowEvent evt) {
  }

  public void windowIconified(WindowEvent evt) {
  }

  public void windowDeiconified(WindowEvent evt) {
  }

}