cursor.c 14.5 KB
Newer Older
dscho's avatar
dscho committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * cursor.c - support for cursor shape updates.
 */

/*
 *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
 *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
 *
 *  This is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this software; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 *  USA.
 */

#include "rfb.h"
26

dscho's avatar
dscho committed
27 28 29 30 31
/*
 * Send cursor shape either in X-style format or in client pixel format.
 */

Bool
32
rfbSendCursorShape(cl)
dscho's avatar
dscho committed
33 34
    rfbClientPtr cl;
{
35
    rfbCursorPtr pCursor;
dscho's avatar
dscho committed
36 37 38
    rfbFramebufferUpdateRectHeader rect;
    rfbXCursorColors colors;
    int saved_ublen;
39
    int bitmapRowBytes, maskBytes, dataBytes;
dscho's avatar
dscho committed
40
    int i, j;
41 42
    uint8_t *bitmapData;
    uint8_t bitmapByte;
dscho's avatar
dscho committed
43

44
    pCursor = cl->screen->getCursorPtr(cl);
45
    /*if(!pCursor) return TRUE;*/
46

dscho's avatar
dscho committed
47
    if (cl->useRichCursorEncoding) {
48 49 50
      if(pCursor && !pCursor->richSource)
	MakeRichCursorFromXCursor(cl->screen,pCursor);
      rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
dscho's avatar
dscho committed
51
    } else {
52
       if(pCursor && !pCursor->source)
53 54
	 MakeXCursorFromRichCursor(cl->screen,pCursor);
       rect.encoding = Swap32IfLE(rfbEncodingXCursor);
dscho's avatar
dscho committed
55 56 57 58
    }

    /* If there is no cursor, send update with empty cursor data. */

59
    if ( pCursor && pCursor->width == 1 &&
60 61
	 pCursor->height == 1 &&
	 pCursor->mask[0] == 0 ) {
dscho's avatar
dscho committed
62 63 64 65
	pCursor = NULL;
    }

    if (pCursor == NULL) {
66
	if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
dscho's avatar
dscho committed
67 68 69 70 71
	    if (!rfbSendUpdateBuf(cl))
		return FALSE;
	}
	rect.r.x = rect.r.y = 0;
	rect.r.w = rect.r.h = 0;
72
	memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
dscho's avatar
dscho committed
73
	       sz_rfbFramebufferUpdateRectHeader);
74
	cl->ublen += sz_rfbFramebufferUpdateRectHeader;
dscho's avatar
dscho committed
75

76 77
	cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader;
	cl->rfbCursorShapeUpdatesSent++;
dscho's avatar
dscho committed
78 79 80 81 82 83 84 85 86

	if (!rfbSendUpdateBuf(cl))
	    return FALSE;

	return TRUE;
    }

    /* Calculate data sizes. */

87 88
    bitmapRowBytes = (pCursor->width + 7) / 8;
    maskBytes = bitmapRowBytes * pCursor->height;
dscho's avatar
dscho committed
89
    dataBytes = (cl->useRichCursorEncoding) ?
90
	(pCursor->width * pCursor->height *
dscho's avatar
dscho committed
91 92 93 94
	 (cl->format.bitsPerPixel / 8)) : maskBytes;

    /* Send buffer contents if needed. */

95
    if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
dscho's avatar
dscho committed
96 97 98 99 100
	 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
	if (!rfbSendUpdateBuf(cl))
	    return FALSE;
    }

101
    if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
dscho's avatar
dscho committed
102 103 104 105
	 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
	return FALSE;		/* FIXME. */
    }

106
    saved_ublen = cl->ublen;
dscho's avatar
dscho committed
107 108 109

    /* Prepare rectangle header. */

110 111 112 113
    rect.r.x = Swap16IfLE(pCursor->xhot);
    rect.r.y = Swap16IfLE(pCursor->yhot);
    rect.r.w = Swap16IfLE(pCursor->width);
    rect.r.h = Swap16IfLE(pCursor->height);
dscho's avatar
dscho committed
114

115 116
    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
