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
39static const int bpp=4;
40static 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... */
45static int maintain_connection = 1;
46
47/* This initializes a nice (?) background */
48
49static 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
67typedef struct ClientData {
71
72static void clientgone(rfbClientPtr cl)
73{
74 free(cl->clientData);
75 cl->clientData = NULL;
76}
77
78static 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
87static 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
104static 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
130static 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
174static 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
218static int exampleXCursorWidth=9,exampleXCursorHeight=7;
219static 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
232static 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
286void intHandler(int dummy) {
287 maintain_connection = 0;
288}
289
290/* Initialization */
291
292int 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