VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp@ 102493

Last change on this file since 102493 was 102482, checked in by vboxsync, 10 months ago

FE/Qt: macOS: Hardcode native Window colors as Qt has them far far away from the native apps.

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

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