add libvncserver
[presencevnc] / libvnc / libvncserver / cursor.c
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                         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                     sraRgnOr(cl->modifiedRegion,rect);
700             sraRgnDestroy(rect);
701         }
702     }
703 }
704
705 #ifdef DEBUG
706
707 static void rfbPrintXCursor(rfbCursorPtr cursor)
708 {
709    int i,i1,j,w=(cursor->width+7)/8;
710    unsigned char bit;
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(' ');
714       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(' ');
717       putchar('\n');
718    }
719 }
720
721 #endif
722
723 void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c)
724 {
725   rfbClientIteratorPtr iterator;
726   rfbClientPtr cl;
727
728   LOCK(rfbScreen->cursorMutex);
729
730   if(rfbScreen->cursor) {
731     iterator=rfbGetClientIterator(rfbScreen);
732     while((cl=rfbClientIteratorNext(iterator)))
733         if(!cl->enableCursorShapeUpdates)
734           rfbRedrawAfterHideCursor(cl,NULL);
735     rfbReleaseClientIterator(iterator);
736
737     if(rfbScreen->cursor->cleanup)
738          rfbFreeCursor(rfbScreen->cursor);
739   }
740
741   rfbScreen->cursor = c;
742
743   iterator=rfbGetClientIterator(rfbScreen);
744   while((cl=rfbClientIteratorNext(iterator))) {
745     cl->cursorWasChanged = TRUE;
746     if(!cl->enableCursorShapeUpdates)
747       rfbRedrawAfterHideCursor(cl,NULL);
748   }
749   rfbReleaseClientIterator(iterator);
750
751   UNLOCK(rfbScreen->cursorMutex);
752 }
753