VirtualBox

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

Last change on this file since 85772 was 85772, checked in by vboxsync, 5 years ago

FE/Qt: bugref:6659: macOS: Extending GUI/Customizations extra-data flag with noUserElements option available on macOS only (alternative to noMenuBar on other platforms) which hides both menu-bar and dock.

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