VBoxSDL.cpp revision 58e8f2bc3ec5551ada61c45bda246a97e9a945c0
e1e1e620f76ef8d3cb2c022269bf846e6e392fbaAllen Rabinovich * VBox frontends: VBoxSDL (simple frontend based on SDL):
6e847ed42c6e59e53bca347d80876b6ecb5a60f7Allen Rabinovich * Copyright (C) 2006-2009 Sun Microsystems, Inc.
21257820ee962f4f2275b39088c43fcfd76f7fdeAllen Rabinovich * This file is part of VirtualBox Open Source Edition (OSE), as
f0e0bfede101cfa5fbfb4ffe85a839033657b5d7Allen Rabinovich * available from http://www.virtualbox.org. This file is free software;
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich * you can redistribute it and/or modify it under the terms of the GNU
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich * General Public License (GPL) as published by the Free Software
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich * Foundation, in version 2 as it comes in the "COPYING" file of the
87fff29257e74dac31f23eac9e31c028a551057fAllen Rabinovich * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich * Clara, CA 95054 USA or visit http://www.sun.com if you need
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich * additional information or have any questions.
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich/*******************************************************************************
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich* Header Files *
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich*******************************************************************************/
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovichusing namespace com;
e459c407a404c834e5f9759744d1a134d820d41bAllen Rabinovich# include <X11/cursorfont.h> /* for XC_left_ptr */
21257820ee962f4f2275b39088c43fcfd76f7fdeAllen Rabinovich#include <SDL_syswm.h> /* for SDL_GetWMInfo() */
#include <vector>
#include <list>
#ifdef VBOX_SECURELABEL
#define VBOXSDL_ADVANCED_OPTIONS
struct PointerShapeChangeData
if (aShape)
if (shape)
enum TitlebarMode
static bool UseAbsoluteMouse(void);
static void ResetKeys(void);
static void InputGrabStart(void);
static void InputGrabEnd(void);
static void HandleGuestCapsChanged(void);
#if defined (DEBUG_dmik)
static const char *gpszPidFile;
#ifdef VBOXSDL_WITH_X11
#ifdef VBOXSDL_WITH_X11
#ifdef VBOX_SECURELABEL
#ifdef RT_OS_WINDOWS
class VBoxSDLCallback :
public IVirtualBoxCallback
#if defined (RT_OS_WINDOWS)
refcnt = 0;
virtual ~VBoxSDLCallback()
#ifdef RT_OS_WINDOWS
if (cnt == 0)
return cnt;
*ppObj = this;
AddRef();
return S_OK;
*ppObj = this;
AddRef();
return S_OK;
return E_NOINTERFACE;
return S_OK;
return S_OK;
if (!changeAllowed)
return E_INVALIDARG;
return S_OK;
#ifdef VBOX_SECURELABEL
if (gMachine)
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
#ifdef RT_OS_WINDOWS
long refcnt;
class VBoxSDLConsoleCallback :
public IConsoleCallback
#if defined (RT_OS_WINDOWS)
refcnt = 0;
virtual ~VBoxSDLConsoleCallback()
#ifdef RT_OS_WINDOWS
if (cnt == 0)
return cnt;
*ppObj = this;
AddRef();
return S_OK;
*ppObj = this;
AddRef();
return S_OK;
return E_NOINTERFACE;
shape);
if (!data)
return E_FAIL;
if (rc)
delete data;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
const char *pszType;
if (fFatal)
return S_OK;
if (!canShow)
return E_POINTER;
#ifdef RT_OS_DARWIN
return S_OK;
#ifndef RT_OS_DARWIN
#if defined (VBOXSDL_WITH_X11)
AssertFailed();
return E_FAIL;
return S_OK;
AssertFailed();
return E_FAIL;
switch (machineState)
#ifdef RT_OS_WINDOWS
long refcnt;
bool m_fIgnorePowerOffEvents;
#ifdef VBOX_WITH_XPCOM
static void show_usage()
" -fixedmode <w> <h> <bpp> Use a fixed SDL video mode with given width, height and bits per pixel\n"
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) /** @todo UNIXISH_TAP stuff out of main and up to Config.kmk! */
#ifdef VBOX_WITH_VRDP
#ifdef VBOX_SECURELABEL
" -seclabelbgcol <rgb> Secure label background color RGB value in 6 digit hexadecimal (eg: FF0000)\n"
#ifdef VBOXSDL_ADVANCED_OPTIONS
pszStat);
if (pwszComponent)
#ifdef VBOXSDL_WITH_X11
ResetKeys();
if (gpszPidFile)
enum ConvertSettings
ConvertSettings_No = 0,
* @note The function is taken from VBoxManage.cpp almost unchanged (except the
bool isGlobalConverted = false;
if (!accessible)
isGlobalConverted = true;
switch (fConvertSettings)
case ConvertSettings_No:
RTPrintf (
RTPrintf (
case ConvertSettings_Yes:
case ConvertSettings_Backup:
AssertFailedReturn (false);
if (isGlobalConverted)
#ifdef VBOXSDL_WITH_X11
* KeyPress/KeyRelease event if the lock key was pressed/released. But the lock status
* to ensure a defined environment and work around the missing KeyPress/KeyRelease
if (rc != 0)
SDL_Quit();
bool fFullscreen = false;
bool fResizable = true;
#ifdef USE_XPCOM_QUEUE_THREAD
bool fXPCOMEventThreadSignaled = false;
#ifdef VBOX_WITH_VRDP
int portVRDP = ~0;
bool fDiscardState = false;
#ifdef VBOX_SECURELABEL
#ifdef VBOXSDL_ADVANCED_OPTIONS
unsigned fRawR0 = ~0U;
unsigned fRawR3 = ~0U;
unsigned fPATM = ~0U;
unsigned fCSAM = ~0U;
#ifdef VBOX_WIN32_UI
bool fWin32UI = true;
bool fShowSDLConfig = false;
enum HKEYSTATE
show_usage();
bool sessionOpened = false;
#ifdef USE_XPCOM_QUEUE_THREAD
fFullscreen = true;
gfFullscreenResize = true;
#ifdef VBOXSDL_WITH_X11
fResizable = false;
gHostKeyMod = 0;
gHostKeySym1 = 0;
for (i=0; i<cStr; i++)
i = cStr;
if (!hdaFile)
RTPrintf("Error: The path to the specified harddisk, '%s', could not be resolved.\n", argv[curArg]);
if (!fdaFile)
RTPrintf("Error: The path to the specified floppy disk, '%s', could not be resolved.\n", argv[curArg]);
if (!cdromFile)
#ifdef RT_OS_LINUX
#ifdef VBOX_WITH_VRDP
portVRDP = 0;
if (port > 0)
curArg++;
fDiscardState = true;
#ifdef VBOX_SECURELABEL
fSecureLabel = true;
#ifdef VBOXSDL_ADVANCED_OPTIONS
fRawR0 = true;
fRawR0 = false;
fRawR3 = true;
fRawR3 = false;
fPATM = true;
fPATM = false;
fCSAM = true;
fCSAM = false;
#ifdef VBOX_WIN32_UI
fWin32UI = true;
fShowSDLConfig = true;
show_usage();
goto leave;
goto leave;
goto leave;
if (!session)
goto leave;
sessionOpened = true;
if (!gMachine)
goto leave;
if (!gConsole)
goto leave;
if (hdaFile)
if (!hardDisk)
if (hardDisk)
goto leave;
if (fdaFile)
bool done = false;
done = true;
if (!done)
goto leave;
if (cdromFile)
bool done = false;
done = true;
if (!done)
goto leave;
if (fDiscardState)
if (cSnapshots)
if (gMachineDebugger)
if (!gDisplay)
goto leave;
if (memorySize)
if (vramSize)
#ifdef VBOX_WIN32_UI
if (fWin32UI)
if (!gpFrameBuffer)
goto leave;
#ifdef VBOX_WIN32_UI
goto leave;
if (fFullscreen)
SetFullscreen(true);
#ifdef VBOX_SECURELABEL
if (fSecureLabel)
if (!secureLabelFontFile)
goto leave;
int rcVBox;
rcVBox = RTLdrGetSymbol(gLibrarySDL_ttf, "TTF_RenderUTF8_Blended", (void**)&pTTF_RenderUTF8_Blended);
rcVBox = gpFrameBuffer->initSecureLabel(SECURE_LABEL_HEIGHT, secureLabelFontFile, secureLabelPointSize, secureLabelFontOffs);
goto leave;
#ifdef VBOXSDL_WITH_X11
goto leave;
#ifdef VBOX_WITH_VRDP
if (portVRDP != ~0)
if (gVrdpServer)
if (portVRDP > 0)
goto leave;
goto leave;
#ifdef VBOXSDL_ADVANCED_OPTIONS
if (fRawR0 != ~0U)
if (!gMachineDebugger)
goto leave;
if (fRawR3 != ~0U)
if (!gMachineDebugger)
goto leave;
if (fPATM != ~0U)
if (!gMachineDebugger)
goto leave;
if (fCSAM != ~0U)
if (!gMachineDebugger)
goto leave;
if (u32WarpDrive != 0)
if (!gMachineDebugger)
goto leave;
#ifdef VBOXSDL_WITH_X11
goto leave;
# if !defined(VBOX_WITHOUT_XCURSOR)
#ifdef VBOXSDL_WITH_X11
goto leave;
#ifdef USE_XPCOM_QUEUE_THREAD
bool fTerminateDuringStartup;
fTerminateDuringStartup = false;
#ifdef USE_XPCOM_QUEUE_THREAD
fXPCOMEventThreadSignaled = true;
case SDL_USER_EVENT_TIMER:
case SDL_USER_EVENT_RESIZE:
#ifdef USE_XPCOM_QUEUE_THREAD
case SDL_USER_EVENT_TERMINATE:
fTerminateDuringStartup = true;
sdlTimer = 0;
goto leave;
RTPrintf("Error: failed to power up VM! No error text available (rc = 0x%x state = %d)\n", rc, machineState);
goto leave;
if (!gKeyboard)
goto leave;
if (!gMouse)
goto leave;
if (gpszPidFile)
#ifdef USE_XPCOM_QUEUE_THREAD
case SDL_VIDEOEXPOSE:
case SDL_KEYDOWN:
case SDL_KEYUP:
switch (enmHKeyState)
case HKEYSTATE_NORMAL:
case HKEYSTATE_DOWN_1ST:
case HKEYSTATE_DOWN_2ND:
case HKEYSTATE_DOWN:
goto leave;
if (!gfGrabbed)
InputGrabEnd();
ResetKeys();
case HKEYSTATE_USED:
goto leave;
case HKEYSTATE_NOT_IT:
case SDL_QUIT:
goto leave;
if (gConsole)
case SDL_MOUSEMOTION:
SendMouseEvent(0, 0, 0);
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
switch (enmHKeyState)
case HKEYSTATE_DOWN_1ST:
case HKEYSTATE_DOWN_2ND:
case HKEYSTATE_DOWN:
case SDL_ACTIVEEVENT:
InputGrabEnd();
case SDL_VIDEORESIZE:
if (gDisplay)
if (gfIgnoreNextResize)
#ifdef VBOX_SECURELABEL
if (fSecureLabel)
if (gSdlResizeTimer)
case SDL_USER_EVENT_RESIZE:
#ifdef USE_XPCOM_QUEUE_THREAD
case SDL_USER_EVENT_TERMINATE:
goto leave;
#ifdef VBOX_SECURELABEL
delete data;
if (gpszPidFile)
#ifdef VBOX_WITH_VRDP
if (gVrdpServer)
if (gMachine)
if ( gConsole
RTPrintf("Failed to power down virtual machine! No error information available (rc = 0x%x).\n", rc);
if ( gMachine
if (sessionOpened)
if (gpDefaultCursor)
#ifdef VBOXSDL_WITH_X11
if (gpCustomCursor)
if (pCustomTempWMCursor)
#if defined (RT_OS_WINDOWS)
if (gDisplay)
if (gpFrameBuffer)
#ifdef VBOX_SECURELABEL
if (gLibrarySDL_ttf)
if (callback)
if (consoleCallback)
#ifndef VBOX_WITH_HARDENING
static bool UseAbsoluteMouse(void)
switch (sym)
case SDLK_EXCLAIM:
case SDLK_AT:
case SDLK_HASH:
case SDLK_DOLLAR:
case SDLK_CARET:
case SDLK_AMPERSAND:
case SDLK_ASTERISK:
case SDLK_LEFTPAREN:
case SDLK_RIGHTPAREN:
case SDLK_UNDERSCORE:
case SDLK_EQUALS:
case SDLK_COLON:
case SDLK_QUOTEDBL:
case SDLK_LESS:
case SDLK_GREATER:
case SDLK_QUESTION:
case SDLK_KP_MULTIPLY:
case SDLK_LMETA:
case SDLK_RMETA:
case SDLK_CLEAR: return 0x;
case SDLK_KP_EQUALS: return 0x;
case SDLK_COMPOSE: return 0x;
case SDLK_HELP: return 0x;
case SDLK_BREAK: return 0x;
case SDLK_POWER: return 0x;
case SDLK_EURO: return 0x;
case SDLK_UNDO: return 0x;
#ifdef VBOXSDL_WITH_X11
keycode = 0;
// Japanese backslash/underscore and Brazilian backslash/question mark
keycode = 0;
/* This is derived partially from SDL_QuartzKeys.h and partially from testing. */
/* set-1 SDL_QuartzKeys.h */
if (keycode == 0)
case SDLK_RMETA:
case SDLK_LMETA:
keycode = 0;
if (!keycode)
#ifdef DEBUG_bird
#ifdef DEBUG_bird
return keycode;
static void ResetKeys(void)
if (!gKeyboard)
if (gaModifiersState[i])
gaModifiersState[i] = 0;
case SDLK_F12:
case SDLK_F11:
case SDLK_F12:
case SDLK_F11:
case SDLK_F10:
case SDLK_F9:
case SDLK_F8:
#ifdef DEBUG_bird
switch(keycode)
ResetKeys();
#ifdef RT_OS_DARWIN
typedef int CGSConnection;
extern CGError CGSGetGlobalHotKeyOperatingMode(CGSConnection Connection, CGSGlobalHotKeyOperatingMode *enmMode);
extern CGError CGSSetGlobalHotKeyOperatingMode(CGSConnection Connection, CGSGlobalHotKeyOperatingMode enmMode);
static bool g_fHotKeysDisabled = false;
static bool g_fConnectedToCGS = false;
if (!g_fConnectedToCGS)
g_fConnectedToCGS = true;
if (fDisable)
static void InputGrabStart(void)
#ifdef RT_OS_DARWIN
DisableGlobalHotKeys(true);
if (!gfGuestNeedsHostCursor)
static void InputGrabEnd(void)
if (!gfGuestNeedsHostCursor)
#ifdef RT_OS_DARWIN
DisableGlobalHotKeys(false);
bool abs;
buttons = 0;
if (abs)
button = 0;
if (!gpOffCursor)
if (gpOffCursor)
int tmp_button = 0;
switch (button)
if (abs)
if (abs)
void ResetVM(void)
if (gConsole)
void SaveState(void)
ResetKeys();
if (gfGrabbed)
InputGrabEnd();
case SDL_USER_EVENT_TIMER:
#ifdef USE_XPCOM_QUEUE_THREAD
case SDL_USER_EVENT_RESIZE:
case SDL_USER_EVENT_TERMINATE:
sdlTimer = 0;
lrc = ~0;
if (!lrc)
if (name)
switch (mode)
case TITLEBAR_NORMAL:
if (gfGrabbed)
if (gMachineDebugger)
case TITLEBAR_STARTUP:
case TITLEBAR_SAVE:
case TITLEBAR_SNAPSHOT:
#ifdef VBOX_WIN32_UI
static void vbox_show_shape (unsigned short w, unsigned short h,
size_t x, y;
unsigned short pitch;
if (c == bg)
if (gpOffCursor)
bool ok = false;
uint32_t shapeSize = ((((data->width + 7) / 8) * data->height + 3) & ~3) + data->width * 4 * data->height;
#if defined (RT_OS_WINDOWS)
void *lpBits;
if (hAlphaCursor)
// see SDL12/src/video/wincommon/SDL_sysmouse.c
if (pCustomTempWMCursor)
ok = true;
if (hMonoBitmap)
if (hBitmap)
if (img)
if (cur)
// see SDL12/src/video/x11/SDL_x11mouse.c
if (pCustomTempWMCursor)
ok = true;
if (!ok)
else if (gfAbsoluteMouseGuest)
static void HandleGuestCapsChanged(void)
if (!gfAbsoluteMouseGuest)
if (gfGrabbed)
InputGrabEnd();
return VERR_NOT_SUPPORTED;
case SDLK_DELETE:
case SDLK_f:
return VERR_NOT_SUPPORTED;
case SDLK_p:
return VERR_NOT_SUPPORTED;
if (gfGrabbed)
InputGrabEnd();
case SDLK_r:
return VERR_NOT_SUPPORTED;
ResetVM();
case SDLK_q:
return VERR_NOT_SUPPORTED;
return VINF_EM_TERMINATE;
case SDLK_s:
return VERR_NOT_SUPPORTED;
SaveState();
return VINF_EM_TERMINATE;
case SDLK_h:
return VERR_NOT_SUPPORTED;
if (gConsole)
case SDLK_n:
return VERR_NOT_SUPPORTED;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VERR_NOT_SUPPORTED;
return VINF_SUCCESS;
return interval;
if (gConsole)
#ifdef USE_XPCOM_QUEUE_THREAD
if (rc == 0)
#ifdef VBOXSDL_WITH_X11
if (!rc)
if (!gfFullscreenResize)
if (enable)