VirtualBox

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

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

VMM,Main,++: Removed VM_IS_RAW_MODE_ENABLED/VM_EXEC_ENGINE_RAW_MODE and added VM_IS_EXEC_ENGINE_IEM/VM_EXEC_ENGINE_IEM instead. In IMachineDebugger::getExecutionEngine VMExecutionEngine_RawMode was removed and VMExecutionEngine_Emulated added. Removed dead code and updated frontends accordingly. On darwin.arm64 HM now falls back on IEM execution since neither HM or NEM is availble there. bugref:9898

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