patch from Const for CursorPosUpdate encoding

pull/1/head
dscho 20 years ago
parent 347ab48bd9
commit 19c7fc0217
  1. 2
      CHANGES
  2. 2
      README
  3. 47
      cursor.c
  4. 34
      main.c
  5. 11
      rfb.h
  6. 126
      rfbproto.h
  7. 44
      rfbserver.c
  8. 24
      stats.c

@ -1,3 +1,5 @@
got patch from Const Kaplisnky with CursorPosUpdate encoding and some Docs
sync'ed with newest RealVNC (ZRLE encoding)
a HTTP request for tunnelling was added (to fool strict web proxies)
sync'ed with TightVNC 1.2.5
0.4

@ -94,8 +94,6 @@ all the details. Just set the cursor and don't bother any more.
To set the mouse coordinates (or emulate mouse clicks), call
defaultPtrAddEvent(buttonMask,x,y,cl);
However, this works only if your client doesn't do local cursor drawing. There
is no way (to my knowledge) to set the pointer of a client via RFB protocol.
IMPORTANT: do this at the end of your function, because this actually draws
the cursor if no cursor encoding is active.

@ -24,6 +24,8 @@
#include "rfb.h"
static unsigned char rfbReverseByte[0x100];
/*
* Send cursor shape either in X-style format or in client pixel format.
*/
@ -73,8 +75,8 @@ rfbSendCursorShape(cl)
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->rfbCursorBytesSent += sz_rfbFramebufferUpdateRectHeader;
cl->rfbCursorUpdatesSent++;
cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader;
cl->rfbCursorShapeUpdatesSent++;
if (!rfbSendUpdateBuf(cl))
return FALSE;
@ -163,8 +165,8 @@ rfbSendCursorShape(cl)
/* Send everything we have prepared in the cl->updateBuf[]. */
cl->rfbCursorBytesSent += (cl->ublen - saved_ublen);
cl->rfbCursorUpdatesSent++;
cl->rfbCursorShapeBytesSent += (cl->ublen - saved_ublen);
cl->rfbCursorShapeUpdatesSent++;
if (!rfbSendUpdateBuf(cl))
return FALSE;
@ -172,8 +174,41 @@ rfbSendCursorShape(cl)
return TRUE;
}
/*
* 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;
}
/* conversion routine for predefined cursors in LSB order */
unsigned char rfbReverseByte[0x100] = {
static unsigned char rfbReverseByte[0x100] = {
/* copied from Xvnc/lib/font/util/utilbitmap.c */
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
@ -452,7 +487,7 @@ void rfbPrintXCursor(rfbCursorPtr cursor)
}
}
extern void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c,Bool freeOld)
void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c,Bool freeOld)
{
LOCK(rfbScreen->cursorMutex);
while(rfbScreen->cursorIsDrawn) {

@ -364,16 +364,32 @@ defaultKbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl)
void
defaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
{
if(x!=cl->screen->cursorX || y!=cl->screen->cursorY) {
if(cl->screen->cursorIsDrawn)
rfbUndrawCursor(cl->screen);
LOCK(cl->screen->cursorMutex);
if(!cl->screen->cursorIsDrawn) {
cl->screen->cursorX = x;
cl->screen->cursorY = y;
rfbClientIteratorPtr iterator;
rfbClientPtr other_client;
if (x != cl->screen->cursorX || y != cl->screen->cursorY) {
if (cl->screen->cursorIsDrawn)
rfbUndrawCursor(cl->screen);
LOCK(cl->screen->cursorMutex);
if (!cl->screen->cursorIsDrawn) {
cl->screen->cursorX = x;
cl->screen->cursorY = y;
}
UNLOCK(cl->screen->cursorMutex);
/* The cursor was moved by this client, so don't send CursorPos. */
if (cl->enableCursorPosUpdates)
cl->cursorWasMoved = FALSE;
/* But inform all remaining clients about this cursor movement. */
iterator = rfbGetClientIterator(cl->screen);
while ((other_client = rfbClientIteratorNext(iterator)) != NULL) {
if (other_client != cl && other_client->enableCursorPosUpdates) {
other_client->cursorWasMoved = TRUE;
}
UNLOCK(cl->screen->cursorMutex);
}
}
rfbReleaseClientIterator(iterator);
}
}
void defaultSetXCutText(char* text, int len, rfbClientPtr cl)

11
rfb.h

@ -483,8 +483,10 @@ typedef struct _rfbClientRec {
int rfbRectanglesSent[MAX_ENCODINGS];
int rfbLastRectMarkersSent;
int rfbLastRectBytesSent;
int rfbCursorBytesSent;
int rfbCursorUpdatesSent;
int rfbCursorShapeBytesSent;
int rfbCursorShapeUpdatesSent;
int rfbCursorPosBytesSent;
int rfbCursorPosUpdatesSent;
int rfbFramebufferUpdateMessagesSent;
int rfbRawBytesEquivalent;
int rfbKeyEventsRcvd;
@ -506,8 +508,10 @@ typedef struct _rfbClientRec {
Bool enableLastRectEncoding; /* client supports LastRect encoding */
Bool enableCursorShapeUpdates; /* client supports cursor shape updates */
Bool enableCursorPosUpdates; /* client supports cursor position updates */
Bool useRichCursorEncoding; /* rfbEncodingRichCursor is preferred */
Bool cursorWasChanged; /* cursor shape update should be sent */
Bool cursorWasMoved; /* cursor position update should be sent */
Bool useNewFBSize; /* client supports NewFBSize encoding */
Bool newFBSizePending; /* framebuffer size was changed */
@ -545,6 +549,7 @@ typedef struct _rfbClientRec {
((!(cl)->enableCursorShapeUpdates && !(cl)->screen->cursorIsDrawn) || \
((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) || \
((cl)->useNewFBSize && (cl)->newFBSizePending) || \
((cl)->enableCursorPosUpdates && (cl)->cursorWasMoved) || \
!sraRgnEmpty((cl)->copyRegion) || !sraRgnEmpty((cl)->modifiedRegion))
/*
@ -705,7 +710,7 @@ typedef struct rfbCursor {
} rfbCursor, *rfbCursorPtr;
extern Bool rfbSendCursorShape(rfbClientPtr cl/*, rfbScreenInfoPtr pScreen*/);
extern unsigned char rfbReverseByte[0x100];
extern Bool rfbSendCursorPos(rfbClientPtr cl);
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);

@ -2,7 +2,7 @@
#define RFBPROTO_H
/*
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
* Copyright (C) 2000-2002 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
*
@ -327,6 +327,7 @@ typedef struct {
#define rfbEncodingXCursor 0xFFFFFF10
#define rfbEncodingRichCursor 0xFFFFFF11
#define rfbEncodingPointerPos 0xFFFFFF18
#define rfbEncodingLastRect 0xFFFFFF20
#define rfbEncodingNewFBSize 0xFFFFFF21
@ -502,7 +503,128 @@ typedef struct {
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Tight Encoding. FIXME: Add more documentation.
* Tight Encoding.
*
*-- The first byte of each Tight-encoded rectangle is a "compression control
* byte". Its format is as follows (bit 0 is the least significant one):
*
* bit 0: if 1, then compression stream 0 should be reset;
* bit 1: if 1, then compression stream 1 should be reset;
* bit 2: if 1, then compression stream 2 should be reset;
* bit 3: if 1, then compression stream 3 should be reset;
* bits 7-4: if 1000 (0x08), then the compression type is "fill",
* if 1001 (0x09), then the compression type is "jpeg",
* if 0xxx, then the compression type is "basic",
* values greater than 1001 are not valid.
*
* If the compression type is "basic", then bits 6..4 of the
* compression control byte (those xxx in 0xxx) specify the following:
*
* bits 5-4: decimal representation is the index of a particular zlib
* stream which should be used for decompressing the data;
* bit 6: if 1, then a "filter id" byte is following this byte.
*
*-- The data that follows after the compression control byte described
* above depends on the compression type ("fill", "jpeg" or "basic").
*
*-- If the compression type is "fill", then the only pixel value follows, in
* client pixel format (see NOTE 1). This value applies to all pixels of the
* rectangle.
*
*-- If the compression type is "jpeg", the following data stream looks like
* this:
*
* 1..3 bytes: data size (N) in compact representation;
* N bytes: JPEG image.
*
* Data size is compactly represented in one, two or three bytes, according
* to the following scheme:
*
* 0xxxxxxx (for values 0..127)
* 1xxxxxxx 0yyyyyyy (for values 128..16383)
* 1xxxxxxx 1yyyyyyy zzzzzzzz (for values 16384..4194303)
*
* Here each character denotes one bit, xxxxxxx are the least significant 7
* bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the
* most significant 8 bits (bits 14-21). For example, decimal value 10000
* should be represented as two bytes: binary 10010000 01001110, or
* hexadecimal 90 4E.
*
*-- If the compression type is "basic" and bit 6 of the compression control
* byte was set to 1, then the next (second) byte specifies "filter id" which
* tells the decoder what filter type was used by the encoder to pre-process
* pixel data before the compression. The "filter id" byte can be one of the
* following:
*
* 0: no filter ("copy" filter);
* 1: "palette" filter;
* 2: "gradient" filter.
*
*-- If bit 6 of the compression control byte is set to 0 (no "filter id"
* byte), or if the filter id is 0, then raw pixel values in the client
* format (see NOTE 1) will be compressed. See below details on the
* compression.
*
*-- The "gradient" filter pre-processes pixel data with a simple algorithm
* which converts each color component to a difference between a "predicted"
* intensity and the actual intensity. Such a technique does not affect
* uncompressed data size, but helps to compress photo-like images better.
* Pseudo-code for converting intensities to differences is the following:
*
* P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
* if (P[i,j] < 0) then P[i,j] := 0;
* if (P[i,j] > MAX) then P[i,j] := MAX;
* D[i,j] := V[i,j] - P[i,j];
*
* Here V[i,j] is the intensity of a color component for a pixel at
* coordinates (i,j). MAX is the maximum value of intensity for a color
* component.
*
*-- The "palette" filter converts true-color pixel data to indexed colors
* and a palette which can consist of 2..256 colors. If the number of colors
* is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to
* encode one pixel. 1-bit encoding is performed such way that the most
* significant bits correspond to the leftmost pixels, and each raw of pixels
* is aligned to the byte boundary. When "palette" filter is used, the
* palette is sent before the pixel data. The palette begins with an unsigned
* byte which value is the number of colors in the palette minus 1 (i.e. 1
* means 2 colors, 255 means 256 colors in the palette). Then follows the
* palette itself which consist of pixel values in client pixel format (see
* NOTE 1).
*
*-- The pixel data is compressed using the zlib library. But if the data
* size after applying the filter but before the compression is less then 12,
* then the data is sent as is, uncompressed. Four separate zlib streams
* (0..3) can be used and the decoder should read the actual stream id from
* the compression control byte (see NOTE 2).
*
* If the compression is not used, then the pixel data is sent as is,
* otherwise the data stream looks like this:
*
* 1..3 bytes: data size (N) in compact representation;
* N bytes: zlib-compressed data.
*
* Data size is compactly represented in one, two or three bytes, just like
* in the "jpeg" compression method (see above).
*
*-- NOTE 1. If the color depth is 24, and all three color components are
* 8-bit wide, then one pixel in Tight encoding is always represented by
* three bytes, where the first byte is red component, the second byte is
* green component, and the third byte is blue component of the pixel color
* value. This applies to colors in palettes as well.
*
*-- NOTE 2. The decoder must reset compression streams' states before
* decoding the rectangle, if some of bits 0,1,2,3 in the compression control
* byte are set to 1. Note that the decoder must reset zlib streams even if
* the compression type is "fill" or "jpeg".
*
*-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
* when bits-per-pixel value is either 16 or 32, not 8.
*
*-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048
* pixels. If a rectangle is wider, it must be split into several rectangles
* and each one should be encoded separately.
*
*/
#define rfbTightExplicitFilter 0x04

@ -293,6 +293,7 @@ rfbNewTCPOrUDPClient(rfbScreen,sock,isUDP)
cl->zsActive[i] = FALSE;
cl->enableCursorShapeUpdates = FALSE;
cl->enableCursorPosUpdates = FALSE;
cl->useRichCursorEncoding = FALSE;
cl->enableLastRectEncoding = FALSE;
cl->useNewFBSize = FALSE;
@ -696,6 +697,7 @@ rfbProcessClientNormalMessage(cl)
cl->preferredEncoding = -1;
cl->useCopyRect = FALSE;
cl->enableCursorShapeUpdates = FALSE;
cl->enableCursorPosUpdates = FALSE;
cl->enableLastRectEncoding = FALSE;
cl->useNewFBSize = FALSE;
@ -764,12 +766,20 @@ rfbProcessClientNormalMessage(cl)
}
break;
case rfbEncodingRichCursor:
rfbLog("Enabling full-color cursor updates for client "
"%s\n", cl->host);
rfbLog("Enabling full-color cursor updates for client %s\n",
cl->host);
cl->enableCursorShapeUpdates = TRUE;
cl->useRichCursorEncoding = TRUE;
cl->cursorWasChanged = TRUE;
break;
case rfbEncodingPointerPos:
if (!cl->enableCursorPosUpdates) {
rfbLog("Enabling cursor position updates for client %s\n",
cl->host);
cl->enableCursorPosUpdates = TRUE;
cl->cursorWasMoved = TRUE;
}
break;
case rfbEncodingLastRect:
if (!cl->enableLastRectEncoding) {
rfbLog("Enabling LastRect protocol extension for client "
@ -824,6 +834,12 @@ rfbProcessClientNormalMessage(cl)
cl->preferredEncoding = rfbEncodingRaw;
}
if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
rfbLog("Disabling cursor position updates for client %s\n",
cl->host);
cl->enableCursorPosUpdates = FALSE;
}
return;
}
@ -972,6 +988,7 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
sraRegionPtr updateRegion,updateCopyRegion,tmpRegion;
int dx, dy;
Bool sendCursorShape = FALSE;
Bool sendCursorPos = FALSE;
if(cl->screen->displayHook)
cl->screen->displayHook(cl);
@ -1013,6 +1030,13 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
}
}
/*
* Do we plan to send cursor position update?
*/
if (cl->enableCursorPosUpdates && cl->cursorWasMoved)
sendCursorPos = TRUE;
LOCK(cl->updateMutex);
/*
@ -1032,7 +1056,8 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
updateRegion = sraRgnCreateRgn(givenUpdateRegion);
sraRgnOr(updateRegion,cl->copyRegion);
if(!sraRgnAnd(updateRegion,cl->requestedRegion) && !sendCursorShape) {
if(!sraRgnAnd(updateRegion,cl->requestedRegion) &&
!sendCursorShape && !sendCursorPos) {
sraRgnDestroy(updateRegion);
UNLOCK(cl->updateMutex);
return TRUE;
@ -1131,8 +1156,9 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
fu->type = rfbFramebufferUpdate;
if (nUpdateRegionRects != 0xFFFF) {
fu->nRects = Swap16IfLE((CARD16)(sraRgnCountRects(updateCopyRegion)
+ nUpdateRegionRects + !!sendCursorShape));
fu->nRects = Swap16IfLE((CARD16)(sraRgnCountRects(updateCopyRegion) +
nUpdateRegionRects +
!!sendCursorShape + !!sendCursorPos));
} else {
fu->nRects = 0xFFFF;
}
@ -1146,6 +1172,14 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
}
}
if (sendCursorPos) {
cl->cursorWasMoved = FALSE;
if (!rfbSendCursorPos(cl)) {
sraRgnDestroy(updateRegion);
return FALSE;
}
}
if (!sraRgnEmpty(updateCopyRegion)) {
if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy)) {
sraRgnDestroy(updateRegion);

@ -51,8 +51,10 @@ rfbResetStats(rfbClientPtr cl)
}
cl->rfbLastRectMarkersSent = 0;
cl->rfbLastRectBytesSent = 0;
cl->rfbCursorBytesSent = 0;
cl->rfbCursorUpdatesSent = 0;
cl->rfbCursorShapeBytesSent = 0;
cl->rfbCursorShapeUpdatesSent = 0;
cl->rfbCursorPosBytesSent = 0;
cl->rfbCursorPosUpdatesSent = 0;
cl->rfbFramebufferUpdateMessagesSent = 0;
cl->rfbRawBytesEquivalent = 0;
cl->rfbKeyEventsRcvd = 0;
@ -77,9 +79,12 @@ rfbPrintStats(rfbClientPtr cl)
totalBytesSent += cl->rfbBytesSent[i];
}
totalRectanglesSent += (cl->rfbCursorUpdatesSent +
totalRectanglesSent += (cl->rfbCursorShapeUpdatesSent +
cl->rfbCursorPosUpdatesSent +
cl->rfbLastRectMarkersSent);
totalBytesSent += (cl->rfbCursorBytesSent + cl->rfbLastRectBytesSent);
totalBytesSent += (cl->rfbCursorShapeBytesSent +
cl->rfbCursorPosBytesSent +
cl->rfbLastRectBytesSent);
rfbLog(" framebuffer updates %d, rectangles %d, bytes %d\n",
cl->rfbFramebufferUpdateMessagesSent, totalRectanglesSent,
@ -89,9 +94,13 @@ rfbPrintStats(rfbClientPtr cl)
rfbLog(" LastRect and NewFBSize markers %d, bytes %d\n",
cl->rfbLastRectMarkersSent, cl->rfbLastRectBytesSent);
if (cl->rfbCursorUpdatesSent != 0)
if (cl->rfbCursorShapeUpdatesSent != 0)
rfbLog(" cursor shape updates %d, bytes %d\n",
cl->rfbCursorUpdatesSent, cl->rfbCursorBytesSent);
cl->rfbCursorShapeUpdatesSent, cl->rfbCursorShapeBytesSent);
if (cl->rfbCursorPosUpdatesSent != 0)
rfbLog(" cursor position updates %d, bytes %d\n",
cl->rfbCursorPosUpdatesSent, cl->rfbCursorPosBytesSent);
for (i = 0; i < MAX_ENCODINGS; i++) {
if (cl->rfbRectanglesSent[i] != 0)
@ -105,7 +114,8 @@ rfbPrintStats(rfbClientPtr cl)
(double)cl->rfbRawBytesEquivalent
/ (double)(totalBytesSent
- cl->rfbBytesSent[rfbEncodingCopyRect]-
cl->rfbCursorBytesSent -
cl->rfbCursorShapeBytesSent -
cl->rfbCursorPosBytesSent -
cl->rfbLastRectBytesSent));
}
}

Loading…
Cancel
Save