Commit 7e6d5c65 authored by dscho's avatar dscho

NewFB encoding added

parent 131ede28
support for NewFB from Const Kaplinsky
memory leaks squashed (localtime pseudo leak is still there :-)
small improvements for OSXvnc (still not working correctly)
synced with TightVNC 1.2.3
......
No preview for this file type
......@@ -8,9 +8,10 @@
<TITLE>
$USER's $DESKTOP desktop ($DISPLAY)
</TITLE>
<APPLET CODE=vncviewer.class ARCHIVE=VncViewer.jar
<APPLET CODE=VncViewer.class ARCHIVE=VncViewer.jar
WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT>
<param name=PORT value=$PORT>
<param name="Open New Window" value=yes>
</APPLET>
<BR>
<A href="http://www.tightvnc.com/">www.TightVNC.com</A>
......
......@@ -34,7 +34,8 @@
#include "rfb.h"
#include "keysym.h"
const int maxx=640, maxy=480, bpp=4;
const int bpp=4;
int maxx=800, maxy=600;
/* TODO: odd maxx doesn't work (vncviewer bug) */
/* This initializes a nice (?) background */
......@@ -74,6 +75,23 @@ enum rfbNewClientAction newclient(rfbClientPtr cl)
return RFB_CLIENT_ACCEPT;
}
/* switch to new framebuffer contents */
void newframebuffer(rfbScreenInfoPtr screen, int width, int height)
{
char *oldfb, *newfb;
maxx = width;
maxy = height;
oldfb = screen->frameBuffer;
newfb = (char*)malloc(maxx * maxy * bpp);
initBuffer(newfb);
rfbNewFramebuffer(screen, newfb, maxx, maxy, 8, 3, bpp);
free(oldfb);
/*** FIXME: Re-install cursor. ***/
}
/* aux function to draw a line */
void drawline(unsigned char* buffer,int rowstride,int bpp,int x1,int y1,int x2,int y2)
......@@ -158,6 +176,22 @@ void dokey(Bool down,KeySym key,rfbClientPtr cl)
rfbUndrawCursor(cl->screen);
initBuffer(cl->screen->frameBuffer);
rfbMarkRectAsModified(cl->screen,0,0,maxx,maxy);
} else if (key == XK_Up) {
if (maxx < 1024) {
if (maxx < 800) {
newframebuffer(cl->screen, 800, 600);
} else {
newframebuffer(cl->screen, 1024, 768);
}
}
} else if(key==XK_Down) {
if (maxx > 640) {
if (maxx > 800) {
newframebuffer(cl->screen, 800, 600);
} else {
newframebuffer(cl->screen, 640, 480);
}
}
} else if(key>=' ' && key<0x100) {
ClientData* cd=cl->clientData;
int x1=cd->oldx,y1=cd->oldy,x2,y2;
......@@ -266,7 +300,7 @@ int main(int argc,char** argv)
#ifdef USE_OWN_LOOP
{
int i;
for(i=0;i<200;i++) {
for(i=0;;i++) {
fprintf(stderr,"%d\r",i);
rfbProcessEvents(rfbScreen,100000);
}
......@@ -275,7 +309,7 @@ int main(int argc,char** argv)
#ifndef BACKGROUND_LOOP_TEST
/* this is the blocking event loop, i.e. it never returns */
/* 40000 are the microseconds, i.e. 0.04 seconds */
/* 40000 are the microseconds to wait on select(), i.e. 0.04 seconds */
rfbRunEventLoop(rfbScreen,40000,FALSE);
#elif !defined(HAVE_PTHREADS)
#error "I need pthreads for that."
......@@ -283,7 +317,7 @@ int main(int argc,char** argv)
/* this is the non-blocking event loop; a background thread is started */
rfbRunEventLoop(rfbScreen,-1,TRUE);
/* now we could do some cool things like rendering */
/* now we could do some cool things like rendering in idle time */
while(1) sleep(5); /* render(); */
#endif
......
......@@ -218,6 +218,8 @@ httpProcessInput(rfbScreenInfoPtr rfbScreen)
fname = &fullFname[strlen(fullFname)];
maxFnameLen = 255 - strlen(fullFname);
buf_filled=0;
/* Read data from the HTTP client until we get a complete request. */
while (1) {
ssize_t got = read (rfbScreen->httpSock, buf + buf_filled,
......
......@@ -468,12 +468,57 @@ enum rfbNewClientAction defaultNewClientHook(rfbClientPtr cl)
return RFB_CLIENT_ACCEPT;
}
/*
* Update server's pixel format in rfbScreenInfo structure. This
* function is called from rfbGetScreen() and rfbNewFramebuffer().
*/
static void rfbInitServerFormat(rfbScreenInfoPtr rfbScreen, int bitsPerSample)
{
rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
format->bitsPerPixel = rfbScreen->bitsPerPixel;
format->depth = rfbScreen->depth;
format->bigEndian = rfbEndianTest?FALSE:TRUE;
format->trueColour = TRUE;
rfbScreen->colourMap.count = 0;
rfbScreen->colourMap.is16 = 0;
rfbScreen->colourMap.data.bytes = NULL;
if (format->bitsPerPixel == 8) {
format->redMax = 7;
format->greenMax = 7;
format->blueMax = 3;
format->redShift = 0;
format->greenShift = 3;
format->blueShift = 6;
} else {
format->redMax = (1 << bitsPerSample) - 1;
format->greenMax = (1 << bitsPerSample) - 1;
format->blueMax = (1 << bitsPerSample) - 1;
if(rfbEndianTest) {
format->redShift = 0;
format->greenShift = bitsPerSample;
format->blueShift = bitsPerSample * 2;
} else {
if(format->bitsPerPixel==8*3) {
format->redShift = bitsPerSample*2;
format->greenShift = bitsPerSample*1;
format->blueShift = 0;
} else {
format->redShift = bitsPerSample*3;
format->greenShift = bitsPerSample*2;
format->blueShift = bitsPerSample;
}
}
}
}
rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
int width,int height,int bitsPerSample,int samplesPerPixel,
int bytesPerPixel)
{
rfbScreenInfoPtr rfbScreen=malloc(sizeof(rfbScreenInfo));
rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
INIT_MUTEX(logMutex);
......@@ -530,41 +575,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
/* format */
format->bitsPerPixel = rfbScreen->bitsPerPixel;
format->depth = rfbScreen->depth;
format->bigEndian = rfbEndianTest?FALSE:TRUE;
format->trueColour = TRUE;
rfbScreen->colourMap.count = 0;
rfbScreen->colourMap.is16 = 0;
rfbScreen->colourMap.data.bytes = NULL;
if(bytesPerPixel == 1) {
format->redMax = 7;
format->greenMax = 7;
format->blueMax = 3;
format->redShift = 0;
format->greenShift = 3;
format->blueShift = 6;
} else {
format->redMax = (1 << bitsPerSample) - 1;
format->greenMax = (1 << bitsPerSample) - 1;
format->blueMax = (1 << bitsPerSample) - 1;
if(rfbEndianTest) {
format->redShift = 0;
format->greenShift = bitsPerSample;
format->blueShift = bitsPerSample * 2;
} else {
if(bytesPerPixel==3) {
format->redShift = bitsPerSample*2;
format->greenShift = bitsPerSample*1;
format->blueShift = 0;
} else {
format->redShift = bitsPerSample*3;
format->greenShift = bitsPerSample*2;
format->blueShift = bitsPerSample;
}
}
}
rfbInitServerFormat(rfbScreen, bitsPerSample);
/* cursor */
......@@ -597,6 +608,84 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
return(rfbScreen);
}
/*
* Switch to another framebuffer (maybe of different size and color
* format). Clients supporting NewFBSize pseudo-encoding will change
* their local framebuffer dimensions if necessary.
* NOTE: Rich cursor data should be converted to new pixel format by
* the caller.
*/
void rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen, char *framebuffer,
int width, int height,
int bitsPerSample, int samplesPerPixel,
int bytesPerPixel)
{
rfbPixelFormat old_format;
Bool format_changed = FALSE;
rfbClientIteratorPtr iterator;
rfbClientPtr cl;
/* Remove the pointer */
rfbUndrawCursor(rfbScreen);
/* Update information in the rfbScreenInfo structure */
old_format = rfbScreen->rfbServerFormat;
if (width & 3)
rfbLog("WARNING: New width (%d) is not a multiple of 4.\n", width);
rfbScreen->width = width;
rfbScreen->height = height;
rfbScreen->bitsPerPixel = rfbScreen->depth = 8*bytesPerPixel;
rfbScreen->paddedWidthInBytes = width*bytesPerPixel;
rfbInitServerFormat(rfbScreen, bitsPerSample);
if (memcmp(&rfbScreen->rfbServerFormat, &old_format,
sizeof(rfbPixelFormat)) != 0) {
format_changed = TRUE;
}
rfbScreen->frameBuffer = framebuffer;
/* Adjust pointer position if necessary */
if (rfbScreen->cursorX >= width)
rfbScreen->cursorX = width - 1;
if (rfbScreen->cursorY >= height)
rfbScreen->cursorY = height - 1;
/* For each client: */
iterator = rfbGetClientIterator(rfbScreen);
while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
/* Re-install color translation tables if necessary */
if (format_changed)
rfbScreen->setTranslateFunction(cl);
/* Mark the screen contents as changed, and schedule sending
NewFBSize message if supported by this client. */
LOCK(cl->updateMutex);
sraRgnDestroy(cl->modifiedRegion);
cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height);
sraRgnMakeEmpty(cl->copyRegion);
cl->copyDX = 0;
cl->copyDY = 0;
if (cl->useNewFBSize)
cl->newFBSizePending = TRUE;
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex);
}
rfbReleaseClientIterator(iterator);
}
void rfbScreenCleanup(rfbScreenInfoPtr rfbScreen)
{
rfbClientIteratorPtr i=rfbGetClientIterator(rfbScreen);
......
......@@ -503,8 +503,12 @@ typedef struct _rfbClientRec {
Bool enableCursorShapeUpdates; /* client supports cursor shape updates */
Bool useRichCursorEncoding; /* rfbEncodingRichCursor is preferred */
Bool cursorWasChanged; /* cursor shape update should be sent */
Bool useNewFBSize; /* client supports NewFBSize encoding */
Bool newFBSizePending; /* framebuffer size was changed */
#ifdef BACKCHANNEL
Bool enableBackChannel;
Bool enableBackChannel; /* custom channel for special clients */
#endif
struct _rfbClientRec *prev;
......@@ -532,9 +536,10 @@ typedef struct _rfbClientRec {
* be sent to the client.
*/
#define FB_UPDATE_PENDING(cl) \
((!(cl)->enableCursorShapeUpdates && !(cl)->screen->cursorIsDrawn) || \
((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) || \
#define FB_UPDATE_PENDING(cl) \
((!(cl)->enableCursorShapeUpdates && !(cl)->screen->cursorIsDrawn) || \
((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) || \
((cl)->useNewFBSize && (cl)->newFBSizePending) || \
!sraRgnEmpty((cl)->copyRegion) || !sraRgnEmpty((cl)->modifiedRegion))
/*
......@@ -603,6 +608,7 @@ extern Bool rfbSendUpdateBuf(rfbClientPtr cl);
extern void rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len);
extern Bool rfbSendCopyRegion(rfbClientPtr cl,sraRegionPtr reg,int dx,int dy);
extern Bool rfbSendLastRectMarker(rfbClientPtr cl);
extern Bool rfbSendNewFBSize(rfbClientPtr cl, int w, int h);
extern Bool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour, int nColours);
extern void rfbSendBell(rfbScreenInfoPtr rfbScreen);
......@@ -796,6 +802,10 @@ extern rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
int width,int height,int bitsPerSample,int samplesPerPixel,
int bytesPerPixel);
extern void rfbInitServer(rfbScreenInfoPtr rfbScreen);
extern void rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen,char *framebuffer,
int width,int height, int bitsPerSample,int samplesPerPixel,
int bytesPerPixel);
extern void rfbScreenCleanup(rfbScreenInfoPtr screenInfo);
/* functions to accept/refuse a client that has been put on hold
......
......@@ -328,6 +328,7 @@ typedef struct {
#define rfbEncodingRichCursor 0xFFFFFF11
#define rfbEncodingLastRect 0xFFFFFF20
#define rfbEncodingNewFBSize 0xFFFFFF21
#define rfbEncodingQualityLevel0 0xFFFFFFE0
#define rfbEncodingQualityLevel1 0xFFFFFFE1
......
......@@ -266,6 +266,7 @@ rfbNewTCPOrUDPClient(rfbScreen,sock,isUDP)
cl->enableCursorShapeUpdates = FALSE;
cl->useRichCursorEncoding = FALSE;
cl->enableLastRectEncoding = FALSE;
cl->useNewFBSize = FALSE;
cl->compStreamInited = FALSE;
cl->compStream.total_in = 0;
......@@ -663,6 +664,7 @@ rfbProcessClientNormalMessage(cl)
cl->useCopyRect = FALSE;
cl->enableCursorShapeUpdates = FALSE;
cl->enableLastRectEncoding = FALSE;
cl->useNewFBSize = FALSE;
for (i = 0; i < msg.se.nEncodings; i++) {
if ((n = ReadExact(cl, (char *)&enc, 4)) <= 0) {
......@@ -742,6 +744,13 @@ rfbProcessClientNormalMessage(cl)
cl->enableLastRectEncoding = TRUE;
}
break;
case rfbEncodingNewFBSize:
if (!cl->useNewFBSize) {
rfbLog("Enabling NewFBSize protocol extension for client "
"%s\n", cl->host);
cl->useNewFBSize = TRUE;
}
break;
#ifdef BACKCHANNEL
case rfbEncodingBackChannel:
if (!cl->enableBackChannel) {
......@@ -924,6 +933,25 @@ rfbSendFramebufferUpdate(cl, givenUpdateRegion)
if(cl->screen->displayHook)
cl->screen->displayHook(cl);
/*
* If framebuffer size was changed and the client supports NewFBSize
* encoding, just send NewFBSize marker and return.
*/
if (cl->useNewFBSize && cl->newFBSizePending) {
LOCK(cl->updateMutex);
cl->newFBSizePending = FALSE;
UNLOCK(cl->updateMutex);
cl->rfbFramebufferUpdateMessagesSent++;
fu->type = rfbFramebufferUpdate;
fu->nRects = Swap16IfLE(1);
cl->ublen = sz_rfbFramebufferUpdateMsg;
if (!rfbSendNewFBSize(cl, cl->screen->width, cl->screen->height)) {
return FALSE;
}
return rfbSendUpdateBuf(cl);
}
/*
* If this client understands cursor shape updates, cursor should be
......@@ -1309,6 +1337,40 @@ rfbSendLastRectMarker(cl)
}
/*
* Send NewFBSize pseudo-rectangle. This tells the client to change
* its framebuffer size.
*/
Bool
rfbSendNewFBSize(cl, w, h)
rfbClientPtr cl;
int w, h;
{
rfbFramebufferUpdateRectHeader rect;
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
if (!rfbSendUpdateBuf(cl))
return FALSE;
}
rect.encoding = Swap32IfLE(rfbEncodingNewFBSize);
rect.r.x = 0;
rect.r.y = 0;
rect.r.w = Swap16IfLE(w);
rect.r.h = Swap16IfLE(h);
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->rfbLastRectMarkersSent++;
cl->rfbLastRectBytesSent += sz_rfbFramebufferUpdateRectHeader;
return TRUE;
}
/*
* Send the contents of cl->updateBuf. Returns 1 if successful, -1 if
* not (errno should be set).
......
......@@ -78,7 +78,7 @@ rfbPrintStats(rfbClientPtr cl)
totalBytesSent);
if (cl->rfbLastRectMarkersSent != 0)
rfbLog(" LastRect markers %d, bytes %d\n",
rfbLog(" LastRect and NewFBSize markers %d, bytes %d\n",
cl->rfbLastRectMarkersSent, cl->rfbLastRectBytesSent);
if (cl->rfbCursorUpdatesSent != 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment