VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp@ 90086

Last change on this file since 90086 was 90086, checked in by vboxsync, 4 years ago

FE/Qt: bugref:5117: Moving restoreCurrentSnapshot functionality from UISession to UICommon as it will be reused from within VirtualBox Manager code as well.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 80.1 KB
Line 
1/* $Id: UISession.cpp 90086 2021-07-08 08:51:06Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISession class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/* Qt includes: */
19#include <QApplication>
20#include <QBitmap>
21#include <QMenuBar>
22#include <QWidget>
23#ifdef VBOX_WS_MAC
24# include <QTimer>
25#endif
26#ifdef VBOX_WS_WIN
27# include <iprt/win/windows.h> /* Workaround for compile errors if included directly by QtWin. */
28# include <QtWin>
29#endif
30#ifdef VBOX_WS_X11
31# include <QX11Info>
32#endif
33
34/* GUI includes: */
35#include "UICommon.h"
36#include "UIDesktopWidgetWatchdog.h"
37#include "UIExtraDataManager.h"
38#include "UISession.h"
39#include "UIMachine.h"
40#include "UIMedium.h"
41#include "UIActionPoolRuntime.h"
42#include "UIMachineLogic.h"
43#include "UIMachineView.h"
44#include "UIMachineWindow.h"
45#include "UIMessageCenter.h"
46#include "UIMousePointerShapeData.h"
47#include "UIPopupCenter.h"
48#include "UIWizardFirstRun.h"
49#include "UIConsoleEventHandler.h"
50#include "UIFrameBuffer.h"
51#include "UISettingsDialogSpecific.h"
52#ifdef VBOX_WS_MAC
53# include "UICocoaApplication.h"
54# include "VBoxUtils-darwin.h"
55#endif
56#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
57# include "UIKeyboardHandler.h"
58# include <signal.h>
59#endif
60
61/* COM includes: */
62#include "CAudioAdapter.h"
63#include "CGraphicsAdapter.h"
64#include "CHostUSBDevice.h"
65#include "CRecordingSettings.h"
66#include "CSystemProperties.h"
67#include "CStorageController.h"
68#include "CMediumAttachment.h"
69#include "CNetworkAdapter.h"
70#include "CHostNetworkInterface.h"
71#include "CVRDEServer.h"
72#include "CUSBController.h"
73#include "CUSBDeviceFilters.h"
74#include "CHostVideoInputDevice.h"
75#include "CSnapshot.h"
76#include "CMedium.h"
77
78/* External includes: */
79#ifdef VBOX_WS_X11
80# include <X11/Xlib.h>
81# include <X11/Xutil.h>
82#endif
83
84
85#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
86static void signalHandlerSIGUSR1(int sig, siginfo_t *, void *);
87#endif
88
89#ifdef VBOX_WS_MAC
90/**
91 * MacOS X: Application Services: Core Graphics: Display reconfiguration callback.
92 *
93 * Notifies UISession about @a display configuration change.
94 * Corresponding change described by Core Graphics @a flags.
95 * Uses UISession @a pHandler to process this change.
96 *
97 * @note Last argument (@a pHandler) must always be valid pointer to UISession object.
98 * @note Calls for UISession::sltHandleHostDisplayAboutToChange() slot if display configuration changed.
99 */
100void cgDisplayReconfigurationCallback(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *pHandler)
101{
102 /* Which flags we are handling? */
103 int iHandledFlags = kCGDisplayAddFlag /* display added */
104 | kCGDisplayRemoveFlag /* display removed */
105 | kCGDisplaySetModeFlag /* display mode changed */;
106
107 /* Handle 'display-add' case: */
108 if (flags & kCGDisplayAddFlag)
109 LogRelFlow(("GUI: UISession::cgDisplayReconfigurationCallback: Display added.\n"));
110 /* Handle 'display-remove' case: */
111 else if (flags & kCGDisplayRemoveFlag)
112 LogRelFlow(("GUI: UISession::cgDisplayReconfigurationCallback: Display removed.\n"));
113 /* Handle 'mode-set' case: */
114 else if (flags & kCGDisplaySetModeFlag)
115 LogRelFlow(("GUI: UISession::cgDisplayReconfigurationCallback: Display mode changed.\n"));
116
117 /* Ask handler to process our callback: */
118 if (flags & iHandledFlags)
119 QTimer::singleShot(0, static_cast<UISession*>(pHandler),
120 SLOT(sltHandleHostDisplayAboutToChange()));
121
122 Q_UNUSED(display);
123}
124#endif /* VBOX_WS_MAC */
125
126/* static */
127bool UISession::create(UISession *&pSession, UIMachine *pMachine)
128{
129 /* Make sure null pointer passed: */
130 AssertReturn(pSession == 0, false);
131
132 /* Create session UI: */
133 pSession = new UISession(pMachine);
134 /* Make sure it's prepared: */
135 if (!pSession->prepare())
136 {
137 /* Destroy session UI otherwise: */
138 destroy(pSession);
139 /* False in that case: */
140 return false;
141 }
142 /* True by default: */
143 return true;
144}
145
146/* static */
147void UISession::destroy(UISession *&pSession)
148{
149 /* Make sure valid pointer passed: */
150 AssertReturnVoid(pSession != 0);
151
152 /* Cleanup session UI: */
153 pSession->cleanup();
154 /* Destroy session: */
155 delete pSession;
156 pSession = 0;
157}
158
159bool UISession::initialize()
160{
161 /* Preprocess initialization: */
162 if (!preprocessInitialization())
163 return false;
164
165 /* Notify user about mouse&keyboard auto-capturing: */
166 if (gEDataManager->autoCaptureEnabled())
167 popupCenter().remindAboutAutoCapture(activeMachineWindow());
168
169 /* Check if we are in teleportation waiting mode.
170 * In that case no first run wizard is necessary. */
171 m_machineState = machine().GetState();
172 if ( isFirstTimeStarted()
173 && !(( m_machineState == KMachineState_PoweredOff
174 || m_machineState == KMachineState_Aborted
175 || m_machineState == KMachineState_Teleported)
176 && machine().GetTeleporterEnabled()))
177 {
178 UISafePointerWizard pWizard = new UIWizardFirstRun(mainMachineWindow(), machine());
179 pWizard->prepare();
180 pWizard->exec();
181 if (pWizard)
182 delete pWizard;
183 }
184
185 /* Apply debug settings from the command line. */
186 if (!debugger().isNull() && debugger().isOk())
187 {
188 if (uiCommon().isPatmDisabled())
189 debugger().SetPATMEnabled(false);
190 if (uiCommon().isCsamDisabled())
191 debugger().SetCSAMEnabled(false);
192 if (uiCommon().isSupervisorCodeExecedRecompiled())
193 debugger().SetRecompileSupervisor(true);
194 if (uiCommon().isUserCodeExecedRecompiled())
195 debugger().SetRecompileUser(true);
196 if (uiCommon().areWeToExecuteAllInIem())
197 debugger().SetExecuteAllInIEM(true);
198 if (!uiCommon().isDefaultWarpPct())
199 debugger().SetVirtualTimeRate(uiCommon().getWarpPct());
200 }
201
202 /* Apply ad-hoc reconfigurations from the command line: */
203 if (uiCommon().hasFloppyImageToMount())
204 mountAdHocImage(KDeviceType_Floppy, UIMediumDeviceType_Floppy, uiCommon().getFloppyImage().toString());
205 if (uiCommon().hasDvdImageToMount())
206 mountAdHocImage(KDeviceType_DVD, UIMediumDeviceType_DVD, uiCommon().getDvdImage().toString());
207
208 /* Power UP if this is NOT separate process: */
209 if (!uiCommon().isSeparateProcess())
210 if (!powerUp())
211 return false;
212
213 /* Make sure all the pending Console events converted to signals
214 * during the powerUp() progress above reached their destinations.
215 * That is necessary to make sure all the pending machine state change events processed.
216 * We can't just use the machine state directly acquired from IMachine because there
217 * will be few places which are using stale machine state, not just this one. */
218 QApplication::sendPostedEvents(0, QEvent::MetaCall);
219
220 /* Check if we missed a really quick termination after successful startup: */
221 if (isTurnedOff())
222 {
223 LogRel(("GUI: Aborting startup due to invalid machine state detected: %d\n", machineState()));
224 return false;
225 }
226
227 /* Postprocess initialization: */
228 if (!postprocessInitialization())
229 return false;
230
231 /* Fetch corresponding states: */
232 if (uiCommon().isSeparateProcess())
233 {
234 m_fIsMouseSupportsAbsolute = mouse().GetAbsoluteSupported();
235 m_fIsMouseSupportsRelative = mouse().GetRelativeSupported();
236 m_fIsMouseSupportsMultiTouch = mouse().GetMultiTouchSupported();
237 m_fIsMouseHostCursorNeeded = mouse().GetNeedsHostCursor();
238 sltAdditionsChange();
239 }
240 machineLogic()->initializePostPowerUp();
241
242 /* Load VM settings: */
243 loadVMSettings();
244
245/* Log whether HID LEDs sync is enabled: */
246#if defined(VBOX_WS_MAC) || defined(VBOX_WS_WIN)
247 LogRel(("GUI: HID LEDs sync is %s\n",
248 uimachine()->machineLogic()->isHidLedsSyncEnabled()
249 ? "enabled" : "disabled"));
250#else /* !VBOX_WS_MAC && !VBOX_WS_WIN */
251 LogRel(("GUI: HID LEDs sync is not supported on this platform\n"));
252#endif /* !VBOX_WS_MAC && !VBOX_WS_WIN */
253
254#ifdef VBOX_GUI_WITH_PIDFILE
255 uiCommon().createPidfile();
256#endif /* VBOX_GUI_WITH_PIDFILE */
257
258 /* Warn listeners about we are initialized: */
259 m_fInitialized = true;
260 emit sigInitialized();
261
262 /* True by default: */
263 return true;
264}
265
266bool UISession::powerUp()
267{
268 /* Power UP machine: */
269 CProgress progress = uiCommon().shouldStartPaused() ? console().PowerUpPaused() : console().PowerUp();
270
271 /* Check for immediate failure: */
272 if (!console().isOk() || progress.isNull())
273 {
274 if (uiCommon().showStartVMErrors())
275 msgCenter().cannotStartMachine(console(), machineName());
276 LogRel(("GUI: Aborting startup due to power up issue detected...\n"));
277 return false;
278 }
279
280 /* Some logging right after we powered up: */
281 LogRel(("Qt version: %s\n", UICommon::qtRTVersionString().toUtf8().constData()));
282#ifdef VBOX_WS_X11
283 LogRel(("X11 Window Manager code: %d\n", (int)uiCommon().typeOfWindowManager()));
284#endif
285
286 /* Enable 'manual-override',
287 * preventing automatic Runtime UI closing
288 * and visual representation mode changes: */
289 if (machineLogic())
290 machineLogic()->setManualOverrideMode(true);
291
292 /* Show "Starting/Restoring" progress dialog: */
293 if (isSaved())
294 {
295 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_state_restore_90px.png", 0, 0);
296 /* After restoring from 'saved' state, machine-window(s) geometry should be adjusted: */
297 machineLogic()->adjustMachineWindowsGeometry();
298 }
299 else
300 {
301 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_start_90px.png");
302 /* After VM start, machine-window(s) size-hint(s) should be sent: */
303 machineLogic()->sendMachineWindowsSizeHints();
304 }
305
306 /* Check for progress failure: */
307 if (!progress.isOk() || progress.GetResultCode() != 0)
308 {
309 if (uiCommon().showStartVMErrors())
310 msgCenter().cannotStartMachine(progress, machineName());
311 LogRel(("GUI: Aborting startup due to power up progress issue detected...\n"));
312 return false;
313 }
314
315 /* Disable 'manual-override' finally: */
316 if (machineLogic())
317 machineLogic()->setManualOverrideMode(false);
318
319 /* True by default: */
320 return true;
321}
322
323bool UISession::detach()
324{
325 /* Nothing here for now: */
326 return true;
327}
328
329bool UISession::saveState()
330{
331 /* Prepare the saving progress: */
332 CProgress progress = machine().SaveState();
333 if (machine().isOk())
334 {
335 /* Show the saving progress: */
336 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_state_save_90px.png");
337 if (!progress.isOk() || progress.GetResultCode() != 0)
338 {
339 /* Failed in progress: */
340 msgCenter().cannotSaveMachineState(progress, machineName());
341 return false;
342 }
343 }
344 else
345 {
346 /* Failed in console: */
347 msgCenter().cannotSaveMachineState(machine());
348 return false;
349 }
350 /* Passed: */
351 return true;
352}
353
354bool UISession::shutdown()
355{
356 /* Send ACPI shutdown signal if possible: */
357 console().PowerButton();
358 if (!console().isOk())
359 {
360 /* Failed in console: */
361 msgCenter().cannotACPIShutdownMachine(console());
362 return false;
363 }
364 /* Passed: */
365 return true;
366}
367
368bool UISession::powerOff(bool fIncludingDiscard, bool &fServerCrashed)
369{
370 /* Prepare the power-off progress: */
371 LogRel(("GUI: Powering VM down on UI session power off request...\n"));
372 CProgress progress = console().PowerDown();
373 if (console().isOk())
374 {
375 /* Show the power-off progress: */
376 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_poweroff_90px.png");
377 if (progress.isOk() && progress.GetResultCode() == 0)
378 {
379 /* Discard the current state if requested: */
380 if (fIncludingDiscard)
381 return uiCommon().restoreCurrentSnapshot(uiCommon().managedVMUuid());
382 }
383 else
384 {
385 /* Failed in progress: */
386 msgCenter().cannotPowerDownMachine(progress, machineName());
387 return false;
388 }
389 }
390 else
391 {
392 /* Check the machine state, it might be already gone: */
393 if (!console().isNull())
394 {
395 /* Failed in console: */
396 COMResult res(console());
397 /* This can happen if VBoxSVC is not running: */
398 if (FAILED_DEAD_INTERFACE(res.rc()))
399 fServerCrashed = true;
400 else
401 msgCenter().cannotPowerDownMachine(console());
402 return false;
403 }
404 }
405 /* Passed: */
406 return true;
407}
408
409UIMachineLogic* UISession::machineLogic() const
410{
411 return uimachine() ? uimachine()->machineLogic() : 0;
412}
413
414QWidget* UISession::mainMachineWindow() const
415{
416 return machineLogic() ? machineLogic()->mainMachineWindow() : 0;
417}
418
419WId UISession::mainMachineWindowId() const
420{
421 return mainMachineWindow()->winId();
422}
423
424UIMachineWindow *UISession::activeMachineWindow() const
425{
426 return machineLogic() ? machineLogic()->activeMachineWindow() : 0;
427}
428
429bool UISession::isVisualStateAllowed(UIVisualStateType state) const
430{
431 return m_pMachine->isVisualStateAllowed(state);
432}
433
434void UISession::changeVisualState(UIVisualStateType visualStateType)
435{
436 m_pMachine->asyncChangeVisualState(visualStateType);
437}
438
439void UISession::setRequestedVisualState(UIVisualStateType visualStateType)
440{
441 m_pMachine->setRequestedVisualState(visualStateType);
442}
443
444UIVisualStateType UISession::requestedVisualState() const
445{
446 return m_pMachine->requestedVisualState();
447}
448
449bool UISession::setPause(bool fOn)
450{
451 if (fOn)
452 console().Pause();
453 else
454 console().Resume();
455
456 bool ok = console().isOk();
457 if (!ok)
458 {
459 if (fOn)
460 msgCenter().cannotPauseMachine(console());
461 else
462 msgCenter().cannotResumeMachine(console());
463 }
464
465 return ok;
466}
467
468void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
469{
470 /* This flag indicates whether we want to do the usual .ISO mounting or not.
471 * First try updating the Guest Additions directly without mounting the .ISO. */
472 bool fDoMount = false;
473
474 /* Auto-update through GUI is currently disabled. */
475#ifndef VBOX_WITH_ADDITIONS_AUTOUPDATE_UI
476 fDoMount = true;
477#else /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
478 /* Initiate installation progress: */
479 QVector<QString> aArgs;
480 QVector<KAdditionsUpdateFlag> aFlagsUpdate;
481 CProgress comProgressInstall = guest().UpdateGuestAdditions(strSource, aArgs, aFlagsUpdate);
482 if (guest().isOk() && comProgressInstall.isNotNull())
483 {
484 /* Show installation progress: */
485 msgCenter().showModalProgressDialog(comProgressInstall, tr("Updating Guest Additions"),
486 ":/progress_install_guest_additions_90px.png",
487 0, 500 /* 500ms delay. */);
488 if (comProgressInstall.GetCanceled())
489 return;
490
491 /* Check whether progress result isn't Ok: */
492 const HRESULT rc = comProgressInstall.GetResultCode();
493 if (!comProgressInstall.isOk() || rc != S_OK)
494 {
495 /* If we got back a VBOX_E_NOT_SUPPORTED we don't complain (guest OS simply isn't
496 * supported yet), so silently fall back to "old" .ISO mounting method. */
497 if ( !SUCCEEDED_WARNING(rc)
498 && rc != VBOX_E_NOT_SUPPORTED)
499 {
500 msgCenter().cannotUpdateGuestAdditions(comProgressInstall);
501
502 /* Throw the error message into release log as well: */
503 const QString &strErr = comProgressInstall.GetErrorInfo().GetText();
504 if (!strErr.isEmpty())
505 LogRel(("%s\n", strErr.toLatin1().constData()));
506 }
507
508 /* Since automatic updating failed, fall back to .ISO mounting: */
509 fDoMount = true;
510 }
511 }
512#endif /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
513
514 /* Check whether we still want mounting? */
515 if (!fDoMount)
516 return;
517
518 /* Mount medium add-hoc: */
519 mountAdHocImage(KDeviceType_DVD, UIMediumDeviceType_DVD, strSource);
520}
521
522void UISession::sltDetachCOM()
523{
524 /* Cleanup everything COM related: */
525 cleanupFramebuffers();
526 cleanupConsoleEventHandlers();
527 cleanupSession();
528}
529
530void UISession::sltCloseRuntimeUI()
531{
532 /* Ask UIMachine to close Runtime UI: */
533 uimachine()->closeRuntimeUI();
534}
535
536#ifdef RT_OS_DARWIN
537void UISession::sltHandleMenuBarConfigurationChange(const QUuid &uMachineID)
538{
539 /* Skip unrelated machine IDs: */
540 if (uiCommon().managedVMUuid() != uMachineID)
541 return;
542
543 /* Update Mac OS X menu-bar: */
544 updateMenu();
545}
546#endif /* RT_OS_DARWIN */
547
548void UISession::sltMousePointerShapeChange(const UIMousePointerShapeData &shapeData)
549{
550 /* In case if shape itself is present: */
551 if (shapeData.shape().size() > 0)
552 {
553 /* We are ignoring visibility flag: */
554 m_fIsHidingHostPointer = false;
555
556 /* And updating current shape data: */
557 m_shapeData = shapeData;
558 updateMousePointerShape();
559 }
560 /* In case if shape itself is NOT present: */
561 else
562 {
563 /* Remember if we should hide the cursor: */
564 m_fIsHidingHostPointer = !shapeData.isVisible();
565 }
566
567 /* Notify listeners about mouse capability changed: */
568 emit sigMousePointerShapeChange();
569}
570
571void UISession::sltMouseCapabilityChange(bool fSupportsAbsolute, bool fSupportsRelative, bool fSupportsMultiTouch, bool fNeedsHostCursor)
572{
573 LogRelFlow(("GUI: UISession::sltMouseCapabilityChange: "
574 "Supports absolute: %s, Supports relative: %s, "
575 "Supports multi-touch: %s, Needs host cursor: %s\n",
576 fSupportsAbsolute ? "TRUE" : "FALSE", fSupportsRelative ? "TRUE" : "FALSE",
577 fSupportsMultiTouch ? "TRUE" : "FALSE", fNeedsHostCursor ? "TRUE" : "FALSE"));
578
579 /* Check if something had changed: */
580 if ( m_fIsMouseSupportsAbsolute != fSupportsAbsolute
581 || m_fIsMouseSupportsRelative != fSupportsRelative
582 || m_fIsMouseSupportsMultiTouch != fSupportsMultiTouch
583 || m_fIsMouseHostCursorNeeded != fNeedsHostCursor)
584 {
585 /* Store new data: */
586 m_fIsMouseSupportsAbsolute = fSupportsAbsolute;
587 m_fIsMouseSupportsRelative = fSupportsRelative;
588 m_fIsMouseSupportsMultiTouch = fSupportsMultiTouch;
589 m_fIsMouseHostCursorNeeded = fNeedsHostCursor;
590
591 /* Notify listeners about mouse capability changed: */
592 emit sigMouseCapabilityChange();
593 }
594}
595
596void UISession::sltCursorPositionChange(bool fContainsData, unsigned long uX, unsigned long uY)
597{
598 LogRelFlow(("GUI: UISession::sltCursorPositionChange: "
599 "Cursor position valid: %d, Cursor position: %dx%d\n",
600 fContainsData ? "TRUE" : "FALSE", uX, uY));
601
602 /* Check if something had changed: */
603 if ( m_fIsValidCursorPositionPresent != fContainsData
604 || m_cursorPosition.x() != (int)uX
605 || m_cursorPosition.y() != (int)uY)
606 {
607 /* Store new data: */
608 m_fIsValidCursorPositionPresent = fContainsData;
609 m_cursorPosition = QPoint(uX, uY);
610
611 /* Notify listeners about cursor position changed: */
612 emit sigCursorPositionChange();
613 }
614}
615
616void UISession::sltKeyboardLedsChangeEvent(bool fNumLock, bool fCapsLock, bool fScrollLock)
617{
618 /* Check if something had changed: */
619 if ( m_fNumLock != fNumLock
620 || m_fCapsLock != fCapsLock
621 || m_fScrollLock != fScrollLock)
622 {
623 /* Store new num lock data: */
624 if (m_fNumLock != fNumLock)
625 {
626 m_fNumLock = fNumLock;
627 m_uNumLockAdaptionCnt = 2;
628 }
629
630 /* Store new caps lock data: */
631 if (m_fCapsLock != fCapsLock)
632 {
633 m_fCapsLock = fCapsLock;
634 m_uCapsLockAdaptionCnt = 2;
635 }
636
637 /* Store new scroll lock data: */
638 if (m_fScrollLock != fScrollLock)
639 {
640 m_fScrollLock = fScrollLock;
641 }
642
643 /* Notify listeners about mouse capability changed: */
644 emit sigKeyboardLedsChange();
645 }
646}
647
648void UISession::sltStateChange(KMachineState state)
649{
650 /* Check if something had changed: */
651 if (m_machineState != state)
652 {
653 /* Store new data: */
654 m_machineStatePrevious = m_machineState;
655 m_machineState = state;
656
657 /* Notify listeners about machine state changed: */
658 emit sigMachineStateChange();
659 }
660}
661
662void UISession::sltVRDEChange()
663{
664 /* Make sure VRDE server is present: */
665 const CVRDEServer server = machine().GetVRDEServer();
666 AssertMsgReturnVoid(machine().isOk() && !server.isNull(),
667 ("VRDE server should NOT be null!\n"));
668
669 /* Check/Uncheck VRDE Server action depending on feature status: */
670 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->blockSignals(true);
671 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->setChecked(server.GetEnabled());
672 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->blockSignals(false);
673
674 /* Notify listeners about VRDE change: */
675 emit sigVRDEChange();
676}
677
678void UISession::sltRecordingChange()
679{
680 CRecordingSettings comRecordingSettings = machine().GetRecordingSettings();
681
682 /* Check/Uncheck Capture action depending on feature status: */
683 actionPool()->action(UIActionIndexRT_M_View_M_Recording_T_Start)->blockSignals(true);
684 actionPool()->action(UIActionIndexRT_M_View_M_Recording_T_Start)->setChecked(comRecordingSettings.GetEnabled());
685 actionPool()->action(UIActionIndexRT_M_View_M_Recording_T_Start)->blockSignals(false);
686
687 /* Notify listeners about Recording change: */
688 emit sigRecordingChange();
689}
690
691void UISession::sltGuestMonitorChange(KGuestMonitorChangedEventType changeType, ulong uScreenId, QRect screenGeo)
692{
693 /* Ignore KGuestMonitorChangedEventType_NewOrigin change event: */
694 if (changeType == KGuestMonitorChangedEventType_NewOrigin)
695 return;
696 /* Ignore KGuestMonitorChangedEventType_Disabled event for primary screen: */
697 AssertMsg(countOfVisibleWindows() > 0, ("All machine windows are hidden!"));
698 if (changeType == KGuestMonitorChangedEventType_Disabled && uScreenId == 0)
699 return;
700
701 /* Process KGuestMonitorChangedEventType_Enabled change event: */
702 if ( !isScreenVisible(uScreenId)
703 && changeType == KGuestMonitorChangedEventType_Enabled)
704 setScreenVisible(uScreenId, true);
705 /* Process KGuestMonitorChangedEventType_Disabled change event: */
706 else if ( isScreenVisible(uScreenId)
707 && changeType == KGuestMonitorChangedEventType_Disabled)
708 setScreenVisible(uScreenId, false);
709
710 /* Notify listeners about the change: */
711 emit sigGuestMonitorChange(changeType, uScreenId, screenGeo);
712}
713
714void UISession::sltHandleStorageDeviceChange(const CMediumAttachment &attachment, bool fRemoved, bool fSilent)
715{
716 /* Update action restrictions: */
717 updateActionRestrictions();
718
719 /* Notify listeners about storage device change: */
720 emit sigStorageDeviceChange(attachment, fRemoved, fSilent);
721}
722
723void UISession::sltAudioAdapterChange()
724{
725 /* Make sure Audio adapter is present: */
726 const CAudioAdapter comAdapter = machine().GetAudioAdapter();
727 AssertMsgReturnVoid(machine().isOk() && comAdapter.isNotNull(),
728 ("Audio adapter should NOT be null!\n"));
729
730 /* Check/Uncheck Audio adapter output/input actions depending on features status: */
731 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->blockSignals(true);
732 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->setChecked(comAdapter.GetEnabledOut());
733 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->blockSignals(false);
734 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->blockSignals(true);
735 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->setChecked(comAdapter.GetEnabledIn());
736 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->blockSignals(false);
737
738 /* Notify listeners about Audio adapter change: */
739 emit sigAudioAdapterChange();
740
741}
742
743void UISession::sltClipboardModeChange(KClipboardMode enmMode)
744{
745 emit sigClipboardModeChange(enmMode);
746}
747
748void UISession::sltDnDModeChange(KDnDMode enmMode)
749{
750 emit sigDnDModeChange(enmMode);
751}
752
753#ifdef RT_OS_DARWIN
754/**
755 * MacOS X: Restarts display-reconfiguration watchdog timer from the beginning.
756 * @note Watchdog is trying to determine display reconfiguration in
757 * UISession::sltCheckIfHostDisplayChanged() slot every 500ms for 40 tries.
758 */
759void UISession::sltHandleHostDisplayAboutToChange()
760{
761 LogRelFlow(("GUI: UISession::sltHandleHostDisplayAboutToChange()\n"));
762
763 if (m_pWatchdogDisplayChange->isActive())
764 m_pWatchdogDisplayChange->stop();
765 m_pWatchdogDisplayChange->setProperty("tryNumber", 1);
766 m_pWatchdogDisplayChange->start();
767}
768
769/**
770 * MacOS X: Determines display reconfiguration.
771 * @note Calls for UISession::sltHandleHostScreenCountChange() if screen count changed.
772 * @note Calls for UISession::sltHandleHostScreenGeometryChange() if screen geometry changed.
773 */
774void UISession::sltCheckIfHostDisplayChanged()
775{
776 LogRelFlow(("GUI: UISession::sltCheckIfHostDisplayChanged()\n"));
777
778 /* Check if display count changed: */
779 if (gpDesktop->screenCount() != m_hostScreens.size())
780 {
781 /* Reset watchdog: */
782 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
783 /* Notify listeners about screen-count changed: */
784 return sltHandleHostScreenCountChange();
785 }
786 else
787 {
788 /* Check if at least one display geometry changed: */
789 for (int iScreenIndex = 0; iScreenIndex < gpDesktop->screenCount(); ++iScreenIndex)
790 {
791 if (gpDesktop->screenGeometry(iScreenIndex) != m_hostScreens.at(iScreenIndex))
792 {
793 /* Reset watchdog: */
794 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
795 /* Notify listeners about screen-geometry changed: */
796 return sltHandleHostScreenGeometryChange();
797 }
798 }
799 }
800
801 /* Check if watchdog expired, restart if not: */
802 int cTryNumber = m_pWatchdogDisplayChange->property("tryNumber").toInt();
803 if (cTryNumber > 0 && cTryNumber < 40)
804 {
805 /* Restart watchdog again: */
806 m_pWatchdogDisplayChange->setProperty("tryNumber", ++cTryNumber);
807 m_pWatchdogDisplayChange->start();
808 }
809 else
810 {
811 /* Reset watchdog: */
812 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
813 }
814}
815#endif /* RT_OS_DARWIN */
816
817void UISession::sltHandleHostScreenCountChange()
818{
819 LogRelFlow(("GUI: UISession: Host-screen count changed.\n"));
820
821 /* Recache display data: */
822 updateHostScreenData();
823
824 /* Notify current machine-logic: */
825 emit sigHostScreenCountChange();
826}
827
828void UISession::sltHandleHostScreenGeometryChange()
829{
830 LogRelFlow(("GUI: UISession: Host-screen geometry changed.\n"));
831
832 /* Recache display data: */
833 updateHostScreenData();
834
835 /* Notify current machine-logic: */
836 emit sigHostScreenGeometryChange();
837}
838
839void UISession::sltHandleHostScreenAvailableAreaChange()
840{
841 LogRelFlow(("GUI: UISession: Host-screen available-area changed.\n"));
842
843 /* Notify current machine-logic: */
844 emit sigHostScreenAvailableAreaChange();
845}
846
847void UISession::sltAdditionsChange()
848{
849 /* Variable flags: */
850 ULONG ulGuestAdditionsRunLevel = guest().GetAdditionsRunLevel();
851 LONG64 lLastUpdatedIgnored;
852 bool fIsGuestSupportsGraphics = guest().GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
853 == KAdditionsFacilityStatus_Active;
854 bool fIsGuestSupportsSeamless = guest().GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
855 == KAdditionsFacilityStatus_Active;
856 /* Check if something had changed: */
857 if (m_ulGuestAdditionsRunLevel != ulGuestAdditionsRunLevel ||
858 m_fIsGuestSupportsGraphics != fIsGuestSupportsGraphics ||
859 m_fIsGuestSupportsSeamless != fIsGuestSupportsSeamless)
860 {
861 /* Store new data: */
862 m_ulGuestAdditionsRunLevel = ulGuestAdditionsRunLevel;
863 m_fIsGuestSupportsGraphics = fIsGuestSupportsGraphics;
864 m_fIsGuestSupportsSeamless = fIsGuestSupportsSeamless;
865
866 /* Make sure action-pool knows whether GA supports graphics: */
867 actionPool()->toRuntime()->setGuestSupportsGraphics(m_fIsGuestSupportsGraphics);
868
869 /* Notify listeners about GA state really changed: */
870 LogRel(("GUI: UISession::sltAdditionsChange: GA state really changed, notifying listeners\n"));
871 emit sigAdditionsStateActualChange();
872 }
873
874 /* Notify listeners about GA state change event came: */
875 LogRel(("GUI: UISession::sltAdditionsChange: GA state change event came, notifying listeners\n"));
876 emit sigAdditionsStateChange();
877}
878
879UISession::UISession(UIMachine *pMachine)
880 : QObject(pMachine)
881 /* Base variables: */
882 , m_pMachine(pMachine)
883 , m_pActionPool(0)
884#ifdef VBOX_WS_MAC
885 , m_pMenuBar(0)
886#endif /* VBOX_WS_MAC */
887 /* Common variables: */
888 , m_machineStatePrevious(KMachineState_Null)
889 , m_machineState(KMachineState_Null)
890 , m_pMachineWindowIcon(0)
891#ifdef VBOX_WS_MAC
892 , m_pWatchdogDisplayChange(0)
893#endif /* VBOX_WS_MAC */
894 , m_defaultCloseAction(MachineCloseAction_Invalid)
895 , m_restrictedCloseActions(MachineCloseAction_Invalid)
896 , m_fAllCloseActionsRestricted(false)
897 /* Common flags: */
898 , m_fInitialized(false)
899 , m_fIsFirstTimeStarted(false)
900 , m_fIsGuestResizeIgnored(false)
901 , m_fIsAutoCaptureDisabled(false)
902 /* Guest additions flags: */
903 , m_ulGuestAdditionsRunLevel(0)
904 , m_fIsGuestSupportsGraphics(false)
905 , m_fIsGuestSupportsSeamless(false)
906 /* Mouse flags: */
907 , m_fNumLock(false)
908 , m_fCapsLock(false)
909 , m_fScrollLock(false)
910 , m_uNumLockAdaptionCnt(2)
911 , m_uCapsLockAdaptionCnt(2)
912 /* Mouse flags: */
913 , m_fIsMouseSupportsAbsolute(false)
914 , m_fIsMouseSupportsRelative(false)
915 , m_fIsMouseSupportsMultiTouch(false)
916 , m_fIsMouseHostCursorNeeded(false)
917 , m_fIsMouseCaptured(false)
918 , m_fIsMouseIntegrated(true)
919 , m_fIsValidPointerShapePresent(false)
920 , m_fIsHidingHostPointer(true)
921 , m_fIsValidCursorPositionPresent(false)
922 , m_enmVMExecutionEngine(KVMExecutionEngine_NotSet)
923 /* CPU hardware virtualization features for VM: */
924 , m_fIsHWVirtExNestedPagingEnabled(false)
925 , m_fIsHWVirtExUXEnabled(false)
926 /* VM's effective paravirtualization provider: */
927 , m_paraVirtProvider(KParavirtProvider_None)
928{
929}
930
931UISession::~UISession()
932{
933}
934
935bool UISession::prepare()
936{
937 /* Prepare COM stuff: */
938 if (!prepareSession())
939 return false;
940 prepareConsoleEventHandlers();
941 prepareFramebuffers();
942
943 /* Prepare GUI stuff: */
944 prepareActions();
945 prepareConnections();
946 prepareMachineWindowIcon();
947 prepareScreens();
948 prepareSignalHandling();
949
950 /* Load settings: */
951 loadSessionSettings();
952
953 /* True by default: */
954 return true;
955}
956
957bool UISession::prepareSession()
958{
959 /* Open session: */
960 m_session = uiCommon().openSession(uiCommon().managedVMUuid(),
961 uiCommon().isSeparateProcess()
962 ? KLockType_Shared
963 : KLockType_VM);
964 if (m_session.isNull())
965 return false;
966
967 /* Get machine: */
968 m_machine = m_session.GetMachine();
969 if (m_machine.isNull())
970 return false;
971
972 /* Get console: */
973 m_console = m_session.GetConsole();
974 if (m_console.isNull())
975 return false;
976
977 /* Get display: */
978 m_display = m_console.GetDisplay();
979 if (m_display.isNull())
980 return false;
981
982 /* Get guest: */
983 m_guest = m_console.GetGuest();
984 if (m_guest.isNull())
985 return false;
986
987 /* Get mouse: */
988 m_mouse = m_console.GetMouse();
989 if (m_mouse.isNull())
990 return false;
991
992 /* Get keyboard: */
993 m_keyboard = m_console.GetKeyboard();
994 if (m_keyboard.isNull())
995 return false;
996
997 /* Get debugger: */
998 m_debugger = m_console.GetDebugger();
999 if (m_debugger.isNull())
1000 return false;
1001
1002 /* Update machine-name: */
1003 m_strMachineName = machine().GetName();
1004
1005 /* Update machine-state: */
1006 m_machineState = machine().GetState();
1007
1008 /* True by default: */
1009 return true;
1010}
1011
1012void UISession::prepareConsoleEventHandlers()
1013{
1014 /* Create console event-handler: */
1015 UIConsoleEventHandler::create(this);
1016
1017 /* Add console event connections: */
1018 connect(gConsoleEvents, &UIConsoleEventHandler::sigMousePointerShapeChange,
1019 this, &UISession::sltMousePointerShapeChange);
1020 connect(gConsoleEvents, &UIConsoleEventHandler::sigMouseCapabilityChange,
1021 this, &UISession::sltMouseCapabilityChange);
1022 connect(gConsoleEvents, &UIConsoleEventHandler::sigCursorPositionChange,
1023 this, &UISession::sltCursorPositionChange);
1024 connect(gConsoleEvents, &UIConsoleEventHandler::sigKeyboardLedsChangeEvent,
1025 this, &UISession::sltKeyboardLedsChangeEvent);
1026 connect(gConsoleEvents, &UIConsoleEventHandler::sigStateChange,
1027 this, &UISession::sltStateChange);
1028 connect(gConsoleEvents, &UIConsoleEventHandler::sigAdditionsChange,
1029 this, &UISession::sltAdditionsChange);
1030 connect(gConsoleEvents, &UIConsoleEventHandler::sigVRDEChange,
1031 this, &UISession::sltVRDEChange);
1032 connect(gConsoleEvents, &UIConsoleEventHandler::sigRecordingChange,
1033 this, &UISession::sltRecordingChange);
1034 connect(gConsoleEvents, &UIConsoleEventHandler::sigNetworkAdapterChange,
1035 this, &UISession::sigNetworkAdapterChange);
1036 connect(gConsoleEvents, &UIConsoleEventHandler::sigStorageDeviceChange,
1037 this, &UISession::sltHandleStorageDeviceChange);
1038 connect(gConsoleEvents, &UIConsoleEventHandler::sigMediumChange,
1039 this, &UISession::sigMediumChange);
1040 connect(gConsoleEvents, &UIConsoleEventHandler::sigUSBControllerChange,
1041 this, &UISession::sigUSBControllerChange);
1042 connect(gConsoleEvents, &UIConsoleEventHandler::sigUSBDeviceStateChange,
1043 this, &UISession::sigUSBDeviceStateChange);
1044 connect(gConsoleEvents, &UIConsoleEventHandler::sigSharedFolderChange,
1045 this, &UISession::sigSharedFolderChange);
1046 connect(gConsoleEvents, &UIConsoleEventHandler::sigRuntimeError,
1047 this, &UISession::sigRuntimeError);
1048#ifdef VBOX_WS_MAC
1049 connect(gConsoleEvents, &UIConsoleEventHandler::sigShowWindow,
1050 this, &UISession::sigShowWindows, Qt::QueuedConnection);
1051#endif /* VBOX_WS_MAC */
1052 connect(gConsoleEvents, &UIConsoleEventHandler::sigCPUExecutionCapChange,
1053 this, &UISession::sigCPUExecutionCapChange);
1054 connect(gConsoleEvents, &UIConsoleEventHandler::sigGuestMonitorChange,
1055 this, &UISession::sltGuestMonitorChange);
1056 connect(gConsoleEvents, &UIConsoleEventHandler::sigAudioAdapterChange,
1057 this, &UISession::sltAudioAdapterChange);
1058 connect(gConsoleEvents, &UIConsoleEventHandler::sigClipboardModeChange,
1059 this, &UISession::sltClipboardModeChange);
1060 connect(gConsoleEvents, &UIConsoleEventHandler::sigDnDModeChange,
1061 this, &UISession::sltDnDModeChange);
1062}
1063
1064void UISession::prepareFramebuffers()
1065{
1066 /* Each framebuffer will be really prepared on first UIMachineView creation: */
1067 m_frameBufferVector.resize(machine().GetGraphicsAdapter().GetMonitorCount());
1068}
1069
1070void UISession::prepareActions()
1071{
1072 /* Create action-pool: */
1073 m_pActionPool = UIActionPool::create(UIActionPoolType_Runtime);
1074 if (actionPool())
1075 {
1076 /* Make sure action-pool knows guest-screen count: */
1077 actionPool()->toRuntime()->setGuestScreenCount(m_frameBufferVector.size());
1078 /* Update action restrictions: */
1079 updateActionRestrictions();
1080
1081#ifdef VBOX_WS_MAC
1082 /* Create Mac OS X menu-bar: */
1083 m_pMenuBar = new QMenuBar;
1084 if (m_pMenuBar)
1085 {
1086 /* Configure Mac OS X menu-bar: */
1087 connect(gEDataManager, &UIExtraDataManager::sigMenuBarConfigurationChange,
1088 this, &UISession::sltHandleMenuBarConfigurationChange);
1089 /* Update Mac OS X menu-bar: */
1090 updateMenu();
1091 }
1092#endif /* VBOX_WS_MAC */
1093 }
1094}
1095
1096void UISession::prepareConnections()
1097{
1098 /* UICommon connections: */
1099 connect(&uiCommon(), &UICommon::sigAskToDetachCOM, this, &UISession::sltDetachCOM);
1100
1101#ifdef VBOX_WS_MAC
1102 /* Install native display reconfiguration callback: */
1103 CGDisplayRegisterReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1104#else /* !VBOX_WS_MAC */
1105 /* Install Qt display reconfiguration callbacks: */
1106 connect(gpDesktop, &UIDesktopWidgetWatchdog::sigHostScreenCountChanged,
1107 this, &UISession::sltHandleHostScreenCountChange);
1108 connect(gpDesktop, &UIDesktopWidgetWatchdog::sigHostScreenResized,
1109 this, &UISession::sltHandleHostScreenGeometryChange);
1110# if defined(VBOX_WS_X11) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
1111 connect(gpDesktop, &UIDesktopWidgetWatchdog::sigHostScreenWorkAreaRecalculated,
1112 this, &UISession::sltHandleHostScreenAvailableAreaChange);
1113# else /* !VBOX_WS_X11 || VBOX_GUI_WITH_CUSTOMIZATIONS1 */
1114 connect(gpDesktop, &UIDesktopWidgetWatchdog::sigHostScreenWorkAreaResized,
1115 this, &UISession::sltHandleHostScreenAvailableAreaChange);
1116# endif /* !VBOX_WS_X11 || VBOX_GUI_WITH_CUSTOMIZATIONS1 */
1117#endif /* !VBOX_WS_MAC */
1118}
1119
1120void UISession::prepareMachineWindowIcon()
1121{
1122 /* Acquire user machine-window icon: */
1123 QIcon icon = uiCommon().vmUserIcon(machine());
1124 /* Use the OS type icon if user one was not set: */
1125 if (icon.isNull())
1126 icon = uiCommon().vmGuestOSTypeIcon(machine().GetOSTypeId());
1127 /* Use the default icon if nothing else works: */
1128 if (icon.isNull())
1129 icon = QIcon(":/VirtualBox_48px.png");
1130 /* Store the icon dynamically: */
1131 m_pMachineWindowIcon = new QIcon(icon);
1132}
1133
1134void UISession::prepareScreens()
1135{
1136 /* Recache display data: */
1137 updateHostScreenData();
1138
1139#ifdef VBOX_WS_MAC
1140 /* Prepare display-change watchdog: */
1141 m_pWatchdogDisplayChange = new QTimer(this);
1142 {
1143 m_pWatchdogDisplayChange->setInterval(500);
1144 m_pWatchdogDisplayChange->setSingleShot(true);
1145 connect(m_pWatchdogDisplayChange, &QTimer::timeout,
1146 this, &UISession::sltCheckIfHostDisplayChanged);
1147 }
1148#endif /* VBOX_WS_MAC */
1149
1150 /* Prepare initial screen visibility status: */
1151 m_monitorVisibilityVector.resize(machine().GetGraphicsAdapter().GetMonitorCount());
1152 m_monitorVisibilityVector.fill(false);
1153 m_monitorVisibilityVector[0] = true;
1154
1155 /* Prepare empty last full-screen size vector: */
1156 m_monitorLastFullScreenSizeVector.resize(machine().GetGraphicsAdapter().GetMonitorCount());
1157 m_monitorLastFullScreenSizeVector.fill(QSize(-1, -1));
1158
1159 /* If machine is in 'saved' state: */
1160 if (isSaved())
1161 {
1162 /* Update screen visibility status from saved-state: */
1163 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1164 {
1165 BOOL fEnabled = true;
1166 ULONG uGuestOriginX = 0, uGuestOriginY = 0, uGuestWidth = 0, uGuestHeight = 0;
1167 machine().QuerySavedGuestScreenInfo(iScreenIndex,
1168 uGuestOriginX, uGuestOriginY,
1169 uGuestWidth, uGuestHeight, fEnabled);
1170 m_monitorVisibilityVector[iScreenIndex] = fEnabled;
1171 }
1172 /* And make sure at least one of them is visible (primary if others are hidden): */
1173 if (countOfVisibleWindows() < 1)
1174 m_monitorVisibilityVector[0] = true;
1175 }
1176 else if (uiCommon().isSeparateProcess())
1177 {
1178 /* Update screen visibility status from display directly: */
1179 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1180 {
1181 KGuestMonitorStatus enmStatus = KGuestMonitorStatus_Disabled;
1182 ULONG uGuestWidth = 0, uGuestHeight = 0, uBpp = 0;
1183 LONG iGuestOriginX = 0, iGuestOriginY = 0;
1184 display().GetScreenResolution(iScreenIndex,
1185 uGuestWidth, uGuestHeight, uBpp,
1186 iGuestOriginX, iGuestOriginY, enmStatus);
1187 m_monitorVisibilityVector[iScreenIndex] = ( enmStatus == KGuestMonitorStatus_Enabled
1188 || enmStatus == KGuestMonitorStatus_Blank);
1189 }
1190 /* And make sure at least one of them is visible (primary if others are hidden): */
1191 if (countOfVisibleWindows() < 1)
1192 m_monitorVisibilityVector[0] = true;
1193 }
1194
1195 /* Prepare initial screen visibility status of host-desires (same as facts): */
1196 m_monitorVisibilityVectorHostDesires.resize(machine().GetGraphicsAdapter().GetMonitorCount());
1197 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1198 m_monitorVisibilityVectorHostDesires[iScreenIndex] = m_monitorVisibilityVector[iScreenIndex];
1199
1200 /* Make sure action-pool knows guest-screen visibility status: */
1201 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1202 actionPool()->toRuntime()->setGuestScreenVisible(iScreenIndex, m_monitorVisibilityVector.at(iScreenIndex));
1203}
1204
1205void UISession::prepareSignalHandling()
1206{
1207#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
1208 struct sigaction sa;
1209 sa.sa_sigaction = &signalHandlerSIGUSR1;
1210 sigemptyset(&sa.sa_mask);
1211 sa.sa_flags = SA_RESTART | SA_SIGINFO;
1212 sigaction(SIGUSR1, &sa, NULL);
1213#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
1214}
1215
1216void UISession::loadSessionSettings()
1217{
1218 /* Load extra-data settings: */
1219 {
1220 /* Get machine ID: */
1221 const QUuid uMachineID = uiCommon().managedVMUuid();
1222
1223#ifndef VBOX_WS_MAC
1224 /* Load user's machine-window name postfix: */
1225 m_strMachineWindowNamePostfix = gEDataManager->machineWindowNamePostfix(uMachineID);
1226#endif
1227
1228 /* Should the First RUN wizard be here? */
1229 m_fIsFirstTimeStarted = gEDataManager->machineFirstTimeStarted(uMachineID);
1230 /* Disable First RUN wizard for subsequent start anyway: */
1231 if (m_fIsFirstTimeStarted)
1232 gEDataManager->setMachineFirstTimeStarted(false, uMachineID);
1233
1234 /* Should guest autoresize? */
1235 QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1236 pGuestAutoresizeSwitch->setChecked(gEDataManager->guestScreenAutoResizeEnabled(uMachineID));
1237
1238#ifdef VBOX_WS_MAC
1239 /* User-element (Menu-bar and Dock) options: */
1240 {
1241 const bool fDisabled = gEDataManager->guiFeatureEnabled(GUIFeatureType_NoUserElements);
1242 if (fDisabled)
1243 UICocoaApplication::instance()->hideUserElements();
1244 }
1245#else /* !VBOX_WS_MAC */
1246 /* Menu-bar options: */
1247 {
1248 const bool fEnabledGlobally = !gEDataManager->guiFeatureEnabled(GUIFeatureType_NoMenuBar);
1249 const bool fEnabledForMachine = gEDataManager->menuBarEnabled(uMachineID);
1250 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1251 QAction *pActionMenuBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_S_Settings);
1252 pActionMenuBarSettings->setEnabled(fEnabled);
1253 QAction *pActionMenuBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_T_Visibility);
1254 pActionMenuBarSwitch->blockSignals(true);
1255 pActionMenuBarSwitch->setChecked(fEnabled);
1256 pActionMenuBarSwitch->blockSignals(false);
1257 }
1258#endif /* !VBOX_WS_MAC */
1259
1260 /* Status-bar options: */
1261 {
1262 const bool fEnabledGlobally = !gEDataManager->guiFeatureEnabled(GUIFeatureType_NoStatusBar);
1263 const bool fEnabledForMachine = gEDataManager->statusBarEnabled(uMachineID);
1264 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1265 QAction *pActionStatusBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_S_Settings);
1266 pActionStatusBarSettings->setEnabled(fEnabled);
1267 QAction *pActionStatusBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility);
1268 pActionStatusBarSwitch->blockSignals(true);
1269 pActionStatusBarSwitch->setChecked(fEnabled);
1270 pActionStatusBarSwitch->blockSignals(false);
1271 }
1272
1273 /* Input options: */
1274 actionPool()->action(UIActionIndexRT_M_Input_M_Mouse_T_Integration)->setChecked(isMouseIntegrated());
1275
1276 /* Devices options: */
1277 {
1278 const CAudioAdapter comAudio = m_machine.GetAudioAdapter();
1279 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->blockSignals(true);
1280 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->setChecked(comAudio.GetEnabledOut());
1281 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->blockSignals(false);
1282 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->blockSignals(true);
1283 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->setChecked(comAudio.GetEnabledIn());
1284 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->blockSignals(false);
1285 }
1286
1287 /* What is the default close action and the restricted are? */
1288 m_defaultCloseAction = gEDataManager->defaultMachineCloseAction(uMachineID);
1289 m_restrictedCloseActions = gEDataManager->restrictedMachineCloseActions(uMachineID);
1290 m_fAllCloseActionsRestricted = (!uiCommon().isSeparateProcess() || (m_restrictedCloseActions & MachineCloseAction_Detach))
1291 && (m_restrictedCloseActions & MachineCloseAction_SaveState)
1292 && (m_restrictedCloseActions & MachineCloseAction_Shutdown)
1293 && (m_restrictedCloseActions & MachineCloseAction_PowerOff);
1294 }
1295}
1296
1297void UISession::cleanupMachineWindowIcon()
1298{
1299 /* Cleanup machine-window icon: */
1300 delete m_pMachineWindowIcon;
1301 m_pMachineWindowIcon = 0;
1302}
1303
1304void UISession::cleanupConnections()
1305{
1306#ifdef VBOX_WS_MAC
1307 /* Remove display reconfiguration callback: */
1308 CGDisplayRemoveReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1309#endif /* VBOX_WS_MAC */
1310}
1311
1312void UISession::cleanupActions()
1313{
1314#ifdef VBOX_WS_MAC
1315 /* Destroy Mac OS X menu-bar: */
1316 delete m_pMenuBar;
1317 m_pMenuBar = 0;
1318#endif /* VBOX_WS_MAC */
1319
1320 /* Destroy action-pool if necessary: */
1321 if (actionPool())
1322 UIActionPool::destroy(actionPool());
1323}
1324
1325void UISession::cleanupFramebuffers()
1326{
1327 /* Cleanup framebuffers finally: */
1328 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
1329 {
1330 UIFrameBuffer *pFrameBuffer = m_frameBufferVector[i];
1331 if (pFrameBuffer)
1332 {
1333 /* Mark framebuffer as unused: */
1334 pFrameBuffer->setMarkAsUnused(true);
1335 /* Detach framebuffer from Display: */
1336 pFrameBuffer->detach();
1337 /* Delete framebuffer reference: */
1338 delete pFrameBuffer;
1339 }
1340 }
1341 m_frameBufferVector.clear();
1342
1343 /* Make sure action-pool knows guest-screen count: */
1344 if (actionPool())
1345 actionPool()->toRuntime()->setGuestScreenCount(m_frameBufferVector.size());
1346}
1347
1348void UISession::cleanupConsoleEventHandlers()
1349{
1350 /* Destroy console event-handler if necessary: */
1351 if (gConsoleEvents)
1352 UIConsoleEventHandler::destroy();
1353}
1354
1355void UISession::cleanupSession()
1356{
1357 /* Detach debugger: */
1358 if (!m_debugger.isNull())
1359 m_debugger.detach();
1360
1361 /* Detach keyboard: */
1362 if (!m_keyboard.isNull())
1363 m_keyboard.detach();
1364
1365 /* Detach mouse: */
1366 if (!m_mouse.isNull())
1367 m_mouse.detach();
1368
1369 /* Detach guest: */
1370 if (!m_guest.isNull())
1371 m_guest.detach();
1372
1373 /* Detach display: */
1374 if (!m_display.isNull())
1375 m_display.detach();
1376
1377 /* Detach console: */
1378 if (!m_console.isNull())
1379 m_console.detach();
1380
1381 /* Detach machine: */
1382 if (!m_machine.isNull())
1383 m_machine.detach();
1384
1385 /* Close session: */
1386 if (!m_session.isNull() && uiCommon().isVBoxSVCAvailable())
1387 {
1388 m_session.UnlockMachine();
1389 m_session.detach();
1390 }
1391}
1392
1393void UISession::cleanup()
1394{
1395 /* Cleanup GUI stuff: */
1396 //cleanupSignalHandling();
1397 //cleanupScreens();
1398 cleanupMachineWindowIcon();
1399 cleanupConnections();
1400 cleanupActions();
1401}
1402
1403#ifdef VBOX_WS_MAC
1404void UISession::updateMenu()
1405{
1406 /* Rebuild Mac OS X menu-bar: */
1407 m_pMenuBar->clear();
1408 foreach (QMenu *pMenu, actionPool()->menus())
1409 {
1410 UIMenu *pMenuUI = qobject_cast<UIMenu*>(pMenu);
1411 if (!pMenuUI->isConsumable() || !pMenuUI->isConsumed())
1412 m_pMenuBar->addMenu(pMenuUI);
1413 if (pMenuUI->isConsumable() && !pMenuUI->isConsumed())
1414 pMenuUI->setConsumed(true);
1415 }
1416 /* Update the dock menu as well: */
1417 if (machineLogic())
1418 machineLogic()->updateDock();
1419}
1420#endif /* VBOX_WS_MAC */
1421
1422/** Generate a BGRA bitmap which approximates a XOR/AND mouse pointer.
1423 *
1424 * Pixels which has 1 in the AND mask and not 0 in the XOR mask are replaced by
1425 * the inverted pixel and 8 surrounding pixels with the original color.
1426 * Fort example a white pixel (W) is replaced with a black (B) pixel:
1427 * WWW
1428 * W -> WBW
1429 * WWW
1430 * The surrounding pixels are written only if the corresponding source pixel
1431 * does not affect the screen, i.e. AND bit is 1 and XOR value is 0.
1432 */
1433static void renderCursorPixels(const uint32_t *pu32XOR, const uint8_t *pu8AND,
1434 uint32_t u32Width, uint32_t u32Height,
1435 uint32_t *pu32Pixels, uint32_t cbPixels)
1436{
1437 /* Output pixels set to 0 which allow to not write transparent pixels anymore. */
1438 memset(pu32Pixels, 0, cbPixels);
1439
1440 const uint32_t *pu32XORSrc = pu32XOR; /* Iterator for source XOR pixels. */
1441 const uint8_t *pu8ANDSrcLine = pu8AND; /* The current AND mask scanline. */
1442 uint32_t *pu32Dst = pu32Pixels; /* Iterator for all destination BGRA pixels. */
1443
1444 /* Some useful constants. */
1445 const int cbANDLine = ((int)u32Width + 7) / 8;
1446
1447 int y;
1448 for (y = 0; y < (int)u32Height; ++y)
1449 {
1450 int x;
1451 for (x = 0; x < (int)u32Width; ++x)
1452 {
1453 const uint32_t u32Pixel = *pu32XORSrc; /* Current pixel at (x,y) */
1454 const uint8_t *pu8ANDSrc = pu8ANDSrcLine + x / 8; /* Byte which containt current AND bit. */
1455
1456 if ((*pu8ANDSrc << (x % 8)) & 0x80)
1457 {
1458 if (u32Pixel)
1459 {
1460 const uint32_t u32PixelInverted = ~u32Pixel;
1461
1462 /* Scan neighbor pixels and assign them if they are transparent. */
1463 int dy;
1464 for (dy = -1; dy <= 1; ++dy)
1465 {
1466 const int yn = y + dy;
1467 if (yn < 0 || yn >= (int)u32Height)
1468 continue; /* Do not cross the bounds. */
1469
1470 int dx;
1471 for (dx = -1; dx <= 1; ++dx)
1472 {
1473 const int xn = x + dx;
1474 if (xn < 0 || xn >= (int)u32Width)
1475 continue; /* Do not cross the bounds. */
1476
1477 if (dx != 0 || dy != 0)
1478 {
1479 /* Check if the neighbor pixel is transparent. */
1480 const uint32_t *pu32XORNeighborSrc = &pu32XORSrc[dy * (int)u32Width + dx];
1481 const uint8_t *pu8ANDNeighborSrc = pu8ANDSrcLine + dy * cbANDLine + xn / 8;
1482 if ( *pu32XORNeighborSrc == 0
1483 && ((*pu8ANDNeighborSrc << (xn % 8)) & 0x80) != 0)
1484 {
1485 /* Transparent neighbor pixels are replaced with the source pixel value. */
1486 uint32_t *pu32PixelNeighborDst = &pu32Dst[dy * (int)u32Width + dx];
1487 *pu32PixelNeighborDst = u32Pixel | 0xFF000000;
1488 }
1489 }
1490 else
1491 {
1492 /* The pixel itself is replaced with inverted value. */
1493 *pu32Dst = u32PixelInverted | 0xFF000000;
1494 }
1495 }
1496 }
1497 }
1498 else
1499 {
1500 /* The pixel does not affect the screen.
1501 * Do nothing. Do not touch destination which can already contain generated pixels.
1502 */
1503 }
1504 }
1505 else
1506 {
1507 /* AND bit is 0, the pixel will be just drawn. */
1508 *pu32Dst = u32Pixel | 0xFF000000;
1509 }
1510
1511 ++pu32XORSrc; /* Next source pixel. */
1512 ++pu32Dst; /* Next destination pixel. */
1513 }
1514
1515 /* Next AND scanline. */
1516 pu8ANDSrcLine += cbANDLine;
1517 }
1518}
1519
1520#ifdef VBOX_WS_WIN
1521static bool isPointer1bpp(const uint8_t *pu8XorMask,
1522 uint uWidth,
1523 uint uHeight)
1524{
1525 /* Check if the pointer has only 0 and 0xFFFFFF pixels, ignoring the alpha channel. */
1526 const uint32_t *pu32Src = (uint32_t *)pu8XorMask;
1527
1528 uint y;
1529 for (y = 0; y < uHeight ; ++y)
1530 {
1531 uint x;
1532 for (x = 0; x < uWidth; ++x)
1533 {
1534 const uint32_t u32Pixel = pu32Src[x] & UINT32_C(0xFFFFFF);
1535 if (u32Pixel != 0 && u32Pixel != UINT32_C(0xFFFFFF))
1536 return false;
1537 }
1538
1539 pu32Src += uWidth;
1540 }
1541
1542 return true;
1543}
1544#endif /* VBOX_WS_WIN */
1545
1546void UISession::updateMousePointerShape()
1547{
1548 /* Fetch incoming shape data: */
1549 const bool fHasAlpha = m_shapeData.hasAlpha();
1550 const uint uWidth = m_shapeData.shapeSize().width();
1551 const uint uHeight = m_shapeData.shapeSize().height();
1552 const uchar *pShapeData = m_shapeData.shape().constData();
1553 AssertMsgReturnVoid(pShapeData, ("Shape data must not be NULL!\n"));
1554
1555 /* Invalidate mouse pointer shape initially: */
1556 m_fIsValidPointerShapePresent = false;
1557 m_cursorShapePixmap = QPixmap();
1558 m_cursorMaskPixmap = QPixmap();
1559
1560 /* Parse incoming shape data: */
1561 const uchar *pSrcAndMaskPtr = pShapeData;
1562 const uint uAndMaskSize = (uWidth + 7) / 8 * uHeight;
1563 const uchar *pSrcShapePtr = pShapeData + ((uAndMaskSize + 3) & ~3);
1564
1565#if defined (VBOX_WS_WIN)
1566
1567 /* Create an ARGB image out of the shape data: */
1568
1569 // WORKAROUND:
1570 // Qt5 QCursor recommends 32 x 32 cursor, therefore the original data is copied to
1571 // a larger QImage if necessary. Cursors like 10x16 did not work correctly (Solaris 10 guest).
1572 // Align the cursor dimensions to 32 bit pixels, because for example a 56x56 monochrome cursor
1573 // did not work correctly on Windows host.
1574 const uint uCursorWidth = RT_ALIGN_32(uWidth, 32);
1575 const uint uCursorHeight = RT_ALIGN_32(uHeight, 32);
1576
1577 if (fHasAlpha)
1578 {
1579 QImage image(uCursorWidth, uCursorHeight, QImage::Format_ARGB32);
1580 memset(image.bits(), 0, image.byteCount());
1581
1582 const uint32_t *pu32SrcShapeScanline = (uint32_t *)pSrcShapePtr;
1583 for (uint y = 0; y < uHeight; ++y, pu32SrcShapeScanline += uWidth)
1584 memcpy(image.scanLine(y), pu32SrcShapeScanline, uWidth * sizeof(uint32_t));
1585
1586 m_cursorShapePixmap = QPixmap::fromImage(image);
1587 }
1588 else
1589 {
1590 if (isPointer1bpp(pSrcShapePtr, uWidth, uHeight))
1591 {
1592 /* Incoming data consist of 32 bit BGR XOR mask and 1 bit AND mask.
1593 * XOR pixels contain either 0x00000000 or 0x00FFFFFF.
1594 *
1595 * Originally intended result (F denotes 0x00FFFFFF):
1596 * XOR AND
1597 * 0 0 black
1598 * F 0 white
1599 * 0 1 transparent
1600 * F 1 xor'd
1601 *
1602 * Actual Qt5 result for color table 0:0xFF000000, 1:0xFFFFFFFF
1603 * (tested on Windows 7 and 10 64 bit hosts):
1604 * Bitmap Mask
1605 * 0 0 black
1606 * 1 0 white
1607 * 0 1 xor
1608 * 1 1 transparent
1609 *
1610 */
1611
1612 QVector<QRgb> colors(2);
1613 colors[0] = UINT32_C(0xFF000000);
1614 colors[1] = UINT32_C(0xFFFFFFFF);
1615
1616 QImage bitmap(uCursorWidth, uCursorHeight, QImage::Format_Mono);
1617 bitmap.setColorTable(colors);
1618 memset(bitmap.bits(), 0xFF, bitmap.byteCount());
1619
1620 QImage mask(uCursorWidth, uCursorHeight, QImage::Format_Mono);
1621 mask.setColorTable(colors);
1622 memset(mask.bits(), 0xFF, mask.byteCount());
1623
1624 const uint8_t *pu8SrcAndScanline = pSrcAndMaskPtr;
1625 const uint32_t *pu32SrcShapeScanline = (uint32_t *)pSrcShapePtr;
1626 for (uint y = 0; y < uHeight; ++y)
1627 {
1628 for (uint x = 0; x < uWidth; ++x)
1629 {
1630 const uint8_t u8Bit = (uint8_t)(1 << (7 - x % 8));
1631
1632 const uint8_t u8SrcMaskByte = pu8SrcAndScanline[x / 8];
1633 const uint8_t u8SrcMaskBit = u8SrcMaskByte & u8Bit;
1634 const uint32_t u32SrcPixel = pu32SrcShapeScanline[x] & UINT32_C(0xFFFFFF);
1635
1636 uint8_t *pu8DstMaskByte = &mask.scanLine(y)[x / 8];
1637 uint8_t *pu8DstBitmapByte = &bitmap.scanLine(y)[x / 8];
1638
1639 if (u8SrcMaskBit == 0)
1640 {
1641 if (u32SrcPixel == 0)
1642 {
1643 /* Black: Qt Bitmap = 0, Mask = 0 */
1644 *pu8DstMaskByte &= ~u8Bit;
1645 *pu8DstBitmapByte &= ~u8Bit;
1646 }
1647 else
1648 {
1649 /* White: Qt Bitmap = 1, Mask = 0 */
1650 *pu8DstMaskByte &= ~u8Bit;
1651 *pu8DstBitmapByte |= u8Bit;
1652 }
1653 }
1654 else
1655 {
1656 if (u32SrcPixel == 0)
1657 {
1658 /* Transparent: Qt Bitmap = 1, Mask = 1 */
1659 *pu8DstMaskByte |= u8Bit;
1660 *pu8DstBitmapByte |= u8Bit;
1661 }
1662 else
1663 {
1664 /* Xor'ed: Qt Bitmap = 0, Mask = 1 */
1665 *pu8DstMaskByte |= u8Bit;
1666 *pu8DstBitmapByte &= ~u8Bit;
1667 }
1668 }
1669 }
1670
1671 pu8SrcAndScanline += (uWidth + 7) / 8;
1672 pu32SrcShapeScanline += uWidth;
1673 }
1674
1675 m_cursorShapePixmap = QBitmap::fromImage(bitmap);
1676 m_cursorMaskPixmap = QBitmap::fromImage(mask);
1677 }
1678 else
1679 {
1680 /* Assign alpha channel values according to the AND mask: 1 -> 0x00, 0 -> 0xFF: */
1681 QImage image(uCursorWidth, uCursorHeight, QImage::Format_ARGB32);
1682 memset(image.bits(), 0, image.byteCount());
1683
1684 const uint8_t *pu8SrcAndScanline = pSrcAndMaskPtr;
1685 const uint32_t *pu32SrcShapeScanline = (uint32_t *)pSrcShapePtr;
1686
1687 for (uint y = 0; y < uHeight; ++y)
1688 {
1689 uint32_t *pu32DstPixel = (uint32_t *)image.scanLine(y);
1690
1691 for (uint x = 0; x < uWidth; ++x)
1692 {
1693 const uint8_t u8Bit = (uint8_t)(1 << (7 - x % 8));
1694 const uint8_t u8SrcMaskByte = pu8SrcAndScanline[x / 8];
1695
1696 if (u8SrcMaskByte & u8Bit)
1697 *pu32DstPixel++ = pu32SrcShapeScanline[x] & UINT32_C(0x00FFFFFF);
1698 else
1699 *pu32DstPixel++ = pu32SrcShapeScanline[x] | UINT32_C(0xFF000000);
1700 }
1701
1702 pu32SrcShapeScanline += uWidth;
1703 pu8SrcAndScanline += (uWidth + 7) / 8;
1704 }
1705
1706 m_cursorShapePixmap = QPixmap::fromImage(image);
1707 }
1708 }
1709
1710 /* Mark mouse pointer shape valid: */
1711 m_fIsValidPointerShapePresent = true;
1712
1713#elif defined(VBOX_WS_X11) || defined(VBOX_WS_MAC)
1714
1715 /* Create an ARGB image out of the shape data: */
1716 QImage image(uWidth, uHeight, QImage::Format_ARGB32);
1717
1718 if (fHasAlpha)
1719 {
1720 memcpy(image.bits(), pSrcShapePtr, uHeight * uWidth * 4);
1721 }
1722 else
1723 {
1724 renderCursorPixels((uint32_t *)pSrcShapePtr, pSrcAndMaskPtr,
1725 uWidth, uHeight,
1726 (uint32_t *)image.bits(), uHeight * uWidth * 4);
1727 }
1728
1729 /* Create cursor-pixmap from the image: */
1730 m_cursorShapePixmap = QPixmap::fromImage(image);
1731
1732 /* Mark mouse pointer shape valid: */
1733 m_fIsValidPointerShapePresent = true;
1734
1735#else
1736
1737# warning "port me"
1738
1739#endif
1740
1741 /* Cache cursor pixmap size and hotspot: */
1742 m_cursorSize = m_cursorShapePixmap.size();
1743 m_cursorHotspot = m_shapeData.hotSpot();
1744}
1745
1746bool UISession::preprocessInitialization()
1747{
1748#ifdef VBOX_WITH_NETFLT
1749 /* Skip further checks if VM in saved state */
1750 if (isSaved())
1751 return true;
1752
1753 /* Make sure all the attached and enabled network
1754 * adapters are present on the host. This check makes sense
1755 * in two cases only - when attachement type is Bridged Network
1756 * or Host-only Interface. NOTE: Only currently enabled
1757 * attachement type is checked (incorrect parameters check for
1758 * currently disabled attachement types is skipped). */
1759 QStringList failedInterfaceNames;
1760 QStringList availableInterfaceNames;
1761
1762 /* Create host network interface names list */
1763 foreach (const CHostNetworkInterface &iface, uiCommon().host().GetNetworkInterfaces())
1764 {
1765 availableInterfaceNames << iface.GetName();
1766 availableInterfaceNames << iface.GetShortName();
1767 }
1768
1769 ulong cCount = uiCommon().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine().GetChipsetType());
1770 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
1771 {
1772 CNetworkAdapter na = machine().GetNetworkAdapter(uAdapterIndex);
1773
1774 if (na.GetEnabled())
1775 {
1776 QString strIfName = QString();
1777
1778 /* Get physical network interface name for currently
1779 * enabled network attachement type */
1780 switch (na.GetAttachmentType())
1781 {
1782 case KNetworkAttachmentType_Bridged:
1783 strIfName = na.GetBridgedInterface();
1784 break;
1785 case KNetworkAttachmentType_HostOnly:
1786 strIfName = na.GetHostOnlyInterface();
1787 break;
1788 default: break; /* Shut up, MSC! */
1789 }
1790
1791 if (!strIfName.isEmpty() &&
1792 !availableInterfaceNames.contains(strIfName))
1793 {
1794 LogFlow(("Found invalid network interface: %s\n", strIfName.toStdString().c_str()));
1795 failedInterfaceNames << QString("%1 (adapter %2)").arg(strIfName).arg(uAdapterIndex + 1);
1796 }
1797 }
1798 }
1799
1800 /* Check if non-existent interfaces found */
1801 if (!failedInterfaceNames.isEmpty())
1802 {
1803 if (msgCenter().cannotStartWithoutNetworkIf(machineName(), failedInterfaceNames.join(", ")))
1804 machineLogic()->openNetworkSettingsDialog();
1805 else
1806 {
1807 LogRel(("GUI: Aborting startup due to preprocess initialization issue detected...\n"));
1808 return false;
1809 }
1810 }
1811#endif /* VBOX_WITH_NETFLT */
1812
1813 /* Check for USB enumeration warning. Don't return false even if we have a warning: */
1814 CHost comHost = uiCommon().host();
1815 if (comHost.GetUSBDevices().isEmpty() && comHost.isWarning())
1816 msgCenter().cannotEnumerateHostUSBDevices(comHost, activeMachineWindow());
1817
1818 /* True by default: */
1819 return true;
1820}
1821
1822bool UISession::mountAdHocImage(KDeviceType enmDeviceType, UIMediumDeviceType enmMediumType, const QString &strMediumName)
1823{
1824 /* Get VBox: */
1825 CVirtualBox comVBox = uiCommon().virtualBox();
1826
1827 /* Prepare medium to mount: */
1828 UIMedium guiMedium;
1829
1830 /* The 'none' medium name means ejecting what ever is in the drive,
1831 * in that case => leave the guiMedium variable null. */
1832 if (strMediumName != "none")
1833 {
1834 /* Open the medium: */
1835 const CMedium comMedium = comVBox.OpenMedium(strMediumName, enmDeviceType, KAccessMode_ReadWrite, false /* fForceNewUuid */);
1836 if (!comVBox.isOk() || comMedium.isNull())
1837 {
1838 popupCenter().cannotOpenMedium(activeMachineWindow(), comVBox, enmMediumType, strMediumName);
1839 return false;
1840 }
1841
1842 /* Make sure medium ID is valid: */
1843 const QUuid uMediumId = comMedium.GetId();
1844 AssertReturn(!uMediumId.isNull(), false);
1845
1846 /* Try to find UIMedium among cached: */
1847 guiMedium = uiCommon().medium(uMediumId);
1848 if (guiMedium.isNull())
1849 {
1850 /* Cache new one if necessary: */
1851 guiMedium = UIMedium(comMedium, enmMediumType, KMediumState_Created);
1852 uiCommon().createMedium(guiMedium);
1853 }
1854 }
1855
1856 /* Search for a suitable storage slots: */
1857 QList<ExactStorageSlot> aFreeStorageSlots;
1858 QList<ExactStorageSlot> aBusyStorageSlots;
1859 foreach (const CStorageController &comController, machine().GetStorageControllers())
1860 {
1861 foreach (const CMediumAttachment &comAttachment, machine().GetMediumAttachmentsOfController(comController.GetName()))
1862 {
1863 /* Look for an optical devices only: */
1864 if (comAttachment.GetType() == enmDeviceType)
1865 {
1866 /* Append storage slot to corresponding list: */
1867 if (comAttachment.GetMedium().isNull())
1868 aFreeStorageSlots << ExactStorageSlot(comController.GetName(), comController.GetBus(),
1869 comAttachment.GetPort(), comAttachment.GetDevice());
1870 else
1871 aBusyStorageSlots << ExactStorageSlot(comController.GetName(), comController.GetBus(),
1872 comAttachment.GetPort(), comAttachment.GetDevice());
1873 }
1874 }
1875 }
1876
1877 /* Make sure at least one storage slot found: */
1878 QList<ExactStorageSlot> sStorageSlots = aFreeStorageSlots + aBusyStorageSlots;
1879 if (sStorageSlots.isEmpty())
1880 {
1881 popupCenter().cannotMountImage(activeMachineWindow(), machineName(), strMediumName);
1882 return false;
1883 }
1884
1885 /* Try to mount medium into first available storage slot: */
1886 while (!sStorageSlots.isEmpty())
1887 {
1888 const ExactStorageSlot storageSlot = sStorageSlots.takeFirst();
1889 machine().MountMedium(storageSlot.controller, storageSlot.port, storageSlot.device, guiMedium.medium(), false /* force */);
1890 if (machine().isOk())
1891 break;
1892 }
1893
1894 /* Show error message if necessary: */
1895 if (!machine().isOk())
1896 {
1897 msgCenter().cannotRemountMedium(machine(), guiMedium, true /* mount? */, false /* retry? */, activeMachineWindow());
1898 return false;
1899 }
1900
1901 /* Save machine settings: */
1902 machine().SaveSettings();
1903
1904 /* Show error message if necessary: */
1905 if (!machine().isOk())
1906 {
1907 popupCenter().cannotSaveMachineSettings(activeMachineWindow(), machine());
1908 return false;
1909 }
1910
1911 /* True by default: */
1912 return true;
1913}
1914
1915bool UISession::postprocessInitialization()
1916{
1917 /* Check if the required virtualization features are active. We get this info only when the session is active. */
1918 const bool fIs64BitsGuest = uiCommon().virtualBox().GetGuestOSType(guest().GetOSTypeId()).GetIs64Bit();
1919 const bool fRecommendVirtEx = uiCommon().virtualBox().GetGuestOSType(guest().GetOSTypeId()).GetRecommendedVirtEx();
1920 AssertMsg(!fIs64BitsGuest || fRecommendVirtEx, ("Virtualization support missed for 64bit guest!\n"));
1921 const KVMExecutionEngine enmEngine = debugger().GetExecutionEngine();
1922 if (fRecommendVirtEx && enmEngine == KVMExecutionEngine_RawMode)
1923 {
1924 /* Check whether vt-x / amd-v supported: */
1925 bool fVTxAMDVSupported = uiCommon().host().GetProcessorFeature(KProcessorFeature_HWVirtEx);
1926
1927 /* Pause VM: */
1928 setPause(true);
1929
1930 /* Ask the user about further actions: */
1931 bool fShouldWeClose;
1932 if (fIs64BitsGuest)
1933 fShouldWeClose = msgCenter().warnAboutVirtExInactiveFor64BitsGuest(fVTxAMDVSupported);
1934 else
1935 fShouldWeClose = msgCenter().warnAboutVirtExInactiveForRecommendedGuest(fVTxAMDVSupported);
1936
1937 /* If user asked to close VM: */
1938 if (fShouldWeClose)
1939 {
1940 /* Enable 'manual-override',
1941 * preventing automatic Runtime UI closing: */
1942 if (machineLogic())
1943 machineLogic()->setManualOverrideMode(true);
1944 /* Power off VM: */
1945 bool fServerCrashed = false;
1946 LogRel(("GUI: Aborting startup due to postprocess initialization issue detected...\n"));
1947 powerOff(false /* do NOT restore current snapshot */, fServerCrashed);
1948 return false;
1949 }
1950
1951 /* Resume VM: */
1952 setPause(false);
1953 }
1954
1955 /* True by default: */
1956 return true;
1957}
1958
1959bool UISession::isScreenVisibleHostDesires(ulong uScreenId) const
1960{
1961 /* Make sure index feats the bounds: */
1962 AssertReturn(uScreenId < (ulong)m_monitorVisibilityVectorHostDesires.size(), false);
1963
1964 /* Return 'actual' (host-desire) visibility status: */
1965 return m_monitorVisibilityVectorHostDesires.value((int)uScreenId);
1966}
1967
1968void UISession::setScreenVisibleHostDesires(ulong uScreenId, bool fIsMonitorVisible)
1969{
1970 /* Make sure index feats the bounds: */
1971 AssertReturnVoid(uScreenId < (ulong)m_monitorVisibilityVectorHostDesires.size());
1972
1973 /* Remember 'actual' (host-desire) visibility status: */
1974 m_monitorVisibilityVectorHostDesires[(int)uScreenId] = fIsMonitorVisible;
1975
1976 /* And remember the request in extra data for guests with VMSVGA: */
1977 /* This should be done before the actual hint is sent in case the guest overrides it. */
1978 gEDataManager->setLastGuestScreenVisibilityStatus(uScreenId, fIsMonitorVisible, uiCommon().managedVMUuid());
1979}
1980
1981bool UISession::isScreenVisible(ulong uScreenId) const
1982{
1983 /* Make sure index feats the bounds: */
1984 AssertReturn(uScreenId < (ulong)m_monitorVisibilityVector.size(), false);
1985
1986 /* Return 'actual' visibility status: */
1987 return m_monitorVisibilityVector.value((int)uScreenId);
1988}
1989
1990void UISession::setScreenVisible(ulong uScreenId, bool fIsMonitorVisible)
1991{
1992 /* Make sure index feats the bounds: */
1993 AssertReturnVoid(uScreenId < (ulong)m_monitorVisibilityVector.size());
1994
1995 /* Remember 'actual' visibility status: */
1996 m_monitorVisibilityVector[(int)uScreenId] = fIsMonitorVisible;
1997 /* Remember 'desired' visibility status: */
1998 /* See note in UIMachineView::sltHandleNotifyChange() regarding the graphics controller check. */
1999 if (machine().GetGraphicsAdapter().GetGraphicsControllerType() != KGraphicsControllerType_VMSVGA)
2000 gEDataManager->setLastGuestScreenVisibilityStatus(uScreenId, fIsMonitorVisible, uiCommon().managedVMUuid());
2001
2002 /* Make sure action-pool knows guest-screen visibility status: */
2003 actionPool()->toRuntime()->setGuestScreenVisible(uScreenId, fIsMonitorVisible);
2004}
2005
2006QSize UISession::lastFullScreenSize(ulong uScreenId) const
2007{
2008 /* Make sure index fits the bounds: */
2009 AssertReturn(uScreenId < (ulong)m_monitorLastFullScreenSizeVector.size(), QSize(-1, -1));
2010
2011 /* Return last full-screen size: */
2012 return m_monitorLastFullScreenSizeVector.value((int)uScreenId);
2013}
2014
2015void UISession::setLastFullScreenSize(ulong uScreenId, QSize size)
2016{
2017 /* Make sure index fits the bounds: */
2018 AssertReturnVoid(uScreenId < (ulong)m_monitorLastFullScreenSizeVector.size());
2019
2020 /* Remember last full-screen size: */
2021 m_monitorLastFullScreenSizeVector[(int)uScreenId] = size;
2022}
2023
2024int UISession::countOfVisibleWindows()
2025{
2026 int cCountOfVisibleWindows = 0;
2027 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
2028 if (m_monitorVisibilityVector[i])
2029 ++cCountOfVisibleWindows;
2030 return cCountOfVisibleWindows;
2031}
2032
2033QList<int> UISession::listOfVisibleWindows() const
2034{
2035 QList<int> visibleWindows;
2036 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
2037 if (m_monitorVisibilityVector.at(i))
2038 visibleWindows.push_back(i);
2039 return visibleWindows;
2040}
2041
2042CMediumVector UISession::machineMedia() const
2043{
2044 CMediumVector comMedia;
2045 /* Enumerate all the controllers: */
2046 foreach (const CStorageController &comController, m_machine.GetStorageControllers())
2047 {
2048 /* Enumerate all the attachments: */
2049 foreach (const CMediumAttachment &comAttachment, m_machine.GetMediumAttachmentsOfController(comController.GetName()))
2050 {
2051 /* Skip unrelated device types: */
2052 const KDeviceType enmDeviceType = comAttachment.GetType();
2053 if ( enmDeviceType != KDeviceType_HardDisk
2054 && enmDeviceType != KDeviceType_Floppy
2055 && enmDeviceType != KDeviceType_DVD)
2056 continue;
2057 if ( comAttachment.GetIsEjected()
2058 || comAttachment.GetMedium().isNull())
2059 continue;
2060 comMedia.append(comAttachment.GetMedium());
2061 }
2062 }
2063 return comMedia;
2064}
2065
2066void UISession::loadVMSettings()
2067{
2068 /* Cache IMachine::ExecutionEngine value. */
2069 m_enmVMExecutionEngine = m_debugger.GetExecutionEngine();
2070 /* Load nested-paging CPU hardware virtualization extension: */
2071 m_fIsHWVirtExNestedPagingEnabled = m_debugger.GetHWVirtExNestedPagingEnabled();
2072 /* Load whether the VM is currently making use of the unrestricted execution feature of VT-x: */
2073 m_fIsHWVirtExUXEnabled = m_debugger.GetHWVirtExUXEnabled();
2074 /* Load VM's effective paravirtualization provider: */
2075 m_paraVirtProvider = m_machine.GetEffectiveParavirtProvider();
2076}
2077
2078UIFrameBuffer* UISession::frameBuffer(ulong uScreenId) const
2079{
2080 Assert(uScreenId < (ulong)m_frameBufferVector.size());
2081 return m_frameBufferVector.value((int)uScreenId, 0);
2082}
2083
2084void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer* pFrameBuffer)
2085{
2086 Assert(uScreenId < (ulong)m_frameBufferVector.size());
2087 if (uScreenId < (ulong)m_frameBufferVector.size())
2088 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
2089}
2090
2091void UISession::updateHostScreenData()
2092{
2093 /* Rebuild host-screen data vector: */
2094 m_hostScreens.clear();
2095 for (int iScreenIndex = 0; iScreenIndex < gpDesktop->screenCount(); ++iScreenIndex)
2096 m_hostScreens << gpDesktop->screenGeometry(iScreenIndex);
2097
2098 /* Make sure action-pool knows host-screen count: */
2099 actionPool()->toRuntime()->setHostScreenCount(m_hostScreens.size());
2100}
2101
2102void UISession::updateActionRestrictions()
2103{
2104 /* Get host and prepare restrictions: */
2105 const CHost host = uiCommon().host();
2106 UIExtraDataMetaDefs::RuntimeMenuMachineActionType restrictionForMachine = UIExtraDataMetaDefs::RuntimeMenuMachineActionType_Invalid;
2107 UIExtraDataMetaDefs::RuntimeMenuViewActionType restrictionForView = UIExtraDataMetaDefs::RuntimeMenuViewActionType_Invalid;
2108 UIExtraDataMetaDefs::RuntimeMenuDevicesActionType restrictionForDevices = UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Invalid;
2109
2110 /* Separate process stuff: */
2111 {
2112 /* Initialize 'Machine' menu: */
2113 if (!uiCommon().isSeparateProcess())
2114 restrictionForMachine = (UIExtraDataMetaDefs::RuntimeMenuMachineActionType)(restrictionForMachine | UIExtraDataMetaDefs::RuntimeMenuMachineActionType_Detach);
2115 }
2116
2117 /* VRDE server stuff: */
2118 {
2119 /* Initialize 'View' menu: */
2120 const CVRDEServer server = machine().GetVRDEServer();
2121 if (server.isNull())
2122 restrictionForView = (UIExtraDataMetaDefs::RuntimeMenuViewActionType)(restrictionForView | UIExtraDataMetaDefs::RuntimeMenuViewActionType_VRDEServer);
2123 }
2124
2125 /* Storage stuff: */
2126 {
2127 /* Initialize CD/FD menus: */
2128 int iDevicesCountCD = 0;
2129 int iDevicesCountFD = 0;
2130 foreach (const CMediumAttachment &attachment, machine().GetMediumAttachments())
2131 {
2132 if (attachment.GetType() == KDeviceType_DVD)
2133 ++iDevicesCountCD;
2134 if (attachment.GetType() == KDeviceType_Floppy)
2135 ++iDevicesCountFD;
2136 }
2137 QAction *pOpticalDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices);
2138 QAction *pFloppyDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices);
2139 pOpticalDevicesMenu->setData(iDevicesCountCD);
2140 pFloppyDevicesMenu->setData(iDevicesCountFD);
2141 if (!iDevicesCountCD)
2142 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_OpticalDevices);
2143 if (!iDevicesCountFD)
2144 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_FloppyDevices);
2145 }
2146
2147 /* Audio stuff: */
2148 {
2149 /* Check whether audio controller is enabled. */
2150 const CAudioAdapter &comAdapter = machine().GetAudioAdapter();
2151 if (comAdapter.isNull() || !comAdapter.GetEnabled())
2152 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Audio);
2153 }
2154
2155 /* Network stuff: */
2156 {
2157 /* Initialize Network menu: */
2158 bool fAtLeastOneAdapterActive = false;
2159 const KChipsetType chipsetType = machine().GetChipsetType();
2160 ULONG uSlots = uiCommon().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(chipsetType);
2161 for (ULONG uSlot = 0; uSlot < uSlots; ++uSlot)
2162 {
2163 const CNetworkAdapter &adapter = machine().GetNetworkAdapter(uSlot);
2164 if (adapter.GetEnabled())
2165 {
2166 fAtLeastOneAdapterActive = true;
2167 break;
2168 }
2169 }
2170 if (!fAtLeastOneAdapterActive)
2171 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Network);
2172 }
2173
2174 /* USB stuff: */
2175 {
2176 /* Check whether there is at least one USB controller with an available proxy. */
2177 const bool fUSBEnabled = !machine().GetUSBDeviceFilters().isNull()
2178 && !machine().GetUSBControllers().isEmpty()
2179 && machine().GetUSBProxyAvailable();
2180 if (!fUSBEnabled)
2181 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_USBDevices);
2182 }
2183
2184 /* WebCams stuff: */
2185 {
2186 /* Check whether there is an accessible video input devices pool: */
2187 host.GetVideoInputDevices();
2188 const bool fWebCamsEnabled = host.isOk() && !machine().GetUSBControllers().isEmpty();
2189 if (!fWebCamsEnabled)
2190 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_WebCams);
2191 }
2192
2193 /* Apply cumulative restriction for 'Machine' menu: */
2194 actionPool()->toRuntime()->setRestrictionForMenuMachine(UIActionRestrictionLevel_Session, restrictionForMachine);
2195 /* Apply cumulative restriction for 'View' menu: */
2196 actionPool()->toRuntime()->setRestrictionForMenuView(UIActionRestrictionLevel_Session, restrictionForView);
2197 /* Apply cumulative restriction for 'Devices' menu: */
2198 actionPool()->toRuntime()->setRestrictionForMenuDevices(UIActionRestrictionLevel_Session, restrictionForDevices);
2199}
2200
2201#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
2202/**
2203 * Custom signal handler. When switching VTs, we might not get release events
2204 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
2205 * be saved with modifier keys stuck. This is annoying enough for introducing
2206 * this hack.
2207 */
2208/* static */
2209static void signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
2210{
2211 /* Only SIGUSR1 is interesting: */
2212 if (sig == SIGUSR1)
2213 if (gpMachine)
2214 gpMachine->uisession()->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
2215}
2216#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
Note: See TracBrowser for help on using the repository browser.

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