FramebufferVNC.cpp revision 9c6395ed47514689cd7deaf5e61c979ef856459a
/* $Id$ */
/** @file
* VBoxHeadless - VNC server implementation for VirtualBox.
*
* Uses LibVNCServer (http://sourceforge.net/projects/libvncserver/)
*/
/*
* Contributed by Ivo Smits <Ivo@UFO-Net.nl>
*
* Copyright (C) 2006-2007 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* 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.
*/
#include "FramebufferVNC.h"
#include <png.h>
// 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.
*/
mBitsPerPixel(0),
mBytesPerLine(0),
mRGBBuffer(0),
mScreenBuffer(0),
mKeyboard(0),
mMouse(0),
vncServer(0),
{
LogFlow(("Creating VNC object %p, width=%u, height=%u, port=%u\n",
}
{
LogFlow(("Destroying VNCFB object %p\n", this));
if (vncServer)
{
if (vncServer->authPasswdData)
{
RTMemFree(papszPassword[0]);
}
}
mRGBBuffer = NULL;
}
{
LogFlow(("Initialising VNCFB object %p\n", this));
vncServer->screenData = (void*)this;
if (mVncPort)
char *pszDesktopName;
if (RT_SUCCESS(rc))
else
if (mVncPassword)
{
}
else
/* Set the initial framebuffer size */
return S_OK;
}
{
}
{
return VINF_SUCCESS;
}
{
}
{
//RTPrintf("VNC mouse: button=%d x=%d y=%d\n", buttonMask, x, y);
if (!mMouse)
{
if (!mMouse)
{
RTPrintf("Warning: could not get mouse object!\n");
return;
}
}
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;
if (fAbsMouseEnabled)
else
mouseX = x;
mouseY = y;
}
{
}
{
if (state && !kbdShiftState)
{
kbdShiftState = 1;
}
else if (!state && kbdShiftState)
{
kbdPutCode(0x2a, 0);
kbdShiftState = 0;
}
}
{
if (code & 0xff00)
}
{
if (shift != kbdShiftState)
if (shift != 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. */
{
//RTPrintf("VNC keyboard: down=%d code=%d -> ", down, keycode);
{
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 //{|}~
};
if (keycode < 32)
{
//ASCII control codes.. unused..
}
else if (keycode < 127)
{
//DEL is in high area
shift = -1;
}
{
}
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 65377: break; //Print screen
}
}
//RTPrintf("down=%d shift=%d code=%d\n", down, shift, code);
{
}
else if (shift != -1)
{
}
else if (code != -1)
{
}
}
void VNCFB::handleVncKeyboardReleaseEvent()
{
kbdSetShift(0);
}
{
}
{
//Release modifier keys
}
// 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).
*/
{
if (!finished)
return E_POINTER;
/* For now, we are doing things synchronously */
*finished = true;
if (mRGBBuffer)
mWidth = w;
mHeight = h;
{
mRGBBuffer = NULL;
}
else
{
mBytesPerLine = w * 4;
mBitsPerPixel = 32;
}
{
}
RTPrintf("Set framebuffer: buffer=%llx w=%lu h=%lu bpp=%d\n",
if (oldBuffer)
return S_OK;
}
//Guest framebuffer update notification
{
if (!mBufferAddress || !mScreenBuffer)
return S_OK;
{
}
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
*/
{
if (!address)
return E_POINTER;
return S_OK;
}
/**
* Return the width of our frame buffer.
*
* @returns COM status code
* @retval width The width of the frame buffer
*/
{
if (!width)
return E_POINTER;
return S_OK;
}
/**
* Return the height of our frame buffer.
*
* @returns COM status code
* @retval height The height of the frame buffer
*/
{
if (!height)
return E_POINTER;
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
*/
{
if (!bitsPerPixel)
return E_POINTER;
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
*/
{
if (!bytesPerLine)
return E_POINTER;
LogFlow(("FFmpeg::COMGETTER(BytesPerLine): returning line size %lu\n", (unsigned long) mBytesPerLine));
return S_OK;
}
/**
* Return the pixel layout of our frame buffer.
*
* @returns COM status code
* @retval pixelFormat The pixel layout
*/
{
if (!pixelFormat)
return E_POINTER;
LogFlow(("FFmpeg::COMGETTER(PixelFormat): returning pixel format: %lu\n", (unsigned long) mPixelFormat));
return S_OK;
}
/**
* Return whether we use the guest VRAM directly.
*
* @returns COM status code
* @retval pixelFormat The pixel layout
*/
{
if (!usesGuestVRAM)
return E_POINTER;
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
*/
{
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
*/
{
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
*/
{
if (!winId)
return E_POINTER;
*winId = 0;
return S_OK;
}
// IFramebuffer methods
/////////////////////////////////////////////////////////////////////////////
{
LogFlow(("VNCFB::Lock: called\n"));
if (rc == VINF_SUCCESS)
return S_OK;
return E_UNEXPECTED;
}
{
LogFlow(("VNCFB::Unlock: called\n"));
return S_OK;
}
/**
* Returns whether we like the given video mode.
*
* @returns COM status code
*/
{
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 */
{
if (!rectangles)
return E_POINTER;
return S_OK;
}
{
return E_NOTIMPL;
}
#ifdef VBOX_WITH_XPCOM
#endif