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