Mercurial > hg > Members > nobuyasu > tightVNCClient
annotate src/myVncClient/VncViewer.java @ 60:18a19d8a09f4
add some files. for to use Client with CUI.
author | e085711 |
---|---|
date | Fri, 05 Aug 2011 01:05:38 +0900 |
parents | c9ef47d9aa55 |
children | 83acdeca0539 |
rev | line source |
---|---|
17 | 1 package myVncClient; |
0 | 2 |
4 | 3 import java.awt.*; |
4 import java.awt.event.*; | |
5 import java.io.*; | |
6 import java.net.*; | |
0 | 7 |
60 | 8 public class VncViewer extends java.applet.Applet implements |
4 | 9 java.lang.Runnable, WindowListener { |
0 | 10 |
4 | 11 boolean inAnApplet = true; |
12 boolean inSeparateFrame = false; | |
50
c07bec8c8617
change echoClient.java EchoClient.java
Yu Taninari <you@cr.ie.u-ryukyu.ac.jp>
parents:
29
diff
changeset
|
13 protected String[] mainArgs; |
0 | 14 |
4 | 15 // |
16 // main() is called when run as a java program from the command line. | |
17 // It simply runs the applet inside a newly-created frame. | |
18 // | |
0 | 19 |
4 | 20 public static void main(String[] argv) { |
21 VncViewer v = new VncViewer(); | |
22 v.mainArgs = argv; | |
23 v.inAnApplet = false; | |
24 v.inSeparateFrame = true; | |
18 | 25 |
4 | 26 v.init(); |
27 v.start(); | |
28 } | |
0 | 29 |
50
c07bec8c8617
change echoClient.java EchoClient.java
Yu Taninari <you@cr.ie.u-ryukyu.ac.jp>
parents:
29
diff
changeset
|
30 String[] echoClient; |
4 | 31 |
15 | 32 MyRfbProto rfb; |
4 | 33 Thread rfbThread; |
26 | 34 Thread accThread; |
50
c07bec8c8617
change echoClient.java EchoClient.java
Yu Taninari <you@cr.ie.u-ryukyu.ac.jp>
parents:
29
diff
changeset
|
35 EchoClient echo; |
0 | 36 |
4 | 37 Frame vncFrame; |
38 Container vncContainer; | |
39 ScrollPane desktopScrollPane; | |
40 GridBagLayout gridbag; | |
41 ButtonPanel buttonPanel; | |
42 Label connStatusLabel; | |
43 VncCanvas vc; | |
44 OptionsFrame options; | |
45 ClipboardFrame clipboard; | |
46 RecordingFrame rec; | |
0 | 47 |
4 | 48 // Control session recording. |
49 Object recordingSync; | |
50 String sessionFileName; | |
51 boolean recordingActive; | |
52 boolean recordingStatusChanged; | |
53 String cursorUpdatesDef; | |
54 String eightBitColorsDef; | |
0 | 55 |
4 | 56 // Variables read from parameter values. |
57 String socketFactory; | |
58 String host; | |
59 int port; | |
60 String passwordParam; | |
61 boolean showControls; | |
62 boolean offerRelogin; | |
63 boolean showOfflineDesktop; | |
64 int deferScreenUpdates; | |
65 int deferCursorUpdates; | |
66 int deferUpdateRequests; | |
67 int debugStatsExcludeUpdates; | |
68 int debugStatsMeasureUpdates; | |
0 | 69 |
4 | 70 // Reference to this applet for inter-applet communication. |
71 public static java.applet.Applet refApplet; | |
0 | 72 |
4 | 73 // |
74 // init() | |
75 // | |
0 | 76 |
4 | 77 public void init() { |
0 | 78 |
4 | 79 readParameters(); |
0 | 80 |
4 | 81 refApplet = this; |
0 | 82 |
4 | 83 if (inSeparateFrame) { |
84 vncFrame = new Frame("TightVNC"); | |
85 if (!inAnApplet) { | |
86 vncFrame.add("Center", this); | |
87 } | |
88 vncContainer = vncFrame; | |
89 } else { | |
90 vncContainer = this; | |
91 } | |
0 | 92 |
4 | 93 recordingSync = new Object(); |
0 | 94 |
4 | 95 options = new OptionsFrame(this); |
96 clipboard = new ClipboardFrame(this); | |
97 if (RecordingFrame.checkSecurity()) | |
98 rec = new RecordingFrame(this); | |
0 | 99 |
4 | 100 sessionFileName = null; |
101 recordingActive = false; | |
102 recordingStatusChanged = false; | |
103 cursorUpdatesDef = null; | |
104 eightBitColorsDef = null; | |
0 | 105 |
4 | 106 if (inSeparateFrame) |
107 vncFrame.addWindowListener(this); | |
0 | 108 |
4 | 109 rfbThread = new Thread(this); |
110 rfbThread.start(); | |
54 | 111 accThread = new Thread(new AcceptThread(rfb)); |
26 | 112 accThread.start(); |
113 | |
114 | |
4 | 115 } |
0 | 116 |
4 | 117 public void update(Graphics g) { |
118 } | |
0 | 119 |
4 | 120 // |
121 // run() - executed by the rfbThread to deal with the RFB socket. | |
122 // | |
123 | |
124 public void run() { | |
0 | 125 |
4 | 126 gridbag = new GridBagLayout(); |
127 vncContainer.setLayout(gridbag); | |
0 | 128 |
4 | 129 GridBagConstraints gbc = new GridBagConstraints(); |
130 gbc.gridwidth = GridBagConstraints.REMAINDER; | |
131 gbc.anchor = GridBagConstraints.NORTHWEST; | |
0 | 132 |
4 | 133 if (showControls) { |
134 buttonPanel = new ButtonPanel(this); | |
135 gridbag.setConstraints(buttonPanel, gbc); | |
136 vncContainer.add(buttonPanel); | |
137 } | |
138 | |
10 | 139 /*****************************************************************************/ |
18 | 140 if(inSeparateFrame) { |
141 vncFrame.pack(); | |
142 vncFrame.setVisible(true); | |
143 } else { | |
144 validate(); | |
145 } | |
4 | 146 try { |
16 | 147 |
6 | 148 rfb = new MyRfbProto(host, port, this); |
10 | 149 rfb.readServerInit(); |
60 | 150 // rfb.readPngData(); |
10 | 151 |
4 | 152 createCanvas(0, 0); |
19 | 153 vc.drawFirstImage(); |
4 | 154 } catch (IOException e) { |
155 System.out.println("Socket error"); | |
156 System.exit(0); | |
157 } | |
158 | |
159 gbc.weightx = 1.0; | |
160 gbc.weighty = 1.0; | |
161 | |
10 | 162 if (inSeparateFrame) { |
0 | 163 |
4 | 164 // Create a panel which itself is resizeable and can hold |
165 // non-resizeable VncCanvas component at the top left corner. | |
166 Panel canvasPanel = new Panel(); | |
167 canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); | |
168 canvasPanel.add(vc); | |
0 | 169 |
4 | 170 // Create a ScrollPane which will hold a panel with VncCanvas |
171 // inside. | |
172 desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED); | |
173 gbc.fill = GridBagConstraints.BOTH; | |
174 gridbag.setConstraints(desktopScrollPane, gbc); | |
175 desktopScrollPane.add(canvasPanel); | |
0 | 176 |
4 | 177 // Finally, add our ScrollPane to the Frame window. |
178 vncFrame.add(desktopScrollPane); | |
179 vncFrame.setTitle(rfb.desktopName); | |
180 vncFrame.pack(); | |
181 vc.resizeDesktopFrame(); | |
0 | 182 |
4 | 183 } else { |
0 | 184 |
4 | 185 // Just add the VncCanvas component to the Applet. |
186 gridbag.setConstraints(vc, gbc); | |
187 add(vc); | |
188 validate(); | |
0 | 189 |
4 | 190 } |
10 | 191 /*****************************************************************************/ |
0 | 192 |
10 | 193 |
4 | 194 try { |
0 | 195 |
4 | 196 if (showControls) |
197 buttonPanel.enableButtons(); | |
0 | 198 |
4 | 199 moveFocusToDesktop(); |
200 processNormalProtocol();// main loop | |
0 | 201 |
4 | 202 } catch (NoRouteToHostException e) { |
203 fatalError("Network error: no route to server: " + host, e); | |
204 } catch (UnknownHostException e) { | |
205 fatalError("Network error: server name unknown: " + host, e); | |
206 } catch (ConnectException e) { | |
207 fatalError("Network error: could not connect to server: " + host | |
208 + ":" + port, e); | |
209 } catch (EOFException e) { | |
29
750ecaa1e1b9
add echoClient.java and waitreply.java. modify MyRfbProto.java
e085711
parents:
26
diff
changeset
|
210 |
750ecaa1e1b9
add echoClient.java and waitreply.java. modify MyRfbProto.java
e085711
parents:
26
diff
changeset
|
211 |
4 | 212 if (showOfflineDesktop) { |
213 e.printStackTrace(); | |
214 System.out | |
215 .println("Network error: remote side closed connection"); | |
216 if (vc != null) { | |
217 vc.enableInput(false); | |
218 } | |
219 if (inSeparateFrame) { | |
220 vncFrame.setTitle(rfb.desktopName + " [disconnected]"); | |
221 } | |
222 if (rfb != null && !rfb.closed()) | |
223 rfb.close(); | |
224 if (showControls && buttonPanel != null) { | |
225 buttonPanel.disableButtonsOnDisconnect(); | |
226 if (inSeparateFrame) { | |
227 vncFrame.pack(); | |
228 } else { | |
229 validate(); | |
230 } | |
231 } | |
232 } else { | |
233 fatalError("Network error: remote side closed connection", e); | |
234 } | |
235 } catch (IOException e) { | |
236 String str = e.getMessage(); | |
237 if (str != null && str.length() != 0) { | |
238 fatalError("Network Error: " + str, e); | |
239 } else { | |
240 fatalError(e.toString(), e); | |
241 } | |
242 } catch (Exception e) { | |
243 String str = e.getMessage(); | |
244 if (str != null && str.length() != 0) { | |
245 fatalError("Error: " + str, e); | |
246 } else { | |
247 fatalError(e.toString(), e); | |
248 } | |
249 } | |
250 | |
0 | 251 } |
252 | |
4 | 253 // |
254 // Create a VncCanvas instance. | |
255 // | |
0 | 256 |
4 | 257 void createCanvas(int maxWidth, int maxHeight) throws IOException { |
258 // Determine if Java 2D API is available and use a special | |
259 // version of VncCanvas if it is present. | |
260 vc = null; | |
261 try { | |
262 // This throws ClassNotFoundException if there is no Java 2D API. | |
263 Class cl = Class.forName("java.awt.Graphics2D"); | |
264 // If we could load Graphics2D class, then we can use VncCanvas2D. | |
265 cl = Class.forName("VncCanvas2"); | |
266 Class[] argClasses = { this.getClass(), Integer.TYPE, Integer.TYPE }; | |
267 java.lang.reflect.Constructor cstr = cl.getConstructor(argClasses); | |
268 Object[] argObjects = { this, new Integer(maxWidth), | |
269 new Integer(maxHeight) }; | |
270 vc = (VncCanvas) cstr.newInstance(argObjects); | |
271 } catch (Exception e) { | |
272 System.out.println("Warning: Java 2D API is not available"); | |
273 } | |
0 | 274 |
4 | 275 // If we failed to create VncCanvas2D, use old VncCanvas. |
276 if (vc == null) | |
277 vc = new VncCanvas(this, maxWidth, maxHeight); | |
278 } | |
0 | 279 |
4 | 280 // |
281 // Process RFB socket messages. | |
282 // If the rfbThread is being stopped, ignore any exceptions, | |
283 // otherwise rethrow the exception so it can be handled. | |
284 // | |
0 | 285 |
4 | 286 void processNormalProtocol() throws Exception { |
287 try { | |
288 vc.processNormalProtocol();// main loop | |
289 } catch (Exception e) { | |
290 if (rfbThread == null) { | |
291 System.out.println("Ignoring RFB socket exceptions" | |
292 + " because applet is stopping"); | |
293 } else { | |
294 throw e; | |
295 } | |
296 } | |
297 } | |
0 | 298 |
4 | 299 // |
300 // Connect to the RFB server and authenticate the user. | |
301 // | |
0 | 302 |
4 | 303 void connectAndAuthenticate() throws Exception { |
304 showConnectionStatus("Initializing..."); | |
305 if (inSeparateFrame) { | |
306 vncFrame.pack(); | |
15 | 307 vncFrame.setVisible(true); |
4 | 308 } else { |
309 validate(); | |
310 } | |
311 | |
312 showConnectionStatus("Connecting to " + host + ", port " + port + "..."); | |
0 | 313 |
15 | 314 rfb = new MyRfbProto(host, port, this); |
4 | 315 showConnectionStatus("Connected to server"); |
0 | 316 |
4 | 317 rfb.readVersionMsg(); |
318 showConnectionStatus("RFB server supports protocol version " | |
319 + rfb.serverMajor + "." + rfb.serverMinor); | |
0 | 320 |
4 | 321 rfb.writeVersionMsg(); |
322 showConnectionStatus("Using RFB protocol version " + rfb.clientMajor | |
323 + "." + rfb.clientMinor); | |
0 | 324 |
4 | 325 int secType = rfb.negotiateSecurity(); |
326 int authType; | |
327 if (secType == RfbProto.SecTypeTight) { | |
328 showConnectionStatus("Enabling TightVNC protocol extensions"); | |
329 rfb.setupTunneling(); | |
330 authType = rfb.negotiateAuthenticationTight(); | |
331 } else { | |
332 authType = secType; | |
333 } | |
0 | 334 |
4 | 335 switch (authType) { |
336 case RfbProto.AuthNone: | |
337 showConnectionStatus("No authentication needed"); | |
338 rfb.authenticateNone(); | |
339 break; | |
340 case RfbProto.AuthVNC: | |
341 showConnectionStatus("Performing standard VNC authentication"); | |
342 if (passwordParam != null) { | |
343 rfb.authenticateVNC(passwordParam); | |
344 } else { | |
345 String pw = askPassword(); | |
346 rfb.authenticateVNC(pw); | |
347 } | |
348 break; | |
349 default: | |
350 throw new Exception("Unknown authentication scheme " + authType); | |
351 } | |
352 } | |
0 | 353 |
4 | 354 // |
355 // Show a message describing the connection status. | |
356 // To hide the connection status label, use (msg == null). | |
357 // | |
0 | 358 |
4 | 359 void showConnectionStatus(String msg) { |
360 if (msg == null) { | |
361 if (vncContainer.isAncestorOf(connStatusLabel)) { | |
362 vncContainer.remove(connStatusLabel); | |
363 } | |
364 return; | |
365 } | |
0 | 366 |
4 | 367 System.out.println(msg); |
0 | 368 |
4 | 369 if (connStatusLabel == null) { |
370 connStatusLabel = new Label("Status: " + msg); | |
371 connStatusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12)); | |
372 } else { | |
373 connStatusLabel.setText("Status: " + msg); | |
374 } | |
0 | 375 |
4 | 376 if (!vncContainer.isAncestorOf(connStatusLabel)) { |
377 GridBagConstraints gbc = new GridBagConstraints(); | |
378 gbc.gridwidth = GridBagConstraints.REMAINDER; | |
379 gbc.fill = GridBagConstraints.HORIZONTAL; | |
380 gbc.anchor = GridBagConstraints.NORTHWEST; | |
381 gbc.weightx = 1.0; | |
382 gbc.weighty = 1.0; | |
383 gbc.insets = new Insets(20, 30, 20, 30); | |
384 gridbag.setConstraints(connStatusLabel, gbc); | |
385 vncContainer.add(connStatusLabel); | |
386 } | |
0 | 387 |
4 | 388 if (inSeparateFrame) { |
389 vncFrame.pack(); | |
390 } else { | |
391 validate(); | |
392 } | |
393 } | |
0 | 394 |
4 | 395 // |
396 // Show an authentication panel. | |
397 // | |
0 | 398 |
4 | 399 String askPassword() throws Exception { |
400 showConnectionStatus(null); | |
401 | |
402 AuthPanel authPanel = new AuthPanel(this); | |
0 | 403 |
4 | 404 GridBagConstraints gbc = new GridBagConstraints(); |
405 gbc.gridwidth = GridBagConstraints.REMAINDER; | |
406 gbc.anchor = GridBagConstraints.NORTHWEST; | |
407 gbc.weightx = 1.0; | |
408 gbc.weighty = 1.0; | |
409 gbc.ipadx = 100; | |
410 gbc.ipady = 50; | |
411 gridbag.setConstraints(authPanel, gbc); | |
412 vncContainer.add(authPanel); | |
0 | 413 |
4 | 414 if (inSeparateFrame) { |
415 vncFrame.pack(); | |
416 } else { | |
417 validate(); | |
418 } | |
0 | 419 |
4 | 420 authPanel.moveFocusToDefaultField(); |
421 String pw = authPanel.getPassword(); | |
422 vncContainer.remove(authPanel); | |
0 | 423 |
4 | 424 return pw; |
425 } | |
0 | 426 |
4 | 427 // |
428 // Do the rest of the protocol initialisation. | |
429 // | |
0 | 430 |
4 | 431 void doProtocolInitialisation() throws IOException { |
432 rfb.writeClientInit(); | |
433 rfb.readServerInit(); | |
0 | 434 |
4 | 435 System.out.println("Desktop name is " + rfb.desktopName); |
436 System.out.println("Desktop size is " + rfb.framebufferWidth + " x " | |
437 + rfb.framebufferHeight); | |
438 | |
439 setEncodings(); | |
0 | 440 |
4 | 441 showConnectionStatus(null); |
442 } | |
0 | 443 |
4 | 444 // |
445 // Send current encoding list to the RFB server. | |
446 // | |
0 | 447 |
4 | 448 int[] encodingsSaved; |
449 int nEncodingsSaved; | |
0 | 450 |
4 | 451 void setEncodings() { |
452 setEncodings(false); | |
453 } | |
0 | 454 |
4 | 455 void autoSelectEncodings() { |
456 setEncodings(true); | |
457 } | |
0 | 458 |
4 | 459 void setEncodings(boolean autoSelectOnly) { |
460 if (options == null || rfb == null || !rfb.inNormalProtocol) | |
461 return; | |
0 | 462 |
4 | 463 int preferredEncoding = options.preferredEncoding; |
464 if (preferredEncoding == -1) { | |
465 long kbitsPerSecond = rfb.kbitsPerSecond(); | |
466 if (nEncodingsSaved < 1) { | |
467 // Choose Tight or ZRLE encoding for the very first update. | |
468 System.out.println("Using Tight/ZRLE encodings"); | |
469 preferredEncoding = RfbProto.EncodingTight; | |
470 } else if (kbitsPerSecond > 2000 | |
471 && encodingsSaved[0] != RfbProto.EncodingHextile) { | |
472 // Switch to Hextile if the connection speed is above 2Mbps. | |
473 System.out.println("Throughput " + kbitsPerSecond | |
474 + " kbit/s - changing to Hextile encoding"); | |
475 preferredEncoding = RfbProto.EncodingHextile; | |
476 } else if (kbitsPerSecond < 1000 | |
477 && encodingsSaved[0] != RfbProto.EncodingTight) { | |
478 // Switch to Tight/ZRLE if the connection speed is below 1Mbps. | |
479 System.out.println("Throughput " + kbitsPerSecond | |
480 + " kbit/s - changing to Tight/ZRLE encodings"); | |
481 preferredEncoding = RfbProto.EncodingTight; | |
482 } else { | |
483 // Don't change the encoder. | |
484 if (autoSelectOnly) | |
485 return; | |
486 preferredEncoding = encodingsSaved[0]; | |
487 } | |
488 } else { | |
489 // Auto encoder selection is not enabled. | |
490 if (autoSelectOnly) | |
491 return; | |
492 } | |
0 | 493 |
4 | 494 int[] encodings = new int[20]; |
495 int nEncodings = 0; | |
0 | 496 |
4 | 497 encodings[nEncodings++] = preferredEncoding; |
498 if (options.useCopyRect) { | |
499 encodings[nEncodings++] = RfbProto.EncodingCopyRect; | |
500 } | |
0 | 501 |
4 | 502 if (preferredEncoding != RfbProto.EncodingTight) { |
503 encodings[nEncodings++] = RfbProto.EncodingTight; | |
504 } | |
505 if (preferredEncoding != RfbProto.EncodingZRLE) { | |
506 encodings[nEncodings++] = RfbProto.EncodingZRLE; | |
507 } | |
508 if (preferredEncoding != RfbProto.EncodingHextile) { | |
509 encodings[nEncodings++] = RfbProto.EncodingHextile; | |
510 } | |
511 if (preferredEncoding != RfbProto.EncodingZlib) { | |
512 encodings[nEncodings++] = RfbProto.EncodingZlib; | |
513 } | |
514 if (preferredEncoding != RfbProto.EncodingCoRRE) { | |
515 encodings[nEncodings++] = RfbProto.EncodingCoRRE; | |
516 } | |
517 if (preferredEncoding != RfbProto.EncodingRRE) { | |
518 encodings[nEncodings++] = RfbProto.EncodingRRE; | |
519 } | |
520 | |
521 if (options.compressLevel >= 0 && options.compressLevel <= 9) { | |
522 encodings[nEncodings++] = RfbProto.EncodingCompressLevel0 | |
523 + options.compressLevel; | |
524 } | |
525 if (options.jpegQuality >= 0 && options.jpegQuality <= 9) { | |
526 encodings[nEncodings++] = RfbProto.EncodingQualityLevel0 | |
527 + options.jpegQuality; | |
528 } | |
0 | 529 |
4 | 530 if (options.requestCursorUpdates) { |
531 encodings[nEncodings++] = RfbProto.EncodingXCursor; | |
532 encodings[nEncodings++] = RfbProto.EncodingRichCursor; | |
533 if (!options.ignoreCursorUpdates) | |
534 encodings[nEncodings++] = RfbProto.EncodingPointerPos; | |
535 } | |
536 | |
537 encodings[nEncodings++] = RfbProto.EncodingLastRect; | |
538 encodings[nEncodings++] = RfbProto.EncodingNewFBSize; | |
0 | 539 |
4 | 540 boolean encodingsWereChanged = false; |
541 if (nEncodings != nEncodingsSaved) { | |
542 encodingsWereChanged = true; | |
543 } else { | |
544 for (int i = 0; i < nEncodings; i++) { | |
545 if (encodings[i] != encodingsSaved[i]) { | |
546 encodingsWereChanged = true; | |
547 break; | |
548 } | |
549 } | |
550 } | |
0 | 551 |
4 | 552 if (encodingsWereChanged) { |
553 try { | |
554 rfb.writeSetEncodings(encodings, nEncodings); | |
555 if (vc != null) { | |
556 vc.softCursorFree(); | |
557 } | |
558 } catch (Exception e) { | |
559 e.printStackTrace(); | |
560 } | |
561 encodingsSaved = encodings; | |
562 nEncodingsSaved = nEncodings; | |
563 } | |
564 } | |
0 | 565 |
4 | 566 // |
567 // setCutText() - send the given cut text to the RFB server. | |
568 // | |
0 | 569 |
4 | 570 void setCutText(String text) { |
571 try { | |
572 if (rfb != null && rfb.inNormalProtocol) { | |
573 rfb.writeClientCutText(text); | |
574 } | |
575 } catch (Exception e) { | |
576 e.printStackTrace(); | |
577 } | |
578 } | |
0 | 579 |
4 | 580 // |
581 // Order change in session recording status. To stop recording, pass | |
582 // null in place of the fname argument. | |
583 // | |
0 | 584 |
4 | 585 void setRecordingStatus(String fname) { |
586 synchronized (recordingSync) { | |
587 sessionFileName = fname; | |
588 recordingStatusChanged = true; | |
589 } | |
590 } | |
591 | |
592 // | |
593 // Start or stop session recording. Returns true if this method call | |
594 // causes recording of a new session. | |
595 // | |
0 | 596 |
4 | 597 boolean checkRecordingStatus() throws IOException { |
598 synchronized (recordingSync) { | |
599 if (recordingStatusChanged) { | |
600 recordingStatusChanged = false; | |
601 if (sessionFileName != null) { | |
602 startRecording(); | |
603 return true; | |
604 } else { | |
605 stopRecording(); | |
606 } | |
607 } | |
608 } | |
609 return false; | |
610 } | |
0 | 611 |
4 | 612 // |
613 // Start session recording. | |
614 // | |
0 | 615 |
4 | 616 protected void startRecording() throws IOException { |
617 synchronized (recordingSync) { | |
618 if (!recordingActive) { | |
619 // Save settings to restore them after recording the session. | |
620 cursorUpdatesDef = options.choices[options.cursorUpdatesIndex] | |
621 .getSelectedItem(); | |
622 eightBitColorsDef = options.choices[options.eightBitColorsIndex] | |
623 .getSelectedItem(); | |
624 // Set options to values suitable for recording. | |
625 options.choices[options.cursorUpdatesIndex].select("Disable"); | |
626 options.choices[options.cursorUpdatesIndex].setEnabled(false); | |
627 options.setEncodings(); | |
628 options.choices[options.eightBitColorsIndex].select("No"); | |
629 options.choices[options.eightBitColorsIndex].setEnabled(false); | |
630 options.setColorFormat(); | |
631 } else { | |
632 rfb.closeSession(); | |
633 } | |
634 | |
635 System.out.println("Recording the session in " + sessionFileName); | |
636 rfb.startSession(sessionFileName); | |
637 recordingActive = true; | |
638 } | |
639 } | |
0 | 640 |
4 | 641 // |
642 // Stop session recording. | |
643 // | |
0 | 644 |
4 | 645 protected void stopRecording() throws IOException { |
646 synchronized (recordingSync) { | |
647 if (recordingActive) { | |
648 // Restore options. | |
649 options.choices[options.cursorUpdatesIndex] | |
650 .select(cursorUpdatesDef); | |
651 options.choices[options.cursorUpdatesIndex].setEnabled(true); | |
652 options.setEncodings(); | |
653 options.choices[options.eightBitColorsIndex] | |
654 .select(eightBitColorsDef); | |
655 options.choices[options.eightBitColorsIndex].setEnabled(true); | |
656 options.setColorFormat(); | |
657 | |
658 rfb.closeSession(); | |
659 System.out.println("Session recording stopped."); | |
660 } | |
661 sessionFileName = null; | |
662 recordingActive = false; | |
663 } | |
664 } | |
0 | 665 |
4 | 666 // |
667 // readParameters() - read parameters from the html source or from the | |
668 // command line. On the command line, the arguments are just a sequence of | |
669 // param_name/param_value pairs where the names and values correspond to | |
670 // those expected in the html applet tag source. | |
671 // | |
0 | 672 |
4 | 673 void readParameters() { |
18 | 674 host = readParameter("HOST", !inAnApplet); |
0 | 675 |
22 | 676 |
26 | 677 if (host == null) { host = getCodeBase().getHost(); |
678 if (host.equals("")) { | |
60 | 679 fatalError("HOST parameter not specified"); |
26 | 680 } |
681 } | |
22 | 682 |
18 | 683 port = readIntParameter("PORT", 5550); |
22 | 684 |
18 | 685 |
4 | 686 // Read "ENCPASSWORD" or "PASSWORD" parameter if specified. |
687 readPasswordParameters(); | |
688 | |
689 String str; | |
22 | 690 |
4 | 691 if (inAnApplet) { |
692 str = readParameter("Open New Window", false); | |
693 if (str != null && str.equalsIgnoreCase("Yes")) | |
694 inSeparateFrame = true; | |
695 } | |
0 | 696 |
22 | 697 |
4 | 698 // "Show Controls" set to "No" disables button panel. |
699 showControls = true; | |
700 str = readParameter("Show Controls", false); | |
701 if (str != null && str.equalsIgnoreCase("No")) | |
702 showControls = false; | |
0 | 703 |
4 | 704 // "Offer Relogin" set to "No" disables "Login again" and "Close |
705 // window" buttons under error messages in applet mode. | |
706 offerRelogin = true; | |
707 str = readParameter("Offer Relogin", false); | |
708 if (str != null && str.equalsIgnoreCase("No")) | |
709 offerRelogin = false; | |
710 | |
711 // Do we continue showing desktop on remote disconnect? | |
712 showOfflineDesktop = false; | |
713 str = readParameter("Show Offline Desktop", false); | |
714 if (str != null && str.equalsIgnoreCase("Yes")) | |
715 showOfflineDesktop = true; | |
0 | 716 |
4 | 717 // Fine tuning options. |
718 deferScreenUpdates = readIntParameter("Defer screen updates", 20); | |
719 deferCursorUpdates = readIntParameter("Defer cursor updates", 10); | |
720 deferUpdateRequests = readIntParameter("Defer update requests", 0); | |
0 | 721 |
4 | 722 // Debugging options. |
723 debugStatsExcludeUpdates = readIntParameter("DEBUG_XU", 0); | |
724 debugStatsMeasureUpdates = readIntParameter("DEBUG_CU", 0); | |
0 | 725 |
4 | 726 // SocketFactory. |
727 socketFactory = readParameter("SocketFactory", false); | |
728 } | |
0 | 729 |
4 | 730 // |
731 // Read password parameters. If an "ENCPASSWORD" parameter is set, | |
732 // then decrypt the password into the passwordParam string. Otherwise, | |
733 // try to read the "PASSWORD" parameter directly to passwordParam. | |
734 // | |
0 | 735 |
4 | 736 private void readPasswordParameters() { |
737 String encPasswordParam = readParameter("ENCPASSWORD", false); | |
738 if (encPasswordParam == null) { | |
739 passwordParam = readParameter("PASSWORD", false); | |
0 | 740 |
4 | 741 } else { |
742 // ENCPASSWORD is hexascii-encoded. Decode. | |
743 byte[] pw = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
744 int len = encPasswordParam.length() / 2; | |
745 if (len > 8) | |
746 len = 8; | |
747 for (int i = 0; i < len; i++) { | |
748 String hex = encPasswordParam.substring(i * 2, i * 2 + 2); | |
749 Integer x = new Integer(Integer.parseInt(hex, 16)); | |
750 pw[i] = x.byteValue(); | |
751 } | |
752 // Decrypt the password. | |
753 byte[] key = { 23, 82, 107, 6, 35, 78, 88, 7 }; | |
754 DesCipher des = new DesCipher(key); | |
755 des.decrypt(pw, 0, pw, 0); | |
756 passwordParam = new String(pw); | |
757 | |
758 } | |
759 } | |
0 | 760 |
4 | 761 public String readParameter(String name, boolean required) { |
762 if (inAnApplet) { | |
763 String s = getParameter(name); | |
764 if ((s == null) && required) { | |
765 fatalError(name + " parameter not specified"); | |
766 } | |
767 return s; | |
768 } | |
0 | 769 |
4 | 770 for (int i = 0; i < mainArgs.length; i += 2) { |
771 if (mainArgs[i].equalsIgnoreCase(name)) { | |
772 try { | |
773 return mainArgs[i + 1]; | |
774 } catch (Exception e) { | |
775 if (required) { | |
776 fatalError(name + " parameter not specified"); | |
777 } | |
778 return null; | |
779 } | |
780 } | |
781 } | |
782 if (required) { | |
783 fatalError(name + " parameter not specified"); | |
784 } | |
785 return null; | |
0 | 786 } |
4 | 787 |
788 int readIntParameter(String name, int defaultValue) { | |
789 String str = readParameter(name, false); | |
790 int result = defaultValue; | |
791 if (str != null) { | |
792 try { | |
793 result = Integer.parseInt(str); | |
794 } catch (NumberFormatException e) { | |
795 } | |
796 } | |
797 return result; | |
798 } | |
0 | 799 |
4 | 800 // |
801 // moveFocusToDesktop() - move keyboard focus either to VncCanvas. | |
802 // | |
0 | 803 |
4 | 804 void moveFocusToDesktop() { |
805 if (vncContainer != null) { | |
806 if (vc != null && vncContainer.isAncestorOf(vc)) | |
807 vc.requestFocus(); | |
808 } | |
809 } | |
0 | 810 |
4 | 811 // |
812 // disconnect() - close connection to server. | |
813 // | |
0 | 814 |
4 | 815 synchronized public void disconnect() { |
816 System.out.println("Disconnecting"); | |
0 | 817 |
4 | 818 if (vc != null) { |
819 double sec = (System.currentTimeMillis() - vc.statStartTime) / 1000.0; | |
820 double rate = Math.round(vc.statNumUpdates / sec * 100) / 100.0; | |
821 int nRealRects = vc.statNumPixelRects; | |
822 int nPseudoRects = vc.statNumTotalRects - vc.statNumPixelRects; | |
823 System.out.println("Updates received: " + vc.statNumUpdates + " (" | |
824 + nRealRects + " rectangles + " + nPseudoRects | |
825 + " pseudo), " + rate + " updates/sec"); | |
826 int numRectsOther = nRealRects - vc.statNumRectsTight | |
827 - vc.statNumRectsZRLE - vc.statNumRectsHextile | |
828 - vc.statNumRectsRaw - vc.statNumRectsCopy; | |
829 System.out.println("Rectangles:" + " Tight=" + vc.statNumRectsTight | |
830 + "(JPEG=" + vc.statNumRectsTightJPEG + ") ZRLE=" | |
831 + vc.statNumRectsZRLE + " Hextile=" | |
832 + vc.statNumRectsHextile + " Raw=" + vc.statNumRectsRaw | |
833 + " CopyRect=" + vc.statNumRectsCopy + " other=" | |
834 + numRectsOther); | |
0 | 835 |
4 | 836 int raw = vc.statNumBytesDecoded; |
837 int compressed = vc.statNumBytesEncoded; | |
838 if (compressed > 0) { | |
839 double ratio = Math.round((double) raw / compressed * 1000) / 1000.0; | |
840 System.out.println("Pixel data: " + vc.statNumBytesDecoded | |
841 + " bytes, " + vc.statNumBytesEncoded | |
842 + " compressed, ratio " + ratio); | |
843 } | |
844 } | |
0 | 845 |
4 | 846 if (rfb != null && !rfb.closed()) |
847 rfb.close(); | |
848 options.dispose(); | |
849 clipboard.dispose(); | |
850 if (rec != null) | |
851 rec.dispose(); | |
0 | 852 |
4 | 853 if (inAnApplet) { |
854 showMessage("Disconnected"); | |
855 } else { | |
856 System.exit(0); | |
857 } | |
858 } | |
859 | |
860 // | |
861 // fatalError() - print out a fatal error message. | |
862 // FIXME: Do we really need two versions of the fatalError() method? | |
863 // | |
864 | |
865 synchronized public void fatalError(String str) { | |
866 System.out.println(str); | |
0 | 867 |
4 | 868 if (inAnApplet) { |
869 // vncContainer null, applet not inited, | |
870 // can not present the error to the user. | |
871 Thread.currentThread().stop(); | |
872 } else { | |
873 System.exit(1); | |
874 } | |
875 } | |
0 | 876 |
4 | 877 synchronized public void fatalError(String str, Exception e) { |
0 | 878 |
4 | 879 if (rfb != null && rfb.closed()) { |
880 // Not necessary to show error message if the error was caused | |
881 // by I/O problems after the rfb.close() method call. | |
882 System.out.println("RFB thread finished"); | |
883 return; | |
884 } | |
885 | |
886 System.out.println(str); | |
887 e.printStackTrace(); | |
0 | 888 |
4 | 889 if (rfb != null) |
890 rfb.close(); | |
0 | 891 |
4 | 892 if (inAnApplet) { |
893 showMessage(str); | |
894 } else { | |
895 System.exit(1); | |
896 } | |
897 } | |
0 | 898 |
4 | 899 // |
900 // Show message text and optionally "Relogin" and "Close" buttons. | |
901 // | |
0 | 902 |
4 | 903 void showMessage(String msg) { |
904 vncContainer.removeAll(); | |
0 | 905 |
4 | 906 Label errLabel = new Label(msg, Label.CENTER); |
907 errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12)); | |
0 | 908 |
4 | 909 if (offerRelogin) { |
0 | 910 |
4 | 911 Panel gridPanel = new Panel(new GridLayout(0, 1)); |
912 Panel outerPanel = new Panel(new FlowLayout(FlowLayout.LEFT)); | |
913 outerPanel.add(gridPanel); | |
914 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 16)); | |
915 vncContainer.add(outerPanel); | |
916 Panel textPanel = new Panel(new FlowLayout(FlowLayout.CENTER)); | |
917 textPanel.add(errLabel); | |
918 gridPanel.add(textPanel); | |
919 gridPanel.add(new ReloginPanel(this)); | |
920 | |
921 } else { | |
0 | 922 |
4 | 923 vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30)); |
924 vncContainer.add(errLabel); | |
925 | |
926 } | |
0 | 927 |
4 | 928 if (inSeparateFrame) { |
929 vncFrame.pack(); | |
930 } else { | |
931 validate(); | |
932 } | |
933 } | |
0 | 934 |
4 | 935 // |
936 // Stop the applet. | |
937 // Main applet thread will terminate on first exception | |
938 // after seeing that rfbThread has been set to null. | |
939 // | |
0 | 940 |
4 | 941 public void stop() { |
942 System.out.println("Stopping applet"); | |
943 rfbThread = null; | |
944 } | |
0 | 945 |
4 | 946 // |
947 // This method is called before the applet is destroyed. | |
948 // | |
949 | |
950 public void destroy() { | |
951 System.out.println("Destroying applet"); | |
0 | 952 |
4 | 953 vncContainer.removeAll(); |
954 options.dispose(); | |
955 clipboard.dispose(); | |
956 if (rec != null) | |
957 rec.dispose(); | |
958 if (rfb != null && !rfb.closed()) | |
959 rfb.close(); | |
960 if (inSeparateFrame) | |
961 vncFrame.dispose(); | |
962 } | |
0 | 963 |
4 | 964 // |
965 // Start/stop receiving mouse events. | |
966 // | |
967 | |
968 public void enableInput(boolean enable) { | |
969 vc.enableInput(enable); | |
970 } | |
0 | 971 |
4 | 972 // |
973 // Close application properly on window close event. | |
974 // | |
0 | 975 |
4 | 976 public void windowClosing(WindowEvent evt) { |
977 System.out.println("Closing window"); | |
978 if (rfb != null) | |
979 disconnect(); | |
0 | 980 |
4 | 981 vncContainer.hide(); |
982 | |
983 if (!inAnApplet) { | |
984 System.exit(0); | |
985 } | |
986 } | |
0 | 987 |
4 | 988 // |
989 // Ignore window events we're not interested in. | |
990 // | |
0 | 991 |
4 | 992 public void windowActivated(WindowEvent evt) { |
993 } | |
994 | |
995 public void windowDeactivated(WindowEvent evt) { | |
996 } | |
0 | 997 |
4 | 998 public void windowOpened(WindowEvent evt) { |
999 } | |
1000 | |
1001 public void windowClosed(WindowEvent evt) { | |
1002 } | |
0 | 1003 |
4 | 1004 public void windowIconified(WindowEvent evt) { |
1005 } | |
1006 | |
1007 public void windowDeiconified(WindowEvent evt) { | |
1008 } | |
0 | 1009 } |