support for server side colour maps, fix for non-pthread, support for 3bpp

pull/1/head
dscho 23 years ago
parent aa8d2ae174
commit 095539cd8c

@ -2,11 +2,15 @@ INCLUDES=-I.
VNCSERVERLIB=-L. -lvncserver -L/usr/local/lib -lz -ljpeg
# Uncomment these two lines to enable use of PThreads
PTHREADDEF = -DHAVE_PTHREADS
PTHREADLIB = -lpthread
#PTHREADDEF = -DHAVE_PTHREADS
#PTHREADLIB = -lpthread
# Comment the following line to disable the use of 3 Bytes/Pixel.
# The code for 3 Bytes/Pixel is not very efficient!
FLAG24 = -DALLOW24BPP
#CC=cc
CFLAGS=-g -Wall $(PTHREADDEF) $(INCLUDES)
CFLAGS=-g -Wall $(PTHREADDEF) $(FLAG24) $(INCLUDES)
#CFLAGS=-O2 -Wall
RANLIB=ranlib
@ -34,6 +38,8 @@ install_OSX: OSXvnc-server
.c.o:
$(CC) $(CFLAGS) -c $<
$(OBJS): Makefile rfb.h
libvncserver.a: $(OBJS)
$(AR) cru $@ $(OBJS)
$(RANLIB) $@
@ -62,6 +68,11 @@ blooptest: blooptest.o libvncserver.a
blooptest.o: example.c
$(CC) $(CFLAGS) -DBACKGROUND_LOOP_TEST -c -o blooptest.o example.c
pnmshow24: pnmshow24.o libvncserver.a
$(CC) -o pnmshow24 pnmshow24.o $(LIBS)
pnmshow24.o: Makefile
clean:
rm -f $(OBJS) *~ core "#"* *.bak *.orig storepasswd.o \
mac.o example.o pnmshow.o sratest.o $(OBJS)

@ -48,8 +48,10 @@ To make a server, you just have to initialise a server structure using the
function rfbDefaultScreenInit, like
rfbScreenInfoPtr rfbScreen =
rfbGetScreen(argc,argv,width,height,8,3,bpp);
where byte per pixel is 1, 2 or 4. This is so because of speed considerations
(you can use native data types of that width).
where byte per pixel should be 1, 2 or 4. If performance doesn't matter,
you may try bpp=3 (internally one cannot use native data types in this
case; if you want to use this, look at pnmshow24).
You then can set hooks and io functions (see below) or other
options (see below).

