1
0
mirror of https://invent.kde.org/network/krfb synced 2024-07-03 00:18:36 +00:00

Added support for Softcursor protocol extension

svn path=/trunk/kdenetwork/krfb/; revision=162994
This commit is contained in:
Tim Jansen 2002-06-24 22:23:45 +00:00
parent cb19c577e7
commit 9f44b0dfee
6 changed files with 285 additions and 5 deletions

2
TODO
View File

@ -1,8 +1,6 @@
Todo (unscheduled features):
- attach .vnc file to invitations?
- SLP support (or UPnP, or whatever KDE will use)
- NAT traversal support (MIDCOM stun/turn, UPnP)
- better cursor encodings
- SSL/TLS support?
- better authentication mechanisms?
- look into adding an extension to xfree to improve speed (get noticed of

View File

@ -172,6 +172,134 @@ rfbSendCursorShape(cl)
return TRUE;
}
/*
* Send soft cursor state and possibly image
*/
Bool
rfbSendSoftCursor(cl)
rfbClientPtr cl;
{
rfbCursorPtr pCursor;
rfbSoftCursorSetImage setImage;
rfbSoftCursorMove moveMsg;
rfbFramebufferUpdateRectHeader rect;
int saved_ublen, i, scOindex, scNindex, nlen, imgLen;
pCursor = cl->screen->getCursorPtr(cl);
MakeSoftCursor(cl->screen,pCursor);
/* If there is no cursor, send update with empty cursor data. */
if ( pCursor && pCursor->width <= 1 &&
pCursor->height <= 1 &&
pCursor->mask[0] == 0 ) {
pCursor = NULL;
}
if (pCursor == NULL)
imgLen = 0;
else
imgLen = pCursor->softCursorLength;
setImage.imageLength = Swap16IfLE(imgLen);
scOindex = -1;
scNindex = -1;
for (i = 0; i < rfbSoftCursorMaxImages; i++) {
rfbSoftCursorSetImage *scsi = cl->softCursorImages[i];
if (!scsi) {
scNindex = i;
break;
}
setImage.imageIndex = scsi->imageIndex;
if (!memcmp((char*)scsi, (char*)&setImage, sizeof(setImage))) {
if (imgLen && !memcmp(((char*)scsi)+sizeof(rfbSoftCursorSetImage),
(char*)pCursor->softSource,
imgLen)) {
scOindex = i;
break;
}
}
}
nlen = 0;
if (scOindex < 0) {
if (scNindex < 0) {
scNindex = cl->nextUnusedSoftCursorImage;
cl->nextUnusedSoftCursorImage = (cl->nextUnusedSoftCursorImage+1)
% rfbSoftCursorMaxImages;
free(cl->softCursorImages[scNindex]);
}
scOindex = scNindex;
setImage.imageIndex = scNindex + rfbSoftCursorSetIconOffset;
nlen = sizeof(setImage) + imgLen;
cl->softCursorImages[scNindex] = calloc(1, nlen);
memcpy((char*)cl->softCursorImages[scNindex], (char*)&setImage,
sizeof(setImage));
if (imgLen)
memcpy(((char*)cl->softCursorImages[scNindex])+sizeof(setImage),
(char*)pCursor->softSource, imgLen);
}
/* Send buffer contents if needed. */
if ( cl->ublen + sizeof(rfbSoftCursorMove) +
((scNindex >= 0) ?
(sizeof(rfbSoftCursorSetImage) + imgLen) : 0)) {
if (!rfbSendUpdateBuf(cl))
return FALSE;
}
saved_ublen = cl->ublen;
if (scNindex >= 0) {
rect.encoding = Swap32IfLE(rfbEncodingSoftCursor);
if (pCursor) {
rect.r.x = Swap16IfLE(pCursor->xhot);
rect.r.y = Swap16IfLE(pCursor->yhot);
rect.r.w = Swap16IfLE(pCursor->width);
rect.r.h = Swap16IfLE(pCursor->height);
}
else {
rect.r.x = 0;
rect.r.y = 0;
rect.r.w = 0;
rect.r.h = 0;
}
memcpy(&cl->updateBuf[cl->ublen],
(char *)&rect,sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
memcpy(&cl->updateBuf[cl->ublen], (char*)cl->softCursorImages[scNindex], nlen);
cl->ublen += nlen;
cl->rfbCursorUpdatesSent++;
}
rect.encoding = Swap32IfLE(rfbEncodingSoftCursor);
rect.r.x = 0;
rect.r.y = 0;
rect.r.w = Swap16IfLE(cl->screen->cursorX);
rect.r.h = Swap16IfLE(cl->screen->cursorY);
moveMsg.imageIndex = scOindex;
moveMsg.buttonMask = 0; /* todo */
memcpy(&cl->updateBuf[cl->ublen],
(char *)&rect,sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
memcpy(&cl->updateBuf[cl->ublen], (char*)&moveMsg, sizeof(moveMsg));
cl->ublen += sizeof(moveMsg);
/* Send everything we have prepared in the cl->updateBuf[]. */
cl->rfbCursorBytesSent += (cl->ublen - saved_ublen);
cl->rfbCursorUpdatesSent++;
return rfbSendUpdateBuf(cl);
}
/* conversion routine for predefined cursors in LSB order */
unsigned char rfbReverseByte[0x100] = {
/* copied from Xvnc/lib/font/util/utilbitmap.c */
@ -332,6 +460,73 @@ void MakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
else memcpy(cp,back,bpp);
}
void MakeSoftCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
{
int w = (cursor->width+7)/8;
int bpp = rfbScreen->rfbServerFormat.bitsPerPixel/8;
unsigned char *cp, *sp;
int state; /* 0 = transparent, 1 otherwise */
CARD8 *counter;
unsigned char bit;
int i,j;
if ((!cursor) || cursor->softSource)
return;
if (!cursor->richSource)
MakeRichCursorFromXCursor(rfbScreen, cursor);
cp=cursor->softSource=(unsigned char*)calloc(cursor->width*(bpp+2),cursor->height);
sp=cursor->richSource;
state = 0;
counter = cp++;
*counter = 0;
for(j=0;j<cursor->height;j++)
for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1)
if(cursor->mask[j*w+i/8]&bit) {
if (state) {
memcpy(cp,sp,bpp);
cp += bpp;
sp += bpp;
(*counter)++;
if (*counter == 255) {
state = 0;
counter = cp++;
*counter = 0;
}
}
else {
state = 1;
counter = cp++;
*counter = 1;
memcpy(cp,sp,bpp);
cp += bpp;
sp += bpp;
}
}
else {
if (!state) {
(*counter)++;
if (*counter == 255) {
state = 1;
counter = cp++;
*counter = 0;
}
}
else {
state = 0;
counter = cp++;
*counter = 1;
}
sp += bpp;
}
cursor->softCursorLength = cp - cursor->softSource;
}
/* functions to draw/hide cursor directly in the frame buffer */
void rfbUndrawCursor(rfbScreenInfoPtr s)

View File

@ -370,6 +370,7 @@ void
defaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
{
if(x!=cl->screen->cursorX || y!=cl->screen->cursorY) {
cl->cursorWasMoved = TRUE;
if(cl->screen->cursorIsDrawn)
rfbUndrawCursor(cl->screen);
LOCK(cl->screen->cursorMutex);

View File

@ -503,10 +503,16 @@ typedef struct _rfbClientRec {
int tightCompressLevel;
int tightQualityLevel;
/* soft cursor images */
rfbSoftCursorSetImage *softCursorImages[rfbSoftCursorMaxImages];
int nextUnusedSoftCursorImage;
Bool enableLastRectEncoding; /* client supports LastRect encoding */
Bool enableSoftCursorUpdates; /* client supports softcursor updates */
Bool enableCursorShapeUpdates; /* client supports cursor shape updates */
Bool useRichCursorEncoding; /* rfbEncodingRichCursor is preferred */
Bool cursorWasChanged; /* cursor shape update should be sent */
Bool cursorWasMoved; /* cursor move shape update should be sent */
#ifdef BACKCHANNEL
Bool enableBackChannel;
#endif
@ -697,16 +703,20 @@ typedef struct rfbCursor {
unsigned short width, height, xhot, yhot; /* metrics */
unsigned short foreRed, foreGreen, foreBlue; /* device-independent colour */
unsigned short backRed, backGreen, backBlue; /* device-independent colour */
unsigned short softCursorLength;
unsigned char *richSource; /* source bytes for a rich cursor */
unsigned char *softSource; /* image for a soft cursor */
} rfbCursor, *rfbCursorPtr;
extern Bool rfbSendCursorShape(rfbClientPtr cl/*, rfbScreenInfoPtr pScreen*/);
extern Bool rfbSendSoftCursor(rfbClientPtr cl);
extern unsigned char rfbReverseByte[0x100];
extern void rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char* bitmap);
extern rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskString);
extern char* rfbMakeMaskForXCursor(int width,int height,char* cursorString);
extern void MakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor);
extern void MakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor);
extern void MakeSoftCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor);
extern void rfbFreeCursor(rfbCursorPtr cursor);
extern void rfbDrawCursor(rfbScreenInfoPtr rfbScreen);
extern void rfbUndrawCursor(rfbScreenInfoPtr rfbScreen);

