12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679 |
- //
- // 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.Canvas;
- import java.awt.Color;
- import java.awt.Dimension;
- import java.awt.Graphics;
- import java.awt.Image;
- import java.awt.Insets;
- import java.awt.Rectangle;
- import java.awt.Toolkit;
- import java.awt.event.KeyEvent;
- import java.awt.event.KeyListener;
- import java.awt.event.MouseEvent;
- import java.awt.event.MouseListener;
- import java.awt.event.MouseMotionListener;
- import java.awt.image.ColorModel;
- import java.awt.image.DirectColorModel;
- import java.awt.image.MemoryImageSource;
- import java.io.ByteArrayInputStream;
- import java.io.DataInputStream;
- import java.io.IOException;
- import java.util.zip.Inflater;
- //
- // VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
- //
- class NoctisVncCanvas
- extends Canvas
- implements KeyListener, MouseListener, MouseMotionListener {
- VncViewer viewer;
- RfbProto rfb;
- ColorModel cm8_256c, cm8_64c, cm8_8c, 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.
- //
- NoctisVncCanvas(VncViewer v) throws IOException {
- viewer = v;
- rfb = viewer.rfb;
- tightInflaters = new Inflater[4];
- // sf@2005 - Adding more color modes
- cm8_256c = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
- cm8_64c = new DirectColorModel(8, (3 << 4), (3 << 2), (3 << 0));
- cm8_8c = new DirectColorModel(8, (1 << 2), (1 << 1), (1 << 0));
-
- cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
- colors = new Color[256];
- // sf@2005 - Now Default
- for (int i = 0; i < 256; i++)
- colors[i] = new Color(cm8_256c.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 {
- // sf@2005 - Adding more color modes
- if (viewer.options.eightBitColors > 0)
- {
- viewer.options.oldEightBitColors = viewer.options.eightBitColors;
- switch (viewer.options.eightBitColors)
- {
- case 1: // 256
- for (int i = 0; i < 256; i++)
- colors[i] = new Color(cm8_256c.getRGB(i));
- rfb.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6, false);
- break;
- case 2: // 64
- for (int i = 0; i < 256; i++)
- colors[i] = new Color(cm8_64c.getRGB(i));
- rfb.writeSetPixelFormat(8, 6, false, true, 3, 3, 3, 4, 2, 0, false);
- break;
- case 3: // 8
- for (int i = 0; i < 256; i++)
- colors[i] = new Color(cm8_8c.getRGB(i));
- rfb.writeSetPixelFormat(8, 3, false, true, 1, 1, 1, 2, 1, 0, false);
- break;
- case 4: // 4 (Grey)
- for (int i = 0; i < 256; i++)
- colors[i] = new Color(cm8_64c.getRGB(i));
- rfb.writeSetPixelFormat(8, 6, false, true, 3, 3, 3, 4, 2, 0, true);
- break;
- case 5: // 2 (B&W)
- for (int i = 0; i < 256; i++)
- colors[i] = new Color(cm8_8c.getRGB(i));
- rfb.writeSetPixelFormat(8, 3, false, true, 1, 1, 1, 2, 1, 0, true);
- break;
- }
- bytesPixel = 1;
- }
- else
- {
- rfb.writeSetPixelFormat(
- 32,
- 24,
- false,
- true,
- 255,
- 255,
- 255,
- 16,
- 8,
- 0,
- false);
- 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];
- // sf@2005
- ColorModel cml = cm8_8c;
-
- // sf@2005
- switch (viewer.options.eightBitColors)
- {
- case 1:
- cml = cm8_256c;
- break;
-
- case 2:
- case 4:
- cml = cm8_64c;
- break;
- case 3:
- case 5:
- cml = cm8_8c;
- break;
- }
-
- pixelsSource =
- new MemoryImageSource(
- fbWidth,
- fbHeight,
- cml,
- 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;
- // marscha - PointerPos
- case RfbProto.EncodingPointerPos :
- handleCursorPosUpdate(rx, ry);
- 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 > 0) && (bytesPixel != 1)
- ||
- (viewer.options.eightBitColors == 0) && (bytesPixel == 1)
- ||
- (viewer.options.eightBitColors != viewer.options.oldEightBitColors)
- )
- {
- 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;
- case RfbProto.rfbFileTransfer :
- viewer.rfb.readRfbFileTransferMsg();
- 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);
- byte[] buf = new byte[nSubrects * (bytesPixel + 8)];
- rfb.is.readFully(buf);
- DataInputStream ds = new DataInputStream(new ByteArrayInputStream(buf));
- if (rfb.rec != null) {
- rfb.rec.writeIntBE(nSubrects);
- rfb.rec.write(bg_buf);
- rfb.rec.write(buf);
- }
- int sx, sy, sw, sh;
- for (int j = 0; j < nSubrects; j++) {
- if (bytesPixel == 1) {
- pixel = colors[ds.readUnsignedByte()];
- } else {
- ds.skip(4);
- pixel =
- new Color(
- buf[j * 12 + 2] & 0xFF,
- buf[j * 12 + 1] & 0xFF,
- buf[j * 12] & 0xFF);
- }
- sx = x + ds.readUnsignedShort();
- sy = y + ds.readUnsignedShort();
- sw = ds.readUnsignedShort();
- sh = ds.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();
- 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);
- byte[] buf = new byte[nSubrects * (bytesPixel + 4)];
- rfb.is.readFully(buf);
- if (rfb.rec != null) {
- rfb.rec.writeIntBE(nSubrects);
- rfb.rec.write(bg_buf);
- rfb.rec.write(buf);
- }
- int sx, sy, sw, sh;
- int i = 0;
- for (int j = 0; j < nSubrects; j++) {
- if (bytesPixel == 1) {
- pixel = colors[buf[i++] & 0xFF];
- } else {
- pixel =
- new Color(
- buf[i + 2] & 0xFF,
- buf[i + 1] & 0xFF,
- buf[i] & 0xFF);
- i += 4;
- }
- sx = x + (buf[i++] & 0xFF);
- sy = y + (buf[i++] & 0xFF);
- sw = buf[i++] & 0xFF;
- sh = buf[i++] & 0xFF;
- 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 {
- int subencoding = rfb.is.readUnsignedByte();
- if (rfb.rec != null) {
- rfb.rec.writeByte(subencoding);
- }
- // Is it a raw-encoded sub-rectangle?
- if ((subencoding & rfb.HextileRaw) != 0) {
- handleRawRect(tx, ty, tw, th, false);
- return;
- }
- // Read and draw the background if specified.
- byte[] cbuf = new byte[bytesPixel];
- if ((subencoding & rfb.HextileBackgroundSpecified) != 0) {
- rfb.is.readFully(cbuf);
- if (bytesPixel == 1) {
- hextile_bg = colors[cbuf[0] & 0xFF];
- } else {
- hextile_bg =
- new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
- }
- if (rfb.rec != null) {
- rfb.rec.write(cbuf);
- }
- }
- memGraphics.setColor(hextile_bg);
- memGraphics.fillRect(tx, ty, tw, th);
- // Read the foreground color if specified.
- if ((subencoding & rfb.HextileForegroundSpecified) != 0) {
- rfb.is.readFully(cbuf);
- if (bytesPixel == 1) {
- hextile_fg = colors[cbuf[0] & 0xFF];
- } else {
- hextile_fg =
- new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
- }
- if (rfb.rec != null) {
- rfb.rec.write(cbuf);
- }
- }
- // Done with this tile if there is no sub-rectangles.
- if ((subencoding & rfb.HextileAnySubrects) == 0)
- return;
- int nSubrects = rfb.is.readUnsignedByte();
- int bufsize = nSubrects * 2;
- if ((subencoding & rfb.HextileSubrectsColoured) != 0) {
- bufsize += nSubrects * bytesPixel;
- }
- byte[] buf = new byte[bufsize];
- rfb.is.readFully(buf);
- if (rfb.rec != null) {
- rfb.rec.writeByte(nSubrects);
- rfb.rec.write(buf);
- }
- int b1, b2, sx, sy, sw, sh;
- int i = 0;
- if ((subencoding & rfb.HextileSubrectsColoured) == 0) {
- // Sub-rectangles are all of the same color.
- memGraphics.setColor(hextile_fg);
- for (int j = 0; j < nSubrects; j++) {
- b1 = buf[i++] & 0xFF;
- b2 = buf[i++] & 0xFF;
- sx = tx + (b1 >> 4);
- sy = ty + (b1 & 0xf);
- sw = (b2 >> 4) + 1;
- sh = (b2 & 0xf) + 1;
- memGraphics.fillRect(sx, sy, sw, sh);
- }
- } else if (bytesPixel == 1) {
- // BGR233 (8-bit color) version for colored sub-rectangles.
- for (int j = 0; j < nSubrects; j++) {
- hextile_fg = colors[buf[i++] & 0xFF];
- b1 = buf[i++] & 0xFF;
- b2 = buf[i++] & 0xFF;
- 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 {
- // Full-color (24-bit) version for colored sub-rectangles.
- for (int j = 0; j < nSubrects; j++) {
- hextile_fg =
- new Color(
- buf[i + 2] & 0xFF,
- buf[i + 1] & 0xFF,
- buf[i] & 0xFF);
- i += 4;
- b1 = buf[i++] & 0xFF;
- b2 = buf[i++] & 0xFF;
- 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);
- }
- }
- }
- //
- // 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);
- if (rfb.rec != null && rfb.recordFromBeginning) {
- rfb.rec.writeIntBE(nBytes);
- rfb.rec.write(zlibBuf, 0, nBytes);
- }
- if (zlibInflater == null) {
- zlibInflater = new Inflater();
- }
- zlibInflater.setInput(zlibBuf, 0, nBytes);
- if (bytesPixel == 1) {
- for (int dy = y; dy < y + h; dy++) {
- zlibInflater.inflate(pixels8, dy * rfb.framebufferWidth + x, w);
- if (rfb.rec != null && !rfb.recordFromBeginning)
- 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++) {
- 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);
- }
- if (rfb.rec != null && !rfb.recordFromBeginning)
- rfb.rec.write(buf);
- }
- }
- 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();
- if (rfb.rec != null) {
- if (rfb.recordFromBeginning
- || comp_ctl == (rfb.TightFill << 4)
- || comp_ctl == (rfb.TightJpeg << 4)) {
- // Send data exactly as received.
- rfb.rec.writeByte(comp_ctl);
- } else {
- // Tell the decoder to flush each of the four zlib streams.
- rfb.rec.writeByte(comp_ctl | 0x0F);
- }
- }
- // 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) {
- if (bytesPixel == 1) {
- int idx = rfb.is.readUnsignedByte();
- memGraphics.setColor(colors[idx]);
- if (rfb.rec != null) {
- rfb.rec.writeByte(idx);
- }
- } else {
- byte[] buf = new byte[3];
- rfb.is.readFully(buf);
- if (rfb.rec != null) {
- rfb.rec.write(buf);
- }
- Color bg =
- new Color(
- 0xFF000000 | (buf[0] & 0xFF)
- << 16 | (buf[1] & 0xFF)
- << 8 | (buf[2] & 0xFF));
- memGraphics.setColor(bg);
- }
- memGraphics.fillRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- return;
- }
- if (comp_ctl == rfb.TightJpeg) {
- // Read JPEG data.
- byte[] jpegData = new byte[rfb.readCompactLen()];
- rfb.is.readFully(jpegData);
- if (rfb.rec != null) {
- if (!rfb.recordFromBeginning) {
- rfb.recordCompactLen(jpegData.length);
- }
- rfb.rec.write(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;
- byte[] palette8 = new byte[2];
- int[] palette24 = new int[256];
- boolean useGradient = false;
- if ((comp_ctl & rfb.TightExplicitFilter) != 0) {
- int filter_id = rfb.is.readUnsignedByte();
- if (rfb.rec != null) {
- rfb.rec.writeByte(filter_id);
- }
- if (filter_id == rfb.TightFilterPalette) {
- numColors = rfb.is.readUnsignedByte() + 1;
- if (rfb.rec != null) {
- rfb.rec.writeByte(numColors - 1);
- }
- if (bytesPixel == 1) {
- if (numColors != 2) {
- throw new Exception(
- "Incorrect tight palette size: " + numColors);
- }
- rfb.is.readFully(palette8);
- if (rfb.rec != null) {
- rfb.rec.write(palette8);
- }
- } else {
- byte[] buf = new byte[numColors * 3];
- rfb.is.readFully(buf);
- if (rfb.rec != null) {
- rfb.rec.write(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 (rfb.rec != null) {
- rfb.rec.write(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);
- if (rfb.rec != null) {
- rfb.rec.write(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);
- if (rfb.rec != null && rfb.recordFromBeginning) {
- rfb.rec.write(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);
- byte[] buf = new byte[dataSize];
- myInflater.inflate(buf);
- if (rfb.rec != null && !rfb.recordFromBeginning) {
- rfb.recordCompressedData(buf);
- }
- if (numColors != 0) {
- // Indexed colors.
- if (numColors == 2) {
- // Two colors.
- if (bytesPixel == 1) {
- decodeMonoData(x, y, w, h, buf, palette8);
- } else {
- decodeMonoData(x, y, w, h, buf, palette24);
- }
- } else {
- // More than two 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[buf[i++] & 0xFF];
- }
- }
- }
- } else if (useGradient) {
- // Compressed "Gradient"-filtered data (assuming bytesPixel == 4).
- decodeGradientData(x, y, w, h, buf);
- } else {
- // Compressed truecolor data.
- if (bytesPixel == 1) {
- int destOffset = y * rfb.framebufferWidth + x;
- for (int dy = 0; dy < h; dy++) {
- System.arraycopy(buf, dy * w, pixels8, destOffset, w);
- destOffset += rfb.framebufferWidth;
- }
- } else {
- int srcOffset = 0;
- int destOffset, i;
- for (int dy = 0; dy < h; dy++) {
- myInflater.inflate(buf);
- destOffset = (y + dy) * rfb.framebufferWidth + x;
- for (i = 0; i < w; i++) {
- pixels24[destOffset + i] =
- (buf[srcOffset] & 0xFF)
- << 16 | (buf[srcOffset + 1] & 0xFF)
- << 8 | (buf[srcOffset + 2] & 0xFF);
- srcOffset += 3;
- }
- }
- }
- }
- }
- 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) {
- // Request repaint, deferred if necessary.
- repaint(viewer.deferScreenUpdates, x, y, w, h);
- }
- //
- // Handle events.
- //
- public void keyPressed(KeyEvent evt) {
- processLocalKeyEvent(evt);
- }
- public void keyReleased(KeyEvent evt) {
- processLocalKeyEvent(evt);
- }
- public void keyTyped(KeyEvent evt) {
- evt.consume();
- }
- public void mousePressed(MouseEvent evt) {
- processLocalMouseEvent(evt, false);
- }
- public void mouseReleased(MouseEvent evt) {
- processLocalMouseEvent(evt, false);
- }
- public void mouseMoved(MouseEvent evt) {
- processLocalMouseEvent(evt, true);
- }
- public void mouseDragged(MouseEvent evt) {
- processLocalMouseEvent(evt, true);
- }
- public void processLocalKeyEvent(KeyEvent evt) {
- if (viewer.rfb != null && rfb.inNormalProtocol) {
- if (!inputEnabled) {
- if ((evt.getKeyChar() == 'r' || evt.getKeyChar() == 'R')
- && evt.getID() == KeyEvent.KEY_PRESSED) {
- // Request screen update.
- try {
- rfb.writeFramebufferUpdateRequest(
- 0,
- 0,
- rfb.framebufferWidth,
- rfb.framebufferHeight,
- false);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- } else {
- // Input enabled.
- synchronized (rfb) {
- try {
- rfb.writeKeyEvent(evt);
- } catch (Exception e) {
- e.printStackTrace();
- }
- rfb.notify();
- }
- }
- }
- // Don't ever pass keyboard events to AWT for default processing.
- // Otherwise, pressing Tab would switch focus to ButtonPanel etc.
- evt.consume();
- }
- public void processLocalMouseEvent(MouseEvent evt, boolean moved) {
- if (viewer.rfb != null && rfb.inNormalProtocol) {
- if (moved) {
- softCursorMove(evt.getX(), evt.getY());
- }
- synchronized (rfb) {
- try {
- rfb.writePointerEvent(evt);
- } catch (Exception e) {
- e.printStackTrace();
- }
- rfb.notify();
- }
- }
- }
- //
- // Ignored events.
- //
- public void mouseClicked(MouseEvent evt) {
- }
- public void mouseEntered(MouseEvent evt) {
- }
- public void mouseExited(MouseEvent evt) {
- }
- //////////////////////////////////////////////////////////////////
- //
- // Handle cursor shape updates (XCursor and RichCursor encodings).
- //
- boolean showSoftCursor = false;
- int[] softCursorPixels;
- MemoryImageSource softCursorSource;
- Image softCursor;
- int cursorX = 0, cursorY = 0;
- int cursorWidth, cursorHeight;
- int hotX, hotY;
- //
- // Handle cursor shape update (XCursor and RichCursor encodings).
- //
- synchronized void handleCursorShapeUpdate(
- int encodingType,
- int xhot,
- int yhot,
- int width,
- int height)
- throws IOException {
- int bytesPerRow = (width + 7) / 8;
- int bytesMaskData = bytesPerRow * height;
- softCursorFree();
- if (width * height == 0)
- return;
- // Ignore cursor shape data if requested by user.
- if (viewer.options.ignoreCursorUpdates) {
- if (encodingType == rfb.EncodingXCursor) {
- rfb.is.skipBytes(6 + bytesMaskData * 2);
- } else {
- // rfb.EncodingRichCursor
- rfb.is.skipBytes(width * height + bytesMaskData);
- }
- return;
- }
- // Decode cursor pixel data.
- softCursorPixels = new int[width * height];
- if (encodingType == rfb.EncodingXCursor) {
- // Read foreground and background colors of the cursor.
- byte[] rgb = new byte[6];
- rfb.is.readFully(rgb);
- int[] colors =
- {
- (0xFF000000 | (rgb[3] & 0xFF)
- << 16 | (rgb[4] & 0xFF)
- << 8 | (rgb[5] & 0xFF)),
- (0xFF000000 | (rgb[0] & 0xFF)
- << 16 | (rgb[1] & 0xFF)
- << 8 | (rgb[2] & 0xFF))};
- // Read pixel and mask data.
- byte[] pixBuf = new byte[bytesMaskData];
- rfb.is.readFully(pixBuf);
- byte[] maskBuf = new byte[bytesMaskData];
- rfb.is.readFully(maskBuf);
- // Decode pixel data into softCursorPixels[].
- byte pixByte, maskByte;
- int x, y, n, result;
- int i = 0;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width / 8; x++) {
- pixByte = pixBuf[y * bytesPerRow + x];
- maskByte = maskBuf[y * bytesPerRow + x];
- for (n = 7; n >= 0; n--) {
- if ((maskByte >> n & 1) != 0) {
- result = colors[pixByte >> n & 1];
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
- for (n = 7; n >= 8 - width % 8; n--) {
- if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
- result = colors[pixBuf[y * bytesPerRow + x] >> n & 1];
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
- } else {
- // encodingType == rfb.EncodingRichCursor
- // Read pixel and mask data.
- byte[] pixBuf = new byte[width * height * bytesPixel];
- rfb.is.readFully(pixBuf);
- byte[] maskBuf = new byte[bytesMaskData];
- rfb.is.readFully(maskBuf);
- // Decode pixel data into softCursorPixels[].
- byte pixByte, maskByte;
- int x, y, n, result;
- int i = 0;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width / 8; x++) {
- maskByte = maskBuf[y * bytesPerRow + x];
- for (n = 7; n >= 0; n--) {
- if ((maskByte >> n & 1) != 0) {
- if (bytesPixel == 1)
- {
- result = 0;
- // sf@2005
- switch (viewer.options.eightBitColors)
- {
- case 1:
- result = cm8_256c.getRGB(pixBuf[i]);
- break;
- case 2:
- case 4:
- result = cm8_64c.getRGB(pixBuf[i]);
- break;
- case 3:
- case 5:
- result = cm8_8c.getRGB(pixBuf[i]);
- break;
- }
- }
- else
- {
- result =
- 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
- << 16 | (pixBuf[i * 4 + 2] & 0xFF)
- << 8 | (pixBuf[i * 4 + 3] & 0xFF);
- }
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
- for (n = 7; n >= 8 - width % 8; n--) {
- if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
- if (bytesPixel == 1)
- {
- result = 0;
- // sf@2005
- switch (viewer.options.eightBitColors)
- {
- case 1:
- result = cm8_256c.getRGB(pixBuf[i]);
- break;
- case 2:
- case 4:
- result = cm8_64c.getRGB(pixBuf[i]);
- break;
- case 3:
- case 5:
- result = cm8_8c.getRGB(pixBuf[i]);
- break;
- } }
- else
- {
- result =
- 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
- << 16 | (pixBuf[i * 4 + 2] & 0xFF)
- << 8 | (pixBuf[i * 4 + 3] & 0xFF);
- }
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
- }
- // Draw the cursor on an off-screen image.
- softCursorSource =
- new MemoryImageSource(width, height, softCursorPixels, 0, width);
- softCursor = createImage(softCursorSource);
- // Set remaining data associated with cursor.
- cursorWidth = width;
- cursorHeight = height;
- hotX = xhot;
- hotY = yhot;
- showSoftCursor = true;
- // Show the cursor.
- repaint(
- viewer.deferCursorUpdates,
- cursorX - hotX,
- cursorY - hotY,
- cursorWidth,
- cursorHeight);
- }
- //
- // marscha - PointerPos
- // Handle cursor position update (PointerPos encoding).
- //
- synchronized void handleCursorPosUpdate(
- int x,
- int y) {
- if (x >= rfb.framebufferWidth)
- x = rfb.framebufferWidth - 1;
- if (y >= rfb.framebufferHeight)
- y = rfb.framebufferHeight - 1;
- softCursorMove(x, y);
- }
-
- //
- // softCursorMove(). Moves soft cursor into a particular location.
- //
- synchronized void softCursorMove(int x, int y) {
- if (showSoftCursor) {
- repaint(
- viewer.deferCursorUpdates,
- cursorX - hotX,
- cursorY - hotY,
- cursorWidth,
- cursorHeight);
- repaint(
- viewer.deferCursorUpdates,
- x - hotX,
- y - hotY,
- cursorWidth,
- cursorHeight);
- }
- cursorX = x;
- cursorY = y;
- }
- //
- // softCursorFree(). Remove soft cursor, dispose resources.
- //
- synchronized void softCursorFree() {
- if (showSoftCursor) {
- showSoftCursor = false;
- softCursor = null;
- softCursorSource = null;
- softCursorPixels = null;
- repaint(
- viewer.deferCursorUpdates,
- cursorX - hotX,
- cursorY - hotY,
- cursorWidth,
- cursorHeight);
- }
- }
- }
|