Changeset 91009 in vbox
- Timestamp:
- Aug 30, 2021 6:24:32 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 146649
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 6 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r91003 r91009 1351 1351 src/globals/UIDialogPanel.cpp \ 1352 1352 src/globals/UIErrorString.cpp \ 1353 src/globals/UIExtension.cpp \ 1353 1354 src/globals/UIIconPool.cpp \ 1354 1355 src/globals/UIImageTools.cpp \ -
trunk/src/VBox/Frontends/VirtualBox/src/extensionpackmanager/UIExtensionPackManager.cpp
r90699 r91009 29 29 #include "UIActionPoolManager.h" 30 30 #include "UICommon.h" 31 #include "UIExtension.h" 31 32 #include "UIExtensionPackManager.h" 32 33 #include "UIExtraDataManager.h" … … 229 230 /* Install the chosen package: */ 230 231 if (!strFilePath.isEmpty()) 231 uiCommon().doExtPackInstallation(strFilePath, QString(), this, NULL);232 UIExtension::install(strFilePath, QString(), this, NULL); 232 233 } 233 234 -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp
r91007 r91009 3376 3376 } 3377 3377 3378 void UICommon::doExtPackInstallation(QString const &strFilePath, QString const &strDigest,3379 QWidget *pParent, QString *pstrExtPackName) const3380 {3381 /* If the extension pack manager isn't available, skip any attempts to install: */3382 CExtPackManager extPackManager = virtualBox().GetExtensionPackManager();3383 if (extPackManager.isNull())3384 return;3385 /* Open the extpack tarball via IExtPackManager: */3386 CExtPackFile comExtPackFile;3387 if (strDigest.isEmpty())3388 comExtPackFile = extPackManager.OpenExtPackFile(strFilePath);3389 else3390 {3391 QString strFileAndHash = QString("%1::SHA-256=%2").arg(strFilePath).arg(strDigest);3392 comExtPackFile = extPackManager.OpenExtPackFile(strFileAndHash);3393 }3394 if (!extPackManager.isOk())3395 {3396 msgCenter().cannotOpenExtPack(strFilePath, extPackManager, pParent);3397 return;3398 }3399 3400 if (!comExtPackFile.GetUsable())3401 {3402 msgCenter().warnAboutBadExtPackFile(strFilePath, comExtPackFile, pParent);3403 return;3404 }3405 3406 const QString strPackName = comExtPackFile.GetName();3407 const QString strPackDescription = comExtPackFile.GetDescription();3408 const QString strPackVersion = QString("%1r%2%3").arg(comExtPackFile.GetVersion()).arg(comExtPackFile.GetRevision()).arg(comExtPackFile.GetEdition());3409 3410 /* Check if there is a version of the extension pack already3411 * installed on the system and let the user decide what to do about it. */3412 CExtPack comExtPackCur = extPackManager.Find(strPackName);3413 bool fReplaceIt = comExtPackCur.isOk();3414 if (fReplaceIt)3415 {3416 QString strPackVersionCur = QString("%1r%2%3").arg(comExtPackCur.GetVersion()).arg(comExtPackCur.GetRevision()).arg(comExtPackCur.GetEdition());3417 if (!msgCenter().confirmReplaceExtensionPack(strPackName, strPackVersion, strPackVersionCur, strPackDescription, pParent))3418 return;3419 }3420 /* If it's a new package just ask for general confirmation. */3421 else3422 {3423 if (!msgCenter().confirmInstallExtensionPack(strPackName, strPackVersion, strPackDescription, pParent))3424 return;3425 }3426 3427 /* Display the license dialog if required by the extension pack. */3428 if (comExtPackFile.GetShowLicense())3429 {3430 QString strLicense = comExtPackFile.GetLicense();3431 VBoxLicenseViewer licenseViewer(pParent);3432 if (licenseViewer.showLicenseFromString(strLicense) != QDialog::Accepted)3433 return;3434 }3435 3436 /* Install the selected package.3437 * Set the package name return value before doing3438 * this as the caller should do a refresh even on failure. */3439 QString strDisplayInfo;3440 #ifdef VBOX_WS_WIN3441 if (pParent)3442 strDisplayInfo.sprintf("hwnd=%#llx", (uint64_t)(uintptr_t)pParent->winId());3443 #endif3444 3445 /* Install extension pack: */3446 UINotificationProgressExtensionPackInstall *pNotification =3447 new UINotificationProgressExtensionPackInstall(comExtPackFile,3448 fReplaceIt,3449 strPackName,3450 strDisplayInfo);3451 connect(pNotification, &UINotificationProgressExtensionPackInstall::sigExtensionPackInstalled,3452 this, &UICommon::sigExtensionPackInstalled);3453 gpNotificationCenter->append(pNotification);3454 3455 /* Store the name: */3456 if (pstrExtPackName)3457 *pstrExtPackName = strPackName;3458 }3459 3460 3378 #ifdef VBOX_WITH_3D_ACCELERATION 3461 3379 /* static */ -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.h
r91003 r91009 551 551 /** Generates tool-tip for passed USB @a comWebcam. */ 552 552 static QString toolTip(const CHostVideoInputDevice &comWebcam); 553 /** @} */554 555 /** @name COM: Extension Pack stuff.556 * @{ */557 /** Initiates the extension pack installation process.558 * @param strFilePath Brings the extension pack file path.559 * @param strDigest Brings the extension pack file digest.560 * @param pParent Brings the parent dialog reference.561 * @param pstrExtPackName Brings the extension pack name. */562 void doExtPackInstallation(QString const &strFilePath,563 QString const &strDigest,564 QWidget *pParent,565 QString *pstrExtPackName) const;566 553 /** @} */ 567 554 -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIExtension.cpp
r91007 r91009 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI Common classimplementation.3 * VBox Qt GUI - UIExtension namespace implementation. 4 4 */ 5 5 … … 16 16 */ 17 17 18 /* Qt includes: */19 #include <QDesktopServices>20 #include <QDir>21 #include <QFileDialog>22 #include <QGraphicsWidget>23 #include <QLibraryInfo>24 #include <QLocale>25 #include <QMenu>26 #include <QMutex>27 #include <QPainter>28 #include <QProcess>29 #include <QProgressDialog>30 #include <QSessionManager>31 #include <QSettings>32 #include <QSpinBox>33 #include <QStandardPaths>34 #include <QStyleOptionSpinBox>35 #include <QThread>36 #include <QTimer>37 #include <QToolButton>38 #include <QToolTip>39 #include <QTranslator>40 #ifdef VBOX_WS_WIN41 # include <QEventLoop>42 # include <QStyleFactory>43 #endif44 #ifdef VBOX_WS_X1145 # include <QScreen>46 # include <QScrollBar>47 # include <QTextBrowser>48 # include <QX11Info>49 #endif50 #ifdef VBOX_GUI_WITH_PIDFILE51 # include <QTextStream>52 #endif53 54 18 /* GUI includes: */ 55 #include "QIDialogButtonBox.h"56 #include "QIFileDialog.h"57 #include "QIMessageBox.h"58 #include "QIWithRestorableGeometry.h"59 19 #include "UICommon.h" 60 #include "UIConverter.h" 61 #include "UIDesktopWidgetWatchdog.h" 62 #include "UIExtraDataManager.h" 63 #include "UIFDCreationDialog.h" 64 #include "UIIconPool.h" 65 #include "UIMedium.h" 66 #include "UIMediumEnumerator.h" 67 #include "UIMediumSelector.h" 20 #include "UIExtension.h" 21 #include "UINotificationCenter.h" 68 22 #include "UIMessageCenter.h" 69 #include "UIModalWindowManager.h"70 #include "UINotificationCenter.h"71 #include "UIPopupCenter.h"72 #include "UIShortcutPool.h"73 #include "UIThreadPool.h"74 #include "UITranslator.h"75 #include "UIVirtualBoxClientEventHandler.h"76 #include "UIVirtualBoxEventHandler.h"77 #include "UIVisoCreator.h"78 #include "UIWizardNewVD.h"79 23 #include "VBoxLicenseViewer.h" 80 #ifdef VBOX_WS_MAC81 # include "UIMachineWindowFullscreen.h"82 # include "UIMachineWindowSeamless.h"83 # include "VBoxUtils-darwin.h"84 #endif85 #ifdef VBOX_WS_X1186 # include "UIHostComboEditor.h"87 # include "VBoxX11Helper.h"88 #endif89 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER90 # include "UINetworkRequestManager.h"91 # include "UIUpdateManager.h"92 #endif93 24 94 25 /* COM includes: */ 95 #include "CAudioAdapter.h"96 #include "CBIOSSettings.h"97 #include "CCloudMachine.h"98 #include "CConsole.h"99 26 #include "CExtPack.h" 100 #include "CExtPackFile.h"101 #include "CExtPackManager.h"102 #include "CHostUSBDevice.h"103 #include "CHostVideoInputDevice.h"104 #include "CMachine.h"105 #include "CMediumAttachment.h"106 #include "CNetworkAdapter.h"107 #include "CSerialPort.h"108 #include "CSharedFolder.h"109 #include "CSnapshot.h"110 #include "CStorageController.h"111 #include "CSystemProperties.h"112 #include "CUSBController.h"113 #include "CUSBDevice.h"114 #include "CUSBDeviceFilter.h"115 #include "CUSBDeviceFilters.h"116 #include "CVRDEServer.h"117 118 /* Other VBox includes: */119 #include <iprt/asm.h>120 #include <iprt/ctype.h>121 #include <iprt/env.h>122 #include <iprt/err.h>123 #include <iprt/file.h>124 #include <iprt/getopt.h>125 #include <iprt/ldr.h>126 #include <iprt/param.h>127 #include <iprt/path.h>128 #include <iprt/stream.h>129 #include <iprt/system.h>130 #ifdef VBOX_WS_X11131 # include <iprt/mem.h>132 #endif133 #include <VBox/sup.h>134 #include <VBox/VBoxOGL.h>135 #include <VBox/vd.h>136 #include <VBox/com/Guid.h>137 138 /* VirtualBox interface declarations: */139 #include <VBox/com/VirtualBox.h>140 141 /* External includes: */142 #ifdef VBOX_WS_WIN143 # include <iprt/win/shlobj.h>144 #endif145 #ifdef VBOX_WS_X11146 # include <xcb/xcb.h>147 #endif148 149 /* External includes: */150 #include <math.h>151 #ifdef VBOX_WS_MAC152 # include <sys/utsname.h>153 #endif154 #ifdef VBOX_WS_X11155 // WORKAROUND:156 // typedef CARD8 BOOL in Xmd.h conflicts with #define BOOL PRBool157 // in COMDefs.h. A better fix would be to isolate X11-specific158 // stuff by placing XX* helpers below to a separate source file.159 # undef BOOL160 # include <X11/X.h>161 # include <X11/Xmd.h>162 # include <X11/Xlib.h>163 # include <X11/Xatom.h>164 # include <X11/Xutil.h>165 # include <X11/extensions/Xinerama.h>166 # define BOOL PRBool167 #endif168 169 /* Namespaces: */170 using namespace UIExtraDataDefs;171 using namespace UIMediumDefs;172 27 173 28 174 /* static */ 175 UICommon *UICommon::s_pInstance = 0; 176 177 /* static */ 178 void UICommon::create(UIType enmType) 179 { 180 /* Make sure instance is NOT created yet: */ 181 AssertReturnVoid(!s_pInstance); 182 183 /* Create instance: */ 184 new UICommon(enmType); 185 /* Prepare instance: */ 186 s_pInstance->prepare(); 187 } 188 189 /* static */ 190 void UICommon::destroy() 191 { 192 /* Make sure instance is NOT destroyed yet: */ 193 AssertPtrReturnVoid(s_pInstance); 194 195 /* Cleanup instance: 196 * 1. By default, automatically on QApplication::aboutToQuit() signal. 197 * 2. But if QApplication was not started at all and we perform 198 * early shutdown, we should do cleanup ourselves. */ 199 if (s_pInstance->isValid()) 200 s_pInstance->cleanup(); 201 /* Destroy instance: */ 202 delete s_pInstance; 203 } 204 205 UICommon::UICommon(UIType enmType) 206 : m_enmType(enmType) 207 , m_fValid(false) 208 , m_fCleaningUp(false) 209 #ifdef VBOX_WS_WIN 210 , m_fDataCommitted(false) 211 #endif 212 #ifdef VBOX_WS_MAC 213 , m_enmMacOSVersion(MacOSXRelease_Old) 214 #endif 215 #ifdef VBOX_WS_X11 216 , m_enmWindowManagerType(X11WMType_Unknown) 217 , m_fCompositingManagerRunning(false) 218 #endif 219 , m_fSeparateProcess(false) 220 , m_fShowStartVMErrors(true) 221 #if defined(DEBUG_bird) 222 , m_fAgressiveCaching(false) 223 #else 224 , m_fAgressiveCaching(true) 225 #endif 226 , m_fRestoreCurrentSnapshot(false) 227 , m_fDisablePatm(false) 228 , m_fDisableCsam(false) 229 , m_fRecompileSupervisor(false) 230 , m_fRecompileUser(false) 231 , m_fExecuteAllInIem(false) 232 , m_uWarpPct(100) 233 #ifdef VBOX_WITH_DEBUGGER_GUI 234 , m_fDbgEnabled(0) 235 , m_fDbgAutoShow(0) 236 , m_fDbgAutoShowCommandLine(0) 237 , m_fDbgAutoShowStatistics(0) 238 , m_hVBoxDbg(NIL_RTLDRMOD) 239 , m_enmLaunchRunning(LaunchRunning_Default) 240 #endif 241 , m_fSettingsPwSet(false) 242 , m_fWrappersValid(false) 243 , m_fVBoxSVCAvailable(true) 244 , m_pThreadPool(0) 245 , m_pThreadPoolCloud(0) 246 , m_pIconPool(0) 247 , m_pMediumEnumerator(0) 248 { 249 /* Assign instance: */ 250 s_pInstance = this; 251 } 252 253 UICommon::~UICommon() 254 { 255 /* Unassign instance: */ 256 s_pInstance = 0; 257 } 258 259 void UICommon::prepare() 260 { 261 /* Make sure QApplication cleanup us on exit: */ 262 qApp->setFallbackSessionManagementEnabled(false); 263 connect(qApp, &QGuiApplication::aboutToQuit, 264 this, &UICommon::sltCleanup); 265 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1 266 /* Make sure we handle host OS session shutdown as well: */ 267 connect(qApp, &QGuiApplication::commitDataRequest, 268 this, &UICommon::sltHandleCommitDataRequest); 269 #endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */ 270 271 #ifdef VBOX_WS_MAC 272 /* Determine OS release early: */ 273 m_enmMacOSVersion = determineOsRelease(); 274 #endif /* VBOX_WS_MAC */ 275 276 /* Create converter: */ 277 UIConverter::create(); 278 279 /* Create desktop-widget watchdog: */ 280 UIDesktopWidgetWatchdog::create(); 281 282 /* Create message-center: */ 283 UIMessageCenter::create(); 284 /* Create popup-center: */ 285 UIPopupCenter::create(); 286 287 /* Prepare general icon-pool: */ 288 m_pIconPool = new UIIconPoolGeneral; 289 290 /* Load translation based on the current locale: */ 291 UITranslator::loadLanguage(); 292 293 HRESULT rc = COMBase::InitializeCOM(true); 294 if (FAILED(rc)) 295 { 296 #ifdef VBOX_WITH_XPCOM 297 if (rc == NS_ERROR_FILE_ACCESS_DENIED) 298 { 299 char szHome[RTPATH_MAX] = ""; 300 com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome)); 301 msgCenter().cannotInitUserHome(QString(szHome)); 302 } 303 else 304 #endif 305 msgCenter().cannotInitCOM(rc); 306 return; 307 } 308 309 /* Make sure VirtualBoxClient instance created: */ 310 m_comVBoxClient.createInstance(CLSID_VirtualBoxClient); 311 if (!m_comVBoxClient.isOk()) 312 { 313 msgCenter().cannotCreateVirtualBoxClient(m_comVBoxClient); 314 return; 315 } 316 /* Make sure VirtualBox instance acquired: */ 317 m_comVBox = m_comVBoxClient.GetVirtualBox(); 318 if (!m_comVBoxClient.isOk()) 319 { 320 msgCenter().cannotAcquireVirtualBox(m_comVBoxClient); 321 return; 322 } 323 /* Init wrappers: */ 324 comWrappersReinit(); 325 326 /* Watch for the VBoxSVC availability changes: */ 327 connect(gVBoxClientEvents, &UIVirtualBoxClientEventHandler::sigVBoxSVCAvailabilityChange, 328 this, &UICommon::sltHandleVBoxSVCAvailabilityChange); 329 330 /* Prepare thread-pool instances: */ 331 m_pThreadPool = new UIThreadPool(3 /* worker count */, 5000 /* worker timeout */); 332 m_pThreadPoolCloud = new UIThreadPool(2 /* worker count */, 1000 /* worker timeout */); 333 334 #ifdef VBOX_WS_WIN 335 /* Load color theme: */ 336 loadColorTheme(); 337 #endif 338 339 /* Load translation based on the user settings: */ 340 QString strLanguageId = gEDataManager->languageId(); 341 if (!strLanguageId.isNull()) 342 UITranslator::loadLanguage(strLanguageId); 343 344 retranslateUi(); 345 346 connect(gEDataManager, &UIExtraDataManager::sigLanguageChange, 347 this, &UICommon::sltGUILanguageChange); 348 349 qApp->installEventFilter(this); 350 351 /* process command line */ 352 353 UIVisualStateType visualStateType = UIVisualStateType_Invalid; 354 355 #ifdef VBOX_WS_X11 356 /* Check whether we have compositing manager running: */ 357 m_fCompositingManagerRunning = X11IsCompositingManagerRunning(); 358 359 /* Acquire current Window Manager type: */ 360 m_enmWindowManagerType = X11WindowManagerType(); 361 #endif /* VBOX_WS_X11 */ 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 /* Ad hoc VM reconfig options: */ 511 else if (!::strcmp(arg, "--fda")) 512 { 513 enmOptType = OptType_VMRunner; 514 if (++i < argc) 515 m_uFloppyImage = arguments.at(i); 516 } 517 else if (!::strcmp(arg, "--dvd") || !::strcmp(arg, "--cdrom")) 518 { 519 enmOptType = OptType_VMRunner; 520 if (++i < argc) 521 m_uDvdImage = arguments.at(i); 522 } 523 /* VMM Options: */ 524 else if (!::strcmp(arg, "--disable-patm")) 525 { 526 enmOptType = OptType_VMRunner; 527 m_fDisablePatm = true; 528 } 529 else if (!::strcmp(arg, "--disable-csam")) 530 { 531 enmOptType = OptType_VMRunner; 532 m_fDisableCsam = true; 533 } 534 else if (!::strcmp(arg, "--recompile-supervisor")) 535 { 536 enmOptType = OptType_VMRunner; 537 m_fRecompileSupervisor = true; 538 } 539 else if (!::strcmp(arg, "--recompile-user")) 540 { 541 enmOptType = OptType_VMRunner; 542 m_fRecompileUser = true; 543 } 544 else if (!::strcmp(arg, "--recompile-all")) 545 { 546 enmOptType = OptType_VMRunner; 547 m_fDisablePatm = m_fDisableCsam = m_fRecompileSupervisor = m_fRecompileUser = true; 548 } 549 else if (!::strcmp(arg, "--execute-all-in-iem")) 550 { 551 enmOptType = OptType_VMRunner; 552 m_fDisablePatm = m_fDisableCsam = m_fExecuteAllInIem = true; 553 } 554 else if (!::strcmp(arg, "--warp-pct")) 555 { 556 enmOptType = OptType_VMRunner; 557 if (++i < argc) 558 m_uWarpPct = RTStrToUInt32(arguments.at(i).toLocal8Bit().constData()); 559 } 560 #ifdef VBOX_WITH_DEBUGGER_GUI 561 /* Debugger/Debugging options: */ 562 else if (!::strcmp(arg, "-dbg") || !::strcmp(arg, "--dbg")) 563 { 564 enmOptType = OptType_VMRunner; 565 setDebuggerVar(&m_fDbgEnabled, true); 566 } 567 else if (!::strcmp( arg, "-debug") || !::strcmp(arg, "--debug")) 568 { 569 enmOptType = OptType_VMRunner; 570 setDebuggerVar(&m_fDbgEnabled, true); 571 setDebuggerVar(&m_fDbgAutoShow, true); 572 setDebuggerVar(&m_fDbgAutoShowCommandLine, true); 573 setDebuggerVar(&m_fDbgAutoShowStatistics, true); 574 } 575 else if (!::strcmp(arg, "--debug-command-line")) 576 { 577 enmOptType = OptType_VMRunner; 578 setDebuggerVar(&m_fDbgEnabled, true); 579 setDebuggerVar(&m_fDbgAutoShow, true); 580 setDebuggerVar(&m_fDbgAutoShowCommandLine, true); 581 } 582 else if (!::strcmp(arg, "--debug-statistics")) 583 { 584 enmOptType = OptType_VMRunner; 585 setDebuggerVar(&m_fDbgEnabled, true); 586 setDebuggerVar(&m_fDbgAutoShow, true); 587 setDebuggerVar(&m_fDbgAutoShowStatistics, true); 588 } 589 else if (!::strcmp(arg, "--statistics-expand") || !::strcmp(arg, "--stats-expand")) 590 { 591 enmOptType = OptType_VMRunner; 592 if (++i < argc) 593 { 594 if (!m_strDbgStatisticsExpand.isEmpty()) 595 m_strDbgStatisticsExpand.append('|'); 596 m_strDbgStatisticsExpand.append(arguments.at(i)); 597 } 598 } 599 else if (!::strncmp(arg, RT_STR_TUPLE("--statistics-expand=")) || !::strncmp(arg, RT_STR_TUPLE("--stats-expand="))) 600 { 601 enmOptType = OptType_VMRunner; 602 if (!m_strDbgStatisticsExpand.isEmpty()) 603 m_strDbgStatisticsExpand.append('|'); 604 m_strDbgStatisticsExpand.append(arguments.at(i).section('=', 1)); 605 } 606 else if (!::strcmp(arg, "--statistics-filter") || !::strcmp(arg, "--stats-filter")) 607 { 608 enmOptType = OptType_VMRunner; 609 if (++i < argc) 610 m_strDbgStatisticsFilter = arguments.at(i); 611 } 612 else if (!::strncmp(arg, RT_STR_TUPLE("--statistics-filter=")) || !::strncmp(arg, RT_STR_TUPLE("--stats-filter="))) 613 { 614 enmOptType = OptType_VMRunner; 615 m_strDbgStatisticsFilter = arguments.at(i).section('=', 1); 616 } 617 else if (!::strcmp(arg, "-no-debug") || !::strcmp(arg, "--no-debug")) 618 { 619 enmOptType = OptType_VMRunner; 620 setDebuggerVar(&m_fDbgEnabled, false); 621 setDebuggerVar(&m_fDbgAutoShow, false); 622 setDebuggerVar(&m_fDbgAutoShowCommandLine, false); 623 setDebuggerVar(&m_fDbgAutoShowStatistics, false); 624 } 625 /* Not quite debug options, but they're only useful with the debugger bits. */ 626 else if (!::strcmp(arg, "--start-paused")) 627 { 628 enmOptType = OptType_VMRunner; 629 m_enmLaunchRunning = LaunchRunning_No; 630 } 631 else if (!::strcmp(arg, "--start-running")) 632 { 633 enmOptType = OptType_VMRunner; 634 m_enmLaunchRunning = LaunchRunning_Yes; 635 } 636 #endif 637 if (enmOptType == OptType_VMRunner && m_enmType != UIType_RuntimeUI) 638 msgCenter().warnAboutUnrelatedOptionType(arg); 639 640 i++; 641 } 642 643 if (m_enmType == UIType_RuntimeUI && startVM) 644 { 645 /* m_fSeparateProcess makes sense only if a VM is started. */ 646 m_fSeparateProcess = fSeparateProcess; 647 648 /* Search for corresponding VM: */ 649 QUuid uuid = QUuid(vmNameOrUuid); 650 const CMachine machine = m_comVBox.FindMachine(vmNameOrUuid); 651 if (!uuid.isNull()) 652 { 653 if (machine.isNull() && showStartVMErrors()) 654 return msgCenter().cannotFindMachineById(m_comVBox, vmNameOrUuid); 655 } 656 else 657 { 658 if (machine.isNull() && showStartVMErrors()) 659 return msgCenter().cannotFindMachineByName(m_comVBox, vmNameOrUuid); 660 } 661 m_strManagedVMId = machine.GetId(); 662 663 if (m_fSeparateProcess) 664 { 665 /* Create a log file for VirtualBoxVM process. */ 666 QString str = machine.GetLogFolder(); 667 com::Utf8Str logDir(str.toUtf8().constData()); 668 669 /* make sure the Logs folder exists */ 670 if (!RTDirExists(logDir.c_str())) 671 RTDirCreateFullPath(logDir.c_str(), 0700); 672 673 com::Utf8Str logFile = com::Utf8StrFmt("%s%cVBoxUI.log", 674 logDir.c_str(), RTPATH_DELIMITER); 675 676 com::VBoxLogRelCreate("GUI (separate)", logFile.c_str(), 677 RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_RESTRICT_GROUPS, 678 "all all.restrict -default.restrict", 679 "VBOX_RELEASE_LOG", RTLOGDEST_FILE, 680 32768 /* cMaxEntriesPerGroup */, 681 0 /* cHistory */, 0 /* uHistoryFileTime */, 682 0 /* uHistoryFileSize */, NULL); 683 } 684 } 685 686 /* For Selector UI: */ 687 if (uiType() == UIType_SelectorUI) 688 { 689 /* We should create separate logging file for VM selector: */ 690 char szLogFile[RTPATH_MAX]; 691 const char *pszLogFile = NULL; 692 com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile)); 693 RTPathAppend(szLogFile, sizeof(szLogFile), "selectorwindow.log"); 694 pszLogFile = szLogFile; 695 /* Create release logger, to file: */ 696 com::VBoxLogRelCreate("GUI VM Selector Window", 697 pszLogFile, 698 RTLOGFLAGS_PREFIX_TIME_PROG, 699 "all", 700 "VBOX_GUI_SELECTORWINDOW_RELEASE_LOG", 701 RTLOGDEST_FILE | RTLOGDEST_F_NO_DENY, 702 UINT32_MAX, 703 10, 704 60 * 60, 705 _1M, 706 NULL /*pErrInfo*/); 707 708 LogRel(("Qt version: %s\n", qtRTVersionString().toUtf8().constData())); 709 } 710 711 if (m_fSettingsPwSet) 712 m_comVBox.SetSettingsSecret(m_astrSettingsPw); 713 714 if (visualStateType != UIVisualStateType_Invalid && !m_strManagedVMId.isNull()) 715 gEDataManager->setRequestedVisualState(visualStateType, m_strManagedVMId); 716 717 #ifdef VBOX_WITH_DEBUGGER_GUI 718 /* For Runtime UI: */ 719 if (uiType() == UIType_RuntimeUI) 720 { 721 /* Setup the debugger GUI: */ 722 if (RTEnvExist("VBOX_GUI_NO_DEBUGGER")) 723 m_fDbgEnabled = m_fDbgAutoShow = m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = false; 724 if (m_fDbgEnabled) 725 { 726 RTERRINFOSTATIC ErrInfo; 727 RTErrInfoInitStatic(&ErrInfo); 728 int vrc = SUPR3HardenedLdrLoadAppPriv("VBoxDbg", &m_hVBoxDbg, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core); 729 if (RT_FAILURE(vrc)) 730 { 731 m_hVBoxDbg = NIL_RTLDRMOD; 732 m_fDbgAutoShow = m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = false; 733 LogRel(("Failed to load VBoxDbg, rc=%Rrc - %s\n", vrc, ErrInfo.Core.pszMsg)); 734 } 735 } 736 } 737 #endif 738 739 m_fValid = true; 740 741 /* Create medium-enumerator but don't do any immediate caching: */ 742 m_pMediumEnumerator = new UIMediumEnumerator; 743 { 744 /* Prepare medium-enumerator: */ 745 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumCreated, 746 this, &UICommon::sigMediumCreated); 747 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumDeleted, 748 this, &UICommon::sigMediumDeleted); 749 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerationStarted, 750 this, &UICommon::sigMediumEnumerationStarted); 751 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerated, 752 this, &UICommon::sigMediumEnumerated); 753 connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerationFinished, 754 this, &UICommon::sigMediumEnumerationFinished); 755 } 756 757 /* Create shortcut pool: */ 758 UIShortcutPool::create(); 759 760 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER 761 /* Create network manager: */ 762 UINetworkRequestManager::create(); 763 764 /* Schedule update manager: */ 765 UIUpdateManager::schedule(); 766 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */ 767 768 #ifdef RT_OS_LINUX 769 /* Make sure no wrong USB mounted: */ 770 checkForWrongUSBMounted(); 771 #endif /* RT_OS_LINUX */ 772 773 /* Populate the list of medium names to be excluded from the 774 recently used media extra data: */ 775 #if 0 /* bird: This is counter productive as it is _frequently_ necessary to re-insert the 776 viso to refresh the files (like after you rebuilt them on the host). 777 The guest caches ISOs aggressively and files sizes may change. */ 778 m_recentMediaExcludeList << "ad-hoc.viso"; 779 #endif 780 } 781 782 void UICommon::cleanup() 783 { 784 LogRel(("GUI: UICommon: Handling aboutToQuit request..\n")); 785 786 /// @todo Shouldn't that be protected with a mutex or something? 787 /* Remember that the cleanup is in progress preventing any unwanted 788 * stuff which could be called from the other threads: */ 789 m_fCleaningUp = true; 790 791 #ifdef VBOX_WS_WIN 792 /* Ask listeners to commit data if haven't yet: */ 793 if (!m_fDataCommitted) 794 { 795 emit sigAskToCommitData(); 796 m_fDataCommitted = true; 797 } 798 #else 799 /* Ask listeners to commit data: */ 800 emit sigAskToCommitData(); 801 #endif 802 803 #ifdef VBOX_WITH_DEBUGGER_GUI 804 /* For Runtime UI: */ 805 if ( uiType() == UIType_RuntimeUI 806 && m_hVBoxDbg != NIL_RTLDRMOD) 807 { 808 RTLdrClose(m_hVBoxDbg); 809 m_hVBoxDbg = NIL_RTLDRMOD; 810 } 811 #endif 812 813 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER 814 /* Shutdown update manager: */ 815 UIUpdateManager::shutdown(); 816 817 /* Destroy network manager: */ 818 UINetworkRequestManager::destroy(); 819 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */ 820 821 /* Destroy shortcut pool: */ 822 UIShortcutPool::destroy(); 823 824 #ifdef VBOX_GUI_WITH_PIDFILE 825 deletePidfile(); 826 #endif /* VBOX_GUI_WITH_PIDFILE */ 827 828 /* Starting medium-enumerator cleanup: */ 829 m_meCleanupProtectionToken.lockForWrite(); 830 { 831 /* Destroy medium-enumerator: */ 832 delete m_pMediumEnumerator; 833 m_pMediumEnumerator = 0; 834 } 835 /* Finishing medium-enumerator cleanup: */ 836 m_meCleanupProtectionToken.unlock(); 837 838 /* Destroy the global (VirtualBox and VirtualBoxClient) Main event 839 * handlers which are used in both Manager and Runtime UIs. */ 840 UIVirtualBoxEventHandler::destroy(); 841 UIVirtualBoxClientEventHandler::destroy(); 842 843 /* Destroy the extra-data manager finally after everything 844 * above which could use it already destroyed: */ 845 UIExtraDataManager::destroy(); 846 847 /* Destroy converter: */ 848 UIConverter::destroy(); 849 850 /* Cleanup thread-pools: */ 851 delete m_pThreadPool; 852 m_pThreadPool = 0; 853 delete m_pThreadPoolCloud; 854 m_pThreadPoolCloud = 0; 855 /* Cleanup general icon-pool: */ 856 delete m_pIconPool; 857 m_pIconPool = 0; 858 859 /* Ensure CGuestOSType objects are no longer used: */ 860 m_guestOSFamilyIDs.clear(); 861 m_guestOSTypes.clear(); 862 863 /* Starting COM cleanup: */ 864 m_comCleanupProtectionToken.lockForWrite(); 865 { 866 /* First, make sure we don't use COM any more: */ 867 emit sigAskToDetachCOM(); 868 m_comHost.detach(); 869 m_comVBox.detach(); 870 m_comVBoxClient.detach(); 871 872 /* There may be UIMedium(s)EnumeratedEvent instances still in the message 873 * queue which reference COM objects. Remove them to release those objects 874 * before uninitializing the COM subsystem. */ 875 QApplication::removePostedEvents(this); 876 877 /* Finally cleanup COM itself: */ 878 COMBase::CleanupCOM(); 879 } 880 /* Finishing COM cleanup: */ 881 m_comCleanupProtectionToken.unlock(); 882 883 /* Notify listener it can close UI now: */ 884 emit sigAskToCloseUI(); 885 886 /* Destroy popup-center: */ 887 UIPopupCenter::destroy(); 888 /* Destroy message-center: */ 889 UIMessageCenter::destroy(); 890 891 /* Destroy desktop-widget watchdog: */ 892 UIDesktopWidgetWatchdog::destroy(); 893 894 m_fValid = false; 895 896 LogRel(("GUI: UICommon: aboutToQuit request handled!\n")); 897 } 898 899 /* static */ 900 QString UICommon::qtRTVersionString() 901 { 902 return QString::fromLatin1(qVersion()); 903 } 904 905 /* static */ 906 uint UICommon::qtRTVersion() 907 { 908 const QString strVersionRT = UICommon::qtRTVersionString(); 909 return (strVersionRT.section('.', 0, 0).toInt() << 16) + 910 (strVersionRT.section('.', 1, 1).toInt() << 8) + 911 strVersionRT.section('.', 2, 2).toInt(); 912 } 913 914 /* static */ 915 uint UICommon::qtRTMajorVersion() 916 { 917 return UICommon::qtRTVersionString().section('.', 0, 0).toInt(); 918 } 919 920 /* static */ 921 uint UICommon::qtRTMinorVersion() 922 { 923 return UICommon::qtRTVersionString().section('.', 1, 1).toInt(); 924 } 925 926 /* static */ 927 uint UICommon::qtRTRevisionNumber() 928 { 929 return UICommon::qtRTVersionString().section('.', 2, 2).toInt(); 930 } 931 932 /* static */ 933 QString UICommon::qtCTVersionString() 934 { 935 return QString::fromLatin1(QT_VERSION_STR); 936 } 937 938 /* static */ 939 uint UICommon::qtCTVersion() 940 { 941 const QString strVersionCompiled = UICommon::qtCTVersionString(); 942 return (strVersionCompiled.section('.', 0, 0).toInt() << 16) + 943 (strVersionCompiled.section('.', 1, 1).toInt() << 8) + 944 strVersionCompiled.section('.', 2, 2).toInt(); 945 } 946 947 QString UICommon::vboxVersionString() const 948 { 949 return m_comVBox.GetVersion(); 950 } 951 952 QString UICommon::vboxVersionStringNormalized() const 953 { 954 return m_comVBox.GetVersionNormalized(); 955 } 956 957 bool UICommon::isBeta() const 958 { 959 return vboxVersionString().contains("BETA", Qt::CaseInsensitive); 960 } 961 962 bool UICommon::brandingIsActive(bool fForce /* = false */) 963 { 964 if (fForce) 965 return true; 966 967 if (m_strBrandingConfigFilePath.isEmpty()) 968 { 969 m_strBrandingConfigFilePath = QDir(QApplication::applicationDirPath()).absolutePath(); 970 m_strBrandingConfigFilePath += "/custom/custom.ini"; 971 } 972 973 return QFile::exists(m_strBrandingConfigFilePath); 974 } 975 976 QString UICommon::brandingGetKey(QString strKey) const 977 { 978 QSettings settings(m_strBrandingConfigFilePath, QSettings::IniFormat); 979 return settings.value(QString("%1").arg(strKey)).toString(); 980 } 981 982 #ifdef VBOX_WS_MAC 983 /* static */ 984 MacOSXRelease UICommon::determineOsRelease() 985 { 986 /* Prepare 'utsname' struct: */ 987 utsname info; 988 if (uname(&info) != -1) 989 { 990 /* Compose map of known releases: */ 991 QMap<int, MacOSXRelease> release; 992 release[10] = MacOSXRelease_SnowLeopard; 993 release[11] = MacOSXRelease_Lion; 994 release[12] = MacOSXRelease_MountainLion; 995 release[13] = MacOSXRelease_Mavericks; 996 release[14] = MacOSXRelease_Yosemite; 997 release[15] = MacOSXRelease_ElCapitan; 998 999 /* Cut the major release index of the string we have, s.a. 'man uname': */ 1000 const int iRelease = QString(info.release).section('.', 0, 0).toInt(); 1001 1002 /* Return release if determined, return 'New' if version more recent than latest, return 'Old' otherwise: */ 1003 return release.value(iRelease, iRelease > release.keys().last() ? MacOSXRelease_New : MacOSXRelease_Old); 1004 } 1005 /* Return 'Old' by default: */ 1006 return MacOSXRelease_Old; 1007 } 1008 #endif /* VBOX_WS_MAC */ 1009 1010 #ifdef VBOX_WS_WIN 1011 /* static */ 1012 void UICommon::loadColorTheme() 1013 { 1014 /* Load saved color theme: */ 1015 UIColorThemeType enmColorTheme = gEDataManager->colorTheme(); 1016 1017 /* Check whether we have dark system theme requested: */ 1018 if (enmColorTheme == UIColorThemeType_Auto) 1019 { 1020 QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 1021 QSettings::NativeFormat); 1022 if (settings.value("AppsUseLightTheme") == 0) 1023 enmColorTheme = UIColorThemeType_Dark; 1024 } 1025 1026 /* Check whether dark theme was requested by any means: */ 1027 if (enmColorTheme == UIColorThemeType_Dark) 1028 { 1029 qApp->setStyle(QStyleFactory::create("Fusion")); 1030 QPalette darkPalette; 1031 QColor windowColor1 = QColor(59, 60, 61); 1032 QColor windowColor2 = QColor(63, 64, 65); 1033 QColor baseColor1 = QColor(46, 47, 48); 1034 QColor baseColor2 = QColor(56, 57, 58); 1035 QColor disabledColor = QColor(113, 114, 115); 1036 darkPalette.setColor(QPalette::Window, windowColor1); 1037 darkPalette.setColor(QPalette::WindowText, Qt::white); 1038 darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, disabledColor); 1039 darkPalette.setColor(QPalette::Base, baseColor1); 1040 darkPalette.setColor(QPalette::AlternateBase, baseColor2); 1041 darkPalette.setColor(QPalette::PlaceholderText, disabledColor); 1042 darkPalette.setColor(QPalette::Text, Qt::white); 1043 darkPalette.setColor(QPalette::Disabled, QPalette::Text, disabledColor); 1044 darkPalette.setColor(QPalette::Button, windowColor2); 1045 darkPalette.setColor(QPalette::ButtonText, Qt::white); 1046 darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, disabledColor); 1047 darkPalette.setColor(QPalette::BrightText, Qt::red); 1048 darkPalette.setColor(QPalette::Link, QColor(179, 214, 242)); 1049 darkPalette.setColor(QPalette::Highlight, QColor(29, 84, 92)); 1050 darkPalette.setColor(QPalette::HighlightedText, Qt::white); 1051 darkPalette.setColor(QPalette::Disabled, QPalette::HighlightedText, disabledColor); 1052 qApp->setPalette(darkPalette); 1053 qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2b2b2b; border: 1px solid #737373; }"); 1054 } 1055 } 1056 #endif /* VBOX_WS_WIN */ 1057 1058 bool UICommon::processArgs() 1059 { 1060 /* Among those arguments: */ 1061 bool fResult = false; 1062 const QStringList args = qApp->arguments(); 1063 1064 /* We are looking for a list of file URLs passed to the executable: */ 1065 QList<QUrl> listArgUrls; 1066 for (int i = 1; i < args.size(); ++i) 1067 { 1068 /* But we break out after the first parameter, cause there 1069 * could be parameters with arguments (e.g. --comment comment). */ 1070 if (args.at(i).startsWith("-")) 1071 break; 1072 1073 #ifdef VBOX_WS_MAC 1074 const QString strArg = ::darwinResolveAlias(args.at(i)); 1075 #else 1076 const QString strArg = args.at(i); 1077 #endif 1078 1079 /* So if the argument file exists, we add it to URL list: */ 1080 if ( !strArg.isEmpty() 1081 && QFile::exists(strArg)) 1082 listArgUrls << QUrl::fromLocalFile(QFileInfo(strArg).absoluteFilePath()); 1083 } 1084 1085 /* If there are file URLs: */ 1086 if (!listArgUrls.isEmpty()) 1087 { 1088 /* We enumerate them and: */ 1089 for (int i = 0; i < listArgUrls.size(); ++i) 1090 { 1091 /* Check which of them has allowed VM extensions: */ 1092 const QUrl url = listArgUrls.at(i); 1093 const QString strFile = url.toLocalFile(); 1094 if (UICommon::hasAllowedExtension(strFile, VBoxFileExts)) 1095 { 1096 /* So that we could run existing VMs: */ 1097 CVirtualBox comVBox = virtualBox(); 1098 CMachine comMachine = comVBox.FindMachine(strFile); 1099 if (!comMachine.isNull()) 1100 { 1101 fResult = true; 1102 launchMachine(comMachine); 1103 /* And remove their URLs from the ULR list: */ 1104 listArgUrls.removeAll(url); 1105 } 1106 } 1107 } 1108 } 1109 1110 /* And if there are *still* URLs: */ 1111 if (!listArgUrls.isEmpty()) 1112 { 1113 /* We store them, they will be handled later: */ 1114 m_listArgUrls = listArgUrls; 1115 } 1116 1117 return fResult; 1118 } 1119 1120 bool UICommon::argumentUrlsPresent() const 1121 { 1122 return !m_listArgUrls.isEmpty(); 1123 } 1124 1125 QList<QUrl> UICommon::takeArgumentUrls() 1126 { 1127 const QList<QUrl> result = m_listArgUrls; 1128 m_listArgUrls.clear(); 1129 return result; 1130 } 1131 1132 #ifdef VBOX_WITH_DEBUGGER_GUI 1133 1134 bool UICommon::isDebuggerEnabled() const 1135 { 1136 return isDebuggerWorker(&m_fDbgEnabled, GUI_Dbg_Enabled); 1137 } 1138 1139 bool UICommon::isDebuggerAutoShowEnabled() const 1140 { 1141 return isDebuggerWorker(&m_fDbgAutoShow, GUI_Dbg_AutoShow); 1142 } 1143 1144 bool UICommon::isDebuggerAutoShowCommandLineEnabled() const 1145 { 1146 return isDebuggerWorker(&m_fDbgAutoShowCommandLine, GUI_Dbg_AutoShow); 1147 } 1148 1149 bool UICommon::isDebuggerAutoShowStatisticsEnabled() const 1150 { 1151 return isDebuggerWorker(&m_fDbgAutoShowStatistics, GUI_Dbg_AutoShow); 1152 } 1153 1154 #endif /* VBOX_WITH_DEBUGGER_GUI */ 1155 1156 bool UICommon::shouldStartPaused() const 1157 { 1158 #ifdef VBOX_WITH_DEBUGGER_GUI 1159 return m_enmLaunchRunning == LaunchRunning_Default ? isDebuggerAutoShowEnabled() : m_enmLaunchRunning == LaunchRunning_No; 1160 #else 1161 return false; 1162 #endif 1163 } 1164 1165 #ifdef VBOX_GUI_WITH_PIDFILE 1166 1167 void UICommon::createPidfile() 1168 { 1169 if (!m_strPidFile.isEmpty()) 1170 { 1171 const qint64 iPid = qApp->applicationPid(); 1172 QFile file(m_strPidFile); 1173 if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) 1174 { 1175 QTextStream out(&file); 1176 out << iPid << endl; 1177 } 1178 else 1179 LogRel(("Failed to create pid file %s\n", m_strPidFile.toUtf8().constData())); 1180 } 1181 } 1182 1183 void UICommon::deletePidfile() 1184 { 1185 if ( !m_strPidFile.isEmpty() 1186 && QFile::exists(m_strPidFile)) 1187 QFile::remove(m_strPidFile); 1188 } 1189 1190 #endif /* VBOX_GUI_WITH_PIDFILE */ 1191 1192 /* static */ 1193 QString UICommon::helpFile() 1194 { 1195 #if defined (VBOX_WITH_QHELP_VIEWER) 1196 const QString strName = "UserManual"; 1197 const QString strSuffix = "qhc"; 1198 #else 1199 #if defined(VBOX_WS_WIN) 1200 const QString strName = "VirtualBox"; 1201 const QString strSuffix = "chm"; 1202 #elif defined(VBOX_WS_MAC) 1203 const QString strName = "UserManual"; 1204 const QString strSuffix = "pdf"; 1205 #elif defined(VBOX_WS_X11) 1206 //# if defined(VBOX_OSE) || !defined(VBOX_WITH_KCHMVIEWER) 1207 const QString strName = "UserManual"; 1208 const QString strSuffix = "pdf"; 1209 #endif 1210 #endif 1211 /* Where are the docs located? */ 1212 char szDocsPath[RTPATH_MAX]; 1213 int rc = RTPathAppDocs(szDocsPath, sizeof(szDocsPath)); 1214 AssertRC(rc); 1215 1216 /* Make sure that the language is in two letter code. 1217 * Note: if languageId() returns an empty string lang.name() will 1218 * return "C" which is an valid language code. */ 1219 QLocale lang(UITranslator::languageId()); 1220 1221 /* Construct the path and the filename: */ 1222 QString strManual = QString("%1/%2_%3.%4").arg(szDocsPath) 1223 .arg(strName) 1224 .arg(lang.name()) 1225 .arg(strSuffix); 1226 1227 /* Check if a help file with that name exists: */ 1228 QFileInfo fi(strManual); 1229 if (fi.exists()) 1230 return strManual; 1231 1232 /* Fall back to the standard: */ 1233 strManual = QString("%1/%2.%4").arg(szDocsPath) 1234 .arg(strName) 1235 .arg(strSuffix); 1236 return strManual; 1237 } 1238 1239 /* static */ 1240 QString UICommon::documentsPath() 1241 { 1242 QString strPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); 1243 QDir dir(strPath); 1244 if (dir.exists()) 1245 return QDir::cleanPath(dir.canonicalPath()); 1246 else 1247 { 1248 dir.setPath(QDir::homePath() + "/Documents"); 1249 if (dir.exists()) 1250 return QDir::cleanPath(dir.canonicalPath()); 1251 else 1252 return QDir::homePath(); 1253 } 1254 } 1255 1256 /* static */ 1257 bool UICommon::hasAllowedExtension(const QString &strFileName, const QStringList &extensions) 1258 { 1259 foreach (const QString &strExtension, extensions) 1260 if (strFileName.endsWith(strExtension, Qt::CaseInsensitive)) 1261 return true; 1262 return false; 1263 } 1264 1265 /* static */ 1266 QString UICommon::findUniqueFileName(const QString &strFullFolderPath, const QString &strBaseFileName) 1267 { 1268 QDir folder(strFullFolderPath); 1269 if (!folder.exists()) 1270 return strBaseFileName; 1271 QFileInfoList folderContent = folder.entryInfoList(); 1272 QSet<QString> fileNameSet; 1273 foreach (const QFileInfo &fileInfo, folderContent) 1274 { 1275 /* Remove the extension : */ 1276 fileNameSet.insert(fileInfo.completeBaseName()); 1277 } 1278 int iSuffix = 0; 1279 QString strNewName(strBaseFileName); 1280 while (fileNameSet.contains(strNewName)) 1281 { 1282 strNewName = strBaseFileName + QString("_") + QString::number(++iSuffix); 1283 } 1284 return strNewName; 1285 } 1286 1287 /* static */ 1288 QRect UICommon::normalizeGeometry(const QRect &rectangle, const QRegion &boundRegion, bool fCanResize /* = true */) 1289 { 1290 /* Perform direct and flipped search of position for @a rectangle to make sure it is fully contained 1291 * inside @a boundRegion region by moving & resizing (if @a fCanResize is specified) @a rectangle if 1292 * necessary. Selects the minimum shifted result between direct and flipped variants. */ 1293 1294 /* Direct search for normalized rectangle: */ 1295 QRect var1(getNormalized(rectangle, boundRegion, fCanResize)); 1296 1297 /* Flipped search for normalized rectangle: */ 1298 QRect var2(flip(getNormalized(flip(rectangle).boundingRect(), 1299 flip(boundRegion), fCanResize)).boundingRect()); 1300 1301 /* Calculate shift from starting position for both variants: */ 1302 double dLength1 = sqrt(pow((double)(var1.x() - rectangle.x()), (double)2) + 1303 pow((double)(var1.y() - rectangle.y()), (double)2)); 1304 double dLength2 = sqrt(pow((double)(var2.x() - rectangle.x()), (double)2) + 1305 pow((double)(var2.y() - rectangle.y()), (double)2)); 1306 1307 /* Return minimum shifted variant: */ 1308 return dLength1 > dLength2 ? var2 : var1; 1309 } 1310 1311 /* static */ 1312 QRect UICommon::getNormalized(const QRect &rectangle, const QRegion &boundRegion, bool /* fCanResize = true */) 1313 { 1314 /* Ensures that the given rectangle @a rectangle is fully contained within the region @a boundRegion 1315 * by moving @a rectangle if necessary. If @a rectangle is larger than @a boundRegion, top left 1316 * corner of @a rectangle is aligned with the top left corner of maximum available rectangle and, 1317 * if @a fCanResize is true, @a rectangle is shrinked to become fully visible. */ 1318 1319 /* Storing available horizontal sub-rectangles & vertical shifts: */ 1320 const int iWindowVertical = rectangle.center().y(); 1321 QList<QRect> rectanglesList; 1322 QList<int> shiftsList; 1323 foreach (QRect currentItem, boundRegion.rects()) 1324 { 1325 const int iCurrentDelta = qAbs(iWindowVertical - currentItem.center().y()); 1326 const int iShift2Top = currentItem.top() - rectangle.top(); 1327 const int iShift2Bot = currentItem.bottom() - rectangle.bottom(); 1328 1329 int iTtemPosition = 0; 1330 foreach (QRect item, rectanglesList) 1331 { 1332 const int iDelta = qAbs(iWindowVertical - item.center().y()); 1333 if (iDelta > iCurrentDelta) 1334 break; 1335 else 1336 ++iTtemPosition; 1337 } 1338 rectanglesList.insert(iTtemPosition, currentItem); 1339 1340 int iShift2TopPos = 0; 1341 foreach (int iShift, shiftsList) 1342 if (qAbs(iShift) > qAbs(iShift2Top)) 1343 break; 1344 else 1345 ++iShift2TopPos; 1346 shiftsList.insert(iShift2TopPos, iShift2Top); 1347 1348 int iShift2BotPos = 0; 1349 foreach (int iShift, shiftsList) 1350 if (qAbs(iShift) > qAbs(iShift2Bot)) 1351 break; 1352 else 1353 ++iShift2BotPos; 1354 shiftsList.insert(iShift2BotPos, iShift2Bot); 1355 } 1356 1357 /* Trying to find the appropriate place for window: */ 1358 QRect result; 1359 for (int i = -1; i < shiftsList.size(); ++i) 1360 { 1361 /* Move to appropriate vertical: */ 1362 QRect newRectangle(rectangle); 1363 if (i >= 0) 1364 newRectangle.translate(0, shiftsList[i]); 1365 1366 /* Search horizontal shift: */ 1367 int iMaxShift = 0; 1368 foreach (QRect item, rectanglesList) 1369 { 1370 QRect trectangle(newRectangle.translated(item.left() - newRectangle.left(), 0)); 1371 if (!item.intersects(trectangle)) 1372 continue; 1373 1374 if (newRectangle.left() < item.left()) 1375 { 1376 const int iShift = item.left() - newRectangle.left(); 1377 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift; 1378 } 1379 else if (newRectangle.right() > item.right()) 1380 { 1381 const int iShift = item.right() - newRectangle.right(); 1382 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift; 1383 } 1384 } 1385 1386 /* Shift across the horizontal direction: */ 1387 newRectangle.translate(iMaxShift, 0); 1388 1389 /* Check the translated rectangle to feat the rules: */ 1390 if (boundRegion.united(newRectangle) == boundRegion) 1391 result = newRectangle; 1392 1393 if (!result.isNull()) 1394 break; 1395 } 1396 1397 if (result.isNull()) 1398 { 1399 /* Resize window to feat desirable size 1400 * using max of available rectangles: */ 1401 QRect maxRectangle; 1402 quint64 uMaxSquare = 0; 1403 foreach (QRect item, rectanglesList) 1404 { 1405 const quint64 uSquare = item.width() * item.height(); 1406 if (uSquare > uMaxSquare) 1407 { 1408 uMaxSquare = uSquare; 1409 maxRectangle = item; 1410 } 1411 } 1412 1413 result = rectangle; 1414 result.moveTo(maxRectangle.x(), maxRectangle.y()); 1415 if (maxRectangle.right() < result.right()) 1416 result.setRight(maxRectangle.right()); 1417 if (maxRectangle.bottom() < result.bottom()) 1418 result.setBottom(maxRectangle.bottom()); 1419 } 1420 1421 return result; 1422 } 1423 1424 /* static */ 1425 QRegion UICommon::flip(const QRegion ®ion) 1426 { 1427 QRegion result; 1428 QVector<QRect> rectangles(region.rects()); 1429 foreach (QRect rectangle, rectangles) 1430 result += QRect(rectangle.y(), rectangle.x(), 1431 rectangle.height(), rectangle.width()); 1432 return result; 1433 } 1434 1435 /* static */ 1436 void UICommon::centerWidget(QWidget *pWidget, QWidget *pRelative, bool fCanResize /* = true */) 1437 { 1438 /* If necessary, pWidget's position is adjusted to make it fully visible within 1439 * the available desktop area. If pWidget is bigger then this area, it will also 1440 * be resized unless fCanResize is false or there is an inappropriate minimum 1441 * size limit (in which case the top left corner will be simply aligned with the top 1442 * left corner of the available desktop area). pWidget must be a top-level widget. 1443 * pRelative may be any widget, but if it's not top-level itself, its top-level 1444 * widget will be used for calculations. pRelative can also be NULL, in which case 1445 * pWidget will be centered relative to the available desktop area. */ 1446 1447 AssertReturnVoid(pWidget); 1448 AssertReturnVoid(pWidget->isTopLevel()); 1449 1450 QRect deskGeo, parentGeo; 1451 if (pRelative) 1452 { 1453 pRelative = pRelative->window(); 1454 deskGeo = gpDesktop->availableGeometry(pRelative); 1455 parentGeo = pRelative->frameGeometry(); 1456 // WORKAROUND: 1457 // On X11/Gnome, geo/frameGeo.x() and y() are always 0 for top level 1458 // widgets with parents, what a shame. Use mapToGlobal() to workaround. 1459 QPoint d = pRelative->mapToGlobal(QPoint(0, 0)); 1460 d.rx() -= pRelative->geometry().x() - pRelative->x(); 1461 d.ry() -= pRelative->geometry().y() - pRelative->y(); 1462 parentGeo.moveTopLeft(d); 1463 } 1464 else 1465 { 1466 deskGeo = gpDesktop->availableGeometry(); 1467 parentGeo = deskGeo; 1468 } 1469 1470 // WORKAROUND: 1471 // On X11, there is no way to determine frame geometry (including WM 1472 // decorations) before the widget is shown for the first time. Stupidly 1473 // enumerate other top level widgets to find the thickest frame. The code 1474 // is based on the idea taken from QDialog::adjustPositionInternal(). 1475 1476 int iExtraW = 0; 1477 int iExtraH = 0; 1478 1479 QWidgetList list = QApplication::topLevelWidgets(); 1480 QListIterator<QWidget*> it(list); 1481 while ((iExtraW == 0 || iExtraH == 0) && it.hasNext()) 1482 { 1483 int iFrameW, iFrameH; 1484 QWidget *pCurrent = it.next(); 1485 if (!pCurrent->isVisible()) 1486 continue; 1487 1488 iFrameW = pCurrent->frameGeometry().width() - pCurrent->width(); 1489 iFrameH = pCurrent->frameGeometry().height() - pCurrent->height(); 1490 1491 iExtraW = qMax(iExtraW, iFrameW); 1492 iExtraH = qMax(iExtraH, iFrameH); 1493 } 1494 1495 /* On non-X11 platforms, the following would be enough instead of the above workaround: */ 1496 // QRect geo = frameGeometry(); 1497 QRect geo = QRect(0, 0, pWidget->width() + iExtraW, 1498 pWidget->height() + iExtraH); 1499 1500 geo.moveCenter(QPoint(parentGeo.x() + (parentGeo.width() - 1) / 2, 1501 parentGeo.y() + (parentGeo.height() - 1) / 2)); 1502 1503 /* Ensure the widget is within the available desktop area: */ 1504 QRect newGeo = normalizeGeometry(geo, deskGeo, fCanResize); 1505 #ifdef VBOX_WS_MAC 1506 // WORKAROUND: 1507 // No idea why, but Qt doesn't respect if there is a unified toolbar on the 1508 // ::move call. So manually add the height of the toolbar before setting 1509 // the position. 1510 if (pRelative) 1511 newGeo.translate(0, ::darwinWindowToolBarHeight(pWidget)); 1512 #endif /* VBOX_WS_MAC */ 1513 1514 pWidget->move(newGeo.topLeft()); 1515 1516 if ( fCanResize 1517 && (geo.width() != newGeo.width() || geo.height() != newGeo.height())) 1518 pWidget->resize(newGeo.width() - iExtraW, newGeo.height() - iExtraH); 1519 } 1520 1521 #ifdef VBOX_WS_X11 1522 typedef struct { 1523 /** User specified flags */ 1524 uint32_t flags; 1525 /** User-specified position */ 1526 int32_t x, y; 1527 /** User-specified size */ 1528 int32_t width, height; 1529 /** Program-specified minimum size */ 1530 int32_t min_width, min_height; 1531 /** Program-specified maximum size */ 1532 int32_t max_width, max_height; 1533 /** Program-specified resize increments */ 1534 int32_t width_inc, height_inc; 1535 /** Program-specified minimum aspect ratios */ 1536 int32_t min_aspect_num, min_aspect_den; 1537 /** Program-specified maximum aspect ratios */ 1538 int32_t max_aspect_num, max_aspect_den; 1539 /** Program-specified base size */ 1540 int32_t base_width, base_height; 1541 /** Program-specified window gravity */ 1542 uint32_t win_gravity; 1543 } xcb_size_hints_t; 1544 #endif /* VBOX_WS_X11 */ 1545 1546 /* static */ 1547 void UICommon::setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int h) 1548 { 1549 AssertPtrReturnVoid(pWidget); 1550 #ifdef VBOX_WS_X11 1551 # define QWINDOWSIZE_MAX ((1<<24)-1) 1552 if (pWidget->isWindow() && pWidget->isVisible()) 1553 { 1554 // WORKAROUND: 1555 // X11 window managers are not required to accept geometry changes on 1556 // the top-level window. Unfortunately, current at Qt 5.6 and 5.7, Qt 1557 // assumes that the change will succeed, and resizes all sub-windows 1558 // unconditionally. By calling ConfigureWindow directly, Qt will see 1559 // our change request as an externally triggered one on success and not 1560 // at all if it is rejected. 1561 const double dDPR = gpDesktop->devicePixelRatio(pWidget); 1562 uint16_t fMask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y 1563 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; 1564 uint32_t values[] = { (uint32_t)(x * dDPR), (uint32_t)(y * dDPR), (uint32_t)(w * dDPR), (uint32_t)(h * dDPR) }; 1565 xcb_configure_window(QX11Info::connection(), (xcb_window_t)pWidget->winId(), 1566 fMask, values); 1567 xcb_size_hints_t hints; 1568 hints.flags = 1 /* XCB_ICCCM_SIZE_HINT_US_POSITION */ 1569 | 2 /* XCB_ICCCM_SIZE_HINT_US_SIZE */ 1570 | 512 /* XCB_ICCCM_SIZE_P_WIN_GRAVITY */; 1571 hints.x = x * dDPR; 1572 hints.y = y * dDPR; 1573 hints.width = w * dDPR; 1574 hints.height = h * dDPR; 1575 hints.min_width = pWidget->minimumSize().width() * dDPR; 1576 hints.min_height = pWidget->minimumSize().height() * dDPR; 1577 hints.max_width = pWidget->maximumSize().width() * dDPR; 1578 hints.max_height = pWidget->maximumSize().height() * dDPR; 1579 hints.width_inc = pWidget->sizeIncrement().width() * dDPR; 1580 hints.height_inc = pWidget->sizeIncrement().height() * dDPR; 1581 hints.base_width = pWidget->baseSize().width() * dDPR; 1582 hints.base_height = pWidget->baseSize().height() * dDPR; 1583 hints.win_gravity = XCB_GRAVITY_STATIC; 1584 if (hints.min_width > 0 || hints.min_height > 0) 1585 hints.flags |= 16 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */; 1586 if (hints.max_width < QWINDOWSIZE_MAX || hints.max_height < QWINDOWSIZE_MAX) 1587 hints.flags |= 32 /* XCB_ICCCM_SIZE_HINT_P_MAX_SIZE */; 1588 if (hints.width_inc > 0 || hints.height_inc) 1589 hints.flags |= 64 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */ 1590 | 256 /* XCB_ICCCM_SIZE_HINT_BASE_SIZE */; 1591 xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, 1592 (xcb_window_t)pWidget->winId(), XCB_ATOM_WM_NORMAL_HINTS, 1593 XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) >> 2, &hints); 1594 xcb_flush(QX11Info::connection()); 1595 } 1596 else 1597 // WORKAROUND: 1598 // Call the Qt method if the window is not visible as otherwise no 1599 // Configure event will arrive to tell Qt what geometry we want. 1600 pWidget->setGeometry(x, y, w, h); 1601 # else /* !VBOX_WS_X11 */ 1602 pWidget->setGeometry(x, y, w, h); 1603 # endif /* !VBOX_WS_X11 */ 1604 } 1605 1606 /* static */ 1607 void UICommon::setTopLevelGeometry(QWidget *pWidget, const QRect &rect) 1608 { 1609 UICommon::setTopLevelGeometry(pWidget, rect.x(), rect.y(), rect.width(), rect.height()); 1610 } 1611 1612 #if defined(VBOX_WS_X11) 1613 1614 static char *XXGetProperty(Display *pDpy, Window windowHandle, Atom propType, const char *pszPropName) 1615 { 1616 Atom propNameAtom = XInternAtom(pDpy, pszPropName, True /* only_if_exists */); 1617 if (propNameAtom == None) 1618 return NULL; 1619 1620 Atom actTypeAtom = None; 1621 int actFmt = 0; 1622 unsigned long nItems = 0; 1623 unsigned long nBytesAfter = 0; 1624 unsigned char *propVal = NULL; 1625 int rc = XGetWindowProperty(pDpy, windowHandle, propNameAtom, 1626 0, LONG_MAX, False /* delete */, 1627 propType, &actTypeAtom, &actFmt, 1628 &nItems, &nBytesAfter, &propVal); 1629 if (rc != Success) 1630 return NULL; 1631 1632 return reinterpret_cast<char*>(propVal); 1633 } 1634 1635 static Bool XXSendClientMessage(Display *pDpy, Window windowHandle, const char *pszMsg, 1636 unsigned long aData0 = 0, unsigned long aData1 = 0, 1637 unsigned long aData2 = 0, unsigned long aData3 = 0, 1638 unsigned long aData4 = 0) 1639 { 1640 Atom msgAtom = XInternAtom(pDpy, pszMsg, True /* only_if_exists */); 1641 if (msgAtom == None) 1642 return False; 1643 1644 XEvent ev; 1645 1646 ev.xclient.type = ClientMessage; 1647 ev.xclient.serial = 0; 1648 ev.xclient.send_event = True; 1649 ev.xclient.display = pDpy; 1650 ev.xclient.window = windowHandle; 1651 ev.xclient.message_type = msgAtom; 1652 1653 /* Always send as 32 bit for now: */ 1654 ev.xclient.format = 32; 1655 ev.xclient.data.l[0] = aData0; 1656 ev.xclient.data.l[1] = aData1; 1657 ev.xclient.data.l[2] = aData2; 1658 ev.xclient.data.l[3] = aData3; 1659 ev.xclient.data.l[4] = aData4; 1660 1661 return XSendEvent(pDpy, DefaultRootWindow(pDpy), False, 1662 SubstructureRedirectMask, &ev) != 0; 1663 } 1664 1665 #endif 1666 1667 /* static */ 1668 bool UICommon::activateWindow(WId wId, bool fSwitchDesktop /* = true */) 1669 { 1670 RT_NOREF(fSwitchDesktop); 1671 bool fResult = true; 1672 1673 #if defined(VBOX_WS_WIN) 1674 1675 HWND handle = (HWND)wId; 1676 1677 if (IsIconic(handle)) 1678 fResult &= !!ShowWindow(handle, SW_RESTORE); 1679 else if (!IsWindowVisible(handle)) 1680 fResult &= !!ShowWindow(handle, SW_SHOW); 1681 1682 fResult &= !!SetForegroundWindow(handle); 1683 1684 #elif defined(VBOX_WS_X11) 1685 1686 Display *pDisplay = QX11Info::display(); 1687 1688 if (fSwitchDesktop) 1689 { 1690 /* try to find the desktop ID using the NetWM property */ 1691 CARD32 *pDesktop = (CARD32 *) XXGetProperty(pDisplay, wId, XA_CARDINAL, 1692 "_NET_WM_DESKTOP"); 1693 if (pDesktop == NULL) 1694 // WORKAROUND: 1695 // if the NetWM properly is not supported try to find 1696 // the desktop ID using the GNOME WM property. 1697 pDesktop = (CARD32 *) XXGetProperty(pDisplay, wId, XA_CARDINAL, 1698 "_WIN_WORKSPACE"); 1699 1700 if (pDesktop != NULL) 1701 { 1702 Bool ok = XXSendClientMessage(pDisplay, DefaultRootWindow(pDisplay), 1703 "_NET_CURRENT_DESKTOP", 1704 *pDesktop); 1705 if (!ok) 1706 { 1707 Log1WarningFunc(("Couldn't switch to pDesktop=%08X\n", pDesktop)); 1708 fResult = false; 1709 } 1710 XFree(pDesktop); 1711 } 1712 else 1713 { 1714 Log1WarningFunc(("Couldn't find a pDesktop ID for wId=%08X\n", wId)); 1715 fResult = false; 1716 } 1717 } 1718 1719 Bool ok = XXSendClientMessage(pDisplay, wId, "_NET_ACTIVE_WINDOW"); 1720 fResult &= !!ok; 1721 1722 XRaiseWindow(pDisplay, wId); 1723 1724 #else 1725 1726 NOREF(wId); 1727 NOREF(fSwitchDesktop); 1728 AssertFailed(); 1729 fResult = false; 1730 1731 #endif 1732 1733 if (!fResult) 1734 Log1WarningFunc(("Couldn't activate wId=%08X\n", wId)); 1735 1736 return fResult; 1737 } 1738 1739 #if defined(VBOX_WS_X11) 1740 1741 /* static */ 1742 bool UICommon::supportsFullScreenMonitorsProtocolX11() 1743 { 1744 /* This method tests whether the current X11 window manager supports full-screen mode as we need it. 1745 * Unfortunately the EWMH specification was not fully clear about whether we can expect to find 1746 * all of these atoms on the _NET_SUPPORTED root window property, so we have to test with all 1747 * interesting window managers. If this fails for a user when you think it should succeed 1748 * they should try executing: 1749 * xprop -root | egrep -w '_NET_WM_FULLSCREEN_MONITORS|_NET_WM_STATE|_NET_WM_STATE_FULLSCREEN' 1750 * in an X11 terminal window. 1751 * All three strings should be found under a property called "_NET_SUPPORTED(ATOM)". */ 1752 1753 /* Using a global to get at the display does not feel right, but that is how it is done elsewhere in the code. */ 1754 Display *pDisplay = QX11Info::display(); 1755 Atom atomSupported = XInternAtom(pDisplay, "_NET_SUPPORTED", 1756 True /* only_if_exists */); 1757 Atom atomWMFullScreenMonitors = XInternAtom(pDisplay, 1758 "_NET_WM_FULLSCREEN_MONITORS", 1759 True /* only_if_exists */); 1760 Atom atomWMState = XInternAtom(pDisplay, 1761 "_NET_WM_STATE", 1762 True /* only_if_exists */); 1763 Atom atomWMStateFullScreen = XInternAtom(pDisplay, 1764 "_NET_WM_STATE_FULLSCREEN", 1765 True /* only_if_exists */); 1766 bool fFoundFullScreenMonitors = false; 1767 bool fFoundState = false; 1768 bool fFoundStateFullScreen = false; 1769 Atom atomType; 1770 int cFormat; 1771 unsigned long cItems; 1772 unsigned long cbLeft; 1773 Atom *pAtomHints; 1774 int rc; 1775 unsigned i; 1776 1777 if ( atomSupported == None || atomWMFullScreenMonitors == None 1778 || atomWMState == None || atomWMStateFullScreen == None) 1779 return false; 1780 /* Get atom value: */ 1781 rc = XGetWindowProperty(pDisplay, DefaultRootWindow(pDisplay), 1782 atomSupported, 0, 0x7fffffff /*LONG_MAX*/, 1783 False /* delete */, XA_ATOM, &atomType, 1784 &cFormat, &cItems, &cbLeft, 1785 (unsigned char **)&pAtomHints); 1786 if (rc != Success) 1787 return false; 1788 if (pAtomHints == NULL) 1789 return false; 1790 if (atomType == XA_ATOM && cFormat == 32 && cbLeft == 0) 1791 for (i = 0; i < cItems; ++i) 1792 { 1793 if (pAtomHints[i] == atomWMFullScreenMonitors) 1794 fFoundFullScreenMonitors = true; 1795 if (pAtomHints[i] == atomWMState) 1796 fFoundState = true; 1797 if (pAtomHints[i] == atomWMStateFullScreen) 1798 fFoundStateFullScreen = true; 1799 } 1800 XFree(pAtomHints); 1801 return fFoundFullScreenMonitors && fFoundState && fFoundStateFullScreen; 1802 } 1803 1804 /* static */ 1805 bool UICommon::setFullScreenMonitorX11(QWidget *pWidget, ulong uScreenId) 1806 { 1807 return XXSendClientMessage(QX11Info::display(), 1808 pWidget->window()->winId(), 1809 "_NET_WM_FULLSCREEN_MONITORS", 1810 uScreenId, uScreenId, uScreenId, uScreenId, 1811 1 /* Source indication (1 = normal application) */); 1812 } 1813 1814 /* static */ 1815 QVector<Atom> UICommon::flagsNetWmState(QWidget *pWidget) 1816 { 1817 /* Get display: */ 1818 Display *pDisplay = QX11Info::display(); 1819 1820 /* Prepare atoms: */ 1821 QVector<Atom> resultNetWmState; 1822 Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */); 1823 1824 /* Get the size of the property data: */ 1825 Atom actual_type; 1826 int iActualFormat; 1827 ulong uPropertyLength; 1828 ulong uBytesLeft; 1829 uchar *pPropertyData = 0; 1830 if (XGetWindowProperty(pDisplay, pWidget->window()->winId(), 1831 net_wm_state, 0, 0, False, XA_ATOM, &actual_type, &iActualFormat, 1832 &uPropertyLength, &uBytesLeft, &pPropertyData) == Success && 1833 actual_type == XA_ATOM && iActualFormat == 32) 1834 { 1835 resultNetWmState.resize(uBytesLeft / 4); 1836 XFree((char*)pPropertyData); 1837 pPropertyData = 0; 1838 1839 /* Fetch all data: */ 1840 if (XGetWindowProperty(pDisplay, pWidget->window()->winId(), 1841 net_wm_state, 0, resultNetWmState.size(), False, XA_ATOM, &actual_type, &iActualFormat, 1842 &uPropertyLength, &uBytesLeft, &pPropertyData) != Success) 1843 resultNetWmState.clear(); 1844 else if (uPropertyLength != (ulong)resultNetWmState.size()) 1845 resultNetWmState.resize(uPropertyLength); 1846 1847 /* Put it into resultNetWmState: */ 1848 if (!resultNetWmState.isEmpty()) 1849 memcpy(resultNetWmState.data(), pPropertyData, resultNetWmState.size() * sizeof(Atom)); 1850 if (pPropertyData) 1851 XFree((char*)pPropertyData); 1852 } 1853 1854 /* Return result: */ 1855 return resultNetWmState; 1856 } 1857 1858 /* static */ 1859 bool UICommon::isFullScreenFlagSet(QWidget *pWidget) 1860 { 1861 /* Get display: */ 1862 Display *pDisplay = QX11Info::display(); 1863 1864 /* Prepare atoms: */ 1865 Atom net_wm_state_fullscreen = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", True /* only if exists */); 1866 1867 /* Check if flagsNetWmState(pWidget) contains full-screen flag: */ 1868 return flagsNetWmState(pWidget).contains(net_wm_state_fullscreen); 1869 } 1870 1871 /* static */ 1872 void UICommon::setFullScreenFlag(QWidget *pWidget) 1873 { 1874 /* Get display: */ 1875 Display *pDisplay = QX11Info::display(); 1876 1877 /* Prepare atoms: */ 1878 QVector<Atom> resultNetWmState = flagsNetWmState(pWidget); 1879 Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */); 1880 Atom net_wm_state_fullscreen = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", True /* only if exists */); 1881 1882 /* Append resultNetWmState with fullscreen flag if necessary: */ 1883 if (!resultNetWmState.contains(net_wm_state_fullscreen)) 1884 { 1885 resultNetWmState.append(net_wm_state_fullscreen); 1886 /* Apply property to widget again: */ 1887 XChangeProperty(pDisplay, pWidget->window()->winId(), 1888 net_wm_state, XA_ATOM, 32, PropModeReplace, 1889 (unsigned char*)resultNetWmState.data(), resultNetWmState.size()); 1890 } 1891 } 1892 1893 /* static */ 1894 void UICommon::setSkipTaskBarFlag(QWidget *pWidget) 1895 { 1896 /* Get display: */ 1897 Display *pDisplay = QX11Info::display(); 1898 1899 /* Prepare atoms: */ 1900 QVector<Atom> resultNetWmState = flagsNetWmState(pWidget); 1901 Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */); 1902 Atom net_wm_state_skip_taskbar = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", True /* only if exists */); 1903 1904 /* Append resultNetWmState with skip-taskbar flag if necessary: */ 1905 if (!resultNetWmState.contains(net_wm_state_skip_taskbar)) 1906 { 1907 resultNetWmState.append(net_wm_state_skip_taskbar); 1908 /* Apply property to widget again: */ 1909 XChangeProperty(pDisplay, pWidget->window()->winId(), 1910 net_wm_state, XA_ATOM, 32, PropModeReplace, 1911 (unsigned char*)resultNetWmState.data(), resultNetWmState.size()); 1912 } 1913 } 1914 1915 /* static */ 1916 void UICommon::setSkipPagerFlag(QWidget *pWidget) 1917 { 1918 /* Get display: */ 1919 Display *pDisplay = QX11Info::display(); 1920 1921 /* Prepare atoms: */ 1922 QVector<Atom> resultNetWmState = flagsNetWmState(pWidget); 1923 Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */); 1924 Atom net_wm_state_skip_pager = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_PAGER", True /* only if exists */); 1925 1926 /* Append resultNetWmState with skip-pager flag if necessary: */ 1927 if (!resultNetWmState.contains(net_wm_state_skip_pager)) 1928 { 1929 resultNetWmState.append(net_wm_state_skip_pager); 1930 /* Apply property to widget again: */ 1931 XChangeProperty(pDisplay, pWidget->window()->winId(), 1932 net_wm_state, XA_ATOM, 32, PropModeReplace, 1933 (unsigned char*)resultNetWmState.data(), resultNetWmState.size()); 1934 } 1935 } 1936 1937 /* static */ 1938 void UICommon::setWMClass(QWidget *pWidget, const QString &strNameString, const QString &strClassString) 1939 { 1940 /* Make sure all arguments set: */ 1941 AssertReturnVoid(pWidget && !strNameString.isNull() && !strClassString.isNull()); 1942 1943 /* Define QByteArray objects to make sure data is alive within the scope: */ 1944 QByteArray nameByteArray; 1945 /* Check the existence of RESOURCE_NAME env. variable and override name string if necessary: */ 1946 const char resourceName[] = "RESOURCE_NAME"; 1947 if (qEnvironmentVariableIsSet(resourceName)) 1948 nameByteArray = qgetenv(resourceName); 1949 else 1950 nameByteArray = strNameString.toLatin1(); 1951 QByteArray classByteArray = strClassString.toLatin1(); 1952 1953 AssertReturnVoid(nameByteArray.data() && classByteArray.data()); 1954 1955 XClassHint windowClass; 1956 windowClass.res_name = nameByteArray.data(); 1957 windowClass.res_class = classByteArray.data(); 1958 /* Set WM_CLASS of the window to passed name and class strings: */ 1959 XSetClassHint(QX11Info::display(), pWidget->window()->winId(), &windowClass); 1960 } 1961 1962 /* static */ 1963 void UICommon::setXwaylandMayGrabKeyboardFlag(QWidget *pWidget) 1964 { 1965 XXSendClientMessage(QX11Info::display(), pWidget->window()->winId(), 1966 "_XWAYLAND_MAY_GRAB_KEYBOARD", 1); 1967 } 1968 #endif /* VBOX_WS_X11 */ 1969 1970 /* static */ 1971 void UICommon::setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount) 1972 { 1973 /* Shame on Qt it hasn't stuff for tuning 1974 * widget size suitable for reflecting content of desired size. 1975 * For example QLineEdit, QSpinBox and similar widgets should have a methods 1976 * to strict the minimum width to reflect at least [n] symbols. */ 1977 1978 /* Load options: */ 1979 QStyleOptionSpinBox option; 1980 option.initFrom(pSpinBox); 1981 1982 /* Acquire edit-field rectangle: */ 1983 QRect rect = pSpinBox->style()->subControlRect(QStyle::CC_SpinBox, 1984 &option, 1985 QStyle::SC_SpinBoxEditField, 1986 pSpinBox); 1987 1988 /* Calculate minimum-width magic: */ 1989 const int iSpinBoxWidth = pSpinBox->width(); 1990 const int iSpinBoxEditFieldWidth = rect.width(); 1991 const int iSpinBoxDelta = qMax(0, iSpinBoxWidth - iSpinBoxEditFieldWidth); 1992 QFontMetrics metrics(pSpinBox->font(), pSpinBox); 1993 const QString strDummy(cCount, '0'); 1994 const int iTextWidth = metrics.width(strDummy); 1995 1996 /* Tune spin-box minimum-width: */ 1997 pSpinBox->setMinimumWidth(iTextWidth + iSpinBoxDelta); 1998 } 1999 2000 QString UICommon::vmGuestOSFamilyDescription(const QString &strFamilyId) const 2001 { 2002 AssertMsg(m_guestOSFamilyDescriptions.contains(strFamilyId), 2003 ("Family ID incorrect: '%s'.", strFamilyId.toLatin1().constData())); 2004 return m_guestOSFamilyDescriptions.value(strFamilyId); 2005 } 2006 2007 QList<CGuestOSType> UICommon::vmGuestOSTypeList(const QString &strFamilyId) const 2008 { 2009 AssertMsg(m_guestOSFamilyIDs.contains(strFamilyId), 2010 ("Family ID incorrect: '%s'.", strFamilyId.toLatin1().constData())); 2011 return m_guestOSFamilyIDs.contains(strFamilyId) ? 2012 m_guestOSTypes[m_guestOSFamilyIDs.indexOf(strFamilyId)] : QList<CGuestOSType>(); 2013 } 2014 2015 CGuestOSType UICommon::vmGuestOSType(const QString &strTypeId, 2016 const QString &strFamilyId /* = QString() */) const 2017 { 2018 QList<CGuestOSType> list; 2019 if (m_guestOSFamilyIDs.contains(strFamilyId)) 2020 { 2021 list = m_guestOSTypes.at(m_guestOSFamilyIDs.indexOf(strFamilyId)); 2022 } 2023 else 2024 { 2025 for (int i = 0; i < m_guestOSFamilyIDs.size(); ++i) 2026 list += m_guestOSTypes.at(i); 2027 } 2028 for (int j = 0; j < list.size(); ++j) 2029 if (!list.at(j).GetId().compare(strTypeId)) 2030 return list.at(j); 2031 return CGuestOSType(); 2032 } 2033 2034 QString UICommon::vmGuestOSTypeDescription(const QString &strTypeId) const 2035 { 2036 for (int i = 0; i < m_guestOSFamilyIDs.size(); ++i) 2037 { 2038 QList<CGuestOSType> list(m_guestOSTypes[i]); 2039 for (int j = 0; j < list.size(); ++j) 2040 if (!list.at(j).GetId().compare(strTypeId)) 2041 return list.at(j).GetDescription(); 2042 } 2043 return QString(); 2044 } 2045 2046 /* static */ 2047 bool UICommon::isDOSType(const QString &strOSTypeId) 2048 { 2049 if ( strOSTypeId.left(3) == "dos" 2050 || strOSTypeId.left(3) == "win" 2051 || strOSTypeId.left(3) == "os2") 2052 return true; 2053 2054 return false; 2055 } 2056 2057 /* static */ 2058 bool UICommon::switchToMachine(CMachine &comMachine) 2059 { 2060 #ifdef VBOX_WS_MAC 2061 const ULONG64 id = comMachine.ShowConsoleWindow(); 2062 #else 2063 const WId id = (WId)comMachine.ShowConsoleWindow(); 2064 #endif 2065 AssertWrapperOk(comMachine); 2066 if (!comMachine.isOk()) 2067 return false; 2068 2069 // WORKAROUND: 2070 // id == 0 means the console window has already done everything 2071 // necessary to implement the "show window" semantics. 2072 if (id == 0) 2073 return true; 2074 2075 #if defined(VBOX_WS_WIN) || defined(VBOX_WS_X11) 2076 2077 return activateWindow(id, true); 2078 2079 #elif defined(VBOX_WS_MAC) 2080 2081 // WORKAROUND: 2082 // This is just for the case were the other process cannot steal 2083 // the focus from us. It will send us a PSN so we can try. 2084 ProcessSerialNumber psn; 2085 psn.highLongOfPSN = id >> 32; 2086 psn.lowLongOfPSN = (UInt32)id; 2087 # ifdef __clang__ 2088 # pragma GCC diagnostic push 2089 # pragma GCC diagnostic ignored "-Wdeprecated-declarations" 2090 OSErr rc = ::SetFrontProcess(&psn); 2091 # pragma GCC diagnostic pop 2092 # else 2093 OSErr rc = ::SetFrontProcess(&psn); 2094 # endif 2095 if (!rc) 2096 Log(("GUI: %#RX64 couldn't do SetFrontProcess on itself, the selector (we) had to do it...\n", id)); 2097 else 2098 Log(("GUI: Failed to bring %#RX64 to front. rc=%#x\n", id, rc)); 2099 return !rc; 2100 2101 #else 2102 2103 return false; 2104 2105 #endif 2106 } 2107 2108 bool UICommon::launchMachine(CMachine &comMachine, LaunchMode enmLaunchMode /* = LaunchMode_Default */) 2109 { 2110 /* Switch to machine window(s) if possible: */ 2111 if ( comMachine.GetSessionState() == KSessionState_Locked /* precondition for CanShowConsoleWindow() */ 2112 && comMachine.CanShowConsoleWindow()) 2113 { 2114 switch (uiType()) 2115 { 2116 /* For Selector UI: */ 2117 case UIType_SelectorUI: 2118 { 2119 /* Just switch to existing VM window: */ 2120 return switchToMachine(comMachine); 2121 } 2122 /* For Runtime UI: */ 2123 case UIType_RuntimeUI: 2124 { 2125 /* Only separate UI process can reach that place. 2126 * Switch to existing VM window and exit. */ 2127 switchToMachine(comMachine); 2128 return false; 2129 } 2130 } 2131 } 2132 2133 /* Not for separate UI (which can connect to machine in any state): */ 2134 if (enmLaunchMode != LaunchMode_Separate) 2135 { 2136 /* Make sure machine-state is one of required: */ 2137 const KMachineState enmState = comMachine.GetState(); NOREF(enmState); 2138 AssertMsg( enmState == KMachineState_PoweredOff 2139 || enmState == KMachineState_Saved 2140 || enmState == KMachineState_Teleported 2141 || enmState == KMachineState_Aborted 2142 , ("Machine must be PoweredOff/Saved/Teleported/Aborted (%d)", enmState)); 2143 } 2144 2145 /* Create empty session instance: */ 2146 CSession comSession; 2147 comSession.createInstance(CLSID_Session); 2148 if (comSession.isNull()) 2149 { 2150 msgCenter().cannotOpenSession(comSession); 2151 return false; 2152 } 2153 2154 /* Configure environment: */ 2155 QVector<QString> astrEnv; 2156 #ifdef VBOX_WS_WIN 2157 /* Allow started VM process to be foreground window: */ 2158 AllowSetForegroundWindow(ASFW_ANY); 2159 #endif 2160 #ifdef VBOX_WS_X11 2161 /* Make sure VM process will start on the same 2162 * display as window this wrapper is called from: */ 2163 const char *pDisplay = RTEnvGet("DISPLAY"); 2164 if (pDisplay) 2165 astrEnv.append(QString("DISPLAY=%1").arg(pDisplay)); 2166 const char *pXauth = RTEnvGet("XAUTHORITY"); 2167 if (pXauth) 2168 astrEnv.append(QString("XAUTHORITY=%1").arg(pXauth)); 2169 #endif 2170 QString strType; 2171 switch (enmLaunchMode) 2172 { 2173 case LaunchMode_Default: strType = ""; break; 2174 case LaunchMode_Separate: strType = isSeparateProcess() ? "headless" : "separate"; break; 2175 case LaunchMode_Headless: strType = "headless"; break; 2176 default: AssertFailedReturn(false); 2177 } 2178 2179 /* Prepare "VM spawning" progress: */ 2180 CProgress comProgress = comMachine.LaunchVMProcess(comSession, strType, astrEnv); 2181 if (!comMachine.isOk()) 2182 { 2183 /* If the VM is started separately and the VM process is already running, then it is OK. */ 2184 if (enmLaunchMode == LaunchMode_Separate) 2185 { 2186 const KMachineState enmState = comMachine.GetState(); 2187 if ( enmState >= KMachineState_FirstOnline 2188 && enmState <= KMachineState_LastOnline) 2189 { 2190 /* Already running: */ 2191 return true; 2192 } 2193 } 2194 2195 msgCenter().cannotOpenSession(comMachine); 2196 return false; 2197 } 2198 2199 /* Show "VM spawning" progress: */ 2200 msgCenter().showModalProgressDialog(comProgress, comMachine.GetName(), 2201 ":/progress_start_90px.png", 0, 0); 2202 if (!comProgress.isOk() || comProgress.GetResultCode() != 0) 2203 msgCenter().cannotOpenSession(comProgress, comMachine.GetName()); 2204 2205 /* Unlock machine, close session: */ 2206 comSession.UnlockMachine(); 2207 2208 /* True finally: */ 2209 return true; 2210 } 2211 2212 CSession UICommon::openSession(const QUuid &uId, KLockType lockType /* = KLockType_Shared */) 2213 { 2214 /* Prepare session: */ 2215 CSession comSession; 2216 2217 /* Simulate try-catch block: */ 2218 bool fSuccess = false; 2219 do 2220 { 2221 /* Create empty session instance: */ 2222 comSession.createInstance(CLSID_Session); 2223 if (comSession.isNull()) 2224 { 2225 msgCenter().cannotOpenSession(comSession); 2226 break; 2227 } 2228 2229 /* Search for the corresponding machine: */ 2230 CMachine comMachine = m_comVBox.FindMachine(uId.toString()); 2231 if (comMachine.isNull()) 2232 { 2233 msgCenter().cannotFindMachineById(m_comVBox, uId); 2234 break; 2235 } 2236 2237 if (lockType == KLockType_VM) 2238 comSession.SetName("GUI/Qt"); 2239 2240 /* Lock found machine to session: */ 2241 comMachine.LockMachine(comSession, lockType); 2242 if (!comMachine.isOk()) 2243 { 2244 msgCenter().cannotOpenSession(comMachine); 2245 break; 2246 } 2247 2248 /* Pass the language ID as the property to the guest: */ 2249 if (comSession.GetType() == KSessionType_Shared) 2250 { 2251 CMachine comStartedMachine = comSession.GetMachine(); 2252 /* Make sure that the language is in two letter code. 2253 * Note: if languageId() returns an empty string lang.name() will 2254 * return "C" which is an valid language code. */ 2255 QLocale lang(UITranslator::languageId()); 2256 comStartedMachine.SetGuestPropertyValue("/VirtualBox/HostInfo/GUI/LanguageID", lang.name()); 2257 } 2258 2259 /* Success finally: */ 2260 fSuccess = true; 2261 } 2262 while (0); 2263 /* Cleanup try-catch block: */ 2264 if (!fSuccess) 2265 comSession.detach(); 2266 2267 /* Return session: */ 2268 return comSession; 2269 } 2270 2271 CSession UICommon::tryToOpenSessionFor(CMachine &comMachine) 2272 { 2273 /* Prepare session: */ 2274 CSession comSession; 2275 2276 /* Session state unlocked? */ 2277 if (comMachine.GetSessionState() == KSessionState_Unlocked) 2278 { 2279 /* Open own 'write' session: */ 2280 comSession = openSession(comMachine.GetId()); 2281 AssertReturn(!comSession.isNull(), CSession()); 2282 comMachine = comSession.GetMachine(); 2283 } 2284 /* Is this a Selector UI call? */ 2285 else if (uiType() == UIType_SelectorUI) 2286 { 2287 /* Open existing 'shared' session: */ 2288 comSession = openExistingSession(comMachine.GetId()); 2289 AssertReturn(!comSession.isNull(), CSession()); 2290 comMachine = comSession.GetMachine(); 2291 } 2292 /* Else this is Runtime UI call 2293 * which has session locked for itself. */ 2294 2295 /* Return session: */ 2296 return comSession; 2297 } 2298 2299 void UICommon::notifyCloudMachineUnregistered(const QString &strProviderShortName, 2300 const QString &strProfileName, 2301 const QUuid &uId) 2302 { 2303 emit sigCloudMachineUnregistered(strProviderShortName, strProfileName, uId); 2304 } 2305 2306 void UICommon::notifyCloudMachineRegistered(const QString &strProviderShortName, 2307 const QString &strProfileName, 2308 const CCloudMachine &comMachine) 2309 { 2310 emit sigCloudMachineRegistered(strProviderShortName, strProfileName, comMachine); 2311 } 2312 2313 void UICommon::enumerateMedia(const CMediumVector &comMedia /* = CMediumVector() */) 2314 { 2315 /* Make sure UICommon is already valid: */ 2316 AssertReturnVoid(m_fValid); 2317 /* Ignore the request during UICommon cleanup: */ 2318 if (m_fCleaningUp) 2319 return; 2320 /* Ignore the request during startup snapshot restoring: */ 2321 if (shouldRestoreCurrentSnapshot()) 2322 return; 2323 2324 /* Make sure medium-enumerator is already created: */ 2325 if (!m_pMediumEnumerator) 2326 return; 2327 2328 /* Redirect request to medium-enumerator under proper lock: */ 2329 if (m_meCleanupProtectionToken.tryLockForRead()) 2330 { 2331 if (m_pMediumEnumerator) 2332 m_pMediumEnumerator->enumerateMedia(comMedia); 2333 m_meCleanupProtectionToken.unlock(); 2334 } 2335 } 2336 2337 void UICommon::refreshMedia() 2338 { 2339 /* Make sure UICommon is already valid: */ 2340 AssertReturnVoid(m_fValid); 2341 /* Ignore the request during UICommon cleanup: */ 2342 if (m_fCleaningUp) 2343 return; 2344 /* Ignore the request during startup snapshot restoring: */ 2345 if (shouldRestoreCurrentSnapshot()) 2346 return; 2347 2348 /* Make sure medium-enumerator is already created: */ 2349 if (!m_pMediumEnumerator) 2350 return; 2351 /* Make sure enumeration is not already started: */ 2352 if (m_pMediumEnumerator->isMediumEnumerationInProgress()) 2353 return; 2354 2355 /* We assume it's safe to call it without locking, 2356 * since we are performing blocking operation here. */ 2357 m_pMediumEnumerator->refreshMedia(); 2358 } 2359 2360 bool UICommon::isFullMediumEnumerationRequested() const 2361 { 2362 /* Redirect request to medium-enumerator: */ 2363 return m_pMediumEnumerator 2364 && m_pMediumEnumerator->isFullMediumEnumerationRequested(); 2365 } 2366 2367 bool UICommon::isMediumEnumerationInProgress() const 2368 { 2369 /* Redirect request to medium-enumerator: */ 2370 return m_pMediumEnumerator 2371 && m_pMediumEnumerator->isMediumEnumerationInProgress(); 2372 } 2373 2374 UIMedium UICommon::medium(const QUuid &uMediumID) const 2375 { 2376 if (m_meCleanupProtectionToken.tryLockForRead()) 2377 { 2378 /* Redirect call to medium-enumerator: */ 2379 UIMedium guiMedium; 2380 if (m_pMediumEnumerator) 2381 guiMedium = m_pMediumEnumerator->medium(uMediumID); 2382 m_meCleanupProtectionToken.unlock(); 2383 return guiMedium; 2384 } 2385 return UIMedium(); 2386 } 2387 2388 QList<QUuid> UICommon::mediumIDs() const 2389 { 2390 if (m_meCleanupProtectionToken.tryLockForRead()) 2391 { 2392 /* Redirect call to medium-enumerator: */ 2393 QList<QUuid> listOfMedia; 2394 if (m_pMediumEnumerator) 2395 listOfMedia = m_pMediumEnumerator->mediumIDs(); 2396 m_meCleanupProtectionToken.unlock(); 2397 return listOfMedia; 2398 } 2399 return QList<QUuid>(); 2400 } 2401 2402 void UICommon::createMedium(const UIMedium &guiMedium) 2403 { 2404 if (m_meCleanupProtectionToken.tryLockForRead()) 2405 { 2406 /* Create medium in medium-enumerator: */ 2407 if (m_pMediumEnumerator) 2408 m_pMediumEnumerator->createMedium(guiMedium); 2409 m_meCleanupProtectionToken.unlock(); 2410 } 2411 } 2412 2413 QUuid UICommon::openMedium(UIMediumDeviceType enmMediumType, QString strMediumLocation, QWidget *pParent /* = 0 */) 2414 { 2415 /* Convert to native separators: */ 2416 strMediumLocation = QDir::toNativeSeparators(strMediumLocation); 2417 2418 /* Initialize variables: */ 2419 CVirtualBox comVBox = virtualBox(); 2420 2421 /* Open corresponding medium: */ 2422 CMedium comMedium = comVBox.OpenMedium(strMediumLocation, mediumTypeToGlobal(enmMediumType), KAccessMode_ReadWrite, false); 2423 2424 if (comVBox.isOk()) 2425 { 2426 /* Prepare vbox medium wrapper: */ 2427 UIMedium guiMedium = medium(comMedium.GetId()); 2428 2429 /* First of all we should test if that medium already opened: */ 2430 if (guiMedium.isNull()) 2431 { 2432 /* And create new otherwise: */ 2433 guiMedium = UIMedium(comMedium, enmMediumType, KMediumState_Created); 2434 createMedium(guiMedium); 2435 } 2436 2437 /* Return guiMedium id: */ 2438 return guiMedium.id(); 2439 } 2440 else 2441 msgCenter().cannotOpenMedium(comVBox, strMediumLocation, pParent); 2442 2443 return QUuid(); 2444 } 2445 2446 QUuid UICommon::openMediumWithFileOpenDialog(UIMediumDeviceType enmMediumType, QWidget *pParent, 2447 const QString &strDefaultFolder /* = QString() */, 2448 bool fUseLastFolder /* = false */) 2449 { 2450 /* Initialize variables: */ 2451 QList<QPair <QString, QString> > filters; 2452 QStringList backends; 2453 QStringList prefixes; 2454 QString strFilter; 2455 QString strTitle; 2456 QString allType; 2457 QString strLastFolder = defaultFolderPathForType(enmMediumType); 2458 2459 /* For DVDs and Floppies always check first the last recently used medium folder. For hard disk use 2460 the caller's setting: */ 2461 fUseLastFolder = (enmMediumType == UIMediumDeviceType_DVD) || (enmMediumType == UIMediumDeviceType_Floppy); 2462 2463 switch (enmMediumType) 2464 { 2465 case UIMediumDeviceType_HardDisk: 2466 { 2467 filters = HDDBackends(virtualBox()); 2468 strTitle = tr("Please choose a virtual hard disk file"); 2469 allType = tr("All virtual hard disk files (%1)"); 2470 break; 2471 } 2472 case UIMediumDeviceType_DVD: 2473 { 2474 filters = DVDBackends(virtualBox()); 2475 strTitle = tr("Please choose a virtual optical disk file"); 2476 allType = tr("All virtual optical disk files (%1)"); 2477 break; 2478 } 2479 case UIMediumDeviceType_Floppy: 2480 { 2481 filters = FloppyBackends(virtualBox()); 2482 strTitle = tr("Please choose a virtual floppy disk file"); 2483 allType = tr("All virtual floppy disk files (%1)"); 2484 break; 2485 } 2486 default: 2487 break; 2488 } 2489 QString strHomeFolder = fUseLastFolder && !strLastFolder.isEmpty() ? strLastFolder : 2490 strDefaultFolder.isEmpty() ? homeFolder() : strDefaultFolder; 2491 2492 /* Prepare filters and backends: */ 2493 for (int i = 0; i < filters.count(); ++i) 2494 { 2495 /* Get iterated filter: */ 2496 QPair<QString, QString> item = filters.at(i); 2497 /* Create one backend filter string: */ 2498 backends << QString("%1 (%2)").arg(item.first).arg(item.second); 2499 /* Save the suffix's for the "All" entry: */ 2500 prefixes << item.second; 2501 } 2502 if (!prefixes.isEmpty()) 2503 backends.insert(0, allType.arg(prefixes.join(" ").trimmed())); 2504 backends << tr("All files (*)"); 2505 strFilter = backends.join(";;").trimmed(); 2506 2507 /* Create open file dialog: */ 2508 QStringList files = QIFileDialog::getOpenFileNames(strHomeFolder, strFilter, pParent, strTitle, 0, true, true); 2509 2510 /* If dialog has some result: */ 2511 if (!files.empty() && !files[0].isEmpty()) 2512 { 2513 QUuid uMediumId = openMedium(enmMediumType, files[0], pParent); 2514 if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy || 2515 (enmMediumType == UIMediumDeviceType_HardDisk && fUseLastFolder)) 2516 updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(uMediumId).location()); 2517 return uMediumId; 2518 } 2519 return QUuid(); 2520 } 2521 2522 2523 /** 2524 * Helper for createVisoMediumWithVisoCreator. 2525 * @returns IPRT status code. 2526 * @param pStrmDst Where to write the quoted string. 2527 * @param pszPrefix Stuff to put in front of it. 2528 * @param rStr The string to quote and write out. 2529 * @param pszPrefix Stuff to put after it. 2530 */ 2531 DECLINLINE(int) visoWriteQuotedString(PRTSTREAM pStrmDst, const char *pszPrefix, QString const &rStr, const char *pszPostFix) 2532 { 2533 QByteArray const utf8Array = rStr.toUtf8(); 2534 const char *apszArgv[2] = { utf8Array.constData(), NULL }; 2535 char *pszQuoted; 2536 int vrc = RTGetOptArgvToString(&pszQuoted, apszArgv, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH); 2537 if (RT_SUCCESS(vrc)) 2538 { 2539 if (pszPrefix) 2540 vrc = RTStrmPutStr(pStrmDst, pszPrefix); 2541 if (RT_SUCCESS(vrc)) 2542 { 2543 vrc = RTStrmPutStr(pStrmDst, pszQuoted); 2544 if (pszPostFix && RT_SUCCESS(vrc)) 2545 vrc = RTStrmPutStr(pStrmDst, pszPostFix); 2546 } 2547 RTStrFree(pszQuoted); 2548 } 2549 2550 return vrc; 2551 } 2552 2553 2554 void UICommon::openMediumCreatorDialog(QWidget *pParent, UIMediumDeviceType enmMediumType, 2555 const QString &strDefaultFolder /* = QString() */, 2556 const QString &strMachineName /* = QString() */, 2557 const QString &strMachineGuestOSTypeId /*= QString() */) 2558 { 2559 /* Depending on medium-type: */ 2560 QUuid uMediumId; 2561 switch (enmMediumType) 2562 { 2563 case UIMediumDeviceType_HardDisk: 2564 createVDWithWizard(pParent, strDefaultFolder, strMachineName, strMachineGuestOSTypeId); 2565 break; 2566 case UIMediumDeviceType_DVD: 2567 uMediumId = createVisoMediumWithVisoCreator(pParent, strDefaultFolder, strMachineName); 2568 break; 2569 case UIMediumDeviceType_Floppy: 2570 uMediumId = showCreateFloppyDiskDialog(pParent, strDefaultFolder, strMachineName); 2571 break; 2572 default: 2573 break; 2574 } 2575 if (uMediumId.isNull()) 2576 return; 2577 2578 /* Update the recent medium list only if the medium type is DVD or floppy: */ 2579 if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy) 2580 updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(uMediumId).location()); 2581 } 2582 2583 QUuid UICommon::createVisoMediumWithVisoCreator(QWidget *pParent, const QString &strDefaultFolder /* = QString */, 2584 const QString &strMachineName /* = QString */) 2585 { 2586 QString strVisoSaveFolder(strDefaultFolder); 2587 if (strVisoSaveFolder.isEmpty()) 2588 strVisoSaveFolder = defaultFolderPathForType(UIMediumDeviceType_DVD); 2589 2590 QWidget *pDialogParent = windowManager().realParentWindow(pParent); 2591 UIVisoCreator *pVisoCreator = new UIVisoCreator(pDialogParent, strMachineName); 2592 2593 if (!pVisoCreator) 2594 return QString(); 2595 windowManager().registerNewParent(pVisoCreator, pDialogParent); 2596 pVisoCreator->setCurrentPath(gEDataManager->visoCreatorRecentFolder()); 2597 2598 if (pVisoCreator->exec(false /* not application modal */)) 2599 { 2600 QStringList files = pVisoCreator->entryList(); 2601 QString strVisoName = pVisoCreator->visoName(); 2602 if (strVisoName.isEmpty()) 2603 strVisoName = strMachineName; 2604 2605 if (files.empty() || files[0].isEmpty()) 2606 { 2607 delete pVisoCreator; 2608 return QUuid(); 2609 } 2610 2611 gEDataManager->setVISOCreatorRecentFolder(pVisoCreator->currentPath()); 2612 2613 /* Produce the VISO. */ 2614 char szVisoPath[RTPATH_MAX]; 2615 QString strFileName = QString("%1%2").arg(strVisoName).arg(".viso"); 2616 int vrc = RTPathJoin(szVisoPath, sizeof(szVisoPath), strVisoSaveFolder.toUtf8().constData(), strFileName.toUtf8().constData()); 2617 if (RT_SUCCESS(vrc)) 2618 { 2619 PRTSTREAM pStrmViso; 2620 vrc = RTStrmOpen(szVisoPath, "w", &pStrmViso); 2621 if (RT_SUCCESS(vrc)) 2622 { 2623 RTUUID Uuid; 2624 vrc = RTUuidCreate(&Uuid); 2625 if (RT_SUCCESS(vrc)) 2626 { 2627 RTStrmPrintf(pStrmViso, "--iprt-iso-maker-file-marker-bourne-sh %RTuuid\n", &Uuid); 2628 vrc = visoWriteQuotedString(pStrmViso, "--volume-id=", strVisoName, "\n"); 2629 2630 for (int iFile = 0; iFile < files.size() && RT_SUCCESS(vrc); iFile++) 2631 vrc = visoWriteQuotedString(pStrmViso, NULL, files[iFile], "\n"); 2632 2633 /* Append custom options if any to the file: */ 2634 const QStringList &customOptions = pVisoCreator->customOptions(); 2635 foreach (QString strLine, customOptions) 2636 RTStrmPrintf(pStrmViso, "%s\n", strLine.toUtf8().constData()); 2637 2638 RTStrmFlush(pStrmViso); 2639 if (RT_SUCCESS(vrc)) 2640 vrc = RTStrmError(pStrmViso); 2641 } 2642 2643 RTStrmClose(pStrmViso); 2644 } 2645 } 2646 2647 /* Done. */ 2648 if (RT_SUCCESS(vrc)) 2649 { 2650 delete pVisoCreator; 2651 return openMedium(UIMediumDeviceType_DVD, QString(szVisoPath), pParent); 2652 } 2653 /** @todo error message. */ 2654 else 2655 { 2656 delete pVisoCreator; 2657 return QUuid(); 2658 } 2659 } 2660 delete pVisoCreator; 2661 return QUuid(); 2662 } 2663 2664 QUuid UICommon::showCreateFloppyDiskDialog(QWidget *pParent, const QString &strDefaultFolder /* QString() */, 2665 const QString &strMachineName /* = QString() */ ) 2666 { 2667 QString strStartPath(strDefaultFolder); 2668 2669 if (strStartPath.isEmpty()) 2670 strStartPath = defaultFolderPathForType(UIMediumDeviceType_Floppy); 2671 2672 QWidget *pDialogParent = windowManager().realParentWindow(pParent); 2673 2674 UIFDCreationDialog *pDialog = new UIFDCreationDialog(pParent, strStartPath, strMachineName); 2675 if (!pDialog) 2676 return QUuid(); 2677 windowManager().registerNewParent(pDialog, pDialogParent); 2678 2679 if (pDialog->exec()) 2680 { 2681 QUuid uMediumID = pDialog->mediumID(); 2682 delete pDialog; 2683 return uMediumID; 2684 } 2685 delete pDialog; 2686 return QUuid(); 2687 } 2688 2689 int UICommon::openMediumSelectorDialog(QWidget *pParent, UIMediumDeviceType enmMediumType, QUuid &outUuid, 2690 const QString &strMachineFolder, const QString &strMachineName, 2691 const QString &strMachineGuestOSTypeId, bool fEnableCreate, const QUuid &uMachineID /* = QUuid() */) 2692 { 2693 QUuid uMachineOrGlobalId = uMachineID == QUuid() ? gEDataManager->GlobalID : uMachineID; 2694 2695 QWidget *pDialogParent = windowManager().realParentWindow(pParent); 2696 QPointer<UIMediumSelector> pSelector = new UIMediumSelector(enmMediumType, strMachineName, 2697 strMachineFolder, strMachineGuestOSTypeId, 2698 uMachineOrGlobalId, pDialogParent); 2699 2700 if (!pSelector) 2701 return static_cast<int>(UIMediumSelector::ReturnCode_Rejected); 2702 pSelector->setEnableCreateAction(fEnableCreate); 2703 windowManager().registerNewParent(pSelector, pDialogParent); 2704 2705 int iResult = pSelector->exec(false); 2706 UIMediumSelector::ReturnCode returnCode; 2707 2708 if (iResult >= static_cast<int>(UIMediumSelector::ReturnCode_Max) || iResult < 0) 2709 returnCode = UIMediumSelector::ReturnCode_Rejected; 2710 else 2711 returnCode = static_cast<UIMediumSelector::ReturnCode>(iResult); 2712 2713 if (returnCode == UIMediumSelector::ReturnCode_Accepted) 2714 { 2715 QList<QUuid> selectedMediumIds = pSelector->selectedMediumIds(); 2716 2717 /* Currently we only care about the 0th since we support single selection by intention: */ 2718 if (selectedMediumIds.isEmpty()) 2719 returnCode = UIMediumSelector::ReturnCode_Rejected; 2720 else 2721 { 2722 outUuid = selectedMediumIds[0]; 2723 updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(outUuid).location()); 2724 } 2725 } 2726 delete pSelector; 2727 return static_cast<int>(returnCode); 2728 } 2729 2730 void UICommon::createVDWithWizard(QWidget *pParent, 2731 const QString &strMachineFolder /* = QString() */, 2732 const QString &strMachineName /* = QString() */, 2733 const QString &strMachineGuestOSTypeId /* = QString() */) 2734 { 2735 /* Initialize variables: */ 2736 QString strDefaultFolder = strMachineFolder; 2737 if (strDefaultFolder.isEmpty()) 2738 strDefaultFolder = defaultFolderPathForType(UIMediumDeviceType_HardDisk); 2739 2740 /* In case we dont have a 'guest os type id' default back to 'Other': */ 2741 const CGuestOSType comGuestOSType = virtualBox().GetGuestOSType( !strMachineGuestOSTypeId.isEmpty() 2742 ? strMachineGuestOSTypeId 2743 : "Other"); 2744 const QString strDiskName = findUniqueFileName(strDefaultFolder, !strMachineName.isEmpty() 2745 ? strMachineName 2746 : "NewVirtualDisk"); 2747 2748 /* Show New VD wizard: */ 2749 UISafePointerWizardNewVD pWizard = new UIWizardNewVD(pParent, 2750 strDiskName, 2751 strDefaultFolder, 2752 comGuestOSType.GetRecommendedHDD()); 2753 if (!pWizard) 2754 return; 2755 QWidget *pDialogParent = windowManager().realParentWindow(pParent); 2756 windowManager().registerNewParent(pWizard, pDialogParent); 2757 pWizard->exec(); 2758 delete pWizard; 2759 } 2760 2761 void UICommon::prepareStorageMenu(QMenu &menu, 2762 QObject *pListener, const char *pszSlotName, 2763 const CMachine &comMachine, const QString &strControllerName, const StorageSlot &storageSlot) 2764 { 2765 /* Current attachment attributes: */ 2766 const CMediumAttachment comCurrentAttachment = comMachine.GetMediumAttachment(strControllerName, 2767 storageSlot.port, 2768 storageSlot.device); 2769 const CMedium comCurrentMedium = comCurrentAttachment.GetMedium(); 2770 const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId(); 2771 const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation(); 2772 2773 /* Other medium-attachments of same machine: */ 2774 const CMediumAttachmentVector comAttachments = comMachine.GetMediumAttachments(); 2775 2776 /* Determine device & medium types: */ 2777 const UIMediumDeviceType enmMediumType = mediumTypeToLocal(comCurrentAttachment.GetType()); 2778 AssertMsgReturnVoid(enmMediumType != UIMediumDeviceType_Invalid, ("Incorrect storage medium type!\n")); 2779 2780 /* Prepare open-existing-medium action: */ 2781 QAction *pActionOpenExistingMedium = menu.addAction(UIIconPool::iconSet(":/select_file_16px.png"), 2782 QString(), pListener, pszSlotName); 2783 pActionOpenExistingMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(), 2784 comCurrentAttachment.GetDevice(), enmMediumType))); 2785 pActionOpenExistingMedium->setText(QApplication::translate("UIMachineSettingsStorage", "Choose/Create a disk image...")); 2786 2787 2788 /* Prepare open medium file action: */ 2789 QAction *pActionFileSelector = menu.addAction(UIIconPool::iconSet(":/select_file_16px.png"), 2790 QString(), pListener, pszSlotName); 2791 pActionFileSelector->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(), 2792 comCurrentAttachment.GetDevice(), enmMediumType, 2793 UIMediumTarget::UIMediumTargetType_WithFileDialog))); 2794 pActionFileSelector->setText(QApplication::translate("UIMachineSettingsStorage", "Choose a disk file...")); 2795 2796 2797 /* Insert separator: */ 2798 menu.addSeparator(); 2799 2800 /* Get existing-host-drive vector: */ 2801 CMediumVector comMedia; 2802 switch (enmMediumType) 2803 { 2804 case UIMediumDeviceType_DVD: comMedia = host().GetDVDDrives(); break; 2805 case UIMediumDeviceType_Floppy: comMedia = host().GetFloppyDrives(); break; 2806 default: break; 2807 } 2808 /* Prepare choose-existing-host-drive actions: */ 2809 foreach (const CMedium &comMedium, comMedia) 2810 { 2811 /* Make sure host-drive usage is unique: */ 2812 bool fIsHostDriveUsed = false; 2813 foreach (const CMediumAttachment &comOtherAttachment, comAttachments) 2814 { 2815 if (comOtherAttachment != comCurrentAttachment) 2816 { 2817 const CMedium &comOtherMedium = comOtherAttachment.GetMedium(); 2818 if (!comOtherMedium.isNull() && comOtherMedium.GetId() == comMedium.GetId()) 2819 { 2820 fIsHostDriveUsed = true; 2821 break; 2822 } 2823 } 2824 } 2825 /* If host-drives usage is unique: */ 2826 if (!fIsHostDriveUsed) 2827 { 2828 QAction *pActionChooseHostDrive = menu.addAction(UIMedium(comMedium, enmMediumType).name(), pListener, pszSlotName); 2829 pActionChooseHostDrive->setCheckable(true); 2830 pActionChooseHostDrive->setChecked(!comCurrentMedium.isNull() && comMedium.GetId() == uCurrentID); 2831 pActionChooseHostDrive->setData(QVariant::fromValue(UIMediumTarget(strControllerName, 2832 comCurrentAttachment.GetPort(), 2833 comCurrentAttachment.GetDevice(), 2834 enmMediumType, 2835 UIMediumTarget::UIMediumTargetType_WithID, 2836 comMedium.GetId().toString()))); 2837 } 2838 } 2839 2840 /* Get recent-medium list: */ 2841 QStringList recentMediumList; 2842 QStringList recentMediumListUsed; 2843 switch (enmMediumType) 2844 { 2845 case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break; 2846 case UIMediumDeviceType_DVD: recentMediumList = gEDataManager->recentListOfOpticalDisks(); break; 2847 case UIMediumDeviceType_Floppy: recentMediumList = gEDataManager->recentListOfFloppyDisks(); break; 2848 default: break; 2849 } 2850 /* Prepare choose-recent-medium actions: */ 2851 foreach (const QString &strRecentMediumLocationBase, recentMediumList) 2852 { 2853 /* Confirm medium uniqueness: */ 2854 if (recentMediumListUsed.contains(strRecentMediumLocationBase)) 2855 continue; 2856 /* Mark medium as known: */ 2857 recentMediumListUsed << strRecentMediumLocationBase; 2858 /* Convert separators to native: */ 2859 const QString strRecentMediumLocation = QDir::toNativeSeparators(strRecentMediumLocationBase); 2860 /* Confirm medium presence: */ 2861 if (!QFile::exists(strRecentMediumLocation)) 2862 continue; 2863 /* Make sure recent-medium usage is unique: */ 2864 bool fIsRecentMediumUsed = false; 2865 if (enmMediumType != UIMediumDeviceType_DVD) 2866 foreach (const CMediumAttachment &otherAttachment, comAttachments) 2867 { 2868 if (otherAttachment != comCurrentAttachment) 2869 { 2870 const CMedium &comOtherMedium = otherAttachment.GetMedium(); 2871 if (!comOtherMedium.isNull() && comOtherMedium.GetLocation() == strRecentMediumLocation) 2872 { 2873 fIsRecentMediumUsed = true; 2874 break; 2875 } 2876 } 2877 } 2878 /* If recent-medium usage is unique: */ 2879 if (!fIsRecentMediumUsed) 2880 { 2881 QAction *pActionChooseRecentMedium = menu.addAction(QFileInfo(strRecentMediumLocation).fileName(), 2882 pListener, pszSlotName); 2883 pActionChooseRecentMedium->setCheckable(true); 2884 pActionChooseRecentMedium->setChecked(!comCurrentMedium.isNull() && strRecentMediumLocation == strCurrentLocation); 2885 pActionChooseRecentMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, 2886 comCurrentAttachment.GetPort(), 2887 comCurrentAttachment.GetDevice(), 2888 enmMediumType, 2889 UIMediumTarget::UIMediumTargetType_WithLocation, 2890 strRecentMediumLocation))); 2891 pActionChooseRecentMedium->setToolTip(strRecentMediumLocation); 2892 } 2893 } 2894 2895 /* Last action for optical/floppy attachments only: */ 2896 if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy) 2897 { 2898 /* Insert separator: */ 2899 menu.addSeparator(); 2900 2901 /* Prepare unmount-current-medium action: */ 2902 QAction *pActionUnmountMedium = menu.addAction(QString(), pListener, pszSlotName); 2903 pActionUnmountMedium->setEnabled(!comCurrentMedium.isNull()); 2904 pActionUnmountMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(), 2905 comCurrentAttachment.GetDevice()))); 2906 pActionUnmountMedium->setText(QApplication::translate("UIMachineSettingsStorage", "Remove disk from virtual drive")); 2907 if (enmMediumType == UIMediumDeviceType_DVD) 2908 pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/cd_unmount_16px.png", ":/cd_unmount_disabled_16px.png")); 2909 else if (enmMediumType == UIMediumDeviceType_Floppy) 2910 pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/fd_unmount_16px.png", ":/fd_unmount_disabled_16px.png")); 2911 } 2912 } 2913 2914 void UICommon::updateMachineStorage(const CMachine &comConstMachine, const UIMediumTarget &target) 2915 { 2916 /* Mount (by default): */ 2917 bool fMount = true; 2918 /* Null medium (by default): */ 2919 CMedium comMedium; 2920 /* With null ID (by default): */ 2921 QUuid uActualID; 2922 2923 /* Current mount-target attributes: */ 2924 const CStorageController comCurrentController = comConstMachine.GetStorageControllerByName(target.name); 2925 const KStorageBus enmCurrentStorageBus = comCurrentController.GetBus(); 2926 const CMediumAttachment comCurrentAttachment = comConstMachine.GetMediumAttachment(target.name, target.port, target.device); 2927 const CMedium comCurrentMedium = comCurrentAttachment.GetMedium(); 2928 const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId(); 2929 const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation(); 2930 2931 /* Which additional info do we have? */ 2932 switch (target.type) 2933 { 2934 /* Do we have an exact ID or do we let the user open a medium? */ 2935 case UIMediumTarget::UIMediumTargetType_WithID: 2936 case UIMediumTarget::UIMediumTargetType_WithFileDialog: 2937 case UIMediumTarget::UIMediumTargetType_CreateAdHocVISO: 2938 case UIMediumTarget::UIMediumTargetType_CreateFloppyDisk: 2939 { 2940 /* New mount-target attributes: */ 2941 QUuid uNewID; 2942 2943 /* Invoke file-open dialog to choose medium ID: */ 2944 if (target.mediumType != UIMediumDeviceType_Invalid && target.data.isNull()) 2945 { 2946 /* Keyboard can be captured by machine-view. 2947 * So we should clear machine-view focus to let file-open dialog get it. 2948 * That way the keyboard will be released too.. */ 2949 QWidget *pLastFocusedWidget = 0; 2950 if (QApplication::focusWidget()) 2951 { 2952 pLastFocusedWidget = QApplication::focusWidget(); 2953 pLastFocusedWidget->clearFocus(); 2954 } 2955 /* Call for file-open dialog: */ 2956 const QString strMachineFolder(QFileInfo(comConstMachine.GetSettingsFilePath()).absolutePath()); 2957 QUuid uMediumID; 2958 if (target.type == UIMediumTarget::UIMediumTargetType_WithID) 2959 { 2960 int iDialogReturn = openMediumSelectorDialog(windowManager().mainWindowShown(), target.mediumType, uMediumID, 2961 strMachineFolder, comConstMachine.GetName(), 2962 comConstMachine.GetOSTypeId(), true /*fEnableCreate */, comConstMachine.GetId()); 2963 if (iDialogReturn == UIMediumSelector::ReturnCode_LeftEmpty && 2964 (target.mediumType == UIMediumDeviceType_DVD || target.mediumType == UIMediumDeviceType_Floppy)) 2965 fMount = false; 2966 } 2967 else if (target.type == UIMediumTarget::UIMediumTargetType_WithFileDialog) 2968 { 2969 uMediumID = openMediumWithFileOpenDialog(target.mediumType, windowManager().mainWindowShown(), 2970 strMachineFolder, false /* fUseLastFolder */); 2971 } 2972 else if(target.type == UIMediumTarget::UIMediumTargetType_CreateAdHocVISO) 2973 uMediumID = createVisoMediumWithVisoCreator(windowManager().mainWindowShown(), strMachineFolder, comConstMachine.GetName()); 2974 2975 else if(target.type == UIMediumTarget::UIMediumTargetType_CreateFloppyDisk) 2976 uMediumID = showCreateFloppyDiskDialog(windowManager().mainWindowShown(), strMachineFolder, comConstMachine.GetName()); 2977 2978 /* Return focus back: */ 2979 if (pLastFocusedWidget) 2980 pLastFocusedWidget->setFocus(); 2981 /* Accept new medium ID: */ 2982 if (!uMediumID.isNull()) 2983 uNewID = uMediumID; 2984 else 2985 /* Else just exit in case left empty is not chosen in medium selector dialog: */ 2986 if (fMount) 2987 return; 2988 } 2989 /* Use medium ID which was passed: */ 2990 else if (!target.data.isNull() && target.data != uCurrentID.toString()) 2991 uNewID = target.data; 2992 2993 /* Should we mount or unmount? */ 2994 fMount = !uNewID.isNull(); 2995 2996 /* Prepare target medium: */ 2997 const UIMedium guiMedium = medium(uNewID); 2998 comMedium = guiMedium.medium(); 2999 uActualID = fMount ? uNewID : uCurrentID; 3000 break; 3001 } 3002 /* Do we have a recent location? */ 3003 case UIMediumTarget::UIMediumTargetType_WithLocation: 3004 { 3005 /* Open medium by location and get new medium ID if any: */ 3006 const QUuid uNewID = openMedium(target.mediumType, target.data); 3007 /* Else just exit: */ 3008 if (uNewID.isNull()) 3009 return; 3010 3011 /* Should we mount or unmount? */ 3012 fMount = uNewID != uCurrentID; 3013 3014 /* Prepare target medium: */ 3015 const UIMedium guiMedium = fMount ? medium(uNewID) : UIMedium(); 3016 comMedium = fMount ? guiMedium.medium() : CMedium(); 3017 uActualID = fMount ? uNewID : uCurrentID; 3018 break; 3019 } 3020 } 3021 3022 /* Do not unmount hard-drives: */ 3023 if (target.mediumType == UIMediumDeviceType_HardDisk && !fMount) 3024 return; 3025 3026 /* Get editable machine & session: */ 3027 CMachine comMachine = comConstMachine; 3028 CSession comSession = tryToOpenSessionFor(comMachine); 3029 3030 /* Remount medium to the predefined port/device: */ 3031 bool fWasMounted = false; 3032 /* Hard drive case: */ 3033 if (target.mediumType == UIMediumDeviceType_HardDisk) 3034 { 3035 /* Detaching: */ 3036 comMachine.DetachDevice(target.name, target.port, target.device); 3037 fWasMounted = comMachine.isOk(); 3038 if (!fWasMounted) 3039 msgCenter().cannotDetachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation, 3040 StorageSlot(enmCurrentStorageBus, target.port, target.device)); 3041 else 3042 { 3043 /* Attaching: */ 3044 comMachine.AttachDevice(target.name, target.port, target.device, KDeviceType_HardDisk, comMedium); 3045 fWasMounted = comMachine.isOk(); 3046 if (!fWasMounted) 3047 msgCenter().cannotAttachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation, 3048 StorageSlot(enmCurrentStorageBus, target.port, target.device)); 3049 } 3050 } 3051 /* Optical/floppy drive case: */ 3052 else 3053 { 3054 /* Remounting: */ 3055 comMachine.MountMedium(target.name, target.port, target.device, comMedium, false /* force? */); 3056 fWasMounted = comMachine.isOk(); 3057 if (!fWasMounted) 3058 { 3059 /* Ask for force remounting: */ 3060 if (msgCenter().cannotRemountMedium(comMachine, medium(uActualID), 3061 fMount, true /* retry? */)) 3062 { 3063 /* Force remounting: */ 3064 comMachine.MountMedium(target.name, target.port, target.device, comMedium, true /* force? */); 3065 fWasMounted = comMachine.isOk(); 3066 if (!fWasMounted) 3067 msgCenter().cannotRemountMedium(comMachine, medium(uActualID), 3068 fMount, false /* retry? */); 3069 } 3070 } 3071 /* If mounting was successful: */ 3072 if (fWasMounted) 3073 { 3074 /* Disable First RUN Wizard: */ 3075 if (gEDataManager->machineFirstTimeStarted(comMachine.GetId())) 3076 gEDataManager->setMachineFirstTimeStarted(false, comMachine.GetId()); 3077 } 3078 } 3079 3080 /* Save settings: */ 3081 if (fWasMounted) 3082 { 3083 comMachine.SaveSettings(); 3084 if (!comMachine.isOk()) 3085 msgCenter().cannotSaveMachineSettings(comMachine, windowManager().mainWindowShown()); 3086 } 3087 3088 /* Close session to editable comMachine if necessary: */ 3089 if (!comSession.isNull()) 3090 comSession.UnlockMachine(); 3091 } 3092 3093 QString UICommon::details(const CMedium &comMedium, bool fPredictDiff, bool fUseHtml /* = true */) 3094 { 3095 /* Search for corresponding UI medium: */ 3096 const QUuid uMediumID = comMedium.isNull() ? UIMedium::nullID() : comMedium.GetId(); 3097 UIMedium guiMedium = medium(uMediumID); 3098 if (!comMedium.isNull() && guiMedium.isNull()) 3099 { 3100 /* UI medium may be new and not among cached media, request enumeration: */ 3101 enumerateMedia(CMediumVector() << comMedium); 3102 3103 /* Search for corresponding UI medium again: */ 3104 guiMedium = medium(uMediumID); 3105 if (guiMedium.isNull()) 3106 { 3107 /* Medium might be deleted already, return null string: */ 3108 return QString(); 3109 } 3110 } 3111 3112 /* For differencing hard-disk we have to request 3113 * enumeration of whole tree based in it's root item: */ 3114 if ( comMedium.isNotNull() 3115 && comMedium.GetDeviceType() == KDeviceType_HardDisk) 3116 { 3117 /* Traverse through parents to root to catch it: */ 3118 CMedium comRootMedium; 3119 CMedium comParentMedium = comMedium.GetParent(); 3120 while (comParentMedium.isNotNull()) 3121 { 3122 comRootMedium = comParentMedium; 3123 comParentMedium = comParentMedium.GetParent(); 3124 } 3125 /* Enumerate root if it's found and wasn't cached: */ 3126 if (comRootMedium.isNotNull()) 3127 { 3128 const QUuid uRootId = comRootMedium.GetId(); 3129 if (medium(uRootId).isNull()) 3130 enumerateMedia(CMediumVector() << comRootMedium); 3131 } 3132 } 3133 3134 /* Return UI medium details: */ 3135 return fUseHtml ? guiMedium.detailsHTML(true /* no diffs? */, fPredictDiff) : 3136 guiMedium.details(true /* no diffs? */, fPredictDiff); 3137 } 3138 3139 void UICommon::updateRecentlyUsedMediumListAndFolder(UIMediumDeviceType enmMediumType, QString strMediumLocation) 3140 { 3141 /** Don't add the medium to extra data if its name is in exclude list, m_recentMediaExcludeList: */ 3142 foreach (QString strExcludeName, m_recentMediaExcludeList) 3143 { 3144 if (strMediumLocation.contains(strExcludeName)) 3145 return; 3146 } 3147 3148 /* Remember the path of the last chosen medium: */ 3149 switch (enmMediumType) 3150 { 3151 case UIMediumDeviceType_HardDisk: gEDataManager->setRecentFolderForHardDrives(QFileInfo(strMediumLocation).absolutePath()); break; 3152 case UIMediumDeviceType_DVD: gEDataManager->setRecentFolderForOpticalDisks(QFileInfo(strMediumLocation).absolutePath()); break; 3153 case UIMediumDeviceType_Floppy: gEDataManager->setRecentFolderForFloppyDisks(QFileInfo(strMediumLocation).absolutePath()); break; 3154 default: break; 3155 } 3156 3157 /* Update recently used list: */ 3158 QStringList recentMediumList; 3159 switch (enmMediumType) 3160 { 3161 case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break; 3162 case UIMediumDeviceType_DVD: recentMediumList = gEDataManager->recentListOfOpticalDisks(); break; 3163 case UIMediumDeviceType_Floppy: recentMediumList = gEDataManager->recentListOfFloppyDisks(); break; 3164 default: break; 3165 } 3166 if (recentMediumList.contains(strMediumLocation)) 3167 recentMediumList.removeAll(strMediumLocation); 3168 recentMediumList.prepend(strMediumLocation); 3169 while(recentMediumList.size() > 5) 3170 recentMediumList.removeLast(); 3171 switch (enmMediumType) 3172 { 3173 case UIMediumDeviceType_HardDisk: gEDataManager->setRecentListOfHardDrives(recentMediumList); break; 3174 case UIMediumDeviceType_DVD: gEDataManager->setRecentListOfOpticalDisks(recentMediumList); break; 3175 case UIMediumDeviceType_Floppy: gEDataManager->setRecentListOfFloppyDisks(recentMediumList); break; 3176 default: break; 3177 } 3178 } 3179 3180 QString UICommon::defaultFolderPathForType(UIMediumDeviceType enmMediumType) 3181 { 3182 QString strLastFolder; 3183 switch (enmMediumType) 3184 { 3185 case UIMediumDeviceType_HardDisk: 3186 strLastFolder = gEDataManager->recentFolderForHardDrives(); 3187 if (strLastFolder.isEmpty()) 3188 strLastFolder = gEDataManager->recentFolderForOpticalDisks(); 3189 if (strLastFolder.isEmpty()) 3190 strLastFolder = gEDataManager->recentFolderForFloppyDisks(); 3191 break; 3192 case UIMediumDeviceType_DVD: 3193 strLastFolder = gEDataManager->recentFolderForOpticalDisks(); 3194 if (strLastFolder.isEmpty()) 3195 strLastFolder = gEDataManager->recentFolderForFloppyDisks(); 3196 if (strLastFolder.isEmpty()) 3197 strLastFolder = gEDataManager->recentFolderForHardDrives(); 3198 break; 3199 case UIMediumDeviceType_Floppy: 3200 strLastFolder = gEDataManager->recentFolderForFloppyDisks(); 3201 if (strLastFolder.isEmpty()) 3202 strLastFolder = gEDataManager->recentFolderForOpticalDisks(); 3203 if (strLastFolder.isEmpty()) 3204 strLastFolder = gEDataManager->recentFolderForHardDrives(); 3205 break; 3206 default: 3207 break; 3208 } 3209 3210 if (strLastFolder.isEmpty()) 3211 return virtualBox().GetSystemProperties().GetDefaultMachineFolder(); 3212 3213 return strLastFolder; 3214 } 3215 3216 #ifdef RT_OS_LINUX 3217 /* static */ 3218 void UICommon::checkForWrongUSBMounted() 3219 { 3220 /* Make sure '/proc/mounts' exists and can be opened: */ 3221 QFile file("/proc/mounts"); 3222 if (!file.exists() || !file.open(QIODevice::ReadOnly | QIODevice::Text)) 3223 return; 3224 3225 /* Fetch contents: */ 3226 QStringList contents; 3227 for (;;) 3228 { 3229 QByteArray line = file.readLine(); 3230 if (line.isEmpty()) 3231 break; 3232 contents << line; 3233 } 3234 /* Grep contents for usbfs presence: */ 3235 QStringList grep1(contents.filter("/sys/bus/usb/drivers")); 3236 QStringList grep2(grep1.filter("usbfs")); 3237 if (grep2.isEmpty()) 3238 return; 3239 3240 /* Show corresponding warning: */ 3241 msgCenter().warnAboutWrongUSBMounted(); 3242 } 3243 #endif /* RT_OS_LINUX */ 3244 3245 /* static */ 3246 QString UICommon::details(const CUSBDevice &comDevice) 3247 { 3248 QString strDetails; 3249 if (comDevice.isNull()) 3250 strDetails = tr("Unknown device", "USB device details"); 3251 else 3252 { 3253 QVector<QString> devInfoVector = comDevice.GetDeviceInfo(); 3254 QString strManufacturer; 3255 QString strProduct; 3256 3257 if (devInfoVector.size() >= 1) 3258 strManufacturer = devInfoVector[0].trimmed(); 3259 if (devInfoVector.size() >= 2) 3260 strProduct = devInfoVector[1].trimmed(); 3261 3262 if (strManufacturer.isEmpty() && strProduct.isEmpty()) 3263 { 3264 strDetails = 3265 tr("Unknown device %1:%2", "USB device details") 3266 .arg(QString().sprintf("%04hX", comDevice.GetVendorId())) 3267 .arg(QString().sprintf("%04hX", comDevice.GetProductId())); 3268 } 3269 else 3270 { 3271 if (strProduct.toUpper().startsWith(strManufacturer.toUpper())) 3272 strDetails = strProduct; 3273 else 3274 strDetails = strManufacturer + " " + strProduct; 3275 } 3276 ushort iRev = comDevice.GetRevision(); 3277 if (iRev != 0) 3278 strDetails += QString().sprintf(" [%04hX]", iRev); 3279 } 3280 3281 return strDetails.trimmed(); 3282 } 3283 3284 /* static */ 3285 QString UICommon::toolTip(const CUSBDevice &comDevice) 3286 { 3287 QString strTip = 3288 tr("<nobr>Vendor ID: %1</nobr><br>" 3289 "<nobr>Product ID: %2</nobr><br>" 3290 "<nobr>Revision: %3</nobr>", "USB device tooltip") 3291 .arg(QString().sprintf("%04hX", comDevice.GetVendorId())) 3292 .arg(QString().sprintf("%04hX", comDevice.GetProductId())) 3293 .arg(QString().sprintf("%04hX", comDevice.GetRevision())); 3294 3295 const QString strSerial = comDevice.GetSerialNumber(); 3296 if (!strSerial.isEmpty()) 3297 strTip += QString(tr("<br><nobr>Serial No. %1</nobr>", "USB device tooltip")) 3298 .arg(strSerial); 3299 3300 /* Add the state field if it's a host USB device: */ 3301 CHostUSBDevice hostDev(comDevice); 3302 if (!hostDev.isNull()) 3303 { 3304 strTip += QString(tr("<br><nobr>State: %1</nobr>", "USB device tooltip")) 3305 .arg(gpConverter->toString(hostDev.GetState())); 3306 } 3307 3308 return strTip; 3309 } 3310 3311 /* static */ 3312 QString UICommon::toolTip(const CUSBDeviceFilter &comFilter) 3313 { 3314 QString strTip; 3315 3316 const QString strVendorId = comFilter.GetVendorId(); 3317 if (!strVendorId.isEmpty()) 3318 strTip += tr("<nobr>Vendor ID: %1</nobr>", "USB filter tooltip") 3319 .arg(strVendorId); 3320 3321 const QString strProductId = comFilter.GetProductId(); 3322 if (!strProductId.isEmpty()) 3323 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product ID: %2</nobr>", "USB filter tooltip") 3324 .arg(strProductId); 3325 3326 const QString strRevision = comFilter.GetRevision(); 3327 if (!strRevision.isEmpty()) 3328 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Revision: %3</nobr>", "USB filter tooltip") 3329 .arg(strRevision); 3330 3331 const QString strProduct = comFilter.GetProduct(); 3332 if (!strProduct.isEmpty()) 3333 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product: %4</nobr>", "USB filter tooltip") 3334 .arg(strProduct); 3335 3336 const QString strManufacturer = comFilter.GetManufacturer(); 3337 if (!strManufacturer.isEmpty()) 3338 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Manufacturer: %5</nobr>", "USB filter tooltip") 3339 .arg(strManufacturer); 3340 3341 const QString strSerial = comFilter.GetSerialNumber(); 3342 if (!strSerial.isEmpty()) 3343 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Serial No.: %1</nobr>", "USB filter tooltip") 3344 .arg(strSerial); 3345 3346 const QString strPort = comFilter.GetPort(); 3347 if (!strPort.isEmpty()) 3348 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Port: %1</nobr>", "USB filter tooltip") 3349 .arg(strPort); 3350 3351 /* Add the state field if it's a host USB device: */ 3352 CHostUSBDevice hostDev(comFilter); 3353 if (!hostDev.isNull()) 3354 { 3355 strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>State: %1</nobr>", "USB filter tooltip") 3356 .arg(gpConverter->toString(hostDev.GetState())); 3357 } 3358 3359 return strTip; 3360 } 3361 3362 /* static */ 3363 QString UICommon::toolTip(const CHostVideoInputDevice &comWebcam) 3364 { 3365 QStringList records; 3366 3367 const QString strName = comWebcam.GetName(); 3368 if (!strName.isEmpty()) 3369 records << strName; 3370 3371 const QString strPath = comWebcam.GetPath(); 3372 if (!strPath.isEmpty()) 3373 records << strPath; 3374 3375 return records.join("<br>"); 3376 } 3377 3378 void UICommon::doExtPackInstallation(QString const &strFilePath, QString const &strDigest, 3379 QWidget *pParent, QString *pstrExtPackName) const 29 void UIExtension::install(QString const &strFilePath, 30 QString const &strDigest, 31 QWidget *pParent, 32 QString *pstrExtPackName) 3380 33 { 3381 34 /* If the extension pack manager isn't available, skip any attempts to install: */ 3382 CExtPackManager extPackManager = virtualBox().GetExtensionPackManager();35 CExtPackManager extPackManager = uiCommon().virtualBox().GetExtensionPackManager(); 3383 36 if (extPackManager.isNull()) 3384 37 return; … … 3449 102 strPackName, 3450 103 strDisplayInfo); 3451 connect(pNotification, &UINotificationProgressExtensionPackInstall::sigExtensionPackInstalled,3452 this, &UICommon::sigExtensionPackInstalled);104 QObject::connect(pNotification, &UINotificationProgressExtensionPackInstall::sigExtensionPackInstalled, 105 &uiCommon(), &UICommon::sigExtensionPackInstalled); 3453 106 gpNotificationCenter->append(pNotification); 3454 107 … … 3457 110 *pstrExtPackName = strPackName; 3458 111 } 3459 3460 #ifdef VBOX_WITH_3D_ACCELERATION3461 /* static */3462 bool UICommon::isWddmCompatibleOsType(const QString &strGuestOSTypeId)3463 {3464 return strGuestOSTypeId.startsWith("WindowsVista")3465 || strGuestOSTypeId.startsWith("Windows7")3466 || strGuestOSTypeId.startsWith("Windows8")3467 || strGuestOSTypeId.startsWith("Windows81")3468 || strGuestOSTypeId.startsWith("Windows10")3469 || strGuestOSTypeId.startsWith("Windows2008")3470 || strGuestOSTypeId.startsWith("Windows2012");3471 }3472 #endif /* VBOX_WITH_3D_ACCELERATION */3473 3474 /* static */3475 quint64 UICommon::requiredVideoMemory(const QString &strGuestOSTypeId, int cMonitors /* = 1 */)3476 {3477 /* We create a list of the size of all available host monitors. This list3478 * is sorted by value and by starting with the biggest one, we calculate3479 * the memory requirements for every guest screen. This is of course not3480 * correct, but as we can't predict on which host screens the user will3481 * open the guest windows, this is the best assumption we can do, cause it3482 * is the worst case. */3483 const int cHostScreens = gpDesktop->screenCount();3484 QVector<int> screenSize(qMax(cMonitors, cHostScreens), 0);3485 for (int i = 0; i < cHostScreens; ++i)3486 {3487 QRect r = gpDesktop->screenGeometry(i);3488 screenSize[i] = r.width() * r.height();3489 }3490 /* Now sort the vector: */3491 std::sort(screenSize.begin(), screenSize.end(), std::greater<int>());3492 /* For the case that there are more guest screens configured then host3493 * screens available, replace all zeros with the greatest value in the3494 * vector. */3495 for (int i = 0; i < screenSize.size(); ++i)3496 if (screenSize.at(i) == 0)3497 screenSize.replace(i, screenSize.at(0));3498 3499 quint64 uNeedBits = 0;3500 for (int i = 0; i < cMonitors; ++i)3501 {3502 /* Calculate summary required memory amount in bits: */3503 uNeedBits += (screenSize.at(i) * /* with x height */3504 32 + /* we will take the maximum possible bpp for now */3505 8 * _1M) + /* current cache per screen - may be changed in future */3506 8 * 4096; /* adapter info */3507 }3508 /* Translate value into megabytes with rounding to highest side: */3509 quint64 uNeedMBytes = uNeedBits % (8 * _1M)3510 ? uNeedBits / (8 * _1M) + 13511 : uNeedBits / (8 * _1M) /* convert to megabytes */;3512 3513 if (strGuestOSTypeId.startsWith("Windows"))3514 {3515 /* Windows guests need offscreen VRAM too for graphics acceleration features: */3516 #ifdef VBOX_WITH_3D_ACCELERATION3517 if (isWddmCompatibleOsType(strGuestOSTypeId))3518 {3519 /* WDDM mode, there are two surfaces for each screen: shadow & primary: */3520 uNeedMBytes *= 3;3521 }3522 else3523 #endif /* VBOX_WITH_3D_ACCELERATION */3524 {3525 uNeedMBytes *= 2;3526 }3527 }3528 3529 return uNeedMBytes * _1M;3530 }3531 3532 QIcon UICommon::vmUserIcon(const CMachine &comMachine) const3533 {3534 /* Prepare fallback icon: */3535 static QIcon nullIcon;3536 3537 /* Make sure general icon-pool initialized: */3538 AssertReturn(m_pIconPool, nullIcon);3539 3540 /* Redirect to general icon-pool: */3541 return m_pIconPool->userMachineIcon(comMachine);3542 }3543 3544 QPixmap UICommon::vmUserPixmap(const CMachine &comMachine, const QSize &size) const3545 {3546 /* Prepare fallback pixmap: */3547 static QPixmap nullPixmap;3548 3549 /* Make sure general icon-pool initialized: */3550 AssertReturn(m_pIconPool, nullPixmap);3551 3552 /* Redirect to general icon-pool: */3553 return m_pIconPool->userMachinePixmap(comMachine, size);3554 }3555 3556 QPixmap UICommon::vmUserPixmapDefault(const CMachine &comMachine, QSize *pLogicalSize /* = 0 */) const3557 {3558 /* Prepare fallback pixmap: */3559 static QPixmap nullPixmap;3560 3561 /* Make sure general icon-pool initialized: */3562 AssertReturn(m_pIconPool, nullPixmap);3563 3564 /* Redirect to general icon-pool: */3565 return m_pIconPool->userMachinePixmapDefault(comMachine, pLogicalSize);3566 }3567 3568 QIcon UICommon::vmGuestOSTypeIcon(const QString &strOSTypeID) const3569 {3570 /* Prepare fallback icon: */3571 static QIcon nullIcon;3572 3573 /* Make sure general icon-pool initialized: */3574 AssertReturn(m_pIconPool, nullIcon);3575 3576 /* Redirect to general icon-pool: */3577 return m_pIconPool->guestOSTypeIcon(strOSTypeID);3578 }3579 3580 QPixmap UICommon::vmGuestOSTypePixmap(const QString &strOSTypeID, const QSize &size) const3581 {3582 /* Prepare fallback pixmap: */3583 static QPixmap nullPixmap;3584 3585 /* Make sure general icon-pool initialized: */3586 AssertReturn(m_pIconPool, nullPixmap);3587 3588 /* Redirect to general icon-pool: */3589 return m_pIconPool->guestOSTypePixmap(strOSTypeID, size);3590 }3591 3592 QPixmap UICommon::vmGuestOSTypePixmapDefault(const QString &strOSTypeID, QSize *pLogicalSize /* = 0 */) const3593 {3594 /* Prepare fallback pixmap: */3595 static QPixmap nullPixmap;3596 3597 /* Make sure general icon-pool initialized: */3598 AssertReturn(m_pIconPool, nullPixmap);3599 3600 /* Redirect to general icon-pool: */3601 return m_pIconPool->guestOSTypePixmapDefault(strOSTypeID, pLogicalSize);3602 }3603 3604 /* static */3605 QPixmap UICommon::joinPixmaps(const QPixmap &pixmap1, const QPixmap &pixmap2)3606 {3607 if (pixmap1.isNull())3608 return pixmap2;3609 if (pixmap2.isNull())3610 return pixmap1;3611 3612 QPixmap result(pixmap1.width() + pixmap2.width() + 2,3613 qMax(pixmap1.height(), pixmap2.height()));3614 result.fill(Qt::transparent);3615 3616 QPainter painter(&result);3617 painter.drawPixmap(0, 0, pixmap1);3618 painter.drawPixmap(pixmap1.width() + 2, result.height() - pixmap2.height(), pixmap2);3619 painter.end();3620 3621 return result;3622 }3623 3624 /* static */3625 void UICommon::setHelpKeyword(QObject *pObject, const QString &strHelpKeyword)3626 {3627 if (pObject)3628 pObject->setProperty("helpkeyword", strHelpKeyword);3629 }3630 3631 /* static */3632 QString UICommon::helpKeyword(const QObject *pObject)3633 {3634 if (!pObject)3635 return QString();3636 return pObject->property("helpkeyword").toString();3637 }3638 3639 bool UICommon::openURL(const QString &strUrl) const3640 {3641 /** Service event. */3642 class ServiceEvent : public QEvent3643 {3644 public:3645 3646 /** Constructs service event on th basis of passed @a fResult. */3647 ServiceEvent(bool fResult)3648 : QEvent(QEvent::User)3649 , m_fResult(fResult)3650 {}3651 3652 /** Returns the result which event brings. */3653 bool result() const { return m_fResult; }3654 3655 private:3656 3657 /** Holds the result which event brings. */3658 bool m_fResult;3659 };3660 3661 /** Service client object. */3662 class ServiceClient : public QEventLoop3663 {3664 public:3665 3666 /** Constructs service client on the basis of passed @a fResult. */3667 ServiceClient()3668 : m_fResult(false)3669 {}3670 3671 /** Returns the result which event brings. */3672 bool result() const { return m_fResult; }3673 3674 private:3675 3676 /** Handles any Qt @a pEvent. */3677 bool event(QEvent *pEvent)3678 {3679 /* Handle service event: */3680 if (pEvent->type() == QEvent::User)3681 {3682 ServiceEvent *pServiceEvent = static_cast<ServiceEvent*>(pEvent);3683 m_fResult = pServiceEvent->result();3684 pServiceEvent->accept();3685 quit();3686 return true;3687 }3688 return false;3689 }3690 3691 bool m_fResult;3692 };3693 3694 /** Service server object. */3695 class ServiceServer : public QThread3696 {3697 public:3698 3699 /** Constructs service server on the basis of passed @a client and @a strUrl. */3700 ServiceServer(ServiceClient &client, const QString &strUrl)3701 : m_client(client), m_strUrl(strUrl) {}3702 3703 private:3704 3705 /** Executes thread task. */3706 void run()3707 {3708 QApplication::postEvent(&m_client, new ServiceEvent(QDesktopServices::openUrl(m_strUrl)));3709 }3710 3711 /** Holds the client reference. */3712 ServiceClient &m_client;3713 /** Holds the URL to be processed. */3714 const QString &m_strUrl;3715 };3716 3717 /* Create client & server: */3718 ServiceClient client;3719 ServiceServer server(client, strUrl);3720 server.start();3721 client.exec();3722 server.wait();3723 3724 /* Acquire client result: */3725 bool fResult = client.result();3726 if (!fResult)3727 UINotificationMessage::cannotOpenURL(strUrl);3728 3729 return fResult;3730 }3731 3732 void UICommon::sltGUILanguageChange(QString strLanguage)3733 {3734 /* Make sure medium-enumeration is not in progress! */3735 AssertReturnVoid(!isMediumEnumerationInProgress());3736 /* Load passed language: */3737 UITranslator::loadLanguage(strLanguage);3738 }3739 3740 void UICommon::sltHandleMediumCreated(const CMedium &comMedium)3741 {3742 /* Acquire device type: */3743 const KDeviceType enmDeviceType = comMedium.GetDeviceType();3744 if (!comMedium.isOk())3745 msgCenter().cannotAcquireMediumAttribute(comMedium);3746 else3747 {3748 /* Convert to medium type: */3749 const UIMediumDeviceType enmMediumType = mediumTypeToLocal(enmDeviceType);3750 3751 /* Make sure we cached created medium in GUI: */3752 createMedium(UIMedium(comMedium, enmMediumType, KMediumState_Created));3753 }3754 }3755 3756 void UICommon::sltHandleMachineCreated(const CMachine &comMachine)3757 {3758 /* Register created machine. */3759 CVirtualBox comVBox = virtualBox();3760 comVBox.RegisterMachine(comMachine);3761 if (!comVBox.isOk())3762 msgCenter().cannotRegisterMachine(comVBox, comMachine.GetName());3763 }3764 3765 void UICommon::sltHandleCloudMachineAdded(const QString &strProviderShortName,3766 const QString &strProfileName,3767 const CCloudMachine &comMachine)3768 {3769 /* Make sure we cached added cloud VM in GUI: */3770 notifyCloudMachineRegistered(strProviderShortName,3771 strProfileName,3772 comMachine);3773 }3774 3775 bool UICommon::eventFilter(QObject *pObject, QEvent *pEvent)3776 {3777 /** @todo Just use the QIWithRetranslateUI3 template wrapper. */3778 3779 if ( pEvent->type() == QEvent::LanguageChange3780 && pObject->isWidgetType()3781 && static_cast<QWidget*>(pObject)->isTopLevel())3782 {3783 /* Catch the language change event before any other widget gets it in3784 * order to invalidate cached string resources (like the details view3785 * templates) that may be used by other widgets. */3786 QWidgetList list = QApplication::topLevelWidgets();3787 if (list.first() == pObject)3788 {3789 /* Call this only once per every language change (see3790 * QApplication::installTranslator() for details): */3791 retranslateUi();3792 }3793 }3794 3795 /* Call to base-class: */3796 return QObject::eventFilter(pObject, pEvent);3797 }3798 3799 void UICommon::retranslateUi()3800 {3801 m_pixWarning = UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_MessageBoxWarning).pixmap(16, 16);3802 Assert(!m_pixWarning.isNull());3803 3804 m_pixError = UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_MessageBoxCritical).pixmap(16, 16);3805 Assert(!m_pixError.isNull());3806 3807 /* Re-enumerate uimedium since they contain some translations too: */3808 if (m_fValid)3809 refreshMedia();3810 3811 #ifdef VBOX_WS_X113812 // WORKAROUND:3813 // As X11 do not have functionality for providing human readable key names,3814 // we keep a table of them, which must be updated when the language is changed.3815 UINativeHotKey::retranslateKeyNames();3816 #endif3817 }3818 3819 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS13820 void UICommon::sltHandleCommitDataRequest(QSessionManager &manager)3821 {3822 LogRel(("GUI: UICommon: Commit data request..\n"));3823 3824 /* Ask listener to commit data: */3825 emit sigAskToCommitData();3826 #ifdef VBOX_WS_WIN3827 m_fDataCommitted = true;3828 #endif3829 3830 /* Depending on UI type: */3831 switch (uiType())3832 {3833 /* For Runtime UI: */3834 case UIType_RuntimeUI:3835 {3836 /* Thin clients will be able to shutdown properly,3837 * but for fat clients: */3838 if (!isSeparateProcess())3839 {3840 // WORKAROUND:3841 // We can't save VM state in one go for fat clients, so we have to ask session manager to cancel shutdown.3842 // To next major release this should be removed in any case, since there will be no fat clients after all.3843 manager.cancel();3844 3845 #ifdef VBOX_WS_WIN3846 // WORKAROUND:3847 // In theory that's Qt5 who should allow us to provide canceling reason as well, but that functionality3848 // seems to be missed in Windows platform plugin, so we are making that ourselves.3849 ShutdownBlockReasonCreateAPI((HWND)windowManager().mainWindowShown()->winId(), L"VM is still running.");3850 #endif3851 }3852 3853 break;3854 }3855 default:3856 break;3857 }3858 }3859 #endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */3860 3861 void UICommon::sltHandleVBoxSVCAvailabilityChange(bool fAvailable)3862 {3863 /* Make sure the VBoxSVC availability changed: */3864 if (m_fVBoxSVCAvailable == fAvailable)3865 return;3866 3867 /* Cache the new VBoxSVC availability value: */3868 m_fVBoxSVCAvailable = fAvailable;3869 3870 /* If VBoxSVC is not available: */3871 if (!m_fVBoxSVCAvailable)3872 {3873 /* Mark wrappers invalid: */3874 m_fWrappersValid = false;3875 /* Re-fetch corresponding CVirtualBox to restart VBoxSVC: */3876 m_comVBox = m_comVBoxClient.GetVirtualBox();3877 if (!m_comVBoxClient.isOk())3878 {3879 // The proper behavior would be to show the message and to exit the app, e.g.:3880 // msgCenter().cannotAcquireVirtualBox(m_comVBoxClient);3881 // return QApplication::quit();3882 // But CVirtualBox is still NULL in current Main implementation,3883 // and this call do not restart anything, so we are waiting3884 // for subsequent event about VBoxSVC is available again.3885 }3886 }3887 /* If VBoxSVC is available: */3888 else3889 {3890 if (!m_fWrappersValid)3891 {3892 /* Re-fetch corresponding CVirtualBox: */3893 m_comVBox = m_comVBoxClient.GetVirtualBox();3894 if (!m_comVBoxClient.isOk())3895 {3896 msgCenter().cannotAcquireVirtualBox(m_comVBoxClient);3897 return QApplication::quit();3898 }3899 /* Re-init wrappers: */3900 comWrappersReinit();3901 3902 /* For Selector UI: */3903 if (uiType() == UIType_SelectorUI)3904 {3905 /* Recreate Main event listeners: */3906 UIVirtualBoxEventHandler::destroy();3907 UIVirtualBoxClientEventHandler::destroy();3908 UIExtraDataManager::destroy();3909 UIExtraDataManager::instance();3910 UIVirtualBoxEventHandler::instance();3911 UIVirtualBoxClientEventHandler::instance();3912 /* Ask UIStarter to restart UI: */3913 emit sigAskToRestartUI();3914 }3915 }3916 }3917 3918 /* Notify listeners about the VBoxSVC availability change: */3919 emit sigVBoxSVCAvailabilityChange();3920 }3921 3922 #ifdef VBOX_WS_WIN3923 /* static */3924 BOOL UICommon::ShutdownBlockReasonCreateAPI(HWND hWnd, LPCWSTR pwszReason)3925 {3926 BOOL fResult = FALSE;3927 typedef BOOL(WINAPI *PFNSHUTDOWNBLOCKREASONCREATE)(HWND hWnd, LPCWSTR pwszReason);3928 3929 PFNSHUTDOWNBLOCKREASONCREATE pfn = (PFNSHUTDOWNBLOCKREASONCREATE)GetProcAddress(3930 GetModuleHandle(L"User32.dll"), "ShutdownBlockReasonCreate");3931 _ASSERTE(pfn);3932 if (pfn)3933 fResult = pfn(hWnd, pwszReason);3934 return fResult;3935 }3936 #endif3937 3938 #ifdef VBOX_WITH_DEBUGGER_GUI3939 3940 # define UICOMMON_DBG_CFG_VAR_FALSE (0)3941 # define UICOMMON_DBG_CFG_VAR_TRUE (1)3942 # define UICOMMON_DBG_CFG_VAR_MASK (1)3943 # define UICOMMON_DBG_CFG_VAR_CMD_LINE RT_BIT(3)3944 # define UICOMMON_DBG_CFG_VAR_DONE RT_BIT(4)3945 3946 void UICommon::initDebuggerVar(int *piDbgCfgVar, const char *pszEnvVar, const char *pszExtraDataName, bool fDefault)3947 {3948 QString strEnvValue;3949 char szEnvValue[256];3950 int rc = RTEnvGetEx(RTENV_DEFAULT, pszEnvVar, szEnvValue, sizeof(szEnvValue), NULL);3951 if (RT_SUCCESS(rc))3952 {3953 strEnvValue = QString::fromUtf8(&szEnvValue[0]).toLower().trimmed();3954 if (strEnvValue.isEmpty())3955 strEnvValue = "yes";3956 }3957 else if (rc != VERR_ENV_VAR_NOT_FOUND)3958 strEnvValue = "veto";3959 3960 QString strExtraValue = m_comVBox.GetExtraData(pszExtraDataName).toLower().trimmed();3961 if (strExtraValue.isEmpty())3962 strExtraValue = QString();3963 3964 if ( strEnvValue.contains("veto") || strExtraValue.contains("veto"))3965 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE;3966 else if (strEnvValue.isNull() && strExtraValue.isNull())3967 *piDbgCfgVar = fDefault ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE;3968 else3969 {3970 QString *pStr = !strEnvValue.isEmpty() ? &strEnvValue : &strExtraValue;3971 if ( pStr->startsWith("y") // yes3972 || pStr->startsWith("e") // enabled3973 || pStr->startsWith("t") // true3974 || pStr->startsWith("on")3975 || pStr->toLongLong() != 0)3976 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_TRUE;3977 else if ( pStr->startsWith("n") // o3978 || pStr->startsWith("d") // disable3979 || pStr->startsWith("f") // false3980 || pStr->startsWith("off")3981 || pStr->contains("veto") /* paranoia */3982 || pStr->toLongLong() == 0)3983 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_FALSE;3984 else3985 {3986 LogFunc(("Ignoring unknown value '%s' for '%s'\n", pStr->toUtf8().constData(), pStr == &strEnvValue ? pszEnvVar : pszExtraDataName));3987 *piDbgCfgVar = fDefault ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE;3988 }3989 }3990 }3991 3992 void UICommon::setDebuggerVar(int *piDbgCfgVar, bool fState)3993 {3994 if (!(*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_DONE))3995 *piDbgCfgVar = (fState ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE)3996 | UICOMMON_DBG_CFG_VAR_CMD_LINE;3997 }3998 3999 bool UICommon::isDebuggerWorker(int *piDbgCfgVar, const char *pszExtraDataName) const4000 {4001 if (!(*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_DONE))4002 {4003 const QString str = gEDataManager->debugFlagValue(pszExtraDataName);4004 if (str.contains("veto"))4005 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE;4006 else if (str.isEmpty() || (*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_CMD_LINE))4007 *piDbgCfgVar |= UICOMMON_DBG_CFG_VAR_DONE;4008 else if ( str.startsWith("y") // yes4009 || str.startsWith("e") // enabled4010 || str.startsWith("t") // true4011 || str.startsWith("on")4012 || str.toLongLong() != 0)4013 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_TRUE;4014 else if ( str.startsWith("n") // no4015 || str.startsWith("d") // disable4016 || str.startsWith("f") // false4017 || str.toLongLong() == 0)4018 *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE;4019 else4020 *piDbgCfgVar |= UICOMMON_DBG_CFG_VAR_DONE;4021 }4022 4023 return (*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_MASK) == UICOMMON_DBG_CFG_VAR_TRUE;4024 }4025 4026 #endif /* VBOX_WITH_DEBUGGER_GUI */4027 4028 void UICommon::comWrappersReinit()4029 {4030 /* Re-fetch corresponding objects/values: */4031 m_comHost = virtualBox().GetHost();4032 m_strHomeFolder = virtualBox().GetHomeFolder();4033 4034 /* Re-initialize guest OS Type list: */4035 m_guestOSFamilyIDs.clear();4036 m_guestOSTypes.clear();4037 const CGuestOSTypeVector guestOSTypes = m_comVBox.GetGuestOSTypes();4038 const int cGuestOSTypeCount = guestOSTypes.size();4039 AssertMsg(cGuestOSTypeCount > 0, ("Number of OS types must not be zero"));4040 if (cGuestOSTypeCount > 0)4041 {4042 /* Here we ASSUME the 'Other' types are always the first,4043 * so we remember them and will append them to the list when finished.4044 * We do a two pass, first adding the specific types, then the two 'Other' types. */4045 for (int j = 0; j < 2; ++j)4046 {4047 int cMax = j == 0 ? cGuestOSTypeCount : RT_MIN(2, cGuestOSTypeCount);4048 for (int i = j == 0 ? 2 : 0; i < cMax; ++i)4049 {4050 const CGuestOSType os = guestOSTypes.at(i);4051 const QString strFamilyID = os.GetFamilyId();4052 const QString strFamilyDescription = os.GetFamilyDescription();4053 if (!m_guestOSFamilyIDs.contains(strFamilyID))4054 {4055 m_guestOSFamilyIDs << strFamilyID;4056 m_guestOSFamilyDescriptions[strFamilyID] = strFamilyDescription;4057 m_guestOSTypes << QList<CGuestOSType>();4058 }4059 m_guestOSTypes[m_guestOSFamilyIDs.indexOf(strFamilyID)].append(os);4060 }4061 }4062 }4063 4064 /* Mark wrappers valid: */4065 m_fWrappersValid = true;4066 } -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIExtension.h
r91003 r91009 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI Common classdeclaration.3 * VBox Qt GUI - UIExtension namespace declaration. 4 4 */ 5 5 … … 16 16 */ 17 17 18 #ifndef FEQT_INCLUDED_SRC_globals_UI Common_h19 #define FEQT_INCLUDED_SRC_globals_UI Common_h18 #ifndef FEQT_INCLUDED_SRC_globals_UIExtension_h 19 #define FEQT_INCLUDED_SRC_globals_UIExtension_h 20 20 #ifndef RT_WITHOUT_PRAGMA_ONCE 21 21 # pragma once 22 22 #endif 23 23 24 /* Qt includes: */ 25 #include <QFileIconProvider> 26 #include <QMap> 27 #include <QReadWriteLock> 24 /* GUI includes: */ 25 #include "UILibraryDefs.h" 28 26 29 /* GUI includes: */ 30 #include "UIDefs.h" 31 #include "UILibraryDefs.h" 32 #include "UIMediumDefs.h" 33 #ifdef VBOX_WS_X11 34 # include "VBoxX11Helper.h" 35 #endif 27 /** Namespace with common extension pack stuff. */ 28 namespace UIExtension 29 { 30 /** Initiates the extension pack installation process. 31 * @param strFilePath Brings the extension pack file path. 32 * @param strDigest Brings the extension pack file digest. 33 * @param pParent Brings the parent dialog reference. 34 * @param pstrExtPackName Brings the extension pack name. */ 35 void SHARED_LIBRARY_STUFF install(QString const &strFilePath, 36 QString const &strDigest, 37 QWidget *pParent, 38 QString *pstrExtPackName); 39 } 36 40 37 /* COM includes: */ 38 #include "CGuestOSType.h" 39 #include "CHost.h" 40 #include "CMedium.h" 41 #include "CSession.h" 42 #include "CVirtualBox.h" 43 #include "CVirtualBoxClient.h" 44 45 /* Other VBox includes: */ 46 #include "VBox/com/Guid.h" 47 48 /* Other includes: */ 49 #ifdef VBOX_WS_X11 50 # include <X11/Xdefs.h> 51 #endif 52 53 /* Forward declarations: */ 54 class QGraphicsWidget; 55 class QMenu; 56 class QSessionManager; 57 class QSpinBox; 58 class QToolButton; 59 class CCloudMachine; 60 class CHostVideoInputDevice; 61 class CMachine; 62 class CUSBDevice; 63 class UIIconPoolGeneral; 64 class UIMedium; 65 class UIMediumEnumerator; 66 class UIThreadPool; 67 68 /** QObject subclass containing common GUI functionality. */ 69 class SHARED_LIBRARY_STUFF UICommon : public QObject 70 { 71 Q_OBJECT; 72 73 signals: 74 75 /** @name Common stuff. 76 * @{ */ 77 /** Asks #UIStarter listener to restart UI. */ 78 void sigAskToRestartUI(); 79 /** Asks #UIStarter listener to close UI. */ 80 void sigAskToCloseUI(); 81 82 /** Notifies listeners about the VBoxSVC availability change. */ 83 void sigVBoxSVCAvailabilityChange(); 84 85 /** Asks listeners to commit data. */ 86 void sigAskToCommitData(); 87 /** Asks listeners to detach COM. */ 88 void sigAskToDetachCOM(); 89 /** @} */ 90 91 /** @name COM: Extension Pack stuff. 92 * @{ */ 93 /** Notifies listeners about extension pack @a strName was installed. */ 94 void sigExtensionPackInstalled(const QString &strName); 95 /** @} */ 96 97 /** @name Cloud Virtual Machine stuff. 98 * @{ */ 99 /** Notifies listeners about cloud VM was unregistered. 100 * @param strProviderShortName Brings provider short name. 101 * @param strProfileName Brings profile name. 102 * @param uId Brings cloud VM id. */ 103 void sigCloudMachineUnregistered(const QString &strProviderShortName, 104 const QString &strProfileName, 105 const QUuid &uId); 106 /** Notifies listeners about cloud VM was registered. 107 * @param strProviderShortName Brings provider short name. 108 * @param strProfileName Brings profile name. 109 * @param comMachine Brings cloud VM. */ 110 void sigCloudMachineRegistered(const QString &strProviderShortName, 111 const QString &strProfileName, 112 const CCloudMachine &comMachine); 113 /** @} */ 114 115 /** @name COM: Virtual Media stuff. 116 * @{ */ 117 /** Notifies listeners about medium with certain @a uMediumID created. */ 118 void sigMediumCreated(const QUuid &uMediumID); 119 /** Notifies listeners about medium with certain @a uMediumID deleted. */ 120 void sigMediumDeleted(const QUuid &uMediumID); 121 122 /** Notifies listeners about medium-enumeration started. */ 123 void sigMediumEnumerationStarted(); 124 /** Notifies listeners about medium with certain @a uMediumID enumerated. */ 125 void sigMediumEnumerated(const QUuid &uMediumID); 126 /** Notifies listeners about medium-enumeration finished. */ 127 void sigMediumEnumerationFinished(); 128 /** @} */ 129 130 public: 131 132 /** UI types. */ 133 enum UIType 134 { 135 UIType_SelectorUI, 136 UIType_RuntimeUI 137 }; 138 139 /** VM launch modes. */ 140 enum LaunchMode 141 { 142 LaunchMode_Invalid, 143 LaunchMode_Default, 144 LaunchMode_Headless, 145 LaunchMode_Separate 146 }; 147 148 /** VM launch running options. */ 149 enum LaunchRunning 150 { 151 LaunchRunning_Default, /**< Default (depends on debug settings). */ 152 LaunchRunning_No, /**< Start the VM paused. */ 153 LaunchRunning_Yes /**< Start the VM running. */ 154 }; 155 156 /** Returns UICommon instance. */ 157 static UICommon *instance() { return s_pInstance; } 158 /** Creates UICommon instance of passed @a enmType. */ 159 static void create(UIType enmType); 160 /** Destroys UICommon instance. */ 161 static void destroy(); 162 163 /** @name General stuff. 164 * @{ */ 165 /** Returns the UI type. */ 166 UIType uiType() const { return m_enmType; } 167 168 /** Returns whether UICommon instance is properly initialized. */ 169 bool isValid() const { return m_fValid; } 170 /** Returns whether UICommon instance cleanup is in progress. */ 171 bool isCleaningUp() const { return m_fCleaningUp; } 172 /** @} */ 173 174 /** @name Versioning stuff. 175 * @{ */ 176 /** Returns Qt runtime version string. */ 177 static QString qtRTVersionString(); 178 /** Returns Qt runtime version. */ 179 static uint qtRTVersion(); 180 /** Returns Qt runtime major version. */ 181 static uint qtRTMajorVersion(); 182 /** Returns Qt runtime minor version. */ 183 static uint qtRTMinorVersion(); 184 /** Returns Qt runtime revision number. */ 185 static uint qtRTRevisionNumber(); 186 187 /** Returns Qt compiled version string. */ 188 static QString qtCTVersionString(); 189 /** Returns Qt compiled version. */ 190 static uint qtCTVersion(); 191 192 /** Returns VBox version string. */ 193 QString vboxVersionString() const; 194 /** Returns normalized VBox version string. */ 195 QString vboxVersionStringNormalized() const; 196 /** Returns whether VBox version string contains BETA word. */ 197 bool isBeta() const; 198 199 /** Returns whether branding is active. */ 200 bool brandingIsActive(bool fForce = false); 201 /** Returns value for certain branding @a strKey from custom.ini file. */ 202 QString brandingGetKey(QString strKey) const; 203 /** @} */ 204 205 /** @name Host OS stuff. 206 * @{ */ 207 #ifdef VBOX_WS_MAC 208 /** Mac OS X: Returns #MacOSXRelease determined by <i>uname</i> call. */ 209 static MacOSXRelease determineOsRelease(); 210 /** Mac OS X: Returns #MacOSXRelease determined during UICommon prepare routine. */ 211 MacOSXRelease osRelease() const { return m_enmMacOSVersion; } 212 #endif 213 214 #ifdef VBOX_WS_WIN 215 /** Loads the color theme. */ 216 static void loadColorTheme(); 217 #endif 218 219 #ifdef VBOX_WS_X11 220 /** X11: Returns whether the Window Manager we are running under is composition one. */ 221 bool isCompositingManagerRunning() const { return m_fCompositingManagerRunning; } 222 /** X11: Returns the type of the Window Manager we are running under. */ 223 X11WMType typeOfWindowManager() const { return m_enmWindowManagerType; } 224 #endif 225 /** @} */ 226 227 /** @name Process arguments stuff. 228 * @{ */ 229 /** Process application args. */ 230 bool processArgs(); 231 232 /** Returns whether there are unhandled URL arguments present. */ 233 bool argumentUrlsPresent() const; 234 /** Takes and returns the URL argument list while clearing the source. */ 235 QList<QUrl> takeArgumentUrls(); 236 237 /** Returns the --startvm option value (managed VM id). */ 238 QUuid managedVMUuid() const { return m_strManagedVMId; } 239 /** Returns the --separate option value (whether GUI process is separate from VM process). */ 240 bool isSeparateProcess() const { return m_fSeparateProcess; } 241 /** Returns the --no-startvm-errormsgbox option value (whether startup VM errors are disabled). */ 242 bool showStartVMErrors() const { return m_fShowStartVMErrors; } 243 244 /** Returns the --aggressive-caching / --no-aggressive-caching option value (whether medium-enumeration is required). */ 245 bool agressiveCaching() const { return m_fAgressiveCaching; } 246 247 /** Returns the --restore-current option value (whether we should restore current snapshot before VM started). */ 248 bool shouldRestoreCurrentSnapshot() const { return m_fRestoreCurrentSnapshot; } 249 /** Defines whether we should fRestore current snapshot before VM started. */ 250 void setShouldRestoreCurrentSnapshot(bool fRestore) { m_fRestoreCurrentSnapshot = fRestore; } 251 252 /** Returns the --fda option value (whether we have floppy image). */ 253 bool hasFloppyImageToMount() const { return !m_uFloppyImage.isNull(); } 254 /** Returns the --dvd | --cdrom option value (whether we have DVD image). */ 255 bool hasDvdImageToMount() const { return !m_uDvdImage.isNull(); } 256 /** Returns floppy image name. */ 257 QUuid getFloppyImage() const { return m_uFloppyImage; } 258 /** Returns DVD image name. */ 259 QUuid getDvdImage() const { return m_uDvdImage; } 260 261 /** Returns the --disable-patm option value. */ 262 bool isPatmDisabled() const { return m_fDisablePatm; } 263 /** Returns the --disable-csam option value. */ 264 bool isCsamDisabled() const { return m_fDisableCsam; } 265 /** Returns the --recompile-supervisor option value. */ 266 bool isSupervisorCodeExecedRecompiled() const { return m_fRecompileSupervisor; } 267 /** Returns the --recompile-user option value. */ 268 bool isUserCodeExecedRecompiled() const { return m_fRecompileUser; } 269 /** Returns the --execute-all-in-iem option value. */ 270 bool areWeToExecuteAllInIem() const { return m_fExecuteAllInIem; } 271 /** Returns whether --warp-factor option value is equal to 100. */ 272 bool isDefaultWarpPct() const { return m_uWarpPct == 100; } 273 /** Returns the --warp-factor option value. */ 274 uint32_t getWarpPct() const { return m_uWarpPct; } 275 276 #ifdef VBOX_WITH_DEBUGGER_GUI 277 /** Holds whether the debugger should be accessible. */ 278 bool isDebuggerEnabled() const; 279 /** Holds whether to show the debugger automatically with the console. */ 280 bool isDebuggerAutoShowEnabled() const; 281 /** Holds whether to show the command line window when m_fDbgAutoShow is set. */ 282 bool isDebuggerAutoShowCommandLineEnabled() const; 283 /** Holds whether to show the statistics window when m_fDbgAutoShow is set. */ 284 bool isDebuggerAutoShowStatisticsEnabled() const; 285 /** Returns the combined --statistics-expand values. */ 286 QString const getDebuggerStatisticsExpand() const { return m_strDbgStatisticsExpand; } 287 /** Returns the --statistics-filter value. */ 288 QString const getDebuggerStatisticsFilter() const { return m_strDbgStatisticsFilter; } 289 290 /** VBoxDbg module handle. */ 291 RTLDRMOD getDebuggerModule() const { return m_hVBoxDbg; } 292 #endif 293 294 /** Returns whether VM should start paused. */ 295 bool shouldStartPaused() const; 296 297 #ifdef VBOX_GUI_WITH_PIDFILE 298 /** Creates PID file. */ 299 void createPidfile(); 300 /** Deletes PID file. */ 301 void deletePidfile(); 302 #endif 303 /** @} */ 304 305 /** @name File-system stuff. 306 * @{ */ 307 /** Returns full help file name. */ 308 static QString helpFile(); 309 310 /** Returns documents path. */ 311 static QString documentsPath(); 312 313 /** Returns whether passed @a strFileName ends with one of allowed extension in the @a extensions list. */ 314 static bool hasAllowedExtension(const QString &strFileName, const QStringList &extensions); 315 316 /** Returns a file name (unique up to extension) wrt. @a strFullFolderPath folder content. Starts 317 * searching strBaseFileName and adds suffixes until a unique file name is found. */ 318 static QString findUniqueFileName(const QString &strFullFolderPath, const QString &strBaseFileName); 319 /** @} */ 320 321 /** @name Window/widget stuff. 322 * @{ */ 323 /** Search position for @a rectangle to make sure it is fully contained @a boundRegion. */ 324 static QRect normalizeGeometry(const QRect &rectangle, const QRegion &boundRegion, 325 bool fCanResize = true); 326 /** Ensures that the given rectangle @a rectangle is fully contained within the region @a boundRegion. */ 327 static QRect getNormalized(const QRect &rectangle, const QRegion &boundRegion, 328 bool fCanResize = true); 329 /** Returns the flipped (transposed) @a region. */ 330 static QRegion flip(const QRegion ®ion); 331 332 /** Aligns the center of @a pWidget with the center of @a pRelative. */ 333 static void centerWidget(QWidget *pWidget, QWidget *pRelative, bool fCanResize = true); 334 335 /** Assigns top-level @a pWidget geometry passed as QRect coordinates. 336 * @note Take into account that this request may fail on X11. */ 337 static void setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int h); 338 /** Assigns top-level @a pWidget geometry passed as @a rect. 339 * @note Take into account that this request may fail on X11. */ 340 static void setTopLevelGeometry(QWidget *pWidget, const QRect &rect); 341 342 /** Activates the specified window with given @a wId. Can @a fSwitchDesktop if requested. */ 343 static bool activateWindow(WId wId, bool fSwitchDesktop = true); 344 345 #ifdef VBOX_WS_X11 346 /** X11: Test whether the current window manager supports full screen mode. */ 347 static bool supportsFullScreenMonitorsProtocolX11(); 348 /** X11: Performs mapping of the passed @a pWidget to host-screen with passed @a uScreenId. */ 349 static bool setFullScreenMonitorX11(QWidget *pWidget, ulong uScreenId); 350 351 /** X11: Returns a list of current _NET_WM_STATE flags for passed @a pWidget. */ 352 static QVector<Atom> flagsNetWmState(QWidget *pWidget); 353 /** X11: Check whether _NET_WM_STATE_FULLSCREEN flag is set for passed @a pWidget. */ 354 static bool isFullScreenFlagSet(QWidget *pWidget); 355 /** X11: Sets _NET_WM_STATE_FULLSCREEN flag for passed @a pWidget. */ 356 static void setFullScreenFlag(QWidget *pWidget); 357 /** X11: Sets _NET_WM_STATE_SKIP_TASKBAR flag for passed @a pWidget. */ 358 static void setSkipTaskBarFlag(QWidget *pWidget); 359 /** X11: Sets _NET_WM_STATE_SKIP_PAGER flag for passed @a pWidget. */ 360 static void setSkipPagerFlag(QWidget *pWidget); 361 362 /** Assigns WM_CLASS property for passed @a pWidget. */ 363 static void setWMClass(QWidget *pWidget, const QString &strNameString, const QString &strClassString); 364 /** Tell the WM we are well behaved wrt Xwayland keyboard-grabs. This will 365 * make the WM turn our grab into a Wayland shortcut inhibition request, 366 * so that e.g. alt+tab will get send to the VM instead of moving the 367 * focus away from the VM. */ 368 static void setXwaylandMayGrabKeyboardFlag(QWidget *pWidget); 369 #endif /* VBOX_WS_X11 */ 370 371 /** Assigns minimum @a pSpinBox to correspond to @a cCount digits. */ 372 static void setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount); 373 /** @} */ 374 375 /** @name COM stuff. 376 * @{ */ 377 /** Try to acquire COM cleanup protection token for reading. */ 378 bool comTokenTryLockForRead() { return m_comCleanupProtectionToken.tryLockForRead(); } 379 /** Unlock previously acquired COM cleanup protection token. */ 380 void comTokenUnlock() { return m_comCleanupProtectionToken.unlock(); } 381 382 /** Returns the copy of VirtualBox client wrapper. */ 383 CVirtualBoxClient virtualBoxClient() const { return m_comVBoxClient; } 384 /** Returns the copy of VirtualBox object wrapper. */ 385 CVirtualBox virtualBox() const { return m_comVBox; } 386 /** Returns the copy of VirtualBox host-object wrapper. */ 387 CHost host() const { return m_comHost; } 388 /** Returns the symbolic VirtualBox home-folder representation. */ 389 QString homeFolder() const { return m_strHomeFolder; } 390 391 /** Returns the VBoxSVC availability value. */ 392 bool isVBoxSVCAvailable() const { return m_fVBoxSVCAvailable; } 393 /** @} */ 394 395 /** @name COM: Guest OS Type. 396 * @{ */ 397 /** Returns the list of family IDs. */ 398 QList<QString> vmGuestOSFamilyIDs() const { return m_guestOSFamilyIDs; } 399 400 /** Returns a family description with passed @a strFamilyId. */ 401 QString vmGuestOSFamilyDescription(const QString &strFamilyId) const; 402 /** Returns a list of all guest OS types with passed @a strFamilyId. */ 403 QList<CGuestOSType> vmGuestOSTypeList(const QString &strFamilyId) const; 404 405 /** Returns the guest OS type for passed @a strTypeId. 406 * It is being serached through the list of family with passed @a strFamilyId if specified. */ 407 CGuestOSType vmGuestOSType(const QString &strTypeId, const QString &strFamilyId = QString()) const; 408 /** Returns a type description with passed @a strTypeId. */ 409 QString vmGuestOSTypeDescription(const QString &strTypeId) const; 410 411 /** Returns whether guest type with passed @a strOSTypeId is one of DOS types. */ 412 static bool isDOSType(const QString &strOSTypeId); 413 /** @} */ 414 415 /** @name COM: Virtual Machine stuff. 416 * @{ */ 417 /** Switches to certain @a comMachine. */ 418 static bool switchToMachine(CMachine &comMachine); 419 /** Launches certain @a comMachine in specified @a enmLaunchMode. */ 420 bool launchMachine(CMachine &comMachine, LaunchMode enmLaunchMode = LaunchMode_Default); 421 422 /** Opens session of certain @a enmLockType for VM with certain @a uId. */ 423 CSession openSession(const QUuid &uId, KLockType enmLockType = KLockType_Write); 424 /** Opens session of KLockType_Shared type for VM with certain @a uId. */ 425 CSession openExistingSession(const QUuid &uId) { return openSession(uId, KLockType_Shared); } 426 /** Tries to guess if new @a comSession needs to be opened for certain @a comMachine, 427 * if yes, new session of required type will be opened and machine will be updated, 428 * otherwise, no session will be created and machine will be left unchanged. */ 429 CSession tryToOpenSessionFor(CMachine &comMachine); 430 /** @} */ 431 432 /** @name Cloud Virtual Machine stuff. 433 * @{ */ 434 /** Notifies listeners about cloud VM was unregistered. 435 * @param strProviderShortName Brings provider short name. 436 * @param strProfileName Brings profile name. 437 * @param uId Brings cloud VM id. */ 438 void notifyCloudMachineUnregistered(const QString &strProviderShortName, 439 const QString &strProfileName, 440 const QUuid &uId); 441 /** Notifies listeners about cloud VM was registered. 442 * @param strProviderShortName Brings provider short name. 443 * @param strProfileName Brings profile name. 444 * @param comMachine Brings cloud VM. */ 445 void notifyCloudMachineRegistered(const QString &strProviderShortName, 446 const QString &strProfileName, 447 const CCloudMachine &comMachine); 448 /** @} */ 449 450 /** @name COM: Virtual Media stuff. 451 * @{ */ 452 /** Enumerates passed @a comMedia. */ 453 void enumerateMedia(const CMediumVector &comMedia = CMediumVector()); 454 /** Calls refresh for each medium which has been already enumerated. */ 455 void refreshMedia(); 456 /** Returns whether full medium-enumeration is requested. */ 457 bool isFullMediumEnumerationRequested() const; 458 /** Returns whether any medium-enumeration is in progress. */ 459 bool isMediumEnumerationInProgress() const; 460 /** Returns enumerated medium with certain @a uMediumID. */ 461 UIMedium medium(const QUuid &uMediumID) const; 462 /** Returns enumerated medium IDs. */ 463 QList<QUuid> mediumIDs() const; 464 /** Creates medium on the basis of passed @a guiMedium description. */ 465 void createMedium(const UIMedium &guiMedium); 466 467 /** Opens external medium by passed @a strMediumLocation. 468 * @param enmMediumType Brings the medium type. 469 * @param pParent Brings the dialog parent. 470 * @param strMediumLocation Brings the file path to load medium from. 471 * @param pParent Brings the dialog parent. */ 472 QUuid openMedium(UIMediumDeviceType enmMediumType, QString strMediumLocation, QWidget *pParent = 0); 473 474 /** Opens external medium using file-open dialog. 475 * @param enmMediumType Brings the medium type. 476 * @param pParent Brings the dialog parent. 477 * @param strDefaultFolder Brings the folder to browse for medium. 478 * @param fUseLastFolder Brings whether we should propose to use last used folder. */ 479 QUuid openMediumWithFileOpenDialog(UIMediumDeviceType enmMediumType, QWidget *pParent = 0, 480 const QString &strDefaultFolder = QString(), bool fUseLastFolder = false); 481 482 483 /** Creates and shows a UIMediumSelector dialog. 484 * @param parent Passes the parent of the dialog, 485 * @param enmMediumType Passes the medium type. 486 * @param strMachineName Passes the name of the machine, 487 * @param strMachineFolder Passes the machine folder, 488 * @param strMachineGuestOSTypeId Passes the type ID of machine's guest os, 489 * @param fEnableCreate Passes whether to show/enable create action in the medium selector dialog, 490 * @param uMachineID Passes the machine UUID, 491 * returns the return code of the UIMediumSelector::ReturnCode as int. In case of a medium selection 492 * UUID of the selected medium is stored in @param outUuid.*/ 493 int openMediumSelectorDialog(QWidget *pParent, UIMediumDeviceType enmMediumType, QUuid &outUuid, 494 const QString &strMachineFolder, const QString &strMachineName, 495 const QString &strMachineGuestOSTypeId, bool fEnableCreate, const QUuid &uMachineID = QUuid()); 496 497 /** Creates and shows a dialog (wizard) to create a medium of type @a enmMediumType. 498 * @param pParent Passes the parent of the dialog, 499 * @param enmMediumType Passes the medium type, 500 * @param strMachineName Passes the name of the machine, 501 * @param strMachineFolder Passes the machine folder, 502 * @param strMachineGuestOSTypeId Passes the type ID of machine's guest os, 503 * @param fEnableCreate Passes whether to show/enable create action in the medium selector dialog. */ 504 void openMediumCreatorDialog(QWidget *pParent, UIMediumDeviceType enmMediumType, 505 const QString &strMachineFolder = QString(), 506 const QString &strMachineName = QString(), 507 const QString &strMachineGuestOSTypeId = QString()); 508 509 /** Prepares storage menu according passed parameters. 510 * @param menu Brings the #QMenu to be prepared. 511 * @param pListener Brings the listener #QObject, this @a menu being prepared for. 512 * @param pszSlotName Brings the name of the SLOT in the @a pListener above, this menu will be handled with. 513 * @param comMachine Brings the #CMachine object, this @a menu being prepared for. 514 * @param strControllerName Brings the name of the #CStorageController in the @a machine above. 515 * @param storageSlot Brings the #StorageSlot of the storage controller with @a strControllerName above. */ 516 void prepareStorageMenu(QMenu &menu, 517 QObject *pListener, const char *pszSlotName, 518 const CMachine &comMachine, const QString &strControllerName, const StorageSlot &storageSlot); 519 /** Updates @a comConstMachine storage with data described by @a target. */ 520 void updateMachineStorage(const CMachine &comConstMachine, const UIMediumTarget &target); 521 522 /** Generates details for passed @a comMedium. 523 * @param fPredictDiff Brings whether medium will be marked differencing on attaching. 524 * @param fUseHtml Brings whether HTML subsets should be used in the generated output. */ 525 QString details(const CMedium &comMedium, bool fPredictDiff, bool fUseHtml = true); 526 527 /** Update extra data related to recently used/referred media. 528 * @param enmMediumType Passes the medium type. 529 * @param strMediumLocation Passes the medium location. */ 530 void updateRecentlyUsedMediumListAndFolder(UIMediumDeviceType enmMediumType, QString strMediumLocation); 531 532 /** Searches extra data for the recently used folder path which corresponds to @a enmMediumType. When that search fails 533 it looks for recent folder extra data for other medium types. As the last resort returns default vm folder path. 534 * @param enmMediumType Passes the medium type. */ 535 QString defaultFolderPathForType(UIMediumDeviceType enmMediumType); 536 /** @} */ 537 538 /** @name COM: USB stuff. 539 * @{ */ 540 #ifdef RT_OS_LINUX 541 /** Verifies that USB drivers are properly configured on Linux. */ 542 static void checkForWrongUSBMounted(); 543 #endif 544 545 /** Generates details for passed USB @a comDevice. */ 546 static QString details(const CUSBDevice &comDevice); 547 /** Generates tool-tip for passed USB @a comDevice. */ 548 static QString toolTip(const CUSBDevice &comDevice); 549 /** Generates tool-tip for passed USB @a comFilter. */ 550 static QString toolTip(const CUSBDeviceFilter &comFilter); 551 /** Generates tool-tip for passed USB @a comWebcam. */ 552 static QString toolTip(const CHostVideoInputDevice &comWebcam); 553 /** @} */ 554 555 /** @name COM: Extension Pack stuff. 556 * @{ */ 557 /** Initiates the extension pack installation process. 558 * @param strFilePath Brings the extension pack file path. 559 * @param strDigest Brings the extension pack file digest. 560 * @param pParent Brings the parent dialog reference. 561 * @param pstrExtPackName Brings the extension pack name. */ 562 void doExtPackInstallation(QString const &strFilePath, 563 QString const &strDigest, 564 QWidget *pParent, 565 QString *pstrExtPackName) const; 566 /** @} */ 567 568 /** @name Display stuff. 569 * @{ */ 570 #ifdef VBOX_WITH_3D_ACCELERATION 571 /** Returns whether guest OS type with passed @a strGuestOSTypeId is WDDM compatible. */ 572 static bool isWddmCompatibleOsType(const QString &strGuestOSTypeId); 573 #endif 574 /** Returns the required video memory in bytes for the current desktop 575 * resolution at maximum possible screen depth in bpp. */ 576 static quint64 requiredVideoMemory(const QString &strGuestOSTypeId, int cMonitors = 1); 577 /** @} */ 578 579 /** @name Thread stuff. 580 * @{ */ 581 /** Returns the thread-pool instance. */ 582 UIThreadPool *threadPool() const { return m_pThreadPool; } 583 /** Returns the thread-pool instance for cloud needs. */ 584 UIThreadPool *threadPoolCloud() const { return m_pThreadPoolCloud; } 585 /** @} */ 586 587 /** @name Icon/Pixmap stuff. 588 * @{ */ 589 /** Returns icon defined for a passed @a comMachine. */ 590 QIcon vmUserIcon(const CMachine &comMachine) const; 591 /** Returns pixmap of a passed @a size defined for a passed @a comMachine. */ 592 QPixmap vmUserPixmap(const CMachine &comMachine, const QSize &size) const; 593 /** Returns pixmap defined for a passed @a comMachine. 594 * In case if non-null @a pLogicalSize pointer provided, it will be updated properly. */ 595 QPixmap vmUserPixmapDefault(const CMachine &comMachine, QSize *pLogicalSize = 0) const; 596 597 /** Returns pixmap corresponding to passed @a strOSTypeID. */ 598 QIcon vmGuestOSTypeIcon(const QString &strOSTypeID) const; 599 /** Returns pixmap corresponding to passed @a strOSTypeID and @a size. */ 600 QPixmap vmGuestOSTypePixmap(const QString &strOSTypeID, const QSize &size) const; 601 /** Returns pixmap corresponding to passed @a strOSTypeID. 602 * In case if non-null @a pLogicalSize pointer provided, it will be updated properly. */ 603 QPixmap vmGuestOSTypePixmapDefault(const QString &strOSTypeID, QSize *pLogicalSize = 0) const; 604 605 /** Returns default icon of certain @a enmType. */ 606 QIcon icon(QFileIconProvider::IconType enmType) { return m_fileIconProvider.icon(enmType); } 607 /** Returns file icon fetched from passed file @a info. */ 608 QIcon icon(const QFileInfo &info) { return m_fileIconProvider.icon(info); } 609 610 /** Returns cached default warning pixmap. */ 611 QPixmap warningIcon() const { return m_pixWarning; } 612 /** Returns cached default error pixmap. */ 613 QPixmap errorIcon() const { return m_pixError; } 614 615 /** Joins two pixmaps horizontally with 2px space between them and returns the result. */ 616 static QPixmap joinPixmaps(const QPixmap &pixmap1, const QPixmap &pixmap2); 617 /** @} */ 618 619 /** @name Context sensitive help related functionality 620 * @{ */ 621 /** Sets the property for help keyword on a QObject 622 * @param pObject The object to set the help keyword property on 623 * @param strKeyword The values of the key word property. */ 624 static void setHelpKeyword(QObject *pObject, const QString &strHelpKeyword); 625 /** Returns the property for help keyword of a QObject. If no such property exists returns an empty QString. 626 * @param pWidget The object to get the help keyword property from. */ 627 static QString helpKeyword(const QObject *pWidget); 628 /** @} */ 629 630 public slots: 631 632 /** @name Process arguments stuff. 633 * @{ */ 634 /** Opens the specified URL using OS/Desktop capabilities. */ 635 bool openURL(const QString &strURL) const; 636 /** @} */ 637 638 /** @name Localization stuff. 639 * @{ */ 640 /** Handles language change to new @a strLanguage. */ 641 void sltGUILanguageChange(QString strLanguage); 642 /** @} */ 643 644 /** @name Media related stuff. 645 * @{ */ 646 /** Handles signal about medium was created. */ 647 void sltHandleMediumCreated(const CMedium &comMedium); 648 /** @} */ 649 650 /** @name Machine related stuff. 651 * @{ */ 652 /** Handles signal about machine was created. */ 653 void sltHandleMachineCreated(const CMachine &comMachine); 654 /** @} */ 655 656 /** @name Cloud Machine related stuff. 657 * @{ */ 658 /** Handles signal about cloud machine was added. */ 659 void sltHandleCloudMachineAdded(const QString &strProviderShortName, 660 const QString &strProfileName, 661 const CCloudMachine &comMachine); 662 /** @} */ 663 664 protected: 665 666 /** Preprocesses any Qt @a pEvent for passed @a pObject. */ 667 virtual bool eventFilter(QObject *pObject, QEvent *pEvent) /* override */; 668 669 /** Handles translation event. */ 670 virtual void retranslateUi() /* override */; 671 672 protected slots: 673 674 /** Calls for cleanup() functionality. */ 675 void sltCleanup() { cleanup(); } 676 677 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1 678 /** @name Common stuff. 679 * @{ */ 680 /** Handles @a manager request for emergency session shutdown. */ 681 void sltHandleCommitDataRequest(QSessionManager &manager); 682 /** @} */ 683 #endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */ 684 685 /** @name COM stuff. 686 * @{ */ 687 /** Handles the VBoxSVC availability change. */ 688 void sltHandleVBoxSVCAvailabilityChange(bool fAvailable); 689 /** @} */ 690 691 private: 692 693 /** Construcs global VirtualBox object of passed @a enmType. */ 694 UICommon(UIType enmType); 695 /** Destrucs global VirtualBox object. */ 696 virtual ~UICommon() /* override final */; 697 698 /** Prepares all. */ 699 void prepare(); 700 /** Cleanups all. */ 701 void cleanup(); 702 703 /** @name COM: Virtual Media create functions. 704 * @{ */ 705 706 /** Creates a VISO by using the VISO creator dialog. 707 * @param pParent Passes the dialog parent. 708 * @param strDefaultFolder Passes the folder to save the VISO file. 709 * @param strMachineName Passes the name of the machine, */ 710 QUuid createVisoMediumWithVisoCreator(QWidget *pParent, const QString &strDefaultFolder = QString(), const QString &strMachineName = QString()); 711 712 /** Creates and shows a dialog thru which user can create a new floppy disk a VISO using the file-open dialog. 713 * @param parent Passes the parent of the dialog, 714 * @param strDefaultFolder Passes the default folder, 715 * @param strMachineName Passes the name of the machine, 716 * returns the ID of the newly created medium if successful, a null QUuid otherwise.*/ 717 QUuid showCreateFloppyDiskDialog(QWidget *pParent, const QString &strDefaultFolder = QString(), 718 const QString &strMachineName = QString()); 719 720 /** Creates and shows a UIWizardNewVD wizard. 721 * @param pParent Passes the parent of the wizard, 722 * @param strMachineFolder Passes the machine folder, 723 * @param strMachineName Passes the name of the machine, 724 * @param strMachineGuestOSTypeId Passes the string of machine's guest OS type ID. */ 725 void createVDWithWizard(QWidget *pParent, 726 const QString &strMachineFolder = QString(), 727 const QString &strMachineName = QString(), 728 const QString &strMachineGuestOSTypeId = QString()); 729 /** @} */ 730 731 /** @name Common stuff. 732 * @{ */ 733 #ifdef VBOX_WS_WIN 734 /** Wraps WinAPI ShutdownBlockReasonCreate function. */ 735 static BOOL ShutdownBlockReasonCreateAPI(HWND hWnd, LPCWSTR pwszReason); 736 #endif 737 /** @} */ 738 739 /** @name Process arguments stuff. 740 * @{ */ 741 #ifdef VBOX_WITH_DEBUGGER_GUI 742 /** Initializes a debugger config variable. 743 * @param piDbgCfgVar Brings the debugger config variable to init. 744 * @param pszEnvVar Brings the environment variable name relating to this variable. 745 * @param pszExtraDataName Brings the extra data name relating to this variable. 746 * @param fDefault Brings the default value. */ 747 void initDebuggerVar(int *piDbgCfgVar, const char *pszEnvVar, const char *pszExtraDataName, bool fDefault = false); 748 /** Set a debugger config variable according according to start up argument. 749 * @param piDbgCfgVar Brings the debugger config variable to set. 750 * @param fState Brings the value from the command line. */ 751 void setDebuggerVar(int *piDbgCfgVar, bool fState); 752 /** Checks the state of a debugger config variable, updating it with the machine settings on the first invocation. 753 * @param piDbgCfgVar Brings the debugger config variable to consult. 754 * @param pszExtraDataName Brings the extra data name relating to this variable. */ 755 bool isDebuggerWorker(int *piDbgCfgVar, const char *pszExtraDataName) const; 756 #endif 757 /** @} */ 758 759 /** @name COM stuff. 760 * @{ */ 761 /** Re-initializes COM wrappers and containers. */ 762 void comWrappersReinit(); 763 /** @} */ 764 765 /** Holds the singleton UICommon instance. */ 766 static UICommon *s_pInstance; 767 768 /** @name General stuff. 769 * @{ */ 770 /** Holds the UI type. */ 771 UIType m_enmType; 772 773 /** Holds whether UICommon instance is properly initialized. */ 774 bool m_fValid; 775 /** Holds whether UICommon instance cleanup is in progress. */ 776 bool m_fCleaningUp; 777 #ifdef VBOX_WS_WIN 778 /** Holds whether overall GUI data is committed. */ 779 bool m_fDataCommitted; 780 #endif 781 /** @} */ 782 783 /** @name Versioning stuff. 784 * @{ */ 785 /** Holds the VBox branding config file path. */ 786 QString m_strBrandingConfigFilePath; 787 /** @} */ 788 789 /** @name Host OS stuff. 790 * @{ */ 791 #ifdef VBOX_WS_MAC 792 /** Mac OS X: Holds the #MacOSXRelease determined using <i>uname</i> call. */ 793 MacOSXRelease m_enmMacOSVersion; 794 #endif 795 796 #ifdef VBOX_WS_X11 797 /** X11: Holds the #X11WMType of the Window Manager we are running under. */ 798 X11WMType m_enmWindowManagerType; 799 /** X11: Holds whether the Window Manager we are running at is composition one. */ 800 bool m_fCompositingManagerRunning; 801 #endif 802 /** @} */ 803 804 /** @name Process arguments stuff. 805 * @{ */ 806 /** Holds the URL arguments list. */ 807 QList<QUrl> m_listArgUrls; 808 809 /** Holds the --startvm option value (managed VM id). */ 810 QUuid m_strManagedVMId; 811 /** Holds the --separate option value (whether GUI process is separate from VM process). */ 812 bool m_fSeparateProcess; 813 /** Holds the --no-startvm-errormsgbox option value (whether startup VM errors are disabled). */ 814 bool m_fShowStartVMErrors; 815 816 /** Holds the --aggressive-caching / --no-aggressive-caching option value (whether medium-enumeration is required). */ 817 bool m_fAgressiveCaching; 818 819 /** Holds the --restore-current option value. */ 820 bool m_fRestoreCurrentSnapshot; 821 822 /** Holds the --fda option value (floppy image). */ 823 QUuid m_uFloppyImage; 824 /** Holds the --dvd | --cdrom option value (DVD image). */ 825 QUuid m_uDvdImage; 826 827 /** Holds the --disable-patm option value. */ 828 bool m_fDisablePatm; 829 /** Holds the --disable-csam option value. */ 830 bool m_fDisableCsam; 831 /** Holds the --recompile-supervisor option value. */ 832 bool m_fRecompileSupervisor; 833 /** Holds the --recompile-user option value. */ 834 bool m_fRecompileUser; 835 /** Holds the --execute-all-in-iem option value. */ 836 bool m_fExecuteAllInIem; 837 /** Holds the --warp-factor option value. */ 838 uint32_t m_uWarpPct; 839 840 #ifdef VBOX_WITH_DEBUGGER_GUI 841 /** Holds whether the debugger should be accessible. */ 842 mutable int m_fDbgEnabled; 843 /** Holds whether to show the debugger automatically with the console. */ 844 mutable int m_fDbgAutoShow; 845 /** Holds whether to show the command line window when m_fDbgAutoShow is set. */ 846 mutable int m_fDbgAutoShowCommandLine; 847 /** Holds whether to show the statistics window when m_fDbgAutoShow is set. */ 848 mutable int m_fDbgAutoShowStatistics; 849 /** Pattern of statistics to expand when opening the viewer. */ 850 QString m_strDbgStatisticsExpand; 851 /** The statistics viewer filter. */ 852 QString m_strDbgStatisticsFilter; 853 854 /** VBoxDbg module handle. */ 855 RTLDRMOD m_hVBoxDbg; 856 857 /** Holds whether --start-running, --start-paused or nothing was given. */ 858 LaunchRunning m_enmLaunchRunning; 859 #endif 860 861 /** Holds the --settingspw option value or the content of --settingspwfile. */ 862 char m_astrSettingsPw[256]; 863 /** Holds the --settingspwfile option value. */ 864 bool m_fSettingsPwSet; 865 866 #ifdef VBOX_GUI_WITH_PIDFILE 867 /** Holds the --pidfile option value (application PID file path). */ 868 QString m_strPidFile; 869 #endif 870 /** @} */ 871 872 /** @name COM stuff. 873 * @{ */ 874 /** Holds the COM cleanup protection token. */ 875 QReadWriteLock m_comCleanupProtectionToken; 876 877 /** Holds the instance of VirtualBox client wrapper. */ 878 CVirtualBoxClient m_comVBoxClient; 879 /** Holds the copy of VirtualBox object wrapper. */ 880 CVirtualBox m_comVBox; 881 /** Holds the copy of VirtualBox host-object wrapper. */ 882 CHost m_comHost; 883 /** Holds the symbolic VirtualBox home-folder representation. */ 884 QString m_strHomeFolder; 885 886 /** Holds whether acquired COM wrappers are currently valid. */ 887 bool m_fWrappersValid; 888 /** Holds whether VBoxSVC is currently available. */ 889 bool m_fVBoxSVCAvailable; 890 891 /** Holds the guest OS family IDs. */ 892 QList<QString> m_guestOSFamilyIDs; 893 /** Holds the guest OS family descriptions. */ 894 QMap<QString, QString> m_guestOSFamilyDescriptions; 895 /** Holds the guest OS types for each family ID. */ 896 QList<QList<CGuestOSType> > m_guestOSTypes; 897 /** @} */ 898 899 /** @name Thread stuff. 900 * @{ */ 901 /** Holds the thread-pool instance. */ 902 UIThreadPool *m_pThreadPool; 903 /** Holds the thread-pool instance for cloud needs. */ 904 UIThreadPool *m_pThreadPoolCloud; 905 /** @} */ 906 907 /** @name Icon/Pixmap stuff. 908 * @{ */ 909 /** Holds the general icon-pool instance. */ 910 UIIconPoolGeneral *m_pIconPool; 911 912 /** Holds the global file icon provider instance. */ 913 QFileIconProvider m_fileIconProvider; 914 915 /** Holds the warning pixmap. */ 916 QPixmap m_pixWarning; 917 /** Holds the error pixmap. */ 918 QPixmap m_pixError; 919 /** @} */ 920 921 /** @name Media related stuff. 922 * @{ */ 923 /** Holds the medium enumerator cleanup protection token. */ 924 mutable QReadWriteLock m_meCleanupProtectionToken; 925 926 /** Holds the medium enumerator. */ 927 UIMediumEnumerator *m_pMediumEnumerator; 928 /** List of medium names that should not appears in the recently used media extra data. */ 929 QStringList m_recentMediaExcludeList; 930 /** @} */ 931 932 #if defined(VBOX_WS_WIN) 933 /** @name ATL stuff. 934 * @{ */ 935 /** Holds the ATL module instance (for use with UICommon shared library only). 936 * @note Required internally by ATL (constructor records instance in global variable). */ 937 ATL::CComModule _Module; 938 /** @} */ 939 #endif 940 941 /** Allows for shortcut access. */ 942 friend UICommon &uiCommon(); 943 }; 944 945 /** Singleton UICommon 'official' name. */ 946 inline UICommon &uiCommon() { return *UICommon::instance(); } 947 948 #endif /* !FEQT_INCLUDED_SRC_globals_UICommon_h */ 41 #endif /* !FEQT_INCLUDED_SRC_globals_UIExtension_h */ -
trunk/src/VBox/Frontends/VirtualBox/src/manager/UIVirtualBoxManager.cpp
r90893 r91009 44 44 #include "UIDesktopWidgetWatchdog.h" 45 45 #include "UIErrorString.h" 46 #include "UIExtension.h" 46 47 #include "UIExtensionPackManager.h" 47 48 #include "UIExtraDataManager.h" … … 692 693 #endif 693 694 /* Propose the user to install EP described by the arguments @a list. */ 694 uiCommon().doExtPackInstallation(strFile, QString(), this, NULL);695 UIExtension::install(strFile, QString(), this, NULL); 695 696 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER 696 697 /* Allow update manager to propose us to update EP: */ -
trunk/src/VBox/Frontends/VirtualBox/src/networking/UIUpdateManager.cpp
r90627 r91009 23 23 #include "UICommon.h" 24 24 #include "UIExecutionQueue.h" 25 #include "UIExtension.h" 25 26 #include "UIExtraDataManager.h" 26 27 #include "UIMessageCenter.h" … … 226 227 /* Warn the user about extension pack was downloaded and saved, propose to install it: */ 227 228 if (msgCenter().proposeInstallExtentionPack(GUI_ExtPackName, strSource, QDir::toNativeSeparators(strTarget))) 228 uiCommon().doExtPackInstallation(strTarget, strDigest, windowManager().mainWindowShown(), NULL);229 UIExtension::install(strTarget, strDigest, windowManager().mainWindowShown(), NULL); 229 230 /* Propose to delete the downloaded extension pack: */ 230 231 if (msgCenter().proposeDeleteExtentionPack(QDir::toNativeSeparators(strTarget)))
Note:
See TracChangeset
for help on using the changeset viewer.