Home | History | Annotate | Download | only in libvncserver
      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 
     29 void 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 
     35 rfbBool
     36 rfbSendCursorShape(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 
    180 rfbBool
    181 rfbSendCursorPos(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 */
    209 unsigned 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 
    245 void 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 
    254 rfbCursorPtr 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 
    285 char* 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 
    310 char* 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 
    346 void 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 */
    370 void 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 
    440 void 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 
    472 void 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 
    514 void 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 
    680 void 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 
    710 static 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 
    726 void 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