2 * cursor.c - support for cursor shape updates.
6 * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
7 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
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.
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.
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,
26 #include <rfb/rfbregion.h>
29 void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
32 * Send cursor shape either in X-style format or in client pixel format.
36 rfbSendCursorShape(rfbClientPtr cl)
39 rfbFramebufferUpdateRectHeader rect;
40 rfbXCursorColors colors;
42 int bitmapRowBytes, maskBytes, dataBytes;
47 /* TODO: scale the cursor data to the correct size */
49 pCursor = cl->screen->getCursorPtr(cl);
50 /*if(!pCursor) return TRUE;*/
52 if (cl->useRichCursorEncoding) {
53 if(pCursor && !pCursor->richSource)
54 rfbMakeRichCursorFromXCursor(cl->screen,pCursor);
55 rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
57 if(pCursor && !pCursor->source)
58 rfbMakeXCursorFromRichCursor(cl->screen,pCursor);
59 rect.encoding = Swap32IfLE(rfbEncodingXCursor);
62 /* If there is no cursor, send update with empty cursor data. */
64 if ( pCursor && pCursor->width == 1 &&
65 pCursor->height == 1 &&
66 pCursor->mask[0] == 0 ) {
70 if (pCursor == NULL) {
71 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
72 if (!rfbSendUpdateBuf(cl))
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;
81 if (!rfbSendUpdateBuf(cl))
87 /* Calculate data sizes. */
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;
95 /* Send buffer contents if needed. */
97 if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
98 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
99 if (!rfbSendUpdateBuf(cl))
103 if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
104 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
105 return FALSE; /* FIXME. */
108 saved_ublen = cl->ublen;
110 /* Prepare rectangle header. */
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);
117 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
118 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
120 /* Prepare actual cursor data (depends on encoding used). */
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);
131 memcpy(&cl->updateBuf[cl->ublen], (char *)&colors, sz_rfbXCursorColors);
132 cl->ublen += sz_rfbXCursorColors;
134 bitmapData = (uint8_t *)pCursor->source;
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;
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);
152 cl->ublen += pCursor->width*bpp2*pCursor->height;
155 /* Prepare transparency mask. */
157 bitmapData = (uint8_t *)pCursor->mask;
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;
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));
170 if (!rfbSendUpdateBuf(cl))
177 * Send cursor position (PointerPos pseudo-encoding).
181 rfbSendCursorPos(rfbClientPtr cl)
183 rfbFramebufferUpdateRectHeader rect;
185 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
186 if (!rfbSendUpdateBuf(cl))
190 rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
191 rect.r.x = Swap16IfLE(cl->screen->cursorX);
192 rect.r.y = Swap16IfLE(cl->screen->cursorY);
196 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
197 sz_rfbFramebufferUpdateRectHeader);
198 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
200 rfbStatRecordEncodingSent(cl, rfbEncodingPointerPos, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
202 if (!rfbSendUpdateBuf(cl))
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
245 void rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char* bitmap)
247 int i,t=(width+7)/8*height;
249 bitmap[i]=rfbReverseByte[(int)bitmap[i]];
252 /* Cursor creation. You "paint" a cursor and let these routines do the work */
254 rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskString)
256 int i,j,w=(width+7)/8;
257 rfbCursorPtr cursor = (rfbCursorPtr)calloc(1,sizeof(rfbCursor));
261 cursor->cleanup=TRUE;
263 cursor->height=height;
264 /*cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff;*/
265 cursor->foreRed=cursor->foreGreen=cursor->foreBlue=0xffff;
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;
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;
279 cursor->mask = (unsigned char*)rfbMakeMaskForXCursor(width,height,(char*)cursor->source);
280 cursor->cleanupMask = TRUE;
285 char* rfbMakeMaskForXCursor(int width,int height,char* source)
287 int i,j,w=(width+7)/8;
288 char* mask=(char*)calloc(w,height);
291 for(j=0;j<height;j++)
292 for(i=w-1;i>=0;i--) {
294 if(j>0) c|=source[(j-1)*w+i];
295 if(j<height-1) c|=source[(j+1)*w+i];
299 if(i<w-1 && (c&0x01))
302 mask[j*w+i]|=(c<<1)|c|(c>>1);
308 /* this function dithers the alpha using Floyd-Steinberg */
310 char* rfbMakeMaskFromAlphaSource(int width,int height,unsigned char* alphaSource)
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);
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];
321 if(currentError<0x80) {
322 /* set to transparent */
323 /* alpha was treated as 0 */
326 result[i/8+j*maskStride]|=(0x100>>(i&7));
327 /* alpha was treated as 0xff */
330 /* propagate to next row */
331 right=currentError/16;
332 middle=currentError*5/16;
333 left=currentError*3/16;
334 currentError-=right+middle+left;
343 return (char *) result;
346 void rfbFreeCursor(rfbCursorPtr 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)
360 cursor->cleanup=cursor->cleanupSource=cursor->cleanupMask
361 =cursor->cleanupRichSource=FALSE;
362 cursor->source=cursor->mask=cursor->richSource=NULL;
363 cursor->alphaSource=NULL;
369 /* background and foregroud colour have to be set beforehand */
370 void rfbMakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
372 rfbPixelFormat* format=&rfbScreen->serverFormat;
373 int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8,
374 width=cursor->width*bpp;
376 char *back=(char*)&background;
378 int interp = 0, db = 0;
380 if(cursor->source && cursor->cleanupSource)
381 free(cursor->source);
382 cursor->source=(unsigned char*)calloc(w,cursor->height);
383 cursor->cleanupSource=TRUE;
385 if(format->bigEndian) {
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)) {
394 cursor->foreRed = cursor->foreGreen = cursor->foreBlue = 0xffff;
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;
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;
407 if (db) fprintf(stderr, "interp: %d\n", interp);
409 for(j=0;j<cursor->height;j++) {
410 for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1) {
412 int r = 0, g = 0, b = 0, grey;
413 char *p = cursor->richSource+j*width+i*bpp;
415 unsigned char* uc = (unsigned char*) p;
417 } else if (bpp == 2) {
418 unsigned short* us = (unsigned short*) p;
420 } else if (bpp == 4) {
421 unsigned int* ui = (unsigned int*) p;
424 grey = (r + g + b) / 3;
426 cursor->source[j*w+i/8]|=bit;
427 if (db) fprintf(stderr, "1");
429 if (db) fprintf(stderr, "0");
432 } else if(memcmp(cursor->richSource+j*width+i*bpp, back, bpp)) {
433 cursor->source[j*w+i/8]|=bit;
436 if (db) fprintf(stderr, "\n");
440 void rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
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;
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;
454 if(format->bigEndian) {
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;
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);
470 /* functions to draw/hide cursor directly in the frame buffer */
472 void rfbHideCursor(rfbClientPtr cl)
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);
480 UNLOCK(s->cursorMutex);
484 /* restore what is under the cursor */
485 x1=cl->cursorX-c->xhot;
488 if(x2>=s->width) x2=s->width-1;
490 UNLOCK(s->cursorMutex);
493 y1=cl->cursorY-c->yhot;
496 if(y2>=s->height) y2=s->height-1;
498 UNLOCK(s->cursorMutex);
504 memcpy(s->frameBuffer+(y1+j)*rowstride+x1*bpp,
505 s->underCursorBuffer+j*x2*bpp,
508 /* Copy to all scaled versions */
509 rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
511 UNLOCK(s->cursorMutex);
514 void rfbShowCursor(rfbClientPtr cl)
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,
521 rfbBool wasChanged=FALSE;
524 LOCK(s->cursorMutex);
526 bufSize=c->width*c->height*bpp;
528 if(s->underCursorBufferLen<bufSize) {
529 if(s->underCursorBuffer!=NULL)
530 free(s->underCursorBuffer);
531 s->underCursorBuffer=malloc(bufSize);
532 s->underCursorBufferLen=bufSize;
535 /* save what is under the cursor */
536 i1=j1=0; /* offset in cursor */
537 x1=cl->cursorX-c->xhot;
539 if(x1<0) { i1=-x1; x1=0; }
540 if(x2>=s->width) x2=s->width-1;
542 UNLOCK(s->cursorMutex);
543 return; /* nothing to do */
546 y1=cl->cursorY-c->yhot;
548 if(y1<0) { j1=-y1; y1=0; }
549 if(y2>=s->height) y2=s->height-1;
551 UNLOCK(s->cursorMutex);
552 return; /* nothing to do */
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)) {
562 memcpy(dest,src,count);
567 rfbMakeRichCursorFromXCursor(s,c);
569 if (c->alphaSource) {
573 int amax = 255; /* alphaSource is always 8bits of info per pixel */
574 unsigned int rmask, gmask, bmask;
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;
583 rmask = (rmax << rshift);
584 gmask = (gmax << gshift);
585 bmask = (bmax << bshift);
590 * we loop over the whole cursor ignoring c->mask[],
591 * using the extracted alpha value instead.
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 */
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);
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;
617 dval |= ((*(dst+0)) << 0);
618 dval |= ((*(dst+1)) << 8);
619 dval |= ((*(dst+2)) << 16);
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);
631 /* extract dest and src RGB */
632 rdst = (dval & rmask) >> rshift; /* fb */
633 gdst = (dval & gmask) >> gshift;
634 bdst = (dval & bmask) >> bshift;
636 rsrc = (sval & rmask) >> rshift; /* richcursor */
637 gsrc = (sval & gmask) >> gshift;
638 bsrc = (sval & bmask) >> bshift;
640 /* blend in fb data. */
641 if (! c->alphaPreMultiplied) {
642 rsrc = (asrc * rsrc)/amax;
643 gsrc = (asrc * gsrc)/amax;
644 bsrc = (asrc * bsrc)/amax;
646 rdst = rsrc + ((amax - asrc) * rdst)/amax;
647 gdst = gsrc + ((amax - asrc) * gdst)/amax;
648 bdst = bsrc + ((amax - asrc) * bdst)/amax;
651 val |= (rdst << rshift);
652 val |= (gdst << gshift);
653 val |= (bdst << bshift);
655 /* insert the cooked pixel into the fb */
656 memcpy(dest, &val, bpp);
660 /* now the cursor has to be drawn */
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);
668 /* Copy to all scaled versions */
669 rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
671 UNLOCK(s->cursorMutex);
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.
680 void rfbRedrawAfterHideCursor(rfbClientPtr cl,sraRegionPtr updateRegion)
682 rfbScreenInfoPtr s = cl->screen;
683 rfbCursorPtr c = s->cursor;
688 x = cl->cursorX-c->xhot;
689 y = cl->cursorY-c->yhot;
693 if(sraClipRect2(&x,&y,&x2,&y2,0,0,s->width,s->height)) {
695 rect = sraRgnCreateRect(x,y,x2,y2);
697 sraRgnOr(updateRegion,rect);
699 sraRgnOr(cl->modifiedRegion,rect);
707 static void rfbPrintXCursor(rfbCursorPtr cursor)
709 int i,i1,j,w=(cursor->width+7)/8;
711 for(j=0;j<cursor->height;j++) {
712 for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
713 if(cursor->source[j*w+i]&bit) putchar('#'); else putchar(' ');
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->mask[j*w+i]&bit) putchar('#'); else putchar(' ');
723 void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c)
725 rfbClientIteratorPtr iterator;
728 LOCK(rfbScreen->cursorMutex);
730 if(rfbScreen->cursor) {
731 iterator=rfbGetClientIterator(rfbScreen);
732 while((cl=rfbClientIteratorNext(iterator)))
733 if(!cl->enableCursorShapeUpdates)
734 rfbRedrawAfterHideCursor(cl,NULL);
735 rfbReleaseClientIterator(iterator);
737 if(rfbScreen->cursor->cleanup)
738 rfbFreeCursor(rfbScreen->cursor);
741 rfbScreen->cursor = c;
743 iterator=rfbGetClientIterator(rfbScreen);
744 while((cl=rfbClientIteratorNext(iterator))) {
745 cl->cursorWasChanged = TRUE;
746 if(!cl->enableCursorShapeUpdates)
747 rfbRedrawAfterHideCursor(cl,NULL);
749 rfbReleaseClientIterator(iterator);
751 UNLOCK(rfbScreen->cursorMutex);