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,
28
* Send cursor shape either in X-style format or in client pixel format.
32
rfbSendCursorShape(cl)
36
rfbFramebufferUpdateRectHeader rect;
37
rfbXCursorColors colors;
39
int bitmapRowBytes, maskBytes, dataBytes;
44
pCursor = cl->screen->getCursorPtr(cl);
45
/*if(!pCursor) return TRUE;*/
47
if (cl->useRichCursorEncoding) {
48
if(pCursor && !pCursor->richSource)
49
MakeRichCursorFromXCursor(cl->screen,pCursor);
50
rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
52
if(pCursor && !pCursor->source)
53
MakeXCursorFromRichCursor(cl->screen,pCursor);
54
rect.encoding = Swap32IfLE(rfbEncodingXCursor);
57
/* If there is no cursor, send update with empty cursor data. */
59
if ( pCursor && pCursor->width == 1 &&
60
pCursor->height == 1 &&
61
pCursor->mask[0] == 0 ) {
65
if (pCursor == NULL) {
66
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
67
if (!rfbSendUpdateBuf(cl))
70
rect.r.x = rect.r.y = 0;
71
rect.r.w = rect.r.h = 0;
72
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
73
sz_rfbFramebufferUpdateRectHeader);
74
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
76
cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader;
77
cl->rfbCursorShapeUpdatesSent++;
79
if (!rfbSendUpdateBuf(cl))
85
/* Calculate data sizes. */
87
bitmapRowBytes = (pCursor->width + 7) / 8;
88
maskBytes = bitmapRowBytes * pCursor->height;
89
dataBytes = (cl->useRichCursorEncoding) ?
90
(pCursor->width * pCursor->height *
91
(cl->format.bitsPerPixel / 8)) : maskBytes;
93
/* Send buffer contents if needed. */
95
if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
96
sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
97
if (!rfbSendUpdateBuf(cl))
101
if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
102
sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
103
return FALSE; /* FIXME. */
106
saved_ublen = cl->ublen;
108
/* Prepare rectangle header. */
110
rect.r.x = Swap16IfLE(pCursor->xhot);
111
rect.r.y = Swap16IfLE(pCursor->yhot);
112
rect.r.w = Swap16IfLE(pCursor->width);
113
rect.r.h = Swap16IfLE(pCursor->height);
115
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
116
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
118
/* Prepare actual cursor data (depends on encoding used). */
120
if (!cl->useRichCursorEncoding) {
121
/* XCursor encoding. */
122
colors.foreRed = (char)(pCursor->foreRed >> 8);
123
colors.foreGreen = (char)(pCursor->foreGreen >> 8);
124
colors.foreBlue = (char)(pCursor->foreBlue >> 8);
125
colors.backRed = (char)(pCursor->backRed >> 8);
126
colors.backGreen = (char)(pCursor->backGreen >> 8);
127
colors.backBlue = (char)(pCursor->backBlue >> 8);
129
memcpy(&cl->updateBuf[cl->ublen], (char *)&colors, sz_rfbXCursorColors);
130
cl->ublen += sz_rfbXCursorColors;
132
bitmapData = (uint8_t *)pCursor->source;
134
for (i = 0; i < pCursor->height; i++) {
135
for (j = 0; j < bitmapRowBytes; j++) {
136
bitmapByte = bitmapData[i * bitmapRowBytes + j];
137
cl->updateBuf[cl->ublen++] = (char)bitmapByte;
141
/* RichCursor encoding. */
142
int bpp1=cl->screen->rfbServerFormat.bitsPerPixel/8,
143
bpp2=cl->format.bitsPerPixel/8;
144
(*cl->translateFn)(cl->translateLookupTable,
145
&(cl->screen->rfbServerFormat),
146
&cl->format, (char*)pCursor->richSource,
147
&cl->updateBuf[cl->ublen],
148
pCursor->width*bpp1, pCursor->width, pCursor->height);
150
cl->ublen += pCursor->width*bpp2*pCursor->height;
153
/* Prepare transparency mask. */
155
bitmapData = (uint8_t *)pCursor->mask;
157
for (i = 0; i < pCursor->height; i++) {
158
for (j = 0; j < bitmapRowBytes; j++) {
159
bitmapByte = bitmapData[i * bitmapRowBytes + j];
160
cl->updateBuf[cl->ublen++] = (char)bitmapByte;
164
/* Send everything we have prepared in the cl->updateBuf[]. */
166
cl->rfbCursorShapeBytesSent += (cl->ublen - saved_ublen);
167
cl->rfbCursorShapeUpdatesSent++;
169
if (!rfbSendUpdateBuf(cl))
176
* Send cursor position (PointerPos pseudo-encoding).
180
rfbSendCursorPos(rfbClientPtr cl)
182
rfbFramebufferUpdateRectHeader rect;
184
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
185
if (!rfbSendUpdateBuf(cl))
189
rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
190
rect.r.x = Swap16IfLE(cl->screen->cursorX);
191
rect.r.y = Swap16IfLE(cl->screen->cursorY);
195
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
196
sz_rfbFramebufferUpdateRectHeader);
197
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
199
cl->rfbCursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader;
200
cl->rfbCursorPosUpdatesSent++;
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
void rfbFreeCursor(rfbCursorPtr cursor)
311
if(cursor->cleanupRichSource && cursor->richSource)
312
free(cursor->richSource);
313
if(cursor->cleanupSource && cursor->source)
314
free(cursor->source);
315
if(cursor->cleanupMask && cursor->mask)
320
cursor->cleanup=cursor->cleanupSource=cursor->cleanupMask
321
=cursor->cleanupRichSource=FALSE;
322
cursor->source=cursor->mask=cursor->richSource=0;
328
/* background and foregroud colour have to be set beforehand */
329
void MakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
331
rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
332
int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8,
333
width=cursor->width*bpp;
335
char *back=(char*)&background;
338
if(cursor->source && cursor->cleanupSource)
339
free(cursor->source);
340
cursor->source=(unsigned char*)calloc(w,cursor->height);
341
cursor->cleanupSource=TRUE;
343
if(format->bigEndian)
346
background=cursor->backRed<<format->redShift|
347
cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift;
349
for(j=0;j<cursor->height;j++)
350
for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1)
351
if(memcmp(cursor->richSource+j*width+i*bpp,back,bpp))
352
cursor->source[j*w+i/8]|=bit;
355
void MakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
357
rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
358
int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8;
359
uint32_t background,foreground;
360
char *back=(char*)&background,*fore=(char*)&foreground;
364
if(cursor->richSource && cursor->cleanupRichSource)
365
free(cursor->richSource);
366
cp=cursor->richSource=(unsigned char*)calloc(cursor->width*bpp,cursor->height);
367
cursor->cleanupRichSource=TRUE;
369
if(format->bigEndian) {
374
background=cursor->backRed<<format->redShift|
375
cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift;
376
foreground=cursor->foreRed<<format->redShift|
377
cursor->foreGreen<<format->greenShift|cursor->foreBlue<<format->blueShift;
379
for(j=0;j<cursor->height;j++)
380
for(i=0,bit=0x80;i<cursor->height;i++,bit=(bit&1)?0x80:bit>>1,cp+=bpp)
381
if(cursor->source[j*w+i/8]&bit) memcpy(cp,fore,bpp);
382
else memcpy(cp,back,bpp);
385
/* functions to draw/hide cursor directly in the frame buffer */
387
void rfbUndrawCursor(rfbScreenInfoPtr s)
389
rfbCursorPtr c=s->cursor;
390
int j,x1,x2,y1,y2,bpp=s->rfbServerFormat.bitsPerPixel/8,
391
rowstride=s->paddedWidthInBytes;
392
LOCK(s->cursorMutex);
393
if(!s->cursorIsDrawn || !c) {
394
UNLOCK(s->cursorMutex);
398
/* restore what is under the cursor */
399
x1=s->cursorX-c->xhot;
402
if(x2>=s->width) x2=s->width-1;
404
UNLOCK(s->cursorMutex);
407
y1=s->cursorY-c->yhot;
410
if(y2>=s->height) y2=s->height-1;
412
UNLOCK(s->cursorMutex);
418
memcpy(s->frameBuffer+(y1+j)*rowstride+x1*bpp,
419
s->underCursorBuffer+j*x2*bpp,
422
/* rfbMarkRectAsModified(s,x1,y1,x1+x2,y1+y2); */
423
s->cursorIsDrawn = FALSE;
424
s->oldCursorX=s->cursorX;
425
s->oldCursorY=s->cursorY;
426
UNLOCK(s->cursorMutex);
429
void rfbDrawCursor(rfbScreenInfoPtr s)
431
rfbCursorPtr c=s->cursor;
432
int i,j,x1,x2,y1,y2,i1,j1,bpp=s->rfbServerFormat.bitsPerPixel/8,
433
rowstride=s->paddedWidthInBytes,
435
rfbBool wasChanged=FALSE;
438
LOCK(s->cursorMutex);
439
if(s->cursorIsDrawn) {
440
/* is already drawn */
441
UNLOCK(s->cursorMutex);
445
if(s->cursor && s->underCursorBuffer &&
446
(s->cursorX!=s->oldCursorX || s->cursorY!=s->oldCursorY)) {
447
int x1=s->oldCursorX-s->cursor->xhot,x2=x1+s->cursor->width;
448
int y1=s->oldCursorY-s->cursor->yhot,y2=y1+s->cursor->height;
449
rfbMarkRectAsModified(s,x1,y1,x2,y2);
451
bufSize=c->width*c->height*bpp;
453
if(s->underCursorBufferLen<bufSize) {
454
if(s->underCursorBuffer!=NULL)
455
free(s->underCursorBuffer);
456
s->underCursorBuffer=malloc(bufSize);
457
s->underCursorBufferLen=bufSize;
459
/* save what is under the cursor */
460
i1=j1=0; /* offset in cursor */
461
x1=s->cursorX-c->xhot;
463
if(x1<0) { i1=-x1; x1=0; }
464
if(x2>=s->width) x2=s->width-1;
466
UNLOCK(s->cursorMutex);
467
return; /* nothing to do */
469
y1=s->cursorY-c->yhot;
471
if(y1<0) { j1=-y1; y1=0; }
472
if(y2>=s->height) y2=s->height-1;
474
UNLOCK(s->cursorMutex);
475
return; /* nothing to do */
480
char* dest=s->underCursorBuffer+j*x2*bpp;
481
const char* src=s->frameBuffer+(y1+j)*rowstride+x1*bpp;
482
unsigned int count=x2*bpp;
483
if(wasChanged || memcmp(dest,src,count)) {
485
memcpy(dest,src,count);
490
MakeRichCursorFromXCursor(s,c);
492
/* now the cursor has to be drawn */
495
if((c->mask[(j+j1)*w+(i+i1)/8]<<((i+i1)&7))&0x80)
496
memcpy(s->frameBuffer+(j+y1)*rowstride+(i+x1)*bpp,
497
c->richSource+(j+j1)*c->width*bpp+(i+i1)*bpp,bpp);
500
rfbMarkRectAsModified(s,x1,y1,x1+x2,y1+y2);
501
s->cursorIsDrawn = TRUE;
502
UNLOCK(s->cursorMutex);
507
void rfbPrintXCursor(rfbCursorPtr cursor)
509
int i,i1,j,w=(cursor->width+7)/8;
511
for(j=0;j<cursor->height;j++) {
512
for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
513
if(cursor->source[j*w+i]&bit) putchar('#'); else putchar(' ');
515
for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
516
if(cursor->mask[j*w+i]&bit) putchar('#'); else putchar(' ');
521
void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c,rfbBool freeOld)
523
LOCK(rfbScreen->cursorMutex);
524
while(rfbScreen->cursorIsDrawn) {
525
UNLOCK(rfbScreen->cursorMutex);
526
rfbUndrawCursor(rfbScreen);
527
LOCK(rfbScreen->cursorMutex);
530
free(rfbScreen->underCursorBuffer);
531
rfbScreen->underCursorBuffer=0;
533
if(rfbScreen->cursor && (freeOld || rfbScreen->cursor->cleanup))
534
rfbFreeCursor(rfbScreen->cursor);
536
rfbScreen->cursor = c;
538
UNLOCK(rfbScreen->cursorMutex);