VirtualBox

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

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

FE/Qt: bugref:9598: UISession, UIMachineView and UIMouseHandler: Now the curious one, mouse pointer shape scaling should be done on per-screen basis, so we had to move corresponding functionality from session to particular machine-view and keep proper signal order hierarchy accordingly; This will probably break frame-buffer cursor functionality.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.4 KB
Line 
1/* $Id: UISession.cpp 82032 2019-11-20 16:21:59Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISession class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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_WITH_VIDEOHWACCEL
53# include "VBox2DHelpers.h"
54#endif
55#ifdef VBOX_WS_MAC
56# include "VBoxUtils-darwin.h"
57#endif
58#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
59# include "UIKeyboardHandler.h"
60# include <signal.h>
61#endif
62
63/* COM includes: */
64#include "CAudioAdapter.h"
65#include "CGraphicsAdapter.h"
66#include "CRecordingSettings.h"
67#include "CSystemProperties.h"
68#include "CStorageController.h"
69#include "CMediumAttachment.h"
70#include "CNetworkAdapter.h"
71#include "CHostNetworkInterface.h"
72#include "CVRDEServer.h"
73#include "CUSBController.h"
74#include "CUSBDeviceFilters.h"
75#include "CHostVideoInputDevice.h"
76#include "CSnapshot.h"
77#include "CMedium.h"
78
79/* External includes: */
80#ifdef VBOX_WS_X11
81# include <X11/Xlib.h>
82# include <X11/Xutil.h>
83#endif
84
85
86#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
87static void signalHandlerSIGUSR1(int sig, siginfo_t *, void *);
88#endif
89
90#ifdef VBOX_WS_MAC
91/**
92 * MacOS X: Application Services: Core Graphics: Display reconfiguration callback.
93 *
94 * Notifies UISession about @a display configuration change.
95 * Corresponding change described by Core Graphics @a flags.
96 * Uses UISession @a pHandler to process this change.
97 *
98 * @note Last argument (@a pHandler) must always be valid pointer to UISession object.
99 * @note Calls for UISession::sltHandleHostDisplayAboutToChange() slot if display configuration changed.
100 */
101void cgDisplayReconfigurationCallback(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *pHandler)
102{
103 /* Which flags we are handling? */
104 int iHandledFlags = kCGDisplayAddFlag /* display added */
105 | kCGDisplayRemoveFlag /* display removed */
106 | kCGDisplaySetModeFlag /* display mode changed */;
107
108 /* Handle 'display-add' case: */
109 if (flags & kCGDisplayAddFlag)
110 LogRelFlow(("GUI: UISession::cgDisplayReconfigurationCallback: Display added.\n"));
111 /* Handle 'display-remove' case: */
112 else if (flags & kCGDisplayRemoveFlag)
113 LogRelFlow(("GUI: UISession::cgDisplayReconfigurationCallback: Display removed.\n"));
114 /* Handle 'mode-set' case: */
115 else if (flags & kCGDisplaySetModeFlag)
116 LogRelFlow(("GUI: UISession::cgDisplayReconfigurationCallback: Display mode changed.\n"));
117
118 /* Ask handler to process our callback: */
119 if (flags & iHandledFlags)
120 QTimer::singleShot(0, static_cast<UISession*>(pHandler),
121 SLOT(sltHandleHostDisplayAboutToChange()));
122
123 Q_UNUSED(display);
124}
125#endif /* VBOX_WS_MAC */
126
127/* static */
128bool UISession::create(UISession *&pSession, UIMachine *pMachine)
129{
130 /* Make sure null pointer passed: */
131 AssertReturn(pSession == 0, false);
132
133 /* Create session UI: */
134 pSession = new UISession(pMachine);
135 /* Make sure it's prepared: */
136 if (!pSession->prepare())
137 {
138 /* Destroy session UI otherwise: */
139 destroy(pSession);
140 /* False in that case: */
141 return false;
142 }
143 /* True by default: */
144 return true;
145}
146
147/* static */
148void UISession::destroy(UISession *&pSession)
149{
150 /* Make sure valid pointer passed: */
151 AssertReturnVoid(pSession != 0);
152
153 /* Cleanup session UI: */
154 pSession->cleanup();
155 /* Destroy session: */
156 delete pSession;
157 pSession = 0;
158}
159
160bool UISession::initialize()
161{
162 /* Preprocess initialization: */
163 if (!preprocessInitialization())
164 return false;
165
166 /* Notify user about mouse&keyboard auto-capturing: */
167 if (gEDataManager->autoCaptureEnabled())
168 popupCenter().remindAboutAutoCapture(activeMachineWindow());
169
170 /* Check if we are in teleportation waiting mode.
171 * In that case no first run wizard is necessary. */
172 m_machineState = machine().GetState();
173 if ( isFirstTimeStarted()
174 && !(( m_machineState == KMachineState_PoweredOff
175 || m_machineState == KMachineState_Aborted
176 || m_machineState == KMachineState_Teleported)
177 && machine().GetTeleporterEnabled()))
178 {
179 UISafePointerWizard pWizard = new UIWizardFirstRun(mainMachineWindow(), machine());
180 pWizard->prepare();
181 pWizard->exec();
182 if (pWizard)
183 delete pWizard;
184 }
185
186 /* Apply debug settings from the command line. */
187 if (!debugger().isNull() && debugger().isOk())
188 {
189 if (uiCommon().isPatmDisabled())
190 debugger().SetPATMEnabled(false);
191 if (uiCommon().isCsamDisabled())
192 debugger().SetCSAMEnabled(false);
193 if (uiCommon().isSupervisorCodeExecedRecompiled())
194 debugger().SetRecompileSupervisor(true);
195 if (uiCommon().isUserCodeExecedRecompiled())
196 debugger().SetRecompileUser(true);
197 if (uiCommon().areWeToExecuteAllInIem())
198 debugger().SetExecuteAllInIEM(true);
199 if (!uiCommon().isDefaultWarpPct())
200 debugger().SetVirtualTimeRate(uiCommon().getWarpPct());
201 }
202
203 /* Apply ad-hoc reconfigurations from the command line: */
204 if (uiCommon().hasFloppyImageToMount())
205 mountAdHocImage(KDeviceType_Floppy, UIMediumDeviceType_Floppy, uiCommon().getFloppyImage().toString());
206 if (uiCommon().hasDvdImageToMount())
207 mountAdHocImage(KDeviceType_DVD, UIMediumDeviceType_DVD, uiCommon().getDvdImage().toString());
208
209 /* Power UP if this is NOT separate process: */
210 if (!uiCommon().isSeparateProcess())
211 if (!powerUp())
212 return false;
213
214 /* Make sure all the pending Console events converted to signals
215 * during the powerUp() progress above reached their destinations.
216 * That is necessary to make sure all the pending machine state change events processed.
217 * We can't just use the machine state directly acquired from IMachine because there
218 * will be few places which are using stale machine state, not just this one. */
219 QApplication::sendPostedEvents(0, QEvent::MetaCall);
220
221 /* Check if we missed a really quick termination after successful startup: */
222 if (isTurnedOff())
223 {
224 LogRel(("GUI: Aborting startup due to invalid machine state detected: %d\n", machineState()));
225 return false;
226 }
227
228 /* Postprocess initialization: */
229 if (!postprocessInitialization())
230 return false;
231
232 /* Fetch corresponding states: */
233 if (uiCommon().isSeparateProcess())
234 {
235 m_fIsMouseSupportsAbsolute = mouse().GetAbsoluteSupported();
236 m_fIsMouseSupportsRelative = mouse().GetRelativeSupported();
237 m_fIsMouseSupportsMultiTouch = mouse().GetMultiTouchSupported();
238 m_fIsMouseHostCursorNeeded = mouse().GetNeedsHostCursor();
239 sltAdditionsChange();
240 }
241 machineLogic()->initializePostPowerUp();
242
243 /* Load VM settings: */
244 loadVMSettings();
245
246#ifdef VBOX_WITH_VIDEOHWACCEL
247 /* Log whether 2D video acceleration is enabled: */
248 LogRel(("GUI: 2D video acceleration is %s\n",
249 machine().GetGraphicsAdapter().GetAccelerate2DVideoEnabled() && VBox2DHelpers::isAcceleration2DVideoAvailable()
250 ? "enabled" : "disabled"));
251#endif /* VBOX_WITH_VIDEOHWACCEL */
252
253/* Log whether HID LEDs sync is enabled: */
254#if defined(VBOX_WS_MAC) || defined(VBOX_WS_WIN)
255 LogRel(("GUI: HID LEDs sync is %s\n",
256 uimachine()->machineLogic()->isHidLedsSyncEnabled()
257 ? "enabled" : "disabled"));
258#else /* !VBOX_WS_MAC && !VBOX_WS_WIN */
259 LogRel(("GUI: HID LEDs sync is not supported on this platform\n"));
260#endif /* !VBOX_WS_MAC && !VBOX_WS_WIN */
261
262#ifdef VBOX_GUI_WITH_PIDFILE
263 uiCommon().createPidfile();
264#endif /* VBOX_GUI_WITH_PIDFILE */
265
266 /* Warn listeners about we are initialized: */
267 emit sigInitialized();
268
269 /* True by default: */
270 return true;
271}
272
273bool UISession::powerUp()
274{
275 /* Power UP machine: */
276 CProgress progress = uiCommon().shouldStartPaused() ? console().PowerUpPaused() : console().PowerUp();
277
278 /* Check for immediate failure: */
279 if (!console().isOk() || progress.isNull())
280 {
281 if (uiCommon().showStartVMErrors())
282 msgCenter().cannotStartMachine(console(), machineName());
283 LogRel(("GUI: Aborting startup due to power up issue detected...\n"));
284 return false;
285 }
286
287 /* Some logging right after we powered up: */
288 LogRel(("Qt version: %s\n", UICommon::qtRTVersionString().toUtf8().constData()));
289#ifdef VBOX_WS_X11
290 LogRel(("X11 Window Manager code: %d\n", (int)uiCommon().typeOfWindowManager()));
291#endif
292
293 /* Enable 'manual-override',
294 * preventing automatic Runtime UI closing
295 * and visual representation mode changes: */
296 if (machineLogic())
297 machineLogic()->setManualOverrideMode(true);
298
299 /* Show "Starting/Restoring" progress dialog: */
300 if (isSaved())
301 {
302 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_state_restore_90px.png", 0, 0);
303 /* After restoring from 'saved' state, machine-window(s) geometry should be adjusted: */
304 machineLogic()->adjustMachineWindowsGeometry();
305 }
306 else
307 {
308 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_start_90px.png");
309 /* After VM start, machine-window(s) size-hint(s) should be sent: */
310 machineLogic()->sendMachineWindowsSizeHints();
311 }
312
313 /* Check for progress failure: */
314 if (!progress.isOk() || progress.GetResultCode() != 0)
315 {
316 if (uiCommon().showStartVMErrors())
317 msgCenter().cannotStartMachine(progress, machineName());
318 LogRel(("GUI: Aborting startup due to power up progress issue detected...\n"));
319 return false;
320 }
321
322 /* Disable 'manual-override' finally: */
323 if (machineLogic())
324 machineLogic()->setManualOverrideMode(false);
325
326 /* True by default: */
327 return true;
328}
329
330bool UISession::detach()
331{
332 /* Nothing here for now: */
333 return true;
334}
335
336bool UISession::saveState()
337{
338 /* Prepare the saving progress: */
339 CProgress progress = machine().SaveState();
340 if (machine().isOk())
341 {
342 /* Show the saving progress: */
343 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_state_save_90px.png");
344 if (!progress.isOk() || progress.GetResultCode() != 0)
345 {
346 /* Failed in progress: */
347 msgCenter().cannotSaveMachineState(progress, machineName());
348 return false;
349 }
350 }
351 else
352 {
353 /* Failed in console: */
354 msgCenter().cannotSaveMachineState(machine());
355 return false;
356 }
357 /* Passed: */
358 return true;
359}
360
361bool UISession::shutdown()
362{
363 /* Send ACPI shutdown signal if possible: */
364 console().PowerButton();
365 if (!console().isOk())
366 {
367 /* Failed in console: */
368 msgCenter().cannotACPIShutdownMachine(console());
369 return false;
370 }
371 /* Passed: */
372 return true;
373}
374
375bool UISession::powerOff(bool fIncludingDiscard, bool &fServerCrashed)
376{
377 /* Prepare the power-off progress: */
378 LogRel(("GUI: Powering VM down on UI session power off request...\n"));
379 CProgress progress = console().PowerDown();
380 if (console().isOk())
381 {
382 /* Show the power-off progress: */
383 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_poweroff_90px.png");
384 if (progress.isOk() && progress.GetResultCode() == 0)
385 {
386 /* Discard the current state if requested: */
387 if (fIncludingDiscard)
388 return restoreCurrentSnapshot();
389 }
390 else
391 {
392 /* Failed in progress: */
393 msgCenter().cannotPowerDownMachine(progress, machineName());
394 return false;
395 }
396 }
397 else
398 {
399 /* Check the machine state, it might be already gone: */
400 if (!console().isNull())
401 {
402 /* Failed in console: */
403 COMResult res(console());
404 /* This can happen if VBoxSVC is not running: */
405 if (FAILED_DEAD_INTERFACE(res.rc()))
406 fServerCrashed = true;
407 else
408 msgCenter().cannotPowerDownMachine(console());
409 return false;
410 }
411 }
412 /* Passed: */
413 return true;
414}
415
416bool UISession::restoreCurrentSnapshot()
417{
418 /* Prepare result: */
419 bool fResult = false;
420
421 /* Simulate try-catch block: */
422 do
423 {
424 /* Search for corresponding VM: */
425 CVirtualBox vbox = uiCommon().virtualBox();
426 const QUuid uMachineID = uiCommon().managedVMUuid();
427 const CMachine mach = vbox.FindMachine(uMachineID.toString());
428 if (!vbox.isOk() || mach.isNull())
429 {
430 /* Unable to find VM: */
431 msgCenter().cannotFindMachineById(vbox, uMachineID);
432 break;
433 }
434
435 /* Open a direct session to modify that VM: */
436 CSession sess = uiCommon().openSession(uiCommon().managedVMUuid(),
437 uiCommon().isSeparateProcess()
438 ? KLockType_Write : KLockType_Shared);
439 if (sess.isNull())
440 {
441 /* Unable to open session: */
442 break;
443 }
444
445 /* Simulate try-catch block: */
446 do
447 {
448 /* Acquire machine for this session: */
449 CMachine machine = sess.GetMachine();
450 if (machine.isNull())
451 {
452 /* Unable to acquire machine: */
453 break;
454 }
455
456 /* Prepare the snapshot-discard progress: */
457 const CSnapshot snap = machine.GetCurrentSnapshot();
458 CProgress prog = machine.RestoreSnapshot(snap);
459 if (!machine.isOk() || prog.isNull())
460 {
461 /* Unable to restore snapshot: */
462 msgCenter().cannotRestoreSnapshot(machine, snap.GetName(), machineName());
463 break;
464 }
465
466 /* Show the snapshot-discard progress: */
467 msgCenter().showModalProgressDialog(prog, machine.GetName(), ":/progress_snapshot_discard_90px.png");
468 if (prog.GetResultCode() != 0)
469 {
470 /* Unable to restore snapshot: */
471 msgCenter().cannotRestoreSnapshot(prog, snap.GetName(), machine.GetName());
472 break;
473 }
474
475 /* Success: */
476 fResult = true;
477 }
478 while (0);
479
480 /* Unlock machine finally: */
481 sess.UnlockMachine();
482 }
483 while (0);
484
485 /* Return result: */
486 return fResult;
487}
488
489UIMachineLogic* UISession::machineLogic() const
490{
491 return uimachine() ? uimachine()->machineLogic() : 0;
492}
493
494QWidget* UISession::mainMachineWindow() const
495{
496 return machineLogic() ? machineLogic()->mainMachineWindow() : 0;
497}
498
499WId UISession::mainMachineWindowId() const
500{
501 return mainMachineWindow()->winId();
502}
503
504UIMachineWindow *UISession::activeMachineWindow() const
505{
506 return machineLogic() ? machineLogic()->activeMachineWindow() : 0;
507}
508
509bool UISession::isVisualStateAllowed(UIVisualStateType state) const
510{
511 return m_pMachine->isVisualStateAllowed(state);
512}
513
514void UISession::changeVisualState(UIVisualStateType visualStateType)
515{
516 m_pMachine->asyncChangeVisualState(visualStateType);
517}
518
519bool UISession::setPause(bool fOn)
520{
521 if (fOn)
522 console().Pause();
523 else
524 console().Resume();
525
526 bool ok = console().isOk();
527 if (!ok)
528 {
529 if (fOn)
530 msgCenter().cannotPauseMachine(console());
531 else
532 msgCenter().cannotResumeMachine(console());
533 }
534
535 return ok;
536}
537
538void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
539{
540 /* This flag indicates whether we want to do the usual .ISO mounting or not.
541 * First try updating the Guest Additions directly without mounting the .ISO. */
542 bool fDoMount = false;
543
544 /* Auto-update through GUI is currently disabled. */
545#ifndef VBOX_WITH_ADDITIONS_AUTOUPDATE_UI
546 fDoMount = true;
547#else /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
548 /* Initiate installation progress: */
549 QVector<QString> aArgs;
550 QVector<KAdditionsUpdateFlag> aFlagsUpdate;
551 CProgress comProgressInstall = guest().UpdateGuestAdditions(strSource, aArgs, aFlagsUpdate);
552 if (guest().isOk() && comProgressInstall.isNotNull())
553 {
554 /* Show installation progress: */
555 msgCenter().showModalProgressDialog(comProgressInstall, tr("Updating Guest Additions"),
556 ":/progress_install_guest_additions_90px.png",
557 0, 500 /* 500ms delay. */);
558 if (comProgressInstall.GetCanceled())
559 return;
560
561 /* Check whether progress result isn't Ok: */
562 const HRESULT rc = comProgressInstall.GetResultCode();
563 if (!comProgressInstall.isOk() || rc != S_OK)
564 {
565 /* If we got back a VBOX_E_NOT_SUPPORTED we don't complain (guest OS simply isn't
566 * supported yet), so silently fall back to "old" .ISO mounting method. */
567 if ( !SUCCEEDED_WARNING(rc)
568 && rc != VBOX_E_NOT_SUPPORTED)
569 {
570 msgCenter().cannotUpdateGuestAdditions(comProgressInstall);
571
572 /* Throw the error message into release log as well: */
573 const QString &strErr = comProgressInstall.GetErrorInfo().GetText();
574 if (!strErr.isEmpty())
575 LogRel(("%s\n", strErr.toLatin1().constData()));
576 }
577
578 /* Since automatic updating failed, fall back to .ISO mounting: */
579 fDoMount = true;
580 }
581 }
582#endif /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
583
584 /* Check whether we still want mounting? */
585 if (!fDoMount)
586 return;
587
588 /* Mount medium add-hoc: */
589 mountAdHocImage(KDeviceType_DVD, UIMediumDeviceType_DVD, strSource);
590}
591
592void UISession::sltCloseRuntimeUI()
593{
594 /* Ask UIMachine to close Runtime UI: */
595 uimachine()->closeRuntimeUI();
596}
597
598#ifdef RT_OS_DARWIN
599void UISession::sltHandleMenuBarConfigurationChange(const QUuid &uMachineID)
600{
601 /* Skip unrelated machine IDs: */
602 if (uiCommon().managedVMUuid() != uMachineID)
603 return;
604
605 /* Update Mac OS X menu-bar: */
606 updateMenu();
607}
608#endif /* RT_OS_DARWIN */
609
610void UISession::sltMousePointerShapeChange(const UIMousePointerShapeData &shapeData)
611{
612 /* In case if shape itself is present: */
613 if (shapeData.shape().size() > 0)
614 {
615 /* We are ignoring visibility flag: */
616 m_fIsHidingHostPointer = false;
617
618 /* And updating current shape data: */
619 m_shapeData = shapeData;
620 updateMousePointerShape();
621 }
622 /* In case if shape itself is NOT present: */
623 else
624 {
625 /* Remember if we should hide the cursor: */
626 m_fIsHidingHostPointer = !shapeData.isVisible();
627 }
628
629 /* Notify listeners about mouse capability changed: */
630 emit sigMousePointerShapeChange();
631}
632
633void UISession::sltMouseCapabilityChange(bool fSupportsAbsolute, bool fSupportsRelative, bool fSupportsMultiTouch, bool fNeedsHostCursor)
634{
635 LogRelFlow(("GUI: UISession::sltMouseCapabilityChange: "
636 "Supports absolute: %s, Supports relative: %s, "
637 "Supports multi-touch: %s, Needs host cursor: %s\n",
638 fSupportsAbsolute ? "TRUE" : "FALSE", fSupportsRelative ? "TRUE" : "FALSE",
639 fSupportsMultiTouch ? "TRUE" : "FALSE", fNeedsHostCursor ? "TRUE" : "FALSE"));
640
641 /* Check if something had changed: */
642 if ( m_fIsMouseSupportsAbsolute != fSupportsAbsolute
643 || m_fIsMouseSupportsRelative != fSupportsRelative
644 || m_fIsMouseSupportsMultiTouch != fSupportsMultiTouch
645 || m_fIsMouseHostCursorNeeded != fNeedsHostCursor)
646 {
647 /* Store new data: */
648 m_fIsMouseSupportsAbsolute = fSupportsAbsolute;
649 m_fIsMouseSupportsRelative = fSupportsRelative;
650 m_fIsMouseSupportsMultiTouch = fSupportsMultiTouch;
651 m_fIsMouseHostCursorNeeded = fNeedsHostCursor;
652
653 /* Notify listeners about mouse capability changed: */
654 emit sigMouseCapabilityChange();
655 }
656}
657
658void UISession::sltCursorPositionChange(bool fContainsData, unsigned long uX, unsigned long uY)
659{
660 LogRelFlow(("GUI: UISession::sltCursorPositionChange: "
661 "Cursor position valid: %d, Cursor position: %dx%d\n",
662 fContainsData ? "TRUE" : "FALSE", uX, uY));
663
664 /* Check if something had changed: */
665 if ( m_fIsValidCursorPositionPresent != fContainsData
666 || m_cursorPosition.x() != (int)uX
667 || m_cursorPosition.y() != (int)uY)
668 {
669 /* Store new data: */
670 m_fIsValidCursorPositionPresent = fContainsData;
671 m_cursorPosition = QPoint(uX, uY);
672
673 /* Notify listeners about cursor position changed: */
674 emit sigCursorPositionChange();
675 }
676}
677
678void UISession::sltKeyboardLedsChangeEvent(bool fNumLock, bool fCapsLock, bool fScrollLock)
679{
680 /* Check if something had changed: */
681 if ( m_fNumLock != fNumLock
682 || m_fCapsLock != fCapsLock
683 || m_fScrollLock != fScrollLock)
684 {
685 /* Store new num lock data: */
686 if (m_fNumLock != fNumLock)
687 {
688 m_fNumLock = fNumLock;
689 m_uNumLockAdaptionCnt = 2;
690 }
691
692 /* Store new caps lock data: */
693 if (m_fCapsLock != fCapsLock)
694 {
695 m_fCapsLock = fCapsLock;
696 m_uCapsLockAdaptionCnt = 2;
697 }
698
699 /* Store new scroll lock data: */
700 if (m_fScrollLock != fScrollLock)
701 {
702 m_fScrollLock = fScrollLock;
703 }
704
705 /* Notify listeners about mouse capability changed: */
706 emit sigKeyboardLedsChange();
707 }
708}
709
710void UISession::sltStateChange(KMachineState state)
711{
712 /* Check if something had changed: */
713 if (m_machineState != state)
714 {
715 /* Store new data: */
716 m_machineStatePrevious = m_machineState;
717 m_machineState = state;
718
719 /* Notify listeners about machine state changed: */
720 emit sigMachineStateChange();
721 }
722}
723
724void UISession::sltVRDEChange()
725{
726 /* Make sure VRDE server is present: */
727 const CVRDEServer server = machine().GetVRDEServer();
728 AssertMsgReturnVoid(machine().isOk() && !server.isNull(),
729 ("VRDE server should NOT be null!\n"));
730
731 /* Check/Uncheck VRDE Server action depending on feature status: */
732 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->blockSignals(true);
733 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->setChecked(server.GetEnabled());
734 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->blockSignals(false);
735
736 /* Notify listeners about VRDE change: */
737 emit sigVRDEChange();
738}
739
740void UISession::sltRecordingChange()
741{
742 CRecordingSettings comRecordingSettings = machine().GetRecordingSettings();
743
744 /* Check/Uncheck Capture action depending on feature status: */
745 actionPool()->action(UIActionIndexRT_M_View_M_Recording_T_Start)->blockSignals(true);
746 actionPool()->action(UIActionIndexRT_M_View_M_Recording_T_Start)->setChecked(comRecordingSettings.GetEnabled());
747 actionPool()->action(UIActionIndexRT_M_View_M_Recording_T_Start)->blockSignals(false);
748
749 /* Notify listeners about Recording change: */
750 emit sigRecordingChange();
751}
752
753void UISession::sltGuestMonitorChange(KGuestMonitorChangedEventType changeType, ulong uScreenId, QRect screenGeo)
754{
755 /* Ignore KGuestMonitorChangedEventType_NewOrigin change event: */
756 if (changeType == KGuestMonitorChangedEventType_NewOrigin)
757 return;
758 /* Ignore KGuestMonitorChangedEventType_Disabled event for primary screen: */
759 AssertMsg(countOfVisibleWindows() > 0, ("All machine windows are hidden!"));
760 if (changeType == KGuestMonitorChangedEventType_Disabled && uScreenId == 0)
761 return;
762
763 /* Process KGuestMonitorChangedEventType_Enabled change event: */
764 if ( !isScreenVisible(uScreenId)
765 && changeType == KGuestMonitorChangedEventType_Enabled)
766 setScreenVisible(uScreenId, true);
767 /* Process KGuestMonitorChangedEventType_Disabled change event: */
768 else if ( isScreenVisible(uScreenId)
769 && changeType == KGuestMonitorChangedEventType_Disabled)
770 setScreenVisible(uScreenId, false);
771
772 /* Notify listeners about the change: */
773 emit sigGuestMonitorChange(changeType, uScreenId, screenGeo);
774}
775
776void UISession::sltHandleStorageDeviceChange(const CMediumAttachment &attachment, bool fRemoved, bool fSilent)
777{
778 /* Update action restrictions: */
779 updateActionRestrictions();
780
781 /* Notify listeners about storage device change: */
782 emit sigStorageDeviceChange(attachment, fRemoved, fSilent);
783}
784
785void UISession::sltAudioAdapterChange()
786{
787 /* Make sure Audio adapter is present: */
788 const CAudioAdapter comAdapter = machine().GetAudioAdapter();
789 AssertMsgReturnVoid(machine().isOk() && comAdapter.isNotNull(),
790 ("Audio adapter should NOT be null!\n"));
791
792 /* Check/Uncheck Audio adapter output/input actions depending on features status: */
793 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->blockSignals(true);
794 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->setChecked(comAdapter.GetEnabledOut());
795 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->blockSignals(false);
796 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->blockSignals(true);
797 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->setChecked(comAdapter.GetEnabledIn());
798 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->blockSignals(false);
799
800 /* Notify listeners about Audio adapter change: */
801 emit sigAudioAdapterChange();
802
803}
804
805void UISession::sltClipboardModeChange(KClipboardMode enmMode)
806{
807 emit sigClipboardModeChange(enmMode);
808}
809
810void UISession::sltDnDModeChange(KDnDMode enmMode)
811{
812 emit sigDnDModeChange(enmMode);
813}
814
815#ifdef RT_OS_DARWIN
816/**
817 * MacOS X: Restarts display-reconfiguration watchdog timer from the beginning.
818 * @note Watchdog is trying to determine display reconfiguration in
819 * UISession::sltCheckIfHostDisplayChanged() slot every 500ms for 40 tries.
820 */
821void UISession::sltHandleHostDisplayAboutToChange()
822{
823 LogRelFlow(("GUI: UISession::sltHandleHostDisplayAboutToChange()\n"));
824
825 if (m_pWatchdogDisplayChange->isActive())
826 m_pWatchdogDisplayChange->stop();
827 m_pWatchdogDisplayChange->setProperty("tryNumber", 1);
828 m_pWatchdogDisplayChange->start();
829}
830
831/**
832 * MacOS X: Determines display reconfiguration.
833 * @note Calls for UISession::sltHandleHostScreenCountChange() if screen count changed.
834 * @note Calls for UISession::sltHandleHostScreenGeometryChange() if screen geometry changed.
835 */
836void UISession::sltCheckIfHostDisplayChanged()
837{
838 LogRelFlow(("GUI: UISession::sltCheckIfHostDisplayChanged()\n"));
839
840 /* Check if display count changed: */
841 if (gpDesktop->screenCount() != m_hostScreens.size())
842 {
843 /* Reset watchdog: */
844 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
845 /* Notify listeners about screen-count changed: */
846 return sltHandleHostScreenCountChange();
847 }
848 else
849 {
850 /* Check if at least one display geometry changed: */
851 for (int iScreenIndex = 0; iScreenIndex < gpDesktop->screenCount(); ++iScreenIndex)
852 {
853 if (gpDesktop->screenGeometry(iScreenIndex) != m_hostScreens.at(iScreenIndex))
854 {
855 /* Reset watchdog: */
856 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
857 /* Notify listeners about screen-geometry changed: */
858 return sltHandleHostScreenGeometryChange();
859 }
860 }
861 }
862
863 /* Check if watchdog expired, restart if not: */
864 int cTryNumber = m_pWatchdogDisplayChange->property("tryNumber").toInt();
865 if (cTryNumber > 0 && cTryNumber < 40)
866 {
867 /* Restart watchdog again: */
868 m_pWatchdogDisplayChange->setProperty("tryNumber", ++cTryNumber);
869 m_pWatchdogDisplayChange->start();
870 }
871 else
872 {
873 /* Reset watchdog: */
874 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
875 }
876}
877#endif /* RT_OS_DARWIN */
878
879void UISession::sltHandleHostScreenCountChange()
880{
881 LogRelFlow(("GUI: UISession: Host-screen count changed.\n"));
882
883 /* Recache display data: */
884 updateHostScreenData();
885
886 /* Notify current machine-logic: */
887 emit sigHostScreenCountChange();
888}
889
890void UISession::sltHandleHostScreenGeometryChange()
891{
892 LogRelFlow(("GUI: UISession: Host-screen geometry changed.\n"));
893
894 /* Recache display data: */
895 updateHostScreenData();
896
897 /* Notify current machine-logic: */
898 emit sigHostScreenGeometryChange();
899}
900
901void UISession::sltHandleHostScreenAvailableAreaChange()
902{
903 LogRelFlow(("GUI: UISession: Host-screen available-area changed.\n"));
904
905 /* Notify current machine-logic: */
906 emit sigHostScreenAvailableAreaChange();
907}
908
909void UISession::sltAdditionsChange()
910{
911 /* Variable flags: */
912 ULONG ulGuestAdditionsRunLevel = guest().GetAdditionsRunLevel();
913 LONG64 lLastUpdatedIgnored;
914 bool fIsGuestSupportsGraphics = guest().GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
915 == KAdditionsFacilityStatus_Active;
916 bool fIsGuestSupportsSeamless = guest().GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
917 == KAdditionsFacilityStatus_Active;
918 /* Check if something had changed: */
919 if (m_ulGuestAdditionsRunLevel != ulGuestAdditionsRunLevel ||
920 m_fIsGuestSupportsGraphics != fIsGuestSupportsGraphics ||
921 m_fIsGuestSupportsSeamless != fIsGuestSupportsSeamless)
922 {
923 /* Store new data: */
924 m_ulGuestAdditionsRunLevel = ulGuestAdditionsRunLevel;
925 m_fIsGuestSupportsGraphics = fIsGuestSupportsGraphics;
926 m_fIsGuestSupportsSeamless = fIsGuestSupportsSeamless;
927
928 /* Make sure action-pool knows whether GA supports graphics: */
929 actionPool()->toRuntime()->setGuestSupportsGraphics(m_fIsGuestSupportsGraphics);
930
931 /* Notify listeners about GA state really changed: */
932 LogRel(("GUI: UISession::sltAdditionsChange: GA state really changed, notifying listeners\n"));
933 emit sigAdditionsStateActualChange();
934 }
935
936 /* Notify listeners about GA state change event came: */
937 LogRel(("GUI: UISession::sltAdditionsChange: GA state change event came, notifying listeners\n"));
938 emit sigAdditionsStateChange();
939}
940
941UISession::UISession(UIMachine *pMachine)
942 : QObject(pMachine)
943 /* Base variables: */
944 , m_pMachine(pMachine)
945 , m_pActionPool(0)
946#ifdef VBOX_WS_MAC
947 , m_pMenuBar(0)
948#endif /* VBOX_WS_MAC */
949 /* Common variables: */
950 , m_machineStatePrevious(KMachineState_Null)
951 , m_machineState(KMachineState_Null)
952 , m_pMachineWindowIcon(0)
953 , m_requestedVisualStateType(UIVisualStateType_Invalid)
954#ifdef VBOX_WS_WIN
955 , m_alphaCursor(0)
956#endif /* VBOX_WS_WIN */
957#ifdef VBOX_WS_MAC
958 , m_pWatchdogDisplayChange(0)
959#endif /* VBOX_WS_MAC */
960 , m_defaultCloseAction(MachineCloseAction_Invalid)
961 , m_restrictedCloseActions(MachineCloseAction_Invalid)
962 , m_fAllCloseActionsRestricted(false)
963 /* Common flags: */
964 , m_fInitialized(false)
965 , m_fIsFirstTimeStarted(false)
966 , m_fIsGuestResizeIgnored(false)
967 , m_fIsAutoCaptureDisabled(false)
968 /* Guest additions flags: */
969 , m_ulGuestAdditionsRunLevel(0)
970 , m_fIsGuestSupportsGraphics(false)
971 , m_fIsGuestSupportsSeamless(false)
972 /* Mouse flags: */
973 , m_fNumLock(false)
974 , m_fCapsLock(false)
975 , m_fScrollLock(false)
976 , m_uNumLockAdaptionCnt(2)
977 , m_uCapsLockAdaptionCnt(2)
978 /* Mouse flags: */
979 , m_fIsMouseSupportsAbsolute(false)
980 , m_fIsMouseSupportsRelative(false)
981 , m_fIsMouseSupportsMultiTouch(false)
982 , m_fIsMouseHostCursorNeeded(false)
983 , m_fIsMouseCaptured(false)
984 , m_fIsMouseIntegrated(true)
985 , m_fIsValidPointerShapePresent(false)
986 , m_fIsHidingHostPointer(true)
987 , m_fIsValidCursorPositionPresent(false)
988 , m_enmVMExecutionEngine(KVMExecutionEngine_NotSet)
989 /* CPU hardware virtualization features for VM: */
990 , m_fIsHWVirtExNestedPagingEnabled(false)
991 , m_fIsHWVirtExUXEnabled(false)
992 /* VM's effective paravirtualization provider: */
993 , m_paraVirtProvider(KParavirtProvider_None)
994{
995}
996
997UISession::~UISession()
998{
999}
1000
1001bool UISession::prepare()
1002{
1003 /* Prepare session: */
1004 if (!prepareSession())
1005 return false;
1006
1007 /* Prepare actions: */
1008 prepareActions();
1009
1010 /* Prepare connections: */
1011 prepareConnections();
1012
1013 /* Prepare console event-handlers: */
1014 prepareConsoleEventHandlers();
1015
1016 /* Prepare screens: */
1017 prepareScreens();
1018
1019 /* Prepare framebuffers: */
1020 prepareFramebuffers();
1021
1022 /* Load settings: */
1023 loadSessionSettings();
1024
1025#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
1026 struct sigaction sa;
1027 sa.sa_sigaction = &signalHandlerSIGUSR1;
1028 sigemptyset(&sa.sa_mask);
1029 sa.sa_flags = SA_RESTART | SA_SIGINFO;
1030 sigaction(SIGUSR1, &sa, NULL);
1031#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
1032
1033 /* True by default: */
1034 return true;
1035}
1036
1037bool UISession::prepareSession()
1038{
1039 /* Open session: */
1040 m_session = uiCommon().openSession(uiCommon().managedVMUuid(),
1041 uiCommon().isSeparateProcess()
1042 ? KLockType_Shared : KLockType_VM);
1043 if (m_session.isNull())
1044 return false;
1045
1046 /* Get machine: */
1047 m_machine = m_session.GetMachine();
1048 if (m_machine.isNull())
1049 return false;
1050
1051 /* Get console: */
1052 m_console = m_session.GetConsole();
1053 if (m_console.isNull())
1054 return false;
1055
1056 /* Get display: */
1057 m_display = m_console.GetDisplay();
1058 if (m_display.isNull())
1059 return false;
1060
1061 /* Get guest: */
1062 m_guest = m_console.GetGuest();
1063 if (m_guest.isNull())
1064 return false;
1065
1066 /* Get mouse: */
1067 m_mouse = m_console.GetMouse();
1068 if (m_mouse.isNull())
1069 return false;
1070
1071 /* Get keyboard: */
1072 m_keyboard = m_console.GetKeyboard();
1073 if (m_keyboard.isNull())
1074 return false;
1075
1076 /* Get debugger: */
1077 m_debugger = m_console.GetDebugger();
1078 if (m_debugger.isNull())
1079 return false;
1080
1081 /* Update machine-name: */
1082 m_strMachineName = machine().GetName();
1083
1084 /* Update machine-state: */
1085 m_machineState = machine().GetState();
1086
1087 /* True by default: */
1088 return true;
1089}
1090
1091void UISession::prepareActions()
1092{
1093 /* Create action-pool: */
1094 m_pActionPool = UIActionPool::create(UIActionPoolType_Runtime);
1095 AssertPtrReturnVoid(actionPool());
1096 {
1097 /* Update action restrictions: */
1098 updateActionRestrictions();
1099
1100#ifdef VBOX_WS_MAC
1101 /* Create Mac OS X menu-bar: */
1102 m_pMenuBar = new QMenuBar;
1103 AssertPtrReturnVoid(m_pMenuBar);
1104 {
1105 /* Configure Mac OS X menu-bar: */
1106 connect(gEDataManager, &UIExtraDataManager::sigMenuBarConfigurationChange,
1107 this, &UISession::sltHandleMenuBarConfigurationChange);
1108 /* Update Mac OS X menu-bar: */
1109 updateMenu();
1110 }
1111#endif /* VBOX_WS_MAC */
1112 }
1113}
1114
1115void UISession::prepareConnections()
1116{
1117 connect(this, &UISession::sigInitialized, this, &UISession::sltMarkInitialized);
1118
1119#ifdef VBOX_WS_MAC
1120 /* Install native display reconfiguration callback: */
1121 CGDisplayRegisterReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1122#else /* !VBOX_WS_MAC */
1123 /* Install Qt display reconfiguration callbacks: */
1124 connect(gpDesktop, &UIDesktopWidgetWatchdog::sigHostScreenCountChanged,
1125 this, &UISession::sltHandleHostScreenCountChange);
1126 connect(gpDesktop, &UIDesktopWidgetWatchdog::sigHostScreenResized,
1127 this, &UISession::sltHandleHostScreenGeometryChange);
1128# ifdef VBOX_WS_X11
1129 connect(gpDesktop, &UIDesktopWidgetWatchdog::sigHostScreenWorkAreaRecalculated,
1130 this, &UISession::sltHandleHostScreenAvailableAreaChange);
1131# else /* !VBOX_WS_X11 */
1132 connect(gpDesktop, &UIDesktopWidgetWatchdog::sigHostScreenWorkAreaResized,
1133 this, &UISession::sltHandleHostScreenAvailableAreaChange);
1134# endif /* !VBOX_WS_X11 */
1135#endif /* !VBOX_WS_MAC */
1136}
1137
1138void UISession::prepareConsoleEventHandlers()
1139{
1140 /* Create console event-handler: */
1141 UIConsoleEventHandler::create(this);
1142
1143 /* Add console event connections: */
1144 connect(gConsoleEvents, &UIConsoleEventHandler::sigMousePointerShapeChange,
1145 this, &UISession::sltMousePointerShapeChange);
1146
1147 connect(gConsoleEvents, &UIConsoleEventHandler::sigMouseCapabilityChange,
1148 this, &UISession::sltMouseCapabilityChange);
1149
1150 connect(gConsoleEvents, &UIConsoleEventHandler::sigCursorPositionChange,
1151 this, &UISession::sltCursorPositionChange);
1152
1153 connect(gConsoleEvents, &UIConsoleEventHandler::sigKeyboardLedsChangeEvent,
1154 this, &UISession::sltKeyboardLedsChangeEvent);
1155
1156 connect(gConsoleEvents, &UIConsoleEventHandler::sigStateChange,
1157 this, &UISession::sltStateChange);
1158
1159 connect(gConsoleEvents, &UIConsoleEventHandler::sigAdditionsChange,
1160 this, &UISession::sltAdditionsChange);
1161
1162 connect(gConsoleEvents, &UIConsoleEventHandler::sigVRDEChange,
1163 this, &UISession::sltVRDEChange);
1164
1165 connect(gConsoleEvents, &UIConsoleEventHandler::sigRecordingChange,
1166 this, &UISession::sltRecordingChange);
1167
1168 connect(gConsoleEvents, &UIConsoleEventHandler::sigNetworkAdapterChange,
1169 this, &UISession::sigNetworkAdapterChange);
1170
1171 connect(gConsoleEvents, &UIConsoleEventHandler::sigStorageDeviceChange,
1172 this, &UISession::sltHandleStorageDeviceChange);
1173
1174 connect(gConsoleEvents, &UIConsoleEventHandler::sigMediumChange,
1175 this, &UISession::sigMediumChange);
1176
1177 connect(gConsoleEvents, &UIConsoleEventHandler::sigUSBControllerChange,
1178 this, &UISession::sigUSBControllerChange);
1179
1180 connect(gConsoleEvents, &UIConsoleEventHandler::sigUSBDeviceStateChange,
1181 this, &UISession::sigUSBDeviceStateChange);
1182
1183 connect(gConsoleEvents, &UIConsoleEventHandler::sigSharedFolderChange,
1184 this, &UISession::sigSharedFolderChange);
1185
1186 connect(gConsoleEvents, &UIConsoleEventHandler::sigRuntimeError,
1187 this, &UISession::sigRuntimeError);
1188
1189#ifdef VBOX_WS_MAC
1190 connect(gConsoleEvents, &UIConsoleEventHandler::sigShowWindow,
1191 this, &UISession::sigShowWindows, Qt::QueuedConnection);
1192#endif /* VBOX_WS_MAC */
1193
1194 connect(gConsoleEvents, &UIConsoleEventHandler::sigCPUExecutionCapChange,
1195 this, &UISession::sigCPUExecutionCapChange);
1196
1197 connect(gConsoleEvents, &UIConsoleEventHandler::sigGuestMonitorChange,
1198 this, &UISession::sltGuestMonitorChange);
1199
1200 connect(gConsoleEvents, &UIConsoleEventHandler::sigAudioAdapterChange,
1201 this, &UISession::sltAudioAdapterChange);
1202
1203 connect(gConsoleEvents, &UIConsoleEventHandler::sigClipboardModeChange,
1204 this, &UISession::sltClipboardModeChange);
1205
1206 connect(gConsoleEvents, &UIConsoleEventHandler::sigDnDModeChange,
1207 this, &UISession::sltDnDModeChange);
1208}
1209
1210void UISession::prepareScreens()
1211{
1212 /* Recache display data: */
1213 updateHostScreenData();
1214
1215#ifdef VBOX_WS_MAC
1216 /* Prepare display-change watchdog: */
1217 m_pWatchdogDisplayChange = new QTimer(this);
1218 {
1219 m_pWatchdogDisplayChange->setInterval(500);
1220 m_pWatchdogDisplayChange->setSingleShot(true);
1221 connect(m_pWatchdogDisplayChange, &QTimer::timeout,
1222 this, &UISession::sltCheckIfHostDisplayChanged);
1223 }
1224#endif /* VBOX_WS_MAC */
1225
1226 /* Prepare initial screen visibility status: */
1227 m_monitorVisibilityVector.resize(machine().GetGraphicsAdapter().GetMonitorCount());
1228 m_monitorVisibilityVector.fill(false);
1229 m_monitorVisibilityVector[0] = true;
1230
1231 /* Prepare empty last full-screen size vector: */
1232 m_monitorLastFullScreenSizeVector.resize(machine().GetGraphicsAdapter().GetMonitorCount());
1233 m_monitorLastFullScreenSizeVector.fill(QSize(-1, -1));
1234
1235 /* If machine is in 'saved' state: */
1236 if (isSaved())
1237 {
1238 /* Update screen visibility status from saved-state: */
1239 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1240 {
1241 BOOL fEnabled = true;
1242 ULONG uGuestOriginX = 0, uGuestOriginY = 0, uGuestWidth = 0, uGuestHeight = 0;
1243 machine().QuerySavedGuestScreenInfo(iScreenIndex,
1244 uGuestOriginX, uGuestOriginY,
1245 uGuestWidth, uGuestHeight, fEnabled);
1246 m_monitorVisibilityVector[iScreenIndex] = fEnabled;
1247 }
1248 /* And make sure at least one of them is visible (primary if others are hidden): */
1249 if (countOfVisibleWindows() < 1)
1250 m_monitorVisibilityVector[0] = true;
1251 }
1252 else if (uiCommon().isSeparateProcess())
1253 {
1254 /* Update screen visibility status from display directly: */
1255 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1256 {
1257 KGuestMonitorStatus enmStatus = KGuestMonitorStatus_Disabled;
1258 ULONG uGuestWidth = 0, uGuestHeight = 0, uBpp = 0;
1259 LONG iGuestOriginX = 0, iGuestOriginY = 0;
1260 display().GetScreenResolution(iScreenIndex,
1261 uGuestWidth, uGuestHeight, uBpp,
1262 iGuestOriginX, iGuestOriginY, enmStatus);
1263 m_monitorVisibilityVector[iScreenIndex] = ( enmStatus == KGuestMonitorStatus_Enabled
1264 || enmStatus == KGuestMonitorStatus_Blank);
1265 }
1266 /* And make sure at least one of them is visible (primary if others are hidden): */
1267 if (countOfVisibleWindows() < 1)
1268 m_monitorVisibilityVector[0] = true;
1269 }
1270
1271 /* Prepare initial screen visibility status of host-desires (same as facts): */
1272 m_monitorVisibilityVectorHostDesires.resize(machine().GetGraphicsAdapter().GetMonitorCount());
1273 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1274 m_monitorVisibilityVectorHostDesires[iScreenIndex] = m_monitorVisibilityVector[iScreenIndex];
1275
1276 /* Make sure action-pool knows guest-screen visibility status: */
1277 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1278 actionPool()->toRuntime()->setGuestScreenVisible(iScreenIndex, m_monitorVisibilityVector.at(iScreenIndex));
1279}
1280
1281void UISession::prepareFramebuffers()
1282{
1283 /* Each framebuffer will be really prepared on first UIMachineView creation: */
1284 m_frameBufferVector.resize(machine().GetGraphicsAdapter().GetMonitorCount());
1285
1286 /* Make sure action-pool knows guest-screen count: */
1287 actionPool()->toRuntime()->setGuestScreenCount(m_frameBufferVector.size());
1288}
1289
1290void UISession::loadSessionSettings()
1291{
1292 /* Load extra-data settings: */
1293 {
1294 /* Get machine ID: */
1295 const QUuid uMachineID = uiCommon().managedVMUuid();
1296
1297 /* Prepare machine-window icon: */
1298 {
1299 /* Acquire user machine-window icon: */
1300 QIcon icon = uiCommon().vmUserIcon(machine());
1301 /* Use the OS type icon if user one was not set: */
1302 if (icon.isNull())
1303 icon = uiCommon().vmGuestOSTypeIcon(machine().GetOSTypeId());
1304 /* Use the default icon if nothing else works: */
1305 if (icon.isNull())
1306 icon = QIcon(":/VirtualBox_48px.png");
1307 /* Store the icon dynamically: */
1308 m_pMachineWindowIcon = new QIcon(icon);
1309 }
1310
1311#ifndef VBOX_WS_MAC
1312 /* Load user's machine-window name postfix: */
1313 m_strMachineWindowNamePostfix = gEDataManager->machineWindowNamePostfix(uMachineID);
1314#endif
1315
1316 /* Is there should be First RUN Wizard? */
1317 m_fIsFirstTimeStarted = gEDataManager->machineFirstTimeStarted(uMachineID);
1318
1319 /* Should guest autoresize? */
1320 QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1321 pGuestAutoresizeSwitch->setChecked(gEDataManager->guestScreenAutoResizeEnabled(uMachineID));
1322
1323#ifndef VBOX_WS_MAC
1324 /* Menu-bar options: */
1325 {
1326 const bool fEnabledGlobally = !gEDataManager->guiFeatureEnabled(GUIFeatureType_NoMenuBar);
1327 const bool fEnabledForMachine = gEDataManager->menuBarEnabled(uMachineID);
1328 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1329 QAction *pActionMenuBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_S_Settings);
1330 pActionMenuBarSettings->setEnabled(fEnabled);
1331 QAction *pActionMenuBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_T_Visibility);
1332 pActionMenuBarSwitch->blockSignals(true);
1333 pActionMenuBarSwitch->setChecked(fEnabled);
1334 pActionMenuBarSwitch->blockSignals(false);
1335 }
1336#endif /* !VBOX_WS_MAC */
1337
1338 /* Status-bar options: */
1339 {
1340 const bool fEnabledGlobally = !gEDataManager->guiFeatureEnabled(GUIFeatureType_NoStatusBar);
1341 const bool fEnabledForMachine = gEDataManager->statusBarEnabled(uMachineID);
1342 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1343 QAction *pActionStatusBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_S_Settings);
1344 pActionStatusBarSettings->setEnabled(fEnabled);
1345 QAction *pActionStatusBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility);
1346 pActionStatusBarSwitch->blockSignals(true);
1347 pActionStatusBarSwitch->setChecked(fEnabled);
1348 pActionStatusBarSwitch->blockSignals(false);
1349 }
1350
1351 /* Input options: */
1352 actionPool()->action(UIActionIndexRT_M_Input_M_Mouse_T_Integration)->setChecked(isMouseIntegrated());
1353
1354 /* Devices options: */
1355 {
1356 const CAudioAdapter comAudio = m_machine.GetAudioAdapter();
1357 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->blockSignals(true);
1358 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->setChecked(comAudio.GetEnabledOut());
1359 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output)->blockSignals(false);
1360 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->blockSignals(true);
1361 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->setChecked(comAudio.GetEnabledIn());
1362 actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input)->blockSignals(false);
1363 }
1364
1365 /* What is the default close action and the restricted are? */
1366 m_defaultCloseAction = gEDataManager->defaultMachineCloseAction(uMachineID);
1367 m_restrictedCloseActions = gEDataManager->restrictedMachineCloseActions(uMachineID);
1368 m_fAllCloseActionsRestricted = (!uiCommon().isSeparateProcess() || (m_restrictedCloseActions & MachineCloseAction_Detach))
1369 && (m_restrictedCloseActions & MachineCloseAction_SaveState)
1370 && (m_restrictedCloseActions & MachineCloseAction_Shutdown)
1371 && (m_restrictedCloseActions & MachineCloseAction_PowerOff);
1372 // Close VM Dialog hides PowerOff_RestoringSnapshot implicitly if PowerOff is hidden..
1373 // && (m_restrictedCloseActions & MachineCloseAction_PowerOff_RestoringSnapshot);
1374 }
1375}
1376
1377void UISession::saveSessionSettings()
1378{
1379 /* Save extra-data settings: */
1380 {
1381 /* Disable First RUN Wizard: */
1382 gEDataManager->setMachineFirstTimeStarted(false, uiCommon().managedVMUuid());
1383
1384 /* Remember if guest should autoresize: */
1385 if (actionPool())
1386 {
1387 const QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1388 gEDataManager->setGuestScreenAutoResizeEnabled(pGuestAutoresizeSwitch->isChecked(), uiCommon().managedVMUuid());
1389 }
1390
1391 /* Cleanup machine-window icon: */
1392 delete m_pMachineWindowIcon;
1393 m_pMachineWindowIcon = 0;
1394 }
1395}
1396
1397void UISession::cleanupFramebuffers()
1398{
1399 /* Cleanup framebuffers finally: */
1400 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
1401 {
1402 UIFrameBuffer *pFrameBuffer = m_frameBufferVector[i];
1403 if (pFrameBuffer)
1404 {
1405 /* Mark framebuffer as unused: */
1406 pFrameBuffer->setMarkAsUnused(true);
1407 /* Detach framebuffer from Display: */
1408 pFrameBuffer->detach();
1409 /* Delete framebuffer reference: */
1410 delete pFrameBuffer;
1411 }
1412 }
1413 m_frameBufferVector.clear();
1414
1415 /* Make sure action-pool knows guest-screen count: */
1416 if (actionPool())
1417 actionPool()->toRuntime()->setGuestScreenCount(m_frameBufferVector.size());
1418}
1419
1420void UISession::cleanupConsoleEventHandlers()
1421{
1422 /* Destroy console event-handler if necessary: */
1423 if (gConsoleEvents)
1424 UIConsoleEventHandler::destroy();
1425}
1426
1427void UISession::cleanupConnections()
1428{
1429#ifdef VBOX_WS_MAC
1430 /* Remove display reconfiguration callback: */
1431 CGDisplayRemoveReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1432#endif /* VBOX_WS_MAC */
1433}
1434
1435void UISession::cleanupActions()
1436{
1437#ifdef VBOX_WS_MAC
1438 /* Destroy Mac OS X menu-bar: */
1439 delete m_pMenuBar;
1440 m_pMenuBar = 0;
1441#endif /* VBOX_WS_MAC */
1442
1443 /* Destroy action-pool if necessary: */
1444 if (actionPool())
1445 UIActionPool::destroy(actionPool());
1446}
1447
1448void UISession::cleanupSession()
1449{
1450 /* Detach debugger: */
1451 if (!m_debugger.isNull())
1452 m_debugger.detach();
1453
1454 /* Detach keyboard: */
1455 if (!m_keyboard.isNull())
1456 m_keyboard.detach();
1457
1458 /* Detach mouse: */
1459 if (!m_mouse.isNull())
1460 m_mouse.detach();
1461
1462 /* Detach guest: */
1463 if (!m_guest.isNull())
1464 m_guest.detach();
1465
1466 /* Detach display: */
1467 if (!m_display.isNull())
1468 m_display.detach();
1469
1470 /* Detach console: */
1471 if (!m_console.isNull())
1472 m_console.detach();
1473
1474 /* Detach machine: */
1475 if (!m_machine.isNull())
1476 m_machine.detach();
1477
1478 /* Close session: */
1479 if (!m_session.isNull() && uiCommon().isVBoxSVCAvailable())
1480 {
1481 m_session.UnlockMachine();
1482 m_session.detach();
1483 }
1484}
1485
1486void UISession::cleanup()
1487{
1488#ifdef VBOX_WS_WIN
1489 /* Destroy alpha cursor: */
1490 if (m_alphaCursor)
1491 DestroyIcon(m_alphaCursor);
1492#endif /* VBOX_WS_WIN */
1493
1494 /* Save settings: */
1495 saveSessionSettings();
1496
1497 /* Cleanup framebuffers: */
1498 cleanupFramebuffers();
1499
1500 /* Cleanup console event-handlers: */
1501 cleanupConsoleEventHandlers();
1502
1503 /* Cleanup connections: */
1504 cleanupConnections();
1505
1506 /* Cleanup actions: */
1507 cleanupActions();
1508
1509 /* Cleanup session: */
1510 cleanupSession();
1511}
1512
1513#ifdef VBOX_WS_MAC
1514void UISession::updateMenu()
1515{
1516 /* Rebuild Mac OS X menu-bar: */
1517 m_pMenuBar->clear();
1518 foreach (QMenu *pMenu, actionPool()->menus())
1519 {
1520 UIMenu *pMenuUI = qobject_cast<UIMenu*>(pMenu);
1521 if (!pMenuUI->isConsumable() || !pMenuUI->isConsumed())
1522 m_pMenuBar->addMenu(pMenuUI);
1523 if (pMenuUI->isConsumable() && !pMenuUI->isConsumed())
1524 pMenuUI->setConsumed(true);
1525 }
1526 /* Update the dock menu as well: */
1527 if (machineLogic())
1528 machineLogic()->updateDock();
1529}
1530#endif /* VBOX_WS_MAC */
1531
1532/** Generate a BGRA bitmap which approximates a XOR/AND mouse pointer.
1533 *
1534 * Pixels which has 1 in the AND mask and not 0 in the XOR mask are replaced by
1535 * the inverted pixel and 8 surrounding pixels with the original color.
1536 * Fort example a white pixel (W) is replaced with a black (B) pixel:
1537 * WWW
1538 * W -> WBW
1539 * WWW
1540 * The surrounding pixels are written only if the corresponding source pixel
1541 * does not affect the screen, i.e. AND bit is 1 and XOR value is 0.
1542 */
1543static void renderCursorPixels(const uint32_t *pu32XOR, const uint8_t *pu8AND,
1544 uint32_t u32Width, uint32_t u32Height,
1545 uint32_t *pu32Pixels, uint32_t cbPixels)
1546{
1547 /* Output pixels set to 0 which allow to not write transparent pixels anymore. */
1548 memset(pu32Pixels, 0, cbPixels);
1549
1550 const uint32_t *pu32XORSrc = pu32XOR; /* Iterator for source XOR pixels. */
1551 const uint8_t *pu8ANDSrcLine = pu8AND; /* The current AND mask scanline. */
1552 uint32_t *pu32Dst = pu32Pixels; /* Iterator for all destination BGRA pixels. */
1553
1554 /* Some useful constants. */
1555 const int cbANDLine = ((int)u32Width + 7) / 8;
1556
1557 int y;
1558 for (y = 0; y < (int)u32Height; ++y)
1559 {
1560 int x;
1561 for (x = 0; x < (int)u32Width; ++x)
1562 {
1563 const uint32_t u32Pixel = *pu32XORSrc; /* Current pixel at (x,y) */
1564 const uint8_t *pu8ANDSrc = pu8ANDSrcLine + x / 8; /* Byte which containt current AND bit. */
1565
1566 if ((*pu8ANDSrc << (x % 8)) & 0x80)
1567 {
1568 if (u32Pixel)
1569 {
1570 const uint32_t u32PixelInverted = ~u32Pixel;
1571
1572 /* Scan neighbor pixels and assign them if they are transparent. */
1573 int dy;
1574 for (dy = -1; dy <= 1; ++dy)
1575 {
1576 const int yn = y + dy;
1577 if (yn < 0 || yn >= (int)u32Height)
1578 continue; /* Do not cross the bounds. */
1579
1580 int dx;
1581 for (dx = -1; dx <= 1; ++dx)
1582 {
1583 const int xn = x + dx;
1584 if (xn < 0 || xn >= (int)u32Width)
1585 continue; /* Do not cross the bounds. */
1586
1587 if (dx != 0 || dy != 0)
1588 {
1589 /* Check if the neighbor pixel is transparent. */
1590 const uint32_t *pu32XORNeighborSrc = &pu32XORSrc[dy * (int)u32Width + dx];
1591 const uint8_t *pu8ANDNeighborSrc = pu8ANDSrcLine + dy * cbANDLine + xn / 8;
1592 if ( *pu32XORNeighborSrc == 0
1593 && ((*pu8ANDNeighborSrc << (xn % 8)) & 0x80) != 0)
1594 {
1595 /* Transparent neighbor pixels are replaced with the source pixel value. */
1596 uint32_t *pu32PixelNeighborDst = &pu32Dst[dy * (int)u32Width + dx];
1597 *pu32PixelNeighborDst = u32Pixel | 0xFF000000;
1598 }
1599 }
1600 else
1601 {
1602 /* The pixel itself is replaced with inverted value. */
1603 *pu32Dst = u32PixelInverted | 0xFF000000;
1604 }
1605 }
1606 }
1607 }
1608 else
1609 {
1610 /* The pixel does not affect the screen.
1611 * Do nothing. Do not touch destination which can already contain generated pixels.
1612 */
1613 }
1614 }
1615 else
1616 {
1617 /* AND bit is 0, the pixel will be just drawn. */
1618 *pu32Dst = u32Pixel | 0xFF000000;
1619 }
1620
1621 ++pu32XORSrc; /* Next source pixel. */
1622 ++pu32Dst; /* Next destination pixel. */
1623 }
1624
1625 /* Next AND scanline. */
1626 pu8ANDSrcLine += cbANDLine;
1627 }
1628}
1629
1630#ifdef VBOX_WS_WIN
1631static bool isPointer1bpp(const uint8_t *pu8XorMask,
1632 uint uWidth,
1633 uint uHeight)
1634{
1635 /* Check if the pointer has only 0 and 0xFFFFFF pixels, ignoring the alpha channel. */
1636 const uint32_t *pu32Src = (uint32_t *)pu8XorMask;
1637
1638 uint y;
1639 for (y = 0; y < uHeight ; ++y)
1640 {
1641 uint x;
1642 for (x = 0; x < uWidth; ++x)
1643 {
1644 const uint32_t u32Pixel = pu32Src[x] & UINT32_C(0xFFFFFF);
1645 if (u32Pixel != 0 && u32Pixel != UINT32_C(0xFFFFFF))
1646 return false;
1647 }
1648
1649 pu32Src += uWidth;
1650 }
1651
1652 return true;
1653}
1654#endif /* VBOX_WS_WIN */
1655
1656void UISession::updateMousePointerShape()
1657{
1658 /* Fetch incoming shape data: */
1659 const bool fHasAlpha = m_shapeData.hasAlpha();
1660 const uint uWidth = m_shapeData.shapeSize().width();
1661 const uint uHeight = m_shapeData.shapeSize().height();
1662 const uchar *pShapeData = m_shapeData.shape().constData();
1663 AssertMsgReturnVoid(pShapeData, ("Shape data must not be NULL!\n"));
1664
1665 /* Invalidate mouse pointer shape initially: */
1666 m_fIsValidPointerShapePresent = false;
1667 m_cursorShapePixmap = QPixmap();
1668 m_cursorMaskPixmap = QPixmap();
1669
1670 /* Parse incoming shape data: */
1671 const uchar *pSrcAndMaskPtr = pShapeData;
1672 const uint uAndMaskSize = (uWidth + 7) / 8 * uHeight;
1673 const uchar *pSrcShapePtr = pShapeData + ((uAndMaskSize + 3) & ~3);
1674
1675#if defined (VBOX_WS_WIN)
1676
1677 /* Create an ARGB image out of the shape data: */
1678
1679 // WORKAROUND:
1680 // Qt5 QCursor recommends 32 x 32 cursor, therefore the original data is copied to
1681 // a larger QImage if necessary. Cursors like 10x16 did not work correctly (Solaris 10 guest).
1682 const uint uCursorWidth = uWidth >= 32 ? uWidth : 32;
1683 const uint uCursorHeight = uHeight >= 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.

© 2023 Oracle
ContactPrivacy policyTerms of Use