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:
parent
cb19c577e7
commit
9f44b0dfee
2
TODO
2
TODO
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user