⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vnccanvas.java

📁 teamviewer source code vc++
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
//
//  Copyright (C) 2001,2002 HorizonLive.com, Inc.  All Rights Reserved.
//  Copyright (C) 2001,2002 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.
//

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.lang.*;
import java.util.zip.*;


//
// VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
//

class VncCanvas extends Canvas
  implements KeyListener, MouseListener, MouseMotionListener {

  VncViewer viewer;
  RfbProto rfb;
  ColorModel cm8, cm24;
  Color[] colors;
  int bytesPixel;

  Image memImage;
  Graphics memGraphics;

  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;

  // True if we process keyboard and mouse events.
  boolean inputEnabled;

  //
  // The constructor.
  //

  VncCanvas(VncViewer v) throws IOException {
    viewer = v;
    rfb = viewer.rfb;

    tightInflaters = new Inflater[4];

    cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
    cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);

    colors = new Color[256];
    for (int i = 0; i < 256; i++)
      colors[i] = new Color(cm8.getRGB(i));

    setPixelFormat();

    inputEnabled = false;
    if (!viewer.options.viewOnly)
      enableInput(true);

    // Keyboard listener is enabled even in view-only mode, to catch
    // 'r' or 'R' key presses used to request screen update.
    addKeyListener(this);
  }

  //
  // Callback methods to determine geometry of our Component.
  //

  public Dimension getPreferredSize() {
    return new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
  }

  public Dimension getMinimumSize() {
    return new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
  }

  public Dimension getMaximumSize() {
    return new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
  }

  //
  // All painting is performed here.
  //

  public void update(Graphics g) {
    paint(g);
  }

  public void paint(Graphics g) {
    synchronized(memImage) {
      g.drawImage(memImage, 0, 0, null);
    }
    if (showSoftCursor) {
      int x0 = cursorX - hotX, y0 = cursorY - hotY;
      Rectangle r = new Rectangle(x0, y0, cursorWidth, cursorHeight);
      if (r.intersects(g.getClipBounds())) {
	g.drawImage(softCursor, x0, y0, null);
      }
    }
  }

  //
  // 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.
    }
  }

  //
  // Start/stop receiving mouse events. Keyboard events are received
  // even in view-only mode, because we want to map the 'r' key to the
  // screen refreshing function.
  //

  public synchronized void enableInput(boolean enable) {
    if (enable && !inputEnabled) {
      inputEnabled = true;
      addMouseListener(this);
      addMouseMotionListener(this);
      if (viewer.showControls) {
	viewer.buttonPanel.enableRemoteAccessControls(true);
      }
    } else if (!enable && inputEnabled) {
      inputEnabled = false;
      removeMouseListener(this);
      removeMouseMotionListener(this);
      if (viewer.showControls) {
	viewer.buttonPanel.enableRemoteAccessControls(false);
      }
    }
  }

  public void setPixelFormat() throws IOException {
    if (viewer.options.eightBitColors) {
      rfb.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6);
      bytesPixel = 1;
    } else {
      rfb.writeSetPixelFormat(32, 24, false, true, 255, 255, 255, 16, 8, 0);
      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 = viewer.createImage(fbWidth, fbHeight);
      memGraphics = memImage.getGraphics();
    } else if (memImage.getWidth(null) != fbWidth ||
	       memImage.getHeight(null) != fbHeight) {
      synchronized(memImage) {
	memImage = viewer.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.
    if (viewer.inSeparateFrame) {
      if (viewer.desktopScrollPane != null)
	resizeDesktopFrame();
    } else {
      setSize(fbWidth, fbHeight);
    }
  }

  void resizeDesktopFrame() {
    setSize(rfb.framebufferWidth, rfb.framebufferHeight);

    // FIXME: Find a better way to determine correct size of a
    // ScrollPane.  -- const
    Insets insets = viewer.desktopScrollPane.getInsets();
    viewer.desktopScrollPane.setSize(rfb.framebufferWidth +
				     2 * Math.min(insets.left, insets.right),
				     rfb.framebufferHeight +
				     2 * Math.min(insets.top, insets.bottom));

    viewer.vncFrame.pack();

    // Try to limit the frame size to the screen size.
    Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize();
    Dimension frameSize = viewer.vncFrame.getSize();
    Dimension newSize = frameSize;
    boolean needToResizeFrame = false;
    if (frameSize.height > screenSize.height) {
      newSize.height = screenSize.height;
      needToResizeFrame = true;
    }
    if (frameSize.width > screenSize.width) {
      newSize.width = screenSize.width;
      needToResizeFrame = true;
    }
    if (needToResizeFrame) {
      viewer.vncFrame.setSize(newSize);
    }

    viewer.desktopScrollPane.doLayout();
  }

  //
  // processNormalProtocol() - executed by the rfbThread to deal with the
  // RFB socket.
  //

  public void processNormalProtocol() throws Exception {

    // Start/stop session recording if necessary.
    viewer.checkRecordingStatus();

    rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
				      rfb.framebufferHeight, false);

    //
    // main dispatch loop
    //

    while (true) {

      // Read message type from the server.
      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) {
	    rfb.setFramebufferSize(rw, rh);
	    updateFramebufferSize();
	    break;
	  }

	  if (rfb.updateRectEncoding == rfb.EncodingXCursor ||
	      rfb.updateRectEncoding == rfb.EncodingRichCursor) {
	    handleCursorShapeUpdate(rfb.updateRectEncoding, rx, ry, rw, rh);
	    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 " +
				rfb.updateRectEncoding);
	  }
	}

	boolean fullUpdateNeeded = false;

	// Start/stop session recording if necessary. Request full
	// update if a new session file was opened.
	if (viewer.checkRecordingStatus())
	  fullUpdateNeeded = true;

	// Defer framebuffer update request if necessary. But wake up
	// immediately on keyboard or mouse event.
	if (viewer.deferUpdateRequests > 0) {
	  synchronized(rfb) {
	    try {
	      rfb.wait(viewer.deferUpdateRequests);
	    } catch (InterruptedException e) {
	    }
	  }
	}

	// Before requesting framebuffer update, check if the pixel
	// format should be changed. If it should, request full update
	// instead of an incremental one.
	if (viewer.options.eightBitColors != (bytesPixel == 1)) {
	  setPixelFormat();
	  fullUpdateNeeded = true;
	}

	rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
					  rfb.framebufferHeight,
					  !fullUpdateNeeded);

	break;

      case RfbProto.SetColourMapEntries:
	throw new Exception("Can't handle SetColourMapEntries message");

      case RfbProto.Bell:
        Toolkit.getDefaultToolkit().beep();
	break;

      case RfbProto.ServerCutText:
	String s = rfb.readServerCutText();
	viewer.clipboard.setCutText(s);
	break;

      default:
	throw new Exception("Unknown RFB message type " + msgType);
      }
    }
  }


  //
  // 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();

    byte[] bg_buf = new byte[bytesPixel];
    rfb.is.readFully(bg_buf);
    Color pixel;
    if (bytesPixel == 1) {
      pixel = colors[bg_buf[0] & 0xFF];
    } else {
      pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF);
    }
    memGraphics.setColor(pixel);
    memGraphics.fillRect(x, y, w, h);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -