From 903009eca89d779b78201c0015073d60f80c6306 Mon Sep 17 00:00:00 2001 From: Constantin Kaplinsky Date: Mon, 20 May 2002 10:55:47 +0000 Subject: [PATCH] Preliminary version of RFB Session Player converted from TightVNC Java viewer sources. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2500 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- .../src/com/tightvnc/rfbplayer/AuthPanel.java | 116 --- .../com/tightvnc/rfbplayer/ButtonPanel.java | 123 +-- .../tightvnc/rfbplayer/ClipboardFrame.java | 133 --- .../src/com/tightvnc/rfbplayer/DesCipher.java | 496 ----------- .../tightvnc/rfbplayer/FbsInputStream.java | 174 ++++ java/src/com/tightvnc/rfbplayer/Makefile | 22 +- .../com/tightvnc/rfbplayer/OptionsFrame.java | 387 --------- java/src/com/tightvnc/rfbplayer/README | 283 +------ .../src/com/tightvnc/rfbplayer/RfbPlayer.java | 353 ++------ java/src/com/tightvnc/rfbplayer/RfbProto.java | 424 +-------- .../src/com/tightvnc/rfbplayer/VncCanvas.java | 801 ++++-------------- java/src/com/tightvnc/rfbplayer/dir.mk | 20 - java/src/com/tightvnc/rfbplayer/hextile.vnc | 19 - java/src/com/tightvnc/rfbplayer/index.html | 9 + java/src/com/tightvnc/rfbplayer/index.vnc | 17 - java/src/com/tightvnc/rfbplayer/noshared.vnc | 17 - java/src/com/tightvnc/rfbplayer/shared.vnc | 17 - java/src/com/tightvnc/rfbplayer/tight.vnc | 18 - java/src/com/tightvnc/rfbplayer/zlib.vnc | 18 - 19 files changed, 482 insertions(+), 2965 deletions(-) delete mode 100644 java/src/com/tightvnc/rfbplayer/AuthPanel.java delete mode 100644 java/src/com/tightvnc/rfbplayer/ClipboardFrame.java delete mode 100644 java/src/com/tightvnc/rfbplayer/DesCipher.java create mode 100644 java/src/com/tightvnc/rfbplayer/FbsInputStream.java delete mode 100644 java/src/com/tightvnc/rfbplayer/OptionsFrame.java delete mode 100644 java/src/com/tightvnc/rfbplayer/dir.mk delete mode 100644 java/src/com/tightvnc/rfbplayer/hextile.vnc create mode 100644 java/src/com/tightvnc/rfbplayer/index.html delete mode 100644 java/src/com/tightvnc/rfbplayer/index.vnc delete mode 100644 java/src/com/tightvnc/rfbplayer/noshared.vnc delete mode 100644 java/src/com/tightvnc/rfbplayer/shared.vnc delete mode 100644 java/src/com/tightvnc/rfbplayer/tight.vnc delete mode 100644 java/src/com/tightvnc/rfbplayer/zlib.vnc diff --git a/java/src/com/tightvnc/rfbplayer/AuthPanel.java b/java/src/com/tightvnc/rfbplayer/AuthPanel.java deleted file mode 100644 index cdc4fe8c..00000000 --- a/java/src/com/tightvnc/rfbplayer/AuthPanel.java +++ /dev/null @@ -1,116 +0,0 @@ -// -// 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. -// - -import java.awt.*; -import java.awt.event.*; - -// -// The panel which implements the user authentication scheme -// - -class AuthPanel extends Panel implements ActionListener { - - Label title, retry, prompt; - TextField password; - Button ok; - - // - // Constructor. - // - - public AuthPanel() { - - title = new Label("VNC Authentication",Label.CENTER); - title.setFont(new Font("Helvetica", Font.BOLD, 18)); - - prompt = new Label("Password:",Label.CENTER); - - password = new TextField(10); - password.setForeground(Color.black); - password.setBackground(Color.white); - password.setEchoChar('*'); - - ok = new Button("OK"); - - retry = new Label("",Label.CENTER); - retry.setFont(new Font("Courier", Font.BOLD, 16)); - - - GridBagLayout gridbag = new GridBagLayout(); - GridBagConstraints gbc = new GridBagConstraints(); - - setLayout(gridbag); - - gbc.gridwidth = GridBagConstraints.REMAINDER; - gridbag.setConstraints(title,gbc); - add(title); - - gbc.fill = GridBagConstraints.HORIZONTAL; - gridbag.setConstraints(retry,gbc); - add(retry); - - gbc.fill = GridBagConstraints.NONE; - gbc.gridwidth = 1; - gridbag.setConstraints(prompt,gbc); - add(prompt); - - gridbag.setConstraints(password,gbc); - add(password); - password.addActionListener(this); - - gbc.ipady = 10; - gbc.gridwidth = GridBagConstraints.REMAINDER; - gbc.fill = GridBagConstraints.BOTH; - gbc.insets = new Insets(0,20,0,0); - gbc.ipadx = 40; - gridbag.setConstraints(ok,gbc); - add(ok); - ok.addActionListener(this); - } - - // - // Move keyboard focus to the password text field object. - // - - public void moveFocusToPasswordField() { - password.requestFocus(); - } - - // - // This method is called when a button is pressed or return is - // pressed in the password text field. - // - - public synchronized void actionPerformed(ActionEvent evt) { - if (evt.getSource() == password || evt.getSource() == ok) { - notify(); - } - } - - // - // retry(). - // - - public void retry() { - retry.setText("Sorry. Try again."); - password.setText(""); - moveFocusToPasswordField(); - } - -} diff --git a/java/src/com/tightvnc/rfbplayer/ButtonPanel.java b/java/src/com/tightvnc/rfbplayer/ButtonPanel.java index de3ddfee..e7cabb58 100644 --- a/java/src/com/tightvnc/rfbplayer/ButtonPanel.java +++ b/java/src/com/tightvnc/rfbplayer/ButtonPanel.java @@ -1,6 +1,5 @@ // -// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved. -// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +// Copyright (C) 2002 HorizonLive.com, Inc. 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 @@ -18,62 +17,55 @@ // USA. // -// -// ButtonPanel class implements panel with four buttons in the -// VNCViewer desktop window. -// - import java.awt.*; import java.awt.event.*; import java.io.*; class ButtonPanel extends Panel implements ActionListener { - VncViewer viewer; - Button disconnectButton; - Button optionsButton; - Button clipboardButton; - Button ctrlAltDelButton; - Button refreshButton; + protected RfbPlayer player; + protected Button playButton; + protected Button pauseButton; - ButtonPanel(VncViewer v) { - viewer = v; + ButtonPanel(RfbPlayer player) { + this.player = player; setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); - disconnectButton = new Button("Disconnect"); - disconnectButton.setEnabled(false); - add(disconnectButton); - disconnectButton.addActionListener(this); - optionsButton = new Button("Options"); - add(optionsButton); - optionsButton.addActionListener(this); - clipboardButton = new Button("Clipboard"); - clipboardButton.setEnabled(false); - add(clipboardButton); - clipboardButton.addActionListener(this); - ctrlAltDelButton = new Button("Send Ctrl-Alt-Del"); - ctrlAltDelButton.setEnabled(false); - add(ctrlAltDelButton); - ctrlAltDelButton.addActionListener(this); - refreshButton = new Button("Refresh"); - refreshButton.setEnabled(false); - add(refreshButton); - refreshButton.addActionListener(this); - } - public void enableButtons() { - disconnectButton.setEnabled(true); - clipboardButton.setEnabled(true); - refreshButton.setEnabled(true); - } + playButton = new Button("Play"); + playButton.setEnabled(false); + add(playButton); + playButton.addActionListener(this); - // - // Enable/disable controls that should not be available in view-only - // mode. - // + pauseButton = new Button("Pause"); + pauseButton.setEnabled(false); + add(pauseButton); + pauseButton.addActionListener(this); + } - void enableRemoteAccessControls(boolean enable) { - ctrlAltDelButton.setEnabled(enable); + public void setMode(int mode) { + switch(mode) { + case RfbPlayer.MODE_PLAYBACK: + playButton.setLabel("Stop"); + playButton.setEnabled(true); + pauseButton.setLabel("Pause"); + pauseButton.setEnabled(true); + break; + case RfbPlayer.MODE_PAUSED: + playButton.setLabel("Stop"); + playButton.setEnabled(true); + pauseButton.setLabel("Resume"); + pauseButton.setEnabled(true); + break; + default: + // case RfbPlayer.MODE_STOPPED: + playButton.setLabel("Play"); + playButton.setEnabled(true); + pauseButton.setLabel("Pause"); + pauseButton.setEnabled(false); + break; + } + player.setMode(mode); } // @@ -81,40 +73,13 @@ class ButtonPanel extends Panel implements ActionListener { // public void actionPerformed(ActionEvent evt) { - if (evt.getSource() == disconnectButton) { - viewer.disconnect(); - - } else if (evt.getSource() == optionsButton) { - viewer.options.setVisible(!viewer.options.isVisible()); - - } else if (evt.getSource() == clipboardButton) { - viewer.clipboard.setVisible(!viewer.clipboard.isVisible()); - - } else if (evt.getSource() == ctrlAltDelButton) { - try { - final int modifiers = InputEvent.CTRL_MASK | InputEvent.ALT_MASK; - - KeyEvent ctrlAltDelEvent = - new KeyEvent(this, KeyEvent.KEY_PRESSED, 0, modifiers, 127); - viewer.rfb.writeKeyEvent(ctrlAltDelEvent); - - ctrlAltDelEvent = - new KeyEvent(this, KeyEvent.KEY_RELEASED, 0, modifiers, 127); - viewer.rfb.writeKeyEvent(ctrlAltDelEvent); - - } catch (IOException e) { - e.printStackTrace(); - } - } else if (evt.getSource() == refreshButton) { - try { - RfbProto rfb = viewer.rfb; - rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth, - rfb.framebufferHeight, false); - } catch (IOException e) { - e.printStackTrace(); - } + if (evt.getSource() == playButton) { + setMode((player.getMode() == RfbPlayer.MODE_STOPPED) ? + RfbPlayer.MODE_PLAYBACK : RfbPlayer.MODE_STOPPED); + } else if (evt.getSource() == pauseButton) { + setMode((player.getMode() == RfbPlayer.MODE_PAUSED) ? + RfbPlayer.MODE_PLAYBACK : RfbPlayer.MODE_PAUSED); } - viewer.moveFocusToDesktop(); } } diff --git a/java/src/com/tightvnc/rfbplayer/ClipboardFrame.java b/java/src/com/tightvnc/rfbplayer/ClipboardFrame.java deleted file mode 100644 index f0a5b8df..00000000 --- a/java/src/com/tightvnc/rfbplayer/ClipboardFrame.java +++ /dev/null @@ -1,133 +0,0 @@ -// -// Copyright (C) 2001 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. -// - -// -// Clipboard frame. -// - -import java.awt.*; -import java.awt.event.*; - -class ClipboardFrame extends Frame - implements WindowListener, ActionListener { - - TextArea textArea; - Button clearButton, closeButton; - String selection; - VncViewer viewer; - - // - // Constructor. - // - - ClipboardFrame(VncViewer v) { - super("TightVNC Clipboard"); - - viewer = v; - - GridBagLayout gridbag = new GridBagLayout(); - setLayout(gridbag); - - GridBagConstraints gbc = new GridBagConstraints(); - gbc.gridwidth = GridBagConstraints.REMAINDER; - gbc.fill = GridBagConstraints.BOTH; - gbc.weighty = 1.0; - - textArea = new TextArea(5, 40); - gridbag.setConstraints(textArea, gbc); - add(textArea); - - gbc.fill = GridBagConstraints.HORIZONTAL; - gbc.weightx = 1.0; - gbc.weighty = 0.0; - gbc.gridwidth = 1; - - clearButton = new Button("Clear"); - gridbag.setConstraints(clearButton, gbc); - add(clearButton); - clearButton.addActionListener(this); - - closeButton = new Button("Close"); - gridbag.setConstraints(closeButton, gbc); - add(closeButton); - closeButton.addActionListener(this); - - pack(); - - addWindowListener(this); - } - - - // - // Set the cut text from the RFB server. - // - - void setCutText(String text) { - selection = text; - textArea.setText(text); - if (isVisible()) { - textArea.selectAll(); - } - } - - - // - // When the focus leaves the window, see if we have new cut text and - // if so send it to the RFB server. - // - - public void windowDeactivated (WindowEvent evt) { - if (selection != null && !selection.equals(textArea.getText())) { - selection = textArea.getText(); - viewer.setCutText(selection); - } - } - - // - // Close our window properly. - // - - public void windowClosing(WindowEvent evt) { - setVisible(false); - } - - // - // Ignore window events we're not interested in. - // - - public void windowActivated(WindowEvent evt) {} - public void windowOpened(WindowEvent evt) {} - public void windowClosed(WindowEvent evt) {} - public void windowIconified(WindowEvent evt) {} - public void windowDeiconified(WindowEvent evt) {} - - - // - // Respond to button presses - // - - public void actionPerformed(ActionEvent evt) { - if (evt.getSource() == clearButton) { - textArea.setText(""); - } else if (evt.getSource() == closeButton) { - setVisible(false); - } - } -} diff --git a/java/src/com/tightvnc/rfbplayer/DesCipher.java b/java/src/com/tightvnc/rfbplayer/DesCipher.java deleted file mode 100644 index 2b7b5f22..00000000 --- a/java/src/com/tightvnc/rfbplayer/DesCipher.java +++ /dev/null @@ -1,496 +0,0 @@ -// -// This DES class has been extracted from package Acme.Crypto for use in VNC. -// The bytebit[] array has been reversed so that the most significant bit -// in each byte of the key is ignored, not the least significant. Also the -// unnecessary odd parity code has been removed. -// -// These changes are: -// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. -// -// 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. -// - -// DesCipher - the DES encryption method -// -// The meat of this code is by Dave Zimmerman , and is: -// -// Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved. -// -// Permission to use, copy, modify, and distribute this software -// and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and -// without fee is hereby granted, provided that this copyright notice is kept -// intact. -// -// WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY -// OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE -// FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR -// DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. -// -// THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE -// CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE -// PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT -// NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE -// SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE -// SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE -// PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP -// SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR -// HIGH RISK ACTIVITIES. -// -// -// The rest is: -// -// Copyright (C) 1996 by Jef Poskanzer . All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. -// -// Visit the ACME Labs Java page for up-to-date versions of this and other -// fine Java utilities: http://www.acme.com/java/ - - -import java.io.*; - -/// The DES encryption method. -//

-// This is surprisingly fast, for pure Java. On a SPARC 20, wrapped -// in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream, -// it does around 7000 bytes/second. -//

-// Most of this code is by Dave Zimmerman , and is -// Copyright (c) 1996 Widget Workshop, Inc. See the source file for details. -//

-// Fetch the software.
-// Fetch the entire Acme package. -//