dscho's avatar
dscho committed
117 118 119 120 121 122 123 124 125 126 127 128

    /* Prepare actual cursor data (depends on encoding used). */

    if (!cl->useRichCursorEncoding) {
	/* XCursor encoding. */
	colors.foreRed   = (char)(pCursor->foreRed   >> 8);
	colors.foreGreen = (char)(pCursor->foreGreen >> 8);
	colors.foreBlue  = (char)(pCursor->foreBlue  >> 8);
	colors.backRed   = (char)(pCursor->backRed   >> 8);
	colors.backGreen = (char)(pCursor->backGreen >> 8);
	colors.backBlue  = (char)(pCursor->backBlue  >> 8);

129 130
	memcpy(&cl->updateBuf[cl->ublen], (char *)&colors, sz_rfbXCursorColors);
	cl->ublen += sz_rfbXCursorColors;
dscho's avatar
dscho committed
131

132
	bitmapData = (uint8_t *)pCursor->source;
dscho's avatar
dscho committed
133

134
	for (i = 0; i < pCursor->height; i++) {
dscho's avatar
dscho committed
135
	    for (j = 0; j < bitmapRowBytes; j++) {
136 137
		bitmapByte = bitmapData[i * bitmapRowBytes + j];
		cl->updateBuf[cl->ublen++] = (char)bitmapByte;
dscho's avatar
dscho committed
138 139 140 141
	    }
	}
    } else {
	/* RichCursor encoding. */
142 143 144 145
       int bpp1=cl->screen->rfbServerFormat.bitsPerPixel/8,
	 bpp2=cl->format.bitsPerPixel/8;
       (*cl->translateFn)(cl->translateLookupTable,
		       &(cl->screen->rfbServerFormat),
dscho's avatar
dscho committed
146
                       &cl->format, (char*)pCursor->richSource,
147 148 149 150
		       &cl->updateBuf[cl->ublen],
                       pCursor->width*bpp1, pCursor->width, pCursor->height);

       cl->ublen += pCursor->width*bpp2*pCursor->height;
dscho's avatar
dscho committed
151 152 153 154
    }

    /* Prepare transparency mask. */

155
    bitmapData = (uint8_t *)pCursor->mask;
dscho's avatar
dscho committed
156

157
    for (i = 0; i < pCursor->height; i++) {
dscho's avatar
dscho committed
158
	for (j = 0; j < bitmapRowBytes; j++) {
159 160
	    bitmapByte = bitmapData[i * bitmapRowBytes + j];
	    cl->updateBuf[cl->ublen++] = (char)bitmapByte;
dscho's avatar
dscho committed
161 162 163
	}
    }

164
    /* Send everything we have prepared in the cl->updateBuf[]. */
dscho's avatar
dscho committed
165

166 167
    cl->rfbCursorShapeBytesSent += (cl->ublen - saved_ublen);
    cl->rfbCursorShapeUpdatesSent++;
dscho's avatar
dscho committed
168 169 170 171 172 173 174

    if (!rfbSendUpdateBuf(cl))
	return FALSE;

    return TRUE;
}

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
/*
 * Send cursor position (PointerPos pseudo-encoding).
 */

Bool
rfbSendCursorPos(rfbClientPtr cl)
{
  rfbFramebufferUpdateRectHeader rect;

  if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
    if (!rfbSendUpdateBuf(cl))
      return FALSE;
  }

  rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
  rect.r.x = Swap16IfLE(cl->screen->cursorX);
  rect.r.y = Swap16IfLE(cl->screen->cursorY);
  rect.r.w = 0;
  rect.r.h = 0;

  memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
	 sz_rfbFramebufferUpdateRectHeader);
  cl->ublen += sz_rfbFramebufferUpdateRectHeader;

  cl->rfbCursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader;
  cl->rfbCursorPosUpdatesSent++;

  if (!rfbSendUpdateBuf(cl))
    return FALSE;

  return TRUE;
}

208
/* conversion routine for predefined cursors in LSB order */
209
unsigned char rfbReverseByte[0x100] = {
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
  /* copied from Xvnc/lib/font/util/utilbitmap.c */
	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
};

245 246 247 248
void rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char* bitmap)
{
   int i,t=(width+7)/8*height;
   for(i=0;i<t;i++)
dscho's avatar
dscho committed
249
     bitmap[i]=rfbReverseByte[(int)bitmap[i]];
250 251
}

252 253
/* Cursor creation. You "paint" a cursor and let these routines do the work */

254 255 256 257 258 259
rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskString)
{
   int i,j,w=(width+7)/8;
   rfbCursorPtr cursor = (rfbCursorPtr)calloc(1,sizeof(rfbCursor));
   char* cp;
   unsigned char bit;
dscho's avatar
dscho committed
260

261 262
   cursor->width=width;
   cursor->height=height;
263
   /*cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff;*/
264 265
   cursor->foreRed=cursor->foreGreen=cursor->foreBlue=0xffff;
   
dscho's avatar
dscho committed
266
   cursor->source = (unsigned char*)calloc(w,height);
267 268 269 270 271
   for(j=0,cp=cursorString;j<height;j++)
      for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
	if(*cp!=' ') cursor->source[j*w+i/8]|=bit;

   if(maskString) {
dscho's avatar
dscho committed
272
      cursor->mask = (unsigned char*)calloc(w,height);
273 274 275 276
      for(j=0,cp=maskString;j<height;j++)
	for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
	  if(*cp!=' ') cursor->mask[j*w+i/8]|=bit;
   } else
dscho's avatar
dscho committed
277
     cursor->mask = (unsigned char*)rfbMakeMaskForXCursor(width,height,(char*)cursor->source);
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307

   return(cursor);
}

