VirtualBox

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

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

FE/Qt, Main/Console+Mouse, VBoxManage: Touchpad support, should be functional now. bugref:9891

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