-// @see Des3Cipher -// @see EncryptedOutputStream -// @see EncryptedInputStream - -public class DesCipher - { - - // Constructor, byte-array key. - public DesCipher( byte[] key ) - { - setKey( key ); - } - - // Key routines. - - private int[] encryptKeys = new int[32]; - private int[] decryptKeys = new int[32]; - - /// Set the key. - public void setKey( byte[] key ) - { - deskey( key, true, encryptKeys ); - deskey( key, false, decryptKeys ); - } - - // Turn an 8-byte key into internal keys. - private void deskey( byte[] keyBlock, boolean encrypting, int[] KnL ) - { - int i, j, l, m, n; - int[] pc1m = new int[56]; - int[] pcr = new int[56]; - int[] kn = new int[32]; - - for ( j = 0; j < 56; ++j ) - { - l = pc1[j]; - m = l & 07; - pc1m[j] = ( (keyBlock[l >>> 3] & bytebit[m]) != 0 )? 1: 0; - } - - for ( i = 0; i < 16; ++i ) - { - if ( encrypting ) - m = i << 1; - else - m = (15-i) << 1; - n = m+1; - kn[m] = kn[n] = 0; - for ( j = 0; j < 28; ++j ) - { - l = j+totrot[i]; - if ( l < 28 ) - pcr[j] = pc1m[l]; - else - pcr[j] = pc1m[l-28]; - } - for ( j=28; j < 56; ++j ) - { - l = j+totrot[i]; - if ( l < 56 ) - pcr[j] = pc1m[l]; - else - pcr[j] = pc1m[l-28]; - } - for ( j = 0; j < 24; ++j ) - { - if ( pcr[pc2[j]] != 0 ) - kn[m] |= bigbyte[j]; - if ( pcr[pc2[j+24]] != 0 ) - kn[n] |= bigbyte[j]; - } - } - cookey( kn, KnL ); - } - - private void cookey( int[] raw, int KnL[] ) - { - int raw0, raw1; - int rawi, KnLi; - int i; - - for ( i = 0, rawi = 0, KnLi = 0; i < 16; ++i ) - { - raw0 = raw[rawi++]; - raw1 = raw[rawi++]; - KnL[KnLi] = (raw0 & 0x00fc0000) << 6; - KnL[KnLi] |= (raw0 & 0x00000fc0) << 10; - KnL[KnLi] |= (raw1 & 0x00fc0000) >>> 10; - KnL[KnLi] |= (raw1 & 0x00000fc0) >>> 6; - ++KnLi; - KnL[KnLi] = (raw0 & 0x0003f000) << 12; - KnL[KnLi] |= (raw0 & 0x0000003f) << 16; - KnL[KnLi] |= (raw1 & 0x0003f000) >>> 4; - KnL[KnLi] |= (raw1 & 0x0000003f); - ++KnLi; - } - } - - - // Block encryption routines. - - private int[] tempInts = new int[2]; - - /// Encrypt a block of eight bytes. - public void encrypt( byte[] clearText, int clearOff, byte[] cipherText, int cipherOff ) - { - squashBytesToInts( clearText, clearOff, tempInts, 0, 2 ); - des( tempInts, tempInts, encryptKeys ); - spreadIntsToBytes( tempInts, 0, cipherText, cipherOff, 2 ); - } - - /// Decrypt a block of eight bytes. - public void decrypt( byte[] cipherText, int cipherOff, byte[] clearText, int clearOff ) - { - squashBytesToInts( cipherText, cipherOff, tempInts, 0, 2 ); - des( tempInts, tempInts, decryptKeys ); - spreadIntsToBytes( tempInts, 0, clearText, clearOff, 2 ); - } - - // The DES function. - private void des( int[] inInts, int[] outInts, int[] keys ) - { - int fval, work, right, leftt; - int round; - int keysi = 0; - - leftt = inInts[0]; - right = inInts[1]; - - work = ((leftt >>> 4) ^ right) & 0x0f0f0f0f; - right ^= work; - leftt ^= (work << 4); - - work = ((leftt >>> 16) ^ right) & 0x0000ffff; - right ^= work; - leftt ^= (work << 16); - - work = ((right >>> 2) ^ leftt) & 0x33333333; - leftt ^= work; - right ^= (work << 2); - - work = ((right >>> 8) ^ leftt) & 0x00ff00ff; - leftt ^= work; - right ^= (work << 8); - right = (right << 1) | ((right >>> 31) & 1); - - work = (leftt ^ right) & 0xaaaaaaaa; - leftt ^= work; - right ^= work; - leftt = (leftt << 1) | ((leftt >>> 31) & 1); - - for ( round = 0; round < 8; ++round ) - { - work = (right << 28) | (right >>> 4); - work ^= keys[keysi++]; - fval = SP7[ work & 0x0000003f ]; - fval |= SP5[(work >>> 8) & 0x0000003f ]; - fval |= SP3[(work >>> 16) & 0x0000003f ]; - fval |= SP1[(work >>> 24) & 0x0000003f ]; - work = right ^ keys[keysi++]; - fval |= SP8[ work & 0x0000003f ]; - fval |= SP6[(work >>> 8) & 0x0000003f ]; - fval |= SP4[(work >>> 16) & 0x0000003f ]; - fval |= SP2[(work >>> 24) & 0x0000003f ]; - leftt ^= fval; - work = (leftt << 28) | (leftt >>> 4); - work ^= keys[keysi++]; - fval = SP7[ work & 0x0000003f ]; - fval |= SP5[(work >>> 8) & 0x0000003f ]; - fval |= SP3[(work >>> 16) & 0x0000003f ]; - fval |= SP1[(work >>> 24) & 0x0000003f ]; - work = leftt ^ keys[keysi++]; - fval |= SP8[ work & 0x0000003f ]; - fval |= SP6[(work >>> 8) & 0x0000003f ]; - fval |= SP4[(work >>> 16) & 0x0000003f ]; - fval |= SP2[(work >>> 24) & 0x0000003f ]; - right ^= fval; - } - - right = (right << 31) | (right >>> 1); - work = (leftt ^ right) & 0xaaaaaaaa; - leftt ^= work; - right ^= work; - leftt = (leftt << 31) | (leftt >>> 1); - work = ((leftt >>> 8) ^ right) & 0x00ff00ff; - right ^= work; - leftt ^= (work << 8); - work = ((leftt >>> 2) ^ right) & 0x33333333; - right ^= work; - leftt ^= (work << 2); - work = ((right >>> 16) ^ leftt) & 0x0000ffff; - leftt ^= work; - right ^= (work << 16); - work = ((right >>> 4) ^ leftt) & 0x0f0f0f0f; - leftt ^= work; - right ^= (work << 4); - outInts[0] = right; - outInts[1] = leftt; - } - - - // Tables, permutations, S-boxes, etc. - - private static byte[] bytebit = { - (byte)0x01, (byte)0x02, (byte)0x04, (byte)0x08, - (byte)0x10, (byte)0x20, (byte)0x40, (byte)0x80 - }; - private static int[] bigbyte = { - 0x800000, 0x400000, 0x200000, 0x100000, - 0x080000, 0x040000, 0x020000, 0x010000, - 0x008000, 0x004000, 0x002000, 0x001000, - 0x000800, 0x000400, 0x000200, 0x000100, - 0x000080, 0x000040, 0x000020, 0x000010, - 0x000008, 0x000004, 0x000002, 0x000001 - }; - private static byte[] pc1 = { - (byte)56, (byte)48, (byte)40, (byte)32, (byte)24, (byte)16, (byte) 8, - (byte) 0, (byte)57, (byte)49, (byte)41, (byte)33, (byte)25, (byte)17, - (byte) 9, (byte) 1, (byte)58, (byte)50, (byte)42, (byte)34, (byte)26, - (byte)18, (byte)10, (byte) 2, (byte)59, (byte)51, (byte)43, (byte)35, - (byte)62, (byte)54, (byte)46, (byte)38, (byte)30, (byte)22, (byte)14, - (byte) 6, (byte)61, (byte)53, (byte)45, (byte)37, (byte)29, (byte)21, - (byte)13, (byte) 5, (byte)60, (byte)52, (byte)44, (byte)36, (byte)28, - (byte)20, (byte)12, (byte) 4, (byte)27, (byte)19, (byte)11, (byte)3 - }; - private static int[] totrot = { - 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 - }; - - private static byte[] pc2 = { - (byte)13, (byte)16, (byte)10, (byte)23, (byte) 0, (byte) 4, - (byte) 2, (byte)27, (byte)14, (byte) 5, (byte)20, (byte) 9, - (byte)22, (byte)18, (byte)11, (byte)3 , (byte)25, (byte) 7, - (byte)15, (byte) 6, (byte)26, (byte)19, (byte)12, (byte) 1, - (byte)40, (byte)51, (byte)30, (byte)36, (byte)46, (byte)54, - (byte)29, (byte)39, (byte)50, (byte)44, (byte)32, (byte)47, - (byte)43, (byte)48, (byte)38, (byte)55, (byte)33, (byte)52, - (byte)45, (byte)41, (byte)49, (byte)35, (byte)28, (byte)31, - }; - - private static int[] SP1 = { - 0x01010400, 0x00000000, 0x00010000, 0x01010404, - 0x01010004, 0x00010404, 0x00000004, 0x00010000, - 0x00000400, 0x01010400, 0x01010404, 0x00000400, - 0x01000404, 0x01010004, 0x01000000, 0x00000004, - 0x00000404, 0x01000400, 0x01000400, 0x00010400, - 0x00010400, 0x01010000, 0x01010000, 0x01000404, - 0x00010004, 0x01000004, 0x01000004, 0x00010004, - 0x00000000, 0x00000404, 0x00010404, 0x01000000, - 0x00010000, 0x01010404, 0x00000004, 0x01010000, - 0x01010400, 0x01000000, 0x01000000, 0x00000400, - 0x01010004, 0x00010000, 0x00010400, 0x01000004, - 0x00000400, 0x00000004, 0x01000404, 0x00010404, - 0x01010404, 0x00010004, 0x01010000, 0x01000404, - 0x01000004, 0x00000404, 0x00010404, 0x01010400, - 0x00000404, 0x01000400, 0x01000400, 0x00000000, - 0x00010004, 0x00010400, 0x00000000, 0x01010004 - }; - private static int[] SP2 = { - 0x80108020, 0x80008000, 0x00008000, 0x00108020, - 0x00100000, 0x00000020, 0x80100020, 0x80008020, - 0x80000020, 0x80108020, 0x80108000, 0x80000000, - 0x80008000, 0x00100000, 0x00000020, 0x80100020, - 0x00108000, 0x00100020, 0x80008020, 0x00000000, - 0x80000000, 0x00008000, 0x00108020, 0x80100000, - 0x00100020, 0x80000020, 0x00000000, 0x00108000, - 0x00008020, 0x80108000, 0x80100000, 0x00008020, - 0x00000000, 0x00108020, 0x80100020, 0x00100000, - 0x80008020, 0x80100000, 0x80108000, 0x00008000, - 0x80100000, 0x80008000, 0x00000020, 0x80108020, - 0x00108020, 0x00000020, 0x00008000, 0x80000000, - 0x00008020, 0x80108000, 0x00100000, 0x80000020, - 0x00100020, 0x80008020, 0x80000020, 0x00100020, - 0x00108000, 0x00000000, 0x80008000, 0x00008020, - 0x80000000, 0x80100020, 0x80108020, 0x00108000 - }; - private static int[] SP3 = { - 0x00000208, 0x08020200, 0x00000000, 0x08020008, - 0x08000200, 0x00000000, 0x00020208, 0x08000200, - 0x00020008, 0x08000008, 0x08000008, 0x00020000, - 0x08020208, 0x00020008, 0x08020000, 0x00000208, - 0x08000000, 0x00000008, 0x08020200, 0x00000200, - 0x00020200, 0x08020000, 0x08020008, 0x00020208, - 0x08000208, 0x00020200, 0x00020000, 0x08000208, - 0x00000008, 0x08020208, 0x00000200, 0x08000000, - 0x08020200, 0x08000000, 0x00020008, 0x00000208, - 0x00020000, 0x08020200, 0x08000200, 0x00000000, - 0x00000200, 0x00020008, 0x08020208, 0x08000200, - 0x08000008, 0x00000200, 0x00000000, 0x08020008, - 0x08000208, 0x00020000, 0x08000000, 0x08020208, - 0x00000008, 0x00020208, 0x00020200, 0x08000008, - 0x08020000, 0x08000208, 0x00000208, 0x08020000, - 0x00020208, 0x00000008, 0x08020008, 0x00020200 - }; - private static int[] SP4 = { - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802080, 0x00800081, 0x00800001, 0x00002001, - 0x00000000, 0x00802000, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00800080, 0x00800001, - 0x00000001, 0x00002000, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002001, 0x00002080, - 0x00800081, 0x00000001, 0x00002080, 0x00800080, - 0x00002000, 0x00802080, 0x00802081, 0x00000081, - 0x00800080, 0x00800001, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00000000, 0x00802000, - 0x00002080, 0x00800080, 0x00800081, 0x00000001, - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802081, 0x00000081, 0x00000001, 0x00002000, - 0x00800001, 0x00002001, 0x00802080, 0x00800081, - 0x00002001, 0x00002080, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002000, 0x00802080 - }; - private static int[] SP5 = { - 0x00000100, 0x02080100, 0x02080000, 0x42000100, - 0x00080000, 0x00000100, 0x40000000, 0x02080000, - 0x40080100, 0x00080000, 0x02000100, 0x40080100, - 0x42000100, 0x42080000, 0x00080100, 0x40000000, - 0x02000000, 0x40080000, 0x40080000, 0x00000000, - 0x40000100, 0x42080100, 0x42080100, 0x02000100, - 0x42080000, 0x40000100, 0x00000000, 0x42000000, - 0x02080100, 0x02000000, 0x42000000, 0x00080100, - 0x00080000, 0x42000100, 0x00000100, 0x02000000, - 0x40000000, 0x02080000, 0x42000100, 0x40080100, - 0x02000100, 0x40000000, 0x42080000, 0x02080100, - 0x40080100, 0x00000100, 0x02000000, 0x42080000, - 0x42080100, 0x00080100, 0x42000000, 0x42080100, - 0x02080000, 0x00000000, 0x40080000, 0x42000000, - 0x00080100, 0x02000100, 0x40000100, 0x00080000, - 0x00000000, 0x40080000, 0x02080100, 0x40000100 - }; - private static int[] SP6 = { - 0x20000010, 0x20400000, 0x00004000, 0x20404010, - 0x20400000, 0x00000010, 0x20404010, 0x00400000, - 0x20004000, 0x00404010, 0x00400000, 0x20000010, - 0x00400010, 0x20004000, 0x20000000, 0x00004010, - 0x00000000, 0x00400010, 0x20004010, 0x00004000, - 0x00404000, 0x20004010, 0x00000010, 0x20400010, - 0x20400010, 0x00000000, 0x00404010, 0x20404000, - 0x00004010, 0x00404000, 0x20404000, 0x20000000, - 0x20004000, 0x00000010, 0x20400010, 0x00404000, - 0x20404010, 0x00400000, 0x00004010, 0x20000010, - 0x00400000, 0x20004000, 0x20000000, 0x00004010, - 0x20000010, 0x20404010, 0x00404000, 0x20400000, - 0x00404010, 0x20404000, 0x00000000, 0x20400010, - 0x00000010, 0x00004000, 0x20400000, 0x00404010, - 0x00004000, 0x00400010, 0x20004010, 0x00000000, - 0x20404000, 0x20000000, 0x00400010, 0x20004010 - }; - private static int[] SP7 = { - 0x00200000, 0x04200002, 0x04000802, 0x00000000, - 0x00000800, 0x04000802, 0x00200802, 0x04200800, - 0x04200802, 0x00200000, 0x00000000, 0x04000002, - 0x00000002, 0x04000000, 0x04200002, 0x00000802, - 0x04000800, 0x00200802, 0x00200002, 0x04000800, - 0x04000002, 0x04200000, 0x04200800, 0x00200002, - 0x04200000, 0x00000800, 0x00000802, 0x04200802, - 0x00200800, 0x00000002, 0x04000000, 0x00200800, - 0x04000000, 0x00200800, 0x00200000, 0x04000802, - 0x04000802, 0x04200002, 0x04200002, 0x00000002, - 0x00200002, 0x04000000, 0x04000800, 0x00200000, - 0x04200800, 0x00000802, 0x00200802, 0x04200800, - 0x00000802, 0x04000002, 0x04200802, 0x04200000, - 0x00200800, 0x00000000, 0x00000002, 0x04200802, - 0x00000000, 0x00200802, 0x04200000, 0x00000800, - 0x04000002, 0x04000800, 0x00000800, 0x00200002 - }; - private static int[] SP8 = { - 0x10001040, 0x00001000, 0x00040000, 0x10041040, - 0x10000000, 0x10001040, 0x00000040, 0x10000000, - 0x00040040, 0x10040000, 0x10041040, 0x00041000, - 0x10041000, 0x00041040, 0x00001000, 0x00000040, - 0x10040000, 0x10000040, 0x10001000, 0x00001040, - 0x00041000, 0x00040040, 0x10040040, 0x10041000, - 0x00001040, 0x00000000, 0x00000000, 0x10040040, - 0x10000040, 0x10001000, 0x00041040, 0x00040000, - 0x00041040, 0x00040000, 0x10041000, 0x00001000, - 0x00000040, 0x10040040, 0x00001000, 0x00041040, - 0x10001000, 0x00000040, 0x10000040, 0x10040000, - 0x10040040, 0x10000000, 0x00040000, 0x10001040, - 0x00000000, 0x10041040, 0x00040040, 0x10000040, - 0x10040000, 0x10001000, 0x10001040, 0x00000000, - 0x10041040, 0x00041000, 0x00041000, 0x00001040, - 0x00001040, 0x00040040, 0x10000000, 0x10041000 - }; - - // Routines taken from other parts of the Acme utilities. - - /// Squash bytes down to ints. - public static void squashBytesToInts( byte[] inBytes, int inOff, int[] outInts, int outOff, int intLen ) - { - for ( int i = 0; i < intLen; ++i ) - outInts[outOff + i] = - ( ( inBytes[inOff + i * 4 ] & 0xff ) << 24 ) | - ( ( inBytes[inOff + i * 4 + 1] & 0xff ) << 16 ) | - ( ( inBytes[inOff + i * 4 + 2] & 0xff ) << 8 ) | - ( inBytes[inOff + i * 4 + 3] & 0xff ); - } - - /// Spread ints into bytes. - public static void spreadIntsToBytes( int[] inInts, int inOff, byte[] outBytes, int outOff, int intLen ) - { - for ( int i = 0; i < intLen; ++i ) - { - outBytes[outOff + i * 4 ] = (byte) ( inInts[inOff + i] >>> 24 ); - outBytes[outOff + i * 4 + 1] = (byte) ( inInts[inOff + i] >>> 16 ); - outBytes[outOff + i * 4 + 2] = (byte) ( inInts[inOff + i] >>> 8 ); - outBytes[outOff + i * 4 + 3] = (byte) inInts[inOff + i]; - } - } - } diff --git a/java/src/com/tightvnc/rfbplayer/FbsInputStream.java b/java/src/com/tightvnc/rfbplayer/FbsInputStream.java new file mode 100644 index 00000000..fab854be --- /dev/null +++ b/java/src/com/tightvnc/rfbplayer/FbsInputStream.java @@ -0,0 +1,174 @@ +// +// Copyright (C) 2002 HorizonLive.com, Inc. 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. +// + +// +// FbsInputStream.java +// + +import java.io.*; + +class FbsInputStream extends InputStream { + + protected InputStream in; + protected long startTime; + protected long timeOffset; + + protected byte[] buffer; + protected int bufferSize; + protected int bufferPos; + + // + // Constructors. + // + + FbsInputStream() throws IOException { + throw new IOException("FbsInputStream: no such constructor"); + } + + FbsInputStream(InputStream in) throws IOException + { + this.in = in; + startTime = System.currentTimeMillis(); + timeOffset = 0; + + byte[] b = new byte[12]; + readFully(b); + + if (b[0] != 'F' || b[1] != 'B' || b[2] != 'S' || b[3] != ' ' || + b[4] != '0' || b[5] != '0' || b[6] != '1' || b[7] != '.' || + b[8] < '0' || b[8] > '9' || b[9] < '0' || b[9] > '9' || + b[10] < '0' || b[10] > '9' || b[11] != '\n') { + throw new IOException("Incorrect protocol version"); + } + + buffer = null; + bufferSize = 0; + bufferPos = 0; + } + + // + // Basic methods overriding InputStream's methods. + // + + public int read() throws IOException + { + while (bufferSize == 0) { + if (!fillBuffer()) + return -1; + } + bufferSize--; + return buffer[bufferPos++] & 0xFF; + } + + public int available() throws IOException + { + // FIXME: This will work incorrectly if our caller will wait until + // some amount of data is available when the buffer contains less + // data than then that. Current implementation never reads more + // data until the buffer is fully exhausted. + return bufferSize; + } + + public void close() throws IOException + { + in.close(); + in = null; + startTime = 0; + timeOffset = 0; + + buffer = null; + bufferSize = 0; + bufferPos = 0; + } + + // + // Methods providing additional functionality. + // + + public void resumeReading() + { + startTime = System.currentTimeMillis() - timeOffset; + } + + // + // Methods for internal use. + // + + private boolean fillBuffer() throws IOException + { + bufferSize = (int)readUnsigned32(); + if (bufferSize >= 0) { + int realSize = (bufferSize + 3) & 0xFFFFFFFC; + buffer = new byte[realSize]; + readFully(buffer); + bufferPos = 0; + + timeOffset = readUnsigned32(); + } + + if (bufferSize < 0 || timeOffset < 0) { + buffer = null; + bufferSize = 0; + bufferPos = 0; + return false; + } + + while (true) { + long timeDiff = startTime + timeOffset - System.currentTimeMillis(); + if (timeDiff <= 0) { + break; + } + try { + Thread.currentThread().sleep(timeDiff); + } catch (InterruptedException e) { + } + } + + return true; + } + + private long readUnsigned32() throws IOException + { + byte[] buf = new byte[4]; + if (!readFully(buf)) + return -1; + + return ((long)(buf[0] & 0xFF) << 24 | + (buf[1] & 0xFF) << 16 | + (buf[2] & 0xFF) << 8 | + (buf[3] & 0xFF)); + } + + private boolean readFully(byte[] b) throws IOException + { + int off = 0; + int len = b.length; + + while (off != len) { + int count = in.read(b, off, len - off); + if (count < 0) { + return false; + } + off += count; + } + + return true; + } +} + diff --git a/java/src/com/tightvnc/rfbplayer/Makefile b/java/src/com/tightvnc/rfbplayer/Makefile index 76dbca43..42d10474 100644 --- a/java/src/com/tightvnc/rfbplayer/Makefile +++ b/java/src/com/tightvnc/rfbplayer/Makefile @@ -3,24 +3,23 @@ # CP = cp +RM = rm JC = javac JAR = jar -ARCHIVE = VncViewer.jar -PAGES = index.vnc shared.vnc noshared.vnc hextile.vnc zlib.vnc tight.vnc -INSTALL_DIR = /usr/local/vnc/classes +ARCHIVE = RfbPlayer.jar +PAGES = index.html +INSTALL_DIR = ./classes -CLASSES = VncViewer.class RfbProto.class AuthPanel.class VncCanvas.class \ - OptionsFrame.class ClipboardFrame.class ButtonPanel.class \ - DesCipher.class +CLASSES = RfbPlayer.class RfbProto.class ButtonPanel.class VncCanvas.class \ + FbsInputStream.class -SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \ - OptionsFrame.java ClipboardFrame.java ButtonPanel.java \ - DesCipher.java +SOURCES = RfbPlayer.java RfbProto.java ButtonPanel.java VncCanvas.java \ + FbsInputStream.java all: $(CLASSES) $(ARCHIVE) $(CLASSES): $(SOURCES) - $(JC) -O $(SOURCES) + $(JC) -g $(SOURCES) $(ARCHIVE): $(CLASSES) $(JAR) cf $(ARCHIVE) $(CLASSES) @@ -28,8 +27,5 @@ $(ARCHIVE): $(CLASSES) install: $(CLASSES) $(ARCHIVE) $(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR) -export:: $(CLASSES) $(ARCHIVE) $(PAGES) - @$(ExportJavaClasses) - clean:: $(RM) *.class *.jar diff --git a/java/src/com/tightvnc/rfbplayer/OptionsFrame.java b/java/src/com/tightvnc/rfbplayer/OptionsFrame.java deleted file mode 100644 index 45e5ab6e..00000000 --- a/java/src/com/tightvnc/rfbplayer/OptionsFrame.java +++ /dev/null @@ -1,387 +0,0 @@ -// -// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved. -// Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved. -// Copyright (C) 2000 Tridia Corporation. 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. -// - -// -// Options frame. -// -// This deals with all the options the user can play with. -// It sets the encodings array and some booleans. -// - -import java.awt.*; -import java.awt.event.*; - -class OptionsFrame extends Frame - implements WindowListener, ActionListener, ItemListener { - - static String[] names = { - "Encoding", - "Compression level", - "JPEG image quality", - "Cursor shape updates", - "Use CopyRect", - "Restricted colors", - "Mouse buttons 2 and 3", - "View only", - "Share desktop", - }; - - static String[][] values = { - { "Raw", "RRE", "CoRRE", "Hextile", "Zlib", "Tight" }, - { "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, - { "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, - { "Enable", "Ignore", "Disable" }, - { "Yes", "No" }, - { "Yes", "No" }, - { "Normal", "Reversed" }, - { "Yes", "No" }, - { "Yes", "No" }, - }; - - final int - encodingIndex = 0, - compressLevelIndex = 1, - jpegQualityIndex = 2, - cursorUpdatesIndex = 3, - useCopyRectIndex = 4, - eightBitColorsIndex = 5, - mouseButtonIndex = 6, - viewOnlyIndex = 7, - shareDesktopIndex = 8; - - Label[] labels = new Label[names.length]; - Choice[] choices = new Choice[names.length]; - Button closeButton; - VncViewer viewer; - - - // - // The actual data which other classes look at: - // - - int[] encodings = new int[20]; - int nEncodings; - - int compressLevel; - int jpegQuality; - - boolean eightBitColors; - - boolean requestCursorUpdates; - boolean ignoreCursorUpdates; - - boolean reverseMouseButtons2And3; - boolean shareDesktop; - boolean viewOnly; - boolean showControls; - - // - // Constructor. Set up the labels and choices from the names and values - // arrays. - // - - OptionsFrame(VncViewer v) { - super("TightVNC Options"); - - viewer = v; - - GridBagLayout gridbag = new GridBagLayout(); - setLayout(gridbag); - - GridBagConstraints gbc = new GridBagConstraints(); - gbc.fill = GridBagConstraints.BOTH; - - for (int i = 0; i < names.length; i++) { - labels[i] = new Label(names[i]); - gbc.gridwidth = 1; - gridbag.setConstraints(labels[i],gbc); - add(labels[i]); - - choices[i] = new Choice(); - gbc.gridwidth = GridBagConstraints.REMAINDER; - gridbag.setConstraints(choices[i],gbc); - add(choices[i]); - choices[i].addItemListener(this); - - for (int j = 0; j < values[i].length; j++) { - choices[i].addItem(values[i][j]); - } - } - - closeButton = new Button("Close"); - gbc.gridwidth = GridBagConstraints.REMAINDER; - gridbag.setConstraints(closeButton, gbc); - add(closeButton); - closeButton.addActionListener(this); - - pack(); - - addWindowListener(this); - - // Set up defaults - - choices[encodingIndex].select("Tight"); - choices[compressLevelIndex].select("Default"); - choices[jpegQualityIndex].select("6"); - choices[cursorUpdatesIndex].select("Enable"); - choices[useCopyRectIndex].select("Yes"); - choices[eightBitColorsIndex].select("No"); - choices[mouseButtonIndex].select("Normal"); - choices[viewOnlyIndex].select("No"); - choices[shareDesktopIndex].select("Yes"); - - // But let them be overridden by parameters - - for (int i = 0; i < names.length; i++) { - String s = viewer.readParameter(names[i], false); - if (s != null) { - for (int j = 0; j < values[i].length; j++) { - if (s.equalsIgnoreCase(values[i][j])) { - choices[i].select(j); - } - } - } - } - - // "Show Controls" setting does not have associated GUI option - - showControls = true; - String s = viewer.readParameter("Show Controls", false); - if (s != null && s.equalsIgnoreCase("No")) - showControls = false; - - // Make the booleans and encodings array correspond to the state of the GUI - - setEncodings(); - setColorFormat(); - setOtherOptions(); - } - - - // - // Disable the shareDesktop option - // - - void disableShareDesktop() { - labels[shareDesktopIndex].setEnabled(false); - choices[shareDesktopIndex].setEnabled(false); - } - - - // - // setEncodings looks at the encoding, compression level, JPEG - // quality level, cursor shape updates and copyRect choices and sets - // the encodings array appropriately. It also calls the VncViewer's - // setEncodings method to send a message to the RFB server if - // necessary. - // - - void setEncodings() { - nEncodings = 0; - if (choices[useCopyRectIndex].getSelectedItem().equals("Yes")) { - encodings[nEncodings++] = RfbProto.EncodingCopyRect; - } - - int preferredEncoding = RfbProto.EncodingRaw; - boolean enableCompressLevel = false; - - if (choices[encodingIndex].getSelectedItem().equals("RRE")) { - preferredEncoding = RfbProto.EncodingRRE; - } else if (choices[encodingIndex].getSelectedItem().equals("CoRRE")) { - preferredEncoding = RfbProto.EncodingCoRRE; - } else if (choices[encodingIndex].getSelectedItem().equals("Hextile")) { - preferredEncoding = RfbProto.EncodingHextile; - } else if (choices[encodingIndex].getSelectedItem().equals("Zlib")) { - preferredEncoding = RfbProto.EncodingZlib; - enableCompressLevel = true; - } else if (choices[encodingIndex].getSelectedItem().equals("Tight")) { - preferredEncoding = RfbProto.EncodingTight; - enableCompressLevel = true; - } - - encodings[nEncodings++] = preferredEncoding; - if (preferredEncoding != RfbProto.EncodingHextile) { - encodings[nEncodings++] = RfbProto.EncodingHextile; - } - if (preferredEncoding != RfbProto.EncodingTight) { - encodings[nEncodings++] = RfbProto.EncodingTight; - } - if (preferredEncoding != RfbProto.EncodingZlib) { - encodings[nEncodings++] = RfbProto.EncodingZlib; - } - if (preferredEncoding != RfbProto.EncodingCoRRE) { - encodings[nEncodings++] = RfbProto.EncodingCoRRE; - } - if (preferredEncoding != RfbProto.EncodingRRE) { - encodings[nEncodings++] = RfbProto.EncodingRRE; - } - - // Handle compression level setting. - - if (enableCompressLevel) { - labels[compressLevelIndex].setEnabled(true); - choices[compressLevelIndex].setEnabled(true); - try { - compressLevel = - Integer.parseInt(choices[compressLevelIndex].getSelectedItem()); - } - catch (NumberFormatException e) { - compressLevel = -1; - } - if (compressLevel >= 1 && compressLevel <= 9) { - encodings[nEncodings++] = - RfbProto.EncodingCompressLevel0 + compressLevel; - } else { - compressLevel = -1; - } - } else { - labels[compressLevelIndex].setEnabled(false); - choices[compressLevelIndex].setEnabled(false); - } - - // Handle JPEG quality setting. - - if (preferredEncoding == RfbProto.EncodingTight) { - labels[jpegQualityIndex].setEnabled(true); - choices[jpegQualityIndex].setEnabled(true); - try { - jpegQuality = - Integer.parseInt(choices[jpegQualityIndex].getSelectedItem()); - } - catch (NumberFormatException e) { - jpegQuality = -1; - } - if (jpegQuality >= 0 && jpegQuality <= 9) { - encodings[nEncodings++] = - RfbProto.EncodingQualityLevel0 + jpegQuality; - } else { - jpegQuality = -1; - } - } else { - labels[jpegQualityIndex].setEnabled(false); - choices[jpegQualityIndex].setEnabled(false); - } - - // Request cursor shape updates if necessary. - - requestCursorUpdates = - !choices[cursorUpdatesIndex].getSelectedItem().equals("Disable"); - - if (requestCursorUpdates) { - encodings[nEncodings++] = RfbProto.EncodingXCursor; - encodings[nEncodings++] = RfbProto.EncodingRichCursor; - ignoreCursorUpdates = - choices[cursorUpdatesIndex].getSelectedItem().equals("Ignore"); - } - - encodings[nEncodings++] = RfbProto.EncodingLastRect; - encodings[nEncodings++] = RfbProto.EncodingNewFBSize; - - viewer.setEncodings(); - } - - // - // setColorFormat sets eightBitColors variable depending on the GUI - // setting, and switches between 8-bit and 24-bit colors mode, if - // necessary. - // - - void setColorFormat() { - - eightBitColors - = choices[eightBitColorsIndex].getSelectedItem().equals("Yes"); - - // FIXME: implement dynamic changing of the color mode. - - } - - // - // setOtherOptions looks at the "other" choices (ones which don't set the - // encoding or the color format) and sets the boolean flags appropriately. - // - - void setOtherOptions() { - - reverseMouseButtons2And3 - = choices[mouseButtonIndex].getSelectedItem().equals("Reversed"); - - viewOnly - = choices[viewOnlyIndex].getSelectedItem().equals("Yes"); - if (viewer.vc != null) - viewer.vc.enableInput(!viewOnly); - - shareDesktop - = choices[shareDesktopIndex].getSelectedItem().equals("Yes"); - } - - - // - // Respond to actions on Choice controls - // - - public void itemStateChanged(ItemEvent evt) { - Object source = evt.getSource(); - - if (source == choices[encodingIndex] || - source == choices[compressLevelIndex] || - source == choices[jpegQualityIndex] || - source == choices[cursorUpdatesIndex] || - source == choices[useCopyRectIndex]) { - - setEncodings(); - - } else if (source == choices[eightBitColorsIndex]) { - - setColorFormat(); - - } else if (source == choices[mouseButtonIndex] || - source == choices[shareDesktopIndex] || - source == choices[viewOnlyIndex]) { - - setOtherOptions(); - } - } - - // - // Respond to button press - // - - public void actionPerformed(ActionEvent evt) { - if (evt.getSource() == closeButton) - setVisible(false); - } - - // - // Respond to window events - // - - public void windowClosing(WindowEvent evt) { - setVisible(false); - } - - 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) {} -} diff --git a/java/src/com/tightvnc/rfbplayer/README b/java/src/com/tightvnc/rfbplayer/README index b9f24c0f..7d52c580 100644 --- a/java/src/com/tightvnc/rfbplayer/README +++ b/java/src/com/tightvnc/rfbplayer/README @@ -1,274 +1,29 @@ -TightVNC 1.2.3 Java Viewer -========================== +RFB Session Player 0.1.0 +======================== -Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved. -Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved. -Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +RFB Session Player is a Java application/applet for playing back RFB +session files in FBS format saved by such programs as VNC Reflector or +rfbproxy. -This software is distributed under the GNU General Public Licence as -published by the Free Software Foundation. See the file LICENCE.TXT for the -conditions under which this software is made available. VNC also contains -code from other sources. See the Acknowledgements section below, and the -individual files for details of the conditions under which they are made -available. - - -Compiling from the sources -========================== - -To compile all the .java files to .class files, simply do: - - % make all - -This will also generate a JAR (Java archive) file containing all the classes. -Copy all the .class files, the .jar file and the .vnc files to an -installation directory (e.g. /usr/local/vnc/classes): - - % cp *.class *.jar *.vnc /usr/local/vnc/classes - -Make sure that the vncserver script is configured to point to the -installation directory. - - -Configuration -============= - -TightVNC Java viewer supports a number of parameters allowing you to -customize its behaviour. Most parameter names copy settings available from -the Options frame in the Java viewer. Both parameter names and their values -are case-insensitive, with one exception for the "PASSWORD" parameter. Here -is the full list of parameters supported in TightVNC Java viewer: - ---> "HOST" (no GUI equivalent) - - Value: host name or IP address of the VNC server. - Default: in applet mode, the host from which the applet was loaded. - - This parameter tells the viewer which server to connect to. Normally, - it's not needed, because default Java security policy allow connections - from applets to the only one host anyway, and that is the host from which - the applet was loaded. - ---> "PORT" (no GUI equivalent) - - Value: TCP port number on the VNC server. - Default: none. - - This parameter is required in all cases. Note that this port is not the - one used for HTTP connection from the browser, it is the port used for - RFB connection. Usually, VNC servers use ports 58xx for HTTP connections, - and ports 59xx for RFB connections. Thus, most likely, this parameter - should be set to something like 5900, 5901 etc. - ---> "PASSWORD" - - Value: session password in plan text. - Default: none, ask user. - - DO NOT EVER USE THIS PARAMETER, unless you really know what you are - doing. It's extremely dangerous from the security point of view. When - this parameter is set, the viewer won't ever ask for a password. - ---> "Encoding" - - Values: "Raw", "RRE", "CoRRE", "Hextile", "Zlib", "Tight". - Default: "Tight". - - The preferred encoding. "Hextile" is a good choice for fast networks, - while "Tight" is better suited for low-bandwidth connections. From the - other side, the "Tight" decoder in TightVNC Java viewer seems to be more - efficient than "Hextile" decoder so it's possible that this default - setting can be ok for fast networks too. - ---> "Compression level" - - Values: "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9". - Default: "Default". ;-) - - Use specified compression level for "Tight" and "Zlib" encodings. Level 1 - uses minimum of CPU time on the server but achieves weak compression - ratios. Level 9 offers best compression but may be slow in terms of CPU - time consumption on the server side. Use high levels with very slow - network connections, and low levels when working over higher-speed - networks. The "Default" value means that the server's default compression - level should be used. - ---> "JPEG image quality" - - Values: "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9". - Default: "6". - - Use the specified image quality level in "Tight" encoding. Quality level - 0 denotes bad image quality but very impressive compression ratios, while - level 9 offers very good image quality at lower compression ratios. If - the value is "JPEG off", the server will not use lossy JPEG compression - in "Tight" encoding. - ---> "Cursor shape updates" - - Values: "Enable", "Ignore", "Disable". - Default: "Enable". - - Cursor shape updates is a protocol extension used to handle remote cursor - movements locally on the client side, saving bandwidth and eliminating - delays in mouse pointer movement. Note that current implementation of - cursor shape updates does not allow a client to track mouse cursor - position at the server side. This means that clients would not see mouse - cursor movements if mouse was moved either locally on the server, or by - another remote VNC client. Set this parameter to "Disable" if you always - want to see real cursor position on the remote side. Setting this option - to "Ignore" is similar to "Enable" but the remote cursor will not be - visible at all. This can be a reasonable setting if you don't care about - cursor shape and don't want to see two mouse cursors, one above another. - ---> "Use CopyRect" - Values: "Yes", "No". - Default: "Yes". +Licensing Terms +=============== - The "CopyRect" encoding saves bandwidth and drawing time when parts of - the remote screen are moving around. Most likely, you don't want to - change this setting. +RFB Session Player is ---> "Restricted colors" + Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved. - Values: "Yes", "No". - Default: "No". +This software is based on the TightVNC Java viewer which is - If set to "No", then 24-bit color format is used to represent pixel data. - If set to "Yes", then only 8 bits are used to represent each pixel. 8-bit - color format can save bandwidth, but colors may look very inaccurate. + Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved. + Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved. + Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ---> "Mouse buttons 2 and 3" - - Values: "Normal", "Reversed". - Default: "Normal". - - If set to "Reversed", then right mouse button (button 2) will act as it - was middle mouse button (button 3), and vice versa. - ---> "View only" - - Values: "Yes", "No". - Default: "No". - - If set to "Yes", then all keyboard and mouse events in the desktop window - will be silently ignored and will not be passed to the remote side. - ---> "Share desktop" - - Values: "Yes", "No". - Default: "Yes". - - Share the connection with other clients on the same VNC server. The exact - behaviour in each case depends on the server configuration. - ---> "Open new window" (no GUI equivalent, applicable only in the applet mode) - - Values: "Yes", "No". - Default: "No". - - Operate in a separate window. This makes possible resizing the desktop, - and adds scroll bars when necessary. If the server supports variable - desktop size, the window will resize automatically when remote desktop - size changes. - ---> "Show controls" (no GUI equivalent) - - Values: "Yes", "No". - Default: "Yes". - - Set to "No" if you want to get rid of that button panel at the top. - ---> "Defer screen updates" (no GUI equivalent) - - Value: time in milliseconds. - Default: "20". - - When updating the desktop contents after receiving an update from server, - schedule repaint within the specified number of milliseconds. Small delay - helps to coalesce several small updates into one drawing operation, - improving CPU usage. Set this parameter to 0 to disable deferred updates. - ---> "Defer cursor updates" (no GUI equivalent) - - Value: time in milliseconds. - Default: "10". - - When updating the desktop after moving the mouse, schedule repaint within - the specified number of milliseconds. This setting makes sense only when - "Cursor shape updates" parameter is set to "Enable". Small delay helps to - coalesce several small updates into one drawing operation, improving CPU - usage. Set this parameter to 0 to disable deferred cursor updates. - ---> "Defer update requests" (no GUI equivalent) - - Value: time in milliseconds. - Default: "50". - - After processing an update received from server, wait for the specified - number of milliseconds before requesting next screen update. Such delay - will end immediately on every mouse or keyboard event if not in the "view - only" mode. Small delay helps the server to coalesce several small - updates into one framebuffer update, improving both bandwidth and CPU - usage. Increasing the parameter value does not affect responsiveness on - mouse and keyboard events, but causes delays in updating the screen when - there is no mouse and keyboard activity on the client side. - - -ACKNOWLEDGEMENTS -================ - -This distribution contains Java DES software by Dave Zimmerman - and Jef Poskanzer . This is: - - Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved. - - Permission to use, copy, modify, and distribute this software and its - documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee - is hereby granted, provided that this copyright notice is kept intact. - - WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE - SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE - LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, - MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. - - THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE - CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE - PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT - NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE - SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE - SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE - PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET - WORKSHOP SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF - FITNESS FOR HIGH RISK ACTIVITIES. - - Copyright (C) 1996 by Jef Poskanzer . All rights - reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +This software is distributed under the GNU General Public Licence as +published by the Free Software Foundation. See the file LICENCE.TXT +for the conditions under which this software is made available. VNC +also contains code from other sources. See the Acknowledgements +section below, and the individual files for details of the conditions +under which they are made available. - Visit the ACME Labs Java page for up-to-date versions of this and other - fine Java utilities: http://www.acme.com/java/ diff --git a/java/src/com/tightvnc/rfbplayer/RfbPlayer.java b/java/src/com/tightvnc/rfbplayer/RfbPlayer.java index 2524a50b..4a9bc2fe 100644 --- a/java/src/com/tightvnc/rfbplayer/RfbPlayer.java +++ b/java/src/com/tightvnc/rfbplayer/RfbPlayer.java @@ -18,17 +18,11 @@ // USA. // -// -// VncViewer.java - the VNC viewer applet. This class mainly just sets up the -// user interface, leaving it to the VncCanvas to do the actual rendering of -// a VNC desktop. -// - import java.awt.*; import java.awt.event.*; import java.io.*; -public class VncViewer extends java.applet.Applet +public class RfbPlayer extends java.applet.Applet implements java.lang.Runnable, WindowListener { boolean inAnApplet = true; @@ -40,13 +34,13 @@ public class VncViewer extends java.applet.Applet // public static void main(String[] argv) { - VncViewer v = new VncViewer(); - v.mainArgs = argv; - v.inAnApplet = false; - v.inSeparateFrame = true; + RfbPlayer p = new RfbPlayer(); + p.mainArgs = argv; + p.inAnApplet = false; + p.inSeparateFrame = true; - v.init(); - v.start(); + p.init(); + p.start(); } String[] mainArgs; @@ -54,24 +48,23 @@ public class VncViewer extends java.applet.Applet RfbProto rfb; Thread rfbThread; + public static final int MODE_STOPPED = 0; + public static final int MODE_PLAYBACK = 1; + public static final int MODE_PAUSED = 2; + protected int mode; + + FbsInputStream fbsStream; + Frame vncFrame; Container vncContainer; ScrollPane desktopScrollPane; GridBagLayout gridbag; ButtonPanel buttonPanel; - AuthPanel authenticator; VncCanvas vc; - OptionsFrame options; - ClipboardFrame clipboard; - // Variables read from parameter values. - String host; - int port; - String passwordParam; + String sessionFileName; + boolean showControls; int deferScreenUpdates; - int deferCursorUpdates; - int deferUpdateRequests; - // // init() @@ -82,7 +75,7 @@ public class VncViewer extends java.applet.Applet readParameters(); if (inSeparateFrame) { - vncFrame = new Frame("TightVNC"); + vncFrame = new Frame("RFB Session Player"); if (!inAnApplet) { vncFrame.add("Center", this); } @@ -91,10 +84,6 @@ public class VncViewer extends java.applet.Applet vncContainer = this; } - options = new OptionsFrame(this); - clipboard = new ClipboardFrame(this); - authenticator = new AuthPanel(); - if (inSeparateFrame) vncFrame.addWindowListener(this); @@ -106,7 +95,7 @@ public class VncViewer extends java.applet.Applet } // - // run() - executed by the rfbThread to deal with the RFB socket. + // run() - executed by the rfbThread to read RFB data. // public void run() { @@ -118,17 +107,24 @@ public class VncViewer extends java.applet.Applet gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.anchor = GridBagConstraints.NORTHWEST; - if (options.showControls) { + if (showControls) { buttonPanel = new ButtonPanel(this); buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); gridbag.setConstraints(buttonPanel, gbc); vncContainer.add(buttonPanel); } - try { - connectAndAuthenticate(); + if (inSeparateFrame) { + vncFrame.pack(); + vncFrame.show(); + } else { + validate(); + } - doProtocolInitialisation(); + try { + FileInputStream file = new FileInputStream(sessionFileName); + fbsStream = new FbsInputStream(file); + rfb = new RfbProto(fbsStream); vc = new VncCanvas(this); gbc.weightx = 1.0; @@ -164,209 +160,40 @@ public class VncViewer extends java.applet.Applet } - if (options.showControls) - buttonPanel.enableButtons(); - - moveFocusToDesktop(); - vc.processNormalProtocol(); - - } catch (Exception e) { - e.printStackTrace(); - fatalError(e.toString()); - } - - } - - - // - // Connect to the RFB server and authenticate the user. - // - - void connectAndAuthenticate() throws IOException { - - // The simplest case -- don't ask user a password, get it from the - // "PASSWORD" parameter instead. Authentication failures would be - // fatal. - - if (passwordParam != null) { - if (inSeparateFrame) { - vncFrame.pack(); - vncFrame.show(); - } else { - validate(); - } - if (!tryAuthenticate(passwordParam)) { - throw new IOException("VNC authentication failed"); - } - return; - } - - // There is no "PASSWORD" parameter -- ask user for a password, - // try to authenticate, retry on authentication failures. - - GridBagConstraints gbc = new GridBagConstraints(); - gbc.gridwidth = GridBagConstraints.REMAINDER; - gbc.anchor = GridBagConstraints.NORTHWEST; - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbc.ipadx = 100; - gbc.ipady = 50; - gridbag.setConstraints(authenticator, gbc); - vncContainer.add(authenticator); - - if (inSeparateFrame) { - vncFrame.pack(); - vncFrame.show(); - } else { - validate(); - // FIXME: here moveFocusToPasswordField() does not always work - // under Netscape 4.7x/Java 1.1.5/Linux. It seems like this call - // is being executed before the password field of the - // authenticator is fully drawn and activated, therefore - // requestFocus() does not work. Currently, I don't know how to - // solve this problem. - // -- const - authenticator.moveFocusToPasswordField(); - } - - while (true) { - // Wait for user entering a password. - synchronized(authenticator) { + while (true) { try { - authenticator.wait(); - } catch (InterruptedException e) { + buttonPanel.setMode(MODE_STOPPED); + vc.processNormalProtocol(); + } catch (EOFException e) { + file.close(); + file = new FileInputStream(sessionFileName); + fbsStream = new FbsInputStream(file); + rfb.newInputStream(fbsStream); } } - // Try to authenticate with a given password. - if (tryAuthenticate(authenticator.password.getText())) - break; - - // Retry on authentication failure. - authenticator.retry(); - } - - vncContainer.remove(authenticator); - } - - - // - // Try to authenticate with a given password. - // - - boolean tryAuthenticate(String pw) throws IOException { - - rfb = new RfbProto(host, port, this); - - rfb.readVersionMsg(); - - System.out.println("RFB server supports protocol version " + - rfb.serverMajor + "." + rfb.serverMinor); - - rfb.writeVersionMsg(); - - int authScheme = rfb.readAuthScheme(); - - switch (authScheme) { - - case RfbProto.NoAuth: - System.out.println("No authentication needed"); - return true; - - case RfbProto.VncAuth: - byte[] challenge = new byte[16]; - rfb.is.readFully(challenge); - - if (pw.length() > 8) - pw = pw.substring(0, 8); // Truncate to 8 chars - - byte[] key = {0, 0, 0, 0, 0, 0, 0, 0}; - System.arraycopy(pw.getBytes(), 0, key, 0, pw.length()); - - DesCipher des = new DesCipher(key); - - des.encrypt(challenge, 0, challenge, 0); - des.encrypt(challenge, 8, challenge, 8); - - rfb.os.write(challenge); - - int authResult = rfb.is.readInt(); - - switch (authResult) { - case RfbProto.VncAuthOK: - System.out.println("VNC authentication succeeded"); - return true; - case RfbProto.VncAuthFailed: - System.out.println("VNC authentication failed"); - break; - case RfbProto.VncAuthTooMany: - throw new IOException("VNC authentication failed - " + - "too many tries"); - default: - throw new IOException("Unknown VNC authentication result " + - authResult); - } - break; - - default: - throw new IOException("Unknown VNC authentication scheme " + - authScheme); - } - return false; - } - - - // - // Do the rest of the protocol initialisation. - // - - void doProtocolInitialisation() throws IOException { - - rfb.writeClientInit(); - - rfb.readServerInit(); - - System.out.println("Desktop name is " + rfb.desktopName); - System.out.println("Desktop size is " + rfb.framebufferWidth + " x " + - rfb.framebufferHeight); - - setEncodings(); - } - - - // - // Send current encoding list to the RFB server. - // - - void setEncodings() { - try { - if (rfb != null && rfb.inNormalProtocol) { - rfb.writeSetEncodings(options.encodings, options.nEncodings); - if (vc != null) { - vc.softCursorFree(); - } - } + } catch (FileNotFoundException e) { + fatalError(e.toString()); } catch (Exception e) { e.printStackTrace(); + fatalError(e.toString()); } + } + public int getMode() { + return mode; + } - // - // setCutText() - send the given cut text to the RFB server. - // - - void setCutText(String text) { - try { - if ((rfb != null) && rfb.inNormalProtocol) { - rfb.writeClientCutText(text); + public void setMode(int mode) { + this.mode = mode; + if (vc != null) { + synchronized(vc) { + vc.notify(); } - } catch (Exception e) { - e.printStackTrace(); } } - // // readParameters() - read parameters from the html source or from the // command line. On the command line, the arguments are just a sequence of @@ -375,16 +202,13 @@ public class VncViewer extends java.applet.Applet // public void readParameters() { - host = readParameter("HOST", !inAnApplet); - if (host == null) { - host = getCodeBase().getHost(); - if (host.equals("")) { - fatalError("HOST parameter not specified"); - } - } - String str = readParameter("PORT", true); - port = Integer.parseInt(str); + sessionFileName = readParameter("FILE", true); + + showControls = true; + String str = readParameter("Show Controls", false); + if (str != null && str.equalsIgnoreCase("No")) + showControls = false; if (inAnApplet) { str = readParameter("Open New Window", false); @@ -392,12 +216,8 @@ public class VncViewer extends java.applet.Applet inSeparateFrame = true; } - passwordParam = readParameter("PASSWORD", false); - // Fine tuning options. deferScreenUpdates = readIntParameter("Defer screen updates", 20); - deferCursorUpdates = readIntParameter("Defer cursor updates", 10); - deferUpdateRequests = readIntParameter("Defer update requests", 50); } public String readParameter(String name, boolean required) { @@ -438,51 +258,6 @@ public class VncViewer extends java.applet.Applet return result; } - // - // moveFocusToDesktop() - move keyboard focus either to the - // VncCanvas or to the AuthPanel. - // - - void moveFocusToDesktop() { - if (vncContainer != null) { - if (vc != null && vncContainer.isAncestorOf(vc)) { - vc.requestFocus(); - } else if (vncContainer.isAncestorOf(authenticator)) { - authenticator.moveFocusToPasswordField(); - } - } - } - - // - // disconnect() - close connection to server. - // - - public void disconnect() { - System.out.println("Disconnect"); - options.dispose(); - clipboard.dispose(); - - if (inAnApplet) { - vncContainer.removeAll(); - if (rfb != null) { - rfb.close(); - rfb = null; - } - Label errLabel = new Label("Disconnected"); - 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(); - } - rfbThread.stop(); - } else { - System.exit(0); - } - } - // // fatalError() - print out a fatal error message. // @@ -493,7 +268,6 @@ public class VncViewer extends java.applet.Applet if (inAnApplet) { vncContainer.removeAll(); if (rfb != null) { - rfb.close(); rfb = null; } Label errLabel = new Label(str); @@ -518,10 +292,8 @@ public class VncViewer extends java.applet.Applet public void destroy() { vncContainer.removeAll(); - options.dispose(); - clipboard.dispose(); if (rfb != null) { - rfb.close(); + rfb = null; } if (inSeparateFrame) { vncFrame.dispose(); @@ -534,8 +306,9 @@ public class VncViewer extends java.applet.Applet // public void windowClosing(WindowEvent evt) { + vncContainer.removeAll(); if (rfb != null) - disconnect(); + rfb = null; vncFrame.dispose(); if (!inAnApplet) { @@ -543,19 +316,11 @@ public class VncViewer extends java.applet.Applet } } - // - // Move the keyboard focus to the password field on window activation. - // - - public void windowActivated(WindowEvent evt) { - if (vncFrame.isAncestorOf(authenticator)) - authenticator.moveFocusToPasswordField(); - } - // // 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) {} diff --git a/java/src/com/tightvnc/rfbplayer/RfbProto.java b/java/src/com/tightvnc/rfbplayer/RfbProto.java index a86aac53..daff66c3 100644 --- a/java/src/com/tightvnc/rfbplayer/RfbProto.java +++ b/java/src/com/tightvnc/rfbplayer/RfbProto.java @@ -73,36 +73,25 @@ class RfbProto { final static int TightMinToCompress = 12; - String host; - int port; - Socket sock; DataInputStream is; - OutputStream os; - boolean inNormalProtocol = false; - VncViewer viewer; // - // Constructor. Just make TCP connection to RFB server. + // Constructor. // - RfbProto(String h, int p, VncViewer v) throws IOException { - viewer = v; - host = h; - port = p; - sock = new Socket(host, port); - is = new DataInputStream(new BufferedInputStream(sock.getInputStream(), - 16384)); - os = sock.getOutputStream(); + RfbProto(InputStream is) throws IOException { + newInputStream(is); } + public void newInputStream(InputStream is) throws IOException { + this.is = new DataInputStream(is); - void close() { - try { - sock.close(); - } catch (Exception e) { - e.printStackTrace(); + readVersionMsg(); + if (readAuthScheme() != NoAuth) { + throw new IOException("Wrong authentication type in the session file"); } + readServerInit(); } // @@ -123,8 +112,7 @@ class RfbProto { || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9') || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n')) { - throw new IOException("Host " + host + " port " + port + - " is not an RFB server"); + throw new IOException("Incorrect protocol version"); } serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0'); @@ -132,15 +120,6 @@ class RfbProto { } - // - // Write our protocol version message - // - - void writeVersionMsg() throws IOException { - os.write(versionMsg.getBytes()); - } - - // // Find out the authentication scheme. // @@ -161,27 +140,12 @@ class RfbProto { return authScheme; default: - throw new IOException("Unknown authentication scheme from RFB " + - "server " + authScheme); + throw new IOException("Unknown authentication scheme " + authScheme); } } - // - // Write the client initialisation message - // - - void writeClientInit() throws IOException { - if (viewer.options.shareDesktop) { - os.write(1); - } else { - os.write(0); - } - viewer.options.disableShareDesktop(); - } - - // // Read the server initialisation message // @@ -211,8 +175,6 @@ class RfbProto { byte[] name = new byte[nameLength]; is.readFully(name); desktopName = new String(name); - - inNormalProtocol = true; } @@ -311,368 +273,4 @@ class RfbProto { return len; } - - // - // Write a FramebufferUpdateRequest message - // - - void writeFramebufferUpdateRequest(int x, int y, int w, int h, - boolean incremental) - throws IOException - { - byte[] b = new byte[10]; - - b[0] = (byte) FramebufferUpdateRequest; - b[1] = (byte) (incremental ? 1 : 0); - b[2] = (byte) ((x >> 8) & 0xff); - b[3] = (byte) (x & 0xff); - b[4] = (byte) ((y >> 8) & 0xff); - b[5] = (byte) (y & 0xff); - b[6] = (byte) ((w >> 8) & 0xff); - b[7] = (byte) (w & 0xff); - b[8] = (byte) ((h >> 8) & 0xff); - b[9] = (byte) (h & 0xff); - - os.write(b); - } - - - // - // Write a SetPixelFormat message - // - - void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian, - boolean trueColour, - int redMax, int greenMax, int blueMax, - int redShift, int greenShift, int blueShift) - throws IOException - { - byte[] b = new byte[20]; - - b[0] = (byte) SetPixelFormat; - b[4] = (byte) bitsPerPixel; - b[5] = (byte) depth; - b[6] = (byte) (bigEndian ? 1 : 0); - b[7] = (byte) (trueColour ? 1 : 0); - b[8] = (byte) ((redMax >> 8) & 0xff); - b[9] = (byte) (redMax & 0xff); - b[10] = (byte) ((greenMax >> 8) & 0xff); - b[11] = (byte) (greenMax & 0xff); - b[12] = (byte) ((blueMax >> 8) & 0xff); - b[13] = (byte) (blueMax & 0xff); - b[14] = (byte) redShift; - b[15] = (byte) greenShift; - b[16] = (byte) blueShift; - - os.write(b); - } - - - // - // Write a FixColourMapEntries message. The values in the red, green and - // blue arrays are from 0 to 65535. - // - - void writeFixColourMapEntries(int firstColour, int nColours, - int[] red, int[] green, int[] blue) - throws IOException - { - byte[] b = new byte[6 + nColours * 6]; - - b[0] = (byte) FixColourMapEntries; - b[2] = (byte) ((firstColour >> 8) & 0xff); - b[3] = (byte) (firstColour & 0xff); - b[4] = (byte) ((nColours >> 8) & 0xff); - b[5] = (byte) (nColours & 0xff); - - for (int i = 0; i < nColours; i++) { - b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff); - b[6 + i * 6 + 1] = (byte) (red[i] & 0xff); - b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff); - b[6 + i * 6 + 3] = (byte) (green[i] & 0xff); - b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff); - b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff); - } - - os.write(b); - } - - - // - // Write a SetEncodings message - // - - void writeSetEncodings(int[] encs, int len) throws IOException { - byte[] b = new byte[4 + 4 * len]; - - b[0] = (byte) SetEncodings; - b[2] = (byte) ((len >> 8) & 0xff); - b[3] = (byte) (len & 0xff); - - for (int i = 0; i < len; i++) { - b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff); - b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff); - b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff); - b[7 + 4 * i] = (byte) (encs[i] & 0xff); - } - - os.write(b); - } - - - // - // Write a ClientCutText message - // - - void writeClientCutText(String text) throws IOException { - byte[] b = new byte[8 + text.length()]; - - b[0] = (byte) ClientCutText; - b[4] = (byte) ((text.length() >> 24) & 0xff); - b[5] = (byte) ((text.length() >> 16) & 0xff); - b[6] = (byte) ((text.length() >> 8) & 0xff); - b[7] = (byte) (text.length() & 0xff); - - System.arraycopy(text.getBytes(), 0, b, 8, text.length()); - - os.write(b); - } - - - // - // A buffer for putting pointer and keyboard events before being sent. This - // is to ensure that multiple RFB events generated from a single Java Event - // will all be sent in a single network packet. The maximum possible - // length is 4 modifier down events, a single key event followed by 4 - // modifier up events i.e. 9 key events or 72 bytes. - // - - byte[] eventBuf = new byte[72]; - int eventBufLen; - - - // Useful shortcuts for modifier masks. - - final static int CTRL_MASK = InputEvent.CTRL_MASK; - final static int SHIFT_MASK = InputEvent.SHIFT_MASK; - final static int META_MASK = InputEvent.META_MASK; - final static int ALT_MASK = InputEvent.ALT_MASK; - - - // - // Write a pointer event message. We may need to send modifier key events - // around it to set the correct modifier state. - // - - int pointerMask = 0; - - void writePointerEvent(MouseEvent evt) throws IOException { - int modifiers = evt.getModifiers(); - - int mask2 = 2; - int mask3 = 4; - if (viewer.options.reverseMouseButtons2And3) { - mask2 = 4; - mask3 = 2; - } - - // Note: For some reason, AWT does not set BUTTON1_MASK on left - // button presses. Here we think that it was the left button if - // modifiers do not include BUTTON2_MASK or BUTTON3_MASK. - - if (evt.getID() == MouseEvent.MOUSE_PRESSED) { - if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { - pointerMask = mask2; - modifiers &= ~ALT_MASK; - } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { - pointerMask = mask3; - modifiers &= ~META_MASK; - } else { - pointerMask = 1; - } - } else if (evt.getID() == MouseEvent.MOUSE_RELEASED) { - pointerMask = 0; - if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { - modifiers &= ~ALT_MASK; - } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { - modifiers &= ~META_MASK; - } - } - - eventBufLen = 0; - writeModifierKeyEvents(modifiers); - - int x = evt.getX(); - int y = evt.getY(); - - if (x < 0) x = 0; - if (y < 0) y = 0; - - eventBuf[eventBufLen++] = (byte) PointerEvent; - eventBuf[eventBufLen++] = (byte) pointerMask; - eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff); - eventBuf[eventBufLen++] = (byte) (x & 0xff); - eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff); - eventBuf[eventBufLen++] = (byte) (y & 0xff); - - // - // Always release all modifiers after an "up" event - // - - if (pointerMask == 0) { - writeModifierKeyEvents(0); - } - - os.write(eventBuf, 0, eventBufLen); - } - - - // - // Write a key event message. We may need to send modifier key events - // around it to set the correct modifier state. Also we need to translate - // from the Java key values to the X keysym values used by the RFB protocol. - // - - void writeKeyEvent(KeyEvent evt) throws IOException { - - int keyChar = evt.getKeyChar(); - - // - // Ignore event if only modifiers were pressed. - // - - // Some JVMs return 0 instead of CHAR_UNDEFINED in getKeyChar(). - if (keyChar == 0) - keyChar = KeyEvent.CHAR_UNDEFINED; - - if (keyChar == KeyEvent.CHAR_UNDEFINED) { - int code = evt.getKeyCode(); - if (code == KeyEvent.VK_CONTROL || code == KeyEvent.VK_SHIFT || - code == KeyEvent.VK_META || code == KeyEvent.VK_ALT) - return; - } - - // - // Key press or key release? - // - - boolean down = (evt.getID() == KeyEvent.KEY_PRESSED); - - int key; - if (evt.isActionKey()) { - - // - // An action key should be one of the following. - // If not then just ignore the event. - // - - switch(evt.getKeyCode()) { - case KeyEvent.VK_HOME: key = 0xff50; break; - case KeyEvent.VK_LEFT: key = 0xff51; break; - case KeyEvent.VK_UP: key = 0xff52; break; - case KeyEvent.VK_RIGHT: key = 0xff53; break; - case KeyEvent.VK_DOWN: key = 0xff54; break; - case KeyEvent.VK_PAGE_UP: key = 0xff55; break; - case KeyEvent.VK_PAGE_DOWN: key = 0xff56; break; - case KeyEvent.VK_END: key = 0xff57; break; - case KeyEvent.VK_INSERT: key = 0xff63; break; - case KeyEvent.VK_F1: key = 0xffbe; break; - case KeyEvent.VK_F2: key = 0xffbf; break; - case KeyEvent.VK_F3: key = 0xffc0; break; - case KeyEvent.VK_F4: key = 0xffc1; break; - case KeyEvent.VK_F5: key = 0xffc2; break; - case KeyEvent.VK_F6: key = 0xffc3; break; - case KeyEvent.VK_F7: key = 0xffc4; break; - case KeyEvent.VK_F8: key = 0xffc5; break; - case KeyEvent.VK_F9: key = 0xffc6; break; - case KeyEvent.VK_F10: key = 0xffc7; break; - case KeyEvent.VK_F11: key = 0xffc8; break; - case KeyEvent.VK_F12: key = 0xffc9; break; - default: - return; - } - - } else { - - // - // A "normal" key press. Ordinary ASCII characters go straight through. - // For CTRL-, CTRL is sent separately so just send . - // Backspace, tab, return, escape and delete have special keysyms. - // Anything else we ignore. - // - - key = keyChar; - - if (key < 32) { - if (evt.isControlDown()) { - key += 96; - } else { - switch(key) { - case KeyEvent.VK_BACK_SPACE: key = 0xff08; break; - case KeyEvent.VK_TAB: key = 0xff09; break; - case KeyEvent.VK_ENTER: key = 0xff0d; break; - case KeyEvent.VK_ESCAPE: key = 0xff1b; break; - } - } - } else if (key >= 127) { - if (key == 127) { - key = 0xffff; - } else { - // JDK1.1 on X incorrectly passes some keysyms straight through, - // so we do too. JDK1.1.4 seems to have fixed this. - if ((key < 0xff00) || (key > 0xffff)) - return; - } - } - } - - eventBufLen = 0; - writeModifierKeyEvents(evt.getModifiers()); - writeKeyEvent(key, down); - - // Always release all modifiers after an "up" event - if (!down) - writeModifierKeyEvents(0); - - os.write(eventBuf, 0, eventBufLen); - } - - - // - // Add a raw key event with the given X keysym to eventBuf. - // - - void writeKeyEvent(int keysym, boolean down) { - eventBuf[eventBufLen++] = (byte) KeyboardEvent; - eventBuf[eventBufLen++] = (byte) (down ? 1 : 0); - eventBuf[eventBufLen++] = (byte) 0; - eventBuf[eventBufLen++] = (byte) 0; - eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff); - eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff); - eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff); - eventBuf[eventBufLen++] = (byte) (keysym & 0xff); - } - - - // - // Write key events to set the correct modifier state. - // - - int oldModifiers = 0; - - void writeModifierKeyEvents(int newModifiers) { - if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK)) - writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0); - - if ((newModifiers & SHIFT_MASK) != (oldModifiers & SHIFT_MASK)) - writeKeyEvent(0xffe1, (newModifiers & SHIFT_MASK) != 0); - - if ((newModifiers & META_MASK) != (oldModifiers & META_MASK)) - writeKeyEvent(0xffe7, (newModifiers & META_MASK) != 0); - - if ((newModifiers & ALT_MASK) != (oldModifiers & ALT_MASK)) - writeKeyEvent(0xffe9, (newModifiers & ALT_MASK) != 0); - - oldModifiers = newModifiers; - } } diff --git a/java/src/com/tightvnc/rfbplayer/VncCanvas.java b/java/src/com/tightvnc/rfbplayer/VncCanvas.java index 6d12aa25..750c8472 100644 --- a/java/src/com/tightvnc/rfbplayer/VncCanvas.java +++ b/java/src/com/tightvnc/rfbplayer/VncCanvas.java @@ -32,21 +32,17 @@ import java.util.zip.*; // VncCanvas is a subclass of Canvas which draws a VNC desktop on it. // -class VncCanvas extends Canvas - implements KeyListener, MouseListener, MouseMotionListener { +class VncCanvas extends Canvas { - VncViewer viewer; + RfbPlayer player; RfbProto rfb; - ColorModel cm8, cm24; - Color[] colors; - int bytesPixel; + ColorModel cm24; Image memImage; Graphics memGraphics; Image rawPixelsImage; MemoryImageSource pixelsSource; - byte[] pixels8; int[] pixels24; // Zlib encoder's data. @@ -64,31 +60,17 @@ class VncCanvas extends Canvas // which decodes and loads JPEG images. Rectangle jpegRect; - // True if we process keyboard and mouse events. - boolean listenersInstalled; - // // The constructor. // - VncCanvas(VncViewer v) throws IOException { - viewer = v; - rfb = viewer.rfb; - - tightInflaters = new Inflater[4]; + VncCanvas(RfbPlayer player) throws IOException { + this.player = player; + rfb = player.rfb; - cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6)); cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF); - colors = new Color[256]; - for (int i = 0; i < 256; i++) - colors[i] = new Color(cm8.getRGB(i)); - - setPixelFormat(); - - listenersInstalled = false; - if (!viewer.options.viewOnly) - enableInput(true); + updateFramebufferSize(); } // @@ -119,13 +101,6 @@ class VncCanvas extends Canvas synchronized(memImage) { g.drawImage(memImage, 0, 0, null); } - if (showSoftCursor) { - int x0 = cursorX - hotX, y0 = cursorY - hotY; - Rectangle r = new Rectangle(x0, y0, cursorWidth, cursorHeight); - if (r.intersects(g.getClipBounds())) { - g.drawImage(softCursor, x0, y0, null); - } - } } // @@ -153,37 +128,6 @@ class VncCanvas extends Canvas } } - // - // Start/stop receiving keyboard and mouse events. - // - - public synchronized void enableInput(boolean enable) { - if (enable && !listenersInstalled) { - listenersInstalled = true; - addKeyListener(this); - addMouseListener(this); - addMouseMotionListener(this); - viewer.buttonPanel.enableRemoteAccessControls(true); - } else if (!enable && listenersInstalled) { - listenersInstalled = false; - removeKeyListener(this); - removeMouseListener(this); - removeMouseMotionListener(this); - viewer.buttonPanel.enableRemoteAccessControls(false); - } - } - - public void setPixelFormat() throws IOException { - if (viewer.options.eightBitColors) { - rfb.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6); - bytesPixel = 1; - } else { - rfb.writeSetPixelFormat(32, 24, true, true, 255, 255, 255, 16, 8, 0); - bytesPixel = 4; - } - updateFramebufferSize(); - } - void updateFramebufferSize() { // Useful shortcuts. @@ -194,37 +138,27 @@ class VncCanvas extends Canvas // its geometry should be changed. It's not necessary to replace // existing image if only pixel format should be changed. if (memImage == null) { - memImage = viewer.createImage(fbWidth, fbHeight); + memImage = player.createImage(fbWidth, fbHeight); memGraphics = memImage.getGraphics(); } else if (memImage.getWidth(null) != fbWidth || memImage.getHeight(null) != fbHeight) { synchronized(memImage) { - memImage = viewer.createImage(fbWidth, fbHeight); + memImage = player.createImage(fbWidth, fbHeight); memGraphics = memImage.getGraphics(); } } // Images with raw pixels should be re-allocated on every change // of geometry or pixel format. - if (bytesPixel == 1) { - pixels24 = null; - pixels8 = new byte[fbWidth * fbHeight]; - - pixelsSource = - new MemoryImageSource(fbWidth, fbHeight, cm8, pixels8, 0, fbWidth); - } else { - pixels8 = null; - pixels24 = new int[fbWidth * fbHeight]; - - pixelsSource = - new MemoryImageSource(fbWidth, fbHeight, cm24, pixels24, 0, fbWidth); - } + pixels24 = new int[fbWidth * fbHeight]; + pixelsSource = + new MemoryImageSource(fbWidth, fbHeight, cm24, pixels24, 0, fbWidth); pixelsSource.setAnimated(true); rawPixelsImage = createImage(pixelsSource); // Update the size of desktop containers. - if (viewer.inSeparateFrame) { - if (viewer.desktopScrollPane != null) + if (player.inSeparateFrame) { + if (player.desktopScrollPane != null) resizeDesktopFrame(); } else { setSize(fbWidth, fbHeight); @@ -236,17 +170,17 @@ class VncCanvas extends Canvas // FIXME: Find a better way to determine correct size of a // ScrollPane. -- const - Insets insets = viewer.desktopScrollPane.getInsets(); - viewer.desktopScrollPane.setSize(rfb.framebufferWidth + + Insets insets = player.desktopScrollPane.getInsets(); + player.desktopScrollPane.setSize(rfb.framebufferWidth + 2 * Math.min(insets.left, insets.right), rfb.framebufferHeight + 2 * Math.min(insets.top, insets.bottom)); - viewer.vncFrame.pack(); + player.vncFrame.pack(); // Try to limit the frame size to the screen size. - Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize(); - Dimension frameSize = viewer.vncFrame.getSize(); + Dimension screenSize = player.vncFrame.getToolkit().getScreenSize(); + Dimension frameSize = player.vncFrame.getSize(); Dimension newSize = frameSize; boolean needToResizeFrame = false; if (frameSize.height > screenSize.height) { @@ -258,10 +192,10 @@ class VncCanvas extends Canvas needToResizeFrame = true; } if (needToResizeFrame) { - viewer.vncFrame.setSize(newSize); + player.vncFrame.setSize(newSize); } - viewer.desktopScrollPane.doLayout(); + player.desktopScrollPane.doLayout(); } // @@ -271,14 +205,28 @@ class VncCanvas extends Canvas public void processNormalProtocol() throws IOException { - rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth, - rfb.framebufferHeight, false); + zlibInflater = new Inflater(); + tightInflaters = new Inflater[4]; - // - // main dispatch loop - // + // Main dispatch loop. while (true) { + + while (player.getMode() != player.MODE_PLAYBACK) { + synchronized(this) { + try { + wait(); + } catch (InterruptedException e) { + } + } + if (player.getMode() == player.MODE_STOPPED) { + throw new EOFException("Playback stopped"); + } + if (player.getMode() == player.MODE_PLAYBACK) { + player.fbsStream.resumeReading(); + } + } + int msgType = rfb.readServerMessageType(); switch (msgType) { @@ -299,10 +247,8 @@ class VncCanvas extends Canvas if (rfb.updateRectEncoding == rfb.EncodingXCursor || rfb.updateRectEncoding == rfb.EncodingRichCursor) { - handleCursorShapeUpdate(rfb.updateRectEncoding, - rfb.updateRectX, rfb.updateRectY, - rfb.updateRectW, rfb.updateRectH); - continue; + throw new IOException("Sorry, no support for" + + " cursor shape updates yet"); } switch (rfb.updateRectEncoding) { @@ -336,35 +282,19 @@ class VncCanvas extends Canvas int x, y, w, h; Color pixel; - if (bytesPixel == 1) { - memGraphics.setColor(colors[rfb.is.readUnsignedByte()]); - memGraphics.fillRect(rx, ry, rw, rh); + pixel = new Color(0xFF000000 | rfb.is.readInt()); + memGraphics.setColor(pixel); + memGraphics.fillRect(rx, ry, rw, rh); - for (int j = 0; j < nSubrects; j++) { - pixel = colors[rfb.is.readUnsignedByte()]; - x = rx + rfb.is.readUnsignedShort(); - y = ry + rfb.is.readUnsignedShort(); - w = rfb.is.readUnsignedShort(); - h = rfb.is.readUnsignedShort(); - - memGraphics.setColor(pixel); - memGraphics.fillRect(x, y, w, h); - } - } else { // 24-bit color + for (int j = 0; j < nSubrects; j++) { pixel = new Color(0xFF000000 | rfb.is.readInt()); - memGraphics.setColor(pixel); - memGraphics.fillRect(rx, ry, rw, rh); - - for (int j = 0; j < nSubrects; j++) { - pixel = new Color(0xFF000000 | rfb.is.readInt()); - x = rx + rfb.is.readUnsignedShort(); - y = ry + rfb.is.readUnsignedShort(); - w = rfb.is.readUnsignedShort(); - h = rfb.is.readUnsignedShort(); + x = rx + rfb.is.readUnsignedShort(); + y = ry + rfb.is.readUnsignedShort(); + w = rfb.is.readUnsignedShort(); + h = rfb.is.readUnsignedShort(); - memGraphics.setColor(pixel); - memGraphics.fillRect(x, y, w, h); - } + memGraphics.setColor(pixel); + memGraphics.fillRect(x, y, w, h); } scheduleRepaint(rx, ry, rw, rh); @@ -379,35 +309,19 @@ class VncCanvas extends Canvas int x, y, w, h; Color pixel; - if (bytesPixel == 1) { - memGraphics.setColor(colors[rfb.is.readUnsignedByte()]); - memGraphics.fillRect(rx, ry, rw, rh); + pixel = new Color(0xFF000000 | rfb.is.readInt()); + memGraphics.setColor(pixel); + memGraphics.fillRect(rx, ry, rw, rh); - for (int j = 0; j < nSubrects; j++) { - pixel = colors[rfb.is.readUnsignedByte()]; - x = rx + rfb.is.readUnsignedByte(); - y = ry + rfb.is.readUnsignedByte(); - w = rfb.is.readUnsignedByte(); - h = rfb.is.readUnsignedByte(); - - memGraphics.setColor(pixel); - memGraphics.fillRect(x, y, w, h); - } - } else { // 24-bit color + for (int j = 0; j < nSubrects; j++) { pixel = new Color(0xFF000000 | rfb.is.readInt()); - memGraphics.setColor(pixel); - memGraphics.fillRect(rx, ry, rw, rh); - - for (int j = 0; j < nSubrects; j++) { - pixel = new Color(0xFF000000 | rfb.is.readInt()); - x = rx + rfb.is.readUnsignedByte(); - y = ry + rfb.is.readUnsignedByte(); - w = rfb.is.readUnsignedByte(); - h = rfb.is.readUnsignedByte(); + x = rx + rfb.is.readUnsignedByte(); + y = ry + rfb.is.readUnsignedByte(); + w = rfb.is.readUnsignedByte(); + h = rfb.is.readUnsignedByte(); - memGraphics.setColor(pixel); - memGraphics.fillRect(x, y, w, h); - } + memGraphics.setColor(pixel); + memGraphics.fillRect(x, y, w, h); } scheduleRepaint(rx, ry, rw, rh); @@ -436,22 +350,16 @@ class VncCanvas extends Canvas // Is it a raw-encoded sub-rectangle? if ((subencoding & rfb.HextileRaw) != 0) { - if (bytesPixel == 1) { - for (int j = ty; j < ty + th; j++) { - rfb.is.readFully(pixels8, j*rfb.framebufferWidth+tx, tw); - } - } else { - byte[] buf = new byte[tw * 4]; - int count, offset; - for (int j = ty; j < ty + th; j++) { - rfb.is.readFully(buf); - offset = j * rfb.framebufferWidth + tx; - for (count = 0; count < tw; count++) { - pixels24[offset + count] = - (buf[count * 4 + 1] & 0xFF) << 16 | - (buf[count * 4 + 2] & 0xFF) << 8 | - (buf[count * 4 + 3] & 0xFF); - } + byte[] buf = new byte[tw * 4]; + int count, offset; + for (int j = ty; j < ty + th; j++) { + rfb.is.readFully(buf); + offset = j * rfb.framebufferWidth + tx; + for (count = 0; count < tw; count++) { + pixels24[offset + count] = + (buf[count * 4 + 1] & 0xFF) << 16 | + (buf[count * 4 + 2] & 0xFF) << 8 | + (buf[count * 4 + 3] & 0xFF); } } handleUpdatedPixels(tx, ty, tw, th); @@ -460,22 +368,14 @@ class VncCanvas extends Canvas // Read and draw the background if specified. if ((subencoding & rfb.HextileBackgroundSpecified) != 0) { - if (bytesPixel == 1) { - bg = colors[rfb.is.readUnsignedByte()]; - } else { - bg = new Color(0xFF000000 | rfb.is.readInt()); - } + bg = new Color(0xFF000000 | rfb.is.readInt()); } memGraphics.setColor(bg); memGraphics.fillRect(tx, ty, tw, th); // Read the foreground color if specified. if ((subencoding & rfb.HextileForegroundSpecified) != 0) { - if (bytesPixel == 1) { - fg = colors[rfb.is.readUnsignedByte()]; - } else { - fg = new Color(0xFF000000 | rfb.is.readInt()); - } + fg = new Color(0xFF000000 | rfb.is.readInt()); } // Done with this tile if there is no sub-rectangles. @@ -485,62 +385,29 @@ class VncCanvas extends Canvas int nSubrects = rfb.is.readUnsignedByte(); int b1, b2, sx, sy, sw, sh; - if (bytesPixel == 1) { - - // BGR233 (8-bit color) version. - if ((subencoding & rfb.HextileSubrectsColoured) != 0) { - for (int j = 0; j < nSubrects; j++) { - fg = colors[rfb.is.readUnsignedByte()]; - b1 = rfb.is.readUnsignedByte(); - b2 = rfb.is.readUnsignedByte(); - sx = tx + (b1 >> 4); - sy = ty + (b1 & 0xf); - sw = (b2 >> 4) + 1; - sh = (b2 & 0xf) + 1; - memGraphics.setColor(fg); - memGraphics.fillRect(sx, sy, sw, sh); - } - } else { + if ((subencoding & rfb.HextileSubrectsColoured) != 0) { + for (int j = 0; j < nSubrects; j++) { + fg = new Color(0xFF000000 | rfb.is.readInt()); + b1 = rfb.is.readUnsignedByte(); + b2 = rfb.is.readUnsignedByte(); + sx = tx + (b1 >> 4); + sy = ty + (b1 & 0xf); + sw = (b2 >> 4) + 1; + sh = (b2 & 0xf) + 1; memGraphics.setColor(fg); - for (int j = 0; j < nSubrects; j++) { - b1 = rfb.is.readUnsignedByte(); - b2 = rfb.is.readUnsignedByte(); - sx = tx + (b1 >> 4); - sy = ty + (b1 & 0xf); - sw = (b2 >> 4) + 1; - sh = (b2 & 0xf) + 1; - memGraphics.fillRect(sx, sy, sw, sh); - } + memGraphics.fillRect(sx, sy, sw, sh); } - } else { - - // Full-color (24-bit) version. - if ((subencoding & rfb.HextileSubrectsColoured) != 0) { - for (int j = 0; j < nSubrects; j++) { - fg = new Color(0xFF000000 | rfb.is.readInt()); - b1 = rfb.is.readUnsignedByte(); - b2 = rfb.is.readUnsignedByte(); - sx = tx + (b1 >> 4); - sy = ty + (b1 & 0xf); - sw = (b2 >> 4) + 1; - sh = (b2 & 0xf) + 1; - memGraphics.setColor(fg); - memGraphics.fillRect(sx, sy, sw, sh); - } - } else { - memGraphics.setColor(fg); - for (int j = 0; j < nSubrects; j++) { - b1 = rfb.is.readUnsignedByte(); - b2 = rfb.is.readUnsignedByte(); - sx = tx + (b1 >> 4); - sy = ty + (b1 & 0xf); - sw = (b2 >> 4) + 1; - sh = (b2 & 0xf) + 1; - memGraphics.fillRect(sx, sy, sw, sh); - } + memGraphics.setColor(fg); + for (int j = 0; j < nSubrects; j++) { + b1 = rfb.is.readUnsignedByte(); + b2 = rfb.is.readUnsignedByte(); + sx = tx + (b1 >> 4); + sy = ty + (b1 & 0xf); + sw = (b2 >> 4) + 1; + sh = (b2 & 0xf) + 1; + memGraphics.fillRect(sx, sy, sw, sh); } - } } @@ -560,10 +427,6 @@ class VncCanvas extends Canvas } rfb.is.readFully(zlibBuf, 0, nBytes); - - if (zlibInflater == null) { - zlibInflater = new Inflater(); - } zlibInflater.setInput(zlibBuf, 0, nBytes); handleZlibRect(rfb.updateRectX, rfb.updateRectY, @@ -586,30 +449,6 @@ class VncCanvas extends Canvas } } - - // Defer framebuffer update request if necessary. But wake up - // immediately on keyboard or mouse event. - if (viewer.deferUpdateRequests > 0) { - synchronized(rfb) { - try { - rfb.wait(viewer.deferUpdateRequests); - } catch (InterruptedException e) { - } - } - } - - // Before requesting framebuffer update, check if the pixel - // format should be changed. If it should, request full update - // instead of incremental one. - if (viewer.options.eightBitColors != (bytesPixel == 1)) { - setPixelFormat(); - rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth, - rfb.framebufferHeight, false); - } else { - rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth, - rfb.framebufferHeight, true); - } - break; case RfbProto.SetColourMapEntries: @@ -621,12 +460,15 @@ class VncCanvas extends Canvas case RfbProto.ServerCutText: String s = rfb.readServerCutText(); - viewer.clipboard.setCutText(s); break; default: throw new IOException("Unknown RFB message type " + msgType); } + + if (player.getMode() == player.MODE_STOPPED) { + throw new EOFException("Playback stopped"); + } } } @@ -637,22 +479,16 @@ class VncCanvas extends Canvas void handleRawRect(int x, int y, int w, int h) throws IOException { - if (bytesPixel == 1) { - for (int dy = y; dy < y + h; dy++) { - rfb.is.readFully(pixels8, dy * rfb.framebufferWidth + x, w); - } - } else { - byte[] buf = new byte[w * 4]; - int i, offset; - for (int dy = y; dy < y + h; dy++) { - rfb.is.readFully(buf); - offset = dy * rfb.framebufferWidth + x; - for (i = 0; i < w; i++) { - pixels24[offset + i] = - (buf[i * 4 + 1] & 0xFF) << 16 | - (buf[i * 4 + 2] & 0xFF) << 8 | - (buf[i * 4 + 3] & 0xFF); - } + byte[] buf = new byte[w * 4]; + int i, offset; + for (int dy = y; dy < y + h; dy++) { + rfb.is.readFully(buf); + offset = dy * rfb.framebufferWidth + x; + for (i = 0; i < w; i++) { + pixels24[offset + i] = + (buf[i * 4 + 1] & 0xFF) << 16 | + (buf[i * 4 + 2] & 0xFF) << 8 | + (buf[i * 4 + 3] & 0xFF); } } @@ -669,22 +505,16 @@ class VncCanvas extends Canvas throws IOException { try { - if (bytesPixel == 1) { - for (int dy = y; dy < y + h; dy++) { - zlibInflater.inflate(pixels8, dy * rfb.framebufferWidth + x, w); - } - } else { - byte[] buf = new byte[w * 4]; - int i, offset; - for (int dy = y; dy < y + h; dy++) { - zlibInflater.inflate(buf); - offset = dy * rfb.framebufferWidth + x; - for (i = 0; i < w; i++) { - pixels24[offset + i] = - (buf[i * 4 + 1] & 0xFF) << 16 | - (buf[i * 4 + 2] & 0xFF) << 8 | - (buf[i * 4 + 3] & 0xFF); - } + byte[] buf = new byte[w * 4]; + int i, offset; + for (int dy = y; dy < y + h; dy++) { + zlibInflater.inflate(buf); + offset = dy * rfb.framebufferWidth + x; + for (i = 0; i < w; i++) { + pixels24[offset + i] = + (buf[i * 4 + 1] & 0xFF) << 16 | + (buf[i * 4 + 2] & 0xFF) << 8 | + (buf[i * 4 + 3] & 0xFF); } } } @@ -720,15 +550,11 @@ class VncCanvas extends Canvas // Handle solid-color rectangles. if (comp_ctl == rfb.TightFill) { - if (bytesPixel == 1) { - memGraphics.setColor(colors[rfb.is.readUnsignedByte()]); - } else { - byte[] buf = new byte[3]; - rfb.is.readFully(buf); - Color bg = new Color(0xFF000000 | (buf[0] & 0xFF) << 16 | - (buf[1] & 0xFF) << 8 | (buf[2] & 0xFF)); - memGraphics.setColor(bg); - } + byte[] buf = new byte[3]; + rfb.is.readFully(buf); + Color bg = new Color(0xFF000000 | (buf[0] & 0xFF) << 16 | + (buf[1] & 0xFF) << 8 | (buf[2] & 0xFF)); + memGraphics.setColor(bg); memGraphics.fillRect(x, y, w, h); scheduleRepaint(x, y, w, h); return; @@ -773,21 +599,12 @@ class VncCanvas extends Canvas int filter_id = rfb.is.readUnsignedByte(); if (filter_id == rfb.TightFilterPalette) { numColors = rfb.is.readUnsignedByte() + 1; - if (bytesPixel == 1) { - if (numColors != 2) { - throw new IOException("Incorrect tight palette size: " + - numColors); - } - palette8[0] = rfb.is.readByte(); - palette8[1] = rfb.is.readByte(); - } else { - byte[] buf = new byte[numColors * 3]; - rfb.is.readFully(buf); - for (int i = 0; i < numColors; i++) { - palette24[i] = ((buf[i * 3] & 0xFF) << 16 | - (buf[i * 3 + 1] & 0xFF) << 8 | - (buf[i * 3 + 2] & 0xFF)); - } + byte[] buf = new byte[numColors * 3]; + rfb.is.readFully(buf); + for (int i = 0; i < numColors; i++) { + palette24[i] = ((buf[i * 3] & 0xFF) << 16 | + (buf[i * 3 + 1] & 0xFF) << 8 | + (buf[i * 3 + 2] & 0xFF)); } if (numColors == 2) rowSize = (w + 7) / 8; @@ -797,7 +614,7 @@ class VncCanvas extends Canvas throw new IOException("Incorrect tight filter id: " + filter_id); } } - if (numColors == 0 && bytesPixel == 4) + if (numColors == 0) rowSize *= 3; // Read, optionally uncompress and decode data. @@ -810,13 +627,9 @@ class VncCanvas extends Canvas rfb.is.readFully(indexedData); if (numColors == 2) { // Two colors. - if (bytesPixel == 1) { - decodeMonoData(x, y, w, h, indexedData, palette8); - } else { - decodeMonoData(x, y, w, h, indexedData, palette24); - } + decodeMonoData(x, y, w, h, indexedData, palette24); } else { - // 3..255 colors (assuming bytesPixel == 4). + // 3..255 colors. int i = 0; for (int dy = y; dy < y + h; dy++) { for (int dx = x; dx < x + w; dx++) { @@ -832,22 +645,16 @@ class VncCanvas extends Canvas decodeGradientData(x, y, w, h, buf); } else { // Raw truecolor data. - if (bytesPixel == 1) { - for (int dy = y; dy < y + h; dy++) { - rfb.is.readFully(pixels8, dy * rfb.framebufferWidth + x, w); - } - } else { - byte[] buf = new byte[w * 3]; - int i, offset; - for (int dy = y; dy < y + h; dy++) { - rfb.is.readFully(buf); - offset = dy * rfb.framebufferWidth + x; - for (i = 0; i < w; i++) { - pixels24[offset + i] = - (buf[i * 3] & 0xFF) << 16 | - (buf[i * 3 + 1] & 0xFF) << 8 | - (buf[i * 3 + 2] & 0xFF); - } + byte[] buf = new byte[w * 3]; + int i, offset; + for (int dy = y; dy < y + h; dy++) { + rfb.is.readFully(buf); + offset = dy * rfb.framebufferWidth + x; + for (i = 0; i < w; i++) { + pixels24[offset + i] = + (buf[i * 3] & 0xFF) << 16 | + (buf[i * 3 + 1] & 0xFF) << 8 | + (buf[i * 3 + 2] & 0xFF); } } } @@ -869,13 +676,9 @@ class VncCanvas extends Canvas myInflater.inflate(indexedData); if (numColors == 2) { // Two colors. - if (bytesPixel == 1) { - decodeMonoData(x, y, w, h, indexedData, palette8); - } else { - decodeMonoData(x, y, w, h, indexedData, palette24); - } + decodeMonoData(x, y, w, h, indexedData, palette24); } else { - // More than two colors (assuming bytesPixel == 4). + // More than two colors. int i = 0; for (int dy = y; dy < y + h; dy++) { for (int dx = x; dx < x + w; dx++) { @@ -885,28 +688,22 @@ class VncCanvas extends Canvas } } } else if (useGradient) { - // Compressed "Gradient"-filtered data (assuming bytesPixel == 4). + // Compressed "Gradient"-filtered data. byte[] buf = new byte[w * h * 3]; myInflater.inflate(buf); decodeGradientData(x, y, w, h, buf); } else { // Compressed truecolor data. - if (bytesPixel == 1) { - for (int dy = y; dy < y + h; dy++) { - myInflater.inflate(pixels8, dy * rfb.framebufferWidth + x, w); - } - } else { - byte[] buf = new byte[w * 3]; - int i, offset; - for (int dy = y; dy < y + h; dy++) { - myInflater.inflate(buf); - offset = dy * rfb.framebufferWidth + x; - for (i = 0; i < w; i++) { - pixels24[offset + i] = - (buf[i * 3] & 0xFF) << 16 | - (buf[i * 3 + 1] & 0xFF) << 8 | - (buf[i * 3 + 2] & 0xFF); - } + byte[] buf = new byte[w * 3]; + int i, offset; + for (int dy = y; dy < y + h; dy++) { + myInflater.inflate(buf); + offset = dy * rfb.framebufferWidth + x; + for (i = 0; i < w; i++) { + pixels24[offset + i] = + (buf[i * 3] & 0xFF) << 16 | + (buf[i * 3 + 1] & 0xFF) << 8 | + (buf[i * 3 + 2] & 0xFF); } } } @@ -921,30 +718,9 @@ class VncCanvas extends Canvas } // - // Decode 1bpp-encoded bi-color rectangle (8-bit and 24-bit versions). + // Decode 1bpp-encoded bi-color rectangle. // - void decodeMonoData(int x, int y, int w, int h, byte[] src, byte[] palette) - throws IOException { - - int dx, dy, n; - int i = y * rfb.framebufferWidth + x; - int rowBytes = (w + 7) / 8; - byte b; - - for (dy = 0; dy < h; dy++) { - for (dx = 0; dx < w / 8; dx++) { - b = src[dy*rowBytes+dx]; - for (n = 7; n >= 0; n--) - pixels8[i++] = palette[b >> n & 1]; - } - for (n = 7; n >= 8 - w % 8; n--) { - pixels8[i++] = palette[src[dy*rowBytes+dx] >> n & 1]; - } - i += (rfb.framebufferWidth - w); - } - } - void decodeMonoData(int x, int y, int w, int h, byte[] src, int[] palette) throws IOException { @@ -1021,6 +797,7 @@ class VncCanvas extends Canvas void handleUpdatedPixels(int x, int y, int w, int h) { // Draw updated pixels of the off-screen image. + pixelsSource.newPixels(x, y, w, h); memGraphics.setClip(x, y, w, h); memGraphics.drawImage(rawPixelsImage, 0, 0, null); @@ -1033,271 +810,7 @@ class VncCanvas extends Canvas void scheduleRepaint(int x, int y, int w, int h) { // Request repaint, deferred if necessary. - repaint(viewer.deferScreenUpdates, x, y, w, h); - } - - - // - // Handle events. - // - - public void keyPressed(KeyEvent evt) { - processLocalKeyEvent(evt); - } - public void keyReleased(KeyEvent evt) { - processLocalKeyEvent(evt); - } - public void keyTyped(KeyEvent evt) { - evt.consume(); - } - - public void mousePressed(MouseEvent evt) { - processLocalMouseEvent(evt, false); - } - public void mouseReleased(MouseEvent evt) { - processLocalMouseEvent(evt, false); - } - public void mouseMoved(MouseEvent evt) { - processLocalMouseEvent(evt, true); - } - public void mouseDragged(MouseEvent evt) { - processLocalMouseEvent(evt, true); - } - - public void processLocalKeyEvent(KeyEvent evt) { - if (rfb != null && rfb.inNormalProtocol) { - synchronized(rfb) { - try { - rfb.writeKeyEvent(evt); - } catch (Exception e) { - e.printStackTrace(); - } - rfb.notify(); - } - } - // Don't ever pass keyboard events to AWT for default processing. - // Otherwise, pressing Tab would switch focus to ButtonPanel etc. - evt.consume(); - } - - public void processLocalMouseEvent(MouseEvent evt, boolean moved) { - if (rfb != null && rfb.inNormalProtocol) { - if (moved) { - softCursorMove(evt.getX(), evt.getY()); - } - synchronized(rfb) { - try { - rfb.writePointerEvent(evt); - } catch (Exception e) { - e.printStackTrace(); - } - rfb.notify(); - } - } - } - - - // - // Ignored events. - // - - public void mouseClicked(MouseEvent evt) {} - public void mouseEntered(MouseEvent evt) {} - public void mouseExited(MouseEvent evt) {} - - - ////////////////////////////////////////////////////////////////// - // - // Handle cursor shape updates (XCursor and RichCursor encodings). - // - - boolean showSoftCursor = false; - - int[] softCursorPixels; - MemoryImageSource softCursorSource; - Image softCursor; - - int cursorX = 0, cursorY = 0; - int cursorWidth, cursorHeight; - int hotX, hotY; - - // - // Handle cursor shape update (XCursor and RichCursor encodings). - // - - synchronized void - handleCursorShapeUpdate(int encodingType, - int xhot, int yhot, int width, int height) - throws IOException { - - int bytesPerRow = (width + 7) / 8; - int bytesMaskData = bytesPerRow * height; - - softCursorFree(); - - if (width * height == 0) - return; - - // Ignore cursor shape data if requested by user. - - if (viewer.options.ignoreCursorUpdates) { - if (encodingType == rfb.EncodingXCursor) { - rfb.is.skipBytes(6 + bytesMaskData * 2); - } else { - // rfb.EncodingRichCursor - rfb.is.skipBytes(width * height + bytesMaskData); - } - return; - } - - // Decode cursor pixel data. - - softCursorPixels = new int[width * height]; - - if (encodingType == rfb.EncodingXCursor) { - - // Read foreground and background colors of the cursor. - byte[] rgb = new byte[6]; - rfb.is.readFully(rgb); - int[] colors = { (0xFF000000 | (rgb[3] & 0xFF) << 16 | - (rgb[4] & 0xFF) << 8 | (rgb[5] & 0xFF)), - (0xFF000000 | (rgb[0] & 0xFF) << 16 | - (rgb[1] & 0xFF) << 8 | (rgb[2] & 0xFF)) }; - - // Read pixel and mask data. - byte[] pixBuf = new byte[bytesMaskData]; - rfb.is.readFully(pixBuf); - byte[] maskBuf = new byte[bytesMaskData]; - rfb.is.readFully(maskBuf); - - // Decode pixel data into softCursorPixels[]. - byte pixByte, maskByte; - int x, y, n, result; - int i = 0; - for (y = 0; y < height; y++) { - for (x = 0; x < width / 8; x++) { - pixByte = pixBuf[y * bytesPerRow + x]; - maskByte = maskBuf[y * bytesPerRow + x]; - for (n = 7; n >= 0; n--) { - if ((maskByte >> n & 1) != 0) { - result = colors[pixByte >> n & 1]; - } else { - result = 0; // Transparent pixel - } - softCursorPixels[i++] = result; - } - } - for (n = 7; n >= 8 - width % 8; n--) { - if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) { - result = colors[pixBuf[y * bytesPerRow + x] >> n & 1]; - } else { - result = 0; // Transparent pixel - } - softCursorPixels[i++] = result; - } - } - - } else { - // encodingType == rfb.EncodingRichCursor - - // Read pixel and mask data. - byte[] pixBuf = new byte[width * height * bytesPixel]; - rfb.is.readFully(pixBuf); - byte[] maskBuf = new byte[bytesMaskData]; - rfb.is.readFully(maskBuf); - - // Decode pixel data into softCursorPixels[]. - byte pixByte, maskByte; - int x, y, n, result; - int i = 0; - for (y = 0; y < height; y++) { - for (x = 0; x < width / 8; x++) { - maskByte = maskBuf[y * bytesPerRow + x]; - for (n = 7; n >= 0; n--) { - if ((maskByte >> n & 1) != 0) { - if (bytesPixel == 1) { - result = cm8.getRGB(pixBuf[i]); - } else { - result = 0xFF000000 | - (pixBuf[i * 4 + 1] & 0xFF) << 16 | - (pixBuf[i * 4 + 2] & 0xFF) << 8 | - (pixBuf[i * 4 + 3] & 0xFF); - } - } else { - result = 0; // Transparent pixel - } - softCursorPixels[i++] = result; - } - } - for (n = 7; n >= 8 - width % 8; n--) { - if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) { - if (bytesPixel == 1) { - result = cm8.getRGB(pixBuf[i]); - } else { - result = 0xFF000000 | - (pixBuf[i * 4 + 1] & 0xFF) << 16 | - (pixBuf[i * 4 + 2] & 0xFF) << 8 | - (pixBuf[i * 4 + 3] & 0xFF); - } - } else { - result = 0; // Transparent pixel - } - softCursorPixels[i++] = result; - } - } - - } - - // Draw the cursor on an off-screen image. - - softCursorSource = - new MemoryImageSource(width, height, softCursorPixels, 0, width); - softCursor = createImage(softCursorSource); - - // Set remaining data associated with cursor. - - cursorWidth = width; - cursorHeight = height; - hotX = xhot; - hotY = yhot; - - showSoftCursor = true; - - // Show the cursor. - - repaint(viewer.deferCursorUpdates, - cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight); - } - - // - // softCursorMove(). Moves soft cursor into a particular location. - // - - synchronized void softCursorMove(int x, int y) { - if (showSoftCursor) { - repaint(viewer.deferCursorUpdates, - cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight); - repaint(viewer.deferCursorUpdates, - x - hotX, y - hotY, cursorWidth, cursorHeight); - } - - cursorX = x; - cursorY = y; + repaint(player.deferScreenUpdates, x, y, w, h); } - // - // softCursorFree(). Remove soft cursor, dispose resources. - // - - synchronized void softCursorFree() { - if (showSoftCursor) { - showSoftCursor = false; - softCursor = null; - softCursorSource = null; - softCursorPixels = null; - - repaint(viewer.deferCursorUpdates, - cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight); - } - } } diff --git a/java/src/com/tightvnc/rfbplayer/dir.mk b/java/src/com/tightvnc/rfbplayer/dir.mk deleted file mode 100644 index 21744056..00000000 --- a/java/src/com/tightvnc/rfbplayer/dir.mk +++ /dev/null @@ -1,20 +0,0 @@ -# -# Making the VNC applet. -# - -CLASSES = VncViewer.class RfbProto.class AuthPanel.class VncCanvas.class \ - OptionsFrame.class ClipboardFrame.class ButtonPanel.class \ - DesCipher.class - -PAGES = index.vnc shared.vnc noshared.vnc hextile.vnc zlib.vnc tight.vnc - -all: $(CLASSES) VncViewer.jar - -VncViewer.jar: $(CLASSES) - @$(JavaArchive) - -export:: $(CLASSES) VncViewer.jar $(PAGES) - @$(ExportJavaClasses) - -clean:: - $(RM) *.class *.jar diff --git a/java/src/com/tightvnc/rfbplayer/hextile.vnc b/java/src/com/tightvnc/rfbplayer/hextile.vnc deleted file mode 100644 index d758ccdf..00000000 --- a/java/src/com/tightvnc/rfbplayer/hextile.vnc +++ /dev/null @@ -1,19 +0,0 @@ - - - - -$USER's $DESKTOP desktop ($DISPLAY) - - - - - -
-www.TightVNC.com - diff --git a/java/src/com/tightvnc/rfbplayer/index.html b/java/src/com/tightvnc/rfbplayer/index.html new file mode 100644 index 00000000..f5e0eea0 --- /dev/null +++ b/java/src/com/tightvnc/rfbplayer/index.html @@ -0,0 +1,9 @@ + +RFB Session Playback + + + + + + diff --git a/java/src/com/tightvnc/rfbplayer/index.vnc b/java/src/com/tightvnc/rfbplayer/index.vnc deleted file mode 100644 index d9bb30ef..00000000 --- a/java/src/com/tightvnc/rfbplayer/index.vnc +++ /dev/null @@ -1,17 +0,0 @@ - - - - -$USER's $DESKTOP desktop ($DISPLAY) - - - - -
-www.TightVNC.com - diff --git a/java/src/com/tightvnc/rfbplayer/noshared.vnc b/java/src/com/tightvnc/rfbplayer/noshared.vnc deleted file mode 100644 index b0dc3afc..00000000 --- a/java/src/com/tightvnc/rfbplayer/noshared.vnc +++ /dev/null @@ -1,17 +0,0 @@ - - - - -$USER's $DESKTOP desktop ($DISPLAY) [not shared] - - - - - -
-www.TightVNC.com - diff --git a/java/src/com/tightvnc/rfbplayer/shared.vnc b/java/src/com/tightvnc/rfbplayer/shared.vnc deleted file mode 100644 index 2f8ea1c5..00000000 --- a/java/src/com/tightvnc/rfbplayer/shared.vnc +++ /dev/null @@ -1,17 +0,0 @@ - - - - -$USER's $DESKTOP desktop ($DISPLAY) [shared] - - - - - -
-www.TightVNC.com - diff --git a/java/src/com/tightvnc/rfbplayer/tight.vnc b/java/src/com/tightvnc/rfbplayer/tight.vnc deleted file mode 100644 index 3ca7a69f..00000000 --- a/java/src/com/tightvnc/rfbplayer/tight.vnc +++ /dev/null @@ -1,18 +0,0 @@ - - - - -$USER's $DESKTOP desktop ($DISPLAY) - - - - - -
-www.TightVNC.com - diff --git a/java/src/com/tightvnc/rfbplayer/zlib.vnc b/java/src/com/tightvnc/rfbplayer/zlib.vnc deleted file mode 100644 index 877ec5d1..00000000 --- a/java/src/com/tightvnc/rfbplayer/zlib.vnc +++ /dev/null @@ -1,18 +0,0 @@ - - - - -$USER's $DESKTOP desktop ($DISPLAY) - - - - - -
-www.TightVNC.com - -- 2.39.5