UIMachineLogicFullscreen.cpp revision 6ed3c00224eb14584c6539cbde1c2d521fd60d7e
/* $Id$ */
/** @file
* VBox Qt GUI - UIMachineLogicFullscreen class implementation.
*/
/*
* Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* 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 <QDesktopWidget>
#include <QTimer>
/* GUI includes: */
#include "VBoxGlobal.h"
#include "UIMessageCenter.h"
#include "UISession.h"
#include "UIActionPoolRuntime.h"
#include "UIMachineLogicFullscreen.h"
#include "UIMachineWindowFullscreen.h"
#include "UIMultiScreenLayout.h"
#include "UIShortcutPool.h"
#include "UIMachineView.h"
#include "QIMenu.h"
#ifdef Q_WS_MAC
# include "UICocoaApplication.h"
# include "UIExtraDataManager.h"
# include "VBoxUtils.h"
# include "UIFrameBuffer.h"
# include <Carbon/Carbon.h>
#endif /* Q_WS_MAC */
UIMachineLogicFullscreen::UIMachineLogicFullscreen(QObject *pParent, UISession *pSession)
: UIMachineLogic(pParent, pSession, UIVisualStateType_Fullscreen)
, m_pPopupMenu(0)
#ifdef Q_WS_MAC
, m_fScreensHaveSeparateSpaces(darwinScreensHaveSeparateSpaces())
#endif /* Q_WS_MAC */
{
/* Create multiscreen layout: */
m_pScreenLayout = new UIMultiScreenLayout(this);
actionPool()->toRuntime()->setMultiScreenLayout(m_pScreenLayout);
}
UIMachineLogicFullscreen::~UIMachineLogicFullscreen()
{
/* Delete multiscreen layout: */
actionPool()->toRuntime()->setMultiScreenLayout(0);
delete m_pScreenLayout;
}
bool UIMachineLogicFullscreen::checkAvailability()
{
/* Temporary get a machine object: */
const CMachine &machine = uisession()->session().GetMachine();
/* Check if there is enough physical memory to enter fullscreen: */
if (uisession()->isGuestAdditionsActive())
{
quint64 availBits = machine.GetVRAMSize() /* VRAM */ * _1M /* MiB to bytes */ * 8 /* to bits */;
quint64 usedBits = m_pScreenLayout->memoryRequirements();
if (availBits < usedBits)
{
if (!msgCenter().cannotEnterFullscreenMode(0, 0, 0, (((usedBits + 7) / 8 + _1M - 1) / _1M) * _1M))
return false;
}
}
/* Show the info message. */
const UIShortcut &shortcut =
gShortcutPool->shortcut(actionPool()->shortcutsExtraDataID(),
actionPool()->action(UIActionIndexRT_M_View_T_Fullscreen)->shortcutExtraDataID());
const QString strHotKey = QString("Host+%1").arg(shortcut.toString());
if (!msgCenter().confirmGoingFullscreen(strHotKey))
return false;
return true;
}
Qt::WindowFlags UIMachineLogicFullscreen::windowFlags(ulong uScreenId) const
{
Q_UNUSED(uScreenId);
#ifdef Q_WS_MAC
return vboxGlobal().osRelease() <= MacOSXRelease_Lion ? Qt::FramelessWindowHint :
uScreenId == 0 || screensHaveSeparateSpaces() ? Qt::Window : Qt::FramelessWindowHint;
#else /* !Q_WS_MAC */
return Qt::FramelessWindowHint;
#endif /* !Q_WS_MAC */
}
/** Adjusts guest screen count/size for the machine-logic we have. */
void UIMachineLogicFullscreen::maybeAdjustGuestScreenSize()
{
LogRel(("UIMachineLogicFullscreen::maybeAdjustGuestScreenSize"));
/* Rebuild multi-screen layout: */
m_pScreenLayout->rebuild();
#ifdef Q_WS_MAC
/* For Lion and previous: */
if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
{
/* Make sure all machine-window(s) have proper geometry: */
foreach (UIMachineWindow *pMachineWindow, machineWindows())
pMachineWindow->showInNecessaryMode();
}
/* Revalidate native fullscreen for ML and next: */
else revalidateNativeFullScreen();
#else /* !Q_WS_MAC */
/* Make sure all machine-window(s) have proper geometry: */
foreach (UIMachineWindow *pMachineWindow, machineWindows())
pMachineWindow->showInNecessaryMode();
#endif /* !Q_WS_MAC */
}
int UIMachineLogicFullscreen::hostScreenForGuestScreen(int iScreenId) const
{
return m_pScreenLayout->hostScreenForGuestScreen(iScreenId);
}
bool UIMachineLogicFullscreen::hasHostScreenForGuestScreen(int iScreenId) const
{
return m_pScreenLayout->hasHostScreenForGuestScreen(iScreenId);
}
#ifdef RT_OS_DARWIN
void UIMachineLogicFullscreen::sltHandleNativeFullscreenWillEnter()
{
/* Make sure this method is only used for ML and next: */
AssertReturnVoid(vboxGlobal().osRelease() > MacOSXRelease_Lion);
/* Get sender machine-window: */
UIMachineWindow *pMachineWindow = qobject_cast<UIMachineWindow*>(sender());
AssertPtrReturnVoid(pMachineWindow);
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenWillEnter: "
"Machine-window #%d will enter native fullscreen.\n",
(int)pMachineWindow->screenId()));
}
void UIMachineLogicFullscreen::sltHandleNativeFullscreenDidEnter()
{
/* Make sure this method is only used for ML and next: */
AssertReturnVoid(vboxGlobal().osRelease() > MacOSXRelease_Lion);
/* Get sender machine-window: */
UIMachineWindow *pMachineWindow = qobject_cast<UIMachineWindow*>(sender());
AssertPtrReturnVoid(pMachineWindow);
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenDidEnter: "
"Machine-window #%d did enter native fullscreen.\n",
(int)pMachineWindow->screenId()));
/* Add machine-window to corresponding set: */
m_fullscreenMachineWindows.insert(pMachineWindow);
AssertReturnVoid(m_fullscreenMachineWindows.contains(pMachineWindow));
/* Rebuild multi-screen layout: */
m_pScreenLayout->rebuild();
/* Revalidate native fullscreen: */
revalidateNativeFullScreen();
}
void UIMachineLogicFullscreen::sltHandleNativeFullscreenWillExit()
{
/* Make sure this method is only used for ML and next: */
AssertReturnVoid(vboxGlobal().osRelease() > MacOSXRelease_Lion);
/* Get sender machine-window: */
UIMachineWindow *pMachineWindow = qobject_cast<UIMachineWindow*>(sender());
AssertPtrReturnVoid(pMachineWindow);
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenWillExit: "
"Machine-window #%d will exit native fullscreen.\n",
(int)pMachineWindow->screenId()));
}
void UIMachineLogicFullscreen::sltHandleNativeFullscreenDidExit()
{
/* Make sure this method is only used for ML and next: */
AssertReturnVoid(vboxGlobal().osRelease() > MacOSXRelease_Lion);
/* Get sender machine-window: */
UIMachineWindow *pMachineWindow = qobject_cast<UIMachineWindow*>(sender());
AssertPtrReturnVoid(pMachineWindow);
/* Remove machine-window from corresponding set: */
bool fResult = m_fullscreenMachineWindows.remove(pMachineWindow);
AssertReturnVoid(!m_fullscreenMachineWindows.contains(pMachineWindow));
/* We have same signal if window did fail to enter native fullscreen.
* In that case window missed in m_fullscreenMachineWindows,
* ignore this signal silently: */
if (!fResult)
return;
/* If that window was invalidated: */
if (m_invalidFullscreenMachineWindows.contains(pMachineWindow))
{
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenDidExit: "
"Machine-window #%d exited invalidated native fullscreen, revalidate it.\n",
(int)pMachineWindow->screenId()));
/* Exclude machine-window from invalidation set: */
m_invalidFullscreenMachineWindows.remove(pMachineWindow);
AssertReturnVoid(!m_invalidFullscreenMachineWindows.contains(pMachineWindow));
/* Rebuild multi-screen layout: */
m_pScreenLayout->rebuild();
/* Revalidate native fullscreen: */
revalidateNativeFullScreen();
}
/* If there are no invalidated windows: */
else if (m_invalidFullscreenMachineWindows.isEmpty())
{
/* If there are 'fullscreen' windows: */
if (!m_fullscreenMachineWindows.isEmpty())
{
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenDidExit: "
"Machine-window #%d exited native fullscreen, asking others to exit too...\n",
(int)pMachineWindow->screenId()));
/* Ask window(s) to exit 'fullscreen' mode: */
emit sigNotifyAboutNativeFullscreenShouldBeExited();
}
/* If there are no 'fullscreen' windows: */
else
{
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenDidExit: "
"Machine-window #%d exited native fullscreen, changing visual-state to requested...\n",
(int)pMachineWindow->screenId()));
/* Change visual-state to requested: */
UIVisualStateType type = uisession()->requestedVisualState();
if (type == UIVisualStateType_Invalid)
type = UIVisualStateType_Normal;
uisession()->setRequestedVisualState(UIVisualStateType_Invalid);
uisession()->changeVisualState(type);
}
}
}
void UIMachineLogicFullscreen::sltHandleNativeFullscreenFailToEnter()
{
/* Make sure this method is only used for ML and next: */
AssertReturnVoid(vboxGlobal().osRelease() > MacOSXRelease_Lion);
/* Get sender machine-window: */
UIMachineWindow *pMachineWindow = qobject_cast<UIMachineWindow*>(sender());
AssertReturnVoid(pMachineWindow);
/* Make sure this window is not registered somewhere: */
AssertReturnVoid(!m_fullscreenMachineWindows.remove(pMachineWindow));
AssertReturnVoid(!m_invalidFullscreenMachineWindows.remove(pMachineWindow));
/* If there are 'fullscreen' windows: */
if (!m_fullscreenMachineWindows.isEmpty())
{
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenFailToEnter: "
"Machine-window #%d failed to enter native fullscreen, asking others to exit...\n",
(int)pMachineWindow->screenId()));
/* Ask window(s) to exit 'fullscreen' mode: */
emit sigNotifyAboutNativeFullscreenShouldBeExited();
}
/* If there are no 'fullscreen' windows: */
else
{
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenFailToEnter: "
"Machine-window #%d failed to enter native fullscreen, requesting change visual-state to normal...\n",
(int)pMachineWindow->screenId()));
/* Ask session to change 'fullscreen' mode to 'normal': */
uisession()->setRequestedVisualState(UIVisualStateType_Normal);
/* If session started already => push mode-change directly: */
if (uisession()->isStarted())
sltCheckForRequestedVisualStateType();
}
}
void UIMachineLogicFullscreen::sltChangeVisualStateToNormal()
{
/* Base-class handling for Lion and previous: */
if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
UIMachineLogic::sltChangeVisualStateToNormal();
/* Special handling for ML and next: */
else
{
/* Request 'normal' (window) visual-state: */
uisession()->setRequestedVisualState(UIVisualStateType_Normal);
/* Ask window(s) to exit 'fullscreen' mode: */
emit sigNotifyAboutNativeFullscreenShouldBeExited();
}
}
void UIMachineLogicFullscreen::sltChangeVisualStateToSeamless()
{
/* Base-class handling for Lion and previous: */
if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
UIMachineLogic::sltChangeVisualStateToSeamless();
/* Special handling for ML and next: */
else
{
/* Request 'seamless' visual-state: */
uisession()->setRequestedVisualState(UIVisualStateType_Seamless);
/* Ask window(s) to exit 'fullscreen' mode: */
emit sigNotifyAboutNativeFullscreenShouldBeExited();
}
}
void UIMachineLogicFullscreen::sltChangeVisualStateToScale()
{
/* Base-class handling for Lion and previous: */
if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
UIMachineLogic::sltChangeVisualStateToScale();
/* Special handling for ML and next: */
else
{
/* Request 'scale' visual-state: */
uisession()->setRequestedVisualState(UIVisualStateType_Scale);
/* Ask window(s) to exit 'fullscreen' mode: */
emit sigNotifyAboutNativeFullscreenShouldBeExited();
}
}
void UIMachineLogicFullscreen::sltCheckForRequestedVisualStateType()
{
/* Do not try to change visual-state type if machine was not started yet: */
if (!uisession()->isRunning() && !uisession()->isPaused())
return;
/* Check requested visual-state types: */
switch (uisession()->requestedVisualState())
{
/* If 'normal' visual-state type is requested: */
case UIVisualStateType_Normal:
{
LogRel(("UIMachineLogicFullscreen::sltCheckForRequestedVisualStateType: "
"Going 'normal' as requested...\n"));
uisession()->setRequestedVisualState(UIVisualStateType_Invalid);
uisession()->changeVisualState(UIVisualStateType_Normal);
break;
}
default:
break;
}
}
#endif /* RT_OS_DARWIN */
void UIMachineLogicFullscreen::sltMachineStateChanged()
{
/* Call to base-class: */
UIMachineLogic::sltMachineStateChanged();
/* If machine-state changed from 'paused' to 'running': */
if (uisession()->isRunning() && uisession()->wasPaused())
{
LogRelFlow(("UIMachineLogicFullscreen: "
"Machine-state changed from 'paused' to 'running': "
"Updating screen-layout...\n"));
/* Make sure further code will be called just once: */
uisession()->forgetPreviousMachineState();
/* Adjust guest-screen size if necessary: */
maybeAdjustGuestScreenSize();
}
}
void UIMachineLogicFullscreen::sltInvokePopupMenu()
{
/* Popup main-menu if present: */
if (m_pPopupMenu && !m_pPopupMenu->isEmpty())
{
m_pPopupMenu->popup(activeMachineWindow()->geometry().center());
QTimer::singleShot(0, m_pPopupMenu, SLOT(sltHighlightFirstAction()));
}
}
#ifdef Q_WS_MAC
void UIMachineLogicFullscreen::sltChangePresentationMode(bool /* fEnabled */)
{
setPresentationModeEnabled(true);
}
#endif /* Q_WS_MAC */
void UIMachineLogicFullscreen::sltScreenLayoutChanged()
{
LogRel(("UIMachineLogicFullscreen::sltScreenLayoutChanged: Multi-screen layout changed.\n"));
#ifdef Q_WS_MAC
/* For Lion and previous: */
if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
{
/* Make sure all machine-window(s) have proper geometry: */
foreach (UIMachineWindow *pMachineWindow, machineWindows())
pMachineWindow->showInNecessaryMode();
/* Update 'presentation mode': */
setPresentationModeEnabled(true);
}
/* Revalidate native fullscreen for ML and next: */
else revalidateNativeFullScreen();
#else /* !Q_WS_MAC */
/* Make sure all machine-window(s) have proper geometry: */
foreach (UIMachineWindow *pMachineWindow, machineWindows())
pMachineWindow->showInNecessaryMode();
#endif /* !Q_WS_MAC */
}
void UIMachineLogicFullscreen::sltGuestMonitorChange(KGuestMonitorChangedEventType changeType, ulong uScreenId, QRect screenGeo)
{
LogRel(("UIMachineLogicFullscreen: Guest-screen count changed.\n"));
/* Rebuild multi-screen layout: */
m_pScreenLayout->rebuild();
#ifdef Q_WS_MAC
/* Call to base-class for Lion and previous: */
if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
UIMachineLogic::sltGuestMonitorChange(changeType, uScreenId, screenGeo);
/* Revalidate native fullscreen for ML and next: */
else revalidateNativeFullScreen();
#else /* !Q_WS_MAC */
/* Call to base-class: */
UIMachineLogic::sltGuestMonitorChange(changeType, uScreenId, screenGeo);
#endif /* !Q_WS_MAC */
}
void UIMachineLogicFullscreen::sltHostScreenCountChange()
{
LogRel(("UIMachineLogicFullscreen: Host-screen count changed.\n"));
/* Rebuild multi-screen layout: */
m_pScreenLayout->rebuild();
#ifdef Q_WS_MAC
/* Call to base-class for Lion and previous: */
if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
UIMachineLogic::sltHostScreenCountChange();
/* Revalidate native fullscreen for ML and next: */
else revalidateNativeFullScreen();
#else /* !Q_WS_MAC */
/* Call to base-class: */
UIMachineLogic::sltHostScreenCountChange();
#endif /* !Q_WS_MAC */
}
void UIMachineLogicFullscreen::sltHostScreenAvailableAreaChange()
{
LogRel(("UIMachineLogicFullscreen: Host-screen available-area change ignored.\n"));
}
void UIMachineLogicFullscreen::prepareActionGroups()
{
/* Call to base-class: */
UIMachineLogic::prepareActionGroups();
/* Restrict 'Adjust Window', 'Status Bar' and 'Resize' actions for 'View' menu: */
actionPool()->toRuntime()->setRestrictionForMenuView(UIActionRestrictionLevel_Logic,
(UIExtraDataMetaDefs::RuntimeMenuViewActionType)
(UIExtraDataMetaDefs::RuntimeMenuViewActionType_AdjustWindow |
UIExtraDataMetaDefs::RuntimeMenuViewActionType_MenuBar |
UIExtraDataMetaDefs::RuntimeMenuViewActionType_StatusBar |
UIExtraDataMetaDefs::RuntimeMenuViewActionType_Resize));
/* Take care of view-action toggle state: */
UIAction *pActionFullscreen = actionPool()->action(UIActionIndexRT_M_View_T_Fullscreen);
if (!pActionFullscreen->isChecked())
{
pActionFullscreen->blockSignals(true);
pActionFullscreen->setChecked(true);
pActionFullscreen->blockSignals(false);
}
}
void UIMachineLogicFullscreen::prepareActionConnections()
{
/* Call to base-class: */
UIMachineLogic::prepareActionConnections();
/* Prepare 'View' actions connections: */
connect(actionPool()->action(UIActionIndexRT_M_View_T_Fullscreen), SIGNAL(triggered(bool)),
this, SLOT(sltChangeVisualStateToNormal()));
connect(actionPool()->action(UIActionIndexRT_M_View_T_Seamless), SIGNAL(triggered(bool)),
this, SLOT(sltChangeVisualStateToSeamless()));
connect(actionPool()->action(UIActionIndexRT_M_View_T_Scale), SIGNAL(triggered(bool)),
this, SLOT(sltChangeVisualStateToScale()));
}
#ifdef Q_WS_MAC
void UIMachineLogicFullscreen::prepareOtherConnections()
{
/* Make sure 'presentation mode' preference handling
* is updated at runtime for Lion and previous: */
if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
connect(gEDataManager, SIGNAL(sigPresentationModeChange(bool)),
this, SLOT(sltChangePresentationMode(bool)));
}
#endif /* Q_WS_MAC */
void UIMachineLogicFullscreen::prepareMachineWindows()
{
/* Do not create machine-window(s) if they created already: */
if (isMachineWindowsCreated())
return;
#ifdef Q_WS_MAC
/* For ML and next: */
if (vboxGlobal().osRelease() > MacOSXRelease_Lion)
{
/* Register to native notifications: */
UICocoaApplication::instance()->registerToNotificationOfWorkspace("NSWorkspaceDidActivateApplicationNotification", this,
UIMachineLogicFullscreen::nativeHandlerForApplicationActivation);
}
/* We have to make sure that we are getting the front most process.
* This is necessary for Qt versions > 4.3.3: */
darwinSetFrontMostProcess();
#endif /* Q_WS_MAC */
/* Update the multi-screen layout: */
m_pScreenLayout->update();
/* Create machine-window(s): */
for (uint cScreenId = 0; cScreenId < session().GetMachine().GetMonitorCount(); ++cScreenId)
addMachineWindow(UIMachineWindow::create(this, cScreenId));
/* Listen for frame-buffer resize: */
foreach (UIMachineWindow *pMachineWindow, machineWindows())
connect(pMachineWindow, SIGNAL(sigFrameBufferResize()),
this, SIGNAL(sigFrameBufferResize()));
emit sigFrameBufferResize();
/* Connect multi-screen layout change handler: */
connect(m_pScreenLayout, SIGNAL(sigScreenLayoutChange()),
this, SLOT(sltScreenLayoutChanged()));
#ifdef Q_WS_MAC
/* Activate 'presentation mode': */
setPresentationModeEnabled(true);
/* For ML and next: */
if (vboxGlobal().osRelease() > MacOSXRelease_Lion)
{
/* Enable native fullscreen support: */
foreach (UIMachineWindow *pMachineWindow, machineWindows())
{
/* Logic => window signals: */
connect(this, SIGNAL(sigNotifyAboutNativeFullscreenShouldBeEntered(UIMachineWindow*)),
pMachineWindow, SLOT(sltEnterNativeFullscreen(UIMachineWindow*)));
connect(this, SIGNAL(sigNotifyAboutNativeFullscreenShouldBeExited(UIMachineWindow*)),
pMachineWindow, SLOT(sltExitNativeFullscreen(UIMachineWindow*)));
/* Window => logic signals: */
connect(pMachineWindow, SIGNAL(sigNotifyAboutNativeFullscreenWillEnter()),
this, SLOT(sltHandleNativeFullscreenWillEnter()),
Qt::QueuedConnection);
connect(pMachineWindow, SIGNAL(sigNotifyAboutNativeFullscreenDidEnter()),
this, SLOT(sltHandleNativeFullscreenDidEnter()),
Qt::QueuedConnection);
connect(pMachineWindow, SIGNAL(sigNotifyAboutNativeFullscreenWillExit()),
this, SLOT(sltHandleNativeFullscreenWillExit()),
Qt::QueuedConnection);
connect(pMachineWindow, SIGNAL(sigNotifyAboutNativeFullscreenDidExit()),
this, SLOT(sltHandleNativeFullscreenDidExit()),
Qt::QueuedConnection);
connect(pMachineWindow, SIGNAL(sigNotifyAboutNativeFullscreenFailToEnter()),
this, SLOT(sltHandleNativeFullscreenFailToEnter()),
Qt::QueuedConnection);
}
/* Revalidate native fullscreen: */
revalidateNativeFullScreen();
}
#endif /* Q_WS_MAC */
/* Mark machine-window(s) created: */
setMachineWindowsCreated(true);
}
void UIMachineLogicFullscreen::prepareMenu()
{
/* Prepare popup-menu: */
m_pPopupMenu = new QIMenu;
AssertPtrReturnVoid(m_pPopupMenu);
{
/* Prepare popup-menu: */
foreach (QMenu *pMenu, actionPool()->menus())
m_pPopupMenu->addMenu(pMenu);
}
}
void UIMachineLogicFullscreen::cleanupMenu()
{
/* Cleanup popup-menu: */
delete m_pPopupMenu;
m_pPopupMenu = 0;
}
void UIMachineLogicFullscreen::cleanupMachineWindows()
{
/* Do not destroy machine-window(s) if they destroyed already: */
if (!isMachineWindowsCreated())
return;
#ifdef Q_WS_MAC
/* For ML and next: */
if (vboxGlobal().osRelease() > MacOSXRelease_Lion)
{
/* Unregister from native notifications: */
UICocoaApplication::instance()->unregisterFromNotificationOfWorkspace("NSWorkspaceDidActivateApplicationNotification", this);
}
#endif/* Q_WS_MAC */
/* Mark machine-window(s) destroyed: */
setMachineWindowsCreated(false);
/* Destroy machine-window(s): */
foreach (UIMachineWindow *pMachineWindow, machineWindows())
UIMachineWindow::destroy(pMachineWindow);
#ifdef Q_WS_MAC
/* Deactivate 'presentation mode': */
setPresentationModeEnabled(false);
#endif/* Q_WS_MAC */
}
void UIMachineLogicFullscreen::cleanupActionConnections()
{
/* "View" actions disconnections: */
disconnect(actionPool()->action(UIActionIndexRT_M_View_T_Fullscreen), SIGNAL(triggered(bool)),
this, SLOT(sltChangeVisualStateToNormal()));
disconnect(actionPool()->action(UIActionIndexRT_M_View_T_Seamless), SIGNAL(triggered(bool)),
this, SLOT(sltChangeVisualStateToSeamless()));
disconnect(actionPool()->action(UIActionIndexRT_M_View_T_Scale), SIGNAL(triggered(bool)),
this, SLOT(sltChangeVisualStateToScale()));
/* Call to base-class: */
UIMachineLogic::cleanupActionConnections();
}
void UIMachineLogicFullscreen::cleanupActionGroups()
{
/* Take care of view-action toggle state: */
UIAction *pActionFullscreen = actionPool()->action(UIActionIndexRT_M_View_T_Fullscreen);
if (pActionFullscreen->isChecked())
{
pActionFullscreen->blockSignals(true);
pActionFullscreen->setChecked(false);
pActionFullscreen->blockSignals(false);
}
/* Allow 'Adjust Window', 'Status Bar' and 'Resize' actions for 'View' menu: */
actionPool()->toRuntime()->setRestrictionForMenuView(UIActionRestrictionLevel_Logic,
UIExtraDataMetaDefs::RuntimeMenuViewActionType_Invalid);
/* Call to base-class: */
UIMachineLogic::cleanupActionGroups();
}
#ifdef Q_WS_MAC
void UIMachineLogicFullscreen::setPresentationModeEnabled(bool fEnabled)
{
/* Should we enable it? */
if (fEnabled)
{
/* For Lion and previous: */
if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
{
/* Check if we have screen which contains the Dock or the Menubar (which hasn't to be the same),
* only than the 'presentation mode' have to be changed. */
if (m_pScreenLayout->isHostTaskbarCovert())
{
if (gEDataManager->presentationModeEnabled(vboxGlobal().managedVMUuid()))
SetSystemUIMode(kUIModeAllHidden, 0);
else
SetSystemUIMode(kUIModeAllSuppressed, 0);
}
}
/* For ML and next: */
else
{
/* I am not sure we have to check anything here.
* Without 'presentation mode' native fullscreen works pretty bad,
* so we have to enable it anyway: */
SetSystemUIMode(kUIModeAllSuppressed, 0);
}
}
/* Should we disable it? */
else SetSystemUIMode(kUIModeNormal, 0);
}
void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMachineWindow)
{
/* Make sure window is not already invalidated: */
if (m_invalidFullscreenMachineWindows.contains(pMachineWindow))
return;
/* Ignore window if it is in 'fullscreen transition': */
if (qobject_cast<UIMachineWindowFullscreen*>(pMachineWindow)->isInFullscreenTransition())
return;
/* Get screen ID: */
const ulong uScreenID = pMachineWindow->screenId();
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: For machine-window #%d.\n",
(int)uScreenID));
/* Validate window which can't be fullscreen: */
if (uScreenID != 0 && !screensHaveSeparateSpaces())
{
/* We are hiding transient window if:
* 1. application is inactive at all or
* 2. there is no fullscreen window or it's invalidated. */
if ( !UICocoaApplication::instance()->isActive()
|| m_fullscreenMachineWindows.isEmpty() || !m_invalidFullscreenMachineWindows.isEmpty())
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask transient machine-window #%d to hide.\n", (int)uScreenID));
pMachineWindow->hide();
}
/* If there is valid fullscreen window: */
else
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask transient machine-window #%d to show/normalize.\n", (int)uScreenID));
/* Make sure window have proper geometry and shown: */
pMachineWindow->showInNecessaryMode();
}
}
/* Validate window which can be fullscreen: */
else
{
/* Validate window which is not in fullscreen: */
if (!darwinIsInFullscreenMode(pMachineWindow))
{
/* If that window
* 1. should really be shown and
* 2. is mapped to some host-screen: */
if ( uisession()->isScreenVisible(uScreenID)
&& hasHostScreenForGuestScreen(uScreenID))
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask machine-window #%d to enter native fullscreen.\n", (int)uScreenID));
/* Update 'presentation mode': */
setPresentationModeEnabled(true);
/* Make sure window have proper geometry and shown: */
pMachineWindow->showInNecessaryMode();
/* Ask window to enter 'fullscreen' mode: */
emit sigNotifyAboutNativeFullscreenShouldBeEntered(pMachineWindow);
}
/* If that window
* is shown while shouldn't: */
else if (pMachineWindow->isVisible())
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask machine-window #%d to hide.\n", (int)uScreenID));
pMachineWindow->hide();
}
}
/* Validate window which is in fullscreen: */
else
{
/* Variables to compare: */
const int iWantedHostScreenIndex = hostScreenForGuestScreen((int)uScreenID);
const int iCurrentHostScreenIndex = QApplication::desktop()->screenNumber(pMachineWindow);
const QSize frameBufferSize((int)uisession()->frameBuffer(uScreenID)->width(), (int)uisession()->frameBuffer(uScreenID)->height());
const QSize screenSize = QApplication::desktop()->screenGeometry(iWantedHostScreenIndex).size();
/* If that window
* 1. shouldn't really be shown or
* 2. isn't mapped to some host-screen or
* 3. should be located on another host-screen than currently. */
if ( !uisession()->isScreenVisible(uScreenID)
|| !hasHostScreenForGuestScreen(uScreenID)
|| iWantedHostScreenIndex != iCurrentHostScreenIndex)
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask machine-window #%d to exit native fullscreen.\n", (int)uScreenID));
/* Mark window as invalidated: */
m_invalidFullscreenMachineWindows << pMachineWindow;
/* Ask window to exit 'fullscreen' mode: */
emit sigNotifyAboutNativeFullscreenShouldBeExited(pMachineWindow);
}
/* If that window
* 1. have another frame-buffer size than actually should. */
else if (frameBufferSize != screenSize)
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask machine-window #%d to adjust guest geometry.\n", (int)uScreenID));
/* Adjust guest screen size if necessary: */
pMachineWindow->machineView()->maybeAdjustGuestScreenSize();
}
}
}
}
void UIMachineLogicFullscreen::revalidateNativeFullScreen()
{
/* Revalidate all fullscreen windows: */
foreach (UIMachineWindow *pMachineWindow, machineWindows())
revalidateNativeFullScreen(pMachineWindow);
}
/* static */
void UIMachineLogicFullscreen::nativeHandlerForApplicationActivation(QObject *pObject, const QMap<QString, QString> &userInfo)
{
/* Handle arrived notification: */
UIMachineLogicFullscreen *pLogic = qobject_cast<UIMachineLogicFullscreen*>(pObject);
AssertPtrReturnVoid(pLogic);
{
/* Redirect arrived notification: */
pLogic->nativeHandlerForApplicationActivation(userInfo);
}
}
void UIMachineLogicFullscreen::nativeHandlerForApplicationActivation(const QMap<QString, QString> &userInfo)
{
/* Make sure we have BundleIdentifier key: */
AssertReturnVoid(userInfo.contains("BundleIdentifier"));
/* On VirtualBox activation: */
if (userInfo.value("BundleIdentifier") == "org.virtualbox.app.VirtualBox")
{
LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: BundleIdentifier = %s\n",
userInfo.value("BundleIdentifier").toAscii().constData()));
/* Make sure all the transient machine-windows updated: */
foreach (UIMachineWindow *pMachineWindow, machineWindows())
if (pMachineWindow->screenId() != 0 && !screensHaveSeparateSpaces())
{
/* If there is no fullscreen window or it's invalidated: */
if (m_fullscreenMachineWindows.isEmpty() || !m_invalidFullscreenMachineWindows.isEmpty())
{
LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: "
"Ask transient machine-window #%d to hide.\n", (int)pMachineWindow->screenId()));
pMachineWindow->hide();
}
/* If there is valid fullscreen window: */
else
{
LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: "
"Ask transient machine-window #%d to show/normalize.\n", (int)pMachineWindow->screenId()));
/* Make sure window have proper geometry and shown: */
pMachineWindow->showInNecessaryMode();
}
}
}
}
#endif /* Q_WS_MAC */