VirtualBox

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

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

FE/Qt: bugref:10067: Runtime UI: Move ACPI shutdown stuff to the place where it belongs (UISession).

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