From 5c3eae92371309d94a5edd4e35caa71a2e481ab9 Mon Sep 17 00:00:00 2001 From: dscho Date: Wed, 26 Sep 2001 21:20:27 +0000 Subject: [PATCH] API corrections --- Makefile | 3 +- README | 124 ++++++++++++++++++++++++++++++++++++++++++++++++------ TODO | 1 + example.c | 16 ++++--- httpd.c | 6 +-- main.c | 34 +++++++++++---- pnmshow.c | 14 ++++-- rfb.h | 12 ++++-- 8 files changed, 169 insertions(+), 41 deletions(-) diff --git a/Makefile b/Makefile index a8b404b..26a3422 100644 --- a/Makefile +++ b/Makefile @@ -4,14 +4,13 @@ CFLAGS=-g -Wall RANLIB=ranlib INCLUDES=-I. -Iinclude -VNCAUTHLIB= VNCSERVERLIB=-L. -lvncserver -lz -ljpeg # These two lines enable useage of PThreads #CFLAGS += -DHAVE_PTHREADS #VNCSERVERLIB += -lpthread -LIBS=$(LDFLAGS) $(VNCSERVERLIB) $(VNCAUTHLIB) +LIBS=$(LDFLAGS) $(VNCSERVERLIB) # for Mac OS X OSX_LIBS = -framework ApplicationServices -framework Carbon diff --git a/README b/README index 5fa5725..46ec6a0 100644 --- a/README +++ b/README @@ -23,37 +23,134 @@ How to use To make a server, you just have to initialise a server structure using the function rfbDefaultScreenInit, like rfbScreenInfoPtr rfbScreen = - rfbDefaultScreenInit(argc,argv,maxx,maxy,8,3,bpp); + rfbGetScreen(argc,argv,maxx,maxy,8,3,bpp); -You then can set hooks and io functions (see below). +You then can set hooks and io functions (see below) or other +options (see below). + +After that, you initialize the server, like + rfbInitServer(rfbScreen); You can use a blocking event loop, a background (pthread based) event loop, -or implement your own using the processEvents function. +or implement your own using the rfbProcessEvents function. + +Making it interactive +--------------------- + +Input is handled by IO functions (see below). + +Whenever you change something in the frame buffer, call rfbMarkRectAsModified. +You should make sure that the cursor is not drawn before drawing yourself +by calling rfbUndrawCursor. You can also draw the cursor using rfbDrawCursor, +but it hardly seems necessary. For cursor details, see below. + +Utility functions +----------------- + +Whenever you draw something, you have to call + rfbMarkRectAsModified(screen,x1,y1,x2,y2). +This tells LibVNCServer to send updates to all connected clients. + +Before you draw something, be sure to call + rfbUndrawCursor(cl). +This tells LibVNCServer to hide the cursor. +Remark: There are vncviewers out there, which know a cursor encoding, so +that network traffic is low, and also the cursor doesn't need to be +drawn the cursor everytime an update is sent. LibVNCServer handles +all the details. Just set the cursor and don't bother any more. + +What is the difference between rfbScreenInfoPtr and rfbClientPtr? +----------------------------------------------------------------- + +The rfbScreenInfoPtr is a pointer to a rfbScreenInfo structure, which +holds information about the server, like pixel format, io functions, +frame buffer etc. + +The rfbClientPtr is a pointer to an rfbClientRec structure, which holds +information about a client, like pixel format, socket of the +connection, etc. + +A server can have several clients, but needn't have any. So, if you +have a server and three clients are connected, you have one instance +of a rfbScreenInfo and three instances of rfbClientRec's. -Also, there is functionality included to draw a cursor (see below). +The rfbClientRec structure holds a member + rfbScreenInfoPtr screen +which points to the server and a member + rfbClientPtr next +to the next client. -To start also an HTTP server (running on port 5800+display_number), you have +The rfbScreenInfo structure holds a member + rfbClientPtr rfbClientHead +which points to the first client. + +So, to access the server from the client structure, you use client->screen. +To access all clients from a server, get screen->rfbClientHead and +iterate using client->next. + +If you change client settings, be sure to use the provided iterator + rfbGetClientIterator(rfbScreen) +with + rfbClientIteratorNext(iterator) +and + rfbReleaseClientIterator +to prevent thread clashes. + +Other options +------------- + +These options have to be set between rfbGetScreen and rfbInitServer. + +If you already have a socket to talk to, just set rfbScreen->inetdSock +(originally this is for inetd handling, but why not use it for your purpose?). + +To also start an HTTP server (running on port 5800+display_number), you have to set rfbScreen->httpdDir to a directory containing vncviewer.jar and index.vnc (like the included "classes" directory). Hooks and IO functions ---------------------- -TODO +There exist the following IO functions as members of rfbScreen: +kbdAddEvent, kbdReleaseAllKeys, ptrAddEvent and setXCutText + +kbdAddEvent(Bool down,KeySym key,rfbClientPtr cl) + is called when a key is pressed. +kbdReleaseAllKeys(rfbClientPtr cl) + is not called at all (maybe in the future). +ptrAddEvent(int buttonMask,int x,int y,rfbClientPtr cl) + is called when the mouse moves or a button is pressed. +setXCutText(char* str,int len,rfbClientPtr cl) + is called when the selection changes. + +There is only one hook: +newClientHook(rfbClientPtr cl) + is called when a new client has connected. + +You can also override the following method: +getCursorPtr(rfbClientPtr cl) + This could be used to make an animated cursor (if you really want ...) Cursor handling --------------- +The screen holds a pointer + rfbCursorPtr cursor +to the current cursor. Whenever you set it, remember that any dynamically +created cursor (like return value from rfbMakeXCursor) is not free'd! + The rfbCursor structure consists mainly of a mask and a source. The mask describes, which pixels are drawn for the cursor (a cursor needn't be rectangular). The source describes, which colour those pixels should have. The standard is an XCursor: a cursor with a foreground and a background -colour (stored in backRed and similar with a range from 0-0xffff). The -arrays "mask" and "source" consist of byte padded rows in MSB order (i.e. a -10x4 cursor's mask has 2x4 bytes, because 2 bytes are needed to hold 10 bits). +colour (stored in backRed,backGreen,backBlue and the same for foreground +in a range from 0-0xffff). Therefore, the arrays "mask" and "source" +contain pixels as single bits stored in bytes in MSB order. The rows are +padded, such that each row begins with a new byte (i.e. a 10x4 +cursor's mask has 2x4 bytes, because 2 bytes are needed to hold 10 bits). -It is very easy to make a cursor like this: +It is however very easy to make a cursor like this: char* cur=" " " xx " @@ -66,10 +163,11 @@ char* mask="xxxx" rfbCursorPtr c=rfbMakeXCursor(4,4,cur,mask); You can even set "mask" to NULL in this call and LibVNCServer will calculate -a mask for you. +a mask for you (dynamically, so you have to free it yourself). There is also an array named "richSource" for colourful cursors. They have -the same format as the frameBuffer. +the same format as the frameBuffer (i.e. if the server is 32 bit, +a 10x4 cursor has 4x10x4 bytes). History ------- @@ -77,6 +175,8 @@ History LibVNCServer is based on Tridia VNC and OSXvnc, which in turn are based on the original code from ORL/AT&T. +VNC fascinated me from t + License ------- diff --git a/TODO b/TODO index bbe0b22..38aa6b6 100644 --- a/TODO +++ b/TODO @@ -9,6 +9,7 @@ in the works: adapt rdp2vnc (rdesktop) optionally dont draw rich cursors as xcursors +use sraRegion from rdp2vnc instead of miregion, because it is much smaller later: ------ diff --git a/example.c b/example.c index 57d0d37..0da149b 100644 --- a/example.c +++ b/example.c @@ -30,8 +30,8 @@ #include "rfb.h" #include "keysym.h" -const int maxx=641, maxy=480, bpp=4; -/* TODO: odd maxx doesn't work */ +const int maxx=640, maxy=480, bpp=4; +/* TODO: odd maxx doesn't work (vncviewer bug) */ /* This initializes a nice (?) background */ @@ -288,7 +288,7 @@ void MakeRichCursor(rfbScreenInfoPtr rfbScreen) int main(int argc,char** argv) { rfbScreenInfoPtr rfbScreen = - rfbDefaultScreenInit(argc,argv,maxx,maxy,8,3,bpp); + rfbGetScreen(argc,argv,maxx,maxy,8,3,bpp); rfbScreen->desktopName = "LibVNCServer Example"; rfbScreen->frameBuffer = (char*)malloc(maxx*maxy*bpp); rfbScreen->rfbAlwaysShared = TRUE; @@ -307,15 +307,17 @@ int main(int argc,char** argv) MakeRichCursor(rfbScreen); + /* initialize the server */ + rfbInitServer(rfbScreen); + /* this is the blocking event loop, i.e. it never returns */ /* 40000 are the microseconds, i.e. 0.04 seconds */ - runEventLoop(rfbScreen,40000,FALSE); + rfbRunEventLoop(rfbScreen,40000,FALSE); /* this is the non-blocking event loop; a background thread is started */ - runEventLoop(rfbScreen,40000,TRUE); - + rfbRunEventLoop(rfbScreen,40000,TRUE); /* now we could do some cool things like rendering */ - while(1); + while(1) /* render() */; return(0); } diff --git a/httpd.c b/httpd.c index b8391fc..a80c44d 100644 --- a/httpd.c +++ b/httpd.c @@ -66,12 +66,10 @@ static char buf[BUF_SIZE]; void httpInitSockets(rfbScreenInfoPtr rfbScreen) { - static Bool done = FALSE; - - if (done) + if (rfbScreen->httpInitDone) return; - done = TRUE; + rfbScreen->httpInitDone = TRUE; if (!rfbScreen->httpDir) return; diff --git a/main.c b/main.c index e0efb8f..18b143b 100644 --- a/main.c +++ b/main.c @@ -340,7 +340,9 @@ void doNothingWithClient(rfbClientPtr cl) { } -rfbScreenInfoPtr rfbDefaultScreenInit(int argc,char** argv,int width,int height,int bitsPerSample,int samplesPerPixel,int bytesPerPixel) +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; @@ -350,18 +352,24 @@ rfbScreenInfoPtr rfbDefaultScreenInit(int argc,char** argv,int width,int height, rfbScreen->rfbPort=5900; rfbScreen->socketInitDone=FALSE; + + rfbScreen->inetdInitDone = FALSE; rfbScreen->inetdSock=-1; + rfbScreen->udpSock=-1; rfbScreen->udpSockConnected=FALSE; + rfbScreen->udpPort=0; + rfbScreen->maxFd=0; rfbScreen->rfbListenSock=-1; - rfbScreen->udpPort=0; + + rfbScreen->httpInitDone=FALSE; rfbScreen->httpPort=0; rfbScreen->httpDir=NULL; rfbScreen->httpListenSock=-1; rfbScreen->httpSock=-1; rfbScreen->httpFP=NULL; - rfbScreen->inetdInitDone = FALSE; + rfbScreen->desktopName = "LibVNCServer"; rfbScreen->rfbAlwaysShared = FALSE; rfbScreen->rfbNeverShared = FALSE; @@ -421,11 +429,20 @@ rfbScreenInfoPtr rfbDefaultScreenInit(int argc,char** argv,int width,int height, rfbScreen->cursor = &myCursor; rfbScreen->newClientHook = doNothingWithClient; + /* initialize client list and iterator mutex */ + rfbClientListInit(rfbScreen); + return(rfbScreen); } +void rfbInitServer(rfbScreenInfoPtr rfbScreen) +{ + rfbInitSockets(rfbScreen); + httpInitSockets(rfbScreen); +} + void -processEvents(rfbScreenInfoPtr rfbScreen,long usec) +rfbProcessEvents(rfbScreenInfoPtr rfbScreen,long usec) { rfbCheckFds(rfbScreen,usec); httpCheckFds(rfbScreen); @@ -445,13 +462,14 @@ processEvents(rfbScreenInfoPtr rfbScreen,long usec) } } -void runEventLoop(rfbScreenInfoPtr rfbScreen, long usec, Bool runInBackground) +void rfbRunEventLoop(rfbScreenInfoPtr rfbScreen, long usec, Bool runInBackground) { + rfbInitServer(rfbScreen); + if(runInBackground) { #ifdef HAVE_PTHREADS pthread_t listener_thread; - rfbClientListInit(rfbScreen); //pthread_mutex_init(&logMutex, NULL); pthread_create(&listener_thread, NULL, listenerRun, rfbScreen); return; @@ -460,8 +478,6 @@ void runEventLoop(rfbScreenInfoPtr rfbScreen, long usec, Bool runInBackground) #endif } - rfbInitSockets(rfbScreen); - httpInitSockets(rfbScreen); while(1) - processEvents(rfbScreen,usec); + rfbProcessEvents(rfbScreen,usec); } diff --git a/pnmshow.c b/pnmshow.c index 15644e7..8f4ceed 100644 --- a/pnmshow.c +++ b/pnmshow.c @@ -45,7 +45,7 @@ int main(int argc,char** argv) paddedWidth+=4-(width&3); /* initialize data for vnc server */ - rfbScreen = rfbDefaultScreenInit(argc,argv,width,height,8,3,4); + rfbScreen = rfbGetScreen(argc,argv,paddedWidth,height,8,3,4); if(argc>1) rfbScreen->desktopName = argv[1]; else @@ -57,19 +57,25 @@ int main(int argc,char** argv) rfbScreen->httpDir = "./classes"; /* allocate picture and read it */ - rfbScreen->frameBuffer = (char*)calloc(paddedWidth*4,height); + rfbScreen->frameBuffer = (char*)malloc(paddedWidth*4*height); fread(rfbScreen->frameBuffer,width*3,height,in); fclose(in); /* correct the format to 4 bytes instead of 3 (and pad to paddedWidth) */ - for(j=height-1;j>=0;j--) + for(j=height-1;j>=0;j--) { for(i=width-1;i>=0;i--) for(k=2;k>=0;k--) rfbScreen->frameBuffer[(j*paddedWidth+i)*4+k]= rfbScreen->frameBuffer[(j*width+i)*3+k]; + for(i=width*4;iframeBuffer[j*paddedWidth*4+i]=0; + } + + /* initialize server */ + rfbInitServer(rfbScreen); /* run event loop */ - runEventLoop(rfbScreen,40000,FALSE); + rfbRunEventLoop(rfbScreen,40000,FALSE); return(0); } diff --git a/rfb.h b/rfb.h index 8c03a22..225e0b9 100644 --- a/rfb.h +++ b/rfb.h @@ -182,11 +182,14 @@ typedef struct Bool inetdInitDone; fd_set allFds; int rfbMaxClientWait; + /* http stuff */ + Bool httpInitDone; int httpPort; char* httpDir; int httpListenSock; int httpSock; FILE* httpFP; + char* rfbAuthPasswdFile; int rfbDeferUpdateTime; char* rfbScreen; @@ -601,12 +604,15 @@ void rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,RegionPtr modRegion); void doNothingWithClient(rfbClientPtr cl); /* functions to make a vnc server */ -extern rfbScreenInfoPtr rfbDefaultScreenInit(int argc,char** argv,int width,int height,int bitsPerSample,int samplesPerPixel,int bytesPerPixel); +extern rfbScreenInfoPtr rfbGetScreen(int argc,char** argv, + int width,int height,int bitsPerSample,int samplesPerPixel, + int bytesPerPixel); +extern void rfbInitServer(rfbScreenInfoPtr rfbScreen); extern void rfbScreenCleanup(rfbScreenInfoPtr screenInfo); /* call one of these two functions to service the vnc clients. usec are the microseconds the select on the fds waits. if you are using the event loop, set this to some value > 0. */ -extern void runEventLoop(rfbScreenInfoPtr screenInfo, long usec, Bool runInBackground); -extern void processEvents(rfbScreenInfoPtr screenInfo,long usec); +extern void rfbRunEventLoop(rfbScreenInfoPtr screenInfo, long usec, Bool runInBackground); +extern void rfbProcessEvents(rfbScreenInfoPtr screenInfo,long usec);