char* rfbMakeMaskForXCursor(int width,int height,char* source)
{
   int i,j,w=(width+7)/8;
   char* mask=(char*)calloc(w,height);
   unsigned char c;
   
   for(j=0;j<height;j++)
     for(i=w-1;i>=0;i--) {
	c=source[j*w+i];
	if(j>0) c|=source[(j-1)*w+i];
	if(j<height-1) c|=source[(j+1)*w+i];
	
	if(i>0 && (c&0x80))
	  mask[j*w+i-1]|=0x01;
	if(i<w-1 && (c&0x01))
	  mask[j*w+i+1]|=0x80;
	
	mask[j*w+i]|=(c<<1)|c|(c>>1);
     }
   
   return(mask);
}

void rfbFreeCursor(rfbCursorPtr cursor)
{
   if(cursor) {
dscho's avatar
dscho committed
308 309
      if(cursor->richSource)
	 free(cursor->richSource);
310 311 312 313 314 315 316 317 318 319 320 321 322
      free(cursor->source);
      free(cursor->mask);
      free(cursor);
   }
   
}

/* background and foregroud colour have to be set beforehand */
void MakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
{
   rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
   int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8,
     width=cursor->width*bpp;
323
   uint32_t background;
324 325 326
   char *back=(char*)&background;
   unsigned char bit;
   
dscho's avatar
dscho committed
327
   cursor->source=(unsigned char*)calloc(w,cursor->height);
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
   
   if(format->bigEndian)
      back+=4-bpp;

   background=cursor->backRed<<format->redShift|
     cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift;

   for(j=0;j<cursor->height;j++)
     for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1)
       if(memcmp(cursor->richSource+j*width+i*bpp,back,bpp))
	 cursor->source[j*w+i/8]|=bit;
}

void MakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
{
   rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
   int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8;
345
   uint32_t background,foreground;
dscho's avatar
dscho committed
346 347
   char *back=(char*)&background,*fore=(char*)&foreground;
   unsigned char *cp;
348 349
   unsigned char bit;

dscho's avatar
dscho committed
350
   cp=cursor->richSource=(unsigned char*)calloc(cursor->width*bpp,cursor->height);
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
   
   if(format->bigEndian) {
      back+=4-bpp;
      fore+=4-bpp;
   }

   background=cursor->backRed<<format->redShift|
     cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift;
   foreground=cursor->foreRed<<format->redShift|
     cursor->foreGreen<<format->greenShift|cursor->foreBlue<<format->blueShift;
   
   for(j=0;j<cursor->height;j++)
     for(i=0,bit=0x80;i<cursor->height;i++,bit=(bit&1)?0x80:bit>>1,cp+=bpp)
       if(cursor->source[j*w+i/8]&bit) memcpy(cp,fore,bpp);
       else memcpy(cp,back,bpp);
}

368 369
/* functions to draw/hide cursor directly in the frame buffer */

370
void rfbUndrawCursor(rfbScreenInfoPtr s)
371 372 373 374
{
   rfbCursorPtr c=s->cursor;
   int j,x1,x2,y1,y2,bpp=s->rfbServerFormat.bitsPerPixel/8,
     rowstride=s->paddedWidthInBytes;
375
   LOCK(s->cursorMutex);
dscho's avatar
dscho committed
376
   if(!s->cursorIsDrawn) {
377
     UNLOCK(s->cursorMutex);
378
     return;
dscho's avatar
dscho committed
379 380
   }
   
381 382 383 384 385
   /* restore what is under the cursor */
   x1=s->cursorX-c->xhot;
   x2=x1+c->width;
   if(x1<0) x1=0;
   if(x2>=s->width) x2=s->width-1;
dscho's avatar
dscho committed
386
   x2-=x1; if(x2<=0) {
387
     UNLOCK(s->cursorMutex);
dscho's avatar
dscho committed
388 389
     return;
   }
390 391 392 393
   y1=s->cursorY-c->yhot;
   y2=y1+c->height;
   if(y1<0) y1=0;
   if(y2>=s->height) y2=s->height-1;
dscho's avatar
dscho committed
394
   y2-=y1; if(y2<=0) {
395
     UNLOCK(s->cursorMutex);
dscho's avatar
dscho committed
396 397
     return;
   }
398 399

   /* get saved data */
400 401 402 403
   for(j=0;j<y2;j++)
     memcpy(s->frameBuffer+(y1+j)*rowstride+x1*bpp,
	    s->underCursorBuffer+j*x2*bpp,
	    x2*bpp);
dscho's avatar
dscho committed
404 405 406
   
   rfbMarkRectAsModified(s,x1,y1,x1+x2,y1+y2);
   s->cursorIsDrawn = FALSE;
407
   UNLOCK(s->cursorMutex);
408 409
}

