diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README | 56 | ||||
-rw-r--r-- | TODO | 20 | ||||
-rw-r--r-- | cursor.c | 376 | ||||
-rw-r--r-- | example.c | 98 | ||||
-rw-r--r-- | httpd.c | 4 | ||||
-rw-r--r-- | main.c | 58 | ||||
-rw-r--r-- | rfb.h | 38 | ||||
-rw-r--r-- | rfbserver.c | 44 | ||||
-rw-r--r-- | sockets.c | 1 | ||||
-rw-r--r-- | zlib.c | 2 |
11 files changed, 545 insertions, 156 deletions
@@ -20,10 +20,10 @@ OSX_LIBS = -framework ApplicationServices -framework Carbon SOURCES=main.c rfbserver.c miregion.c auth.c sockets.c xalloc.c \ stats.c corre.c hextile.c rre.c translate.c cutpaste.c \ - zlib.c tight.c httpd.c + zlib.c tight.c httpd.c cursor.o OBJS=main.o rfbserver.o miregion.o auth.o sockets.o xalloc.o \ stats.o corre.o hextile.o rre.o translate.o cutpaste.o \ - zlib.o tight.o httpd.o + zlib.o tight.o httpd.o cursor.o all: example pnmshow storepasswd @@ -1,6 +1,15 @@ LibVNCServer: a library for easy implementation of a RDP/VNC server. Copyright (C) 2001 Johannes E. Schindelin +What is it? +----------- + +VNC is set of programs using the RFB (Remote Frame Buffer) protocol. They +are designed to "export" a frame buffer via net. It is already in wide use +for administration, but it is not that easy to make a server yourself. + +This has been changed by LibVNCServer. + There are two examples included: - example, a shared scribble sheet - pnmshow, a program to show PNMs (pictures) over the net. @@ -12,13 +21,56 @@ How to use ---------- To make a server, you just have to initialise a server structure using the -function rfbDefaultScreenInit. +function rfbDefaultScreenInit, like + rfbScreenInfoPtr rfbScreen = + rfbDefaultScreenInit(argc,argv,maxx,maxy,8,3,bpp); -You then can set hooks and io functions. +You then can set hooks and io functions (see below). You can use a blocking event loop, a background (pthread based) event loop, or implement your own using the processEvents function. +Also, there is functionality included to draw a cursor (see below). + +To start also 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 + +Cursor handling +--------------- + +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). + +It is very easy to make a cursor like this: + +char* cur=" " + " xx " + " x " + " "; +char* mask="xxxx" + "xxxx" + "xxxx" + "xxx "; +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. + +There is also an array named "richSource" for colourful cursors. They have +the same format as the frameBuffer. + History ------- @@ -1,17 +1,15 @@ -.cutpaste - -httpd - -.other encodings - +dont draw rich cursors as xcursors +test drawing of cursors when not using xcursor or rich cursor encoding adapt rdp2vnc (rdesktop) - udp - rfbCloseClient, rfbConnect, ConnectToTcpAddr - CORBA - translate.c: warning about non 8-bit colourmaps -cursors +done: + +.cursors +.cutpaste +.httpd +.other encodings + @@ -24,11 +24,13 @@ #include <stdio.h> #include "rfb.h" -#include "mipointer.h" + +/* + #include "mipointer.h" #include "sprite.h" #include "cursorstr.h" #include "servermd.h" - +*/ /* Copied from Xvnc/lib/font/util/utilbitmap.c */ static unsigned char _reverse_byte[0x100] = { @@ -67,12 +69,12 @@ static unsigned char _reverse_byte[0x100] = { }; -static int EncodeRichCursorData8 (char *buf, rfbPixelFormat *fmt, - CursorPtr pCursor); -static int EncodeRichCursorData16 (char *buf, rfbPixelFormat *fmt, - CursorPtr pCursor); -static int EncodeRichCursorData32 (char *buf, rfbPixelFormat *fmt, - CursorPtr pCursor); +static int EncodeRichCursorData8 (rfbClientPtr cl, char *buf, rfbPixelFormat *fmt, + rfbCursorPtr pCursor); +static int EncodeRichCursorData16 (rfbClientPtr cl, char *buf, rfbPixelFormat *fmt, + rfbCursorPtr pCursor); +static int EncodeRichCursorData32 (rfbClientPtr cl, char *buf, rfbPixelFormat *fmt, + rfbCursorPtr pCursor); /* @@ -80,45 +82,54 @@ static int EncodeRichCursorData32 (char *buf, rfbPixelFormat *fmt, */ Bool -rfbSendCursorShape(cl, pScreen) +rfbSendCursorShape(cl) rfbClientPtr cl; - ScreenPtr pScreen; { - CursorPtr pCursor; + rfbCursorPtr pCursor; rfbFramebufferUpdateRectHeader rect; rfbXCursorColors colors; int saved_ublen; - int bitmapRowBytes, paddedRowBytes, maskBytes, dataBytes; + int bitmapRowBytes, maskBytes, dataBytes; int i, j; CARD8 *bitmapData; CARD8 bitmapByte; + pCursor = cl->screen->getCursorPtr(cl); + if (cl->useRichCursorEncoding) { - rect.encoding = Swap32IfLE(rfbEncodingRichCursor); + if(!pCursor->richSource) + MakeRichCursorFromXCursor(cl->screen,pCursor); + rect.encoding = Swap32IfLE(rfbEncodingRichCursor); } else { - rect.encoding = Swap32IfLE(rfbEncodingXCursor); + if(!pCursor->source) + MakeXCursorFromRichCursor(cl->screen,pCursor); + rect.encoding = Swap32IfLE(rfbEncodingXCursor); } - pCursor = rfbSpriteGetCursorPtr(pScreen); - + /*{ + rfbScreenInfoPtr s=cl->screen; + SetXCutTextProcPtr sx=cl->screen->setXCutText; + GetCursorProcPtr g=cl->screen->getCursorPtr; + }*/ + /* If there is no cursor, send update with empty cursor data. */ - if ( pCursor->bits->width == 1 && - pCursor->bits->height == 1 && - pCursor->bits->mask[0] == 0 ) { + if ( pCursor->width == 1 && + pCursor->height == 1 && + pCursor->mask[0] == 0 ) { pCursor = NULL; } if (pCursor == NULL) { - if (ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) { + if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = rect.r.y = 0; rect.r.w = rect.r.h = 0; - memcpy(&updateBuf[ublen], (char *)&rect, + memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); - ublen += sz_rfbFramebufferUpdateRectHeader; + cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->rfbCursorBytesSent += sz_rfbFramebufferUpdateRectHeader; cl->rfbCursorUpdatesSent++; @@ -131,37 +142,36 @@ rfbSendCursorShape(cl, pScreen) /* Calculate data sizes. */ - bitmapRowBytes = (pCursor->bits->width + 7) / 8; - paddedRowBytes = PixmapBytePad(pCursor->bits->width, 1); - maskBytes = bitmapRowBytes * pCursor->bits->height; + bitmapRowBytes = (pCursor->width + 7) / 8; + maskBytes = bitmapRowBytes * pCursor->height; dataBytes = (cl->useRichCursorEncoding) ? - (pCursor->bits->width * pCursor->bits->height * + (pCursor->width * pCursor->height * (cl->format.bitsPerPixel / 8)) : maskBytes; /* Send buffer contents if needed. */ - if ( ublen + sz_rfbFramebufferUpdateRectHeader + + if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { if (!rfbSendUpdateBuf(cl)) return FALSE; } - if ( ublen + sz_rfbFramebufferUpdateRectHeader + + if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { return FALSE; /* FIXME. */ } - saved_ublen = ublen; + saved_ublen = cl->ublen; /* Prepare rectangle header. */ - rect.r.x = Swap16IfLE(pCursor->bits->xhot); - rect.r.y = Swap16IfLE(pCursor->bits->yhot); - rect.r.w = Swap16IfLE(pCursor->bits->width); - rect.r.h = Swap16IfLE(pCursor->bits->height); + rect.r.x = Swap16IfLE(pCursor->xhot); + rect.r.y = Swap16IfLE(pCursor->yhot); + rect.r.w = Swap16IfLE(pCursor->width); + rect.r.h = Swap16IfLE(pCursor->height); - memcpy(&updateBuf[ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); - ublen += sz_rfbFramebufferUpdateRectHeader; + memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); + cl->ublen += sz_rfbFramebufferUpdateRectHeader; /* Prepare actual cursor data (depends on encoding used). */ @@ -174,57 +184,68 @@ rfbSendCursorShape(cl, pScreen) colors.backGreen = (char)(pCursor->backGreen >> 8); colors.backBlue = (char)(pCursor->backBlue >> 8); - memcpy(&updateBuf[ublen], (char *)&colors, sz_rfbXCursorColors); - ublen += sz_rfbXCursorColors; + memcpy(&cl->updateBuf[cl->ublen], (char *)&colors, sz_rfbXCursorColors); + cl->ublen += sz_rfbXCursorColors; - bitmapData = (CARD8 *)pCursor->bits->source; + bitmapData = (CARD8 *)pCursor->source; - for (i = 0; i < pCursor->bits->height; i++) { + for (i = 0; i < pCursor->height; i++) { for (j = 0; j < bitmapRowBytes; j++) { - bitmapByte = bitmapData[i * paddedRowBytes + j]; - if (screenInfo.bitmapBitOrder == LSBFirst) { + bitmapByte = bitmapData[i * bitmapRowBytes + j]; + /*if (screenInfo.bitmapBitOrder == LSBFirst) { bitmapByte = _reverse_byte[bitmapByte]; - } - updateBuf[ublen++] = (char)bitmapByte; + }*/ + cl->updateBuf[cl->ublen++] = (char)bitmapByte; } } } else { /* RichCursor encoding. */ + int bpp1=cl->screen->rfbServerFormat.bitsPerPixel/8, + bpp2=cl->format.bitsPerPixel/8; + (*cl->translateFn)(cl->translateLookupTable, + &(cl->screen->rfbServerFormat), + &cl->format, pCursor->richSource, + &cl->updateBuf[cl->ublen], + pCursor->width*bpp1, pCursor->width, pCursor->height); + + cl->ublen += pCursor->width*bpp2*pCursor->height; + /* switch (cl->format.bitsPerPixel) { case 8: - ublen += EncodeRichCursorData8(&updateBuf[ublen], + cl->ublen += EncodeRichCursorData8(cl, &cl->updateBuf[cl->ublen], &cl->format, pCursor); break; case 16: - ublen += EncodeRichCursorData16(&updateBuf[ublen], + cl->ublen += EncodeRichCursorData16(cl, &cl->updateBuf[cl->ublen], &cl->format, pCursor); break; case 32: - ublen += EncodeRichCursorData32(&updateBuf[ublen], + cl->ublen += EncodeRichCursorData32(cl, &cl->updateBuf[cl->ublen], &cl->format, pCursor); break; default: return FALSE; } + */ } /* Prepare transparency mask. */ - bitmapData = (CARD8 *)pCursor->bits->mask; + bitmapData = (CARD8 *)pCursor->mask; - for (i = 0; i < pCursor->bits->height; i++) { + for (i = 0; i < pCursor->height; i++) { for (j = 0; j < bitmapRowBytes; j++) { - bitmapByte = bitmapData[i * paddedRowBytes + j]; - if (screenInfo.bitmapBitOrder == LSBFirst) { + bitmapByte = bitmapData[i * bitmapRowBytes + j]; + /*if (screenInfo.bitmapBitOrder == LSBFirst) { bitmapByte = _reverse_byte[bitmapByte]; - } - updateBuf[ublen++] = (char)bitmapByte; + }*/ + cl->updateBuf[cl->ublen++] = (char)bitmapByte; } } - /* Send everything we have prepared in the updateBuf[]. */ + /* Send everything we have prepared in the cl->updateBuf[]. */ - cl->rfbCursorBytesSent += (ublen - saved_ublen); + cl->rfbCursorBytesSent += (cl->ublen - saved_ublen); cl->rfbCursorUpdatesSent++; if (!rfbSendUpdateBuf(cl)) @@ -244,10 +265,11 @@ rfbSendCursorShape(cl, pScreen) ((CARD32)(b) * ((fmt)->blueMax + 1) >> 16) << (fmt)->blueShift) static int -EncodeRichCursorData8(buf, fmt, pCursor) +EncodeRichCursorData8(cl, buf, fmt, pCursor) + rfbClientPtr cl; char *buf; rfbPixelFormat *fmt; - CursorPtr pCursor; + rfbCursorPtr pCursor; { int widthPixels, widthBytes; int x, y, b; @@ -260,41 +282,42 @@ EncodeRichCursorData8(buf, fmt, pCursor) pix[1] = (char)RGB48_TO_PIXEL(fmt, pCursor->foreRed, pCursor->foreGreen, pCursor->foreBlue); - src = (CARD8 *)pCursor->bits->source; - widthPixels = pCursor->bits->width; - widthBytes = PixmapBytePad(widthPixels, 1); + src = (CARD8 *)pCursor->richSource; + widthPixels = pCursor->width; + widthBytes = widthPixels; - for (y = 0; y < pCursor->bits->height; y++) { + for (y = 0; y < pCursor->height; y++) { for (x = 0; x < widthPixels / 8; x++) { bitmapByte = src[y * widthBytes + x]; - if (screenInfo.bitmapBitOrder == LSBFirst) { + /*if (screenInfo.bitmapBitOrder == LSBFirst) { bitmapByte = _reverse_byte[bitmapByte]; - } + }*/ for (b = 7; b >= 0; b--) { *buf++ = pix[bitmapByte >> b & 1]; } } if (widthPixels % 8) { bitmapByte = src[y * widthBytes + x]; - if (screenInfo.bitmapBitOrder == LSBFirst) { + /*if (screenInfo.bitmapBitOrder == LSBFirst) { bitmapByte = _reverse_byte[bitmapByte]; - } + }*/ for (b = 7; b > 7 - widthPixels % 8; b--) { *buf++ = pix[bitmapByte >> b & 1]; } } } - return (widthPixels * pCursor->bits->height); + return (widthPixels * pCursor->height); } #define DEFINE_RICH_ENCODE(bpp) \ \ static int \ -EncodeRichCursorData##bpp(buf, fmt, pCursor) \ +EncodeRichCursorData##bpp(cl, buf, fmt, pCursor) \ + rfbClientPtr cl; \ char *buf; \ rfbPixelFormat *fmt; \ - CursorPtr pCursor; \ + rfbCursorPtr pCursor; \ { \ int widthPixels, widthBytes; \ int x, y, b; \ @@ -308,21 +331,21 @@ EncodeRichCursorData##bpp(buf, fmt, pCursor) \ pix[1] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->foreRed, \ pCursor->foreGreen, \ pCursor->foreBlue); \ - if (!rfbServerFormat.bigEndian != !fmt->bigEndian) { \ + if (!cl->screen->rfbServerFormat.bigEndian != !fmt->bigEndian) { \ pix[0] = Swap##bpp(pix[0]); \ pix[1] = Swap##bpp(pix[1]); \ } \ \ - src = (CARD8 *)pCursor->bits->source; \ - widthPixels = pCursor->bits->width; \ - widthBytes = PixmapBytePad(widthPixels, 1); \ + src = (CARD8 *)pCursor->richSource; \ + widthPixels = pCursor->width; \ + widthBytes = (pCursor->width*bpp)/8; \ \ - for (y = 0; y < pCursor->bits->height; y++) { \ + for (y = 0; y < pCursor->height; y++) { \ for (x = 0; x < widthPixels / 8; x++) { \ bitmapByte = src[y * widthBytes + x]; \ - if (screenInfo.bitmapBitOrder == LSBFirst) { \ + /*if (screenInfo.bitmapBitOrder == LSBFirst) { \ bitmapByte = _reverse_byte[bitmapByte]; \ - } \ + }*/ \ for (b = 7; b >= 0; b--) { \ memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ sizeof(CARD##bpp)); \ @@ -331,9 +354,9 @@ EncodeRichCursorData##bpp(buf, fmt, pCursor) \ } \ if (widthPixels % 8) { \ bitmapByte = src[y * widthBytes + x]; \ - if (screenInfo.bitmapBitOrder == LSBFirst) { \ + /*if (cl->screen.bitmapBitOrder == LSBFirst) { \ bitmapByte = _reverse_byte[bitmapByte]; \ - } \ + }*/ \ for (b = 7; b > 7 - widthPixels % 8; b--) { \ memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ sizeof(CARD##bpp)); \ @@ -342,9 +365,208 @@ EncodeRichCursorData##bpp(buf, fmt, pCursor) \ } \ } \ \ - return (widthPixels * pCursor->bits->height * (bpp / 8)); \ + return (widthPixels * pCursor->height * (bpp / 8)); \ } DEFINE_RICH_ENCODE(16) DEFINE_RICH_ENCODE(32) +void rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char* bitmap) +{ + int i,t=(width+7)/8*height; + for(i=0;i<t;i++) + bitmap[i]=_reverse_byte[(int)bitmap[i]]; +} + +rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskString) +{ + int i,j,w=(width+7)/8; + rfbCursorPtr cursor = (rfbCursorPtr)calloc(1,sizeof(rfbCursor)); + char* cp; + unsigned char bit; + + cursor->width=width; + cursor->height=height; + //cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff; + cursor->foreRed=cursor->foreGreen=cursor->foreBlue=0xffff; + + cursor->source = (char*)calloc(w,height); + for(j=0,cp=cursorString;j<height;j++) + for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++) + if(*cp!=' ') cursor->source[j*w+i/8]|=bit; + + if(maskString) { + cursor->mask = (char*)calloc(w,height); + for(j=0,cp=maskString;j<height;j++) + for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++) + if(*cp!=' ') cursor->mask[j*w+i/8]|=bit; + } else + cursor->mask = rfbMakeMaskForXCursor(width,height,cursor->source); + + return(cursor); +} + +char* rfbMakeMaskForXCursor(int width,int height,char* source) +{ + int i,j,w=(width+7)/8; + char* mask=(char*)calloc(w,height); + unsigned char c; + + for(j=0;j<height;j++) + for(i=w-1;i>=0;i--) { + c=source[j*w+i]; + if(j>0) c|=source[(j-1)*w+i]; + if(j<height-1) c|=source[(j+1)*w+i]; + + if(i>0 && (c&0x80)) + mask[j*w+i-1]|=0x01; + if(i<w-1 && (c&0x01)) + mask[j*w+i+1]|=0x80; + + mask[j*w+i]|=(c<<1)|c|(c>>1); + } + + return(mask); +} + +void rfbFreeCursor(rfbCursorPtr cursor) +{ + if(cursor) { + free(cursor->source); + free(cursor->mask); + free(cursor); + } + +} + +/* background and foregroud colour have to be set beforehand */ +void MakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor) +{ + rfbPixelFormat* format=&rfbScreen->rfbServerFormat; + int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8, + width=cursor->width*bpp; + CARD32 background; + char *back=(char*)&background; + unsigned char bit; + + cursor->source=(char*)calloc(w,cursor->height); + + if(format->bigEndian) + back+=4-bpp; + + background=cursor->backRed<<format->redShift| + cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift; + + for(j=0;j<cursor->height;j++) + for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1) + if(memcmp(cursor->richSource+j*width+i*bpp,back,bpp)) + cursor->source[j*w+i/8]|=bit; +} + +void MakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor) +{ + rfbPixelFormat* format=&rfbScreen->rfbServerFormat; + int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8; + CARD32 background,foreground; + char *cp,*back=(char*)&background,*fore=(char*)&foreground; + unsigned char bit; + + cp=cursor->richSource=(char*)calloc(cursor->width*bpp,cursor->height); + + if(format->bigEndian) { + back+=4-bpp; + fore+=4-bpp; + } + + background=cursor->backRed<<format->redShift| + cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift; + foreground=cursor->foreRed<<format->redShift| + cursor->foreGreen<<format->greenShift|cursor->foreBlue<<format->blueShift; + + for(j=0;j<cursor->height;j++) + for(i=0,bit=0x80;i<cursor->height;i++,bit=(bit&1)?0x80:bit>>1,cp+=bpp) + if(cursor->source[j*w+i/8]&bit) memcpy(cp,fore,bpp); + else memcpy(cp,back,bpp); +} + +void rfbUndrawCursor(rfbClientPtr cl) +{ + rfbScreenInfoPtr s=cl->screen; + rfbCursorPtr c=s->cursor; + int j,x1,x2,y1,y2,bpp=s->rfbServerFormat.bitsPerPixel/8, + rowstride=s->paddedWidthInBytes; + if(!s->cursorIsDrawn) + return; + /* restore what is under the cursor */ + x1=s->cursorX-c->xhot; + x2=x1+c->width; + if(x1<0) x1=0; + if(x2>=s->width) x2=s->width-1; + x2-=x1; + y1=s->cursorY-c->yhot; + y2=y1+c->height; + if(y1<0) y1=0; + if(y2>=s->height) y2=s->height-1; + y2-=y1; + for(j=0;j<y2;j++) + memcpy(s->frameBuffer+(y1+j)*rowstride+x1*bpp, + s->underCursorBuffer+j*x2*bpp, + x2*bpp); +} + +void rfbDrawCursor(rfbClientPtr cl) +{ + rfbScreenInfoPtr s=cl->screen; + rfbCursorPtr c=s->cursor; + int i,j,x1,x2,y1,y2,i1,j1,bpp=s->rfbServerFormat.bitsPerPixel/8, + rowstride=s->paddedWidthInBytes, + bufSize=c->width*c->height*bpp,w=(c->width+7)/8; + if(s->cursorIsDrawn) + rfbUndrawCursor(cl); + if(s->underCursorBufferLen<bufSize) { + if(s->underCursorBuffer!=NULL) + free(s->underCursorBuffer); + s->underCursorBuffer=malloc(bufSize); + s->underCursorBufferLen=bufSize; + } + /* save what is under the cursor */ + i1=j1=0; /* offset in cursor */ + x1=s->cursorX-c->xhot; + x2=x1+c->width; + if(x1<0) { i1=-x1; x1=0; } + if(x2>=s->width) x2=s->width-1; + x2-=x1; + y1=s->cursorY-c->yhot; + y2=y1+c->height; + if(y1<0) { j1=-y1; y1=0; } + if(y2>=s->height) y2=s->height-1; + y2-=y1; + for(j=0;j<y2;j++) + memcpy(s->underCursorBuffer+j*x2*bpp, + s->frameBuffer+(y1+j)*rowstride+x1*bpp, + x2*bpp); + + if(!c->richSource) + MakeRichCursorFromXCursor(s,c); + + /* now the cursor has to be drawn */ + for(j=0;j<y2;j++) + for(i=0;i<x2;i++) + if((c->mask[(j+j1)*w+(i+i1)/8]<<((i+i1)&7))&0x80) + memcpy(s->frameBuffer+(j+y1)*rowstride+(i+x1)*bpp, + c->richSource+(j+j1)*c->width*bpp+(i+i1)*bpp,bpp); +} + +void rfbPrintXCursor(rfbCursorPtr cursor) +{ + int i,i1,j,w=(cursor->width+7)/8; + unsigned char bit; + for(j=0;j<cursor->height;j++) { + for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1) + if(cursor->source[j*w+i]&bit) putchar('#'); else putchar(' '); + putchar(':'); + for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1) + if(cursor->mask[j*w+i]&bit) putchar('#'); else putchar(' '); + putchar('\n'); + } +} @@ -68,6 +68,11 @@ void drawline(unsigned char* buffer,int rowstride,int bpp,int x1,int y1,int x2,i { int i,j; i=x1-x2; j=y1-y2; + if(i==0 && j==0) { + for(i=0;i<bpp;i++) + buffer[y1*rowstride+x1*bpp+i]=0xff; + return; + } if(i<0) i=-i; if(j<0) j=-j; if(i<j) { @@ -89,32 +94,34 @@ void drawline(unsigned char* buffer,int rowstride,int bpp,int x1,int y1,int x2,i void doptr(int buttonMask,int x,int y,rfbClientPtr cl) { ClientData* cd=cl->clientData; - if(buttonMask && x>=0 && y>=0 && x<maxx && y<maxy) { - int i,j,x1,x2,y1,y2; - - if(cd->oldButton==buttonMask) { /* draw a line */ - drawline(cl->screen->frameBuffer,cl->screen->paddedWidthInBytes,bpp, - x,y,cd->oldx,cd->oldy); - rfbMarkRectAsModified(cl->screen,x,y,cd->oldx,cd->oldy); - } else { /* draw a point (diameter depends on button) */ - x1=x-buttonMask; if(x1<0) x1=0; - x2=x+buttonMask; if(x2>maxx) x2=maxx; - y1=y-buttonMask; if(y1<0) y1=0; - y2=y+buttonMask; if(y2>maxy) y2=maxy; - - for(i=x1*bpp;i<x2*bpp;i++) - for(j=y1;j<y2;j++) - cl->screen->frameBuffer[j*cl->screen->paddedWidthInBytes+i]=0xff; - rfbMarkRectAsModified(cl->screen,x1,y1,x2-1,y2-1); - } + if(x>=0 && y>=0 && x<maxx && y<maxy) { + if(buttonMask) { + int i,j,x1,x2,y1,y2; + + if(cd->oldButton==buttonMask) { /* draw a line */ + drawline(cl->screen->frameBuffer,cl->screen->paddedWidthInBytes,bpp, + x,y,cd->oldx,cd->oldy); + rfbMarkRectAsModified(cl->screen,x,y,cd->oldx,cd->oldy); + } else { /* draw a point (diameter depends on button) */ + x1=x-buttonMask; if(x1<0) x1=0; + x2=x+buttonMask; if(x2>maxx) x2=maxx; + y1=y-buttonMask; if(y1<0) y1=0; + y2=y+buttonMask; if(y2>maxy) y2=maxy; - /* we could get a selection like that: - rfbGotXCutText(cl->screen,"Hallo",5); - */ - } else - cd->oldButton=0; + for(i=x1*bpp;i<x2*bpp;i++) + for(j=y1;j<y2;j++) + cl->screen->frameBuffer[j*cl->screen->paddedWidthInBytes+i]=0xff; + rfbMarkRectAsModified(cl->screen,x1,y1,x2-1,y2-1); + } - cd->oldx=x; cd->oldy=y; cd->oldButton=buttonMask; + /* we could get a selection like that: + rfbGotXCutText(cl->screen,"Hallo",5); + */ + } else + cd->oldButton=0; + + cd->oldx=x; cd->oldy=y; cd->oldButton=buttonMask; + } } /* aux function to draw a character to x, y */ @@ -196,6 +203,24 @@ void dokey(Bool down,KeySym key,rfbClientPtr cl) } } +/* +extern void rfbPrintXCursor(rfbCursorPtr cursor); +int exampleCursorWidth=9,exampleCursorHeight=7; +char exampleCursor[]= + " " + " xx xx " + " xx xx " + " xxx " + " xx xx " + " xx xx " + " "; +rfbCursorPtr exampleCurse; +rfbCursorPtr exampleGetCursor(rfbClientPtr cl) +{ + return(exampleCurse); +} +*/ + /* Initialization */ int main(int argc,char** argv) @@ -211,8 +236,31 @@ int main(int argc,char** argv) rfbScreen->httpDir = "./classes"; initBuffer(rfbScreen->frameBuffer); + drawstring(rfbScreen->frameBuffer,maxx*bpp,bpp,20,100,"Hello, World!"); - drawstring(rfbScreen->frameBuffer,maxx*bpp,bpp,20,100,"Hallo, Welt!"); + //exampleCurse = rfbMakeXCursor(exampleCursorWidth,exampleCursorHeight,exampleCursor,0); + { + int i,j,w=32,h=32; + rfbCursorPtr c = rfbScreen->cursor; + char x[32*32],mask[32*32/8]; + c=rfbScreen->cursor = rfbMakeXCursor(w,h,x,mask); + c->mask[0]=0xff; c->mask[1]=0x0; + memset(c->mask,255,h*w/8); + c->richSource = malloc(w*h*bpp); + for(j=0;j<h;j++) { + for(i=0;i<w;i++) { + c->richSource[j*w*bpp+i*bpp+0]=0; + c->richSource[j*w*bpp+i*bpp+1]=0; + c->richSource[j*w*bpp+i*bpp+2]=j*0xff/h; + c->richSource[j*w*bpp+i*bpp+3]=0; + } + c->richSource[j*w*bpp+(w-1)*bpp+0]=0xff; + c->richSource[j*w*bpp+(w-1)*bpp+1]=0xff; + c->richSource[j*w*bpp+(w-1)*bpp+2]=0xff; + c->richSource[j*w*bpp+(w-1)*bpp+3]=0xff; + } + //memset(c->richSource,0xff,w*h*bpp); + } /* this is the blocking event loop, i.e. it never returns */ /* 40000 are the microseconds, i.e. 0.04 seconds */ @@ -31,6 +31,8 @@ #include <fcntl.h> #include <errno.h> #include <pwd.h> +#include <arpa/inet.h> +#include <unistd.h> #include "rfb.h" @@ -99,7 +101,7 @@ httpInitSockets(rfbScreenInfoPtr rfbScreen) void httpCheckFds(rfbScreenInfoPtr rfbScreen) { - int nfds, n; + int nfds; fd_set fds; struct timeval tv; struct sockaddr_in addr; @@ -37,6 +37,7 @@ #endif #include <unistd.h> #include <signal.h> +#include <time.h> #include "rfb.h" @@ -93,8 +94,16 @@ void rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y RegionRec region; int i; if(x1>x2) { i=x1; x1=x2; x2=i; } + x2++; + if(x1<0) { x1=0; if(x2==x1) x2++; } + if(x2>=rfbScreen->width) { x2=rfbScreen->width-1; if(x1==x2) x1--; } + if(y1>y2) { i=y1; y1=y2; y2=i; } - box.x1=x1; box.y1=y1; box.x2=x2+1; box.y2=y2+1; + y2++; + if(y1<0) { y1=0; if(y2==y1) y2++; } + if(y2>=rfbScreen->height) { y2=rfbScreen->height-1; if(y1==y2) y1--; } + + box.x1=x1; box.y1=y1; box.x2=x2; box.y2=y2; REGION_INIT(cl->screen,®ion,&box,0); rfbMarkRegionAsModified(rfbScreen,®ion); } @@ -295,6 +304,38 @@ void defaultSetXCutText(char* text, int len, rfbClientPtr cl) { } +static rfbCursor myCursor = +{ + //width: 8, height: 7, xhot: 3, yhot: 3, + width: 8, height: 7, xhot: 0, yhot: 0, + //source: "\000\102\044\030\044\102\000", + //mask: "\347\347\176\074\176\347\347", + source: "\000\074\176\146\176\074\000", + mask: "\176\377\377\377\377\377\176", + foreRed: 0, foreGreen: 0, foreBlue: 0, + backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff, + #define D "\000\000\000\000" + #define R "\377\000\000\000" + #define G "\000\377\000\000" + #define B "\000\000\377\000" + #define S "\377\377\000\000" + #define H "\000\377\377\000" + #define C "\377\000\377\000" + richSource: 0 + /*D D D D D D D D + D D R R R R D D + D S S S S S S D + D G G D D G G D + D H H H H H H D + D D B B B B D D + D D D D D D D D*/ +}; + +rfbCursorPtr defaultGetCursorPtr(rfbClientPtr cl) +{ + return(cl->screen->cursor); +} + void doNothingWithClient(rfbClientPtr cl) { } @@ -348,15 +389,12 @@ rfbScreenInfoPtr rfbDefaultScreenInit(int argc,char** argv,int width,int height, rfbScreen->rfbServerFormat.redShift = bitsPerSample * 2; rfbScreen->rfbServerFormat.greenShift = bitsPerSample; rfbScreen->rfbServerFormat.blueShift = 0; -fprintf(stderr,"format: %d %d %d %d %d %d\n", - rfbScreen->rfbServerFormat.redMax, - rfbScreen->rfbServerFormat.greenMax, - rfbScreen->rfbServerFormat.blueMax, - rfbScreen->rfbServerFormat.redShift, - rfbScreen->rfbServerFormat.greenShift, - rfbScreen->rfbServerFormat.blueShift); - + rfbScreen->cursorIsDrawn = FALSE; + rfbScreen->dontSendFramebufferUpdate = FALSE; + rfbScreen->cursorX=rfbScreen->cursorY=rfbScreen->underCursorBufferLen=0; + rfbScreen->underCursorBuffer=NULL; + /* We want to use the X11 REGION_* macros without having an actual X11 ScreenPtr, so we do this. Pretty ugly, but at least it lets us avoid hacking up regionstr.h, or changing every call to REGION_* @@ -384,6 +422,8 @@ fprintf(stderr,"format: %d %d %d %d %d %d\n", rfbScreen->kbdReleaseAllKeys = doNothingWithClient; rfbScreen->ptrAddEvent = defaultPtrAddEvent; rfbScreen->setXCutText = defaultSetXCutText; + rfbScreen->getCursorPtr = defaultGetCursorPtr; + rfbScreen->cursor = &myCursor; rfbScreen->newClientHook = doNothingWithClient; return(rfbScreen); @@ -23,6 +23,8 @@ * USA. */ +#include <stdlib.h> +#include <string.h> #include "scrnintstr.h" /* trying to replace the above with some more minimal set of includes */ @@ -60,12 +62,14 @@ #endif struct rfbClientRec; -//typedef struct rfbClientInfo* rfbClientPtr; +struct rfbScreenInfo; +struct rfbCursor; + typedef void (*KbdAddEventProcPtr) (Bool down, KeySym keySym, struct rfbClientRec* cl); typedef void (*KbdReleaseAllKeysProcPtr) (struct rfbClientRec* cl); typedef void (*PtrAddEventProcPtr) (int buttonMask, int x, int y, struct rfbClientRec* cl); typedef void (*SetXCutTextProcPtr) (char* str,int len, struct rfbClientRec* cl); - +typedef struct rfbCursor* (*GetCursorProcPtr) (struct rfbClientRec* pScreen); typedef void (*NewClientHookPtr)(struct rfbClientRec* cl); /* @@ -125,7 +129,11 @@ typedef struct Bool cursorIsDrawn; /* TRUE if the cursor is currently drawn */ Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the cursor */ - + + /* these variables are needed to save the area under the cursor */ + int cursorX, cursorY,underCursorBufferLen; + char* underCursorBuffer; + /* wrapped screen functions */ CloseScreenProcPtr CloseScreen; @@ -167,14 +175,16 @@ typedef struct Bool rfbNeverShared; Bool rfbDontDisconnect; struct rfbClientRec* rfbClientHead; - + struct rfbCursor* cursor; + /* the following members have to be supplied by the serving process */ char* frameBuffer; KbdAddEventProcPtr kbdAddEvent; KbdReleaseAllKeysProcPtr kbdReleaseAllKeys; PtrAddEventProcPtr ptrAddEvent; SetXCutTextProcPtr setXCutText; - + GetCursorProcPtr getCursorPtr; + /* the following members are hooks, i.e. they are called if set, but not overriding original functionality */ /* newClientHook is called just after a new client is created */ @@ -513,8 +523,22 @@ extern Bool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h); /* cursor.c */ -extern Bool rfbSendCursorShape(rfbClientPtr cl, ScreenPtr pScreen); - +typedef struct rfbCursor { + unsigned char *source; /* points to bits */ + unsigned char *mask; /* points to bits */ + unsigned short width, height, xhot, yhot; /* metrics */ + unsigned short foreRed, foreGreen, foreBlue; /* device-independent color */ + unsigned short backRed, backGreen, backBlue; /* device-independent color */ + unsigned char *richSource; /* source bytes for a rich cursor */ +} rfbCursor, *rfbCursorPtr; + +extern Bool rfbSendCursorShape(rfbClientPtr cl/*, rfbScreenInfoPtr pScreen*/); +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); +extern void MakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor); +extern void MakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor); +extern void rfbFreeCursor(rfbCursorPtr cursor); /* stats.c */ diff --git a/rfbserver.c b/rfbserver.c index b90fb05..6f48cf1 100644 --- a/rfbserver.c +++ b/rfbserver.c @@ -221,6 +221,7 @@ rfbNewClient(rfbScreen,sock) cl->zsActive[i] = FALSE; cl->enableCursorShapeUpdates = FALSE; + cl->useRichCursorEncoding = FALSE; cl->enableLastRectEncoding = FALSE; rfbResetStats(cl); @@ -630,18 +631,15 @@ rfbProcessClientNormalMessage(cl) rfbLog("Enabling X-style cursor updates for client %s\n", cl->host); cl->enableCursorShapeUpdates = TRUE; - cl->useRichCursorEncoding = FALSE; cl->cursorWasChanged = TRUE; break; case rfbEncodingRichCursor: - if (!cl->enableCursorShapeUpdates) { - rfbLog("Enabling full-color cursor updates for client " - "%s\n", cl->host); - cl->enableCursorShapeUpdates = TRUE; - cl->useRichCursorEncoding = TRUE; - cl->cursorWasChanged = TRUE; - } - break; + rfbLog("Enabling full-color cursor updates for client " + "%s\n", cl->host); + cl->enableCursorShapeUpdates = TRUE; + cl->useRichCursorEncoding = TRUE; + cl->cursorWasChanged = TRUE; + break; case rfbEncodingLastRect: if (!cl->enableLastRectEncoding) { rfbLog("Enabling LastRect protocol extension for client " @@ -829,23 +827,24 @@ rfbSendFramebufferUpdate(cl, updateRegion) RegionRec updateCopyRegion; int dx, dy; Bool sendCursorShape = FALSE; + Bool cursorWasDrawn = FALSE; /* * If this client understands cursor shape updates, cursor should be * removed from the framebuffer. Otherwise, make sure it's put up. */ -#ifdef NOT_YET if (cl->enableCursorShapeUpdates) { - if (cl->screen->cursorIsDrawn) - rfbSpriteRemoveCursor(pScreen); - if (!cl->screen->cursorIsDrawn && cl->cursorWasChanged) - sendCursorShape = TRUE; + cursorWasDrawn = cl->screen->cursorIsDrawn; + if (cl->screen->cursorIsDrawn) { + fprintf(stderr,"rfbSpriteRemoveCursor(pScreen); not yet!\n"); + } + if (!cl->screen->cursorIsDrawn && cl->cursorWasChanged) + sendCursorShape = TRUE; } else { - if (!cl->screen->cursorIsDrawn) - rfbSpriteRestoreCursor(pScreen); + if (!cl->screen->cursorIsDrawn) + fprintf(stderr,"rfbSpriteRestoreCursor(pScreen); not yet!\n"); } -#endif /* * The modifiedRegion may overlap the destination copyRegion. We remove @@ -976,13 +975,11 @@ rfbSendFramebufferUpdate(cl, updateRegion) } cl->ublen = sz_rfbFramebufferUpdateMsg; -#ifdef NOT_YET if (sendCursorShape) { cl->cursorWasChanged = FALSE; - if (!rfbSendCursorShape(cl, pScreen)) + if (!rfbSendCursorShape(cl)) return FALSE; } -#endif if (REGION_NOTEMPTY(pScreen,&updateCopyRegion)) { if (!rfbSendCopyRegion(cl,&updateCopyRegion,dx,dy)) { @@ -1047,6 +1044,13 @@ rfbSendFramebufferUpdate(cl, updateRegion) if (!rfbSendUpdateBuf(cl)) return FALSE; + if(cursorWasDrawn != cl->screen->cursorIsDrawn) { + if(cursorWasDrawn) + fprintf(stderr,"rfbSpriteRestoreCursor(pScreen); not yet!!\n"); + else + fprintf(stderr,"rfbSpriteRemoveCursor(pScreen); not yet!!\n"); + } + return TRUE; } @@ -57,6 +57,7 @@ struct timeval #include <errno.h> #include <unistd.h> #include <pthread.h> +#include <arpa/inet.h> #include "rfb.h" @@ -235,8 +235,6 @@ rfbSendRectEncodingZlib(cl, x, y, w, h) rfbClientPtr cl; int x, y, w, h; { - int totalSize = 0; - int partialSize = 0; int maxLines; int linesRemaining; rfbRectangle partialRect; |