VirtualBox

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

Last change on this file since 97681 was 97681, checked in by vboxsync, 2 years ago

FE/Qt: bugref:9898: Cleanup/rework for UIDesktopWidgetWatchdog class; Converting member stuff to static.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette