summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordscho <dscho>2005-10-06 19:26:41 +0000
committerdscho <dscho>2005-10-06 19:26:41 +0000
commit194a76df115db3b6fe62adbccfe4181ed46d2c52 (patch)
tree1b7e853cbd4c4482173d3b2f675580169dfd56d6
parent11fc700c5db6afc6978211f5735707848b94ae8e (diff)
downloadlibtdevnc-194a76df.tar.gz
libtdevnc-194a76df.zip
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.
-rw-r--r--client_examples/Makefile.am2
-rw-r--r--client_examples/SDLvncviewer.c6
-rw-r--r--client_examples/backchannel.c99
-rw-r--r--libvncclient/rfbproto.c101
-rw-r--r--rfb/rfbclient.h31
5 files changed, 219 insertions, 20 deletions
diff --git a/client_examples/Makefile.am b/client_examples/Makefile.am
index 6ffcf51..77998f0 100644
--- a/client_examples/Makefile.am
+++ b/client_examples/Makefile.am
@@ -23,7 +23,7 @@ SDLvncviewer_CFLAGS=$(SDL_CFLAGS)
SDLvncviewer_LDADD=$(LDADD) $(SDL_LIBS)
endif
-noinst_PROGRAMS=ppmtest $(SDLVIEWER) $(FFMPEG_CLIENT)
+noinst_PROGRAMS=ppmtest $(SDLVIEWER) $(FFMPEG_CLIENT) backchannel
diff --git a/client_examples/SDLvncviewer.c b/client_examples/SDLvncviewer.c
index 07d3869..8375ea6 100644
--- a/client_examples/SDLvncviewer.c
+++ b/client_examples/SDLvncviewer.c
@@ -16,7 +16,7 @@ static rfbBool resize(rfbClient* client) {
okay=SDL_VideoModeOK(width,height,depth,flags);
if(okay) {
SDL_Surface* sdl=SDL_SetVideoMode(width,height,depth,flags);
- client->clientData=sdl;
+ rfbClientSetClientData(client, SDL_Init, sdl);
client->frameBuffer=sdl->pixels;
if(first || depth!=client->format.bitsPerPixel) {
first=FALSE;
@@ -30,7 +30,7 @@ static rfbBool resize(rfbClient* client) {
SetFormatAndEncodings(client);
}
} else {
- SDL_Surface* sdl=client->clientData;
+ SDL_Surface* sdl=rfbClientGetClientData(client, SDL_Init);
rfbClientLog("Could not set resolution %dx%d!\n",
client->width,client->height);
if(sdl) {
@@ -188,7 +188,7 @@ static rfbKeySym SDL_keysym2rfbKeySym(int keysym) {
}
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__
diff --git a/client_examples/backchannel.c b/client_examples/backchannel.c
new file mode 100644
index 0000000..643754e
--- /dev/null
+++ b/client_examples/backchannel.c
@@ -0,0 +1,99 @@
+/* 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;
+}
+
diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c
index 0e8ccfe..1a491a9 100644
--- a/libvncclient/rfbproto.c
+++ b/libvncclient/rfbproto.c
@@ -77,6 +77,49 @@ rfbDefaultClientLog(const char *format, ...)
rfbClientLogProc rfbClientLog=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) {
int i,j;
@@ -259,6 +302,12 @@ InitialiseRFBConnection(rfbClient* client)
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",
major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
@@ -394,6 +443,7 @@ SetFormatAndEncodings(rfbClient* client)
rfbBool requestCompressLevel = FALSE;
rfbBool requestQualityLevel = FALSE;
rfbBool requestLastRectEncoding = FALSE;
+ rfbClientProtocolExtension* e;
spf.type = rfbSetPixelFormat;
spf.format = client->format;
@@ -535,6 +585,13 @@ SetFormatAndEncodings(rfbClient* client)
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;
se->nEncodings = rfbClientSwap16IfLE(se->nEncodings);
@@ -923,9 +980,20 @@ HandleRFBServerMessage(rfbClient* client)
#endif
default:
- rfbClientLog("Unknown rect encoding %d\n",
- (int)rect.encoding);
- return FALSE;
+ {
+ 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",
+ (int)rect.encoding);
+ return FALSE;
+ }
+ }
}
/* Now we may discard "soft cursor locks". */
@@ -934,16 +1002,6 @@ HandleRFBServerMessage(rfbClient* client)
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))
return FALSE;
@@ -981,8 +1039,21 @@ HandleRFBServerMessage(rfbClient* client)
}
default:
- rfbClientLog("Unknown message type %d from VNC server\n",msg.type);
- return FALSE;
+ {
+ 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);
+ return FALSE;
+ }
+ }
}
return TRUE;
diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h
index 5d34526..c99f4f9 100644
--- a/rfb/rfbclient.h
+++ b/rfb/rfbclient.h
@@ -63,6 +63,15 @@ typedef struct {
rfbBool doNotSleep;
} rfbVNCRec;
+/* client data */
+
+typedef struct rfbClientData {
+ void* tag;
+ void* data;
+ struct rfbClientData* next;
+} rfbClientData;
+
+/* app data (belongs into rfbClient?) */
typedef struct {
rfbBool shareDesktop;
@@ -181,7 +190,7 @@ typedef struct _rfbClient {
uint8_t *rcSource, *rcMask;
/* private data pointer */
- void* clientData;
+ rfbClientData* clientData;
rfbVNCRec* vncRec;
@@ -223,6 +232,26 @@ extern rfbBool HandleRFBServerMessage(rfbClient* client);
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 */
extern rfbBool errorMessageOnReadFailure;