UISession.cpp revision 4d5a2d10140117cca0a93d7e1b4d71304701d6e1
/* $Id$ */
/** @file
*
* VBox frontends: Qt GUI ("VirtualBox"):
* UISession stuff implementation
*/
/*
* Copyright (C) 2006-2012 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.
*/
/* Qt includes: */
#include <QApplication>
#include <QWidget>
#include <QTimer>
/* GUI includes: */
#include "VBoxGlobal.h"
#include "UISession.h"
#include "UIMachine.h"
#include "UIActionPoolRuntime.h"
#include "UIMachineLogic.h"
#include "UIMachineWindow.h"
#include "UIMachineMenuBar.h"
#include "UIMessageCenter.h"
#include "UIWizardFirstRun.h"
#include "UIConsoleEventHandler.h"
#include "UIFrameBuffer.h"
#ifdef VBOX_WITH_VIDEOHWACCEL
# include "VBoxFBOverlay.h"
#endif /* VBOX_WITH_VIDEOHWACCEL */
#ifdef Q_WS_X11
# include <QX11Info>
# ifndef VBOX_WITHOUT_XCURSOR
# endif /* VBOX_WITHOUT_XCURSOR */
#endif /* Q_WS_X11 */
# include "UIKeyboardHandler.h"
# include <signal.h>
#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
/* COM includes: */
#include "CConsole.h"
#include "CSystemProperties.h"
#include "CMachineDebugger.h"
#include "CGuest.h"
#include "CStorageController.h"
#include "CMediumAttachment.h"
#include "CDisplay.h"
#include "CFramebuffer.h"
#include "CNetworkAdapter.h"
#include "CVRDEServer.h"
#include "CUSBController.h"
/* Base variables: */
/* Common variables: */
, m_pMenuPool(0)
#ifdef Q_WS_WIN
, m_alphaCursor(0)
#endif /* Q_WS_WIN */
/* Common flags: */
, m_fIsFirstTimeStarted(false)
, m_fIsIgnoreRuntimeMediumsChanging(false)
, m_fIsGuestResizeIgnored(false)
, m_fIsSeamlessModeRequested(false)
, m_fIsAutoCaptureDisabled(false)
/* Guest additions flags: */
, m_fIsGuestSupportsGraphics(false)
, m_fIsGuestSupportsSeamless(false)
/* Mouse flags: */
, m_fNumLock(false)
, m_fCapsLock(false)
, m_fScrollLock(false)
/* Mouse flags: */
, m_fIsMouseSupportsAbsolute(false)
, m_fIsMouseSupportsRelative(false)
, m_fIsMouseHostCursorNeeded(false)
, m_fIsMouseCaptured(false)
, m_fIsMouseIntegrated(true)
, m_fIsValidPointerShapePresent(false)
, m_fIsHidingHostPointer(true)
{
/* Prepare console event-handlers: */
/* Prepare screens: */
/* Prepare framebuffers: */
/* Prepare main-menu: */
/* Load settings: */
#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
}
{
/* Save settings: */
/* Cleanup main-menu: */
/* Cleanup framebuffers: */
/* Cleanup console event-handlers: */
#ifdef Q_WS_WIN
/* Destroy alpha cursor: */
if (m_alphaCursor)
#endif /* Q_WS_WIN */
}
{
/* Do nothing if we had started already: */
return;
/* Prepare powerup: */
/* Apply debug settings from the command line. */
{
if (vboxGlobal().isPatmDisabled())
debugger.SetPATMEnabled(false);
if (vboxGlobal().isCsamDisabled())
debugger.SetCSAMEnabled(false);
debugger.SetRecompileSupervisor(true);
if (vboxGlobal().isUserCodeExecedRecompiled())
debugger.SetRecompileUser(true);
}
/* Power UP machine: */
CProgress progress = vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled(machine) ?
/* Check for immediate failure: */
{
if (vboxGlobal().showStartVMErrors())
return;
}
/* Guard progressbar warnings from auto-closing: */
if (uimachine()->machineLogic())
if (isSaved())
msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_restore_90px.png", mainMachineWindow(), true, 0);
else
msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_start_90px.png", mainMachineWindow(), true);
/* Check for a progress failure: */
if (progress.GetResultCode() != 0)
{
if (vboxGlobal().showStartVMErrors())
return;
}
/* Allow further auto-closing: */
if (uimachine()->machineLogic())
/* Check if we missed a really quick termination after successful startup, and process it if we did: */
if (isTurnedOff())
{
return;
}
/* Check if the required virtualization features are active. We get this
* info only when the session is active. */
bool fIs64BitsGuest = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetIs64Bit();
bool fRecommendVirtEx = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetRecommendedVirtEx();
AssertMsg(!fIs64BitsGuest || fRecommendVirtEx, ("Virtualization support missed for 64bit guest!\n"));
if (fRecommendVirtEx && !fIsVirtEnabled)
{
bool fShouldWeClose;
setPause(true);
if (fIs64BitsGuest)
else
if (fShouldWeClose)
{
/* At this point the console is powered up. So we have to close
* this session again. */
{
/* Guard progressbar warnings from auto-closing: */
if (uimachine()->machineLogic())
/* Show the power down progress dialog */
msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_poweroff_90px.png", mainMachineWindow(), true);
if (progress.GetResultCode() != 0)
/* Allow further auto-closing: */
if (uimachine()->machineLogic())
}
else
/* Now signal the destruction of the rest. */
return;
}
setPause(false);
}
#ifdef VBOX_WITH_VIDEOHWACCEL
LogRel(("2D video acceleration is %s.\n",
? "enabled"
: "disabled"));
#endif
#ifdef VBOX_GUI_WITH_PIDFILE
vboxGlobal().createPidfile();
#endif
/* Warn listeners about machine was started: */
}
{
return uimachine()->machineLogic();
}
{
return machineLogic()->mainMachineWindow();
}
{
/* Create new menu: */
/* Re-init menu pool for the case menu were recreated: */
/* Return newly created menu: */
return pMenu;
}
{
/* Create new menubar: */
/* Re-init menu pool for the case menu were recreated: */
/* Return newly created menubar: */
return pMenuBar;
}
{
if (fOn)
else
if (!ok)
{
if (fOn)
else
}
return ok;
}
{
/*
* Flag indicating whether we want to do the usual .ISO mounting or not.
* First try updating the Guest Additions directly without mounting the .ISO.
*/
bool fDoMount = false;
/* Auto-update in GUI currently is disabled. */
fDoMount = true;
#else
/* Since we are going to show a modal progress dialog we don't want to wait for the whole
* update progress being complete - the user might need to interact with the VM to confirm (WHQL)
* popups - instead we only wait until the actual update process was started. */
if (fResult)
{
msgCenter().showModalProgressDialog(progressInstall, tr("Install"), ":/progress_install_guest_additions_90px.png",
if (progressInstall.GetCanceled())
return;
{
/* If we got back a VBOX_E_NOT_SUPPORTED we don't complain (guest OS
* simply isn't supported yet), so silently fall back to "old" .ISO
* mounting method. */
if ( !SUCCEEDED_WARNING(rc)
&& rc != VBOX_E_NOT_SUPPORTED)
{
/* Log the error message in the release log. */
}
fDoMount = true; /* Since automatic updating failed, fall back to .ISO mounting. */
}
}
#endif /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
if (fDoMount) /* Fallback to only mounting the .ISO file. */
{
CMedium image = vbox.OpenMedium(strSource, KDeviceType_DVD, KAccessMode_ReadWrite, false /* fForceNewUuid */);
{
image = vbox.OpenMedium(strSource, KDeviceType_DVD, KAccessMode_ReadWrite, false /* fForceNewUuid */);
}
else
{
return;
}
/* Searching for the first suitable slot */
{
int i = 0;
{
CMediumAttachmentVector attachments = machine.GetMediumAttachmentsOfController(controller.GetName());
int j = 0;
{
{
}
++ j;
}
++ i;
}
}
if (!strCntName.isNull())
{
/* Create a new UIMedium: */
/* Register it in GUI internal list: */
{
/* Ask for force mounting: */
if (msgCenter().cannotRemountMedium(0, machine, vboxMedium, true /* mount? */, true /* retry? */) == QIMessageBox::Ok)
{
}
}
}
else
}
}
void UISession::sltCloseVirtualSession()
{
* We have to make sure such window is hidden even if close-event was rejected.
* We are re-throwing this slot if any widget present to test again.
if (pWidget)
{
return;
}
/* Recursively close all the opened warnings... */
if (msgCenter().isAnyWarningShown())
{
return;
}
/* Finally, ask for closing virtual machine: */
}
void UISession::sltMousePointerShapeChange(bool fVisible, bool fAlpha, QPoint hotCorner, QSize size, QVector<uint8_t> shape)
{
/* In case of shape data is present: */
{
/* We are ignoring visibility flag: */
m_fIsHidingHostPointer = false;
/* And updating current cursor shape: */
}
/* In case of shape data is NOT present: */
else
{
/* Remember if we should hide the cursor: */
}
/* Notify listeners about mouse capability changed: */
}
void UISession::sltMouseCapabilityChange(bool fSupportsAbsolute, bool fSupportsRelative, bool fNeedsHostCursor)
{
/* Check if something had changed: */
{
/* Store new data: */
/* Notify listeners about mouse capability changed: */
}
}
{
/* Check if something had changed: */
if ( m_fNumLock != fNumLock
|| m_fCapsLock != fCapsLock
|| m_fScrollLock != fScrollLock)
{
/* Store new num lock data: */
if (m_fNumLock != fNumLock)
{
}
/* Store new caps lock data: */
if (m_fCapsLock != fCapsLock)
{
}
/* Store new scroll lock data: */
if (m_fScrollLock != fScrollLock)
{
}
/* Notify listeners about mouse capability changed: */
}
}
{
/* Check if something had changed: */
if (m_machineState != state)
{
/* Store new data: */
/* Notify listeners about machine state changed: */
}
}
void UISession::sltVRDEChange()
{
/* Get machine: */
/* Get VRDE server: */
/* Notify listeners about VRDE change: */
}
void UISession::sltAdditionsChange()
{
/* Get our guest: */
/* Variable flags: */
bool fIsGuestSupportsGraphics = guest.GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
bool fIsGuestSupportsSeamless = guest.GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
/* Check if something had changed: */
{
/* Store new data: */
/* Notify listeners about guest additions state changed: */
}
}
void UISession::prepareConsoleEventHandlers()
{
/* Initialize console event-handler: */
UIConsoleEventHandler::instance(this);
/* Add console event connections: */
connect(gConsoleEvents, SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
this, SLOT(sltMouseCapabilityChange(bool, bool, bool)));
this, SLOT(sltKeyboardLedsChangeEvent(bool, bool, bool)));
this, SLOT(sltAdditionsChange()));
this, SLOT(sltVRDEChange()));
this, SIGNAL(sigUSBControllerChange()));
this, SIGNAL(sigSharedFolderChange()));
#ifdef Q_WS_MAC
#endif /* Q_WS_MAC */
this, SIGNAL(sigCPUExecutionCapChange()));
}
void UISession::prepareScreens()
{
/* Get machine: */
/* Prepare initial screen visibility status: */
m_monitorVisibilityVector.fill(false);
m_monitorVisibilityVector[0] = true;
/* If machine is in 'saved' state: */
if (isSaved())
{
/* Update screen visibility status from saved-state: */
for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
{
machine.QuerySavedGuestScreenInfo(i, guestOriginX, guestOriginY, guestWidth, guestHeight, fEnabled);
}
/* And make sure at least one of them is visible (primary if others are hidden): */
if (countOfVisibleWindows() < 1)
m_monitorVisibilityVector[0] = true;
}
}
void UISession::prepareFramebuffers()
{
/* Each framebuffer will be really prepared on first UIMachineView creation: */
}
void UISession::prepareMenuPool()
{
m_pMenuPool = new UIMachineMenuBar;
}
void UISession::loadSessionSettings()
{
/* Get uisession machine: */
/* Load extra-data settings: */
{
/* Temporary: */
/* Is there should be First RUN Wizard? */
if (strSettings == "yes")
m_fIsFirstTimeStarted = true;
/* Ignore mediums mounted at runtime? */
if (strSettings == "no")
/* Should guest autoresize? */
#if 0 /* Disabled for now! */
# ifdef Q_WS_WIN
/* Disable host screen-saver if requested: */
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, false, 0, 0);
# endif /* Q_WS_WIN */
#endif
}
}
void UISession::saveSessionSettings()
{
/* Get uisession machine: */
/* Save extra-data settings: */
{
/* Disable First RUN Wizard for the since now: */
/* Remember if guest should autoresize: */
QString() : "off");
#if 0 /* Disabled for now! */
# ifdef Q_WS_WIN
/* Restore screen-saver activity to system default: */
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, true, 0, 0);
# endif /* Q_WS_WIN */
#endif
}
}
void UISession::cleanupMenuPool()
{
delete m_pMenuPool;
m_pMenuPool = 0;
}
void UISession::cleanupFramebuffers()
{
/* Cleanup framebuffers finally: */
{
if (pFb)
{
/* Warn framebuffer about its no more necessary: */
pFb->setDeleted(true);
/* Detach framebuffer from Display: */
/* Release the reference: */
}
}
}
void UISession::cleanupConsoleEventHandlers()
{
/* Destroy console event-handler: */
}
{
return mainMachineWindow()->winId();
}
{
m_fIsValidPointerShapePresent = false;
#if defined (Q_WS_WIN)
void *lpBits;
if (fHasAlpha)
else
bi.bV5AlphaMask = 0;
/* Create the DIB section with an alpha channel: */
hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD) 0);
if (fHasAlpha)
{
/* Create an empty mask bitmap: */
}
else
{
/* Word aligned AND mask. Will be allocated and created if necessary. */
/* Width in bytes of the original AND mask scan line. */
if (cbAndMaskScan & 1)
{
/* Original AND mask is not word aligned. */
/* Allocate memory for aligned AND mask. */
{
/* According to MSDN the padding bits must be 0.
* Compute the bit mask to set padding bits to 0 in the last byte of original AND mask. */
Log(("u8LastBytesPaddingMask = %02X, aligned w = %d, width = %d, cbAndMaskScan = %d\n",
unsigned i;
for (i = 0; i < uHeight; i++)
{
src += cbAndMaskScan;
}
}
}
/* Create the AND mask bitmap: */
{
}
}
if (hBitmap && hMonoBitmap)
{
{
dstShapePtr += uWidth;
}
if (hAlphaCursor)
{
/* Set the new cursor: */
if (m_alphaCursor)
m_fIsValidPointerShapePresent = true;
}
}
if (hMonoBitmap)
if (hBitmap)
if (img)
{
{
if (!fHasAlpha)
{
/* Convert AND mask to the alpha channel: */
{
if (!(x % 8))
byte = *(srcAndMaskPtr ++);
else
byte <<= 1;
if (byte & 0x80)
{
/* Linux doesn't support inverted pixels (XOR ops,
* to be exact) in cursor shapes, so we detect such
* pixels and always replace them with black ones to
* make them visible at least over light colors */
if (dstShapePtr [x] & 0x00FFFFFF)
dstShapePtr [x] = 0xFF000000;
else
dstShapePtr [x] = 0x00000000;
}
else
dstShapePtr [x] |= 0xFF000000;
}
}
dstShapePtr += uWidth;
}
/* Set the new cursor: */
m_fIsValidPointerShapePresent = true;
}
/* Create a ARGB image out of the shape data. */
for (unsigned int y = 0; y < uHeight; ++y)
{
for (unsigned int x = 0; x < uWidth; ++x)
{
/* If the alpha channel isn't in the shape data, we have to
* create them from the and-mask. This is a bit field where 1
* represent transparency & 0 opaque respectively. */
if (!fHasAlpha)
{
color |= 0xff000000;
else
{
/* This isn't quite right, but it's the best we can do I think... */
if (color & 0x00ffffff)
color = 0xff000000;
else
color = 0x00000000;
}
}
}
/* Move one scanline forward. */
}
/* Set the new cursor: */
m_fIsValidPointerShapePresent = true;
#else
# warning "port me"
#endif
}
void UISession::reinitMenuPool()
{
/* Get uisession machine: */
/* Storage stuff: */
{
int iDevicesCountCD = 0;
int iDevicesCountFD = 0;
for (int i = 0; i < attachments.size(); ++i)
{
}
}
/* Network stuff: */
{
bool fAtLeastOneAdapterActive = false;
ULONG uSlots = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3);
{
if (adapter.GetEnabled())
{
fAtLeastOneAdapterActive = true;
break;
}
}
gActionPool->action(UIActionIndexRuntime_Simple_NetworkAdaptersDialog)->setVisible(fAtLeastOneAdapterActive);
}
/* USB stuff: */
{
/* Get USB controller: */
bool fUSBControllerEnabled = !usbController.isNull() && usbController.GetEnabled() && usbController.GetProxyAvailable();
}
}
void UISession::preparePowerUp()
{
/* Notify user about mouse&keyboard auto-capturing: */
/* Shows First Run wizard if necessary: */
/* Check if we are in teleportation waiting mode.
* In that case no first run wizard is necessary. */
if ( isFirstTimeStarted()
&& !(( m_machineState == KMachineState_PoweredOff
&& machine.GetTeleporterEnabled()))
{
}
}
{
}
{
}
int UISession::countOfVisibleWindows()
{
int cCountOfVisibleWindows = 0;
for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
if (m_monitorVisibilityVector[i])
return cCountOfVisibleWindows;
}
{
}
{
}
/**
* Custom signal handler. When switching VTs, we might not get release events
* for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
* be saved with modifier keys stuck. This is annoying enough for introducing
* this hack.
*/
/* static */
{
/* only SIGUSR1 is interesting */
}
#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */