VirtualBox

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

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

FE/Qt: bugref:9974. Removing first run wizard.

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