VirtualBox

Changeset 90941 in vbox


Ignore:
Timestamp:
Aug 27, 2021 10:03:18 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
146579
Message:

FE/Qt: bugref:10067: Move translation stuff from UICommon to newly created UITranslator.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
5 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r90827 r90941  
    817817        src/globals/UIThreadPool.h \
    818818        src/globals/UITextTable.h \
     819        src/globals/UITranslator.h \
    819820        src/globals/UIVirtualBoxEventHandler.h \
    820821        src/globals/UIVirtualBoxClientEventHandler.h \
     
    13661367        src/globals/UITask.cpp \
    13671368        src/globals/UIThreadPool.cpp \
     1369        src/globals/UITranslator.cpp \
    13681370        src/globals/UIVersion.cpp \
    13691371        src/globals/UIVirtualBoxEventHandler.cpp \
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp

    r90939 r90941  
    7272#include "UIShortcutPool.h"
    7373#include "UIThreadPool.h"
     74#include "UITranslator.h"
    7475#include "UIVirtualBoxClientEventHandler.h"
    7576#include "UIVirtualBoxEventHandler.h"
     
    171172
    172173
    173 /** QTranslator subclass for VBox needs. */
    174 class VBoxTranslator : public QTranslator
    175 {
    176 public:
    177 
    178     /** Constructs translator passing @a pParent to the base-class. */
    179     VBoxTranslator(QObject *pParent = 0)
    180         : QTranslator(pParent)
    181     {}
    182 
    183     /** Loads language file with gained @a strFileName. */
    184     bool loadFile(const QString &strFileName)
    185     {
    186         QFile file(strFileName);
    187         if (!file.open(QIODevice::ReadOnly))
    188             return false;
    189         m_data = file.readAll();
    190         return load((uchar*)m_data.data(), m_data.size());
    191     }
    192 
    193 private:
    194 
    195     /** Holds the loaded data. */
    196     QByteArray m_data;
    197 };
    198 
    199 /** Holds the static #VBoxTranslator instance. */
    200 static VBoxTranslator *sTranslator = 0;
    201 
    202 
    203174/** Port config cache. */
    204175struct PortConfig
     
    233204/* static */
    234205UICommon *UICommon::s_pInstance = 0;
    235 QString   UICommon::s_strLoadedLanguageId = vboxBuiltInLanguageName();
    236206QString   UICommon::s_strUserDefinedPortName = QString();
    237207
     
    350320
    351321    /* Load translation based on the current locale: */
    352     loadLanguage();
     322    UITranslator::loadLanguage();
    353323
    354324    HRESULT rc = COMBase::InitializeCOM(true);
     
    399369
    400370    /* Load translation based on the user settings: */
    401     QString sLanguageId = gEDataManager->languageId();
    402     if (!sLanguageId.isNull())
    403         loadLanguage(sLanguageId);
     371    QString strLanguageId = gEDataManager->languageId();
     372    if (!strLanguageId.isNull())
     373        UITranslator::loadLanguage(strLanguageId);
    404374
    405375    retranslateUi();
     
    12031173#endif /* VBOX_GUI_WITH_PIDFILE */
    12041174
    1205 /* static */
    1206 QString UICommon::languageName()
    1207 {
    1208     /* Returns "English" if no translation is installed
    1209      * or if the translation file is invalid. */
    1210     return QApplication::translate("@@@", "English",
    1211                                    "Native language name");
    1212 }
    1213 
    1214 /* static */
    1215 QString UICommon::languageCountry()
    1216 {
    1217     /* Returns "--" if no translation is installed or if the translation file
    1218      * is invalid, or if the language is independent on the country. */
    1219     return QApplication::translate("@@@", "--",
    1220                                    "Native language country name "
    1221                                    "(empty if this language is for all countries)");
    1222 }
    1223 
    1224 /* static */
    1225 QString UICommon::languageNameEnglish()
    1226 {
    1227     /* Returns "English" if no translation is installed
    1228      * or if the translation file is invalid. */
    1229     return QApplication::translate("@@@", "English",
    1230                                    "Language name, in English");
    1231 }
    1232 
    1233 /* static */
    1234 QString UICommon::languageCountryEnglish()
    1235 {
    1236     /* Returns "--" if no translation is installed or if the translation file
    1237      * is invalid, or if the language is independent on the country. */
    1238     return QApplication::translate("@@@", "--",
    1239                                    "Language country name, in English "
    1240                                    "(empty if native country name is empty)");
    1241 }
    1242 
    1243 /* static */
    1244 QString UICommon::languageTranslators()
    1245 {
    1246     /* Returns "Oracle Corporation" if no translation is installed or if the translation file
    1247      * is invalid, or if the translation is supplied by Oracle Corporation. */
    1248     return QApplication::translate("@@@", "Oracle Corporation",
    1249                                    "Comma-separated list of translators");
    1250 }
    1251 
    1252 /* static */
    1253 QString UICommon::vboxLanguageSubDirectory()
    1254 {
    1255     return "/nls";
    1256 }
    1257 
    1258 /* static */
    1259 QString UICommon::vboxLanguageFileBase()
    1260 {
    1261     return "VirtualBox_";
    1262 }
    1263 
    1264 /* static */
    1265 QString UICommon::vboxLanguageFileExtension()
    1266 {
    1267     return ".qm";
    1268 }
    1269 
    1270 /* static */
    1271 QString UICommon::vboxLanguageIdRegExp()
    1272 {
    1273     return "(([a-z]{2})(?:_([A-Z]{2}))?)|(C)";
    1274 }
    1275 
    1276 /* static */
    1277 QString UICommon::vboxBuiltInLanguageName()
    1278 {
    1279     return "C";
    1280 }
    1281 
    1282 /* static */
    1283 QString UICommon::languageId()
    1284 {
    1285     /* Note that it may not match with UIExtraDataManager::languageId() if the specified language cannot be loaded.
    1286      *
    1287      * If the built-in language is active, this method returns "C". "C" is treated as the built-in language for
    1288      * simplicity -- the C locale is used in unix environments as a fallback when the requested locale is invalid.
    1289      * This way we don't need to process both the "built_in" language and the "C" language (which is a valid
    1290      * environment setting) separately. */
    1291 
    1292     return s_strLoadedLanguageId;
    1293 }
    1294 
    1295 /* static */
    1296 QString UICommon::systemLanguageId()
    1297 {
    1298     /* This does exactly the same as QLocale::system().name() but corrects its wrong behavior on Linux systems
    1299      * (LC_NUMERIC for some strange reason takes precedence over any other locale setting in the QLocale::system()
    1300      * implementation). This implementation first looks at LC_ALL (as defined by SUS), then looks at LC_MESSAGES
    1301      * which is designed to define a language for program messages in case if it differs from the language for
    1302      * other locale categories. Then it looks for LANG and finally falls back to QLocale::system().name().
    1303      *
    1304      * The order of precedence is well defined here:
    1305      * http://opengroup.org/onlinepubs/007908799/xbd/envvar.html
    1306      *
    1307      * This method will return "C" when the requested locale is invalid or when the "C" locale is set explicitly. */
    1308 
    1309 #if defined(VBOX_WS_MAC)
    1310     /* QLocale return the right id only if the user select the format
    1311      * of the language also. So we use our own implementation */
    1312     return ::darwinSystemLanguage();
    1313 #elif defined(Q_OS_UNIX)
    1314     const char *pszValue = RTEnvGet("LC_ALL");
    1315     if (pszValue == 0)
    1316         pszValue = RTEnvGet("LC_MESSAGES");
    1317     if (pszValue == 0)
    1318         pszValue = RTEnvGet("LANG");
    1319     if (pszValue != 0)
    1320         return QLocale(pszValue).name();
    1321 #endif
    1322     return QLocale::system().name();
    1323 }
    1324 
    13251175#ifdef VBOX_WS_WIN
    13261176/* static */
     
    13721222
    13731223/* static */
    1374 void UICommon::loadLanguage(const QString &strLangId)
    1375 {
    1376     QString strEffectiveLangId = strLangId.isEmpty()
    1377                                ? UICommon::systemLanguageId()
    1378                                : strLangId;
    1379     QString strLanguageFileName;
    1380     QString strSelectedLangId = vboxBuiltInLanguageName();
    1381 
    1382     /* If C is selected we change it temporary to en. This makes sure any extra
    1383      * "en" translation file will be loaded. This is necessary for loading the
    1384      * plural forms of some of our translations. */
    1385     bool fResetToC = false;
    1386     if (strEffectiveLangId == "C")
    1387     {
    1388         strEffectiveLangId = "en";
    1389         fResetToC = true;
    1390     }
    1391 
    1392     char szNlsPath[RTPATH_MAX];
    1393     int rc;
    1394 
    1395     rc = RTPathAppPrivateNoArch(szNlsPath, sizeof(szNlsPath));
    1396     AssertRC(rc);
    1397 
    1398     QString strNlsPath = QString(szNlsPath) + vboxLanguageSubDirectory();
    1399     QDir nlsDir(strNlsPath);
    1400 
    1401     Assert(!strEffectiveLangId.isEmpty());
    1402     if (!strEffectiveLangId.isEmpty() && strEffectiveLangId != vboxBuiltInLanguageName())
    1403     {
    1404         QRegExp regExp(vboxLanguageIdRegExp());
    1405         int iPos = regExp.indexIn(strEffectiveLangId);
    1406         /* The language ID should match the regexp completely: */
    1407         AssertReturnVoid(iPos == 0);
    1408 
    1409         QString strStrippedLangId = regExp.cap(2);
    1410 
    1411         if (nlsDir.exists(vboxLanguageFileBase() + strEffectiveLangId + vboxLanguageFileExtension()))
    1412         {
    1413             strLanguageFileName = nlsDir.absoluteFilePath(vboxLanguageFileBase() +
    1414                                                           strEffectiveLangId +
    1415                                                           vboxLanguageFileExtension());
    1416             strSelectedLangId = strEffectiveLangId;
    1417         }
    1418         else if (nlsDir.exists(vboxLanguageFileBase() + strStrippedLangId + vboxLanguageFileExtension()))
    1419         {
    1420             strLanguageFileName = nlsDir.absoluteFilePath(vboxLanguageFileBase() +
    1421                                                           strStrippedLangId +
    1422                                                           vboxLanguageFileExtension());
    1423             strSelectedLangId = strStrippedLangId;
    1424         }
    1425         else
    1426         {
    1427             /* Never complain when the default language is requested.  In any
    1428              * case, if no explicit language file exists, we will simply
    1429              * fall-back to English (built-in). */
    1430             if (!strLangId.isNull() && strEffectiveLangId != "en")
    1431                 msgCenter().cannotFindLanguage(strEffectiveLangId, strNlsPath);
    1432             /* strSelectedLangId remains built-in here: */
    1433             AssertReturnVoid(strSelectedLangId == vboxBuiltInLanguageName());
    1434         }
    1435     }
    1436 
    1437     /* Delete the old translator if there is one: */
    1438     if (sTranslator)
    1439     {
    1440         /* QTranslator destructor will call qApp->removeTranslator() for
    1441          * us. It will also delete all its child translations we attach to it
    1442          * below, so we don't have to care about them specially. */
    1443         delete sTranslator;
    1444     }
    1445 
    1446     /* Load new language files: */
    1447     sTranslator = new VBoxTranslator(qApp);
    1448     Assert(sTranslator);
    1449     bool fLoadOk = true;
    1450     if (sTranslator)
    1451     {
    1452         if (strSelectedLangId != vboxBuiltInLanguageName())
    1453         {
    1454             Assert(!strLanguageFileName.isNull());
    1455             fLoadOk = sTranslator->loadFile(strLanguageFileName);
    1456         }
    1457         /* We install the translator in any case: on failure, this will
    1458          * activate an empty translator that will give us English (built-in): */
    1459         qApp->installTranslator(sTranslator);
    1460     }
    1461     else
    1462         fLoadOk = false;
    1463 
    1464     if (fLoadOk)
    1465         s_strLoadedLanguageId = strSelectedLangId;
    1466     else
    1467     {
    1468         msgCenter().cannotLoadLanguage(strLanguageFileName);
    1469         s_strLoadedLanguageId = vboxBuiltInLanguageName();
    1470     }
    1471 
    1472     /* Try to load the corresponding Qt translation: */
    1473     if (languageId() != vboxBuiltInLanguageName() && languageId() != "en")
    1474     {
    1475 #ifdef Q_OS_UNIX
    1476         /* We use system installations of Qt on Linux systems, so first, try
    1477          * to load the Qt translation from the system location. */
    1478         strLanguageFileName = QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" +
    1479                               languageId() + vboxLanguageFileExtension();
    1480         QTranslator *pQtSysTr = new QTranslator(sTranslator);
    1481         Assert(pQtSysTr);
    1482         if (pQtSysTr && pQtSysTr->load(strLanguageFileName))
    1483             qApp->installTranslator(pQtSysTr);
    1484         /* Note that the Qt translation supplied by Oracle is always loaded
    1485          * afterwards to make sure it will take precedence over the system
    1486          * translation (it may contain more decent variants of translation
    1487          * that better correspond to VirtualBox UI). We need to load both
    1488          * because a newer version of Qt may be installed on the user computer
    1489          * and the Oracle version may not fully support it. We don't do it on
    1490          * Win32 because we supply a Qt library there and therefore the
    1491          * Oracle translation is always the best one. */
    1492 #endif
    1493         strLanguageFileName = nlsDir.absoluteFilePath(QString("qt_") +
    1494                                                       languageId() +
    1495                                                       vboxLanguageFileExtension());
    1496         QTranslator *pQtTr = new QTranslator(sTranslator);
    1497         Assert(pQtTr);
    1498         if (pQtTr && (fLoadOk = pQtTr->load(strLanguageFileName)))
    1499             qApp->installTranslator(pQtTr);
    1500         /* The below message doesn't fit 100% (because it's an additional
    1501          * language and the main one won't be reset to built-in on failure)
    1502          * but the load failure is so rare here that it's not worth a separate
    1503          * message (but still, having something is better than having none) */
    1504         if (!fLoadOk && !strLangId.isNull())
    1505             msgCenter().cannotLoadLanguage(strLanguageFileName);
    1506     }
    1507     if (fResetToC)
    1508         s_strLoadedLanguageId = vboxBuiltInLanguageName();
    1509 #ifdef VBOX_WS_MAC
    1510     /* Qt doesn't translate the items in the Application menu initially.
    1511      * Manually trigger an update. */
    1512     ::darwinRetranslateAppMenu();
    1513 #endif
    1514 }
    1515 
    1516 /* static */
    15171224QString UICommon::yearsToString(uint32_t cVal)
    15181225{
     
    20381745     * Note: if languageId() returns an empty string lang.name() will
    20391746     * return "C" which is an valid language code. */
    2040     QLocale lang(UICommon::languageId());
     1747    QLocale lang(UITranslator::languageId());
    20411748
    20421749    /* Construct the path and the filename: */
     
    31792886             * Note: if languageId() returns an empty string lang.name() will
    31802887             * return "C" which is an valid language code. */
    3181             QLocale lang(UICommon::languageId());
     2888            QLocale lang(UITranslator::languageId());
    31822889            comStartedMachine.SetGuestPropertyValue("/VirtualBox/HostInfo/GUI/LanguageID", lang.name());
    31832890        }
     
    46624369    AssertReturnVoid(!isMediumEnumerationInProgress());
    46634370    /* Load passed language: */
    4664     loadLanguage(strLanguage);
     4371    UITranslator::loadLanguage(strLanguage);
    46654372}
    46664373
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.h

    r90939 r90941  
    294294    /** @name Localization stuff.
    295295     * @{ */
    296         /** Native language name of the currently installed translation. */
    297         static QString languageName();
    298         /** Native language country name of the currently installed translation. */
    299         static QString languageCountry();
    300         /** Language name of the currently installed translation, in English. */
    301         static QString languageNameEnglish();
    302         /** Language country name of the currently installed translation, in English. */
    303         static QString languageCountryEnglish();
    304         /** Comma-separated list of authors of the currently installed translation. */
    305         static QString languageTranslators();
    306 
    307         /** Returns VBox language sub-directory. */
    308         static QString vboxLanguageSubDirectory();
    309         /** Returns VBox language file-base. */
    310         static QString vboxLanguageFileBase();
    311         /** Returns VBox language file-extension. */
    312         static QString vboxLanguageFileExtension();
    313         /** Returns VBox language ID reg-exp. */
    314         static QString vboxLanguageIdRegExp();
    315         /** Returns built in language name. */
    316         static QString vboxBuiltInLanguageName();
    317 
    318         /** Returns the loaded (active) language ID. */
    319         static QString languageId();
    320         /** Returns the system language ID. */
    321         static QString systemLanguageId();
    322 
    323296#ifdef VBOX_WS_WIN
    324297        /** Loads the color theme. */
    325298        static void loadColorTheme();
    326299#endif
    327 
    328         /** Loads the language by language ID.
    329           * @param  strLangId  Brings the language ID in in form of xx_YY.
    330           *                    QString() means the system default language. */
    331         static void loadLanguage(const QString &strLangId = QString());
    332300
    333301        /** Returns tr("%n year(s)"). */
     
    860828    /** @name Common stuff.
    861829     * @{ */
    862         /** Holds the currently loaded language ID. */
    863         static QString  s_strLoadedLanguageId;
    864 
    865830        /** Holds the tr("User Defined") port name. */
    866831        static QString  s_strUserDefinedPortName;
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp

    r90933 r90941  
    4040#include "UIModalWindowManager.h"
    4141#include "UIProgressDialog.h"
     42#include "UITranslator.h"
    4243#include "VBoxAboutDlg.h"
    4344#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
     
    28822883                          tr("<p>Are you sure you want to download the <b>VirtualBox Guest Additions</b> disk image file "
    28832884                             "from <nobr><a href=\"%1\">%1</a></nobr> (size %2 bytes)?</p>")
    2884                              .arg(strUrl, QLocale(UICommon::languageId()).toString(uSize)),
     2885                             .arg(strUrl, QLocale(UITranslator::languageId()).toString(uSize)),
    28852886                          0 /* auto-confirm id */,
    28862887                          tr("Download"));
     
    29432944                          tr("<p>Are you sure you want to download the <b>VirtualBox User Manual</b> "
    29442945                             "from <nobr><a href=\"%1\">%1</a></nobr> (size %2 bytes)?</p>")
    2945                              .arg(strURL, QLocale(UICommon::languageId()).toString(uSize)),
     2946                             .arg(strURL, QLocale(UITranslator::languageId()).toString(uSize)),
    29462947                          0 /* auto-confirm id */,
    29472948                          tr("Download"));
     
    29822983                          tr("<p>Are you sure you want to download the <b><nobr>%1</nobr></b> "
    29832984                             "from <nobr><a href=\"%2\">%2</a></nobr> (size %3 bytes)?</p>")
    2984                              .arg(strExtPackName, strURL, QLocale(UICommon::languageId()).toString(uSize)),
     2985                             .arg(strExtPackName, strURL, QLocale(UITranslator::languageId()).toString(uSize)),
    29852986                          0 /* auto-confirm id */,
    29862987                          tr("Download"));
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UITranslator.cpp

    r90939 r90941  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UICommon class implementation.
     3 * VBox Qt GUI - UITranslator class implementation.
    44 */
    55
     
    1717
    1818/* Qt includes: */
    19 #include <QDesktopServices>
     19#include <QApplication>
    2020#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_WIN
    41 # include <QEventLoop>
    42 # include <QStyleFactory>
    43 #endif
    44 #ifdef VBOX_WS_X11
    45 # include <QScreen>
    46 # include <QScrollBar>
    47 # include <QTextBrowser>
    48 # include <QX11Info>
    49 #endif
    50 #ifdef VBOX_GUI_WITH_PIDFILE
    51 # include <QTextStream>
    52 #endif
    5321
    5422/* GUI includes: */
    55 #include "QIDialogButtonBox.h"
    56 #include "QIFileDialog.h"
    57 #include "QIMessageBox.h"
    58 #include "QIWithRestorableGeometry.h"
    59 #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"
    6823#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 "UIVirtualBoxClientEventHandler.h"
    75 #include "UIVirtualBoxEventHandler.h"
    76 #include "UIVisoCreator.h"
    77 #include "UIWizardNewVD.h"
    78 #include "VBoxLicenseViewer.h"
    79 #ifdef VBOX_WS_MAC
    80 # include "UIMachineWindowFullscreen.h"
    81 # include "UIMachineWindowSeamless.h"
    82 # include "VBoxUtils-darwin.h"
    83 #endif
    84 #ifdef VBOX_WS_X11
    85 # include "UIHostComboEditor.h"
    86 # include "VBoxX11Helper.h"
    87 #endif
    88 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER
    89 # include "UINetworkRequestManager.h"
    90 # include "UIUpdateManager.h"
    91 #endif
    92 
    93 /* COM includes: */
    94 #include "CAudioAdapter.h"
    95 #include "CBIOSSettings.h"
    96 #include "CCloudMachine.h"
    97 #include "CConsole.h"
    98 #include "CExtPack.h"
    99 #include "CExtPackFile.h"
    100 #include "CExtPackManager.h"
    101 #include "CHostUSBDevice.h"
    102 #include "CHostVideoInputDevice.h"
    103 #include "CMachine.h"
    104 #include "CMediumAttachment.h"
    105 #include "CNetworkAdapter.h"
    106 #include "CSerialPort.h"
    107 #include "CSharedFolder.h"
    108 #include "CSnapshot.h"
    109 #include "CStorageController.h"
    110 #include "CSystemProperties.h"
    111 #include "CUSBController.h"
    112 #include "CUSBDevice.h"
    113 #include "CUSBDeviceFilter.h"
    114 #include "CUSBDeviceFilters.h"
    115 #include "CVRDEServer.h"
     24#include "UITranslator.h"
    11625
    11726/* Other VBox includes: */
    118 #include <iprt/asm.h>
    119 #include <iprt/ctype.h>
    120 #include <iprt/env.h>
    121 #include <iprt/err.h>
    122 #include <iprt/file.h>
    123 #include <iprt/getopt.h>
    124 #include <iprt/ldr.h>
    125 #include <iprt/param.h>
     27#include <iprt/assert.h>
    12628#include <iprt/path.h>
    127 #include <iprt/stream.h>
    128 #include <iprt/system.h>
    129 #ifdef VBOX_WS_X11
    130 # include <iprt/mem.h>
    131 #endif
    132 #include <VBox/sup.h>
    133 #include <VBox/VBoxOGL.h>
    134 #include <VBox/vd.h>
    135 #include <VBox/com/Guid.h>
    136 
    137 /* VirtualBox interface declarations: */
    138 #include <VBox/com/VirtualBox.h>
    139 
    140 /* External includes: */
    141 #ifdef VBOX_WS_WIN
    142 # include <iprt/win/shlobj.h>
    143 #endif
    144 #ifdef VBOX_WS_X11
    145 # include <xcb/xcb.h>
    146 #endif
    147 
    148 /* External includes: */
    149 #include <math.h>
    150 #ifdef VBOX_WS_MAC
    151 # include <sys/utsname.h>
    152 #endif
    153 #ifdef VBOX_WS_X11
    154 // WORKAROUND:
    155 // typedef CARD8 BOOL in Xmd.h conflicts with #define BOOL PRBool
    156 // in COMDefs.h. A better fix would be to isolate X11-specific
    157 // stuff by placing XX* helpers below to a separate source file.
    158 # undef BOOL
    159 # include <X11/X.h>
    160 # include <X11/Xmd.h>
    161 # include <X11/Xlib.h>
    162 # include <X11/Xatom.h>
    163 # include <X11/Xutil.h>
    164 # include <X11/extensions/Xinerama.h>
    165 # define BOOL PRBool
    166 #endif
    167 
    168 /* Namespaces: */
    169 using namespace UIExtraDataDefs;
    170 using namespace UIMediumDefs;
    171 
    172 
    173 /** QTranslator subclass for VBox needs. */
    174 class VBoxTranslator : public QTranslator
    175 {
    176 public:
    177 
    178     /** Constructs translator passing @a pParent to the base-class. */
    179     VBoxTranslator(QObject *pParent = 0)
    180         : QTranslator(pParent)
    181     {}
    182 
    183     /** Loads language file with gained @a strFileName. */
    184     bool loadFile(const QString &strFileName)
    185     {
    186         QFile file(strFileName);
    187         if (!file.open(QIODevice::ReadOnly))
    188             return false;
    189         m_data = file.readAll();
    190         return load((uchar*)m_data.data(), m_data.size());
    191     }
    192 
    193 private:
    194 
    195     /** Holds the loaded data. */
    196     QByteArray m_data;
    197 };
    198 
    199 /** Holds the static #VBoxTranslator instance. */
    200 static VBoxTranslator *sTranslator = 0;
    201 
    202 
    203 /** Port config cache. */
    204 struct PortConfig
    205 {
    206     const char *name;
    207     const ulong IRQ;
    208     const ulong IOBase;
    209 };
    210 
    211 /** Known port config COM ports. */
    212 static const PortConfig kComKnownPorts[] =
    213 {
    214     { "COM1", 4, 0x3F8 },
    215     { "COM2", 3, 0x2F8 },
    216     { "COM3", 4, 0x3E8 },
    217     { "COM4", 3, 0x2E8 },
    218     /* Must not contain an element with IRQ=0 and IOBase=0 used to cause
    219      * toCOMPortName() to return the "User-defined" string for these values. */
    220 };
    221 
    222 /** Known port config LPT ports. */
    223 static const PortConfig kLptKnownPorts[] =
    224 {
    225     { "LPT1", 7, 0x378 },
    226     { "LPT2", 5, 0x278 },
    227     { "LPT1", 2, 0x3BC },
    228     /* Must not contain an element with IRQ=0 and IOBase=0 used to cause
    229      * toLPTPortName() to return the "User-defined" string for these values. */
    230 };
    231 
    232 
    233 /* static */
    234 UICommon *UICommon::s_pInstance = 0;
    235 QString   UICommon::s_strLoadedLanguageId = vboxBuiltInLanguageName();
    236 QString   UICommon::s_strUserDefinedPortName = QString();
    237 
    238 /* static */
    239 void UICommon::create(UIType enmType)
    240 {
    241     /* Make sure instance is NOT created yet: */
    242     AssertReturnVoid(!s_pInstance);
    243 
    244     /* Create instance: */
    245     new UICommon(enmType);
    246     /* Prepare instance: */
    247     s_pInstance->prepare();
    248 }
    249 
    250 /* static */
    251 void UICommon::destroy()
    252 {
    253     /* Make sure instance is NOT destroyed yet: */
    254     AssertPtrReturnVoid(s_pInstance);
    255 
    256     /* Cleanup instance:
    257      * 1. By default, automatically on QApplication::aboutToQuit() signal.
    258      * 2. But if QApplication was not started at all and we perform
    259      *    early shutdown, we should do cleanup ourselves. */
    260     if (s_pInstance->isValid())
    261         s_pInstance->cleanup();
    262     /* Destroy instance: */
    263     delete s_pInstance;
    264 }
    265 
    266 UICommon::UICommon(UIType enmType)
    267     : m_enmType(enmType)
    268     , m_fValid(false)
    269     , m_fCleaningUp(false)
    270 #ifdef VBOX_WS_WIN
    271     , m_fDataCommitted(false)
    272 #endif
    273 #ifdef VBOX_WS_MAC
    274     , m_enmMacOSVersion(MacOSXRelease_Old)
    275 #endif
    276 #ifdef VBOX_WS_X11
    277     , m_enmWindowManagerType(X11WMType_Unknown)
    278     , m_fCompositingManagerRunning(false)
    279 #endif
    280     , m_fSeparateProcess(false)
    281     , m_fShowStartVMErrors(true)
    282 #if defined(DEBUG_bird)
    283     , m_fAgressiveCaching(false)
    284 #else
    285     , m_fAgressiveCaching(true)
    286 #endif
    287     , m_fRestoreCurrentSnapshot(false)
    288     , m_fDisablePatm(false)
    289     , m_fDisableCsam(false)
    290     , m_fRecompileSupervisor(false)
    291     , m_fRecompileUser(false)
    292     , m_fExecuteAllInIem(false)
    293     , m_uWarpPct(100)
    294 #ifdef VBOX_WITH_DEBUGGER_GUI
    295     , m_fDbgEnabled(0)
    296     , m_fDbgAutoShow(0)
    297     , m_fDbgAutoShowCommandLine(0)
    298     , m_fDbgAutoShowStatistics(0)
    299     , m_hVBoxDbg(NIL_RTLDRMOD)
    300     , m_enmLaunchRunning(LaunchRunning_Default)
    301 #endif
    302     , m_fSettingsPwSet(false)
    303     , m_fWrappersValid(false)
    304     , m_fVBoxSVCAvailable(true)
    305     , m_pThreadPool(0)
    306     , m_pThreadPoolCloud(0)
    307     , m_pIconPool(0)
    308     , m_pMediumEnumerator(0)
    309 {
    310     /* Assign instance: */
    311     s_pInstance = this;
    312 }
    313 
    314 UICommon::~UICommon()
    315 {
    316     /* Unassign instance: */
    317     s_pInstance = 0;
    318 }
    319 
    320 void UICommon::prepare()
    321 {
    322     /* Make sure QApplication cleanup us on exit: */
    323     qApp->setFallbackSessionManagementEnabled(false);
    324     connect(qApp, &QGuiApplication::aboutToQuit,
    325             this, &UICommon::sltCleanup);
    326 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1
    327     /* Make sure we handle host OS session shutdown as well: */
    328     connect(qApp, &QGuiApplication::commitDataRequest,
    329             this, &UICommon::sltHandleCommitDataRequest);
    330 #endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
    331 
    332 #ifdef VBOX_WS_MAC
    333     /* Determine OS release early: */
    334     m_enmMacOSVersion = determineOsRelease();
    335 #endif /* VBOX_WS_MAC */
    336 
    337     /* Create converter: */
    338     UIConverter::create();
    339 
    340     /* Create desktop-widget watchdog: */
    341     UIDesktopWidgetWatchdog::create();
    342 
    343     /* Create message-center: */
    344     UIMessageCenter::create();
    345     /* Create popup-center: */
    346     UIPopupCenter::create();
    347 
    348     /* Prepare general icon-pool: */
    349     m_pIconPool = new UIIconPoolGeneral;
    350 
    351     /* Load translation based on the current locale: */
    352     loadLanguage();
    353 
    354     HRESULT rc = COMBase::InitializeCOM(true);
    355     if (FAILED(rc))
    356     {
    357 #ifdef VBOX_WITH_XPCOM
    358         if (rc == NS_ERROR_FILE_ACCESS_DENIED)
    359         {
    360             char szHome[RTPATH_MAX] = "";
    361             com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome));
    362             msgCenter().cannotInitUserHome(QString(szHome));
    363         }
    364         else
    365 #endif
    366             msgCenter().cannotInitCOM(rc);
    367         return;
    368     }
    369 
    370     /* Make sure VirtualBoxClient instance created: */
    371     m_comVBoxClient.createInstance(CLSID_VirtualBoxClient);
    372     if (!m_comVBoxClient.isOk())
    373     {
    374         msgCenter().cannotCreateVirtualBoxClient(m_comVBoxClient);
    375         return;
    376     }
    377     /* Make sure VirtualBox instance acquired: */
    378     m_comVBox = m_comVBoxClient.GetVirtualBox();
    379     if (!m_comVBoxClient.isOk())
    380     {
    381         msgCenter().cannotAcquireVirtualBox(m_comVBoxClient);
    382         return;
    383     }
    384     /* Init wrappers: */
    385     comWrappersReinit();
    386 
    387     /* Watch for the VBoxSVC availability changes: */
    388     connect(gVBoxClientEvents, &UIVirtualBoxClientEventHandler::sigVBoxSVCAvailabilityChange,
    389             this, &UICommon::sltHandleVBoxSVCAvailabilityChange);
    390 
    391     /* Prepare thread-pool instances: */
    392     m_pThreadPool = new UIThreadPool(3 /* worker count */, 5000 /* worker timeout */);
    393     m_pThreadPoolCloud = new UIThreadPool(2 /* worker count */, 1000 /* worker timeout */);
    394 
    395 #ifdef VBOX_WS_WIN
    396     /* Load color theme: */
    397     loadColorTheme();
    398 #endif
    399 
    400     /* Load translation based on the user settings: */
    401     QString sLanguageId = gEDataManager->languageId();
    402     if (!sLanguageId.isNull())
    403         loadLanguage(sLanguageId);
    404 
    405     retranslateUi();
    406 
    407     connect(gEDataManager, &UIExtraDataManager::sigLanguageChange,
    408             this, &UICommon::sltGUILanguageChange);
    409 
    410     qApp->installEventFilter(this);
    411 
    412     /* process command line */
    413 
    414     UIVisualStateType visualStateType = UIVisualStateType_Invalid;
    415 
    416 #ifdef VBOX_WS_X11
    417     /* Check whether we have compositing manager running: */
    418     m_fCompositingManagerRunning = X11IsCompositingManagerRunning();
    419 
    420     /* Acquire current Window Manager type: */
    421     m_enmWindowManagerType = X11WindowManagerType();
    422 #endif /* VBOX_WS_X11 */
    423 
    424 #ifdef VBOX_WITH_DEBUGGER_GUI
    425 # ifdef VBOX_WITH_DEBUGGER_GUI_MENU
    426     initDebuggerVar(&m_fDbgEnabled, "VBOX_GUI_DBG_ENABLED", GUI_Dbg_Enabled, true);
    427 # else
    428     initDebuggerVar(&m_fDbgEnabled, "VBOX_GUI_DBG_ENABLED", GUI_Dbg_Enabled, false);
    429 # endif
    430     initDebuggerVar(&m_fDbgAutoShow, "VBOX_GUI_DBG_AUTO_SHOW", GUI_Dbg_AutoShow, false);
    431     m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = m_fDbgAutoShow;
    432 #endif
    433 
    434     /*
    435      * Parse the command line options.
    436      *
    437      * This is a little sloppy but we're trying to tighten it up.  Unfortuately,
    438      * both on X11 and darwin (IIRC) there might be additional arguments aimed
    439      * for client libraries with GUI processes.  So, using RTGetOpt or similar
    440      * is a bit hard since we have to cope with unknown options.
    441      */
    442     m_fShowStartVMErrors = true;
    443     bool startVM = false;
    444     bool fSeparateProcess = false;
    445     QString vmNameOrUuid;
    446 
    447     const QStringList &arguments = QCoreApplication::arguments();
    448     const int argc = arguments.size();
    449     int i = 1;
    450     while (i < argc)
    451     {
    452         const QByteArray &argBytes = arguments.at(i).toUtf8();
    453         const char *arg = argBytes.constData();
    454         enum { OptType_Unknown, OptType_VMRunner, OptType_VMSelector, OptType_MaybeBoth } enmOptType = OptType_Unknown;
    455         /* NOTE: the check here must match the corresponding check for the
    456          * options to start a VM in main.cpp and hardenedmain.cpp exactly,
    457          * otherwise there will be weird error messages. */
    458         if (   !::strcmp(arg, "--startvm")
    459             || !::strcmp(arg, "-startvm"))
    460         {
    461             enmOptType = OptType_VMRunner;
    462             if (++i < argc)
    463             {
    464                 vmNameOrUuid = arguments.at(i);
    465                 startVM = true;
    466             }
    467         }
    468         else if (!::strcmp(arg, "-separate") || !::strcmp(arg, "--separate"))
    469         {
    470             enmOptType = OptType_VMRunner;
    471             fSeparateProcess = true;
    472         }
    473 #ifdef VBOX_GUI_WITH_PIDFILE
    474         else if (!::strcmp(arg, "-pidfile") || !::strcmp(arg, "--pidfile"))
    475         {
    476             enmOptType = OptType_MaybeBoth;
    477             if (++i < argc)
    478                 m_strPidFile = arguments.at(i);
    479         }
    480 #endif /* VBOX_GUI_WITH_PIDFILE */
    481         /* Visual state type options: */
    482         else if (!::strcmp(arg, "-normal") || !::strcmp(arg, "--normal"))
    483         {
    484             enmOptType = OptType_MaybeBoth;
    485             visualStateType = UIVisualStateType_Normal;
    486         }
    487         else if (!::strcmp(arg, "-fullscreen") || !::strcmp(arg, "--fullscreen"))
    488         {
    489             enmOptType = OptType_MaybeBoth;
    490             visualStateType = UIVisualStateType_Fullscreen;
    491         }
    492         else if (!::strcmp(arg, "-seamless") || !::strcmp(arg, "--seamless"))
    493         {
    494             enmOptType = OptType_MaybeBoth;
    495             visualStateType = UIVisualStateType_Seamless;
    496         }
    497         else if (!::strcmp(arg, "-scale") || !::strcmp(arg, "--scale"))
    498         {
    499             enmOptType = OptType_MaybeBoth;
    500             visualStateType = UIVisualStateType_Scale;
    501         }
    502         /* Passwords: */
    503         else if (!::strcmp(arg, "--settingspw"))
    504         {
    505             enmOptType = OptType_MaybeBoth;
    506             if (++i < argc)
    507             {
    508                 RTStrCopy(m_astrSettingsPw, sizeof(m_astrSettingsPw), arguments.at(i).toLocal8Bit().constData());
    509                 m_fSettingsPwSet = true;
    510             }
    511         }
    512         else if (!::strcmp(arg, "--settingspwfile"))
    513         {
    514             enmOptType = OptType_MaybeBoth;
    515             if (++i < argc)
    516             {
    517                 const QByteArray &argFileBytes = arguments.at(i).toLocal8Bit();
    518                 const char *pszFile = argFileBytes.constData();
    519                 bool fStdIn = !::strcmp(pszFile, "stdin");
    520                 int vrc = VINF_SUCCESS;
    521                 PRTSTREAM pStrm;
    522                 if (!fStdIn)
    523                     vrc = RTStrmOpen(pszFile, "r", &pStrm);
    524                 else
    525                     pStrm = g_pStdIn;
    526                 if (RT_SUCCESS(vrc))
    527                 {
    528                     size_t cbFile;
    529                     vrc = RTStrmReadEx(pStrm, m_astrSettingsPw, sizeof(m_astrSettingsPw) - 1, &cbFile);
    530                     if (RT_SUCCESS(vrc))
    531                     {
    532                         if (cbFile >= sizeof(m_astrSettingsPw) - 1)
    533                             cbFile = sizeof(m_astrSettingsPw) - 1;
    534                         unsigned i;
    535                         for (i = 0; i < cbFile && !RT_C_IS_CNTRL(m_astrSettingsPw[i]); i++)
    536                             ;
    537                         m_astrSettingsPw[i] = '\0';
    538                         m_fSettingsPwSet = true;
    539                     }
    540                     if (!fStdIn)
    541                         RTStrmClose(pStrm);
    542                 }
    543             }
    544         }
    545         /* Misc options: */
    546         else if (!::strcmp(arg, "-comment") || !::strcmp(arg, "--comment"))
    547         {
    548             enmOptType = OptType_MaybeBoth;
    549             ++i;
    550         }
    551         else if (!::strcmp(arg, "--no-startvm-errormsgbox"))
    552         {
    553             enmOptType = OptType_VMRunner;
    554             m_fShowStartVMErrors = false;
    555         }
    556         else if (!::strcmp(arg, "--aggressive-caching"))
    557         {
    558             enmOptType = OptType_MaybeBoth;
    559             m_fAgressiveCaching = true;
    560         }
    561         else if (!::strcmp(arg, "--no-aggressive-caching"))
    562         {
    563             enmOptType = OptType_MaybeBoth;
    564             m_fAgressiveCaching = false;
    565         }
    566         else if (!::strcmp(arg, "--restore-current"))
    567         {
    568             enmOptType = OptType_VMRunner;
    569             m_fRestoreCurrentSnapshot = true;
    570         }
    571         /* Ad hoc VM reconfig options: */
    572         else if (!::strcmp(arg, "--fda"))
    573         {
    574             enmOptType = OptType_VMRunner;
    575             if (++i < argc)
    576                 m_strFloppyImage = arguments.at(i);
    577         }
    578         else if (!::strcmp(arg, "--dvd") || !::strcmp(arg, "--cdrom"))
    579         {
    580             enmOptType = OptType_VMRunner;
    581             if (++i < argc)
    582                 m_strDvdImage = arguments.at(i);
    583         }
    584         /* VMM Options: */
    585         else if (!::strcmp(arg, "--disable-patm"))
    586         {
    587             enmOptType = OptType_VMRunner;
    588             m_fDisablePatm = true;
    589         }
    590         else if (!::strcmp(arg, "--disable-csam"))
    591         {
    592             enmOptType = OptType_VMRunner;
    593             m_fDisableCsam = true;
    594         }
    595         else if (!::strcmp(arg, "--recompile-supervisor"))
    596         {
    597             enmOptType = OptType_VMRunner;
    598             m_fRecompileSupervisor = true;
    599         }
    600         else if (!::strcmp(arg, "--recompile-user"))
    601         {
    602             enmOptType = OptType_VMRunner;
    603             m_fRecompileUser = true;
    604         }
    605         else if (!::strcmp(arg, "--recompile-all"))
    606         {
    607             enmOptType = OptType_VMRunner;
    608             m_fDisablePatm = m_fDisableCsam = m_fRecompileSupervisor = m_fRecompileUser = true;
    609         }
    610         else if (!::strcmp(arg, "--execute-all-in-iem"))
    611         {
    612             enmOptType = OptType_VMRunner;
    613             m_fDisablePatm = m_fDisableCsam = m_fExecuteAllInIem = true;
    614         }
    615         else if (!::strcmp(arg, "--warp-pct"))
    616         {
    617             enmOptType = OptType_VMRunner;
    618             if (++i < argc)
    619                 m_uWarpPct = RTStrToUInt32(arguments.at(i).toLocal8Bit().constData());
    620         }
    621 #ifdef VBOX_WITH_DEBUGGER_GUI
    622         /* Debugger/Debugging options: */
    623         else if (!::strcmp(arg, "-dbg") || !::strcmp(arg, "--dbg"))
    624         {
    625             enmOptType = OptType_VMRunner;
    626             setDebuggerVar(&m_fDbgEnabled, true);
    627         }
    628         else if (!::strcmp( arg, "-debug") || !::strcmp(arg, "--debug"))
    629         {
    630             enmOptType = OptType_VMRunner;
    631             setDebuggerVar(&m_fDbgEnabled, true);
    632             setDebuggerVar(&m_fDbgAutoShow, true);
    633             setDebuggerVar(&m_fDbgAutoShowCommandLine, true);
    634             setDebuggerVar(&m_fDbgAutoShowStatistics, true);
    635         }
    636         else if (!::strcmp(arg, "--debug-command-line"))
    637         {
    638             enmOptType = OptType_VMRunner;
    639             setDebuggerVar(&m_fDbgEnabled, true);
    640             setDebuggerVar(&m_fDbgAutoShow, true);
    641             setDebuggerVar(&m_fDbgAutoShowCommandLine, true);
    642         }
    643         else if (!::strcmp(arg, "--debug-statistics"))
    644         {
    645             enmOptType = OptType_VMRunner;
    646             setDebuggerVar(&m_fDbgEnabled, true);
    647             setDebuggerVar(&m_fDbgAutoShow, true);
    648             setDebuggerVar(&m_fDbgAutoShowStatistics, true);
    649         }
    650         else if (!::strcmp(arg, "--statistics-expand") || !::strcmp(arg, "--stats-expand"))
    651         {
    652             enmOptType = OptType_VMRunner;
    653             if (++i < argc)
    654             {
    655                 if (!m_strDbgStatisticsExpand.isEmpty())
    656                     m_strDbgStatisticsExpand.append('|');
    657                 m_strDbgStatisticsExpand.append(arguments.at(i));
    658             }
    659         }
    660         else if (!::strncmp(arg, RT_STR_TUPLE("--statistics-expand=")) || !::strncmp(arg, RT_STR_TUPLE("--stats-expand=")))
    661         {
    662             enmOptType = OptType_VMRunner;
    663             if (!m_strDbgStatisticsExpand.isEmpty())
    664                 m_strDbgStatisticsExpand.append('|');
    665             m_strDbgStatisticsExpand.append(arguments.at(i).section('=', 1));
    666         }
    667         else if (!::strcmp(arg, "--statistics-filter") || !::strcmp(arg, "--stats-filter"))
    668         {
    669             enmOptType = OptType_VMRunner;
    670             if (++i < argc)
    671                 m_strDbgStatisticsFilter = arguments.at(i);
    672         }
    673         else if (!::strncmp(arg, RT_STR_TUPLE("--statistics-filter=")) || !::strncmp(arg, RT_STR_TUPLE("--stats-filter=")))
    674         {
    675             enmOptType = OptType_VMRunner;
    676             m_strDbgStatisticsFilter = arguments.at(i).section('=', 1);
    677         }
    678         else if (!::strcmp(arg, "-no-debug") || !::strcmp(arg, "--no-debug"))
    679         {
    680             enmOptType = OptType_VMRunner;
    681             setDebuggerVar(&m_fDbgEnabled, false);
    682             setDebuggerVar(&m_fDbgAutoShow, false);
    683             setDebuggerVar(&m_fDbgAutoShowCommandLine, false);
    684             setDebuggerVar(&m_fDbgAutoShowStatistics, false);
    685         }
    686         /* Not quite debug options, but they're only useful with the debugger bits. */
    687         else if (!::strcmp(arg, "--start-paused"))
    688         {
    689             enmOptType = OptType_VMRunner;
    690             m_enmLaunchRunning = LaunchRunning_No;
    691         }
    692         else if (!::strcmp(arg, "--start-running"))
    693         {
    694             enmOptType = OptType_VMRunner;
    695             m_enmLaunchRunning = LaunchRunning_Yes;
    696         }
    697 #endif
    698         if (enmOptType == OptType_VMRunner && m_enmType != UIType_RuntimeUI)
    699             msgCenter().warnAboutUnrelatedOptionType(arg);
    700 
    701         i++;
    702     }
    703 
    704     if (m_enmType == UIType_RuntimeUI && startVM)
    705     {
    706         /* m_fSeparateProcess makes sense only if a VM is started. */
    707         m_fSeparateProcess = fSeparateProcess;
    708 
    709         /* Search for corresponding VM: */
    710         QUuid uuid = QUuid(vmNameOrUuid);
    711         const CMachine machine = m_comVBox.FindMachine(vmNameOrUuid);
    712         if (!uuid.isNull())
    713         {
    714             if (machine.isNull() && showStartVMErrors())
    715                 return msgCenter().cannotFindMachineById(m_comVBox, vmNameOrUuid);
    716         }
    717         else
    718         {
    719             if (machine.isNull() && showStartVMErrors())
    720                 return msgCenter().cannotFindMachineByName(m_comVBox, vmNameOrUuid);
    721         }
    722         m_strManagedVMId = machine.GetId();
    723 
    724         if (m_fSeparateProcess)
    725         {
    726             /* Create a log file for VirtualBoxVM process. */
    727             QString str = machine.GetLogFolder();
    728             com::Utf8Str logDir(str.toUtf8().constData());
    729 
    730             /* make sure the Logs folder exists */
    731             if (!RTDirExists(logDir.c_str()))
    732                 RTDirCreateFullPath(logDir.c_str(), 0700);
    733 
    734             com::Utf8Str logFile = com::Utf8StrFmt("%s%cVBoxUI.log",
    735                                                    logDir.c_str(), RTPATH_DELIMITER);
    736 
    737             com::VBoxLogRelCreate("GUI (separate)", logFile.c_str(),
    738                                   RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_RESTRICT_GROUPS,
    739                                   "all all.restrict -default.restrict",
    740                                   "VBOX_RELEASE_LOG", RTLOGDEST_FILE,
    741                                   32768 /* cMaxEntriesPerGroup */,
    742                                   0 /* cHistory */, 0 /* uHistoryFileTime */,
    743                                   0 /* uHistoryFileSize */, NULL);
    744         }
    745     }
    746 
    747     /* For Selector UI: */
    748     if (uiType() == UIType_SelectorUI)
    749     {
    750         /* We should create separate logging file for VM selector: */
    751         char szLogFile[RTPATH_MAX];
    752         const char *pszLogFile = NULL;
    753         com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
    754         RTPathAppend(szLogFile, sizeof(szLogFile), "selectorwindow.log");
    755         pszLogFile = szLogFile;
    756         /* Create release logger, to file: */
    757         com::VBoxLogRelCreate("GUI VM Selector Window",
    758                               pszLogFile,
    759                               RTLOGFLAGS_PREFIX_TIME_PROG,
    760                               "all",
    761                               "VBOX_GUI_SELECTORWINDOW_RELEASE_LOG",
    762                               RTLOGDEST_FILE | RTLOGDEST_F_NO_DENY,
    763                               UINT32_MAX,
    764                               10,
    765                               60 * 60,
    766                               _1M,
    767                               NULL /*pErrInfo*/);
    768 
    769         LogRel(("Qt version: %s\n", qtRTVersionString().toUtf8().constData()));
    770     }
    771 
    772     if (m_fSettingsPwSet)
    773         m_comVBox.SetSettingsSecret(m_astrSettingsPw);
    774 
    775     if (visualStateType != UIVisualStateType_Invalid && !m_strManagedVMId.isNull())
    776         gEDataManager->setRequestedVisualState(visualStateType, m_strManagedVMId);
    777 
    778 #ifdef VBOX_WITH_DEBUGGER_GUI
    779     /* For Runtime UI: */
    780     if (uiType() == UIType_RuntimeUI)
    781     {
    782         /* Setup the debugger GUI: */
    783         if (RTEnvExist("VBOX_GUI_NO_DEBUGGER"))
    784             m_fDbgEnabled = m_fDbgAutoShow =  m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = false;
    785         if (m_fDbgEnabled)
    786         {
    787             RTERRINFOSTATIC ErrInfo;
    788             RTErrInfoInitStatic(&ErrInfo);
    789             int vrc = SUPR3HardenedLdrLoadAppPriv("VBoxDbg", &m_hVBoxDbg, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
    790             if (RT_FAILURE(vrc))
    791             {
    792                 m_hVBoxDbg = NIL_RTLDRMOD;
    793                 m_fDbgAutoShow = m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = false;
    794                 LogRel(("Failed to load VBoxDbg, rc=%Rrc - %s\n", vrc, ErrInfo.Core.pszMsg));
    795             }
    796         }
    797     }
    798 #endif
    799 
    800     m_fValid = true;
    801 
    802     /* Create medium-enumerator but don't do any immediate caching: */
    803     m_pMediumEnumerator = new UIMediumEnumerator;
    804     {
    805         /* Prepare medium-enumerator: */
    806         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumCreated,
    807                 this, &UICommon::sigMediumCreated);
    808         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumDeleted,
    809                 this, &UICommon::sigMediumDeleted);
    810         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerationStarted,
    811                 this, &UICommon::sigMediumEnumerationStarted);
    812         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerated,
    813                 this, &UICommon::sigMediumEnumerated);
    814         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerationFinished,
    815                 this, &UICommon::sigMediumEnumerationFinished);
    816     }
    817 
    818     /* Create shortcut pool: */
    819     UIShortcutPool::create();
    820 
    821 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER
    822     /* Create network manager: */
    823     UINetworkRequestManager::create();
    824 
    825     /* Schedule update manager: */
    826     UIUpdateManager::schedule();
    827 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
    828 
    829 #ifdef RT_OS_LINUX
    830     /* Make sure no wrong USB mounted: */
    831     checkForWrongUSBMounted();
    832 #endif /* RT_OS_LINUX */
    833 
    834     /* Populate the list of medium names to be excluded from the
    835        recently used media extra data: */
    836 #if 0 /* bird: This is counter productive as it is _frequently_ necessary to re-insert the
    837                viso to refresh the files (like after you rebuilt them on the host).
    838                The guest caches ISOs aggressively and files sizes may change. */
    839     m_recentMediaExcludeList << "ad-hoc.viso";
    840 #endif
    841 }
    842 
    843 void UICommon::cleanup()
    844 {
    845     LogRel(("GUI: UICommon: Handling aboutToQuit request..\n"));
    846 
    847     /// @todo Shouldn't that be protected with a mutex or something?
    848     /* Remember that the cleanup is in progress preventing any unwanted
    849      * stuff which could be called from the other threads: */
    850     m_fCleaningUp = true;
    851 
    852 #ifdef VBOX_WS_WIN
    853     /* Ask listeners to commit data if haven't yet: */
    854     if (!m_fDataCommitted)
    855     {
    856         emit sigAskToCommitData();
    857         m_fDataCommitted = true;
    858     }
    859 #else
    860     /* Ask listeners to commit data: */
    861     emit sigAskToCommitData();
    862 #endif
    863 
    864 #ifdef VBOX_WITH_DEBUGGER_GUI
    865     /* For Runtime UI: */
    866     if (   uiType() == UIType_RuntimeUI
    867         && m_hVBoxDbg != NIL_RTLDRMOD)
    868     {
    869         RTLdrClose(m_hVBoxDbg);
    870         m_hVBoxDbg = NIL_RTLDRMOD;
    871     }
    872 #endif
    873 
    874 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER
    875     /* Shutdown update manager: */
    876     UIUpdateManager::shutdown();
    877 
    878     /* Destroy network manager: */
    879     UINetworkRequestManager::destroy();
    880 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
    881 
    882     /* Destroy shortcut pool: */
    883     UIShortcutPool::destroy();
    884 
    885 #ifdef VBOX_GUI_WITH_PIDFILE
    886     deletePidfile();
    887 #endif /* VBOX_GUI_WITH_PIDFILE */
    888 
    889     /* Starting medium-enumerator cleanup: */
    890     m_meCleanupProtectionToken.lockForWrite();
    891     {
    892         /* Destroy medium-enumerator: */
    893         delete m_pMediumEnumerator;
    894         m_pMediumEnumerator = 0;
    895     }
    896     /* Finishing medium-enumerator cleanup: */
    897     m_meCleanupProtectionToken.unlock();
    898 
    899     /* Destroy the global (VirtualBox and VirtualBoxClient) Main event
    900      * handlers which are used in both Manager and Runtime UIs. */
    901     UIVirtualBoxEventHandler::destroy();
    902     UIVirtualBoxClientEventHandler::destroy();
    903 
    904     /* Destroy the extra-data manager finally after everything
    905      * above which could use it already destroyed: */
    906     UIExtraDataManager::destroy();
    907 
    908     /* Destroy converter: */
    909     UIConverter::destroy();
    910 
    911     /* Cleanup thread-pools: */
    912     delete m_pThreadPool;
    913     m_pThreadPool = 0;
    914     delete m_pThreadPoolCloud;
    915     m_pThreadPoolCloud = 0;
    916     /* Cleanup general icon-pool: */
    917     delete m_pIconPool;
    918     m_pIconPool = 0;
    919 
    920     /* Ensure CGuestOSType objects are no longer used: */
    921     m_guestOSFamilyIDs.clear();
    922     m_guestOSTypes.clear();
    923 
    924     /* Starting COM cleanup: */
    925     m_comCleanupProtectionToken.lockForWrite();
    926     {
    927         /* First, make sure we don't use COM any more: */
    928         emit sigAskToDetachCOM();
    929         m_comHost.detach();
    930         m_comVBox.detach();
    931         m_comVBoxClient.detach();
    932 
    933         /* There may be UIMedium(s)EnumeratedEvent instances still in the message
    934          * queue which reference COM objects. Remove them to release those objects
    935          * before uninitializing the COM subsystem. */
    936         QApplication::removePostedEvents(this);
    937 
    938         /* Finally cleanup COM itself: */
    939         COMBase::CleanupCOM();
    940     }
    941     /* Finishing COM cleanup: */
    942     m_comCleanupProtectionToken.unlock();
    943 
    944     /* Notify listener it can close UI now: */
    945     emit sigAskToCloseUI();
    946 
    947     /* Destroy popup-center: */
    948     UIPopupCenter::destroy();
    949     /* Destroy message-center: */
    950     UIMessageCenter::destroy();
    951 
    952     /* Destroy desktop-widget watchdog: */
    953     UIDesktopWidgetWatchdog::destroy();
    954 
    955     m_fValid = false;
    956 
    957     LogRel(("GUI: UICommon: aboutToQuit request handled!\n"));
    958 }
    959 
    960 /* static */
    961 QString UICommon::qtRTVersionString()
    962 {
    963     return QString::fromLatin1(qVersion());
    964 }
    965 
    966 /* static */
    967 uint UICommon::qtRTVersion()
    968 {
    969     const QString strVersionRT = UICommon::qtRTVersionString();
    970     return (strVersionRT.section('.', 0, 0).toInt() << 16) +
    971            (strVersionRT.section('.', 1, 1).toInt() << 8) +
    972            strVersionRT.section('.', 2, 2).toInt();
    973 }
    974 
    975 /* static */
    976 uint UICommon::qtRTMajorVersion()
    977 {
    978     return UICommon::qtRTVersionString().section('.', 0, 0).toInt();
    979 }
    980 
    981 /* static */
    982 uint UICommon::qtRTMinorVersion()
    983 {
    984     return UICommon::qtRTVersionString().section('.', 1, 1).toInt();
    985 }
    986 
    987 /* static */
    988 uint UICommon::qtRTRevisionNumber()
    989 {
    990     return UICommon::qtRTVersionString().section('.', 2, 2).toInt();
    991 }
    992 
    993 /* static */
    994 QString UICommon::qtCTVersionString()
    995 {
    996     return QString::fromLatin1(QT_VERSION_STR);
    997 }
    998 
    999 /* static */
    1000 uint UICommon::qtCTVersion()
    1001 {
    1002     const QString strVersionCompiled = UICommon::qtCTVersionString();
    1003     return (strVersionCompiled.section('.', 0, 0).toInt() << 16) +
    1004            (strVersionCompiled.section('.', 1, 1).toInt() << 8) +
    1005            strVersionCompiled.section('.', 2, 2).toInt();
    1006 }
    1007 
    1008 QString UICommon::vboxVersionString() const
    1009 {
    1010     return m_comVBox.GetVersion();
    1011 }
    1012 
    1013 QString UICommon::vboxVersionStringNormalized() const
    1014 {
    1015     return m_comVBox.GetVersionNormalized();
    1016 }
    1017 
    1018 bool UICommon::isBeta() const
    1019 {
    1020     return vboxVersionString().contains("BETA", Qt::CaseInsensitive);
    1021 }
    1022 
    1023 #ifdef VBOX_WS_MAC
    1024 /* static */
    1025 MacOSXRelease UICommon::determineOsRelease()
    1026 {
    1027     /* Prepare 'utsname' struct: */
    1028     utsname info;
    1029     if (uname(&info) != -1)
    1030     {
    1031         /* Compose map of known releases: */
    1032         QMap<int, MacOSXRelease> release;
    1033         release[10] = MacOSXRelease_SnowLeopard;
    1034         release[11] = MacOSXRelease_Lion;
    1035         release[12] = MacOSXRelease_MountainLion;
    1036         release[13] = MacOSXRelease_Mavericks;
    1037         release[14] = MacOSXRelease_Yosemite;
    1038         release[15] = MacOSXRelease_ElCapitan;
    1039 
    1040         /* Cut the major release index of the string we have, s.a. 'man uname': */
    1041         const int iRelease = QString(info.release).section('.', 0, 0).toInt();
    1042 
    1043         /* Return release if determined, return 'New' if version more recent than latest, return 'Old' otherwise: */
    1044         return release.value(iRelease, iRelease > release.keys().last() ? MacOSXRelease_New : MacOSXRelease_Old);
    1045     }
    1046     /* Return 'Old' by default: */
    1047     return MacOSXRelease_Old;
    1048 }
    1049 #endif /* VBOX_WS_MAC */
    1050 
    1051 bool UICommon::brandingIsActive(bool fForce /* = false */)
    1052 {
    1053     if (fForce)
    1054         return true;
    1055 
    1056     if (m_strBrandingConfigFilePath.isEmpty())
    1057     {
    1058         m_strBrandingConfigFilePath = QDir(QApplication::applicationDirPath()).absolutePath();
    1059         m_strBrandingConfigFilePath += "/custom/custom.ini";
    1060     }
    1061 
    1062     return QFile::exists(m_strBrandingConfigFilePath);
    1063 }
    1064 
    1065 QString UICommon::brandingGetKey(QString strKey)
    1066 {
    1067     QSettings settings(m_strBrandingConfigFilePath, QSettings::IniFormat);
    1068     return settings.value(QString("%1").arg(strKey)).toString();
    1069 }
    1070 
    1071 bool UICommon::processArgs()
    1072 {
    1073     /* Among those arguments: */
    1074     bool fResult = false;
    1075     const QStringList args = qApp->arguments();
    1076 
    1077     /* We are looking for a list of file URLs passed to the executable: */
    1078     QList<QUrl> listArgUrls;
    1079     for (int i = 1; i < args.size(); ++i)
    1080     {
    1081         /* But we break out after the first parameter, cause there
    1082          * could be parameters with arguments (e.g. --comment comment). */
    1083         if (args.at(i).startsWith("-"))
    1084             break;
    1085 
    1086 #ifdef VBOX_WS_MAC
    1087         const QString strArg = ::darwinResolveAlias(args.at(i));
    1088 #else
    1089         const QString strArg = args.at(i);
    1090 #endif
    1091 
    1092         /* So if the argument file exists, we add it to URL list: */
    1093         if (   !strArg.isEmpty()
    1094             && QFile::exists(strArg))
    1095             listArgUrls << QUrl::fromLocalFile(QFileInfo(strArg).absoluteFilePath());
    1096     }
    1097 
    1098     /* If there are file URLs: */
    1099     if (!listArgUrls.isEmpty())
    1100     {
    1101         /* We enumerate them and: */
    1102         for (int i = 0; i < listArgUrls.size(); ++i)
    1103         {
    1104             /* Check which of them has allowed VM extensions: */
    1105             const QUrl url = listArgUrls.at(i);
    1106             const QString strFile = url.toLocalFile();
    1107             if (UICommon::hasAllowedExtension(strFile, VBoxFileExts))
    1108             {
    1109                 /* So that we could run existing VMs: */
    1110                 CVirtualBox comVBox = virtualBox();
    1111                 CMachine comMachine = comVBox.FindMachine(strFile);
    1112                 if (!comMachine.isNull())
    1113                 {
    1114                     fResult = true;
    1115                     launchMachine(comMachine);
    1116                     /* And remove their URLs from the ULR list: */
    1117                     listArgUrls.removeAll(url);
    1118                 }
    1119             }
    1120         }
    1121     }
    1122 
    1123     /* And if there are *still* URLs: */
    1124     if (!listArgUrls.isEmpty())
    1125     {
    1126         /* We store them, they will be handled later: */
    1127         m_listArgUrls = listArgUrls;
    1128     }
    1129 
    1130     return fResult;
    1131 }
    1132 
    1133 bool UICommon::argumentUrlsPresent() const
    1134 {
    1135     return !m_listArgUrls.isEmpty();
    1136 }
    1137 
    1138 QList<QUrl> UICommon::takeArgumentUrls()
    1139 {
    1140     const QList<QUrl> result = m_listArgUrls;
    1141     m_listArgUrls.clear();
    1142     return result;
    1143 }
    1144 
    1145 #ifdef VBOX_WITH_DEBUGGER_GUI
    1146 
    1147 bool UICommon::isDebuggerEnabled() const
    1148 {
    1149     return isDebuggerWorker(&m_fDbgEnabled, GUI_Dbg_Enabled);
    1150 }
    1151 
    1152 bool UICommon::isDebuggerAutoShowEnabled() const
    1153 {
    1154     return isDebuggerWorker(&m_fDbgAutoShow, GUI_Dbg_AutoShow);
    1155 }
    1156 
    1157 bool UICommon::isDebuggerAutoShowCommandLineEnabled() const
    1158 {
    1159     return isDebuggerWorker(&m_fDbgAutoShowCommandLine, GUI_Dbg_AutoShow);
    1160 }
    1161 
    1162 bool UICommon::isDebuggerAutoShowStatisticsEnabled() const
    1163 {
    1164     return isDebuggerWorker(&m_fDbgAutoShowStatistics, GUI_Dbg_AutoShow);
    1165 }
    1166 
    1167 #endif /* VBOX_WITH_DEBUGGER_GUI */
    1168 
    1169 bool UICommon::shouldStartPaused() const
    1170 {
    1171 #ifdef VBOX_WITH_DEBUGGER_GUI
    1172     return m_enmLaunchRunning == LaunchRunning_Default ? isDebuggerAutoShowEnabled() : m_enmLaunchRunning == LaunchRunning_No;
    1173 #else
    1174     return false;
    1175 #endif
    1176 }
    1177 
    1178 #ifdef VBOX_GUI_WITH_PIDFILE
    1179 
    1180 void UICommon::createPidfile()
    1181 {
    1182     if (!m_strPidFile.isEmpty())
    1183     {
    1184         const qint64 iPid = qApp->applicationPid();
    1185         QFile file(m_strPidFile);
    1186         if (file.open(QIODevice::WriteOnly | QIODevice::Truncate))
    1187         {
    1188              QTextStream out(&file);
    1189              out << iPid << endl;
    1190         }
    1191         else
    1192             LogRel(("Failed to create pid file %s\n", m_strPidFile.toUtf8().constData()));
    1193     }
    1194 }
    1195 
    1196 void UICommon::deletePidfile()
    1197 {
    1198     if (   !m_strPidFile.isEmpty()
    1199         && QFile::exists(m_strPidFile))
    1200         QFile::remove(m_strPidFile);
    1201 }
    1202 
    1203 #endif /* VBOX_GUI_WITH_PIDFILE */
    1204 
    1205 /* static */
    1206 QString UICommon::languageName()
    1207 {
    1208     /* Returns "English" if no translation is installed
    1209      * or if the translation file is invalid. */
    1210     return QApplication::translate("@@@", "English",
    1211                                    "Native language name");
    1212 }
    1213 
    1214 /* static */
    1215 QString UICommon::languageCountry()
    1216 {
    1217     /* Returns "--" if no translation is installed or if the translation file
    1218      * is invalid, or if the language is independent on the country. */
    1219     return QApplication::translate("@@@", "--",
    1220                                    "Native language country name "
    1221                                    "(empty if this language is for all countries)");
    1222 }
    1223 
    1224 /* static */
    1225 QString UICommon::languageNameEnglish()
    1226 {
    1227     /* Returns "English" if no translation is installed
    1228      * or if the translation file is invalid. */
    1229     return QApplication::translate("@@@", "English",
    1230                                    "Language name, in English");
    1231 }
    1232 
    1233 /* static */
    1234 QString UICommon::languageCountryEnglish()
    1235 {
    1236     /* Returns "--" if no translation is installed or if the translation file
    1237      * is invalid, or if the language is independent on the country. */
    1238     return QApplication::translate("@@@", "--",
    1239                                    "Language country name, in English "
    1240                                    "(empty if native country name is empty)");
    1241 }
    1242 
    1243 /* static */
    1244 QString UICommon::languageTranslators()
    1245 {
    1246     /* Returns "Oracle Corporation" if no translation is installed or if the translation file
    1247      * is invalid, or if the translation is supplied by Oracle Corporation. */
    1248     return QApplication::translate("@@@", "Oracle Corporation",
    1249                                    "Comma-separated list of translators");
    1250 }
    1251 
    1252 /* static */
    1253 QString UICommon::vboxLanguageSubDirectory()
    1254 {
    1255     return "/nls";
    1256 }
    1257 
    1258 /* static */
    1259 QString UICommon::vboxLanguageFileBase()
    1260 {
    1261     return "VirtualBox_";
    1262 }
    1263 
    1264 /* static */
    1265 QString UICommon::vboxLanguageFileExtension()
    1266 {
    1267     return ".qm";
    1268 }
    1269 
    1270 /* static */
    1271 QString UICommon::vboxLanguageIdRegExp()
    1272 {
    1273     return "(([a-z]{2})(?:_([A-Z]{2}))?)|(C)";
    1274 }
    1275 
    1276 /* static */
    1277 QString UICommon::vboxBuiltInLanguageName()
    1278 {
    1279     return "C";
    1280 }
    1281 
    1282 /* static */
    1283 QString UICommon::languageId()
    1284 {
    1285     /* Note that it may not match with UIExtraDataManager::languageId() if the specified language cannot be loaded.
    1286      *
    1287      * If the built-in language is active, this method returns "C". "C" is treated as the built-in language for
    1288      * simplicity -- the C locale is used in unix environments as a fallback when the requested locale is invalid.
    1289      * This way we don't need to process both the "built_in" language and the "C" language (which is a valid
    1290      * environment setting) separately. */
    1291 
    1292     return s_strLoadedLanguageId;
    1293 }
    1294 
    1295 /* static */
    1296 QString UICommon::systemLanguageId()
    1297 {
    1298     /* This does exactly the same as QLocale::system().name() but corrects its wrong behavior on Linux systems
    1299      * (LC_NUMERIC for some strange reason takes precedence over any other locale setting in the QLocale::system()
    1300      * implementation). This implementation first looks at LC_ALL (as defined by SUS), then looks at LC_MESSAGES
    1301      * which is designed to define a language for program messages in case if it differs from the language for
    1302      * other locale categories. Then it looks for LANG and finally falls back to QLocale::system().name().
    1303      *
    1304      * The order of precedence is well defined here:
    1305      * http://opengroup.org/onlinepubs/007908799/xbd/envvar.html
    1306      *
    1307      * This method will return "C" when the requested locale is invalid or when the "C" locale is set explicitly. */
    1308 
    1309 #if defined(VBOX_WS_MAC)
    1310     /* QLocale return the right id only if the user select the format
    1311      * of the language also. So we use our own implementation */
    1312     return ::darwinSystemLanguage();
    1313 #elif defined(Q_OS_UNIX)
    1314     const char *pszValue = RTEnvGet("LC_ALL");
    1315     if (pszValue == 0)
    1316         pszValue = RTEnvGet("LC_MESSAGES");
    1317     if (pszValue == 0)
    1318         pszValue = RTEnvGet("LANG");
    1319     if (pszValue != 0)
    1320         return QLocale(pszValue).name();
    1321 #endif
    1322     return QLocale::system().name();
    1323 }
    1324 
    1325 #ifdef VBOX_WS_WIN
    1326 /* static */
    1327 void UICommon::loadColorTheme()
    1328 {
    1329     /* Load saved color theme: */
    1330     UIColorThemeType enmColorTheme = gEDataManager->colorTheme();
    1331 
    1332     /* Check whether we have dark system theme requested: */
    1333     if (enmColorTheme == UIColorThemeType_Auto)
    1334     {
    1335         QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
    1336                            QSettings::NativeFormat);
    1337         if (settings.value("AppsUseLightTheme") == 0)
    1338             enmColorTheme = UIColorThemeType_Dark;
    1339     }
    1340 
    1341     /* Check whether dark theme was requested by any means: */
    1342     if (enmColorTheme == UIColorThemeType_Dark)
    1343     {
    1344         qApp->setStyle(QStyleFactory::create("Fusion"));
    1345         QPalette darkPalette;
    1346         QColor windowColor1 = QColor(59, 60, 61);
    1347         QColor windowColor2 = QColor(63, 64, 65);
    1348         QColor baseColor1 = QColor(46, 47, 48);
    1349         QColor baseColor2 = QColor(56, 57, 58);
    1350         QColor disabledColor = QColor(113, 114, 115);
    1351         darkPalette.setColor(QPalette::Window, windowColor1);
    1352         darkPalette.setColor(QPalette::WindowText, Qt::white);
    1353         darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, disabledColor);
    1354         darkPalette.setColor(QPalette::Base, baseColor1);
    1355         darkPalette.setColor(QPalette::AlternateBase, baseColor2);
    1356         darkPalette.setColor(QPalette::PlaceholderText, disabledColor);
    1357         darkPalette.setColor(QPalette::Text, Qt::white);
    1358         darkPalette.setColor(QPalette::Disabled, QPalette::Text, disabledColor);
    1359         darkPalette.setColor(QPalette::Button, windowColor2);
    1360         darkPalette.setColor(QPalette::ButtonText, Qt::white);
    1361         darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, disabledColor);
    1362         darkPalette.setColor(QPalette::BrightText, Qt::red);
    1363         darkPalette.setColor(QPalette::Link, QColor(179, 214, 242));
    1364         darkPalette.setColor(QPalette::Highlight, QColor(29, 84, 92));
    1365         darkPalette.setColor(QPalette::HighlightedText, Qt::white);
    1366         darkPalette.setColor(QPalette::Disabled, QPalette::HighlightedText, disabledColor);
    1367         qApp->setPalette(darkPalette);
    1368         qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2b2b2b; border: 1px solid #737373; }");
    1369     }
    1370 }
    1371 #endif /* VBOX_WS_WIN */
    1372 
    1373 /* static */
    1374 void UICommon::loadLanguage(const QString &strLangId)
     29
     30/* static */
     31UITranslator *UITranslator::s_pTranslator = 0;
     32QString UITranslator::s_strLoadedLanguageId = UITranslator::vboxBuiltInLanguageName();
     33
     34/* static */
     35void UITranslator::loadLanguage(const QString &strLangId /* = QString() */)
    137536{
    137637    QString strEffectiveLangId = strLangId.isEmpty()
    1377                                ? UICommon::systemLanguageId()
     38                               ? systemLanguageId()
    137839                               : strLangId;
    137940    QString strLanguageFileName;
     
    143697
    143798    /* Delete the old translator if there is one: */
    1438     if (sTranslator)
     99    if (s_pTranslator)
    1439100    {
    1440101        /* QTranslator destructor will call qApp->removeTranslator() for
    1441102         * us. It will also delete all its child translations we attach to it
    1442103         * below, so we don't have to care about them specially. */
    1443         delete sTranslator;
     104        delete s_pTranslator;
    1444105    }
    1445106
    1446107    /* Load new language files: */
    1447     sTranslator = new VBoxTranslator(qApp);
    1448     Assert(sTranslator);
     108    s_pTranslator = new UITranslator(qApp);
     109    Assert(s_pTranslator);
    1449110    bool fLoadOk = true;
    1450     if (sTranslator)
     111    if (s_pTranslator)
    1451112    {
    1452113        if (strSelectedLangId != vboxBuiltInLanguageName())
    1453114        {
    1454115            Assert(!strLanguageFileName.isNull());
    1455             fLoadOk = sTranslator->loadFile(strLanguageFileName);
     116            fLoadOk = s_pTranslator->loadFile(strLanguageFileName);
    1456117        }
    1457118        /* We install the translator in any case: on failure, this will
    1458119         * activate an empty translator that will give us English (built-in): */
    1459         qApp->installTranslator(sTranslator);
     120        qApp->installTranslator(s_pTranslator);
    1460121    }
    1461122    else
     
    1474135    {
    1475136#ifdef Q_OS_UNIX
    1476         /* We use system installations of Qt on Linux systems, so first, try
    1477          * to load the Qt translation from the system location. */
     137        // We use system installations of Qt on Linux systems, so first, try
     138        // to load the Qt translation from the system location.
    1478139        strLanguageFileName = QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" +
    1479140                              languageId() + vboxLanguageFileExtension();
    1480         QTranslator *pQtSysTr = new QTranslator(sTranslator);
     141        QTranslator *pQtSysTr = new QTranslator(s_pTranslator);
    1481142        Assert(pQtSysTr);
    1482143        if (pQtSysTr && pQtSysTr->load(strLanguageFileName))
    1483144            qApp->installTranslator(pQtSysTr);
    1484         /* Note that the Qt translation supplied by Oracle is always loaded
    1485          * afterwards to make sure it will take precedence over the system
    1486          * translation (it may contain more decent variants of translation
    1487          * that better correspond to VirtualBox UI). We need to load both
    1488          * because a newer version of Qt may be installed on the user computer
    1489          * and the Oracle version may not fully support it. We don't do it on
    1490          * Win32 because we supply a Qt library there and therefore the
    1491          * Oracle translation is always the best one. */
     145        // Note that the Qt translation supplied by Oracle is always loaded
     146        // afterwards to make sure it will take precedence over the system
     147        // translation (it may contain more decent variants of translation
     148        // that better correspond to VirtualBox UI). We need to load both
     149        // because a newer version of Qt may be installed on the user computer
     150        // and the Oracle version may not fully support it. We don't do it on
     151        // Win32 because we supply a Qt library there and therefore the
     152        // Oracle translation is always the best one. */
    1492153#endif
    1493154        strLanguageFileName = nlsDir.absoluteFilePath(QString("qt_") +
    1494155                                                      languageId() +
    1495156                                                      vboxLanguageFileExtension());
    1496         QTranslator *pQtTr = new QTranslator(sTranslator);
     157        QTranslator *pQtTr = new QTranslator(s_pTranslator);
    1497158        Assert(pQtTr);
    1498159        if (pQtTr && (fLoadOk = pQtTr->load(strLanguageFileName)))
     
    1508169        s_strLoadedLanguageId = vboxBuiltInLanguageName();
    1509170#ifdef VBOX_WS_MAC
    1510     /* Qt doesn't translate the items in the Application menu initially.
    1511      * Manually trigger an update. */
     171    // Qt doesn't translate the items in the Application menu initially.
     172    // Manually trigger an update.
    1512173    ::darwinRetranslateAppMenu();
    1513174#endif
     
    1515176
    1516177/* static */
    1517 QString UICommon::yearsToString(uint32_t cVal)
    1518 {
    1519     return QApplication::translate("UICommon", "%n year(s)", "", cVal);
    1520 }
    1521 
    1522 /* static */
    1523 QString UICommon::monthsToString(uint32_t cVal)
    1524 {
    1525     return QApplication::translate("UICommon", "%n month(s)", "", cVal);
    1526 }
    1527 
    1528 /* static */
    1529 QString UICommon::daysToString(uint32_t cVal)
    1530 {
    1531     return QApplication::translate("UICommon", "%n day(s)", "", cVal);
    1532 }
    1533 
    1534 /* static */
    1535 QString UICommon::hoursToString(uint32_t cVal)
    1536 {
    1537     return QApplication::translate("UICommon", "%n hour(s)", "", cVal);
    1538 }
    1539 
    1540 /* static */
    1541 QString UICommon::minutesToString(uint32_t cVal)
    1542 {
    1543     return QApplication::translate("UICommon", "%n minute(s)", "", cVal);
    1544 }
    1545 
    1546 /* static */
    1547 QString UICommon::secondsToString(uint32_t cVal)
    1548 {
    1549     return QApplication::translate("UICommon", "%n second(s)", "", cVal);
    1550 }
    1551 
    1552 /* static */
    1553 QChar UICommon::decimalSep()
    1554 {
    1555     return QLocale::system().decimalPoint();
    1556 }
    1557 
    1558 /* static */
    1559 QString UICommon::sizeRegexp()
    1560 {
    1561     /* This regexp will capture 5 groups of text:
    1562      * - cap(1): integer number in case when no decimal point is present
    1563      *           (if empty, it means that decimal point is present)
    1564      * - cap(2): size suffix in case when no decimal point is present (may be empty)
    1565      * - cap(3): integer number in case when decimal point is present (may be empty)
    1566      * - cap(4): fraction number (hundredth) in case when decimal point is present
    1567      * - cap(5): size suffix in case when decimal point is present (note that
    1568      *           B cannot appear there). */
    1569 
    1570     const QString strRegexp =
    1571         QString("^(?:(?:(\\d+)(?:\\s?(%2|%3|%4|%5|%6|%7))?)|(?:(\\d*)%1(\\d{1,2})(?:\\s?(%3|%4|%5|%6|%7))))$")
    1572             .arg(decimalSep())
    1573             .arg(tr("B", "size suffix Bytes"))
    1574             .arg(tr("KB", "size suffix KBytes=1024 Bytes"))
    1575             .arg(tr("MB", "size suffix MBytes=1024 KBytes"))
    1576             .arg(tr("GB", "size suffix GBytes=1024 MBytes"))
    1577             .arg(tr("TB", "size suffix TBytes=1024 GBytes"))
    1578             .arg(tr("PB", "size suffix PBytes=1024 TBytes"));
    1579     return strRegexp;
    1580 }
    1581 
    1582 /* static */
    1583 quint64 UICommon::parseSize(const QString &strText)
    1584 {
    1585     /* Text should be in form of B|KB|MB|GB|TB|PB. */
    1586     QRegExp regexp(sizeRegexp());
    1587     int iPos = regexp.indexIn(strText);
    1588     if (iPos != -1)
    1589     {
    1590         QString strInteger = regexp.cap(1);
    1591         QString strHundred;
    1592         QString strSuff = regexp.cap(2);
    1593         if (strInteger.isEmpty())
    1594         {
    1595             strInteger = regexp.cap(3);
    1596             strHundred = regexp.cap(4);
    1597             strSuff = regexp.cap(5);
    1598         }
    1599 
    1600         quint64 uDenominator = 0;
    1601         if (strSuff.isEmpty() || strSuff == tr("B", "size suffix Bytes"))
    1602             uDenominator = 1;
    1603         else if (strSuff == tr("KB", "size suffix KBytes=1024 Bytes"))
    1604             uDenominator = _1K;
    1605         else if (strSuff == tr("MB", "size suffix MBytes=1024 KBytes"))
    1606             uDenominator = _1M;
    1607         else if (strSuff == tr("GB", "size suffix GBytes=1024 MBytes"))
    1608             uDenominator = _1G;
    1609         else if (strSuff == tr("TB", "size suffix TBytes=1024 GBytes"))
    1610             uDenominator = _1T;
    1611         else if (strSuff == tr("PB", "size suffix PBytes=1024 TBytes"))
    1612             uDenominator = _1P;
    1613 
    1614         quint64 iInteger = strInteger.toULongLong();
    1615         if (uDenominator == 1)
    1616             return iInteger;
    1617 
    1618         quint64 iHundred = strHundred.leftJustified(2, '0').toULongLong();
    1619         iHundred = iHundred * uDenominator / 100;
    1620         iInteger = iInteger * uDenominator + iHundred;
    1621         return iInteger;
    1622     }
    1623     else
    1624         return 0;
    1625 }
    1626 
    1627 /* static */
    1628 SizeSuffix UICommon::parseSizeSuffix(const QString &strText)
    1629 {
    1630     /* Text should be in form of B|KB|MB|GB|TB|PB. */
    1631     QRegExp regexp(sizeRegexp());
    1632     int iPos = regexp.indexIn(strText);
    1633     if (iPos != -1)
    1634     {
    1635         QString strInteger = regexp.cap(1);
    1636         QString strSuff = regexp.cap(2);
    1637         if (strInteger.isEmpty())
    1638         {
    1639             strInteger = regexp.cap(3);
    1640             strSuff = regexp.cap(5);
    1641         }
    1642 
    1643         SizeSuffix enmSizeSuffix = SizeSuffix_Byte;
    1644 
    1645         if (strSuff.isEmpty() || strSuff == tr("B", "size suffix Bytes"))
    1646             enmSizeSuffix = SizeSuffix_Byte;
    1647         else if (strSuff == tr("KB", "size suffix KBytes=1024 Bytes"))
    1648             enmSizeSuffix = SizeSuffix_KiloByte;
    1649         else if (strSuff == tr("MB", "size suffix MBytes=1024 KBytes"))
    1650             enmSizeSuffix = SizeSuffix_MegaByte;
    1651         else if (strSuff == tr("GB", "size suffix GBytes=1024 MBytes"))
    1652             enmSizeSuffix = SizeSuffix_GigaByte;
    1653         else if (strSuff == tr("TB", "size suffix TBytes=1024 GBytes"))
    1654             enmSizeSuffix = SizeSuffix_TeraByte;
    1655         else if (strSuff == tr("PB", "size suffix PBytes=1024 TBytes"))
    1656             enmSizeSuffix = SizeSuffix_PetaByte;
    1657         return enmSizeSuffix;
    1658     }
    1659     else
    1660         return SizeSuffix_Byte;
    1661 }
    1662 
    1663 /* static */
    1664 bool UICommon::hasSizeSuffix(const QString &strText)
    1665 {
    1666     /* Text should be in form of B|KB|MB|GB|TB|PB. */
    1667     QRegExp regexp(sizeRegexp());
    1668     int iPos = regexp.indexIn(strText);
    1669     if (iPos != -1)
    1670     {
    1671         QString strInteger = regexp.cap(1);
    1672         QString strSuff = regexp.cap(2);
    1673         if (strInteger.isEmpty())
    1674         {
    1675             strInteger = regexp.cap(3);
    1676             strSuff = regexp.cap(5);
    1677         }
    1678 
    1679         if (strSuff.isEmpty())
    1680             return false;
    1681         if (strSuff == tr("B", "size suffix Bytes") ||
    1682             strSuff == tr("KB", "size suffix KBytes=1024 Bytes") ||
    1683             strSuff == tr("MB", "size suffix MBytes=1024 KBytes") ||
    1684             strSuff == tr("GB", "size suffix GBytes=1024 MBytes") ||
    1685             strSuff == tr("TB", "size suffix TBytes=1024 GBytes") ||
    1686             strSuff == tr("PB", "size suffix PBytes=1024 TBytes"))
    1687             return true;
     178QString UITranslator::vboxLanguageSubDirectory()
     179{
     180    return "/nls";
     181}
     182
     183/* static */
     184QString UITranslator::vboxLanguageFileBase()
     185{
     186    return "VirtualBox_";
     187}
     188
     189/* static */
     190QString UITranslator::vboxLanguageFileExtension()
     191{
     192    return ".qm";
     193}
     194
     195/* static */
     196QString UITranslator::vboxLanguageIdRegExp()
     197{
     198    return "(([a-z]{2})(?:_([A-Z]{2}))?)|(C)";
     199}
     200
     201/* static */
     202QString UITranslator::vboxBuiltInLanguageName()
     203{
     204    return "C";
     205}
     206
     207/* static */
     208QString UITranslator::languageId()
     209{
     210    /* Note that it may not match with UIExtraDataManager::languageId() if the specified language cannot be loaded.
     211     *
     212     * If the built-in language is active, this method returns "C". "C" is treated as the built-in language for
     213     * simplicity -- the C locale is used in unix environments as a fallback when the requested locale is invalid.
     214     * This way we don't need to process both the "built_in" language and the "C" language (which is a valid
     215     * environment setting) separately. */
     216
     217    return s_strLoadedLanguageId;
     218}
     219
     220UITranslator::UITranslator(QObject *pParent /* = 0 */)
     221    : QTranslator(pParent)
     222{
     223}
     224
     225bool UITranslator::loadFile(const QString &strFileName)
     226{
     227    QFile file(strFileName);
     228    if (!file.open(QIODevice::ReadOnly))
    1688229        return false;
    1689     }
    1690     else
    1691         return false;
    1692 }
    1693 
    1694 /* static */
    1695 QString UICommon::formatSize(quint64 uSize, uint cDecimal /* = 2 */,
    1696                                FormatSize enmMode /* = FormatSize_Round */)
    1697 {
    1698     /* Text will be in form of B|KB|MB|GB|TB|PB.
     230    m_data = file.readAll();
     231    return load((uchar*)m_data.data(), m_data.size());
     232}
     233
     234/* static */
     235QString UITranslator::languageName()
     236{
     237    /* Returns "English" if no translation is installed
     238     * or if the translation file is invalid. */
     239    return QApplication::translate("@@@", "English",
     240                                   "Native language name");
     241}
     242
     243/* static */
     244QString UITranslator::languageCountry()
     245{
     246    /* Returns "--" if no translation is installed or if the translation file
     247     * is invalid, or if the language is independent on the country. */
     248    return QApplication::translate("@@@", "--",
     249                                   "Native language country name "
     250                                   "(empty if this language is for all countries)");
     251}
     252
     253/* static */
     254QString UITranslator::languageNameEnglish()
     255{
     256    /* Returns "English" if no translation is installed
     257     * or if the translation file is invalid. */
     258    return QApplication::translate("@@@", "English",
     259                                   "Language name, in English");
     260}
     261
     262/* static */
     263QString UITranslator::languageCountryEnglish()
     264{
     265    /* Returns "--" if no translation is installed or if the translation file
     266     * is invalid, or if the language is independent on the country. */
     267    return QApplication::translate("@@@", "--",
     268                                   "Language country name, in English "
     269                                   "(empty if native country name is empty)");
     270}
     271
     272/* static */
     273QString UITranslator::languageTranslators()
     274{
     275    /* Returns "Oracle Corporation" if no translation is installed or if the translation file
     276     * is invalid, or if the translation is supplied by Oracle Corporation. */
     277    return QApplication::translate("@@@", "Oracle Corporation",
     278                                   "Comma-separated list of translators");
     279}
     280
     281/* static */
     282QString UITranslator::systemLanguageId()
     283{
     284    /* This does exactly the same as QLocale::system().name() but corrects its wrong behavior on Linux systems
     285     * (LC_NUMERIC for some strange reason takes precedence over any other locale setting in the QLocale::system()
     286     * implementation). This implementation first looks at LC_ALL (as defined by SUS), then looks at LC_MESSAGES
     287     * which is designed to define a language for program messages in case if it differs from the language for
     288     * other locale categories. Then it looks for LANG and finally falls back to QLocale::system().name().
    1699289     *
    1700      * When enmMode is FormatSize_Round, the result is rounded to the
    1701      *              closest number containing @a aDecimal decimal digits.
    1702      * When enmMode is FormatSize_RoundDown, the result is rounded to the
    1703      *              largest number with @a aDecimal decimal digits that is not greater than
    1704      *              the result. This guarantees that converting the resulting string back to
    1705      *              the integer value in bytes will not produce a value greater that the
    1706      *              initial size parameter.
    1707      * When enmMode is FormatSize_RoundUp, the result is rounded to the
    1708      *              smallest number with @a aDecimal decimal digits that is not less than the
    1709      *              result. This guarantees that converting the resulting string back to the
    1710      *              integer value in bytes will not produce a value less that the initial
    1711      *              size parameter. */
    1712 
    1713     quint64 uDenominator = 0;
    1714     int iSuffix = 0;
    1715 
    1716     if (uSize < _1K)
    1717     {
    1718         uDenominator = 1;
    1719         iSuffix = 0;
    1720     }
    1721     else if (uSize < _1M)
    1722     {
    1723         uDenominator = _1K;
    1724         iSuffix = 1;
    1725     }
    1726     else if (uSize < _1G)
    1727     {
    1728         uDenominator = _1M;
    1729         iSuffix = 2;
    1730     }
    1731     else if (uSize < _1T)
    1732     {
    1733         uDenominator = _1G;
    1734         iSuffix = 3;
    1735     }
    1736     else if (uSize < _1P)
    1737     {
    1738         uDenominator = _1T;
    1739         iSuffix = 4;
    1740     }
    1741     else
    1742     {
    1743         uDenominator = _1P;
    1744         iSuffix = 5;
    1745     }
    1746 
    1747     quint64 uInteger = uSize / uDenominator;
    1748     quint64 uDecimal = uSize % uDenominator;
    1749     quint64 uMult = 1;
    1750     for (uint i = 0; i < cDecimal; ++i)
    1751         uMult *= 10;
    1752 
    1753     QString strNumber;
    1754     if (uDenominator > 1)
    1755     {
    1756         if (uDecimal)
    1757         {
    1758             uDecimal *= uMult;
    1759             /* Not greater: */
    1760             if (enmMode == FormatSize_RoundDown)
    1761                 uDecimal = uDecimal / uDenominator;
    1762             /* Not less: */
    1763             else if (enmMode == FormatSize_RoundUp)
    1764                 uDecimal = (uDecimal + uDenominator - 1) / uDenominator;
    1765             /* Nearest: */
    1766             else
    1767                 uDecimal = (uDecimal + uDenominator / 2) / uDenominator;
    1768         }
    1769         /* Check for the fractional part overflow due to rounding: */
    1770         if (uDecimal == uMult)
    1771         {
    1772             uDecimal = 0;
    1773             ++uInteger;
    1774             /* Check if we've got 1024 XB after rounding and scale down if so: */
    1775             if (uInteger == 1024 && iSuffix + 1 < (int)SizeSuffix_Max)
    1776             {
    1777                 uInteger /= 1024;
    1778                 ++iSuffix;
    1779             }
    1780         }
    1781         strNumber = QString::number(uInteger);
    1782         if (cDecimal)
    1783             strNumber += QString("%1%2").arg(decimalSep())
    1784                                         .arg(QString::number(uDecimal).rightJustified(cDecimal, '0'));
    1785     }
    1786     else
    1787     {
    1788         strNumber = QString::number(uInteger);
    1789     }
    1790 
    1791     return QString("%1 %2").arg(strNumber).arg(gpConverter->toString(static_cast<SizeSuffix>(iSuffix)));
    1792 }
    1793 
    1794 /* static */
    1795 QString UICommon::addMetricSuffixToNumber(quint64 uNumber)
    1796 {
    1797     if (uNumber <= 0)
    1798         return QString();
    1799     /* See https://en.wikipedia.org/wiki/Metric_prefix for metric suffixes:*/
    1800     char suffixes[] = {'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'};
    1801     int zeroCount = (int)log10((long double)uNumber);
    1802     if (zeroCount < 3)
    1803         return QString::number(uNumber);
    1804     int h = 3 * (zeroCount / 3);
    1805     char result[128];
    1806     sprintf(result, "%.2f", uNumber / (float)pow((double)10, h));
    1807     return QString("%1%2").arg(result).arg(suffixes[h / 3 - 1]);
    1808 }
    1809 
    1810 /* static */
    1811 QStringList UICommon::COMPortNames()
    1812 {
    1813     QStringList list;
    1814     for (size_t i = 0; i < RT_ELEMENTS(kComKnownPorts); ++i)
    1815         list << kComKnownPorts[i].name;
    1816 
    1817     return list;
    1818 }
    1819 
    1820 /* static */
    1821 QString UICommon::toCOMPortName(ulong uIRQ, ulong uIOBase)
    1822 {
    1823     for (size_t i = 0; i < RT_ELEMENTS(kComKnownPorts); ++i)
    1824         if (kComKnownPorts[i].IRQ == uIRQ &&
    1825             kComKnownPorts[i].IOBase == uIOBase)
    1826             return kComKnownPorts[i].name;
    1827 
    1828     return s_strUserDefinedPortName;
    1829 }
    1830 
    1831 /* static */
    1832 bool UICommon::toCOMPortNumbers(const QString &strName, ulong &uIRQ, ulong &uIOBase)
    1833 {
    1834     for (size_t i = 0; i < RT_ELEMENTS(kComKnownPorts); ++i)
    1835         if (strcmp(kComKnownPorts[i].name, strName.toUtf8().data()) == 0)
    1836         {
    1837             uIRQ = kComKnownPorts[i].IRQ;
    1838             uIOBase = kComKnownPorts[i].IOBase;
    1839             return true;
    1840         }
    1841 
    1842     return false;
    1843 }
    1844 
    1845 /* static */
    1846 QStringList UICommon::LPTPortNames()
    1847 {
    1848     QStringList list;
    1849     for (size_t i = 0; i < RT_ELEMENTS(kLptKnownPorts); ++i)
    1850         list << kLptKnownPorts[i].name;
    1851 
    1852     return list;
    1853 }
    1854 
    1855 /* static */
    1856 QString UICommon::toLPTPortName(ulong uIRQ, ulong uIOBase)
    1857 {
    1858     for (size_t i = 0; i < RT_ELEMENTS(kLptKnownPorts); ++i)
    1859         if (kLptKnownPorts[i].IRQ == uIRQ &&
    1860             kLptKnownPorts[i].IOBase == uIOBase)
    1861             return kLptKnownPorts[i].name;
    1862 
    1863     return s_strUserDefinedPortName;
    1864 }
    1865 
    1866 /* static */
    1867 bool UICommon::toLPTPortNumbers(const QString &strName, ulong &uIRQ, ulong &uIOBase)
    1868 {
    1869     for (size_t i = 0; i < RT_ELEMENTS(kLptKnownPorts); ++i)
    1870         if (strcmp(kLptKnownPorts[i].name, strName.toUtf8().data()) == 0)
    1871         {
    1872             uIRQ = kLptKnownPorts[i].IRQ;
    1873             uIOBase = kLptKnownPorts[i].IOBase;
    1874             return true;
    1875         }
    1876 
    1877     return false;
    1878 }
    1879 
    1880 /* static */
    1881 QString UICommon::highlight(QString strText, bool fToolTip /* = false */)
    1882 {
    1883     /* We should reformat the input strText so that:
    1884      * - strings in single quotes will be put inside <nobr> and marked
    1885      *   with blue color;
    1886      * - UUIDs be put inside <nobr> and marked
    1887      *   with green color;
    1888      * - replaces new line chars with </p><p> constructs to form paragraphs
    1889      *   (note that <p\> and </p> are not appended to the beginning and to the
    1890      *    end of the string respectively, to allow the result be appended
    1891      *    or prepended to the existing paragraph).
     290     * The order of precedence is well defined here:
     291     * http://opengroup.org/onlinepubs/007908799/xbd/envvar.html
    1892292     *
    1893      *  If @a fToolTip is true, colouring is not applied, only the <nobr> tag
    1894      *  is added. Also, new line chars are replaced with <br> instead of <p>. */
    1895 
    1896     QString strFont;
    1897     QString uuidFont;
    1898     QString endFont;
    1899     if (!fToolTip)
    1900     {
    1901         strFont = "<font color=#0000CC>";
    1902         uuidFont = "<font color=#008000>";
    1903         endFont = "</font>";
    1904     }
    1905 
    1906     /* Replace special entities, '&' -- first! */
    1907     strText.replace('&', "&amp;");
    1908     strText.replace('<', "&lt;");
    1909     strText.replace('>', "&gt;");
    1910     strText.replace('\"', "&quot;");
    1911 
    1912     /* Mark strings in single quotes with color: */
    1913     QRegExp rx = QRegExp("((?:^|\\s)[(]?)'([^']*)'(?=[:.-!);]?(?:\\s|$))");
    1914     rx.setMinimal(true);
    1915     strText.replace(rx, QString("\\1%1<nobr>'\\2'</nobr>%2").arg(strFont).arg(endFont));
    1916 
    1917     /* Mark UUIDs with color: */
    1918     strText.replace(QRegExp(
    1919         "((?:^|\\s)[(]?)"
    1920         "(\\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\\})"
    1921         "(?=[:.-!);]?(?:\\s|$))"),
    1922         QString("\\1%1<nobr>\\2</nobr>%2").arg(uuidFont).arg(endFont));
    1923 
    1924     /* Split to paragraphs at \n chars: */
    1925     if (!fToolTip)
    1926         strText.replace('\n', "</p><p>");
    1927     else
    1928         strText.replace('\n', "<br>");
    1929 
    1930     return strText;
    1931 }
    1932 
    1933 /* static */
    1934 QString UICommon::emphasize(QString strText)
    1935 {
    1936     /* We should reformat the input string @a strText so that:
    1937      * - strings in single quotes will be put inside \<nobr\> and marked
    1938      *   with bold style;
    1939      * - UUIDs be put inside \<nobr\> and marked
    1940      *   with italic style;
    1941      * - replaces new line chars with \</p\>\<p\> constructs to form paragraphs
    1942      *   (note that \<p\> and \</p\> are not appended to the beginning and to the
    1943      *    end of the string respectively, to allow the result be appended
    1944      *    or prepended to the existing paragraph). */
    1945 
    1946     QString strEmphStart("<b>");
    1947     QString strEmphEnd("</b>");
    1948     QString uuidEmphStart("<i>");
    1949     QString uuidEmphEnd("</i>");
    1950 
    1951     /* Replace special entities, '&' -- first! */
    1952     strText.replace('&', "&amp;");
    1953     strText.replace('<', "&lt;");
    1954     strText.replace('>', "&gt;");
    1955     strText.replace('\"', "&quot;");
    1956 
    1957     /* Mark strings in single quotes with bold style: */
    1958     QRegExp rx = QRegExp("((?:^|\\s)[(]?)'([^']*)'(?=[:.-!);]?(?:\\s|$))");
    1959     rx.setMinimal(true);
    1960     strText.replace(rx, QString("\\1%1<nobr>'\\2'</nobr>%2").arg(strEmphStart).arg(strEmphEnd));
    1961 
    1962     /* Mark UUIDs with italic style: */
    1963     strText.replace(QRegExp(
    1964         "((?:^|\\s)[(]?)"
    1965         "(\\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\\})"
    1966         "(?=[:.-!);]?(?:\\s|$))"),
    1967         QString("\\1%1<nobr>\\2</nobr>%2").arg(uuidEmphStart).arg(uuidEmphEnd));
    1968 
    1969     /* Split to paragraphs at \n chars: */
    1970     strText.replace('\n', "</p><p>");
    1971 
    1972     return strText;
    1973 }
    1974 
    1975 /* static */
    1976 QString UICommon::removeAccelMark(QString strText)
    1977 {
    1978     /* In order to support accelerators used in non-alphabet languages
    1979      * (e.g. Japanese) that has a form of "(&<L>)" (where <L> is a latin letter),
    1980      * this method first searches for this pattern and, if found, removes it as a
    1981      * whole. If such a pattern is not found, then the '&' character is simply
    1982      * removed from the string. */
    1983 
    1984     QRegExp accel("\\(&[a-zA-Z]\\)");
    1985     int iPos = accel.indexIn(strText);
    1986     if (iPos >= 0)
    1987         strText.remove(iPos, accel.cap().length());
    1988     else
    1989     {
    1990         iPos = strText.indexOf('&');
    1991         if (iPos >= 0)
    1992             strText.remove(iPos, 1);
    1993     }
    1994 
    1995     return strText;
    1996 }
    1997 
    1998 /* static */
    1999 QString UICommon::insertKeyToActionText(const QString &strText, const QString &strKey)
    2000 {
    2001 #ifdef VBOX_WS_MAC
    2002     QString strPattern("%1 (Host+%2)");
    2003 #else
    2004     QString strPattern("%1 \tHost+%2");
     293     * This method will return "C" when the requested locale is invalid or when the "C" locale is set explicitly. */
     294
     295#if defined(VBOX_WS_MAC)
     296    // QLocale return the right id only if the user select the format
     297    // of the language also. So we use our own implementation */
     298    return ::darwinSystemLanguage();
     299#elif defined(Q_OS_UNIX)
     300    const char *pszValue = RTEnvGet("LC_ALL");
     301    if (pszValue == 0)
     302        pszValue = RTEnvGet("LC_MESSAGES");
     303    if (pszValue == 0)
     304        pszValue = RTEnvGet("LANG");
     305    if (pszValue != 0)
     306        return QLocale(pszValue).name();
    2005307#endif
    2006     if (   strKey.isEmpty()
    2007         || strKey.compare("None", Qt::CaseInsensitive) == 0)
    2008         return strText;
    2009     else
    2010         return strPattern.arg(strText).arg(QKeySequence(strKey).toString(QKeySequence::NativeText));
    2011 }
    2012 
    2013 /* static */
    2014 QString UICommon::helpFile()
    2015 {
    2016 #if defined (VBOX_WITH_QHELP_VIEWER)
    2017     const QString strName = "UserManual";
    2018     const QString strSuffix = "qhc";
    2019 #else
    2020  #if defined(VBOX_WS_WIN)
    2021      const QString strName = "VirtualBox";
    2022      const QString strSuffix = "chm";
    2023  #elif defined(VBOX_WS_MAC)
    2024      const QString strName = "UserManual";
    2025      const QString strSuffix = "pdf";
    2026  #elif defined(VBOX_WS_X11)
    2027      //# if defined(VBOX_OSE) || !defined(VBOX_WITH_KCHMVIEWER)
    2028      const QString strName = "UserManual";
    2029      const QString strSuffix = "pdf";
    2030  #endif
    2031 #endif
    2032     /* Where are the docs located? */
    2033     char szDocsPath[RTPATH_MAX];
    2034     int rc = RTPathAppDocs(szDocsPath, sizeof(szDocsPath));
    2035     AssertRC(rc);
    2036 
    2037     /* Make sure that the language is in two letter code.
    2038      * Note: if languageId() returns an empty string lang.name() will
    2039      * return "C" which is an valid language code. */
    2040     QLocale lang(UICommon::languageId());
    2041 
    2042     /* Construct the path and the filename: */
    2043     QString strManual = QString("%1/%2_%3.%4").arg(szDocsPath)
    2044                                               .arg(strName)
    2045                                               .arg(lang.name())
    2046                                               .arg(strSuffix);
    2047 
    2048     /* Check if a help file with that name exists: */
    2049     QFileInfo fi(strManual);
    2050     if (fi.exists())
    2051         return strManual;
    2052 
    2053     /* Fall back to the standard: */
    2054     strManual = QString("%1/%2.%4").arg(szDocsPath)
    2055                                    .arg(strName)
    2056                                    .arg(strSuffix);
    2057     return strManual;
    2058 }
    2059 
    2060 /* static */
    2061 QString UICommon::documentsPath()
    2062 {
    2063     QString strPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    2064     QDir dir(strPath);
    2065     if (dir.exists())
    2066         return QDir::cleanPath(dir.canonicalPath());
    2067     else
    2068     {
    2069         dir.setPath(QDir::homePath() + "/Documents");
    2070         if (dir.exists())
    2071             return QDir::cleanPath(dir.canonicalPath());
    2072         else
    2073             return QDir::homePath();
    2074     }
    2075 }
    2076 
    2077 /* static */
    2078 bool UICommon::hasAllowedExtension(const QString &strFileName, const QStringList &extensions)
    2079 {
    2080     foreach (const QString &strExtension, extensions)
    2081         if (strFileName.endsWith(strExtension, Qt::CaseInsensitive))
    2082             return true;
    2083     return false;
    2084 }
    2085 
    2086 /* static */
    2087 QString UICommon::findUniqueFileName(const QString &strFullFolderPath, const QString &strBaseFileName)
    2088 {
    2089     QDir folder(strFullFolderPath);
    2090     if (!folder.exists())
    2091         return strBaseFileName;
    2092     QFileInfoList folderContent = folder.entryInfoList();
    2093     QSet<QString> fileNameSet;
    2094     foreach (const QFileInfo &fileInfo, folderContent)
    2095     {
    2096         /* Remove the extension : */
    2097         fileNameSet.insert(fileInfo.completeBaseName());
    2098     }
    2099     int iSuffix = 0;
    2100     QString strNewName(strBaseFileName);
    2101     while (fileNameSet.contains(strNewName))
    2102     {
    2103         strNewName = strBaseFileName + QString("_") + QString::number(++iSuffix);
    2104     }
    2105     return strNewName;
    2106 }
    2107 
    2108 /* static */
    2109 QRect UICommon::normalizeGeometry(const QRect &rectangle, const QRegion &boundRegion, bool fCanResize /* = true */)
    2110 {
    2111     /* Perform direct and flipped search of position for @a rectangle to make sure it is fully contained
    2112      * inside @a boundRegion region by moving & resizing (if @a fCanResize is specified) @a rectangle if
    2113      * necessary. Selects the minimum shifted result between direct and flipped variants. */
    2114 
    2115     /* Direct search for normalized rectangle: */
    2116     QRect var1(getNormalized(rectangle, boundRegion, fCanResize));
    2117 
    2118     /* Flipped search for normalized rectangle: */
    2119     QRect var2(flip(getNormalized(flip(rectangle).boundingRect(),
    2120                                   flip(boundRegion), fCanResize)).boundingRect());
    2121 
    2122     /* Calculate shift from starting position for both variants: */
    2123     double dLength1 = sqrt(pow((double)(var1.x() - rectangle.x()), (double)2) +
    2124                            pow((double)(var1.y() - rectangle.y()), (double)2));
    2125     double dLength2 = sqrt(pow((double)(var2.x() - rectangle.x()), (double)2) +
    2126                            pow((double)(var2.y() - rectangle.y()), (double)2));
    2127 
    2128     /* Return minimum shifted variant: */
    2129     return dLength1 > dLength2 ? var2 : var1;
    2130 }
    2131 
    2132 /* static */
    2133 QRect UICommon::getNormalized(const QRect &rectangle, const QRegion &boundRegion, bool /* fCanResize = true */)
    2134 {
    2135     /* Ensures that the given rectangle @a rectangle is fully contained within the region @a boundRegion
    2136      * by moving @a rectangle if necessary. If @a rectangle is larger than @a boundRegion, top left
    2137      * corner of @a rectangle is aligned with the top left corner of maximum available rectangle and,
    2138      * if @a fCanResize is true, @a rectangle is shrinked to become fully visible. */
    2139 
    2140     /* Storing available horizontal sub-rectangles & vertical shifts: */
    2141     const int iWindowVertical = rectangle.center().y();
    2142     QList<QRect> rectanglesList;
    2143     QList<int> shiftsList;
    2144     foreach (QRect currentItem, boundRegion.rects())
    2145     {
    2146         const int iCurrentDelta = qAbs(iWindowVertical - currentItem.center().y());
    2147         const int iShift2Top = currentItem.top() - rectangle.top();
    2148         const int iShift2Bot = currentItem.bottom() - rectangle.bottom();
    2149 
    2150         int iTtemPosition = 0;
    2151         foreach (QRect item, rectanglesList)
    2152         {
    2153             const int iDelta = qAbs(iWindowVertical - item.center().y());
    2154             if (iDelta > iCurrentDelta)
    2155                 break;
    2156             else
    2157                 ++iTtemPosition;
    2158         }
    2159         rectanglesList.insert(iTtemPosition, currentItem);
    2160 
    2161         int iShift2TopPos = 0;
    2162         foreach (int iShift, shiftsList)
    2163             if (qAbs(iShift) > qAbs(iShift2Top))
    2164                 break;
    2165             else
    2166                 ++iShift2TopPos;
    2167         shiftsList.insert(iShift2TopPos, iShift2Top);
    2168 
    2169         int iShift2BotPos = 0;
    2170         foreach (int iShift, shiftsList)
    2171             if (qAbs(iShift) > qAbs(iShift2Bot))
    2172                 break;
    2173             else
    2174                 ++iShift2BotPos;
    2175         shiftsList.insert(iShift2BotPos, iShift2Bot);
    2176     }
    2177 
    2178     /* Trying to find the appropriate place for window: */
    2179     QRect result;
    2180     for (int i = -1; i < shiftsList.size(); ++i)
    2181     {
    2182         /* Move to appropriate vertical: */
    2183         QRect newRectangle(rectangle);
    2184         if (i >= 0)
    2185             newRectangle.translate(0, shiftsList[i]);
    2186 
    2187         /* Search horizontal shift: */
    2188         int iMaxShift = 0;
    2189         foreach (QRect item, rectanglesList)
    2190         {
    2191             QRect trectangle(newRectangle.translated(item.left() - newRectangle.left(), 0));
    2192             if (!item.intersects(trectangle))
    2193                 continue;
    2194 
    2195             if (newRectangle.left() < item.left())
    2196             {
    2197                 const int iShift = item.left() - newRectangle.left();
    2198                 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift;
    2199             }
    2200             else if (newRectangle.right() > item.right())
    2201             {
    2202                 const int iShift = item.right() - newRectangle.right();
    2203                 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift;
    2204             }
    2205         }
    2206 
    2207         /* Shift across the horizontal direction: */
    2208         newRectangle.translate(iMaxShift, 0);
    2209 
    2210         /* Check the translated rectangle to feat the rules: */
    2211         if (boundRegion.united(newRectangle) == boundRegion)
    2212             result = newRectangle;
    2213 
    2214         if (!result.isNull())
    2215             break;
    2216     }
    2217 
    2218     if (result.isNull())
    2219     {
    2220         /* Resize window to feat desirable size
    2221          * using max of available rectangles: */
    2222         QRect maxRectangle;
    2223         quint64 uMaxSquare = 0;
    2224         foreach (QRect item, rectanglesList)
    2225         {
    2226             const quint64 uSquare = item.width() * item.height();
    2227             if (uSquare > uMaxSquare)
    2228             {
    2229                 uMaxSquare = uSquare;
    2230                 maxRectangle = item;
    2231             }
    2232         }
    2233 
    2234         result = rectangle;
    2235         result.moveTo(maxRectangle.x(), maxRectangle.y());
    2236         if (maxRectangle.right() < result.right())
    2237             result.setRight(maxRectangle.right());
    2238         if (maxRectangle.bottom() < result.bottom())
    2239             result.setBottom(maxRectangle.bottom());
    2240     }
    2241 
    2242     return result;
    2243 }
    2244 
    2245 /* static */
    2246 QRegion UICommon::flip(const QRegion &region)
    2247 {
    2248     QRegion result;
    2249     QVector<QRect> rectangles(region.rects());
    2250     foreach (QRect rectangle, rectangles)
    2251         result += QRect(rectangle.y(), rectangle.x(),
    2252                         rectangle.height(), rectangle.width());
    2253     return result;
    2254 }
    2255 
    2256 /* static */
    2257 void UICommon::centerWidget(QWidget *pWidget, QWidget *pRelative, bool fCanResize /* = true */)
    2258 {
    2259     /* If necessary, pWidget's position is adjusted to make it fully visible within
    2260      * the available desktop area. If pWidget is bigger then this area, it will also
    2261      * be resized unless fCanResize is false or there is an inappropriate minimum
    2262      * size limit (in which case the top left corner will be simply aligned with the top
    2263      * left corner of the available desktop area). pWidget must be a top-level widget.
    2264      * pRelative may be any widget, but if it's not top-level itself, its top-level
    2265      * widget will be used for calculations. pRelative can also be NULL, in which case
    2266      * pWidget will be centered relative to the available desktop area. */
    2267 
    2268     AssertReturnVoid(pWidget);
    2269     AssertReturnVoid(pWidget->isTopLevel());
    2270 
    2271     QRect deskGeo, parentGeo;
    2272     if (pRelative)
    2273     {
    2274         pRelative = pRelative->window();
    2275         deskGeo = gpDesktop->availableGeometry(pRelative);
    2276         parentGeo = pRelative->frameGeometry();
    2277         // WORKAROUND:
    2278         // On X11/Gnome, geo/frameGeo.x() and y() are always 0 for top level
    2279         // widgets with parents, what a shame. Use mapToGlobal() to workaround.
    2280         QPoint d = pRelative->mapToGlobal(QPoint(0, 0));
    2281         d.rx() -= pRelative->geometry().x() - pRelative->x();
    2282         d.ry() -= pRelative->geometry().y() - pRelative->y();
    2283         parentGeo.moveTopLeft(d);
    2284     }
    2285     else
    2286     {
    2287         deskGeo = gpDesktop->availableGeometry();
    2288         parentGeo = deskGeo;
    2289     }
    2290 
    2291     // WORKAROUND:
    2292     // On X11, there is no way to determine frame geometry (including WM
    2293     // decorations) before the widget is shown for the first time. Stupidly
    2294     // enumerate other top level widgets to find the thickest frame. The code
    2295     // is based on the idea taken from QDialog::adjustPositionInternal().
    2296 
    2297     int iExtraW = 0;
    2298     int iExtraH = 0;
    2299 
    2300     QWidgetList list = QApplication::topLevelWidgets();
    2301     QListIterator<QWidget*> it(list);
    2302     while ((iExtraW == 0 || iExtraH == 0) && it.hasNext())
    2303     {
    2304         int iFrameW, iFrameH;
    2305         QWidget *pCurrent = it.next();
    2306         if (!pCurrent->isVisible())
    2307             continue;
    2308 
    2309         iFrameW = pCurrent->frameGeometry().width() - pCurrent->width();
    2310         iFrameH = pCurrent->frameGeometry().height() - pCurrent->height();
    2311 
    2312         iExtraW = qMax(iExtraW, iFrameW);
    2313         iExtraH = qMax(iExtraH, iFrameH);
    2314     }
    2315 
    2316     /* On non-X11 platforms, the following would be enough instead of the above workaround: */
    2317     // QRect geo = frameGeometry();
    2318     QRect geo = QRect(0, 0, pWidget->width() + iExtraW,
    2319                             pWidget->height() + iExtraH);
    2320 
    2321     geo.moveCenter(QPoint(parentGeo.x() + (parentGeo.width() - 1) / 2,
    2322                           parentGeo.y() + (parentGeo.height() - 1) / 2));
    2323 
    2324     /* Ensure the widget is within the available desktop area: */
    2325     QRect newGeo = normalizeGeometry(geo, deskGeo, fCanResize);
    2326 #ifdef VBOX_WS_MAC
    2327     // WORKAROUND:
    2328     // No idea why, but Qt doesn't respect if there is a unified toolbar on the
    2329     // ::move call. So manually add the height of the toolbar before setting
    2330     // the position.
    2331     if (pRelative)
    2332         newGeo.translate(0, ::darwinWindowToolBarHeight(pWidget));
    2333 #endif /* VBOX_WS_MAC */
    2334 
    2335     pWidget->move(newGeo.topLeft());
    2336 
    2337     if (   fCanResize
    2338         && (geo.width() != newGeo.width() || geo.height() != newGeo.height()))
    2339         pWidget->resize(newGeo.width() - iExtraW, newGeo.height() - iExtraH);
    2340 }
    2341 
    2342 #ifdef VBOX_WS_X11
    2343 typedef struct {
    2344 /** User specified flags */
    2345 uint32_t flags;
    2346 /** User-specified position */
    2347 int32_t x, y;
    2348 /** User-specified size */
    2349 int32_t width, height;
    2350 /** Program-specified minimum size */
    2351 int32_t min_width, min_height;
    2352 /** Program-specified maximum size */
    2353 int32_t max_width, max_height;
    2354 /** Program-specified resize increments */
    2355 int32_t width_inc, height_inc;
    2356 /** Program-specified minimum aspect ratios */
    2357 int32_t min_aspect_num, min_aspect_den;
    2358 /** Program-specified maximum aspect ratios */
    2359 int32_t max_aspect_num, max_aspect_den;
    2360 /** Program-specified base size */
    2361 int32_t base_width, base_height;
    2362 /** Program-specified window gravity */
    2363 uint32_t win_gravity;
    2364 } xcb_size_hints_t;
    2365 #endif /* VBOX_WS_X11 */
    2366 
    2367 /* static */
    2368 void UICommon::setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int h)
    2369 {
    2370     AssertPtrReturnVoid(pWidget);
    2371 #ifdef VBOX_WS_X11
    2372 # define QWINDOWSIZE_MAX ((1<<24)-1)
    2373     if (pWidget->isWindow() && pWidget->isVisible())
    2374     {
    2375         // WORKAROUND:
    2376         // X11 window managers are not required to accept geometry changes on
    2377         // the top-level window.  Unfortunately, current at Qt 5.6 and 5.7, Qt
    2378         // assumes that the change will succeed, and resizes all sub-windows
    2379         // unconditionally.  By calling ConfigureWindow directly, Qt will see
    2380         // our change request as an externally triggered one on success and not
    2381         // at all if it is rejected.
    2382         const double dDPR = gpDesktop->devicePixelRatio(pWidget);
    2383         uint16_t fMask =   XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
    2384                          | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
    2385         uint32_t values[] = { (uint32_t)(x * dDPR), (uint32_t)(y * dDPR), (uint32_t)(w * dDPR), (uint32_t)(h * dDPR) };
    2386         xcb_configure_window(QX11Info::connection(), (xcb_window_t)pWidget->winId(),
    2387                              fMask, values);
    2388         xcb_size_hints_t hints;
    2389         hints.flags =   1 /* XCB_ICCCM_SIZE_HINT_US_POSITION */
    2390                       | 2 /* XCB_ICCCM_SIZE_HINT_US_SIZE */
    2391                       | 512 /* XCB_ICCCM_SIZE_P_WIN_GRAVITY */;
    2392         hints.x           = x * dDPR;
    2393         hints.y           = y * dDPR;
    2394         hints.width       = w * dDPR;
    2395         hints.height      = h * dDPR;
    2396         hints.min_width   = pWidget->minimumSize().width() * dDPR;
    2397         hints.min_height  = pWidget->minimumSize().height() * dDPR;
    2398         hints.max_width   = pWidget->maximumSize().width() * dDPR;
    2399         hints.max_height  = pWidget->maximumSize().height() * dDPR;
    2400         hints.width_inc   = pWidget->sizeIncrement().width() * dDPR;
    2401         hints.height_inc  = pWidget->sizeIncrement().height() * dDPR;
    2402         hints.base_width  = pWidget->baseSize().width() * dDPR;
    2403         hints.base_height = pWidget->baseSize().height() * dDPR;
    2404         hints.win_gravity = XCB_GRAVITY_STATIC;
    2405         if (hints.min_width > 0 || hints.min_height > 0)
    2406             hints.flags |= 16 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */;
    2407         if (hints.max_width < QWINDOWSIZE_MAX || hints.max_height < QWINDOWSIZE_MAX)
    2408             hints.flags |= 32 /* XCB_ICCCM_SIZE_HINT_P_MAX_SIZE */;
    2409         if (hints.width_inc > 0 || hints.height_inc)
    2410             hints.flags |=   64 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */
    2411                            | 256 /* XCB_ICCCM_SIZE_HINT_BASE_SIZE */;
    2412         xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE,
    2413                             (xcb_window_t)pWidget->winId(), XCB_ATOM_WM_NORMAL_HINTS,
    2414                             XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) >> 2, &hints);
    2415         xcb_flush(QX11Info::connection());
    2416     }
    2417     else
    2418         // WORKAROUND:
    2419         // Call the Qt method if the window is not visible as otherwise no
    2420         // Configure event will arrive to tell Qt what geometry we want.
    2421         pWidget->setGeometry(x, y, w, h);
    2422 # else /* !VBOX_WS_X11 */
    2423     pWidget->setGeometry(x, y, w, h);
    2424 # endif /* !VBOX_WS_X11 */
    2425 }
    2426 
    2427 /* static */
    2428 void UICommon::setTopLevelGeometry(QWidget *pWidget, const QRect &rect)
    2429 {
    2430     UICommon::setTopLevelGeometry(pWidget, rect.x(), rect.y(), rect.width(), rect.height());
    2431 }
    2432 
    2433 #if defined(VBOX_WS_X11)
    2434 
    2435 static char *XXGetProperty(Display *pDpy, Window windowHandle, Atom propType, const char *pszPropName)
    2436 {
    2437     Atom propNameAtom = XInternAtom(pDpy, pszPropName, True /* only_if_exists */);
    2438     if (propNameAtom == None)
    2439         return NULL;
    2440 
    2441     Atom actTypeAtom = None;
    2442     int actFmt = 0;
    2443     unsigned long nItems = 0;
    2444     unsigned long nBytesAfter = 0;
    2445     unsigned char *propVal = NULL;
    2446     int rc = XGetWindowProperty(pDpy, windowHandle, propNameAtom,
    2447                                 0, LONG_MAX, False /* delete */,
    2448                                 propType, &actTypeAtom, &actFmt,
    2449                                 &nItems, &nBytesAfter, &propVal);
    2450     if (rc != Success)
    2451         return NULL;
    2452 
    2453     return reinterpret_cast<char*>(propVal);
    2454 }
    2455 
    2456 static Bool XXSendClientMessage(Display *pDpy, Window windowHandle, const char *pszMsg,
    2457                                 unsigned long aData0 = 0, unsigned long aData1 = 0,
    2458                                 unsigned long aData2 = 0, unsigned long aData3 = 0,
    2459                                 unsigned long aData4 = 0)
    2460 {
    2461     Atom msgAtom = XInternAtom(pDpy, pszMsg, True /* only_if_exists */);
    2462     if (msgAtom == None)
    2463         return False;
    2464 
    2465     XEvent ev;
    2466 
    2467     ev.xclient.type = ClientMessage;
    2468     ev.xclient.serial = 0;
    2469     ev.xclient.send_event = True;
    2470     ev.xclient.display = pDpy;
    2471     ev.xclient.window = windowHandle;
    2472     ev.xclient.message_type = msgAtom;
    2473 
    2474     /* Always send as 32 bit for now: */
    2475     ev.xclient.format = 32;
    2476     ev.xclient.data.l[0] = aData0;
    2477     ev.xclient.data.l[1] = aData1;
    2478     ev.xclient.data.l[2] = aData2;
    2479     ev.xclient.data.l[3] = aData3;
    2480     ev.xclient.data.l[4] = aData4;
    2481 
    2482     return XSendEvent(pDpy, DefaultRootWindow(pDpy), False,
    2483                       SubstructureRedirectMask, &ev) != 0;
    2484 }
    2485 
    2486 #endif
    2487 
    2488 /* static */
    2489 bool UICommon::activateWindow(WId wId, bool fSwitchDesktop /* = true */)
    2490 {
    2491     RT_NOREF(fSwitchDesktop);
    2492     bool fResult = true;
    2493 
    2494 #if defined(VBOX_WS_WIN)
    2495 
    2496     HWND handle = (HWND)wId;
    2497 
    2498     if (IsIconic(handle))
    2499         fResult &= !!ShowWindow(handle, SW_RESTORE);
    2500     else if (!IsWindowVisible(handle))
    2501         fResult &= !!ShowWindow(handle, SW_SHOW);
    2502 
    2503     fResult &= !!SetForegroundWindow(handle);
    2504 
    2505 #elif defined(VBOX_WS_X11)
    2506 
    2507     Display *pDisplay = QX11Info::display();
    2508 
    2509     if (fSwitchDesktop)
    2510     {
    2511         /* try to find the desktop ID using the NetWM property */
    2512         CARD32 *pDesktop = (CARD32 *) XXGetProperty(pDisplay, wId, XA_CARDINAL,
    2513                                                     "_NET_WM_DESKTOP");
    2514         if (pDesktop == NULL)
    2515             // WORKAROUND:
    2516             // if the NetWM properly is not supported try to find
    2517             // the desktop ID using the GNOME WM property.
    2518             pDesktop = (CARD32 *) XXGetProperty(pDisplay, wId, XA_CARDINAL,
    2519                                                 "_WIN_WORKSPACE");
    2520 
    2521         if (pDesktop != NULL)
    2522         {
    2523             Bool ok = XXSendClientMessage(pDisplay, DefaultRootWindow(pDisplay),
    2524                                           "_NET_CURRENT_DESKTOP",
    2525                                           *pDesktop);
    2526             if (!ok)
    2527             {
    2528                 Log1WarningFunc(("Couldn't switch to pDesktop=%08X\n", pDesktop));
    2529                 fResult = false;
    2530             }
    2531             XFree(pDesktop);
    2532         }
    2533         else
    2534         {
    2535             Log1WarningFunc(("Couldn't find a pDesktop ID for wId=%08X\n", wId));
    2536             fResult = false;
    2537         }
    2538     }
    2539 
    2540     Bool ok = XXSendClientMessage(pDisplay, wId, "_NET_ACTIVE_WINDOW");
    2541     fResult &= !!ok;
    2542 
    2543     XRaiseWindow(pDisplay, wId);
    2544 
    2545 #else
    2546 
    2547     NOREF(wId);
    2548     NOREF(fSwitchDesktop);
    2549     AssertFailed();
    2550     fResult = false;
    2551 
    2552 #endif
    2553 
    2554     if (!fResult)
    2555         Log1WarningFunc(("Couldn't activate wId=%08X\n", wId));
    2556 
    2557     return fResult;
    2558 }
    2559 
    2560 /* static */
    2561 void UICommon::setCursor(QWidget *pWidget, const QCursor &cursor)
    2562 {
    2563     if (!pWidget)
    2564         return;
    2565 
    2566 #ifdef VBOX_WS_X11
    2567     /* As reported in https://www.virtualbox.org/ticket/16348,
    2568      * in X11 QWidget::setCursor(..) call uses RENDER
    2569      * extension. Qt (before 5.11) fails to handle the case where the mentioned extension
    2570      * is missing. Please see https://codereview.qt-project.org/#/c/225665/ for Qt patch: */
    2571     if ((UICommon::qtRTMajorVersion() < 5) ||
    2572         (UICommon::qtRTMajorVersion() == 5 && UICommon::qtRTMinorVersion() < 11))
    2573     {
    2574         if (X11CheckExtension("RENDER"))
    2575             pWidget->setCursor(cursor);
    2576     }
    2577     else
    2578     {
    2579         pWidget->setCursor(cursor);
    2580     }
    2581 #else
    2582     pWidget->setCursor(cursor);
    2583 #endif
    2584 }
    2585 
    2586 /* static */
    2587 void UICommon::setCursor(QGraphicsWidget *pWidget, const QCursor &cursor)
    2588 {
    2589     if (!pWidget)
    2590         return;
    2591 
    2592 #ifdef VBOX_WS_X11
    2593     /* As reported in https://www.virtualbox.org/ticket/16348,
    2594      * in X11 QGraphicsWidget::setCursor(..) call uses RENDER
    2595      * extension. Qt (before 5.11) fails to handle the case where the mentioned extension
    2596      * is missing. Please see https://codereview.qt-project.org/#/c/225665/ for Qt patch: */
    2597     if ((UICommon::qtRTMajorVersion() < 5) ||
    2598         (UICommon::qtRTMajorVersion() == 5 && UICommon::qtRTMinorVersion() < 11))
    2599     {
    2600         if (X11CheckExtension("RENDER"))
    2601             pWidget->setCursor(cursor);
    2602     }
    2603     else
    2604     {
    2605         pWidget->setCursor(cursor);
    2606     }
    2607 #else
    2608     pWidget->setCursor(cursor);
    2609 #endif
    2610 }
    2611 
    2612 /* static */
    2613 void UICommon::unsetCursor(QWidget *pWidget)
    2614 {
    2615     if (!pWidget)
    2616         return;
    2617 
    2618 #ifdef VBOX_WS_X11
    2619     /* As reported in https://www.virtualbox.org/ticket/16348,
    2620      * in X11 QWidget::unsetCursor(..) call uses RENDER
    2621      * extension. Qt (before 5.11) fails to handle the case where the mentioned extension
    2622      * is missing. Please see https://codereview.qt-project.org/#/c/225665/ for Qt patch: */
    2623     if ((UICommon::qtRTMajorVersion() < 5) ||
    2624         (UICommon::qtRTMajorVersion() == 5 && UICommon::qtRTMinorVersion() < 11))
    2625     {
    2626         if (X11CheckExtension("RENDER"))
    2627             pWidget->unsetCursor();
    2628     }
    2629     else
    2630     {
    2631         pWidget->unsetCursor();
    2632     }
    2633 #else
    2634     pWidget->unsetCursor();
    2635 #endif
    2636 }
    2637 
    2638 /* static */
    2639 void UICommon::unsetCursor(QGraphicsWidget *pWidget)
    2640 {
    2641     if (!pWidget)
    2642         return;
    2643 
    2644 #ifdef VBOX_WS_X11
    2645     /* As reported in https://www.virtualbox.org/ticket/16348,
    2646      * in X11 QGraphicsWidget::unsetCursor(..) call uses RENDER
    2647      * extension. Qt (before 5.11) fails to handle the case where the mentioned extension
    2648      * is missing. Please see https://codereview.qt-project.org/#/c/225665/ for Qt patch: */
    2649     if ((UICommon::qtRTMajorVersion() < 5) ||
    2650         (UICommon::qtRTMajorVersion() == 5 && UICommon::qtRTMinorVersion() < 11))
    2651     {
    2652         if (X11CheckExtension("RENDER"))
    2653             pWidget->unsetCursor();
    2654     }
    2655     else
    2656     {
    2657         pWidget->unsetCursor();
    2658     }
    2659 #else
    2660     pWidget->unsetCursor();
    2661 #endif
    2662 }
    2663 
    2664 
    2665 #if defined(VBOX_WS_X11)
    2666 
    2667 /* static */
    2668 bool UICommon::supportsFullScreenMonitorsProtocolX11()
    2669 {
    2670     /* This method tests whether the current X11 window manager supports full-screen mode as we need it.
    2671      * Unfortunately the EWMH specification was not fully clear about whether we can expect to find
    2672      * all of these atoms on the _NET_SUPPORTED root window property, so we have to test with all
    2673      * interesting window managers. If this fails for a user when you think it should succeed
    2674      * they should try executing:
    2675      * xprop -root | egrep -w '_NET_WM_FULLSCREEN_MONITORS|_NET_WM_STATE|_NET_WM_STATE_FULLSCREEN'
    2676      * in an X11 terminal window.
    2677      * All three strings should be found under a property called "_NET_SUPPORTED(ATOM)". */
    2678 
    2679     /* Using a global to get at the display does not feel right, but that is how it is done elsewhere in the code. */
    2680     Display *pDisplay = QX11Info::display();
    2681     Atom atomSupported            = XInternAtom(pDisplay, "_NET_SUPPORTED",
    2682                                                 True /* only_if_exists */);
    2683     Atom atomWMFullScreenMonitors = XInternAtom(pDisplay,
    2684                                                 "_NET_WM_FULLSCREEN_MONITORS",
    2685                                                 True /* only_if_exists */);
    2686     Atom atomWMState              = XInternAtom(pDisplay,
    2687                                                 "_NET_WM_STATE",
    2688                                                 True /* only_if_exists */);
    2689     Atom atomWMStateFullScreen    = XInternAtom(pDisplay,
    2690                                                 "_NET_WM_STATE_FULLSCREEN",
    2691                                                 True /* only_if_exists */);
    2692     bool fFoundFullScreenMonitors = false;
    2693     bool fFoundState              = false;
    2694     bool fFoundStateFullScreen    = false;
    2695     Atom atomType;
    2696     int cFormat;
    2697     unsigned long cItems;
    2698     unsigned long cbLeft;
    2699     Atom *pAtomHints;
    2700     int rc;
    2701     unsigned i;
    2702 
    2703     if (   atomSupported == None || atomWMFullScreenMonitors == None
    2704         || atomWMState == None || atomWMStateFullScreen == None)
    2705         return false;
    2706     /* Get atom value: */
    2707     rc = XGetWindowProperty(pDisplay, DefaultRootWindow(pDisplay),
    2708                             atomSupported, 0, 0x7fffffff /*LONG_MAX*/,
    2709                             False /* delete */, XA_ATOM, &atomType,
    2710                             &cFormat, &cItems, &cbLeft,
    2711                             (unsigned char **)&pAtomHints);
    2712     if (rc != Success)
    2713         return false;
    2714     if (pAtomHints == NULL)
    2715         return false;
    2716     if (atomType == XA_ATOM && cFormat == 32 && cbLeft == 0)
    2717         for (i = 0; i < cItems; ++i)
    2718         {
    2719             if (pAtomHints[i] == atomWMFullScreenMonitors)
    2720                 fFoundFullScreenMonitors = true;
    2721             if (pAtomHints[i] == atomWMState)
    2722                 fFoundState = true;
    2723             if (pAtomHints[i] == atomWMStateFullScreen)
    2724                 fFoundStateFullScreen = true;
    2725         }
    2726     XFree(pAtomHints);
    2727     return fFoundFullScreenMonitors && fFoundState && fFoundStateFullScreen;
    2728 }
    2729 
    2730 /* static */
    2731 bool UICommon::setFullScreenMonitorX11(QWidget *pWidget, ulong uScreenId)
    2732 {
    2733     return XXSendClientMessage(QX11Info::display(),
    2734                                pWidget->window()->winId(),
    2735                                "_NET_WM_FULLSCREEN_MONITORS",
    2736                                uScreenId, uScreenId, uScreenId, uScreenId,
    2737                                1 /* Source indication (1 = normal application) */);
    2738 }
    2739 
    2740 /* static */
    2741 QVector<Atom> UICommon::flagsNetWmState(QWidget *pWidget)
    2742 {
    2743     /* Get display: */
    2744     Display *pDisplay = QX11Info::display();
    2745 
    2746     /* Prepare atoms: */
    2747     QVector<Atom> resultNetWmState;
    2748     Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
    2749 
    2750     /* Get the size of the property data: */
    2751     Atom actual_type;
    2752     int iActualFormat;
    2753     ulong uPropertyLength;
    2754     ulong uBytesLeft;
    2755     uchar *pPropertyData = 0;
    2756     if (XGetWindowProperty(pDisplay, pWidget->window()->winId(),
    2757                            net_wm_state, 0, 0, False, XA_ATOM, &actual_type, &iActualFormat,
    2758                            &uPropertyLength, &uBytesLeft, &pPropertyData) == Success &&
    2759         actual_type == XA_ATOM && iActualFormat == 32)
    2760     {
    2761         resultNetWmState.resize(uBytesLeft / 4);
    2762         XFree((char*)pPropertyData);
    2763         pPropertyData = 0;
    2764 
    2765         /* Fetch all data: */
    2766         if (XGetWindowProperty(pDisplay, pWidget->window()->winId(),
    2767                                net_wm_state, 0, resultNetWmState.size(), False, XA_ATOM, &actual_type, &iActualFormat,
    2768                                &uPropertyLength, &uBytesLeft, &pPropertyData) != Success)
    2769             resultNetWmState.clear();
    2770         else if (uPropertyLength != (ulong)resultNetWmState.size())
    2771             resultNetWmState.resize(uPropertyLength);
    2772 
    2773         /* Put it into resultNetWmState: */
    2774         if (!resultNetWmState.isEmpty())
    2775             memcpy(resultNetWmState.data(), pPropertyData, resultNetWmState.size() * sizeof(Atom));
    2776         if (pPropertyData)
    2777             XFree((char*)pPropertyData);
    2778     }
    2779 
    2780     /* Return result: */
    2781     return resultNetWmState;
    2782 }
    2783 
    2784 /* static */
    2785 bool UICommon::isFullScreenFlagSet(QWidget *pWidget)
    2786 {
    2787     /* Get display: */
    2788     Display *pDisplay = QX11Info::display();
    2789 
    2790     /* Prepare atoms: */
    2791     Atom net_wm_state_fullscreen = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", True /* only if exists */);
    2792 
    2793     /* Check if flagsNetWmState(pWidget) contains full-screen flag: */
    2794     return flagsNetWmState(pWidget).contains(net_wm_state_fullscreen);
    2795 }
    2796 
    2797 /* static */
    2798 void UICommon::setFullScreenFlag(QWidget *pWidget)
    2799 {
    2800     /* Get display: */
    2801     Display *pDisplay = QX11Info::display();
    2802 
    2803     /* Prepare atoms: */
    2804     QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
    2805     Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
    2806     Atom net_wm_state_fullscreen = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", True /* only if exists */);
    2807 
    2808     /* Append resultNetWmState with fullscreen flag if necessary: */
    2809     if (!resultNetWmState.contains(net_wm_state_fullscreen))
    2810     {
    2811         resultNetWmState.append(net_wm_state_fullscreen);
    2812         /* Apply property to widget again: */
    2813         XChangeProperty(pDisplay, pWidget->window()->winId(),
    2814                         net_wm_state, XA_ATOM, 32, PropModeReplace,
    2815                         (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
    2816     }
    2817 }
    2818 
    2819 /* static */
    2820 void UICommon::setSkipTaskBarFlag(QWidget *pWidget)
    2821 {
    2822     /* Get display: */
    2823     Display *pDisplay = QX11Info::display();
    2824 
    2825     /* Prepare atoms: */
    2826     QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
    2827     Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
    2828     Atom net_wm_state_skip_taskbar = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", True /* only if exists */);
    2829 
    2830     /* Append resultNetWmState with skip-taskbar flag if necessary: */
    2831     if (!resultNetWmState.contains(net_wm_state_skip_taskbar))
    2832     {
    2833         resultNetWmState.append(net_wm_state_skip_taskbar);
    2834         /* Apply property to widget again: */
    2835         XChangeProperty(pDisplay, pWidget->window()->winId(),
    2836                         net_wm_state, XA_ATOM, 32, PropModeReplace,
    2837                         (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
    2838     }
    2839 }
    2840 
    2841 /* static */
    2842 void UICommon::setSkipPagerFlag(QWidget *pWidget)
    2843 {
    2844     /* Get display: */
    2845     Display *pDisplay = QX11Info::display();
    2846 
    2847     /* Prepare atoms: */
    2848     QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
    2849     Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
    2850     Atom net_wm_state_skip_pager = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_PAGER", True /* only if exists */);
    2851 
    2852     /* Append resultNetWmState with skip-pager flag if necessary: */
    2853     if (!resultNetWmState.contains(net_wm_state_skip_pager))
    2854     {
    2855         resultNetWmState.append(net_wm_state_skip_pager);
    2856         /* Apply property to widget again: */
    2857         XChangeProperty(pDisplay, pWidget->window()->winId(),
    2858                         net_wm_state, XA_ATOM, 32, PropModeReplace,
    2859                         (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
    2860     }
    2861 }
    2862 
    2863 /* static */
    2864 void UICommon::setWMClass(QWidget *pWidget, const QString &strNameString, const QString &strClassString)
    2865 {
    2866     /* Make sure all arguments set: */
    2867     AssertReturnVoid(pWidget && !strNameString.isNull() && !strClassString.isNull());
    2868 
    2869     /* Define QByteArray objects to make sure data is alive within the scope: */
    2870     QByteArray nameByteArray;
    2871     /* Check the existence of RESOURCE_NAME env. variable and override name string if necessary: */
    2872     const char resourceName[] = "RESOURCE_NAME";
    2873     if (qEnvironmentVariableIsSet(resourceName))
    2874         nameByteArray = qgetenv(resourceName);
    2875     else
    2876         nameByteArray = strNameString.toLatin1();
    2877     QByteArray classByteArray = strClassString.toLatin1();
    2878 
    2879     AssertReturnVoid(nameByteArray.data() && classByteArray.data());
    2880 
    2881     XClassHint windowClass;
    2882     windowClass.res_name = nameByteArray.data();
    2883     windowClass.res_class = classByteArray.data();
    2884     /* Set WM_CLASS of the window to passed name and class strings: */
    2885     XSetClassHint(QX11Info::display(), pWidget->window()->winId(), &windowClass);
    2886 }
    2887 
    2888 /* static */
    2889 void UICommon::setXwaylandMayGrabKeyboardFlag(QWidget *pWidget)
    2890 {
    2891     XXSendClientMessage(QX11Info::display(), pWidget->window()->winId(),
    2892                         "_XWAYLAND_MAY_GRAB_KEYBOARD", 1);
    2893 }
    2894 #endif /* VBOX_WS_X11 */
    2895 
    2896 /* static */
    2897 void UICommon::setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount)
    2898 {
    2899     /* Shame on Qt it hasn't stuff for tuning
    2900      * widget size suitable for reflecting content of desired size.
    2901      * For example QLineEdit, QSpinBox and similar widgets should have a methods
    2902      * to strict the minimum width to reflect at least [n] symbols. */
    2903 
    2904     /* Load options: */
    2905     QStyleOptionSpinBox option;
    2906     option.initFrom(pSpinBox);
    2907 
    2908     /* Acquire edit-field rectangle: */
    2909     QRect rect = pSpinBox->style()->subControlRect(QStyle::CC_SpinBox,
    2910                                                    &option,
    2911                                                    QStyle::SC_SpinBoxEditField,
    2912                                                    pSpinBox);
    2913 
    2914     /* Calculate minimum-width magic: */
    2915     const int iSpinBoxWidth = pSpinBox->width();
    2916     const int iSpinBoxEditFieldWidth = rect.width();
    2917     const int iSpinBoxDelta = qMax(0, iSpinBoxWidth - iSpinBoxEditFieldWidth);
    2918     QFontMetrics metrics(pSpinBox->font(), pSpinBox);
    2919     const QString strDummy(cCount, '0');
    2920     const int iTextWidth = metrics.width(strDummy);
    2921 
    2922     /* Tune spin-box minimum-width: */
    2923     pSpinBox->setMinimumWidth(iTextWidth + iSpinBoxDelta);
    2924 }
    2925 
    2926 QString UICommon::vmGuestOSFamilyDescription(const QString &strFamilyId) const
    2927 {
    2928     AssertMsg(m_guestOSFamilyDescriptions.contains(strFamilyId),
    2929               ("Family ID incorrect: '%s'.", strFamilyId.toLatin1().constData()));
    2930     return m_guestOSFamilyDescriptions.value(strFamilyId);
    2931 }
    2932 
    2933 QList<CGuestOSType> UICommon::vmGuestOSTypeList(const QString &strFamilyId) const
    2934 {
    2935     AssertMsg(m_guestOSFamilyIDs.contains(strFamilyId),
    2936               ("Family ID incorrect: '%s'.", strFamilyId.toLatin1().constData()));
    2937     return m_guestOSFamilyIDs.contains(strFamilyId) ?
    2938            m_guestOSTypes[m_guestOSFamilyIDs.indexOf(strFamilyId)] : QList<CGuestOSType>();
    2939 }
    2940 
    2941 CGuestOSType UICommon::vmGuestOSType(const QString &strTypeId,
    2942                                        const QString &strFamilyId /* = QString() */) const
    2943 {
    2944     QList<CGuestOSType> list;
    2945     if (m_guestOSFamilyIDs.contains(strFamilyId))
    2946     {
    2947         list = m_guestOSTypes.at(m_guestOSFamilyIDs.indexOf(strFamilyId));
    2948     }
    2949     else
    2950     {
    2951         for (int i = 0; i < m_guestOSFamilyIDs.size(); ++i)
    2952             list += m_guestOSTypes.at(i);
    2953     }
    2954     for (int j = 0; j < list.size(); ++j)
    2955         if (!list.at(j).GetId().compare(strTypeId))
    2956             return list.at(j);
    2957     return CGuestOSType();
    2958 }
    2959 
    2960 QString UICommon::vmGuestOSTypeDescription(const QString &strTypeId) const
    2961 {
    2962     for (int i = 0; i < m_guestOSFamilyIDs.size(); ++i)
    2963     {
    2964         QList<CGuestOSType> list(m_guestOSTypes[i]);
    2965         for (int j = 0; j < list.size(); ++j)
    2966             if (!list.at(j).GetId().compare(strTypeId))
    2967                 return list.at(j).GetDescription();
    2968     }
    2969     return QString();
    2970 }
    2971 
    2972 /* static */
    2973 bool UICommon::isDOSType(const QString &strOSTypeId)
    2974 {
    2975     if (   strOSTypeId.left(3) == "dos"
    2976         || strOSTypeId.left(3) == "win"
    2977         || strOSTypeId.left(3) == "os2")
    2978         return true;
    2979 
    2980     return false;
    2981 }
    2982 
    2983 /* static */
    2984 bool UICommon::switchToMachine(CMachine &comMachine)
    2985 {
    2986 #ifdef VBOX_WS_MAC
    2987     const ULONG64 id = comMachine.ShowConsoleWindow();
    2988 #else
    2989     const WId id = (WId)comMachine.ShowConsoleWindow();
    2990 #endif
    2991     AssertWrapperOk(comMachine);
    2992     if (!comMachine.isOk())
    2993         return false;
    2994 
    2995     // WORKAROUND:
    2996     // id == 0 means the console window has already done everything
    2997     // necessary to implement the "show window" semantics.
    2998     if (id == 0)
    2999         return true;
    3000 
    3001 #if defined(VBOX_WS_WIN) || defined(VBOX_WS_X11)
    3002 
    3003     return activateWindow(id, true);
    3004 
    3005 #elif defined(VBOX_WS_MAC)
    3006 
    3007     // WORKAROUND:
    3008     // This is just for the case were the other process cannot steal
    3009     // the focus from us. It will send us a PSN so we can try.
    3010     ProcessSerialNumber psn;
    3011     psn.highLongOfPSN = id >> 32;
    3012     psn.lowLongOfPSN = (UInt32)id;
    3013 # ifdef __clang__
    3014 #  pragma GCC diagnostic push
    3015 #  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    3016     OSErr rc = ::SetFrontProcess(&psn);
    3017 #  pragma GCC diagnostic pop
    3018 # else
    3019     OSErr rc = ::SetFrontProcess(&psn);
    3020 # endif
    3021     if (!rc)
    3022         Log(("GUI: %#RX64 couldn't do SetFrontProcess on itself, the selector (we) had to do it...\n", id));
    3023     else
    3024         Log(("GUI: Failed to bring %#RX64 to front. rc=%#x\n", id, rc));
    3025     return !rc;
    3026 
    3027 #else
    3028 
    3029     return false;
    3030 
    3031 #endif
    3032 }
    3033 
    3034 bool UICommon::launchMachine(CMachine &comMachine, LaunchMode enmLaunchMode /* = LaunchMode_Default */)
    3035 {
    3036     /* Switch to machine window(s) if possible: */
    3037     if (   comMachine.GetSessionState() == KSessionState_Locked /* precondition for CanShowConsoleWindow() */
    3038         && comMachine.CanShowConsoleWindow())
    3039     {
    3040         switch (uiType())
    3041         {
    3042             /* For Selector UI: */
    3043             case UIType_SelectorUI:
    3044             {
    3045                 /* Just switch to existing VM window: */
    3046                 return switchToMachine(comMachine);
    3047             }
    3048             /* For Runtime UI: */
    3049             case UIType_RuntimeUI:
    3050             {
    3051                 /* Only separate UI process can reach that place.
    3052                  * Switch to existing VM window and exit. */
    3053                 switchToMachine(comMachine);
    3054                 return false;
    3055             }
    3056         }
    3057     }
    3058 
    3059     /* Not for separate UI (which can connect to machine in any state): */
    3060     if (enmLaunchMode != LaunchMode_Separate)
    3061     {
    3062         /* Make sure machine-state is one of required: */
    3063         const KMachineState enmState = comMachine.GetState(); NOREF(enmState);
    3064         AssertMsg(   enmState == KMachineState_PoweredOff
    3065                   || enmState == KMachineState_Saved
    3066                   || enmState == KMachineState_Teleported
    3067                   || enmState == KMachineState_Aborted
    3068                   , ("Machine must be PoweredOff/Saved/Teleported/Aborted (%d)", enmState));
    3069     }
    3070 
    3071     /* Create empty session instance: */
    3072     CSession comSession;
    3073     comSession.createInstance(CLSID_Session);
    3074     if (comSession.isNull())
    3075     {
    3076         msgCenter().cannotOpenSession(comSession);
    3077         return false;
    3078     }
    3079 
    3080     /* Configure environment: */
    3081     QVector<QString> astrEnv;
    3082 #ifdef VBOX_WS_WIN
    3083     /* Allow started VM process to be foreground window: */
    3084     AllowSetForegroundWindow(ASFW_ANY);
    3085 #endif
    3086 #ifdef VBOX_WS_X11
    3087     /* Make sure VM process will start on the same
    3088      * display as window this wrapper is called from: */
    3089     const char *pDisplay = RTEnvGet("DISPLAY");
    3090     if (pDisplay)
    3091         astrEnv.append(QString("DISPLAY=%1").arg(pDisplay));
    3092     const char *pXauth = RTEnvGet("XAUTHORITY");
    3093     if (pXauth)
    3094         astrEnv.append(QString("XAUTHORITY=%1").arg(pXauth));
    3095 #endif
    3096     QString strType;
    3097     switch (enmLaunchMode)
    3098     {
    3099         case LaunchMode_Default:  strType = ""; break;
    3100         case LaunchMode_Separate: strType = isSeparateProcess() ? "headless" : "separate"; break;
    3101         case LaunchMode_Headless: strType = "headless"; break;
    3102         default: AssertFailedReturn(false);
    3103     }
    3104 
    3105     /* Prepare "VM spawning" progress: */
    3106     CProgress comProgress = comMachine.LaunchVMProcess(comSession, strType, astrEnv);
    3107     if (!comMachine.isOk())
    3108     {
    3109         /* If the VM is started separately and the VM process is already running, then it is OK. */
    3110         if (enmLaunchMode == LaunchMode_Separate)
    3111         {
    3112             const KMachineState enmState = comMachine.GetState();
    3113             if (   enmState >= KMachineState_FirstOnline
    3114                 && enmState <= KMachineState_LastOnline)
    3115             {
    3116                 /* Already running: */
    3117                 return true;
    3118             }
    3119         }
    3120 
    3121         msgCenter().cannotOpenSession(comMachine);
    3122         return false;
    3123     }
    3124 
    3125     /* Show "VM spawning" progress: */
    3126     msgCenter().showModalProgressDialog(comProgress, comMachine.GetName(),
    3127                                         ":/progress_start_90px.png", 0, 0);
    3128     if (!comProgress.isOk() || comProgress.GetResultCode() != 0)
    3129         msgCenter().cannotOpenSession(comProgress, comMachine.GetName());
    3130 
    3131     /* Unlock machine, close session: */
    3132     comSession.UnlockMachine();
    3133 
    3134     /* True finally: */
    3135     return true;
    3136 }
    3137 
    3138 CSession UICommon::openSession(const QUuid &uId, KLockType lockType /* = KLockType_Shared */)
    3139 {
    3140     /* Prepare session: */
    3141     CSession comSession;
    3142 
    3143     /* Simulate try-catch block: */
    3144     bool fSuccess = false;
    3145     do
    3146     {
    3147         /* Create empty session instance: */
    3148         comSession.createInstance(CLSID_Session);
    3149         if (comSession.isNull())
    3150         {
    3151             msgCenter().cannotOpenSession(comSession);
    3152             break;
    3153         }
    3154 
    3155         /* Search for the corresponding machine: */
    3156         CMachine comMachine = m_comVBox.FindMachine(uId.toString());
    3157         if (comMachine.isNull())
    3158         {
    3159             msgCenter().cannotFindMachineById(m_comVBox, uId);
    3160             break;
    3161         }
    3162 
    3163         if (lockType == KLockType_VM)
    3164             comSession.SetName("GUI/Qt");
    3165 
    3166         /* Lock found machine to session: */
    3167         comMachine.LockMachine(comSession, lockType);
    3168         if (!comMachine.isOk())
    3169         {
    3170             msgCenter().cannotOpenSession(comMachine);
    3171             break;
    3172         }
    3173 
    3174         /* Pass the language ID as the property to the guest: */
    3175         if (comSession.GetType() == KSessionType_Shared)
    3176         {
    3177             CMachine comStartedMachine = comSession.GetMachine();
    3178             /* Make sure that the language is in two letter code.
    3179              * Note: if languageId() returns an empty string lang.name() will
    3180              * return "C" which is an valid language code. */
    3181             QLocale lang(UICommon::languageId());
    3182             comStartedMachine.SetGuestPropertyValue("/VirtualBox/HostInfo/GUI/LanguageID", lang.name());
    3183         }
    3184 
    3185         /* Success finally: */
    3186         fSuccess = true;
    3187     }
    3188     while (0);
    3189     /* Cleanup try-catch block: */
    3190     if (!fSuccess)
    3191         comSession.detach();
    3192 
    3193     /* Return session: */
    3194     return comSession;
    3195 }
    3196 
    3197 CSession UICommon::tryToOpenSessionFor(CMachine &comMachine)
    3198 {
    3199     /* Prepare session: */
    3200     CSession comSession;
    3201 
    3202     /* Session state unlocked? */
    3203     if (comMachine.GetSessionState() == KSessionState_Unlocked)
    3204     {
    3205         /* Open own 'write' session: */
    3206         comSession = openSession(comMachine.GetId());
    3207         AssertReturn(!comSession.isNull(), CSession());
    3208         comMachine = comSession.GetMachine();
    3209     }
    3210     /* Is this a Selector UI call? */
    3211     else if (uiType() == UIType_SelectorUI)
    3212     {
    3213         /* Open existing 'shared' session: */
    3214         comSession = openExistingSession(comMachine.GetId());
    3215         AssertReturn(!comSession.isNull(), CSession());
    3216         comMachine = comSession.GetMachine();
    3217     }
    3218     /* Else this is Runtime UI call
    3219      * which has session locked for itself. */
    3220 
    3221     /* Return session: */
    3222     return comSession;
    3223 }
    3224 
    3225 void UICommon::notifyCloudMachineUnregistered(const QString &strProviderShortName,
    3226                                               const QString &strProfileName,
    3227                                               const QUuid &uId)
    3228 {
    3229     emit sigCloudMachineUnregistered(strProviderShortName, strProfileName, uId);
    3230 }
    3231 
    3232 void UICommon::notifyCloudMachineRegistered(const QString &strProviderShortName,
    3233                                             const QString &strProfileName,
    3234                                             const CCloudMachine &comMachine)
    3235 {
    3236     emit sigCloudMachineRegistered(strProviderShortName, strProfileName, comMachine);
    3237 }
    3238 
    3239 void UICommon::enumerateMedia(const CMediumVector &comMedia /* = CMediumVector() */)
    3240 {
    3241     /* Make sure UICommon is already valid: */
    3242     AssertReturnVoid(m_fValid);
    3243     /* Ignore the request during UICommon cleanup: */
    3244     if (m_fCleaningUp)
    3245         return;
    3246     /* Ignore the request during startup snapshot restoring: */
    3247     if (shouldRestoreCurrentSnapshot())
    3248         return;
    3249 
    3250     /* Make sure medium-enumerator is already created: */
    3251     if (!m_pMediumEnumerator)
    3252         return;
    3253 
    3254     /* Redirect request to medium-enumerator under proper lock: */
    3255     if (m_meCleanupProtectionToken.tryLockForRead())
    3256     {
    3257         if (m_pMediumEnumerator)
    3258             m_pMediumEnumerator->enumerateMedia(comMedia);
    3259         m_meCleanupProtectionToken.unlock();
    3260     }
    3261 }
    3262 
    3263 void UICommon::refreshMedia()
    3264 {
    3265     /* Make sure UICommon is already valid: */
    3266     AssertReturnVoid(m_fValid);
    3267     /* Ignore the request during UICommon cleanup: */
    3268     if (m_fCleaningUp)
    3269         return;
    3270     /* Ignore the request during startup snapshot restoring: */
    3271     if (shouldRestoreCurrentSnapshot())
    3272         return;
    3273 
    3274     /* Make sure medium-enumerator is already created: */
    3275     if (!m_pMediumEnumerator)
    3276         return;
    3277     /* Make sure enumeration is not already started: */
    3278     if (m_pMediumEnumerator->isMediumEnumerationInProgress())
    3279         return;
    3280 
    3281     /* We assume it's safe to call it without locking,
    3282      * since we are performing blocking operation here. */
    3283     m_pMediumEnumerator->refreshMedia();
    3284 }
    3285 
    3286 bool UICommon::isFullMediumEnumerationRequested() const
    3287 {
    3288     /* Redirect request to medium-enumerator: */
    3289     return    m_pMediumEnumerator
    3290            && m_pMediumEnumerator->isFullMediumEnumerationRequested();
    3291 }
    3292 
    3293 bool UICommon::isMediumEnumerationInProgress() const
    3294 {
    3295     /* Redirect request to medium-enumerator: */
    3296     return    m_pMediumEnumerator
    3297            && m_pMediumEnumerator->isMediumEnumerationInProgress();
    3298 }
    3299 
    3300 UIMedium UICommon::medium(const QUuid &uMediumID) const
    3301 {
    3302     if (m_meCleanupProtectionToken.tryLockForRead())
    3303     {
    3304         /* Redirect call to medium-enumerator: */
    3305         UIMedium guiMedium;
    3306         if (m_pMediumEnumerator)
    3307             guiMedium = m_pMediumEnumerator->medium(uMediumID);
    3308         m_meCleanupProtectionToken.unlock();
    3309         return guiMedium;
    3310     }
    3311     return UIMedium();
    3312 }
    3313 
    3314 QList<QUuid> UICommon::mediumIDs() const
    3315 {
    3316     if (m_meCleanupProtectionToken.tryLockForRead())
    3317     {
    3318         /* Redirect call to medium-enumerator: */
    3319         QList<QUuid> listOfMedia;
    3320         if (m_pMediumEnumerator)
    3321             listOfMedia = m_pMediumEnumerator->mediumIDs();
    3322         m_meCleanupProtectionToken.unlock();
    3323         return listOfMedia;
    3324     }
    3325     return QList<QUuid>();
    3326 }
    3327 
    3328 void UICommon::createMedium(const UIMedium &guiMedium)
    3329 {
    3330     if (m_meCleanupProtectionToken.tryLockForRead())
    3331     {
    3332         /* Create medium in medium-enumerator: */
    3333         if (m_pMediumEnumerator)
    3334             m_pMediumEnumerator->createMedium(guiMedium);
    3335         m_meCleanupProtectionToken.unlock();
    3336     }
    3337 }
    3338 
    3339 QUuid UICommon::openMedium(UIMediumDeviceType enmMediumType, QString strMediumLocation, QWidget *pParent /* = 0 */)
    3340 {
    3341     /* Convert to native separators: */
    3342     strMediumLocation = QDir::toNativeSeparators(strMediumLocation);
    3343 
    3344     /* Initialize variables: */
    3345     CVirtualBox comVBox = virtualBox();
    3346 
    3347     /* Open corresponding medium: */
    3348     CMedium comMedium = comVBox.OpenMedium(strMediumLocation, mediumTypeToGlobal(enmMediumType), KAccessMode_ReadWrite, false);
    3349 
    3350     if (comVBox.isOk())
    3351     {
    3352         /* Prepare vbox medium wrapper: */
    3353         UIMedium guiMedium = medium(comMedium.GetId());
    3354 
    3355         /* First of all we should test if that medium already opened: */
    3356         if (guiMedium.isNull())
    3357         {
    3358             /* And create new otherwise: */
    3359             guiMedium = UIMedium(comMedium, enmMediumType, KMediumState_Created);
    3360             createMedium(guiMedium);
    3361         }
    3362 
    3363         /* Return guiMedium id: */
    3364         return guiMedium.id();
    3365     }
    3366     else
    3367         msgCenter().cannotOpenMedium(comVBox, strMediumLocation, pParent);
    3368 
    3369     return QUuid();
    3370 }
    3371 
    3372 QUuid UICommon::openMediumWithFileOpenDialog(UIMediumDeviceType enmMediumType, QWidget *pParent,
    3373                                                const QString &strDefaultFolder /* = QString() */,
    3374                                                bool fUseLastFolder /* = false */)
    3375 {
    3376     /* Initialize variables: */
    3377     QList<QPair <QString, QString> > filters;
    3378     QStringList backends;
    3379     QStringList prefixes;
    3380     QString strFilter;
    3381     QString strTitle;
    3382     QString allType;
    3383     QString strLastFolder = defaultFolderPathForType(enmMediumType);
    3384 
    3385     /* For DVDs and Floppies always check first the last recently used medium folder. For hard disk use
    3386        the caller's setting: */
    3387     fUseLastFolder = (enmMediumType == UIMediumDeviceType_DVD) || (enmMediumType == UIMediumDeviceType_Floppy);
    3388 
    3389     switch (enmMediumType)
    3390     {
    3391         case UIMediumDeviceType_HardDisk:
    3392         {
    3393             filters = HDDBackends(virtualBox());
    3394             strTitle = tr("Please choose a virtual hard disk file");
    3395             allType = tr("All virtual hard disk files (%1)");
    3396             break;
    3397         }
    3398         case UIMediumDeviceType_DVD:
    3399         {
    3400             filters = DVDBackends(virtualBox());
    3401             strTitle = tr("Please choose a virtual optical disk file");
    3402             allType = tr("All virtual optical disk files (%1)");
    3403             break;
    3404         }
    3405         case UIMediumDeviceType_Floppy:
    3406         {
    3407             filters = FloppyBackends(virtualBox());
    3408             strTitle = tr("Please choose a virtual floppy disk file");
    3409             allType = tr("All virtual floppy disk files (%1)");
    3410             break;
    3411         }
    3412         default:
    3413             break;
    3414     }
    3415     QString strHomeFolder = fUseLastFolder && !strLastFolder.isEmpty() ? strLastFolder :
    3416                             strDefaultFolder.isEmpty() ? homeFolder() : strDefaultFolder;
    3417 
    3418     /* Prepare filters and backends: */
    3419     for (int i = 0; i < filters.count(); ++i)
    3420     {
    3421         /* Get iterated filter: */
    3422         QPair<QString, QString> item = filters.at(i);
    3423         /* Create one backend filter string: */
    3424         backends << QString("%1 (%2)").arg(item.first).arg(item.second);
    3425         /* Save the suffix's for the "All" entry: */
    3426         prefixes << item.second;
    3427     }
    3428     if (!prefixes.isEmpty())
    3429         backends.insert(0, allType.arg(prefixes.join(" ").trimmed()));
    3430     backends << tr("All files (*)");
    3431     strFilter = backends.join(";;").trimmed();
    3432 
    3433     /* Create open file dialog: */
    3434     QStringList files = QIFileDialog::getOpenFileNames(strHomeFolder, strFilter, pParent, strTitle, 0, true, true);
    3435 
    3436     /* If dialog has some result: */
    3437     if (!files.empty() && !files[0].isEmpty())
    3438     {
    3439         QUuid uMediumId = openMedium(enmMediumType, files[0], pParent);
    3440         if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy ||
    3441             (enmMediumType == UIMediumDeviceType_HardDisk && fUseLastFolder))
    3442             updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(uMediumId).location());
    3443         return uMediumId;
    3444     }
    3445     return QUuid();
    3446 }
    3447 
    3448 
    3449 /**
    3450  * Helper for createVisoMediumWithVisoCreator.
    3451  * @returns IPRT status code.
    3452  * @param   pStrmDst            Where to write the quoted string.
    3453  * @param   pszPrefix           Stuff to put in front of it.
    3454  * @param   rStr                The string to quote and write out.
    3455  * @param   pszPrefix           Stuff to put after it.
    3456  */
    3457 DECLINLINE(int) visoWriteQuotedString(PRTSTREAM pStrmDst, const char *pszPrefix, QString const &rStr, const char *pszPostFix)
    3458 {
    3459     QByteArray const utf8Array   = rStr.toUtf8();
    3460     const char      *apszArgv[2] = { utf8Array.constData(), NULL };
    3461     char            *pszQuoted;
    3462     int vrc = RTGetOptArgvToString(&pszQuoted, apszArgv, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
    3463     if (RT_SUCCESS(vrc))
    3464     {
    3465         if (pszPrefix)
    3466             vrc = RTStrmPutStr(pStrmDst, pszPrefix);
    3467         if (RT_SUCCESS(vrc))
    3468         {
    3469             vrc = RTStrmPutStr(pStrmDst, pszQuoted);
    3470             if (pszPostFix && RT_SUCCESS(vrc))
    3471                 vrc = RTStrmPutStr(pStrmDst, pszPostFix);
    3472         }
    3473         RTStrFree(pszQuoted);
    3474     }
    3475 
    3476     return vrc;
    3477 }
    3478 
    3479 
    3480 void UICommon::openMediumCreatorDialog(QWidget *pParent, UIMediumDeviceType enmMediumType,
    3481                                        const QString &strDefaultFolder /* = QString() */,
    3482                                        const QString &strMachineName /* = QString() */,
    3483                                        const QString &strMachineGuestOSTypeId /*= QString() */)
    3484 {
    3485     /* Depending on medium-type: */
    3486     QUuid uMediumId;
    3487     switch (enmMediumType)
    3488     {
    3489         case UIMediumDeviceType_HardDisk:
    3490             createVDWithWizard(pParent, strDefaultFolder, strMachineName, strMachineGuestOSTypeId);
    3491             break;
    3492         case UIMediumDeviceType_DVD:
    3493             uMediumId = createVisoMediumWithVisoCreator(pParent, strDefaultFolder, strMachineName);
    3494             break;
    3495         case UIMediumDeviceType_Floppy:
    3496             uMediumId = showCreateFloppyDiskDialog(pParent, strDefaultFolder, strMachineName);
    3497             break;
    3498         default:
    3499             break;
    3500     }
    3501     if (uMediumId.isNull())
    3502         return;
    3503 
    3504     /* Update the recent medium list only if the medium type is DVD or floppy: */
    3505     if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy)
    3506         updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(uMediumId).location());
    3507 }
    3508 
    3509 QUuid UICommon::createVisoMediumWithVisoCreator(QWidget *pParent, const QString &strDefaultFolder /* = QString */,
    3510                                                   const QString &strMachineName /* = QString */)
    3511 {
    3512     QString strVisoSaveFolder(strDefaultFolder);
    3513     if (strVisoSaveFolder.isEmpty())
    3514         strVisoSaveFolder = defaultFolderPathForType(UIMediumDeviceType_DVD);
    3515 
    3516     QWidget *pDialogParent = windowManager().realParentWindow(pParent);
    3517     UIVisoCreator *pVisoCreator = new UIVisoCreator(pDialogParent, strMachineName);
    3518 
    3519     if (!pVisoCreator)
    3520         return QString();
    3521     windowManager().registerNewParent(pVisoCreator, pDialogParent);
    3522     pVisoCreator->setCurrentPath(gEDataManager->visoCreatorRecentFolder());
    3523 
    3524     if (pVisoCreator->exec(false /* not application modal */))
    3525     {
    3526         QStringList files = pVisoCreator->entryList();
    3527         QString strVisoName = pVisoCreator->visoName();
    3528         if (strVisoName.isEmpty())
    3529             strVisoName = strMachineName;
    3530 
    3531         if (files.empty() || files[0].isEmpty())
    3532         {
    3533             delete pVisoCreator;
    3534             return QUuid();
    3535         }
    3536 
    3537         gEDataManager->setVISOCreatorRecentFolder(pVisoCreator->currentPath());
    3538 
    3539         /* Produce the VISO. */
    3540         char szVisoPath[RTPATH_MAX];
    3541         QString strFileName = QString("%1%2").arg(strVisoName).arg(".viso");
    3542         int vrc = RTPathJoin(szVisoPath, sizeof(szVisoPath), strVisoSaveFolder.toUtf8().constData(), strFileName.toUtf8().constData());
    3543         if (RT_SUCCESS(vrc))
    3544         {
    3545             PRTSTREAM pStrmViso;
    3546             vrc = RTStrmOpen(szVisoPath, "w", &pStrmViso);
    3547             if (RT_SUCCESS(vrc))
    3548             {
    3549                 RTUUID Uuid;
    3550                 vrc = RTUuidCreate(&Uuid);
    3551                 if (RT_SUCCESS(vrc))
    3552                 {
    3553                     RTStrmPrintf(pStrmViso, "--iprt-iso-maker-file-marker-bourne-sh %RTuuid\n", &Uuid);
    3554                     vrc = visoWriteQuotedString(pStrmViso, "--volume-id=", strVisoName, "\n");
    3555 
    3556                     for (int iFile = 0; iFile < files.size() && RT_SUCCESS(vrc); iFile++)
    3557                         vrc = visoWriteQuotedString(pStrmViso, NULL, files[iFile], "\n");
    3558 
    3559                     /* Append custom options if any to the file: */
    3560                     const QStringList &customOptions = pVisoCreator->customOptions();
    3561                     foreach (QString strLine, customOptions)
    3562                         RTStrmPrintf(pStrmViso, "%s\n", strLine.toUtf8().constData());
    3563 
    3564                     RTStrmFlush(pStrmViso);
    3565                     if (RT_SUCCESS(vrc))
    3566                         vrc = RTStrmError(pStrmViso);
    3567                 }
    3568 
    3569                 RTStrmClose(pStrmViso);
    3570             }
    3571         }
    3572 
    3573         /* Done. */
    3574         if (RT_SUCCESS(vrc))
    3575         {
    3576             delete pVisoCreator;
    3577             return openMedium(UIMediumDeviceType_DVD, QString(szVisoPath), pParent);
    3578         }
    3579         /** @todo error message. */
    3580         else
    3581         {
    3582             delete pVisoCreator;
    3583             return QUuid();
    3584         }
    3585     }
    3586     delete pVisoCreator;
    3587     return QUuid();
    3588 }
    3589 
    3590 QUuid UICommon::showCreateFloppyDiskDialog(QWidget *pParent, const QString &strDefaultFolder /* QString() */,
    3591                                              const QString &strMachineName /* = QString() */ )
    3592 {
    3593     QString strStartPath(strDefaultFolder);
    3594 
    3595     if (strStartPath.isEmpty())
    3596         strStartPath = defaultFolderPathForType(UIMediumDeviceType_Floppy);
    3597 
    3598     QWidget *pDialogParent = windowManager().realParentWindow(pParent);
    3599 
    3600     UIFDCreationDialog *pDialog = new UIFDCreationDialog(pParent, strStartPath, strMachineName);
    3601     if (!pDialog)
    3602         return QUuid();
    3603     windowManager().registerNewParent(pDialog, pDialogParent);
    3604 
    3605     if (pDialog->exec())
    3606     {
    3607         QUuid uMediumID = pDialog->mediumID();
    3608         delete pDialog;
    3609         return uMediumID;
    3610     }
    3611     delete pDialog;
    3612     return QUuid();
    3613 }
    3614 
    3615 int UICommon::openMediumSelectorDialog(QWidget *pParent, UIMediumDeviceType  enmMediumType, QUuid &outUuid,
    3616                                        const QString &strMachineFolder, const QString &strMachineName,
    3617                                        const QString &strMachineGuestOSTypeId, bool fEnableCreate, const QUuid &uMachineID /* = QUuid() */)
    3618 {
    3619     QUuid uMachineOrGlobalId = uMachineID == QUuid() ? gEDataManager->GlobalID : uMachineID;
    3620 
    3621     QWidget *pDialogParent = windowManager().realParentWindow(pParent);
    3622     QPointer<UIMediumSelector> pSelector = new UIMediumSelector(enmMediumType, strMachineName,
    3623                                                                 strMachineFolder, strMachineGuestOSTypeId,
    3624                                                                 uMachineOrGlobalId, pDialogParent);
    3625 
    3626     if (!pSelector)
    3627         return static_cast<int>(UIMediumSelector::ReturnCode_Rejected);
    3628     pSelector->setEnableCreateAction(fEnableCreate);
    3629     windowManager().registerNewParent(pSelector, pDialogParent);
    3630 
    3631     int iResult = pSelector->exec(false);
    3632     UIMediumSelector::ReturnCode returnCode;
    3633 
    3634     if (iResult >= static_cast<int>(UIMediumSelector::ReturnCode_Max) || iResult < 0)
    3635         returnCode = UIMediumSelector::ReturnCode_Rejected;
    3636     else
    3637         returnCode = static_cast<UIMediumSelector::ReturnCode>(iResult);
    3638 
    3639     if (returnCode == UIMediumSelector::ReturnCode_Accepted)
    3640     {
    3641         QList<QUuid> selectedMediumIds = pSelector->selectedMediumIds();
    3642 
    3643         /* Currently we only care about the 0th since we support single selection by intention: */
    3644         if (selectedMediumIds.isEmpty())
    3645             returnCode = UIMediumSelector::ReturnCode_Rejected;
    3646         else
    3647         {
    3648             outUuid = selectedMediumIds[0];
    3649             updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(outUuid).location());
    3650         }
    3651     }
    3652     delete pSelector;
    3653     return static_cast<int>(returnCode);
    3654 }
    3655 
    3656 void UICommon::createVDWithWizard(QWidget *pParent,
    3657                                   const QString &strMachineFolder /* = QString() */,
    3658                                   const QString &strMachineName /* = QString() */,
    3659                                   const QString &strMachineGuestOSTypeId  /* = QString() */)
    3660 {
    3661     /* Initialize variables: */
    3662     QString strDefaultFolder = strMachineFolder;
    3663     if (strDefaultFolder.isEmpty())
    3664         strDefaultFolder = defaultFolderPathForType(UIMediumDeviceType_HardDisk);
    3665 
    3666     /* In case we dont have a 'guest os type id' default back to 'Other': */
    3667     const CGuestOSType comGuestOSType = virtualBox().GetGuestOSType(  !strMachineGuestOSTypeId.isEmpty()
    3668                                                                     ? strMachineGuestOSTypeId
    3669                                                                     : "Other");
    3670     const QString strDiskName = findUniqueFileName(strDefaultFolder,   !strMachineName.isEmpty()
    3671                                                                      ? strMachineName
    3672                                                                      : "NewVirtualDisk");
    3673 
    3674     /* Show New VD wizard: */
    3675     UISafePointerWizardNewVD pWizard = new UIWizardNewVD(pParent,
    3676                                                          strDiskName,
    3677                                                          strDefaultFolder,
    3678                                                          comGuestOSType.GetRecommendedHDD());
    3679     if (!pWizard)
    3680         return;
    3681     QWidget *pDialogParent = windowManager().realParentWindow(pParent);
    3682     windowManager().registerNewParent(pWizard, pDialogParent);
    3683     pWizard->exec();
    3684     delete pWizard;
    3685 }
    3686 
    3687 void UICommon::prepareStorageMenu(QMenu &menu,
    3688                                     QObject *pListener, const char *pszSlotName,
    3689                                     const CMachine &comMachine, const QString &strControllerName, const StorageSlot &storageSlot)
    3690 {
    3691     /* Current attachment attributes: */
    3692     const CMediumAttachment comCurrentAttachment = comMachine.GetMediumAttachment(strControllerName,
    3693                                                                                   storageSlot.port,
    3694                                                                                   storageSlot.device);
    3695     const CMedium comCurrentMedium = comCurrentAttachment.GetMedium();
    3696     const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId();
    3697     const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation();
    3698 
    3699     /* Other medium-attachments of same machine: */
    3700     const CMediumAttachmentVector comAttachments = comMachine.GetMediumAttachments();
    3701 
    3702     /* Determine device & medium types: */
    3703     const UIMediumDeviceType enmMediumType = mediumTypeToLocal(comCurrentAttachment.GetType());
    3704     AssertMsgReturnVoid(enmMediumType != UIMediumDeviceType_Invalid, ("Incorrect storage medium type!\n"));
    3705 
    3706     /* Prepare open-existing-medium action: */
    3707     QAction *pActionOpenExistingMedium = menu.addAction(UIIconPool::iconSet(":/select_file_16px.png"),
    3708                                                         QString(), pListener, pszSlotName);
    3709     pActionOpenExistingMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(),
    3710                                                                           comCurrentAttachment.GetDevice(), enmMediumType)));
    3711     pActionOpenExistingMedium->setText(QApplication::translate("UIMachineSettingsStorage", "Choose/Create a disk image..."));
    3712 
    3713 
    3714     /* Prepare open medium file action: */
    3715     QAction *pActionFileSelector = menu.addAction(UIIconPool::iconSet(":/select_file_16px.png"),
    3716                                                   QString(), pListener, pszSlotName);
    3717     pActionFileSelector->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(),
    3718                                                                     comCurrentAttachment.GetDevice(), enmMediumType,
    3719                                                                     UIMediumTarget::UIMediumTargetType_WithFileDialog)));
    3720     pActionFileSelector->setText(QApplication::translate("UIMachineSettingsStorage", "Choose a disk file..."));
    3721 
    3722 
    3723     /* Insert separator: */
    3724     menu.addSeparator();
    3725 
    3726     /* Get existing-host-drive vector: */
    3727     CMediumVector comMedia;
    3728     switch (enmMediumType)
    3729     {
    3730         case UIMediumDeviceType_DVD:    comMedia = host().GetDVDDrives(); break;
    3731         case UIMediumDeviceType_Floppy: comMedia = host().GetFloppyDrives(); break;
    3732         default: break;
    3733     }
    3734     /* Prepare choose-existing-host-drive actions: */
    3735     foreach (const CMedium &comMedium, comMedia)
    3736     {
    3737         /* Make sure host-drive usage is unique: */
    3738         bool fIsHostDriveUsed = false;
    3739         foreach (const CMediumAttachment &comOtherAttachment, comAttachments)
    3740         {
    3741             if (comOtherAttachment != comCurrentAttachment)
    3742             {
    3743                 const CMedium &comOtherMedium = comOtherAttachment.GetMedium();
    3744                 if (!comOtherMedium.isNull() && comOtherMedium.GetId() == comMedium.GetId())
    3745                 {
    3746                     fIsHostDriveUsed = true;
    3747                     break;
    3748                 }
    3749             }
    3750         }
    3751         /* If host-drives usage is unique: */
    3752         if (!fIsHostDriveUsed)
    3753         {
    3754             QAction *pActionChooseHostDrive = menu.addAction(UIMedium(comMedium, enmMediumType).name(), pListener, pszSlotName);
    3755             pActionChooseHostDrive->setCheckable(true);
    3756             pActionChooseHostDrive->setChecked(!comCurrentMedium.isNull() && comMedium.GetId() == uCurrentID);
    3757             pActionChooseHostDrive->setData(QVariant::fromValue(UIMediumTarget(strControllerName,
    3758                                                                                comCurrentAttachment.GetPort(),
    3759                                                                                comCurrentAttachment.GetDevice(),
    3760                                                                                enmMediumType,
    3761                                                                                UIMediumTarget::UIMediumTargetType_WithID,
    3762                                                                                comMedium.GetId().toString())));
    3763         }
    3764     }
    3765 
    3766     /* Get recent-medium list: */
    3767     QStringList recentMediumList;
    3768     QStringList recentMediumListUsed;
    3769     switch (enmMediumType)
    3770     {
    3771         case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break;
    3772         case UIMediumDeviceType_DVD:      recentMediumList = gEDataManager->recentListOfOpticalDisks(); break;
    3773         case UIMediumDeviceType_Floppy:   recentMediumList = gEDataManager->recentListOfFloppyDisks(); break;
    3774         default: break;
    3775     }
    3776     /* Prepare choose-recent-medium actions: */
    3777     foreach (const QString &strRecentMediumLocationBase, recentMediumList)
    3778     {
    3779         /* Confirm medium uniqueness: */
    3780         if (recentMediumListUsed.contains(strRecentMediumLocationBase))
    3781             continue;
    3782         /* Mark medium as known: */
    3783         recentMediumListUsed << strRecentMediumLocationBase;
    3784         /* Convert separators to native: */
    3785         const QString strRecentMediumLocation = QDir::toNativeSeparators(strRecentMediumLocationBase);
    3786         /* Confirm medium presence: */
    3787         if (!QFile::exists(strRecentMediumLocation))
    3788             continue;
    3789         /* Make sure recent-medium usage is unique: */
    3790         bool fIsRecentMediumUsed = false;
    3791         if (enmMediumType != UIMediumDeviceType_DVD)
    3792             foreach (const CMediumAttachment &otherAttachment, comAttachments)
    3793             {
    3794                 if (otherAttachment != comCurrentAttachment)
    3795                 {
    3796                     const CMedium &comOtherMedium = otherAttachment.GetMedium();
    3797                     if (!comOtherMedium.isNull() && comOtherMedium.GetLocation() == strRecentMediumLocation)
    3798                     {
    3799                         fIsRecentMediumUsed = true;
    3800                         break;
    3801                     }
    3802                 }
    3803             }
    3804         /* If recent-medium usage is unique: */
    3805         if (!fIsRecentMediumUsed)
    3806         {
    3807             QAction *pActionChooseRecentMedium = menu.addAction(QFileInfo(strRecentMediumLocation).fileName(),
    3808                                                                 pListener, pszSlotName);
    3809             pActionChooseRecentMedium->setCheckable(true);
    3810             pActionChooseRecentMedium->setChecked(!comCurrentMedium.isNull() && strRecentMediumLocation == strCurrentLocation);
    3811             pActionChooseRecentMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName,
    3812                                                                                   comCurrentAttachment.GetPort(),
    3813                                                                                   comCurrentAttachment.GetDevice(),
    3814                                                                                   enmMediumType,
    3815                                                                                   UIMediumTarget::UIMediumTargetType_WithLocation,
    3816                                                                                   strRecentMediumLocation)));
    3817             pActionChooseRecentMedium->setToolTip(strRecentMediumLocation);
    3818         }
    3819     }
    3820 
    3821     /* Last action for optical/floppy attachments only: */
    3822     if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy)
    3823     {
    3824         /* Insert separator: */
    3825         menu.addSeparator();
    3826 
    3827         /* Prepare unmount-current-medium action: */
    3828         QAction *pActionUnmountMedium = menu.addAction(QString(), pListener, pszSlotName);
    3829         pActionUnmountMedium->setEnabled(!comCurrentMedium.isNull());
    3830         pActionUnmountMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(),
    3831                                                                          comCurrentAttachment.GetDevice())));
    3832         pActionUnmountMedium->setText(QApplication::translate("UIMachineSettingsStorage", "Remove disk from virtual drive"));
    3833         if (enmMediumType == UIMediumDeviceType_DVD)
    3834             pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/cd_unmount_16px.png", ":/cd_unmount_disabled_16px.png"));
    3835         else if (enmMediumType == UIMediumDeviceType_Floppy)
    3836             pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/fd_unmount_16px.png", ":/fd_unmount_disabled_16px.png"));
    3837     }
    3838 }
    3839 
    3840 void UICommon::updateMachineStorage(const CMachine &comConstMachine, const UIMediumTarget &target)
    3841 {
    3842     /* Mount (by default): */
    3843     bool fMount = true;
    3844     /* Null medium (by default): */
    3845     CMedium comMedium;
    3846     /* With null ID (by default): */
    3847     QUuid uActualID;
    3848 
    3849     /* Current mount-target attributes: */
    3850     const CStorageController comCurrentController = comConstMachine.GetStorageControllerByName(target.name);
    3851     const KStorageBus enmCurrentStorageBus = comCurrentController.GetBus();
    3852     const CMediumAttachment comCurrentAttachment = comConstMachine.GetMediumAttachment(target.name, target.port, target.device);
    3853     const CMedium comCurrentMedium = comCurrentAttachment.GetMedium();
    3854     const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId();
    3855     const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation();
    3856 
    3857     /* Which additional info do we have? */
    3858     switch (target.type)
    3859     {
    3860         /* Do we have an exact ID or do we let the user open a medium? */
    3861         case UIMediumTarget::UIMediumTargetType_WithID:
    3862         case UIMediumTarget::UIMediumTargetType_WithFileDialog:
    3863         case UIMediumTarget::UIMediumTargetType_CreateAdHocVISO:
    3864         case UIMediumTarget::UIMediumTargetType_CreateFloppyDisk:
    3865         {
    3866             /* New mount-target attributes: */
    3867             QUuid uNewID;
    3868 
    3869             /* Invoke file-open dialog to choose medium ID: */
    3870             if (target.mediumType != UIMediumDeviceType_Invalid && target.data.isNull())
    3871             {
    3872                 /* Keyboard can be captured by machine-view.
    3873                  * So we should clear machine-view focus to let file-open dialog get it.
    3874                  * That way the keyboard will be released too.. */
    3875                 QWidget *pLastFocusedWidget = 0;
    3876                 if (QApplication::focusWidget())
    3877                 {
    3878                     pLastFocusedWidget = QApplication::focusWidget();
    3879                     pLastFocusedWidget->clearFocus();
    3880                 }
    3881                 /* Call for file-open dialog: */
    3882                 const QString strMachineFolder(QFileInfo(comConstMachine.GetSettingsFilePath()).absolutePath());
    3883                 QUuid uMediumID;
    3884                 if (target.type == UIMediumTarget::UIMediumTargetType_WithID)
    3885                 {
    3886                     int iDialogReturn = openMediumSelectorDialog(windowManager().mainWindowShown(), target.mediumType, uMediumID,
    3887                                                                  strMachineFolder, comConstMachine.GetName(),
    3888                                                                  comConstMachine.GetOSTypeId(), true /*fEnableCreate */, comConstMachine.GetId());
    3889                     if (iDialogReturn == UIMediumSelector::ReturnCode_LeftEmpty &&
    3890                         (target.mediumType == UIMediumDeviceType_DVD || target.mediumType == UIMediumDeviceType_Floppy))
    3891                         fMount = false;
    3892                 }
    3893                 else if (target.type == UIMediumTarget::UIMediumTargetType_WithFileDialog)
    3894                 {
    3895                     uMediumID = openMediumWithFileOpenDialog(target.mediumType, windowManager().mainWindowShown(),
    3896                                                              strMachineFolder, false /* fUseLastFolder */);
    3897                 }
    3898                 else if(target.type == UIMediumTarget::UIMediumTargetType_CreateAdHocVISO)
    3899                     uMediumID = createVisoMediumWithVisoCreator(windowManager().mainWindowShown(), strMachineFolder, comConstMachine.GetName());
    3900 
    3901                 else if(target.type == UIMediumTarget::UIMediumTargetType_CreateFloppyDisk)
    3902                     uMediumID = showCreateFloppyDiskDialog(windowManager().mainWindowShown(), strMachineFolder, comConstMachine.GetName());
    3903 
    3904                 /* Return focus back: */
    3905                 if (pLastFocusedWidget)
    3906                     pLastFocusedWidget->setFocus();
    3907                 /* Accept new medium ID: */
    3908                 if (!uMediumID.isNull())
    3909                     uNewID = uMediumID;
    3910                 else
    3911                     /* Else just exit in case left empty is not chosen in medium selector dialog: */
    3912                     if (fMount)
    3913                         return;
    3914             }
    3915             /* Use medium ID which was passed: */
    3916             else if (!target.data.isNull() && target.data != uCurrentID.toString())
    3917                 uNewID = target.data;
    3918 
    3919             /* Should we mount or unmount? */
    3920             fMount = !uNewID.isNull();
    3921 
    3922             /* Prepare target medium: */
    3923             const UIMedium guiMedium = medium(uNewID);
    3924             comMedium = guiMedium.medium();
    3925             uActualID = fMount ? uNewID : uCurrentID;
    3926             break;
    3927         }
    3928         /* Do we have a recent location? */
    3929         case UIMediumTarget::UIMediumTargetType_WithLocation:
    3930         {
    3931             /* Open medium by location and get new medium ID if any: */
    3932             const QUuid uNewID = openMedium(target.mediumType, target.data);
    3933             /* Else just exit: */
    3934             if (uNewID.isNull())
    3935                 return;
    3936 
    3937             /* Should we mount or unmount? */
    3938             fMount = uNewID != uCurrentID;
    3939 
    3940             /* Prepare target medium: */
    3941             const UIMedium guiMedium = fMount ? medium(uNewID) : UIMedium();
    3942             comMedium = fMount ? guiMedium.medium() : CMedium();
    3943             uActualID = fMount ? uNewID : uCurrentID;
    3944             break;
    3945         }
    3946     }
    3947 
    3948     /* Do not unmount hard-drives: */
    3949     if (target.mediumType == UIMediumDeviceType_HardDisk && !fMount)
    3950         return;
    3951 
    3952     /* Get editable machine & session: */
    3953     CMachine comMachine = comConstMachine;
    3954     CSession comSession = tryToOpenSessionFor(comMachine);
    3955 
    3956     /* Remount medium to the predefined port/device: */
    3957     bool fWasMounted = false;
    3958     /* Hard drive case: */
    3959     if (target.mediumType == UIMediumDeviceType_HardDisk)
    3960     {
    3961         /* Detaching: */
    3962         comMachine.DetachDevice(target.name, target.port, target.device);
    3963         fWasMounted = comMachine.isOk();
    3964         if (!fWasMounted)
    3965             msgCenter().cannotDetachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation,
    3966                                            StorageSlot(enmCurrentStorageBus, target.port, target.device));
    3967         else
    3968         {
    3969             /* Attaching: */
    3970             comMachine.AttachDevice(target.name, target.port, target.device, KDeviceType_HardDisk, comMedium);
    3971             fWasMounted = comMachine.isOk();
    3972             if (!fWasMounted)
    3973                 msgCenter().cannotAttachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation,
    3974                                                StorageSlot(enmCurrentStorageBus, target.port, target.device));
    3975         }
    3976     }
    3977     /* Optical/floppy drive case: */
    3978     else
    3979     {
    3980         /* Remounting: */
    3981         comMachine.MountMedium(target.name, target.port, target.device, comMedium, false /* force? */);
    3982         fWasMounted = comMachine.isOk();
    3983         if (!fWasMounted)
    3984         {
    3985             /* Ask for force remounting: */
    3986             if (msgCenter().cannotRemountMedium(comMachine, medium(uActualID),
    3987                                                 fMount, true /* retry? */))
    3988             {
    3989                 /* Force remounting: */
    3990                 comMachine.MountMedium(target.name, target.port, target.device, comMedium, true /* force? */);
    3991                 fWasMounted = comMachine.isOk();
    3992                 if (!fWasMounted)
    3993                     msgCenter().cannotRemountMedium(comMachine, medium(uActualID),
    3994                                                     fMount, false /* retry? */);
    3995             }
    3996         }
    3997         /* If mounting was successful: */
    3998         if (fWasMounted)
    3999         {
    4000             /* Disable First RUN Wizard: */
    4001             if (gEDataManager->machineFirstTimeStarted(comMachine.GetId()))
    4002                 gEDataManager->setMachineFirstTimeStarted(false, comMachine.GetId());
    4003         }
    4004     }
    4005 
    4006     /* Save settings: */
    4007     if (fWasMounted)
    4008     {
    4009         comMachine.SaveSettings();
    4010         if (!comMachine.isOk())
    4011             msgCenter().cannotSaveMachineSettings(comMachine, windowManager().mainWindowShown());
    4012     }
    4013 
    4014     /* Close session to editable comMachine if necessary: */
    4015     if (!comSession.isNull())
    4016         comSession.UnlockMachine();
    4017 }
    4018 
    4019 QString UICommon::details(const CMedium &comMedium, bool fPredictDiff, bool fUseHtml /* = true */)
    4020 {
    4021     /* Search for corresponding UI medium: */
    4022     const QUuid uMediumID = comMedium.isNull() ? UIMedium::nullID() : comMedium.GetId();
    4023     UIMedium guiMedium = medium(uMediumID);
    4024     if (!comMedium.isNull() && guiMedium.isNull())
    4025     {
    4026         /* UI medium may be new and not among cached media, request enumeration: */
    4027         enumerateMedia(CMediumVector() << comMedium);
    4028 
    4029         /* Search for corresponding UI medium again: */
    4030         guiMedium = medium(uMediumID);
    4031         if (guiMedium.isNull())
    4032         {
    4033             /* Medium might be deleted already, return null string: */
    4034             return QString();
    4035         }
    4036     }
    4037 
    4038     /* For differencing hard-disk we have to request
    4039      * enumeration of whole tree based in it's root item: */
    4040     if (   comMedium.isNotNull()
    4041         && comMedium.GetDeviceType() == KDeviceType_HardDisk)
    4042     {
    4043         /* Traverse through parents to root to catch it: */
    4044         CMedium comRootMedium;
    4045         CMedium comParentMedium = comMedium.GetParent();
    4046         while (comParentMedium.isNotNull())
    4047         {
    4048             comRootMedium = comParentMedium;
    4049             comParentMedium = comParentMedium.GetParent();
    4050         }
    4051         /* Enumerate root if it's found and wasn't cached: */
    4052         if (comRootMedium.isNotNull())
    4053         {
    4054             const QUuid uRootId = comRootMedium.GetId();
    4055             if (medium(uRootId).isNull())
    4056                 enumerateMedia(CMediumVector() << comRootMedium);
    4057         }
    4058     }
    4059 
    4060     /* Return UI medium details: */
    4061     return fUseHtml ? guiMedium.detailsHTML(true /* no diffs? */, fPredictDiff) :
    4062                       guiMedium.details(true /* no diffs? */, fPredictDiff);
    4063 }
    4064 
    4065 void UICommon::updateRecentlyUsedMediumListAndFolder(UIMediumDeviceType enmMediumType, QString strMediumLocation)
    4066 {
    4067     /** Don't add the medium to extra data if its name is in exclude list, m_recentMediaExcludeList: */
    4068     foreach (QString strExcludeName, m_recentMediaExcludeList)
    4069     {
    4070         if (strMediumLocation.contains(strExcludeName))
    4071             return;
    4072     }
    4073 
    4074     /* Remember the path of the last chosen medium: */
    4075     switch (enmMediumType)
    4076     {
    4077         case UIMediumDeviceType_HardDisk: gEDataManager->setRecentFolderForHardDrives(QFileInfo(strMediumLocation).absolutePath()); break;
    4078         case UIMediumDeviceType_DVD:      gEDataManager->setRecentFolderForOpticalDisks(QFileInfo(strMediumLocation).absolutePath()); break;
    4079         case UIMediumDeviceType_Floppy:   gEDataManager->setRecentFolderForFloppyDisks(QFileInfo(strMediumLocation).absolutePath()); break;
    4080         default: break;
    4081     }
    4082 
    4083     /* Update recently used list: */
    4084     QStringList recentMediumList;
    4085     switch (enmMediumType)
    4086     {
    4087         case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break;
    4088         case UIMediumDeviceType_DVD:      recentMediumList = gEDataManager->recentListOfOpticalDisks(); break;
    4089         case UIMediumDeviceType_Floppy:   recentMediumList = gEDataManager->recentListOfFloppyDisks(); break;
    4090         default: break;
    4091     }
    4092     if (recentMediumList.contains(strMediumLocation))
    4093         recentMediumList.removeAll(strMediumLocation);
    4094     recentMediumList.prepend(strMediumLocation);
    4095     while(recentMediumList.size() > 5)
    4096         recentMediumList.removeLast();
    4097     switch (enmMediumType)
    4098     {
    4099         case UIMediumDeviceType_HardDisk: gEDataManager->setRecentListOfHardDrives(recentMediumList); break;
    4100         case UIMediumDeviceType_DVD:      gEDataManager->setRecentListOfOpticalDisks(recentMediumList); break;
    4101         case UIMediumDeviceType_Floppy:   gEDataManager->setRecentListOfFloppyDisks(recentMediumList); break;
    4102         default: break;
    4103     }
    4104 }
    4105 
    4106 QString UICommon::defaultFolderPathForType(UIMediumDeviceType enmMediumType)
    4107 {
    4108     QString strLastFolder;
    4109     switch (enmMediumType)
    4110     {
    4111         case UIMediumDeviceType_HardDisk:
    4112             strLastFolder = gEDataManager->recentFolderForHardDrives();
    4113             if (strLastFolder.isEmpty())
    4114                 strLastFolder = gEDataManager->recentFolderForOpticalDisks();
    4115             if (strLastFolder.isEmpty())
    4116                 strLastFolder = gEDataManager->recentFolderForFloppyDisks();
    4117             break;
    4118         case UIMediumDeviceType_DVD:
    4119             strLastFolder = gEDataManager->recentFolderForOpticalDisks();
    4120             if (strLastFolder.isEmpty())
    4121                 strLastFolder = gEDataManager->recentFolderForFloppyDisks();
    4122             if (strLastFolder.isEmpty())
    4123                 strLastFolder = gEDataManager->recentFolderForHardDrives();
    4124             break;
    4125         case UIMediumDeviceType_Floppy:
    4126             strLastFolder = gEDataManager->recentFolderForFloppyDisks();
    4127             if (strLastFolder.isEmpty())
    4128                 strLastFolder = gEDataManager->recentFolderForOpticalDisks();
    4129             if (strLastFolder.isEmpty())
    4130                 strLastFolder = gEDataManager->recentFolderForHardDrives();
    4131             break;
    4132         default:
    4133             break;
    4134     }
    4135 
    4136     if (strLastFolder.isEmpty())
    4137         return virtualBox().GetSystemProperties().GetDefaultMachineFolder();
    4138 
    4139     return strLastFolder;
    4140 }
    4141 
    4142 #ifdef RT_OS_LINUX
    4143 /* static */
    4144 void UICommon::checkForWrongUSBMounted()
    4145 {
    4146     /* Make sure '/proc/mounts' exists and can be opened: */
    4147     QFile file("/proc/mounts");
    4148     if (!file.exists() || !file.open(QIODevice::ReadOnly | QIODevice::Text))
    4149         return;
    4150 
    4151     /* Fetch contents: */
    4152     QStringList contents;
    4153     for (;;)
    4154     {
    4155         QByteArray line = file.readLine();
    4156         if (line.isEmpty())
    4157             break;
    4158         contents << line;
    4159     }
    4160     /* Grep contents for usbfs presence: */
    4161     QStringList grep1(contents.filter("/sys/bus/usb/drivers"));
    4162     QStringList grep2(grep1.filter("usbfs"));
    4163     if (grep2.isEmpty())
    4164         return;
    4165 
    4166     /* Show corresponding warning: */
    4167     msgCenter().warnAboutWrongUSBMounted();
    4168 }
    4169 #endif /* RT_OS_LINUX */
    4170 
    4171 /* static */
    4172 QString UICommon::details(const CUSBDevice &comDevice)
    4173 {
    4174     QString strDetails;
    4175     if (comDevice.isNull())
    4176         strDetails = tr("Unknown device", "USB device details");
    4177     else
    4178     {
    4179         QVector<QString> devInfoVector = comDevice.GetDeviceInfo();
    4180         QString strManufacturer;
    4181         QString strProduct;
    4182 
    4183         if (devInfoVector.size() >= 1)
    4184             strManufacturer = devInfoVector[0].trimmed();
    4185         if (devInfoVector.size() >= 2)
    4186             strProduct = devInfoVector[1].trimmed();
    4187 
    4188         if (strManufacturer.isEmpty() && strProduct.isEmpty())
    4189         {
    4190             strDetails =
    4191                 tr("Unknown device %1:%2", "USB device details")
    4192                    .arg(QString().sprintf("%04hX", comDevice.GetVendorId()))
    4193                    .arg(QString().sprintf("%04hX", comDevice.GetProductId()));
    4194         }
    4195         else
    4196         {
    4197             if (strProduct.toUpper().startsWith(strManufacturer.toUpper()))
    4198                 strDetails = strProduct;
    4199             else
    4200                 strDetails = strManufacturer + " " + strProduct;
    4201         }
    4202         ushort iRev = comDevice.GetRevision();
    4203         if (iRev != 0)
    4204             strDetails += QString().sprintf(" [%04hX]", iRev);
    4205     }
    4206 
    4207     return strDetails.trimmed();
    4208 }
    4209 
    4210 /* static */
    4211 QString UICommon::toolTip(const CUSBDevice &comDevice)
    4212 {
    4213     QString strTip =
    4214         tr("<nobr>Vendor ID: %1</nobr><br>"
    4215            "<nobr>Product ID: %2</nobr><br>"
    4216            "<nobr>Revision: %3</nobr>", "USB device tooltip")
    4217            .arg(QString().sprintf("%04hX", comDevice.GetVendorId()))
    4218            .arg(QString().sprintf("%04hX", comDevice.GetProductId()))
    4219            .arg(QString().sprintf("%04hX", comDevice.GetRevision()));
    4220 
    4221     const QString strSerial = comDevice.GetSerialNumber();
    4222     if (!strSerial.isEmpty())
    4223         strTip += QString(tr("<br><nobr>Serial No. %1</nobr>", "USB device tooltip"))
    4224                              .arg(strSerial);
    4225 
    4226     /* Add the state field if it's a host USB device: */
    4227     CHostUSBDevice hostDev(comDevice);
    4228     if (!hostDev.isNull())
    4229     {
    4230         strTip += QString(tr("<br><nobr>State: %1</nobr>", "USB device tooltip"))
    4231                              .arg(gpConverter->toString(hostDev.GetState()));
    4232     }
    4233 
    4234     return strTip;
    4235 }
    4236 
    4237 /* static */
    4238 QString UICommon::toolTip(const CUSBDeviceFilter &comFilter)
    4239 {
    4240     QString strTip;
    4241 
    4242     const QString strVendorId = comFilter.GetVendorId();
    4243     if (!strVendorId.isEmpty())
    4244         strTip += tr("<nobr>Vendor ID: %1</nobr>", "USB filter tooltip")
    4245                      .arg(strVendorId);
    4246 
    4247     const QString strProductId = comFilter.GetProductId();
    4248     if (!strProductId.isEmpty())
    4249         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product ID: %2</nobr>", "USB filter tooltip")
    4250                                                      .arg(strProductId);
    4251 
    4252     const QString strRevision = comFilter.GetRevision();
    4253     if (!strRevision.isEmpty())
    4254         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Revision: %3</nobr>", "USB filter tooltip")
    4255                                                      .arg(strRevision);
    4256 
    4257     const QString strProduct = comFilter.GetProduct();
    4258     if (!strProduct.isEmpty())
    4259         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product: %4</nobr>", "USB filter tooltip")
    4260                                                      .arg(strProduct);
    4261 
    4262     const QString strManufacturer = comFilter.GetManufacturer();
    4263     if (!strManufacturer.isEmpty())
    4264         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Manufacturer: %5</nobr>", "USB filter tooltip")
    4265                                                      .arg(strManufacturer);
    4266 
    4267     const QString strSerial = comFilter.GetSerialNumber();
    4268     if (!strSerial.isEmpty())
    4269         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Serial No.: %1</nobr>", "USB filter tooltip")
    4270                                                      .arg(strSerial);
    4271 
    4272     const QString strPort = comFilter.GetPort();
    4273     if (!strPort.isEmpty())
    4274         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Port: %1</nobr>", "USB filter tooltip")
    4275                                                      .arg(strPort);
    4276 
    4277     /* Add the state field if it's a host USB device: */
    4278     CHostUSBDevice hostDev(comFilter);
    4279     if (!hostDev.isNull())
    4280     {
    4281         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>State: %1</nobr>", "USB filter tooltip")
    4282                                                      .arg(gpConverter->toString(hostDev.GetState()));
    4283     }
    4284 
    4285     return strTip;
    4286 }
    4287 
    4288 /* static */
    4289 QString UICommon::toolTip(const CHostVideoInputDevice &comWebcam)
    4290 {
    4291     QStringList records;
    4292 
    4293     const QString strName = comWebcam.GetName();
    4294     if (!strName.isEmpty())
    4295         records << strName;
    4296 
    4297     const QString strPath = comWebcam.GetPath();
    4298     if (!strPath.isEmpty())
    4299         records << strPath;
    4300 
    4301     return records.join("<br>");
    4302 }
    4303 
    4304 void UICommon::doExtPackInstallation(QString const &strFilePath, QString const &strDigest,
    4305                                      QWidget *pParent, QString *pstrExtPackName) const
    4306 {
    4307     /* If the extension pack manager isn't available, skip any attempts to install: */
    4308     CExtPackManager extPackManager = virtualBox().GetExtensionPackManager();
    4309     if (extPackManager.isNull())
    4310         return;
    4311     /* Open the extpack tarball via IExtPackManager: */
    4312     CExtPackFile comExtPackFile;
    4313     if (strDigest.isEmpty())
    4314         comExtPackFile = extPackManager.OpenExtPackFile(strFilePath);
    4315     else
    4316     {
    4317         QString strFileAndHash = QString("%1::SHA-256=%2").arg(strFilePath).arg(strDigest);
    4318         comExtPackFile = extPackManager.OpenExtPackFile(strFileAndHash);
    4319     }
    4320     if (!extPackManager.isOk())
    4321     {
    4322         msgCenter().cannotOpenExtPack(strFilePath, extPackManager, pParent);
    4323         return;
    4324     }
    4325 
    4326     if (!comExtPackFile.GetUsable())
    4327     {
    4328         msgCenter().warnAboutBadExtPackFile(strFilePath, comExtPackFile, pParent);
    4329         return;
    4330     }
    4331 
    4332     const QString strPackName = comExtPackFile.GetName();
    4333     const QString strPackDescription = comExtPackFile.GetDescription();
    4334     const QString strPackVersion = QString("%1r%2%3").arg(comExtPackFile.GetVersion()).arg(comExtPackFile.GetRevision()).arg(comExtPackFile.GetEdition());
    4335 
    4336     /* Check if there is a version of the extension pack already
    4337      * installed on the system and let the user decide what to do about it. */
    4338     CExtPack comExtPackCur = extPackManager.Find(strPackName);
    4339     bool fReplaceIt = comExtPackCur.isOk();
    4340     if (fReplaceIt)
    4341     {
    4342         QString strPackVersionCur = QString("%1r%2%3").arg(comExtPackCur.GetVersion()).arg(comExtPackCur.GetRevision()).arg(comExtPackCur.GetEdition());
    4343         if (!msgCenter().confirmReplaceExtensionPack(strPackName, strPackVersion, strPackVersionCur, strPackDescription, pParent))
    4344             return;
    4345     }
    4346     /* If it's a new package just ask for general confirmation. */
    4347     else
    4348     {
    4349         if (!msgCenter().confirmInstallExtensionPack(strPackName, strPackVersion, strPackDescription, pParent))
    4350             return;
    4351     }
    4352 
    4353     /* Display the license dialog if required by the extension pack. */
    4354     if (comExtPackFile.GetShowLicense())
    4355     {
    4356         QString strLicense = comExtPackFile.GetLicense();
    4357         VBoxLicenseViewer licenseViewer(pParent);
    4358         if (licenseViewer.showLicenseFromString(strLicense) != QDialog::Accepted)
    4359             return;
    4360     }
    4361 
    4362     /* Install the selected package.
    4363      * Set the package name return value before doing
    4364      * this as the caller should do a refresh even on failure. */
    4365     QString strDisplayInfo;
    4366 #ifdef VBOX_WS_WIN
    4367     if (pParent)
    4368         strDisplayInfo.sprintf("hwnd=%#llx", (uint64_t)(uintptr_t)pParent->winId());
    4369 #endif
    4370 
    4371     /* Install extension pack: */
    4372     UINotificationProgressExtensionPackInstall *pNotification =
    4373             new UINotificationProgressExtensionPackInstall(comExtPackFile,
    4374                                                            fReplaceIt,
    4375                                                            strPackName,
    4376                                                            strDisplayInfo);
    4377     connect(pNotification, &UINotificationProgressExtensionPackInstall::sigExtensionPackInstalled,
    4378             this, &UICommon::sigExtensionPackInstalled);
    4379     gpNotificationCenter->append(pNotification);
    4380 
    4381     /* Store the name: */
    4382     if (pstrExtPackName)
    4383         *pstrExtPackName = strPackName;
    4384 }
    4385 
    4386 #ifdef VBOX_WITH_3D_ACCELERATION
    4387 /* static */
    4388 bool UICommon::isWddmCompatibleOsType(const QString &strGuestOSTypeId)
    4389 {
    4390     return    strGuestOSTypeId.startsWith("WindowsVista")
    4391            || strGuestOSTypeId.startsWith("Windows7")
    4392            || strGuestOSTypeId.startsWith("Windows8")
    4393            || strGuestOSTypeId.startsWith("Windows81")
    4394            || strGuestOSTypeId.startsWith("Windows10")
    4395            || strGuestOSTypeId.startsWith("Windows2008")
    4396            || strGuestOSTypeId.startsWith("Windows2012");
    4397 }
    4398 #endif /* VBOX_WITH_3D_ACCELERATION */
    4399 
    4400 /* static */
    4401 quint64 UICommon::requiredVideoMemory(const QString &strGuestOSTypeId, int cMonitors /* = 1 */)
    4402 {
    4403     /* We create a list of the size of all available host monitors. This list
    4404      * is sorted by value and by starting with the biggest one, we calculate
    4405      * the memory requirements for every guest screen. This is of course not
    4406      * correct, but as we can't predict on which host screens the user will
    4407      * open the guest windows, this is the best assumption we can do, cause it
    4408      * is the worst case. */
    4409     const int cHostScreens = gpDesktop->screenCount();
    4410     QVector<int> screenSize(qMax(cMonitors, cHostScreens), 0);
    4411     for (int i = 0; i < cHostScreens; ++i)
    4412     {
    4413         QRect r = gpDesktop->screenGeometry(i);
    4414         screenSize[i] = r.width() * r.height();
    4415     }
    4416     /* Now sort the vector: */
    4417     std::sort(screenSize.begin(), screenSize.end(), std::greater<int>());
    4418     /* For the case that there are more guest screens configured then host
    4419      * screens available, replace all zeros with the greatest value in the
    4420      * vector. */
    4421     for (int i = 0; i < screenSize.size(); ++i)
    4422         if (screenSize.at(i) == 0)
    4423             screenSize.replace(i, screenSize.at(0));
    4424 
    4425     quint64 uNeedBits = 0;
    4426     for (int i = 0; i < cMonitors; ++i)
    4427     {
    4428         /* Calculate summary required memory amount in bits: */
    4429         uNeedBits += (screenSize.at(i) * /* with x height */
    4430                      32 + /* we will take the maximum possible bpp for now */
    4431                      8 * _1M) + /* current cache per screen - may be changed in future */
    4432                      8 * 4096; /* adapter info */
    4433     }
    4434     /* Translate value into megabytes with rounding to highest side: */
    4435     quint64 uNeedMBytes = uNeedBits % (8 * _1M)
    4436                         ? uNeedBits / (8 * _1M) + 1
    4437                         : uNeedBits / (8 * _1M) /* convert to megabytes */;
    4438 
    4439     if (strGuestOSTypeId.startsWith("Windows"))
    4440     {
    4441         /* Windows guests need offscreen VRAM too for graphics acceleration features: */
    4442 #ifdef VBOX_WITH_3D_ACCELERATION
    4443         if (isWddmCompatibleOsType(strGuestOSTypeId))
    4444         {
    4445             /* WDDM mode, there are two surfaces for each screen: shadow & primary: */
    4446             uNeedMBytes *= 3;
    4447         }
    4448         else
    4449 #endif /* VBOX_WITH_3D_ACCELERATION */
    4450         {
    4451             uNeedMBytes *= 2;
    4452         }
    4453     }
    4454 
    4455     return uNeedMBytes * _1M;
    4456 }
    4457 
    4458 QIcon UICommon::vmUserIcon(const CMachine &comMachine) const
    4459 {
    4460     /* Prepare fallback icon: */
    4461     static QIcon nullIcon;
    4462 
    4463     /* Make sure general icon-pool initialized: */
    4464     AssertReturn(m_pIconPool, nullIcon);
    4465 
    4466     /* Redirect to general icon-pool: */
    4467     return m_pIconPool->userMachineIcon(comMachine);
    4468 }
    4469 
    4470 QPixmap UICommon::vmUserPixmap(const CMachine &comMachine, const QSize &size) const
    4471 {
    4472     /* Prepare fallback pixmap: */
    4473     static QPixmap nullPixmap;
    4474 
    4475     /* Make sure general icon-pool initialized: */
    4476     AssertReturn(m_pIconPool, nullPixmap);
    4477 
    4478     /* Redirect to general icon-pool: */
    4479     return m_pIconPool->userMachinePixmap(comMachine, size);
    4480 }
    4481 
    4482 QPixmap UICommon::vmUserPixmapDefault(const CMachine &comMachine, QSize *pLogicalSize /* = 0 */) const
    4483 {
    4484     /* Prepare fallback pixmap: */
    4485     static QPixmap nullPixmap;
    4486 
    4487     /* Make sure general icon-pool initialized: */
    4488     AssertReturn(m_pIconPool, nullPixmap);
    4489 
    4490     /* Redirect to general icon-pool: */
    4491     return m_pIconPool->userMachinePixmapDefault(comMachine, pLogicalSize);
    4492 }
    4493 
    4494 QIcon UICommon::vmGuestOSTypeIcon(const QString &strOSTypeID) const
    4495 {
    4496     /* Prepare fallback icon: */
    4497     static QIcon nullIcon;
    4498 
    4499     /* Make sure general icon-pool initialized: */
    4500     AssertReturn(m_pIconPool, nullIcon);
    4501 
    4502     /* Redirect to general icon-pool: */
    4503     return m_pIconPool->guestOSTypeIcon(strOSTypeID);
    4504 }
    4505 
    4506 QPixmap UICommon::vmGuestOSTypePixmap(const QString &strOSTypeID, const QSize &size) const
    4507 {
    4508     /* Prepare fallback pixmap: */
    4509     static QPixmap nullPixmap;
    4510 
    4511     /* Make sure general icon-pool initialized: */
    4512     AssertReturn(m_pIconPool, nullPixmap);
    4513 
    4514     /* Redirect to general icon-pool: */
    4515     return m_pIconPool->guestOSTypePixmap(strOSTypeID, size);
    4516 }
    4517 
    4518 QPixmap UICommon::vmGuestOSTypePixmapDefault(const QString &strOSTypeID, QSize *pLogicalSize /* = 0 */) const
    4519 {
    4520     /* Prepare fallback pixmap: */
    4521     static QPixmap nullPixmap;
    4522 
    4523     /* Make sure general icon-pool initialized: */
    4524     AssertReturn(m_pIconPool, nullPixmap);
    4525 
    4526     /* Redirect to general icon-pool: */
    4527     return m_pIconPool->guestOSTypePixmapDefault(strOSTypeID, pLogicalSize);
    4528 }
    4529 
    4530 /* static */
    4531 QPixmap UICommon::joinPixmaps(const QPixmap &pixmap1, const QPixmap &pixmap2)
    4532 {
    4533     if (pixmap1.isNull())
    4534         return pixmap2;
    4535     if (pixmap2.isNull())
    4536         return pixmap1;
    4537 
    4538     QPixmap result(pixmap1.width() + pixmap2.width() + 2,
    4539                    qMax(pixmap1.height(), pixmap2.height()));
    4540     result.fill(Qt::transparent);
    4541 
    4542     QPainter painter(&result);
    4543     painter.drawPixmap(0, 0, pixmap1);
    4544     painter.drawPixmap(pixmap1.width() + 2, result.height() - pixmap2.height(), pixmap2);
    4545     painter.end();
    4546 
    4547     return result;
    4548 }
    4549 
    4550 /* static */
    4551 void UICommon::setHelpKeyword(QObject *pObject, const QString &strHelpKeyword)
    4552 {
    4553     if (pObject)
    4554         pObject->setProperty("helpkeyword", strHelpKeyword);
    4555 }
    4556 
    4557 /* static */
    4558 QString UICommon::helpKeyword(const QObject *pObject)
    4559 {
    4560     if (!pObject)
    4561         return QString();
    4562     return pObject->property("helpkeyword").toString();
    4563 }
    4564 
    4565 bool UICommon::openURL(const QString &strUrl) const
    4566 {
    4567     /** Service event. */
    4568     class ServiceEvent : public QEvent
    4569     {
    4570     public:
    4571 
    4572         /** Constructs service event on th basis of passed @a fResult. */
    4573         ServiceEvent(bool fResult)
    4574             : QEvent(QEvent::User)
    4575             , m_fResult(fResult)
    4576         {}
    4577 
    4578         /** Returns the result which event brings. */
    4579         bool result() const { return m_fResult; }
    4580 
    4581     private:
    4582 
    4583         /** Holds the result which event brings. */
    4584         bool m_fResult;
    4585     };
    4586 
    4587     /** Service client object. */
    4588     class ServiceClient : public QEventLoop
    4589     {
    4590     public:
    4591 
    4592         /** Constructs service client on the basis of passed @a fResult. */
    4593         ServiceClient()
    4594             : m_fResult(false)
    4595         {}
    4596 
    4597         /** Returns the result which event brings. */
    4598         bool result() const { return m_fResult; }
    4599 
    4600     private:
    4601 
    4602         /** Handles any Qt @a pEvent. */
    4603         bool event(QEvent *pEvent)
    4604         {
    4605             /* Handle service event: */
    4606             if (pEvent->type() == QEvent::User)
    4607             {
    4608                 ServiceEvent *pServiceEvent = static_cast<ServiceEvent*>(pEvent);
    4609                 m_fResult = pServiceEvent->result();
    4610                 pServiceEvent->accept();
    4611                 quit();
    4612                 return true;
    4613             }
    4614             return false;
    4615         }
    4616 
    4617         bool m_fResult;
    4618     };
    4619 
    4620     /** Service server object. */
    4621     class ServiceServer : public QThread
    4622     {
    4623     public:
    4624 
    4625         /** Constructs service server on the basis of passed @a client and @a strUrl. */
    4626         ServiceServer(ServiceClient &client, const QString &strUrl)
    4627             : m_client(client), m_strUrl(strUrl) {}
    4628 
    4629     private:
    4630 
    4631         /** Executes thread task. */
    4632         void run()
    4633         {
    4634             QApplication::postEvent(&m_client, new ServiceEvent(QDesktopServices::openUrl(m_strUrl)));
    4635         }
    4636 
    4637         /** Holds the client reference. */
    4638         ServiceClient &m_client;
    4639         /** Holds the URL to be processed. */
    4640         const QString &m_strUrl;
    4641     };
    4642 
    4643     /* Create client & server: */
    4644     ServiceClient client;
    4645     ServiceServer server(client, strUrl);
    4646     server.start();
    4647     client.exec();
    4648     server.wait();
    4649 
    4650     /* Acquire client result: */
    4651     bool fResult = client.result();
    4652 
    4653     if (!fResult)
    4654         msgCenter().cannotOpenURL(strUrl);
    4655 
    4656     return fResult;
    4657 }
    4658 
    4659 void UICommon::sltGUILanguageChange(QString strLanguage)
    4660 {
    4661     /* Make sure medium-enumeration is not in progress! */
    4662     AssertReturnVoid(!isMediumEnumerationInProgress());
    4663     /* Load passed language: */
    4664     loadLanguage(strLanguage);
    4665 }
    4666 
    4667 void UICommon::sltHandleMediumCreated(const CMedium &comMedium)
    4668 {
    4669     /* Acquire device type: */
    4670     const KDeviceType enmDeviceType = comMedium.GetDeviceType();
    4671     if (!comMedium.isOk())
    4672         msgCenter().cannotAcquireMediumAttribute(comMedium);
    4673     else
    4674     {
    4675         /* Convert to medium type: */
    4676         const UIMediumDeviceType enmMediumType = mediumTypeToLocal(enmDeviceType);
    4677 
    4678         /* Make sure we cached created medium in GUI: */
    4679         createMedium(UIMedium(comMedium, enmMediumType, KMediumState_Created));
    4680     }
    4681 }
    4682 
    4683 void UICommon::sltHandleMachineCreated(const CMachine &comMachine)
    4684 {
    4685     /* Register created machine. */
    4686     CVirtualBox comVBox = virtualBox();
    4687     comVBox.RegisterMachine(comMachine);
    4688     if (!comVBox.isOk())
    4689         msgCenter().cannotRegisterMachine(comVBox, comMachine.GetName());
    4690 }
    4691 
    4692 void UICommon::sltHandleCloudMachineAdded(const QString &strProviderShortName,
    4693                                           const QString &strProfileName,
    4694                                           const CCloudMachine &comMachine)
    4695 {
    4696     /* Make sure we cached added cloud VM in GUI: */
    4697     notifyCloudMachineRegistered(strProviderShortName,
    4698                                  strProfileName,
    4699                                  comMachine);
    4700 }
    4701 
    4702 bool UICommon::eventFilter(QObject *pObject, QEvent *pEvent)
    4703 {
    4704     /** @todo Just use the QIWithRetranslateUI3 template wrapper. */
    4705 
    4706     if (   pEvent->type() == QEvent::LanguageChange
    4707         && pObject->isWidgetType()
    4708         && static_cast<QWidget*>(pObject)->isTopLevel())
    4709     {
    4710         /* Catch the language change event before any other widget gets it in
    4711          * order to invalidate cached string resources (like the details view
    4712          * templates) that may be used by other widgets. */
    4713         QWidgetList list = QApplication::topLevelWidgets();
    4714         if (list.first() == pObject)
    4715         {
    4716             /* Call this only once per every language change (see
    4717              * QApplication::installTranslator() for details): */
    4718             retranslateUi();
    4719         }
    4720     }
    4721 
    4722     /* Call to base-class: */
    4723     return QObject::eventFilter(pObject, pEvent);
    4724 }
    4725 
    4726 void UICommon::retranslateUi()
    4727 {
    4728     s_strUserDefinedPortName = tr("User-defined", "serial port");
    4729 
    4730     m_pixWarning = UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_MessageBoxWarning).pixmap(16, 16);
    4731     Assert(!m_pixWarning.isNull());
    4732 
    4733     m_pixError = UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_MessageBoxCritical).pixmap(16, 16);
    4734     Assert(!m_pixError.isNull());
    4735 
    4736     /* Re-enumerate uimedium since they contain some translations too: */
    4737     if (m_fValid)
    4738         refreshMedia();
    4739 
    4740 #ifdef VBOX_WS_X11
    4741     // WORKAROUND:
    4742     // As X11 do not have functionality for providing human readable key names,
    4743     // we keep a table of them, which must be updated when the language is changed.
    4744     UINativeHotKey::retranslateKeyNames();
    4745 #endif
    4746 }
    4747 
    4748 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1
    4749 void UICommon::sltHandleCommitDataRequest(QSessionManager &manager)
    4750 {
    4751     LogRel(("GUI: UICommon: Commit data request..\n"));
    4752 
    4753     /* Ask listener to commit data: */
    4754     emit sigAskToCommitData();
    4755 #ifdef VBOX_WS_WIN
    4756     m_fDataCommitted = true;
    4757 #endif
    4758 
    4759     /* Depending on UI type: */
    4760     switch (uiType())
    4761     {
    4762         /* For Runtime UI: */
    4763         case UIType_RuntimeUI:
    4764         {
    4765             /* Thin clients will be able to shutdown properly,
    4766              * but for fat clients: */
    4767             if (!isSeparateProcess())
    4768             {
    4769                 // WORKAROUND:
    4770                 // We can't save VM state in one go for fat clients, so we have to ask session manager to cancel shutdown.
    4771                 // To next major release this should be removed in any case, since there will be no fat clients after all.
    4772                 manager.cancel();
    4773 
    4774 #ifdef VBOX_WS_WIN
    4775                 // WORKAROUND:
    4776                 // In theory that's Qt5 who should allow us to provide canceling reason as well, but that functionality
    4777                 // seems to be missed in Windows platform plugin, so we are making that ourselves.
    4778                 ShutdownBlockReasonCreateAPI((HWND)windowManager().mainWindowShown()->winId(), L"VM is still running.");
    4779 #endif
    4780             }
    4781 
    4782             break;
    4783         }
    4784         default:
    4785             break;
    4786     }
    4787 }
    4788 #endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
    4789 
    4790 void UICommon::sltHandleVBoxSVCAvailabilityChange(bool fAvailable)
    4791 {
    4792     /* Make sure the VBoxSVC availability changed: */
    4793     if (m_fVBoxSVCAvailable == fAvailable)
    4794         return;
    4795 
    4796     /* Cache the new VBoxSVC availability value: */
    4797     m_fVBoxSVCAvailable = fAvailable;
    4798 
    4799     /* If VBoxSVC is not available: */
    4800     if (!m_fVBoxSVCAvailable)
    4801     {
    4802         /* Mark wrappers invalid: */
    4803         m_fWrappersValid = false;
    4804         /* Re-fetch corresponding CVirtualBox to restart VBoxSVC: */
    4805         m_comVBox = m_comVBoxClient.GetVirtualBox();
    4806         if (!m_comVBoxClient.isOk())
    4807         {
    4808             // The proper behavior would be to show the message and to exit the app, e.g.:
    4809             // msgCenter().cannotAcquireVirtualBox(m_comVBoxClient);
    4810             // return QApplication::quit();
    4811             // But CVirtualBox is still NULL in current Main implementation,
    4812             // and this call do not restart anything, so we are waiting
    4813             // for subsequent event about VBoxSVC is available again.
    4814         }
    4815     }
    4816     /* If VBoxSVC is available: */
    4817     else
    4818     {
    4819         if (!m_fWrappersValid)
    4820         {
    4821             /* Re-fetch corresponding CVirtualBox: */
    4822             m_comVBox = m_comVBoxClient.GetVirtualBox();
    4823             if (!m_comVBoxClient.isOk())
    4824             {
    4825                 msgCenter().cannotAcquireVirtualBox(m_comVBoxClient);
    4826                 return QApplication::quit();
    4827             }
    4828             /* Re-init wrappers: */
    4829             comWrappersReinit();
    4830 
    4831             /* For Selector UI: */
    4832             if (uiType() == UIType_SelectorUI)
    4833             {
    4834                 /* Recreate Main event listeners: */
    4835                 UIVirtualBoxEventHandler::destroy();
    4836                 UIVirtualBoxClientEventHandler::destroy();
    4837                 UIExtraDataManager::destroy();
    4838                 UIExtraDataManager::instance();
    4839                 UIVirtualBoxEventHandler::instance();
    4840                 UIVirtualBoxClientEventHandler::instance();
    4841                 /* Ask UIStarter to restart UI: */
    4842                 emit sigAskToRestartUI();
    4843             }
    4844         }
    4845     }
    4846 
    4847     /* Notify listeners about the VBoxSVC availability change: */
    4848     emit sigVBoxSVCAvailabilityChange();
    4849 }
    4850 
    4851 #ifdef VBOX_WS_WIN
    4852 /* static */
    4853 BOOL UICommon::ShutdownBlockReasonCreateAPI(HWND hWnd, LPCWSTR pwszReason)
    4854 {
    4855     BOOL fResult = FALSE;
    4856     typedef BOOL(WINAPI *PFNSHUTDOWNBLOCKREASONCREATE)(HWND hWnd, LPCWSTR pwszReason);
    4857 
    4858     PFNSHUTDOWNBLOCKREASONCREATE pfn = (PFNSHUTDOWNBLOCKREASONCREATE)GetProcAddress(
    4859         GetModuleHandle(L"User32.dll"), "ShutdownBlockReasonCreate");
    4860     _ASSERTE(pfn);
    4861     if (pfn)
    4862         fResult = pfn(hWnd, pwszReason);
    4863     return fResult;
    4864 }
    4865 #endif
    4866 
    4867 #ifdef VBOX_WITH_DEBUGGER_GUI
    4868 
    4869 # define UICOMMON_DBG_CFG_VAR_FALSE       (0)
    4870 # define UICOMMON_DBG_CFG_VAR_TRUE        (1)
    4871 # define UICOMMON_DBG_CFG_VAR_MASK        (1)
    4872 # define UICOMMON_DBG_CFG_VAR_CMD_LINE    RT_BIT(3)
    4873 # define UICOMMON_DBG_CFG_VAR_DONE        RT_BIT(4)
    4874 
    4875 void UICommon::initDebuggerVar(int *piDbgCfgVar, const char *pszEnvVar, const char *pszExtraDataName, bool fDefault)
    4876 {
    4877     QString strEnvValue;
    4878     char    szEnvValue[256];
    4879     int rc = RTEnvGetEx(RTENV_DEFAULT, pszEnvVar, szEnvValue, sizeof(szEnvValue), NULL);
    4880     if (RT_SUCCESS(rc))
    4881     {
    4882         strEnvValue = QString::fromUtf8(&szEnvValue[0]).toLower().trimmed();
    4883         if (strEnvValue.isEmpty())
    4884             strEnvValue = "yes";
    4885     }
    4886     else if (rc != VERR_ENV_VAR_NOT_FOUND)
    4887         strEnvValue = "veto";
    4888 
    4889     QString strExtraValue = m_comVBox.GetExtraData(pszExtraDataName).toLower().trimmed();
    4890     if (strExtraValue.isEmpty())
    4891         strExtraValue = QString();
    4892 
    4893     if ( strEnvValue.contains("veto") || strExtraValue.contains("veto"))
    4894         *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE;
    4895     else if (strEnvValue.isNull() && strExtraValue.isNull())
    4896         *piDbgCfgVar = fDefault ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE;
    4897     else
    4898     {
    4899         QString *pStr = !strEnvValue.isEmpty() ? &strEnvValue : &strExtraValue;
    4900         if (   pStr->startsWith("y")  // yes
    4901             || pStr->startsWith("e")  // enabled
    4902             || pStr->startsWith("t")  // true
    4903             || pStr->startsWith("on")
    4904             || pStr->toLongLong() != 0)
    4905             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_TRUE;
    4906         else if (   pStr->startsWith("n")  // o
    4907                  || pStr->startsWith("d")  // disable
    4908                  || pStr->startsWith("f")  // false
    4909                  || pStr->startsWith("off")
    4910                  || pStr->contains("veto") /* paranoia */
    4911                  || pStr->toLongLong() == 0)
    4912             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_FALSE;
    4913         else
    4914         {
    4915             LogFunc(("Ignoring unknown value '%s' for '%s'\n", pStr->toUtf8().constData(), pStr == &strEnvValue ? pszEnvVar : pszExtraDataName));
    4916             *piDbgCfgVar = fDefault ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE;
    4917         }
    4918     }
    4919 }
    4920 
    4921 void UICommon::setDebuggerVar(int *piDbgCfgVar, bool fState)
    4922 {
    4923     if (!(*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_DONE))
    4924         *piDbgCfgVar = (fState ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE)
    4925                      | UICOMMON_DBG_CFG_VAR_CMD_LINE;
    4926 }
    4927 
    4928 bool UICommon::isDebuggerWorker(int *piDbgCfgVar, const char *pszExtraDataName) const
    4929 {
    4930     if (!(*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_DONE))
    4931     {
    4932         const QString str = gEDataManager->debugFlagValue(pszExtraDataName);
    4933         if (str.contains("veto"))
    4934             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE;
    4935         else if (str.isEmpty() || (*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_CMD_LINE))
    4936             *piDbgCfgVar |= UICOMMON_DBG_CFG_VAR_DONE;
    4937         else if (   str.startsWith("y")  // yes
    4938                  || str.startsWith("e")  // enabled
    4939                  || str.startsWith("t")  // true
    4940                  || str.startsWith("on")
    4941                  || str.toLongLong() != 0)
    4942             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_TRUE;
    4943         else if (   str.startsWith("n")  // no
    4944                  || str.startsWith("d")  // disable
    4945                  || str.startsWith("f")  // false
    4946                  || str.toLongLong() == 0)
    4947             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE;
    4948         else
    4949             *piDbgCfgVar |= UICOMMON_DBG_CFG_VAR_DONE;
    4950     }
    4951 
    4952     return (*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_MASK) == UICOMMON_DBG_CFG_VAR_TRUE;
    4953 }
    4954 
    4955 #endif /* VBOX_WITH_DEBUGGER_GUI */
    4956 
    4957 void UICommon::comWrappersReinit()
    4958 {
    4959     /* Re-fetch corresponding objects/values: */
    4960     m_comHost = virtualBox().GetHost();
    4961     m_strHomeFolder = virtualBox().GetHomeFolder();
    4962 
    4963     /* Re-initialize guest OS Type list: */
    4964     m_guestOSFamilyIDs.clear();
    4965     m_guestOSTypes.clear();
    4966     const CGuestOSTypeVector guestOSTypes = m_comVBox.GetGuestOSTypes();
    4967     const int cGuestOSTypeCount = guestOSTypes.size();
    4968     AssertMsg(cGuestOSTypeCount > 0, ("Number of OS types must not be zero"));
    4969     if (cGuestOSTypeCount > 0)
    4970     {
    4971         /* Here we ASSUME the 'Other' types are always the first,
    4972          * so we remember them and will append them to the list when finished.
    4973          * We do a two pass, first adding the specific types, then the two 'Other' types. */
    4974         for (int j = 0; j < 2; ++j)
    4975         {
    4976             int cMax = j == 0 ? cGuestOSTypeCount : RT_MIN(2, cGuestOSTypeCount);
    4977             for (int i = j == 0 ? 2 : 0; i < cMax; ++i)
    4978             {
    4979                 const CGuestOSType os = guestOSTypes.at(i);
    4980                 const QString strFamilyID = os.GetFamilyId();
    4981                 const QString strFamilyDescription = os.GetFamilyDescription();
    4982                 if (!m_guestOSFamilyIDs.contains(strFamilyID))
    4983                 {
    4984                     m_guestOSFamilyIDs << strFamilyID;
    4985                     m_guestOSFamilyDescriptions[strFamilyID] = strFamilyDescription;
    4986                     m_guestOSTypes << QList<CGuestOSType>();
    4987                 }
    4988                 m_guestOSTypes[m_guestOSFamilyIDs.indexOf(strFamilyID)].append(os);
    4989             }
    4990         }
    4991     }
    4992 
    4993     /* Mark wrappers valid: */
    4994     m_fWrappersValid = true;
    4995 }
     308    return QLocale::system().name();
     309}
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UITranslator.h

    r90939 r90941  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UICommon class implementation.
     3 * VBox Qt GUI - UITranslator class declaration.
    44 */
    55
     
    1717
    1818/* 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>
    3919#include <QTranslator>
    40 #ifdef VBOX_WS_WIN
    41 # include <QEventLoop>
    42 # include <QStyleFactory>
    43 #endif
    44 #ifdef VBOX_WS_X11
    45 # include <QScreen>
    46 # include <QScrollBar>
    47 # include <QTextBrowser>
    48 # include <QX11Info>
    49 #endif
    50 #ifdef VBOX_GUI_WITH_PIDFILE
    51 # include <QTextStream>
    52 #endif
    53 
    54 /* GUI includes: */
    55 #include "QIDialogButtonBox.h"
    56 #include "QIFileDialog.h"
    57 #include "QIMessageBox.h"
    58 #include "QIWithRestorableGeometry.h"
    59 #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"
    68 #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 "UIVirtualBoxClientEventHandler.h"
    75 #include "UIVirtualBoxEventHandler.h"
    76 #include "UIVisoCreator.h"
    77 #include "UIWizardNewVD.h"
    78 #include "VBoxLicenseViewer.h"
    79 #ifdef VBOX_WS_MAC
    80 # include "UIMachineWindowFullscreen.h"
    81 # include "UIMachineWindowSeamless.h"
    82 # include "VBoxUtils-darwin.h"
    83 #endif
    84 #ifdef VBOX_WS_X11
    85 # include "UIHostComboEditor.h"
    86 # include "VBoxX11Helper.h"
    87 #endif
    88 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER
    89 # include "UINetworkRequestManager.h"
    90 # include "UIUpdateManager.h"
    91 #endif
    92 
    93 /* COM includes: */
    94 #include "CAudioAdapter.h"
    95 #include "CBIOSSettings.h"
    96 #include "CCloudMachine.h"
    97 #include "CConsole.h"
    98 #include "CExtPack.h"
    99 #include "CExtPackFile.h"
    100 #include "CExtPackManager.h"
    101 #include "CHostUSBDevice.h"
    102 #include "CHostVideoInputDevice.h"
    103 #include "CMachine.h"
    104 #include "CMediumAttachment.h"
    105 #include "CNetworkAdapter.h"
    106 #include "CSerialPort.h"
    107 #include "CSharedFolder.h"
    108 #include "CSnapshot.h"
    109 #include "CStorageController.h"
    110 #include "CSystemProperties.h"
    111 #include "CUSBController.h"
    112 #include "CUSBDevice.h"
    113 #include "CUSBDeviceFilter.h"
    114 #include "CUSBDeviceFilters.h"
    115 #include "CVRDEServer.h"
    116 
    117 /* Other VBox includes: */
    118 #include <iprt/asm.h>
    119 #include <iprt/ctype.h>
    120 #include <iprt/env.h>
    121 #include <iprt/err.h>
    122 #include <iprt/file.h>
    123 #include <iprt/getopt.h>
    124 #include <iprt/ldr.h>
    125 #include <iprt/param.h>
    126 #include <iprt/path.h>
    127 #include <iprt/stream.h>
    128 #include <iprt/system.h>
    129 #ifdef VBOX_WS_X11
    130 # include <iprt/mem.h>
    131 #endif
    132 #include <VBox/sup.h>
    133 #include <VBox/VBoxOGL.h>
    134 #include <VBox/vd.h>
    135 #include <VBox/com/Guid.h>
    136 
    137 /* VirtualBox interface declarations: */
    138 #include <VBox/com/VirtualBox.h>
    139 
    140 /* External includes: */
    141 #ifdef VBOX_WS_WIN
    142 # include <iprt/win/shlobj.h>
    143 #endif
    144 #ifdef VBOX_WS_X11
    145 # include <xcb/xcb.h>
    146 #endif
    147 
    148 /* External includes: */
    149 #include <math.h>
    150 #ifdef VBOX_WS_MAC
    151 # include <sys/utsname.h>
    152 #endif
    153 #ifdef VBOX_WS_X11
    154 // WORKAROUND:
    155 // typedef CARD8 BOOL in Xmd.h conflicts with #define BOOL PRBool
    156 // in COMDefs.h. A better fix would be to isolate X11-specific
    157 // stuff by placing XX* helpers below to a separate source file.
    158 # undef BOOL
    159 # include <X11/X.h>
    160 # include <X11/Xmd.h>
    161 # include <X11/Xlib.h>
    162 # include <X11/Xatom.h>
    163 # include <X11/Xutil.h>
    164 # include <X11/extensions/Xinerama.h>
    165 # define BOOL PRBool
    166 #endif
    167 
    168 /* Namespaces: */
    169 using namespace UIExtraDataDefs;
    170 using namespace UIMediumDefs;
    171 
    17220
    17321/** QTranslator subclass for VBox needs. */
    174 class VBoxTranslator : public QTranslator
     22class UITranslator : public QTranslator
    17523{
     24    Q_OBJECT;
     25
    17626public:
    17727
    178     /** Constructs translator passing @a pParent to the base-class. */
    179     VBoxTranslator(QObject *pParent = 0)
    180         : QTranslator(pParent)
    181     {}
     28    /** Loads the language by language ID.
     29      * @param  strLangId  Brings the language ID in in form of xx_YY.
     30      *                    QString() means the system default language. */
     31    static void loadLanguage(const QString &strLangId = QString());
    18232
    183     /** Loads language file with gained @a strFileName. */
    184     bool loadFile(const QString &strFileName)
    185     {
    186         QFile file(strFileName);
    187         if (!file.open(QIODevice::ReadOnly))
    188             return false;
    189         m_data = file.readAll();
    190         return load((uchar*)m_data.data(), m_data.size());
    191     }
     33    /** Returns VBox language sub-directory. */
     34    static QString vboxLanguageSubDirectory();
     35    /** Returns VBox language file-base. */
     36    static QString vboxLanguageFileBase();
     37    /** Returns VBox language file-extension. */
     38    static QString vboxLanguageFileExtension();
     39    /** Returns VBox language ID reg-exp. */
     40    static QString vboxLanguageIdRegExp();
     41    /** Returns built in language name. */
     42    static QString vboxBuiltInLanguageName();
     43
     44    /** Returns the loaded (active) language ID. */
     45    static QString languageId();
    19246
    19347private:
    19448
     49    /** Constructs translator passing @a pParent to the base-class. */
     50    UITranslator(QObject *pParent = 0);
     51
     52    /** Loads language file with gained @a strFileName. */
     53    bool loadFile(const QString &strFileName);
     54
     55    /** Native language name of the currently installed translation. */
     56    static QString languageName();
     57    /** Native language country name of the currently installed translation. */
     58    static QString languageCountry();
     59    /** Language name of the currently installed translation, in English. */
     60    static QString languageNameEnglish();
     61    /** Language country name of the currently installed translation, in English. */
     62    static QString languageCountryEnglish();
     63    /** Comma-separated list of authors of the currently installed translation. */
     64    static QString languageTranslators();
     65
     66    /** Returns the system language ID. */
     67    static QString systemLanguageId();
     68
     69    /** Holds the singleton instance. */
     70    static UITranslator *s_pTranslator;
     71    /** Holds the currently loaded language ID. */
     72    static QString       s_strLoadedLanguageId;
     73
    19574    /** Holds the loaded data. */
    196     QByteArray m_data;
     75    QByteArray  m_data;
    19776};
    198 
    199 /** Holds the static #VBoxTranslator instance. */
    200 static VBoxTranslator *sTranslator = 0;
    201 
    202 
    203 /** Port config cache. */
    204 struct PortConfig
    205 {
    206     const char *name;
    207     const ulong IRQ;
    208     const ulong IOBase;
    209 };
    210 
    211 /** Known port config COM ports. */
    212 static const PortConfig kComKnownPorts[] =
    213 {
    214     { "COM1", 4, 0x3F8 },
    215     { "COM2", 3, 0x2F8 },
    216     { "COM3", 4, 0x3E8 },
    217     { "COM4", 3, 0x2E8 },
    218     /* Must not contain an element with IRQ=0 and IOBase=0 used to cause
    219      * toCOMPortName() to return the "User-defined" string for these values. */
    220 };
    221 
    222 /** Known port config LPT ports. */
    223 static const PortConfig kLptKnownPorts[] =
    224 {
    225     { "LPT1", 7, 0x378 },
    226     { "LPT2", 5, 0x278 },
    227     { "LPT1", 2, 0x3BC },
    228     /* Must not contain an element with IRQ=0 and IOBase=0 used to cause
    229      * toLPTPortName() to return the "User-defined" string for these values. */
    230 };
    231 
    232 
    233 /* static */
    234 UICommon *UICommon::s_pInstance = 0;
    235 QString   UICommon::s_strLoadedLanguageId = vboxBuiltInLanguageName();
    236 QString   UICommon::s_strUserDefinedPortName = QString();
    237 
    238 /* static */
    239 void UICommon::create(UIType enmType)
    240 {
    241     /* Make sure instance is NOT created yet: */
    242     AssertReturnVoid(!s_pInstance);
    243 
    244     /* Create instance: */
    245     new UICommon(enmType);
    246     /* Prepare instance: */
    247     s_pInstance->prepare();
    248 }
    249 
    250 /* static */
    251 void UICommon::destroy()
    252 {
    253     /* Make sure instance is NOT destroyed yet: */
    254     AssertPtrReturnVoid(s_pInstance);
    255 
    256     /* Cleanup instance:
    257      * 1. By default, automatically on QApplication::aboutToQuit() signal.
    258      * 2. But if QApplication was not started at all and we perform
    259      *    early shutdown, we should do cleanup ourselves. */
    260     if (s_pInstance->isValid())
    261         s_pInstance->cleanup();
    262     /* Destroy instance: */
    263     delete s_pInstance;
    264 }
    265 
    266 UICommon::UICommon(UIType enmType)
    267     : m_enmType(enmType)
    268     , m_fValid(false)
    269     , m_fCleaningUp(false)
    270 #ifdef VBOX_WS_WIN
    271     , m_fDataCommitted(false)
    272 #endif
    273 #ifdef VBOX_WS_MAC
    274     , m_enmMacOSVersion(MacOSXRelease_Old)
    275 #endif
    276 #ifdef VBOX_WS_X11
    277     , m_enmWindowManagerType(X11WMType_Unknown)
    278     , m_fCompositingManagerRunning(false)
    279 #endif
    280     , m_fSeparateProcess(false)
    281     , m_fShowStartVMErrors(true)
    282 #if defined(DEBUG_bird)
    283     , m_fAgressiveCaching(false)
    284 #else
    285     , m_fAgressiveCaching(true)
    286 #endif
    287     , m_fRestoreCurrentSnapshot(false)
    288     , m_fDisablePatm(false)
    289     , m_fDisableCsam(false)
    290     , m_fRecompileSupervisor(false)
    291     , m_fRecompileUser(false)
    292     , m_fExecuteAllInIem(false)
    293     , m_uWarpPct(100)
    294 #ifdef VBOX_WITH_DEBUGGER_GUI
    295     , m_fDbgEnabled(0)
    296     , m_fDbgAutoShow(0)
    297     , m_fDbgAutoShowCommandLine(0)
    298     , m_fDbgAutoShowStatistics(0)
    299     , m_hVBoxDbg(NIL_RTLDRMOD)
    300     , m_enmLaunchRunning(LaunchRunning_Default)
    301 #endif
    302     , m_fSettingsPwSet(false)
    303     , m_fWrappersValid(false)
    304     , m_fVBoxSVCAvailable(true)
    305     , m_pThreadPool(0)
    306     , m_pThreadPoolCloud(0)
    307     , m_pIconPool(0)
    308     , m_pMediumEnumerator(0)
    309 {
    310     /* Assign instance: */
    311     s_pInstance = this;
    312 }
    313 
    314 UICommon::~UICommon()
    315 {
    316     /* Unassign instance: */
    317     s_pInstance = 0;
    318 }
    319 
    320 void UICommon::prepare()
    321 {
    322     /* Make sure QApplication cleanup us on exit: */
    323     qApp->setFallbackSessionManagementEnabled(false);
    324     connect(qApp, &QGuiApplication::aboutToQuit,
    325             this, &UICommon::sltCleanup);
    326 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1
    327     /* Make sure we handle host OS session shutdown as well: */
    328     connect(qApp, &QGuiApplication::commitDataRequest,
    329             this, &UICommon::sltHandleCommitDataRequest);
    330 #endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
    331 
    332 #ifdef VBOX_WS_MAC
    333     /* Determine OS release early: */
    334     m_enmMacOSVersion = determineOsRelease();
    335 #endif /* VBOX_WS_MAC */
    336 
    337     /* Create converter: */
    338     UIConverter::create();
    339 
    340     /* Create desktop-widget watchdog: */
    341     UIDesktopWidgetWatchdog::create();
    342 
    343     /* Create message-center: */
    344     UIMessageCenter::create();
    345     /* Create popup-center: */
    346     UIPopupCenter::create();
    347 
    348     /* Prepare general icon-pool: */
    349     m_pIconPool = new UIIconPoolGeneral;
    350 
    351     /* Load translation based on the current locale: */
    352     loadLanguage();
    353 
    354     HRESULT rc = COMBase::InitializeCOM(true);
    355     if (FAILED(rc))
    356     {
    357 #ifdef VBOX_WITH_XPCOM
    358         if (rc == NS_ERROR_FILE_ACCESS_DENIED)
    359         {
    360             char szHome[RTPATH_MAX] = "";
    361             com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome));
    362             msgCenter().cannotInitUserHome(QString(szHome));
    363         }
    364         else
    365 #endif
    366             msgCenter().cannotInitCOM(rc);
    367         return;
    368     }
    369 
    370     /* Make sure VirtualBoxClient instance created: */
    371     m_comVBoxClient.createInstance(CLSID_VirtualBoxClient);
    372     if (!m_comVBoxClient.isOk())
    373     {
    374         msgCenter().cannotCreateVirtualBoxClient(m_comVBoxClient);
    375         return;
    376     }
    377     /* Make sure VirtualBox instance acquired: */
    378     m_comVBox = m_comVBoxClient.GetVirtualBox();
    379     if (!m_comVBoxClient.isOk())
    380     {
    381         msgCenter().cannotAcquireVirtualBox(m_comVBoxClient);
    382         return;
    383     }
    384     /* Init wrappers: */
    385     comWrappersReinit();
    386 
    387     /* Watch for the VBoxSVC availability changes: */
    388     connect(gVBoxClientEvents, &UIVirtualBoxClientEventHandler::sigVBoxSVCAvailabilityChange,
    389             this, &UICommon::sltHandleVBoxSVCAvailabilityChange);
    390 
    391     /* Prepare thread-pool instances: */
    392     m_pThreadPool = new UIThreadPool(3 /* worker count */, 5000 /* worker timeout */);
    393     m_pThreadPoolCloud = new UIThreadPool(2 /* worker count */, 1000 /* worker timeout */);
    394 
    395 #ifdef VBOX_WS_WIN
    396     /* Load color theme: */
    397     loadColorTheme();
    398 #endif
    399 
    400     /* Load translation based on the user settings: */
    401     QString sLanguageId = gEDataManager->languageId();
    402     if (!sLanguageId.isNull())
    403         loadLanguage(sLanguageId);
    404 
    405     retranslateUi();
    406 
    407     connect(gEDataManager, &UIExtraDataManager::sigLanguageChange,
    408             this, &UICommon::sltGUILanguageChange);
    409 
    410     qApp->installEventFilter(this);
    411 
    412     /* process command line */
    413 
    414     UIVisualStateType visualStateType = UIVisualStateType_Invalid;
    415 
    416 #ifdef VBOX_WS_X11
    417     /* Check whether we have compositing manager running: */
    418     m_fCompositingManagerRunning = X11IsCompositingManagerRunning();
    419 
    420     /* Acquire current Window Manager type: */
    421     m_enmWindowManagerType = X11WindowManagerType();
    422 #endif /* VBOX_WS_X11 */
    423 
    424 #ifdef VBOX_WITH_DEBUGGER_GUI
    425 # ifdef VBOX_WITH_DEBUGGER_GUI_MENU
    426     initDebuggerVar(&m_fDbgEnabled, "VBOX_GUI_DBG_ENABLED", GUI_Dbg_Enabled, true);
    427 # else
    428     initDebuggerVar(&m_fDbgEnabled, "VBOX_GUI_DBG_ENABLED", GUI_Dbg_Enabled, false);
    429 # endif
    430     initDebuggerVar(&m_fDbgAutoShow, "VBOX_GUI_DBG_AUTO_SHOW", GUI_Dbg_AutoShow, false);
    431     m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = m_fDbgAutoShow;
    432 #endif
    433 
    434     /*
    435      * Parse the command line options.
    436      *
    437      * This is a little sloppy but we're trying to tighten it up.  Unfortuately,
    438      * both on X11 and darwin (IIRC) there might be additional arguments aimed
    439      * for client libraries with GUI processes.  So, using RTGetOpt or similar
    440      * is a bit hard since we have to cope with unknown options.
    441      */
    442     m_fShowStartVMErrors = true;
    443     bool startVM = false;
    444     bool fSeparateProcess = false;
    445     QString vmNameOrUuid;
    446 
    447     const QStringList &arguments = QCoreApplication::arguments();
    448     const int argc = arguments.size();
    449     int i = 1;
    450     while (i < argc)
    451     {
    452         const QByteArray &argBytes = arguments.at(i).toUtf8();
    453         const char *arg = argBytes.constData();
    454         enum { OptType_Unknown, OptType_VMRunner, OptType_VMSelector, OptType_MaybeBoth } enmOptType = OptType_Unknown;
    455         /* NOTE: the check here must match the corresponding check for the
    456          * options to start a VM in main.cpp and hardenedmain.cpp exactly,
    457          * otherwise there will be weird error messages. */
    458         if (   !::strcmp(arg, "--startvm")
    459             || !::strcmp(arg, "-startvm"))
    460         {
    461             enmOptType = OptType_VMRunner;
    462             if (++i < argc)
    463             {
    464                 vmNameOrUuid = arguments.at(i);
    465                 startVM = true;
    466             }
    467         }
    468         else if (!::strcmp(arg, "-separate") || !::strcmp(arg, "--separate"))
    469         {
    470             enmOptType = OptType_VMRunner;
    471             fSeparateProcess = true;
    472         }
    473 #ifdef VBOX_GUI_WITH_PIDFILE
    474         else if (!::strcmp(arg, "-pidfile") || !::strcmp(arg, "--pidfile"))
    475         {
    476             enmOptType = OptType_MaybeBoth;
    477             if (++i < argc)
    478                 m_strPidFile = arguments.at(i);
    479         }
    480 #endif /* VBOX_GUI_WITH_PIDFILE */
    481         /* Visual state type options: */
    482         else if (!::strcmp(arg, "-normal") || !::strcmp(arg, "--normal"))
    483         {
    484             enmOptType = OptType_MaybeBoth;
    485             visualStateType = UIVisualStateType_Normal;
    486         }
    487         else if (!::strcmp(arg, "-fullscreen") || !::strcmp(arg, "--fullscreen"))
    488         {
    489             enmOptType = OptType_MaybeBoth;
    490             visualStateType = UIVisualStateType_Fullscreen;
    491         }
    492         else if (!::strcmp(arg, "-seamless") || !::strcmp(arg, "--seamless"))
    493         {
    494             enmOptType = OptType_MaybeBoth;
    495             visualStateType = UIVisualStateType_Seamless;
    496         }
    497         else if (!::strcmp(arg, "-scale") || !::strcmp(arg, "--scale"))
    498         {
    499             enmOptType = OptType_MaybeBoth;
    500             visualStateType = UIVisualStateType_Scale;
    501         }
    502         /* Passwords: */
    503         else if (!::strcmp(arg, "--settingspw"))
    504         {
    505             enmOptType = OptType_MaybeBoth;
    506             if (++i < argc)
    507             {
    508                 RTStrCopy(m_astrSettingsPw, sizeof(m_astrSettingsPw), arguments.at(i).toLocal8Bit().constData());
    509                 m_fSettingsPwSet = true;
    510             }
    511         }
    512         else if (!::strcmp(arg, "--settingspwfile"))
    513         {
    514             enmOptType = OptType_MaybeBoth;
    515             if (++i < argc)
    516             {
    517                 const QByteArray &argFileBytes = arguments.at(i).toLocal8Bit();
    518                 const char *pszFile = argFileBytes.constData();
    519                 bool fStdIn = !::strcmp(pszFile, "stdin");
    520                 int vrc = VINF_SUCCESS;
    521                 PRTSTREAM pStrm;
    522                 if (!fStdIn)
    523                     vrc = RTStrmOpen(pszFile, "r", &pStrm);
    524                 else
    525                     pStrm = g_pStdIn;
    526                 if (RT_SUCCESS(vrc))
    527                 {
    528                     size_t cbFile;
    529                     vrc = RTStrmReadEx(pStrm, m_astrSettingsPw, sizeof(m_astrSettingsPw) - 1, &cbFile);
    530                     if (RT_SUCCESS(vrc))
    531                     {
    532                         if (cbFile >= sizeof(m_astrSettingsPw) - 1)
    533                             cbFile = sizeof(m_astrSettingsPw) - 1;
    534                         unsigned i;
    535                         for (i = 0; i < cbFile && !RT_C_IS_CNTRL(m_astrSettingsPw[i]); i++)
    536                             ;
    537                         m_astrSettingsPw[i] = '\0';
    538                         m_fSettingsPwSet = true;
    539                     }
    540                     if (!fStdIn)
    541                         RTStrmClose(pStrm);
    542                 }
    543             }
    544         }
    545         /* Misc options: */
    546         else if (!::strcmp(arg, "-comment") || !::strcmp(arg, "--comment"))
    547         {
    548             enmOptType = OptType_MaybeBoth;
    549             ++i;
    550         }
    551         else if (!::strcmp(arg, "--no-startvm-errormsgbox"))
    552         {
    553             enmOptType = OptType_VMRunner;
    554             m_fShowStartVMErrors = false;
    555         }
    556         else if (!::strcmp(arg, "--aggressive-caching"))
    557         {
    558             enmOptType = OptType_MaybeBoth;
    559             m_fAgressiveCaching = true;
    560         }
    561         else if (!::strcmp(arg, "--no-aggressive-caching"))
    562         {
    563             enmOptType = OptType_MaybeBoth;
    564             m_fAgressiveCaching = false;
    565         }
    566         else if (!::strcmp(arg, "--restore-current"))
    567         {
    568             enmOptType = OptType_VMRunner;
    569             m_fRestoreCurrentSnapshot = true;
    570         }
    571         /* Ad hoc VM reconfig options: */
    572         else if (!::strcmp(arg, "--fda"))
    573         {
    574             enmOptType = OptType_VMRunner;
    575             if (++i < argc)
    576                 m_strFloppyImage = arguments.at(i);
    577         }
    578         else if (!::strcmp(arg, "--dvd") || !::strcmp(arg, "--cdrom"))
    579         {
    580             enmOptType = OptType_VMRunner;
    581             if (++i < argc)
    582                 m_strDvdImage = arguments.at(i);
    583         }
    584         /* VMM Options: */
    585         else if (!::strcmp(arg, "--disable-patm"))
    586         {
    587             enmOptType = OptType_VMRunner;
    588             m_fDisablePatm = true;
    589         }
    590         else if (!::strcmp(arg, "--disable-csam"))
    591         {
    592             enmOptType = OptType_VMRunner;
    593             m_fDisableCsam = true;
    594         }
    595         else if (!::strcmp(arg, "--recompile-supervisor"))
    596         {
    597             enmOptType = OptType_VMRunner;
    598             m_fRecompileSupervisor = true;
    599         }
    600         else if (!::strcmp(arg, "--recompile-user"))
    601         {
    602             enmOptType = OptType_VMRunner;
    603             m_fRecompileUser = true;
    604         }
    605         else if (!::strcmp(arg, "--recompile-all"))
    606         {
    607             enmOptType = OptType_VMRunner;
    608             m_fDisablePatm = m_fDisableCsam = m_fRecompileSupervisor = m_fRecompileUser = true;
    609         }
    610         else if (!::strcmp(arg, "--execute-all-in-iem"))
    611         {
    612             enmOptType = OptType_VMRunner;
    613             m_fDisablePatm = m_fDisableCsam = m_fExecuteAllInIem = true;
    614         }
    615         else if (!::strcmp(arg, "--warp-pct"))
    616         {
    617             enmOptType = OptType_VMRunner;
    618             if (++i < argc)
    619                 m_uWarpPct = RTStrToUInt32(arguments.at(i).toLocal8Bit().constData());
    620         }
    621 #ifdef VBOX_WITH_DEBUGGER_GUI
    622         /* Debugger/Debugging options: */
    623         else if (!::strcmp(arg, "-dbg") || !::strcmp(arg, "--dbg"))
    624         {
    625             enmOptType = OptType_VMRunner;
    626             setDebuggerVar(&m_fDbgEnabled, true);
    627         }
    628         else if (!::strcmp( arg, "-debug") || !::strcmp(arg, "--debug"))
    629         {
    630             enmOptType = OptType_VMRunner;
    631             setDebuggerVar(&m_fDbgEnabled, true);
    632             setDebuggerVar(&m_fDbgAutoShow, true);
    633             setDebuggerVar(&m_fDbgAutoShowCommandLine, true);
    634             setDebuggerVar(&m_fDbgAutoShowStatistics, true);
    635         }
    636         else if (!::strcmp(arg, "--debug-command-line"))
    637         {
    638             enmOptType = OptType_VMRunner;
    639             setDebuggerVar(&m_fDbgEnabled, true);
    640             setDebuggerVar(&m_fDbgAutoShow, true);
    641             setDebuggerVar(&m_fDbgAutoShowCommandLine, true);
    642         }
    643         else if (!::strcmp(arg, "--debug-statistics"))
    644         {
    645             enmOptType = OptType_VMRunner;
    646             setDebuggerVar(&m_fDbgEnabled, true);
    647             setDebuggerVar(&m_fDbgAutoShow, true);
    648             setDebuggerVar(&m_fDbgAutoShowStatistics, true);
    649         }
    650         else if (!::strcmp(arg, "--statistics-expand") || !::strcmp(arg, "--stats-expand"))
    651         {
    652             enmOptType = OptType_VMRunner;
    653             if (++i < argc)
    654             {
    655                 if (!m_strDbgStatisticsExpand.isEmpty())
    656                     m_strDbgStatisticsExpand.append('|');
    657                 m_strDbgStatisticsExpand.append(arguments.at(i));
    658             }
    659         }
    660         else if (!::strncmp(arg, RT_STR_TUPLE("--statistics-expand=")) || !::strncmp(arg, RT_STR_TUPLE("--stats-expand=")))
    661         {
    662             enmOptType = OptType_VMRunner;
    663             if (!m_strDbgStatisticsExpand.isEmpty())
    664                 m_strDbgStatisticsExpand.append('|');
    665             m_strDbgStatisticsExpand.append(arguments.at(i).section('=', 1));
    666         }
    667         else if (!::strcmp(arg, "--statistics-filter") || !::strcmp(arg, "--stats-filter"))
    668         {
    669             enmOptType = OptType_VMRunner;
    670             if (++i < argc)
    671                 m_strDbgStatisticsFilter = arguments.at(i);
    672         }
    673         else if (!::strncmp(arg, RT_STR_TUPLE("--statistics-filter=")) || !::strncmp(arg, RT_STR_TUPLE("--stats-filter=")))
    674         {
    675             enmOptType = OptType_VMRunner;
    676             m_strDbgStatisticsFilter = arguments.at(i).section('=', 1);
    677         }
    678         else if (!::strcmp(arg, "-no-debug") || !::strcmp(arg, "--no-debug"))
    679         {
    680             enmOptType = OptType_VMRunner;
    681             setDebuggerVar(&m_fDbgEnabled, false);
    682             setDebuggerVar(&m_fDbgAutoShow, false);
    683             setDebuggerVar(&m_fDbgAutoShowCommandLine, false);
    684             setDebuggerVar(&m_fDbgAutoShowStatistics, false);
    685         }
    686         /* Not quite debug options, but they're only useful with the debugger bits. */
    687         else if (!::strcmp(arg, "--start-paused"))
    688         {
    689             enmOptType = OptType_VMRunner;
    690             m_enmLaunchRunning = LaunchRunning_No;
    691         }
    692         else if (!::strcmp(arg, "--start-running"))
    693         {
    694             enmOptType = OptType_VMRunner;
    695             m_enmLaunchRunning = LaunchRunning_Yes;
    696         }
    697 #endif
    698         if (enmOptType == OptType_VMRunner && m_enmType != UIType_RuntimeUI)
    699             msgCenter().warnAboutUnrelatedOptionType(arg);
    700 
    701         i++;
    702     }
    703 
    704     if (m_enmType == UIType_RuntimeUI && startVM)
    705     {
    706         /* m_fSeparateProcess makes sense only if a VM is started. */
    707         m_fSeparateProcess = fSeparateProcess;
    708 
    709         /* Search for corresponding VM: */
    710         QUuid uuid = QUuid(vmNameOrUuid);
    711         const CMachine machine = m_comVBox.FindMachine(vmNameOrUuid);
    712         if (!uuid.isNull())
    713         {
    714             if (machine.isNull() && showStartVMErrors())
    715                 return msgCenter().cannotFindMachineById(m_comVBox, vmNameOrUuid);
    716         }
    717         else
    718         {
    719             if (machine.isNull() && showStartVMErrors())
    720                 return msgCenter().cannotFindMachineByName(m_comVBox, vmNameOrUuid);
    721         }
    722         m_strManagedVMId = machine.GetId();
    723 
    724         if (m_fSeparateProcess)
    725         {
    726             /* Create a log file for VirtualBoxVM process. */
    727             QString str = machine.GetLogFolder();
    728             com::Utf8Str logDir(str.toUtf8().constData());
    729 
    730             /* make sure the Logs folder exists */
    731             if (!RTDirExists(logDir.c_str()))
    732                 RTDirCreateFullPath(logDir.c_str(), 0700);
    733 
    734             com::Utf8Str logFile = com::Utf8StrFmt("%s%cVBoxUI.log",
    735                                                    logDir.c_str(), RTPATH_DELIMITER);
    736 
    737             com::VBoxLogRelCreate("GUI (separate)", logFile.c_str(),
    738                                   RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_RESTRICT_GROUPS,
    739                                   "all all.restrict -default.restrict",
    740                                   "VBOX_RELEASE_LOG", RTLOGDEST_FILE,
    741                                   32768 /* cMaxEntriesPerGroup */,
    742                                   0 /* cHistory */, 0 /* uHistoryFileTime */,
    743                                   0 /* uHistoryFileSize */, NULL);
    744         }
    745     }
    746 
    747     /* For Selector UI: */
    748     if (uiType() == UIType_SelectorUI)
    749     {
    750         /* We should create separate logging file for VM selector: */
    751         char szLogFile[RTPATH_MAX];
    752         const char *pszLogFile = NULL;
    753         com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
    754         RTPathAppend(szLogFile, sizeof(szLogFile), "selectorwindow.log");
    755         pszLogFile = szLogFile;
    756         /* Create release logger, to file: */
    757         com::VBoxLogRelCreate("GUI VM Selector Window",
    758                               pszLogFile,
    759                               RTLOGFLAGS_PREFIX_TIME_PROG,
    760                               "all",
    761                               "VBOX_GUI_SELECTORWINDOW_RELEASE_LOG",
    762                               RTLOGDEST_FILE | RTLOGDEST_F_NO_DENY,
    763                               UINT32_MAX,
    764                               10,
    765                               60 * 60,
    766                               _1M,
    767                               NULL /*pErrInfo*/);
    768 
    769         LogRel(("Qt version: %s\n", qtRTVersionString().toUtf8().constData()));
    770     }
    771 
    772     if (m_fSettingsPwSet)
    773         m_comVBox.SetSettingsSecret(m_astrSettingsPw);
    774 
    775     if (visualStateType != UIVisualStateType_Invalid && !m_strManagedVMId.isNull())
    776         gEDataManager->setRequestedVisualState(visualStateType, m_strManagedVMId);
    777 
    778 #ifdef VBOX_WITH_DEBUGGER_GUI
    779     /* For Runtime UI: */
    780     if (uiType() == UIType_RuntimeUI)
    781     {
    782         /* Setup the debugger GUI: */
    783         if (RTEnvExist("VBOX_GUI_NO_DEBUGGER"))
    784             m_fDbgEnabled = m_fDbgAutoShow =  m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = false;
    785         if (m_fDbgEnabled)
    786         {
    787             RTERRINFOSTATIC ErrInfo;
    788             RTErrInfoInitStatic(&ErrInfo);
    789             int vrc = SUPR3HardenedLdrLoadAppPriv("VBoxDbg", &m_hVBoxDbg, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
    790             if (RT_FAILURE(vrc))
    791             {
    792                 m_hVBoxDbg = NIL_RTLDRMOD;
    793                 m_fDbgAutoShow = m_fDbgAutoShowCommandLine = m_fDbgAutoShowStatistics = false;
    794                 LogRel(("Failed to load VBoxDbg, rc=%Rrc - %s\n", vrc, ErrInfo.Core.pszMsg));
    795             }
    796         }
    797     }
    798 #endif
    799 
    800     m_fValid = true;
    801 
    802     /* Create medium-enumerator but don't do any immediate caching: */
    803     m_pMediumEnumerator = new UIMediumEnumerator;
    804     {
    805         /* Prepare medium-enumerator: */
    806         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumCreated,
    807                 this, &UICommon::sigMediumCreated);
    808         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumDeleted,
    809                 this, &UICommon::sigMediumDeleted);
    810         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerationStarted,
    811                 this, &UICommon::sigMediumEnumerationStarted);
    812         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerated,
    813                 this, &UICommon::sigMediumEnumerated);
    814         connect(m_pMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerationFinished,
    815                 this, &UICommon::sigMediumEnumerationFinished);
    816     }
    817 
    818     /* Create shortcut pool: */
    819     UIShortcutPool::create();
    820 
    821 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER
    822     /* Create network manager: */
    823     UINetworkRequestManager::create();
    824 
    825     /* Schedule update manager: */
    826     UIUpdateManager::schedule();
    827 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
    828 
    829 #ifdef RT_OS_LINUX
    830     /* Make sure no wrong USB mounted: */
    831     checkForWrongUSBMounted();
    832 #endif /* RT_OS_LINUX */
    833 
    834     /* Populate the list of medium names to be excluded from the
    835        recently used media extra data: */
    836 #if 0 /* bird: This is counter productive as it is _frequently_ necessary to re-insert the
    837                viso to refresh the files (like after you rebuilt them on the host).
    838                The guest caches ISOs aggressively and files sizes may change. */
    839     m_recentMediaExcludeList << "ad-hoc.viso";
    840 #endif
    841 }
    842 
    843 void UICommon::cleanup()
    844 {
    845     LogRel(("GUI: UICommon: Handling aboutToQuit request..\n"));
    846 
    847     /// @todo Shouldn't that be protected with a mutex or something?
    848     /* Remember that the cleanup is in progress preventing any unwanted
    849      * stuff which could be called from the other threads: */
    850     m_fCleaningUp = true;
    851 
    852 #ifdef VBOX_WS_WIN
    853     /* Ask listeners to commit data if haven't yet: */
    854     if (!m_fDataCommitted)
    855     {
    856         emit sigAskToCommitData();
    857         m_fDataCommitted = true;
    858     }
    859 #else
    860     /* Ask listeners to commit data: */
    861     emit sigAskToCommitData();
    862 #endif
    863 
    864 #ifdef VBOX_WITH_DEBUGGER_GUI
    865     /* For Runtime UI: */
    866     if (   uiType() == UIType_RuntimeUI
    867         && m_hVBoxDbg != NIL_RTLDRMOD)
    868     {
    869         RTLdrClose(m_hVBoxDbg);
    870         m_hVBoxDbg = NIL_RTLDRMOD;
    871     }
    872 #endif
    873 
    874 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER
    875     /* Shutdown update manager: */
    876     UIUpdateManager::shutdown();
    877 
    878     /* Destroy network manager: */
    879     UINetworkRequestManager::destroy();
    880 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
    881 
    882     /* Destroy shortcut pool: */
    883     UIShortcutPool::destroy();
    884 
    885 #ifdef VBOX_GUI_WITH_PIDFILE
    886     deletePidfile();
    887 #endif /* VBOX_GUI_WITH_PIDFILE */
    888 
    889     /* Starting medium-enumerator cleanup: */
    890     m_meCleanupProtectionToken.lockForWrite();
    891     {
    892         /* Destroy medium-enumerator: */
    893         delete m_pMediumEnumerator;
    894         m_pMediumEnumerator = 0;
    895     }
    896     /* Finishing medium-enumerator cleanup: */
    897     m_meCleanupProtectionToken.unlock();
    898 
    899     /* Destroy the global (VirtualBox and VirtualBoxClient) Main event
    900      * handlers which are used in both Manager and Runtime UIs. */
    901     UIVirtualBoxEventHandler::destroy();
    902     UIVirtualBoxClientEventHandler::destroy();
    903 
    904     /* Destroy the extra-data manager finally after everything
    905      * above which could use it already destroyed: */
    906     UIExtraDataManager::destroy();
    907 
    908     /* Destroy converter: */
    909     UIConverter::destroy();
    910 
    911     /* Cleanup thread-pools: */
    912     delete m_pThreadPool;
    913     m_pThreadPool = 0;
    914     delete m_pThreadPoolCloud;
    915     m_pThreadPoolCloud = 0;
    916     /* Cleanup general icon-pool: */
    917     delete m_pIconPool;
    918     m_pIconPool = 0;
    919 
    920     /* Ensure CGuestOSType objects are no longer used: */
    921     m_guestOSFamilyIDs.clear();
    922     m_guestOSTypes.clear();
    923 
    924     /* Starting COM cleanup: */
    925     m_comCleanupProtectionToken.lockForWrite();
    926     {
    927         /* First, make sure we don't use COM any more: */
    928         emit sigAskToDetachCOM();
    929         m_comHost.detach();
    930         m_comVBox.detach();
    931         m_comVBoxClient.detach();
    932 
    933         /* There may be UIMedium(s)EnumeratedEvent instances still in the message
    934          * queue which reference COM objects. Remove them to release those objects
    935          * before uninitializing the COM subsystem. */
    936         QApplication::removePostedEvents(this);
    937 
    938         /* Finally cleanup COM itself: */
    939         COMBase::CleanupCOM();
    940     }
    941     /* Finishing COM cleanup: */
    942     m_comCleanupProtectionToken.unlock();
    943 
    944     /* Notify listener it can close UI now: */
    945     emit sigAskToCloseUI();
    946 
    947     /* Destroy popup-center: */
    948     UIPopupCenter::destroy();
    949     /* Destroy message-center: */
    950     UIMessageCenter::destroy();
    951 
    952     /* Destroy desktop-widget watchdog: */
    953     UIDesktopWidgetWatchdog::destroy();
    954 
    955     m_fValid = false;
    956 
    957     LogRel(("GUI: UICommon: aboutToQuit request handled!\n"));
    958 }
    959 
    960 /* static */
    961 QString UICommon::qtRTVersionString()
    962 {
    963     return QString::fromLatin1(qVersion());
    964 }
    965 
    966 /* static */
    967 uint UICommon::qtRTVersion()
    968 {
    969     const QString strVersionRT = UICommon::qtRTVersionString();
    970     return (strVersionRT.section('.', 0, 0).toInt() << 16) +
    971            (strVersionRT.section('.', 1, 1).toInt() << 8) +
    972            strVersionRT.section('.', 2, 2).toInt();
    973 }
    974 
    975 /* static */
    976 uint UICommon::qtRTMajorVersion()
    977 {
    978     return UICommon::qtRTVersionString().section('.', 0, 0).toInt();
    979 }
    980 
    981 /* static */
    982 uint UICommon::qtRTMinorVersion()
    983 {
    984     return UICommon::qtRTVersionString().section('.', 1, 1).toInt();
    985 }
    986 
    987 /* static */
    988 uint UICommon::qtRTRevisionNumber()
    989 {
    990     return UICommon::qtRTVersionString().section('.', 2, 2).toInt();
    991 }
    992 
    993 /* static */
    994 QString UICommon::qtCTVersionString()
    995 {
    996     return QString::fromLatin1(QT_VERSION_STR);
    997 }
    998 
    999 /* static */
    1000 uint UICommon::qtCTVersion()
    1001 {
    1002     const QString strVersionCompiled = UICommon::qtCTVersionString();
    1003     return (strVersionCompiled.section('.', 0, 0).toInt() << 16) +
    1004            (strVersionCompiled.section('.', 1, 1).toInt() << 8) +
    1005            strVersionCompiled.section('.', 2, 2).toInt();
    1006 }
    1007 
    1008 QString UICommon::vboxVersionString() const
    1009 {
    1010     return m_comVBox.GetVersion();
    1011 }
    1012 
    1013 QString UICommon::vboxVersionStringNormalized() const
    1014 {
    1015     return m_comVBox.GetVersionNormalized();
    1016 }
    1017 
    1018 bool UICommon::isBeta() const
    1019 {
    1020     return vboxVersionString().contains("BETA", Qt::CaseInsensitive);
    1021 }
    1022 
    1023 #ifdef VBOX_WS_MAC
    1024 /* static */
    1025 MacOSXRelease UICommon::determineOsRelease()
    1026 {
    1027     /* Prepare 'utsname' struct: */
    1028     utsname info;
    1029     if (uname(&info) != -1)
    1030     {
    1031         /* Compose map of known releases: */
    1032         QMap<int, MacOSXRelease> release;
    1033         release[10] = MacOSXRelease_SnowLeopard;
    1034         release[11] = MacOSXRelease_Lion;
    1035         release[12] = MacOSXRelease_MountainLion;
    1036         release[13] = MacOSXRelease_Mavericks;
    1037         release[14] = MacOSXRelease_Yosemite;
    1038         release[15] = MacOSXRelease_ElCapitan;
    1039 
    1040         /* Cut the major release index of the string we have, s.a. 'man uname': */
    1041         const int iRelease = QString(info.release).section('.', 0, 0).toInt();
    1042 
    1043         /* Return release if determined, return 'New' if version more recent than latest, return 'Old' otherwise: */
    1044         return release.value(iRelease, iRelease > release.keys().last() ? MacOSXRelease_New : MacOSXRelease_Old);
    1045     }
    1046     /* Return 'Old' by default: */
    1047     return MacOSXRelease_Old;
    1048 }
    1049 #endif /* VBOX_WS_MAC */
    1050 
    1051 bool UICommon::brandingIsActive(bool fForce /* = false */)
    1052 {
    1053     if (fForce)
    1054         return true;
    1055 
    1056     if (m_strBrandingConfigFilePath.isEmpty())
    1057     {
    1058         m_strBrandingConfigFilePath = QDir(QApplication::applicationDirPath()).absolutePath();
    1059         m_strBrandingConfigFilePath += "/custom/custom.ini";
    1060     }
    1061 
    1062     return QFile::exists(m_strBrandingConfigFilePath);
    1063 }
    1064 
    1065 QString UICommon::brandingGetKey(QString strKey)
    1066 {
    1067     QSettings settings(m_strBrandingConfigFilePath, QSettings::IniFormat);
    1068     return settings.value(QString("%1").arg(strKey)).toString();
    1069 }
    1070 
    1071 bool UICommon::processArgs()
    1072 {
    1073     /* Among those arguments: */
    1074     bool fResult = false;
    1075     const QStringList args = qApp->arguments();
    1076 
    1077     /* We are looking for a list of file URLs passed to the executable: */
    1078     QList<QUrl> listArgUrls;
    1079     for (int i = 1; i < args.size(); ++i)
    1080     {
    1081         /* But we break out after the first parameter, cause there
    1082          * could be parameters with arguments (e.g. --comment comment). */
    1083         if (args.at(i).startsWith("-"))
    1084             break;
    1085 
    1086 #ifdef VBOX_WS_MAC
    1087         const QString strArg = ::darwinResolveAlias(args.at(i));
    1088 #else
    1089         const QString strArg = args.at(i);
    1090 #endif
    1091 
    1092         /* So if the argument file exists, we add it to URL list: */
    1093         if (   !strArg.isEmpty()
    1094             && QFile::exists(strArg))
    1095             listArgUrls << QUrl::fromLocalFile(QFileInfo(strArg).absoluteFilePath());
    1096     }
    1097 
    1098     /* If there are file URLs: */
    1099     if (!listArgUrls.isEmpty())
    1100     {
    1101         /* We enumerate them and: */
    1102         for (int i = 0; i < listArgUrls.size(); ++i)
    1103         {
    1104             /* Check which of them has allowed VM extensions: */
    1105             const QUrl url = listArgUrls.at(i);
    1106             const QString strFile = url.toLocalFile();
    1107             if (UICommon::hasAllowedExtension(strFile, VBoxFileExts))
    1108             {
    1109                 /* So that we could run existing VMs: */
    1110                 CVirtualBox comVBox = virtualBox();
    1111                 CMachine comMachine = comVBox.FindMachine(strFile);
    1112                 if (!comMachine.isNull())
    1113                 {
    1114                     fResult = true;
    1115                     launchMachine(comMachine);
    1116                     /* And remove their URLs from the ULR list: */
    1117                     listArgUrls.removeAll(url);
    1118                 }
    1119             }
    1120         }
    1121     }
    1122 
    1123     /* And if there are *still* URLs: */
    1124     if (!listArgUrls.isEmpty())
    1125     {
    1126         /* We store them, they will be handled later: */
    1127         m_listArgUrls = listArgUrls;
    1128     }
    1129 
    1130     return fResult;
    1131 }
    1132 
    1133 bool UICommon::argumentUrlsPresent() const
    1134 {
    1135     return !m_listArgUrls.isEmpty();
    1136 }
    1137 
    1138 QList<QUrl> UICommon::takeArgumentUrls()
    1139 {
    1140     const QList<QUrl> result = m_listArgUrls;
    1141     m_listArgUrls.clear();
    1142     return result;
    1143 }
    1144 
    1145 #ifdef VBOX_WITH_DEBUGGER_GUI
    1146 
    1147 bool UICommon::isDebuggerEnabled() const
    1148 {
    1149     return isDebuggerWorker(&m_fDbgEnabled, GUI_Dbg_Enabled);
    1150 }
    1151 
    1152 bool UICommon::isDebuggerAutoShowEnabled() const
    1153 {
    1154     return isDebuggerWorker(&m_fDbgAutoShow, GUI_Dbg_AutoShow);
    1155 }
    1156 
    1157 bool UICommon::isDebuggerAutoShowCommandLineEnabled() const
    1158 {
    1159     return isDebuggerWorker(&m_fDbgAutoShowCommandLine, GUI_Dbg_AutoShow);
    1160 }
    1161 
    1162 bool UICommon::isDebuggerAutoShowStatisticsEnabled() const
    1163 {
    1164     return isDebuggerWorker(&m_fDbgAutoShowStatistics, GUI_Dbg_AutoShow);
    1165 }
    1166 
    1167 #endif /* VBOX_WITH_DEBUGGER_GUI */
    1168 
    1169 bool UICommon::shouldStartPaused() const
    1170 {
    1171 #ifdef VBOX_WITH_DEBUGGER_GUI
    1172     return m_enmLaunchRunning == LaunchRunning_Default ? isDebuggerAutoShowEnabled() : m_enmLaunchRunning == LaunchRunning_No;
    1173 #else
    1174     return false;
    1175 #endif
    1176 }
    1177 
    1178 #ifdef VBOX_GUI_WITH_PIDFILE
    1179 
    1180 void UICommon::createPidfile()
    1181 {
    1182     if (!m_strPidFile.isEmpty())
    1183     {
    1184         const qint64 iPid = qApp->applicationPid();
    1185         QFile file(m_strPidFile);
    1186         if (file.open(QIODevice::WriteOnly | QIODevice::Truncate))
    1187         {
    1188              QTextStream out(&file);
    1189              out << iPid << endl;
    1190         }
    1191         else
    1192             LogRel(("Failed to create pid file %s\n", m_strPidFile.toUtf8().constData()));
    1193     }
    1194 }
    1195 
    1196 void UICommon::deletePidfile()
    1197 {
    1198     if (   !m_strPidFile.isEmpty()
    1199         && QFile::exists(m_strPidFile))
    1200         QFile::remove(m_strPidFile);
    1201 }
    1202 
    1203 #endif /* VBOX_GUI_WITH_PIDFILE */
    1204 
    1205 /* static */
    1206 QString UICommon::languageName()
    1207 {
    1208     /* Returns "English" if no translation is installed
    1209      * or if the translation file is invalid. */
    1210     return QApplication::translate("@@@", "English",
    1211                                    "Native language name");
    1212 }
    1213 
    1214 /* static */
    1215 QString UICommon::languageCountry()
    1216 {
    1217     /* Returns "--" if no translation is installed or if the translation file
    1218      * is invalid, or if the language is independent on the country. */
    1219     return QApplication::translate("@@@", "--",
    1220                                    "Native language country name "
    1221                                    "(empty if this language is for all countries)");
    1222 }
    1223 
    1224 /* static */
    1225 QString UICommon::languageNameEnglish()
    1226 {
    1227     /* Returns "English" if no translation is installed
    1228      * or if the translation file is invalid. */
    1229     return QApplication::translate("@@@", "English",
    1230                                    "Language name, in English");
    1231 }
    1232 
    1233 /* static */
    1234 QString UICommon::languageCountryEnglish()
    1235 {
    1236     /* Returns "--" if no translation is installed or if the translation file
    1237      * is invalid, or if the language is independent on the country. */
    1238     return QApplication::translate("@@@", "--",
    1239                                    "Language country name, in English "
    1240                                    "(empty if native country name is empty)");
    1241 }
    1242 
    1243 /* static */
    1244 QString UICommon::languageTranslators()
    1245 {
    1246     /* Returns "Oracle Corporation" if no translation is installed or if the translation file
    1247      * is invalid, or if the translation is supplied by Oracle Corporation. */
    1248     return QApplication::translate("@@@", "Oracle Corporation",
    1249                                    "Comma-separated list of translators");
    1250 }
    1251 
    1252 /* static */
    1253 QString UICommon::vboxLanguageSubDirectory()
    1254 {
    1255     return "/nls";
    1256 }
    1257 
    1258 /* static */
    1259 QString UICommon::vboxLanguageFileBase()
    1260 {
    1261     return "VirtualBox_";
    1262 }
    1263 
    1264 /* static */
    1265 QString UICommon::vboxLanguageFileExtension()
    1266 {
    1267     return ".qm";
    1268 }
    1269 
    1270 /* static */
    1271 QString UICommon::vboxLanguageIdRegExp()
    1272 {
    1273     return "(([a-z]{2})(?:_([A-Z]{2}))?)|(C)";
    1274 }
    1275 
    1276 /* static */
    1277 QString UICommon::vboxBuiltInLanguageName()
    1278 {
    1279     return "C";
    1280 }
    1281 
    1282 /* static */
    1283 QString UICommon::languageId()
    1284 {
    1285     /* Note that it may not match with UIExtraDataManager::languageId() if the specified language cannot be loaded.
    1286      *
    1287      * If the built-in language is active, this method returns "C". "C" is treated as the built-in language for
    1288      * simplicity -- the C locale is used in unix environments as a fallback when the requested locale is invalid.
    1289      * This way we don't need to process both the "built_in" language and the "C" language (which is a valid
    1290      * environment setting) separately. */
    1291 
    1292     return s_strLoadedLanguageId;
    1293 }
    1294 
    1295 /* static */
    1296 QString UICommon::systemLanguageId()
    1297 {
    1298     /* This does exactly the same as QLocale::system().name() but corrects its wrong behavior on Linux systems
    1299      * (LC_NUMERIC for some strange reason takes precedence over any other locale setting in the QLocale::system()
    1300      * implementation). This implementation first looks at LC_ALL (as defined by SUS), then looks at LC_MESSAGES
    1301      * which is designed to define a language for program messages in case if it differs from the language for
    1302      * other locale categories. Then it looks for LANG and finally falls back to QLocale::system().name().
    1303      *
    1304      * The order of precedence is well defined here:
    1305      * http://opengroup.org/onlinepubs/007908799/xbd/envvar.html
    1306      *
    1307      * This method will return "C" when the requested locale is invalid or when the "C" locale is set explicitly. */
    1308 
    1309 #if defined(VBOX_WS_MAC)
    1310     /* QLocale return the right id only if the user select the format
    1311      * of the language also. So we use our own implementation */
    1312     return ::darwinSystemLanguage();
    1313 #elif defined(Q_OS_UNIX)
    1314     const char *pszValue = RTEnvGet("LC_ALL");
    1315     if (pszValue == 0)
    1316         pszValue = RTEnvGet("LC_MESSAGES");
    1317     if (pszValue == 0)
    1318         pszValue = RTEnvGet("LANG");
    1319     if (pszValue != 0)
    1320         return QLocale(pszValue).name();
    1321 #endif
    1322     return QLocale::system().name();
    1323 }
    1324 
    1325 #ifdef VBOX_WS_WIN
    1326 /* static */
    1327 void UICommon::loadColorTheme()
    1328 {
    1329     /* Load saved color theme: */
    1330     UIColorThemeType enmColorTheme = gEDataManager->colorTheme();
    1331 
    1332     /* Check whether we have dark system theme requested: */
    1333     if (enmColorTheme == UIColorThemeType_Auto)
    1334     {
    1335         QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
    1336                            QSettings::NativeFormat);
    1337         if (settings.value("AppsUseLightTheme") == 0)
    1338             enmColorTheme = UIColorThemeType_Dark;
    1339     }
    1340 
    1341     /* Check whether dark theme was requested by any means: */
    1342     if (enmColorTheme == UIColorThemeType_Dark)
    1343     {
    1344         qApp->setStyle(QStyleFactory::create("Fusion"));
    1345         QPalette darkPalette;
    1346         QColor windowColor1 = QColor(59, 60, 61);
    1347         QColor windowColor2 = QColor(63, 64, 65);
    1348         QColor baseColor1 = QColor(46, 47, 48);
    1349         QColor baseColor2 = QColor(56, 57, 58);
    1350         QColor disabledColor = QColor(113, 114, 115);
    1351         darkPalette.setColor(QPalette::Window, windowColor1);
    1352         darkPalette.setColor(QPalette::WindowText, Qt::white);
    1353         darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, disabledColor);
    1354         darkPalette.setColor(QPalette::Base, baseColor1);
    1355         darkPalette.setColor(QPalette::AlternateBase, baseColor2);
    1356         darkPalette.setColor(QPalette::PlaceholderText, disabledColor);
    1357         darkPalette.setColor(QPalette::Text, Qt::white);
    1358         darkPalette.setColor(QPalette::Disabled, QPalette::Text, disabledColor);
    1359         darkPalette.setColor(QPalette::Button, windowColor2);
    1360         darkPalette.setColor(QPalette::ButtonText, Qt::white);
    1361         darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, disabledColor);
    1362         darkPalette.setColor(QPalette::BrightText, Qt::red);
    1363         darkPalette.setColor(QPalette::Link, QColor(179, 214, 242));
    1364         darkPalette.setColor(QPalette::Highlight, QColor(29, 84, 92));
    1365         darkPalette.setColor(QPalette::HighlightedText, Qt::white);
    1366         darkPalette.setColor(QPalette::Disabled, QPalette::HighlightedText, disabledColor);
    1367         qApp->setPalette(darkPalette);
    1368         qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2b2b2b; border: 1px solid #737373; }");
    1369     }
    1370 }
    1371 #endif /* VBOX_WS_WIN */
    1372 
    1373 /* static */
    1374 void UICommon::loadLanguage(const QString &strLangId)
    1375 {
    1376     QString strEffectiveLangId = strLangId.isEmpty()
    1377                                ? UICommon::systemLanguageId()
    1378                                : strLangId;
    1379     QString strLanguageFileName;
    1380     QString strSelectedLangId = vboxBuiltInLanguageName();
    1381 
    1382     /* If C is selected we change it temporary to en. This makes sure any extra
    1383      * "en" translation file will be loaded. This is necessary for loading the
    1384      * plural forms of some of our translations. */
    1385     bool fResetToC = false;
    1386     if (strEffectiveLangId == "C")
    1387     {
    1388         strEffectiveLangId = "en";
    1389         fResetToC = true;
    1390     }
    1391 
    1392     char szNlsPath[RTPATH_MAX];
    1393     int rc;
    1394 
    1395     rc = RTPathAppPrivateNoArch(szNlsPath, sizeof(szNlsPath));
    1396     AssertRC(rc);
    1397 
    1398     QString strNlsPath = QString(szNlsPath) + vboxLanguageSubDirectory();
    1399     QDir nlsDir(strNlsPath);
    1400 
    1401     Assert(!strEffectiveLangId.isEmpty());
    1402     if (!strEffectiveLangId.isEmpty() && strEffectiveLangId != vboxBuiltInLanguageName())
    1403     {
    1404         QRegExp regExp(vboxLanguageIdRegExp());
    1405         int iPos = regExp.indexIn(strEffectiveLangId);
    1406         /* The language ID should match the regexp completely: */
    1407         AssertReturnVoid(iPos == 0);
    1408 
    1409         QString strStrippedLangId = regExp.cap(2);
    1410 
    1411         if (nlsDir.exists(vboxLanguageFileBase() + strEffectiveLangId + vboxLanguageFileExtension()))
    1412         {
    1413             strLanguageFileName = nlsDir.absoluteFilePath(vboxLanguageFileBase() +
    1414                                                           strEffectiveLangId +
    1415                                                           vboxLanguageFileExtension());
    1416             strSelectedLangId = strEffectiveLangId;
    1417         }
    1418         else if (nlsDir.exists(vboxLanguageFileBase() + strStrippedLangId + vboxLanguageFileExtension()))
    1419         {
    1420             strLanguageFileName = nlsDir.absoluteFilePath(vboxLanguageFileBase() +
    1421                                                           strStrippedLangId +
    1422                                                           vboxLanguageFileExtension());
    1423             strSelectedLangId = strStrippedLangId;
    1424         }
    1425         else
    1426         {
    1427             /* Never complain when the default language is requested.  In any
    1428              * case, if no explicit language file exists, we will simply
    1429              * fall-back to English (built-in). */
    1430             if (!strLangId.isNull() && strEffectiveLangId != "en")
    1431                 msgCenter().cannotFindLanguage(strEffectiveLangId, strNlsPath);
    1432             /* strSelectedLangId remains built-in here: */
    1433             AssertReturnVoid(strSelectedLangId == vboxBuiltInLanguageName());
    1434         }
    1435     }
    1436 
    1437     /* Delete the old translator if there is one: */
    1438     if (sTranslator)
    1439     {
    1440         /* QTranslator destructor will call qApp->removeTranslator() for
    1441          * us. It will also delete all its child translations we attach to it
    1442          * below, so we don't have to care about them specially. */
    1443         delete sTranslator;
    1444     }
    1445 
    1446     /* Load new language files: */
    1447     sTranslator = new VBoxTranslator(qApp);
    1448     Assert(sTranslator);
    1449     bool fLoadOk = true;
    1450     if (sTranslator)
    1451     {
    1452         if (strSelectedLangId != vboxBuiltInLanguageName())
    1453         {
    1454             Assert(!strLanguageFileName.isNull());
    1455             fLoadOk = sTranslator->loadFile(strLanguageFileName);
    1456         }
    1457         /* We install the translator in any case: on failure, this will
    1458          * activate an empty translator that will give us English (built-in): */
    1459         qApp->installTranslator(sTranslator);
    1460     }
    1461     else
    1462         fLoadOk = false;
    1463 
    1464     if (fLoadOk)
    1465         s_strLoadedLanguageId = strSelectedLangId;
    1466     else
    1467     {
    1468         msgCenter().cannotLoadLanguage(strLanguageFileName);
    1469         s_strLoadedLanguageId = vboxBuiltInLanguageName();
    1470     }
    1471 
    1472     /* Try to load the corresponding Qt translation: */
    1473     if (languageId() != vboxBuiltInLanguageName() && languageId() != "en")
    1474     {
    1475 #ifdef Q_OS_UNIX
    1476         /* We use system installations of Qt on Linux systems, so first, try
    1477          * to load the Qt translation from the system location. */
    1478         strLanguageFileName = QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" +
    1479                               languageId() + vboxLanguageFileExtension();
    1480         QTranslator *pQtSysTr = new QTranslator(sTranslator);
    1481         Assert(pQtSysTr);
    1482         if (pQtSysTr && pQtSysTr->load(strLanguageFileName))
    1483             qApp->installTranslator(pQtSysTr);
    1484         /* Note that the Qt translation supplied by Oracle is always loaded
    1485          * afterwards to make sure it will take precedence over the system
    1486          * translation (it may contain more decent variants of translation
    1487          * that better correspond to VirtualBox UI). We need to load both
    1488          * because a newer version of Qt may be installed on the user computer
    1489          * and the Oracle version may not fully support it. We don't do it on
    1490          * Win32 because we supply a Qt library there and therefore the
    1491          * Oracle translation is always the best one. */
    1492 #endif
    1493         strLanguageFileName = nlsDir.absoluteFilePath(QString("qt_") +
    1494                                                       languageId() +
    1495                                                       vboxLanguageFileExtension());
    1496         QTranslator *pQtTr = new QTranslator(sTranslator);
    1497         Assert(pQtTr);
    1498         if (pQtTr && (fLoadOk = pQtTr->load(strLanguageFileName)))
    1499             qApp->installTranslator(pQtTr);
    1500         /* The below message doesn't fit 100% (because it's an additional
    1501          * language and the main one won't be reset to built-in on failure)
    1502          * but the load failure is so rare here that it's not worth a separate
    1503          * message (but still, having something is better than having none) */
    1504         if (!fLoadOk && !strLangId.isNull())
    1505             msgCenter().cannotLoadLanguage(strLanguageFileName);
    1506     }
    1507     if (fResetToC)
    1508         s_strLoadedLanguageId = vboxBuiltInLanguageName();
    1509 #ifdef VBOX_WS_MAC
    1510     /* Qt doesn't translate the items in the Application menu initially.
    1511      * Manually trigger an update. */
    1512     ::darwinRetranslateAppMenu();
    1513 #endif
    1514 }
    1515 
    1516 /* static */
    1517 QString UICommon::yearsToString(uint32_t cVal)
    1518 {
    1519     return QApplication::translate("UICommon", "%n year(s)", "", cVal);
    1520 }
    1521 
    1522 /* static */
    1523 QString UICommon::monthsToString(uint32_t cVal)
    1524 {
    1525     return QApplication::translate("UICommon", "%n month(s)", "", cVal);
    1526 }
    1527 
    1528 /* static */
    1529 QString UICommon::daysToString(uint32_t cVal)
    1530 {
    1531     return QApplication::translate("UICommon", "%n day(s)", "", cVal);
    1532 }
    1533 
    1534 /* static */
    1535 QString UICommon::hoursToString(uint32_t cVal)
    1536 {
    1537     return QApplication::translate("UICommon", "%n hour(s)", "", cVal);
    1538 }
    1539 
    1540 /* static */
    1541 QString UICommon::minutesToString(uint32_t cVal)
    1542 {
    1543     return QApplication::translate("UICommon", "%n minute(s)", "", cVal);
    1544 }
    1545 
    1546 /* static */
    1547 QString UICommon::secondsToString(uint32_t cVal)
    1548 {
    1549     return QApplication::translate("UICommon", "%n second(s)", "", cVal);
    1550 }
    1551 
    1552 /* static */
    1553 QChar UICommon::decimalSep()
    1554 {
    1555     return QLocale::system().decimalPoint();
    1556 }
    1557 
    1558 /* static */
    1559 QString UICommon::sizeRegexp()
    1560 {
    1561     /* This regexp will capture 5 groups of text:
    1562      * - cap(1): integer number in case when no decimal point is present
    1563      *           (if empty, it means that decimal point is present)
    1564      * - cap(2): size suffix in case when no decimal point is present (may be empty)
    1565      * - cap(3): integer number in case when decimal point is present (may be empty)
    1566      * - cap(4): fraction number (hundredth) in case when decimal point is present
    1567      * - cap(5): size suffix in case when decimal point is present (note that
    1568      *           B cannot appear there). */
    1569 
    1570     const QString strRegexp =
    1571         QString("^(?:(?:(\\d+)(?:\\s?(%2|%3|%4|%5|%6|%7))?)|(?:(\\d*)%1(\\d{1,2})(?:\\s?(%3|%4|%5|%6|%7))))$")
    1572             .arg(decimalSep())
    1573             .arg(tr("B", "size suffix Bytes"))
    1574             .arg(tr("KB", "size suffix KBytes=1024 Bytes"))
    1575             .arg(tr("MB", "size suffix MBytes=1024 KBytes"))
    1576             .arg(tr("GB", "size suffix GBytes=1024 MBytes"))
    1577             .arg(tr("TB", "size suffix TBytes=1024 GBytes"))
    1578             .arg(tr("PB", "size suffix PBytes=1024 TBytes"));
    1579     return strRegexp;
    1580 }
    1581 
    1582 /* static */
    1583 quint64 UICommon::parseSize(const QString &strText)
    1584 {
    1585     /* Text should be in form of B|KB|MB|GB|TB|PB. */
    1586     QRegExp regexp(sizeRegexp());
    1587     int iPos = regexp.indexIn(strText);
    1588     if (iPos != -1)
    1589     {
    1590         QString strInteger = regexp.cap(1);
    1591         QString strHundred;
    1592         QString strSuff = regexp.cap(2);
    1593         if (strInteger.isEmpty())
    1594         {
    1595             strInteger = regexp.cap(3);
    1596             strHundred = regexp.cap(4);
    1597             strSuff = regexp.cap(5);
    1598         }
    1599 
    1600         quint64 uDenominator = 0;
    1601         if (strSuff.isEmpty() || strSuff == tr("B", "size suffix Bytes"))
    1602             uDenominator = 1;
    1603         else if (strSuff == tr("KB", "size suffix KBytes=1024 Bytes"))
    1604             uDenominator = _1K;
    1605         else if (strSuff == tr("MB", "size suffix MBytes=1024 KBytes"))
    1606             uDenominator = _1M;
    1607         else if (strSuff == tr("GB", "size suffix GBytes=1024 MBytes"))
    1608             uDenominator = _1G;
    1609         else if (strSuff == tr("TB", "size suffix TBytes=1024 GBytes"))
    1610             uDenominator = _1T;
    1611         else if (strSuff == tr("PB", "size suffix PBytes=1024 TBytes"))
    1612             uDenominator = _1P;
    1613 
    1614         quint64 iInteger = strInteger.toULongLong();
    1615         if (uDenominator == 1)
    1616             return iInteger;
    1617 
    1618         quint64 iHundred = strHundred.leftJustified(2, '0').toULongLong();
    1619         iHundred = iHundred * uDenominator / 100;
    1620         iInteger = iInteger * uDenominator + iHundred;
    1621         return iInteger;
    1622     }
    1623     else
    1624         return 0;
    1625 }
    1626 
    1627 /* static */
    1628 SizeSuffix UICommon::parseSizeSuffix(const QString &strText)
    1629 {
    1630     /* Text should be in form of B|KB|MB|GB|TB|PB. */
    1631     QRegExp regexp(sizeRegexp());
    1632     int iPos = regexp.indexIn(strText);
    1633     if (iPos != -1)
    1634     {
    1635         QString strInteger = regexp.cap(1);
    1636         QString strSuff = regexp.cap(2);
    1637         if (strInteger.isEmpty())
    1638         {
    1639             strInteger = regexp.cap(3);
    1640             strSuff = regexp.cap(5);
    1641         }
    1642 
    1643         SizeSuffix enmSizeSuffix = SizeSuffix_Byte;
    1644 
    1645         if (strSuff.isEmpty() || strSuff == tr("B", "size suffix Bytes"))
    1646             enmSizeSuffix = SizeSuffix_Byte;
    1647         else if (strSuff == tr("KB", "size suffix KBytes=1024 Bytes"))
    1648             enmSizeSuffix = SizeSuffix_KiloByte;
    1649         else if (strSuff == tr("MB", "size suffix MBytes=1024 KBytes"))
    1650             enmSizeSuffix = SizeSuffix_MegaByte;
    1651         else if (strSuff == tr("GB", "size suffix GBytes=1024 MBytes"))
    1652             enmSizeSuffix = SizeSuffix_GigaByte;
    1653         else if (strSuff == tr("TB", "size suffix TBytes=1024 GBytes"))
    1654             enmSizeSuffix = SizeSuffix_TeraByte;
    1655         else if (strSuff == tr("PB", "size suffix PBytes=1024 TBytes"))
    1656             enmSizeSuffix = SizeSuffix_PetaByte;
    1657         return enmSizeSuffix;
    1658     }
    1659     else
    1660         return SizeSuffix_Byte;
    1661 }
    1662 
    1663 /* static */
    1664 bool UICommon::hasSizeSuffix(const QString &strText)
    1665 {
    1666     /* Text should be in form of B|KB|MB|GB|TB|PB. */
    1667     QRegExp regexp(sizeRegexp());
    1668     int iPos = regexp.indexIn(strText);
    1669     if (iPos != -1)
    1670     {
    1671         QString strInteger = regexp.cap(1);
    1672         QString strSuff = regexp.cap(2);
    1673         if (strInteger.isEmpty())
    1674         {
    1675             strInteger = regexp.cap(3);
    1676             strSuff = regexp.cap(5);
    1677         }
    1678 
    1679         if (strSuff.isEmpty())
    1680             return false;
    1681         if (strSuff == tr("B", "size suffix Bytes") ||
    1682             strSuff == tr("KB", "size suffix KBytes=1024 Bytes") ||
    1683             strSuff == tr("MB", "size suffix MBytes=1024 KBytes") ||
    1684             strSuff == tr("GB", "size suffix GBytes=1024 MBytes") ||
    1685             strSuff == tr("TB", "size suffix TBytes=1024 GBytes") ||
    1686             strSuff == tr("PB", "size suffix PBytes=1024 TBytes"))
    1687             return true;
    1688         return false;
    1689     }
    1690     else
    1691         return false;
    1692 }
    1693 
    1694 /* static */
    1695 QString UICommon::formatSize(quint64 uSize, uint cDecimal /* = 2 */,
    1696                                FormatSize enmMode /* = FormatSize_Round */)
    1697 {
    1698     /* Text will be in form of B|KB|MB|GB|TB|PB.
    1699      *
    1700      * When enmMode is FormatSize_Round, the result is rounded to the
    1701      *              closest number containing @a aDecimal decimal digits.
    1702      * When enmMode is FormatSize_RoundDown, the result is rounded to the
    1703      *              largest number with @a aDecimal decimal digits that is not greater than
    1704      *              the result. This guarantees that converting the resulting string back to
    1705      *              the integer value in bytes will not produce a value greater that the
    1706      *              initial size parameter.
    1707      * When enmMode is FormatSize_RoundUp, the result is rounded to the
    1708      *              smallest number with @a aDecimal decimal digits that is not less than the
    1709      *              result. This guarantees that converting the resulting string back to the
    1710      *              integer value in bytes will not produce a value less that the initial
    1711      *              size parameter. */
    1712 
    1713     quint64 uDenominator = 0;
    1714     int iSuffix = 0;
    1715 
    1716     if (uSize < _1K)
    1717     {
    1718         uDenominator = 1;
    1719         iSuffix = 0;
    1720     }
    1721     else if (uSize < _1M)
    1722     {
    1723         uDenominator = _1K;
    1724         iSuffix = 1;
    1725     }
    1726     else if (uSize < _1G)
    1727     {
    1728         uDenominator = _1M;
    1729         iSuffix = 2;
    1730     }
    1731     else if (uSize < _1T)
    1732     {
    1733         uDenominator = _1G;
    1734         iSuffix = 3;
    1735     }
    1736     else if (uSize < _1P)
    1737     {
    1738         uDenominator = _1T;
    1739         iSuffix = 4;
    1740     }
    1741     else
    1742     {
    1743         uDenominator = _1P;
    1744         iSuffix = 5;
    1745     }
    1746 
    1747     quint64 uInteger = uSize / uDenominator;
    1748     quint64 uDecimal = uSize % uDenominator;
    1749     quint64 uMult = 1;
    1750     for (uint i = 0; i < cDecimal; ++i)
    1751         uMult *= 10;
    1752 
    1753     QString strNumber;
    1754     if (uDenominator > 1)
    1755     {
    1756         if (uDecimal)
    1757         {
    1758             uDecimal *= uMult;
    1759             /* Not greater: */
    1760             if (enmMode == FormatSize_RoundDown)
    1761                 uDecimal = uDecimal / uDenominator;
    1762             /* Not less: */
    1763             else if (enmMode == FormatSize_RoundUp)
    1764                 uDecimal = (uDecimal + uDenominator - 1) / uDenominator;
    1765             /* Nearest: */
    1766             else
    1767                 uDecimal = (uDecimal + uDenominator / 2) / uDenominator;
    1768         }
    1769         /* Check for the fractional part overflow due to rounding: */
    1770         if (uDecimal == uMult)
    1771         {
    1772             uDecimal = 0;
    1773             ++uInteger;
    1774             /* Check if we've got 1024 XB after rounding and scale down if so: */
    1775             if (uInteger == 1024 && iSuffix + 1 < (int)SizeSuffix_Max)
    1776             {
    1777                 uInteger /= 1024;
    1778                 ++iSuffix;
    1779             }
    1780         }
    1781         strNumber = QString::number(uInteger);
    1782         if (cDecimal)
    1783             strNumber += QString("%1%2").arg(decimalSep())
    1784                                         .arg(QString::number(uDecimal).rightJustified(cDecimal, '0'));
    1785     }
    1786     else
    1787     {
    1788         strNumber = QString::number(uInteger);
    1789     }
    1790 
    1791     return QString("%1 %2").arg(strNumber).arg(gpConverter->toString(static_cast<SizeSuffix>(iSuffix)));
    1792 }
    1793 
    1794 /* static */
    1795 QString UICommon::addMetricSuffixToNumber(quint64 uNumber)
    1796 {
    1797     if (uNumber <= 0)
    1798         return QString();
    1799     /* See https://en.wikipedia.org/wiki/Metric_prefix for metric suffixes:*/
    1800     char suffixes[] = {'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'};
    1801     int zeroCount = (int)log10((long double)uNumber);
    1802     if (zeroCount < 3)
    1803         return QString::number(uNumber);
    1804     int h = 3 * (zeroCount / 3);
    1805     char result[128];
    1806     sprintf(result, "%.2f", uNumber / (float)pow((double)10, h));
    1807     return QString("%1%2").arg(result).arg(suffixes[h / 3 - 1]);
    1808 }
    1809 
    1810 /* static */
    1811 QStringList UICommon::COMPortNames()
    1812 {
    1813     QStringList list;
    1814     for (size_t i = 0; i < RT_ELEMENTS(kComKnownPorts); ++i)
    1815         list << kComKnownPorts[i].name;
    1816 
    1817     return list;
    1818 }
    1819 
    1820 /* static */
    1821 QString UICommon::toCOMPortName(ulong uIRQ, ulong uIOBase)
    1822 {
    1823     for (size_t i = 0; i < RT_ELEMENTS(kComKnownPorts); ++i)
    1824         if (kComKnownPorts[i].IRQ == uIRQ &&
    1825             kComKnownPorts[i].IOBase == uIOBase)
    1826             return kComKnownPorts[i].name;
    1827 
    1828     return s_strUserDefinedPortName;
    1829 }
    1830 
    1831 /* static */
    1832 bool UICommon::toCOMPortNumbers(const QString &strName, ulong &uIRQ, ulong &uIOBase)
    1833 {
    1834     for (size_t i = 0; i < RT_ELEMENTS(kComKnownPorts); ++i)
    1835         if (strcmp(kComKnownPorts[i].name, strName.toUtf8().data()) == 0)
    1836         {
    1837             uIRQ = kComKnownPorts[i].IRQ;
    1838             uIOBase = kComKnownPorts[i].IOBase;
    1839             return true;
    1840         }
    1841 
    1842     return false;
    1843 }
    1844 
    1845 /* static */
    1846 QStringList UICommon::LPTPortNames()
    1847 {
    1848     QStringList list;
    1849     for (size_t i = 0; i < RT_ELEMENTS(kLptKnownPorts); ++i)
    1850         list << kLptKnownPorts[i].name;
    1851 
    1852     return list;
    1853 }
    1854 
    1855 /* static */
    1856 QString UICommon::toLPTPortName(ulong uIRQ, ulong uIOBase)
    1857 {
    1858     for (size_t i = 0; i < RT_ELEMENTS(kLptKnownPorts); ++i)
    1859         if (kLptKnownPorts[i].IRQ == uIRQ &&
    1860             kLptKnownPorts[i].IOBase == uIOBase)
    1861             return kLptKnownPorts[i].name;
    1862 
    1863     return s_strUserDefinedPortName;
    1864 }
    1865 
    1866 /* static */
    1867 bool UICommon::toLPTPortNumbers(const QString &strName, ulong &uIRQ, ulong &uIOBase)
    1868 {
    1869     for (size_t i = 0; i < RT_ELEMENTS(kLptKnownPorts); ++i)
    1870         if (strcmp(kLptKnownPorts[i].name, strName.toUtf8().data()) == 0)
    1871         {
    1872             uIRQ = kLptKnownPorts[i].IRQ;
    1873             uIOBase = kLptKnownPorts[i].IOBase;
    1874             return true;
    1875         }
    1876 
    1877     return false;
    1878 }
    1879 
    1880 /* static */
    1881 QString UICommon::highlight(QString strText, bool fToolTip /* = false */)
    1882 {
    1883     /* We should reformat the input strText so that:
    1884      * - strings in single quotes will be put inside <nobr> and marked
    1885      *   with blue color;
    1886      * - UUIDs be put inside <nobr> and marked
    1887      *   with green color;
    1888      * - replaces new line chars with </p><p> constructs to form paragraphs
    1889      *   (note that <p\> and </p> are not appended to the beginning and to the
    1890      *    end of the string respectively, to allow the result be appended
    1891      *    or prepended to the existing paragraph).
    1892      *
    1893      *  If @a fToolTip is true, colouring is not applied, only the <nobr> tag
    1894      *  is added. Also, new line chars are replaced with <br> instead of <p>. */
    1895 
    1896     QString strFont;
    1897     QString uuidFont;
    1898     QString endFont;
    1899     if (!fToolTip)
    1900     {
    1901         strFont = "<font color=#0000CC>";
    1902         uuidFont = "<font color=#008000>";
    1903         endFont = "</font>";
    1904     }
    1905 
    1906     /* Replace special entities, '&' -- first! */
    1907     strText.replace('&', "&amp;");
    1908     strText.replace('<', "&lt;");
    1909     strText.replace('>', "&gt;");
    1910     strText.replace('\"', "&quot;");
    1911 
    1912     /* Mark strings in single quotes with color: */
    1913     QRegExp rx = QRegExp("((?:^|\\s)[(]?)'([^']*)'(?=[:.-!);]?(?:\\s|$))");
    1914     rx.setMinimal(true);
    1915     strText.replace(rx, QString("\\1%1<nobr>'\\2'</nobr>%2").arg(strFont).arg(endFont));
    1916 
    1917     /* Mark UUIDs with color: */
    1918     strText.replace(QRegExp(
    1919         "((?:^|\\s)[(]?)"
    1920         "(\\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\\})"
    1921         "(?=[:.-!);]?(?:\\s|$))"),
    1922         QString("\\1%1<nobr>\\2</nobr>%2").arg(uuidFont).arg(endFont));
    1923 
    1924     /* Split to paragraphs at \n chars: */
    1925     if (!fToolTip)
    1926         strText.replace('\n', "</p><p>");
    1927     else
    1928         strText.replace('\n', "<br>");
    1929 
    1930     return strText;
    1931 }
    1932 
    1933 /* static */
    1934 QString UICommon::emphasize(QString strText)
    1935 {
    1936     /* We should reformat the input string @a strText so that:
    1937      * - strings in single quotes will be put inside \<nobr\> and marked
    1938      *   with bold style;
    1939      * - UUIDs be put inside \<nobr\> and marked
    1940      *   with italic style;
    1941      * - replaces new line chars with \</p\>\<p\> constructs to form paragraphs
    1942      *   (note that \<p\> and \</p\> are not appended to the beginning and to the
    1943      *    end of the string respectively, to allow the result be appended
    1944      *    or prepended to the existing paragraph). */
    1945 
    1946     QString strEmphStart("<b>");
    1947     QString strEmphEnd("</b>");
    1948     QString uuidEmphStart("<i>");
    1949     QString uuidEmphEnd("</i>");
    1950 
    1951     /* Replace special entities, '&' -- first! */
    1952     strText.replace('&', "&amp;");
    1953     strText.replace('<', "&lt;");
    1954     strText.replace('>', "&gt;");
    1955     strText.replace('\"', "&quot;");
    1956 
    1957     /* Mark strings in single quotes with bold style: */
    1958     QRegExp rx = QRegExp("((?:^|\\s)[(]?)'([^']*)'(?=[:.-!);]?(?:\\s|$))");
    1959     rx.setMinimal(true);
    1960     strText.replace(rx, QString("\\1%1<nobr>'\\2'</nobr>%2").arg(strEmphStart).arg(strEmphEnd));
    1961 
    1962     /* Mark UUIDs with italic style: */
    1963     strText.replace(QRegExp(
    1964         "((?:^|\\s)[(]?)"
    1965         "(\\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\\})"
    1966         "(?=[:.-!);]?(?:\\s|$))"),
    1967         QString("\\1%1<nobr>\\2</nobr>%2").arg(uuidEmphStart).arg(uuidEmphEnd));
    1968 
    1969     /* Split to paragraphs at \n chars: */
    1970     strText.replace('\n', "</p><p>");
    1971 
    1972     return strText;
    1973 }
    1974 
    1975 /* static */
    1976 QString UICommon::removeAccelMark(QString strText)
    1977 {
    1978     /* In order to support accelerators used in non-alphabet languages
    1979      * (e.g. Japanese) that has a form of "(&<L>)" (where <L> is a latin letter),
    1980      * this method first searches for this pattern and, if found, removes it as a
    1981      * whole. If such a pattern is not found, then the '&' character is simply
    1982      * removed from the string. */
    1983 
    1984     QRegExp accel("\\(&[a-zA-Z]\\)");
    1985     int iPos = accel.indexIn(strText);
    1986     if (iPos >= 0)
    1987         strText.remove(iPos, accel.cap().length());
    1988     else
    1989     {
    1990         iPos = strText.indexOf('&');
    1991         if (iPos >= 0)
    1992             strText.remove(iPos, 1);
    1993     }
    1994 
    1995     return strText;
    1996 }
    1997 
    1998 /* static */
    1999 QString UICommon::insertKeyToActionText(const QString &strText, const QString &strKey)
    2000 {
    2001 #ifdef VBOX_WS_MAC
    2002     QString strPattern("%1 (Host+%2)");
    2003 #else
    2004     QString strPattern("%1 \tHost+%2");
    2005 #endif
    2006     if (   strKey.isEmpty()
    2007         || strKey.compare("None", Qt::CaseInsensitive) == 0)
    2008         return strText;
    2009     else
    2010         return strPattern.arg(strText).arg(QKeySequence(strKey).toString(QKeySequence::NativeText));
    2011 }
    2012 
    2013 /* static */
    2014 QString UICommon::helpFile()
    2015 {
    2016 #if defined (VBOX_WITH_QHELP_VIEWER)
    2017     const QString strName = "UserManual";
    2018     const QString strSuffix = "qhc";
    2019 #else
    2020  #if defined(VBOX_WS_WIN)
    2021      const QString strName = "VirtualBox";
    2022      const QString strSuffix = "chm";
    2023  #elif defined(VBOX_WS_MAC)
    2024      const QString strName = "UserManual";
    2025      const QString strSuffix = "pdf";
    2026  #elif defined(VBOX_WS_X11)
    2027      //# if defined(VBOX_OSE) || !defined(VBOX_WITH_KCHMVIEWER)
    2028      const QString strName = "UserManual";
    2029      const QString strSuffix = "pdf";
    2030  #endif
    2031 #endif
    2032     /* Where are the docs located? */
    2033     char szDocsPath[RTPATH_MAX];
    2034     int rc = RTPathAppDocs(szDocsPath, sizeof(szDocsPath));
    2035     AssertRC(rc);
    2036 
    2037     /* Make sure that the language is in two letter code.
    2038      * Note: if languageId() returns an empty string lang.name() will
    2039      * return "C" which is an valid language code. */
    2040     QLocale lang(UICommon::languageId());
    2041 
    2042     /* Construct the path and the filename: */
    2043     QString strManual = QString("%1/%2_%3.%4").arg(szDocsPath)
    2044                                               .arg(strName)
    2045                                               .arg(lang.name())
    2046                                               .arg(strSuffix);
    2047 
    2048     /* Check if a help file with that name exists: */
    2049     QFileInfo fi(strManual);
    2050     if (fi.exists())
    2051         return strManual;
    2052 
    2053     /* Fall back to the standard: */
    2054     strManual = QString("%1/%2.%4").arg(szDocsPath)
    2055                                    .arg(strName)
    2056                                    .arg(strSuffix);
    2057     return strManual;
    2058 }
    2059 
    2060 /* static */
    2061 QString UICommon::documentsPath()
    2062 {
    2063     QString strPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    2064     QDir dir(strPath);
    2065     if (dir.exists())
    2066         return QDir::cleanPath(dir.canonicalPath());
    2067     else
    2068     {
    2069         dir.setPath(QDir::homePath() + "/Documents");
    2070         if (dir.exists())
    2071             return QDir::cleanPath(dir.canonicalPath());
    2072         else
    2073             return QDir::homePath();
    2074     }
    2075 }
    2076 
    2077 /* static */
    2078 bool UICommon::hasAllowedExtension(const QString &strFileName, const QStringList &extensions)
    2079 {
    2080     foreach (const QString &strExtension, extensions)
    2081         if (strFileName.endsWith(strExtension, Qt::CaseInsensitive))
    2082             return true;
    2083     return false;
    2084 }
    2085 
    2086 /* static */
    2087 QString UICommon::findUniqueFileName(const QString &strFullFolderPath, const QString &strBaseFileName)
    2088 {
    2089     QDir folder(strFullFolderPath);
    2090     if (!folder.exists())
    2091         return strBaseFileName;
    2092     QFileInfoList folderContent = folder.entryInfoList();
    2093     QSet<QString> fileNameSet;
    2094     foreach (const QFileInfo &fileInfo, folderContent)
    2095     {
    2096         /* Remove the extension : */
    2097         fileNameSet.insert(fileInfo.completeBaseName());
    2098     }
    2099     int iSuffix = 0;
    2100     QString strNewName(strBaseFileName);
    2101     while (fileNameSet.contains(strNewName))
    2102     {
    2103         strNewName = strBaseFileName + QString("_") + QString::number(++iSuffix);
    2104     }
    2105     return strNewName;
    2106 }
    2107 
    2108 /* static */
    2109 QRect UICommon::normalizeGeometry(const QRect &rectangle, const QRegion &boundRegion, bool fCanResize /* = true */)
    2110 {
    2111     /* Perform direct and flipped search of position for @a rectangle to make sure it is fully contained
    2112      * inside @a boundRegion region by moving & resizing (if @a fCanResize is specified) @a rectangle if
    2113      * necessary. Selects the minimum shifted result between direct and flipped variants. */
    2114 
    2115     /* Direct search for normalized rectangle: */
    2116     QRect var1(getNormalized(rectangle, boundRegion, fCanResize));
    2117 
    2118     /* Flipped search for normalized rectangle: */
    2119     QRect var2(flip(getNormalized(flip(rectangle).boundingRect(),
    2120                                   flip(boundRegion), fCanResize)).boundingRect());
    2121 
    2122     /* Calculate shift from starting position for both variants: */
    2123     double dLength1 = sqrt(pow((double)(var1.x() - rectangle.x()), (double)2) +
    2124                            pow((double)(var1.y() - rectangle.y()), (double)2));
    2125     double dLength2 = sqrt(pow((double)(var2.x() - rectangle.x()), (double)2) +
    2126                            pow((double)(var2.y() - rectangle.y()), (double)2));
    2127 
    2128     /* Return minimum shifted variant: */
    2129     return dLength1 > dLength2 ? var2 : var1;
    2130 }
    2131 
    2132 /* static */
    2133 QRect UICommon::getNormalized(const QRect &rectangle, const QRegion &boundRegion, bool /* fCanResize = true */)
    2134 {
    2135     /* Ensures that the given rectangle @a rectangle is fully contained within the region @a boundRegion
    2136      * by moving @a rectangle if necessary. If @a rectangle is larger than @a boundRegion, top left
    2137      * corner of @a rectangle is aligned with the top left corner of maximum available rectangle and,
    2138      * if @a fCanResize is true, @a rectangle is shrinked to become fully visible. */
    2139 
    2140     /* Storing available horizontal sub-rectangles & vertical shifts: */
    2141     const int iWindowVertical = rectangle.center().y();
    2142     QList<QRect> rectanglesList;
    2143     QList<int> shiftsList;
    2144     foreach (QRect currentItem, boundRegion.rects())
    2145     {
    2146         const int iCurrentDelta = qAbs(iWindowVertical - currentItem.center().y());
    2147         const int iShift2Top = currentItem.top() - rectangle.top();
    2148         const int iShift2Bot = currentItem.bottom() - rectangle.bottom();
    2149 
    2150         int iTtemPosition = 0;
    2151         foreach (QRect item, rectanglesList)
    2152         {
    2153             const int iDelta = qAbs(iWindowVertical - item.center().y());
    2154             if (iDelta > iCurrentDelta)
    2155                 break;
    2156             else
    2157                 ++iTtemPosition;
    2158         }
    2159         rectanglesList.insert(iTtemPosition, currentItem);
    2160 
    2161         int iShift2TopPos = 0;
    2162         foreach (int iShift, shiftsList)
    2163             if (qAbs(iShift) > qAbs(iShift2Top))
    2164                 break;
    2165             else
    2166                 ++iShift2TopPos;
    2167         shiftsList.insert(iShift2TopPos, iShift2Top);
    2168 
    2169         int iShift2BotPos = 0;
    2170         foreach (int iShift, shiftsList)
    2171             if (qAbs(iShift) > qAbs(iShift2Bot))
    2172                 break;
    2173             else
    2174                 ++iShift2BotPos;
    2175         shiftsList.insert(iShift2BotPos, iShift2Bot);
    2176     }
    2177 
    2178     /* Trying to find the appropriate place for window: */
    2179     QRect result;
    2180     for (int i = -1; i < shiftsList.size(); ++i)
    2181     {
    2182         /* Move to appropriate vertical: */
    2183         QRect newRectangle(rectangle);
    2184         if (i >= 0)
    2185             newRectangle.translate(0, shiftsList[i]);
    2186 
    2187         /* Search horizontal shift: */
    2188         int iMaxShift = 0;
    2189         foreach (QRect item, rectanglesList)
    2190         {
    2191             QRect trectangle(newRectangle.translated(item.left() - newRectangle.left(), 0));
    2192             if (!item.intersects(trectangle))
    2193                 continue;
    2194 
    2195             if (newRectangle.left() < item.left())
    2196             {
    2197                 const int iShift = item.left() - newRectangle.left();
    2198                 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift;
    2199             }
    2200             else if (newRectangle.right() > item.right())
    2201             {
    2202                 const int iShift = item.right() - newRectangle.right();
    2203                 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift;
    2204             }
    2205         }
    2206 
    2207         /* Shift across the horizontal direction: */
    2208         newRectangle.translate(iMaxShift, 0);
    2209 
    2210         /* Check the translated rectangle to feat the rules: */
    2211         if (boundRegion.united(newRectangle) == boundRegion)
    2212             result = newRectangle;
    2213 
    2214         if (!result.isNull())
    2215             break;
    2216     }
    2217 
    2218     if (result.isNull())
    2219     {
    2220         /* Resize window to feat desirable size
    2221          * using max of available rectangles: */
    2222         QRect maxRectangle;
    2223         quint64 uMaxSquare = 0;
    2224         foreach (QRect item, rectanglesList)
    2225         {
    2226             const quint64 uSquare = item.width() * item.height();
    2227             if (uSquare > uMaxSquare)
    2228             {
    2229                 uMaxSquare = uSquare;
    2230                 maxRectangle = item;
    2231             }
    2232         }
    2233 
    2234         result = rectangle;
    2235         result.moveTo(maxRectangle.x(), maxRectangle.y());
    2236         if (maxRectangle.right() < result.right())
    2237             result.setRight(maxRectangle.right());
    2238         if (maxRectangle.bottom() < result.bottom())
    2239             result.setBottom(maxRectangle.bottom());
    2240     }
    2241 
    2242     return result;
    2243 }
    2244 
    2245 /* static */
    2246 QRegion UICommon::flip(const QRegion &region)
    2247 {
    2248     QRegion result;
    2249     QVector<QRect> rectangles(region.rects());
    2250     foreach (QRect rectangle, rectangles)
    2251         result += QRect(rectangle.y(), rectangle.x(),
    2252                         rectangle.height(), rectangle.width());
    2253     return result;
    2254 }
    2255 
    2256 /* static */
    2257 void UICommon::centerWidget(QWidget *pWidget, QWidget *pRelative, bool fCanResize /* = true */)
    2258 {
    2259     /* If necessary, pWidget's position is adjusted to make it fully visible within
    2260      * the available desktop area. If pWidget is bigger then this area, it will also
    2261      * be resized unless fCanResize is false or there is an inappropriate minimum
    2262      * size limit (in which case the top left corner will be simply aligned with the top
    2263      * left corner of the available desktop area). pWidget must be a top-level widget.
    2264      * pRelative may be any widget, but if it's not top-level itself, its top-level
    2265      * widget will be used for calculations. pRelative can also be NULL, in which case
    2266      * pWidget will be centered relative to the available desktop area. */
    2267 
    2268     AssertReturnVoid(pWidget);
    2269     AssertReturnVoid(pWidget->isTopLevel());
    2270 
    2271     QRect deskGeo, parentGeo;
    2272     if (pRelative)
    2273     {
    2274         pRelative = pRelative->window();
    2275         deskGeo = gpDesktop->availableGeometry(pRelative);
    2276         parentGeo = pRelative->frameGeometry();
    2277         // WORKAROUND:
    2278         // On X11/Gnome, geo/frameGeo.x() and y() are always 0 for top level
    2279         // widgets with parents, what a shame. Use mapToGlobal() to workaround.
    2280         QPoint d = pRelative->mapToGlobal(QPoint(0, 0));
    2281         d.rx() -= pRelative->geometry().x() - pRelative->x();
    2282         d.ry() -= pRelative->geometry().y() - pRelative->y();
    2283         parentGeo.moveTopLeft(d);
    2284     }
    2285     else
    2286     {
    2287         deskGeo = gpDesktop->availableGeometry();
    2288         parentGeo = deskGeo;
    2289     }
    2290 
    2291     // WORKAROUND:
    2292     // On X11, there is no way to determine frame geometry (including WM
    2293     // decorations) before the widget is shown for the first time. Stupidly
    2294     // enumerate other top level widgets to find the thickest frame. The code
    2295     // is based on the idea taken from QDialog::adjustPositionInternal().
    2296 
    2297     int iExtraW = 0;
    2298     int iExtraH = 0;
    2299 
    2300     QWidgetList list = QApplication::topLevelWidgets();
    2301     QListIterator<QWidget*> it(list);
    2302     while ((iExtraW == 0 || iExtraH == 0) && it.hasNext())
    2303     {
    2304         int iFrameW, iFrameH;
    2305         QWidget *pCurrent = it.next();
    2306         if (!pCurrent->isVisible())
    2307             continue;
    2308 
    2309         iFrameW = pCurrent->frameGeometry().width() - pCurrent->width();
    2310         iFrameH = pCurrent->frameGeometry().height() - pCurrent->height();
    2311 
    2312         iExtraW = qMax(iExtraW, iFrameW);
    2313         iExtraH = qMax(iExtraH, iFrameH);
    2314     }
    2315 
    2316     /* On non-X11 platforms, the following would be enough instead of the above workaround: */
    2317     // QRect geo = frameGeometry();
    2318     QRect geo = QRect(0, 0, pWidget->width() + iExtraW,
    2319                             pWidget->height() + iExtraH);
    2320 
    2321     geo.moveCenter(QPoint(parentGeo.x() + (parentGeo.width() - 1) / 2,
    2322                           parentGeo.y() + (parentGeo.height() - 1) / 2));
    2323 
    2324     /* Ensure the widget is within the available desktop area: */
    2325     QRect newGeo = normalizeGeometry(geo, deskGeo, fCanResize);
    2326 #ifdef VBOX_WS_MAC
    2327     // WORKAROUND:
    2328     // No idea why, but Qt doesn't respect if there is a unified toolbar on the
    2329     // ::move call. So manually add the height of the toolbar before setting
    2330     // the position.
    2331     if (pRelative)
    2332         newGeo.translate(0, ::darwinWindowToolBarHeight(pWidget));
    2333 #endif /* VBOX_WS_MAC */
    2334 
    2335     pWidget->move(newGeo.topLeft());
    2336 
    2337     if (   fCanResize
    2338         && (geo.width() != newGeo.width() || geo.height() != newGeo.height()))
    2339         pWidget->resize(newGeo.width() - iExtraW, newGeo.height() - iExtraH);
    2340 }
    2341 
    2342 #ifdef VBOX_WS_X11
    2343 typedef struct {
    2344 /** User specified flags */
    2345 uint32_t flags;
    2346 /** User-specified position */
    2347 int32_t x, y;
    2348 /** User-specified size */
    2349 int32_t width, height;
    2350 /** Program-specified minimum size */
    2351 int32_t min_width, min_height;
    2352 /** Program-specified maximum size */
    2353 int32_t max_width, max_height;
    2354 /** Program-specified resize increments */
    2355 int32_t width_inc, height_inc;
    2356 /** Program-specified minimum aspect ratios */
    2357 int32_t min_aspect_num, min_aspect_den;
    2358 /** Program-specified maximum aspect ratios */
    2359 int32_t max_aspect_num, max_aspect_den;
    2360 /** Program-specified base size */
    2361 int32_t base_width, base_height;
    2362 /** Program-specified window gravity */
    2363 uint32_t win_gravity;
    2364 } xcb_size_hints_t;
    2365 #endif /* VBOX_WS_X11 */
    2366 
    2367 /* static */
    2368 void UICommon::setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int h)
    2369 {
    2370     AssertPtrReturnVoid(pWidget);
    2371 #ifdef VBOX_WS_X11
    2372 # define QWINDOWSIZE_MAX ((1<<24)-1)
    2373     if (pWidget->isWindow() && pWidget->isVisible())
    2374     {
    2375         // WORKAROUND:
    2376         // X11 window managers are not required to accept geometry changes on
    2377         // the top-level window.  Unfortunately, current at Qt 5.6 and 5.7, Qt
    2378         // assumes that the change will succeed, and resizes all sub-windows
    2379         // unconditionally.  By calling ConfigureWindow directly, Qt will see
    2380         // our change request as an externally triggered one on success and not
    2381         // at all if it is rejected.
    2382         const double dDPR = gpDesktop->devicePixelRatio(pWidget);
    2383         uint16_t fMask =   XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
    2384                          | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
    2385         uint32_t values[] = { (uint32_t)(x * dDPR), (uint32_t)(y * dDPR), (uint32_t)(w * dDPR), (uint32_t)(h * dDPR) };
    2386         xcb_configure_window(QX11Info::connection(), (xcb_window_t)pWidget->winId(),
    2387                              fMask, values);
    2388         xcb_size_hints_t hints;
    2389         hints.flags =   1 /* XCB_ICCCM_SIZE_HINT_US_POSITION */
    2390                       | 2 /* XCB_ICCCM_SIZE_HINT_US_SIZE */
    2391                       | 512 /* XCB_ICCCM_SIZE_P_WIN_GRAVITY */;
    2392         hints.x           = x * dDPR;
    2393         hints.y           = y * dDPR;
    2394         hints.width       = w * dDPR;
    2395         hints.height      = h * dDPR;
    2396         hints.min_width   = pWidget->minimumSize().width() * dDPR;
    2397         hints.min_height  = pWidget->minimumSize().height() * dDPR;
    2398         hints.max_width   = pWidget->maximumSize().width() * dDPR;
    2399         hints.max_height  = pWidget->maximumSize().height() * dDPR;
    2400         hints.width_inc   = pWidget->sizeIncrement().width() * dDPR;
    2401         hints.height_inc  = pWidget->sizeIncrement().height() * dDPR;
    2402         hints.base_width  = pWidget->baseSize().width() * dDPR;
    2403         hints.base_height = pWidget->baseSize().height() * dDPR;
    2404         hints.win_gravity = XCB_GRAVITY_STATIC;
    2405         if (hints.min_width > 0 || hints.min_height > 0)
    2406             hints.flags |= 16 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */;
    2407         if (hints.max_width < QWINDOWSIZE_MAX || hints.max_height < QWINDOWSIZE_MAX)
    2408             hints.flags |= 32 /* XCB_ICCCM_SIZE_HINT_P_MAX_SIZE */;
    2409         if (hints.width_inc > 0 || hints.height_inc)
    2410             hints.flags |=   64 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */
    2411                            | 256 /* XCB_ICCCM_SIZE_HINT_BASE_SIZE */;
    2412         xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE,
    2413                             (xcb_window_t)pWidget->winId(), XCB_ATOM_WM_NORMAL_HINTS,
    2414                             XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) >> 2, &hints);
    2415         xcb_flush(QX11Info::connection());
    2416     }
    2417     else
    2418         // WORKAROUND:
    2419         // Call the Qt method if the window is not visible as otherwise no
    2420         // Configure event will arrive to tell Qt what geometry we want.
    2421         pWidget->setGeometry(x, y, w, h);
    2422 # else /* !VBOX_WS_X11 */
    2423     pWidget->setGeometry(x, y, w, h);
    2424 # endif /* !VBOX_WS_X11 */
    2425 }
    2426 
    2427 /* static */
    2428 void UICommon::setTopLevelGeometry(QWidget *pWidget, const QRect &rect)
    2429 {
    2430     UICommon::setTopLevelGeometry(pWidget, rect.x(), rect.y(), rect.width(), rect.height());
    2431 }
    2432 
    2433 #if defined(VBOX_WS_X11)
    2434 
    2435 static char *XXGetProperty(Display *pDpy, Window windowHandle, Atom propType, const char *pszPropName)
    2436 {
    2437     Atom propNameAtom = XInternAtom(pDpy, pszPropName, True /* only_if_exists */);
    2438     if (propNameAtom == None)
    2439         return NULL;
    2440 
    2441     Atom actTypeAtom = None;
    2442     int actFmt = 0;
    2443     unsigned long nItems = 0;
    2444     unsigned long nBytesAfter = 0;
    2445     unsigned char *propVal = NULL;
    2446     int rc = XGetWindowProperty(pDpy, windowHandle, propNameAtom,
    2447                                 0, LONG_MAX, False /* delete */,
    2448                                 propType, &actTypeAtom, &actFmt,
    2449                                 &nItems, &nBytesAfter, &propVal);
    2450     if (rc != Success)
    2451         return NULL;
    2452 
    2453     return reinterpret_cast<char*>(propVal);
    2454 }
    2455 
    2456 static Bool XXSendClientMessage(Display *pDpy, Window windowHandle, const char *pszMsg,
    2457                                 unsigned long aData0 = 0, unsigned long aData1 = 0,
    2458                                 unsigned long aData2 = 0, unsigned long aData3 = 0,
    2459                                 unsigned long aData4 = 0)
    2460 {
    2461     Atom msgAtom = XInternAtom(pDpy, pszMsg, True /* only_if_exists */);
    2462     if (msgAtom == None)
    2463         return False;
    2464 
    2465     XEvent ev;
    2466 
    2467     ev.xclient.type = ClientMessage;
    2468     ev.xclient.serial = 0;
    2469     ev.xclient.send_event = True;
    2470     ev.xclient.display = pDpy;
    2471     ev.xclient.window = windowHandle;
    2472     ev.xclient.message_type = msgAtom;
    2473 
    2474     /* Always send as 32 bit for now: */
    2475     ev.xclient.format = 32;
    2476     ev.xclient.data.l[0] = aData0;
    2477     ev.xclient.data.l[1] = aData1;
    2478     ev.xclient.data.l[2] = aData2;
    2479     ev.xclient.data.l[3] = aData3;
    2480     ev.xclient.data.l[4] = aData4;
    2481 
    2482     return XSendEvent(pDpy, DefaultRootWindow(pDpy), False,
    2483                       SubstructureRedirectMask, &ev) != 0;
    2484 }
    2485 
    2486 #endif
    2487 
    2488 /* static */
    2489 bool UICommon::activateWindow(WId wId, bool fSwitchDesktop /* = true */)
    2490 {
    2491     RT_NOREF(fSwitchDesktop);
    2492     bool fResult = true;
    2493 
    2494 #if defined(VBOX_WS_WIN)
    2495 
    2496     HWND handle = (HWND)wId;
    2497 
    2498     if (IsIconic(handle))
    2499         fResult &= !!ShowWindow(handle, SW_RESTORE);
    2500     else if (!IsWindowVisible(handle))
    2501         fResult &= !!ShowWindow(handle, SW_SHOW);
    2502 
    2503     fResult &= !!SetForegroundWindow(handle);
    2504 
    2505 #elif defined(VBOX_WS_X11)
    2506 
    2507     Display *pDisplay = QX11Info::display();
    2508 
    2509     if (fSwitchDesktop)
    2510     {
    2511         /* try to find the desktop ID using the NetWM property */
    2512         CARD32 *pDesktop = (CARD32 *) XXGetProperty(pDisplay, wId, XA_CARDINAL,
    2513                                                     "_NET_WM_DESKTOP");
    2514         if (pDesktop == NULL)
    2515             // WORKAROUND:
    2516             // if the NetWM properly is not supported try to find
    2517             // the desktop ID using the GNOME WM property.
    2518             pDesktop = (CARD32 *) XXGetProperty(pDisplay, wId, XA_CARDINAL,
    2519                                                 "_WIN_WORKSPACE");
    2520 
    2521         if (pDesktop != NULL)
    2522         {
    2523             Bool ok = XXSendClientMessage(pDisplay, DefaultRootWindow(pDisplay),
    2524                                           "_NET_CURRENT_DESKTOP",
    2525                                           *pDesktop);
    2526             if (!ok)
    2527             {
    2528                 Log1WarningFunc(("Couldn't switch to pDesktop=%08X\n", pDesktop));
    2529                 fResult = false;
    2530             }
    2531             XFree(pDesktop);
    2532         }
    2533         else
    2534         {
    2535             Log1WarningFunc(("Couldn't find a pDesktop ID for wId=%08X\n", wId));
    2536             fResult = false;
    2537         }
    2538     }
    2539 
    2540     Bool ok = XXSendClientMessage(pDisplay, wId, "_NET_ACTIVE_WINDOW");
    2541     fResult &= !!ok;
    2542 
    2543     XRaiseWindow(pDisplay, wId);
    2544 
    2545 #else
    2546 
    2547     NOREF(wId);
    2548     NOREF(fSwitchDesktop);
    2549     AssertFailed();
    2550     fResult = false;
    2551 
    2552 #endif
    2553 
    2554     if (!fResult)
    2555         Log1WarningFunc(("Couldn't activate wId=%08X\n", wId));
    2556 
    2557     return fResult;
    2558 }
    2559 
    2560 /* static */
    2561 void UICommon::setCursor(QWidget *pWidget, const QCursor &cursor)
    2562 {
    2563     if (!pWidget)
    2564         return;
    2565 
    2566 #ifdef VBOX_WS_X11
    2567     /* As reported in https://www.virtualbox.org/ticket/16348,
    2568      * in X11 QWidget::setCursor(..) call uses RENDER
    2569      * extension. Qt (before 5.11) fails to handle the case where the mentioned extension
    2570      * is missing. Please see https://codereview.qt-project.org/#/c/225665/ for Qt patch: */
    2571     if ((UICommon::qtRTMajorVersion() < 5) ||
    2572         (UICommon::qtRTMajorVersion() == 5 && UICommon::qtRTMinorVersion() < 11))
    2573     {
    2574         if (X11CheckExtension("RENDER"))
    2575             pWidget->setCursor(cursor);
    2576     }
    2577     else
    2578     {
    2579         pWidget->setCursor(cursor);
    2580     }
    2581 #else
    2582     pWidget->setCursor(cursor);
    2583 #endif
    2584 }
    2585 
    2586 /* static */
    2587 void UICommon::setCursor(QGraphicsWidget *pWidget, const QCursor &cursor)
    2588 {
    2589     if (!pWidget)
    2590         return;
    2591 
    2592 #ifdef VBOX_WS_X11
    2593     /* As reported in https://www.virtualbox.org/ticket/16348,
    2594      * in X11 QGraphicsWidget::setCursor(..) call uses RENDER
    2595      * extension. Qt (before 5.11) fails to handle the case where the mentioned extension
    2596      * is missing. Please see https://codereview.qt-project.org/#/c/225665/ for Qt patch: */
    2597     if ((UICommon::qtRTMajorVersion() < 5) ||
    2598         (UICommon::qtRTMajorVersion() == 5 && UICommon::qtRTMinorVersion() < 11))
    2599     {
    2600         if (X11CheckExtension("RENDER"))
    2601             pWidget->setCursor(cursor);
    2602     }
    2603     else
    2604     {
    2605         pWidget->setCursor(cursor);
    2606     }
    2607 #else
    2608     pWidget->setCursor(cursor);
    2609 #endif
    2610 }
    2611 
    2612 /* static */
    2613 void UICommon::unsetCursor(QWidget *pWidget)
    2614 {
    2615     if (!pWidget)
    2616         return;
    2617 
    2618 #ifdef VBOX_WS_X11
    2619     /* As reported in https://www.virtualbox.org/ticket/16348,
    2620      * in X11 QWidget::unsetCursor(..) call uses RENDER
    2621      * extension. Qt (before 5.11) fails to handle the case where the mentioned extension
    2622      * is missing. Please see https://codereview.qt-project.org/#/c/225665/ for Qt patch: */
    2623     if ((UICommon::qtRTMajorVersion() < 5) ||
    2624         (UICommon::qtRTMajorVersion() == 5 && UICommon::qtRTMinorVersion() < 11))
    2625     {
    2626         if (X11CheckExtension("RENDER"))
    2627             pWidget->unsetCursor();
    2628     }
    2629     else
    2630     {
    2631         pWidget->unsetCursor();
    2632     }
    2633 #else
    2634     pWidget->unsetCursor();
    2635 #endif
    2636 }
    2637 
    2638 /* static */
    2639 void UICommon::unsetCursor(QGraphicsWidget *pWidget)
    2640 {
    2641     if (!pWidget)
    2642         return;
    2643 
    2644 #ifdef VBOX_WS_X11
    2645     /* As reported in https://www.virtualbox.org/ticket/16348,
    2646      * in X11 QGraphicsWidget::unsetCursor(..) call uses RENDER
    2647      * extension. Qt (before 5.11) fails to handle the case where the mentioned extension
    2648      * is missing. Please see https://codereview.qt-project.org/#/c/225665/ for Qt patch: */
    2649     if ((UICommon::qtRTMajorVersion() < 5) ||
    2650         (UICommon::qtRTMajorVersion() == 5 && UICommon::qtRTMinorVersion() < 11))
    2651     {
    2652         if (X11CheckExtension("RENDER"))
    2653             pWidget->unsetCursor();
    2654     }
    2655     else
    2656     {
    2657         pWidget->unsetCursor();
    2658     }
    2659 #else
    2660     pWidget->unsetCursor();
    2661 #endif
    2662 }
    2663 
    2664 
    2665 #if defined(VBOX_WS_X11)
    2666 
    2667 /* static */
    2668 bool UICommon::supportsFullScreenMonitorsProtocolX11()
    2669 {
    2670     /* This method tests whether the current X11 window manager supports full-screen mode as we need it.
    2671      * Unfortunately the EWMH specification was not fully clear about whether we can expect to find
    2672      * all of these atoms on the _NET_SUPPORTED root window property, so we have to test with all
    2673      * interesting window managers. If this fails for a user when you think it should succeed
    2674      * they should try executing:
    2675      * xprop -root | egrep -w '_NET_WM_FULLSCREEN_MONITORS|_NET_WM_STATE|_NET_WM_STATE_FULLSCREEN'
    2676      * in an X11 terminal window.
    2677      * All three strings should be found under a property called "_NET_SUPPORTED(ATOM)". */
    2678 
    2679     /* Using a global to get at the display does not feel right, but that is how it is done elsewhere in the code. */
    2680     Display *pDisplay = QX11Info::display();
    2681     Atom atomSupported            = XInternAtom(pDisplay, "_NET_SUPPORTED",
    2682                                                 True /* only_if_exists */);
    2683     Atom atomWMFullScreenMonitors = XInternAtom(pDisplay,
    2684                                                 "_NET_WM_FULLSCREEN_MONITORS",
    2685                                                 True /* only_if_exists */);
    2686     Atom atomWMState              = XInternAtom(pDisplay,
    2687                                                 "_NET_WM_STATE",
    2688                                                 True /* only_if_exists */);
    2689     Atom atomWMStateFullScreen    = XInternAtom(pDisplay,
    2690                                                 "_NET_WM_STATE_FULLSCREEN",
    2691                                                 True /* only_if_exists */);
    2692     bool fFoundFullScreenMonitors = false;
    2693     bool fFoundState              = false;
    2694     bool fFoundStateFullScreen    = false;
    2695     Atom atomType;
    2696     int cFormat;
    2697     unsigned long cItems;
    2698     unsigned long cbLeft;
    2699     Atom *pAtomHints;
    2700     int rc;
    2701     unsigned i;
    2702 
    2703     if (   atomSupported == None || atomWMFullScreenMonitors == None
    2704         || atomWMState == None || atomWMStateFullScreen == None)
    2705         return false;
    2706     /* Get atom value: */
    2707     rc = XGetWindowProperty(pDisplay, DefaultRootWindow(pDisplay),
    2708                             atomSupported, 0, 0x7fffffff /*LONG_MAX*/,
    2709                             False /* delete */, XA_ATOM, &atomType,
    2710                             &cFormat, &cItems, &cbLeft,
    2711                             (unsigned char **)&pAtomHints);
    2712     if (rc != Success)
    2713         return false;
    2714     if (pAtomHints == NULL)
    2715         return false;
    2716     if (atomType == XA_ATOM && cFormat == 32 && cbLeft == 0)
    2717         for (i = 0; i < cItems; ++i)
    2718         {
    2719             if (pAtomHints[i] == atomWMFullScreenMonitors)
    2720                 fFoundFullScreenMonitors = true;
    2721             if (pAtomHints[i] == atomWMState)
    2722                 fFoundState = true;
    2723             if (pAtomHints[i] == atomWMStateFullScreen)
    2724                 fFoundStateFullScreen = true;
    2725         }
    2726     XFree(pAtomHints);
    2727     return fFoundFullScreenMonitors && fFoundState && fFoundStateFullScreen;
    2728 }
    2729 
    2730 /* static */
    2731 bool UICommon::setFullScreenMonitorX11(QWidget *pWidget, ulong uScreenId)
    2732 {
    2733     return XXSendClientMessage(QX11Info::display(),
    2734                                pWidget->window()->winId(),
    2735                                "_NET_WM_FULLSCREEN_MONITORS",
    2736                                uScreenId, uScreenId, uScreenId, uScreenId,
    2737                                1 /* Source indication (1 = normal application) */);
    2738 }
    2739 
    2740 /* static */
    2741 QVector<Atom> UICommon::flagsNetWmState(QWidget *pWidget)
    2742 {
    2743     /* Get display: */
    2744     Display *pDisplay = QX11Info::display();
    2745 
    2746     /* Prepare atoms: */
    2747     QVector<Atom> resultNetWmState;
    2748     Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
    2749 
    2750     /* Get the size of the property data: */
    2751     Atom actual_type;
    2752     int iActualFormat;
    2753     ulong uPropertyLength;
    2754     ulong uBytesLeft;
    2755     uchar *pPropertyData = 0;
    2756     if (XGetWindowProperty(pDisplay, pWidget->window()->winId(),
    2757                            net_wm_state, 0, 0, False, XA_ATOM, &actual_type, &iActualFormat,
    2758                            &uPropertyLength, &uBytesLeft, &pPropertyData) == Success &&
    2759         actual_type == XA_ATOM && iActualFormat == 32)
    2760     {
    2761         resultNetWmState.resize(uBytesLeft / 4);
    2762         XFree((char*)pPropertyData);
    2763         pPropertyData = 0;
    2764 
    2765         /* Fetch all data: */
    2766         if (XGetWindowProperty(pDisplay, pWidget->window()->winId(),
    2767                                net_wm_state, 0, resultNetWmState.size(), False, XA_ATOM, &actual_type, &iActualFormat,
    2768                                &uPropertyLength, &uBytesLeft, &pPropertyData) != Success)
    2769             resultNetWmState.clear();
    2770         else if (uPropertyLength != (ulong)resultNetWmState.size())
    2771             resultNetWmState.resize(uPropertyLength);
    2772 
    2773         /* Put it into resultNetWmState: */
    2774         if (!resultNetWmState.isEmpty())
    2775             memcpy(resultNetWmState.data(), pPropertyData, resultNetWmState.size() * sizeof(Atom));
    2776         if (pPropertyData)
    2777             XFree((char*)pPropertyData);
    2778     }
    2779 
    2780     /* Return result: */
    2781     return resultNetWmState;
    2782 }
    2783 
    2784 /* static */
    2785 bool UICommon::isFullScreenFlagSet(QWidget *pWidget)
    2786 {
    2787     /* Get display: */
    2788     Display *pDisplay = QX11Info::display();
    2789 
    2790     /* Prepare atoms: */
    2791     Atom net_wm_state_fullscreen = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", True /* only if exists */);
    2792 
    2793     /* Check if flagsNetWmState(pWidget) contains full-screen flag: */
    2794     return flagsNetWmState(pWidget).contains(net_wm_state_fullscreen);
    2795 }
    2796 
    2797 /* static */
    2798 void UICommon::setFullScreenFlag(QWidget *pWidget)
    2799 {
    2800     /* Get display: */
    2801     Display *pDisplay = QX11Info::display();
    2802 
    2803     /* Prepare atoms: */
    2804     QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
    2805     Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
    2806     Atom net_wm_state_fullscreen = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", True /* only if exists */);
    2807 
    2808     /* Append resultNetWmState with fullscreen flag if necessary: */
    2809     if (!resultNetWmState.contains(net_wm_state_fullscreen))
    2810     {
    2811         resultNetWmState.append(net_wm_state_fullscreen);
    2812         /* Apply property to widget again: */
    2813         XChangeProperty(pDisplay, pWidget->window()->winId(),
    2814                         net_wm_state, XA_ATOM, 32, PropModeReplace,
    2815                         (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
    2816     }
    2817 }
    2818 
    2819 /* static */
    2820 void UICommon::setSkipTaskBarFlag(QWidget *pWidget)
    2821 {
    2822     /* Get display: */
    2823     Display *pDisplay = QX11Info::display();
    2824 
    2825     /* Prepare atoms: */
    2826     QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
    2827     Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
    2828     Atom net_wm_state_skip_taskbar = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", True /* only if exists */);
    2829 
    2830     /* Append resultNetWmState with skip-taskbar flag if necessary: */
    2831     if (!resultNetWmState.contains(net_wm_state_skip_taskbar))
    2832     {
    2833         resultNetWmState.append(net_wm_state_skip_taskbar);
    2834         /* Apply property to widget again: */
    2835         XChangeProperty(pDisplay, pWidget->window()->winId(),
    2836                         net_wm_state, XA_ATOM, 32, PropModeReplace,
    2837                         (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
    2838     }
    2839 }
    2840 
    2841 /* static */
    2842 void UICommon::setSkipPagerFlag(QWidget *pWidget)
    2843 {
    2844     /* Get display: */
    2845     Display *pDisplay = QX11Info::display();
    2846 
    2847     /* Prepare atoms: */
    2848     QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
    2849     Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
    2850     Atom net_wm_state_skip_pager = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_PAGER", True /* only if exists */);
    2851 
    2852     /* Append resultNetWmState with skip-pager flag if necessary: */
    2853     if (!resultNetWmState.contains(net_wm_state_skip_pager))
    2854     {
    2855         resultNetWmState.append(net_wm_state_skip_pager);
    2856         /* Apply property to widget again: */
    2857         XChangeProperty(pDisplay, pWidget->window()->winId(),
    2858                         net_wm_state, XA_ATOM, 32, PropModeReplace,
    2859                         (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
    2860     }
    2861 }
    2862 
    2863 /* static */
    2864 void UICommon::setWMClass(QWidget *pWidget, const QString &strNameString, const QString &strClassString)
    2865 {
    2866     /* Make sure all arguments set: */
    2867     AssertReturnVoid(pWidget && !strNameString.isNull() && !strClassString.isNull());
    2868 
    2869     /* Define QByteArray objects to make sure data is alive within the scope: */
    2870     QByteArray nameByteArray;
    2871     /* Check the existence of RESOURCE_NAME env. variable and override name string if necessary: */
    2872     const char resourceName[] = "RESOURCE_NAME";
    2873     if (qEnvironmentVariableIsSet(resourceName))
    2874         nameByteArray = qgetenv(resourceName);
    2875     else
    2876         nameByteArray = strNameString.toLatin1();
    2877     QByteArray classByteArray = strClassString.toLatin1();
    2878 
    2879     AssertReturnVoid(nameByteArray.data() && classByteArray.data());
    2880 
    2881     XClassHint windowClass;
    2882     windowClass.res_name = nameByteArray.data();
    2883     windowClass.res_class = classByteArray.data();
    2884     /* Set WM_CLASS of the window to passed name and class strings: */
    2885     XSetClassHint(QX11Info::display(), pWidget->window()->winId(), &windowClass);
    2886 }
    2887 
    2888 /* static */
    2889 void UICommon::setXwaylandMayGrabKeyboardFlag(QWidget *pWidget)
    2890 {
    2891     XXSendClientMessage(QX11Info::display(), pWidget->window()->winId(),
    2892                         "_XWAYLAND_MAY_GRAB_KEYBOARD", 1);
    2893 }
    2894 #endif /* VBOX_WS_X11 */
    2895 
    2896 /* static */
    2897 void UICommon::setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount)
    2898 {
    2899     /* Shame on Qt it hasn't stuff for tuning
    2900      * widget size suitable for reflecting content of desired size.
    2901      * For example QLineEdit, QSpinBox and similar widgets should have a methods
    2902      * to strict the minimum width to reflect at least [n] symbols. */
    2903 
    2904     /* Load options: */
    2905     QStyleOptionSpinBox option;
    2906     option.initFrom(pSpinBox);
    2907 
    2908     /* Acquire edit-field rectangle: */
    2909     QRect rect = pSpinBox->style()->subControlRect(QStyle::CC_SpinBox,
    2910                                                    &option,
    2911                                                    QStyle::SC_SpinBoxEditField,
    2912                                                    pSpinBox);
    2913 
    2914     /* Calculate minimum-width magic: */
    2915     const int iSpinBoxWidth = pSpinBox->width();
    2916     const int iSpinBoxEditFieldWidth = rect.width();
    2917     const int iSpinBoxDelta = qMax(0, iSpinBoxWidth - iSpinBoxEditFieldWidth);
    2918     QFontMetrics metrics(pSpinBox->font(), pSpinBox);
    2919     const QString strDummy(cCount, '0');
    2920     const int iTextWidth = metrics.width(strDummy);
    2921 
    2922     /* Tune spin-box minimum-width: */
    2923     pSpinBox->setMinimumWidth(iTextWidth + iSpinBoxDelta);
    2924 }
    2925 
    2926 QString UICommon::vmGuestOSFamilyDescription(const QString &strFamilyId) const
    2927 {
    2928     AssertMsg(m_guestOSFamilyDescriptions.contains(strFamilyId),
    2929               ("Family ID incorrect: '%s'.", strFamilyId.toLatin1().constData()));
    2930     return m_guestOSFamilyDescriptions.value(strFamilyId);
    2931 }
    2932 
    2933 QList<CGuestOSType> UICommon::vmGuestOSTypeList(const QString &strFamilyId) const
    2934 {
    2935     AssertMsg(m_guestOSFamilyIDs.contains(strFamilyId),
    2936               ("Family ID incorrect: '%s'.", strFamilyId.toLatin1().constData()));
    2937     return m_guestOSFamilyIDs.contains(strFamilyId) ?
    2938            m_guestOSTypes[m_guestOSFamilyIDs.indexOf(strFamilyId)] : QList<CGuestOSType>();
    2939 }
    2940 
    2941 CGuestOSType UICommon::vmGuestOSType(const QString &strTypeId,
    2942                                        const QString &strFamilyId /* = QString() */) const
    2943 {
    2944     QList<CGuestOSType> list;
    2945     if (m_guestOSFamilyIDs.contains(strFamilyId))
    2946     {
    2947         list = m_guestOSTypes.at(m_guestOSFamilyIDs.indexOf(strFamilyId));
    2948     }
    2949     else
    2950     {
    2951         for (int i = 0; i < m_guestOSFamilyIDs.size(); ++i)
    2952             list += m_guestOSTypes.at(i);
    2953     }
    2954     for (int j = 0; j < list.size(); ++j)
    2955         if (!list.at(j).GetId().compare(strTypeId))
    2956             return list.at(j);
    2957     return CGuestOSType();
    2958 }
    2959 
    2960 QString UICommon::vmGuestOSTypeDescription(const QString &strTypeId) const
    2961 {
    2962     for (int i = 0; i < m_guestOSFamilyIDs.size(); ++i)
    2963     {
    2964         QList<CGuestOSType> list(m_guestOSTypes[i]);
    2965         for (int j = 0; j < list.size(); ++j)
    2966             if (!list.at(j).GetId().compare(strTypeId))
    2967                 return list.at(j).GetDescription();
    2968     }
    2969     return QString();
    2970 }
    2971 
    2972 /* static */
    2973 bool UICommon::isDOSType(const QString &strOSTypeId)
    2974 {
    2975     if (   strOSTypeId.left(3) == "dos"
    2976         || strOSTypeId.left(3) == "win"
    2977         || strOSTypeId.left(3) == "os2")
    2978         return true;
    2979 
    2980     return false;
    2981 }
    2982 
    2983 /* static */
    2984 bool UICommon::switchToMachine(CMachine &comMachine)
    2985 {
    2986 #ifdef VBOX_WS_MAC
    2987     const ULONG64 id = comMachine.ShowConsoleWindow();
    2988 #else
    2989     const WId id = (WId)comMachine.ShowConsoleWindow();
    2990 #endif
    2991     AssertWrapperOk(comMachine);
    2992     if (!comMachine.isOk())
    2993         return false;
    2994 
    2995     // WORKAROUND:
    2996     // id == 0 means the console window has already done everything
    2997     // necessary to implement the "show window" semantics.
    2998     if (id == 0)
    2999         return true;
    3000 
    3001 #if defined(VBOX_WS_WIN) || defined(VBOX_WS_X11)
    3002 
    3003     return activateWindow(id, true);
    3004 
    3005 #elif defined(VBOX_WS_MAC)
    3006 
    3007     // WORKAROUND:
    3008     // This is just for the case were the other process cannot steal
    3009     // the focus from us. It will send us a PSN so we can try.
    3010     ProcessSerialNumber psn;
    3011     psn.highLongOfPSN = id >> 32;
    3012     psn.lowLongOfPSN = (UInt32)id;
    3013 # ifdef __clang__
    3014 #  pragma GCC diagnostic push
    3015 #  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    3016     OSErr rc = ::SetFrontProcess(&psn);
    3017 #  pragma GCC diagnostic pop
    3018 # else
    3019     OSErr rc = ::SetFrontProcess(&psn);
    3020 # endif
    3021     if (!rc)
    3022         Log(("GUI: %#RX64 couldn't do SetFrontProcess on itself, the selector (we) had to do it...\n", id));
    3023     else
    3024         Log(("GUI: Failed to bring %#RX64 to front. rc=%#x\n", id, rc));
    3025     return !rc;
    3026 
    3027 #else
    3028 
    3029     return false;
    3030 
    3031 #endif
    3032 }
    3033 
    3034 bool UICommon::launchMachine(CMachine &comMachine, LaunchMode enmLaunchMode /* = LaunchMode_Default */)
    3035 {
    3036     /* Switch to machine window(s) if possible: */
    3037     if (   comMachine.GetSessionState() == KSessionState_Locked /* precondition for CanShowConsoleWindow() */
    3038         && comMachine.CanShowConsoleWindow())
    3039     {
    3040         switch (uiType())
    3041         {
    3042             /* For Selector UI: */
    3043             case UIType_SelectorUI:
    3044             {
    3045                 /* Just switch to existing VM window: */
    3046                 return switchToMachine(comMachine);
    3047             }
    3048             /* For Runtime UI: */
    3049             case UIType_RuntimeUI:
    3050             {
    3051                 /* Only separate UI process can reach that place.
    3052                  * Switch to existing VM window and exit. */
    3053                 switchToMachine(comMachine);
    3054                 return false;
    3055             }
    3056         }
    3057     }
    3058 
    3059     /* Not for separate UI (which can connect to machine in any state): */
    3060     if (enmLaunchMode != LaunchMode_Separate)
    3061     {
    3062         /* Make sure machine-state is one of required: */
    3063         const KMachineState enmState = comMachine.GetState(); NOREF(enmState);
    3064         AssertMsg(   enmState == KMachineState_PoweredOff
    3065                   || enmState == KMachineState_Saved
    3066                   || enmState == KMachineState_Teleported
    3067                   || enmState == KMachineState_Aborted
    3068                   , ("Machine must be PoweredOff/Saved/Teleported/Aborted (%d)", enmState));
    3069     }
    3070 
    3071     /* Create empty session instance: */
    3072     CSession comSession;
    3073     comSession.createInstance(CLSID_Session);
    3074     if (comSession.isNull())
    3075     {
    3076         msgCenter().cannotOpenSession(comSession);
    3077         return false;
    3078     }
    3079 
    3080     /* Configure environment: */
    3081     QVector<QString> astrEnv;
    3082 #ifdef VBOX_WS_WIN
    3083     /* Allow started VM process to be foreground window: */
    3084     AllowSetForegroundWindow(ASFW_ANY);
    3085 #endif
    3086 #ifdef VBOX_WS_X11
    3087     /* Make sure VM process will start on the same
    3088      * display as window this wrapper is called from: */
    3089     const char *pDisplay = RTEnvGet("DISPLAY");
    3090     if (pDisplay)
    3091         astrEnv.append(QString("DISPLAY=%1").arg(pDisplay));
    3092     const char *pXauth = RTEnvGet("XAUTHORITY");
    3093     if (pXauth)
    3094         astrEnv.append(QString("XAUTHORITY=%1").arg(pXauth));
    3095 #endif
    3096     QString strType;
    3097     switch (enmLaunchMode)
    3098     {
    3099         case LaunchMode_Default:  strType = ""; break;
    3100         case LaunchMode_Separate: strType = isSeparateProcess() ? "headless" : "separate"; break;
    3101         case LaunchMode_Headless: strType = "headless"; break;
    3102         default: AssertFailedReturn(false);
    3103     }
    3104 
    3105     /* Prepare "VM spawning" progress: */
    3106     CProgress comProgress = comMachine.LaunchVMProcess(comSession, strType, astrEnv);
    3107     if (!comMachine.isOk())
    3108     {
    3109         /* If the VM is started separately and the VM process is already running, then it is OK. */
    3110         if (enmLaunchMode == LaunchMode_Separate)
    3111         {
    3112             const KMachineState enmState = comMachine.GetState();
    3113             if (   enmState >= KMachineState_FirstOnline
    3114                 && enmState <= KMachineState_LastOnline)
    3115             {
    3116                 /* Already running: */
    3117                 return true;
    3118             }
    3119         }
    3120 
    3121         msgCenter().cannotOpenSession(comMachine);
    3122         return false;
    3123     }
    3124 
    3125     /* Show "VM spawning" progress: */
    3126     msgCenter().showModalProgressDialog(comProgress, comMachine.GetName(),
    3127                                         ":/progress_start_90px.png", 0, 0);
    3128     if (!comProgress.isOk() || comProgress.GetResultCode() != 0)
    3129         msgCenter().cannotOpenSession(comProgress, comMachine.GetName());
    3130 
    3131     /* Unlock machine, close session: */
    3132     comSession.UnlockMachine();
    3133 
    3134     /* True finally: */
    3135     return true;
    3136 }
    3137 
    3138 CSession UICommon::openSession(const QUuid &uId, KLockType lockType /* = KLockType_Shared */)
    3139 {
    3140     /* Prepare session: */
    3141     CSession comSession;
    3142 
    3143     /* Simulate try-catch block: */
    3144     bool fSuccess = false;
    3145     do
    3146     {
    3147         /* Create empty session instance: */
    3148         comSession.createInstance(CLSID_Session);
    3149         if (comSession.isNull())
    3150         {
    3151             msgCenter().cannotOpenSession(comSession);
    3152             break;
    3153         }
    3154 
    3155         /* Search for the corresponding machine: */
    3156         CMachine comMachine = m_comVBox.FindMachine(uId.toString());
    3157         if (comMachine.isNull())
    3158         {
    3159             msgCenter().cannotFindMachineById(m_comVBox, uId);
    3160             break;
    3161         }
    3162 
    3163         if (lockType == KLockType_VM)
    3164             comSession.SetName("GUI/Qt");
    3165 
    3166         /* Lock found machine to session: */
    3167         comMachine.LockMachine(comSession, lockType);
    3168         if (!comMachine.isOk())
    3169         {
    3170             msgCenter().cannotOpenSession(comMachine);
    3171             break;
    3172         }
    3173 
    3174         /* Pass the language ID as the property to the guest: */
    3175         if (comSession.GetType() == KSessionType_Shared)
    3176         {
    3177             CMachine comStartedMachine = comSession.GetMachine();
    3178             /* Make sure that the language is in two letter code.
    3179              * Note: if languageId() returns an empty string lang.name() will
    3180              * return "C" which is an valid language code. */
    3181             QLocale lang(UICommon::languageId());
    3182             comStartedMachine.SetGuestPropertyValue("/VirtualBox/HostInfo/GUI/LanguageID", lang.name());
    3183         }
    3184 
    3185         /* Success finally: */
    3186         fSuccess = true;
    3187     }
    3188     while (0);
    3189     /* Cleanup try-catch block: */
    3190     if (!fSuccess)
    3191         comSession.detach();
    3192 
    3193     /* Return session: */
    3194     return comSession;
    3195 }
    3196 
    3197 CSession UICommon::tryToOpenSessionFor(CMachine &comMachine)
    3198 {
    3199     /* Prepare session: */
    3200     CSession comSession;
    3201 
    3202     /* Session state unlocked? */
    3203     if (comMachine.GetSessionState() == KSessionState_Unlocked)
    3204     {
    3205         /* Open own 'write' session: */
    3206         comSession = openSession(comMachine.GetId());
    3207         AssertReturn(!comSession.isNull(), CSession());
    3208         comMachine = comSession.GetMachine();
    3209     }
    3210     /* Is this a Selector UI call? */
    3211     else if (uiType() == UIType_SelectorUI)
    3212     {
    3213         /* Open existing 'shared' session: */
    3214         comSession = openExistingSession(comMachine.GetId());
    3215         AssertReturn(!comSession.isNull(), CSession());
    3216         comMachine = comSession.GetMachine();
    3217     }
    3218     /* Else this is Runtime UI call
    3219      * which has session locked for itself. */
    3220 
    3221     /* Return session: */
    3222     return comSession;
    3223 }
    3224 
    3225 void UICommon::notifyCloudMachineUnregistered(const QString &strProviderShortName,
    3226                                               const QString &strProfileName,
    3227                                               const QUuid &uId)
    3228 {
    3229     emit sigCloudMachineUnregistered(strProviderShortName, strProfileName, uId);
    3230 }
    3231 
    3232 void UICommon::notifyCloudMachineRegistered(const QString &strProviderShortName,
    3233                                             const QString &strProfileName,
    3234                                             const CCloudMachine &comMachine)
    3235 {
    3236     emit sigCloudMachineRegistered(strProviderShortName, strProfileName, comMachine);
    3237 }
    3238 
    3239 void UICommon::enumerateMedia(const CMediumVector &comMedia /* = CMediumVector() */)
    3240 {
    3241     /* Make sure UICommon is already valid: */
    3242     AssertReturnVoid(m_fValid);
    3243     /* Ignore the request during UICommon cleanup: */
    3244     if (m_fCleaningUp)
    3245         return;
    3246     /* Ignore the request during startup snapshot restoring: */
    3247     if (shouldRestoreCurrentSnapshot())
    3248         return;
    3249 
    3250     /* Make sure medium-enumerator is already created: */
    3251     if (!m_pMediumEnumerator)
    3252         return;
    3253 
    3254     /* Redirect request to medium-enumerator under proper lock: */
    3255     if (m_meCleanupProtectionToken.tryLockForRead())
    3256     {
    3257         if (m_pMediumEnumerator)
    3258             m_pMediumEnumerator->enumerateMedia(comMedia);
    3259         m_meCleanupProtectionToken.unlock();
    3260     }
    3261 }
    3262 
    3263 void UICommon::refreshMedia()
    3264 {
    3265     /* Make sure UICommon is already valid: */
    3266     AssertReturnVoid(m_fValid);
    3267     /* Ignore the request during UICommon cleanup: */
    3268     if (m_fCleaningUp)
    3269         return;
    3270     /* Ignore the request during startup snapshot restoring: */
    3271     if (shouldRestoreCurrentSnapshot())
    3272         return;
    3273 
    3274     /* Make sure medium-enumerator is already created: */
    3275     if (!m_pMediumEnumerator)
    3276         return;
    3277     /* Make sure enumeration is not already started: */
    3278     if (m_pMediumEnumerator->isMediumEnumerationInProgress())
    3279         return;
    3280 
    3281     /* We assume it's safe to call it without locking,
    3282      * since we are performing blocking operation here. */
    3283     m_pMediumEnumerator->refreshMedia();
    3284 }
    3285 
    3286 bool UICommon::isFullMediumEnumerationRequested() const
    3287 {
    3288     /* Redirect request to medium-enumerator: */
    3289     return    m_pMediumEnumerator
    3290            && m_pMediumEnumerator->isFullMediumEnumerationRequested();
    3291 }
    3292 
    3293 bool UICommon::isMediumEnumerationInProgress() const
    3294 {
    3295     /* Redirect request to medium-enumerator: */
    3296     return    m_pMediumEnumerator
    3297            && m_pMediumEnumerator->isMediumEnumerationInProgress();
    3298 }
    3299 
    3300 UIMedium UICommon::medium(const QUuid &uMediumID) const
    3301 {
    3302     if (m_meCleanupProtectionToken.tryLockForRead())
    3303     {
    3304         /* Redirect call to medium-enumerator: */
    3305         UIMedium guiMedium;
    3306         if (m_pMediumEnumerator)
    3307             guiMedium = m_pMediumEnumerator->medium(uMediumID);
    3308         m_meCleanupProtectionToken.unlock();
    3309         return guiMedium;
    3310     }
    3311     return UIMedium();
    3312 }
    3313 
    3314 QList<QUuid> UICommon::mediumIDs() const
    3315 {
    3316     if (m_meCleanupProtectionToken.tryLockForRead())
    3317     {
    3318         /* Redirect call to medium-enumerator: */
    3319         QList<QUuid> listOfMedia;
    3320         if (m_pMediumEnumerator)
    3321             listOfMedia = m_pMediumEnumerator->mediumIDs();
    3322         m_meCleanupProtectionToken.unlock();
    3323         return listOfMedia;
    3324     }
    3325     return QList<QUuid>();
    3326 }
    3327 
    3328 void UICommon::createMedium(const UIMedium &guiMedium)
    3329 {
    3330     if (m_meCleanupProtectionToken.tryLockForRead())
    3331     {
    3332         /* Create medium in medium-enumerator: */
    3333         if (m_pMediumEnumerator)
    3334             m_pMediumEnumerator->createMedium(guiMedium);
    3335         m_meCleanupProtectionToken.unlock();
    3336     }
    3337 }
    3338 
    3339 QUuid UICommon::openMedium(UIMediumDeviceType enmMediumType, QString strMediumLocation, QWidget *pParent /* = 0 */)
    3340 {
    3341     /* Convert to native separators: */
    3342     strMediumLocation = QDir::toNativeSeparators(strMediumLocation);
    3343 
    3344     /* Initialize variables: */
    3345     CVirtualBox comVBox = virtualBox();
    3346 
    3347     /* Open corresponding medium: */
    3348     CMedium comMedium = comVBox.OpenMedium(strMediumLocation, mediumTypeToGlobal(enmMediumType), KAccessMode_ReadWrite, false);
    3349 
    3350     if (comVBox.isOk())
    3351     {
    3352         /* Prepare vbox medium wrapper: */
    3353         UIMedium guiMedium = medium(comMedium.GetId());
    3354 
    3355         /* First of all we should test if that medium already opened: */
    3356         if (guiMedium.isNull())
    3357         {
    3358             /* And create new otherwise: */
    3359             guiMedium = UIMedium(comMedium, enmMediumType, KMediumState_Created);
    3360             createMedium(guiMedium);
    3361         }
    3362 
    3363         /* Return guiMedium id: */
    3364         return guiMedium.id();
    3365     }
    3366     else
    3367         msgCenter().cannotOpenMedium(comVBox, strMediumLocation, pParent);
    3368 
    3369     return QUuid();
    3370 }
    3371 
    3372 QUuid UICommon::openMediumWithFileOpenDialog(UIMediumDeviceType enmMediumType, QWidget *pParent,
    3373                                                const QString &strDefaultFolder /* = QString() */,
    3374                                                bool fUseLastFolder /* = false */)
    3375 {
    3376     /* Initialize variables: */
    3377     QList<QPair <QString, QString> > filters;
    3378     QStringList backends;
    3379     QStringList prefixes;
    3380     QString strFilter;
    3381     QString strTitle;
    3382     QString allType;
    3383     QString strLastFolder = defaultFolderPathForType(enmMediumType);
    3384 
    3385     /* For DVDs and Floppies always check first the last recently used medium folder. For hard disk use
    3386        the caller's setting: */
    3387     fUseLastFolder = (enmMediumType == UIMediumDeviceType_DVD) || (enmMediumType == UIMediumDeviceType_Floppy);
    3388 
    3389     switch (enmMediumType)
    3390     {
    3391         case UIMediumDeviceType_HardDisk:
    3392         {
    3393             filters = HDDBackends(virtualBox());
    3394             strTitle = tr("Please choose a virtual hard disk file");
    3395             allType = tr("All virtual hard disk files (%1)");
    3396             break;
    3397         }
    3398         case UIMediumDeviceType_DVD:
    3399         {
    3400             filters = DVDBackends(virtualBox());
    3401             strTitle = tr("Please choose a virtual optical disk file");
    3402             allType = tr("All virtual optical disk files (%1)");
    3403             break;
    3404         }
    3405         case UIMediumDeviceType_Floppy:
    3406         {
    3407             filters = FloppyBackends(virtualBox());
    3408             strTitle = tr("Please choose a virtual floppy disk file");
    3409             allType = tr("All virtual floppy disk files (%1)");
    3410             break;
    3411         }
    3412         default:
    3413             break;
    3414     }
    3415     QString strHomeFolder = fUseLastFolder && !strLastFolder.isEmpty() ? strLastFolder :
    3416                             strDefaultFolder.isEmpty() ? homeFolder() : strDefaultFolder;
    3417 
    3418     /* Prepare filters and backends: */
    3419     for (int i = 0; i < filters.count(); ++i)
    3420     {
    3421         /* Get iterated filter: */
    3422         QPair<QString, QString> item = filters.at(i);
    3423         /* Create one backend filter string: */
    3424         backends << QString("%1 (%2)").arg(item.first).arg(item.second);
    3425         /* Save the suffix's for the "All" entry: */
    3426         prefixes << item.second;
    3427     }
    3428     if (!prefixes.isEmpty())
    3429         backends.insert(0, allType.arg(prefixes.join(" ").trimmed()));
    3430     backends << tr("All files (*)");
    3431     strFilter = backends.join(";;").trimmed();
    3432 
    3433     /* Create open file dialog: */
    3434     QStringList files = QIFileDialog::getOpenFileNames(strHomeFolder, strFilter, pParent, strTitle, 0, true, true);
    3435 
    3436     /* If dialog has some result: */
    3437     if (!files.empty() && !files[0].isEmpty())
    3438     {
    3439         QUuid uMediumId = openMedium(enmMediumType, files[0], pParent);
    3440         if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy ||
    3441             (enmMediumType == UIMediumDeviceType_HardDisk && fUseLastFolder))
    3442             updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(uMediumId).location());
    3443         return uMediumId;
    3444     }
    3445     return QUuid();
    3446 }
    3447 
    3448 
    3449 /**
    3450  * Helper for createVisoMediumWithVisoCreator.
    3451  * @returns IPRT status code.
    3452  * @param   pStrmDst            Where to write the quoted string.
    3453  * @param   pszPrefix           Stuff to put in front of it.
    3454  * @param   rStr                The string to quote and write out.
    3455  * @param   pszPrefix           Stuff to put after it.
    3456  */
    3457 DECLINLINE(int) visoWriteQuotedString(PRTSTREAM pStrmDst, const char *pszPrefix, QString const &rStr, const char *pszPostFix)
    3458 {
    3459     QByteArray const utf8Array   = rStr.toUtf8();
    3460     const char      *apszArgv[2] = { utf8Array.constData(), NULL };
    3461     char            *pszQuoted;
    3462     int vrc = RTGetOptArgvToString(&pszQuoted, apszArgv, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
    3463     if (RT_SUCCESS(vrc))
    3464     {
    3465         if (pszPrefix)
    3466             vrc = RTStrmPutStr(pStrmDst, pszPrefix);
    3467         if (RT_SUCCESS(vrc))
    3468         {
    3469             vrc = RTStrmPutStr(pStrmDst, pszQuoted);
    3470             if (pszPostFix && RT_SUCCESS(vrc))
    3471                 vrc = RTStrmPutStr(pStrmDst, pszPostFix);
    3472         }
    3473         RTStrFree(pszQuoted);
    3474     }
    3475 
    3476     return vrc;
    3477 }
    3478 
    3479 
    3480 void UICommon::openMediumCreatorDialog(QWidget *pParent, UIMediumDeviceType enmMediumType,
    3481                                        const QString &strDefaultFolder /* = QString() */,
    3482                                        const QString &strMachineName /* = QString() */,
    3483                                        const QString &strMachineGuestOSTypeId /*= QString() */)
    3484 {
    3485     /* Depending on medium-type: */
    3486     QUuid uMediumId;
    3487     switch (enmMediumType)
    3488     {
    3489         case UIMediumDeviceType_HardDisk:
    3490             createVDWithWizard(pParent, strDefaultFolder, strMachineName, strMachineGuestOSTypeId);
    3491             break;
    3492         case UIMediumDeviceType_DVD:
    3493             uMediumId = createVisoMediumWithVisoCreator(pParent, strDefaultFolder, strMachineName);
    3494             break;
    3495         case UIMediumDeviceType_Floppy:
    3496             uMediumId = showCreateFloppyDiskDialog(pParent, strDefaultFolder, strMachineName);
    3497             break;
    3498         default:
    3499             break;
    3500     }
    3501     if (uMediumId.isNull())
    3502         return;
    3503 
    3504     /* Update the recent medium list only if the medium type is DVD or floppy: */
    3505     if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy)
    3506         updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(uMediumId).location());
    3507 }
    3508 
    3509 QUuid UICommon::createVisoMediumWithVisoCreator(QWidget *pParent, const QString &strDefaultFolder /* = QString */,
    3510                                                   const QString &strMachineName /* = QString */)
    3511 {
    3512     QString strVisoSaveFolder(strDefaultFolder);
    3513     if (strVisoSaveFolder.isEmpty())
    3514         strVisoSaveFolder = defaultFolderPathForType(UIMediumDeviceType_DVD);
    3515 
    3516     QWidget *pDialogParent = windowManager().realParentWindow(pParent);
    3517     UIVisoCreator *pVisoCreator = new UIVisoCreator(pDialogParent, strMachineName);
    3518 
    3519     if (!pVisoCreator)
    3520         return QString();
    3521     windowManager().registerNewParent(pVisoCreator, pDialogParent);
    3522     pVisoCreator->setCurrentPath(gEDataManager->visoCreatorRecentFolder());
    3523 
    3524     if (pVisoCreator->exec(false /* not application modal */))
    3525     {
    3526         QStringList files = pVisoCreator->entryList();
    3527         QString strVisoName = pVisoCreator->visoName();
    3528         if (strVisoName.isEmpty())
    3529             strVisoName = strMachineName;
    3530 
    3531         if (files.empty() || files[0].isEmpty())
    3532         {
    3533             delete pVisoCreator;
    3534             return QUuid();
    3535         }
    3536 
    3537         gEDataManager->setVISOCreatorRecentFolder(pVisoCreator->currentPath());
    3538 
    3539         /* Produce the VISO. */
    3540         char szVisoPath[RTPATH_MAX];
    3541         QString strFileName = QString("%1%2").arg(strVisoName).arg(".viso");
    3542         int vrc = RTPathJoin(szVisoPath, sizeof(szVisoPath), strVisoSaveFolder.toUtf8().constData(), strFileName.toUtf8().constData());
    3543         if (RT_SUCCESS(vrc))
    3544         {
    3545             PRTSTREAM pStrmViso;
    3546             vrc = RTStrmOpen(szVisoPath, "w", &pStrmViso);
    3547             if (RT_SUCCESS(vrc))
    3548             {
    3549                 RTUUID Uuid;
    3550                 vrc = RTUuidCreate(&Uuid);
    3551                 if (RT_SUCCESS(vrc))
    3552                 {
    3553                     RTStrmPrintf(pStrmViso, "--iprt-iso-maker-file-marker-bourne-sh %RTuuid\n", &Uuid);
    3554                     vrc = visoWriteQuotedString(pStrmViso, "--volume-id=", strVisoName, "\n");
    3555 
    3556                     for (int iFile = 0; iFile < files.size() && RT_SUCCESS(vrc); iFile++)
    3557                         vrc = visoWriteQuotedString(pStrmViso, NULL, files[iFile], "\n");
    3558 
    3559                     /* Append custom options if any to the file: */
    3560                     const QStringList &customOptions = pVisoCreator->customOptions();
    3561                     foreach (QString strLine, customOptions)
    3562                         RTStrmPrintf(pStrmViso, "%s\n", strLine.toUtf8().constData());
    3563 
    3564                     RTStrmFlush(pStrmViso);
    3565                     if (RT_SUCCESS(vrc))
    3566                         vrc = RTStrmError(pStrmViso);
    3567                 }
    3568 
    3569                 RTStrmClose(pStrmViso);
    3570             }
    3571         }
    3572 
    3573         /* Done. */
    3574         if (RT_SUCCESS(vrc))
    3575         {
    3576             delete pVisoCreator;
    3577             return openMedium(UIMediumDeviceType_DVD, QString(szVisoPath), pParent);
    3578         }
    3579         /** @todo error message. */
    3580         else
    3581         {
    3582             delete pVisoCreator;
    3583             return QUuid();
    3584         }
    3585     }
    3586     delete pVisoCreator;
    3587     return QUuid();
    3588 }
    3589 
    3590 QUuid UICommon::showCreateFloppyDiskDialog(QWidget *pParent, const QString &strDefaultFolder /* QString() */,
    3591                                              const QString &strMachineName /* = QString() */ )
    3592 {
    3593     QString strStartPath(strDefaultFolder);
    3594 
    3595     if (strStartPath.isEmpty())
    3596         strStartPath = defaultFolderPathForType(UIMediumDeviceType_Floppy);
    3597 
    3598     QWidget *pDialogParent = windowManager().realParentWindow(pParent);
    3599 
    3600     UIFDCreationDialog *pDialog = new UIFDCreationDialog(pParent, strStartPath, strMachineName);
    3601     if (!pDialog)
    3602         return QUuid();
    3603     windowManager().registerNewParent(pDialog, pDialogParent);
    3604 
    3605     if (pDialog->exec())
    3606     {
    3607         QUuid uMediumID = pDialog->mediumID();
    3608         delete pDialog;
    3609         return uMediumID;
    3610     }
    3611     delete pDialog;
    3612     return QUuid();
    3613 }
    3614 
    3615 int UICommon::openMediumSelectorDialog(QWidget *pParent, UIMediumDeviceType  enmMediumType, QUuid &outUuid,
    3616                                        const QString &strMachineFolder, const QString &strMachineName,
    3617                                        const QString &strMachineGuestOSTypeId, bool fEnableCreate, const QUuid &uMachineID /* = QUuid() */)
    3618 {
    3619     QUuid uMachineOrGlobalId = uMachineID == QUuid() ? gEDataManager->GlobalID : uMachineID;
    3620 
    3621     QWidget *pDialogParent = windowManager().realParentWindow(pParent);
    3622     QPointer<UIMediumSelector> pSelector = new UIMediumSelector(enmMediumType, strMachineName,
    3623                                                                 strMachineFolder, strMachineGuestOSTypeId,
    3624                                                                 uMachineOrGlobalId, pDialogParent);
    3625 
    3626     if (!pSelector)
    3627         return static_cast<int>(UIMediumSelector::ReturnCode_Rejected);
    3628     pSelector->setEnableCreateAction(fEnableCreate);
    3629     windowManager().registerNewParent(pSelector, pDialogParent);
    3630 
    3631     int iResult = pSelector->exec(false);
    3632     UIMediumSelector::ReturnCode returnCode;
    3633 
    3634     if (iResult >= static_cast<int>(UIMediumSelector::ReturnCode_Max) || iResult < 0)
    3635         returnCode = UIMediumSelector::ReturnCode_Rejected;
    3636     else
    3637         returnCode = static_cast<UIMediumSelector::ReturnCode>(iResult);
    3638 
    3639     if (returnCode == UIMediumSelector::ReturnCode_Accepted)
    3640     {
    3641         QList<QUuid> selectedMediumIds = pSelector->selectedMediumIds();
    3642 
    3643         /* Currently we only care about the 0th since we support single selection by intention: */
    3644         if (selectedMediumIds.isEmpty())
    3645             returnCode = UIMediumSelector::ReturnCode_Rejected;
    3646         else
    3647         {
    3648             outUuid = selectedMediumIds[0];
    3649             updateRecentlyUsedMediumListAndFolder(enmMediumType, medium(outUuid).location());
    3650         }
    3651     }
    3652     delete pSelector;
    3653     return static_cast<int>(returnCode);
    3654 }
    3655 
    3656 void UICommon::createVDWithWizard(QWidget *pParent,
    3657                                   const QString &strMachineFolder /* = QString() */,
    3658                                   const QString &strMachineName /* = QString() */,
    3659                                   const QString &strMachineGuestOSTypeId  /* = QString() */)
    3660 {
    3661     /* Initialize variables: */
    3662     QString strDefaultFolder = strMachineFolder;
    3663     if (strDefaultFolder.isEmpty())
    3664         strDefaultFolder = defaultFolderPathForType(UIMediumDeviceType_HardDisk);
    3665 
    3666     /* In case we dont have a 'guest os type id' default back to 'Other': */
    3667     const CGuestOSType comGuestOSType = virtualBox().GetGuestOSType(  !strMachineGuestOSTypeId.isEmpty()
    3668                                                                     ? strMachineGuestOSTypeId
    3669                                                                     : "Other");
    3670     const QString strDiskName = findUniqueFileName(strDefaultFolder,   !strMachineName.isEmpty()
    3671                                                                      ? strMachineName
    3672                                                                      : "NewVirtualDisk");
    3673 
    3674     /* Show New VD wizard: */
    3675     UISafePointerWizardNewVD pWizard = new UIWizardNewVD(pParent,
    3676                                                          strDiskName,
    3677                                                          strDefaultFolder,
    3678                                                          comGuestOSType.GetRecommendedHDD());
    3679     if (!pWizard)
    3680         return;
    3681     QWidget *pDialogParent = windowManager().realParentWindow(pParent);
    3682     windowManager().registerNewParent(pWizard, pDialogParent);
    3683     pWizard->exec();
    3684     delete pWizard;
    3685 }
    3686 
    3687 void UICommon::prepareStorageMenu(QMenu &menu,
    3688                                     QObject *pListener, const char *pszSlotName,
    3689                                     const CMachine &comMachine, const QString &strControllerName, const StorageSlot &storageSlot)
    3690 {
    3691     /* Current attachment attributes: */
    3692     const CMediumAttachment comCurrentAttachment = comMachine.GetMediumAttachment(strControllerName,
    3693                                                                                   storageSlot.port,
    3694                                                                                   storageSlot.device);
    3695     const CMedium comCurrentMedium = comCurrentAttachment.GetMedium();
    3696     const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId();
    3697     const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation();
    3698 
    3699     /* Other medium-attachments of same machine: */
    3700     const CMediumAttachmentVector comAttachments = comMachine.GetMediumAttachments();
    3701 
    3702     /* Determine device & medium types: */
    3703     const UIMediumDeviceType enmMediumType = mediumTypeToLocal(comCurrentAttachment.GetType());
    3704     AssertMsgReturnVoid(enmMediumType != UIMediumDeviceType_Invalid, ("Incorrect storage medium type!\n"));
    3705 
    3706     /* Prepare open-existing-medium action: */
    3707     QAction *pActionOpenExistingMedium = menu.addAction(UIIconPool::iconSet(":/select_file_16px.png"),
    3708                                                         QString(), pListener, pszSlotName);
    3709     pActionOpenExistingMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(),
    3710                                                                           comCurrentAttachment.GetDevice(), enmMediumType)));
    3711     pActionOpenExistingMedium->setText(QApplication::translate("UIMachineSettingsStorage", "Choose/Create a disk image..."));
    3712 
    3713 
    3714     /* Prepare open medium file action: */
    3715     QAction *pActionFileSelector = menu.addAction(UIIconPool::iconSet(":/select_file_16px.png"),
    3716                                                   QString(), pListener, pszSlotName);
    3717     pActionFileSelector->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(),
    3718                                                                     comCurrentAttachment.GetDevice(), enmMediumType,
    3719                                                                     UIMediumTarget::UIMediumTargetType_WithFileDialog)));
    3720     pActionFileSelector->setText(QApplication::translate("UIMachineSettingsStorage", "Choose a disk file..."));
    3721 
    3722 
    3723     /* Insert separator: */
    3724     menu.addSeparator();
    3725 
    3726     /* Get existing-host-drive vector: */
    3727     CMediumVector comMedia;
    3728     switch (enmMediumType)
    3729     {
    3730         case UIMediumDeviceType_DVD:    comMedia = host().GetDVDDrives(); break;
    3731         case UIMediumDeviceType_Floppy: comMedia = host().GetFloppyDrives(); break;
    3732         default: break;
    3733     }
    3734     /* Prepare choose-existing-host-drive actions: */
    3735     foreach (const CMedium &comMedium, comMedia)
    3736     {
    3737         /* Make sure host-drive usage is unique: */
    3738         bool fIsHostDriveUsed = false;
    3739         foreach (const CMediumAttachment &comOtherAttachment, comAttachments)
    3740         {
    3741             if (comOtherAttachment != comCurrentAttachment)
    3742             {
    3743                 const CMedium &comOtherMedium = comOtherAttachment.GetMedium();
    3744                 if (!comOtherMedium.isNull() && comOtherMedium.GetId() == comMedium.GetId())
    3745                 {
    3746                     fIsHostDriveUsed = true;
    3747                     break;
    3748                 }
    3749             }
    3750         }
    3751         /* If host-drives usage is unique: */
    3752         if (!fIsHostDriveUsed)
    3753         {
    3754             QAction *pActionChooseHostDrive = menu.addAction(UIMedium(comMedium, enmMediumType).name(), pListener, pszSlotName);
    3755             pActionChooseHostDrive->setCheckable(true);
    3756             pActionChooseHostDrive->setChecked(!comCurrentMedium.isNull() && comMedium.GetId() == uCurrentID);
    3757             pActionChooseHostDrive->setData(QVariant::fromValue(UIMediumTarget(strControllerName,
    3758                                                                                comCurrentAttachment.GetPort(),
    3759                                                                                comCurrentAttachment.GetDevice(),
    3760                                                                                enmMediumType,
    3761                                                                                UIMediumTarget::UIMediumTargetType_WithID,
    3762                                                                                comMedium.GetId().toString())));
    3763         }
    3764     }
    3765 
    3766     /* Get recent-medium list: */
    3767     QStringList recentMediumList;
    3768     QStringList recentMediumListUsed;
    3769     switch (enmMediumType)
    3770     {
    3771         case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break;
    3772         case UIMediumDeviceType_DVD:      recentMediumList = gEDataManager->recentListOfOpticalDisks(); break;
    3773         case UIMediumDeviceType_Floppy:   recentMediumList = gEDataManager->recentListOfFloppyDisks(); break;
    3774         default: break;
    3775     }
    3776     /* Prepare choose-recent-medium actions: */
    3777     foreach (const QString &strRecentMediumLocationBase, recentMediumList)
    3778     {
    3779         /* Confirm medium uniqueness: */
    3780         if (recentMediumListUsed.contains(strRecentMediumLocationBase))
    3781             continue;
    3782         /* Mark medium as known: */
    3783         recentMediumListUsed << strRecentMediumLocationBase;
    3784         /* Convert separators to native: */
    3785         const QString strRecentMediumLocation = QDir::toNativeSeparators(strRecentMediumLocationBase);
    3786         /* Confirm medium presence: */
    3787         if (!QFile::exists(strRecentMediumLocation))
    3788             continue;
    3789         /* Make sure recent-medium usage is unique: */
    3790         bool fIsRecentMediumUsed = false;
    3791         if (enmMediumType != UIMediumDeviceType_DVD)
    3792             foreach (const CMediumAttachment &otherAttachment, comAttachments)
    3793             {
    3794                 if (otherAttachment != comCurrentAttachment)
    3795                 {
    3796                     const CMedium &comOtherMedium = otherAttachment.GetMedium();
    3797                     if (!comOtherMedium.isNull() && comOtherMedium.GetLocation() == strRecentMediumLocation)
    3798                     {
    3799                         fIsRecentMediumUsed = true;
    3800                         break;
    3801                     }
    3802                 }
    3803             }
    3804         /* If recent-medium usage is unique: */
    3805         if (!fIsRecentMediumUsed)
    3806         {
    3807             QAction *pActionChooseRecentMedium = menu.addAction(QFileInfo(strRecentMediumLocation).fileName(),
    3808                                                                 pListener, pszSlotName);
    3809             pActionChooseRecentMedium->setCheckable(true);
    3810             pActionChooseRecentMedium->setChecked(!comCurrentMedium.isNull() && strRecentMediumLocation == strCurrentLocation);
    3811             pActionChooseRecentMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName,
    3812                                                                                   comCurrentAttachment.GetPort(),
    3813                                                                                   comCurrentAttachment.GetDevice(),
    3814                                                                                   enmMediumType,
    3815                                                                                   UIMediumTarget::UIMediumTargetType_WithLocation,
    3816                                                                                   strRecentMediumLocation)));
    3817             pActionChooseRecentMedium->setToolTip(strRecentMediumLocation);
    3818         }
    3819     }
    3820 
    3821     /* Last action for optical/floppy attachments only: */
    3822     if (enmMediumType == UIMediumDeviceType_DVD || enmMediumType == UIMediumDeviceType_Floppy)
    3823     {
    3824         /* Insert separator: */
    3825         menu.addSeparator();
    3826 
    3827         /* Prepare unmount-current-medium action: */
    3828         QAction *pActionUnmountMedium = menu.addAction(QString(), pListener, pszSlotName);
    3829         pActionUnmountMedium->setEnabled(!comCurrentMedium.isNull());
    3830         pActionUnmountMedium->setData(QVariant::fromValue(UIMediumTarget(strControllerName, comCurrentAttachment.GetPort(),
    3831                                                                          comCurrentAttachment.GetDevice())));
    3832         pActionUnmountMedium->setText(QApplication::translate("UIMachineSettingsStorage", "Remove disk from virtual drive"));
    3833         if (enmMediumType == UIMediumDeviceType_DVD)
    3834             pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/cd_unmount_16px.png", ":/cd_unmount_disabled_16px.png"));
    3835         else if (enmMediumType == UIMediumDeviceType_Floppy)
    3836             pActionUnmountMedium->setIcon(UIIconPool::iconSet(":/fd_unmount_16px.png", ":/fd_unmount_disabled_16px.png"));
    3837     }
    3838 }
    3839 
    3840 void UICommon::updateMachineStorage(const CMachine &comConstMachine, const UIMediumTarget &target)
    3841 {
    3842     /* Mount (by default): */
    3843     bool fMount = true;
    3844     /* Null medium (by default): */
    3845     CMedium comMedium;
    3846     /* With null ID (by default): */
    3847     QUuid uActualID;
    3848 
    3849     /* Current mount-target attributes: */
    3850     const CStorageController comCurrentController = comConstMachine.GetStorageControllerByName(target.name);
    3851     const KStorageBus enmCurrentStorageBus = comCurrentController.GetBus();
    3852     const CMediumAttachment comCurrentAttachment = comConstMachine.GetMediumAttachment(target.name, target.port, target.device);
    3853     const CMedium comCurrentMedium = comCurrentAttachment.GetMedium();
    3854     const QUuid uCurrentID = comCurrentMedium.isNull() ? QUuid() : comCurrentMedium.GetId();
    3855     const QString strCurrentLocation = comCurrentMedium.isNull() ? QString() : comCurrentMedium.GetLocation();
    3856 
    3857     /* Which additional info do we have? */
    3858     switch (target.type)
    3859     {
    3860         /* Do we have an exact ID or do we let the user open a medium? */
    3861         case UIMediumTarget::UIMediumTargetType_WithID:
    3862         case UIMediumTarget::UIMediumTargetType_WithFileDialog:
    3863         case UIMediumTarget::UIMediumTargetType_CreateAdHocVISO:
    3864         case UIMediumTarget::UIMediumTargetType_CreateFloppyDisk:
    3865         {
    3866             /* New mount-target attributes: */
    3867             QUuid uNewID;
    3868 
    3869             /* Invoke file-open dialog to choose medium ID: */
    3870             if (target.mediumType != UIMediumDeviceType_Invalid && target.data.isNull())
    3871             {
    3872                 /* Keyboard can be captured by machine-view.
    3873                  * So we should clear machine-view focus to let file-open dialog get it.
    3874                  * That way the keyboard will be released too.. */
    3875                 QWidget *pLastFocusedWidget = 0;
    3876                 if (QApplication::focusWidget())
    3877                 {
    3878                     pLastFocusedWidget = QApplication::focusWidget();
    3879                     pLastFocusedWidget->clearFocus();
    3880                 }
    3881                 /* Call for file-open dialog: */
    3882                 const QString strMachineFolder(QFileInfo(comConstMachine.GetSettingsFilePath()).absolutePath());
    3883                 QUuid uMediumID;
    3884                 if (target.type == UIMediumTarget::UIMediumTargetType_WithID)
    3885                 {
    3886                     int iDialogReturn = openMediumSelectorDialog(windowManager().mainWindowShown(), target.mediumType, uMediumID,
    3887                                                                  strMachineFolder, comConstMachine.GetName(),
    3888                                                                  comConstMachine.GetOSTypeId(), true /*fEnableCreate */, comConstMachine.GetId());
    3889                     if (iDialogReturn == UIMediumSelector::ReturnCode_LeftEmpty &&
    3890                         (target.mediumType == UIMediumDeviceType_DVD || target.mediumType == UIMediumDeviceType_Floppy))
    3891                         fMount = false;
    3892                 }
    3893                 else if (target.type == UIMediumTarget::UIMediumTargetType_WithFileDialog)
    3894                 {
    3895                     uMediumID = openMediumWithFileOpenDialog(target.mediumType, windowManager().mainWindowShown(),
    3896                                                              strMachineFolder, false /* fUseLastFolder */);
    3897                 }
    3898                 else if(target.type == UIMediumTarget::UIMediumTargetType_CreateAdHocVISO)
    3899                     uMediumID = createVisoMediumWithVisoCreator(windowManager().mainWindowShown(), strMachineFolder, comConstMachine.GetName());
    3900 
    3901                 else if(target.type == UIMediumTarget::UIMediumTargetType_CreateFloppyDisk)
    3902                     uMediumID = showCreateFloppyDiskDialog(windowManager().mainWindowShown(), strMachineFolder, comConstMachine.GetName());
    3903 
    3904                 /* Return focus back: */
    3905                 if (pLastFocusedWidget)
    3906                     pLastFocusedWidget->setFocus();
    3907                 /* Accept new medium ID: */
    3908                 if (!uMediumID.isNull())
    3909                     uNewID = uMediumID;
    3910                 else
    3911                     /* Else just exit in case left empty is not chosen in medium selector dialog: */
    3912                     if (fMount)
    3913                         return;
    3914             }
    3915             /* Use medium ID which was passed: */
    3916             else if (!target.data.isNull() && target.data != uCurrentID.toString())
    3917                 uNewID = target.data;
    3918 
    3919             /* Should we mount or unmount? */
    3920             fMount = !uNewID.isNull();
    3921 
    3922             /* Prepare target medium: */
    3923             const UIMedium guiMedium = medium(uNewID);
    3924             comMedium = guiMedium.medium();
    3925             uActualID = fMount ? uNewID : uCurrentID;
    3926             break;
    3927         }
    3928         /* Do we have a recent location? */
    3929         case UIMediumTarget::UIMediumTargetType_WithLocation:
    3930         {
    3931             /* Open medium by location and get new medium ID if any: */
    3932             const QUuid uNewID = openMedium(target.mediumType, target.data);
    3933             /* Else just exit: */
    3934             if (uNewID.isNull())
    3935                 return;
    3936 
    3937             /* Should we mount or unmount? */
    3938             fMount = uNewID != uCurrentID;
    3939 
    3940             /* Prepare target medium: */
    3941             const UIMedium guiMedium = fMount ? medium(uNewID) : UIMedium();
    3942             comMedium = fMount ? guiMedium.medium() : CMedium();
    3943             uActualID = fMount ? uNewID : uCurrentID;
    3944             break;
    3945         }
    3946     }
    3947 
    3948     /* Do not unmount hard-drives: */
    3949     if (target.mediumType == UIMediumDeviceType_HardDisk && !fMount)
    3950         return;
    3951 
    3952     /* Get editable machine & session: */
    3953     CMachine comMachine = comConstMachine;
    3954     CSession comSession = tryToOpenSessionFor(comMachine);
    3955 
    3956     /* Remount medium to the predefined port/device: */
    3957     bool fWasMounted = false;
    3958     /* Hard drive case: */
    3959     if (target.mediumType == UIMediumDeviceType_HardDisk)
    3960     {
    3961         /* Detaching: */
    3962         comMachine.DetachDevice(target.name, target.port, target.device);
    3963         fWasMounted = comMachine.isOk();
    3964         if (!fWasMounted)
    3965             msgCenter().cannotDetachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation,
    3966                                            StorageSlot(enmCurrentStorageBus, target.port, target.device));
    3967         else
    3968         {
    3969             /* Attaching: */
    3970             comMachine.AttachDevice(target.name, target.port, target.device, KDeviceType_HardDisk, comMedium);
    3971             fWasMounted = comMachine.isOk();
    3972             if (!fWasMounted)
    3973                 msgCenter().cannotAttachDevice(comMachine, UIMediumDeviceType_HardDisk, strCurrentLocation,
    3974                                                StorageSlot(enmCurrentStorageBus, target.port, target.device));
    3975         }
    3976     }
    3977     /* Optical/floppy drive case: */
    3978     else
    3979     {
    3980         /* Remounting: */
    3981         comMachine.MountMedium(target.name, target.port, target.device, comMedium, false /* force? */);
    3982         fWasMounted = comMachine.isOk();
    3983         if (!fWasMounted)
    3984         {
    3985             /* Ask for force remounting: */
    3986             if (msgCenter().cannotRemountMedium(comMachine, medium(uActualID),
    3987                                                 fMount, true /* retry? */))
    3988             {
    3989                 /* Force remounting: */
    3990                 comMachine.MountMedium(target.name, target.port, target.device, comMedium, true /* force? */);
    3991                 fWasMounted = comMachine.isOk();
    3992                 if (!fWasMounted)
    3993                     msgCenter().cannotRemountMedium(comMachine, medium(uActualID),
    3994                                                     fMount, false /* retry? */);
    3995             }
    3996         }
    3997         /* If mounting was successful: */
    3998         if (fWasMounted)
    3999         {
    4000             /* Disable First RUN Wizard: */
    4001             if (gEDataManager->machineFirstTimeStarted(comMachine.GetId()))
    4002                 gEDataManager->setMachineFirstTimeStarted(false, comMachine.GetId());
    4003         }
    4004     }
    4005 
    4006     /* Save settings: */
    4007     if (fWasMounted)
    4008     {
    4009         comMachine.SaveSettings();
    4010         if (!comMachine.isOk())
    4011             msgCenter().cannotSaveMachineSettings(comMachine, windowManager().mainWindowShown());
    4012     }
    4013 
    4014     /* Close session to editable comMachine if necessary: */
    4015     if (!comSession.isNull())
    4016         comSession.UnlockMachine();
    4017 }
    4018 
    4019 QString UICommon::details(const CMedium &comMedium, bool fPredictDiff, bool fUseHtml /* = true */)
    4020 {
    4021     /* Search for corresponding UI medium: */
    4022     const QUuid uMediumID = comMedium.isNull() ? UIMedium::nullID() : comMedium.GetId();
    4023     UIMedium guiMedium = medium(uMediumID);
    4024     if (!comMedium.isNull() && guiMedium.isNull())
    4025     {
    4026         /* UI medium may be new and not among cached media, request enumeration: */
    4027         enumerateMedia(CMediumVector() << comMedium);
    4028 
    4029         /* Search for corresponding UI medium again: */
    4030         guiMedium = medium(uMediumID);
    4031         if (guiMedium.isNull())
    4032         {
    4033             /* Medium might be deleted already, return null string: */
    4034             return QString();
    4035         }
    4036     }
    4037 
    4038     /* For differencing hard-disk we have to request
    4039      * enumeration of whole tree based in it's root item: */
    4040     if (   comMedium.isNotNull()
    4041         && comMedium.GetDeviceType() == KDeviceType_HardDisk)
    4042     {
    4043         /* Traverse through parents to root to catch it: */
    4044         CMedium comRootMedium;
    4045         CMedium comParentMedium = comMedium.GetParent();
    4046         while (comParentMedium.isNotNull())
    4047         {
    4048             comRootMedium = comParentMedium;
    4049             comParentMedium = comParentMedium.GetParent();
    4050         }
    4051         /* Enumerate root if it's found and wasn't cached: */
    4052         if (comRootMedium.isNotNull())
    4053         {
    4054             const QUuid uRootId = comRootMedium.GetId();
    4055             if (medium(uRootId).isNull())
    4056                 enumerateMedia(CMediumVector() << comRootMedium);
    4057         }
    4058     }
    4059 
    4060     /* Return UI medium details: */
    4061     return fUseHtml ? guiMedium.detailsHTML(true /* no diffs? */, fPredictDiff) :
    4062                       guiMedium.details(true /* no diffs? */, fPredictDiff);
    4063 }
    4064 
    4065 void UICommon::updateRecentlyUsedMediumListAndFolder(UIMediumDeviceType enmMediumType, QString strMediumLocation)
    4066 {
    4067     /** Don't add the medium to extra data if its name is in exclude list, m_recentMediaExcludeList: */
    4068     foreach (QString strExcludeName, m_recentMediaExcludeList)
    4069     {
    4070         if (strMediumLocation.contains(strExcludeName))
    4071             return;
    4072     }
    4073 
    4074     /* Remember the path of the last chosen medium: */
    4075     switch (enmMediumType)
    4076     {
    4077         case UIMediumDeviceType_HardDisk: gEDataManager->setRecentFolderForHardDrives(QFileInfo(strMediumLocation).absolutePath()); break;
    4078         case UIMediumDeviceType_DVD:      gEDataManager->setRecentFolderForOpticalDisks(QFileInfo(strMediumLocation).absolutePath()); break;
    4079         case UIMediumDeviceType_Floppy:   gEDataManager->setRecentFolderForFloppyDisks(QFileInfo(strMediumLocation).absolutePath()); break;
    4080         default: break;
    4081     }
    4082 
    4083     /* Update recently used list: */
    4084     QStringList recentMediumList;
    4085     switch (enmMediumType)
    4086     {
    4087         case UIMediumDeviceType_HardDisk: recentMediumList = gEDataManager->recentListOfHardDrives(); break;
    4088         case UIMediumDeviceType_DVD:      recentMediumList = gEDataManager->recentListOfOpticalDisks(); break;
    4089         case UIMediumDeviceType_Floppy:   recentMediumList = gEDataManager->recentListOfFloppyDisks(); break;
    4090         default: break;
    4091     }
    4092     if (recentMediumList.contains(strMediumLocation))
    4093         recentMediumList.removeAll(strMediumLocation);
    4094     recentMediumList.prepend(strMediumLocation);
    4095     while(recentMediumList.size() > 5)
    4096         recentMediumList.removeLast();
    4097     switch (enmMediumType)
    4098     {
    4099         case UIMediumDeviceType_HardDisk: gEDataManager->setRecentListOfHardDrives(recentMediumList); break;
    4100         case UIMediumDeviceType_DVD:      gEDataManager->setRecentListOfOpticalDisks(recentMediumList); break;
    4101         case UIMediumDeviceType_Floppy:   gEDataManager->setRecentListOfFloppyDisks(recentMediumList); break;
    4102         default: break;
    4103     }
    4104 }
    4105 
    4106 QString UICommon::defaultFolderPathForType(UIMediumDeviceType enmMediumType)
    4107 {
    4108     QString strLastFolder;
    4109     switch (enmMediumType)
    4110     {
    4111         case UIMediumDeviceType_HardDisk:
    4112             strLastFolder = gEDataManager->recentFolderForHardDrives();
    4113             if (strLastFolder.isEmpty())
    4114                 strLastFolder = gEDataManager->recentFolderForOpticalDisks();
    4115             if (strLastFolder.isEmpty())
    4116                 strLastFolder = gEDataManager->recentFolderForFloppyDisks();
    4117             break;
    4118         case UIMediumDeviceType_DVD:
    4119             strLastFolder = gEDataManager->recentFolderForOpticalDisks();
    4120             if (strLastFolder.isEmpty())
    4121                 strLastFolder = gEDataManager->recentFolderForFloppyDisks();
    4122             if (strLastFolder.isEmpty())
    4123                 strLastFolder = gEDataManager->recentFolderForHardDrives();
    4124             break;
    4125         case UIMediumDeviceType_Floppy:
    4126             strLastFolder = gEDataManager->recentFolderForFloppyDisks();
    4127             if (strLastFolder.isEmpty())
    4128                 strLastFolder = gEDataManager->recentFolderForOpticalDisks();
    4129             if (strLastFolder.isEmpty())
    4130                 strLastFolder = gEDataManager->recentFolderForHardDrives();
    4131             break;
    4132         default:
    4133             break;
    4134     }
    4135 
    4136     if (strLastFolder.isEmpty())
    4137         return virtualBox().GetSystemProperties().GetDefaultMachineFolder();
    4138 
    4139     return strLastFolder;
    4140 }
    4141 
    4142 #ifdef RT_OS_LINUX
    4143 /* static */
    4144 void UICommon::checkForWrongUSBMounted()
    4145 {
    4146     /* Make sure '/proc/mounts' exists and can be opened: */
    4147     QFile file("/proc/mounts");
    4148     if (!file.exists() || !file.open(QIODevice::ReadOnly | QIODevice::Text))
    4149         return;
    4150 
    4151     /* Fetch contents: */
    4152     QStringList contents;
    4153     for (;;)
    4154     {
    4155         QByteArray line = file.readLine();
    4156         if (line.isEmpty())
    4157             break;
    4158         contents << line;
    4159     }
    4160     /* Grep contents for usbfs presence: */
    4161     QStringList grep1(contents.filter("/sys/bus/usb/drivers"));
    4162     QStringList grep2(grep1.filter("usbfs"));
    4163     if (grep2.isEmpty())
    4164         return;
    4165 
    4166     /* Show corresponding warning: */
    4167     msgCenter().warnAboutWrongUSBMounted();
    4168 }
    4169 #endif /* RT_OS_LINUX */
    4170 
    4171 /* static */
    4172 QString UICommon::details(const CUSBDevice &comDevice)
    4173 {
    4174     QString strDetails;
    4175     if (comDevice.isNull())
    4176         strDetails = tr("Unknown device", "USB device details");
    4177     else
    4178     {
    4179         QVector<QString> devInfoVector = comDevice.GetDeviceInfo();
    4180         QString strManufacturer;
    4181         QString strProduct;
    4182 
    4183         if (devInfoVector.size() >= 1)
    4184             strManufacturer = devInfoVector[0].trimmed();
    4185         if (devInfoVector.size() >= 2)
    4186             strProduct = devInfoVector[1].trimmed();
    4187 
    4188         if (strManufacturer.isEmpty() && strProduct.isEmpty())
    4189         {
    4190             strDetails =
    4191                 tr("Unknown device %1:%2", "USB device details")
    4192                    .arg(QString().sprintf("%04hX", comDevice.GetVendorId()))
    4193                    .arg(QString().sprintf("%04hX", comDevice.GetProductId()));
    4194         }
    4195         else
    4196         {
    4197             if (strProduct.toUpper().startsWith(strManufacturer.toUpper()))
    4198                 strDetails = strProduct;
    4199             else
    4200                 strDetails = strManufacturer + " " + strProduct;
    4201         }
    4202         ushort iRev = comDevice.GetRevision();
    4203         if (iRev != 0)
    4204             strDetails += QString().sprintf(" [%04hX]", iRev);
    4205     }
    4206 
    4207     return strDetails.trimmed();
    4208 }
    4209 
    4210 /* static */
    4211 QString UICommon::toolTip(const CUSBDevice &comDevice)
    4212 {
    4213     QString strTip =
    4214         tr("<nobr>Vendor ID: %1</nobr><br>"
    4215            "<nobr>Product ID: %2</nobr><br>"
    4216            "<nobr>Revision: %3</nobr>", "USB device tooltip")
    4217            .arg(QString().sprintf("%04hX", comDevice.GetVendorId()))
    4218            .arg(QString().sprintf("%04hX", comDevice.GetProductId()))
    4219            .arg(QString().sprintf("%04hX", comDevice.GetRevision()));
    4220 
    4221     const QString strSerial = comDevice.GetSerialNumber();
    4222     if (!strSerial.isEmpty())
    4223         strTip += QString(tr("<br><nobr>Serial No. %1</nobr>", "USB device tooltip"))
    4224                              .arg(strSerial);
    4225 
    4226     /* Add the state field if it's a host USB device: */
    4227     CHostUSBDevice hostDev(comDevice);
    4228     if (!hostDev.isNull())
    4229     {
    4230         strTip += QString(tr("<br><nobr>State: %1</nobr>", "USB device tooltip"))
    4231                              .arg(gpConverter->toString(hostDev.GetState()));
    4232     }
    4233 
    4234     return strTip;
    4235 }
    4236 
    4237 /* static */
    4238 QString UICommon::toolTip(const CUSBDeviceFilter &comFilter)
    4239 {
    4240     QString strTip;
    4241 
    4242     const QString strVendorId = comFilter.GetVendorId();
    4243     if (!strVendorId.isEmpty())
    4244         strTip += tr("<nobr>Vendor ID: %1</nobr>", "USB filter tooltip")
    4245                      .arg(strVendorId);
    4246 
    4247     const QString strProductId = comFilter.GetProductId();
    4248     if (!strProductId.isEmpty())
    4249         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product ID: %2</nobr>", "USB filter tooltip")
    4250                                                      .arg(strProductId);
    4251 
    4252     const QString strRevision = comFilter.GetRevision();
    4253     if (!strRevision.isEmpty())
    4254         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Revision: %3</nobr>", "USB filter tooltip")
    4255                                                      .arg(strRevision);
    4256 
    4257     const QString strProduct = comFilter.GetProduct();
    4258     if (!strProduct.isEmpty())
    4259         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Product: %4</nobr>", "USB filter tooltip")
    4260                                                      .arg(strProduct);
    4261 
    4262     const QString strManufacturer = comFilter.GetManufacturer();
    4263     if (!strManufacturer.isEmpty())
    4264         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Manufacturer: %5</nobr>", "USB filter tooltip")
    4265                                                      .arg(strManufacturer);
    4266 
    4267     const QString strSerial = comFilter.GetSerialNumber();
    4268     if (!strSerial.isEmpty())
    4269         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Serial No.: %1</nobr>", "USB filter tooltip")
    4270                                                      .arg(strSerial);
    4271 
    4272     const QString strPort = comFilter.GetPort();
    4273     if (!strPort.isEmpty())
    4274         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>Port: %1</nobr>", "USB filter tooltip")
    4275                                                      .arg(strPort);
    4276 
    4277     /* Add the state field if it's a host USB device: */
    4278     CHostUSBDevice hostDev(comFilter);
    4279     if (!hostDev.isNull())
    4280     {
    4281         strTip += strTip.isEmpty() ? "":"<br/>" + tr("<nobr>State: %1</nobr>", "USB filter tooltip")
    4282                                                      .arg(gpConverter->toString(hostDev.GetState()));
    4283     }
    4284 
    4285     return strTip;
    4286 }
    4287 
    4288 /* static */
    4289 QString UICommon::toolTip(const CHostVideoInputDevice &comWebcam)
    4290 {
    4291     QStringList records;
    4292 
    4293     const QString strName = comWebcam.GetName();
    4294     if (!strName.isEmpty())
    4295         records << strName;
    4296 
    4297     const QString strPath = comWebcam.GetPath();
    4298     if (!strPath.isEmpty())
    4299         records << strPath;
    4300 
    4301     return records.join("<br>");
    4302 }
    4303 
    4304 void UICommon::doExtPackInstallation(QString const &strFilePath, QString const &strDigest,
    4305                                      QWidget *pParent, QString *pstrExtPackName) const
    4306 {
    4307     /* If the extension pack manager isn't available, skip any attempts to install: */
    4308     CExtPackManager extPackManager = virtualBox().GetExtensionPackManager();
    4309     if (extPackManager.isNull())
    4310         return;
    4311     /* Open the extpack tarball via IExtPackManager: */
    4312     CExtPackFile comExtPackFile;
    4313     if (strDigest.isEmpty())
    4314         comExtPackFile = extPackManager.OpenExtPackFile(strFilePath);
    4315     else
    4316     {
    4317         QString strFileAndHash = QString("%1::SHA-256=%2").arg(strFilePath).arg(strDigest);
    4318         comExtPackFile = extPackManager.OpenExtPackFile(strFileAndHash);
    4319     }
    4320     if (!extPackManager.isOk())
    4321     {
    4322         msgCenter().cannotOpenExtPack(strFilePath, extPackManager, pParent);
    4323         return;
    4324     }
    4325 
    4326     if (!comExtPackFile.GetUsable())
    4327     {
    4328         msgCenter().warnAboutBadExtPackFile(strFilePath, comExtPackFile, pParent);
    4329         return;
    4330     }
    4331 
    4332     const QString strPackName = comExtPackFile.GetName();
    4333     const QString strPackDescription = comExtPackFile.GetDescription();
    4334     const QString strPackVersion = QString("%1r%2%3").arg(comExtPackFile.GetVersion()).arg(comExtPackFile.GetRevision()).arg(comExtPackFile.GetEdition());
    4335 
    4336     /* Check if there is a version of the extension pack already
    4337      * installed on the system and let the user decide what to do about it. */
    4338     CExtPack comExtPackCur = extPackManager.Find(strPackName);
    4339     bool fReplaceIt = comExtPackCur.isOk();
    4340     if (fReplaceIt)
    4341     {
    4342         QString strPackVersionCur = QString("%1r%2%3").arg(comExtPackCur.GetVersion()).arg(comExtPackCur.GetRevision()).arg(comExtPackCur.GetEdition());
    4343         if (!msgCenter().confirmReplaceExtensionPack(strPackName, strPackVersion, strPackVersionCur, strPackDescription, pParent))
    4344             return;
    4345     }
    4346     /* If it's a new package just ask for general confirmation. */
    4347     else
    4348     {
    4349         if (!msgCenter().confirmInstallExtensionPack(strPackName, strPackVersion, strPackDescription, pParent))
    4350             return;
    4351     }
    4352 
    4353     /* Display the license dialog if required by the extension pack. */
    4354     if (comExtPackFile.GetShowLicense())
    4355     {
    4356         QString strLicense = comExtPackFile.GetLicense();
    4357         VBoxLicenseViewer licenseViewer(pParent);
    4358         if (licenseViewer.showLicenseFromString(strLicense) != QDialog::Accepted)
    4359             return;
    4360     }
    4361 
    4362     /* Install the selected package.
    4363      * Set the package name return value before doing
    4364      * this as the caller should do a refresh even on failure. */
    4365     QString strDisplayInfo;
    4366 #ifdef VBOX_WS_WIN
    4367     if (pParent)
    4368         strDisplayInfo.sprintf("hwnd=%#llx", (uint64_t)(uintptr_t)pParent->winId());
    4369 #endif
    4370 
    4371     /* Install extension pack: */
    4372     UINotificationProgressExtensionPackInstall *pNotification =
    4373             new UINotificationProgressExtensionPackInstall(comExtPackFile,
    4374                                                            fReplaceIt,
    4375                                                            strPackName,
    4376                                                            strDisplayInfo);
    4377     connect(pNotification, &UINotificationProgressExtensionPackInstall::sigExtensionPackInstalled,
    4378             this, &UICommon::sigExtensionPackInstalled);
    4379     gpNotificationCenter->append(pNotification);
    4380 
    4381     /* Store the name: */
    4382     if (pstrExtPackName)
    4383         *pstrExtPackName = strPackName;
    4384 }
    4385 
    4386 #ifdef VBOX_WITH_3D_ACCELERATION
    4387 /* static */
    4388 bool UICommon::isWddmCompatibleOsType(const QString &strGuestOSTypeId)
    4389 {
    4390     return    strGuestOSTypeId.startsWith("WindowsVista")
    4391            || strGuestOSTypeId.startsWith("Windows7")
    4392            || strGuestOSTypeId.startsWith("Windows8")
    4393            || strGuestOSTypeId.startsWith("Windows81")
    4394            || strGuestOSTypeId.startsWith("Windows10")
    4395            || strGuestOSTypeId.startsWith("Windows2008")
    4396            || strGuestOSTypeId.startsWith("Windows2012");
    4397 }
    4398 #endif /* VBOX_WITH_3D_ACCELERATION */
    4399 
    4400 /* static */
    4401 quint64 UICommon::requiredVideoMemory(const QString &strGuestOSTypeId, int cMonitors /* = 1 */)
    4402 {
    4403     /* We create a list of the size of all available host monitors. This list
    4404      * is sorted by value and by starting with the biggest one, we calculate
    4405      * the memory requirements for every guest screen. This is of course not
    4406      * correct, but as we can't predict on which host screens the user will
    4407      * open the guest windows, this is the best assumption we can do, cause it
    4408      * is the worst case. */
    4409     const int cHostScreens = gpDesktop->screenCount();
    4410     QVector<int> screenSize(qMax(cMonitors, cHostScreens), 0);
    4411     for (int i = 0; i < cHostScreens; ++i)
    4412     {
    4413         QRect r = gpDesktop->screenGeometry(i);
    4414         screenSize[i] = r.width() * r.height();
    4415     }
    4416     /* Now sort the vector: */
    4417     std::sort(screenSize.begin(), screenSize.end(), std::greater<int>());
    4418     /* For the case that there are more guest screens configured then host
    4419      * screens available, replace all zeros with the greatest value in the
    4420      * vector. */
    4421     for (int i = 0; i < screenSize.size(); ++i)
    4422         if (screenSize.at(i) == 0)
    4423             screenSize.replace(i, screenSize.at(0));
    4424 
    4425     quint64 uNeedBits = 0;
    4426     for (int i = 0; i < cMonitors; ++i)
    4427     {
    4428         /* Calculate summary required memory amount in bits: */
    4429         uNeedBits += (screenSize.at(i) * /* with x height */
    4430                      32 + /* we will take the maximum possible bpp for now */
    4431                      8 * _1M) + /* current cache per screen - may be changed in future */
    4432                      8 * 4096; /* adapter info */
    4433     }
    4434     /* Translate value into megabytes with rounding to highest side: */
    4435     quint64 uNeedMBytes = uNeedBits % (8 * _1M)
    4436                         ? uNeedBits / (8 * _1M) + 1
    4437                         : uNeedBits / (8 * _1M) /* convert to megabytes */;
    4438 
    4439     if (strGuestOSTypeId.startsWith("Windows"))
    4440     {
    4441         /* Windows guests need offscreen VRAM too for graphics acceleration features: */
    4442 #ifdef VBOX_WITH_3D_ACCELERATION
    4443         if (isWddmCompatibleOsType(strGuestOSTypeId))
    4444         {
    4445             /* WDDM mode, there are two surfaces for each screen: shadow & primary: */
    4446             uNeedMBytes *= 3;
    4447         }
    4448         else
    4449 #endif /* VBOX_WITH_3D_ACCELERATION */
    4450         {
    4451             uNeedMBytes *= 2;
    4452         }
    4453     }
    4454 
    4455     return uNeedMBytes * _1M;
    4456 }
    4457 
    4458 QIcon UICommon::vmUserIcon(const CMachine &comMachine) const
    4459 {
    4460     /* Prepare fallback icon: */
    4461     static QIcon nullIcon;
    4462 
    4463     /* Make sure general icon-pool initialized: */
    4464     AssertReturn(m_pIconPool, nullIcon);
    4465 
    4466     /* Redirect to general icon-pool: */
    4467     return m_pIconPool->userMachineIcon(comMachine);
    4468 }
    4469 
    4470 QPixmap UICommon::vmUserPixmap(const CMachine &comMachine, const QSize &size) const
    4471 {
    4472     /* Prepare fallback pixmap: */
    4473     static QPixmap nullPixmap;
    4474 
    4475     /* Make sure general icon-pool initialized: */
    4476     AssertReturn(m_pIconPool, nullPixmap);
    4477 
    4478     /* Redirect to general icon-pool: */
    4479     return m_pIconPool->userMachinePixmap(comMachine, size);
    4480 }
    4481 
    4482 QPixmap UICommon::vmUserPixmapDefault(const CMachine &comMachine, QSize *pLogicalSize /* = 0 */) const
    4483 {
    4484     /* Prepare fallback pixmap: */
    4485     static QPixmap nullPixmap;
    4486 
    4487     /* Make sure general icon-pool initialized: */
    4488     AssertReturn(m_pIconPool, nullPixmap);
    4489 
    4490     /* Redirect to general icon-pool: */
    4491     return m_pIconPool->userMachinePixmapDefault(comMachine, pLogicalSize);
    4492 }
    4493 
    4494 QIcon UICommon::vmGuestOSTypeIcon(const QString &strOSTypeID) const
    4495 {
    4496     /* Prepare fallback icon: */
    4497     static QIcon nullIcon;
    4498 
    4499     /* Make sure general icon-pool initialized: */
    4500     AssertReturn(m_pIconPool, nullIcon);
    4501 
    4502     /* Redirect to general icon-pool: */
    4503     return m_pIconPool->guestOSTypeIcon(strOSTypeID);
    4504 }
    4505 
    4506 QPixmap UICommon::vmGuestOSTypePixmap(const QString &strOSTypeID, const QSize &size) const
    4507 {
    4508     /* Prepare fallback pixmap: */
    4509     static QPixmap nullPixmap;
    4510 
    4511     /* Make sure general icon-pool initialized: */
    4512     AssertReturn(m_pIconPool, nullPixmap);
    4513 
    4514     /* Redirect to general icon-pool: */
    4515     return m_pIconPool->guestOSTypePixmap(strOSTypeID, size);
    4516 }
    4517 
    4518 QPixmap UICommon::vmGuestOSTypePixmapDefault(const QString &strOSTypeID, QSize *pLogicalSize /* = 0 */) const
    4519 {
    4520     /* Prepare fallback pixmap: */
    4521     static QPixmap nullPixmap;
    4522 
    4523     /* Make sure general icon-pool initialized: */
    4524     AssertReturn(m_pIconPool, nullPixmap);
    4525 
    4526     /* Redirect to general icon-pool: */
    4527     return m_pIconPool->guestOSTypePixmapDefault(strOSTypeID, pLogicalSize);
    4528 }
    4529 
    4530 /* static */
    4531 QPixmap UICommon::joinPixmaps(const QPixmap &pixmap1, const QPixmap &pixmap2)
    4532 {
    4533     if (pixmap1.isNull())
    4534         return pixmap2;
    4535     if (pixmap2.isNull())
    4536         return pixmap1;
    4537 
    4538     QPixmap result(pixmap1.width() + pixmap2.width() + 2,
    4539                    qMax(pixmap1.height(), pixmap2.height()));
    4540     result.fill(Qt::transparent);
    4541 
    4542     QPainter painter(&result);
    4543     painter.drawPixmap(0, 0, pixmap1);
    4544     painter.drawPixmap(pixmap1.width() + 2, result.height() - pixmap2.height(), pixmap2);
    4545     painter.end();
    4546 
    4547     return result;
    4548 }
    4549 
    4550 /* static */
    4551 void UICommon::setHelpKeyword(QObject *pObject, const QString &strHelpKeyword)
    4552 {
    4553     if (pObject)
    4554         pObject->setProperty("helpkeyword", strHelpKeyword);
    4555 }
    4556 
    4557 /* static */
    4558 QString UICommon::helpKeyword(const QObject *pObject)
    4559 {
    4560     if (!pObject)
    4561         return QString();
    4562     return pObject->property("helpkeyword").toString();
    4563 }
    4564 
    4565 bool UICommon::openURL(const QString &strUrl) const
    4566 {
    4567     /** Service event. */
    4568     class ServiceEvent : public QEvent
    4569     {
    4570     public:
    4571 
    4572         /** Constructs service event on th basis of passed @a fResult. */
    4573         ServiceEvent(bool fResult)
    4574             : QEvent(QEvent::User)
    4575             , m_fResult(fResult)
    4576         {}
    4577 
    4578         /** Returns the result which event brings. */
    4579         bool result() const { return m_fResult; }
    4580 
    4581     private:
    4582 
    4583         /** Holds the result which event brings. */
    4584         bool m_fResult;
    4585     };
    4586 
    4587     /** Service client object. */
    4588     class ServiceClient : public QEventLoop
    4589     {
    4590     public:
    4591 
    4592         /** Constructs service client on the basis of passed @a fResult. */
    4593         ServiceClient()
    4594             : m_fResult(false)
    4595         {}
    4596 
    4597         /** Returns the result which event brings. */
    4598         bool result() const { return m_fResult; }
    4599 
    4600     private:
    4601 
    4602         /** Handles any Qt @a pEvent. */
    4603         bool event(QEvent *pEvent)
    4604         {
    4605             /* Handle service event: */
    4606             if (pEvent->type() == QEvent::User)
    4607             {
    4608                 ServiceEvent *pServiceEvent = static_cast<ServiceEvent*>(pEvent);
    4609                 m_fResult = pServiceEvent->result();
    4610                 pServiceEvent->accept();
    4611                 quit();
    4612                 return true;
    4613             }
    4614             return false;
    4615         }
    4616 
    4617         bool m_fResult;
    4618     };
    4619 
    4620     /** Service server object. */
    4621     class ServiceServer : public QThread
    4622     {
    4623     public:
    4624 
    4625         /** Constructs service server on the basis of passed @a client and @a strUrl. */
    4626         ServiceServer(ServiceClient &client, const QString &strUrl)
    4627             : m_client(client), m_strUrl(strUrl) {}
    4628 
    4629     private:
    4630 
    4631         /** Executes thread task. */
    4632         void run()
    4633         {
    4634             QApplication::postEvent(&m_client, new ServiceEvent(QDesktopServices::openUrl(m_strUrl)));
    4635         }
    4636 
    4637         /** Holds the client reference. */
    4638         ServiceClient &m_client;
    4639         /** Holds the URL to be processed. */
    4640         const QString &m_strUrl;
    4641     };
    4642 
    4643     /* Create client & server: */
    4644     ServiceClient client;
    4645     ServiceServer server(client, strUrl);
    4646     server.start();
    4647     client.exec();
    4648     server.wait();
    4649 
    4650     /* Acquire client result: */
    4651     bool fResult = client.result();
    4652 
    4653     if (!fResult)
    4654         msgCenter().cannotOpenURL(strUrl);
    4655 
    4656     return fResult;
    4657 }
    4658 
    4659 void UICommon::sltGUILanguageChange(QString strLanguage)
    4660 {
    4661     /* Make sure medium-enumeration is not in progress! */
    4662     AssertReturnVoid(!isMediumEnumerationInProgress());
    4663     /* Load passed language: */
    4664     loadLanguage(strLanguage);
    4665 }
    4666 
    4667 void UICommon::sltHandleMediumCreated(const CMedium &comMedium)
    4668 {
    4669     /* Acquire device type: */
    4670     const KDeviceType enmDeviceType = comMedium.GetDeviceType();
    4671     if (!comMedium.isOk())
    4672         msgCenter().cannotAcquireMediumAttribute(comMedium);
    4673     else
    4674     {
    4675         /* Convert to medium type: */
    4676         const UIMediumDeviceType enmMediumType = mediumTypeToLocal(enmDeviceType);
    4677 
    4678         /* Make sure we cached created medium in GUI: */
    4679         createMedium(UIMedium(comMedium, enmMediumType, KMediumState_Created));
    4680     }
    4681 }
    4682 
    4683 void UICommon::sltHandleMachineCreated(const CMachine &comMachine)
    4684 {
    4685     /* Register created machine. */
    4686     CVirtualBox comVBox = virtualBox();
    4687     comVBox.RegisterMachine(comMachine);
    4688     if (!comVBox.isOk())
    4689         msgCenter().cannotRegisterMachine(comVBox, comMachine.GetName());
    4690 }
    4691 
    4692 void UICommon::sltHandleCloudMachineAdded(const QString &strProviderShortName,
    4693                                           const QString &strProfileName,
    4694                                           const CCloudMachine &comMachine)
    4695 {
    4696     /* Make sure we cached added cloud VM in GUI: */
    4697     notifyCloudMachineRegistered(strProviderShortName,
    4698                                  strProfileName,
    4699                                  comMachine);
    4700 }
    4701 
    4702 bool UICommon::eventFilter(QObject *pObject, QEvent *pEvent)
    4703 {
    4704     /** @todo Just use the QIWithRetranslateUI3 template wrapper. */
    4705 
    4706     if (   pEvent->type() == QEvent::LanguageChange
    4707         && pObject->isWidgetType()
    4708         && static_cast<QWidget*>(pObject)->isTopLevel())
    4709     {
    4710         /* Catch the language change event before any other widget gets it in
    4711          * order to invalidate cached string resources (like the details view
    4712          * templates) that may be used by other widgets. */
    4713         QWidgetList list = QApplication::topLevelWidgets();
    4714         if (list.first() == pObject)
    4715         {
    4716             /* Call this only once per every language change (see
    4717              * QApplication::installTranslator() for details): */
    4718             retranslateUi();
    4719         }
    4720     }
    4721 
    4722     /* Call to base-class: */
    4723     return QObject::eventFilter(pObject, pEvent);
    4724 }
    4725 
    4726 void UICommon::retranslateUi()
    4727 {
    4728     s_strUserDefinedPortName = tr("User-defined", "serial port");
    4729 
    4730     m_pixWarning = UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_MessageBoxWarning).pixmap(16, 16);
    4731     Assert(!m_pixWarning.isNull());
    4732 
    4733     m_pixError = UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_MessageBoxCritical).pixmap(16, 16);
    4734     Assert(!m_pixError.isNull());
    4735 
    4736     /* Re-enumerate uimedium since they contain some translations too: */
    4737     if (m_fValid)
    4738         refreshMedia();
    4739 
    4740 #ifdef VBOX_WS_X11
    4741     // WORKAROUND:
    4742     // As X11 do not have functionality for providing human readable key names,
    4743     // we keep a table of them, which must be updated when the language is changed.
    4744     UINativeHotKey::retranslateKeyNames();
    4745 #endif
    4746 }
    4747 
    4748 #ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1
    4749 void UICommon::sltHandleCommitDataRequest(QSessionManager &manager)
    4750 {
    4751     LogRel(("GUI: UICommon: Commit data request..\n"));
    4752 
    4753     /* Ask listener to commit data: */
    4754     emit sigAskToCommitData();
    4755 #ifdef VBOX_WS_WIN
    4756     m_fDataCommitted = true;
    4757 #endif
    4758 
    4759     /* Depending on UI type: */
    4760     switch (uiType())
    4761     {
    4762         /* For Runtime UI: */
    4763         case UIType_RuntimeUI:
    4764         {
    4765             /* Thin clients will be able to shutdown properly,
    4766              * but for fat clients: */
    4767             if (!isSeparateProcess())
    4768             {
    4769                 // WORKAROUND:
    4770                 // We can't save VM state in one go for fat clients, so we have to ask session manager to cancel shutdown.
    4771                 // To next major release this should be removed in any case, since there will be no fat clients after all.
    4772                 manager.cancel();
    4773 
    4774 #ifdef VBOX_WS_WIN
    4775                 // WORKAROUND:
    4776                 // In theory that's Qt5 who should allow us to provide canceling reason as well, but that functionality
    4777                 // seems to be missed in Windows platform plugin, so we are making that ourselves.
    4778                 ShutdownBlockReasonCreateAPI((HWND)windowManager().mainWindowShown()->winId(), L"VM is still running.");
    4779 #endif
    4780             }
    4781 
    4782             break;
    4783         }
    4784         default:
    4785             break;
    4786     }
    4787 }
    4788 #endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
    4789 
    4790 void UICommon::sltHandleVBoxSVCAvailabilityChange(bool fAvailable)
    4791 {
    4792     /* Make sure the VBoxSVC availability changed: */
    4793     if (m_fVBoxSVCAvailable == fAvailable)
    4794         return;
    4795 
    4796     /* Cache the new VBoxSVC availability value: */
    4797     m_fVBoxSVCAvailable = fAvailable;
    4798 
    4799     /* If VBoxSVC is not available: */
    4800     if (!m_fVBoxSVCAvailable)
    4801     {
    4802         /* Mark wrappers invalid: */
    4803         m_fWrappersValid = false;
    4804         /* Re-fetch corresponding CVirtualBox to restart VBoxSVC: */
    4805         m_comVBox = m_comVBoxClient.GetVirtualBox();
    4806         if (!m_comVBoxClient.isOk())
    4807         {
    4808             // The proper behavior would be to show the message and to exit the app, e.g.:
    4809             // msgCenter().cannotAcquireVirtualBox(m_comVBoxClient);
    4810             // return QApplication::quit();
    4811             // But CVirtualBox is still NULL in current Main implementation,
    4812             // and this call do not restart anything, so we are waiting
    4813             // for subsequent event about VBoxSVC is available again.
    4814         }
    4815     }
    4816     /* If VBoxSVC is available: */
    4817     else
    4818     {
    4819         if (!m_fWrappersValid)
    4820         {
    4821             /* Re-fetch corresponding CVirtualBox: */
    4822             m_comVBox = m_comVBoxClient.GetVirtualBox();
    4823             if (!m_comVBoxClient.isOk())
    4824             {
    4825                 msgCenter().cannotAcquireVirtualBox(m_comVBoxClient);
    4826                 return QApplication::quit();
    4827             }
    4828             /* Re-init wrappers: */
    4829             comWrappersReinit();
    4830 
    4831             /* For Selector UI: */
    4832             if (uiType() == UIType_SelectorUI)
    4833             {
    4834                 /* Recreate Main event listeners: */
    4835                 UIVirtualBoxEventHandler::destroy();
    4836                 UIVirtualBoxClientEventHandler::destroy();
    4837                 UIExtraDataManager::destroy();
    4838                 UIExtraDataManager::instance();
    4839                 UIVirtualBoxEventHandler::instance();
    4840                 UIVirtualBoxClientEventHandler::instance();
    4841                 /* Ask UIStarter to restart UI: */
    4842                 emit sigAskToRestartUI();
    4843             }
    4844         }
    4845     }
    4846 
    4847     /* Notify listeners about the VBoxSVC availability change: */
    4848     emit sigVBoxSVCAvailabilityChange();
    4849 }
    4850 
    4851 #ifdef VBOX_WS_WIN
    4852 /* static */
    4853 BOOL UICommon::ShutdownBlockReasonCreateAPI(HWND hWnd, LPCWSTR pwszReason)
    4854 {
    4855     BOOL fResult = FALSE;
    4856     typedef BOOL(WINAPI *PFNSHUTDOWNBLOCKREASONCREATE)(HWND hWnd, LPCWSTR pwszReason);
    4857 
    4858     PFNSHUTDOWNBLOCKREASONCREATE pfn = (PFNSHUTDOWNBLOCKREASONCREATE)GetProcAddress(
    4859         GetModuleHandle(L"User32.dll"), "ShutdownBlockReasonCreate");
    4860     _ASSERTE(pfn);
    4861     if (pfn)
    4862         fResult = pfn(hWnd, pwszReason);
    4863     return fResult;
    4864 }
    4865 #endif
    4866 
    4867 #ifdef VBOX_WITH_DEBUGGER_GUI
    4868 
    4869 # define UICOMMON_DBG_CFG_VAR_FALSE       (0)
    4870 # define UICOMMON_DBG_CFG_VAR_TRUE        (1)
    4871 # define UICOMMON_DBG_CFG_VAR_MASK        (1)
    4872 # define UICOMMON_DBG_CFG_VAR_CMD_LINE    RT_BIT(3)
    4873 # define UICOMMON_DBG_CFG_VAR_DONE        RT_BIT(4)
    4874 
    4875 void UICommon::initDebuggerVar(int *piDbgCfgVar, const char *pszEnvVar, const char *pszExtraDataName, bool fDefault)
    4876 {
    4877     QString strEnvValue;
    4878     char    szEnvValue[256];
    4879     int rc = RTEnvGetEx(RTENV_DEFAULT, pszEnvVar, szEnvValue, sizeof(szEnvValue), NULL);
    4880     if (RT_SUCCESS(rc))
    4881     {
    4882         strEnvValue = QString::fromUtf8(&szEnvValue[0]).toLower().trimmed();
    4883         if (strEnvValue.isEmpty())
    4884             strEnvValue = "yes";
    4885     }
    4886     else if (rc != VERR_ENV_VAR_NOT_FOUND)
    4887         strEnvValue = "veto";
    4888 
    4889     QString strExtraValue = m_comVBox.GetExtraData(pszExtraDataName).toLower().trimmed();
    4890     if (strExtraValue.isEmpty())
    4891         strExtraValue = QString();
    4892 
    4893     if ( strEnvValue.contains("veto") || strExtraValue.contains("veto"))
    4894         *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE;
    4895     else if (strEnvValue.isNull() && strExtraValue.isNull())
    4896         *piDbgCfgVar = fDefault ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE;
    4897     else
    4898     {
    4899         QString *pStr = !strEnvValue.isEmpty() ? &strEnvValue : &strExtraValue;
    4900         if (   pStr->startsWith("y")  // yes
    4901             || pStr->startsWith("e")  // enabled
    4902             || pStr->startsWith("t")  // true
    4903             || pStr->startsWith("on")
    4904             || pStr->toLongLong() != 0)
    4905             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_TRUE;
    4906         else if (   pStr->startsWith("n")  // o
    4907                  || pStr->startsWith("d")  // disable
    4908                  || pStr->startsWith("f")  // false
    4909                  || pStr->startsWith("off")
    4910                  || pStr->contains("veto") /* paranoia */
    4911                  || pStr->toLongLong() == 0)
    4912             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_FALSE;
    4913         else
    4914         {
    4915             LogFunc(("Ignoring unknown value '%s' for '%s'\n", pStr->toUtf8().constData(), pStr == &strEnvValue ? pszEnvVar : pszExtraDataName));
    4916             *piDbgCfgVar = fDefault ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE;
    4917         }
    4918     }
    4919 }
    4920 
    4921 void UICommon::setDebuggerVar(int *piDbgCfgVar, bool fState)
    4922 {
    4923     if (!(*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_DONE))
    4924         *piDbgCfgVar = (fState ? UICOMMON_DBG_CFG_VAR_TRUE : UICOMMON_DBG_CFG_VAR_FALSE)
    4925                      | UICOMMON_DBG_CFG_VAR_CMD_LINE;
    4926 }
    4927 
    4928 bool UICommon::isDebuggerWorker(int *piDbgCfgVar, const char *pszExtraDataName) const
    4929 {
    4930     if (!(*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_DONE))
    4931     {
    4932         const QString str = gEDataManager->debugFlagValue(pszExtraDataName);
    4933         if (str.contains("veto"))
    4934             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE;
    4935         else if (str.isEmpty() || (*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_CMD_LINE))
    4936             *piDbgCfgVar |= UICOMMON_DBG_CFG_VAR_DONE;
    4937         else if (   str.startsWith("y")  // yes
    4938                  || str.startsWith("e")  // enabled
    4939                  || str.startsWith("t")  // true
    4940                  || str.startsWith("on")
    4941                  || str.toLongLong() != 0)
    4942             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_TRUE;
    4943         else if (   str.startsWith("n")  // no
    4944                  || str.startsWith("d")  // disable
    4945                  || str.startsWith("f")  // false
    4946                  || str.toLongLong() == 0)
    4947             *piDbgCfgVar = UICOMMON_DBG_CFG_VAR_DONE | UICOMMON_DBG_CFG_VAR_FALSE;
    4948         else
    4949             *piDbgCfgVar |= UICOMMON_DBG_CFG_VAR_DONE;
    4950     }
    4951 
    4952     return (*piDbgCfgVar & UICOMMON_DBG_CFG_VAR_MASK) == UICOMMON_DBG_CFG_VAR_TRUE;
    4953 }
    4954 
    4955 #endif /* VBOX_WITH_DEBUGGER_GUI */
    4956 
    4957 void UICommon::comWrappersReinit()
    4958 {
    4959     /* Re-fetch corresponding objects/values: */
    4960     m_comHost = virtualBox().GetHost();
    4961     m_strHomeFolder = virtualBox().GetHomeFolder();
    4962 
    4963     /* Re-initialize guest OS Type list: */
    4964     m_guestOSFamilyIDs.clear();
    4965     m_guestOSTypes.clear();
    4966     const CGuestOSTypeVector guestOSTypes = m_comVBox.GetGuestOSTypes();
    4967     const int cGuestOSTypeCount = guestOSTypes.size();
    4968     AssertMsg(cGuestOSTypeCount > 0, ("Number of OS types must not be zero"));
    4969     if (cGuestOSTypeCount > 0)
    4970     {
    4971         /* Here we ASSUME the 'Other' types are always the first,
    4972          * so we remember them and will append them to the list when finished.
    4973          * We do a two pass, first adding the specific types, then the two 'Other' types. */
    4974         for (int j = 0; j < 2; ++j)
    4975         {
    4976             int cMax = j == 0 ? cGuestOSTypeCount : RT_MIN(2, cGuestOSTypeCount);
    4977             for (int i = j == 0 ? 2 : 0; i < cMax; ++i)
    4978             {
    4979                 const CGuestOSType os = guestOSTypes.at(i);
    4980                 const QString strFamilyID = os.GetFamilyId();
    4981                 const QString strFamilyDescription = os.GetFamilyDescription();
    4982                 if (!m_guestOSFamilyIDs.contains(strFamilyID))
    4983                 {
    4984                     m_guestOSFamilyIDs << strFamilyID;
    4985                     m_guestOSFamilyDescriptions[strFamilyID] = strFamilyDescription;
    4986                     m_guestOSTypes << QList<CGuestOSType>();
    4987                 }
    4988                 m_guestOSTypes[m_guestOSFamilyIDs.indexOf(strFamilyID)].append(os);
    4989             }
    4990         }
    4991     }
    4992 
    4993     /* Mark wrappers valid: */
    4994     m_fWrappersValid = true;
    4995 }
  • trunk/src/VBox/Frontends/VirtualBox/src/settings/editors/UILanguageSettingsEditor.cpp

    r88794 r90941  
    2727#include "QIRichTextLabel.h"
    2828#include "QITreeWidget.h"
    29 #include "UICommon.h"
    3029#include "UILanguageSettingsEditor.h"
     30#include "UITranslator.h"
    3131
    3232/* Other VBox includes: */
     33#include <iprt/assert.h>
     34#include <iprt/err.h>
    3335#include <iprt/path.h>
    3436
     
    8688    Assert(!strId.isEmpty());
    8789
    88     /* Note: context/source/comment arguments below must match strings used in UICommon::languageName() and friends
     90    /* Note: context/source/comment arguments below must match strings used in UITranslator::languageName() and friends
    8991     *       (the latter are the source of information for the lupdate tool that generates translation files). */
    9092
     
    125127
    126128    /* Current language appears in bold: */
    127     if (text(1) == UICommon::languageId())
     129    if (text(1) == UITranslator::languageId())
    128130    {
    129131        QFont fnt = font(0);
     
    383385    const int rc = RTPathAppPrivateNoArch(szNlsPath, sizeof(szNlsPath));
    384386    AssertRC(rc);
    385     const QString strNlsPath = QString(szNlsPath) + UICommon::vboxLanguageSubDirectory();
     387    const QString strNlsPath = QString(szNlsPath) + UITranslator::vboxLanguageSubDirectory();
    386388    QDir nlsDir(strNlsPath);
    387     QStringList files = nlsDir.entryList(QStringList(QString("%1*%2").arg(UICommon::vboxLanguageFileBase(),
    388                                                                           UICommon::vboxLanguageFileExtension())),
     389    QStringList files = nlsDir.entryList(QStringList(QString("%1*%2").arg(UITranslator::vboxLanguageFileBase(),
     390                                                                          UITranslator::vboxLanguageFileExtension())),
    389391                                         QDir::Files);
    390392
     
    393395    new UILanguageItem(m_pTreeWidget);
    394396    /* Add the built-in language: */
    395     new UILanguageItem(m_pTreeWidget, translator, UICommon::vboxBuiltInLanguageName(), true /* built-in */);
     397    new UILanguageItem(m_pTreeWidget, translator, UITranslator::vboxBuiltInLanguageName(), true /* built-in */);
    396398    /* Add all existing languages */
    397399    for (QStringList::Iterator it = files.begin(); it != files.end(); ++it)
    398400    {
    399401        QString strFileName = *it;
    400         QRegExp regExp(UICommon::vboxLanguageFileBase() + UICommon::vboxLanguageIdRegExp());
     402        QRegExp regExp(UITranslator::vboxLanguageFileBase() + UITranslator::vboxLanguageIdRegExp());
    401403        int iPos = regExp.indexIn(strFileName);
    402404        if (iPos == -1)
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette