Commit 194a76df authored by dscho's avatar dscho

add an extension mechanism for LibVNCClient, modify the client data handling

so that more than one data structure can be attached, and add an example
to speak the client part of the back channel.
parent 11fc700c
...@@ -23,7 +23,7 @@ SDLvncviewer_CFLAGS=$(SDL_CFLAGS) ...@@ -23,7 +23,7 @@ SDLvncviewer_CFLAGS=$(SDL_CFLAGS)
SDLvncviewer_LDADD=$(LDADD) $(SDL_LIBS) SDLvncviewer_LDADD=$(LDADD) $(SDL_LIBS)
endif endif
noinst_PROGRAMS=ppmtest $(SDLVIEWER) $(FFMPEG_CLIENT) noinst_PROGRAMS=ppmtest $(SDLVIEWER) $(FFMPEG_CLIENT) backchannel
...@@ -16,7 +16,7 @@ static rfbBool resize(rfbClient* client) { ...@@ -16,7 +16,7 @@ static rfbBool resize(rfbClient* client) {
okay=SDL_VideoModeOK(width,height,depth,flags); okay=SDL_VideoModeOK(width,height,depth,flags);
if(okay) { if(okay) {
SDL_Surface* sdl=SDL_SetVideoMode(width,height,depth,flags); SDL_Surface* sdl=SDL_SetVideoMode(width,height,depth,flags);
client->clientData=sdl; rfbClientSetClientData(client, SDL_Init, sdl);
client->frameBuffer=sdl->pixels; client->frameBuffer=sdl->pixels;
if(first || depth!=client->format.bitsPerPixel) { if(first || depth!=client->format.bitsPerPixel) {
first=FALSE; first=FALSE;
...@@ -30,7 +30,7 @@ static rfbBool resize(rfbClient* client) { ...@@ -30,7 +30,7 @@ static rfbBool resize(rfbClient* client) {
SetFormatAndEncodings(client); SetFormatAndEncodings(client);
} }
} else { } else {
SDL_Surface* sdl=client->clientData; SDL_Surface* sdl=rfbClientGetClientData(client, SDL_Init);
rfbClientLog("Could not set resolution %dx%d!\n", rfbClientLog("Could not set resolution %dx%d!\n",
client->width,client->height); client->width,client->height);
if(sdl) { if(sdl) {
...@@ -188,7 +188,7 @@ static rfbKeySym SDL_keysym2rfbKeySym(int keysym) { ...@@ -188,7 +188,7 @@ static rfbKeySym SDL_keysym2rfbKeySym(int keysym) {
} }
static void update(rfbClient* cl,int x,int y,int w,int h) { static void update(rfbClient* cl,int x,int y,int w,int h) {
SDL_UpdateRect(cl->clientData, x, y, w, h); SDL_UpdateRect(rfbClientGetClientData(cl, SDL_Init), x, y, w, h);
} }
#ifdef __MINGW32__ #ifdef __MINGW32__
......
/* A simple example of an RFB client */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <rfb/rfbclient.h>
static void HandleRect(rfbClient* client, int x, int y, int w, int h) {
}
/*
* The client part of the back channel extension example.
*
*/
#define rfbBackChannel 155
typedef struct backChannelMsg {
uint8_t type;
uint8_t pad1;
uint16_t pad2;
uint32_t size;
} backChannelMsg;
static void sendMessage(rfbClient* client, char* text)
{
backChannelMsg msg;
uint32_t length = strlen(text)+1;
msg.type = rfbBackChannel;
msg.size = rfbClientSwap32IfLE(length);
if(!WriteToRFBServer(client, (char*)&msg, sizeof(msg)) ||
!WriteToRFBServer(client, text, length)) {
rfbClientLog("enableBackChannel: write error (%d: %s)", errno, strerror(errno));
}
}
static rfbBool handleBackChannelMessage(rfbClient* client,
rfbServerToClientMsg* message)
{
backChannelMsg msg;
char* text;
if(message->type != rfbBackChannel)
return FALSE;
rfbClientSetClientData(client, sendMessage, sendMessage);
if(!ReadFromRFBServer(client, ((char*)&msg)+1, sizeof(msg)-1))
return TRUE;
msg.size = rfbClientSwap32IfLE(msg.size);
text = malloc(msg.size);
if(!ReadFromRFBServer(client, text, msg.size)) {
free(text);
return TRUE;
}
rfbClientLog("got back channel message: %s\n", text);
free(text);
return TRUE;
}
static int backChannelEncodings[] = { rfbBackChannel, 0 };
static rfbClientProtocolExtension backChannel = {
backChannelEncodings, /* encodings */
NULL, /* handleEncoding */
handleBackChannelMessage, /* handleMessage */
NULL /* next extension */
};
int
main(int argc, char **argv)
{
rfbClient* client = rfbGetClient(8,3,4);
client->GotFrameBufferUpdate = HandleRect;
rfbClientRegisterExtension(&backChannel);
if (!rfbInitClient(client,&argc,argv))
return 1;
while (1) {
/* After each idle second, send a message */
if(WaitForMessage(client,1000000)>0)
HandleRFBServerMessage(client);
else if(rfbClientGetClientData(client, sendMessage))
sendMessage(client, "Dear Server,\n"
"thank you for understanding "
"back channel messages!");
}
rfbClientCleanup(client);
return 0;
}
...@@ -77,6 +77,49 @@ rfbDefaultClientLog(const char *format, ...) ...@@ -77,6 +77,49 @@ rfbDefaultClientLog(const char *format, ...)
rfbClientLogProc rfbClientLog=rfbDefaultClientLog; rfbClientLogProc rfbClientLog=rfbDefaultClientLog;
rfbClientLogProc rfbClientErr=rfbDefaultClientLog; rfbClientLogProc rfbClientErr=rfbDefaultClientLog;
/* extensions */
rfbClientProtocolExtension* rfbClientExtensions = NULL;
void rfbClientRegisterExtension(rfbClientProtocolExtension* e)
{
e->next = rfbClientExtensions;
rfbClientExtensions = e;
}
/* client data */
void rfbClientSetClientData(rfbClient* client, void* tag, void* data)
{
rfbClientData* clientData = client->clientData;
while(clientData && clientData->tag != tag)
clientData = clientData->next;
if(clientData == NULL) {
clientData = calloc(sizeof(rfbClientData), 1);
clientData->next = client->clientData;
client->clientData = clientData;
clientData->tag = tag;
}
clientData->data = data;
}
void* rfbClientGetClientData(rfbClient* client, void* tag)
{
rfbClientData* clientData = client->clientData;
while(clientData) {
if(clientData->tag == tag)
return clientData->data;
clientData = clientData->next;
}
return NULL;
}
/* messages */
static void FillRectangle(rfbClient* client, int x, int y, int w, int h, uint32_t colour) { static void FillRectangle(rfbClient* client, int x, int y, int w, int h, uint32_t colour) {
int i,j; int i,j;
...@@ -259,6 +302,12 @@ InitialiseRFBConnection(rfbClient* client) ...@@ -259,6 +302,12 @@ InitialiseRFBConnection(rfbClient* client)
return FALSE; return FALSE;
} }
#if rfbProtocolMinorVersion == 7
/* work around LibVNCClient not yet speaking RFB 3.7 */
#undef rfbProtocolMinorVersion
#define rfbProtocolMinorVersion 3
#endif
rfbClientLog("VNC server supports protocol version %d.%d (viewer %d.%d)\n", rfbClientLog("VNC server supports protocol version %d.%d (viewer %d.%d)\n",
major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion); major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
...@@ -394,6 +443,7 @@ SetFormatAndEncodings(rfbClient* client) ...@@ -394,6 +443,7 @@ SetFormatAndEncodings(rfbClient* client)
rfbBool requestCompressLevel = FALSE; rfbBool requestCompressLevel = FALSE;
rfbBool requestQualityLevel = FALSE; rfbBool requestQualityLevel = FALSE;
rfbBool requestLastRectEncoding = FALSE; rfbBool requestLastRectEncoding = FALSE;
rfbClientProtocolExtension* e;
spf.type = rfbSetPixelFormat; spf.type = rfbSetPixelFormat;
spf.format = client->format; spf.format = client->format;
...@@ -535,6 +585,13 @@ SetFormatAndEncodings(rfbClient* client) ...@@ -535,6 +585,13 @@ SetFormatAndEncodings(rfbClient* client)
encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingLastRect); encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingLastRect);
} }
for(e = rfbClientExtensions; e; e = e->next)
if(e->encodings) {
int* enc;
for(enc = e->encodings; *enc; enc++)
encs[se->nEncodings++] = rfbClientSwap32IfLE(*enc);
}
len = sz_rfbSetEncodingsMsg + se->nEncodings * 4; len = sz_rfbSetEncodingsMsg + se->nEncodings * 4;
se->nEncodings = rfbClientSwap16IfLE(se->nEncodings); se->nEncodings = rfbClientSwap16IfLE(se->nEncodings);
...@@ -923,10 +980,21 @@ HandleRFBServerMessage(rfbClient* client) ...@@ -923,10 +980,21 @@ HandleRFBServerMessage(rfbClient* client)
#endif #endif
default: default:
{
rfbBool handled = FALSE;
rfbClientProtocolExtension* e;
for(e = rfbClientExtensions; !handled && e; e = e->next)
if(e->handleEncoding && e->handleEncoding(client, &rect))
handled = TRUE;
if(!handled) {
rfbClientLog("Unknown rect encoding %d\n", rfbClientLog("Unknown rect encoding %d\n",
(int)rect.encoding); (int)rect.encoding);
return FALSE; return FALSE;
} }
}
}
/* Now we may discard "soft cursor locks". */ /* Now we may discard "soft cursor locks". */
client->SoftCursorUnlockScreen(client); client->SoftCursorUnlockScreen(client);
...@@ -934,16 +1002,6 @@ HandleRFBServerMessage(rfbClient* client) ...@@ -934,16 +1002,6 @@ HandleRFBServerMessage(rfbClient* client)
client->GotFrameBufferUpdate(client, rect.r.x, rect.r.y, rect.r.w, rect.r.h); client->GotFrameBufferUpdate(client, rect.r.x, rect.r.y, rect.r.w, rect.r.h);
} }
#ifdef MITSHM
/* if using shared memory PutImage, make sure that the X server has
updated its framebuffer before we reuse the shared memory. This is
mainly to avoid copyrect using invalid screen contents - not sure
if we'd need it otherwise. */
if (client->appData.useShm)
XSync(dpy, FALSE);
#endif
if (!SendIncrementalFramebufferUpdateRequest(client)) if (!SendIncrementalFramebufferUpdateRequest(client))
return FALSE; return FALSE;
...@@ -981,9 +1039,22 @@ HandleRFBServerMessage(rfbClient* client) ...@@ -981,9 +1039,22 @@ HandleRFBServerMessage(rfbClient* client)
} }
default: default:
{
rfbBool handled = FALSE;
rfbClientProtocolExtension* e;
for(e = rfbClientExtensions; !handled && e; e = e->next)
if(e->handleMessage && e->handleMessage(client, &msg))
handled = TRUE;
if(!handled) {
char buffer[256];
ReadFromRFBServer(client, buffer, 256);
rfbClientLog("Unknown message type %d from VNC server\n",msg.type); rfbClientLog("Unknown message type %d from VNC server\n",msg.type);
return FALSE; return FALSE;
} }
}
}
return TRUE; return TRUE;
} }
......
...@@ -63,6 +63,15 @@ typedef struct { ...@@ -63,6 +63,15 @@ typedef struct {
rfbBool doNotSleep; rfbBool doNotSleep;
} rfbVNCRec; } rfbVNCRec;
/* client data */
typedef struct rfbClientData {
void* tag;
void* data;
struct rfbClientData* next;
} rfbClientData;
/* app data (belongs into rfbClient?) */
typedef struct { typedef struct {
rfbBool shareDesktop; rfbBool shareDesktop;
...@@ -181,7 +190,7 @@ typedef struct _rfbClient { ...@@ -181,7 +190,7 @@ typedef struct _rfbClient {
uint8_t *rcSource, *rcMask; uint8_t *rcSource, *rcMask;
/* private data pointer */ /* private data pointer */
void* clientData; rfbClientData* clientData;
rfbVNCRec* vncRec; rfbVNCRec* vncRec;
...@@ -223,6 +232,26 @@ extern rfbBool HandleRFBServerMessage(rfbClient* client); ...@@ -223,6 +232,26 @@ extern rfbBool HandleRFBServerMessage(rfbClient* client);
extern void PrintPixelFormat(rfbPixelFormat *format); extern void PrintPixelFormat(rfbPixelFormat *format);
/* client data */
void rfbClientSetClientData(rfbClient* client, void* tag, void* data);
void* rfbClientGetClientData(rfbClient* client, void* tag);
/* protocol extensions */
typedef struct _rfbClientProtocolExtension {
int* encodings;
/* returns TRUE if the encoding was handled */
rfbBool (*handleEncoding)(rfbClient* cl,
rfbFramebufferUpdateRectHeader* rect);
/* returns TRUE if it handled the message */
rfbBool (*handleMessage)(rfbClient* cl,
rfbServerToClientMsg* message);
struct _rfbClientProtocolExtension* next;
} rfbClientProtocolExtension;
void rfbClientRegisterExtension(rfbClientProtocolExtension* e);
/* sockets.c */ /* sockets.c */
extern rfbBool errorMessageOnReadFailure; extern rfbBool errorMessageOnReadFailure;
......
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