Changeset 103765 in vbox
- Timestamp:
- Mar 11, 2024 1:52:33 PM (13 months ago)
- svn:sync-xref-src-repo-rev:
- 162134
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 3 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r103131 r103765 822 822 src/globals/UIFileSystemModel.h \ 823 823 src/globals/UIDesktopWidgetWatchdog.h \ 824 src/globals/UIGlobalSession.h \ 824 825 src/globals/UIMainEventListener.h \ 825 826 src/globals/UIMessageCenter.h \ … … 1394 1395 src/globals/UIErrorString.cpp \ 1395 1396 src/globals/UIExtension.cpp \ 1397 src/globals/UIGlobalSession.cpp \ 1396 1398 src/globals/UIGuestOSType.cpp \ 1397 1399 src/globals/UIIconPool.cpp \ -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp
r103704 r103765 5 5 6 6 /* 7 * Copyright (C) 2006-202 3Oracle and/or its affiliates.7 * Copyright (C) 2006-2024 Oracle and/or its affiliates. 8 8 * 9 9 * This file is part of VirtualBox base platform packages, as … … 63 63 #include "UIConverter.h" 64 64 #include "UIDesktopWidgetWatchdog.h" 65 #include "UIGlobalSession.h" 65 66 #include "UIGuestOSType.h" 66 67 #include "UIExtraDataDefs.h" … … 222 223 #endif 223 224 , m_fSettingsPwSet(false) 224 , m_fWrappersValid(false)225 , m_fVBoxSVCAvailable(true)226 225 , m_pThreadPool(0) 227 226 , m_pThreadPoolCloud(0) 228 , m_pGuestOSTypeManager(0)229 227 , m_pMediumEnumerator(0) 230 228 { … … 280 278 UITranslator::loadLanguage(); 281 279 282 /* Prepare guest OS type manager before COM stuff: */ 283 m_pGuestOSTypeManager = new UIGuestOSTypeManager; 284 285 HRESULT rc = COMBase::InitializeCOM(true); 286 if (FAILED(rc)) 287 { 288 #ifdef VBOX_WITH_XPCOM 289 if (rc == NS_ERROR_FILE_ACCESS_DENIED) 290 { 291 char szHome[RTPATH_MAX] = ""; 292 com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome)); 293 msgCenter().cannotInitUserHome(QString(szHome)); 294 } 295 else 296 #endif 297 msgCenter().cannotInitCOM(rc); 280 /* Init COM: */ 281 UIGlobalSession::create(); 282 if (!gpGlobalSession->prepare()) 298 283 return; 299 } 300 301 /* Make sure VirtualBoxClient instance created: */ 302 m_comVBoxClient.createInstance(CLSID_VirtualBoxClient); 303 if (!m_comVBoxClient.isOk()) 304 { 305 msgCenter().cannotCreateVirtualBoxClient(m_comVBoxClient); 306 return; 307 } 308 /* Make sure VirtualBox instance acquired: */ 309 m_comVBox = m_comVBoxClient.GetVirtualBox(); 310 if (!m_comVBoxClient.isOk()) 311 { 312 msgCenter().cannotAcquireVirtualBox(m_comVBoxClient); 313 return; 314 } 315 /* Init wrappers: */ 316 comWrappersReinit(); 317 318 /* Watch for the VBoxSVC availability changes: */ 319 connect(gVBoxClientEvents, &UIVirtualBoxClientEventHandler::sigVBoxSVCAvailabilityChange, 284 connect(gpGlobalSession, &UIGlobalSession::sigVBoxSVCAvailabilityChange, 320 285 this, &UICommon::sltHandleVBoxSVCAvailabilityChange); 321 286 … … 641 606 /* Search for corresponding VM: */ 642 607 QUuid uuid = QUuid(vmNameOrUuid); 643 const CMachine machine = m_comVBox.FindMachine(vmNameOrUuid); 608 const CVirtualBox comVBox = gpGlobalSession->virtualBox(); 609 const CMachine comMachine = comVBox.FindMachine(vmNameOrUuid); 644 610 if (!uuid.isNull()) 645 611 { 646 if ( machine.isNull() && showStartVMErrors())647 return msgCenter().cannotFindMachineById( m_comVBox, uuid);612 if (comMachine.isNull() && showStartVMErrors()) 613 return msgCenter().cannotFindMachineById(comVBox, uuid); 648 614 } 649 615 else 650 616 { 651 if ( machine.isNull() && showStartVMErrors())652 return msgCenter().cannotFindMachineByName( m_comVBox, vmNameOrUuid);653 } 654 m_uManagedVMId = machine.GetId();617 if (comMachine.isNull() && showStartVMErrors()) 618 return msgCenter().cannotFindMachineByName(comVBox, vmNameOrUuid); 619 } 620 m_uManagedVMId = comMachine.GetId(); 655 621 656 622 if (m_fSeparateProcess) 657 623 { 658 624 /* Create a log file for VirtualBoxVM process. */ 659 QString str = machine.GetLogFolder();625 QString str = comMachine.GetLogFolder(); 660 626 com::Utf8Str logDir(str.toUtf8().constData()); 661 627 … … 703 669 704 670 if (m_fSettingsPwSet) 705 m_comVBox.SetSettingsSecret(m_astrSettingsPw); 671 { 672 CVirtualBox comVBox = gpGlobalSession->virtualBox(); 673 comVBox.SetSettingsSecret(m_astrSettingsPw); 674 } 706 675 707 676 if (visualStateType != UIVisualStateType_Invalid && !m_uManagedVMId.isNull()) … … 852 821 m_pThreadPoolCloud = 0; 853 822 854 /* Cleanup guest OS type manager before COM stuff: */ 855 delete m_pGuestOSTypeManager; 856 m_pGuestOSTypeManager = 0; 857 858 /* Starting COM cleanup: */ 859 m_comCleanupProtectionToken.lockForWrite(); 860 { 861 /* First, make sure we don't use COM any more: */ 862 emit sigAskToDetachCOM(); 863 m_comHost.detach(); 864 m_comVBox.detach(); 865 m_comVBoxClient.detach(); 866 867 /* There may be UIMedium(s)EnumeratedEvent instances still in the message 868 * queue which reference COM objects. Remove them to release those objects 869 * before uninitializing the COM subsystem. */ 870 QApplication::removePostedEvents(this); 871 872 /* Finally cleanup COM itself: */ 873 COMBase::CleanupCOM(); 874 } 875 /* Finishing COM cleanup: */ 876 m_comCleanupProtectionToken.unlock(); 823 /* First, make sure we don't use COM any more: */ 824 emit sigAskToDetachCOM(); 825 826 /* Cleanup COM: */ 827 gpGlobalSession->cleanup(); 828 UIGlobalSession::destroy(); 877 829 878 830 /* Notify listener it can close UI now: */ … … 945 897 QString UICommon::vboxVersionString() const 946 898 { 947 return m_comVBox.GetVersion(); 899 const CVirtualBox comVBox = gpGlobalSession->virtualBox(); 900 return comVBox.GetVersion(); 948 901 } 949 902 950 903 QString UICommon::vboxVersionStringNormalized() const 951 904 { 952 return m_comVBox.GetVersionNormalized(); 905 const CVirtualBox comVBox = gpGlobalSession->virtualBox(); 906 return comVBox.GetVersionNormalized(); 953 907 } 954 908 … … 1021 975 QString UICommon::hostOperatingSystem() const 1022 976 { 1023 if (!m_comHost.isOk()) 1024 return QString(); 1025 return m_comHost.GetOperatingSystem(); 977 const CHost comHost = gpGlobalSession->host(); 978 return comHost.GetOperatingSystem(); 1026 979 } 1027 980 … … 1344 1297 #endif /* VBOX_GUI_WITH_PIDFILE */ 1345 1298 1299 bool UICommon::comTokenTryLockForRead() 1300 { 1301 return gpGlobalSession->comTokenTryLockForRead(); 1302 } 1303 1304 void UICommon::comTokenUnlock() 1305 { 1306 return gpGlobalSession->comTokenUnlock(); 1307 } 1308 1309 CVirtualBoxClient UICommon::virtualBoxClient() const 1310 { 1311 return gpGlobalSession->virtualBoxClient(); 1312 } 1313 1314 CVirtualBox UICommon::virtualBox() const 1315 { 1316 return gpGlobalSession->virtualBox(); 1317 } 1318 1319 CHost UICommon::host() const 1320 { 1321 return gpGlobalSession->host(); 1322 } 1323 1324 QString UICommon::homeFolder() const 1325 { 1326 return gpGlobalSession->homeFolder(); 1327 } 1328 1329 bool UICommon::isVBoxSVCAvailable() const 1330 { 1331 return gpGlobalSession->isVBoxSVCAvailable(); 1332 } 1333 1346 1334 /* static */ 1347 1335 bool UICommon::switchToMachine(CMachine &comMachine) … … 1525 1513 1526 1514 /* Search for the corresponding machine: */ 1527 CMachine comMachine = m_comVBox.FindMachine(uId.toString()); 1515 const CVirtualBox comVBox = gpGlobalSession->virtualBox(); 1516 CMachine comMachine = comVBox.FindMachine(uId.toString()); 1528 1517 if (comMachine.isNull()) 1529 1518 { 1530 msgCenter().cannotFindMachineById( m_comVBox, uId);1519 msgCenter().cannotFindMachineById(comVBox, uId); 1531 1520 break; 1532 1521 } … … 1614 1603 } 1615 1604 1616 const UIGuestOSTypeManager &UICommon::guestOSTypeManager() 1617 { 1618 /* Handle exceptional and undesired case! 1619 * This object is created and destroyed within own timeframe. 1620 * If pointer isn't yet initialized or already cleaned up, 1621 * something is definitely wrong. */ 1622 AssertPtr(m_pGuestOSTypeManager); 1623 if (!m_pGuestOSTypeManager) 1624 { 1625 m_pGuestOSTypeManager = new UIGuestOSTypeManager; 1626 m_pGuestOSTypeManager->reCacheGuestOSTypes(); 1627 } 1628 1629 /* Return an object instance: */ 1630 return *m_pGuestOSTypeManager; 1605 const UIGuestOSTypeManager &UICommon::guestOSTypeManager() const 1606 { 1607 return gpGlobalSession->guestOSTypeManager(); 1631 1608 } 1632 1609 … … 2745 2722 KGraphicsControllerType UICommon::getRecommendedGraphicsController(const QString &strGuestOSTypeId) const 2746 2723 { 2747 return m_pGuestOSTypeManager 2748 ? m_pGuestOSTypeManager->getRecommendedGraphicsController(strGuestOSTypeId) 2749 : KGraphicsControllerType_Null; 2724 return guestOSTypeManager().getRecommendedGraphicsController(strGuestOSTypeId); 2750 2725 } 2751 2726 … … 3046 3021 void UICommon::sltHandleVBoxSVCAvailabilityChange(bool fAvailable) 3047 3022 { 3048 /* Make sure the VBoxSVC availability changed: */3049 if (m_fVBoxSVCAvailable == fAvailable)3050 return;3051 3052 /* Cache the new VBoxSVC availability value: */3053 m_fVBoxSVCAvailable = fAvailable;3054 3055 /* If VBoxSVC is not available: */3056 if (!m_fVBoxSVCAvailable)3057 {3058 /* Mark wrappers invalid: */3059 m_fWrappersValid = false;3060 /* Re-fetch corresponding CVirtualBox to restart VBoxSVC: */3061 m_comVBox = m_comVBoxClient.GetVirtualBox();3062 if (!m_comVBoxClient.isOk())3063 {3064 // The proper behavior would be to show the message and to exit the app, e.g.:3065 // msgCenter().cannotAcquireVirtualBox(m_comVBoxClient);3066 // return QApplication::quit();3067 // But CVirtualBox is still NULL in current Main implementation,3068 // and this call do not restart anything, so we are waiting3069 // for subsequent event about VBoxSVC is available again.3070 }3071 }3072 3023 /* If VBoxSVC is available: */ 3073 else 3074 { 3075 if (!m_fWrappersValid) 3076 { 3077 /* Re-fetch corresponding CVirtualBox: */ 3078 m_comVBox = m_comVBoxClient.GetVirtualBox(); 3079 if (!m_comVBoxClient.isOk()) 3080 { 3081 msgCenter().cannotAcquireVirtualBox(m_comVBoxClient); 3082 return QApplication::quit(); 3083 } 3084 /* Re-init wrappers: */ 3085 comWrappersReinit(); 3086 3087 /* For Selector UI: */ 3088 if (uiType() == UIType_ManagerUI) 3089 { 3090 /* Recreate Main event listeners: */ 3091 UIVirtualBoxEventHandler::destroy(); 3092 UIVirtualBoxClientEventHandler::destroy(); 3093 UIExtraDataManager::destroy(); 3094 UIExtraDataManager::instance(); 3095 UIVirtualBoxEventHandler::instance(); 3096 UIVirtualBoxClientEventHandler::instance(); 3097 /* Ask UIStarter to restart UI: */ 3098 emit sigAskToRestartUI(); 3099 } 3100 } 3101 } 3102 3103 /* Notify listeners about the VBoxSVC availability change: */ 3104 emit sigVBoxSVCAvailabilityChange(); 3024 if (fAvailable) 3025 { 3026 /* For Selector UI: */ 3027 if (uiType() == UIType_ManagerUI) 3028 { 3029 /* Recreate Main event listeners: */ 3030 UIVirtualBoxEventHandler::destroy(); 3031 UIVirtualBoxClientEventHandler::destroy(); 3032 UIExtraDataManager::destroy(); 3033 UIExtraDataManager::instance(); 3034 UIVirtualBoxEventHandler::instance(); 3035 UIVirtualBoxClientEventHandler::instance(); 3036 /* Ask UIStarter to restart UI: */ 3037 emit sigAskToRestartUI(); 3038 } 3039 } 3105 3040 } 3106 3041 … … 3127 3062 strEnvValue = "veto"; 3128 3063 3129 QString strExtraValue = m_comVBox.GetExtraData(pszExtraDataName).toLower().trimmed(); 3064 CVirtualBox comVBox = gpGlobalSession->virtualBox(); 3065 QString strExtraValue = comVBox.GetExtraData(pszExtraDataName).toLower().trimmed(); 3130 3066 if (strExtraValue.isEmpty()) 3131 3067 strExtraValue = QString(); … … 3194 3130 3195 3131 #endif /* VBOX_WITH_DEBUGGER_GUI */ 3196 3197 void UICommon::comWrappersReinit()3198 {3199 /* Re-fetch corresponding objects/values: */3200 m_comHost = virtualBox().GetHost();3201 m_strHomeFolder = virtualBox().GetHomeFolder();3202 3203 /* Re-initialize guest OS type database: */3204 if (m_pGuestOSTypeManager)3205 m_pGuestOSTypeManager->reCacheGuestOSTypes();3206 3207 /* Mark wrappers valid: */3208 m_fWrappersValid = true;3209 } -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.h
r103713 r103765 5 5 6 6 /* 7 * Copyright (C) 2006-202 3Oracle and/or its affiliates.7 * Copyright (C) 2006-2024 Oracle and/or its affiliates. 8 8 * 9 9 * This file is part of VirtualBox base platform packages, as … … 33 33 34 34 /* Qt includes: */ 35 #include <Q Map>35 #include <QObject> 36 36 #include <QReadWriteLock> 37 #include <QObject>38 37 39 38 /* GUI includes: */ … … 53 52 54 53 /* Forward declarations: */ 55 class QGraphicsWidget;56 54 class QMenu; 57 55 class QSessionManager; 58 56 class QSpinBox; 59 class QToolButton;60 57 class CCloudMachine; 61 58 class CHostVideoInputDevice; … … 319 316 * @{ */ 320 317 /** Try to acquire COM cleanup protection token for reading. */ 321 bool comTokenTryLockForRead() { return m_comCleanupProtectionToken.tryLockForRead(); }318 bool comTokenTryLockForRead(); 322 319 /** Unlock previously acquired COM cleanup protection token. */ 323 void comTokenUnlock() { return m_comCleanupProtectionToken.unlock(); }320 void comTokenUnlock(); 324 321 325 322 /** Returns the copy of VirtualBox client wrapper. */ 326 CVirtualBoxClient virtualBoxClient() const { return m_comVBoxClient; }323 CVirtualBoxClient virtualBoxClient() const; 327 324 /** Returns the copy of VirtualBox object wrapper. */ 328 CVirtualBox virtualBox() const { return m_comVBox; }325 CVirtualBox virtualBox() const; 329 326 /** Returns the copy of VirtualBox host-object wrapper. */ 330 CHost host() const { return m_comHost; }327 CHost host() const; 331 328 /** Returns the symbolic VirtualBox home-folder representation. */ 332 QString homeFolder() const { return m_strHomeFolder; }329 QString homeFolder() const; 333 330 334 331 /** Returns the VBoxSVC availability value. */ 335 bool isVBoxSVCAvailable() const { return m_fVBoxSVCAvailable; }332 bool isVBoxSVCAvailable() const; 336 333 /** @} */ 337 334 … … 375 372 /** @name COM: Guest OS type stuff. 376 373 * @{ */ 377 const UIGuestOSTypeManager &guestOSTypeManager() ;374 const UIGuestOSTypeManager &guestOSTypeManager() const; 378 375 /** @} */ 379 376 … … 632 629 /** @} */ 633 630 634 /** @name COM stuff.635 * @{ */636 /** Re-initializes COM wrappers and containers. */637 void comWrappersReinit();638 /** @} */639 640 631 /** Holds the singleton UICommon instance. */ 641 632 static UICommon *s_pInstance; … … 747 738 /** @} */ 748 739 749 /** @name COM stuff.750 * @{ */751 /** Holds the COM cleanup protection token. */752 QReadWriteLock m_comCleanupProtectionToken;753 754 /** Holds the instance of VirtualBox client wrapper. */755 CVirtualBoxClient m_comVBoxClient;756 /** Holds the copy of VirtualBox object wrapper. */757 CVirtualBox m_comVBox;758 /** Holds the copy of VirtualBox host-object wrapper. */759 CHost m_comHost;760 /** Holds the symbolic VirtualBox home-folder representation. */761 QString m_strHomeFolder;762 763 /** Holds whether acquired COM wrappers are currently valid. */764 bool m_fWrappersValid;765 /** Holds whether VBoxSVC is currently available. */766 bool m_fVBoxSVCAvailable;767 /** @} */768 769 740 /** @name Thread stuff. 770 741 * @{ */ … … 775 746 /** @} */ 776 747 777 /** @name Guest OS type related stuff.778 * @{ */779 /** Holds the guest OS type manager instance. */780 UIGuestOSTypeManager *m_pGuestOSTypeManager;781 /** @} */782 783 748 /** @name Media related stuff. 784 749 * @{ */ … … 792 757 /** @} */ 793 758 794 #ifdef VBOX_WS_WIN795 /** @name ATL stuff.796 * @{ */797 /** Holds the ATL module instance (for use with UICommon shared library only).798 * @note Required internally by ATL (constructor records instance in global variable). */799 ATL::CComModule _Module;800 /** @} */801 #endif802 759 /** @name Font scaling related variables. 803 760 * @{ */ -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIGlobalSession.cpp
r103737 r103765 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI Common class implementation.3 * VBox Qt GUI - UIGlobalSession class implementation. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-202 3Oracle and/or its affiliates.7 * Copyright (C) 2006-2024 Oracle and/or its affiliates. 8 8 * 9 9 * This file is part of VirtualBox base platform packages, as … … 27 27 28 28 /* Qt includes: */ 29 #include <QDesktopServices> 30 #include <QDir> 31 #include <QFileDialog> 32 #include <QGraphicsWidget> 33 #include <QLibraryInfo> 34 #include <QLocale> 35 #include <QMenu> 36 #include <QMutex> 37 #include <QProcess> 38 #include <QProgressDialog> 39 #include <QRegularExpression> 40 #include <QSessionManager> 41 #include <QSettings> 42 #include <QSpinBox> 43 #include <QStandardPaths> 44 #include <QStyleOptionSpinBox> 45 #include <QThread> 46 #include <QTimer> 47 #include <QToolButton> 48 #include <QToolTip> 49 #include <QTranslator> 50 #ifdef VBOX_WS_WIN 51 # include <QStyleFactory> 52 #endif 53 #ifdef VBOX_GUI_WITH_PIDFILE 54 # include <QTextStream> 55 #endif 29 #include <QApplication> 56 30 57 31 /* GUI includes: */ 58 #include "QIDialogButtonBox.h" 59 #include "QIFileDialog.h" 60 #include "QIMessageBox.h" 61 #include "QIWithRestorableGeometry.h" 62 #include "UICommon.h" 63 #include "UIConverter.h" 64 #include "UIDesktopWidgetWatchdog.h" 32 #include "UIGlobalSession.h" 65 33 #include "UIGuestOSType.h" 66 #include "UIExtraDataDefs.h"67 #include "UIExtraDataManager.h"68 #include "UIFDCreationDialog.h"69 #include "UIIconPool.h"70 #include "UILoggingDefs.h"71 #include "UIMedium.h"72 #include "UIMediumEnumerator.h"73 #include "UIMediumSelector.h"74 34 #include "UIMessageCenter.h" 75 #include "UIModalWindowManager.h"76 #include "UINotificationCenter.h"77 #include "UIPopupCenter.h"78 #include "UIShortcutPool.h"79 #include "UIThreadPool.h"80 #include "UITranslator.h"81 35 #include "UIVirtualBoxClientEventHandler.h" 82 #include "UIVirtualBoxEventHandler.h"83 #include "UIVisoCreator.h"84 #include "UIWizardNewVD.h"85 #ifdef VBOX_WS_MAC86 # include "UICocoaApplication.h"87 # include "UIMachineWindowFullscreen.h"88 # include "UIMachineWindowSeamless.h"89 #endif90 #ifdef VBOX_WS_WIN91 # include "VBoxUtils-win.h"92 #endif93 #ifdef VBOX_WS_NIX94 # include "UIHostComboEditor.h"95 #endif96 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER97 # include "UINetworkRequestManager.h"98 # include "UIUpdateManager.h"99 #endif100 101 /* COM includes: */102 #include "CAudioAdapter.h"103 #include "CCloudMachine.h"104 #include "CConsole.h"105 #include "CExtPack.h"106 #include "CExtPackFile.h"107 #include "CExtPackManager.h"108 #include "CHostUSBDevice.h"109 #include "CHostVideoInputDevice.h"110 #include "CMachine.h"111 #include "CMediumAttachment.h"112 #include "CNetworkAdapter.h"113 #include "CSerialPort.h"114 #include "CSharedFolder.h"115 #include "CSnapshot.h"116 #include "CStorageController.h"117 #include "CSystemProperties.h"118 #include "CUSBController.h"119 #include "CUSBDevice.h"120 #include "CUSBDeviceFilter.h"121 #include "CUSBDeviceFilters.h"122 #include "CVRDEServer.h"123 #include <VBox/com/VirtualBox.h> /* For GUEST_OS_ID_STR_PARTIAL. */124 125 /* Other VBox includes: */126 #include <iprt/asm.h>127 #include <iprt/ctype.h>128 #include <iprt/env.h>129 #include <iprt/err.h>130 #include <iprt/file.h>131 #include <iprt/ldr.h>132 #include <iprt/param.h>133 #include <iprt/path.h>134 #include <iprt/stream.h>135 #include <iprt/system.h>136 #include <VBox/sup.h>137 #include <VBox/VBoxOGL.h>138 #include <VBox/vd.h>139 #include <VBox/com/Guid.h>140 36 141 37 /* VirtualBox interface declarations: */ 142 #include <VBox/com/VirtualBox.h> 143 144 /* External includes: */ 145 #ifdef VBOX_WS_MAC 146 # include <sys/utsname.h> 147 #endif 148 #ifdef VBOX_WS_NIX 149 # include <xcb/xcb.h> 150 #endif 151 152 /* Namespaces: */ 153 using namespace UIExtraDataDefs; 154 using namespace UIMediumDefs; 38 #include <VBox/com/VirtualBox.h> // for CLSID_VirtualBoxClient 155 39 156 40 157 41 /* static */ 158 UI Common *UICommon::s_pInstance = 0;42 UIGlobalSession *UIGlobalSession::s_pInstance = 0; 159 43 160 44 /* static */ 161 void UI Common::create(UIType enmType)45 void UIGlobalSession::create() 162 46 { 163 47 /* Make sure instance is NOT created yet: */ … … 165 49 166 50 /* Create instance: */ 167 new UICommon(enmType); 168 /* Prepare instance: */ 169 s_pInstance->prepare(); 51 new UIGlobalSession; 170 52 } 171 53 172 54 /* static */ 173 void UI Common::destroy()55 void UIGlobalSession::destroy() 174 56 { 175 57 /* Make sure instance is NOT destroyed yet: */ 176 58 AssertPtrReturnVoid(s_pInstance); 177 59 178 /* Cleanup instance:179 * 1. By default, automatically on QApplication::aboutToQuit() signal.180 * 2. But if QApplication was not started at all and we perform181 * early shutdown, we should do cleanup ourselves. */182 if (s_pInstance->isValid())183 s_pInstance->cleanup();184 60 /* Destroy instance: */ 185 61 delete s_pInstance; 186 }187 188 UICommon::UICommon(UIType enmType)189 : m_enmType(enmType)190 , m_fValid(false)191 , m_fCleaningUp(false)192 #ifdef VBOX_WS_WIN193 , m_fDataCommitted(false)194 #endif195 #ifdef VBOX_WS_MAC196 , m_enmMacOSVersion(MacOSXRelease_Old)197 #endif198 #ifdef VBOX_WS_NIX199 , m_enmWindowManagerType(X11WMType_Unknown)200 , m_fCompositingManagerRunning(false)201 , m_enmDisplayServerType(VBGHDISPLAYSERVERTYPE_NONE)202 #endif203 , m_fDarkMode(false)204 , m_fSeparateProcess(false)205 , m_fShowStartVMErrors(true)206 #if defined(DEBUG_bird)207 , m_fAgressiveCaching(false)208 #else209 , m_fAgressiveCaching(true)210 #endif211 , m_fRestoreCurrentSnapshot(false)212 , m_fNoKeyboardGrabbing(false)213 , m_fExecuteAllInIem(false)214 , m_uWarpPct(100)215 #ifdef VBOX_WITH_DEBUGGER_GUI216 , m_fDbgEnabled(0)217 , m_fDbgAutoShow(0)218 , m_fDbgAutoShowCommandLine(0)219 , m_fDbgAutoShowStatistics(0)220 , m_hVBoxDbg(NIL_RTLDRMOD)221 , m_enmLaunchRunning(LaunchRunning_Default)222 #endif223 , m_fSettingsPwSet(false)224 , m_fWrappersValid(false)225 , m_fVBoxSVCAvailable(true)226 , m_pThreadPool(0)227 , m_pThreadPoolCloud(0)228 , m_pGuestOSTypeManager(0)229 , m_pMediumEnumerator(0)230 {231 /* Assign instance: */232 s_pInstance = this;233 }234 235 UICommon::~UICommon()236 {237 /* Unassign instance: */238 62 s_pInstance = 0; 239 63 } 240 64 241 void UICommon::prepare() 242 { 243 /* Make sure QApplication cleanup us on exit: */ 244 #ifndef VBOX_IS_QT6_OR_LATER /** @todo qt6: ... */ 245 qApp->setFallbackSessionManagementEnabled(false); 246 #endif 247 connect(qApp, &QGuiApplication::aboutToQuit, 248 this, &UICommon::sltCleanup); 249 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1 250 /* Make sure we handle host OS session shutdown as well: */ 251 connect(qApp, &QGuiApplication::commitDataRequest, 252 this, &UICommon::sltHandleCommitDataRequest); 253 #endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */ 254 255 #ifdef VBOX_WS_MAC 256 /* Determine OS release early: */ 257 m_enmMacOSVersion = determineOsRelease(); 258 #endif 259 260 #ifdef VBOX_WS_NIX 261 /* Detect display server type: */ 262 m_enmDisplayServerType = VBGHDisplayServerTypeDetect(); 263 #endif 264 265 /* Create converter: */ 266 UIConverter::create(); 267 268 /* Create desktop-widget watchdog: */ 269 UIDesktopWidgetWatchdog::create(); 270 271 /* Create message-center: */ 272 UIMessageCenter::create(); 273 /* Create popup-center: */ 274 UIPopupCenter::create(); 275 276 /* Prepare general icon-pool: */ 277 UIIconPoolGeneral::create(); 278 279 /* Load translation based on the current locale: */ 280 UITranslator::loadLanguage(); 281 65 bool UIGlobalSession::prepare() 66 { 282 67 /* Prepare guest OS type manager before COM stuff: */ 283 68 m_pGuestOSTypeManager = new UIGuestOSTypeManager; 284 69 70 /* Init COM: */ 285 71 HRESULT rc = COMBase::InitializeCOM(true); 286 72 if (FAILED(rc)) … … 296 82 #endif 297 83 msgCenter().cannotInitCOM(rc); 298 return ;84 return false; 299 85 } 300 86 … … 304 90 { 305 91 msgCenter().cannotCreateVirtualBoxClient(m_comVBoxClient); 306 return; 307 } 308 /* Make sure VirtualBox instance acquired: */ 309 m_comVBox = m_comVBoxClient.GetVirtualBox(); 310 if (!m_comVBoxClient.isOk()) 311 { 312 msgCenter().cannotAcquireVirtualBox(m_comVBoxClient); 313 return; 314 } 92 return false; 93 } 94 315 95 /* Init wrappers: */ 316 96 comWrappersReinit(); … … 318 98 /* Watch for the VBoxSVC availability changes: */ 319 99 connect(gVBoxClientEvents, &UIVirtualBoxClientEventHandler::sigVBoxSVCAvailabilityChange, 320 this, &UICommon::sltHandleVBoxSVCAvailabilityChange); 321 322 /* Prepare thread-pool instances: */ 323 m_pThreadPool = new UIThreadPool(3 /* worker count */, 5000 /* worker timeout */); 324 m_pThreadPoolCloud = new UIThreadPool(2 /* worker count */, 1000 /* worker timeout */); 325 326 /* Load whether host OS is in Dark mode: */ 327 #if defined(VBOX_WS_MAC) 328 m_fDarkMode = UICocoaApplication::instance()->isDarkMode(); 329 #elif defined(VBOX_WS_WIN) 330 m_fDarkMode = isWindowsInDarkMode(); 331 #else /* Linux, BSD, Solaris */ 332 m_fDarkMode = isPaletteInDarkMode(); 333 #endif /* Linux, BSD, Solaris */ 334 /* Load color theme: */ 335 loadColorTheme(); 336 337 /* Load translation based on the user settings: */ 338 QString strLanguageId = gEDataManager->languageId(); 339 if (!strLanguageId.isNull()) 340 UITranslator::loadLanguage(strLanguageId); 341 342 retranslateUi(); 343 344 connect(gEDataManager, &UIExtraDataManager::sigLanguageChange, 345 this, &UICommon::sltGUILanguageChange); 346 connect(gEDataManager, &UIExtraDataManager::sigFontScaleFactorChanged, 347 this, &UICommon::sltHandleFontScaleFactorChanged); 348 349 qApp->installEventFilter(this); 350 351 /* process command line */ 352 353 UIVisualStateType visualStateType = UIVisualStateType_Invalid; 354 355 #ifdef VBOX_WS_NIX 356 /* Check whether we have compositing manager running: */ 357 m_fCompositingManagerRunning = NativeWindowSubsystem::isCompositingManagerRunning(X11ServerAvailable()); 358 359 /* Acquire current Window Manager type: */ 360 m_enmWindowManagerType = NativeWindowSubsystem::windowManagerType(X11ServerAvailable()); 361 #endif /* VBOX_WS_NIX */ 362 363 #ifdef VBOX_WITH_DEBUGGER_GUI 364 # ifdef VBOX_WITH_DEBUGGER_GUI_MENU 365 initDebuggerVar(&m_fDbgEnabled, "VBOX_GUI_DBG_ENABLED", GUI_Dbg_Enabled, true); 366 # else 367 initDebuggerVar(&m_fDbgEnabled, "VBOX_GUI_DBG_ENABLED", GUI_Dbg_Enabled, false); 368 # endif 369 initDebuggerVar(&m_fDbgAutoShow, "VBOX_GUI_DBG_AUTO_SHOW", GUI_Dbg_AutoShow, false); 370 m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = m_fDbgAutoShow; 371 #endif 372 373 /* 374 * Parse the command line options. 375 * 376 * This is a little sloppy but we're trying to tighten it up. Unfortuately, 377 * both on X11 and darwin (IIRC) there might be additional arguments aimed 378 * for client libraries with GUI processes. So, using RTGetOpt or similar 379 * is a bit hard since we have to cope with unknown options. 380 */ 381 m_fShowStartVMErrors = true; 382 bool startVM = false; 383 bool fSeparateProcess = false; 384 QString vmNameOrUuid; 385 386 const QStringList &arguments = QCoreApplication::arguments(); 387 const int argc = arguments.size(); 388 int i = 1; 389 while (i < argc) 390 { 391 const QByteArray &argBytes = arguments.at(i).toUtf8(); 392 const char *arg = argBytes.constData(); 393 enum { OptType_Unknown, OptType_VMRunner, OptType_VMSelector, OptType_MaybeBoth } enmOptType = OptType_Unknown; 394 /* NOTE: the check here must match the corresponding check for the 395 * options to start a VM in main.cpp and hardenedmain.cpp exactly, 396 * otherwise there will be weird error messages. */ 397 if ( !::strcmp(arg, "--startvm") 398 || !::strcmp(arg, "-startvm")) 399 { 400 enmOptType = OptType_VMRunner; 401 if (++i < argc) 402 { 403 vmNameOrUuid = arguments.at(i); 404 startVM = true; 405 } 406 } 407 else if (!::strcmp(arg, "-separate") || !::strcmp(arg, "--separate")) 408 { 409 enmOptType = OptType_VMRunner; 410 fSeparateProcess = true; 411 } 412 #ifdef VBOX_GUI_WITH_PIDFILE 413 else if (!::strcmp(arg, "-pidfile") || !::strcmp(arg, "--pidfile")) 414 { 415 enmOptType = OptType_MaybeBoth; 416 if (++i < argc) 417 m_strPidFile = arguments.at(i); 418 } 419 #endif /* VBOX_GUI_WITH_PIDFILE */ 420 /* Visual state type options: */ 421 else if (!::strcmp(arg, "-normal") || !::strcmp(arg, "--normal")) 422 { 423 enmOptType = OptType_MaybeBoth; 424 visualStateType = UIVisualStateType_Normal; 425 } 426 else if (!::strcmp(arg, "-fullscreen") || !::strcmp(arg, "--fullscreen")) 427 { 428 enmOptType = OptType_MaybeBoth; 429 visualStateType = UIVisualStateType_Fullscreen; 430 } 431 else if (!::strcmp(arg, "-seamless") || !::strcmp(arg, "--seamless")) 432 { 433 enmOptType = OptType_MaybeBoth; 434 visualStateType = UIVisualStateType_Seamless; 435 } 436 else if (!::strcmp(arg, "-scale") || !::strcmp(arg, "--scale")) 437 { 438 enmOptType = OptType_MaybeBoth; 439 visualStateType = UIVisualStateType_Scale; 440 } 441 /* Passwords: */ 442 else if (!::strcmp(arg, "--settingspw")) 443 { 444 enmOptType = OptType_MaybeBoth; 445 if (++i < argc) 446 { 447 RTStrCopy(m_astrSettingsPw, sizeof(m_astrSettingsPw), arguments.at(i).toLocal8Bit().constData()); 448 m_fSettingsPwSet = true; 449 } 450 } 451 else if (!::strcmp(arg, "--settingspwfile")) 452 { 453 enmOptType = OptType_MaybeBoth; 454 if (++i < argc) 455 { 456 const QByteArray &argFileBytes = arguments.at(i).toLocal8Bit(); 457 const char *pszFile = argFileBytes.constData(); 458 bool fStdIn = !::strcmp(pszFile, "stdin"); 459 int vrc = VINF_SUCCESS; 460 PRTSTREAM pStrm; 461 if (!fStdIn) 462 vrc = RTStrmOpen(pszFile, "r", &pStrm); 463 else 464 pStrm = g_pStdIn; 465 if (RT_SUCCESS(vrc)) 466 { 467 size_t cbFile; 468 vrc = RTStrmReadEx(pStrm, m_astrSettingsPw, sizeof(m_astrSettingsPw) - 1, &cbFile); 469 if (RT_SUCCESS(vrc)) 470 { 471 if (cbFile >= sizeof(m_astrSettingsPw) - 1) 472 cbFile = sizeof(m_astrSettingsPw) - 1; 473 unsigned i; 474 for (i = 0; i < cbFile && !RT_C_IS_CNTRL(m_astrSettingsPw[i]); i++) 475 ; 476 m_astrSettingsPw[i] = '\0'; 477 m_fSettingsPwSet = true; 478 } 479 if (!fStdIn) 480 RTStrmClose(pStrm); 481 } 482 } 483 } 484 /* Misc options: */ 485 else if (!::strcmp(arg, "-comment") || !::strcmp(arg, "--comment")) 486 { 487 enmOptType = OptType_MaybeBoth; 488 ++i; 489 } 490 else if (!::strcmp(arg, "--no-startvm-errormsgbox")) 491 { 492 enmOptType = OptType_VMRunner; 493 m_fShowStartVMErrors = false; 494 } 495 else if (!::strcmp(arg, "--aggressive-caching")) 496 { 497 enmOptType = OptType_MaybeBoth; 498 m_fAgressiveCaching = true; 499 } 500 else if (!::strcmp(arg, "--no-aggressive-caching")) 501 { 502 enmOptType = OptType_MaybeBoth; 503 m_fAgressiveCaching = false; 504 } 505 else if (!::strcmp(arg, "--restore-current")) 506 { 507 enmOptType = OptType_VMRunner; 508 m_fRestoreCurrentSnapshot = true; 509 } 510 else if (!::strcmp(arg, "--no-keyboard-grabbing")) 511 { 512 enmOptType = OptType_VMRunner; 513 m_fNoKeyboardGrabbing = true; 514 } 515 /* Ad hoc VM reconfig options: */ 516 else if (!::strcmp(arg, "--fda")) 517 { 518 enmOptType = OptType_VMRunner; 519 if (++i < argc) 520 m_uFloppyImage = QUuid(arguments.at(i)); 521 } 522 else if (!::strcmp(arg, "--dvd") || !::strcmp(arg, "--cdrom")) 523 { 524 enmOptType = OptType_VMRunner; 525 if (++i < argc) 526 m_uDvdImage = QUuid(arguments.at(i)); 527 } 528 /* VMM Options: */ 529 else if (!::strcmp(arg, "--execute-all-in-iem")) 530 { 531 enmOptType = OptType_VMRunner; 532 m_fExecuteAllInIem = true; 533 } 534 else if (!::strcmp(arg, "--driverless")) 535 enmOptType = OptType_VMRunner; 536 else if (!::strcmp(arg, "--warp-pct")) 537 { 538 enmOptType = OptType_VMRunner; 539 if (++i < argc) 540 m_uWarpPct = RTStrToUInt32(arguments.at(i).toLocal8Bit().constData()); 541 } 542 #ifdef VBOX_WITH_DEBUGGER_GUI 543 /* Debugger/Debugging options: */ 544 else if (!::strcmp(arg, "-dbg") || !::strcmp(arg, "--dbg")) 545 { 546 enmOptType = OptType_VMRunner; 547 setDebuggerVar(&m_fDbgEnabled, true); 548 } 549 else if (!::strcmp( arg, "-debug") || !::strcmp(arg, "--debug")) 550 { 551 enmOptType = OptType_VMRunner; 552 setDebuggerVar(&m_fDbgEnabled, true); 553 setDebuggerVar(&m_fDbgAutoShow, true); 554 setDebuggerVar(&m_fDbgAutoShowCommandLine, true); 555 setDebuggerVar(&m_fDbgAutoShowStatistics, true); 556 } 557 else if (!::strcmp(arg, "--debug-command-line")) 558 { 559 enmOptType = OptType_VMRunner; 560 setDebuggerVar(&m_fDbgEnabled, true); 561 setDebuggerVar(&m_fDbgAutoShow, true); 562 setDebuggerVar(&m_fDbgAutoShowCommandLine, true); 563 } 564 else if (!::strcmp(arg, "--debug-statistics")) 565 { 566 enmOptType = OptType_VMRunner; 567 setDebuggerVar(&m_fDbgEnabled, true); 568 setDebuggerVar(&m_fDbgAutoShow, true); 569 setDebuggerVar(&m_fDbgAutoShowStatistics, true); 570 } 571 else if (!::strcmp(arg, "--statistics-expand") || !::strcmp(arg, "--stats-expand")) 572 { 573 enmOptType = OptType_VMRunner; 574 if (++i < argc) 575 { 576 if (!m_strDbgStatisticsExpand.isEmpty()) 577 m_strDbgStatisticsExpand.append('|'); 578 m_strDbgStatisticsExpand.append(arguments.at(i)); 579 } 580 } 581 else if (!::strncmp(arg, RT_STR_TUPLE("--statistics-expand=")) || !::strncmp(arg, RT_STR_TUPLE("--stats-expand="))) 582 { 583 enmOptType = OptType_VMRunner; 584 if (!m_strDbgStatisticsExpand.isEmpty()) 585 m_strDbgStatisticsExpand.append('|'); 586 m_strDbgStatisticsExpand.append(arguments.at(i).section('=', 1)); 587 } 588 else if (!::strcmp(arg, "--statistics-filter") || !::strcmp(arg, "--stats-filter")) 589 { 590 enmOptType = OptType_VMRunner; 591 if (++i < argc) 592 m_strDbgStatisticsFilter = arguments.at(i); 593 } 594 else if (!::strncmp(arg, RT_STR_TUPLE("--statistics-filter=")) || !::strncmp(arg, RT_STR_TUPLE("--stats-filter="))) 595 { 596 enmOptType = OptType_VMRunner; 597 m_strDbgStatisticsFilter = arguments.at(i).section('=', 1); 598 } 599 else if (!::strcmp(arg, "--statistics-config") || !::strcmp(arg, "--stats-config")) 600 { 601 enmOptType = OptType_VMRunner; 602 if (++i < argc) 603 m_strDbgStatisticsConfig = arguments.at(i); 604 } 605 else if (!::strncmp(arg, RT_STR_TUPLE("--statistics-config=")) || !::strncmp(arg, RT_STR_TUPLE("--stats-config="))) 606 { 607 enmOptType = OptType_VMRunner; 608 m_strDbgStatisticsConfig = arguments.at(i).section('=', 1); 609 } 610 else if (!::strcmp(arg, "-no-debug") || !::strcmp(arg, "--no-debug")) 611 { 612 enmOptType = OptType_VMRunner; 613 setDebuggerVar(&m_fDbgEnabled, false); 614 setDebuggerVar(&m_fDbgAutoShow, false); 615 setDebuggerVar(&m_fDbgAutoShowCommandLine, false); 616 setDebuggerVar(&m_fDbgAutoShowStatistics, false); 617 } 618 /* Not quite debug options, but they're only useful with the debugger bits. */ 619 else if (!::strcmp(arg, "--start-paused")) 620 { 621 enmOptType = OptType_VMRunner; 622 m_enmLaunchRunning = LaunchRunning_No; 623 } 624 else if (!::strcmp(arg, "--start-running")) 625 { 626 enmOptType = OptType_VMRunner; 627 m_enmLaunchRunning = LaunchRunning_Yes; 628 } 629 #endif 630 if (enmOptType == OptType_VMRunner && m_enmType != UIType_RuntimeUI) 631 msgCenter().cannotHandleRuntimeOption(arg); 632 633 i++; 634 } 635 636 if (uiType() == UIType_RuntimeUI && startVM) 637 { 638 /* m_fSeparateProcess makes sense only if a VM is started. */ 639 m_fSeparateProcess = fSeparateProcess; 640 641 /* Search for corresponding VM: */ 642 QUuid uuid = QUuid(vmNameOrUuid); 643 const CMachine machine = m_comVBox.FindMachine(vmNameOrUuid); 644 if (!uuid.isNull()) 645 { 646 if (machine.isNull() && showStartVMErrors()) 647 return msgCenter().cannotFindMachineById(m_comVBox, uuid); 648 } 649 else 650 { 651 if (machine.isNull() && showStartVMErrors()) 652 return msgCenter().cannotFindMachineByName(m_comVBox, vmNameOrUuid); 653 } 654 m_uManagedVMId = machine.GetId(); 655 656 if (m_fSeparateProcess) 657 { 658 /* Create a log file for VirtualBoxVM process. */ 659 QString str = machine.GetLogFolder(); 660 com::Utf8Str logDir(str.toUtf8().constData()); 661 662 /* make sure the Logs folder exists */ 663 if (!RTDirExists(logDir.c_str())) 664 RTDirCreateFullPath(logDir.c_str(), 0700); 665 666 com::Utf8Str logFile = com::Utf8StrFmt("%s%cVBoxUI.log", 667 logDir.c_str(), RTPATH_DELIMITER); 668 669 com::VBoxLogRelCreate("GUI (separate)", logFile.c_str(), 670 RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_RESTRICT_GROUPS, 671 "all all.restrict -default.restrict", 672 "VBOX_RELEASE_LOG", RTLOGDEST_FILE, 673 32768 /* cMaxEntriesPerGroup */, 674 0 /* cHistory */, 0 /* uHistoryFileTime */, 675 0 /* uHistoryFileSize */, NULL); 676 } 677 } 678 679 /* For Selector UI: */ 680 if (uiType() == UIType_ManagerUI) 681 { 682 /* We should create separate logging file for VM selector: */ 683 char szLogFile[RTPATH_MAX]; 684 const char *pszLogFile = NULL; 685 com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile)); 686 RTPathAppend(szLogFile, sizeof(szLogFile), "selectorwindow.log"); 687 pszLogFile = szLogFile; 688 /* Create release logger, to file: */ 689 com::VBoxLogRelCreate("GUI VM Selector Window", 690 pszLogFile, 691 RTLOGFLAGS_PREFIX_TIME_PROG, 692 "all", 693 "VBOX_GUI_SELECTORWINDOW_RELEASE_LOG", 694 RTLOGDEST_FILE | RTLOGDEST_F_NO_DENY, 695 UINT32_MAX, 696 10, 697 60 * 60, 698 _1M, 699 NULL /*pErrInfo*/); 700 701 LogRel(("Qt version: %s\n", qtRTVersionString().toUtf8().constData())); 702 } 703 704 if (m_fSettingsPwSet) 705 m_comVBox.SetSettingsSecret(m_astrSettingsPw); 706 707 if (visualStateType != UIVisualStateType_Invalid && !m_uManagedVMId.isNull()) 708 gEDataManager->setRequestedVisualState(visualStateType, m_uManagedVMId); 709 710 #ifdef VBOX_WITH_DEBUGGER_GUI 711 /* For Runtime UI: */ 712 if (uiType() == UIType_RuntimeUI) 713 { 714 /* Setup the debugger GUI: */ 715 if (RTEnvExist("VBOX_GUI_NO_DEBUGGER")) 716 m_fDbgEnabled = m_fDbgAutoShow = m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = false; 717 if (m_fDbgEnabled) 718 { 719 RTERRINFOSTATIC ErrInfo; 720 RTErrInfoInitStatic(&ErrInfo); 721 int vrc = SUPR3HardenedLdrLoadAppPriv("VBoxDbg", &m_hVBoxDbg, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core); 722 if (RT_FAILURE(vrc)) 723 { 724 m_hVBoxDbg = NIL_RTLDRMOD; 725 m_fDbgAutoShow = m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = false; 726 LogRel(("Failed to load VBoxDbg, rc=%Rrc - %s\n", vrc, ErrInfo.Core.pszMsg)); 727 } 728 } 729 } 730 #endif 731 732 m_fValid = true; 733 734 /* Create medium-enumerator but don't do any immediate caching: */ 735 m_pMediumEnumerator = new UIMediumEnumerator; 736 { 737 /* Prepare medium-enumerator: */ 738 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumCreated, 739 this, &UICommon::sigMediumCreated); 740 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumDeleted, 741 this, &UICommon::sigMediumDeleted); 742 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerationStarted, 743 this, &UICommon::sigMediumEnumerationStarted); 744 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerated, 745 this, &UICommon::sigMediumEnumerated); 746 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerationFinished, 747 this, &UICommon::sigMediumEnumerationFinished); 748 } 749 750 /* Create shortcut pool: */ 751 UIShortcutPool::create(uiType()); 752 753 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER 754 /* Create network manager: */ 755 UINetworkRequestManager::create(); 756 757 /* Schedule update manager: */ 758 UIUpdateManager::schedule(); 759 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */ 760 761 #ifdef RT_OS_LINUX 762 /* Make sure no wrong USB mounted: */ 763 checkForWrongUSBMounted(); 764 #endif /* RT_OS_LINUX */ 765 766 /* Populate the list of medium names to be excluded from the 767 recently used media extra data: */ 768 #if 0 /* bird: This is counter productive as it is _frequently_ necessary to re-insert the 769 viso to refresh the files (like after you rebuilt them on the host). 770 The guest caches ISOs aggressively and files sizes may change. */ 771 m_recentMediaExcludeList << "ad-hoc.viso"; 772 #endif 773 774 775 iOriginalFontPixelSize = qApp->font().pixelSize(); 776 iOriginalFontPointSize = qApp->font().pointSize(); 777 sltHandleFontScaleFactorChanged(gEDataManager->fontScaleFactor()); 778 } 779 780 void UICommon::cleanup() 781 { 782 LogRel(("GUI: UICommon: Handling aboutToQuit request..\n")); 783 784 /// @todo Shouldn't that be protected with a mutex or something? 785 /* Remember that the cleanup is in progress preventing any unwanted 786 * stuff which could be called from the other threads: */ 787 m_fCleaningUp = true; 788 789 #ifdef VBOX_WS_WIN 790 /* Ask listeners to commit data if haven't yet: */ 791 if (!m_fDataCommitted) 792 { 793 emit sigAskToCommitData(); 794 m_fDataCommitted = true; 795 } 796 #else 797 /* Ask listeners to commit data: */ 798 emit sigAskToCommitData(); 799 #endif 800 801 #ifdef VBOX_WITH_DEBUGGER_GUI 802 /* For Runtime UI: */ 803 if ( uiType() == UIType_RuntimeUI 804 && m_hVBoxDbg != NIL_RTLDRMOD) 805 { 806 RTLdrClose(m_hVBoxDbg); 807 m_hVBoxDbg = NIL_RTLDRMOD; 808 } 809 #endif 810 811 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER 812 /* Shutdown update manager: */ 813 UIUpdateManager::shutdown(); 814 815 /* Destroy network manager: */ 816 UINetworkRequestManager::destroy(); 817 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */ 818 819 /* Destroy shortcut pool: */ 820 UIShortcutPool::destroy(); 821 822 #ifdef VBOX_GUI_WITH_PIDFILE 823 deletePidfile(); 824 #endif /* VBOX_GUI_WITH_PIDFILE */ 825 826 /* Starting medium-enumerator cleanup: */ 827 m_meCleanupProtectionToken.lockForWrite(); 828 { 829 /* Destroy medium-enumerator: */ 830 delete m_pMediumEnumerator; 831 m_pMediumEnumerator = 0; 832 } 833 /* Finishing medium-enumerator cleanup: */ 834 m_meCleanupProtectionToken.unlock(); 835 836 /* Destroy the global (VirtualBox and VirtualBoxClient) Main event 837 * handlers which are used in both Manager and Runtime UIs. */ 838 UIVirtualBoxEventHandler::destroy(); 839 UIVirtualBoxClientEventHandler::destroy(); 840 841 /* Destroy the extra-data manager finally after everything 842 * above which could use it already destroyed: */ 843 UIExtraDataManager::destroy(); 844 845 /* Destroy converter: */ 846 UIConverter::destroy(); 847 848 /* Cleanup thread-pools: */ 849 delete m_pThreadPool; 850 m_pThreadPool = 0; 851 delete m_pThreadPoolCloud; 852 m_pThreadPoolCloud = 0; 853 100 this, &UIGlobalSession::sltHandleVBoxSVCAvailabilityChange); 101 102 /* Success finally: */ 103 return true; 104 } 105 106 void UIGlobalSession::cleanup() 107 { 854 108 /* Cleanup guest OS type manager before COM stuff: */ 855 109 delete m_pGuestOSTypeManager; … … 858 112 /* Starting COM cleanup: */ 859 113 m_comCleanupProtectionToken.lockForWrite(); 860 { 861 /* First, make sure we don't use COM any more: */ 862 emit sigAskToDetachCOM(); 863 m_comHost.detach(); 864 m_comVBox.detach(); 865 m_comVBoxClient.detach(); 866 867 /* There may be UIMedium(s)EnumeratedEvent instances still in the message 868 * queue which reference COM objects. Remove them to release those objects 869 * before uninitializing the COM subsystem. */ 870 QApplication::removePostedEvents(this); 871 872 /* Finally cleanup COM itself: */ 873 COMBase::CleanupCOM(); 874 } 114 115 /* Detach COM wrappers: */ 116 m_comHost.detach(); 117 m_comVBox.detach(); 118 m_comVBoxClient.detach(); 119 120 /* There may be COM related event instances still in the message queue 121 * which reference COM objects. Remove them to release those objects 122 * before uninitializing the COM subsystem. */ 123 QApplication::removePostedEvents(this); 124 125 /* Finally cleanup COM itself: */ 126 COMBase::CleanupCOM(); 127 875 128 /* Finishing COM cleanup: */ 876 129 m_comCleanupProtectionToken.unlock(); 877 878 /* Notify listener it can close UI now: */ 879 emit sigAskToCloseUI(); 880 881 /* Cleanup general icon-pool: */ 882 UIIconPoolGeneral::destroy(); 883 884 /* Destroy popup-center: */ 885 UIPopupCenter::destroy(); 886 /* Destroy message-center: */ 887 UIMessageCenter::destroy(); 888 889 /* Destroy desktop-widget watchdog: */ 890 UIDesktopWidgetWatchdog::destroy(); 891 892 m_fValid = false; 893 894 LogRel(("GUI: UICommon: aboutToQuit request handled!\n")); 895 } 896 897 /* static */ 898 QString UICommon::qtRTVersionString() 899 { 900 return QString::fromLatin1(qVersion()); 901 } 902 903 /* static */ 904 uint UICommon::qtRTVersion() 905 { 906 const QString strVersionRT = UICommon::qtRTVersionString(); 907 return (strVersionRT.section('.', 0, 0).toInt() << 16) + 908 (strVersionRT.section('.', 1, 1).toInt() << 8) + 909 strVersionRT.section('.', 2, 2).toInt(); 910 } 911 912 /* static */ 913 uint UICommon::qtRTMajorVersion() 914 { 915 return UICommon::qtRTVersionString().section('.', 0, 0).toInt(); 916 } 917 918 /* static */ 919 uint UICommon::qtRTMinorVersion() 920 { 921 return UICommon::qtRTVersionString().section('.', 1, 1).toInt(); 922 } 923 924 /* static */ 925 uint UICommon::qtRTRevisionNumber() 926 { 927 return UICommon::qtRTVersionString().section('.', 2, 2).toInt(); 928 } 929 930 /* static */ 931 QString UICommon::qtCTVersionString() 932 { 933 return QString::fromLatin1(QT_VERSION_STR); 934 } 935 936 /* static */ 937 uint UICommon::qtCTVersion() 938 { 939 const QString strVersionCompiled = UICommon::qtCTVersionString(); 940 return (strVersionCompiled.section('.', 0, 0).toInt() << 16) + 941 (strVersionCompiled.section('.', 1, 1).toInt() << 8) + 942 strVersionCompiled.section('.', 2, 2).toInt(); 943 } 944 945 QString UICommon::vboxVersionString() const 946 { 947 return m_comVBox.GetVersion(); 948 } 949 950 QString UICommon::vboxVersionStringNormalized() const 951 { 952 return m_comVBox.GetVersionNormalized(); 953 } 954 955 bool UICommon::isBeta() const 956 { 957 return vboxVersionString().contains(QRegularExpression("BETA|ALPHA", QRegularExpression::CaseInsensitiveOption)); 958 } 959 960 bool UICommon::showBetaLabel() const 961 { 962 return isBeta() 963 && !gEDataManager->preventBetaBuildLavel(); 964 } 965 966 bool UICommon::brandingIsActive(bool fForce /* = false */) 967 { 968 if (fForce) 969 return true; 970 971 if (m_strBrandingConfigFilePath.isEmpty()) 972 { 973 m_strBrandingConfigFilePath = QDir(QApplication::applicationDirPath()).absolutePath(); 974 m_strBrandingConfigFilePath += "/custom/custom.ini"; 975 } 976 977 return QFile::exists(m_strBrandingConfigFilePath); 978 } 979 980 QString UICommon::brandingGetKey(QString strKey) const 981 { 982 QSettings settings(m_strBrandingConfigFilePath, QSettings::IniFormat); 983 return settings.value(QString("%1").arg(strKey)).toString(); 984 } 985 986 #ifdef VBOX_WS_MAC 987 /* static */ 988 MacOSXRelease UICommon::determineOsRelease() 989 { 990 /* Prepare 'utsname' struct: */ 991 utsname info; 992 if (uname(&info) != -1) 993 { 994 /* Cut the major release index of the string we have, s.a. 'man uname': */ 995 const int iRelease = QString(info.release).section('.', 0, 0).toInt(); 996 /* Check boundaries: */ 997 if (iRelease <= MacOSXRelease_FirstUnknown) 998 return MacOSXRelease_Old; 999 else if (iRelease >= MacOSXRelease_LastUnknown) 1000 return MacOSXRelease_New; 1001 else 1002 return (MacOSXRelease)iRelease; 1003 } 1004 /* Return 'Old' by default: */ 1005 return MacOSXRelease_Old; 1006 } 1007 #endif /* VBOX_WS_MAC */ 1008 1009 #ifdef VBOX_WS_NIX 1010 bool UICommon::X11ServerAvailable() const 1011 { 1012 return VBGHDisplayServerTypeIsXAvailable(m_enmDisplayServerType); 1013 } 1014 1015 VBGHDISPLAYSERVERTYPE UICommon::displayServerType() const 1016 { 1017 return m_enmDisplayServerType; 1018 } 1019 #endif 1020 1021 QString UICommon::hostOperatingSystem() const 1022 { 1023 if (!m_comHost.isOk()) 1024 return QString(); 1025 return m_comHost.GetOperatingSystem(); 1026 } 1027 1028 #if defined(VBOX_WS_MAC) 1029 // Provided by UICocoaApplication .. 1030 1031 #elif defined(VBOX_WS_WIN) 1032 1033 bool UICommon::isWindowsInDarkMode() const 1034 { 1035 /* Load saved color theme: */ 1036 UIColorThemeType enmColorTheme = gEDataManager->colorTheme(); 1037 1038 /* Check whether we have dark system theme requested: */ 1039 if (enmColorTheme == UIColorThemeType_Auto) 1040 { 1041 QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 1042 QSettings::NativeFormat); 1043 if (settings.value("AppsUseLightTheme") == 0) 1044 enmColorTheme = UIColorThemeType_Dark; 1045 } 1046 1047 /* Return result: */ 1048 return enmColorTheme == UIColorThemeType_Dark; 1049 } 1050 1051 #else /* Linux, BSD, Solaris */ 1052 1053 bool UICommon::isPaletteInDarkMode() const 1054 { 1055 const QPalette pal = qApp->palette(); 1056 const QColor background = pal.color(QPalette::Active, QPalette::Window); 1057 const double dLuminance = (0.299 * background.red() + 0.587 * background.green() + 0.114 * background.blue()) / 255; 1058 return dLuminance < 0.5; 1059 } 1060 #endif /* Linux, BSD, Solaris */ 1061 1062 void UICommon::loadColorTheme() 1063 { 1064 #if defined (VBOX_WS_MAC) 1065 /* macOS has Window color hardcoded somewhere inside, Qt has no access to it, 1066 * moreover these colors are influenced by window background blending, 1067 * making Qt default colors incredibly inconsistent with native macOS apps. */ 1068 1069 /* Redefine colors for known OS types: */ 1070 enum ColorSlot 1071 { 1072 ColorSlot_DarkActive, 1073 ColorSlot_DarkInactive, 1074 ColorSlot_DarkAlternate, 1075 ColorSlot_LightActive, 1076 ColorSlot_LightInactive, 1077 ColorSlot_LightAlternate, 1078 }; 1079 QMap<ColorSlot, QColor> colors; 1080 switch (osRelease()) 1081 { 1082 case MacOSXRelease_BigSur: 1083 { 1084 colors[ColorSlot_DarkActive] = QColor("#282628"); 1085 colors[ColorSlot_DarkInactive] = QColor("#2E292E"); 1086 colors[ColorSlot_LightActive] = QColor("#E7E2E3"); 1087 colors[ColorSlot_LightInactive] = QColor("#EEE9EA"); 1088 break; 1089 } 1090 case MacOSXRelease_Monterey: 1091 { 1092 colors[ColorSlot_DarkActive] = QColor("#252328"); 1093 colors[ColorSlot_DarkInactive] = QColor("#2A2630"); 1094 colors[ColorSlot_LightActive] = QColor("#E1DEE4"); 1095 colors[ColorSlot_LightInactive] = QColor("#EEE8E9"); 1096 break; 1097 } 1098 case MacOSXRelease_Ventura: 1099 { 1100 colors[ColorSlot_DarkActive] = QColor("#322827"); 1101 colors[ColorSlot_DarkInactive] = QColor("#332A28"); 1102 colors[ColorSlot_LightActive] = QColor("#E5E0DF"); 1103 colors[ColorSlot_LightInactive] = QColor("#ECE7E5"); 1104 break; 1105 } 1106 default: 1107 break; 1108 } 1109 /* Redefine colors common for various OS types: */ 1110 // we do it only if we have redefined something above: 1111 if (!colors.isEmpty()) 1112 { 1113 colors[ColorSlot_DarkAlternate] = QColor("#2F2A2F"); 1114 colors[ColorSlot_LightAlternate] = QColor("#F4F5F5"); 1115 } 1116 1117 /* Do we have redefined colors? */ 1118 if (!colors.isEmpty()) 1119 { 1120 QPalette pal = qApp->palette(); 1121 if (isInDarkMode()) 1122 { 1123 pal.setColor(QPalette::Active, QPalette::Window, colors.value(ColorSlot_DarkActive)); 1124 pal.setColor(QPalette::Inactive, QPalette::Window, colors.value(ColorSlot_DarkInactive)); 1125 pal.setColor(QPalette::Active, QPalette::AlternateBase, colors.value(ColorSlot_DarkAlternate)); 1126 pal.setColor(QPalette::Inactive, QPalette::AlternateBase, colors.value(ColorSlot_DarkAlternate)); 1127 } 1128 else 1129 { 1130 pal.setColor(QPalette::Active, QPalette::Window, colors.value(ColorSlot_LightActive)); 1131 pal.setColor(QPalette::Inactive, QPalette::Window, colors.value(ColorSlot_LightInactive)); 1132 pal.setColor(QPalette::Active, QPalette::AlternateBase, colors.value(ColorSlot_LightAlternate)); 1133 pal.setColor(QPalette::Inactive, QPalette::AlternateBase, colors.value(ColorSlot_LightAlternate)); 1134 } 1135 qApp->setPalette(pal); 1136 } 1137 1138 #elif defined(VBOX_WS_WIN) 1139 1140 /* For the Dark mode! */ 1141 if (isInDarkMode()) 1142 { 1143 qApp->setStyle(QStyleFactory::create("Fusion")); 1144 QPalette darkPalette; 1145 QColor windowColor1 = QColor(59, 60, 61); 1146 QColor windowColor2 = QColor(63, 64, 65); 1147 QColor baseColor1 = QColor(46, 47, 48); 1148 QColor baseColor2 = QColor(56, 57, 58); 1149 QColor disabledColor = QColor(113, 114, 115); 1150 darkPalette.setColor(QPalette::Window, windowColor1); 1151 darkPalette.setColor(QPalette::WindowText, Qt::white); 1152 darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, disabledColor); 1153 darkPalette.setColor(QPalette::Base, baseColor1); 1154 darkPalette.setColor(QPalette::AlternateBase, baseColor2); 1155 darkPalette.setColor(QPalette::PlaceholderText, disabledColor); 1156 darkPalette.setColor(QPalette::Text, Qt::white); 1157 darkPalette.setColor(QPalette::Disabled, QPalette::Text, disabledColor); 1158 darkPalette.setColor(QPalette::Button, windowColor2); 1159 darkPalette.setColor(QPalette::ButtonText, Qt::white); 1160 darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, disabledColor); 1161 darkPalette.setColor(QPalette::BrightText, Qt::red); 1162 darkPalette.setColor(QPalette::Link, QColor(179, 214, 242)); 1163 darkPalette.setColor(QPalette::Highlight, QColor(29, 84, 92)); 1164 darkPalette.setColor(QPalette::HighlightedText, Qt::white); 1165 darkPalette.setColor(QPalette::Disabled, QPalette::HighlightedText, disabledColor); 1166 qApp->setPalette(darkPalette); 1167 qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2b2b2b; border: 1px solid #737373; }"); 1168 } 1169 1170 #else /* Linux, BSD, Solaris */ 1171 1172 /* For the Dark mode! */ 1173 if (isInDarkMode()) 1174 { 1175 // WORKAROUND: 1176 // Have seen it on Linux with Qt5 but still see it with Qt6. 1177 // In Dark themes on KDE (at least) PlaceholderText foreground 1178 // is indistinguishable on Base background. 1179 1180 /* Acquire global palette: */ 1181 QPalette darkPalette = qApp->palette(); 1182 1183 /* Get text base color: */ 1184 const QColor base = darkPalette.color(QPalette::Active, QPalette::Base); 1185 1186 /* Get possible foreground colors: */ 1187 const QColor simpleText = darkPalette.color(QPalette::Active, QPalette::Text); 1188 const QColor placeholderText = darkPalette.color(QPalette::Active, QPalette::PlaceholderText); 1189 QColor lightText = simpleText.black() < placeholderText.black() ? simpleText : placeholderText; 1190 QColor darkText = simpleText.black() > placeholderText.black() ? simpleText : placeholderText; 1191 if (lightText.black() > 128) 1192 lightText = QColor(Qt::white); 1193 lightText = lightText.darker(150); 1194 if (darkText.black() < 128) 1195 darkText = QColor(Qt::black); 1196 darkText = darkText.lighter(150); 1197 1198 /* Measure base luminance: */ 1199 double dLuminance = (0.299 * base.red() + 0.587 * base.green() + 0.114 * base.blue()) / 255; 1200 1201 /* Adjust color accordingly: */ 1202 darkPalette.setColor(QPalette::Active, QPalette::PlaceholderText, 1203 dLuminance > 0.5 ? darkText : lightText); 1204 1205 /* Put palette back: */ 1206 qApp->setPalette(darkPalette); 1207 } 1208 1209 #endif /* Linux, BSD, Solaris */ 1210 } 1211 1212 bool UICommon::processArgs() 1213 { 1214 /* Among those arguments: */ 1215 bool fResult = false; 1216 const QStringList args = qApp->arguments(); 1217 1218 /* We are looking for a list of file URLs passed to the executable: */ 1219 QList<QUrl> listArgUrls; 1220 for (int i = 1; i < args.size(); ++i) 1221 { 1222 /* But we break out after the first parameter, cause there 1223 * could be parameters with arguments (e.g. --comment comment). */ 1224 if (args.at(i).startsWith("-")) 1225 break; 1226 1227 #ifdef VBOX_WS_MAC 1228 const QString strArg = ::darwinResolveAlias(args.at(i)); 1229 #else 1230 const QString strArg = args.at(i); 1231 #endif 1232 1233 /* So if the argument file exists, we add it to URL list: */ 1234 if ( !strArg.isEmpty() 1235 && QFile::exists(strArg)) 1236 listArgUrls << QUrl::fromLocalFile(QFileInfo(strArg).absoluteFilePath()); 1237 } 1238 1239 /* If there are file URLs: */ 1240 if (!listArgUrls.isEmpty()) 1241 { 1242 /* We enumerate them and: */ 1243 for (int i = 0; i < listArgUrls.size(); ++i) 1244 { 1245 /* Check which of them has allowed VM extensions: */ 1246 const QUrl url = listArgUrls.at(i); 1247 const QString strFile = url.toLocalFile(); 1248 if (UICommon::hasAllowedExtension(strFile, VBoxFileExts)) 1249 { 1250 /* So that we could run existing VMs: */ 1251 CVirtualBox comVBox = virtualBox(); 1252 CMachine comMachine = comVBox.FindMachine(strFile); 1253 if (!comMachine.isNull()) 1254 { 1255 fResult = true; 1256 launchMachine(comMachine); 1257 /* And remove their URLs from the ULR list: */ 1258 listArgUrls.removeAll(url); 1259 } 1260 } 1261 } 1262 } 1263 1264 /* And if there are *still* URLs: */ 1265 if (!listArgUrls.isEmpty()) 1266 { 1267 /* We store them, they will be handled later: */ 1268 m_listArgUrls = listArgUrls; 1269 } 1270 1271 return fResult; 1272 } 1273 1274 bool UICommon::argumentUrlsPresent() const 1275 { 1276 return !m_listArgUrls.isEmpty(); 1277 } 1278 1279 QList<QUrl> UICommon::takeArgumentUrls() 1280 { 1281 const QList<QUrl> result = m_listArgUrls; 1282 m_listArgUrls.clear(); 1283 return result; 1284 } 1285 1286 #ifdef VBOX_WITH_DEBUGGER_GUI 1287 1288 bool UICommon::isDebuggerEnabled() const 1289 { 1290 return isDebuggerWorker(&m_fDbgEnabled, GUI_Dbg_Enabled); 1291 } 1292 1293 bool UICommon::isDebuggerAutoShowEnabled() const 1294 { 1295 return isDebuggerWorker(&m_fDbgAutoShow, GUI_Dbg_AutoShow); 1296 } 1297 1298 bool UICommon::isDebuggerAutoShowCommandLineEnabled() const 1299 { 1300 return isDebuggerWorker(&m_fDbgAutoShowCommandLine, GUI_Dbg_AutoShow); 1301 } 1302 1303 bool UICommon::isDebuggerAutoShowStatisticsEnabled() const 1304 { 1305 return isDebuggerWorker(&m_fDbgAutoShowStatistics, GUI_Dbg_AutoShow); 1306 } 1307 1308 #endif /* VBOX_WITH_DEBUGGER_GUI */ 1309 1310 bool UICommon::shouldStartPaused() const 1311 { 1312 #ifdef VBOX_WITH_DEBUGGER_GUI 1313 return m_enmLaunchRunning == LaunchRunning_Default ? isDebuggerAutoShowEnabled() : m_enmLaunchRunning == LaunchRunning_No; 1314 #else 1315 return false; 1316 #endif 1317 } 1318 1319 #ifdef VBOX_GUI_WITH_PIDFILE 1320 1321 void UICommon::createPidfile() 1322 { 1323 if (!m_strPidFile.isEmpty()) 1324 { 1325 const qint64 iPid = qApp->applicationPid(); 1326 QFile file(m_strPidFile); 1327 if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) 1328 { 1329 QTextStream out(&file); 1330 out << iPid << endl; 1331 } 1332 else 1333 LogRel(("Failed to create pid file %s\n", m_strPidFile.toUtf8().constData())); 1334 } 1335 } 1336 1337 void UICommon::deletePidfile() 1338 { 1339 if ( !m_strPidFile.isEmpty() 1340 && QFile::exists(m_strPidFile)) 1341 QFile::remove(m_strPidFile); 1342 } 1343 1344 #endif /* VBOX_GUI_WITH_PIDFILE */ 1345 1346 /* static */ 1347 bool UICommon::switchToMachine(CMachine &comMachine) 1348 { 1349 #ifdef VBOX_WS_MAC 1350 const ULONG64 id = comMachine.ShowConsoleWindow(); 1351 #else 1352 const WId id = (WId)comMachine.ShowConsoleWindow(); 1353 #endif 1354 Assert(comMachine.isOk()); 1355 if (!comMachine.isOk()) 1356 return false; 1357 1358 // WORKAROUND: 1359 // id == 0 means the console window has already done everything 1360 // necessary to implement the "show window" semantics. 1361 if (id == 0) 1362 return true; 1363 1364 #if defined(VBOX_WS_WIN) || defined(VBOX_WS_NIX) 1365 1366 return UIDesktopWidgetWatchdog::activateWindow(id, true); 1367 1368 #elif defined(VBOX_WS_MAC) 1369 1370 // WORKAROUND: 1371 // This is just for the case were the other process cannot steal 1372 // the focus from us. It will send us a PSN so we can try. 1373 ProcessSerialNumber psn; 1374 psn.highLongOfPSN = id >> 32; 1375 psn.lowLongOfPSN = (UInt32)id; 1376 # ifdef __clang__ 1377 # pragma GCC diagnostic push 1378 # pragma GCC diagnostic ignored "-Wdeprecated-declarations" 1379 OSErr rc = ::SetFrontProcess(&psn); 1380 # pragma GCC diagnostic pop 1381 # else 1382 OSErr rc = ::SetFrontProcess(&psn); 1383 # endif 1384 if (!rc) 1385 Log(("GUI: %#RX64 couldn't do SetFrontProcess on itself, the selector (we) had to do it...\n", id)); 1386 else 1387 Log(("GUI: Failed to bring %#RX64 to front. rc=%#x\n", id, rc)); 1388 return !rc; 1389 1390 #else 1391 1392 return false; 1393 1394 #endif 1395 } 1396 1397 /* static */ 1398 bool UICommon::launchMachine(CMachine &comMachine, UILaunchMode enmLaunchMode /* = UILaunchMode_Default */) 1399 { 1400 /* Switch to machine window(s) if possible: */ 1401 if ( comMachine.GetSessionState() == KSessionState_Locked /* precondition for CanShowConsoleWindow() */ 1402 && comMachine.CanShowConsoleWindow()) 1403 { 1404 switch (uiCommon().uiType()) 1405 { 1406 /* For Selector UI: */ 1407 case UIType_ManagerUI: 1408 { 1409 /* Just switch to existing VM window: */ 1410 return switchToMachine(comMachine); 1411 } 1412 /* For Runtime UI: */ 1413 case UIType_RuntimeUI: 1414 { 1415 /* Only separate UI process can reach that place. 1416 * Switch to existing VM window and exit. */ 1417 switchToMachine(comMachine); 1418 return false; 1419 } 1420 } 1421 } 1422 1423 /* Not for separate UI (which can connect to machine in any state): */ 1424 if (enmLaunchMode != UILaunchMode_Separate) 1425 { 1426 /* Make sure machine-state is one of required: */ 1427 const KMachineState enmState = comMachine.GetState(); NOREF(enmState); 1428 AssertMsg( enmState == KMachineState_PoweredOff 1429 || enmState == KMachineState_Saved 1430 || enmState == KMachineState_Teleported 1431 || enmState == KMachineState_Aborted 1432 || enmState == KMachineState_AbortedSaved 1433 , ("Machine must be PoweredOff/Saved/Teleported/Aborted (%d)", enmState)); 1434 } 1435 1436 /* Create empty session instance: */ 1437 CSession comSession; 1438 comSession.createInstance(CLSID_Session); 1439 if (comSession.isNull()) 1440 { 1441 msgCenter().cannotOpenSession(comSession); 1442 return false; 1443 } 1444 1445 /* Configure environment: */ 1446 QVector<QString> astrEnv; 1447 #ifdef VBOX_WS_WIN 1448 /* Allow started VM process to be foreground window: */ 1449 AllowSetForegroundWindow(ASFW_ANY); 1450 #endif 1451 #ifdef VBOX_WS_NIX 1452 /* Make sure VM process will start on the same 1453 * display as window this wrapper is called from: */ 1454 const char *pDisplay = RTEnvGet("DISPLAY"); 1455 if (pDisplay) 1456 astrEnv.append(QString("DISPLAY=%1").arg(pDisplay)); 1457 const char *pXauth = RTEnvGet("XAUTHORITY"); 1458 if (pXauth) 1459 astrEnv.append(QString("XAUTHORITY=%1").arg(pXauth)); 1460 #endif 1461 QString strType; 1462 switch (enmLaunchMode) 1463 { 1464 case UILaunchMode_Default: strType = ""; break; 1465 case UILaunchMode_Separate: strType = uiCommon().isSeparateProcess() ? "headless" : "separate"; break; 1466 case UILaunchMode_Headless: strType = "headless"; break; 1467 default: AssertFailedReturn(false); 1468 } 1469 1470 /* Prepare "VM spawning" progress: */ 1471 CProgress comProgress = comMachine.LaunchVMProcess(comSession, strType, astrEnv); 1472 if (!comMachine.isOk()) 1473 { 1474 /* If the VM is started separately and the VM process is already running, then it is OK. */ 1475 if (enmLaunchMode == UILaunchMode_Separate) 1476 { 1477 const KMachineState enmState = comMachine.GetState(); 1478 if ( enmState >= KMachineState_FirstOnline 1479 && enmState <= KMachineState_LastOnline) 1480 { 1481 /* Already running: */ 1482 return true; 1483 } 1484 } 1485 1486 msgCenter().cannotOpenSession(comMachine); 1487 return false; 1488 } 1489 1490 /* Show "VM spawning" progress: */ 1491 msgCenter().showModalProgressDialog(comProgress, comMachine.GetName(), 1492 ":/progress_start_90px.png", 0, 0); 1493 if (!comProgress.isOk() || comProgress.GetResultCode() != 0) 1494 msgCenter().cannotOpenSession(comProgress, comMachine.GetName()); 1495 1496 /* Unlock machine, close session: */ 1497 comSession.UnlockMachine(); 1498 1499 /* True finally: */ 1500 return true; 1501 } 1502 1503 CSession UICommon::openSession(QUuid uId, KLockType enmLockType /* = KLockType_Write */) 1504 { 1505 /* Prepare session: */ 1506 CSession comSession; 1507 1508 /* Make sure uId isn't null: */ 1509 if (uId.isNull()) 1510 uId = managedVMUuid(); 1511 if (uId.isNull()) 1512 return comSession; 1513 1514 /* Simulate try-catch block: */ 1515 bool fSuccess = false; 1516 do 1517 { 1518 /* Create empty session instance: */ 1519 comSession.createInstance(CLSID_Session); 1520 if (comSession.isNull()) 1521 { 1522 msgCenter().cannotOpenSession(comSession); 1523 break; 1524 } 1525 1526 /* Search for the corresponding machine: */ 1527 CMachine comMachine = m_comVBox.FindMachine(uId.toString()); 1528 if (comMachine.isNull()) 1529 { 1530 msgCenter().cannotFindMachineById(m_comVBox, uId); 1531 break; 1532 } 1533 1534 if (enmLockType == KLockType_VM) 1535 comSession.SetName("GUI/Qt"); 1536 1537 /* Lock found machine to session: */ 1538 comMachine.LockMachine(comSession, enmLockType); 1539 if (!comMachine.isOk()) 1540 { 1541 msgCenter().cannotOpenSession(comMachine); 1542 break; 1543 } 1544 1545 /* Pass the language ID as the property to the guest: */ 1546 if (comSession.GetType() == KSessionType_Shared) 1547 { 1548 CMachine comStartedMachine = comSession.GetMachine(); 1549 /* Make sure that the language is in two letter code. 1550 * Note: if languageId() returns an empty string lang.name() will 1551 * return "C" which is an valid language code. */ 1552 QLocale lang(UITranslator::languageId()); 1553 comStartedMachine.SetGuestPropertyValue("/VirtualBox/HostInfo/GUI/LanguageID", lang.name()); 1554 } 1555 1556 /* Success finally: */ 1557 fSuccess = true; 1558 } 1559 while (0); 1560 /* Cleanup try-catch block: */ 1561 if (!fSuccess) 1562 comSession.detach(); 1563 1564 /* Return session: */ 1565 return comSession; 1566 } 1567 1568 CSession UICommon::openSession(KLockType enmLockType /* = KLockType_Write */) 1569 { 1570 /* Pass to function above: */ 1571 return openSession(managedVMUuid(), enmLockType); 1572 } 1573 1574 CSession UICommon::tryToOpenSessionFor(CMachine &comMachine) 1575 { 1576 /* Prepare session: */ 1577 CSession comSession; 1578 1579 /* Session state unlocked? */ 1580 if (comMachine.GetSessionState() == KSessionState_Unlocked) 1581 { 1582 /* Open own 'write' session: */ 1583 comSession = openSession(comMachine.GetId()); 1584 AssertReturn(!comSession.isNull(), CSession()); 1585 comMachine = comSession.GetMachine(); 1586 } 1587 /* Is this a Selector UI call? */ 1588 else if (uiType() == UIType_ManagerUI) 1589 { 1590 /* Open existing 'shared' session: */ 1591 comSession = openExistingSession(comMachine.GetId()); 1592 AssertReturn(!comSession.isNull(), CSession()); 1593 comMachine = comSession.GetMachine(); 1594 } 1595 /* Else this is Runtime UI call 1596 * which has session locked for itself. */ 1597 1598 /* Return session: */ 1599 return comSession; 1600 } 1601 1602 void UICommon::notifyCloudMachineUnregistered(const QString &strProviderShortName, 1603 const QString &strProfileName, 1604 const QUuid &uId) 1605 { 1606 emit sigCloudMachineUnregistered(strProviderShortName, strProfileName, uId); 1607 } 1608 1609 void UICommon::notifyCloudMachineRegistered(const QString &strProviderShortName, 1610 const QString &strProfileName, 1611 const CCloudMachine &comMachine) 1612 { 1613 emit sigCloudMachineRegistered(strProviderShortName, strProfileName, comMachine); 1614 } 1615 1616 const UIGuestOSTypeManager &UICommon::guestOSTypeManager() 130 } 131 132 const UIGuestOSTypeManager &UIGlobalSession::guestOSTypeManager() 1617 133 { 1618 134 /* Handle exceptional and undesired case! … … 1631 147 } 1632 148 1633 void UICommon::enumerateMedia(const CMediumVector &comMedia /* = CMediumVector() */) 1634 { 1635 /* Make sure UICommon is already valid: */ 1636 AssertReturnVoid(m_fValid); 1637 /* Ignore the request during UICommon cleanup: */ 1638 if (m_fCleaningUp) 1639 return; 1640 /* Ignore the request during startup snapshot restoring: */ 1641 if (shouldRestoreCurrentSnapshot()) 1642 return; 1643 1644 /* Make sure medium-enumerator is already created: */ 1645 if (!m_pMediumEnumerator) 1646 return; 1647 1648 /* Redirect request to medium-enumerator under proper lock: */ 1649 if (m_meCleanupProtectionToken.tryLockForRead()) 1650 { 1651 if (m_pMediumEnumerator) 1652 m_pMediumEnumerator->enumerateMedia(comMedia); 1653 m_meCleanupProtectionToken.unlock(); 1654 } 1655 } 1656 1657 void UICommon::refreshMedia() 1658 { 1659 /* Make sure UICommon is already valid: */ 1660 AssertReturnVoid(m_fValid); 1661 /* Ignore the request during UICommon cleanup: */ 1662 if (m_fCleaningUp) 1663 return; 1664 /* Ignore the request during startup snapshot restoring: */ 1665 if (shouldRestoreCurrentSnapshot()) 1666 return; 1667 1668 /* Make sure medium-enumerator is already created: */ 1669 if (!m_pMediumEnumerator) 1670 return; 1671 /* Make sure enumeration is not already started: */ 1672 if (m_pMediumEnumerator->isMediumEnumerationInProgress()) 1673 return; 1674 1675 /* We assume it's safe to call it without locking, 1676 * since we are performing blocking operation here. */ 1677 m_pMediumEnumerator->refreshMedia(); 1678 } 1679 1680 bool UICommon::isFullMediumEnumerationRequested() const 1681 { 1682 /* Redirect request to medium-enumerator: */ 1683 return m_pMediumEnumerator 1684 && m_pMediumEnumerator->isFullMediumEnumerationRequested(); 1685 } 1686 1687 bool UICommon::isMediumEnumerationInProgress() const 1688 { 1689 /* Redirect request to medium-enumerator: */ 1690 return m_pMediumEnumerator 1691 && m_pMediumEnumerator->isMediumEnumerationInProgress(); 1692 } 1693 1694 UIMedium UICommon::medium(const QUuid &uMediumID) const 1695 { 1696 if (m_meCleanupProtectionToken.tryLockForRead()) 1697 { 1698 /* Redirect call to medium-enumerator: */ 1699 UIMedium guiMedium; 1700 if (m_pMediumEnumerator) 1701 guiMedium = m_pMediumEnumerator->medium(uMediumID); 1702 m_meCleanupProtectionToken.unlock(); 1703 return guiMedium; 1704 } 1705 return UIMedium(); 1706 } 1707 1708 QList<QUuid> UICommon::mediumIDs() const 1709 { 1710 if (m_meCleanupProtectionToken.tryLockForRead()) 1711 { 1712 /* Redirect call to medium-enumerator: */ 1713 QList<QUuid> listOfMedia; 1714 if (m_pMediumEnumerator) 1715 listOfMedia = m_pMediumEnumerator->mediumIDs(); 1716 m_meCleanupProtectionToken.unlock(); 1717 return listOfMedia; 1718 } 1719 return QList<QUuid>(); 1720 } 1721 1722 void UICommon::createMedium(const UIMedium &guiMedium) 1723 { 1724 if (m_meCleanupProtectionToken.tryLockForRead()) 1725 { 1726 /* Create medium in medium-enumerator: */ 1727 if (m_pMediumEnumerator) 1728 m_pMediumEnumerator->createMedium(guiMedium); 1729 m_meCleanupProtectionToken.unlock(); 1730 } 1731 } 1732 1733 QUuid UICommon::openMedium(UIMediumDeviceType enmMediumType, QString strMediumLocation, QWidget *pParent /* = 0 */) 1734 { 1735 /* Convert to native separators: */ 1736 strMediumLocation = QDir::toNativeSeparators(strMediumLocation); 1737 1738 /* Initialize variables: */ 1739 CVirtualBox comVBox = virtualBox(); 1740 1741 /* Open corresponding medium: */ 1742 CMedium comMedium = comVBox.OpenMedium(strMediumLocation, mediumTypeToGlobal(enmMediumType), KAccessMode_ReadWrite, false); 1743 1744 if (comVBox.isOk()) 1745 { 1746 /* Prepare vbox medium wrapper: */ 1747 UIMedium guiMedium = medium(comMedium.GetId()); 1748 1749 /* First of all we should test if that medium already opened: */ 1750 if (guiMedium.isNull()) 1751 { 1752 /* And create new otherwise: */ 1753 guiMedium = UIMedium(comMedium, enmMediumType, KMediumState_Created); 1754 createMedium(guiMedium); 1755 } 1756 1757 /* Return guiMedium id: */ 1758 return guiMedium.id(); 1759 } 1760 else 1761 msgCenter().cannotOpenMedium(comVBox, strMediumLocation, pParent); 1762 1763 return QUuid(); 1764 } 1765 1766 QUuid UICommon::openMediumWithFileOpenDialog(UIMediumDeviceType enmMediumType, QWidget *pParent, 1767 const QString &strDefaultFolder /* = QString() */, 1768 bool fUseLastFolder /* = false */) 1769 { 1770 /* Initialize variables: */ 1771 QList<QPair <QString, QString> > filters; 1772 QStringList backends; 1773 QStringList prefixes; 1774 QString strFilter; 1775 QString strTitle; 1776 QString allType; 1777 QString strLastFolder = defaultFolderPathForType(enmMediumType); 1778 1779 /* For DVDs and Floppies always check first the last recently used medium folder. For hard disk use 1780 the caller's setting: */ 1781 fUseLastFolder = (enmMediumType == UIMediumDeviceType_DVD) || (enmMediumType == UIMediumDeviceType_Floppy); 1782 1783 switch (enmMediumType) 1784 { 1785 case UIMediumDeviceType_HardDisk: 1786 { 1787 filters = HDDBackends(virtualBox()); 1788 strTitle = tr("Please choose a virtual hard disk file"); 1789 allType = tr("All virtual hard disk files (%1)"); 1790 break; 1791 } 1792 case UIMediumDeviceType_DVD: 1793 { 1794 filters = DVDBackends(virtualBox()); 1795 strTitle = tr("Please choose a virtual optical disk file"); 1796 allType = tr("All virtual optical disk files (%1)"); 1797 break; 1798 } 1799 case UIMediumDeviceType_Floppy: 1800 { 1801 filters = FloppyBackends(virtualBox()); 1802 strTitle = tr("Please choose a virtual floppy disk file"); 1803 allType = tr("All virtual floppy disk files (%1)"); 1804 break; 1805 } 1806 default: 1807 break; 1808 } 1809 QString strHomeFolder = fUseLastFolder && !strLastFolder.isEmpty() ? strLastFolder : 1810 strDefaultFolder.isEmpty() ? homeFolder() : strDefaultFolder; 1811 1812 /* Prepare filters and backends: */ 1813 for (int i = 0; i < filters.count(); ++i) 1814 { 1815 /* Get iterated filter: */ 1816 QPair<QString, QString> item = filters.at(i); 1817 /* Create one backend filter string: */ 1818 backends << QString("%1 (%2)").arg(item.first).arg(item.second); 1819 /* Save the suffix's for the "All" entry: */ 1820 prefixes << item.second; 1821 } 1822 if (!prefixes.isEmpty()) 1823 backends.insert(0, allType.arg(prefixes.join(" ").trimmed())); 1824 backends << tr("All files (*)"); 1825 strFilter = backends.join(";;").trimmed(); 1826 1827 /* Create open file dialog: */ 1828 QStringList files = QIFileDialog::getOpenFileNames(strHomeFolder, strFilter, pParent, strTitle, 0, true, true); 1829 1830 /* If dialog has some result: */ 1831 if (!files.empty() && !files[0].isEmpty()) 1832 { 1833 QUuid uMediumId = openMedium(enmMediumType, files[0], pParent); 1834 if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy || 1835 (enmMediumType == UIMediumDeviceType_HardDisk && fUseLastFolder)) 1836 updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(uMediumId).location()); 1837 return uMediumId; 1838 } 1839 return QUuid(); 1840 } 1841 1842 QUuid UICommon::openMediumCreatorDialog(UIActionPool *pActionPool, QWidget *pParent, UIMediumDeviceType enmMediumType, 1843 const QString &strDefaultFolder /* = QString() */, 1844 const QString &strMachineName /* = QString() */, 1845 const QString &strMachineGuestOSTypeId /*= QString() */) 1846 { 1847 /* Depending on medium-type: */ 1848 QUuid uMediumId; 1849 switch (enmMediumType) 1850 { 1851 case UIMediumDeviceType_HardDisk: 1852 uMediumId = UIWizardNewVD::createVDWithWizard(pParent, strDefaultFolder, strMachineName, strMachineGuestOSTypeId); 1853 break; 1854 case UIMediumDeviceType_DVD: 1855 uMediumId = UIVisoCreatorDialog::createViso(pActionPool, pParent, strDefaultFolder, strMachineName); 1856 break; 1857 case UIMediumDeviceType_Floppy: 1858 uMediumId = UIFDCreationDialog::createFloppyDisk(pParent, strDefaultFolder, strMachineName); 1859 break; 1860 default: 1861 break; 1862 } 1863 if (uMediumId.isNull()) 1864 return QUuid(); 1865 1866 /* Update the recent medium list only if the medium type is floppy since updating when a VISO is created is not optimal: */ 1867 if (enmMediumType == UIMediumDeviceType_Floppy) 1868 updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(uMediumId).location()); 1869 return uMediumId; 1870 } 1871 1872 void UICommon::prepareStorageMenu(QMenu *pMenu, 1873 QObject *pListener, const char *pszSlotName, 1874 const CMachine &comMachine, const QString &strControllerName, const StorageSlot &storageSlot) 1875 { 1876 /* Current attachment attributes: */ 1877 const CMediumAttachment comCurrentAttachment = comMachine.GetMediumAttachment(strControllerName, 1878 storageSlot.port, 1879 storageSlot.device); 1880 const CMedium comCurrentMedium = comCurrentAttachment.GetMedium(); 1881 const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId(); 1882 const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation(); 1883 1884 /* Other medium-attachments of same machine: */ 1885 const CMediumAttachmentVector comAttachments = comMachine.GetMediumAttachments(); 1886 1887 /* Determine device & medium types: */ 1888 const UIMediumDeviceType enmMediumType = mediumTypeToLocal(comCurrentAttachment.GetType()); 1889 AssertMsgReturnVoid(enmMediumType != UIMediumDeviceType_Invalid, ("Incorrect storage medium type!\n")); 1890 1891 /* Prepare open-existing-medium action: */ 1892 QAction *pActionOpenExistingMedium = pMenu->addAction(UIIconPool::iconSet(":/select_file_16px.png"), 1893 QString(), pListener, pszSlotName); 1894 pActionOpenExistingMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(), 1895 comCurrentAttachment.GetDevice(), enmMediumType))); 1896 pActionOpenExistingMedium->setText(QApplication::translate("UIMachineSettingsStorage", "Choose/Create a disk image...")); 1897 1898 1899 /* Prepare open medium file action: */ 1900 QAction *pActionFileSelector = pMenu->addAction(UIIconPool::iconSet(":/select_file_16px.png"), 1901 QString(), pListener, pszSlotName); 1902 pActionFileSelector->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(), 1903 comCurrentAttachment.GetDevice(), enmMediumType, 1904 UIMediumTarget::UIMediumTargetType_WithFileDialog))); 1905 pActionFileSelector->setText(QApplication::translate("UIMachineSettingsStorage", "Choose a disk file...")); 1906 1907 1908 /* Insert separator: */ 1909 pMenu->addSeparator(); 1910 1911 /* Get existing-host-drive vector: */ 1912 CMediumVector comMedia; 1913 switch (enmMediumType) 1914 { 1915 case UIMediumDeviceType_DVD: comMedia = host().GetDVDDrives(); break; 1916 case UIMediumDeviceType_Floppy: comMedia = host().GetFloppyDrives(); break; 1917 default: break; 1918 } 1919 /* Prepare choose-existing-host-drive actions: */ 1920 foreach (const CMedium &comMedium, comMedia) 1921 { 1922 /* Make sure host-drive usage is unique: */ 1923 bool fIsHostDriveUsed = false; 1924 foreach (const CMediumAttachment &comOtherAttachment, comAttachments) 1925 { 1926 if (comOtherAttachment != comCurrentAttachment) 1927 { 1928 const CMedium &comOtherMedium = comOtherAttachment.GetMedium(); 1929 if (!comOtherMedium.isNull() && comOtherMedium.GetId() == comMedium.GetId()) 1930 { 1931 fIsHostDriveUsed = true; 1932 break; 1933 } 1934 } 1935 } 1936 /* If host-drives usage is unique: */ 1937 if (!fIsHostDriveUsed) 1938 { 1939 QAction *pActionChooseHostDrive = pMenu->addAction(UIMedium(comMedium, enmMediumType).name(), pListener, pszSlotName); 1940 pActionChooseHostDrive->setCheckable(true); 1941 pActionChooseHostDrive->setChecked(!comCurrentMedium.isNull() && comMedium.GetId() == uCurrentID); 1942 pActionChooseHostDrive->setData(QVariant::fromValue(UIMediumTarget(strControllerName, 1943 comCurrentAttachment.GetPort(), 1944 comCurrentAttachment.GetDevice(), 1945 enmMediumType, 1946 UIMediumTarget::UIMediumTargetType_WithID, 1947 comMedium.GetId().toString()))); 1948 } 1949 } 1950 1951 /* Get recent-medium list: */ 1952 QStringList recentMediumList; 1953 QStringList recentMediumListUsed; 1954 switch (enmMediumType) 1955 { 1956 case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break; 1957 case UIMediumDeviceType_DVD: recentMediumList = gEDataManager->recentListOfOpticalDisks(); break; 1958 case UIMediumDeviceType_Floppy: recentMediumList = gEDataManager->recentListOfFloppyDisks(); break; 1959 default: break; 1960 } 1961 /* Prepare choose-recent-medium actions: */ 1962 foreach (const QString &strRecentMediumLocationBase, recentMediumList) 1963 { 1964 /* Confirm medium uniqueness: */ 1965 if (recentMediumListUsed.contains(strRecentMediumLocationBase)) 1966 continue; 1967 /* Mark medium as known: */ 1968 recentMediumListUsed << strRecentMediumLocationBase; 1969 /* Convert separators to native: */ 1970 const QString strRecentMediumLocation = QDir::toNativeSeparators(strRecentMediumLocationBase); 1971 /* Confirm medium presence: */ 1972 if (!QFile::exists(strRecentMediumLocation)) 1973 continue; 1974 /* Make sure recent-medium usage is unique: */ 1975 bool fIsRecentMediumUsed = false; 1976 if (enmMediumType != UIMediumDeviceType_DVD) 1977 { 1978 foreach (const CMediumAttachment &otherAttachment, comAttachments) 1979 { 1980 if (otherAttachment != comCurrentAttachment) 1981 { 1982 const CMedium &comOtherMedium = otherAttachment.GetMedium(); 1983 if (!comOtherMedium.isNull() && comOtherMedium.GetLocation() == strRecentMediumLocation) 1984 { 1985 fIsRecentMediumUsed = true; 1986 break; 1987 } 1988 } 1989 } 1990 } 1991 /* If recent-medium usage is unique: */ 1992 if (!fIsRecentMediumUsed) 1993 { 1994 QAction *pActionChooseRecentMedium = pMenu->addAction(QFileInfo(strRecentMediumLocation).fileName(), 1995 pListener, pszSlotName); 1996 pActionChooseRecentMedium->setCheckable(true); 1997 pActionChooseRecentMedium->setChecked(!comCurrentMedium.isNull() && strRecentMediumLocation == strCurrentLocation); 1998 pActionChooseRecentMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, 1999 comCurrentAttachment.GetPort(), 2000 comCurrentAttachment.GetDevice(), 2001 enmMediumType, 2002 UIMediumTarget::UIMediumTargetType_WithLocation, 2003 strRecentMediumLocation))); 2004 pActionChooseRecentMedium->setToolTip(strRecentMediumLocation); 2005 } 2006 } 2007 2008 /* Last action for optical/floppy attachments only: */ 2009 if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy) 2010 { 2011 /* Insert separator: */ 2012 pMenu->addSeparator(); 2013 2014 /* Prepare unmount-current-medium action: */ 2015 QAction *pActionUnmountMedium = pMenu->addAction(QString(), pListener, pszSlotName); 2016 pActionUnmountMedium->setEnabled(!comCurrentMedium.isNull()); 2017 pActionUnmountMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(), 2018 comCurrentAttachment.GetDevice()))); 2019 pActionUnmountMedium->setText(QApplication::translate("UIMachineSettingsStorage", "Remove disk from virtual drive")); 2020 if (enmMediumType == UIMediumDeviceType_DVD) 2021 pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/cd_unmount_16px.png", ":/cd_unmount_disabled_16px.png")); 2022 else if (enmMediumType == UIMediumDeviceType_Floppy) 2023 pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/fd_unmount_16px.png", ":/fd_unmount_disabled_16px.png")); 2024 } 2025 } 2026 2027 void UICommon::updateMachineStorage(const CMachine &comConstMachine, const UIMediumTarget &target, UIActionPool *pActionPool) 2028 { 2029 /* Mount (by default): */ 2030 bool fMount = true; 2031 /* Null medium (by default): */ 2032 CMedium comMedium; 2033 /* With null ID (by default): */ 2034 QUuid uActualID; 2035 2036 /* Current mount-target attributes: */ 2037 const CStorageController comCurrentController = comConstMachine.GetStorageControllerByName(target.name); 2038 const KStorageBus enmCurrentStorageBus = comCurrentController.GetBus(); 2039 const CMediumAttachment comCurrentAttachment = comConstMachine.GetMediumAttachment(target.name, target.port, target.device); 2040 const CMedium comCurrentMedium = comCurrentAttachment.GetMedium(); 2041 const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId(); 2042 const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation(); 2043 2044 /* Which additional info do we have? */ 2045 switch (target.type) 2046 { 2047 /* Do we have an exact ID or do we let the user open a medium? */ 2048 case UIMediumTarget::UIMediumTargetType_WithID: 2049 case UIMediumTarget::UIMediumTargetType_WithFileDialog: 2050 case UIMediumTarget::UIMediumTargetType_CreateAdHocVISO: 2051 case UIMediumTarget::UIMediumTargetType_CreateFloppyDisk: 2052 { 2053 /* New mount-target attributes: */ 2054 QUuid uNewID; 2055 2056 /* Invoke file-open dialog to choose medium ID: */ 2057 if (target.mediumType != UIMediumDeviceType_Invalid && target.data.isNull()) 2058 { 2059 /* Keyboard can be captured by machine-view. 2060 * So we should clear machine-view focus to let file-open dialog get it. 2061 * That way the keyboard will be released too.. */ 2062 QWidget *pLastFocusedWidget = 0; 2063 if (QApplication::focusWidget()) 2064 { 2065 pLastFocusedWidget = QApplication::focusWidget(); 2066 pLastFocusedWidget->clearFocus(); 2067 } 2068 /* Call for file-open dialog: */ 2069 const QString strMachineFolder(QFileInfo(comConstMachine.GetSettingsFilePath()).absolutePath()); 2070 QUuid uMediumID; 2071 if (target.type == UIMediumTarget::UIMediumTargetType_WithID) 2072 { 2073 int iDialogReturn = UIMediumSelector::openMediumSelectorDialog(windowManager().mainWindowShown(), target.mediumType, 2074 uCurrentID, uMediumID, 2075 strMachineFolder, comConstMachine.GetName(), 2076 comConstMachine.GetOSTypeId(), true /*fEnableCreate */, 2077 comConstMachine.GetId(), pActionPool); 2078 if (iDialogReturn == UIMediumSelector::ReturnCode_LeftEmpty && 2079 (target.mediumType == UIMediumDeviceType_DVD || target.mediumType == UIMediumDeviceType_Floppy)) 2080 fMount = false; 2081 } 2082 else if (target.type == UIMediumTarget::UIMediumTargetType_WithFileDialog) 2083 { 2084 uMediumID = openMediumWithFileOpenDialog(target.mediumType, windowManager().mainWindowShown(), 2085 strMachineFolder, false /* fUseLastFolder */); 2086 } 2087 else if(target.type == UIMediumTarget::UIMediumTargetType_CreateAdHocVISO) 2088 UIVisoCreatorDialog::createViso(pActionPool, windowManager().mainWindowShown(), 2089 strMachineFolder, comConstMachine.GetName()); 2090 2091 else if(target.type == UIMediumTarget::UIMediumTargetType_CreateFloppyDisk) 2092 uMediumID = UIFDCreationDialog::createFloppyDisk(windowManager().mainWindowShown(), strMachineFolder, comConstMachine.GetName()); 2093 2094 /* Return focus back: */ 2095 if (pLastFocusedWidget) 2096 pLastFocusedWidget->setFocus(); 2097 /* Accept new medium ID: */ 2098 if (!uMediumID.isNull()) 2099 uNewID = uMediumID; 2100 else 2101 /* Else just exit in case left empty is not chosen in medium selector dialog: */ 2102 if (fMount) 2103 return; 2104 } 2105 /* Use medium ID which was passed: */ 2106 else if (!target.data.isNull() && target.data != uCurrentID.toString()) 2107 uNewID = QUuid(target.data); 2108 2109 /* Should we mount or unmount? */ 2110 fMount = !uNewID.isNull(); 2111 2112 /* Prepare target medium: */ 2113 const UIMedium guiMedium = medium(uNewID); 2114 comMedium = guiMedium.medium(); 2115 uActualID = fMount ? uNewID : uCurrentID; 2116 break; 2117 } 2118 /* Do we have a recent location? */ 2119 case UIMediumTarget::UIMediumTargetType_WithLocation: 2120 { 2121 /* Open medium by location and get new medium ID if any: */ 2122 const QUuid uNewID = openMedium(target.mediumType, target.data); 2123 /* Else just exit: */ 2124 if (uNewID.isNull()) 2125 return; 2126 2127 /* Should we mount or unmount? */ 2128 fMount = uNewID != uCurrentID; 2129 2130 /* Prepare target medium: */ 2131 const UIMedium guiMedium = fMount ? medium(uNewID) : UIMedium(); 2132 comMedium = fMount ? guiMedium.medium() : CMedium(); 2133 uActualID = fMount ? uNewID : uCurrentID; 2134 break; 2135 } 2136 } 2137 2138 /* Do not unmount hard-drives: */ 2139 if (target.mediumType == UIMediumDeviceType_HardDisk && !fMount) 2140 return; 2141 2142 /* Get editable machine & session: */ 2143 CMachine comMachine = comConstMachine; 2144 CSession comSession = tryToOpenSessionFor(comMachine); 2145 2146 /* Remount medium to the predefined port/device: */ 2147 bool fWasMounted = false; 2148 /* Hard drive case: */ 2149 if (target.mediumType == UIMediumDeviceType_HardDisk) 2150 { 2151 /* Detaching: */ 2152 comMachine.DetachDevice(target.name, target.port, target.device); 2153 fWasMounted = comMachine.isOk(); 2154 if (!fWasMounted) 2155 msgCenter().cannotDetachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation, 2156 StorageSlot(enmCurrentStorageBus, target.port, target.device)); 2157 else 2158 { 2159 /* Attaching: */ 2160 comMachine.AttachDevice(target.name, target.port, target.device, KDeviceType_HardDisk, comMedium); 2161 fWasMounted = comMachine.isOk(); 2162 if (!fWasMounted) 2163 msgCenter().cannotAttachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation, 2164 StorageSlot(enmCurrentStorageBus, target.port, target.device)); 2165 } 2166 } 2167 /* Optical/floppy drive case: */ 2168 else 2169 { 2170 /* Remounting: */ 2171 comMachine.MountMedium(target.name, target.port, target.device, comMedium, false /* force? */); 2172 fWasMounted = comMachine.isOk(); 2173 if (!fWasMounted) 2174 { 2175 /* Ask for force remounting: */ 2176 if (msgCenter().cannotRemountMedium(comMachine, medium(uActualID), 2177 fMount, true /* retry? */)) 2178 { 2179 /* Force remounting: */ 2180 comMachine.MountMedium(target.name, target.port, target.device, comMedium, true /* force? */); 2181 fWasMounted = comMachine.isOk(); 2182 if (!fWasMounted) 2183 msgCenter().cannotRemountMedium(comMachine, medium(uActualID), 2184 fMount, false /* retry? */); 2185 } 2186 } 2187 } 2188 2189 /* Save settings: */ 2190 if (fWasMounted) 2191 { 2192 comMachine.SaveSettings(); 2193 if (!comMachine.isOk()) 2194 msgCenter().cannotSaveMachineSettings(comMachine, windowManager().mainWindowShown()); 2195 } 2196 2197 /* Close session to editable comMachine if necessary: */ 2198 if (!comSession.isNull()) 2199 comSession.UnlockMachine(); 2200 } 2201 2202 QString UICommon::storageDetails(const CMedium &comMedium, bool fPredictDiff, bool fUseHtml /* = true */) 2203 { 2204 /* Search for corresponding UI medium: */ 2205 const QUuid uMediumID = comMedium.isNull() ? UIMedium::nullID() : comMedium.GetId(); 2206 UIMedium guiMedium = medium(uMediumID); 2207 if (!comMedium.isNull() && guiMedium.isNull()) 2208 { 2209 /* UI medium may be new and not among cached media, request enumeration: */ 2210 enumerateMedia(CMediumVector() << comMedium); 2211 2212 /* Search for corresponding UI medium again: */ 2213 guiMedium = medium(uMediumID); 2214 if (guiMedium.isNull()) 2215 { 2216 /* Medium might be deleted already, return null string: */ 2217 return QString(); 2218 } 2219 } 2220 2221 /* For differencing hard-disk we have to request 2222 * enumeration of whole tree based in it's root item: */ 2223 if ( comMedium.isNotNull() 2224 && comMedium.GetDeviceType() == KDeviceType_HardDisk) 2225 { 2226 /* Traverse through parents to root to catch it: */ 2227 CMedium comRootMedium; 2228 CMedium comParentMedium = comMedium.GetParent(); 2229 while (comParentMedium.isNotNull()) 2230 { 2231 comRootMedium = comParentMedium; 2232 comParentMedium = comParentMedium.GetParent(); 2233 } 2234 /* Enumerate root if it's found and wasn't cached: */ 2235 if (comRootMedium.isNotNull()) 2236 { 2237 const QUuid uRootId = comRootMedium.GetId(); 2238 if (medium(uRootId).isNull()) 2239 enumerateMedia(CMediumVector() << comRootMedium); 2240 } 2241 } 2242 2243 /* Return UI medium details: */ 2244 return fUseHtml ? guiMedium.detailsHTML(true /* no diffs? */, fPredictDiff) : 2245 guiMedium.details(true /* no diffs? */, fPredictDiff); 2246 } 2247 2248 void UICommon::updateRecentlyUsedMediumListAndFolder(UIMediumDeviceType enmMediumType, QString strMediumLocation) 2249 { 2250 /** Don't add the medium to extra data if its name is in exclude list, m_recentMediaExcludeList: */ 2251 foreach (QString strExcludeName, m_recentMediaExcludeList) 2252 { 2253 if (strMediumLocation.contains(strExcludeName)) 2254 return; 2255 } 2256 2257 /* Remember the path of the last chosen medium: */ 2258 switch (enmMediumType) 2259 { 2260 case UIMediumDeviceType_HardDisk: gEDataManager->setRecentFolderForHardDrives(QFileInfo(strMediumLocation).absolutePath()); break; 2261 case UIMediumDeviceType_DVD: gEDataManager->setRecentFolderForOpticalDisks(QFileInfo(strMediumLocation).absolutePath()); break; 2262 case UIMediumDeviceType_Floppy: gEDataManager->setRecentFolderForFloppyDisks(QFileInfo(strMediumLocation).absolutePath()); break; 2263 default: break; 2264 } 2265 2266 /* Update recently used list: */ 2267 QStringList recentMediumList; 2268 switch (enmMediumType) 2269 { 2270 case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break; 2271 case UIMediumDeviceType_DVD: recentMediumList = gEDataManager->recentListOfOpticalDisks(); break; 2272 case UIMediumDeviceType_Floppy: recentMediumList = gEDataManager->recentListOfFloppyDisks(); break; 2273 default: break; 2274 } 2275 if (recentMediumList.contains(strMediumLocation)) 2276 recentMediumList.removeAll(strMediumLocation); 2277 recentMediumList.prepend(strMediumLocation); 2278 while(recentMediumList.size() > 5) 2279 recentMediumList.removeLast(); 2280 switch (enmMediumType) 2281 { 2282 case UIMediumDeviceType_HardDisk: gEDataManager->setRecentListOfHardDrives(recentMediumList); break; 2283 case UIMediumDeviceType_DVD: gEDataManager->setRecentListOfOpticalDisks(recentMediumList); break; 2284 case UIMediumDeviceType_Floppy: gEDataManager->setRecentListOfFloppyDisks(recentMediumList); break; 2285 default: break; 2286 } 2287 emit sigRecentMediaListUpdated(enmMediumType); 2288 } 2289 2290 QString UICommon::defaultFolderPathForType(UIMediumDeviceType enmMediumType) 2291 { 2292 QString strLastFolder; 2293 switch (enmMediumType) 2294 { 2295 case UIMediumDeviceType_HardDisk: 2296 strLastFolder = gEDataManager->recentFolderForHardDrives(); 2297 if (strLastFolder.isEmpty()) 2298 strLastFolder = gEDataManager->recentFolderForOpticalDisks(); 2299 if (strLastFolder.isEmpty()) 2300 strLastFolder = gEDataManager->recentFolderForFloppyDisks(); 2301 break; 2302 case UIMediumDeviceType_DVD: 2303 strLastFolder = gEDataManager->recentFolderForOpticalDisks(); 2304 if (strLastFolder.isEmpty()) 2305 strLastFolder = gEDataManager->recentFolderForFloppyDisks(); 2306 if (strLastFolder.isEmpty()) 2307 strLastFolder = gEDataManager->recentFolderForHardDrives(); 2308 break; 2309 case UIMediumDeviceType_Floppy: 2310 strLastFolder = gEDataManager->recentFolderForFloppyDisks(); 2311 if (strLastFolder.isEmpty()) 2312 strLastFolder = gEDataManager->recentFolderForOpticalDisks(); 2313 if (strLastFolder.isEmpty()) 2314 strLastFolder = gEDataManager->recentFolderForHardDrives(); 2315 break; 2316 default: 2317 break; 2318 } 2319 2320 if (strLastFolder.isEmpty()) 2321 return virtualBox().GetSystemProperties().GetDefaultMachineFolder(); 2322 2323 return strLastFolder; 2324 } 2325 2326 /* static */ 2327 bool UICommon::acquireAmountOfImmutableImages(const CMachine &comMachine, ulong &cAmount) 2328 { 2329 /* Acquire state: */ 2330 ulong cAmountOfImmutableImages = 0; 2331 const KMachineState enmState = comMachine.GetState(); 2332 bool fSuccess = comMachine.isOk(); 2333 if (!fSuccess) 2334 UINotificationMessage::cannotAcquireMachineParameter(comMachine); 2335 else 2336 { 2337 /// @todo Who knows why 13 years ago this condition was added .. 2338 if (enmState == KMachineState_Paused) 2339 { 2340 const CMediumAttachmentVector comAttachments = comMachine.GetMediumAttachments(); 2341 fSuccess = comMachine.isOk(); 2342 if (!fSuccess) 2343 UINotificationMessage::cannotAcquireMachineParameter(comMachine); 2344 else 2345 { 2346 /* Calculate the amount of immutable attachments: */ 2347 foreach (const CMediumAttachment &comAttachment, comAttachments) 2348 { 2349 /* Get the medium: */ 2350 const CMedium comMedium = comAttachment.GetMedium(); 2351 if ( comMedium.isNull() /* Null medium is valid case as well */ 2352 || comMedium.GetParent().isNull() /* Null parent is valid case as well */) 2353 continue; 2354 /* Get the base medium: */ 2355 const CMedium comBaseMedium = comMedium.GetBase(); 2356 fSuccess = comMedium.isOk(); 2357 if (!fSuccess) 2358 UINotificationMessage::cannotAcquireMediumParameter(comMedium); 2359 else 2360 { 2361 const KMediumType enmType = comBaseMedium.GetType(); 2362 fSuccess = comBaseMedium.isOk(); 2363 if (!fSuccess) 2364 UINotificationMessage::cannotAcquireMediumParameter(comBaseMedium); 2365 else if (enmType == KMediumType_Immutable) 2366 ++cAmountOfImmutableImages; 2367 } 2368 if (!fSuccess) 2369 break; 2370 } 2371 } 2372 } 2373 } 2374 if (fSuccess) 2375 cAmount = cAmountOfImmutableImages; 2376 return fSuccess; 2377 } 2378 2379 #ifdef RT_OS_LINUX 2380 /* static */ 2381 void UICommon::checkForWrongUSBMounted() 2382 { 2383 /* Make sure '/proc/mounts' exists and can be opened: */ 2384 QFile file("/proc/mounts"); 2385 if (!file.exists() || !file.open(QIODevice::ReadOnly | QIODevice::Text)) 2386 return; 2387 2388 /* Fetch contents: */ 2389 QStringList contents; 2390 for (;;) 2391 { 2392 QByteArray line = file.readLine(); 2393 if (line.isEmpty()) 2394 break; 2395 contents << line; 2396 } 2397 /* Grep contents for usbfs presence: */ 2398 QStringList grep1(contents.filter("/sys/bus/usb/drivers")); 2399 QStringList grep2(grep1.filter("usbfs")); 2400 if (grep2.isEmpty()) 2401 return; 2402 2403 /* Show corresponding warning: */ 2404 msgCenter().warnAboutWrongUSBMounted(); 2405 } 2406 #endif /* RT_OS_LINUX */ 2407 2408 /* static */ 2409 QString UICommon::usbDetails(const CUSBDevice &comDevice) 2410 { 2411 QString strDetails; 2412 if (comDevice.isNull()) 2413 strDetails = tr("Unknown device", "USB device details"); 2414 else 2415 { 2416 QVector<QString> devInfoVector = comDevice.GetDeviceInfo(); 2417 QString strManufacturer; 2418 QString strProduct; 2419 2420 if (devInfoVector.size() >= 1) 2421 strManufacturer = devInfoVector[0].trimmed(); 2422 if (devInfoVector.size() >= 2) 2423 strProduct = devInfoVector[1].trimmed(); 2424 2425 if (strManufacturer.isEmpty() && strProduct.isEmpty()) 2426 { 2427 strDetails = 2428 tr("Unknown device %1:%2", "USB device details") 2429 .arg(QString::number(comDevice.GetVendorId(), 16).toUpper().rightJustified(4, '0')) 2430 .arg(QString::number(comDevice.GetProductId(), 16).toUpper().rightJustified(4, '0')); 2431 } 2432 else 2433 { 2434 if (strProduct.toUpper().startsWith(strManufacturer.toUpper())) 2435 strDetails = strProduct; 2436 else 2437 strDetails = strManufacturer + " " + strProduct; 2438 } 2439 ushort iRev = comDevice.GetRevision(); 2440 if (iRev != 0) 2441 { 2442 strDetails += " ["; 2443 strDetails += QString::number(iRev, 16).toUpper().rightJustified(4, '0'); 2444 strDetails += "]"; 2445 } 2446 } 2447 2448 return strDetails.trimmed(); 2449 } 2450 2451 /* static */ 2452 QString UICommon::usbToolTip(const CUSBDevice &comDevice) 2453 { 2454 QString strTip = 2455 tr("<nobr>Vendor ID: %1</nobr><br>" 2456 "<nobr>Product ID: %2</nobr><br>" 2457 "<nobr>Revision: %3</nobr>", "USB device tooltip") 2458 .arg(QString::number(comDevice.GetVendorId(), 16).toUpper().rightJustified(4, '0')) 2459 .arg(QString::number(comDevice.GetProductId(), 16).toUpper().rightJustified(4, '0')) 2460 .arg(QString::number(comDevice.GetRevision(), 16).toUpper().rightJustified(4, '0')); 2461 2462 const QString strSerial = comDevice.GetSerialNumber(); 2463 if (!strSerial.isEmpty()) 2464 strTip += QString(tr("<br><nobr>Serial No. %1</nobr>", "USB device tooltip")) 2465 .arg(strSerial); 2466 2467 /* Add the state field if it's a host USB device: */ 2468 CHostUSBDevice hostDev(comDevice); 2469 if (!hostDev.isNull()) 2470 { 2471 strTip += QString(tr("<br><nobr>State: %1</nobr>", "USB device tooltip")) 2472 .arg(gpConverter->toString(hostDev.GetState())); 2473 } 2474 2475 return strTip; 2476 } 2477 2478 /* static */ 2479 QString UICommon::usbToolTip(const CUSBDeviceFilter &comFilter) 2480 { 2481 QString strTip; 2482 2483 const QString strVendorId = comFilter.GetVendorId(); 2484 if (!strVendorId.isEmpty()) 2485 strTip += tr("<nobr>Vendor ID: %1</nobr>", "USB filter tooltip") 2486 .arg(strVendorId); 2487 2488 const QString strProductId = comFilter.GetProductId(); 2489 if (!strProductId.isEmpty()) 2490 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product ID: %2</nobr>", "USB filter tooltip") 2491 .arg(strProductId); 2492 2493 const QString strRevision = comFilter.GetRevision(); 2494 if (!strRevision.isEmpty()) 2495 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Revision: %3</nobr>", "USB filter tooltip") 2496 .arg(strRevision); 2497 2498 const QString strProduct = comFilter.GetProduct(); 2499 if (!strProduct.isEmpty()) 2500 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product: %4</nobr>", "USB filter tooltip") 2501 .arg(strProduct); 2502 2503 const QString strManufacturer = comFilter.GetManufacturer(); 2504 if (!strManufacturer.isEmpty()) 2505 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Manufacturer: %5</nobr>", "USB filter tooltip") 2506 .arg(strManufacturer); 2507 2508 const QString strSerial = comFilter.GetSerialNumber(); 2509 if (!strSerial.isEmpty()) 2510 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Serial No.: %1</nobr>", "USB filter tooltip") 2511 .arg(strSerial); 2512 2513 const QString strPort = comFilter.GetPort(); 2514 if (!strPort.isEmpty()) 2515 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Port: %1</nobr>", "USB filter tooltip") 2516 .arg(strPort); 2517 2518 /* Add the state field if it's a host USB device: */ 2519 CHostUSBDevice hostDev(comFilter); 2520 if (!hostDev.isNull()) 2521 { 2522 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>State: %1</nobr>", "USB filter tooltip") 2523 .arg(gpConverter->toString(hostDev.GetState())); 2524 } 2525 2526 return strTip; 2527 } 2528 2529 /* static */ 2530 QString UICommon::usbToolTip(const CHostVideoInputDevice &comWebcam) 2531 { 2532 QStringList records; 2533 2534 const QString strName = comWebcam.GetName(); 2535 if (!strName.isEmpty()) 2536 records << strName; 2537 2538 const QString strPath = comWebcam.GetPath(); 2539 if (!strPath.isEmpty()) 2540 records << strPath; 2541 2542 return records.join("<br>"); 2543 } 2544 2545 int UICommon::supportedRecordingFeatures() const 2546 { 2547 int iSupportedFlag = 0; 2548 CSystemProperties comProperties = virtualBox().GetSystemProperties(); 2549 foreach (const KRecordingFeature &enmFeature, comProperties.GetSupportedRecordingFeatures()) 2550 iSupportedFlag |= enmFeature; 2551 return iSupportedFlag; 2552 } 2553 2554 /* static */ 2555 QString UICommon::helpFile() 2556 { 2557 const QString strName = "UserManual"; 2558 const QString strSuffix = "qhc"; 2559 2560 /* Where are the docs located? */ 2561 char szDocsPath[RTPATH_MAX]; 2562 int rc = RTPathAppDocs(szDocsPath, sizeof(szDocsPath)); 2563 AssertRC(rc); 2564 2565 /* Make sure that the language is in two letter code. 2566 * Note: if languageId() returns an empty string lang.name() will 2567 * return "C" which is an valid language code. */ 2568 QLocale lang(UITranslator::languageId()); 2569 2570 /* Construct the path and the filename: */ 2571 QString strManual = QString("%1/%2_%3.%4").arg(szDocsPath) 2572 .arg(strName) 2573 .arg(lang.name()) 2574 .arg(strSuffix); 2575 2576 /* Check if a help file with that name exists: */ 2577 QFileInfo fi(strManual); 2578 if (fi.exists()) 2579 return strManual; 2580 2581 /* Fall back to the standard: */ 2582 strManual = QString("%1/%2.%4").arg(szDocsPath) 2583 .arg(strName) 2584 .arg(strSuffix); 2585 return strManual; 2586 } 2587 2588 /* static */ 2589 QString UICommon::documentsPath() 2590 { 2591 QString strPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); 2592 QDir dir(strPath); 2593 if (dir.exists()) 2594 return QDir::cleanPath(dir.canonicalPath()); 2595 else 2596 { 2597 dir.setPath(QDir::homePath() + "/Documents"); 2598 if (dir.exists()) 2599 return QDir::cleanPath(dir.canonicalPath()); 2600 else 2601 return QDir::homePath(); 2602 } 2603 } 2604 2605 /* static */ 2606 bool UICommon::hasAllowedExtension(const QString &strFileName, const QStringList &extensions) 2607 { 2608 foreach (const QString &strExtension, extensions) 2609 if (strFileName.endsWith(strExtension, Qt::CaseInsensitive)) 2610 return true; 2611 return false; 2612 } 2613 2614 /* static */ 2615 QString UICommon::findUniqueFileName(const QString &strFullFolderPath, const QString &strBaseFileName) 2616 { 2617 QDir folder(strFullFolderPath); 2618 if (!folder.exists()) 2619 return strBaseFileName; 2620 QFileInfoList folderContent = folder.entryInfoList(); 2621 QSet<QString> fileNameSet; 2622 foreach (const QFileInfo &fileInfo, folderContent) 2623 { 2624 /* Remove the extension : */ 2625 fileNameSet.insert(fileInfo.completeBaseName()); 2626 } 2627 int iSuffix = 0; 2628 QString strNewName(strBaseFileName); 2629 while (fileNameSet.contains(strNewName)) 2630 { 2631 strNewName = strBaseFileName + QString("_") + QString::number(++iSuffix); 2632 } 2633 return strNewName; 2634 } 2635 2636 /* static */ 2637 void UICommon::setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount) 2638 { 2639 /* Shame on Qt it hasn't stuff for tuning 2640 * widget size suitable for reflecting content of desired size. 2641 * For example QLineEdit, QSpinBox and similar widgets should have a methods 2642 * to strict the minimum width to reflect at least [n] symbols. */ 2643 2644 /* Load options: */ 2645 QStyleOptionSpinBox option; 2646 option.initFrom(pSpinBox); 2647 2648 /* Acquire edit-field rectangle: */ 2649 QRect rect = pSpinBox->style()->subControlRect(QStyle::CC_SpinBox, 2650 &option, 2651 QStyle::SC_SpinBoxEditField, 2652 pSpinBox); 2653 2654 /* Calculate minimum-width magic: */ 2655 const int iSpinBoxWidth = pSpinBox->width(); 2656 const int iSpinBoxEditFieldWidth = rect.width(); 2657 const int iSpinBoxDelta = qMax(0, iSpinBoxWidth - iSpinBoxEditFieldWidth); 2658 QFontMetrics metrics(pSpinBox->font(), pSpinBox); 2659 const QString strDummy(cCount, '0'); 2660 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) 2661 const int iTextWidth = metrics.horizontalAdvance(strDummy); 2662 #else 2663 const int iTextWidth = metrics.width(strDummy); 2664 #endif 2665 2666 /* Tune spin-box minimum-width: */ 2667 pSpinBox->setMinimumWidth(iTextWidth + iSpinBoxDelta); 2668 } 2669 2670 #ifdef VBOX_WITH_3D_ACCELERATION 2671 /* static */ 2672 bool UICommon::isWddmCompatibleOsType(const QString &strGuestOSTypeId) 2673 { 2674 return strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("WindowsVista")) 2675 || strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows7")) 2676 || strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows8")) 2677 || strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows81")) 2678 || strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows10")) 2679 || strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows11")) 2680 || strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows2008")) 2681 || strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows2012")) 2682 || strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows2016")) 2683 || strGuestOSTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows2019")); 2684 } 2685 #endif /* VBOX_WITH_3D_ACCELERATION */ 2686 2687 /* static */ 2688 quint64 UICommon::requiredVideoMemory(const QString &strGuestOSTypeId, int cMonitors /* = 1 */) 2689 { 2690 /* We create a list of the size of all available host monitors. This list 2691 * is sorted by value and by starting with the biggest one, we calculate 2692 * the memory requirements for every guest screen. This is of course not 2693 * correct, but as we can't predict on which host screens the user will 2694 * open the guest windows, this is the best assumption we can do, cause it 2695 * is the worst case. */ 2696 const int cHostScreens = UIDesktopWidgetWatchdog::screenCount(); 2697 QVector<int> screenSize(qMax(cMonitors, cHostScreens), 0); 2698 for (int i = 0; i < cHostScreens; ++i) 2699 { 2700 QRect r = gpDesktop->screenGeometry(i); 2701 screenSize[i] = r.width() * r.height(); 2702 } 2703 /* Now sort the vector: */ 2704 std::sort(screenSize.begin(), screenSize.end(), std::greater<int>()); 2705 /* For the case that there are more guest screens configured then host 2706 * screens available, replace all zeros with the greatest value in the 2707 * vector. */ 2708 for (int i = 0; i < screenSize.size(); ++i) 2709 if (screenSize.at(i) == 0) 2710 screenSize.replace(i, screenSize.at(0)); 2711 2712 quint64 uNeedBits = 0; 2713 for (int i = 0; i < cMonitors; ++i) 2714 { 2715 /* Calculate summary required memory amount in bits: */ 2716 uNeedBits += (screenSize.at(i) * /* with x height */ 2717 32 + /* we will take the maximum possible bpp for now */ 2718 8 * _1M) + /* current cache per screen - may be changed in future */ 2719 8 * 4096; /* adapter info */ 2720 } 2721 /* Translate value into megabytes with rounding to highest side: */ 2722 quint64 uNeedMBytes = uNeedBits % (8 * _1M) 2723 ? uNeedBits / (8 * _1M) + 1 2724 : uNeedBits / (8 * _1M) /* convert to megabytes */; 2725 2726 if (strGuestOSTypeId.startsWith("Windows")) 2727 { 2728 /* Windows guests need offscreen VRAM too for graphics acceleration features: */ 2729 #ifdef VBOX_WITH_3D_ACCELERATION 2730 if (isWddmCompatibleOsType(strGuestOSTypeId)) 2731 { 2732 /* WDDM mode, there are two surfaces for each screen: shadow & primary: */ 2733 uNeedMBytes *= 3; 2734 } 2735 else 2736 #endif /* VBOX_WITH_3D_ACCELERATION */ 2737 { 2738 uNeedMBytes *= 2; 2739 } 2740 } 2741 2742 return uNeedMBytes * _1M; 2743 } 2744 2745 KGraphicsControllerType UICommon::getRecommendedGraphicsController(const QString &strGuestOSTypeId) const 2746 { 2747 return m_pGuestOSTypeManager 2748 ? m_pGuestOSTypeManager->getRecommendedGraphicsController(strGuestOSTypeId) 2749 : KGraphicsControllerType_Null; 2750 } 2751 2752 /* static */ 2753 void UICommon::setHelpKeyword(QObject *pObject, const QString &strHelpKeyword) 2754 { 2755 if (pObject) 2756 pObject->setProperty("helpkeyword", strHelpKeyword); 2757 } 2758 2759 /* static */ 2760 QString UICommon::helpKeyword(const QObject *pObject) 2761 { 2762 if (!pObject) 2763 return QString(); 2764 return pObject->property("helpkeyword").toString(); 2765 } 2766 2767 bool UICommon::isExtentionPackInstalled() const 2768 { 2769 const CExtPackManager comEPManager = virtualBox().GetExtensionPackManager(); 2770 2771 if (!virtualBox().isOk()) 2772 return false; 2773 2774 const QVector<CExtPack> extensionPacks = comEPManager.GetInstalledExtPacks(); 2775 if (!comEPManager.isOk()) 2776 return false; 2777 foreach (const CExtPack &comExtensionPack, extensionPacks) 2778 { 2779 if (!comExtensionPack.isOk()) 2780 continue; 2781 bool fUsable = comExtensionPack.GetUsable(); 2782 if (comExtensionPack.isOk() && fUsable) 2783 return true; 2784 } 2785 return false; 2786 } 2787 2788 bool UICommon::openURL(const QString &strUrl) const 2789 { 2790 /** Service event. */ 2791 class ServiceEvent : public QEvent 2792 { 2793 public: 2794 2795 /** Constructs service event on th basis of passed @a fResult. */ 2796 ServiceEvent(bool fResult) 2797 : QEvent(QEvent::User) 2798 , m_fResult(fResult) 2799 {} 2800 2801 /** Returns the result which event brings. */ 2802 bool result() const { return m_fResult; } 2803 2804 private: 2805 2806 /** Holds the result which event brings. */ 2807 bool m_fResult; 2808 }; 2809 2810 /** Service client object. */ 2811 class ServiceClient : public QEventLoop 2812 { 2813 public: 2814 2815 /** Constructs service client on the basis of passed @a fResult. */ 2816 ServiceClient() 2817 : m_fResult(false) 2818 {} 2819 2820 /** Returns the result which event brings. */ 2821 bool result() const { return m_fResult; } 2822 2823 private: 2824 2825 /** Handles any Qt @a pEvent. */ 2826 bool event(QEvent *pEvent) 2827 { 2828 /* Handle service event: */ 2829 if (pEvent->type() == QEvent::User) 2830 { 2831 ServiceEvent *pServiceEvent = static_cast<ServiceEvent*>(pEvent); 2832 m_fResult = pServiceEvent->result(); 2833 pServiceEvent->accept(); 2834 quit(); 2835 return true; 2836 } 2837 return false; 2838 } 2839 2840 bool m_fResult; 2841 }; 2842 2843 /** Service server object. */ 2844 class ServiceServer : public QThread 2845 { 2846 public: 2847 2848 /** Constructs service server on the basis of passed @a client and @a strUrl. */ 2849 ServiceServer(ServiceClient &client, const QString &strUrl) 2850 : m_client(client), m_strUrl(strUrl) {} 2851 2852 private: 2853 2854 /** Executes thread task. */ 2855 void run() 2856 { 2857 QApplication::postEvent(&m_client, new ServiceEvent(QDesktopServices::openUrl(m_strUrl))); 2858 } 2859 2860 /** Holds the client reference. */ 2861 ServiceClient &m_client; 2862 /** Holds the URL to be processed. */ 2863 const QString &m_strUrl; 2864 }; 2865 2866 /* Create client & server: */ 2867 ServiceClient client; 2868 ServiceServer server(client, strUrl); 2869 server.start(); 2870 client.exec(); 2871 server.wait(); 2872 2873 /* Acquire client result: */ 2874 bool fResult = client.result(); 2875 if (!fResult) 2876 UINotificationMessage::cannotOpenURL(strUrl); 2877 2878 return fResult; 2879 } 2880 2881 void UICommon::sltGUILanguageChange(QString strLanguage) 2882 { 2883 /* Make sure medium-enumeration is not in progress! */ 2884 AssertReturnVoid(!isMediumEnumerationInProgress()); 2885 /* Load passed language: */ 2886 UITranslator::loadLanguage(strLanguage); 2887 } 2888 2889 void UICommon::sltHandleMediumCreated(const CMedium &comMedium) 2890 { 2891 /* Acquire device type: */ 2892 const KDeviceType enmDeviceType = comMedium.GetDeviceType(); 2893 if (!comMedium.isOk()) 2894 UINotificationMessage::cannotAcquireMediumParameter(comMedium); 2895 else 2896 { 2897 /* Convert to medium type: */ 2898 const UIMediumDeviceType enmMediumType = mediumTypeToLocal(enmDeviceType); 2899 2900 /* Make sure we cached created medium in GUI: */ 2901 createMedium(UIMedium(comMedium, enmMediumType, KMediumState_Created)); 2902 } 2903 } 2904 2905 void UICommon::sltHandleMachineCreated(const CMachine &comMachine) 2906 { 2907 /* Register created machine. */ 2908 CVirtualBox comVBox = virtualBox(); 2909 comVBox.RegisterMachine(comMachine); 2910 if (!comVBox.isOk()) 2911 UINotificationMessage::cannotRegisterMachine(comVBox, comMachine.GetName()); 2912 } 2913 2914 void UICommon::sltHandleCloudMachineAdded(const QString &strProviderShortName, 2915 const QString &strProfileName, 2916 const CCloudMachine &comMachine) 2917 { 2918 /* Make sure we cached added cloud VM in GUI: */ 2919 notifyCloudMachineRegistered(strProviderShortName, 2920 strProfileName, 2921 comMachine); 2922 } 2923 2924 bool UICommon::eventFilter(QObject *pObject, QEvent *pEvent) 2925 { 2926 /** @todo Just use the QIWithRetranslateUI3 template wrapper. */ 2927 2928 if ( pEvent->type() == QEvent::LanguageChange 2929 && pObject->isWidgetType() 2930 && qobject_cast<QWidget*>(pObject)->isWindow()) 2931 { 2932 /* Catch the language change event before any other widget gets it in 2933 * order to invalidate cached string resources (like the details view 2934 * templates) that may be used by other widgets. */ 2935 QWidgetList list = QApplication::topLevelWidgets(); 2936 if (list.first() == pObject) 2937 { 2938 /* Call this only once per every language change (see 2939 * QApplication::installTranslator() for details): */ 2940 retranslateUi(); 2941 } 2942 } 2943 2944 /* Handle application palette change event: */ 2945 if ( pEvent->type() == QEvent::ApplicationPaletteChange 2946 && pObject == windowManager().mainWindowShown()) 2947 { 2948 #if defined(VBOX_WS_MAC) 2949 const bool fDarkMode = UICocoaApplication::instance()->isDarkMode(); 2950 #elif defined(VBOX_WS_WIN) 2951 const bool fDarkMode = isWindowsInDarkMode(); 2952 #else /* Linux, BSD, Solaris */ 2953 const bool fDarkMode = isPaletteInDarkMode(); 2954 #endif /* Linux, BSD, Solaris */ 2955 if (m_fDarkMode != fDarkMode) 2956 { 2957 m_fDarkMode = fDarkMode; 2958 loadColorTheme(); 2959 emit sigThemeChange(); 2960 } 2961 } 2962 2963 /* Call to base-class: */ 2964 return QObject::eventFilter(pObject, pEvent); 2965 } 2966 2967 void UICommon::sltHandleFontScaleFactorChanged(int iFontScaleFactor) 2968 { 2969 QFont appFont = qApp->font(); 2970 2971 if (iOriginalFontPixelSize != -1) 2972 appFont.setPixelSize(iFontScaleFactor / 100.f * iOriginalFontPixelSize); 2973 else 2974 appFont.setPointSize(iFontScaleFactor / 100.f * iOriginalFontPointSize); 2975 qApp->setFont(appFont); 2976 } 2977 2978 void UICommon::retranslateUi() 2979 { 2980 /* Re-enumerate uimedium since they contain some translations too: */ 2981 if (m_fValid) 2982 refreshMedia(); 2983 2984 #ifdef VBOX_WS_NIX 2985 // WORKAROUND: 2986 // As X11 do not have functionality for providing human readable key names, 2987 // we keep a table of them, which must be updated when the language is changed. 2988 UINativeHotKey::retranslateKeyNames(); 2989 #endif 2990 } 2991 2992 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1 2993 void UICommon::sltHandleCommitDataRequest(QSessionManager &manager) 2994 { 2995 LogRel(("GUI: UICommon: Commit data request...\n")); 2996 2997 /* Ask listener to commit data: */ 2998 emit sigAskToCommitData(); 2999 # ifdef VBOX_WS_WIN 3000 m_fDataCommitted = true; 3001 # endif 3002 3003 /* Depending on UI type: */ 3004 switch (uiType()) 3005 { 3006 /* For Runtime UI: */ 3007 case UIType_RuntimeUI: 3008 { 3009 /* Thin clients will be able to shutdown properly, 3010 * but for fat clients: */ 3011 if (!isSeparateProcess()) 3012 { 3013 # if defined(VBOX_WS_MAC) && defined(VBOX_IS_QT6_OR_LATER) /** @todo qt6: ... */ 3014 Q_UNUSED(manager); 3015 /* This code prevents QWindowSystemInterface::handleApplicationTermination 3016 for running, so among other things QApplication::closeAllWindows isn't 3017 called and we're somehow stuck in a half closed down state. That said, 3018 just disabling this isn't sufficent, there we also have to accept() the 3019 QCloseEvent in UIMachineWindow. */ 3020 /** @todo qt6: This isn't quite the right fix, I bet... I'm sure I haven't 3021 * quite understood all that's going on here. So, leaving this for 3022 * the real GUI experts to look into... :-) */ 3023 # else 3024 // WORKAROUND: 3025 // We can't save VM state in one go for fat clients, so we have to ask session manager to cancel shutdown. 3026 // To next major release this should be removed in any case, since there will be no fat clients after all. 3027 manager.cancel(); 3028 3029 # ifdef VBOX_WS_WIN 3030 // WORKAROUND: 3031 // In theory that's Qt5 who should allow us to provide canceling reason as well, but that functionality 3032 // seems to be missed in Windows platform plugin, so we are making that ourselves. 3033 NativeWindowSubsystem::ShutdownBlockReasonCreateAPI((HWND)windowManager().mainWindowShown()->winId(), L"VM is still running."); 3034 # endif 3035 # endif 3036 } 3037 3038 break; 3039 } 3040 default: 3041 break; 3042 } 3043 } 3044 #endif /* !VBOX_GUI_WITH_CUSTOMIZATIONS1 */ 3045 3046 void UICommon::sltHandleVBoxSVCAvailabilityChange(bool fAvailable) 149 UIGlobalSession::UIGlobalSession() 150 : m_fWrappersValid(false) 151 , m_fVBoxSVCAvailable(true) 152 , m_pGuestOSTypeManager(0) 153 { 154 /* Assign instance: */ 155 s_pInstance = this; 156 } 157 158 UIGlobalSession::~UIGlobalSession() 159 { 160 /* Unassign instance: */ 161 s_pInstance = 0; 162 } 163 164 void UIGlobalSession::sltHandleVBoxSVCAvailabilityChange(bool fAvailable) 3047 165 { 3048 166 /* Make sure the VBoxSVC availability changed: */ … … 3058 176 /* Mark wrappers invalid: */ 3059 177 m_fWrappersValid = false; 178 3060 179 /* Re-fetch corresponding CVirtualBox to restart VBoxSVC: */ 3061 m_comVBox = m_comVBoxClient.GetVirtualBox(); 3062 if (!m_comVBoxClient.isOk()) 180 CVirtualBoxClient comVBoxClient = virtualBoxClient(); 181 m_comVBox = comVBoxClient.GetVirtualBox(); 182 if (!comVBoxClient.isOk()) 3063 183 { 3064 184 // The proper behavior would be to show the message and to exit the app, e.g.: … … 3073 193 else 3074 194 { 3075 if (!m_fWrappersValid) 3076 { 3077 /* Re-fetch corresponding CVirtualBox: */ 3078 m_comVBox = m_comVBoxClient.GetVirtualBox(); 3079 if (!m_comVBoxClient.isOk()) 3080 { 3081 msgCenter().cannotAcquireVirtualBox(m_comVBoxClient); 3082 return QApplication::quit(); 3083 } 3084 /* Re-init wrappers: */ 3085 comWrappersReinit(); 3086 3087 /* For Selector UI: */ 3088 if (uiType() == UIType_ManagerUI) 3089 { 3090 /* Recreate Main event listeners: */ 3091 UIVirtualBoxEventHandler::destroy(); 3092 UIVirtualBoxClientEventHandler::destroy(); 3093 UIExtraDataManager::destroy(); 3094 UIExtraDataManager::instance(); 3095 UIVirtualBoxEventHandler::instance(); 3096 UIVirtualBoxClientEventHandler::instance(); 3097 /* Ask UIStarter to restart UI: */ 3098 emit sigAskToRestartUI(); 3099 } 3100 } 195 /* Try to re-init wrappers, quit if failed: */ 196 if ( !m_fWrappersValid 197 && !comWrappersReinit()) 198 return QApplication::quit(); 3101 199 } 3102 200 3103 201 /* Notify listeners about the VBoxSVC availability change: */ 3104 emit sigVBoxSVCAvailabilityChange(); 3105 } 3106 3107 #ifdef VBOX_WITH_DEBUGGER_GUI 3108 3109 # define UICOMMON_DBG_CFG_VAR_FALSE (0) 3110 # define UICOMMON_DBG_CFG_VAR_TRUE (1) 3111 # define UICOMMON_DBG_CFG_VAR_MASK (1) 3112 # define UICOMMON_DBG_CFG_VAR_CMD_LINE RT_BIT(3) 3113 # define UICOMMON_DBG_CFG_VAR_DONE RT_BIT(4) 3114 3115 void UICommon::initDebuggerVar(int *piDbgCfgVar, const char *pszEnvVar, const char *pszExtraDataName, bool fDefault) 3116 { 3117 QString strEnvValue; 3118 char szEnvValue[256]; 3119 int rc = RTEnvGetEx(RTENV_DEFAULT, pszEnvVar, szEnvValue, sizeof(szEnvValue), NULL); 3120 if (RT_SUCCESS(rc)) 3121 { 3122 strEnvValue = QString::fromUtf8(&szEnvValue[0]).toLower().trimmed(); 3123 if (strEnvValue.isEmpty()) 3124 strEnvValue = "yes"; 3125 } 3126 else if (rc != VERR_ENV_VAR_NOT_FOUND) 3127 strEnvValue = "veto"; 3128 3129 QString strExtraValue = m_comVBox.GetExtraData(pszExtraDataName).toLower().trimmed(); 3130 if (strExtraValue.isEmpty()) 3131 strExtraValue = QString(); 3132 3133 if ( strEnvValue.contains("veto") || strExtraValue.contains("veto")) 3134 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE; 3135 else if (strEnvValue.isNull() && strExtraValue.isNull()) 3136 *piDbgCfgVar = fDefault ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE; 3137 else 3138 { 3139 QString *pStr = !strEnvValue.isEmpty() ? &strEnvValue : &strExtraValue; 3140 if ( pStr->startsWith("y") // yes 3141 || pStr->startsWith("e") // enabled 3142 || pStr->startsWith("t") // true 3143 || pStr->startsWith("on") 3144 || pStr->toLongLong() != 0) 3145 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_TRUE; 3146 else if ( pStr->startsWith("n") // o 3147 || pStr->startsWith("d") // disable 3148 || pStr->startsWith("f") // false 3149 || pStr->startsWith("off") 3150 || pStr->contains("veto") /* paranoia */ 3151 || pStr->toLongLong() == 0) 3152 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_FALSE; 3153 else 3154 { 3155 LogFunc(("Ignoring unknown value '%s' for '%s'\n", pStr->toUtf8().constData(), pStr == &strEnvValue ? pszEnvVar : pszExtraDataName)); 3156 *piDbgCfgVar = fDefault ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE; 3157 } 3158 } 3159 } 3160 3161 void UICommon::setDebuggerVar(int *piDbgCfgVar, bool fState) 3162 { 3163 if (!(*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_DONE)) 3164 *piDbgCfgVar = (fState ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE) 3165 | UICOMMON_DBG_CFG_VAR_CMD_LINE; 3166 } 3167 3168 bool UICommon::isDebuggerWorker(int *piDbgCfgVar, const char *pszExtraDataName) const 3169 { 3170 if (!(*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_DONE)) 3171 { 3172 const QString str = gEDataManager->debugFlagValue(pszExtraDataName); 3173 if (str.contains("veto")) 3174 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE; 3175 else if (str.isEmpty() || (*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_CMD_LINE)) 3176 *piDbgCfgVar |= UICOMMON_DBG_CFG_VAR_DONE; 3177 else if ( str.startsWith("y") // yes 3178 || str.startsWith("e") // enabled 3179 || str.startsWith("t") // true 3180 || str.startsWith("on") 3181 || str.toLongLong() != 0) 3182 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_TRUE; 3183 else if ( str.startsWith("n") // no 3184 || str.startsWith("d") // disable 3185 || str.startsWith("f") // false 3186 || str.toLongLong() == 0) 3187 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE; 3188 else 3189 *piDbgCfgVar |= UICOMMON_DBG_CFG_VAR_DONE; 3190 } 3191 3192 return (*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_MASK) == UICOMMON_DBG_CFG_VAR_TRUE; 3193 } 3194 3195 #endif /* VBOX_WITH_DEBUGGER_GUI */ 3196 3197 void UICommon::comWrappersReinit() 3198 { 3199 /* Re-fetch corresponding objects/values: */ 3200 m_comHost = virtualBox().GetHost(); 3201 m_strHomeFolder = virtualBox().GetHomeFolder(); 202 emit sigVBoxSVCAvailabilityChange(m_fVBoxSVCAvailable); 203 } 204 205 bool UIGlobalSession::comWrappersReinit() 206 { 207 /* Make sure VirtualBox instance acquired: */ 208 CVirtualBoxClient comVBoxClient = virtualBoxClient(); 209 m_comVBox = comVBoxClient.GetVirtualBox(); 210 if (!comVBoxClient.isOk()) 211 { 212 msgCenter().cannotAcquireVirtualBox(comVBoxClient); 213 return false; 214 } 215 216 /* Acquire host: */ 217 CVirtualBox comVBox = virtualBox(); 218 m_comHost = comVBox.GetHost(); 219 // if (!comVBox.isOk()) 220 // { 221 // msgCenter().cannotAcquireVirtualBoxParameter(comVBoxClient); 222 // return false; 223 // } 224 225 /* Acquire home folder: */ 226 m_strHomeFolder = comVBox.GetHomeFolder(); 227 // if (!comVBox.isOk()) 228 // { 229 // msgCenter().cannotAcquireVirtualBoxParameter(comVBoxClient); 230 // return false; 231 // } 3202 232 3203 233 /* Re-initialize guest OS type database: */ … … 3207 237 /* Mark wrappers valid: */ 3208 238 m_fWrappersValid = true; 3209 } 239 240 /* Success finally: */ 241 return true; 242 } -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIGlobalSession.h
r103737 r103765 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI Common class declaration.3 * VBox Qt GUI - UIGlobalSession class declaration. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-202 3Oracle and/or its affiliates.7 * Copyright (C) 2006-2024 Oracle and/or its affiliates. 8 8 * 9 9 * This file is part of VirtualBox base platform packages, as … … 26 26 */ 27 27 28 #ifndef FEQT_INCLUDED_SRC_globals_UI Common_h29 #define FEQT_INCLUDED_SRC_globals_UI Common_h28 #ifndef FEQT_INCLUDED_SRC_globals_UIGlobalSession_h 29 #define FEQT_INCLUDED_SRC_globals_UIGlobalSession_h 30 30 #ifndef RT_WITHOUT_PRAGMA_ONCE 31 31 # pragma once … … 33 33 34 34 /* Qt includes: */ 35 #include <QMap>36 35 #include <QReadWriteLock> 37 #include <QObject>38 39 /* GUI includes: */40 #include "UIDefs.h"41 #include "UILibraryDefs.h"42 #include "UIMediumDefs.h"43 #ifdef VBOX_WS_NIX44 # include "VBoxUtils-nix.h"45 #endif46 36 47 37 /* COM includes: */ 38 #include "COMEnums.h" 48 39 #include "CHost.h" 49 #include "CMedium.h"50 #include "CSession.h"51 40 #include "CVirtualBox.h" 52 41 #include "CVirtualBoxClient.h" 53 42 54 43 /* Forward declarations: */ 55 class QGraphicsWidget;56 class QMenu;57 class QSessionManager;58 class QSpinBox;59 class QToolButton;60 class CCloudMachine;61 class CHostVideoInputDevice;62 class CMachine;63 class CUSBDevice;64 class UIActionPool;65 44 class UIGuestOSTypeManager; 66 class UIMedium;67 class UIMediumEnumerator;68 class UIThreadPool;69 45 70 /** QObject subclass containing common GUIfunctionality. */71 class SHARED_LIBRARY_STUFF UI Common : public QObject46 /** QObject subclass wrapping global COM session functionality. */ 47 class SHARED_LIBRARY_STUFF UIGlobalSession : public QObject 72 48 { 73 49 Q_OBJECT; … … 75 51 signals: 76 52 77 /** @name Commonstuff.53 /** @name General COM stuff. 78 54 * @{ */ 79 /** Asks #UIStarter listener to restart UI. */80 void sigAskToRestartUI();81 /** Asks #UIStarter listener to close UI. */82 void sigAskToCloseUI();83 84 55 /** Notifies listeners about the VBoxSVC availability change. */ 85 void sigVBoxSVCAvailabilityChange(); 86 87 /** Asks listeners to commit data. */ 88 void sigAskToCommitData(); 89 /** Asks listeners to detach COM. */ 90 void sigAskToDetachCOM(); 91 /** @} */ 92 93 /** @name Theme stuff. 94 * @{ */ 95 /** Notifies listeners about theme change. */ 96 void sigThemeChange(); 97 /** @} */ 98 99 /** @name COM: Extension Pack stuff. 100 * @{ */ 101 /** Notifies listeners about extension pack @a strName was installed. */ 102 void sigExtensionPackInstalled(const QString &strName); 103 /** Notifies listeners about extension pack @a strName was uninstalled. */ 104 void sigExtensionPackUninstalled(const QString &strName); 105 /** @} */ 106 107 /** @name Cloud Virtual Machine stuff. 108 * @{ */ 109 /** Notifies listeners about cloud VM was unregistered. 110 * @param strProviderShortName Brings provider short name. 111 * @param strProfileName Brings profile name. 112 * @param uId Brings cloud VM id. */ 113 void sigCloudMachineUnregistered(const QString &strProviderShortName, 114 const QString &strProfileName, 115 const QUuid &uId); 116 /** Notifies listeners about cloud VM was registered. 117 * @param strProviderShortName Brings provider short name. 118 * @param strProfileName Brings profile name. 119 * @param comMachine Brings cloud VM. */ 120 void sigCloudMachineRegistered(const QString &strProviderShortName, 121 const QString &strProfileName, 122 const CCloudMachine &comMachine); 123 /** @} */ 124 125 /** @name COM: Virtual Media stuff. 126 * @{ */ 127 /** Notifies listeners about medium with certain @a uMediumID created. */ 128 void sigMediumCreated(const QUuid &uMediumID); 129 /** Notifies listeners about medium with certain @a uMediumID deleted. */ 130 void sigMediumDeleted(const QUuid &uMediumID); 131 132 /** Notifies listeners about medium-enumeration started. */ 133 void sigMediumEnumerationStarted(); 134 /** Notifies listeners about medium with certain @a uMediumID enumerated. */ 135 void sigMediumEnumerated(const QUuid &uMediumID); 136 /** Notifies listeners about medium-enumeration finished. */ 137 void sigMediumEnumerationFinished(); 138 /** Notifies listeners about update of recently media list. */ 139 void sigRecentMediaListUpdated(UIMediumDeviceType enmMediumType); 56 void sigVBoxSVCAvailabilityChange(bool fAvailable); 140 57 /** @} */ 141 58 142 59 public: 143 60 144 /** VM launch running options. */ 145 enum LaunchRunning 146 { 147 LaunchRunning_Default, /**< Default (depends on debug settings). */ 148 LaunchRunning_No, /**< Start the VM paused. */ 149 LaunchRunning_Yes /**< Start the VM running. */ 150 }; 151 152 /** Returns UICommon instance. */ 153 static UICommon *instance() { return s_pInstance; } 154 /** Creates UICommon instance of passed @a enmType. */ 155 static void create(UIType enmType); 156 /** Destroys UICommon instance. */ 61 /** Returns static UIGlobalSession instance. */ 62 static UIGlobalSession *instance() { return s_pInstance; } 63 /** Creates static UIGlobalSession instance. */ 64 static void create(); 65 /** Destroys static UIGlobalSession instance. */ 157 66 static void destroy(); 158 67 159 /** @name General stuff.160 * @{ */161 /** Returns the UI type. */162 UIType uiType() const { return m_enmType; }68 /** Prepares all. */ 69 bool prepare(); 70 /** Cleanups all. */ 71 void cleanup(); 163 72 164 /** Returns whether UICommon instance is properly initialized. */ 165 bool isValid() const { return m_fValid; } 166 /** Returns whether UICommon instance cleanup is in progress. */ 167 bool isCleaningUp() const { return m_fCleaningUp; } 168 /** @} */ 169 170 /** @name Versioning stuff. 171 * @{ */ 172 /** Returns Qt runtime version string. */ 173 static QString qtRTVersionString(); 174 /** Returns Qt runtime version. */ 175 static uint qtRTVersion(); 176 /** Returns Qt runtime major version. */ 177 static uint qtRTMajorVersion(); 178 /** Returns Qt runtime minor version. */ 179 static uint qtRTMinorVersion(); 180 /** Returns Qt runtime revision number. */ 181 static uint qtRTRevisionNumber(); 182 183 /** Returns Qt compiled version string. */ 184 static QString qtCTVersionString(); 185 /** Returns Qt compiled version. */ 186 static uint qtCTVersion(); 187 188 /** Returns VBox version string. */ 189 QString vboxVersionString() const; 190 /** Returns normalized VBox version string. */ 191 QString vboxVersionStringNormalized() const; 192 /** Returns whether VBox version string contains BETA word. */ 193 bool isBeta() const; 194 /** Returns whether BETA label should be shown. */ 195 bool showBetaLabel() const; 196 197 /** Returns whether branding is active. */ 198 bool brandingIsActive(bool fForce = false); 199 /** Returns value for certain branding @a strKey from custom.ini file. */ 200 QString brandingGetKey(QString strKey) const; 201 /** @} */ 202 203 /** @name Host OS stuff. 204 * @{ */ 205 #ifdef VBOX_WS_MAC 206 /** macOS: Returns #MacOSXRelease determined by <i>uname</i> call. */ 207 static MacOSXRelease determineOsRelease(); 208 /** macOS: Returns #MacOSXRelease determined during UICommon prepare routine. */ 209 MacOSXRelease osRelease() const { return m_enmMacOSVersion; } 210 #endif 211 212 #ifdef VBOX_WS_NIX 213 /** X11: Returns the type of the Window Manager we are running under. */ 214 X11WMType typeOfWindowManager() const { return m_enmWindowManagerType; } 215 /** X11: Returns whether the Window Manager we are running under is composition one. */ 216 bool isCompositingManagerRunning() const { return m_fCompositingManagerRunning; } 217 /** Returns true if the detected display server type is either xorg or xwayland. */ 218 bool X11ServerAvailable() const; 219 /** Returns display server type. */ 220 VBGHDISPLAYSERVERTYPE displayServerType() const; 221 #endif 222 /** Returns the name of the host OS by using IHost::getOperatingSystem. */ 223 QString hostOperatingSystem() const; 224 225 #if defined(VBOX_WS_MAC) 226 // Provided by UICocoaApplication .. 227 #elif defined(VBOX_WS_WIN) 228 /** Returns whether Windows host is in Dark mode. */ 229 bool isWindowsInDarkMode() const; 230 #else /* Linux, BSD, Solaris */ 231 /** Returns whether palette is in Dark mode. */ 232 bool isPaletteInDarkMode() const; 233 #endif /* Linux, BSD, Solaris */ 234 235 /** Returns whether host OS is in Dark mode. */ 236 bool isInDarkMode() const { return m_fDarkMode; } 237 238 /** Loads the color theme. */ 239 void loadColorTheme(); 240 /** @} */ 241 242 /** @name Process arguments stuff. 243 * @{ */ 244 /** Process application args. */ 245 bool processArgs(); 246 247 /** Returns whether there are unhandled URL arguments present. */ 248 bool argumentUrlsPresent() const; 249 /** Takes and returns the URL argument list while clearing the source. */ 250 QList<QUrl> takeArgumentUrls(); 251 252 /** Returns the --startvm option value (managed VM id). */ 253 QUuid managedVMUuid() const { return m_uManagedVMId; } 254 /** Returns the --separate option value (whether GUI process is separate from VM process). */ 255 bool isSeparateProcess() const { return m_fSeparateProcess; } 256 /** Returns the --no-startvm-errormsgbox option value (whether startup VM errors are disabled). */ 257 bool showStartVMErrors() const { return m_fShowStartVMErrors; } 258 259 /** Returns the --aggressive-caching / --no-aggressive-caching option value (whether medium-enumeration is required). */ 260 bool agressiveCaching() const { return m_fAgressiveCaching; } 261 262 /** Returns the --restore-current option value (whether we should restore current snapshot before VM started). */ 263 bool shouldRestoreCurrentSnapshot() const { return m_fRestoreCurrentSnapshot; } 264 /** Defines whether we should fRestore current snapshot before VM started. */ 265 void setShouldRestoreCurrentSnapshot(bool fRestore) { m_fRestoreCurrentSnapshot = fRestore; } 266 267 /** Returns the --no-keyboard-grabbing option value (whether we should restore 268 * grab the keyboard or not - for debugging). */ 269 bool shouldNotGrabKeyboard() const { return m_fNoKeyboardGrabbing; } 270 271 /** Returns the --fda option value (whether we have floppy image). */ 272 bool hasFloppyImageToMount() const { return !m_uFloppyImage.isNull(); } 273 /** Returns the --dvd | --cdrom option value (whether we have DVD image). */ 274 bool hasDvdImageToMount() const { return !m_uDvdImage.isNull(); } 275 /** Returns floppy image name. */ 276 QUuid getFloppyImage() const { return m_uFloppyImage; } 277 /** Returns DVD image name. */ 278 QUuid getDvdImage() const { return m_uDvdImage; } 279 280 /** Returns the --execute-all-in-iem option value. */ 281 bool areWeToExecuteAllInIem() const { return m_fExecuteAllInIem; } 282 /** Returns whether --warp-factor option value is equal to 100. */ 283 bool isDefaultWarpPct() const { return m_uWarpPct == 100; } 284 /** Returns the --warp-factor option value. */ 285 uint32_t getWarpPct() const { return m_uWarpPct; } 286 287 #ifdef VBOX_WITH_DEBUGGER_GUI 288 /** Holds whether the debugger should be accessible. */ 289 bool isDebuggerEnabled() const; 290 /** Holds whether to show the debugger automatically with the console. */ 291 bool isDebuggerAutoShowEnabled() const; 292 /** Holds whether to show the command line window when m_fDbgAutoShow is set. */ 293 bool isDebuggerAutoShowCommandLineEnabled() const; 294 /** Holds whether to show the statistics window when m_fDbgAutoShow is set. */ 295 bool isDebuggerAutoShowStatisticsEnabled() const; 296 /** Returns the combined --statistics-expand values. */ 297 QString const getDebuggerStatisticsExpand() const { return m_strDbgStatisticsExpand; } 298 /** Returns the --statistics-filter value. */ 299 QString const getDebuggerStatisticsFilter() const { return m_strDbgStatisticsFilter; } 300 /** Returns the --statistics-config value. */ 301 QString const getDebuggerStatisticsConfig() const { return m_strDbgStatisticsConfig; } 302 303 /** VBoxDbg module handle. */ 304 RTLDRMOD getDebuggerModule() const { return m_hVBoxDbg; } 305 #endif 306 307 /** Returns whether VM should start paused. */ 308 bool shouldStartPaused() const; 309 310 #ifdef VBOX_GUI_WITH_PIDFILE 311 /** Creates PID file. */ 312 void createPidfile(); 313 /** Deletes PID file. */ 314 void deletePidfile(); 315 #endif 316 /** @} */ 317 318 /** @name COM stuff. 73 /** @name General COM stuff. 319 74 * @{ */ 320 75 /** Try to acquire COM cleanup protection token for reading. */ … … 336 91 /** @} */ 337 92 338 /** @name COM: Virtual Machine stuff. 339 * @{ */ 340 /** Switches to certain @a comMachine. */ 341 static bool switchToMachine(CMachine &comMachine); 342 /** Launches certain @a comMachine in specified @a enmLaunchMode. */ 343 static bool launchMachine(CMachine &comMachine, UILaunchMode enmLaunchMode = UILaunchMode_Default); 344 345 /** Opens session of certain @a enmLockType for VM with certain @a uId. */ 346 CSession openSession(QUuid uId, KLockType enmLockType = KLockType_Write); 347 /** Opens session of certain @a enmLockType for currently chosen VM. */ 348 CSession openSession(KLockType enmLockType = KLockType_Write); 349 /** Opens session of KLockType_Shared type for VM with certain @a uId. */ 350 CSession openExistingSession(const QUuid &uId) { return openSession(uId, KLockType_Shared); } 351 /** Tries to guess if new @a comSession needs to be opened for certain @a comMachine, 352 * if yes, new session of required type will be opened and machine will be updated, 353 * otherwise, no session will be created and machine will be left unchanged. */ 354 CSession tryToOpenSessionFor(CMachine &comMachine); 355 /** @} */ 356 357 /** @name COM: Cloud Virtual Machine stuff. 358 * @{ */ 359 /** Notifies listeners about cloud VM was unregistered. 360 * @param strProviderShortName Brings provider short name. 361 * @param strProfileName Brings profile name. 362 * @param uId Brings cloud VM id. */ 363 void notifyCloudMachineUnregistered(const QString &strProviderShortName, 364 const QString &strProfileName, 365 const QUuid &uId); 366 /** Notifies listeners about cloud VM was registered. 367 * @param strProviderShortName Brings provider short name. 368 * @param strProfileName Brings profile name. 369 * @param comMachine Brings cloud VM. */ 370 void notifyCloudMachineRegistered(const QString &strProviderShortName, 371 const QString &strProfileName, 372 const CCloudMachine &comMachine); 373 /** @} */ 374 375 /** @name COM: Guest OS type stuff. 93 /** @name Guest OS type stuff. 376 94 * @{ */ 377 95 const UIGuestOSTypeManager &guestOSTypeManager(); 378 96 /** @} */ 379 97 380 /** @name COM: Virtual Media stuff.381 * @{ */382 /** Enumerates passed @a comMedia. */383 void enumerateMedia(const CMediumVector &comMedia = CMediumVector());384 /** Calls refresh for each medium which has been already enumerated. */385 void refreshMedia();386 /** Returns whether full medium-enumeration is requested. */387 bool isFullMediumEnumerationRequested() const;388 /** Returns whether any medium-enumeration is in progress. */389 bool isMediumEnumerationInProgress() const;390 /** Returns enumerated medium with certain @a uMediumID. */391 UIMedium medium(const QUuid &uMediumID) const;392 /** Returns enumerated medium IDs. */393 QList<QUuid> mediumIDs() const;394 /** Creates medium on the basis of passed @a guiMedium description. */395 void createMedium(const UIMedium &guiMedium);396 397 /** Opens external medium by passed @a strMediumLocation.398 * @param enmMediumType Brings the medium type.399 * @param pParent Brings the dialog parent.400 * @param strMediumLocation Brings the file path to load medium from.401 * @param pParent Brings the dialog parent. */402 QUuid openMedium(UIMediumDeviceType enmMediumType, QString strMediumLocation, QWidget *pParent = 0);403 404 /** Opens external medium using file-open dialog.405 * @param enmMediumType Brings the medium type.406 * @param pParent Brings the dialog parent.407 * @param strDefaultFolder Brings the folder to browse for medium.408 * @param fUseLastFolder Brings whether we should propose to use last used folder. */409 QUuid openMediumWithFileOpenDialog(UIMediumDeviceType enmMediumType, QWidget *pParent = 0,410 const QString &strDefaultFolder = QString(), bool fUseLastFolder = false);411 412 /** Creates and shows a dialog (wizard) to create a medium of type @a enmMediumType.413 * @param pParent Passes the parent of the dialog,414 * @param enmMediumType Passes the medium type,415 * @param strMachineName Passes the name of the machine,416 * @param strMachineFolder Passes the machine folder,417 * @param strMachineGuestOSTypeId Passes the type ID of machine's guest os,418 * @param fEnableCreate Passes whether to show/enable create action in the medium selector dialog,419 * returns QUuid of the new medium */420 QUuid openMediumCreatorDialog(UIActionPool *pActionPool, QWidget *pParent, UIMediumDeviceType enmMediumType,421 const QString &strMachineFolder = QString(), const QString &strMachineName = QString(),422 const QString &strMachineGuestOSTypeId = QString());423 424 /** Prepares storage menu according passed parameters.425 * @param menu Brings the #QMenu to be prepared.426 * @param pListener Brings the listener #QObject, this @a menu being prepared for.427 * @param pszSlotName Brings the name of the SLOT in the @a pListener above, this menu will be handled with.428 * @param comMachine Brings the #CMachine object, this @a menu being prepared for.429 * @param strControllerName Brings the name of the #CStorageController in the @a machine above.430 * @param storageSlot Brings the #StorageSlot of the storage controller with @a strControllerName above. */431 void prepareStorageMenu(QMenu *pMenu,432 QObject *pListener, const char *pszSlotName,433 const CMachine &comMachine, const QString &strControllerName, const StorageSlot &storageSlot);434 /** Updates @a comConstMachine storage with data described by @a target. */435 void updateMachineStorage(const CMachine &comConstMachine, const UIMediumTarget &target, UIActionPool *pActionPool);436 437 /** Generates details for passed @a comMedium.438 * @param fPredictDiff Brings whether medium will be marked differencing on attaching.439 * @param fUseHtml Brings whether HTML subsets should be used in the generated output. */440 QString storageDetails(const CMedium &comMedium, bool fPredictDiff, bool fUseHtml = true);441 442 /** Update extra data related to recently used/referred media.443 * @param enmMediumType Passes the medium type.444 * @param strMediumLocation Passes the medium location. */445 void updateRecentlyUsedMediumListAndFolder(UIMediumDeviceType enmMediumType, QString strMediumLocation);446 447 /** Searches extra data for the recently used folder path which corresponds to @a enmMediumType. When that search fails448 it looks for recent folder extra data for other medium types. As the last resort returns default vm folder path.449 * @param enmMediumType Passes the medium type. */450 QString defaultFolderPathForType(UIMediumDeviceType enmMediumType);451 452 /** Calculates @a cAmount of immutable images used by @a comMachine specified. */453 static bool acquireAmountOfImmutableImages(const CMachine &comMachine, ulong &cAmount);454 /** @} */455 456 /** @name COM: USB stuff.457 * @{ */458 #ifdef RT_OS_LINUX459 /** Verifies that USB drivers are properly configured on Linux. */460 static void checkForWrongUSBMounted();461 #endif462 463 /** Generates details for passed USB @a comDevice. */464 static QString usbDetails(const CUSBDevice &comDevice);465 /** Generates tool-tip for passed USB @a comDevice. */466 static QString usbToolTip(const CUSBDevice &comDevice);467 /** Generates tool-tip for passed USB @a comFilter. */468 static QString usbToolTip(const CUSBDeviceFilter &comFilter);469 /** Generates tool-tip for passed USB @a comWebcam. */470 static QString usbToolTip(const CHostVideoInputDevice &comWebcam);471 /** @} */472 473 /** @name COM: Recording stuff.474 * @{ */475 /** Returns supported recording features flag. */476 int supportedRecordingFeatures() const;477 /** @} */478 479 /** @name File-system stuff.480 * @{ */481 /** Returns full help file name. */482 static QString helpFile();483 484 /** Returns documents path. */485 static QString documentsPath();486 487 /** Returns whether passed @a strFileName ends with one of allowed extension in the @a extensions list. */488 static bool hasAllowedExtension(const QString &strFileName, const QStringList &extensions);489 490 /** Returns a file name (unique up to extension) wrt. @a strFullFolderPath folder content. Starts491 * searching strBaseFileName and adds suffixes until a unique file name is found. */492 static QString findUniqueFileName(const QString &strFullFolderPath, const QString &strBaseFileName);493 /** @} */494 495 /** @name Widget stuff.496 * @{ */497 /** Assigns minimum @a pSpinBox to correspond to @a cCount digits. */498 static void setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount);499 /** @} */500 501 /** @name Display stuff.502 * @{ */503 #ifdef VBOX_WITH_3D_ACCELERATION504 /** Returns whether guest OS type with passed @a strGuestOSTypeId is WDDM compatible. */505 static bool isWddmCompatibleOsType(const QString &strGuestOSTypeId);506 #endif507 /** Returns the required video memory in bytes for the current desktop508 * resolution at maximum possible screen depth in bpp. */509 static quint64 requiredVideoMemory(const QString &strGuestOSTypeId, int cMonitors = 1);510 KGraphicsControllerType getRecommendedGraphicsController(const QString &strGuestOSTypeId) const;511 /** @} */512 513 /** @name Thread stuff.514 * @{ */515 /** Returns the thread-pool instance. */516 UIThreadPool *threadPool() const { return m_pThreadPool; }517 /** Returns the thread-pool instance for cloud needs. */518 UIThreadPool *threadPoolCloud() const { return m_pThreadPoolCloud; }519 /** @} */520 521 /** @name Context sensitive help related functionality522 * @{ */523 /** Sets the property for help keyword on a QObject524 * @param pObject The object to set the help keyword property on525 * @param strKeyword The values of the key word property. */526 static void setHelpKeyword(QObject *pObject, const QString &strHelpKeyword);527 /** Returns the property for help keyword of a QObject. If no such property exists returns an empty QString.528 * @param pWidget The object to get the help keyword property from. */529 static QString helpKeyword(const QObject *pWidget);530 /** @} */531 532 /** @name COM: Extension Pack stuff.533 * @{ */534 /** Returns true if it can find at least one usable ext. pack. Else returns false. */535 bool isExtentionPackInstalled() const;536 /** @} */537 538 public slots:539 540 /** @name Process arguments stuff.541 * @{ */542 /** Opens the specified URL using OS/Desktop capabilities. */543 bool openURL(const QString &strURL) const;544 /** @} */545 546 /** @name Localization stuff.547 * @{ */548 /** Handles language change to new @a strLanguage. */549 void sltGUILanguageChange(QString strLanguage);550 /** @} */551 552 /** @name Media related stuff.553 * @{ */554 /** Handles signal about medium was created. */555 void sltHandleMediumCreated(const CMedium &comMedium);556 /** @} */557 558 /** @name Machine related stuff.559 * @{ */560 /** Handles signal about machine was created. */561 void sltHandleMachineCreated(const CMachine &comMachine);562 /** @} */563 564 /** @name Cloud Machine related stuff.565 * @{ */566 /** Handles signal about cloud machine was added. */567 void sltHandleCloudMachineAdded(const QString &strProviderShortName,568 const QString &strProfileName,569 const CCloudMachine &comMachine);570 /** @} */571 572 protected:573 574 /** Preprocesses any Qt @a pEvent for passed @a pObject. */575 virtual bool eventFilter(QObject *pObject, QEvent *pEvent) RT_OVERRIDE;576 577 /** Handles translation event. */578 virtual void retranslateUi();579 580 98 protected slots: 581 99 582 /** Calls for cleanup() functionality. */ 583 void sltCleanup() { cleanup(); } 584 585 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1 586 /** @name Common stuff. 587 * @{ */ 588 /** Handles @a manager request for emergency session shutdown. */ 589 void sltHandleCommitDataRequest(QSessionManager &manager); 590 /** @} */ 591 #endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */ 592 593 /** @name COM stuff. 100 /** @name General COM stuff. 594 101 * @{ */ 595 102 /** Handles the VBoxSVC availability change. */ … … 597 104 /** @} */ 598 105 599 /* Handle font scale factor change. */600 void sltHandleFontScaleFactorChanged(int iFontScaleFactor);601 602 106 private: 603 107 604 /** Construcs global VirtualBox object of passed @a enmType. */605 UI Common(UIType enmType);606 /** Destrucs global VirtualBoxobject. */607 virtual ~UI Common() /* override final */;108 /** Construcs global COM session object. */ 109 UIGlobalSession(); 110 /** Destrucs global COM session object. */ 111 virtual ~UIGlobalSession() override final; 608 112 609 /** Prepares all. */ 610 void prepare(); 611 /** Cleanups all. */ 612 void cleanup(); 613 614 /** @name Process arguments stuff. 113 /** @name General COM stuff. 615 114 * @{ */ 616 #ifdef VBOX_WITH_DEBUGGER_GUI 617 /** Initializes a debugger config variable. 618 * @param piDbgCfgVar Brings the debugger config variable to init. 619 * @param pszEnvVar Brings the environment variable name relating to this variable. 620 * @param pszExtraDataName Brings the extra data name relating to this variable. 621 * @param fDefault Brings the default value. */ 622 void initDebuggerVar(int *piDbgCfgVar, const char *pszEnvVar, const char *pszExtraDataName, bool fDefault = false); 623 /** Set a debugger config variable according according to start up argument. 624 * @param piDbgCfgVar Brings the debugger config variable to set. 625 * @param fState Brings the value from the command line. */ 626 void setDebuggerVar(int *piDbgCfgVar, bool fState); 627 /** Checks the state of a debugger config variable, updating it with the machine settings on the first invocation. 628 * @param piDbgCfgVar Brings the debugger config variable to consult. 629 * @param pszExtraDataName Brings the extra data name relating to this variable. */ 630 bool isDebuggerWorker(int *piDbgCfgVar, const char *pszExtraDataName) const; 631 #endif 115 /** Re-initializes COM wrappers and containers. */ 116 bool comWrappersReinit(); 632 117 /** @} */ 633 118 634 /** @name COM stuff. 635 * @{ */ 636 /** Re-initializes COM wrappers and containers. */ 637 void comWrappersReinit(); 638 /** @} */ 119 /** Holds the singleton UIGlobalSession instance. */ 120 static UIGlobalSession *s_pInstance; 639 121 640 /** Holds the singleton UICommon instance. */ 641 static UICommon *s_pInstance; 642 643 /** @name General stuff. 644 * @{ */ 645 /** Holds the UI type. */ 646 UIType m_enmType; 647 648 /** Holds whether UICommon instance is properly initialized. */ 649 bool m_fValid; 650 /** Holds whether UICommon instance cleanup is in progress. */ 651 bool m_fCleaningUp; 652 #ifdef VBOX_WS_WIN 653 /** Holds whether overall GUI data is committed. */ 654 bool m_fDataCommitted; 655 #endif 656 /** @} */ 657 658 /** @name Versioning stuff. 659 * @{ */ 660 /** Holds the VBox branding config file path. */ 661 QString m_strBrandingConfigFilePath; 662 /** @} */ 663 664 /** @name Host OS stuff. 665 * @{ */ 666 #ifdef VBOX_WS_MAC 667 /** macOS: Holds the #MacOSXRelease determined using <i>uname</i> call. */ 668 MacOSXRelease m_enmMacOSVersion; 669 #endif 670 671 #ifdef VBOX_WS_NIX 672 /** X11: Holds the #X11WMType of the Window Manager we are running under. */ 673 X11WMType m_enmWindowManagerType; 674 /** X11: Holds whether the Window Manager we are running at is composition one. */ 675 bool m_fCompositingManagerRunning; 676 /** Unixes: Holds the display server type. */ 677 VBGHDISPLAYSERVERTYPE m_enmDisplayServerType; 678 #endif 679 680 /** Holds whether host OS is in Dark mode. */ 681 bool m_fDarkMode; 682 /** @} */ 683 684 /** @name Process arguments stuff. 685 * @{ */ 686 /** Holds the URL arguments list. */ 687 QList<QUrl> m_listArgUrls; 688 689 /** Holds the --startvm option value (managed VM id). */ 690 QUuid m_uManagedVMId; 691 /** Holds the --separate option value (whether GUI process is separate from VM process). */ 692 bool m_fSeparateProcess; 693 /** Holds the --no-startvm-errormsgbox option value (whether startup VM errors are disabled). */ 694 bool m_fShowStartVMErrors; 695 696 /** Holds the --aggressive-caching / --no-aggressive-caching option value (whether medium-enumeration is required). */ 697 bool m_fAgressiveCaching; 698 699 /** Holds the --restore-current option value. */ 700 bool m_fRestoreCurrentSnapshot; 701 702 /** Holds the --no-keyboard-grabbing option value. */ 703 bool m_fNoKeyboardGrabbing; 704 705 /** Holds the --fda option value (floppy image). */ 706 QUuid m_uFloppyImage; 707 /** Holds the --dvd | --cdrom option value (DVD image). */ 708 QUuid m_uDvdImage; 709 710 /** Holds the --execute-all-in-iem option value. */ 711 bool m_fExecuteAllInIem; 712 /** Holds the --warp-factor option value. */ 713 uint32_t m_uWarpPct; 714 715 #ifdef VBOX_WITH_DEBUGGER_GUI 716 /** Holds whether the debugger should be accessible. */ 717 mutable int m_fDbgEnabled; 718 /** Holds whether to show the debugger automatically with the console. */ 719 mutable int m_fDbgAutoShow; 720 /** Holds whether to show the command line window when m_fDbgAutoShow is set. */ 721 mutable int m_fDbgAutoShowCommandLine; 722 /** Holds whether to show the statistics window when m_fDbgAutoShow is set. */ 723 mutable int m_fDbgAutoShowStatistics; 724 /** Pattern of statistics to expand when opening the viewer. */ 725 QString m_strDbgStatisticsExpand; 726 /** The statistics viewer main filter pattern. */ 727 QString m_strDbgStatisticsFilter; 728 /** The statistics viewer advanced filter configuration and possibly more. */ 729 QString m_strDbgStatisticsConfig; 730 731 /** VBoxDbg module handle. */ 732 RTLDRMOD m_hVBoxDbg; 733 734 /** Holds whether --start-running, --start-paused or nothing was given. */ 735 LaunchRunning m_enmLaunchRunning; 736 #endif 737 738 /** Holds the --settingspw option value or the content of --settingspwfile. */ 739 char m_astrSettingsPw[256]; 740 /** Holds the --settingspwfile option value. */ 741 bool m_fSettingsPwSet; 742 743 #ifdef VBOX_GUI_WITH_PIDFILE 744 /** Holds the --pidfile option value (application PID file path). */ 745 QString m_strPidFile; 746 #endif 747 /** @} */ 748 749 /** @name COM stuff. 122 /** @name General COM stuff. 750 123 * @{ */ 751 124 /** Holds the COM cleanup protection token. */ … … 767 140 /** @} */ 768 141 769 /** @name Thread stuff. 770 * @{ */ 771 /** Holds the thread-pool instance. */ 772 UIThreadPool *m_pThreadPool; 773 /** Holds the thread-pool instance for cloud needs. */ 774 UIThreadPool *m_pThreadPoolCloud; 775 /** @} */ 776 777 /** @name Guest OS type related stuff. 142 /** @name Guest OS type stuff. 778 143 * @{ */ 779 144 /** Holds the guest OS type manager instance. */ … … 781 146 /** @} */ 782 147 783 /** @name Media related stuff.784 * @{ */785 /** Holds the medium enumerator cleanup protection token. */786 mutable QReadWriteLock m_meCleanupProtectionToken;787 788 /** Holds the medium enumerator. */789 UIMediumEnumerator *m_pMediumEnumerator;790 /** List of medium names that should not appears in the recently used media extra data. */791 QStringList m_recentMediaExcludeList;792 /** @} */793 794 148 #ifdef VBOX_WS_WIN 795 149 /** @name ATL stuff. 796 150 * @{ */ 797 /** Holds the ATL module instance (for use with UI Common shared library only).151 /** Holds the ATL module instance (for use with UIGlobalSession shared library only). 798 152 * @note Required internally by ATL (constructor records instance in global variable). */ 799 153 ATL::CComModule _Module; 800 154 /** @} */ 801 155 #endif 802 /** @name Font scaling related variables.803 * @{ */804 int iOriginalFontPixelSize;805 int iOriginalFontPointSize;806 /** @} */807 808 /** Allows for shortcut access. */809 friend UICommon &uiCommon();810 156 }; 811 157 812 /** Singleton UICommon 'official' name. */ 813 inline UICommon &uiCommon() { return *UICommon::instance(); } 158 #define gpGlobalSession UIGlobalSession::instance() 814 159 815 #endif /* !FEQT_INCLUDED_SRC_globals_UI Common_h */160 #endif /* !FEQT_INCLUDED_SRC_globals_UIGlobalSession_h */
Note:
See TracChangeset
for help on using the changeset viewer.