View File

@ -326,6 +326,7 @@ typedef struct {
#define rfbEncodingXCursor 0xFFFFFF10
#define rfbEncodingRichCursor 0xFFFFFF11
#define rfbEncodingSoftCursor 0xFFFFFF12
#define rfbEncodingLastRect 0xFFFFFF20
@ -557,6 +558,53 @@ typedef struct {
* default local cursor should be set by the client).
*/
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* SoftCursor encoding. This encoding is used to transmit image and position
* of the remote cursor. It has two sub-messages: SetImage is used to upload
* one of 16 images, and Move selects the image and sets the position of the
* cursor.
* Each SoftCursor message starts with a CARD8. If it is in the 0-63 range
* it specifies the image of the cursor and is followed by the
* rfbSoftCursorMove message. If the given cursor has not been set yet the
* message will be ignored. If the first CARD8 is in the 128-191 range it
* specifies the cursor that will be set in the following
* rfbSoftCursorSetImage message. To hide the cursor send a SetCursor
* message with width and height 0 and imageLength 0.
* SetImage transports the hotspot coordinates in the x/y fields of the
* rfbFramebufferUpdateRectHeader, width and height of the image in the
* header's width and height fields.
* Move transports the pointer coordinates in the w/h fields of the
* header, x/y are always 0.
*/
typedef struct {
CARD8 imageIndex;
CARD8 buttonMask; /* bits 0-7 are buttons 1-8, 0=up, 1=down */
} rfbSoftCursorMove;
typedef struct {
CARD8 imageIndex;
CARD8 padding;
CARD16 imageLength;
/*
* Followed by an image of the cursor in the client's image format
* with the following RLE mask compression. It begins with CARD8 that
* specifies the number of mask'ed pixels that will be NOT transmitted.
* Then follows a CARD8 that specified by the number of unmask'd pixels
* that will be transmitted next. Then a CARD8 with the number of mask'd
* pixels and so on.
*/
} rfbSoftCursorSetImage;
typedef union {
CARD8 type;
rfbSoftCursorMove move;
rfbSoftCursorSetImage setImage;
} rfbSoftCursorMsg;
#define rfbSoftCursorMaxImages 16
#define rfbSoftCursorSetIconOffset 128
/*-----------------------------------------------------------------------------
* SetColourMapEntries - these messages are only sent if the pixel

View File

@ -732,6 +732,13 @@ rfbProcessClientNormalMessage(cl)
cl->useRichCursorEncoding = TRUE;
cl->cursorWasChanged = TRUE;
break;
case rfbEncodingSoftCursor:
rfbLog("Enabling soft cursor updates for client "
"%s\n", cl->host);
cl->enableSoftCursorUpdates = TRUE;
cl->cursorWasChanged = TRUE;
cl->cursorWasMoved = TRUE;
break;
case rfbEncodingLastRect:
if (!cl->enableLastRectEncoding) {
rfbLog("Enabling LastRect protocol extension for client "
@ -918,6 +925,7 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
sraRegionPtr updateRegion,updateCopyRegion,tmpRegion;
int dx, dy;
Bool sendCursorShape = FALSE;
int sendSoftCursorRects = 0;
if(cl->screen->displayHook)
cl->screen->displayHook(cl);
@ -934,6 +942,15 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
if (!cl->screen->cursorIsDrawn && cl->cursorWasChanged &&
cl->readyForSetColourMapEntries)
sendCursorShape = TRUE;
}
else if (cl->enableSoftCursorUpdates) {
if (cl->screen->cursorIsDrawn) {
rfbUndrawCursor(cl->screen);
}
if (cl->cursorWasChanged)
sendSoftCursorRects=2;
else if (cl->cursorWasMoved)
sendSoftCursorRects=1;
} else {
if (!cl->screen->cursorIsDrawn) {
rfbDrawCursor(cl->screen);
@ -959,7 +976,8 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
updateRegion = sraRgnCreateRgn(givenUpdateRegion);
sraRgnOr(updateRegion,cl->copyRegion);
if(!sraRgnAnd(updateRegion,cl->requestedRegion) && !sendCursorShape) {
if(!sraRgnAnd(updateRegion,cl->requestedRegion) &&
!(sendCursorShape || sendSoftCursorRects)) {
sraRgnDestroy(updateRegion);
UNLOCK(cl->updateMutex);
return TRUE;
@ -1059,7 +1077,8 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
fu->type = rfbFramebufferUpdate;
if (nUpdateRegionRects != 0xFFFF) {
fu->nRects = Swap16IfLE((CARD16)(sraRgnCountRects(updateCopyRegion)
+ nUpdateRegionRects + !!sendCursorShape));
+ nUpdateRegionRects
+ !!sendCursorShape + sendSoftCursorRects));
} else {
fu->nRects = 0xFFFF;
}
@ -1072,7 +1091,16 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
return FALSE;
}
}
if (sendSoftCursorRects) {
cl->cursorWasChanged = FALSE;
cl->cursorWasMoved = FALSE;
if (!rfbSendSoftCursor(cl)) {
sraRgnDestroy(updateRegion);
return FALSE;
}
}
if (!sraRgnEmpty(updateCopyRegion)) {
if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy)) {
sraRgnDestroy(updateRegion);