NoctisVncCanvas.java 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679
  1. //
  2. // Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
  3. // Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved.
  4. // Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
  5. // Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
  6. //
  7. // This is free software; you can redistribute it and/or modify
  8. // it under the terms of the GNU General Public License as published by
  9. // the Free Software Foundation; either version 2 of the License, or
  10. // (at your option) any later version.
  11. //
  12. // This software is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. // GNU General Public License for more details.
  16. //
  17. // You should have received a copy of the GNU General Public License
  18. // along with this software; if not, write to the Free Software
  19. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  20. // USA.
  21. //
  22. import java.awt.Canvas;
  23. import java.awt.Color;
  24. import java.awt.Dimension;
  25. import java.awt.Graphics;
  26. import java.awt.Image;
  27. import java.awt.Insets;
  28. import java.awt.Rectangle;
  29. import java.awt.Toolkit;
  30. import java.awt.event.KeyEvent;
  31. import java.awt.event.KeyListener;
  32. import java.awt.event.MouseEvent;
  33. import java.awt.event.MouseListener;
  34. import java.awt.event.MouseMotionListener;
  35. import java.awt.image.ColorModel;
  36. import java.awt.image.DirectColorModel;
  37. import java.awt.image.MemoryImageSource;
  38. import java.io.ByteArrayInputStream;
  39. import java.io.DataInputStream;
  40. import java.io.IOException;
  41. import java.util.zip.Inflater;
  42. //
  43. // VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
  44. //
  45. class NoctisVncCanvas
  46. extends Canvas
  47. implements KeyListener, MouseListener, MouseMotionListener {
  48. VncViewer viewer;
  49. RfbProto rfb;
  50. ColorModel cm8_256c, cm8_64c, cm8_8c, cm24;
  51. Color[] colors;
  52. int bytesPixel;
  53. Image memImage;
  54. Graphics memGraphics;
  55. Image rawPixelsImage;
  56. MemoryImageSource pixelsSource;
  57. byte[] pixels8;
  58. int[] pixels24;
  59. // Zlib encoder's data.
  60. byte[] zlibBuf;
  61. int zlibBufLen = 0;
  62. Inflater zlibInflater;
  63. // Tight encoder's data.
  64. final static int tightZlibBufferSize = 512;
  65. Inflater[] tightInflaters;
  66. // Since JPEG images are loaded asynchronously, we have to remember
  67. // their position in the framebuffer. Also, this jpegRect object is
  68. // used for synchronization between the rfbThread and a JVM's thread
  69. // which decodes and loads JPEG images.
  70. Rectangle jpegRect;
  71. // True if we process keyboard and mouse events.
  72. boolean inputEnabled;
  73. //
  74. // The constructor.
  75. //
  76. NoctisVncCanvas(VncViewer v) throws IOException {
  77. viewer = v;
  78. rfb = viewer.rfb;
  79. tightInflaters = new Inflater[4];
  80. // sf@2005 - Adding more color modes
  81. cm8_256c = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
  82. cm8_64c = new DirectColorModel(8, (3 << 4), (3 << 2), (3 << 0));
  83. cm8_8c = new DirectColorModel(8, (1 << 2), (1 << 1), (1 << 0));
  84. cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
  85. colors = new Color[256];
  86. // sf@2005 - Now Default
  87. for (int i = 0; i < 256; i++)
  88. colors[i] = new Color(cm8_256c.getRGB(i));
  89. setPixelFormat();
  90. inputEnabled = false;
  91. if (!viewer.options.viewOnly)
  92. enableInput(true);
  93. // Keyboard listener is enabled even in view-only mode, to catch
  94. // 'r' or 'R' key presses used to request screen update.
  95. addKeyListener(this);
  96. }
  97. //
  98. // Callback methods to determine geometry of our Component.
  99. //
  100. public Dimension getPreferredSize() {
  101. return new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
  102. }
  103. public Dimension getMinimumSize() {
  104. return new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
  105. }
  106. public Dimension getMaximumSize() {
  107. return new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
  108. }
  109. //
  110. // All painting is performed here.
  111. //
  112. public void update(Graphics g) {
  113. paint(g);
  114. }
  115. public void paint(Graphics g) {
  116. synchronized (memImage) {
  117. g.drawImage(memImage, 0, 0, null);
  118. }
  119. if (showSoftCursor) {
  120. int x0 = cursorX - hotX, y0 = cursorY - hotY;
  121. Rectangle r = new Rectangle(x0, y0, cursorWidth, cursorHeight);
  122. if (r.intersects(g.getClipBounds())) {
  123. g.drawImage(softCursor, x0, y0, null);
  124. }
  125. }
  126. }
  127. //
  128. // Override the ImageObserver interface method to handle drawing of
  129. // JPEG-encoded data.
  130. //
  131. public boolean imageUpdate(
  132. Image img,
  133. int infoflags,
  134. int x,
  135. int y,
  136. int width,
  137. int height) {
  138. if ((infoflags & (ALLBITS | ABORT)) == 0) {
  139. return true; // We need more image data.
  140. } else {
  141. // If the whole image is available, draw it now.
  142. if ((infoflags & ALLBITS) != 0) {
  143. if (jpegRect != null) {
  144. synchronized (jpegRect) {
  145. memGraphics.drawImage(
  146. img,
  147. jpegRect.x,
  148. jpegRect.y,
  149. null);
  150. scheduleRepaint(
  151. jpegRect.x,
  152. jpegRect.y,
  153. jpegRect.width,
  154. jpegRect.height);
  155. jpegRect.notify();
  156. }
  157. }
  158. }
  159. return false; // All image data was processed.
  160. }
  161. }
  162. //
  163. // Start/stop receiving mouse events. Keyboard events are received
  164. // even in view-only mode, because we want to map the 'r' key to the
  165. // screen refreshing function.
  166. //
  167. public synchronized void enableInput(boolean enable) {
  168. if (enable && !inputEnabled) {
  169. inputEnabled = true;
  170. addMouseListener(this);
  171. addMouseMotionListener(this);
  172. if (viewer.showControls) {
  173. viewer.buttonPanel.enableRemoteAccessControls(true);
  174. }
  175. } else if (!enable && inputEnabled) {
  176. inputEnabled = false;
  177. removeMouseListener(this);
  178. removeMouseMotionListener(this);
  179. if (viewer.showControls) {
  180. viewer.buttonPanel.enableRemoteAccessControls(false);
  181. }
  182. }
  183. }
  184. public void setPixelFormat() throws IOException {
  185. // sf@2005 - Adding more color modes
  186. if (viewer.options.eightBitColors > 0)
  187. {
  188. viewer.options.oldEightBitColors = viewer.options.eightBitColors;
  189. switch (viewer.options.eightBitColors)
  190. {
  191. case 1: // 256
  192. for (int i = 0; i < 256; i++)
  193. colors[i] = new Color(cm8_256c.getRGB(i));
  194. rfb.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6, false);
  195. break;
  196. case 2: // 64
  197. for (int i = 0; i < 256; i++)
  198. colors[i] = new Color(cm8_64c.getRGB(i));
  199. rfb.writeSetPixelFormat(8, 6, false, true, 3, 3, 3, 4, 2, 0, false);
  200. break;
  201. case 3: // 8
  202. for (int i = 0; i < 256; i++)
  203. colors[i] = new Color(cm8_8c.getRGB(i));
  204. rfb.writeSetPixelFormat(8, 3, false, true, 1, 1, 1, 2, 1, 0, false);
  205. break;
  206. case 4: // 4 (Grey)
  207. for (int i = 0; i < 256; i++)
  208. colors[i] = new Color(cm8_64c.getRGB(i));
  209. rfb.writeSetPixelFormat(8, 6, false, true, 3, 3, 3, 4, 2, 0, true);
  210. break;
  211. case 5: // 2 (B&W)
  212. for (int i = 0; i < 256; i++)
  213. colors[i] = new Color(cm8_8c.getRGB(i));
  214. rfb.writeSetPixelFormat(8, 3, false, true, 1, 1, 1, 2, 1, 0, true);
  215. break;
  216. }
  217. bytesPixel = 1;
  218. }
  219. else
  220. {
  221. rfb.writeSetPixelFormat(
  222. 32,
  223. 24,
  224. false,
  225. true,
  226. 255,
  227. 255,
  228. 255,
  229. 16,
  230. 8,
  231. 0,
  232. false);
  233. bytesPixel = 4;
  234. }
  235. updateFramebufferSize();
  236. }
  237. void updateFramebufferSize() {
  238. // Useful shortcuts.
  239. int fbWidth = rfb.framebufferWidth;
  240. int fbHeight = rfb.framebufferHeight;
  241. // Create new off-screen image either if it does not exist, or if
  242. // its geometry should be changed. It's not necessary to replace
  243. // existing image if only pixel format should be changed.
  244. if (memImage == null) {
  245. memImage = viewer.createImage(fbWidth, fbHeight);
  246. memGraphics = memImage.getGraphics();
  247. } else if (
  248. memImage.getWidth(null) != fbWidth
  249. || memImage.getHeight(null) != fbHeight) {
  250. synchronized (memImage) {
  251. memImage = viewer.createImage(fbWidth, fbHeight);
  252. memGraphics = memImage.getGraphics();
  253. }
  254. }
  255. // Images with raw pixels should be re-allocated on every change
  256. // of geometry or pixel format.
  257. if (bytesPixel == 1) {
  258. pixels24 = null;
  259. pixels8 = new byte[fbWidth * fbHeight];
  260. // sf@2005
  261. ColorModel cml = cm8_8c;
  262. // sf@2005
  263. switch (viewer.options.eightBitColors)
  264. {
  265. case 1:
  266. cml = cm8_256c;
  267. break;
  268. case 2:
  269. case 4:
  270. cml = cm8_64c;
  271. break;
  272. case 3:
  273. case 5:
  274. cml = cm8_8c;
  275. break;
  276. }
  277. pixelsSource =
  278. new MemoryImageSource(
  279. fbWidth,
  280. fbHeight,
  281. cml,
  282. pixels8,
  283. 0,
  284. fbWidth);
  285. } else {
  286. pixels8 = null;
  287. pixels24 = new int[fbWidth * fbHeight];
  288. pixelsSource =
  289. new MemoryImageSource(
  290. fbWidth,
  291. fbHeight,
  292. cm24,
  293. pixels24,
  294. 0,
  295. fbWidth);
  296. }
  297. pixelsSource.setAnimated(true);
  298. rawPixelsImage = createImage(pixelsSource);
  299. // Update the size of desktop containers.
  300. if (viewer.inSeparateFrame) {
  301. if (viewer.desktopScrollPane != null)
  302. resizeDesktopFrame();
  303. } else {
  304. setSize(fbWidth, fbHeight);
  305. }
  306. }
  307. void resizeDesktopFrame() {
  308. setSize(rfb.framebufferWidth, rfb.framebufferHeight);
  309. // FIXME: Find a better way to determine correct size of a
  310. // ScrollPane. -- const
  311. Insets insets = viewer.desktopScrollPane.getInsets();
  312. viewer.desktopScrollPane.setSize(
  313. rfb.framebufferWidth + 2 * Math.min(insets.left, insets.right),
  314. rfb.framebufferHeight + 2 * Math.min(insets.top, insets.bottom));
  315. viewer.vncFrame.pack();
  316. // Try to limit the frame size to the screen size.
  317. Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize();
  318. Dimension frameSize = viewer.vncFrame.getSize();
  319. Dimension newSize = frameSize;
  320. boolean needToResizeFrame = false;
  321. if (frameSize.height > screenSize.height) {
  322. newSize.height = screenSize.height;
  323. needToResizeFrame = true;
  324. }
  325. if (frameSize.width > screenSize.width) {
  326. newSize.width = screenSize.width;
  327. needToResizeFrame = true;
  328. }
  329. if (needToResizeFrame) {
  330. viewer.vncFrame.setSize(newSize);
  331. }
  332. viewer.desktopScrollPane.doLayout();
  333. }
  334. //
  335. // processNormalProtocol() - executed by the rfbThread to deal with the
  336. // RFB socket.
  337. //
  338. public void processNormalProtocol() throws Exception {
  339. // Start/stop session recording if necessary.
  340. viewer.checkRecordingStatus();
  341. rfb.writeFramebufferUpdateRequest(
  342. 0,
  343. 0,
  344. rfb.framebufferWidth,
  345. rfb.framebufferHeight,
  346. false);
  347. //
  348. // main dispatch loop
  349. //
  350. while (true) {
  351. // Read message type from the server.
  352. int msgType = rfb.readServerMessageType();
  353. // Process the message depending on its type.
  354. switch (msgType) {
  355. case RfbProto.FramebufferUpdate :
  356. rfb.readFramebufferUpdate();
  357. for (int i = 0; i < rfb.updateNRects; i++) {
  358. rfb.readFramebufferUpdateRectHdr();
  359. int rx = rfb.updateRectX, ry = rfb.updateRectY;
  360. int rw = rfb.updateRectW, rh = rfb.updateRectH;
  361. if (rfb.updateRectEncoding == rfb.EncodingLastRect)
  362. break;
  363. if (rfb.updateRectEncoding == rfb.EncodingNewFBSize) {
  364. rfb.setFramebufferSize(rw, rh);
  365. updateFramebufferSize();
  366. break;
  367. }
  368. if (rfb.updateRectEncoding == rfb.EncodingXCursor
  369. || rfb.updateRectEncoding == rfb.EncodingRichCursor) {
  370. handleCursorShapeUpdate(
  371. rfb.updateRectEncoding,
  372. rx,
  373. ry,
  374. rw,
  375. rh);
  376. continue;
  377. }
  378. switch (rfb.updateRectEncoding) {
  379. case RfbProto.EncodingRaw :
  380. handleRawRect(rx, ry, rw, rh);
  381. break;
  382. case RfbProto.EncodingCopyRect :
  383. handleCopyRect(rx, ry, rw, rh);
  384. break;
  385. case RfbProto.EncodingRRE :
  386. handleRRERect(rx, ry, rw, rh);
  387. break;
  388. case RfbProto.EncodingCoRRE :
  389. handleCoRRERect(rx, ry, rw, rh);
  390. break;
  391. case RfbProto.EncodingHextile :
  392. handleHextileRect(rx, ry, rw, rh);
  393. break;
  394. case RfbProto.EncodingZlib :
  395. handleZlibRect(rx, ry, rw, rh);
  396. break;
  397. case RfbProto.EncodingTight :
  398. handleTightRect(rx, ry, rw, rh);
  399. break;
  400. // marscha - PointerPos
  401. case RfbProto.EncodingPointerPos :
  402. handleCursorPosUpdate(rx, ry);
  403. break;
  404. default :
  405. throw new Exception(
  406. "Unknown RFB rectangle encoding "
  407. + rfb.updateRectEncoding);
  408. }
  409. }
  410. boolean fullUpdateNeeded = false;
  411. // Start/stop session recording if necessary. Request full
  412. // update if a new session file was opened.
  413. if (viewer.checkRecordingStatus())
  414. fullUpdateNeeded = true;
  415. // Defer framebuffer update request if necessary. But wake up
  416. // immediately on keyboard or mouse event.
  417. if (viewer.deferUpdateRequests > 0) {
  418. synchronized (rfb) {
  419. try {
  420. rfb.wait(viewer.deferUpdateRequests);
  421. } catch (InterruptedException e) {
  422. }
  423. }
  424. }
  425. // Before requesting framebuffer update, check if the pixel
  426. // format should be changed. If it should, request full update
  427. // instead of an incremental one.
  428. if ((viewer.options.eightBitColors > 0) && (bytesPixel != 1)
  429. ||
  430. (viewer.options.eightBitColors == 0) && (bytesPixel == 1)
  431. ||
  432. (viewer.options.eightBitColors != viewer.options.oldEightBitColors)
  433. )
  434. {
  435. setPixelFormat();
  436. fullUpdateNeeded = true;
  437. }
  438. rfb.writeFramebufferUpdateRequest(
  439. 0,
  440. 0,
  441. rfb.framebufferWidth,
  442. rfb.framebufferHeight,
  443. !fullUpdateNeeded);
  444. break;
  445. case RfbProto.SetColourMapEntries :
  446. throw new Exception("Can't handle SetColourMapEntries message");
  447. case RfbProto.Bell :
  448. Toolkit.getDefaultToolkit().beep();
  449. break;
  450. case RfbProto.ServerCutText :
  451. String s = rfb.readServerCutText();
  452. viewer.clipboard.setCutText(s);
  453. break;
  454. case RfbProto.rfbFileTransfer :
  455. viewer.rfb.readRfbFileTransferMsg();
  456. break;
  457. default :
  458. throw new Exception("Unknown RFB message type " + msgType);
  459. }
  460. }
  461. }
  462. //
  463. // Handle a raw rectangle. The second form with paint==false is used
  464. // by the Hextile decoder for raw-encoded tiles.
  465. //
  466. void handleRawRect(int x, int y, int w, int h) throws IOException {
  467. handleRawRect(x, y, w, h, true);
  468. }
  469. void handleRawRect(int x, int y, int w, int h, boolean paint)
  470. throws IOException {
  471. if (bytesPixel == 1) {
  472. for (int dy = y; dy < y + h; dy++) {
  473. rfb.is.readFully(pixels8, dy * rfb.framebufferWidth + x, w);
  474. if (rfb.rec != null) {
  475. rfb.rec.write(pixels8, dy * rfb.framebufferWidth + x, w);
  476. }
  477. }
  478. } else {
  479. byte[] buf = new byte[w * 4];
  480. int i, offset;
  481. for (int dy = y; dy < y + h; dy++) {
  482. rfb.is.readFully(buf);
  483. if (rfb.rec != null) {
  484. rfb.rec.write(buf);
  485. }
  486. offset = dy * rfb.framebufferWidth + x;
  487. for (i = 0; i < w; i++) {
  488. pixels24[offset + i] =
  489. (buf[i * 4 + 2] & 0xFF)
  490. << 16 | (buf[i * 4 + 1] & 0xFF)
  491. << 8 | (buf[i * 4] & 0xFF);
  492. }
  493. }
  494. }
  495. handleUpdatedPixels(x, y, w, h);
  496. if (paint)
  497. scheduleRepaint(x, y, w, h);
  498. }
  499. //
  500. // Handle a CopyRect rectangle.
  501. //
  502. void handleCopyRect(int x, int y, int w, int h) throws IOException {
  503. rfb.readCopyRect();
  504. memGraphics.copyArea(
  505. rfb.copyRectSrcX,
  506. rfb.copyRectSrcY,
  507. w,
  508. h,
  509. x - rfb.copyRectSrcX,
  510. y - rfb.copyRectSrcY);
  511. scheduleRepaint(x, y, w, h);
  512. }
  513. //
  514. // Handle an RRE-encoded rectangle.
  515. //
  516. void handleRRERect(int x, int y, int w, int h) throws IOException {
  517. int nSubrects = rfb.is.readInt();
  518. byte[] bg_buf = new byte[bytesPixel];
  519. rfb.is.readFully(bg_buf);
  520. Color pixel;
  521. if (bytesPixel == 1)
  522. {
  523. pixel = colors[bg_buf[0] & 0xFF];
  524. }
  525. else
  526. {
  527. pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF);
  528. }
  529. memGraphics.setColor(pixel);
  530. memGraphics.fillRect(x, y, w, h);
  531. byte[] buf = new byte[nSubrects * (bytesPixel + 8)];
  532. rfb.is.readFully(buf);
  533. DataInputStream ds = new DataInputStream(new ByteArrayInputStream(buf));
  534. if (rfb.rec != null) {
  535. rfb.rec.writeIntBE(nSubrects);
  536. rfb.rec.write(bg_buf);
  537. rfb.rec.write(buf);
  538. }
  539. int sx, sy, sw, sh;
  540. for (int j = 0; j < nSubrects; j++) {
  541. if (bytesPixel == 1) {
  542. pixel = colors[ds.readUnsignedByte()];
  543. } else {
  544. ds.skip(4);
  545. pixel =
  546. new Color(
  547. buf[j * 12 + 2] & 0xFF,
  548. buf[j * 12 + 1] & 0xFF,
  549. buf[j * 12] & 0xFF);
  550. }
  551. sx = x + ds.readUnsignedShort();
  552. sy = y + ds.readUnsignedShort();
  553. sw = ds.readUnsignedShort();
  554. sh = ds.readUnsignedShort();
  555. memGraphics.setColor(pixel);
  556. memGraphics.fillRect(sx, sy, sw, sh);
  557. }
  558. scheduleRepaint(x, y, w, h);
  559. }
  560. //
  561. // Handle a CoRRE-encoded rectangle.
  562. //
  563. void handleCoRRERect(int x, int y, int w, int h) throws IOException {
  564. int nSubrects = rfb.is.readInt();
  565. byte[] bg_buf = new byte[bytesPixel];
  566. rfb.is.readFully(bg_buf);
  567. Color pixel;
  568. if (bytesPixel == 1) {
  569. pixel = colors[bg_buf[0] & 0xFF];
  570. } else {
  571. pixel =
  572. new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF);
  573. }
  574. memGraphics.setColor(pixel);
  575. memGraphics.fillRect(x, y, w, h);
  576. byte[] buf = new byte[nSubrects * (bytesPixel + 4)];
  577. rfb.is.readFully(buf);
  578. if (rfb.rec != null) {
  579. rfb.rec.writeIntBE(nSubrects);
  580. rfb.rec.write(bg_buf);
  581. rfb.rec.write(buf);
  582. }
  583. int sx, sy, sw, sh;
  584. int i = 0;
  585. for (int j = 0; j < nSubrects; j++) {
  586. if (bytesPixel == 1) {
  587. pixel = colors[buf[i++] & 0xFF];
  588. } else {
  589. pixel =
  590. new Color(
  591. buf[i + 2] & 0xFF,
  592. buf[i + 1] & 0xFF,
  593. buf[i] & 0xFF);
  594. i += 4;
  595. }
  596. sx = x + (buf[i++] & 0xFF);
  597. sy = y + (buf[i++] & 0xFF);
  598. sw = buf[i++] & 0xFF;
  599. sh = buf[i++] & 0xFF;
  600. memGraphics.setColor(pixel);
  601. memGraphics.fillRect(sx, sy, sw, sh);
  602. }
  603. scheduleRepaint(x, y, w, h);
  604. }
  605. //
  606. // Handle a Hextile-encoded rectangle.
  607. //
  608. // These colors should be kept between handleHextileSubrect() calls.
  609. private Color hextile_bg, hextile_fg;
  610. void handleHextileRect(int x, int y, int w, int h) throws IOException {
  611. hextile_bg = new Color(0);
  612. hextile_fg = new Color(0);
  613. for (int ty = y; ty < y + h; ty += 16) {
  614. int th = 16;
  615. if (y + h - ty < 16)
  616. th = y + h - ty;
  617. for (int tx = x; tx < x + w; tx += 16) {
  618. int tw = 16;
  619. if (x + w - tx < 16)
  620. tw = x + w - tx;
  621. handleHextileSubrect(tx, ty, tw, th);
  622. }
  623. // Finished with a row of tiles, now let's show it.
  624. scheduleRepaint(x, y, w, h);
  625. }
  626. }
  627. //
  628. // Handle one tile in the Hextile-encoded data.
  629. //
  630. void handleHextileSubrect(int tx, int ty, int tw, int th)
  631. throws IOException {
  632. int subencoding = rfb.is.readUnsignedByte();
  633. if (rfb.rec != null) {
  634. rfb.rec.writeByte(subencoding);
  635. }
  636. // Is it a raw-encoded sub-rectangle?
  637. if ((subencoding & rfb.HextileRaw) != 0) {
  638. handleRawRect(tx, ty, tw, th, false);
  639. return;
  640. }
  641. // Read and draw the background if specified.
  642. byte[] cbuf = new byte[bytesPixel];
  643. if ((subencoding & rfb.HextileBackgroundSpecified) != 0) {
  644. rfb.is.readFully(cbuf);
  645. if (bytesPixel == 1) {
  646. hextile_bg = colors[cbuf[0] & 0xFF];
  647. } else {
  648. hextile_bg =
  649. new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
  650. }
  651. if (rfb.rec != null) {
  652. rfb.rec.write(cbuf);
  653. }
  654. }
  655. memGraphics.setColor(hextile_bg);
  656. memGraphics.fillRect(tx, ty, tw, th);
  657. // Read the foreground color if specified.
  658. if ((subencoding & rfb.HextileForegroundSpecified) != 0) {
  659. rfb.is.readFully(cbuf);
  660. if (bytesPixel == 1) {
  661. hextile_fg = colors[cbuf[0] & 0xFF];
  662. } else {
  663. hextile_fg =
  664. new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
  665. }
  666. if (rfb.rec != null) {
  667. rfb.rec.write(cbuf);
  668. }
  669. }
  670. // Done with this tile if there is no sub-rectangles.
  671. if ((subencoding & rfb.HextileAnySubrects) == 0)
  672. return;
  673. int nSubrects = rfb.is.readUnsignedByte();
  674. int bufsize = nSubrects * 2;
  675. if ((subencoding & rfb.HextileSubrectsColoured) != 0) {
  676. bufsize += nSubrects * bytesPixel;
  677. }
  678. byte[] buf = new byte[bufsize];
  679. rfb.is.readFully(buf);
  680. if (rfb.rec != null) {
  681. rfb.rec.writeByte(nSubrects);
  682. rfb.rec.write(buf);
  683. }
  684. int b1, b2, sx, sy, sw, sh;
  685. int i = 0;
  686. if ((subencoding & rfb.HextileSubrectsColoured) == 0) {
  687. // Sub-rectangles are all of the same color.
  688. memGraphics.setColor(hextile_fg);
  689. for (int j = 0; j < nSubrects; j++) {
  690. b1 = buf[i++] & 0xFF;
  691. b2 = buf[i++] & 0xFF;
  692. sx = tx + (b1 >> 4);
  693. sy = ty + (b1 & 0xf);
  694. sw = (b2 >> 4) + 1;
  695. sh = (b2 & 0xf) + 1;
  696. memGraphics.fillRect(sx, sy, sw, sh);
  697. }
  698. } else if (bytesPixel == 1) {
  699. // BGR233 (8-bit color) version for colored sub-rectangles.
  700. for (int j = 0; j < nSubrects; j++) {
  701. hextile_fg = colors[buf[i++] & 0xFF];
  702. b1 = buf[i++] & 0xFF;
  703. b2 = buf[i++] & 0xFF;
  704. sx = tx + (b1 >> 4);
  705. sy = ty + (b1 & 0xf);
  706. sw = (b2 >> 4) + 1;
  707. sh = (b2 & 0xf) + 1;
  708. memGraphics.setColor(hextile_fg);
  709. memGraphics.fillRect(sx, sy, sw, sh);
  710. }
  711. } else {
  712. // Full-color (24-bit) version for colored sub-rectangles.
  713. for (int j = 0; j < nSubrects; j++) {
  714. hextile_fg =
  715. new Color(
  716. buf[i + 2] & 0xFF,
  717. buf[i + 1] & 0xFF,
  718. buf[i] & 0xFF);
  719. i += 4;
  720. b1 = buf[i++] & 0xFF;
  721. b2 = buf[i++] & 0xFF;
  722. sx = tx + (b1 >> 4);
  723. sy = ty + (b1 & 0xf);
  724. sw = (b2 >> 4) + 1;
  725. sh = (b2 & 0xf) + 1;
  726. memGraphics.setColor(hextile_fg);
  727. memGraphics.fillRect(sx, sy, sw, sh);
  728. }
  729. }
  730. }
  731. //
  732. // Handle a Zlib-encoded rectangle.
  733. //
  734. void handleZlibRect(int x, int y, int w, int h) throws Exception {
  735. int nBytes = rfb.is.readInt();
  736. if (zlibBuf == null || zlibBufLen < nBytes) {
  737. zlibBufLen = nBytes * 2;
  738. zlibBuf = new byte[zlibBufLen];
  739. }
  740. rfb.is.readFully(zlibBuf, 0, nBytes);
  741. if (rfb.rec != null && rfb.recordFromBeginning) {
  742. rfb.rec.writeIntBE(nBytes);
  743. rfb.rec.write(zlibBuf, 0, nBytes);
  744. }
  745. if (zlibInflater == null) {
  746. zlibInflater = new Inflater();
  747. }
  748. zlibInflater.setInput(zlibBuf, 0, nBytes);
  749. if (bytesPixel == 1) {
  750. for (int dy = y; dy < y + h; dy++) {
  751. zlibInflater.inflate(pixels8, dy * rfb.framebufferWidth + x, w);
  752. if (rfb.rec != null && !rfb.recordFromBeginning)
  753. rfb.rec.write(pixels8, dy * rfb.framebufferWidth + x, w);
  754. }
  755. } else {
  756. byte[] buf = new byte[w * 4];
  757. int i, offset;
  758. for (int dy = y; dy < y + h; dy++) {
  759. zlibInflater.inflate(buf);
  760. offset = dy * rfb.framebufferWidth + x;
  761. for (i = 0; i < w; i++) {
  762. pixels24[offset + i] =
  763. (buf[i * 4 + 2] & 0xFF)
  764. << 16 | (buf[i * 4 + 1] & 0xFF)
  765. << 8 | (buf[i * 4] & 0xFF);
  766. }
  767. if (rfb.rec != null && !rfb.recordFromBeginning)
  768. rfb.rec.write(buf);
  769. }
  770. }
  771. handleUpdatedPixels(x, y, w, h);
  772. scheduleRepaint(x, y, w, h);
  773. }
  774. //
  775. // Handle a Tight-encoded rectangle.
  776. //
  777. void handleTightRect(int x, int y, int w, int h) throws Exception {
  778. int comp_ctl = rfb.is.readUnsignedByte();
  779. if (rfb.rec != null) {
  780. if (rfb.recordFromBeginning
  781. || comp_ctl == (rfb.TightFill << 4)
  782. || comp_ctl == (rfb.TightJpeg << 4)) {
  783. // Send data exactly as received.
  784. rfb.rec.writeByte(comp_ctl);
  785. } else {
  786. // Tell the decoder to flush each of the four zlib streams.
  787. rfb.rec.writeByte(comp_ctl | 0x0F);
  788. }
  789. }
  790. // Flush zlib streams if we are told by the server to do so.
  791. for (int stream_id = 0; stream_id < 4; stream_id++) {
  792. if ((comp_ctl & 1) != 0 && tightInflaters[stream_id] != null) {
  793. tightInflaters[stream_id] = null;
  794. }
  795. comp_ctl >>= 1;
  796. }
  797. // Check correctness of subencoding value.
  798. if (comp_ctl > rfb.TightMaxSubencoding) {
  799. throw new Exception("Incorrect tight subencoding: " + comp_ctl);
  800. }
  801. // Handle solid-color rectangles.
  802. if (comp_ctl == rfb.TightFill) {
  803. if (bytesPixel == 1) {
  804. int idx = rfb.is.readUnsignedByte();
  805. memGraphics.setColor(colors[idx]);
  806. if (rfb.rec != null) {
  807. rfb.rec.writeByte(idx);
  808. }
  809. } else {
  810. byte[] buf = new byte[3];
  811. rfb.is.readFully(buf);
  812. if (rfb.rec != null) {
  813. rfb.rec.write(buf);
  814. }
  815. Color bg =
  816. new Color(
  817. 0xFF000000 | (buf[0] & 0xFF)
  818. << 16 | (buf[1] & 0xFF)
  819. << 8 | (buf[2] & 0xFF));
  820. memGraphics.setColor(bg);
  821. }
  822. memGraphics.fillRect(x, y, w, h);
  823. scheduleRepaint(x, y, w, h);
  824. return;
  825. }
  826. if (comp_ctl == rfb.TightJpeg) {
  827. // Read JPEG data.
  828. byte[] jpegData = new byte[rfb.readCompactLen()];
  829. rfb.is.readFully(jpegData);
  830. if (rfb.rec != null) {
  831. if (!rfb.recordFromBeginning) {
  832. rfb.recordCompactLen(jpegData.length);
  833. }
  834. rfb.rec.write(jpegData);
  835. }
  836. // Create an Image object from the JPEG data.
  837. Image jpegImage = Toolkit.getDefaultToolkit().createImage(jpegData);
  838. // Remember the rectangle where the image should be drawn.
  839. jpegRect = new Rectangle(x, y, w, h);
  840. // Let the imageUpdate() method do the actual drawing, here just
  841. // wait until the image is fully loaded and drawn.
  842. synchronized (jpegRect) {
  843. Toolkit.getDefaultToolkit().prepareImage(
  844. jpegImage,
  845. -1,
  846. -1,
  847. this);
  848. try {
  849. // Wait no longer than three seconds.
  850. jpegRect.wait(3000);
  851. } catch (InterruptedException e) {
  852. throw new Exception("Interrupted while decoding JPEG image");
  853. }
  854. }
  855. // Done, jpegRect is not needed any more.
  856. jpegRect = null;
  857. return;
  858. }
  859. // Read filter id and parameters.
  860. int numColors = 0, rowSize = w;
  861. byte[] palette8 = new byte[2];
  862. int[] palette24 = new int[256];
  863. boolean useGradient = false;
  864. if ((comp_ctl & rfb.TightExplicitFilter) != 0) {
  865. int filter_id = rfb.is.readUnsignedByte();
  866. if (rfb.rec != null) {
  867. rfb.rec.writeByte(filter_id);
  868. }
  869. if (filter_id == rfb.TightFilterPalette) {
  870. numColors = rfb.is.readUnsignedByte() + 1;
  871. if (rfb.rec != null) {
  872. rfb.rec.writeByte(numColors - 1);
  873. }
  874. if (bytesPixel == 1) {
  875. if (numColors != 2) {
  876. throw new Exception(
  877. "Incorrect tight palette size: " + numColors);
  878. }
  879. rfb.is.readFully(palette8);
  880. if (rfb.rec != null) {
  881. rfb.rec.write(palette8);
  882. }
  883. } else {
  884. byte[] buf = new byte[numColors * 3];
  885. rfb.is.readFully(buf);
  886. if (rfb.rec != null) {
  887. rfb.rec.write(buf);
  888. }
  889. for (int i = 0; i < numColors; i++) {
  890. palette24[i] =
  891. ((buf[i * 3] & 0xFF)
  892. << 16 | (buf[i * 3 + 1] & 0xFF)
  893. << 8 | (buf[i * 3 + 2] & 0xFF));
  894. }
  895. }
  896. if (numColors == 2)
  897. rowSize = (w + 7) / 8;
  898. } else if (filter_id == rfb.TightFilterGradient) {
  899. useGradient = true;
  900. } else if (filter_id != rfb.TightFilterCopy) {
  901. throw new Exception("Incorrect tight filter id: " + filter_id);
  902. }
  903. }
  904. if (numColors == 0 && bytesPixel == 4)
  905. rowSize *= 3;
  906. // Read, optionally uncompress and decode data.
  907. int dataSize = h * rowSize;
  908. if (dataSize < rfb.TightMinToCompress) {
  909. // Data size is small - not compressed with zlib.
  910. if (numColors != 0) {
  911. // Indexed colors.
  912. byte[] indexedData = new byte[dataSize];
  913. rfb.is.readFully(indexedData);
  914. if (rfb.rec != null) {
  915. rfb.rec.write(indexedData);
  916. }
  917. if (numColors == 2) {
  918. // Two colors.
  919. if (bytesPixel == 1) {
  920. decodeMonoData(x, y, w, h, indexedData, palette8);
  921. } else {
  922. decodeMonoData(x, y, w, h, indexedData, palette24);
  923. }
  924. } else {
  925. // 3..255 colors (assuming bytesPixel == 4).
  926. int i = 0;
  927. for (int dy = y; dy < y + h; dy++) {
  928. for (int dx = x; dx < x + w; dx++) {
  929. pixels24[dy * rfb.framebufferWidth + dx] =
  930. palette24[indexedData[i++] & 0xFF];
  931. }
  932. }
  933. }
  934. } else if (useGradient) {
  935. // "Gradient"-processed data
  936. byte[] buf = new byte[w * h * 3];
  937. rfb.is.readFully(buf);
  938. if (rfb.rec != null) {
  939. rfb.rec.write(buf);
  940. }
  941. decodeGradientData(x, y, w, h, buf);
  942. } else {
  943. // Raw truecolor data.
  944. if (bytesPixel == 1) {
  945. for (int dy = y; dy < y + h; dy++) {
  946. rfb.is.readFully(
  947. pixels8,
  948. dy * rfb.framebufferWidth + x,
  949. w);
  950. if (rfb.rec != null) {
  951. rfb.rec.write(
  952. pixels8,
  953. dy * rfb.framebufferWidth + x,
  954. w);
  955. }
  956. }
  957. } else {
  958. byte[] buf = new byte[w * 3];
  959. int i, offset;
  960. for (int dy = y; dy < y + h; dy++) {
  961. rfb.is.readFully(buf);
  962. if (rfb.rec != null) {
  963. rfb.rec.write(buf);
  964. }
  965. offset = dy * rfb.framebufferWidth + x;
  966. for (i = 0; i < w; i++) {
  967. pixels24[offset + i] =
  968. (buf[i * 3] & 0xFF)
  969. << 16 | (buf[i * 3 + 1] & 0xFF)
  970. << 8 | (buf[i * 3 + 2] & 0xFF);
  971. }
  972. }
  973. }
  974. }
  975. } else {
  976. // Data was compressed with zlib.
  977. int zlibDataLen = rfb.readCompactLen();
  978. byte[] zlibData = new byte[zlibDataLen];
  979. rfb.is.readFully(zlibData);
  980. if (rfb.rec != null && rfb.recordFromBeginning) {
  981. rfb.rec.write(zlibData);
  982. }
  983. int stream_id = comp_ctl & 0x03;
  984. if (tightInflaters[stream_id] == null) {
  985. tightInflaters[stream_id] = new Inflater();
  986. }
  987. Inflater myInflater = tightInflaters[stream_id];
  988. myInflater.setInput(zlibData);
  989. byte[] buf = new byte[dataSize];
  990. myInflater.inflate(buf);
  991. if (rfb.rec != null && !rfb.recordFromBeginning) {
  992. rfb.recordCompressedData(buf);
  993. }
  994. if (numColors != 0) {
  995. // Indexed colors.
  996. if (numColors == 2) {
  997. // Two colors.
  998. if (bytesPixel == 1) {
  999. decodeMonoData(x, y, w, h, buf, palette8);
  1000. } else {
  1001. decodeMonoData(x, y, w, h, buf, palette24);
  1002. }
  1003. } else {
  1004. // More than two colors (assuming bytesPixel == 4).
  1005. int i = 0;
  1006. for (int dy = y; dy < y + h; dy++) {
  1007. for (int dx = x; dx < x + w; dx++) {
  1008. pixels24[dy * rfb.framebufferWidth + dx] =
  1009. palette24[buf[i++] & 0xFF];
  1010. }
  1011. }
  1012. }
  1013. } else if (useGradient) {
  1014. // Compressed "Gradient"-filtered data (assuming bytesPixel == 4).
  1015. decodeGradientData(x, y, w, h, buf);
  1016. } else {
  1017. // Compressed truecolor data.
  1018. if (bytesPixel == 1) {
  1019. int destOffset = y * rfb.framebufferWidth + x;
  1020. for (int dy = 0; dy < h; dy++) {
  1021. System.arraycopy(buf, dy * w, pixels8, destOffset, w);
  1022. destOffset += rfb.framebufferWidth;
  1023. }
  1024. } else {
  1025. int srcOffset = 0;
  1026. int destOffset, i;
  1027. for (int dy = 0; dy < h; dy++) {
  1028. myInflater.inflate(buf);
  1029. destOffset = (y + dy) * rfb.framebufferWidth + x;
  1030. for (i = 0; i < w; i++) {
  1031. pixels24[destOffset + i] =
  1032. (buf[srcOffset] & 0xFF)
  1033. << 16 | (buf[srcOffset + 1] & 0xFF)
  1034. << 8 | (buf[srcOffset + 2] & 0xFF);
  1035. srcOffset += 3;
  1036. }
  1037. }
  1038. }
  1039. }
  1040. }
  1041. handleUpdatedPixels(x, y, w, h);
  1042. scheduleRepaint(x, y, w, h);
  1043. }
  1044. //
  1045. // Decode 1bpp-encoded bi-color rectangle (8-bit and 24-bit versions).
  1046. //
  1047. void decodeMonoData(
  1048. int x,
  1049. int y,
  1050. int w,
  1051. int h,
  1052. byte[] src,
  1053. byte[] palette) {
  1054. int dx, dy, n;
  1055. int i = y * rfb.framebufferWidth + x;
  1056. int rowBytes = (w + 7) / 8;
  1057. byte b;
  1058. for (dy = 0; dy < h; dy++) {
  1059. for (dx = 0; dx < w / 8; dx++) {
  1060. b = src[dy * rowBytes + dx];
  1061. for (n = 7; n >= 0; n--)
  1062. pixels8[i++] = palette[b >> n & 1];
  1063. }
  1064. for (n = 7; n >= 8 - w % 8; n--) {
  1065. pixels8[i++] = palette[src[dy * rowBytes + dx] >> n & 1];
  1066. }
  1067. i += (rfb.framebufferWidth - w);
  1068. }
  1069. }
  1070. void decodeMonoData(
  1071. int x,
  1072. int y,
  1073. int w,
  1074. int h,
  1075. byte[] src,
  1076. int[] palette) {
  1077. int dx, dy, n;
  1078. int i = y * rfb.framebufferWidth + x;
  1079. int rowBytes = (w + 7) / 8;
  1080. byte b;
  1081. for (dy = 0; dy < h; dy++) {
  1082. for (dx = 0; dx < w / 8; dx++) {
  1083. b = src[dy * rowBytes + dx];
  1084. for (n = 7; n >= 0; n--)
  1085. pixels24[i++] = palette[b >> n & 1];
  1086. }
  1087. for (n = 7; n >= 8 - w % 8; n--) {
  1088. pixels24[i++] = palette[src[dy * rowBytes + dx] >> n & 1];
  1089. }
  1090. i += (rfb.framebufferWidth - w);
  1091. }
  1092. }
  1093. //
  1094. // Decode data processed with the "Gradient" filter.
  1095. //
  1096. void decodeGradientData(int x, int y, int w, int h, byte[] buf) {
  1097. int dx, dy, c;
  1098. byte[] prevRow = new byte[w * 3];
  1099. byte[] thisRow = new byte[w * 3];
  1100. byte[] pix = new byte[3];
  1101. int[] est = new int[3];
  1102. int offset = y * rfb.framebufferWidth + x;
  1103. for (dy = 0; dy < h; dy++) {
  1104. /* First pixel in a row */
  1105. for (c = 0; c < 3; c++) {
  1106. pix[c] = (byte) (prevRow[c] + buf[dy * w * 3 + c]);
  1107. thisRow[c] = pix[c];
  1108. }
  1109. pixels24[offset++] =
  1110. (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF);
  1111. /* Remaining pixels of a row */
  1112. for (dx = 1; dx < w; dx++) {
  1113. for (c = 0; c < 3; c++) {
  1114. est[c] =
  1115. ((prevRow[dx * 3 + c] & 0xFF)
  1116. + (pix[c] & 0xFF)
  1117. - (prevRow[(dx - 1) * 3 + c] & 0xFF));
  1118. if (est[c] > 0xFF) {
  1119. est[c] = 0xFF;
  1120. } else if (est[c] < 0x00) {
  1121. est[c] = 0x00;
  1122. }
  1123. pix[c] = (byte) (est[c] + buf[(dy * w + dx) * 3 + c]);
  1124. thisRow[dx * 3 + c] = pix[c];
  1125. }
  1126. pixels24[offset++] =
  1127. (pix[0] & 0xFF)
  1128. << 16 | (pix[1] & 0xFF)
  1129. << 8 | (pix[2] & 0xFF);
  1130. }
  1131. System.arraycopy(thisRow, 0, prevRow, 0, w * 3);
  1132. offset += (rfb.framebufferWidth - w);
  1133. }
  1134. }
  1135. //
  1136. // Display newly updated area of pixels.
  1137. //
  1138. void handleUpdatedPixels(int x, int y, int w, int h) {
  1139. // Draw updated pixels of the off-screen image.
  1140. pixelsSource.newPixels(x, y, w, h);
  1141. memGraphics.setClip(x, y, w, h);
  1142. memGraphics.drawImage(rawPixelsImage, 0, 0, null);
  1143. memGraphics.setClip(0, 0, rfb.framebufferWidth, rfb.framebufferHeight);
  1144. }
  1145. //
  1146. // Tell JVM to repaint specified desktop area.
  1147. //
  1148. void scheduleRepaint(int x, int y, int w, int h) {
  1149. // Request repaint, deferred if necessary.
  1150. repaint(viewer.deferScreenUpdates, x, y, w, h);
  1151. }
  1152. //
  1153. // Handle events.
  1154. //
  1155. public void keyPressed(KeyEvent evt) {
  1156. processLocalKeyEvent(evt);
  1157. }
  1158. public void keyReleased(KeyEvent evt) {
  1159. processLocalKeyEvent(evt);
  1160. }
  1161. public void keyTyped(KeyEvent evt) {
  1162. evt.consume();
  1163. }
  1164. public void mousePressed(MouseEvent evt) {
  1165. processLocalMouseEvent(evt, false);
  1166. }
  1167. public void mouseReleased(MouseEvent evt) {
  1168. processLocalMouseEvent(evt, false);
  1169. }
  1170. public void mouseMoved(MouseEvent evt) {
  1171. processLocalMouseEvent(evt, true);
  1172. }
  1173. public void mouseDragged(MouseEvent evt) {
  1174. processLocalMouseEvent(evt, true);
  1175. }
  1176. public void processLocalKeyEvent(KeyEvent evt) {
  1177. if (viewer.rfb != null && rfb.inNormalProtocol) {
  1178. if (!inputEnabled) {
  1179. if ((evt.getKeyChar() == 'r' || evt.getKeyChar() == 'R')
  1180. && evt.getID() == KeyEvent.KEY_PRESSED) {
  1181. // Request screen update.
  1182. try {
  1183. rfb.writeFramebufferUpdateRequest(
  1184. 0,
  1185. 0,
  1186. rfb.framebufferWidth,
  1187. rfb.framebufferHeight,
  1188. false);
  1189. } catch (IOException e) {
  1190. e.printStackTrace();
  1191. }
  1192. }
  1193. } else {
  1194. // Input enabled.
  1195. synchronized (rfb) {
  1196. try {
  1197. rfb.writeKeyEvent(evt);
  1198. } catch (Exception e) {
  1199. e.printStackTrace();
  1200. }
  1201. rfb.notify();
  1202. }
  1203. }
  1204. }
  1205. // Don't ever pass keyboard events to AWT for default processing.
  1206. // Otherwise, pressing Tab would switch focus to ButtonPanel etc.
  1207. evt.consume();
  1208. }
  1209. public void processLocalMouseEvent(MouseEvent evt, boolean moved) {
  1210. if (viewer.rfb != null && rfb.inNormalProtocol) {
  1211. if (moved) {
  1212. softCursorMove(evt.getX(), evt.getY());
  1213. }
  1214. synchronized (rfb) {
  1215. try {
  1216. rfb.writePointerEvent(evt);
  1217. } catch (Exception e) {
  1218. e.printStackTrace();
  1219. }
  1220. rfb.notify();
  1221. }
  1222. }
  1223. }
  1224. //
  1225. // Ignored events.
  1226. //
  1227. public void mouseClicked(MouseEvent evt) {
  1228. }
  1229. public void mouseEntered(MouseEvent evt) {
  1230. }
  1231. public void mouseExited(MouseEvent evt) {
  1232. }
  1233. //////////////////////////////////////////////////////////////////
  1234. //
  1235. // Handle cursor shape updates (XCursor and RichCursor encodings).
  1236. //
  1237. boolean showSoftCursor = false;
  1238. int[] softCursorPixels;
  1239. MemoryImageSource softCursorSource;
  1240. Image softCursor;
  1241. int cursorX = 0, cursorY = 0;
  1242. int cursorWidth, cursorHeight;
  1243. int hotX, hotY;
  1244. //
  1245. // Handle cursor shape update (XCursor and RichCursor encodings).
  1246. //
  1247. synchronized void handleCursorShapeUpdate(
  1248. int encodingType,
  1249. int xhot,
  1250. int yhot,
  1251. int width,
  1252. int height)
  1253. throws IOException {
  1254. int bytesPerRow = (width + 7) / 8;
  1255. int bytesMaskData = bytesPerRow * height;
  1256. softCursorFree();
  1257. if (width * height == 0)
  1258. return;
  1259. // Ignore cursor shape data if requested by user.
  1260. if (viewer.options.ignoreCursorUpdates) {
  1261. if (encodingType == rfb.EncodingXCursor) {
  1262. rfb.is.skipBytes(6 + bytesMaskData * 2);
  1263. } else {
  1264. // rfb.EncodingRichCursor
  1265. rfb.is.skipBytes(width * height + bytesMaskData);
  1266. }
  1267. return;
  1268. }
  1269. // Decode cursor pixel data.
  1270. softCursorPixels = new int[width * height];
  1271. if (encodingType == rfb.EncodingXCursor) {
  1272. // Read foreground and background colors of the cursor.
  1273. byte[] rgb = new byte[6];
  1274. rfb.is.readFully(rgb);
  1275. int[] colors =
  1276. {
  1277. (0xFF000000 | (rgb[3] & 0xFF)
  1278. << 16 | (rgb[4] & 0xFF)
  1279. << 8 | (rgb[5] & 0xFF)),
  1280. (0xFF000000 | (rgb[0] & 0xFF)
  1281. << 16 | (rgb[1] & 0xFF)
  1282. << 8 | (rgb[2] & 0xFF))};
  1283. // Read pixel and mask data.
  1284. byte[] pixBuf = new byte[bytesMaskData];
  1285. rfb.is.readFully(pixBuf);
  1286. byte[] maskBuf = new byte[bytesMaskData];
  1287. rfb.is.readFully(maskBuf);
  1288. // Decode pixel data into softCursorPixels[].
  1289. byte pixByte, maskByte;
  1290. int x, y, n, result;
  1291. int i = 0;
  1292. for (y = 0; y < height; y++) {
  1293. for (x = 0; x < width / 8; x++) {
  1294. pixByte = pixBuf[y * bytesPerRow + x];
  1295. maskByte = maskBuf[y * bytesPerRow + x];
  1296. for (n = 7; n >= 0; n--) {
  1297. if ((maskByte >> n & 1) != 0) {
  1298. result = colors[pixByte >> n & 1];
  1299. } else {
  1300. result = 0; // Transparent pixel
  1301. }
  1302. softCursorPixels[i++] = result;
  1303. }
  1304. }
  1305. for (n = 7; n >= 8 - width % 8; n--) {
  1306. if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
  1307. result = colors[pixBuf[y * bytesPerRow + x] >> n & 1];
  1308. } else {
  1309. result = 0; // Transparent pixel
  1310. }
  1311. softCursorPixels[i++] = result;
  1312. }
  1313. }
  1314. } else {
  1315. // encodingType == rfb.EncodingRichCursor
  1316. // Read pixel and mask data.
  1317. byte[] pixBuf = new byte[width * height * bytesPixel];
  1318. rfb.is.readFully(pixBuf);
  1319. byte[] maskBuf = new byte[bytesMaskData];
  1320. rfb.is.readFully(maskBuf);
  1321. // Decode pixel data into softCursorPixels[].
  1322. byte pixByte, maskByte;
  1323. int x, y, n, result;
  1324. int i = 0;
  1325. for (y = 0; y < height; y++) {
  1326. for (x = 0; x < width / 8; x++) {
  1327. maskByte = maskBuf[y * bytesPerRow + x];
  1328. for (n = 7; n >= 0; n--) {
  1329. if ((maskByte >> n & 1) != 0) {
  1330. if (bytesPixel == 1)
  1331. {
  1332. result = 0;
  1333. // sf@2005
  1334. switch (viewer.options.eightBitColors)
  1335. {
  1336. case 1:
  1337. result = cm8_256c.getRGB(pixBuf[i]);
  1338. break;
  1339. case 2:
  1340. case 4:
  1341. result = cm8_64c.getRGB(pixBuf[i]);
  1342. break;
  1343. case 3:
  1344. case 5:
  1345. result = cm8_8c.getRGB(pixBuf[i]);
  1346. break;
  1347. }
  1348. }
  1349. else
  1350. {
  1351. result =
  1352. 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
  1353. << 16 | (pixBuf[i * 4 + 2] & 0xFF)
  1354. << 8 | (pixBuf[i * 4 + 3] & 0xFF);
  1355. }
  1356. } else {
  1357. result = 0; // Transparent pixel
  1358. }
  1359. softCursorPixels[i++] = result;
  1360. }
  1361. }
  1362. for (n = 7; n >= 8 - width % 8; n--) {
  1363. if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
  1364. if (bytesPixel == 1)
  1365. {
  1366. result = 0;
  1367. // sf@2005
  1368. switch (viewer.options.eightBitColors)
  1369. {
  1370. case 1:
  1371. result = cm8_256c.getRGB(pixBuf[i]);
  1372. break;
  1373. case 2:
  1374. case 4:
  1375. result = cm8_64c.getRGB(pixBuf[i]);
  1376. break;
  1377. case 3:
  1378. case 5:
  1379. result = cm8_8c.getRGB(pixBuf[i]);
  1380. break;
  1381. } }
  1382. else
  1383. {
  1384. result =
  1385. 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
  1386. << 16 | (pixBuf[i * 4 + 2] & 0xFF)
  1387. << 8 | (pixBuf[i * 4 + 3] & 0xFF);
  1388. }
  1389. } else {
  1390. result = 0; // Transparent pixel
  1391. }
  1392. softCursorPixels[i++] = result;
  1393. }
  1394. }
  1395. }
  1396. // Draw the cursor on an off-screen image.
  1397. softCursorSource =
  1398. new MemoryImageSource(width, height, softCursorPixels, 0, width);
  1399. softCursor = createImage(softCursorSource);
  1400. // Set remaining data associated with cursor.
  1401. cursorWidth = width;
  1402. cursorHeight = height;
  1403. hotX = xhot;
  1404. hotY = yhot;
  1405. showSoftCursor = true;
  1406. // Show the cursor.
  1407. repaint(
  1408. viewer.deferCursorUpdates,
  1409. cursorX - hotX,
  1410. cursorY - hotY,
  1411. cursorWidth,
  1412. cursorHeight);
  1413. }
  1414. //
  1415. // marscha - PointerPos
  1416. // Handle cursor position update (PointerPos encoding).
  1417. //
  1418. synchronized void handleCursorPosUpdate(
  1419. int x,
  1420. int y) {
  1421. if (x >= rfb.framebufferWidth)
  1422. x = rfb.framebufferWidth - 1;
  1423. if (y >= rfb.framebufferHeight)
  1424. y = rfb.framebufferHeight - 1;
  1425. softCursorMove(x, y);
  1426. }
  1427. //
  1428. // softCursorMove(). Moves soft cursor into a particular location.
  1429. //
  1430. synchronized void softCursorMove(int x, int y) {
  1431. if (showSoftCursor) {
  1432. repaint(
  1433. viewer.deferCursorUpdates,
  1434. cursorX - hotX,
  1435. cursorY - hotY,
  1436. cursorWidth,
  1437. cursorHeight);
  1438. repaint(
  1439. viewer.deferCursorUpdates,
  1440. x - hotX,
  1441. y - hotY,
  1442. cursorWidth,
  1443. cursorHeight);
  1444. }
  1445. cursorX = x;
  1446. cursorY = y;
  1447. }
  1448. //
  1449. // softCursorFree(). Remove soft cursor, dispose resources.
  1450. //
  1451. synchronized void softCursorFree() {
  1452. if (showSoftCursor) {
  1453. showSoftCursor = false;
  1454. softCursor = null;
  1455. softCursorSource = null;
  1456. softCursorPixels = null;
  1457. repaint(
  1458. viewer.deferCursorUpdates,
  1459. cursorX - hotX,
  1460. cursorY - hotY,
  1461. cursorWidth,
  1462. cursorHeight);
  1463. }
  1464. }
  1465. }