VirtualBox

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

Last change on this file since 90856 was 90856, checked in by vboxsync, 3 years ago

FE/Qt: bugref:10067: Notification signature for virtual machine save-state progress (in Runtime UI) which should now go to center instead of modal dialogs, s.a. r145993.

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