VirtualBox

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

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

FE/Qt: qt6: QX11Info is gone, kind of replaced by QNativeInterface::QX11Application (6.2+). Added X11GetDisplay, X11GetConnection and X11GetAppRootWindow to the NativeWindowSubsystem namespace to keep the differences in one place. bugref:9898

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