@ -19,15 +19,18 @@ cursor "smears" sometimes when not using cursor encoding
(seems to be gone now; haven't debugged properly, though)
udp
autoconf? at least Sun Solaris compilation
rfbCloseClient, rfbConnect, ConnectToTcpAddr
rfbConnect, ConnectToTcpAddr
CORBA
translate.c: warning about non 8-bit colourmaps
set colourmap
documentation
done:
-----
.translate.c: warning about non 8-bit colourmaps
16-bit colourmaps are 192k -> no use without fast net.
.rfbCloseClient
.set colourmap
.support 3 bytes per pixel
.cursors
.cutpaste
.httpd

@ -315,6 +315,8 @@ int main(int argc,char** argv)
/* this is the blocking event loop, i.e. it never returns */
/* 40000 are the microseconds, i.e. 0.04 seconds */
rfbRunEventLoop(rfbScreen,40000,FALSE);
#elif !defined(HAVE_PTHREADS)
#error "I need pthreads for that."
#endif
/* this is the non-blocking event loop; a background thread is started */

@ -31,7 +31,7 @@
#include <time.h>
#include "rfb.h"
#include "region.h"
#include "sraRegion.h"
#ifdef HAVE_PTHREADS
pthread_mutex_t logMutex;
@ -75,10 +75,14 @@ void rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,sraRegionPtr modRegion)
iterator=rfbGetClientIterator(rfbScreen);
while((cl=rfbClientIteratorNext(iterator))) {
#ifdef HAVE_PTHREADS
pthread_mutex_lock(&cl->updateMutex);
#endif
sraRgnOr(cl->modifiedRegion,modRegion);
#ifdef HAVE_PTHREADS
pthread_cond_signal(&cl->updateCond);
pthread_mutex_unlock(&cl->updateMutex);
#endif
}
rfbReleaseClientIterator(iterator);
@ -353,7 +357,9 @@ rfbScreenInfoPtr rfbGetScreen(int argc,char** argv,
format->depth = rfbScreen->depth;
format->bigEndian = rfbEndianTest?FALSE:TRUE;
format->trueColour = TRUE;
rfbScreen->colourMap = NULL;
rfbScreen->colourMap.count = 0;
rfbScreen->colourMap.is16 = 0;
rfbScreen->colourMap.data.bytes = NULL;
if(bytesPerPixel == 8) {
format->redMax = 7;

24
rfb.h

@ -98,6 +98,15 @@ typedef struct rfbCursor* (*GetCursorProcPtr) (struct rfbClientRec* pScreen);
typedef Bool (*SetTranslateFunctionProcPtr)(struct rfbClientRec* cl);
typedef void (*NewClientHookPtr)(struct rfbClientRec* cl);
typedef struct {
int count;
Bool is16; /* is the data format short? */
union {
CARD8* bytes;
CARD16* shorts;
} data; /* there have to be count*3 entries */
} rfbColourMap;
/*
* Per-screen (framebuffer) structure. There is only one of these, since we
* don't allow the X server to have multiple screens.
@ -184,7 +193,7 @@ typedef struct
ScreenRec screen;
*/
rfbPixelFormat rfbServerFormat;
CARD16* colourMap; /* set this if rfbServerFormat.trueColour==FALSE */
rfbColourMap colourMap; /* set this if rfbServerFormat.trueColour==FALSE */
char* desktopName;
char rfbThisHost[255];
int rfbPort;
@ -453,6 +462,9 @@ typedef struct rfbClientRec {
#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
#define Swap24(l) ((((l) & 0xff) << 16) | (((l) >> 16) & 0xff) | \
(((l) & 0x00ff00)))
#define Swap32(l) (((l) >> 24) | \
(((l) & 0x00ff0000) >> 8) | \
(((l) & 0x0000ff00) << 8) | \
@ -462,7 +474,7 @@ typedef struct rfbClientRec {
static const int rfbEndianTest = (_BYTE_ORDER == _LITTLE_ENDIAN);
#define Swap16IfLE(s) (rfbEndianTest ? Swap16(s) : (s))
#define Swap24IfLE(l) (rfbEndianTest ? Swap24(l) : (l))
#define Swap32IfLE(l) (rfbEndianTest ? Swap32(l) : (l))
/* main.c */
@ -511,6 +523,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 rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour, int nColours);
void rfbGotXCutText(rfbScreenInfoPtr rfbScreen, char *str, int len);
@ -524,7 +537,8 @@ extern void rfbTranslateNone(char *table, rfbPixelFormat *in,
int bytesBetweenInputLines,
int width, int height);
extern Bool rfbSetTranslateFunction(rfbClientPtr cl);
extern Bool rfbSetClientColourMap(rfbClientPtr cl, int firstColour, int nColours);
extern void rfbSetClientColourMaps(rfbScreenInfoPtr rfbScreen, int firstColour, int nColours);
/* httpd.c */
@ -595,8 +609,8 @@ 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 short foreRed, foreGreen, foreBlue; /* device-independent colour */
unsigned short backRed, backGreen, backBlue; /* device-independent colour */
unsigned char *richSource; /* source bytes for a rich cursor */
#ifdef HAVE_PTHREADS
pthread_mutex_t mutex;

@ -26,7 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "rfb.h"
#include "region.h"
#include "sraRegion.h"
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
@ -699,7 +699,6 @@ rfbProcessClientNormalMessage(cl)
#endif
sraRgnOr(cl->requestedRegion,tmpRegion);
#ifdef NOT_YET
if (!cl->readyForSetColourMapEntries) {
/* client hasn't sent a SetPixelFormat so is using server's */
cl->readyForSetColourMapEntries = TRUE;
@ -710,7 +709,6 @@ rfbProcessClientNormalMessage(cl)
}
}
}
#endif
if (!msg.fur.incremental) {
sraRgnOr(cl->modifiedRegion,tmpRegion);
@ -1221,7 +1219,6 @@ rfbSendUpdateBuf(cl)
return TRUE;
}
#ifdef NOT_YET
/*
* rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
* client, using values from the currently installed colormap.
@ -1236,7 +1233,8 @@ rfbSendSetColourMapEntries(cl, firstColour, nColours)
char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
EntryPtr pent;
rfbColourMap* cm = &cl->screen->colourMap;
int i, len;
scme->type = rfbSetColourMapEntries;
@ -1246,30 +1244,29 @@ rfbSendSetColourMapEntries(cl, firstColour, nColours)
len = sz_rfbSetColourMapEntriesMsg;
pent = (EntryPtr)&rfbInstalledColormap->red[firstColour];
for (i = 0; i < nColours; i++) {
if (pent->fShared) {
rgb[i*3] = Swap16IfLE(pent->co.shco.red->color);
rgb[i*3+1] = Swap16IfLE(pent->co.shco.green->color);
rgb[i*3+2] = Swap16IfLE(pent->co.shco.blue->color);
if(i<cm->count) {
if(cm->is16) {
rgb[i*3] = Swap16IfLE(cm->data.shorts[i*3]);
rgb[i*3+1] = Swap16IfLE(cm->data.shorts[i*3+1]);
rgb[i*3+2] = Swap16IfLE(cm->data.shorts[i*3+2]);
} else {
rgb[i*3] = Swap16IfLE(pent->co.local.red);
rgb[i*3+1] = Swap16IfLE(pent->co.local.green);
rgb[i*3+2] = Swap16IfLE(pent->co.local.blue);
rgb[i*3] = Swap16IfLE(cm->data.bytes[i*3]);
rgb[i*3+1] = Swap16IfLE(cm->data.bytes[i*3+1]);
rgb[i*3+2] = Swap16IfLE(cm->data.bytes[i*3+2]);
}
}
pent++;
}
len += nColours * 3 * 2;
if (WriteExact(cl->sock, buf, len) < 0) {
if (WriteExact(cl, buf, len) < 0) {
rfbLogPerror("rfbSendSetColourMapEntries: write");
rfbCloseClient(cl);
return FALSE;
}
return TRUE;
}
#endif
/*
* rfbSendBell sends a Bell message to all the clients.

@ -276,14 +276,17 @@ void
rfbCloseClient(cl)
rfbClientPtr cl;
{
#ifdef HAVE_PTHREADS
pthread_mutex_lock(&cl->updateMutex);
#endif
FD_CLR(cl->sock,&(cl->screen->allFds));
close(cl->sock);
cl->sock = -1;
#ifdef HAVE_PTHREADS
pthread_cond_signal(&cl->updateCond);
//pthread_mutex_lock(&cl->updateMutex);
//rfbClientConnectionGone(cl);
pthread_mutex_unlock(&cl->updateMutex);
#endif
}

@ -43,39 +43,39 @@
CONCAT2E(rfbInitColourMapSingleTable,OUT)
static void
rfbInitColourMapSingleTableOUT (char **table, rfbPixelFormat *in,
rfbPixelFormat *out)
rfbInitColourMapSingleTableOUT(char **table, rfbPixelFormat *in,
rfbPixelFormat *out,rfbColourMap* colourMap)
{
int i, r, g, b;
CARD32 i, r, g, b;
OUT_T *t;
EntryPtr pent;
int nEntries = 1 << in->bitsPerPixel;
int shift = colourMap->is16?16:8;
if (*table) free(*table);
*table = (char *)malloc(nEntries * sizeof(OUT_T));
t = (OUT_T *)*table;
pent = (EntryPtr)&rfbInstalledColormap->red[0];
for (i = 0; i < nEntries; i++) {
if (pent->fShared) {
r = pent->co.shco.red->color;
g = pent->co.shco.green->color;
b = pent->co.shco.blue->color;
r = g = b = 0;
if(i < colourMap->count) {
if(colourMap->is16) {
r = colourMap->data.shorts[3*i+0];
g = colourMap->data.shorts[3*i+1];
b = colourMap->data.shorts[3*i+2];
} else {
r = pent->co.local.red;
g = pent->co.local.green;
b = pent->co.local.blue;
r = colourMap->data.bytes[3*i+0];
g = colourMap->data.bytes[3*i+1];
b = colourMap->data.bytes[3*i+2];
}
}
t[i] = ((((r * out->redMax + 32767) / 65535) << out->redShift) |
(((g * out->greenMax + 32767) / 65535) << out->greenShift) |
(((b * out->blueMax + 32767) / 65535) << out->blueShift));
t[i] = ((((r * (1 + out->redMax)) >> shift) << out->redShift) |
(((g * (1 + out->greenMax)) >> shift) << out->greenShift) |
(((b * (1 + out->blueMax)) >> shift) << out->blueShift));
#if (OUT != 8)
if (out->bigEndian != in->bigEndian) {
t[i] = SwapOUT(t[i]);
}
#endif
pent++;
}
}

@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "rfb.h"
#include "sraRegion.h"
static void PrintPixelFormat(rfbPixelFormat *pf);
static Bool rfbSetClientColourMapBGR233();
@ -63,6 +64,7 @@ static const rfbPixelFormat BGR233Format = {
#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
#define OUT 8
#include "tableinitcmtemplate.c"
#include "tableinittctemplate.c"
#define IN 8
#include "tabletranstemplate.c"
@ -76,6 +78,7 @@ static const rfbPixelFormat BGR233Format = {
#undef OUT
#define OUT 16
#include "tableinitcmtemplate.c"
#include "tableinittctemplate.c"
#define IN 8
#include "tabletranstemplate.c"
@ -89,6 +92,7 @@ static const rfbPixelFormat BGR233Format = {
#undef OUT
#define OUT 32
#include "tableinitcmtemplate.c"
#include "tableinittctemplate.c"
#define IN 8
#include "tabletranstemplate.c"
@ -101,42 +105,110 @@ static const rfbPixelFormat BGR233Format = {
#undef IN
#undef OUT
#ifdef ALLOW24BPP
#define COUNT_OFFSETS 4
#define BPP2OFFSET(bpp) ((bpp)/8-1)
#include "tableinit24.c"
#define BPP 8
#include "tabletrans24template.c"
#undef BPP
#define BPP 16
#include "tabletrans24template.c"
#undef BPP
#define BPP 24
#include "tabletrans24template.c"
#undef BPP
#define BPP 32
#include "tabletrans24template.c"
#undef BPP
#else
#define COUNT_OFFSETS 3
#define BPP2OFFSET(bpp) ((int)(bpp)/16)
#endif
typedef void (*rfbInitCMTableFnType)(char **table, rfbPixelFormat *in,
rfbPixelFormat *out,rfbColourMap* cm);
typedef void (*rfbInitTableFnType)(char **table, rfbPixelFormat *in,
rfbPixelFormat *out);
rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = {
rfbInitCMTableFnType rfbInitColourMapSingleTableFns[COUNT_OFFSETS] = {
rfbInitColourMapSingleTable8,
rfbInitColourMapSingleTable16,
#ifdef ALLOW24BPP
rfbInitColourMapSingleTable24,
#endif
rfbInitColourMapSingleTable32
};
rfbInitTableFnType rfbInitTrueColourSingleTableFns[COUNT_OFFSETS] = {
rfbInitTrueColourSingleTable8,
rfbInitTrueColourSingleTable16,
#ifdef ALLOW24BPP
rfbInitTrueColourSingleTable24,
#endif
rfbInitTrueColourSingleTable32
};
rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = {
rfbInitTableFnType rfbInitTrueColourRGBTablesFns[COUNT_OFFSETS] = {
rfbInitTrueColourRGBTables8,
rfbInitTrueColourRGBTables16,
#ifdef ALLOW24BPP
rfbInitTrueColourRGBTables24,
#endif
rfbInitTrueColourRGBTables32
};
rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = {
rfbTranslateFnType rfbTranslateWithSingleTableFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
{ rfbTranslateWithSingleTable8to8,
rfbTranslateWithSingleTable8to16,
#ifdef ALLOW24BPP
rfbTranslateWithSingleTable8to24,
#endif
rfbTranslateWithSingleTable8to32 },
{ rfbTranslateWithSingleTable16to8,
rfbTranslateWithSingleTable16to16,
#ifdef ALLOW24BPP
rfbTranslateWithSingleTable16to24,
#endif
rfbTranslateWithSingleTable16to32 },
#ifdef ALLOW24BPP
{ rfbTranslateWithSingleTable24to8,
rfbTranslateWithSingleTable24to16,
rfbTranslateWithSingleTable24to24,
rfbTranslateWithSingleTable24to32 },
#endif
{ rfbTranslateWithSingleTable32to8,
rfbTranslateWithSingleTable32to16,
#ifdef ALLOW24BPP
rfbTranslateWithSingleTable32to24,
#endif
rfbTranslateWithSingleTable32to32 }
};
rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = {
rfbTranslateFnType rfbTranslateWithRGBTablesFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
{ rfbTranslateWithRGBTables8to8,
rfbTranslateWithRGBTables8to16,
#ifdef ALLOW24BPP
rfbTranslateWithRGBTables8to24,
#endif
rfbTranslateWithRGBTables8to32 },
{ rfbTranslateWithRGBTables16to8,
rfbTranslateWithRGBTables16to16,
#ifdef ALLOW24BPP
rfbTranslateWithRGBTables16to24,
#endif
rfbTranslateWithRGBTables16to32 },
#ifdef ALLOW24BPP
{ rfbTranslateWithRGBTables24to8,
rfbTranslateWithRGBTables24to16,
rfbTranslateWithRGBTables24to24,
rfbTranslateWithRGBTables24to32 },
#endif
{ rfbTranslateWithRGBTables32to8,
rfbTranslateWithRGBTables32to16,
#ifdef ALLOW24BPP
rfbTranslateWithRGBTables32to24,
#endif
rfbTranslateWithRGBTables32to32 }
};
@ -179,6 +251,9 @@ rfbSetTranslateFunction(cl)
if ((cl->screen->rfbServerFormat.bitsPerPixel != 8) &&
(cl->screen->rfbServerFormat.bitsPerPixel != 16) &&
#ifdef ALLOW24BPP
(cl->screen->rfbServerFormat.bitsPerPixel != 24) &&
#endif
(cl->screen->rfbServerFormat.bitsPerPixel != 32))
{
rfbLog("%s: server bits per pixel not 8, 16 or 32\n",
@ -189,6 +264,9 @@ rfbSetTranslateFunction(cl)
if ((cl->format.bitsPerPixel != 8) &&
(cl->format.bitsPerPixel != 16) &&
#ifdef ALLOW24BPP
(cl->format.bitsPerPixel != 24) &&
#endif
(cl->format.bitsPerPixel != 32))
{
rfbLog("%s: client bits per pixel not 8, 16 or 32\n",
@ -235,28 +313,34 @@ rfbSetTranslateFunction(cl)
}
if ((cl->screen->rfbServerFormat.bitsPerPixel < 16) ||
(!rfbEconomicTranslate && (cl->screen->rfbServerFormat.bitsPerPixel == 16))) {
((!cl->screen->rfbServerFormat.trueColour || !rfbEconomicTranslate) &&
(cl->screen->rfbServerFormat.bitsPerPixel == 16))) {
/* we can use a single lookup table for <= 16 bpp */
cl->translateFn = rfbTranslateWithSingleTableFns
[cl->screen->rfbServerFormat.bitsPerPixel / 16]
[cl->format.bitsPerPixel / 16];
[BPP2OFFSET(cl->screen->rfbServerFormat.bitsPerPixel)]
[BPP2OFFSET(cl->format.bitsPerPixel)];
if(cl->screen->rfbServerFormat.trueColour)
(*rfbInitTrueColourSingleTableFns
[cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable,
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
&(cl->screen->rfbServerFormat), &cl->format);
else
(*rfbInitColourMapSingleTableFns
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
&(cl->screen->rfbServerFormat), &cl->format,&cl->screen->colourMap);
} else {
/* otherwise we use three separate tables for red, green and blue */
cl->translateFn = rfbTranslateWithRGBTablesFns
[cl->screen->rfbServerFormat.bitsPerPixel / 16]
[cl->format.bitsPerPixel / 16];
[BPP2OFFSET(cl->screen->rfbServerFormat.bitsPerPixel)]
[BPP2OFFSET(cl->format.bitsPerPixel)];
(*rfbInitTrueColourRGBTablesFns
[cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable,
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
&(cl->screen->rfbServerFormat), &cl->format);
}
@ -280,7 +364,7 @@ rfbSetClientColourMapBGR233(cl)
int i, len;
int r, g, b;
if (cl->format.bitsPerPixel != 8) {
if (cl->format.bitsPerPixel != 8 ) {
rfbLog("%s: client not 8 bits per pixel\n",
"rfbSetClientColourMapBGR233");
rfbCloseClient(cl);
@ -316,7 +400,9 @@ rfbSetClientColourMapBGR233(cl)
return TRUE;
}
#ifdef NOT_YET
/* this function is not called very often, so it needn't be
efficient. */
/*
* rfbSetClientColourMap is called to set the client's colour map. If the
* client is a true colour client, we simply update our own translation table
@ -329,26 +415,22 @@ rfbSetClientColourMap(cl, firstColour, nColours)
int firstColour;
int nColours;
{
EntryPtr pent;
int i, r, g, b;
BoxRec box;
if (nColours == 0) {
nColours = rfbInstalledColormap->pVisual->ColormapEntries;
if (cl->screen->rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) {
return TRUE;
}
if (rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) {
return TRUE;
if (nColours == 0) {
nColours = cl->screen->colourMap.count;
}
if (cl->format.trueColour) {
(*rfbInitColourMapSingleTableFns
[cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable,
&rfbServerFormat, &cl->format);
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
&cl->screen->rfbServerFormat, &cl->format,&cl->screen->colourMap);
sraRgnDestroy(cl->modifiedRegion);
cl->modifiedRegion =
sraRgnCreateRect(0,0,rfbScreen.width,rfbScreen.height);
sraRgnCreateRect(0,0,cl->screen->width,cl->screen->height);
return TRUE;
}
@ -374,7 +456,6 @@ rfbSetClientColourMaps(rfbScreen, firstColour, nColours)
rfbSetClientColourMap(cl, firstColour, nColours);
}
}
#endif
static void
PrintPixelFormat(pf)

Loading…
Cancel
Save