UISession.cpp revision 346af0930020342df40a1ca8d13eb185ad48067e
/* $Id$ */
/** @file
*
* VBox frontends: Qt GUI ("VirtualBox"):
* UISession stuff implementation
*/
/*
* Copyright (C) 2010 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.
*/
/* Global inclues */
#include <QApplication>
#include <QWidget>
#include <QTimer>
/* Local includes */
#include "UISession.h"
#include "UIMachine.h"
#include "UIActionsPool.h"
#include "UIMachineLogic.h"
#include "UIMachineWindow.h"
#include "UIMachineMenuBar.h"
#include "VBoxProblemReporter.h"
#include "UIFirstRunWzd.h"
#include "UIConsoleEventHandler.h"
#ifdef VBOX_WITH_VIDEOHWACCEL
# include "VBoxFBOverlay.h"
# include "UIFrameBuffer.h"
#endif
#ifdef Q_WS_X11
# include <QX11Info>
# ifndef VBOX_WITHOUT_XCURSOR
# endif
#endif
/* Base variables: */
/* Common variables: */
, m_pMenuPool(0)
#ifdef VBOX_WITH_VIDEOHWACCEL
#endif
#if defined(Q_WS_WIN)
, m_alphaCursor(0)
#endif
/* Common flags: */
, m_fIsFirstTimeStarted(false)
, m_fIsIgnoreRuntimeMediumsChanging(false)
, m_fIsGuestResizeIgnored(false)
, m_fIsSeamlessModeRequested(false)
, m_fIsAutoCaptureDisabled(false)
/* Guest additions flags: */
, m_fIsGuestAdditionsActive(false)
, 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)
{
/* Explicit initialize the 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, SIGNAL(sigUSBControllerChange()));
#ifdef Q_WS_MAC
this, SIGNAL(sigShowWindows()),
#endif /* Q_WS_MAC */
/* Prepare main menu: */
/* Load uisession settings: */
}
{
/* Save uisession settings: */
/* Cleanup main menu: */
/* Destroy the console event handler */
#if defined(Q_WS_WIN)
/* Destroy alpha cursor: */
if (m_alphaCursor)
#endif
#ifdef VBOX_WITH_VIDEOHWACCEL
{
if (pFb)
{
/* Warn framebuffer about its no more necessary: */
pFb->setDeleted(true);
/* Detach framebuffer from Display: */
/* Release the reference: */
}
}
#endif
}
{
/* Do nothing if we had started already: */
return;
/* Prepare powerup: */
/* Power UP machine: */
CProgress progress = vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled() ?
/* Check for immediate failure: */
{
if (vboxGlobal().showStartVMErrors())
return;
}
/* Guard progressbar warnings from auto-closing: */
if (uimachine()->machineLogic())
if (isSaved())
else
/* Allow further auto-closing: */
if (uimachine()->machineLogic())
/* Check for a progress failure: */
if (progress.GetResultCode() != 0)
{
if (vboxGlobal().showStartVMErrors())
return;
}
/* 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;
bool fVTxAMDVSupported = vboxGlobal().virtualBox().GetHost().GetProcessorFeature(KProcessorFeature_HWVirtEx);
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 */
if (progress.GetResultCode() != 0)
/* Allow further auto-closing: */
if (uimachine()->machineLogic())
}
else
/* Now signal the destruction of the rest. */
return;
}
else
setPause(false);
}
#if 0 // TODO: Rework debugger logic!
# ifdef VBOX_WITH_DEBUGGER_GUI
/* Open the debugger in "full screen" mode requested by the user. */
else if (vboxGlobal().isDebuggerAutoShowEnabled())
{
/* console in upper left corner of the desktop. */
if (desktop)
if (!vboxGlobal().isStartPausedEnabled())
}
# endif
#endif
#ifdef VBOX_WITH_VIDEOHWACCEL
LogRel(("2D video acceleration is %s.\n",
? "enabled"
: "disabled"));
#endif
/* Warn listeners about machine was started: */
}
{
return m_pMachine->actionsPool();
}
{
}
{
return uimachine()->machineLogic();
}
{
/* 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;
}
{
/* Commenting it out as isPaused() could reflect
* quite obsolete state due to synchronization: */
//if (isPaused() == fOn)
// return true;
if (fOn)
else
if (!ok)
{
if (fOn)
else
}
return ok;
}
{
{
}
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())
{
bool fIsMounted = false;
fIsMounted = true;
else
{
/* Ask for force mounting */
{
fIsMounted = true;
else
true /* mount? */, false /* retry? */);
}
}
}
else
}
void UISession::sltCloseVirtualSession()
{
/* Use a single shot with timeout 0 to allow the widgets to cleanly close and test then again.
* If all open widgets are closed destroy ourself: */
QApplication::activePopupWidget() : 0;
if (widget)
{
return;
}
}
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::sltAdditionsChange()
{
/* Get our guest: */
/* Variable flags: */
/* Check if something had changed: */
{
/* Store new data: */
/* Notify listeners about guest additions state changed: */
}
}
{
}
void UISession::prepareMenuPool()
{
m_pMenuPool = new UIMachineMenuBar;
}
void UISession::loadSessionSettings()
{
/* Get uisession machine: */
/* Availability settings: */
{
/* VRDP Stuff: */
if (vrdpServer.isNull())
{
/* Hide VRDP Action: */
}
else
{
}
}
/* Load extra-data settings: */
{
/* Temporary: */
/* Is there shoul be First RUN Wizard? */
if (strSettings == "yes")
m_fIsFirstTimeStarted = true;
/* Ignore mediums mounted at runtime? */
if (strSettings == "no")
/* Should guest autoresize? */
QAction *pGuestAutoresizeSwitch = uimachine()->actionsPool()->action(UIActionIndex_Toggle_GuestAutoresize);
}
}
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");
}
}
void UISession::cleanupMenuPool()
{
delete m_pMenuPool;
m_pMenuPool = 0;
}
{
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: */
/* Availability settings: */
{
/* USB Stuff: */
if ( usbController.isNull()
|| !usbController.GetEnabled()
|| !usbController.GetProxyAvailable())
{
/* Hide USB menu if controller is NULL or no USB proxy available: */
}
else
{
uimachine()->actionsPool()->action(UIActionIndex_Menu_USBDevices)->setEnabled(usbController.GetEnabled());
}
}
/* Prepare some initial settings: */
{
int iDevicesCountCD = 0;
int iDevicesCountFD = 0;
{
++ iDevicesCountCD;
++ iDevicesCountFD;
}
QAction *pOpticalDevicesMenu = uimachine()->actionsPool()->action(UIActionIndex_Menu_OpticalDevices);
}
}
void UISession::preparePowerUp()
{
#ifdef VBOX_WITH_UPDATE_REQUEST
/* Check for updates if necessary: */
#endif
/* 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()
&& !(( state == KMachineState_PoweredOff
|| state == KMachineState_Aborted
|| state == KMachineState_Teleported)
&& machine.GetTeleporterEnabled()))
{
}
}
#ifdef VBOX_WITH_VIDEOHWACCEL
{
}
{
{
return VINF_SUCCESS;
}
return VERR_INVALID_PARAMETER;
}
#endif