LibVNCServer/LibVNCClient
example.c
Go to the documentation of this file.
1 
24 #ifdef WIN32
25 #define sleep Sleep
26 #else
27 #include <unistd.h>
28 #endif
29 
30 #ifdef __IRIX__
31 #include <netdb.h>
32 #endif
33 
34 #include <signal.h>
35 
36 #include <rfb/rfb.h>
37 #include <rfb/keysym.h>
38 
39 static const int bpp=4;
40 static int maxx=800, maxy=600;
41 /* TODO: odd maxx doesn't work (vncviewer bug) */
42 
43 /* Flag used for threaded mode that's global so we can set it via
44  a signal handler... */
45 static int maintain_connection = 1;
46 
47 /* This initializes a nice (?) background */
48 
49 static void initBuffer(unsigned char* buffer)
50 {
51  int i,j;
52  for(j=0;j<maxy;++j) {
53  for(i=0;i<maxx;++i) {
54  buffer[(j*maxx+i)*bpp+0]=(i+j)*128/(maxx+maxy); /* red */
55  buffer[(j*maxx+i)*bpp+1]=i*128/maxx; /* green */
56  buffer[(j*maxx+i)*bpp+2]=j*256/maxy; /* blue */
57  }
58  buffer[j*maxx*bpp+0]=0xff;
59  buffer[j*maxx*bpp+1]=0xff;
60  buffer[j*maxx*bpp+2]=0xff;
61  buffer[j*maxx*bpp+3]=0xff;
62  }
63 }
64 
65 /* Here we create a structure so that every client has its own pointer */
66 
67 typedef struct ClientData {
69  int oldx,oldy;
70 } ClientData;
71 
72 static void clientgone(rfbClientPtr cl)
73 {
74  free(cl->clientData);
75  cl->clientData = NULL;
76 }
77 
78 static enum rfbNewClientAction newclient(rfbClientPtr cl)
79 {
80  cl->clientData = (void*)calloc(sizeof(ClientData),1);
81  cl->clientGoneHook = clientgone;
82  return RFB_CLIENT_ACCEPT;
83 }
84 
85 /* switch to new framebuffer contents */
86 
87 static void newframebuffer(rfbScreenInfoPtr screen, int width, int height)
88 {
89  unsigned char *oldfb, *newfb;
90 
91  maxx = width;
92  maxy = height;
93  oldfb = (unsigned char*)screen->frameBuffer;
94  newfb = (unsigned char*)malloc(maxx * maxy * bpp);
95  initBuffer(newfb);
96  rfbNewFramebuffer(screen, (char*)newfb, maxx, maxy, 8, 3, bpp);
97  free(oldfb);
98 
99  /*** FIXME: Re-install cursor. ***/
100 }
101 
102 /* aux function to draw a line */
103 
104 static void drawline(unsigned char* buffer,int rowstride,int bpp,int x1,int y1,int x2,int y2)
105 {
106  int i,j;
107  i=x1-x2; j=y1-y2;
108  if(i==0 && j==0) {
109  for(i=0;i<bpp;i++)
110  buffer[y1*rowstride+x1*bpp+i]=0xff;
111  return;
112  }
113  if(i<0) i=-i;
114  if(j<0) j=-j;
115  if(i<j) {
116  if(y1>y2) { i=y2; y2=y1; y1=i; i=x2; x2=x1; x1=i; }
117  for(j=y1;j<=y2;j++)
118  for(i=0;i<bpp;i++)
119  buffer[j*rowstride+(x1+(j-y1)*(x2-x1)/(y2-y1))*bpp+i]=0xff;
120  } else {
121  if(x1>x2) { i=y2; y2=y1; y1=i; i=x2; x2=x1; x1=i; }
122  for(i=x1;i<=x2;i++)
123  for(j=0;j<bpp;j++)
124  buffer[(y1+(i-x1)*(y2-y1)/(x2-x1))*rowstride+i*bpp+j]=0xff;
125  }
126 }
127 
128 /* Here the pointer events are handled */
129 
130 static void doptr(int buttonMask,int x,int y,rfbClientPtr cl)
131 {
132  ClientData* cd=cl->clientData;
133 
134  if(x>=0 && y>=0 && x<maxx && y<maxy) {
135  if(buttonMask) {
136  int i,j,x1,x2,y1,y2;
137 
138  if(cd->oldButton==buttonMask) { /* draw a line */
139  drawline((unsigned char*)cl->screen->frameBuffer,cl->screen->paddedWidthInBytes,bpp,
140  x,y,cd->oldx,cd->oldy);
141  x1=x; y1=y;
142  if(x1>cd->oldx) x1++; else cd->oldx++;
143  if(y1>cd->oldy) y1++; else cd->oldy++;
144  rfbMarkRectAsModified(cl->screen,x,y,cd->oldx,cd->oldy);
145  } else { /* draw a point (diameter depends on button) */
146  int w=cl->screen->paddedWidthInBytes;
147  x1=x-buttonMask; if(x1<0) x1=0;
148  x2=x+buttonMask; if(x2>maxx) x2=maxx;
149  y1=y-buttonMask; if(y1<0) y1=0;
150  y2=y+buttonMask; if(y2>maxy) y2=maxy;
151 
152  for(i=x1*bpp;i<x2*bpp;i++)
153  for(j=y1;j<y2;j++)
154  cl->screen->frameBuffer[j*w+i]=(char)0xff;
155  rfbMarkRectAsModified(cl->screen,x1,y1,x2,y2);
156  }
157 
158  /* we could get a selection like that:
159  rfbGotXCutText(cl->screen,"Hallo",5);
160  */
161  }
162 
163  cd->oldx=x; cd->oldy=y; cd->oldButton=buttonMask;
164  }
165  rfbDefaultPtrAddEvent(buttonMask,x,y,cl);
166 }
167 
168 /* aux function to draw a character to x, y */
169 
170 #include "radon.h"
171 
172 /* Here the key events are handled */
173 
174 static void dokey(rfbBool down,rfbKeySym key,rfbClientPtr cl)
175 {
176  if(down) {
177  if(key==XK_Escape)
178  rfbCloseClient(cl);
179  else if(key==XK_F12)
180  /* close down server, disconnecting clients */
181  rfbShutdownServer(cl->screen,TRUE);
182  else if(key==XK_F11)
183  /* close down server, but wait for all clients to disconnect */
184  rfbShutdownServer(cl->screen,FALSE);
185  else if(key==XK_Page_Up) {
186  initBuffer((unsigned char*)cl->screen->frameBuffer);
187  rfbMarkRectAsModified(cl->screen,0,0,maxx,maxy);
188  } else if (key == XK_Up) {
189  if (maxx < 1024) {
190  if (maxx < 800) {
191  newframebuffer(cl->screen, 800, 600);
192  } else {
193  newframebuffer(cl->screen, 1024, 768);
194  }
195  }
196  } else if(key==XK_Down) {
197  if (maxx > 640) {
198  if (maxx > 800) {
199  newframebuffer(cl->screen, 800, 600);
200  } else {
201  newframebuffer(cl->screen, 640, 480);
202  }
203  }
204  } else if(key>=' ' && key<0x100) {
205  ClientData* cd=cl->clientData;
206  int x1=cd->oldx,y1=cd->oldy,x2,y2;
207  cd->oldx+=rfbDrawCharWithClip(cl->screen,&radonFont,cd->oldx,cd->oldy,(char)key,0,0,cl->screen->width,cl->screen->height,0x00ffffff,0x00ffffff);
208  rfbFontBBox(&radonFont,(char)key,&x1,&y1,&x2,&y2);
209  rfbMarkRectAsModified(cl->screen,x1,y1,x2-1,y2-1);
210  }
211  }
212 }
213 
214 /* Example for an XCursor (foreground/background only) */
215 
216 #ifdef JUST_AN_EXAMPLE
217 
218 static int exampleXCursorWidth=9,exampleXCursorHeight=7;
219 static char exampleXCursor[]=
220  " "
221  " xx xx "
222  " xx xx "
223  " xxx "
224  " xx xx "
225  " xx xx "
226  " ";
227 
228 #endif
229 
230 /* Example for a rich cursor (full-colour) */
231 
232 static void MakeRichCursor(rfbScreenInfoPtr rfbScreen)
233 {
234  int i,j,w=32,h=32;
235  rfbCursorPtr c;
236  char bitmap[]=
237  " "
238  " xxxxxx "
239  " xxxxxxxxxxxxxxxxx "
240  " xxxxxxxxxxxxxxxxxxxxxx "
241  " xxxxx xxxxxxxx xxxxxxxx "
242  " xxxxxxxxxxxxxxxxxxxxxxxxxxx "
243  " xxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
244  " xxxxx xxxxxxxxxxx xxxxxxx "
245  " xxxx xxxxxxxxx xxxxxx "
246  " xxxxx xxxxxxxxxxx xxxxxxx "
247  " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
248  " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
249  " xxxxxxxxxxxx xxxxxxxxxxxxxxx "
250  " xxxxxxxxxxxxxxxxxxxxxxxxxxxx "
251  " xxxxxxxxxxxxxxxxxxxxxxxxxxxx "
252  " xxxxxxxxxxx xxxxxxxxxxxxxx "
253  " xxxxxxxxxx xxxxxxxxxxxx "
254  " xxxxxxxxx xxxxxxxxx "
255  " xxxxxxxxxx xxxxxxxxx "
256  " xxxxxxxxxxxxxxxxxxx "
257  " xxxxxxxxxxxxxxxxxxx "
258  " xxxxxxxxxxxxxxxxxxx "
259  " xxxxxxxxxxxxxxxxx "
260  " xxxxxxxxxxxxxxx "
261  " xxxx xxxxxxxxxxxxx "
262  " xx x xxxxxxxxxxx "
263  " xxx xxxxxxxxxxx "
264  " xxxx xxxxxxxxxxx "
265  " xxxxxx xxxxxxxxxxxx "
266  " xxxxxxxxxxxxxxxxxxxxxx "
267  " xxxxxxxxxxxxxxxx "
268  " ";
269  c=rfbScreen->cursor = rfbMakeXCursor(w,h,bitmap,bitmap);
270  c->xhot = 16; c->yhot = 24;
271 
272  c->richSource = (unsigned char*)malloc(w*h*bpp);
273  if(!c->richSource)
274  return;
275  c->cleanupRichSource = TRUE;
276  for(j=0;j<h;j++) {
277  for(i=0;i<w;i++) {
278  c->richSource[j*w*bpp+i*bpp+0]=i*0xff/w;
279  c->richSource[j*w*bpp+i*bpp+1]=(i+j)*0xff/(w+h);
280  c->richSource[j*w*bpp+i*bpp+2]=j*0xff/h;
281  c->richSource[j*w*bpp+i*bpp+3]=0;
282  }
283  }
284 }
285 
286 void intHandler(int dummy) {
287  maintain_connection = 0;
288 }
289 
290 /* Initialization */
291 
292 int main(int argc,char** argv)
293 {
294  rfbScreenInfoPtr rfbScreen = rfbGetScreen(&argc,argv,maxx,maxy,8,3,bpp);
295  if(!rfbScreen)
296  return 1;
297  rfbScreen->desktopName = "LibVNCServer Example";
298  rfbScreen->frameBuffer = (char*)malloc(maxx*maxy*bpp);
299  rfbScreen->alwaysShared = TRUE;
300  rfbScreen->ptrAddEvent = doptr;
301  rfbScreen->kbdAddEvent = dokey;
302  rfbScreen->newClientHook = newclient;
303  rfbScreen->httpDir = "../webclients";
304  rfbScreen->httpEnableProxyConnect = TRUE;
305 
306  initBuffer((unsigned char*)rfbScreen->frameBuffer);
307  rfbDrawString(rfbScreen,&radonFont,20,100,"Hello, World!",0xffffff);
308 
309  /* This call creates a mask and then a cursor: */
310  /* rfbScreen->defaultCursor =
311  rfbMakeXCursor(exampleCursorWidth,exampleCursorHeight,exampleCursor,0);
312  */
313 
314  MakeRichCursor(rfbScreen);
315 
316  /* initialize the server */
317  rfbInitServer(rfbScreen);
318 
319 #ifndef BACKGROUND_LOOP_TEST
320 #ifdef USE_OWN_LOOP
321  {
322  int i;
323  for(i=0;rfbIsActive(rfbScreen);i++) {
324  fprintf(stderr,"%d\r",i);
325  rfbProcessEvents(rfbScreen,100000);
326  }
327  }
328 #else
329  /* this is the blocking event loop, i.e. it never returns */
330  /* 40000 are the microseconds to wait on select(), i.e. 0.04 seconds */
331  rfbRunEventLoop(rfbScreen,40000,FALSE);
332 #endif /* OWN LOOP */
333 #else
334 #if !defined(LIBVNCSERVER_HAVE_LIBPTHREAD) && !defined(LIBVNCSERVER_HAVE_WIN32THREADS)
335 #error "I need pthreads or win32 threads for that."
336 #endif
337  /* catch Ctrl-C to set a flag for the main thread */
338  signal(SIGINT, intHandler);
339  /* this is the non-blocking event loop; a background thread is started */
340  rfbRunEventLoop(rfbScreen,-1,TRUE);
341  fprintf(stderr, "Running background loop...\n");
342  /* now we could do some cool things like rendering in idle time */
343  while (maintain_connection) {
344  sleep(5); /* render(); */
345  }
346  fprintf(stderr, "\nShutting down...\n");
347  rfbShutdownServer(rfbScreen, TRUE);
348 #endif /* BACKGROUND_LOOP */
349 
350  free(rfbScreen->frameBuffer);
351  rfbScreenCleanup(rfbScreen);
352 
353  return(0);
354 }
int y
Definition: SDLvncviewer.c:34
int x
Definition: SDLvncviewer.c:34
void intHandler(int dummy)
Definition: example.c:286
int main(int argc, char **argv)
Definition: example.c:292
void rfbInitServer(rfbScreenInfoPtr rfbScreen)
void rfbRunEventLoop(rfbScreenInfoPtr screenInfo, long usec, rfbBool runInBackground)
int rfbDrawCharWithClip(rfbScreenInfoPtr rfbScreen, rfbFontDataPtr font, int x, int y, unsigned char c, int x1, int y1, int x2, int y2, rfbPixel colour, rfbPixel backColour)
if colour==backColour, background is transparent
void rfbCloseClient(rfbClientPtr cl)
void rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen, int x1, int y1, int x2, int y2)
void rfbShutdownServer(rfbScreenInfoPtr rfbScreen, rfbBool disconnectClients)
void rfbDefaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
cursor handling for the pointer
void rfbScreenCleanup(rfbScreenInfoPtr screenInfo)
rfbScreenInfoPtr rfbGetScreen(int *argc, char **argv, int width, int height, int bitsPerSample, int samplesPerPixel, int bytesPerPixel)
rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo)
rfbBool rfbProcessEvents(rfbScreenInfoPtr screenInfo, long usec)
void rfbDrawString(rfbScreenInfoPtr rfbScreen, rfbFontDataPtr font, int x, int y, const char *string, rfbPixel colour)
void rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen, char *framebuffer, int width, int height, int bitsPerSample, int samplesPerPixel, int bytesPerPixel)
rfbCursorPtr rfbMakeXCursor(int width, int height, char *cursorString, char *maskString)
void rfbFontBBox(rfbFontDataPtr font, unsigned char c, int *x1, int *y1, int *x2, int *y2)
rfbNewClientAction
Definition: rfb.h:91
@ RFB_CLIENT_ACCEPT
Definition: rfb.h:92
#define XK_F11
Definition: keysym.h:259
#define XK_Down
Definition: keysym.h:173
#define XK_F12
Definition: keysym.h:261
#define XK_Escape
Definition: keysym.h:131
#define XK_Up
Definition: keysym.h:171
#define XK_Page_Up
Definition: keysym.h:175
int8_t rfbBool
Definition: rfbproto.h:108
uint32_t rfbKeySym
Definition: rfbproto.h:122
#define TRUE
Definition: rfbproto.h:112
#define FALSE
Definition: rfbproto.h:110
int oldx
Definition: example.c:69
rfbBool oldButton
Definition: example.c:68
int oldy
Definition: example.c:69
#define height
Definition: vncev.c:19
#define width
Definition: vncev.c:18