I have written a VNC server extension to VirtualBox. After requesting this feature in the Bug tracker (http://www.virtualbox.org/ticket/6020), I decided to see whether I could write it myself.

The result is currently part of the VBoxHeadless application and implemented in a shared library (much like, and based on, the FFMPEG extension).

I am willing to release any of my (modified) source code under the MIT license, however, the required VNC server library (libvncserver, http://libvncserver.sourceforge.net/) is distributed under the GPL license.

The diff/patch file is attached (patch -p1, please). I hope this patch can somehow be useful.

Thank you all very much for your work on VirtualBox - I love it.

Best regards,

Ivo Smits

diff -crBN -x '*~' org-3.1.2/src/VBox/Frontends/VBoxHeadless/Makefile.kmk vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/Makefile.kmk
*** org-3.1.2/src/VBox/Frontends/VBoxHeadless/Makefile.kmk	2009-12-17 15:27:56.000000000 +0100
--- vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/Makefile.kmk	2010-01-21 17:04:13.504384395 +0100
***************
*** 26,31 ****
--- 26,32 ----
  ifdef VBOX_WITH_FFMPEG
   include $(PATH_SUB_CURRENT)/VideoCapture/Makefile.kmk
  endif
+ include $(PATH_SUB_CURRENT)/VNC/Makefile.kmk
  
  #
  # Targets.
diff -crBN -x '*~' org-3.1.2/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
*** org-3.1.2/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp	2009-12-17 15:27:56.000000000 +0100
--- vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp	2010-01-22 01:33:02.454944089 +0100
***************
*** 356,361 ****
--- 356,364 ----
  {
      RTPrintf("Usage:\n"
               "   -s, -startvm, --startvm <name|uuid>   Start given VM (required argument)\n"
+              "   -n, -vnc                              Enable the built in VNC server\n"
+              "   -m, -vncport                          TCP port number to use for the VNC server\n"
+              "   -o, -vncpass <pw>                     Set the VNC server password\n"
  #ifdef VBOX_WITH_VRDP
               "   -v, -vrdp, --vrdp on|off|config       Enable (default) or disable the VRDP\n"
               "                                         server or don't change the setting\n"
***************
*** 427,432 ****
--- 430,438 ----
   */
  extern "C" DECLEXPORT (int) TrustedMain (int argc, char **argv, char **envp)
  {
+     int vncEnable = false;
+     int vncPort = 0; //default port
+     char* vncPass = NULL; //no password
  #ifdef VBOX_WITH_VRDP
      const char *vrdpPort = NULL;
      const char *vrdpAddress = NULL;
***************
*** 482,487 ****
--- 488,496 ----
      {
          { "-startvm", 's', RTGETOPT_REQ_STRING },
          { "--startvm", 's', RTGETOPT_REQ_STRING },
+         { "-vncport", 'm', RTGETOPT_REQ_INT32 },
+         { "-vncpass", 'o', RTGETOPT_REQ_STRING },
+         { "-vnc", 'n', 0 },
  #ifdef VBOX_WITH_VRDP
          { "-vrdpport", 'p', RTGETOPT_REQ_STRING },
          { "--vrdpport", 'p', RTGETOPT_REQ_STRING },
***************
*** 533,538 ****
--- 542,550 ----
                  if (!id)
                      name = ValueUnion.psz;
                  break;
+ 	    case 'n': vncEnable = true; break;
+ 	    case 'm': vncPort = ValueUnion.i32; break;
+ 	    case 'o': vncPass = (char*)ValueUnion.psz; break;
  #ifdef VBOX_WITH_VRDP
              case 'p':
                  vrdpPort = ValueUnion.psz;
***************
*** 721,731 ****
          ComPtr <IDisplay> display;
          CHECK_ERROR_BREAK(console, COMGETTER(Display) (display.asOutParam()));
  
! #ifdef VBOX_FFMPEG
          IFramebuffer *pFramebuffer = 0;
          RTLDRMOD hLdrFFmpegFB;
          PFNREGISTERFFMPEGFB pfnRegisterFFmpegFB;
  
          if (fFFMPEG)
          {
              int rrc = VINF_SUCCESS, rcc = S_OK;
--- 733,749 ----
          ComPtr <IDisplay> display;
          CHECK_ERROR_BREAK(console, COMGETTER(Display) (display.asOutParam()));
  
! 	/* These two variables shouldn't harm, we use the same variables for the VNC framebuffer
! 	 * Careful! The Framebuffer has to be released some time, so if both FFMPEG and VNC would
! 	 * be allowed one day, make sure to release them both! For now it is save to re-use these,
! 	 * as both extensions are mutually exclusive. */
          IFramebuffer *pFramebuffer = 0;
          RTLDRMOD hLdrFFmpegFB;
+ #ifdef VBOX_FFMPEG
          PFNREGISTERFFMPEGFB pfnRegisterFFmpegFB;
  
+ 	if (fFFMPEG && vncEnable) LogError("Sorry, the VNC server and FFMPEG capturing are currently mutually exclusive.\n", E_FAIL);
+ 
          if (fFFMPEG)
          {
              int rrc = VINF_SUCCESS, rcc = S_OK;
***************
*** 767,772 ****
--- 785,817 ----
          }
  #endif /* defined(VBOX_FFMPEG) */
  
+ 	if (vncEnable) {
+ 	        PFNREGISTERVNCFB pfnRegisterVNCFB;
+ 		int rrc = VINF_SUCCESS, rcc = S_OK;
+ 		rrc = SUPR3HardenedLdrLoadAppPriv("VBoxVNC", &hLdrFFmpegFB); //We borrow this variable from the FFMPEG code
+ 		if (RT_SUCCESS(rrc)) {
+ 			rrc = RTLdrGetSymbol(hLdrFFmpegFB, "VBoxRegisterVNCFB",
+                                      reinterpret_cast<void **>(&pfnRegisterVNCFB));
+                 if (RT_FAILURE(rrc))
+                     LogError("Failed to load the vnc server extension, possibly due to a damaged file\n", rrc);
+ 	        } else {
+                     LogError("Failed to load the vnc server extension\n", rrc);
+ 	        }
+                 if (RT_SUCCESS(rrc)) {
+         	        rcc = pfnRegisterVNCFB(console, vncPort, vncPass, &pFramebuffer); //We re-use the framebuffer variable as well
+                 if (rcc != S_OK)
+                     LogError("Failed to initialise video capturing - make sure that the file format\n"
+                              "you wish to use is supported on your system\n", rcc);
+             }
+             if (RT_SUCCESS(rrc) && (S_OK == rcc)) {
+                 Log2(("VBoxHeadless: Registering VNC framebuffer\n"));
+                 pFramebuffer->AddRef();
+                 display->SetFramebuffer(VBOX_VIDEO_PRIMARY_SCREEN, pFramebuffer);
+             }
+             if (!RT_SUCCESS(rrc) || (rcc != S_OK)) rc = E_FAIL;
+         }
+         if (rc != S_OK) break;
+ 
          ULONG cMonitors = 1;
          machine->COMGETTER(MonitorCount)(&cMonitors);
  
diff -crBN -x '*~' org-3.1.2/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.h vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.h
*** org-3.1.2/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.h	2009-12-17 15:27:56.000000000 +0100
--- vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.h	2010-01-22 00:32:45.454947483 +0100
***************
*** 50,53 ****
--- 50,56 ----
                                       IFramebuffer **retVal);
  typedef FNREGISTERFFMPEGFB *PFNREGISTERFFMPEGFB;
  
+ typedef DECLCALLBACK(HRESULT) FNREGISTERVNCFB(ComPtr <IConsole> console, int port, char* password, IFramebuffer **retVal);
+ typedef FNREGISTERVNCFB *PFNREGISTERVNCFB;
+ 
  #endif // __H_VBOXVRDP
diff -crBN -x '*~' org-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/Makefile.kmk vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/Makefile.kmk
*** org-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/Makefile.kmk	1970-01-01 01:00:00.000000000 +0100
--- vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/Makefile.kmk	2010-01-21 17:05:36.124385715 +0100
***************
*** 0 ****
--- 1,37 ----
+ # $Id: Makefile.kmk $
+ ## @file
+ # Sub-Makefile for the ffmpeg frame buffer module.
+ #
+ 
+ #
+ # Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ # Copyright (C) 2010 Ivo Smits <[email protected]>
+ #
+ # This file is part of VirtualBox Open Source Edition (OSE), as
+ # available from http://www.virtualbox.org. This file is free software;
+ # you can redistribute it and/or modify it under the terms of the GNU
+ # General Public License (GPL) as published by the Free Software
+ # Foundation, in version 2 as it comes in the "COPYING" file of the
+ # VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ # hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ #
+ # Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ # Clara, CA 95054 USA or visit http://www.sun.com if you need
+ # additional information or have any questions.
+ #
+ 
+ SUB_DEPTH = ../../../../..
+ include $(KBUILD_PATH)/subheader.kmk
+ 
+ SDK_VBOX_VNC = VNC server library
+ SDK_VBOX_VNC_INCS = /usr/include/
+ SDK_VBOX_VNC_LIBS = vncserver
+ 
+ DLLS += VBoxVNC
+ VBoxVNC_TEMPLATE        = VBOXMAINCLIENTDLL
+ VBoxVNC_SDKS            = VBOX_VNC
+ VBoxVNC_SOURCES         = VNC.cpp
+ #VBoxVNC_CXXFLAGS.linux += -fPIC
+ 
+ include $(KBUILD_PATH)/subfooter.kmk
+ 
diff -crBN -x '*~' org-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/VNC.cpp vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/VNC.cpp
*** org-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/VNC.cpp	1970-01-01 01:00:00.000000000 +0100
--- vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/VNC.cpp	2010-01-22 01:09:01.570944453 +0100
***************
*** 0 ****
--- 1,603 ----
+ /** @file
+  * VNC server implementation for VirtualBox
+  * based on libvncserver and the VirtualBox FFMPEG framebuffer
+  */
+ 
+ /*
+  * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+  * Copyright (C) 2010 Ivo Smits <[email protected]>
+  *
+  * This file is part of VirtualBox Open Source Edition (OSE), as
+  * available from http://www.virtualbox.org. This file is free software;
+  * you can redistribute it and/or modify it under the terms of the GNU
+  * General Public License (GPL) as published by the Free Software
+  * Foundation, in version 2 as it comes in the "COPYING" file of the
+  * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+  *
+  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+  * Clara, CA 95054 USA or visit http://www.sun.com if you need
+  * additional information or have any questions.
+  */
+ 
+ #include "VNC.h"
+ 
+ #include <iprt/file.h>
+ #include <iprt/param.h>
+ #include <iprt/assert.h>
+ #include <VBox/log.h>
+ #include <png.h>
+ #include <iprt/stream.h>
+ 
+ #include <rfb/rfb.h>
+ #include <pthread.h>
+ 
+ // external constructor for dynamic loading
+ /////////////////////////////////////////////////////////////////////////////
+ 
+ /**
+  * Callback function to register an ffmpeg framebuffer.
+  *
+  * @returns COM status code.
+  * @param   width        Framebuffer width.
+  * @param   height       Framebuffer height.
+  * @param   bitrate      Bitrate of mpeg file to be created.
+  * @param   filename     Name of mpeg file to be created
+  * @retval  retVal       The new framebuffer
+  */
+ extern "C" DECLEXPORT(HRESULT) VBoxRegisterVNCFB(ComPtr <IConsole> console, int port, char* password, IFramebuffer **retVal) {
+ 	Log2(("VBoxRegisterVNCFB: called\n"));
+ 	VNCFB *pFramebuffer = new VNCFB(console, port, password);
+ 	int rc = pFramebuffer->init();
+ 	AssertMsg(rc == S_OK, ("failed to initialise the VNC framebuffer, rc = %d\n", rc));
+ 	if (rc == S_OK) {
+ 		*retVal = pFramebuffer;
+ 		return S_OK;
+ 	}
+ 	delete pFramebuffer;
+ 	return rc;
+ }
+ 
+ // constructor / destructor
+ /////////////////////////////////////////////////////////////////////////////
+ 
+ /**
+  * Perform parts of initialisation which are guaranteed not to fail
+  * unless we run out of memory.  In this case, we just set the guest
+  * buffer to 0 so that RequestResize() does not free it the first time
+  * it is called.
+  */
+ VNCFB::VNCFB(ComPtr <IConsole> console, int port, char* password) :
+     mConsole(console),
+     mPixelFormat(FramebufferPixelFormat_Opaque),
+     mBitsPerPixel(0),
+     mBytesPerLine(0),
+     mRGBBuffer(0),
+     mScreenBuffer(0),
+     mKeyboard(0),
+     mMouse(0),
+     mWidth(800), mHeight(600),
+     mVncPort(port),
+     vncServer(0),
+     vncPassword(password) {
+ 
+     LogFlow(("Creating VNC object %p, width=%lu, height=%lu, port=%u\n",
+              this, (unsigned long) width,  (unsigned long) height, port));
+ }
+ 
+ 
+ VNCFB::~VNCFB() {
+     LogFlow(("Destroying VNCFB object %p\n", this));
+     RTCritSectDelete(&mCritSect);
+     if (vncServer) {
+ 	if (vncServer->authPasswdData) {
+ 	    char** passwords = (char**)vncServer->authPasswdData;
+ 	    vncServer->authPasswdData = NULL;
+ 	    if (passwords[0]) free(passwords[0]);
+ 	    free(passwords);
+ 	}
+         rfbScreenCleanup(vncServer);
+     }
+     if (mRGBBuffer) RTMemFree(mRGBBuffer);
+     if (mScreenBuffer) RTMemFree(mScreenBuffer);
+ }
+ 
+ HRESULT VNCFB::init() {
+     LogFlow(("Initialising VNCFB object %p\n", this));
+     int rc = RTCritSectInit(&mCritSect);
+     AssertReturn(rc == VINF_SUCCESS, E_UNEXPECTED);
+ 
+     vncServer = rfbGetScreen(0, NULL, mWidth, mHeight, 8, 3, 1);
+     vncServer->screenData = (void*)this;
+     if (mVncPort) vncServer->port = mVncPort;
+     vncServer->desktopName = "VirtualBox";
+ 
+     if (vncPassword) {
+ 	char** passwords = (char**)malloc(1 * sizeof(char**));
+ 	passwords[0] = (char*)malloc(strlen(vncPassword));
+ 	strcpy(passwords[0], vncPassword);
+ 	vncServer->authPasswdData = passwords;
+         vncServer->passwordCheck = rfbCheckPasswordByList; //Password list based authentication
+     } else {
+ 	vncServer->authPasswdData = NULL;
+     }
+ 
+     rfbInitServer(vncServer);
+     vncServer->kbdAddEvent = vncKeyboardEvent;
+     vncServer->kbdReleaseAllKeys = vncReleaseKeysEvent;
+     vncServer->ptrAddEvent = vncMouseEvent;
+ 
+     /* Set the initial framebuffer size */
+     BOOL finished;
+     RequestResize(0, FramebufferPixelFormat_Opaque, NULL, 0, 0, mWidth, mHeight, &finished);
+ 
+     rc = pthread_create(&vncThread, NULL, vncFunc, vncServer);
+     AssertReturn(rc == VINF_SUCCESS, E_UNEXPECTED);
+ 
+     return rc;
+ }
+ 
+ void* VNCFB::vncFunc(void* arg) {
+     rfbRunEventLoop((rfbScreenInfoPtr)arg,-1,FALSE);
+     return NULL;
+ }
+ 
+ void VNCFB::vncMouseEvent(int buttonMask, int x, int y, rfbClientPtr cl) {
+ 	((VNCFB*)(cl->screen->screenData))->handleVncMouseEvent(buttonMask, x, y);
+ 	rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
+ }
+ 
+ void VNCFB::handleVncMouseEvent(int buttonMask, int x, int y) {
+ 	//RTPrintf("VNC mouse: button=%d x=%d y=%d\n", buttonMask, x, y);
+ 	if (!mMouse) {
+ 		this->mConsole->COMGETTER(Mouse)(mMouse.asOutParam());
+ 		if (!mMouse) {
+ 			RTPrintf("Warning: could not get mouse object!\n");
+ 			return;
+ 		}
+ 	}
+ 	int dz = 0, buttons = 0;
+ 	if (buttonMask & 16) dz = 1; else if (buttonMask & 8) dz = -1;
+ 	if (buttonMask & 1) buttons |= 1;
+ 	if (buttonMask & 2) buttons |= 4;
+ 	if (buttonMask & 4) buttons |= 2;
+ 	mMouse->PutMouseEvent(x - mouseX, y - mouseY, dz, 0, buttons);
+ 	//mMouse->PutMouseEventAbsolute(x + 1, y + 1, dz, 0, buttonMask);
+ 	mouseX = x;
+ 	mouseY = y;
+ }
+ 
+ void VNCFB::kbdPutCode(int code) {
+ 	mKeyboard->PutScancode(code);
+ }
+ void VNCFB::kbdSetShift(int state) {
+ 	if (state && !kbdShiftState) {
+ 		kbdPutCode(0x2a, 1);
+ 		kbdShiftState = 1;
+ 	} else if (!state && kbdShiftState) {
+ 		kbdPutCode(0x2a, 0);
+ 		kbdShiftState = 0;
+ 	}
+ }
+ void VNCFB::kbdPutCode(int code, int down) {
+ 	if (code & 0xff00) kbdPutCode((code >> 8) & 0xff);
+ 	kbdPutCode((code & 0xff) | (down ? 0 : 0x80));
+ }
+ void VNCFB::kbdPutCodeShift(int shift, int code, int down) {
+ 	if (shift != kbdShiftState) kbdPutCode(0x2a, shift);
+ 	kbdPutCode(code, down);
+ 	if (shift != kbdShiftState) kbdPutCode(0x2a, kbdShiftState);
+ }
+ 
+ /* Handle VNC keyboard code (X11 compatible?) to AT scancode conversion.
+  * Have tried the code from the SDL frontend, but that didn't work.
+  * Now we're using one lookup table for the lower X11 key codes (ASCII characters)
+  * and a switch() block to handle some special keys. */
+ void VNCFB::handleVncKeyboardEvent(int down, int keycode) {
+ 	//RTPrintf("VNC keyboard: down=%d code=%d -> ", down, keycode);
+ 	if (mKeyboard == NULL) {
+ 		this->mConsole->COMGETTER(Keyboard)(mKeyboard.asOutParam());
+ 		if (!mKeyboard) {
+ 			RTPrintf("Warning: could not get keyboard object!\n");
+ 			return;
+ 		}
+ 	}
+ 	/* Conversion table for key code range 32-127 (which happen to equal the ASCII codes)
+ 	 * The values in the table differ slightly from the actual scancode values that will be sent,
+ 	 * values 0xe0?? indicate that a 0xe0 scancode will be sent first (extended keys), then code ?? is sent
+ 	 * values 0x01?? indicate that the shift key must be 'down', then ?? is sent
+ 	 * values 0x00?? or 0x?? indicate that the shift key must be 'up', then ?? is sent
+ 	 * values 0x02?? indicate that the shift key can be ignored, and scancode ?? is sent
+ 	 * This is necessary because the VNC protocol sends a shift key sequence, but also
+ 	 * sends the 'shifted' version of the characters. */
+ 	static int codes_low[] = { //Conversion table for VNC key code range 32-127
+ 		0x0239, 0x0102, 0x0128, 0x0104, 0x0105, 0x0106, 0x0108, 0x0028, 0x010a, 0x010b, 0x0109, 0x010d, 0x0029, 0x000c, 0x0034, 0x0035, //space, !"#$%&'()*+`-./
+ 		0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, //0123456789
+ 		0x0127, 0x0027, 0x0133, 0x000d, 0x0134, 0x0135, 0x0103, //:;<=>?@
+ 		0x11e, 0x130, 0x12e, 0x120, 0x112, 0x121, 0x122, 0x123, 0x117, 0x124, 0x125, 0x126, 0x132, 0x131, 0x118, 0x119, 0x110, 0x113, 0x11f, 0x114, 0x116, 0x12f, 0x111, 0x12d, 0x115, 0x12c, //A-Z
+ 		0x001a, 0x002b, 0x001b, 0x0107, 0x010c, 0x0029, //[\]^_`
+ 		0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, //a-z
+ 		0x011a, 0x012b, 0x011b, 0x0129 //{|}~
+ 	};
+ 	int shift = -1, code = -1;
+ 	if (keycode < 32) { //ASCII control codes.. unused..
+ 	} else if (keycode < 127) { //DEL is in high area
+ 		code = codes_low[keycode - 32];
+ 		shift = (code >> 8) & 0x03; if (shift == 0x02 || code & 0xe000) shift = -1;
+ 		code = code & 0xe0ff;
+ 	} else if ((keycode & 0xFF00) != 0xFF00) {
+ 	} else {
+ 		switch(keycode) {
+ /*Numpad keys - these have to be implemented yet
+ Todo: numpad arrows, home, pageup, pagedown, end, insert, delete
+ 65421 Numpad return
+ 
+ 65450 Numpad *
+ 65451 Numpad +
+ 65453 Numpad -
+ 65454 Numpad .
+ 65455 Numpad /
+ 65457 Numpad 1
+ 65458 Numpad 2
+ 65459 Numpad 3
+ 
+ 65460 Numpad 4
+ 65461 Numpad 5
+ 65462 Numpad 6
+ 65463 Numpad 7
+ 65464 Numpad 8
+ 65465 Numpad 9
+ 65456 Numpad 0
+ */
+ 			case 65288: code =   0x0e; break; //Backspace
+ 			case 65289: code =   0x0f; break; //Tab
+ 
+ 			case 65293: code =   0x1c; break; //Return
+ 			//case 65299: break; Pause/break
+ 			case 65307: code =   0x01; break; //Escape
+ 
+ 			case 65360: code = 0xe047; break; //Home
+ 			case 65361: code = 0xe04b; break; //Left
+ 			case 65362: code = 0xe048; break; //Up
+ 			case 65363: code = 0xe04d; break; //Right
+ 			case 65364: code = 0xe050; break; //Down
+ 			case 65365: code = 0xe049; break; //Page up
+ 			case 65366: code = 0xe051; break; //Page down
+ 			case 65367: code = 0xe04f; break; //End
+ 
+ 			//case 65377: break; //Print screen
+ 			case 65379: code = 0xe052; break; //Insert
+ 
+ 			case 65383: code = 0xe05d; break; //Menu
+ 
+ 			case 65470: code =   0x3b; break; //F1
+ 			case 65471: code =   0x3c; break; //F2
+ 			case 65472: code =   0x3d; break; //F3
+ 			case 65473: code =   0x3e; break; //F4
+ 			case 65474: code =   0x3f; break; //F5
+ 			case 65475: code =   0x40; break; //F6
+ 			case 65476: code =   0x41; break; //F7
+ 			case 65477: code =   0x42; break; //F8
+ 			case 65478: code =   0x43; break; //F9
+ 			case 65479: code =   0x44; break; //F10
+ 			case 65480: code =   0x57; break; //F11
+ 			case 65481: code =   0x58; break; //F12
+ 
+ 			case 65505: shift =  down; break; //Shift (left + right)
+ 			case 65507: code =   0x1d; break; //Left ctrl
+ 			case 65508: code = 0xe01d; break; //Right ctrl
+ 			case 65513: code =   0x38; break; //Left Alt
+ 			case 65514: code = 0xe038; break; //Right Alt
+ 			case 65515: code = 0xe05b; break; //Left windows key
+ 			case 65516: code = 0xe05c; break; //Right windows key
+ 			case 65535: code = 0xe053; break; //Delete
+ 			default: RTPrintf("VNC unhandled keyboard code: down=%d code=%d\n", down, keycode); break;
+ 		}
+ 	}
+ 	//RTPrintf("down=%d shift=%d code=%d\n", down, shift, code);
+ 	if (shift != -1 && code != -1) {
+ 		kbdPutCodeShift(shift, code, down);
+ 	} else if (shift != -1) {
+ 		kbdSetShift(shift);
+ 	} else if (code != -1) {
+ 		kbdPutCode(code, down);
+ 	}
+ }
+ void VNCFB::handleVncKeyboardReleaseEvent() {
+ 	kbdSetShift(0);
+ 	kbdPutCode(0x1d, 0); //Left ctrl
+ 	kbdPutCode(0xe01d, 0); //Right ctrl
+ 	kbdPutCode(0x38, 0); //Left alt
+ 	kbdPutCode(0xe038, 0); //Right alt
+ }
+ 
+ void VNCFB::vncKeyboardEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) {
+ 	((VNCFB*)(cl->screen->screenData))->handleVncKeyboardEvent(down, keySym);
+ }
+ void VNCFB::vncReleaseKeysEvent(rfbClientPtr cl) { //Release modifier keys
+ 	((VNCFB*)(cl->screen->screenData))->handleVncKeyboardReleaseEvent();
+ }
+ 
+ // IFramebuffer properties
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+  * Requests a resize of our "screen".
+  *
+  * @returns COM status code
+  * @param   pixelFormat Layout of the guest video RAM (i.e. 16, 24,
+  *                      32 bpp)
+  * @param   vram        host context pointer to the guest video RAM,
+  *                      in case we can cope with the format
+  * @param   bitsPerPixel color depth of the guest video RAM
+  * @param   bytesPerLine length of a screen line in the guest video RAM
+  * @param   w           video mode width in pixels
+  * @param   h           video mode height in pixels
+  * @retval  finished    set to true if the method is synchronous and
+  *                      to false otherwise
+  *
+  * This method is called when the guest attempts to resize the virtual
+  * screen.  The pointer to the guest's video RAM is supplied in case
+  * the framebuffer can handle the pixel format.  If it can't, it should
+  * allocate a memory buffer itself, and the virtual VGA device will copy
+  * the guest VRAM to that in a format we can handle.  The
+  * COMGETTER(UsesGuestVRAM) method is used to tell the VGA device which method
+  * we have chosen, and the other COMGETTER methods tell the device about
+  * the layout of our buffer.  We currently handle all VRAM layouts except
+  * FramebufferPixelFormat_Opaque (which cannot be handled by
+  * definition).
+  */
+ 
+ STDMETHODIMP VNCFB::RequestResize(ULONG aScreenId, ULONG pixelFormat,
+                                      BYTE *vram, ULONG bitsPerPixel,
+                                      ULONG bytesPerLine,
+                                      ULONG w, ULONG h, BOOL *finished) {
+ 	NOREF(aScreenId);
+ 	if (!finished) return E_POINTER;
+ 
+ 	/* For now, we are doing things synchronously */
+ 	*finished = true;
+ 
+ 	if (mRGBBuffer) RTMemFree(mRGBBuffer);
+ 
+ 	mWidth = w;
+ 	mHeight = h;
+ 
+ 	if (pixelFormat == FramebufferPixelFormat_FOURCC_RGB && bitsPerPixel == 32) {
+ 		mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
+         	mBufferAddress = reinterpret_cast<uint8_t *>(vram);
+         	mBytesPerLine = bytesPerLine;
+         	mBitsPerPixel = bitsPerPixel;
+         	mRGBBuffer = NULL;
+ 	} else {
+         	mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
+         	mBytesPerLine = w * 4;
+         	mBitsPerPixel = 32;
+         	mRGBBuffer = reinterpret_cast<uint8_t *>(RTMemAlloc(mBytesPerLine * h));
+         	AssertReturn(mRGBBuffer != 0, E_OUTOFMEMORY);
+         	mBufferAddress = mRGBBuffer;
+ 	}
+ 
+ 	uint8_t *oldBuffer = mScreenBuffer;
+ 	mScreenBuffer = reinterpret_cast<uint8_t *>(RTMemAlloc(mBytesPerLine * h));
+        	AssertReturn(mScreenBuffer != 0, E_OUTOFMEMORY);
+ 
+ 	for (ULONG i = 0; i < mBytesPerLine * h; i += 4) {
+ 		mScreenBuffer[i]   = mBufferAddress[i+2];
+ 		mScreenBuffer[i+1] = mBufferAddress[i+1];
+ 		mScreenBuffer[i+2] = mBufferAddress[i];
+ 	}
+ 
+ 	RTPrintf("Set framebuffer: buffer=%d w=%lu h=%lu bpp=%d\n", mBufferAddress, mWidth, mHeight, (int)mBitsPerPixel);
+ 	rfbNewFramebuffer(vncServer, (char*)mScreenBuffer, mWidth, mHeight, 8, 3, mBitsPerPixel / 8);
+ 	if (oldBuffer) RTMemFree(oldBuffer);
+ 	return S_OK;
+ }
+ 
+ //Guest framebuffer update notification
+ STDMETHODIMP VNCFB::NotifyUpdate(ULONG x, ULONG y, ULONG w, ULONG h) {
+ 	if (!mBufferAddress || !mScreenBuffer) return S_OK;
+ 	ULONG joff = y * mBytesPerLine + x * 4;
+ 	for (ULONG j = joff; j < joff + h * mBytesPerLine; j += mBytesPerLine)
+ 	for (ULONG i = j; i < j + w * 4; i += 4) {
+ 		mScreenBuffer[i]   = mBufferAddress[i+2];
+ 		mScreenBuffer[i+1] = mBufferAddress[i+1];
+ 		mScreenBuffer[i+2] = mBufferAddress[i];
+ 	}
+ 	rfbMarkRectAsModified(vncServer, x, y, x+w, y+h);
+ 	return S_OK;
+ }
+ 
+ 
+ 
+ 
+ /**
+  * Return the address of the frame buffer for the virtual VGA device to
+  * write to.  If COMGETTER(UsesGuestVRAM) returns FLASE (or if this address
+  * is not the same as the guests VRAM buffer), the device will perform
+  * translation.
+  *
+  * @returns         COM status code
+  * @retval  address The address of the buffer
+  */
+ STDMETHODIMP VNCFB::COMGETTER(Address) (BYTE **address) {
+     if (!address) return E_POINTER;
+     LogFlow(("FFmpeg::COMGETTER(Address): returning address %p\n", mBufferAddress));
+     *address = mBufferAddress;
+     return S_OK;
+ }
+ 
+ /**
+  * Return the width of our frame buffer.
+  *
+  * @returns       COM status code
+  * @retval  width The width of the frame buffer
+  */
+ STDMETHODIMP VNCFB::COMGETTER(Width) (ULONG *width) {
+     if (!width) return E_POINTER;
+     LogFlow(("FFmpeg::COMGETTER(Width): returning width %lu\n", (unsigned long) mWidth));
+     *width = mWidth;
+     return S_OK;
+ }
+ 
+ /**
+  * Return the height of our frame buffer.
+  *
+  * @returns        COM status code
+  * @retval  height The height of the frame buffer
+  */
+ STDMETHODIMP VNCFB::COMGETTER(Height) (ULONG *height) {
+     if (!height) return E_POINTER;
+     LogFlow(("FFmpeg::COMGETTER(Height): returning height %lu\n", (unsigned long) mGuestHeight));
+     *height = mHeight;
+     return S_OK;
+ }
+ 
+ /**
+  * Return the colour depth of our frame buffer.  Note that we actually
+  * store the pixel format, not the colour depth internally, since
+  * when display sets FramebufferPixelFormat_Opaque, it
+  * wants to retreive FramebufferPixelFormat_Opaque and
+  * nothing else.
+  *
+  * @returns            COM status code
+  * @retval  bitsPerPixel The colour depth of the frame buffer
+  */
+ STDMETHODIMP VNCFB::COMGETTER(BitsPerPixel) (ULONG *bitsPerPixel) {
+     if (!bitsPerPixel) return E_POINTER;
+     *bitsPerPixel = mBitsPerPixel;
+     LogFlow(("FFmpeg::COMGETTER(BitsPerPixel): returning depth %lu\n",
+               (unsigned long) *bitsPerPixel));
+     return S_OK;
+ }
+ 
+ /**
+  * Return the number of bytes per line in our frame buffer.
+  *
+  * @returns          COM status code
+  * @retval  bytesPerLine The number of bytes per line
+  */
+ STDMETHODIMP VNCFB::COMGETTER(BytesPerLine) (ULONG *bytesPerLine) {
+     if (!bytesPerLine) return E_POINTER;
+     LogFlow(("FFmpeg::COMGETTER(BytesPerLine): returning line size %lu\n", (unsigned long) mBytesPerLine));
+     *bytesPerLine = mBytesPerLine;
+     return S_OK;
+ }
+ 
+ /**
+  * Return the pixel layout of our frame buffer.
+  *
+  * @returns             COM status code
+  * @retval  pixelFormat The pixel layout
+  */
+ STDMETHODIMP VNCFB::COMGETTER(PixelFormat) (ULONG *pixelFormat) {
+     if (!pixelFormat) return E_POINTER;
+     LogFlow(("FFmpeg::COMGETTER(PixelFormat): returning pixel format: %lu\n", (unsigned long) mPixelFormat));
+     *pixelFormat = mPixelFormat;
+     return S_OK;
+ }
+ 
+ /**
+  * Return whether we use the guest VRAM directly.
+  *
+  * @returns             COM status code
+  * @retval  pixelFormat The pixel layout
+  */
+ STDMETHODIMP VNCFB::COMGETTER(UsesGuestVRAM) (BOOL *usesGuestVRAM) {
+     if (!usesGuestVRAM) return E_POINTER;
+     LogFlow(("FFmpeg::COMGETTER(UsesGuestVRAM): uses guest VRAM? %d\n", mRGBBuffer == NULL));
+     *usesGuestVRAM = (mRGBBuffer == NULL);
+     return S_OK;
+ }
+ 
+ /**
+  * Return the number of lines of our frame buffer which can not be used
+  * (e.g. for status lines etc?).
+  *
+  * @returns                 COM status code
+  * @retval  heightReduction The number of unused lines
+  */
+ STDMETHODIMP VNCFB::COMGETTER(HeightReduction) (ULONG *heightReduction) {
+     if (!heightReduction) return E_POINTER;
+     /* no reduction */
+     *heightReduction = 0;
+     LogFlow(("FFmpeg::COMGETTER(HeightReduction): returning 0\n"));
+     return S_OK;
+ }
+ 
+ /**
+  * Return a pointer to the alpha-blended overlay used to render status icons
+  * etc above the framebuffer.
+  *
+  * @returns          COM status code
+  * @retval  aOverlay The overlay framebuffer
+  */
+ STDMETHODIMP VNCFB::COMGETTER(Overlay) (IFramebufferOverlay **aOverlay) {
+     if (!aOverlay) return E_POINTER;
+     /* not yet implemented */
+     *aOverlay = 0;
+     LogFlow(("FFmpeg::COMGETTER(Overlay): returning 0\n"));
+     return S_OK;
+ }
+ 
+ /**
+  * Return id of associated window
+  *
+  * @returns          COM status code
+  * @retval  winId Associated window id
+  */
+ STDMETHODIMP VNCFB::COMGETTER(WinId) (ULONG64 *winId) {
+     if (!winId) return E_POINTER;
+     *winId = 0;
+     return S_OK;
+ }
+ 
+ // IFramebuffer methods
+ /////////////////////////////////////////////////////////////////////////////
+ 
+ STDMETHODIMP VNCFB::Lock() {
+     LogFlow(("VNCFB::Lock: called\n"));
+     int rc = RTCritSectEnter(&mCritSect);
+     AssertRC(rc);
+     if (rc == VINF_SUCCESS) return S_OK;
+     return E_UNEXPECTED;
+ }
+ 
+ STDMETHODIMP VNCFB::Unlock() {
+     LogFlow(("VNCFB::Unlock: called\n"));
+     RTCritSectLeave(&mCritSect);
+     return S_OK;
+ }
+ 
+ 
+ /**
+  * Returns whether we like the given video mode.
+  *
+  * @returns COM status code
+  */
+ STDMETHODIMP VNCFB::VideoModeSupported(ULONG width, ULONG height, ULONG bpp, BOOL *supported) {
+     if (!supported) return E_POINTER;
+     *supported = true;
+     return S_OK;
+ }
+ 
+ /** Stubbed */
+ STDMETHODIMP VNCFB::GetVisibleRegion(BYTE *rectangles, ULONG /* count */, ULONG * /* countCopied */) {
+     if (!rectangles) return E_POINTER;
+     *rectangles = 0;
+     return S_OK;
+ }
+ 
+ /** Stubbed */
+ STDMETHODIMP VNCFB::SetVisibleRegion(BYTE *rectangles, ULONG /* count */) {
+     if (!rectangles) return E_POINTER;
+     return S_OK;
+ }
+ 
+ STDMETHODIMP VNCFB::ProcessVHWACommand(BYTE *pCommand) {
+     return E_NOTIMPL;
+ }
+ 
+ #ifdef VBOX_WITH_XPCOM
+ NS_DECL_CLASSINFO(VNCFB)
+ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VNCFB, IFramebuffer)
+ #endif
diff -crBN -x '*~' org-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/VNC.h vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/VNC.h
*** org-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/VNC.h	1970-01-01 01:00:00.000000000 +0100
--- vnc-3.1.2/src/VBox/Frontends/VBoxHeadless/VNC/VNC.h	2010-01-22 01:10:23.518944686 +0100
***************
*** 0 ****
--- 1,132 ----
+ /** @file
+  *
+  * VBox Remote Desktop Protocol.
+  * VNC server interface
+  */
+ 
+ /*
+  * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+  * Copyright (C) 2009 Ivo Smits <[email protected]>
+  *
+  * This file is part of VirtualBox Open Source Edition (OSE), as
+  * available from http://www.virtualbox.org. This file is free software;
+  * you can redistribute it and/or modify it under the terms of the GNU
+  * General Public License (GPL) as published by the Free Software
+  * Foundation, in version 2 as it comes in the "COPYING" file of the
+  * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+  *
+  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+  * Clara, CA 95054 USA or visit http://www.sun.com if you need
+  * additional information or have any questions.
+  */
+ 
+ #include <VBox/com/VirtualBox.h>
+ 
+ #include <iprt/uuid.h>
+ 
+ #include <VBox/com/com.h>
+ #include <VBox/com/string.h>
+ 
+ #include <iprt/initterm.h>
+ #include <iprt/critsect.h>
+ 
+ #include <rfb/rfb.h>
+ #include <pthread.h>
+ 
+ class VNCFB : VBOX_SCRIPTABLE_IMPL(IFramebuffer) {
+ public:
+     VNCFB(ComPtr <IConsole> console, int port, char* password);
+     virtual ~VNCFB();
+ 
+ #ifndef VBOX_WITH_XPCOM
+     STDMETHOD_(ULONG, AddRef)() {
+         return ::InterlockedIncrement (&refcnt);
+     }
+     STDMETHOD_(ULONG, Release)() {
+         long cnt = ::InterlockedDecrement (&refcnt);
+         if (cnt == 0) delete this;
+         return cnt;
+     }
+ #endif
+     VBOX_SCRIPTABLE_DISPATCH_IMPL(IFramebuffer)
+ 
+     NS_DECL_ISUPPORTS
+ 
+     // public methods only for internal purposes
+     HRESULT init ();
+ 
+     STDMETHOD(COMGETTER(Width))(ULONG *width);
+     STDMETHOD(COMGETTER(Height))(ULONG *height);
+     STDMETHOD(Lock)();
+     STDMETHOD(Unlock)();
+     STDMETHOD(COMGETTER(Address))(BYTE **address);
+     STDMETHOD(COMGETTER(BitsPerPixel))(ULONG *bitsPerPixel);
+     STDMETHOD(COMGETTER(BytesPerLine))(ULONG *bytesPerLine);
+     STDMETHOD(COMGETTER(PixelFormat)) (ULONG *pixelFormat);
+     STDMETHOD(COMGETTER(UsesGuestVRAM)) (BOOL *usesGuestVRAM);
+     STDMETHOD(COMGETTER(HeightReduction)) (ULONG *heightReduction);
+     STDMETHOD(COMGETTER(Overlay)) (IFramebufferOverlay **aOverlay);
+     STDMETHOD(COMGETTER(WinId)) (ULONG64 *winId);
+ 
+     STDMETHOD(NotifyUpdate)(ULONG x, ULONG y, ULONG w, ULONG h);
+     STDMETHOD(RequestResize)(ULONG aScreenId, ULONG pixelFormat, BYTE *vram,
+                              ULONG bitsPerPixel, ULONG bytesPerLine,
+                              ULONG w, ULONG h, BOOL *finished);
+     STDMETHOD(VideoModeSupported)(ULONG width, ULONG height, ULONG bpp, BOOL *supported);
+     STDMETHOD(GetVisibleRegion)(BYTE *rectangles, ULONG count, ULONG *countCopied);
+     STDMETHOD(SetVisibleRegion)(BYTE *rectangles, ULONG count);
+ 
+     STDMETHOD(ProcessVHWACommand)(BYTE *pCommand);
+ 
+ private:
+ 	/** Guest framebuffer pixel format */
+ 	ULONG mPixelFormat;
+ 	/** Guest framebuffer color depth */
+ 	ULONG mBitsPerPixel;
+ 	/** Guest framebuffer line length */
+ 	ULONG mBytesPerLine;
+ 
+ 	//Our own framebuffer, in case we can't use the VRAM
+ 	uint8_t *mRGBBuffer;
+ 	//The source framebuffer (either our own mRGBBuffer or the guest VRAM)
+ 	uint8_t *mBufferAddress;
+ 	//VNC display framebuffer (RGB -> BGR converted)
+ 	uint8_t *mScreenBuffer;
+ 
+ 	int mVncPort;
+ 
+ 	ComPtr<IConsole> mConsole;
+ 	ComPtr<IKeyboard> mKeyboard;
+ 	ComPtr<IMouse> mMouse;
+ 
+ 	int kbdShiftState;
+ 	void kbdSetShift(int state);
+ 	void kbdPutCode(int code);
+ 	void kbdPutCode(int code, int down);
+ 	void kbdPutCodeShift(int shift, int code, int down);
+ 
+ 	ULONG mWidth, mHeight;
+ 
+ 	RTCRITSECT mCritSect;
+ 
+ 	rfbScreenInfoPtr vncServer;
+ 	pthread_t vncThread;
+ 	static void* vncFunc(void* arg);
+ 	char* vncPassword;
+ 
+ 	static void vncKeyboardEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl);
+ 	static void vncMouseEvent(int buttonMask, int x, int y, rfbClientPtr cl);
+ 	static void vncReleaseKeysEvent(rfbClientPtr cl);
+ 
+ 	void handleVncKeyboardEvent(int down, int keySym);
+ 	void handleVncMouseEvent(int buttonMask, int x, int y);
+ 	void handleVncKeyboardReleaseEvent();
+ 
+ 	int mouseX, mouseY;
+ 
+ #ifndef VBOX_WITH_XPCOM
+ 	long refcnt;
+ #endif
+ };
+ 


_______________________________________________
vbox-dev mailing list
[email protected]
http://vbox.innotek.de/mailman/listinfo/vbox-dev

Reply via email to