1/** 2 * @example example.c 3 * This is an example of how to use libvncserver. 4 * 5 * libvncserver example 6 * Copyright (C) 2001 Johannes E. Schindelin <Johannes.Schindelin@gmx.de> 7 * 8 * This is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This software is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this software; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 21 * USA. 22 */ 23 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 <rfb/rfb.h> 35#include <rfb/keysym.h> 36 37static const int bpp=4; 38static int maxx=800, maxy=600; 39/* TODO: odd maxx doesn't work (vncviewer bug) */ 40 41/* This initializes a nice (?) background */ 42 43static void initBuffer(unsigned char* buffer) 44{ 45 int i,j; 46 for(j=0;j<maxy;++j) { 47 for(i=0;i<maxx;++i) { 48 buffer[(j*maxx+i)*bpp+0]=(i+j)*128/(maxx+maxy); /* red */ 49 buffer[(j*maxx+i)*bpp+1]=i*128/maxx; /* green */ 50 buffer[(j*maxx+i)*bpp+2]=j*256/maxy; /* blue */ 51 } 52 buffer[j*maxx*bpp+0]=0xff; 53 buffer[j*maxx*bpp+1]=0xff; 54 buffer[j*maxx*bpp+2]=0xff; 55 buffer[j*maxx*bpp+3]=0xff; 56 } 57} 58 59/* Here we create a structure so that every client has it's own pointer */ 60 61typedef struct ClientData { 62 rfbBool oldButton; 63 int oldx,oldy; 64} ClientData; 65 66static void clientgone(rfbClientPtr cl) 67{ 68 free(cl->clientData); 69} 70 71static enum rfbNewClientAction newclient(rfbClientPtr cl) 72{ 73 cl->clientData = (void*)calloc(sizeof(ClientData),1); 74 cl->clientGoneHook = clientgone; 75 return RFB_CLIENT_ACCEPT; 76} 77 78/* switch to new framebuffer contents */ 79 80static void newframebuffer(rfbScreenInfoPtr screen, int width, int height) 81{ 82 unsigned char *oldfb, *newfb; 83 84 maxx = width; 85 maxy = height; 86 oldfb = (unsigned char*)screen->frameBuffer; 87 newfb = (unsigned char*)malloc(maxx * maxy * bpp); 88 initBuffer(newfb); 89 rfbNewFramebuffer(screen, (char*)newfb, maxx, maxy, 8, 3, bpp); 90 free(oldfb); 91 92 /*** FIXME: Re-install cursor. ***/ 93} 94 95/* aux function to draw a line */ 96 97static void drawline(unsigned char* buffer,int rowstride,int bpp,int x1,int y1,int x2,int y2) 98{ 99 int i,j; 100 i=x1-x2; j=y1-y2; 101 if(i==0 && j==0) { 102 for(i=0;i<bpp;i++) 103 buffer[y1*rowstride+x1*bpp+i]=0xff; 104 return; 105 } 106 if(i<0) i=-i; 107 if(j<0) j=-j; 108 if(i<j) { 109 if(y1>y2) { i=y2; y2=y1; y1=i; i=x2; x2=x1; x1=i; } 110 for(j=y1;j<=y2;j++) 111 for(i=0;i<bpp;i++) 112 buffer[j*rowstride+(x1+(j-y1)*(x2-x1)/(y2-y1))*bpp+i]=0xff; 113 } else { 114 if(x1>x2) { i=y2; y2=y1; y1=i; i=x2; x2=x1; x1=i; } 115 for(i=x1;i<=x2;i++) 116 for(j=0;j<bpp;j++) 117 buffer[(y1+(i-x1)*(y2-y1)/(x2-x1))*rowstride+i*bpp+j]=0xff; 118 } 119} 120 121/* Here the pointer events are handled */ 122 123static void doptr(int buttonMask,int x,int y,rfbClientPtr cl) 124{ 125 ClientData* cd=cl->clientData; 126 127 if(x>=0 && y>=0 && x<maxx && y<maxy) { 128 if(buttonMask) { 129 int i,j,x1,x2,y1,y2; 130 131 if(cd->oldButton==buttonMask) { /* draw a line */ 132 drawline((unsigned char*)cl->screen->frameBuffer,cl->screen->paddedWidthInBytes,bpp, 133 x,y,cd->oldx,cd->oldy); 134 x1=x; y1=y; 135 if(x1>cd->oldx) x1++; else cd->oldx++; 136 if(y1>cd->oldy) y1++; else cd->oldy++; 137 rfbMarkRectAsModified(cl->screen,x,y,cd->oldx,cd->oldy); 138 } else { /* draw a point (diameter depends on button) */ 139 int w=cl->screen->paddedWidthInBytes; 140 x1=x-buttonMask; if(x1<0) x1=0; 141 x2=x+buttonMask; if(x2>maxx) x2=maxx; 142 y1=y-buttonMask; if(y1<0) y1=0; 143 y2=y+buttonMask; if(y2>maxy) y2=maxy; 144 145 for(i=x1*bpp;i<x2*bpp;i++) 146 for(j=y1;j<y2;j++) 147 cl->screen->frameBuffer[j*w+i]=(char)0xff; 148 rfbMarkRectAsModified(cl->screen,x1,y1,x2,y2); 149 } 150 151 /* we could get a selection like that: 152 rfbGotXCutText(cl->screen,"Hallo",5); 153 */ 154 } else 155 cd->oldButton=0; 156 157 cd->oldx=x; cd->oldy=y; cd->oldButton=buttonMask; 158 } 159 rfbDefaultPtrAddEvent(buttonMask,x,y,cl); 160} 161 162/* aux function to draw a character to x, y */ 163 164#include "radon.h" 165 166/* Here the key events are handled */ 167 168static void dokey(rfbBool down,rfbKeySym key,rfbClientPtr cl) 169{ 170 if(down) { 171 if(key==XK_Escape) 172 rfbCloseClient(cl); 173 else if(key==XK_F12) 174 /* close down server, disconnecting clients */ 175 rfbShutdownServer(cl->screen,TRUE); 176 else if(key==XK_F11) 177 /* close down server, but wait for all clients to disconnect */ 178 rfbShutdownServer(cl->screen,FALSE); 179 else if(key==XK_Page_Up) { 180 initBuffer((unsigned char*)cl->screen->frameBuffer); 181 rfbMarkRectAsModified(cl->screen,0,0,maxx,maxy); 182 } else if (key == XK_Up) { 183 if (maxx < 1024) { 184 if (maxx < 800) { 185 newframebuffer(cl->screen, 800, 600); 186 } else { 187 newframebuffer(cl->screen, 1024, 768); 188 } 189 } 190 } else if(key==XK_Down) { 191 if (maxx > 640) { 192 if (maxx > 800) { 193 newframebuffer(cl->screen, 800, 600); 194 } else { 195 newframebuffer(cl->screen, 640, 480); 196 } 197 } 198 } else if(key>=' ' && key<0x100) { 199 ClientData* cd=cl->clientData; 200 int x1=cd->oldx,y1=cd->oldy,x2,y2; 201 cd->oldx+=rfbDrawCharWithClip(cl->screen,&radonFont,cd->oldx,cd->oldy,(char)key,0,0,cl->screen->width,cl->screen->height,0x00ffffff,0x00ffffff); 202 rfbFontBBox(&radonFont,(char)key,&x1,&y1,&x2,&y2); 203 rfbMarkRectAsModified(cl->screen,x1,y1,x2-1,y2-1); 204 } 205 } 206} 207 208/* Example for an XCursor (foreground/background only) */ 209 210#ifdef JUST_AN_EXAMPLE 211 212static int exampleXCursorWidth=9,exampleXCursorHeight=7; 213static char exampleXCursor[]= 214 " " 215 " xx xx " 216 " xx xx " 217 " xxx " 218 " xx xx " 219 " xx xx " 220 " "; 221 222#endif 223 224/* Example for a rich cursor (full-colour) */ 225 226static void MakeRichCursor(rfbScreenInfoPtr rfbScreen) 227{ 228 int i,j,w=32,h=32; 229 rfbCursorPtr c = rfbScreen->cursor; 230 char bitmap[]= 231 " " 232 " xxxxxx " 233 " xxxxxxxxxxxxxxxxx " 234 " xxxxxxxxxxxxxxxxxxxxxx " 235 " xxxxx xxxxxxxx xxxxxxxx " 236 " xxxxxxxxxxxxxxxxxxxxxxxxxxx " 237 " xxxxxxxxxxxxxxxxxxxxxxxxxxxxx " 238 " xxxxx xxxxxxxxxxx xxxxxxx " 239 " xxxx xxxxxxxxx xxxxxx " 240 " xxxxx xxxxxxxxxxx xxxxxxx " 241 " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx " 242 " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx " 243 " xxxxxxxxxxxx xxxxxxxxxxxxxxx " 244 " xxxxxxxxxxxxxxxxxxxxxxxxxxxx " 245 " xxxxxxxxxxxxxxxxxxxxxxxxxxxx " 246 " xxxxxxxxxxx xxxxxxxxxxxxxx " 247 " xxxxxxxxxx xxxxxxxxxxxx " 248 " xxxxxxxxx xxxxxxxxx " 249 " xxxxxxxxxx xxxxxxxxx " 250 " xxxxxxxxxxxxxxxxxxx " 251 " xxxxxxxxxxxxxxxxxxx " 252 " xxxxxxxxxxxxxxxxxxx " 253 " xxxxxxxxxxxxxxxxx " 254 " xxxxxxxxxxxxxxx " 255 " xxxx xxxxxxxxxxxxx " 256 " xx x xxxxxxxxxxx " 257 " xxx xxxxxxxxxxx " 258 " xxxx xxxxxxxxxxx " 259 " xxxxxx xxxxxxxxxxxx " 260 " xxxxxxxxxxxxxxxxxxxxxx " 261 " xxxxxxxxxxxxxxxx " 262 " "; 263 c=rfbScreen->cursor = rfbMakeXCursor(w,h,bitmap,bitmap); 264 c->xhot = 16; c->yhot = 24; 265 266 c->richSource = (unsigned char*)malloc(w*h*bpp); 267 c->cleanupRichSource = TRUE; 268 for(j=0;j<h;j++) { 269 for(i=0;i<w;i++) { 270 c->richSource[j*w*bpp+i*bpp+0]=i*0xff/w; 271 c->richSource[j*w*bpp+i*bpp+1]=(i+j)*0xff/(w+h); 272 c->richSource[j*w*bpp+i*bpp+2]=j*0xff/h; 273 c->richSource[j*w*bpp+i*bpp+3]=0; 274 } 275 } 276} 277 278/* Initialization */ 279 280int main(int argc,char** argv) 281{ 282 rfbScreenInfoPtr rfbScreen = rfbGetScreen(&argc,argv,maxx,maxy,8,3,bpp); 283 if(!rfbScreen) 284 return 0; 285 rfbScreen->desktopName = "LibVNCServer Example"; 286 rfbScreen->frameBuffer = (char*)malloc(maxx*maxy*bpp); 287 rfbScreen->alwaysShared = TRUE; 288 rfbScreen->ptrAddEvent = doptr; 289 rfbScreen->kbdAddEvent = dokey; 290 rfbScreen->newClientHook = newclient; 291 rfbScreen->httpDir = "../webclients"; 292 rfbScreen->httpEnableProxyConnect = TRUE; 293 294 initBuffer((unsigned char*)rfbScreen->frameBuffer); 295 rfbDrawString(rfbScreen,&radonFont,20,100,"Hello, World!",0xffffff); 296 297 /* This call creates a mask and then a cursor: */ 298 /* rfbScreen->defaultCursor = 299 rfbMakeXCursor(exampleCursorWidth,exampleCursorHeight,exampleCursor,0); 300 */ 301 302 MakeRichCursor(rfbScreen); 303 304 /* initialize the server */ 305 rfbInitServer(rfbScreen); 306 307#ifndef BACKGROUND_LOOP_TEST 308#ifdef USE_OWN_LOOP 309 { 310 int i; 311 for(i=0;rfbIsActive(rfbScreen);i++) { 312 fprintf(stderr,"%d\r",i); 313 rfbProcessEvents(rfbScreen,100000); 314 } 315 } 316#else 317 /* this is the blocking event loop, i.e. it never returns */ 318 /* 40000 are the microseconds to wait on select(), i.e. 0.04 seconds */ 319 rfbRunEventLoop(rfbScreen,40000,FALSE); 320#endif /* OWN LOOP */ 321#else 322#if !defined(LIBVNCSERVER_HAVE_LIBPTHREAD) 323#error "I need pthreads for that." 324#endif 325 326 /* this is the non-blocking event loop; a background thread is started */ 327 rfbRunEventLoop(rfbScreen,-1,TRUE); 328 fprintf(stderr, "Running background loop...\n"); 329 /* now we could do some cool things like rendering in idle time */ 330 while(1) sleep(5); /* render(); */ 331#endif /* BACKGROUND_LOOP */ 332 333 free(rfbScreen->frameBuffer); 334 rfbScreenCleanup(rfbScreen); 335 336 return(0); 337} 338