VncCanvas.java 40 KB

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