410
void rfbDrawCursor(rfbScreenInfoPtr s)
411 412 413 414
{
   rfbCursorPtr c=s->cursor;
   int i,j,x1,x2,y1,y2,i1,j1,bpp=s->rfbServerFormat.bitsPerPixel/8,
     rowstride=s->paddedWidthInBytes,
415 416
     bufSize,w;
   if(!c) return;
417
   LOCK(s->cursorMutex);
dscho's avatar
dscho committed
418 419
   if(s->cursorIsDrawn) {
     /* is already drawn */
420
     UNLOCK(s->cursorMutex);
dscho's avatar
dscho committed
421 422
     return;
   }
423 424
   bufSize=c->width*c->height*bpp;
   w=(c->width+7)/8;
425 426 427 428 429 430 431 432 433 434 435 436
   if(s->underCursorBufferLen<bufSize) {
      if(s->underCursorBuffer!=NULL)
	free(s->underCursorBuffer);
      s->underCursorBuffer=malloc(bufSize);
      s->underCursorBufferLen=bufSize;
   }
   /* save what is under the cursor */
   i1=j1=0; /* offset in cursor */
   x1=s->cursorX-c->xhot;
   x2=x1+c->width;
   if(x1<0) { i1=-x1; x1=0; }
   if(x2>=s->width) x2=s->width-1;
dscho's avatar
dscho committed
437
   x2-=x1; if(x2<=0) {
438
     UNLOCK(s->cursorMutex);
dscho's avatar
dscho committed
439 440
     return; /* nothing to do */
   }
441 442 443 444
   y1=s->cursorY-c->yhot;
   y2=y1+c->height;
   if(y1<0) { j1=-y1; y1=0; }
   if(y2>=s->height) y2=s->height-1;
dscho's avatar
dscho committed
445
   y2-=y1; if(y2<=0) {
446
     UNLOCK(s->cursorMutex);
dscho's avatar
dscho committed
447 448
     return; /* nothing to do */
   }
449 450

   /* save data */
451 452 453 454 455 456 457 458 459 460 461 462 463 464
   for(j=0;j<y2;j++)
     memcpy(s->underCursorBuffer+j*x2*bpp,
	    s->frameBuffer+(y1+j)*rowstride+x1*bpp,
	    x2*bpp);
   
   if(!c->richSource)
     MakeRichCursorFromXCursor(s,c);
   
   /* now the cursor has to be drawn */
   for(j=0;j<y2;j++)
     for(i=0;i<x2;i++)
       if((c->mask[(j+j1)*w+(i+i1)/8]<<((i+i1)&7))&0x80)
	 memcpy(s->frameBuffer+(j+y1)*rowstride+(i+x1)*bpp,
		c->richSource+(j+j1)*c->width*bpp+(i+i1)*bpp,bpp);
dscho's avatar
dscho committed
465

466

dscho's avatar
dscho committed
467 468
   rfbMarkRectAsModified(s,x1,y1,x1+x2,y1+y2);
   s->cursorIsDrawn = TRUE;
469
   UNLOCK(s->cursorMutex);
470 471
}

472 473
/* for debugging */

474 475 476 477 478 479 480 481 482 483 484 485 486
void rfbPrintXCursor(rfbCursorPtr cursor)
{
   int i,i1,j,w=(cursor->width+7)/8;
   unsigned char bit;
   for(j=0;j<cursor->height;j++) {
      for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
	if(cursor->source[j*w+i]&bit) putchar('#'); else putchar(' ');
      putchar(':');
      for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
	if(cursor->mask[j*w+i]&bit) putchar('#'); else putchar(' ');
      putchar('\n');
   }
}
dscho's avatar
dscho committed
487

488
void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c,Bool freeOld)
dscho's avatar
dscho committed
489
{
490
  LOCK(rfbScreen->cursorMutex);
dscho's avatar
dscho committed
491 492 493 494 495
  while(rfbScreen->cursorIsDrawn) {
    UNLOCK(rfbScreen->cursorMutex);
    rfbUndrawCursor(rfbScreen);
    LOCK(rfbScreen->cursorMutex);
  }
496

dscho's avatar
dscho committed
497 498 499 500
  if(freeOld && rfbScreen->cursor)
    rfbFreeCursor(rfbScreen->cursor);

  rfbScreen->cursor = c;
501 502

  UNLOCK(rfbScreen->cursorMutex);
dscho's avatar
dscho committed
503
}