/apps/desktop/libvncserver/cursor.c

http://ftk.googlecode.com/ · C · 753 lines · 564 code · 118 blank · 71 comment · 161 complexity · 96cd2486576790995416a82c8262ea48 MD5 · raw file

  1. /*
  2. * cursor.c - support for cursor shape updates.
  3. */
  4. /*
  5. * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
  6. * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
  7. *
  8. * This is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This software is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this software; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  21. * USA.
  22. */
  23. #include <rfb/rfb.h>
  24. #include <rfb/rfbregion.h>
  25. #include "private.h"
  26. void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
  27. /*
  28. * Send cursor shape either in X-style format or in client pixel format.
  29. */
  30. rfbBool
  31. rfbSendCursorShape(rfbClientPtr cl)
  32. {
  33. rfbCursorPtr pCursor;
  34. rfbFramebufferUpdateRectHeader rect;
  35. rfbXCursorColors colors;
  36. int saved_ublen;
  37. int bitmapRowBytes, maskBytes, dataBytes;
  38. int i, j;
  39. uint8_t *bitmapData;
  40. uint8_t bitmapByte;
  41. /* TODO: scale the cursor data to the correct size */
  42. pCursor = cl->screen->getCursorPtr(cl);
  43. /*if(!pCursor) return TRUE;*/
  44. if (cl->useRichCursorEncoding) {
  45. if(pCursor && !pCursor->richSource)
  46. rfbMakeRichCursorFromXCursor(cl->screen,pCursor);
  47. rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
  48. } else {
  49. if(pCursor && !pCursor->source)
  50. rfbMakeXCursorFromRichCursor(cl->screen,pCursor);
  51. rect.encoding = Swap32IfLE(rfbEncodingXCursor);
  52. }
  53. /* If there is no cursor, send update with empty cursor data. */
  54. if ( pCursor && pCursor->width == 1 &&
  55. pCursor->height == 1 &&
  56. pCursor->mask[0] == 0 ) {
  57. pCursor = NULL;
  58. }
  59. if (pCursor == NULL) {
  60. if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
  61. if (!rfbSendUpdateBuf(cl))
  62. return FALSE;
  63. }
  64. rect.r.x = rect.r.y = 0;
  65. rect.r.w = rect.r.h = 0;
  66. memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
  67. sz_rfbFramebufferUpdateRectHeader);
  68. cl->ublen += sz_rfbFramebufferUpdateRectHeader;
  69. if (!rfbSendUpdateBuf(cl))
  70. return FALSE;
  71. return TRUE;
  72. }
  73. /* Calculate data sizes. */
  74. bitmapRowBytes = (pCursor->width + 7) / 8;
  75. maskBytes = bitmapRowBytes * pCursor->height;
  76. dataBytes = (cl->useRichCursorEncoding) ?
  77. (pCursor->width * pCursor->height *
  78. (cl->format.bitsPerPixel / 8)) : maskBytes;
  79. /* Send buffer contents if needed. */
  80. if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
  81. sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
  82. if (!rfbSendUpdateBuf(cl))
  83. return FALSE;
  84. }
  85. if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
  86. sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
  87. return FALSE; /* FIXME. */
  88. }
  89. saved_ublen = cl->ublen;
  90. /* Prepare rectangle header. */
  91. rect.r.x = Swap16IfLE(pCursor->xhot);
  92. rect.r.y = Swap16IfLE(pCursor->yhot);
  93. rect.r.w = Swap16IfLE(pCursor->width);
  94. rect.r.h = Swap16IfLE(pCursor->height);
  95. memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
  96. cl->ublen += sz_rfbFramebufferUpdateRectHeader;
  97. /* Prepare actual cursor data (depends on encoding used). */
  98. if (!cl->useRichCursorEncoding) {
  99. /* XCursor encoding. */
  100. colors.foreRed = (char)(pCursor->foreRed >> 8);
  101. colors.foreGreen = (char)(pCursor->foreGreen >> 8);
  102. colors.foreBlue = (char)(pCursor->foreBlue >> 8);
  103. colors.backRed = (char)(pCursor->backRed >> 8);
  104. colors.backGreen = (char)(pCursor->backGreen >> 8);
  105. colors.backBlue = (char)(pCursor->backBlue >> 8);
  106. memcpy(&cl->updateBuf[cl->ublen], (char *)&colors, sz_rfbXCursorColors);
  107. cl->ublen += sz_rfbXCursorColors;
  108. bitmapData = (uint8_t *)pCursor->source;
  109. for (i = 0; i < pCursor->height; i++) {
  110. for (j = 0; j < bitmapRowBytes; j++) {
  111. bitmapByte = bitmapData[i * bitmapRowBytes + j];
  112. cl->updateBuf[cl->ublen++] = (char)bitmapByte;
  113. }
  114. }
  115. } else {
  116. /* RichCursor encoding. */
  117. int bpp1=cl->screen->serverFormat.bitsPerPixel/8,
  118. bpp2=cl->format.bitsPerPixel/8;
  119. (*cl->translateFn)(cl->translateLookupTable,
  120. &(cl->screen->serverFormat),
  121. &cl->format, (char*)pCursor->richSource,
  122. &cl->updateBuf[cl->ublen],
  123. pCursor->width*bpp1, pCursor->width, pCursor->height);
  124. cl->ublen += pCursor->width*bpp2*pCursor->height;
  125. }
  126. /* Prepare transparency mask. */
  127. bitmapData = (uint8_t *)pCursor->mask;
  128. for (i = 0; i < pCursor->height; i++) {
  129. for (j = 0; j < bitmapRowBytes; j++) {
  130. bitmapByte = bitmapData[i * bitmapRowBytes + j];
  131. cl->updateBuf[cl->ublen++] = (char)bitmapByte;
  132. }
  133. }
  134. /* Send everything we have prepared in the cl->updateBuf[]. */
  135. rfbStatRecordEncodingSent(cl, (cl->useRichCursorEncoding ? rfbEncodingRichCursor : rfbEncodingXCursor),
  136. sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen), sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen));
  137. if (!rfbSendUpdateBuf(cl))
  138. return FALSE;
  139. return TRUE;
  140. }
  141. /*
  142. * Send cursor position (PointerPos pseudo-encoding).
  143. */
  144. rfbBool
  145. rfbSendCursorPos(rfbClientPtr cl)
  146. {
  147. rfbFramebufferUpdateRectHeader rect;
  148. if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
  149. if (!rfbSendUpdateBuf(cl))
  150. return FALSE;
  151. }
  152. rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
  153. rect.r.x = Swap16IfLE(cl->screen->cursorX);
  154. rect.r.y = Swap16IfLE(cl->screen->cursorY);
  155. rect.r.w = 0;
  156. rect.r.h = 0;
  157. memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
  158. sz_rfbFramebufferUpdateRectHeader);
  159. cl->ublen += sz_rfbFramebufferUpdateRectHeader;
  160. rfbStatRecordEncodingSent(cl, rfbEncodingPointerPos, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
  161. if (!rfbSendUpdateBuf(cl))
  162. return FALSE;
  163. return TRUE;
  164. }
  165. /* conversion routine for predefined cursors in LSB order */
  166. unsigned char rfbReverseByte[0x100] = {
  167. /* copied from Xvnc/lib/font/util/utilbitmap.c */
  168. 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
  169. 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
  170. 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
  171. 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
  172. 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
  173. 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
  174. 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
  175. 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
  176. 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
  177. 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
  178. 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
  179. 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
  180. 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
  181. 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
  182. 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
  183. 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
  184. 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
  185. 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
  186. 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
  187. 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
  188. 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
  189. 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
  190. 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
  191. 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
  192. 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
  193. 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
  194. 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
  195. 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
  196. 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
  197. 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
  198. 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
  199. 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
  200. };
  201. void rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char* bitmap)
  202. {
  203. int i,t=(width+7)/8*height;
  204. for(i=0;i<t;i++)
  205. bitmap[i]=rfbReverseByte[(int)bitmap[i]];
  206. }
  207. /* Cursor creation. You "paint" a cursor and let these routines do the work */
  208. rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskString)
  209. {
  210. int i,j,w=(width+7)/8;
  211. rfbCursorPtr cursor = (rfbCursorPtr)calloc(1,sizeof(rfbCursor));
  212. char* cp;
  213. unsigned char bit;
  214. cursor->cleanup=TRUE;
  215. cursor->width=width;
  216. cursor->height=height;
  217. /*cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff;*/
  218. cursor->foreRed=cursor->foreGreen=cursor->foreBlue=0xffff;
  219. cursor->source = (unsigned char*)calloc(w,height);
  220. cursor->cleanupSource = TRUE;
  221. for(j=0,cp=cursorString;j<height;j++)
  222. for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
  223. if(*cp!=' ') cursor->source[j*w+i/8]|=bit;
  224. if(maskString) {
  225. cursor->mask = (unsigned char*)calloc(w,height);
  226. for(j=0,cp=maskString;j<height;j++)
  227. for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
  228. if(*cp!=' ') cursor->mask[j*w+i/8]|=bit;
  229. } else
  230. cursor->mask = (unsigned char*)rfbMakeMaskForXCursor(width,height,(char*)cursor->source);
  231. cursor->cleanupMask = TRUE;
  232. return(cursor);
  233. }
  234. char* rfbMakeMaskForXCursor(int width,int height,char* source)
  235. {
  236. int i,j,w=(width+7)/8;
  237. char* mask=(char*)calloc(w,height);
  238. unsigned char c;
  239. for(j=0;j<height;j++)
  240. for(i=w-1;i>=0;i--) {
  241. c=source[j*w+i];
  242. if(j>0) c|=source[(j-1)*w+i];
  243. if(j<height-1) c|=source[(j+1)*w+i];
  244. if(i>0 && (c&0x80))
  245. mask[j*w+i-1]|=0x01;
  246. if(i<w-1 && (c&0x01))
  247. mask[j*w+i+1]|=0x80;
  248. mask[j*w+i]|=(c<<1)|c|(c>>1);
  249. }
  250. return(mask);
  251. }
  252. /* this function dithers the alpha using Floyd-Steinberg */
  253. char* rfbMakeMaskFromAlphaSource(int width,int height,unsigned char* alphaSource)
  254. {
  255. int* error=(int*)calloc(sizeof(int),width);
  256. int i,j,currentError=0,maskStride=(width+7)/8;
  257. unsigned char* result=(unsigned char*)calloc(maskStride,height);
  258. for(j=0;j<height;j++)
  259. for(i=0;i<width;i++) {
  260. int right,middle,left;
  261. currentError+=alphaSource[i+width*j]+error[i];
  262. if(currentError<0x80) {
  263. /* set to transparent */
  264. /* alpha was treated as 0 */
  265. } else {
  266. /* set to solid */
  267. result[i/8+j*maskStride]|=(0x100>>(i&7));
  268. /* alpha was treated as 0xff */
  269. currentError-=0xff;
  270. }
  271. /* propagate to next row */
  272. right=currentError/16;
  273. middle=currentError*5/16;
  274. left=currentError*3/16;
  275. currentError-=right+middle+left;
  276. error[i]=right;
  277. if(i>0) {
  278. error[i-1]=middle;
  279. if(i>1)
  280. error[i-2]=left;
  281. }
  282. }
  283. free(error);
  284. return (char *) result;
  285. }
  286. void rfbFreeCursor(rfbCursorPtr cursor)
  287. {
  288. if(cursor) {
  289. if(cursor->cleanupRichSource && cursor->richSource)
  290. free(cursor->richSource);
  291. if(cursor->cleanupRichSource && cursor->alphaSource)
  292. free(cursor->alphaSource);
  293. if(cursor->cleanupSource && cursor->source)
  294. free(cursor->source);
  295. if(cursor->cleanupMask && cursor->mask)
  296. free(cursor->mask);
  297. if(cursor->cleanup)
  298. free(cursor);
  299. else {
  300. cursor->cleanup=cursor->cleanupSource=cursor->cleanupMask
  301. =cursor->cleanupRichSource=FALSE;
  302. cursor->source=cursor->mask=cursor->richSource=NULL;
  303. cursor->alphaSource=NULL;
  304. }
  305. }
  306. }
  307. /* background and foregroud colour have to be set beforehand */
  308. void rfbMakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
  309. {
  310. rfbPixelFormat* format=&rfbScreen->serverFormat;
  311. int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8,
  312. width=cursor->width*bpp;
  313. uint32_t background;
  314. char *back=(char*)&background;
  315. unsigned char bit;
  316. int interp = 0, db = 0;
  317. if(cursor->source && cursor->cleanupSource)
  318. free(cursor->source);
  319. cursor->source=(unsigned char*)calloc(w,cursor->height);
  320. cursor->cleanupSource=TRUE;
  321. if(format->bigEndian) {
  322. back+=4-bpp;
  323. }
  324. /* all zeros means we should interpolate to black+white ourselves */
  325. if (!cursor->backRed && !cursor->backGreen && !cursor->backBlue &&
  326. !cursor->foreRed && !cursor->foreGreen && !cursor->foreBlue) {
  327. if (format->trueColour && (bpp == 1 || bpp == 2 || bpp == 4)) {
  328. interp = 1;
  329. cursor->foreRed = cursor->foreGreen = cursor->foreBlue = 0xffff;
  330. }
  331. }
  332. background = ((format->redMax * cursor->backRed) / 0xffff) << format->redShift |
  333. ((format->greenMax * cursor->backGreen) / 0xffff) << format->greenShift |
  334. ((format->blueMax * cursor->backBlue) / 0xffff) << format->blueShift;
  335. #define SETRGB(u) \
  336. r = (255 * (((format->redMax << format->redShift) & (*u)) >> format->redShift)) / format->redMax; \
  337. g = (255 * (((format->greenMax << format->greenShift) & (*u)) >> format->greenShift)) / format->greenMax; \
  338. b = (255 * (((format->blueMax << format->blueShift) & (*u)) >> format->blueShift)) / format->blueMax;
  339. if (db) fprintf(stderr, "interp: %d\n", interp);
  340. for(j=0;j<cursor->height;j++) {
  341. for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1) {
  342. if (interp) {
  343. int r = 0, g = 0, b = 0, grey;
  344. char *p = cursor->richSource+j*width+i*bpp;
  345. if (bpp == 1) {
  346. unsigned char* uc = (unsigned char*) p;
  347. SETRGB(uc);
  348. } else if (bpp == 2) {
  349. unsigned short* us = (unsigned short*) p;
  350. SETRGB(us);
  351. } else if (bpp == 4) {
  352. unsigned int* ui = (unsigned int*) p;
  353. SETRGB(ui);
  354. }
  355. grey = (r + g + b) / 3;
  356. if (grey >= 128) {
  357. cursor->source[j*w+i/8]|=bit;
  358. if (db) fprintf(stderr, "1");
  359. } else {
  360. if (db) fprintf(stderr, "0");
  361. }
  362. } else if(memcmp(cursor->richSource+j*width+i*bpp, back, bpp)) {
  363. cursor->source[j*w+i/8]|=bit;
  364. }
  365. }
  366. if (db) fprintf(stderr, "\n");
  367. }
  368. }
  369. void rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
  370. {
  371. rfbPixelFormat* format=&rfbScreen->serverFormat;
  372. int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8;
  373. uint32_t background,foreground;
  374. char *back=(char*)&background,*fore=(char*)&foreground;
  375. unsigned char *cp;
  376. unsigned char bit;
  377. if(cursor->richSource && cursor->cleanupRichSource)
  378. free(cursor->richSource);
  379. cp=cursor->richSource=(unsigned char*)calloc(cursor->width*bpp,cursor->height);
  380. cursor->cleanupRichSource=TRUE;
  381. if(format->bigEndian) {
  382. back+=4-bpp;
  383. fore+=4-bpp;
  384. }
  385. background=cursor->backRed<<format->redShift|
  386. cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift;
  387. foreground=cursor->foreRed<<format->redShift|
  388. cursor->foreGreen<<format->greenShift|cursor->foreBlue<<format->blueShift;
  389. for(j=0;j<cursor->height;j++)
  390. for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1,cp+=bpp)
  391. if(cursor->source[j*w+i/8]&bit) memcpy(cp,fore,bpp);
  392. else memcpy(cp,back,bpp);
  393. }
  394. /* functions to draw/hide cursor directly in the frame buffer */
  395. void rfbHideCursor(rfbClientPtr cl)
  396. {
  397. rfbScreenInfoPtr s=cl->screen;
  398. rfbCursorPtr c=s->cursor;
  399. int j,x1,x2,y1,y2,bpp=s->serverFormat.bitsPerPixel/8,
  400. rowstride=s->paddedWidthInBytes;
  401. LOCK(s->cursorMutex);
  402. if(!c) {
  403. UNLOCK(s->cursorMutex);
  404. return;
  405. }
  406. /* restore what is under the cursor */
  407. x1=cl->cursorX-c->xhot;
  408. x2=x1+c->width;
  409. if(x1<0) x1=0;
  410. if(x2>=s->width) x2=s->width-1;
  411. x2-=x1; if(x2<=0) {
  412. UNLOCK(s->cursorMutex);
  413. return;
  414. }
  415. y1=cl->cursorY-c->yhot;
  416. y2=y1+c->height;
  417. if(y1<0) y1=0;
  418. if(y2>=s->height) y2=s->height-1;
  419. y2-=y1; if(y2<=0) {
  420. UNLOCK(s->cursorMutex);
  421. return;
  422. }
  423. /* get saved data */
  424. for(j=0;j<y2;j++)
  425. memcpy(s->frameBuffer+(y1+j)*rowstride+x1*bpp,
  426. s->underCursorBuffer+j*x2*bpp,
  427. x2*bpp);
  428. /* Copy to all scaled versions */
  429. rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
  430. UNLOCK(s->cursorMutex);
  431. }
  432. void rfbShowCursor(rfbClientPtr cl)
  433. {
  434. rfbScreenInfoPtr s=cl->screen;
  435. rfbCursorPtr c=s->cursor;
  436. int i,j,x1,x2,y1,y2,i1,j1,bpp=s->serverFormat.bitsPerPixel/8,
  437. rowstride=s->paddedWidthInBytes,
  438. bufSize,w;
  439. rfbBool wasChanged=FALSE;
  440. if(!c) return;
  441. LOCK(s->cursorMutex);
  442. bufSize=c->width*c->height*bpp;
  443. w=(c->width+7)/8;
  444. if(s->underCursorBufferLen<bufSize) {
  445. if(s->underCursorBuffer!=NULL)
  446. free(s->underCursorBuffer);
  447. s->underCursorBuffer=malloc(bufSize);
  448. s->underCursorBufferLen=bufSize;
  449. }
  450. /* save what is under the cursor */
  451. i1=j1=0; /* offset in cursor */
  452. x1=cl->cursorX-c->xhot;
  453. x2=x1+c->width;
  454. if(x1<0) { i1=-x1; x1=0; }
  455. if(x2>=s->width) x2=s->width-1;
  456. x2-=x1; if(x2<=0) {
  457. UNLOCK(s->cursorMutex);
  458. return; /* nothing to do */
  459. }
  460. y1=cl->cursorY-c->yhot;
  461. y2=y1+c->height;
  462. if(y1<0) { j1=-y1; y1=0; }
  463. if(y2>=s->height) y2=s->height-1;
  464. y2-=y1; if(y2<=0) {
  465. UNLOCK(s->cursorMutex);
  466. return; /* nothing to do */
  467. }
  468. /* save data */
  469. for(j=0;j<y2;j++) {
  470. char* dest=s->underCursorBuffer+j*x2*bpp;
  471. const char* src=s->frameBuffer+(y1+j)*rowstride+x1*bpp;
  472. unsigned int count=x2*bpp;
  473. if(wasChanged || memcmp(dest,src,count)) {
  474. wasChanged=TRUE;
  475. memcpy(dest,src,count);
  476. }
  477. }
  478. if(!c->richSource)
  479. rfbMakeRichCursorFromXCursor(s,c);
  480. if (c->alphaSource) {
  481. int rmax, rshift;
  482. int gmax, gshift;
  483. int bmax, bshift;
  484. int amax = 255; /* alphaSource is always 8bits of info per pixel */
  485. unsigned int rmask, gmask, bmask;
  486. rmax = s->serverFormat.redMax;
  487. gmax = s->serverFormat.greenMax;
  488. bmax = s->serverFormat.blueMax;
  489. rshift = s->serverFormat.redShift;
  490. gshift = s->serverFormat.greenShift;
  491. bshift = s->serverFormat.blueShift;
  492. rmask = (rmax << rshift);
  493. gmask = (gmax << gshift);
  494. bmask = (bmax << bshift);
  495. for(j=0;j<y2;j++) {
  496. for(i=0;i<x2;i++) {
  497. /*
  498. * we loop over the whole cursor ignoring c->mask[],
  499. * using the extracted alpha value instead.
  500. */
  501. char *dest;
  502. unsigned char *src, *aptr;
  503. unsigned int val, dval, sval;
  504. int rdst, gdst, bdst; /* fb RGB */
  505. int asrc, rsrc, gsrc, bsrc; /* rich source ARGB */
  506. dest = s->frameBuffer + (j+y1)*rowstride + (i+x1)*bpp;
  507. src = c->richSource + (j+j1)*c->width*bpp + (i+i1)*bpp;
  508. aptr = c->alphaSource + (j+j1)*c->width + (i+i1);
  509. asrc = *aptr;
  510. if (!asrc) {
  511. continue;
  512. }
  513. if (bpp == 1) {
  514. dval = *((unsigned char*) dest);
  515. sval = *((unsigned char*) src);
  516. } else if (bpp == 2) {
  517. dval = *((unsigned short*) dest);
  518. sval = *((unsigned short*) src);
  519. } else if (bpp == 3) {
  520. unsigned char *dst = (unsigned char *) dest;
  521. dval = 0;
  522. dval |= ((*(dst+0)) << 0);
  523. dval |= ((*(dst+1)) << 8);
  524. dval |= ((*(dst+2)) << 16);
  525. sval = 0;
  526. sval |= ((*(src+0)) << 0);
  527. sval |= ((*(src+1)) << 8);
  528. sval |= ((*(src+2)) << 16);
  529. } else if (bpp == 4) {
  530. dval = *((unsigned int*) dest);
  531. sval = *((unsigned int*) src);
  532. } else {
  533. continue;
  534. }
  535. /* extract dest and src RGB */
  536. rdst = (dval & rmask) >> rshift; /* fb */
  537. gdst = (dval & gmask) >> gshift;
  538. bdst = (dval & bmask) >> bshift;
  539. rsrc = (sval & rmask) >> rshift; /* richcursor */
  540. gsrc = (sval & gmask) >> gshift;
  541. bsrc = (sval & bmask) >> bshift;
  542. /* blend in fb data. */
  543. if (! c->alphaPreMultiplied) {
  544. rsrc = (asrc * rsrc)/amax;
  545. gsrc = (asrc * gsrc)/amax;
  546. bsrc = (asrc * bsrc)/amax;
  547. }
  548. rdst = rsrc + ((amax - asrc) * rdst)/amax;
  549. gdst = gsrc + ((amax - asrc) * gdst)/amax;
  550. bdst = bsrc + ((amax - asrc) * bdst)/amax;
  551. val = 0;
  552. val |= (rdst << rshift);
  553. val |= (gdst << gshift);
  554. val |= (bdst << bshift);
  555. /* insert the cooked pixel into the fb */
  556. memcpy(dest, &val, bpp);
  557. }
  558. }
  559. } else {
  560. /* now the cursor has to be drawn */
  561. for(j=0;j<y2;j++)
  562. for(i=0;i<x2;i++)
  563. if((c->mask[(j+j1)*w+(i+i1)/8]<<((i+i1)&7))&0x80)
  564. memcpy(s->frameBuffer+(j+y1)*rowstride+(i+x1)*bpp,
  565. c->richSource+(j+j1)*c->width*bpp+(i+i1)*bpp,bpp);
  566. }
  567. /* Copy to all scaled versions */
  568. rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
  569. UNLOCK(s->cursorMutex);
  570. }
  571. /*
  572. * If enableCursorShapeUpdates is FALSE, and the cursor is hidden, make sure
  573. * that if the frameBuffer was transmitted with a cursor drawn, then that
  574. * region gets redrawn.
  575. */
  576. void rfbRedrawAfterHideCursor(rfbClientPtr cl,sraRegionPtr updateRegion)
  577. {
  578. rfbScreenInfoPtr s = cl->screen;
  579. rfbCursorPtr c = s->cursor;
  580. if(c) {
  581. int x,y,x2,y2;
  582. x = cl->cursorX-c->xhot;
  583. y = cl->cursorY-c->yhot;
  584. x2 = x+c->width;
  585. y2 = y+c->height;
  586. if(sraClipRect2(&x,&y,&x2,&y2,0,0,s->width,s->height)) {
  587. sraRegionPtr rect;
  588. rect = sraRgnCreateRect(x,y,x2,y2);
  589. if(updateRegion)
  590. sraRgnOr(updateRegion,rect);
  591. else
  592. sraRgnOr(cl->modifiedRegion,rect);
  593. sraRgnDestroy(rect);
  594. }
  595. }
  596. }
  597. #ifdef DEBUG
  598. static void rfbPrintXCursor(rfbCursorPtr cursor)
  599. {
  600. int i,i1,j,w=(cursor->width+7)/8;
  601. unsigned char bit;
  602. for(j=0;j<cursor->height;j++) {
  603. for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
  604. if(cursor->source[j*w+i]&bit) putchar('#'); else putchar(' ');
  605. putchar(':');
  606. for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
  607. if(cursor->mask[j*w+i]&bit) putchar('#'); else putchar(' ');
  608. putchar('\n');
  609. }
  610. }
  611. #endif
  612. void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c)
  613. {
  614. rfbClientIteratorPtr iterator;
  615. rfbClientPtr cl;
  616. LOCK(rfbScreen->cursorMutex);
  617. if(rfbScreen->cursor) {
  618. iterator=rfbGetClientIterator(rfbScreen);
  619. while((cl=rfbClientIteratorNext(iterator)))
  620. if(!cl->enableCursorShapeUpdates)
  621. rfbRedrawAfterHideCursor(cl,NULL);
  622. rfbReleaseClientIterator(iterator);
  623. if(rfbScreen->cursor->cleanup)
  624. rfbFreeCursor(rfbScreen->cursor);
  625. }
  626. rfbScreen->cursor = c;
  627. iterator=rfbGetClientIterator(rfbScreen);
  628. while((cl=rfbClientIteratorNext(iterator))) {
  629. cl->cursorWasChanged = TRUE;
  630. if(!cl->enableCursorShapeUpdates)
  631. rfbRedrawAfterHideCursor(cl,NULL);
  632. }
  633. rfbReleaseClientIterator(iterator);
  634. UNLOCK(rfbScreen->cursorMutex);
  635. }