UIMachineLogicFullscreen.cpp revision 1989f94eb97ec131b14e841c8025f7d9af72a412
/* $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;
* 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 "QIMenu.h"
#ifdef Q_WS_MAC
# include "UIExtraDataManager.h"
# include "VBoxUtils.h"
# include "UIFrameBuffer.h"
#endif /* Q_WS_MAC */
, m_pPopupMenu(0)
#ifdef Q_WS_MAC
#endif /* Q_WS_MAC */
{
/* Create multiscreen layout: */
m_pScreenLayout = new UIMultiScreenLayout(this);
}
{
/* Delete multiscreen layout: */
delete m_pScreenLayout;
}
{
/* Temporary get a machine object: */
/* Check if there is enough physical memory to enter fullscreen: */
if (uisession()->isGuestAdditionsActive())
{
{
return false;
}
}
/* Show the info message. */
const UIShortcut &shortcut =
return false;
return true;
}
{
/* We should rebuild screen-layout: */
/* Make sure all machine-window(s) have proper geometry: */
}
{
}
{
}
#ifdef RT_OS_DARWIN
{
/* Make sure this method is only used for ML and next: */
/* Get sender machine-window: */
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenWillEnter: "
"Machine-window #%d will enter native fullscreen.\n",
(int)pMachineWindow->screenId()));
/* Fade to black: */
fadeToBlack();
}
{
/* Make sure this method is only used for ML and next: */
/* Get sender machine-window: */
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenDidEnter: "
"Machine-window #%d did enter native fullscreen.\n",
(int)pMachineWindow->screenId()));
/* Add machine-window to corresponding set: */
/* Fade to normal if necessary: */
if ( !screensHaveSeparateSpaces()
fadeToNormal();
}
{
/* Make sure this method is only used for ML and next: */
/* Get sender machine-window: */
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenWillExit: "
"Machine-window #%d will exit native fullscreen.\n",
(int)pMachineWindow->screenId()));
/* Fade to black: */
fadeToBlack();
}
{
/* Make sure this method is only used for ML and next: */
/* Get sender machine-window: */
/* Remove machine-window from corresponding set: */
/* 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: */
{
LogRel(("UIMachineLogicFullscreen::sltHandleNativeFullscreenDidExit: "
"Machine-window #%d exited invalidated native fullscreen, revalidate it.\n",
(int)pMachineWindow->screenId()));
/* Exclude window from invalidation list: */
/* Revalidate 'fullscreen' window: */
}
/* 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: */
}
/* 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: */
if (type == UIVisualStateType_Invalid)
/* Fade to normal: */
fadeToNormal();
}
}
}
{
/* Make sure this method is only used for ML and next: */
/* Get sender machine-window: */
/* Make sure this window is not registered somewhere: */
/* 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: */
}
/* 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': */
/* If session started already => push mode-change directly: */
}
}
{
/* Base-class handling for Lion and previous: */
/* Special handling for ML and next: */
else
{
/* Request 'normal' (window) visual-state: */
/* Ask window(s) to exit 'fullscreen' mode: */
}
}
{
/* Base-class handling for Lion and previous: */
/* Special handling for ML and next: */
else
{
/* Request 'seamless' visual-state: */
/* Ask window(s) to exit 'fullscreen' mode: */
}
}
{
/* Base-class handling for Lion and previous: */
/* Special handling for ML and next: */
else
{
/* Request 'scale' visual-state: */
/* Ask window(s) to exit 'fullscreen' mode: */
}
}
{
/* Do not try to change visual-state type if machine was not started yet: */
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"));
break;
}
default:
break;
}
}
#endif /* RT_OS_DARWIN */
{
/* Call to base-class: */
/* If machine-state changed from 'paused' to 'running': */
{
LogRelFlow(("UIMachineLogicFullscreen: "
"Machine-state changed from 'paused' to 'running': "
"Updating screen-layout...\n"));
/* Make sure further code will be called just once: */
/* We should rebuild screen-layout: */
/* Make sure all machine-window(s) have proper geometry: */
}
}
{
/* Popup main-menu if present: */
{
}
}
#ifdef Q_WS_MAC
{
setPresentationModeEnabled(true);
}
#endif /* Q_WS_MAC */
{
LogRel(("UIMachineLogicFullscreen::sltScreenLayoutChanged: Multi-screen layout changed.\n"));
#ifdef Q_WS_MAC
/* For Lion and previous: */
{
/* Make sure all machine-window(s) have proper geometry: */
/* Update 'presentation mode': */
setPresentationModeEnabled(true);
}
/* Revalidate 'fullscreen' windows for ML and next: */
else revalidateNativeFullScreen();
#else /* !Q_WS_MAC */
/* Make sure all machine-window(s) have proper geometry: */
#endif /* !Q_WS_MAC */
}
void UIMachineLogicFullscreen::sltGuestMonitorChange(KGuestMonitorChangedEventType changeType, ulong uScreenId, QRect screenGeo)
{
LogRel(("UIMachineLogicFullscreen: Guest-screen count changed.\n"));
/* Update multi-screen layout before any window update: */
#ifdef Q_WS_MAC
/* Call to base-class for Lion and previous: */
/* Revalidate 'fullscreen' windows for ML and next: */
else revalidateNativeFullScreen();
#else /* !Q_WS_MAC */
/* Call to base-class: */
#endif /* !Q_WS_MAC */
}
{
LogRel(("UIMachineLogicFullscreen: Host-screen count changed.\n"));
/* Update multi-screen layout before any window update: */
#ifdef Q_WS_MAC
/* Call to base-class for Lion and previous: */
/* Revalidate 'fullscreen' windows for ML and next: */
else revalidateNativeFullScreen();
#else /* !Q_WS_MAC */
/* Call to base-class: */
#endif /* !Q_WS_MAC */
}
{
LogRel(("UIMachineLogicFullscreen: Host-screen available-area change ignored.\n"));
}
{
/* Call to base-class: */
/* Restrict 'Adjust Window', 'Status Bar' and 'Resize' actions for 'View' menu: */
/* Take care of view-action toggle state: */
if (!pActionFullscreen->isChecked())
{
pActionFullscreen->blockSignals(true);
pActionFullscreen->setChecked(true);
pActionFullscreen->blockSignals(false);
}
}
{
/* Call to base-class: */
/* Prepare 'View' actions connections: */
this, SLOT(sltChangeVisualStateToNormal()));
this, SLOT(sltChangeVisualStateToSeamless()));
this, SLOT(sltChangeVisualStateToScale()));
}
#ifdef Q_WS_MAC
{
/* Make sure 'presentation mode' preference handling
* is updated at runtime for Lion and previous: */
this, SLOT(sltChangePresentationMode(bool)));
}
#endif /* Q_WS_MAC */
{
/* Do not create machine-window(s) if they created already: */
if (isMachineWindowsCreated())
return;
#ifdef Q_WS_MAC
/* We have to make sure that we are getting the front most process.
* This is necessary for Qt versions > 4.3.3: */
/* Fade to black: */
fadeToBlack();
#endif /* Q_WS_MAC */
/* Update the multi-screen layout: */
/* Create machine-window(s): */
/* Listen for frame-buffer resize: */
this, SIGNAL(sigFrameBufferResize()));
/* Connect multi-screen layout change handler: */
this, SLOT(sltScreenLayoutChanged()));
#ifdef Q_WS_MAC
/* Activate 'presentation mode': */
setPresentationModeEnabled(true);
/* For Lion and previous fade to normal: */
fadeToNormal();
/* For ML and next: */
{
/* Enable native fullscreen support: */
{
/* Logic => window signals: */
/* Window => logic signals: */
this, SLOT(sltHandleNativeFullscreenWillEnter()),
this, SLOT(sltHandleNativeFullscreenDidEnter()),
this, SLOT(sltHandleNativeFullscreenWillExit()),
this, SLOT(sltHandleNativeFullscreenDidExit()),
this, SLOT(sltHandleNativeFullscreenFailToEnter()),
}
/* Revalidate 'fullscreen' windows: */
}
#endif /* Q_WS_MAC */
/* Mark machine-window(s) created: */
setMachineWindowsCreated(true);
}
void UIMachineLogicFullscreen::prepareMenu()
{
/* Prepare popup-menu: */
m_pPopupMenu = new QIMenu;
{
/* Prepare popup-menu: */
}
}
void UIMachineLogicFullscreen::cleanupMenu()
{
/* Cleanup popup-menu: */
delete m_pPopupMenu;
m_pPopupMenu = 0;
}
{
/* Do not destroy machine-window(s) if they destroyed already: */
if (!isMachineWindowsCreated())
return;
#ifdef Q_WS_MAC
/* For Lion and previous fade to black: */
fadeToBlack();
#endif/* Q_WS_MAC */
/* Mark machine-window(s) destroyed: */
setMachineWindowsCreated(false);
/* Destroy machine-window(s): */
#ifdef Q_WS_MAC
/* Deactivate 'presentation mode': */
setPresentationModeEnabled(false);
/* Fade to normal: */
fadeToNormal();
#endif/* Q_WS_MAC */
}
{
/* "View" actions disconnections: */
this, SLOT(sltChangeVisualStateToNormal()));
this, SLOT(sltChangeVisualStateToSeamless()));
this, SLOT(sltChangeVisualStateToScale()));
/* Call to base-class: */
}
{
/* Take care of view-action toggle state: */
if (pActionFullscreen->isChecked())
{
pActionFullscreen->blockSignals(true);
pActionFullscreen->setChecked(false);
pActionFullscreen->blockSignals(false);
}
/* Allow 'Adjust Window', 'Status Bar' and 'Resize' actions for 'View' menu: */
/* Call to base-class: */
}
#ifdef Q_WS_MAC
{
/* Should we enable it? */
if (fEnabled)
{
/* For Lion and previous: */
{
/* 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())
{
else
}
}
/* 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: */
}
}
/* Should we disable it? */
else SetSystemUIMode(kUIModeNormal, 0);
}
void UIMachineLogicFullscreen::fadeToBlack()
{
/* Make sure fade-token invalid: */
return;
/* Acquire fade-token: */
LogRel(("UIMachineLogicFullscreen::fadeToBlack\n"));
CGDisplayFade(m_fadeToken, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, true);
}
void UIMachineLogicFullscreen::fadeToNormal()
{
/* Make sure fade-token valid: */
return;
/* Release fade-token: */
LogRel(("UIMachineLogicFullscreen::fadeToNormal\n"));
CGDisplayFade(m_fadeToken, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, false);
}
{
/* Make sure window is not already invalidated: */
return;
/* Ignore window if it is in 'fullscreen transition': */
return;
/* Get screen ID: */
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: For machine-window #%d.\n",
(int)uScreenID));
/* Validate window which can't be fullscreen: */
if (uScreenID != 0 && !screensHaveSeparateSpaces())
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
/* Make sure window have proper geometry: */
}
/* Validate window which can be fullscreen: */
else
{
/* Validate window which is not in fullscreen: */
{
/* If that window
* 1. should really be shown and
* 2. is mapped to some host-screen: */
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask machine-window #%d to enter native fullscreen.\n", (int)uScreenID));
/* Fade to black: */
fadeToBlack();
/* Update 'presentation mode': */
setPresentationModeEnabled(true);
/* Make sure window have proper geometry and shown: */
/* Ask window to enter 'fullscreen' mode: */
}
/* If that window
* is shown while shouldn't: */
else if (pMachineWindow->isVisible())
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask machine-window #%d to hide.\n", (int)uScreenID));
/* Else make sure that window is hidden: */
/* Fade to normal: */
fadeToNormal();
}
}
/* Validate window which is in fullscreen: */
else
{
/* Variables to compare: */
const QSize frameBufferSize((int)uisession()->frameBuffer(uScreenID)->width(), (int)uisession()->frameBuffer(uScreenID)->height());
/* 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 or
* 4. have another frame-buffer size than actually should. */
|| frameBufferSize != screenSize)
{
LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
"Ask machine-window #%d to exit native fullscreen.\n", (int)uScreenID));
/* Fade to black: */
fadeToBlack();
/* Mark window as invalidated: */
/* Ask window to exit 'fullscreen' mode: */
}
}
}
}
{
/* Revalidate all fullscreen windows: */
}
#endif /* Q_WS_MAC */