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