VBoxSDL.cpp revision b7307c9c040a1a8aed0dbabed6574466d0bff2e4
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * VBox frontends: VBoxSDL (simple frontend based on SDL):
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * Main code
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * Copyright (C) 2006-2014 Oracle Corporation
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * available from http://www.virtualbox.org. This file is free software;
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * you can redistribute it and/or modify it under the terms of the GNU
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * General Public License (GPL) as published by the Free Software
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/*******************************************************************************
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync* Header Files *
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync*******************************************************************************/
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncusing namespace com;
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/* Xlib would re-define our enums */
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/*******************************************************************************
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync* Defined Constants And Macros *
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync*******************************************************************************/
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/** extra data key for the secure label */
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync#define VBOXSDL_SECURELABEL_EXTRADATA "VBoxSDL/SecureLabel"
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/** label area height in pixels */
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/** Enables the rawr[0|3], patm, and casm options. */
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/*******************************************************************************
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync* Structures and Typedefs *
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync*******************************************************************************/
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/** Pointer shape change event data structure */
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync PointerShapeChangeData(BOOL aVisible, BOOL aAlpha, ULONG aXHot, ULONG aYHot,
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync ULONG aWidth, ULONG aHeight, ComSafeArrayIn(BYTE,pShape))
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync : visible(aVisible), alpha(aAlpha), xHot(aXHot), yHot(aYHot),
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync // make a copy of the shape
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync com::SafeArray<BYTE> aShape(ComSafeArrayInArg(pShape));
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/*******************************************************************************
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync* Internal Functions *
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync*******************************************************************************/
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic bool UseAbsoluteMouse(void);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic void ResetKeys(void);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic void InputGrabStart(void);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic void InputGrabEnd(void);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic void SendMouseEvent(VBoxSDLFB *fb, int dz, int button, int down);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic void UpdateTitlebar(TitlebarMode mode, uint32_t u32User = 0);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic void SetPointerShape(const PointerShapeChangeData *data);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic void HandleGuestCapsChanged(void);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic int HandleHostKey(const SDL_KeyboardEvent *pEv);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic Uint32 StartupTimer(Uint32 interval, void *param);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic Uint32 ResizeTimer(Uint32 interval, void *param);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic Uint32 QuitTimer(Uint32 interval, void *param);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFilename);
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/*******************************************************************************
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync* Global Variables *
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync*******************************************************************************/
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic const char *gHostKeyDisabledCombinations = "";
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic const char *gpszPidFile;
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync/** modifier keypress status (scancode as index) */
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync#if defined(VBOXSDL_WITH_X11) && !defined(VBOX_WITH_SDL13)
b9a21c3c91c47e090316e28d759194e46628ed49vboxsyncstatic volatile int32_t g_cNotifyUpdateEventsPending;
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * Event handler for VirtualBoxClient events
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent * aEvent)
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync ComPtr<IVBoxSVCAvailabilityChangedEvent> pVSACEv = aEvent;
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync LogRel(("VBoxSDL: VBoxSVC became unavailable, exiting.\n"));
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync RTPrintf("VBoxSVC became unavailable, exiting.\n");
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync /* Send QUIT event to terminate the VM as cleanly as possible
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * given that VBoxSVC is no longer present. */
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync * Event handler for VirtualBox (server) events
b9a21c3c91c47e090316e28d759194e46628ed49vboxsync STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent * aEvent)
#ifdef VBOX_SECURELABEL
if (gpMachine)
AssertFailed();
return S_OK;
virtual ~VBoxSDLConsoleEventListener()
return S_OK;
void uninit()
switch (aType)
if (!data)
if (rc)
delete data;
const char *pszType;
if (fFatal)
#ifdef RT_OS_DARWIN
#ifndef RT_OS_DARWIN
#if defined(VBOXSDL_WITH_X11)
AssertFailed();
AssertFailed();
return S_OK;
switch (machineState)
bool m_fIgnorePowerOffEvents;
static void show_usage()
" --fixedmode <w> <h> <bpp> Use a fixed SDL video mode with given width, height and bits per pixel\n"
" --vrdp <ports> Listen for VRDP connections on one of specified ports (default if not specified)\n"
#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)
#ifdef RT_OS_WINDOWS
#ifdef Q_WS_X11
if (!XInitThreads())
#ifdef VBOXSDL_WITH_X11
* generating a KeyPress/KeyRelease event if the lock key was
* and work around the missing KeyPress/KeyRelease events in ProcessKeys().
if (rc != 0)
SDL_Quit();
int vrc;
bool fSeparate = false;
bool fFullscreen = false;
bool fResizable = true;
#ifdef USE_XPCOM_QUEUE_THREAD
bool fXPCOMEventThreadSignaled = false;
bool fDiscardState = false;
#ifdef VBOX_SECURELABEL
#ifdef VBOXSDL_ADVANCED_OPTIONS
unsigned fRawR0 = ~0U;
unsigned fRawR3 = ~0U;
unsigned fPATM = ~0U;
unsigned fCSAM = ~0U;
unsigned fHWVirt = ~0U;
#ifdef VBOX_WIN32_UI
bool fWin32UI = true;
bool fShowSDLConfig = false;
enum HKEYSTATE
show_usage();
fSeparate = true;
fFullscreen = true;
gfFullscreenResize = true;
#ifdef VBOXSDL_WITH_X11
fResizable = false;
gHostKeyMod = 0;
gHostKeySym1 = 0;
if (!pcszHdaFile)
RTPrintf("Error: The path to the specified harddisk, '%s', could not be resolved.\n", argv[curArg]);
if (!pcszFdaFile)
RTPrintf("Error: The path to the specified floppy disk, '%s', could not be resolved.\n", argv[curArg]);
if (!pcszCdromFile)
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;
fHWVirt = true;
fHWVirt = false;
#ifdef VBOX_WIN32_UI
fWin32UI = true;
fShowSDLConfig = true;
show_usage();
#ifdef VBOX_WITH_XPCOM
RTPrintf("Failed to initialize COM because the global settings directory '%s' is not accessible!\n", szHome);
bool sessionOpened = false;
RTPrintf("Failed to create VirtualBoxClient object! No error information available (rc=%Rhrc).\n", rc);
goto leave;
goto leave;
goto leave;
if (pcszSettingsPw)
goto leave;
else if (pcszSettingsPwFile)
goto leave;
goto leave;
else if (vmName)
goto leave;
goto leave;
if (fSeparate)
goto leave;
goto leave;
if (!pSession)
goto leave;
sessionOpened = true;
if (!gpMachine)
goto leave;
if (!gpConsole)
goto leave;
if (pcszHdaFile)
if (!pMedium)
if (pMedium)
if (pStorageCtl)
goto leave;
if (pcszFdaFile)
if (pStorageCtl)
goto leave;
if (pcszCdromFile)
if (pStorageCtl)
goto leave;
if (fDiscardState)
if (cSnapshots)
goto leave;
if (gpMachineDebugger)
if (!gpDisplay)
goto leave;
if (memorySize)
if (vramSize)
#ifdef VBOX_WIN32_UI
if (fWin32UI)
goto leave;
for (unsigned i = 0; i < gcMonitors; i++)
goto leave;
#ifdef VBOX_WIN32_UI
for (unsigned i = 0; i < gcMonitors; i++)
goto leave;
if (fFullscreen)
SetFullscreen(true);
#ifdef VBOX_SECURELABEL
if (fSecureLabel)
if (!secureLabelFontFile)
goto leave;
vrc = gpFramebuffer[0]->initSecureLabel(SECURE_LABEL_HEIGHT, secureLabelFontFile, secureLabelPointSize, secureLabelFontOffs);
goto leave;
#ifdef VBOXSDL_WITH_X11
goto leave;
if (pszPortVRDP)
if (gpVRDEServer)
goto leave;
goto leave;
#ifdef VBOXSDL_ADVANCED_OPTIONS
if (fRawR0 != ~0U)
if (!gpMachineDebugger)
goto leave;
if (fRawR3 != ~0U)
if (!gpMachineDebugger)
goto leave;
if (fPATM != ~0U)
if (!gpMachineDebugger)
goto leave;
if (fCSAM != ~0U)
if (!gpMachineDebugger)
goto leave;
if (fHWVirt != ~0U)
if (u32WarpDrive != 0)
if (!gpMachineDebugger)
goto leave;
#if !defined(VBOX_WITH_SDL13)
# if defined(VBOXSDL_WITH_X11)
# if !defined(VBOX_WITHOUT_XCURSOR)
if (gfXCursorEnabled)
#ifdef VBOXSDL_WITH_X11
if (!fSeparate)
goto leave;
#ifdef USE_XPCOM_QUEUE_THREAD
bool fTerminateDuringStartup;
fTerminateDuringStartup = false;
#ifdef USE_XPCOM_QUEUE_THREAD
fXPCOMEventThreadSignaled = true;
case SDL_USER_EVENT_TIMER:
rc = gpDisplay->GetScreenResolution(event.user.code, &dummy, &dummy, &dummy, &xOrigin, &yOrigin, &monitorStatus);
#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 (!gpKeyboard)
goto leave;
if (!gpMouse)
goto leave;
if (gpszPidFile)
#ifdef USE_XPCOM_QUEUE_THREAD
#ifdef VBOX_WITH_SDL13
case SDL_WINDOWEVENT:
case SDL_WINDOWEVENT_EXPOSED:
if (fb)
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 (gpConsole)
case SDL_MOUSEMOTION:
#ifdef VBOX_WITH_SDL13
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
switch (enmHKeyState)
case HKEYSTATE_DOWN_1ST:
case HKEYSTATE_DOWN_2ND:
case HKEYSTATE_DOWN:
#ifdef VBOX_WITH_SDL13
case SDL_ACTIVEEVENT:
InputGrabEnd();
case SDL_VIDEORESIZE:
if (gpDisplay)
if (gfIgnoreNextResize)
#ifdef VBOX_SECURELABEL
if (fSecureLabel)
if (gSdlResizeTimer)
rc = gpDisplay->GetScreenResolution(event.user.code, &dummy, &dummy, &dummy, &xOrigin, &yOrigin, &monitorStatus);
#ifdef USE_XPCOM_QUEUE_THREAD
case SDL_USER_EVENT_TERMINATE:
goto leave;
#ifdef VBOX_SECURELABEL
delete data;
if (gpszPidFile)
if (gpVRDEServer)
if (gpMachine)
if (!fSeparate)
if ( gpConsole
RTPrintf("Failed to power down virtual machine! No error information available (rc = 0x%x).\n", hrc);
if (pConsoleListener)
if ( gpMachine
if (sessionOpened)
#ifndef VBOX_WITH_SDL13
if (gpDefaultCursor)
# ifdef VBOXSDL_WITH_X11
if (gfXCursorEnabled)
if (gfXCursorEnabled)
if (gpCustomCursor)
if (pCustomTempWMCursor)
# if defined(RT_OS_WINDOWS)
if (gfXCursorEnabled)
if (gpDisplay)
for (unsigned i = 0; i < gcMonitors; i++)
for (unsigned i = 0; i < gcMonitors; i++)
if (gpFramebuffer[i])
#ifdef VBOX_SECURELABEL
if (gLibrarySDL_ttf)
if (pVBoxListener)
if (pVBoxClientListener)
if (!fStdIn)
if (!fStdIn)
return rcExit;
int rc;
return rcExit;
#ifndef VBOX_WITH_HARDENING
#ifdef Q_WS_X11
if (!XInitThreads())
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
# ifdef VBOX_WITH_SDL13
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_QUOTEDBL:
case SDLK_KP_MULTIPLY:
/* 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 (!gpKeyboard)
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);
#ifdef VBOX_WITH_SDL13
static void InputGrabEnd(void)
#ifdef RT_OS_DARWIN
DisableGlobalHotKeys(false);
bool abs;
#ifdef VBOX_WITH_SDL13
if (!fb)
SDL_GetMouseState(0, &x, &y);
|| !gfRelativeMouseGuest;
#ifdef VBOX_WITH_SDL13
#ifdef VBOX_WITH_SDL13
buttons = 0;
if (abs)
x += xOrigin;
y += yOrigin;
button = 0;
if (!gpOffCursor)
if (gpOffCursor)
int tmp_button = 0;
switch (button)
if (abs)
if (abs)
void ResetVM(void)
if (gpConsole)
void SaveState(void)
ResetKeys();
if (gfGrabbed)
InputGrabEnd();
case SDL_USER_EVENT_TIMER:
#ifdef USE_XPCOM_QUEUE_THREAD
case SDL_USER_EVENT_TERMINATE:
sdlTimer = 0;
lrc = ~0;
if (!lrc)
switch (mode)
case TITLEBAR_NORMAL:
if (gfGrabbed)
if (gpMachineDebugger)
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 (gfXCursorEnabled)
if (img)
#ifndef VBOX_WITH_SDL13
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;
if (fPauseIt)
if (fPauseIt)
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 (gpConsole)
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 (gpConsole)
#ifdef USE_XPCOM_QUEUE_THREAD
#ifdef VBOX_WITH_SDL13
if (rc == 0)
#ifdef VBOXSDL_WITH_X11
#ifdef VBOX_WITH_SDL13
if (fSuccess)
if (!gfFullscreenResize)
if (enable)
#ifdef VBOX_WITH_SDL13
for (unsigned i = 0; i < gcMonitors; i++)
return gpFramebuffer[i];
return NULL;