+++ /dev/null
-//
-// 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.
-//
-
-package com.tightvnc.rfbplayer;
-
-import java.awt.*;
-import java.awt.event.*;
-
-class ButtonPanel extends Panel implements ActionListener {
-
- protected RfbPlayer player;
- protected Button playButton;
- protected TextField posText;
- protected TextField timeScaleText;
-
- protected int lastPosSeconds = -1;
-
- ButtonPanel(RfbPlayer player) {
- this.player = player;
-
- setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
-
- playButton = new Button("Play");
- playButton.setEnabled(false);
- add(playButton);
- playButton.addActionListener(this);
-
- add(new Label(" Position:"));
- posText = new TextField(5);
- add(posText);
- posText.addActionListener(this);
-
- add(new Label(" Speed:"));
- timeScaleText = new TextField(5);
- timeScaleText.setText(String.valueOf(player.getSpeed()));
- add(timeScaleText);
- timeScaleText.addActionListener(this);
- }
-
- public void setPaused(boolean paused) {
- if (paused) {
- playButton.setLabel("Play");
- } else {
- playButton.setLabel("Pause");
- }
- playButton.setEnabled(true);
- }
-
- public void setPos(long pos) {
- int seconds = (int)(pos / 1000);
- if (seconds != lastPosSeconds) {
- lastPosSeconds = seconds;
- char[] zeroes = {'0', '0', '0', '0'};
- String text = String.valueOf(seconds);
- if (text.length() < 4) {
- text = new String(zeroes, 0, 4 - text.length()) + text;
- }
- posText.setText(text);
- posText.setCaretPosition(text.length());
- }
- }
-
- //
- // Event processing.
- //
- public void actionPerformed(ActionEvent evt) {
- if (evt.getSource() == playButton) {
- player.setPaused(playButton.getLabel().equals("Pause"));
- } else if (evt.getSource() == posText) {
- player.setPos(Long.parseLong(posText.getText()) * 1000);
- } else if (evt.getSource() == timeScaleText) {
- double speed = Double.valueOf(timeScaleText.getText()).doubleValue();
- if (speed <= 0.0)
- speed = 1.0;
- timeScaleText.setText(String.valueOf(speed));
- player.setSpeed(speed);
- }
- }
-
-}
-
+++ /dev/null
-//
-// Copyright (C) 2008 Wimba, 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.
-//
-
-//
-// FbsConnection.java
-//
-
-package com.tightvnc.rfbplayer;
-
-import java.io.*;
-import java.net.*;
-import java.applet.Applet;
-
-public class FbsConnection {
-
- URL fbsURL;
- URL fbiURL;
- URL fbkURL;
-
- /** Index data loaded from the .fbi file. */
- FbsEntryPoint[] indexData;
- int numIndexRecords;
-
- /** RFB initialization data loaded from the .fbi file. */
- byte[] rfbInitData;
-
- FbsConnection(String fbsLocation, String indexLocationPrefix, Applet applet)
- throws MalformedURLException {
-
- // Construct URLs from strings.
- URL base = null;
- if (applet != null) {
- base = applet.getCodeBase();
- }
- fbsURL = new URL(base, fbsLocation);
- fbiURL = fbkURL = null;
- if (indexLocationPrefix != null) {
- try {
- fbiURL = new URL(base, indexLocationPrefix + ".fbi");
- fbkURL = new URL(base, indexLocationPrefix + ".fbk");
- } catch (MalformedURLException e) {
- fbiURL = fbkURL = null;
- }
- }
-
- // Try to load the .fbi index file.
- indexData = null;
- numIndexRecords = 0;
- rfbInitData = null;
- loadIndex();
- }
-
- FbsInputStream connect(long timeOffset) throws IOException {
- FbsInputStream fbs = null;
-
- // Try efficient seeking first.
- int i = indexForTimeOffset(timeOffset);
- if (i >= 0) {
- FbsEntryPoint entryPoint = indexData[i];
- if (entryPoint.key_size < entryPoint.fbs_fpos) {
- try {
- fbs = openFbsFile(entryPoint);
- } catch (IOException e) {
- System.err.println(e);
- }
- if (fbs == null) {
- System.err.println("Could not open FBS file at entry point " +
- entryPoint.timestamp + " ms");
- }
- }
- }
-
- // Fallback to the dumb version of openFbsFile().
- if (fbs == null) {
- fbs = openFbsFile();
- }
-
- // Seek to the specified position.
- fbs.setTimeOffset(timeOffset, false);
- return fbs;
- }
-
- /**
- * Load index data from .fbi file to {@link #indexData}.
- */
- private void loadIndex() {
- // Loading .fbi makes sense only if both .fbi and .fbk files are available.
- if (fbiURL != null && fbkURL != null) {
- FbsEntryPoint[] newIndex;
- int numRecordsRead = 0;
- byte[] newInitData;
- try {
- // Connect.
- URLConnection connection = fbiURL.openConnection();
- connection.connect();
- DataInputStream is = new DataInputStream(connection.getInputStream());
-
- // Check file signature.
- byte[] b = new byte[12];
- is.readFully(b);
- if (b[0] != 'F' || b[1] != 'B' || b[2] != 'I' || 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') {
- System.err.println("Could not load index: bad .fbi file signature");
- return;
- }
-
- // Read the record counter and allocate index array.
- int numRecords = is.readInt();
- if (numRecords <= 0) {
- System.err.println("Could not load index: bad .fbi record counter");
- return;
- }
- newIndex = new FbsEntryPoint[numRecords];
-
- // Read byte counter and allocate byte array for RFB initialization.
- int initSize = is.readInt();
- if (initSize <= 0) {
- System.err.println("Could not load index: bad RFB init data size");
- return;
- }
- newInitData = new byte[initSize];
-
- // Load index from the .fbi file.
- try {
- for (int i = 0; i < numRecords; i++) {
- FbsEntryPoint record = new FbsEntryPoint();
- record.timestamp = (long)is.readInt() & 0xFFFFFFFFL;
- record.key_fpos = (long)is.readInt() & 0xFFFFFFFFL;
- record.key_size = (long)is.readInt() & 0xFFFFFFFFL;
- record.fbs_fpos = (long)is.readInt() & 0xFFFFFFFFL;
- record.fbs_skip = (long)is.readInt() & 0xFFFFFFFFL;
- newIndex[i] = record;
- numRecordsRead++;
- }
- } catch (EOFException e) {
- System.err.println("Preliminary end of .fbi file");
- } catch (IOException e) {
- System.err.println("Ignored exception: " + e);
- }
- if (numRecordsRead == 0) {
- System.err.println("Could not load index: failed to read .fbi data");
- return;
- } else if (numRecordsRead != numRecords) {
- System.err.println("Warning: read not as much .fbi data as expected");
- }
- is.readFully(newInitData);
- } catch (FileNotFoundException e) {
- System.err.println("Could not load index: .fbi file not found: " +
- e.getMessage());
- return;
- } catch (IOException e) {
- System.err.println(e);
- System.err.println("Could not load index: failed to load .fbi file");
- return;
- }
- // Check correctness of the data read.
- for (int i = 1; i < numRecordsRead; i++) {
- if (newIndex[i].timestamp <= newIndex[i - 1].timestamp) {
- System.err.println("Could not load index: wrong .fbi file contents");
- return;
- }
- }
- // Loaded successfully.
- indexData = newIndex;
- numIndexRecords = numRecordsRead;
- rfbInitData = newInitData;
- System.err.println("Loaded index data, " + numRecordsRead + " records");
- }
- }
-
- private int indexForTimeOffset(long timeOffset) {
- if (timeOffset > 0 && indexData != null && numIndexRecords > 0) {
- int i = 0;
- while (i < numIndexRecords && indexData[i].timestamp <= timeOffset) {
- i++;
- }
- return i - 1;
- } else {
- return -1;
- }
- }
-
- /**
- * Open FBS file identified by {@link #fbsURL}. The file is open at its very
- * beginning, no seek is performed.
- *
- * @return a newly created FBS input stream.
- * @throws java.io.IOException if an I/O exception occurs.
- */
- private FbsInputStream openFbsFile() throws IOException {
- return new FbsInputStream(fbsURL.openStream());
- }
-
- /**
- * Open FBS file identified by {@link #fbsURL}. The stream is
- * positioned at the entry point described by <code>entryPoint</code>.
- *
- * @param entryPoint entry point information.
- *
- * @return a newly created FBS input stream on success, <code>null</code> if
- * any error occured and the FBS stream is not opened.
- * @throws java.io.IOException if an I/O exception occurs.
- */
- private FbsInputStream openFbsFile(FbsEntryPoint entry)
- throws IOException {
-
- System.err.println("Entering FBS at " + entry.timestamp + " ms");
-
- // Make sure the protocol is HTTP.
- if (!fbkURL.getProtocol().equalsIgnoreCase("http") ||
- !fbsURL.getProtocol().equalsIgnoreCase("http")) {
- System.err.println("Indexed access requires HTTP protocol in URLs");
- return null;
- }
-
- // Seek to the keyframe.
- InputStream is = openHttpByteRange(fbkURL, entry.key_fpos, entry.key_size);
- if (is == null) {
- return null;
- }
-
- // Load keyframe data from the .fbk file, prepend RFB initialization data.
- DataInputStream data = new DataInputStream(is);
- byte[] keyData = new byte[rfbInitData.length + (int)entry.key_size];
- System.arraycopy(rfbInitData, 0, keyData, 0, rfbInitData.length);
- data.readFully(keyData, rfbInitData.length, (int)entry.key_size);
- data.close();
-
- // Open the FBS stream.
- is = openHttpByteRange(fbsURL, entry.fbs_fpos, -1);
- if (is == null) {
- return null;
- }
- return new FbsInputStream(is, entry.timestamp, keyData, entry.fbs_skip);
- }
-
- private static InputStream openHttpByteRange(URL url, long offset, long len)
- throws IOException {
- HttpURLConnection conn = (HttpURLConnection)url.openConnection();
- String rangeSpec = "bytes=" + offset + "-";
- if (len != -1) {
- long lastByteOffset = offset + len - 1;
- rangeSpec += lastByteOffset;
- }
- conn.setRequestProperty("Range", rangeSpec);
- conn.connect();
- InputStream is = conn.getInputStream();
- if (conn.getResponseCode() != HttpURLConnection.HTTP_PARTIAL) {
- System.err.println("HTTP server does not support Range request headers");
- is.close();
- return null;
- }
- return is;
- }
-
-}
+++ /dev/null
-//
-// Copyright (C) 2008 Wimba, 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.
-//
-
-//
-// FbsEntryPoint.java
-//
-
-package com.tightvnc.rfbplayer;
-
-/**
- * Representation of an individual record of the .fbi (FrameBuffer Index) file.
- * It includes data that constitutes an entry point to indexed framebuffer
- * stream at a particular time offset.
- *
- * @author Constantin Kaplinsky
- */
-public class FbsEntryPoint {
-
- /**
- * Timestamp in milliseconds corresponding to the keyframe data.
- * 32-bit unsigned integer.
- */
- public long timestamp;
-
- /**
- * Keyframe position in the respective .fbk file, offset in bytes from the
- * very beginning of the file. It should point to the byte counter of an FBS
- * data block. 32-bit unsigned integer.
- */
- public long key_fpos;
-
- /**
- * Keyframe data size in the respective .fbk file, in bytes. 32-bit unsigned
- * integer.
- */
- public long key_size;
-
- /**
- * Position of the next update in the .fbs file, offset in bytes from the
- * very beginning of the file. It should point to the byte counter of an FBS
- * data block. 32-bit unsigned integer.
- */
- public long fbs_fpos;
-
- /**
- * Offset in the FBS data block referenced by fbs_fpos. It allows addressing
- * those updates that begin not on the data block boundary. 32-bit unsigned
- * integer.
- */
- public long fbs_skip;
-
- /**
- * A replacement for {@link Object#toString()}.
- *
- * @return a string representation of the object.
- */
- public String toString() {
- String s = "[ timestamp:" + timestamp;
- s += " key_fpos:" + key_fpos;
- s += " key_size:" + key_size;
- s += " fbs_fpos:" + fbs_fpos;
- s += " fbs_skip:" + fbs_skip + " ]";
-
- return s;
- }
-
-}
+++ /dev/null
-//
-// Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 2008 Wimba, 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
-//
-
-package com.tightvnc.rfbplayer;
-
-import java.io.*;
-import java.util.*;
-
-class FbsInputStream extends InputStream {
-
- protected InputStream in;
- protected long startTime;
- protected long timeOffset;
- protected long seekOffset;
- protected boolean farSeeking;
- protected boolean paused;
- protected boolean isQuitting = false;
- protected double playbackSpeed;
-
- protected byte[] buffer;
- protected int bufferSize;
- protected int bufferPos;
-
- /** The number of bytes to skip in the beginning of the next data block. */
- protected long nextBlockOffset;
-
- protected Observer obs;
-
- /**
- * Construct FbsInputStream object based on the given InputStream, positioned
- * at the very beginning of the corresponding FBS file. This constructor
- * reads and checks FBS file signature which would look like "FBS 001.000\n",
- * but any decimal number is allowed after the dot.
- *
- * @param in the InputStream object that will be used as a base for this new
- * FbsInputStream instance. It should be positioned at the very beginning of
- * the corresponding FBS file, so that first 12 bytes read from the stream
- * should form FBS file signature.
- * @throws java.io.IOException thrown on read error or on incorrect FBS file
- * signature.
- */
- FbsInputStream(InputStream in) throws IOException {
- this(in, 0, null, 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 FBS file signature");
- }
- }
-
- /**
- * Construct FbsInputStream object based on the given byte array and
- * continued in the specified InputStream. Arbitrary position in the FBS file
- * is allowed.
- *
- * @param in
- * the input stream for reading future data, after <code>buffer</code>
- * will be exhausted. The stream should be positioned at any data block
- * boundary (byte counter should follow in next four bytes).
- * @param timeOffset
- * time position corresponding the the data block provided in
- * <code>buffer</code>.
- * @param buffer
- * the data block that will be treated as the beginning of this FBS data
- * stream. This byte array is not copied into the new object so it should
- * not be altered by the caller afterwards.
- * @param nextBlockOffset
- * the number of bytes that should be skipped in first data block read
- * from <code>in</code>.
- */
- FbsInputStream(InputStream in, long timeOffset, byte[] buffer,
- long nextBlockOffset) {
-
- this.in = in;
- startTime = System.currentTimeMillis() - timeOffset;
- this.timeOffset = timeOffset;
- seekOffset = -1;
- farSeeking = false;
- paused = false;
- playbackSpeed = 1.0;
-
- this.buffer = buffer;
- bufferSize = (buffer != null) ? buffer.length : 0;
- bufferPos = 0;
-
- this.nextBlockOffset = nextBlockOffset;
- }
-
- // Force stream to finish any wait.
- public void quit() {
- isQuitting = true;
- synchronized(this) {
- notify();
- }
- }
-
- //
- // 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 synchronized void close() throws IOException {
- if (in != null)
- in.close();
- in = null;
- startTime = -1;
- timeOffset = 0;
- seekOffset = -1;
- farSeeking = false;
- paused = false;
- playbackSpeed = 1.0;
-
- buffer = null;
- bufferSize = 0;
- bufferPos = 0;
-
- nextBlockOffset = 0;
- obs = null;
- }
-
- //
- // Methods providing additional functionality.
- //
- public synchronized long getTimeOffset() {
- long off = Math.max(seekOffset, timeOffset);
- return (long)(off * playbackSpeed);
- }
-
- public synchronized void setTimeOffset(long pos, boolean allowJump) {
- seekOffset = (long)(pos / playbackSpeed);
- if (allowJump) {
- long minJumpForwardOffset = timeOffset + (long)(10000 / playbackSpeed);
- if (seekOffset < timeOffset || seekOffset > minJumpForwardOffset) {
- farSeeking = true;
- }
- }
- notify();
- }
-
- public synchronized void setSpeed(double newSpeed) {
- long newOffset = (long)(timeOffset * playbackSpeed / newSpeed);
- startTime += timeOffset - newOffset;
- timeOffset = newOffset;
- if (isSeeking()) {
- seekOffset = (long)(seekOffset * playbackSpeed / newSpeed);
- }
- playbackSpeed = newSpeed;
- }
-
- public boolean isSeeking() {
- return (seekOffset >= 0);
- }
-
- public long getSeekOffset() {
- return (long)(seekOffset * playbackSpeed);
- }
-
- public boolean isPaused() {
- return paused;
- }
-
- public synchronized void pausePlayback() {
- paused = true;
- notify();
- }
-
- public synchronized void resumePlayback() {
- paused = false;
- startTime = System.currentTimeMillis() - timeOffset;
- notify();
- }
-
- public void addObserver(Observer target) {
- obs = target;
- }
-
- //
- // Methods for internal use.
- //
- private synchronized boolean fillBuffer() throws IOException {
- // The reading thread should be interrupted on far seeking.
- if (farSeeking)
- throw new EOFException("[JUMP]");
-
- // Just wait unless we are performing playback OR seeking.
- waitWhilePaused();
-
- if (!readDataBlock()) {
- return false;
- }
-
- if (seekOffset >= 0) {
- if (timeOffset >= seekOffset) {
- startTime = System.currentTimeMillis() - seekOffset;
- seekOffset = -1;
- } else {
- return true;
- }
- }
-
- while (!isQuitting) {
- long timeDiff = startTime + timeOffset - System.currentTimeMillis();
- if (timeDiff <= 0) {
- break;
- }
- try {
- wait(timeDiff);
- } catch (InterruptedException e) {
- }
- waitWhilePaused();
- }
-
- return true;
- }
-
- /**
- * Read FBS data block into the buffer.
- * If {@link #nextBlockOffset} is not zero, that number of bytes will be
- * skipped in the beginning of the data block.
- *
- * @return true on success, false if end of file was reached.
- * @throws java.io.IOException can be thrown while reading from the
- * underlying input stream, or as a result of bad FBS file data.
- */
- private boolean readDataBlock() throws IOException {
- // Read byte counter, check for EOF condition.
- long readResult = readUnsigned32();
- if (readResult < 0) {
- return false;
- }
-
- bufferSize = (int)readResult;
- int alignedSize = (bufferSize + 3) & 0xFFFFFFFC;
-
- if (nextBlockOffset > 0) {
- in.skip(nextBlockOffset);
- bufferSize -= nextBlockOffset;
- alignedSize -= nextBlockOffset;
- nextBlockOffset = 0;
- }
-
- if (bufferSize >= 0) {
- buffer = new byte[alignedSize];
- readFully(buffer);
- bufferPos = 0;
- timeOffset = (long)(readUnsigned32() / playbackSpeed);
- }
-
- if (bufferSize < 0 || timeOffset < 0 || bufferPos >= bufferSize) {
- buffer = null;
- bufferSize = 0;
- bufferPos = 0;
- throw new IOException("Invalid FBS file data");
- }
-
- return true;
- }
-
- //
- // In paused mode, wait for external notification on this object.
- //
- private void waitWhilePaused() {
- while (paused && !isSeeking() && !isQuitting) {
- synchronized(this) {
- try {
- // Note: we call Observer.update(Observable,Object) method
- // directly instead of maintaining an Observable object.
- obs.update(null, null);
- wait();
- } catch (InterruptedException e) {
- }
- }
- }
- }
-
- 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;
- }
-
-}
-
+++ /dev/null
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-\f
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-\f
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-\f
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-\f
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-\f
- Appendix: How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- This program 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 program 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 program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
+++ /dev/null
-
-package com.tightvnc.rfbplayer;
-
-import java.awt.*;
-import java.awt.event.*;
-
-class LWScrollPane extends Container implements AdjustmentListener {
-
- /** position info */
- private Point scrollPosition = new Point(0, 0);
-
- /** panel to hold component to scroll */
- private Panel innerPanel = new Panel() {
-
- public void update(Graphics g) {
- if (needClear) {
- super.update(g);
- needClear = false;
- } else
- this.paint(g);
- }
-
- };
-
- /** component to display */
- private Component containedComp;
-
- /** layout info */
- private GridBagLayout gb;
- private GridBagConstraints gbc;
-
- /** scroll bars */
- private Scrollbar xScroller;
- private Scrollbar yScroller;
-
- /** flags indicating which scollbars are visible */
- private boolean showingXScroll = false;
- private boolean showingYScroll = false;
-
- /** flag indicating when innerpanel needs to repaint background */
- private boolean needClear = false;
-
- /** dimensions for our preferred size */
- private int width = 0;
- private int height = 0;
-
- /** c'tor for a new scroll pane */
- public LWScrollPane() {
- // create scroll bars
- xScroller = new Scrollbar(Scrollbar.HORIZONTAL) {
-
- public boolean isFocusable() {
- return false;
- }
-
- };
- yScroller = new Scrollbar(Scrollbar.VERTICAL) {
-
- public boolean isFocusable() {
- return false;
- }
-
- };
- xScroller.addAdjustmentListener(this);
- yScroller.addAdjustmentListener(this);
-
- // layout info
- gb = new GridBagLayout();
- gbc = new GridBagConstraints();
- setLayout(gb);
- setBackground(Color.white);
-
- // added inner panel
- //innerPanel.setBackground(Color.blue);
- gbc.fill = GridBagConstraints.BOTH;
- gbc.gridx = 0;
- gbc.gridy = 0;
- gbc.weightx = 100;
- gbc.weighty = 100;
- gb.setConstraints(innerPanel, gbc);
- add(innerPanel);
- innerPanel.setLayout(null);
- }
- /*
- public void update(Graphics g) {
- paint(g);
- }
- */
- /*
- public void paint(Graphics g) {
- super.paint(g);
- }
- */
-
- /**
- * Provided to allow the containing frame to resize.
- * OS X JVM 1.3 would not allow a frame to be made
- * smaller without overriding getMinimumSize.
- */
- public Dimension getMinimumSize() {
- return new Dimension(0, 0);
- }
-
- public Dimension getPreferredSize() {
- return new Dimension(width, height);
- }
-
- public void setSize(int width, int height) {
- this.width = width;
- this.height = height;
- super.setSize(width, height);
- }
-
- public void setSize(Dimension d) {
- setSize(d.width, d.height);
- }
-
- /**
- * Force component to clear itself before repainting.
- * Primarily useful if the contained component shrinks
- * without the scroll pane reducing in size.
- */
- public void clearAndRepaint() {
- needClear = true;
- innerPanel.repaint();
- }
-
- /** Add the component to be scrolled by scroll pane */
- void addComp(Component comp) {
- containedComp = comp;
- innerPanel.add(containedComp);
- }
-
- /**
- * Set the point of the component to display in the
- * upper left corner of the viewport.
- */
- void setScrollPosition(int x, int y) {
- Dimension vps = getViewportSize();
- Dimension ccs = containedComp.getPreferredSize();
-
- // skip entirely if component smaller than viewer
- if (ccs.width <= vps.width && ccs.height <= vps.height)
- return;
-
- // don't scroll too far left or up
- if (x < 0)
- x = 0;
- if (y < 0)
- y = 0;
-
- // don't scroll too far right or down
- if (ccs.width <= vps.width)
- x = 0;
- else if (x > (ccs.width - vps.width))
- x = ccs.width - vps.width;
- if (ccs.height <= vps.height)
- y = 0;
- else if (y > (ccs.height - vps.height))
- y = ccs.height - vps.height;
-
- scrollPosition = new Point(x, y);
- containedComp.setLocation(-scrollPosition.x, -scrollPosition.y);
- xScroller.setValue(scrollPosition.x);
- yScroller.setValue(scrollPosition.y);
- }
-
- /** Returns the point at the upper left corner of viewport */
- Point getScrollPosition() {
- return new Point(scrollPosition);
- }
-
- /** Return the dimensions of the viewport */
- public Dimension getViewportSize() {
- int vpW, vpH;
- Dimension size = getSize();
- vpW = size.width;
- vpH = size.height;
- if (showingYScroll)
- vpW -= yScroller.getSize().width;
- if (showingXScroll)
- vpH -= xScroller.getSize().height;
-
- return new Dimension(vpW, vpH);
- }
-
- /**
- * Ensure that the scroll pane is properly arranged after
- * a component is added, the pane is resized, etc.
- */
- public void doLayout() {
- /** Add scroll bars as necessary */
- boolean needX = false, needY = false;
- Dimension innerSize = containedComp.getPreferredSize();
- Dimension scrollDimension = getSize();
-
- if (innerSize.width > scrollDimension.width)
- needX = true;
- if (innerSize.height > scrollDimension.height)
- needY = true;
-
- showingXScroll = false;
- showingYScroll = false;
- remove(yScroller);
- remove(xScroller);
-
- if (needY) {
- gbc.gridy = 0;
- gbc.gridx = 1;
- gbc.weightx = 0;
- gb.setConstraints(yScroller, gbc);
- add(yScroller);
- showingYScroll = true;
- }
-
- if (needX) {
- gbc.gridy = 1;
- gbc.gridx = 0;
- gbc.weightx = 100;
- gbc.weighty = 0;
- gb.setConstraints(xScroller, gbc);
- add(xScroller);
- showingXScroll = true;
- }
-
- /* set scroll bar values */
- int vpW, vpH;
- vpW = scrollDimension.width;
- vpH = scrollDimension.height;
- if (showingYScroll)
- vpW -= yScroller.getSize().width;
- if (showingXScroll)
- vpH -= xScroller.getSize().height;
- yScroller.setValues(0, vpH, 0, innerSize.height);
- xScroller.setValues(0, vpW, 0, innerSize.width);
-
- containedComp.setLocation(0, 0);
- super.doLayout();
- }
-
- /**
- * Adjustment listener method for receiving callbacks
- * from scroll actions.
- *
- * @param e the AdjustmentEvent
- * @return void
- */
- public void adjustmentValueChanged(AdjustmentEvent e) {
- Point p = containedComp.getLocation();
- if (e.getAdjustable() == xScroller) {
- p.x = -e.getValue();
- scrollPosition.x = e.getValue();
- } else {
- p.y = -e.getValue();
- scrollPosition.y = e.getValue();
- }
- containedComp.setLocation(p);
- }
-
-}
+++ /dev/null
-#
-# Making the VNC applet.
-#
-
-CP = cp
-RM = rm
-JC = javac
-JAR = jar
-ARCHIVE = RfbPlayer.jar
-PAGES = index.html
-INSTALL_DIR = ./classes
-
-CLASSES = RfbPlayer.class RfbProto.class ButtonPanel.class VncCanvas.class \
- FbsInputStream.class
-
-SOURCES = RfbPlayer.java RfbProto.java ButtonPanel.java VncCanvas.java \
- FbsInputStream.java
-
-all: $(CLASSES) $(ARCHIVE)
-
-$(CLASSES): $(SOURCES)
- $(JC) -g $(SOURCES)
-
-$(ARCHIVE): $(CLASSES)
- $(JAR) cf $(ARCHIVE) $(CLASSES)
-
-install: $(CLASSES) $(ARCHIVE)
- $(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR)
-
-clean::
- $(RM) *.class *.jar
+++ /dev/null
-
-package com.tightvnc.rfbplayer;
-
-import java.applet.*;
-
-public class PARfbSender extends Applet {
-
- public void init() {
- Applet receiver = null;
- receiver = RfbSharedStatic.refApplet;
- long time = Long.valueOf(getParameter("time")).longValue();
- boolean pause = (Integer.parseInt(getParameter("pause")) != 0);
- boolean unpause = (Integer.parseInt(getParameter("unpause")) != 0);
-
- if (receiver != null) {
-
- if (pause) {
- ((RfbPlayer)receiver).setPaused(true);
- } else if (unpause) {
- ((RfbPlayer)receiver).setPaused(false);
- } else {
- ((RfbPlayer)receiver).jumpTo(time);
- }
- } else
- System.err.println("Couldn't jump to time: " + time + " in RfbPlayer.");
- }
-
-}
+++ /dev/null
-
-RFB Session Player 1.0.1
-========================
-
-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.
-
-Usage: java RfbPlayer URL file:test.fbs position 5000
- java RfbPlayer URL http://remote.host/sessions/test.fbs
-
-
-Applet Parameters
-=================
-
---> "URL"
-
- Value: URL of the session file to play.
- Default: none (required parameter).
-
- This parameter tells the player which session file to play. The URL can
- be either a complete one (e.g. "file:/your/path/session.fbs") or relative
- (e.g. "session.fbs"). Please note that if the player operates as an
- unsigned applet, it is able to play only files from the host where the
- applet was loaded from. It's a usual JVM security limitation.
-
---> "Position"
-
- Value: time in milliseconds.
- Default: 0.
-
- Set initial time position in the session file, in milliseconds.
-
---> "Autoplay"
-
- Values: "Yes", "No".
- Default: "No".
-
- If set to "Yes", then start in the playback mode. By default, the
- player starts in the paused state.
-
---> "Open new window" (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"
-
- Values: "Yes", "No".
- Default: "Yes".
-
- Set to "No" if you want to get rid of the control panel at the top.
- Please note that hiding the panel in current version makes playback
- impossible. :-)
-
---> "Defer screen updates"
-
- Value: time in milliseconds.
- Default: "20".
-
- When updating the desktop contents after reading each update, 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.
-
---> "Speed"
-
- Value: positive fixed-point or floating-point number.
- Default: "1.0".
-
- Sets playback speed where 1 is normal speed, 2 is double speed,
- and 0.5 is half speed etc. Both number formats like 0.2 and 2e-1
- are acceptable.
-
-
-Licensing Terms
-===============
-
-RFB Session Player is
-
- Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved.
-
-This software is based on the TightVNC Java viewer which is
-
- 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.
-
-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.
-
+++ /dev/null
-//
-// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This software is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-package com.tightvnc.rfbplayer;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.io.*;
-
-public class RfbPlayer extends java.applet.Applet
- implements java.lang.Runnable, WindowListener {
-
- boolean inAnApplet = true;
- boolean inSeparateFrame = false;
-
- /** current applet width */
- int dispW = 300;
- /** current applet height */
- int dispH = 200;
-
- //
- // main() is called when run as a java program from the command line.
- // It simply runs the applet inside a newly-created frame.
- //
- public static void main(String[] argv) {
- RfbPlayer p = new RfbPlayer();
- p.mainArgs = argv;
- p.inAnApplet = false;
- p.inSeparateFrame = true;
-
- p.init();
- p.start();
- }
-
- String[] mainArgs;
-
- FbsInputStream fbs;
- RfbProto rfb;
- Thread rfbThread;
-
- Frame vncFrame;
- Container vncContainer;
- //ScrollPane desktopScrollPane;
- LWScrollPane desktopScrollPane;
- GridBagLayout gridbag;
- ButtonPanel buttonPanel;
- VncCanvas vc;
-
- String sessionURL;
- String idxPrefix;
- long initialTimeOffset;
- double playbackSpeed;
- boolean autoPlay;
- boolean showControls;
- boolean isQuitting = false;
- int deferScreenUpdates;
-
- //
- // init()
- //
- public void init() {
-
- // LiveConnect work-a-round
- RfbSharedStatic.refApplet = this;
-
- readParameters();
-
- if (inSeparateFrame) {
- vncFrame = new Frame("RFB Session Player");
- if (!inAnApplet) {
- vncFrame.add("Center", this);
- }
- vncContainer = vncFrame;
- } else {
- vncContainer = this;
- }
-
- if (inSeparateFrame)
- vncFrame.addWindowListener(this);
-
- rfbThread = new Thread(this, "RfbThread");
- rfbThread.start();
- }
-
- public void update(Graphics g) {
- }
-
- //
- // run() - executed by the rfbThread to read RFB data.
- //
- public void run() {
-
- gridbag = new GridBagLayout();
- vncContainer.setLayout(gridbag);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.anchor = GridBagConstraints.NORTHWEST;
-
- if (showControls) {
- buttonPanel = new ButtonPanel(this);
- buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
- gridbag.setConstraints(buttonPanel, gbc);
- vncContainer.add(buttonPanel);
- }
-
- if (inSeparateFrame) {
- vncFrame.pack();
- vncFrame.setVisible(true);
- } else {
- validate();
- }
-
- try {
- java.applet.Applet applet = (inAnApplet) ? this : null;
- FbsConnection conn = new FbsConnection(sessionURL, idxPrefix, applet);
- fbs = conn.connect(initialTimeOffset);
- rfb = new RfbProto(fbs);
-
- vc = new VncCanvas(this);
- gbc.weightx = 1.0;
- gbc.weighty = 1.0;
-
- // Create a panel which itself is resizeable and can hold
- // non-resizeable VncCanvas component at the top left corner.
- //Panel canvasPanel = new Panel();
- //canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
- //canvasPanel.add(vc);
-
- // Create a ScrollPane which will hold a panel with VncCanvas
- // inside.
- //desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
- desktopScrollPane = new LWScrollPane();
- gbc.fill = GridBagConstraints.BOTH;
- gridbag.setConstraints(vc, gbc);
- //gridbag.setConstraints(canvasPanel, gbc);
- desktopScrollPane.addComp(vc);
- desktopScrollPane.setSize(dispW, dispH);
- //desktopScrollPane.add(canvasPanel);
-
- // Now add the scroll bar to the container.
- if (inSeparateFrame) {
- gridbag.setConstraints(desktopScrollPane, gbc);
- vncFrame.add(desktopScrollPane);
- vncFrame.setTitle(rfb.desktopName);
- vc.resizeDesktopFrame();
- } else {
- // Size the scroll pane to display size.
- desktopScrollPane.setSize(dispW, dispH);
-
- // Just add the VncCanvas component to the Applet.
- gbc.fill = GridBagConstraints.NONE;
- gridbag.setConstraints(desktopScrollPane, gbc);
- add(desktopScrollPane);
- validate();
- vc.resizeEmbeddedApplet();
- }
-
- while (!isQuitting) {
- try {
- setPaused(!autoPlay);
- fbs.setSpeed(playbackSpeed);
- vc.processNormalProtocol();
- } catch (EOFException e) {
- long newTimeOffset;
- if (e.getMessage() != null && e.getMessage().equals("[JUMP]")) {
- // A special type of EOFException allowing us to close FBS stream
- // and then re-open it for jumping to a different time offset.
- newTimeOffset = fbs.getSeekOffset();
- autoPlay = !fbs.isPaused();
- } else {
- // Return to the beginning after the playback is finished.
- newTimeOffset = 0;
- autoPlay = false;
- }
- fbs.close();
- fbs = conn.connect(newTimeOffset);
- rfb.newSession(fbs);
- vc.updateFramebufferSize();
- } catch (NullPointerException e) {
- // catching this causes a hang with 1.4.1 JVM's under Win32 IE
- throw e;
- }
- }
-
- } catch (FileNotFoundException e) {
- fatalError(e.toString());
- } catch (Exception e) {
- e.printStackTrace();
- fatalError(e.toString());
- }
-
- }
-
- public void setPausedInt(String paused) {
- // default to true (pause)
- int pause = 1;
-
- try {
- pause = Integer.parseInt(paused);
- } catch (NumberFormatException e) {
- }
-
- if (pause == 0) {
- setPaused(false);
- } else {
- setPaused(true);
- }
- }
-
- public void setPaused(boolean paused) {
- if (showControls)
- buttonPanel.setPaused(paused);
- if (paused) {
- fbs.pausePlayback();
- } else {
- fbs.resumePlayback();
- }
- }
-
- public double getSpeed() {
- return playbackSpeed;
- }
-
- public void setSpeed(double speed) {
- playbackSpeed = speed;
- fbs.setSpeed(speed);
- }
-
- public void jumpTo(long pos) {
- long diff = Math.abs(pos - fbs.getTimeOffset());
-
- // Current threshold is 5 seconds
- if (diff > 5000) {
- fbs.pausePlayback();
- setPos(pos);
- fbs.resumePlayback();
- }
- }
-
- public void setPos(long pos) {
- fbs.setTimeOffset(pos, true);
- }
-
- public void updatePos() {
- if (showControls && buttonPanel != null)
- buttonPanel.setPos(fbs.getTimeOffset());
- }
-
- //
- // readParameters() - read parameters from the html source or from the
- // command line. On the command line, the arguments are just a sequence of
- // param_name/param_value pairs where the names and values correspond to
- // those expected in the html applet tag source.
- //
- public void readParameters() {
-
- sessionURL = readParameter("URL", true);
- idxPrefix = readParameter("Index", false);
-
- initialTimeOffset = readLongParameter("Position", 0);
- if (initialTimeOffset < 0)
- initialTimeOffset = 0;
-
- playbackSpeed = readDoubleParameter("Speed", 1.0);
- if (playbackSpeed <= 0.0)
- playbackSpeed = 1.0;
-
- autoPlay = false;
- String str = readParameter("Autoplay", false);
- if (str != null && str.equalsIgnoreCase("Yes"))
- autoPlay = true;
-
- showControls = true;
- str = readParameter("Show_Controls", false);
- if (str != null && str.equalsIgnoreCase("No"))
- showControls = false;
-
- if (inAnApplet) {
- str = readParameter("Open_New_Window", false);
- if (str != null && str.equalsIgnoreCase("Yes"))
- inSeparateFrame = true;
- }
-
- // Fine tuning options.
- deferScreenUpdates = (int)readLongParameter("Defer_screen_updates", 20);
- if (deferScreenUpdates < 0)
- deferScreenUpdates = 0; // Just in case.
-
- // Display width and height.
- dispW = readIntParameter("DISPLAY_WIDTH", dispW);
- dispH = readIntParameter("DISPLAY_HEIGHT", dispH);
- }
-
- public String readParameter(String name, boolean required) {
- if (inAnApplet) {
- String s = getParameter(name);
- if ((s == null) && required) {
- fatalError(name + " parameter not specified");
- }
- return s;
- }
-
- for (int i = 0; i < mainArgs.length; i += 2) {
- if (mainArgs[i].equalsIgnoreCase(name)) {
- try {
- return mainArgs[i + 1];
- } catch (Exception e) {
- if (required) {
- fatalError(name + " parameter not specified");
- }
- return null;
- }
- }
- }
- if (required) {
- fatalError(name + " parameter not specified");
- }
- return null;
- }
-
- long readLongParameter(String name, long defaultValue) {
- String str = readParameter(name, false);
- long result = defaultValue;
- if (str != null) {
- try {
- result = Long.parseLong(str);
- } catch (NumberFormatException e) {
- }
- }
- return result;
- }
-
- double readDoubleParameter(String name, double defaultValue) {
- String str = readParameter(name, false);
- double result = defaultValue;
- if (str != null) {
- try {
- result = Double.valueOf(str).doubleValue();
- } catch (NumberFormatException e) {
- }
- }
- return result;
- }
-
- int readIntParameter(String name, int defaultValue) {
- String str = readParameter(name, false);
- int result = defaultValue;
- if (str != null) {
- try {
- result = Integer.parseInt(str);
- } catch (NumberFormatException e) {
- }
- }
- return result;
- }
-
- //
- // fatalError() - print out a fatal error message.
- //
- public void fatalError(String str) {
- System.err.println(str);
-
- if (inAnApplet) {
- vncContainer.removeAll();
- if (rfb != null) {
- rfb = null;
- }
- Label errLabel = new Label(str);
- errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
- vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
- vncContainer.add(errLabel);
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
- Thread.currentThread().stop();
- } else {
- System.exit(1);
- }
- }
-
-
- //
- // This method is called before the applet is destroyed.
- //
- public void destroy() {
- isQuitting = true;
- vncContainer.removeAll();
- if (fbs != null) {
- fbs.quit();
- try {
- fbs.close();
- } catch (IOException e) {
- }
- }
- try {
- rfbThread.join();
- } catch (InterruptedException e) {
- }
- if (inSeparateFrame) {
- vncFrame.removeWindowListener(this);
- vncFrame.dispose();
- }
- }
-
- //
- // Set the new width and height of the applet. Call when browser is resized to
- // resize the viewer.
- //
- public void displaySize(int width, int height) {
- dispW = width;
- dispH = height;
- if (!inSeparateFrame) {
- vc.resizeEmbeddedApplet();
- }
- }
-
- //
- // Close application properly on window close event.
- //
- public void windowClosing(WindowEvent evt) {
- vncContainer.removeAll();
- if (rfb != null)
- rfb = null;
-
- vncFrame.dispose();
- if (!inAnApplet) {
- System.exit(0);
- }
- }
-
- //
- // Ignore window events we're not interested in.
- //
- public void windowActivated(WindowEvent evt) {
- }
-
- public void windowDeactivated(WindowEvent evt) {
- }
-
- public void windowOpened(WindowEvent evt) {
- }
-
- public void windowClosed(WindowEvent evt) {
- }
-
- public void windowIconified(WindowEvent evt) {
- }
-
- public void windowDeiconified(WindowEvent evt) {
- }
-
-}
+++ /dev/null
-
-package com.tightvnc.rfbplayer;
-
-import java.applet.*;
-
-public class RfbPlayerSetDisplaySize extends Applet {
-
- public void init() {
- Applet receiver = null;
- receiver = RfbSharedStatic.refApplet;
- int width = Integer.valueOf(getParameter("DISPLAY_WIDTH")).intValue();
- int height = Integer.valueOf(getParameter("DISPLAY_HEIGHT")).intValue();
-
- if (receiver != null) {
- ((RfbPlayer)receiver).displaySize(width, height);
- } else
- System.err.println("Couldn't resize RfbPlayer.");
- }
-
-}
+++ /dev/null
-//
-// Copyright (C) 2008 Wimba, Inc. All Rights Reserved.
-// Copyright (C) 2001,2002 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.
-//
-
-//
-// RfbProto.java
-//
-
-package com.tightvnc.rfbplayer;
-
-import java.io.*;
-
-class RfbProto {
-
- final static String versionMsg = "RFB 003.003\n";
-
- final static int ConnFailed = 0;
- final static int NoAuth = 1;
- final static int VncAuth = 2;
-
- final static int VncAuthOK = 0;
- final static int VncAuthFailed = 1;
- final static int VncAuthTooMany = 2;
-
- final static int FramebufferUpdate = 0;
- final static int SetColourMapEntries = 1;
- final static int Bell = 2;
- final static int ServerCutText = 3;
-
- final static int SetPixelFormat = 0;
- final static int FixColourMapEntries = 1;
- final static int SetEncodings = 2;
- final static int FramebufferUpdateRequest = 3;
- final static int KeyboardEvent = 4;
- final static int PointerEvent = 5;
- final static int ClientCutText = 6;
-
- final static int EncodingRaw = 0;
- final static int EncodingCopyRect = 1;
- final static int EncodingRRE = 2;
- final static int EncodingCoRRE = 4;
- final static int EncodingHextile = 5;
- final static int EncodingZlib = 6;
- final static int EncodingTight = 7;
- final static int EncodingCompressLevel0 = 0xFFFFFF00;
- final static int EncodingQualityLevel0 = 0xFFFFFFE0;
- final static int EncodingXCursor = 0xFFFFFF10;
- final static int EncodingRichCursor = 0xFFFFFF11;
- final static int EncodingPointerPos = 0xFFFFFF18;
- final static int EncodingLastRect = 0xFFFFFF20;
- final static int EncodingNewFBSize = 0xFFFFFF21;
-
- final static int MaxNormalEncoding = 7;
-
- final static int HextileRaw = (1 << 0);
- final static int HextileBackgroundSpecified = (1 << 1);
- final static int HextileForegroundSpecified = (1 << 2);
- final static int HextileAnySubrects = (1 << 3);
- final static int HextileSubrectsColoured = (1 << 4);
-
- final static int TightExplicitFilter = 0x04;
- final static int TightFill = 0x08;
- final static int TightJpeg = 0x09;
- final static int TightMaxSubencoding = 0x09;
- final static int TightFilterCopy = 0x00;
- final static int TightFilterPalette = 0x01;
- final static int TightFilterGradient = 0x02;
-
- final static int TightMinToCompress = 12;
-
- DataInputStream is;
-
- /**
- * Constructor. It calls <code>{@link #newSession(InputStream)}</code> to open
- * new session.
- *
- * @param is the input stream from which RFB data will be read.
- * @throws java.lang.Exception
- * @throws java.io.IOException
- */
- RfbProto(InputStream is) throws Exception {
- newSession(is);
- }
-
- /**
- * Open new session that can be read from the specified InputStream.
- *
- * @param is the input stream.
- * @throws java.lang.Exception
- * @throws java.io.IOException
- */
- public void newSession(InputStream is) throws Exception {
-
- this.is = new DataInputStream(is);
-
- readVersionMsg();
- if (readAuthScheme() != NoAuth) {
- throw new Exception("Wrong authentication type in the session file");
- }
- readServerInit();
- }
-
- //
- // Read server's protocol version message.
- //
- int serverMajor, serverMinor;
-
- void readVersionMsg() throws IOException {
-
- byte[] b = new byte[12];
-
- for (int i = 0; i < b.length; i++)
- b[i] = (byte)'0';
-
- is.readFully(b);
-
- if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ') ||
- (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9') || (b[6] <
- '0') || (b[6] > '9') || (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");
- }
-
- serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
- serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
- }
-
-
- //
- // Find out the authentication scheme.
- //
- int readAuthScheme() throws IOException {
- int authScheme = is.readInt();
-
- switch (authScheme) {
-
- case ConnFailed:
- int reasonLen = is.readInt();
- byte[] reason = new byte[reasonLen];
- is.readFully(reason);
- throw new IOException(new String(reason));
-
- case NoAuth:
- case VncAuth:
- return authScheme;
-
- default:
- throw new IOException("Unknown authentication scheme " + authScheme);
-
- }
- }
-
-
- //
- // Read the server initialisation message
- //
- String desktopName;
- int framebufferWidth, framebufferHeight;
- int bitsPerPixel, depth;
- boolean bigEndian, trueColour;
- int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
-
- void readServerInit() throws Exception {
- framebufferWidth = is.readUnsignedShort();
- framebufferHeight = is.readUnsignedShort();
- bitsPerPixel = is.readUnsignedByte();
- depth = is.readUnsignedByte();
- bigEndian = (is.readUnsignedByte() != 0);
- trueColour = (is.readUnsignedByte() != 0);
- redMax = is.readUnsignedShort();
- greenMax = is.readUnsignedShort();
- blueMax = is.readUnsignedShort();
- redShift = is.readUnsignedByte();
- greenShift = is.readUnsignedByte();
- blueShift = is.readUnsignedByte();
- byte[] pad = new byte[3];
- is.readFully(pad);
- int nameLength = is.readInt();
- byte[] name = new byte[nameLength];
- is.readFully(name);
- desktopName = new String(name);
- }
-
-
- //
- // Set new framebuffer size
- //
- void setFramebufferSize(int width, int height) {
- framebufferWidth = width;
- framebufferHeight = height;
- }
-
-
- //
- // Read the server message type
- //
- int readServerMessageType() throws IOException {
- return is.readUnsignedByte();
- }
-
-
- //
- // Read a FramebufferUpdate message
- //
- int updateNRects;
-
- void readFramebufferUpdate() throws IOException {
- is.readByte();
- updateNRects = is.readUnsignedShort();
- }
-
- // Read a FramebufferUpdate rectangle header
- int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
-
- void readFramebufferUpdateRectHdr() throws IOException {
- updateRectX = is.readUnsignedShort();
- updateRectY = is.readUnsignedShort();
- updateRectW = is.readUnsignedShort();
- updateRectH = is.readUnsignedShort();
- updateRectEncoding = is.readInt();
-
- if (updateRectEncoding < 0 || updateRectEncoding > MaxNormalEncoding)
- return;
-
- if ((updateRectX + updateRectW > framebufferWidth) ||
- (updateRectY + updateRectH > framebufferHeight)) {
- throw new IOException("Framebuffer update rectangle too large: " +
- updateRectW + "x" + updateRectH + " at (" +
- updateRectX + "," + updateRectY + ")");
- }
- }
-
- // Read CopyRect source X and Y.
- int copyRectSrcX, copyRectSrcY;
-
- void readCopyRect() throws IOException {
- copyRectSrcX = is.readUnsignedShort();
- copyRectSrcY = is.readUnsignedShort();
- }
-
-
- //
- // Read a ServerCutText message
- //
- String readServerCutText() throws IOException {
- byte[] pad = new byte[3];
- is.readFully(pad);
- int len = is.readInt();
- byte[] text = new byte[len];
- is.readFully(text);
- return new String(text);
- }
-
-
- //
- // Read integer in compact representation
- //
- int readCompactLen() throws IOException {
- int portion = is.readUnsignedByte();
- int len = portion & 0x7F;
- if ((portion & 0x80) != 0) {
- portion = is.readUnsignedByte();
- len |= (portion & 0x7F) << 7;
- if ((portion & 0x80) != 0) {
- portion = is.readUnsignedByte();
- len |= (portion & 0xFF) << 14;
- }
- }
- return len;
- }
-
-}
+++ /dev/null
-
-package com.tightvnc.rfbplayer;
-
-import java.applet.*;
-
-public class RfbSharedStatic {
-
- public static Applet refApplet;
-}
+++ /dev/null
-//
-// Copyright (C) 2004 Horizon Wimba. All Rights Reserved.
-// Copyright (C) 2001-2003 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.
-//
-
-package com.tightvnc.rfbplayer;
-
-import java.awt.*;
-import java.awt.image.*;
-import java.io.*;
-import java.util.*;
-import java.util.zip.*;
-
-
-//
-// VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
-//
-class VncCanvas extends Component
- implements Observer {
-
- RfbPlayer appClass;
- RfbProto rfb;
- ColorModel cm8, cm24;
- int bytesPixel;
-
- Image memImage;
- Graphics memGraphics;
-
- Image offImage;
- Graphics offGraphics;
-
- Image rawPixelsImage;
- MemoryImageSource pixelsSource;
- byte[] pixels8;
- int[] pixels24;
-
- // Zlib encoder's data.
- byte[] zlibBuf;
- int zlibBufLen = 0;
- Inflater zlibInflater;
-
- // Tight encoder's data.
- final static int tightZlibBufferSize = 512;
- Inflater[] tightInflaters;
-
- // Since JPEG images are loaded asynchronously, we have to remember
- // their position in the framebuffer. Also, this jpegRect object is
- // used for synchronization between the rfbThread and a JVM's thread
- // which decodes and loads JPEG images.
- Rectangle jpegRect;
-
- // When we're in the seeking mode, we should not update the desktop.
- // This variable helps us to remember that repainting the desktop at
- // once is necessary when the seek operation is finished.
- boolean seekMode;
-
- // Distance of mouse from viewer border to trigger automatic scrolling
- final static int SCROLL_MARGIN = 50;
-
- // Color for border around small shared area
- static final Color DARK_GRAY = new Color(132, 138, 156);
-
- //
- // The constructor.
- //
- VncCanvas(RfbPlayer player) throws IOException {
- this.appClass = player;
- rfb = appClass.rfb;
- seekMode = false;
-
- cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
-
- setPixelFormat();
-
- // Style canvas.
- setBackground(Color.white);
-
- }
-
- //
- // Override the 1.4 focus traversal keys accesor to allow
- // our keyListener to receive tab presses.
- //
- public boolean getFocusTraversalKeysEnabled() {
- return false;
- }
-
- //
- // Callback methods to determine geometry of our Component.
- //
- public Dimension getPreferredSize() {
- Dimension d = appClass.desktopScrollPane.getViewportSize();
- Dimension sz = new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
- if (d.width > sz.width)
- sz.width = d.width;
- if (d.height > sz.height)
- sz.height = d.height;
- return sz;
- }
-
- public Dimension getMinimumSize() {
- return getPreferredSize();
- }
-
- public Dimension getMaximumSize() {
- return getPreferredSize();
- }
-
- Point getImageOrigin() {
- int x = 0, y = 0;
- Dimension d = appClass.desktopScrollPane.getViewportSize();
- if (rfb.framebufferWidth < d.width)
- x = d.width / 2 - rfb.framebufferWidth / 2;
- if (rfb.framebufferHeight < d.height)
- y = d.height / 2 - rfb.framebufferHeight / 2;
- return new Point(x, y);
- }
-
- //
- // All painting is performed here.
- //
- public void update(Graphics g) {
- paint(g);
- }
-
- public void paint(Graphics g) {
- Point o = getImageOrigin();
- Dimension d = getPreferredSize();
-
- // create new offscreen
- if (offImage == null) {
- offImage = createImage(d.width, d.height);
- offGraphics = offImage.getGraphics();
- } else if (offImage.getWidth(null) != d.width ||
- offImage.getHeight(null) != d.height) {
- offGraphics.dispose();
- offGraphics = null;
- offImage.flush();
- offImage = null;
- offImage = createImage(d.width, d.height);
- offGraphics = offImage.getGraphics();
- }
-
- synchronized(memImage) {
- offGraphics.drawImage(memImage, o.x, o.y, null);
- }
-
- // fill in background
- if (o.x > 0 || o.y > 0) {
- // left, right, top, bottom
- Color c = g.getColor();
- offGraphics.setColor(Color.white);
- offGraphics.fillRect(0, 0, o.x, d.height);
- offGraphics.fillRect(o.x + rfb.framebufferWidth, 0, d.width - (o.x +
- rfb.framebufferWidth), d.height);
- offGraphics.fillRect(o.x, 0, rfb.framebufferWidth, o.y);
- offGraphics.fillRect(o.x, o.y + rfb.framebufferHeight,
- rfb.framebufferWidth, d.height - (o.y +
- rfb.framebufferHeight));
- offGraphics.setColor(c);
- }
-
- // draw border
- Color oc = g.getColor();
- offGraphics.setColor(DARK_GRAY);
- offGraphics.drawRect(o.x - 1, o.y - 1, rfb.framebufferWidth + 1,
- rfb.framebufferHeight + 1);
- offGraphics.setColor(oc);
-
- // draw cursor
- if (showSoftCursor) {
- int x0 = cursorX - hotX, y0 = cursorY - hotY;
- x0 += o.x;
- y0 += o.y;
- Rectangle r = new Rectangle(x0, y0, cursorWidth, cursorHeight);
- if (r.intersects(g.getClipBounds())) {
- offGraphics.setClip(o.x, o.y, rfb.framebufferWidth,
- rfb.framebufferHeight);
- offGraphics.drawImage(softCursor, x0, y0, null);
- offGraphics.setClip(null);
- }
- }
-
- // draw offscreen
- g.drawImage(offImage, 0, 0, null);
- }
-
- //
- // Override the ImageObserver interface method to handle drawing of
- // JPEG-encoded data.
- //
- public boolean imageUpdate(Image img, int infoflags,
- int x, int y, int width, int height) {
- if ((infoflags & (ALLBITS | ABORT)) == 0) {
- return true; // We need more image data.
- } else {
- // If the whole image is available, draw it now.
- if ((infoflags & ALLBITS) != 0) {
- if (jpegRect != null) {
- synchronized(jpegRect) {
- memGraphics.drawImage(img, jpegRect.x, jpegRect.y, null);
- scheduleRepaint(jpegRect.x, jpegRect.y,
- jpegRect.width, jpegRect.height);
- jpegRect.notify();
- }
- }
- }
- return false; // All image data was processed.
- }
- }
-
- private void setPixelFormat() throws IOException {
- bytesPixel = 4;
- updateFramebufferSize();
- }
-
- void updateFramebufferSize() {
-
- // Useful shortcuts.
- int fbWidth = rfb.framebufferWidth;
- int fbHeight = rfb.framebufferHeight;
-
- // Create new off-screen image either if it does not exist, or if
- // its geometry should be changed. It's not necessary to replace
- // existing image if only pixel format should be changed.
- if (memImage == null) {
- memImage = appClass.createImage(fbWidth, fbHeight);
- memGraphics = memImage.getGraphics();
- } else if (memImage.getWidth(null) != fbWidth ||
- memImage.getHeight(null) != fbHeight) {
- synchronized(memImage) {
- memImage = appClass.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);
- }
- pixelsSource.setAnimated(true);
- rawPixelsImage = createImage(pixelsSource);
-
- // Update the size of desktop containers unless seeking
- if (!seekMode && appClass.desktopScrollPane != null) {
- if (appClass.inSeparateFrame) {
- resizeDesktopFrame();
- } else {
- resizeEmbeddedApplet();
- // if the framebuffer shrunk, need to clear and repaint
- appClass.desktopScrollPane.clearAndRepaint();
- }
- }
- }
-
- void resizeDesktopFrame() {
- // determine screen size
- Dimension screenSize = appClass.vncFrame.getToolkit().getScreenSize();
- Dimension scrollSize = appClass.desktopScrollPane.getSize();
-
- // Reduce Screen Size by 30 pixels in each direction;
- // This is a (poor) attempt to account for
- // 1) Menu bar on Macintosh (should really also account for
- // Dock on OSX). Usually 22px on top of screen.
- // 2) Taxkbar on Windows (usually about 28 px on bottom)
- // 3) Other obstructions.
- screenSize.height -= 30;
- screenSize.width -= 30;
-
- // Further reduce the screen size to account for the
- // scroll pane's insets.
- Insets insets = appClass.desktopScrollPane.getInsets();
- screenSize.height -= insets.top + insets.bottom;
- screenSize.width -= insets.left + insets.right;
-
- // Limit pane size to fit on screen.
- boolean needResize = false;
- if (scrollSize.width != rfb.framebufferWidth ||
- scrollSize.height != rfb.framebufferHeight)
- needResize = true;
- int w = rfb.framebufferWidth, h = rfb.framebufferHeight;
- if (w > screenSize.width) {
- w = screenSize.width;
- needResize = true;
- }
- if (h > screenSize.height) {
- h = screenSize.height;
- needResize = true;
- }
- if (needResize) {
- appClass.desktopScrollPane.setSize(w, h);
- appClass.desktopScrollPane.validate();
- }
-
- // size the canvas
- setSize(getPreferredSize());
-
- appClass.vncFrame.pack();
- }
-
- void resizeEmbeddedApplet() {
- // resize scroll pane if necessary
- Dimension scrollSize = appClass.desktopScrollPane.getSize();
- if (scrollSize.width != appClass.dispW ||
- scrollSize.height != appClass.dispH) {
- appClass.desktopScrollPane.setSize(appClass.dispW, appClass.dispH);
- }
- appClass.desktopScrollPane.validate();
- // size the canvas
- setSize(getPreferredSize());
- }
-
- //
- // processNormalProtocol() - executed by the rfbThread to deal with
- // the RFB data.
- //
- public void processNormalProtocol() throws Exception {
-
- zlibInflater = new Inflater();
- tightInflaters = new Inflater[4];
-
- // Show current time position in the control panel.
- appClass.updatePos();
-
- // Tell our FbsInputStream object to notify us when it goes to the
- // `paused' mode.
- appClass.fbs.addObserver(this);
-
- //
- // main dispatch loop
- //
-
- while (true) {
-
- int msgType = rfb.readServerMessageType();
-
- // Process the message depending on its type.
- switch (msgType) {
- case RfbProto.FramebufferUpdate:
- rfb.readFramebufferUpdate();
-
- for (int i = 0; i < rfb.updateNRects; i++) {
- rfb.readFramebufferUpdateRectHdr();
- int rx = rfb.updateRectX, ry = rfb.updateRectY;
- int rw = rfb.updateRectW, rh = rfb.updateRectH;
-
- if (rfb.updateRectEncoding == rfb.EncodingLastRect)
- break;
-
- if (rfb.updateRectEncoding == rfb.EncodingNewFBSize) {
- if (rw != 0 && rh != 0) {
- rfb.setFramebufferSize(rw, rh);
- updateFramebufferSize();
- }
- break;
- }
-
- if (rfb.updateRectEncoding == rfb.EncodingXCursor ||
- rfb.updateRectEncoding == rfb.EncodingRichCursor) {
- handleCursorShapeUpdate(rfb.updateRectEncoding, rx, ry, rw, rh);
- continue;
- }
-
- if (rfb.updateRectEncoding == rfb.EncodingPointerPos) {
- softCursorMove(rx, ry);
- continue;
- }
-
- switch (rfb.updateRectEncoding) {
- case RfbProto.EncodingRaw:
- handleRawRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingCopyRect:
- handleCopyRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingRRE:
- handleRRERect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingCoRRE:
- handleCoRRERect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingHextile:
- handleHextileRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingZlib:
- handleZlibRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingTight:
- handleTightRect(rx, ry, rw, rh);
- break;
- default:
- throw new Exception("Unknown RFB rectangle encoding " +
- Integer.toString(rfb.updateRectEncoding, 16));
- }
- }
- break;
-
- case RfbProto.SetColourMapEntries:
- throw new Exception("Can't handle SetColourMapEntries message");
-
- case RfbProto.Bell:
- Toolkit.getDefaultToolkit().beep();
- break;
-
- case RfbProto.ServerCutText:
- rfb.readServerCutText();
- break;
-
- default:
- throw new Exception("Unknown RFB message type " + msgType);
- }
-
- appClass.updatePos();
- }
- }
-
-
- //
- // Handle a raw rectangle. The second form with paint==false is used
- // by the Hextile decoder for raw-encoded tiles.
- //
- void handleRawRect(int x, int y, int w, int h) throws IOException {
- handleRawRect(x, y, w, h, true);
- }
-
- void handleRawRect(int x, int y, int w, int h, boolean paint)
- throws IOException {
-
- if (bytesPixel == 1) {
- for (int dy = y; dy < y + h; dy++) {
- rfb.is.readFully(pixels8, dy * rfb.framebufferWidth + x, w);
- //if (rfb.rec != null) {
- // rfb.rec.write(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);
- //if (rfb.rec != null) {
- // rfb.rec.write(buf);
- //}
- offset = dy * rfb.framebufferWidth + x;
- for (i = 0; i < w; i++) {
- pixels24[offset + i] =
- (buf[i * 4 + 2] & 0xFF) << 16 |
- (buf[i * 4 + 1] & 0xFF) << 8 |
- (buf[i * 4] & 0xFF);
- }
- }
- }
-
- handleUpdatedPixels(x, y, w, h);
- if (paint)
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a CopyRect rectangle.
- //
- void handleCopyRect(int x, int y, int w, int h) throws IOException {
-
- rfb.readCopyRect();
- memGraphics.copyArea(rfb.copyRectSrcX, rfb.copyRectSrcY, w, h,
- x - rfb.copyRectSrcX, y - rfb.copyRectSrcY);
-
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle an RRE-encoded rectangle.
- //
- void handleRRERect(int x, int y, int w, int h) throws IOException {
-
- int nSubrects = rfb.is.readInt();
- int sx, sy, sw, sh;
-
- byte[] buf = new byte[4];
- rfb.is.readFully(buf);
- Color pixel = new Color(buf[2] & 0xFF, buf[1] & 0xFF, buf[0] & 0xFF);
- memGraphics.setColor(pixel);
- memGraphics.fillRect(x, y, w, h);
-
- for (int j = 0; j < nSubrects; j++) {
- rfb.is.readFully(buf);
- pixel = new Color(buf[2] & 0xFF, buf[1] & 0xFF, buf[0] & 0xFF);
- sx = x + rfb.is.readUnsignedShort();
- sy = y + rfb.is.readUnsignedShort();
- sw = rfb.is.readUnsignedShort();
- sh = rfb.is.readUnsignedShort();
-
- memGraphics.setColor(pixel);
- memGraphics.fillRect(sx, sy, sw, sh);
- }
-
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a CoRRE-encoded rectangle.
- //
- void handleCoRRERect(int x, int y, int w, int h) throws IOException {
- int nSubrects = rfb.is.readInt();
- int sx, sy, sw, sh;
-
- byte[] buf = new byte[4];
- rfb.is.readFully(buf);
- Color pixel = new Color(buf[2] & 0xFF, buf[1] & 0xFF, buf[0] & 0xFF);
- memGraphics.setColor(pixel);
- memGraphics.fillRect(x, y, w, h);
-
- for (int j = 0; j < nSubrects; j++) {
- rfb.is.readFully(buf);
- pixel = new Color(buf[2] & 0xFF, buf[1] & 0xFF, buf[0] & 0xFF);
- sx = x + rfb.is.readUnsignedByte();
- sy = y + rfb.is.readUnsignedByte();
- sw = rfb.is.readUnsignedByte();
- sh = rfb.is.readUnsignedByte();
-
- memGraphics.setColor(pixel);
- memGraphics.fillRect(sx, sy, sw, sh);
- }
-
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a Hextile-encoded rectangle.
- //
-
- // These colors should be kept between handleHextileSubrect() calls.
- private Color hextile_bg, hextile_fg;
-
- void handleHextileRect(int x, int y, int w, int h) throws IOException {
-
- hextile_bg = new Color(0);
- hextile_fg = new Color(0);
-
- for (int ty = y; ty < y + h; ty += 16) {
- int th = 16;
- if (y + h - ty < 16)
- th = y + h - ty;
-
- for (int tx = x; tx < x + w; tx += 16) {
- int tw = 16;
- if (x + w - tx < 16)
- tw = x + w - tx;
-
- handleHextileSubrect(tx, ty, tw, th);
- }
-
- // Finished with a row of tiles, now let's show it.
- scheduleRepaint(x, y, w, h);
- }
- }
-
- //
- // Handle one tile in the Hextile-encoded data.
- //
- void handleHextileSubrect(int tx, int ty, int tw, int th)
- throws IOException {
-
- byte[] buf = new byte[256 * 4];
-
- int subencoding = rfb.is.readUnsignedByte();
-
- // Is it a raw-encoded sub-rectangle?
- if ((subencoding & rfb.HextileRaw) != 0) {
- int count, offset;
- for (int j = ty; j < ty + th; j++) {
- rfb.is.readFully(buf, 0, tw * 4);
- offset = j * rfb.framebufferWidth + tx;
- for (count = 0; count < tw; count++) {
- pixels24[offset + count] =
- (buf[count * 4 + 2] & 0xFF) << 16 |
- (buf[count * 4 + 1] & 0xFF) << 8 |
- (buf[count * 4] & 0xFF);
- }
- }
- handleUpdatedPixels(tx, ty, tw, th);
- return;
- }
-
- // Read and draw the background if specified.
- if ((subencoding & rfb.HextileBackgroundSpecified) != 0) {
- rfb.is.readFully(buf, 0, 4);
- hextile_bg = new Color(buf[2] & 0xFF, buf[1] & 0xFF, buf[0] & 0xFF);
- }
- memGraphics.setColor(hextile_bg);
- memGraphics.fillRect(tx, ty, tw, th);
-
- // Read the foreground color if specified.
- if ((subencoding & rfb.HextileForegroundSpecified) != 0) {
- rfb.is.readFully(buf, 0, 4);
- hextile_fg = new Color(buf[2] & 0xFF, buf[1] & 0xFF, buf[0] & 0xFF);
- }
-
- // Done with this tile if there is no sub-rectangles.
- if ((subencoding & rfb.HextileAnySubrects) == 0)
- return;
-
- int nSubrects = rfb.is.readUnsignedByte();
-
- int b1, b2, sx, sy, sw, sh;
- if ((subencoding & rfb.HextileSubrectsColoured) != 0) {
- for (int j = 0; j < nSubrects; j++) {
- rfb.is.readFully(buf, 0, 4);
- hextile_fg = new Color(buf[2] & 0xFF, buf[1] & 0xFF, buf[0] & 0xFF);
- 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(hextile_fg);
- memGraphics.fillRect(sx, sy, sw, sh);
- }
-
- } else {
- memGraphics.setColor(hextile_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);
- }
-
- }
- }
-
- //
- // Handle a Zlib-encoded rectangle.
- //
- void handleZlibRect(int x, int y, int w, int h) throws Exception {
-
- int nBytes = rfb.is.readInt();
-
- if (zlibBuf == null || zlibBufLen < nBytes) {
- zlibBufLen = nBytes * 2;
- zlibBuf = new byte[zlibBufLen];
- }
-
- rfb.is.readFully(zlibBuf, 0, nBytes);
- zlibInflater.setInput(zlibBuf, 0, nBytes);
-
- try {
- 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 + 2] & 0xFF) << 16 |
- (buf[i * 4 + 1] & 0xFF) << 8 |
- (buf[i * 4] & 0xFF);
- }
- }
- } catch (DataFormatException dfe) {
- throw new Exception(dfe.toString());
- }
-
- handleUpdatedPixels(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a Tight-encoded rectangle.
- //
- void handleTightRect(int x, int y, int w, int h) throws Exception {
-
- int comp_ctl = rfb.is.readUnsignedByte();
-
- // Flush zlib streams if we are told by the server to do so.
- for (int stream_id = 0; stream_id < 4; stream_id++) {
- if ((comp_ctl & 1) != 0 && tightInflaters[stream_id] != null) {
- tightInflaters[stream_id] = null;
- }
- comp_ctl >>= 1;
- }
-
- // Check correctness of subencoding value.
- if (comp_ctl > rfb.TightMaxSubencoding) {
- throw new Exception("Incorrect tight subencoding: " + comp_ctl);
- }
-
- // Handle solid-color rectangles.
- if (comp_ctl == rfb.TightFill) {
- byte[] buf = new byte[3];
- rfb.is.readFully(buf);
- Color bg = new Color(buf[0] & 0xFF, buf[1] & 0xFF, buf[2] & 0xFF);
- memGraphics.setColor(bg);
- memGraphics.fillRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- return;
-
- }
-
- if (comp_ctl == rfb.TightJpeg) {
-
- // Read JPEG data.
- byte[] jpegData = new byte[rfb.readCompactLen()];
- rfb.is.readFully(jpegData);
-
- // Create an Image object from the JPEG data.
- Image jpegImage = Toolkit.getDefaultToolkit().createImage(jpegData);
-
- // Remember the rectangle where the image should be drawn.
- jpegRect = new Rectangle(x, y, w, h);
-
- // Let the imageUpdate() method do the actual drawing, here just
- // wait until the image is fully loaded and drawn.
- synchronized(jpegRect) {
- Toolkit.getDefaultToolkit().prepareImage(jpegImage, -1, -1, this);
- try {
- // Wait no longer than three seconds.
- jpegRect.wait(3000);
- } catch (InterruptedException e) {
- throw new Exception("Interrupted while decoding JPEG image");
- }
- }
-
- // Done, jpegRect is not needed any more.
- jpegRect = null;
- return;
-
- }
-
- // Read filter id and parameters.
- int numColors = 0, rowSize = w;
- int[] palette24 = new int[256];
- boolean useGradient = false;
- if ((comp_ctl & rfb.TightExplicitFilter) != 0) {
- int filter_id = rfb.is.readUnsignedByte();
- if (filter_id == rfb.TightFilterPalette) {
- numColors = rfb.is.readUnsignedByte() + 1;
- 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;
- } else if (filter_id == rfb.TightFilterGradient) {
- useGradient = true;
- } else if (filter_id != rfb.TightFilterCopy) {
- throw new Exception("Incorrect tight filter id: " + filter_id);
- }
- }
- if (numColors == 0 && bytesPixel == 4)
- rowSize *= 3;
-
- // Read, optionally uncompress and decode data.
- int dataSize = h * rowSize;
- if (dataSize < rfb.TightMinToCompress) {
- // Data size is small - not compressed with zlib.
- if (numColors != 0) {
- // Indexed colors.
- byte[] indexedData = new byte[dataSize];
- 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);
- //}
- } else {
- // 3..255 colors (assuming bytesPixel == 4).
- int i = 0;
- for (int dy = y; dy < y + h; dy++) {
- for (int dx = x; dx < x + w; dx++) {
- pixels24[dy * rfb.framebufferWidth + dx] =
- palette24[indexedData[i++] & 0xFF];
- }
- }
- }
- } else if (useGradient) {
- // "Gradient"-processed data
- byte[] buf = new byte[w * h * 3];
- rfb.is.readFully(buf);
- 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);
- //if (rfb.rec != null) {
- // rfb.rec.write(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);
- //if (rfb.rec != null) {
- // rfb.rec.write(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);
- }
- }
- }
- }
- } else {
- // Data was compressed with zlib.
- int zlibDataLen = rfb.readCompactLen();
- byte[] zlibData = new byte[zlibDataLen];
- rfb.is.readFully(zlibData);
- int stream_id = comp_ctl & 0x03;
- if (tightInflaters[stream_id] == null) {
- tightInflaters[stream_id] = new Inflater();
- }
- Inflater myInflater = tightInflaters[stream_id];
- myInflater.setInput(zlibData);
- try {
- if (numColors != 0) {
- // Indexed colors.
- byte[] indexedData = new byte[dataSize];
- myInflater.inflate(indexedData);
- if (numColors == 2) {
- // Two colors.
- decodeMonoData(x, y, w, h, indexedData, palette24);
- } else {
- // More than two colors.
- int i = 0;
- for (int dy = y; dy < y + h; dy++) {
- for (int dx = x; dx < x + w; dx++) {
- pixels24[dy * rfb.framebufferWidth + dx] =
- palette24[indexedData[i++] & 0xFF];
- }
- }
- }
- } else if (useGradient) {
- // Compressed "Gradient"-filtered data.
- byte[] buf = new byte[w * h * 3];
- myInflater.inflate(buf);
- decodeGradientData(x, y, w, h, buf);
- } else {
- // Compressed truecolor data.
- 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);
- }
- }
- }
- } catch (DataFormatException dfe) {
- throw new Exception(dfe.toString());
- }
- }
-
- handleUpdatedPixels(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Decode 1bpp-encoded bi-color rectangle (8-bit and 24-bit versions).
- //
- void decodeMonoData(int x, int y, int w, int h, byte[] src, byte[] palette) {
-
- 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) {
-
- 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--)
- pixels24[i++] = palette[b >> n & 1];
- }
- for (n = 7; n >= 8 - w % 8; n--) {
- pixels24[i++] = palette[src[dy * rowBytes + dx] >> n & 1];
- }
- i += (rfb.framebufferWidth - w);
- }
- }
-
- //
- // Decode data processed with the "Gradient" filter.
- //
- void decodeGradientData(int x, int y, int w, int h, byte[] buf) {
-
- int dx, dy, c;
- byte[] prevRow = new byte[w * 3];
- byte[] thisRow = new byte[w * 3];
- byte[] pix = new byte[3];
- int[] est = new int[3];
-
- int offset = y * rfb.framebufferWidth + x;
-
- for (dy = 0; dy < h; dy++) {
-
- /* First pixel in a row */
- for (c = 0; c < 3; c++) {
- pix[c] = (byte)(prevRow[c] + buf[dy * w * 3 + c]);
- thisRow[c] = pix[c];
- }
- pixels24[offset++] =
- (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF);
-
- /* Remaining pixels of a row */
- for (dx = 1; dx < w; dx++) {
- for (c = 0; c < 3; c++) {
- est[c] = ((prevRow[dx * 3 + c] & 0xFF) + (pix[c] & 0xFF) -
- (prevRow[(dx - 1) * 3 + c] & 0xFF));
- if (est[c] > 0xFF) {
- est[c] = 0xFF;
- } else if (est[c] < 0x00) {
- est[c] = 0x00;
- }
- pix[c] = (byte)(est[c] + buf[(dy * w + dx) * 3 + c]);
- thisRow[dx * 3 + c] = pix[c];
- }
- pixels24[offset++] =
- (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF);
- }
-
- System.arraycopy(thisRow, 0, prevRow, 0, w * 3);
- offset += (rfb.framebufferWidth - w);
- }
- }
-
- //
- // Display newly updated area of pixels.
- //
- 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);
- memGraphics.setClip(0, 0, rfb.framebufferWidth, rfb.framebufferHeight);
- }
-
- //
- // Tell JVM to repaint specified desktop area.
- //
- void scheduleRepaint(int x, int y, int w, int h) {
- if (appClass.fbs.isSeeking()) {
- // Do nothing, and remember we are seeking.
- seekMode = true;
- } else {
- if (seekMode) {
- // Immediate repaint of the whole desktop after seeking.
- seekMode = false;
- if (showSoftCursor)
- scrollToPoint(cursorX, cursorY);
- updateFramebufferSize();
- repaint();
- } else {
- // Usual incremental repaint.
- Point o = getImageOrigin();
- repaint(appClass.deferScreenUpdates, o.x + x, o.y + y, w, h);
- }
- }
- }
-
-
- //////////////////////////////////////////////////////////////////
- //
- // Handle cursor shape updates (XCursor and RichCursor encodings).
- //
- boolean showSoftCursor = false;
-
- MemoryImageSource softCursorSource;
- Image softCursor;
-
- int cursorX = 0, cursorY = 0;
- int cursorWidth, cursorHeight;
- int origCursorWidth, origCursorHeight;
- int hotX, hotY;
- int origHotX, origHotY;
-
- //
- // Handle cursor shape update (XCursor and RichCursor encodings).
- //
- synchronized void handleCursorShapeUpdate(int encodingType,
- int xhot, int yhot, int width,
- int height)
- throws IOException {
-
- softCursorFree();
-
- if (width * height == 0)
- return;
-
- // Ignore cursor shape data if requested by user.
- //if (appClass.options.ignoreCursorUpdates) {
- if (false) {
- int bytesPerRow = (width + 7) / 8;
- int bytesMaskData = bytesPerRow * height;
-
- if (encodingType == rfb.EncodingXCursor) {
- rfb.is.skipBytes(6 + bytesMaskData * 2);
- } else {
- // rfb.EncodingRichCursor
- rfb.is.skipBytes(width * height + bytesMaskData);
- }
- return;
- }
-
- // Decode cursor pixel data.
- softCursorSource = decodeCursorShape(encodingType, width, height);
-
- // Set original (non-scaled) cursor dimensions.
- origCursorWidth = width;
- origCursorHeight = height;
- origHotX = xhot;
- origHotY = yhot;
-
- // Create off-screen cursor image.
- createSoftCursor();
-
- // Show the cursor.
- showSoftCursor = true;
- Point p = getImageOrigin();
- scheduleCursorRepaint(cursorX - hotX + p.x, cursorY - hotY + p.y,
- cursorWidth, cursorHeight, 5);
- }
-
- //
- // decodeCursorShape(). Decode cursor pixel data and return
- // corresponding MemoryImageSource instance.
- //
- synchronized MemoryImageSource decodeCursorShape(int encodingType, int width,
- int height)
- throws IOException {
-
- int bytesPerRow = (width + 7) / 8;
- int bytesMaskData = bytesPerRow * height;
-
- int[] 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 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 = (pixBuf[i * 4] & 0xFF) << 24 |
- (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;
- }
- }
-
- }
-
- return new MemoryImageSource(width, height, softCursorPixels, 0, width);
- }
-
- //
- // createSoftCursor(). Assign softCursor new Image (scaled if necessary).
- // Uses softCursorSource as a source for new cursor image.
- //
- synchronized void createSoftCursor() {
-
- if (softCursorSource == null)
- return;
-
- int scaleCursor = 100;
- //int scaleCursor = appClass.options.scaleCursor;
- //if (scaleCursor == 0 || !inputEnabled)
- //scaleCursor = 100;
-
- cursorWidth = (origCursorWidth * scaleCursor + 50) / 100;
- cursorHeight = (origCursorHeight * scaleCursor + 50) / 100;
- hotX = (origHotX * scaleCursor + 50) / 100;
- hotY = (origHotY * scaleCursor + 50) / 100;
- softCursor = Toolkit.getDefaultToolkit().createImage(softCursorSource);
-
- if (scaleCursor != 100) {
- softCursor = softCursor.getScaledInstance(cursorWidth, cursorHeight,
- Image.SCALE_SMOOTH);
- }
- }
-
- private void scrollToPoint(int x, int y) {
- // Automatic viewport scrolling
- if (appClass.desktopScrollPane != null) {
- boolean needScroll = false;
- Dimension d = appClass.desktopScrollPane.getViewportSize();
- Point topLeft = appClass.desktopScrollPane.getScrollPosition();
- Point botRight = new Point(topLeft.x + d.width, topLeft.y + d.height);
-
- if (x < topLeft.x + SCROLL_MARGIN) {
- // shift left
- topLeft.x = x - SCROLL_MARGIN;
- needScroll = true;
- } else if (x > botRight.x - SCROLL_MARGIN) {
- // shift right
- topLeft.x = x - d.width + SCROLL_MARGIN;
- needScroll = true;
- }
- if (y < topLeft.y + SCROLL_MARGIN) {
- // shift up
- topLeft.y = y - SCROLL_MARGIN;
- needScroll = true;
- } else if (y > botRight.y - SCROLL_MARGIN) {
- // shift down
- topLeft.y = y - d.height + SCROLL_MARGIN;
- needScroll = true;
- }
- if (needScroll)
- appClass.desktopScrollPane.setScrollPosition(topLeft.x, topLeft.y);
- }
- }
-
- //
- // softCursorMove(). Moves soft cursor into a particular location.
- //
- synchronized void softCursorMove(int x, int y) {
- Point o = getImageOrigin();
- int oldX = cursorX + o.x;
- int oldY = cursorY + o.y;
- cursorX = x;
- cursorY = y;
- if (showSoftCursor) {
- scheduleCursorRepaint(oldX - hotX, oldY - hotY, cursorWidth, cursorHeight,
- 0);
- scheduleCursorRepaint(cursorX - hotX + o.x, cursorY - hotY + o.y,
- cursorWidth, cursorHeight, 1);
- if (!seekMode)
- scrollToPoint(x, y);
- }
- }
-
- //
- // softCursorFree(). Remove soft cursor, dispose resources.
- //
- synchronized void softCursorFree() {
- if (showSoftCursor) {
- showSoftCursor = false;
- softCursor = null;
- softCursorSource = null;
-
- Point p = getImageOrigin();
- scheduleCursorRepaint(cursorX - hotX + p.x, cursorY - hotY + p.y,
- cursorWidth, cursorHeight, 3);
- }
- }
-
- Point getFrameCenter() {
- Dimension d = appClass.desktopScrollPane.getViewportSize();
- Point p = appClass.desktopScrollPane.getScrollPosition();
- if (d.width > rfb.framebufferWidth)
- p.x = d.width / 2;
- else
- p.x += d.width / 2;
- if (d.height > rfb.framebufferHeight)
- p.y = d.height / 2;
- else
- p.y += d.height / 2;
- return p;
- }
-
- //
- // We are observing our FbsInputStream object to get notified on
- // switching to the `paused' mode. In such cases we want to repaint
- // our desktop if we were seeking.
- //
- public void update(Observable o, Object arg) {
- // Immediate repaint of the whole desktop after seeking.
- repaint();
- // Let next scheduleRepaint() call invoke incremental drawing.
- seekMode = false;
- }
-
- void scheduleCursorRepaint(int x, int y, int w, int h, int n) {
- if (appClass.fbs.isSeeking()) {
- // Do nothing, and remember we are seeking.
- seekMode = true;
- } else {
- if (seekMode) {
- // Immediate repaint of the whole desktop after seeking.
- seekMode = false;
- if (showSoftCursor)
- scrollToPoint(cursorX, cursorY);
- updateFramebufferSize();
- repaint();
- } else {
- // Usual incremental repaint.
- repaint(appClass.deferScreenUpdates, x, y, w, h);
- }
- }
- }
-
-}
+++ /dev/null
-<HTML>
-<TITLE>RFB Session Playback</TITLE>
-<BODY>
-<APPLET CODE=RfbPlayer.class ARCHIVE=RfbPlayer.jar
- WIDTH=800 HEIGHT=640>
-<param name=URL value="session.fbs">
-</APPLET>
-</BODY>
-</HTML>