VirtualBox

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

Last change on this file since 68392 was 68392, checked in by vboxsync, 7 years ago

FE/Qt: bugref:8900: Selector UI: Use classic (title-bar) beta label instead of rotated one because there is no place for the latter since Tools toolbar was implemented.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.9 KB
Line 
1/* $Id: UISession.cpp 68392 2017-08-11 12:38:02Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISession class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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#ifdef VBOX_WITH_PRECOMPILED_HEADERS
19# include <precomp.h>
20#else /* !VBOX_WITH_PRECOMPILED_HEADERS */
21
22/* Qt includes: */
23# include <QApplication>
24# include <QBitmap>
25# include <QMenuBar>
26# include <QWidget>
27# ifdef VBOX_WS_MAC
28# include <QTimer>
29# endif /* VBOX_WS_MAC */
30
31/* GUI includes: */
32# include "VBoxGlobal.h"
33# include "UIDesktopWidgetWatchdog.h"
34# include "UIExtraDataManager.h"
35# include "UISession.h"
36# include "UIMachine.h"
37# include "UIMedium.h"
38# include "UIActionPoolRuntime.h"
39# include "UIMachineLogic.h"
40# include "UIMachineView.h"
41# include "UIMachineWindow.h"
42# include "UIMessageCenter.h"
43# include "UIPopupCenter.h"
44# include "UIWizardFirstRun.h"
45# include "UIConsoleEventHandler.h"
46# include "UIFrameBuffer.h"
47# include "UISettingsDialogSpecific.h"
48# ifdef VBOX_WITH_VIDEOHWACCEL
49# include "VBoxFBOverlay.h"
50# endif /* VBOX_WITH_VIDEOHWACCEL */
51# ifdef VBOX_WS_MAC
52# include "VBoxUtils-darwin.h"
53# endif /* VBOX_WS_MAC */
54
55# ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
56# include "UIKeyboardHandler.h"
57# include <signal.h>
58# endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
59
60/* COM includes: */
61# include "CSystemProperties.h"
62# include "CStorageController.h"
63# include "CMediumAttachment.h"
64# include "CNetworkAdapter.h"
65# include "CHostNetworkInterface.h"
66# include "CVRDEServer.h"
67# include "CUSBController.h"
68# include "CUSBDeviceFilters.h"
69# include "CHostVideoInputDevice.h"
70# include "CSnapshot.h"
71# include "CMedium.h"
72
73#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
74
75/* Qt includes: */
76#ifdef VBOX_WS_WIN
77# include <QtWin>
78#endif /* VBOX_WS_WIN */
79
80#ifdef VBOX_WS_X11
81# include <QX11Info>
82# include <X11/Xlib.h>
83# include <X11/Xutil.h>
84#endif /* VBOX_WS_X11 */
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(machineLogic()->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 (vboxGlobal().isPatmDisabled())
190 debugger().SetPATMEnabled(false);
191 if (vboxGlobal().isCsamDisabled())
192 debugger().SetCSAMEnabled(false);
193 if (vboxGlobal().isSupervisorCodeExecedRecompiled())
194 debugger().SetRecompileSupervisor(true);
195 if (vboxGlobal().isUserCodeExecedRecompiled())
196 debugger().SetRecompileUser(true);
197 if (vboxGlobal().areWeToExecuteAllInIem())
198 debugger().SetExecuteAllInIEM(true);
199 if (!vboxGlobal().isDefaultWarpPct())
200 debugger().SetVirtualTimeRate(vboxGlobal().getWarpPct());
201 }
202
203 /* Apply ad-hoc reconfigurations from the command line: */
204 if (vboxGlobal().hasFloppyImageToMount())
205 mountAdHocImage(KDeviceType_Floppy, UIMediumType_Floppy, vboxGlobal().getFloppyImage());
206 if (vboxGlobal().hasDvdImageToMount())
207 mountAdHocImage(KDeviceType_DVD, UIMediumType_DVD, vboxGlobal().getDvdImage());
208
209 /* Power UP if this is NOT separate process: */
210 if (!vboxGlobal().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 (vboxGlobal().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().GetAccelerate2DVideoEnabled() && VBoxGlobal::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 vboxGlobal().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 = vboxGlobal().shouldStartPaused() ? console().PowerUpPaused() : console().PowerUp();
277
278 /* Check for immediate failure: */
279 if (!console().isOk() || progress.isNull())
280 {
281 if (vboxGlobal().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", VBoxGlobal::qtRTVersionString().toUtf8().constData()));
289#ifdef VBOX_WS_X11
290 LogRel(("X11 Window Manager code: %d\n", (int)vboxGlobal().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 (vboxGlobal().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 = vboxGlobal().virtualBox();
426 const QString strMachineID = vboxGlobal().managedVMUuid();
427 const CMachine mach = vbox.FindMachine(strMachineID);
428 if (!vbox.isOk() || mach.isNull())
429 {
430 /* Unable to find VM: */
431 msgCenter().cannotFindMachineById(vbox, strMachineID);
432 break;
433 }
434
435 /* Open a direct session to modify that VM: */
436 CSession sess = vboxGlobal().openSession(vboxGlobal().managedVMUuid(),
437 vboxGlobal().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
504bool UISession::isVisualStateAllowed(UIVisualStateType state) const
505{
506 return m_pMachine->isVisualStateAllowed(state);
507}
508
509void UISession::changeVisualState(UIVisualStateType visualStateType)
510{
511 m_pMachine->asyncChangeVisualState(visualStateType);
512}
513
514bool UISession::setPause(bool fOn)
515{
516 if (fOn)
517 console().Pause();
518 else
519 console().Resume();
520
521 bool ok = console().isOk();
522 if (!ok)
523 {
524 if (fOn)
525 msgCenter().cannotPauseMachine(console());
526 else
527 msgCenter().cannotResumeMachine(console());
528 }
529
530 return ok;
531}
532
533void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
534{
535 /* This flag indicates whether we want to do the usual .ISO mounting or not.
536 * First try updating the Guest Additions directly without mounting the .ISO. */
537 bool fDoMount = false;
538
539 /* Auto-update through GUI is currently disabled. */
540#ifndef VBOX_WITH_ADDITIONS_AUTOUPDATE_UI
541 fDoMount = true;
542#else /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
543 /* Initiate installation progress: */
544 QVector<QString> aArgs;
545 QVector<KAdditionsUpdateFlag> aFlagsUpdate;
546 CProgress comProgressInstall = guest().UpdateGuestAdditions(strSource, aArgs, aFlagsUpdate);
547 if (guest().isOk() && comProgressInstall.isNotNull())
548 {
549 /* Show installation progress: */
550 msgCenter().showModalProgressDialog(comProgressInstall, tr("Updating Guest Additions"),
551 ":/progress_install_guest_additions_90px.png",
552 0, 500 /* 500ms delay. */);
553 if (comProgressInstall.GetCanceled())
554 return;
555
556 /* Check whether progress result isn't Ok: */
557 const HRESULT rc = comProgressInstall.GetResultCode();
558 if (!comProgressInstall.isOk() || rc != S_OK)
559 {
560 /* If we got back a VBOX_E_NOT_SUPPORTED we don't complain (guest OS simply isn't
561 * supported yet), so silently fall back to "old" .ISO mounting method. */
562 if ( !SUCCEEDED_WARNING(rc)
563 && rc != VBOX_E_NOT_SUPPORTED)
564 {
565 msgCenter().cannotUpdateGuestAdditions(comProgressInstall);
566
567 /* Throw the error message into release log as well: */
568 const QString &strErr = comProgressInstall.GetErrorInfo().GetText();
569 if (!strErr.isEmpty())
570 LogRel(("%s\n", strErr.toLatin1().constData()));
571 }
572
573 /* Since automatic updating failed, fall back to .ISO mounting: */
574 fDoMount = true;
575 }
576 }
577#endif /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
578
579 /* Check whether we still want mounting? */
580 if (!fDoMount)
581 return;
582
583 /* Mount medium add-hoc: */
584 mountAdHocImage(KDeviceType_DVD, UIMediumType_DVD, strSource);
585}
586
587void UISession::sltCloseRuntimeUI()
588{
589 /* Ask UIMachine to close Runtime UI: */
590 uimachine()->closeRuntimeUI();
591}
592
593#ifdef RT_OS_DARWIN
594void UISession::sltHandleMenuBarConfigurationChange(const QString &strMachineID)
595{
596 /* Skip unrelated machine IDs: */
597 if (vboxGlobal().managedVMUuid() != strMachineID)
598 return;
599
600 /* Update Mac OS X menu-bar: */
601 updateMenu();
602}
603#endif /* RT_OS_DARWIN */
604
605void UISession::sltMousePointerShapeChange(bool fVisible, bool fAlpha, QPoint hotCorner, QSize size, QVector<uint8_t> shape)
606{
607 /* In case of shape data is present: */
608 if (shape.size() > 0)
609 {
610 /* We are ignoring visibility flag: */
611 m_fIsHidingHostPointer = false;
612
613 /* And updating current cursor shape: */
614 setPointerShape(shape.data(), fAlpha,
615 hotCorner.x(), hotCorner.y(),
616 size.width(), size.height());
617 }
618 /* In case of shape data is NOT present: */
619 else
620 {
621 /* Remember if we should hide the cursor: */
622 m_fIsHidingHostPointer = !fVisible;
623 }
624
625 /* Notify listeners about mouse capability changed: */
626 emit sigMousePointerShapeChange();
627
628}
629
630void UISession::sltMouseCapabilityChange(bool fSupportsAbsolute, bool fSupportsRelative, bool fSupportsMultiTouch, bool fNeedsHostCursor)
631{
632 LogRelFlow(("GUI: UISession::sltMouseCapabilityChange: "
633 "Supports absolute: %s, Supports relative: %s, "
634 "Supports multi-touch: %s, Needs host cursor: %s\n",
635 fSupportsAbsolute ? "TRUE" : "FALSE", fSupportsRelative ? "TRUE" : "FALSE",
636 fSupportsMultiTouch ? "TRUE" : "FALSE", fNeedsHostCursor ? "TRUE" : "FALSE"));
637
638 /* Check if something had changed: */
639 if ( m_fIsMouseSupportsAbsolute != fSupportsAbsolute
640 || m_fIsMouseSupportsRelative != fSupportsRelative
641 || m_fIsMouseSupportsMultiTouch != fSupportsMultiTouch
642 || m_fIsMouseHostCursorNeeded != fNeedsHostCursor)
643 {
644 /* Store new data: */
645 m_fIsMouseSupportsAbsolute = fSupportsAbsolute;
646 m_fIsMouseSupportsRelative = fSupportsRelative;
647 m_fIsMouseSupportsMultiTouch = fSupportsMultiTouch;
648 m_fIsMouseHostCursorNeeded = fNeedsHostCursor;
649
650 /* Notify listeners about mouse capability changed: */
651 emit sigMouseCapabilityChange();
652 }
653}
654
655void UISession::sltKeyboardLedsChangeEvent(bool fNumLock, bool fCapsLock, bool fScrollLock)
656{
657 /* Check if something had changed: */
658 if ( m_fNumLock != fNumLock
659 || m_fCapsLock != fCapsLock
660 || m_fScrollLock != fScrollLock)
661 {
662 /* Store new num lock data: */
663 if (m_fNumLock != fNumLock)
664 {
665 m_fNumLock = fNumLock;
666 m_uNumLockAdaptionCnt = 2;
667 }
668
669 /* Store new caps lock data: */
670 if (m_fCapsLock != fCapsLock)
671 {
672 m_fCapsLock = fCapsLock;
673 m_uCapsLockAdaptionCnt = 2;
674 }
675
676 /* Store new scroll lock data: */
677 if (m_fScrollLock != fScrollLock)
678 {
679 m_fScrollLock = fScrollLock;
680 }
681
682 /* Notify listeners about mouse capability changed: */
683 emit sigKeyboardLedsChange();
684 }
685}
686
687void UISession::sltStateChange(KMachineState state)
688{
689 /* Check if something had changed: */
690 if (m_machineState != state)
691 {
692 /* Store new data: */
693 m_machineStatePrevious = m_machineState;
694 m_machineState = state;
695
696 /* Notify listeners about machine state changed: */
697 emit sigMachineStateChange();
698 }
699}
700
701void UISession::sltVRDEChange()
702{
703 /* Make sure VRDE server is present: */
704 const CVRDEServer server = machine().GetVRDEServer();
705 AssertMsgReturnVoid(machine().isOk() && !server.isNull(),
706 ("VRDE server should NOT be null!\n"));
707
708 /* Check/Uncheck VRDE Server action depending on feature status: */
709 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->blockSignals(true);
710 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->setChecked(server.GetEnabled());
711 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->blockSignals(false);
712
713 /* Notify listeners about VRDE change: */
714 emit sigVRDEChange();
715}
716
717void UISession::sltVideoCaptureChange()
718{
719 /* Check/Uncheck Video Capture action depending on feature status: */
720 actionPool()->action(UIActionIndexRT_M_View_M_VideoCapture_T_Start)->blockSignals(true);
721 actionPool()->action(UIActionIndexRT_M_View_M_VideoCapture_T_Start)->setChecked(machine().GetVideoCaptureEnabled());
722 actionPool()->action(UIActionIndexRT_M_View_M_VideoCapture_T_Start)->blockSignals(false);
723
724 /* Notify listeners about Video Capture change: */
725 emit sigVideoCaptureChange();
726}
727
728void UISession::sltGuestMonitorChange(KGuestMonitorChangedEventType changeType, ulong uScreenId, QRect screenGeo)
729{
730 /* Ignore KGuestMonitorChangedEventType_NewOrigin change event: */
731 if (changeType == KGuestMonitorChangedEventType_NewOrigin)
732 return;
733 /* Ignore KGuestMonitorChangedEventType_Disabled event for primary screen: */
734 AssertMsg(countOfVisibleWindows() > 0, ("All machine windows are hidden!"));
735 if (changeType == KGuestMonitorChangedEventType_Disabled && uScreenId == 0)
736 return;
737
738 /* Process KGuestMonitorChangedEventType_Enabled change event: */
739 if ( !isScreenVisible(uScreenId)
740 && changeType == KGuestMonitorChangedEventType_Enabled)
741 setScreenVisible(uScreenId, true);
742 /* Process KGuestMonitorChangedEventType_Disabled change event: */
743 else if ( isScreenVisible(uScreenId)
744 && changeType == KGuestMonitorChangedEventType_Disabled)
745 setScreenVisible(uScreenId, false);
746
747 /* Notify listeners about the change: */
748 emit sigGuestMonitorChange(changeType, uScreenId, screenGeo);
749}
750
751void UISession::sltHandleStorageDeviceChange(const CMediumAttachment &attachment, bool fRemoved, bool fSilent)
752{
753 /* Update action restrictions: */
754 updateActionRestrictions();
755
756 /* Notify listeners about storage device change: */
757 emit sigStorageDeviceChange(attachment, fRemoved, fSilent);
758}
759
760#ifdef RT_OS_DARWIN
761/**
762 * MacOS X: Restarts display-reconfiguration watchdog timer from the beginning.
763 * @note Watchdog is trying to determine display reconfiguration in
764 * UISession::sltCheckIfHostDisplayChanged() slot every 500ms for 40 tries.
765 */
766void UISession::sltHandleHostDisplayAboutToChange()
767{
768 LogRelFlow(("GUI: UISession::sltHandleHostDisplayAboutToChange()\n"));
769
770 if (m_pWatchdogDisplayChange->isActive())
771 m_pWatchdogDisplayChange->stop();
772 m_pWatchdogDisplayChange->setProperty("tryNumber", 1);
773 m_pWatchdogDisplayChange->start();
774}
775
776/**
777 * MacOS X: Determines display reconfiguration.
778 * @note Calls for UISession::sltHandleHostScreenCountChange() if screen count changed.
779 * @note Calls for UISession::sltHandleHostScreenGeometryChange() if screen geometry changed.
780 */
781void UISession::sltCheckIfHostDisplayChanged()
782{
783 LogRelFlow(("GUI: UISession::sltCheckIfHostDisplayChanged()\n"));
784
785 /* Check if display count changed: */
786 if (gpDesktop->screenCount() != m_hostScreens.size())
787 {
788 /* Reset watchdog: */
789 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
790 /* Notify listeners about screen-count changed: */
791 return sltHandleHostScreenCountChange();
792 }
793 else
794 {
795 /* Check if at least one display geometry changed: */
796 for (int iScreenIndex = 0; iScreenIndex < gpDesktop->screenCount(); ++iScreenIndex)
797 {
798 if (gpDesktop->screenGeometry(iScreenIndex) != m_hostScreens.at(iScreenIndex))
799 {
800 /* Reset watchdog: */
801 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
802 /* Notify listeners about screen-geometry changed: */
803 return sltHandleHostScreenGeometryChange();
804 }
805 }
806 }
807
808 /* Check if watchdog expired, restart if not: */
809 int cTryNumber = m_pWatchdogDisplayChange->property("tryNumber").toInt();
810 if (cTryNumber > 0 && cTryNumber < 40)
811 {
812 /* Restart watchdog again: */
813 m_pWatchdogDisplayChange->setProperty("tryNumber", ++cTryNumber);
814 m_pWatchdogDisplayChange->start();
815 }
816 else
817 {
818 /* Reset watchdog: */
819 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
820 }
821}
822#endif /* RT_OS_DARWIN */
823
824void UISession::sltHandleHostScreenCountChange()
825{
826 LogRelFlow(("GUI: UISession: Host-screen count changed.\n"));
827
828 /* Recache display data: */
829 updateHostScreenData();
830
831 /* Notify current machine-logic: */
832 emit sigHostScreenCountChange();
833}
834
835void UISession::sltHandleHostScreenGeometryChange()
836{
837 LogRelFlow(("GUI: UISession: Host-screen geometry changed.\n"));
838
839 /* Recache display data: */
840 updateHostScreenData();
841
842 /* Notify current machine-logic: */
843 emit sigHostScreenGeometryChange();
844}
845
846void UISession::sltHandleHostScreenAvailableAreaChange()
847{
848 LogRelFlow(("GUI: UISession: Host-screen available-area changed.\n"));
849
850 /* Notify current machine-logic: */
851 emit sigHostScreenAvailableAreaChange();
852}
853
854void UISession::sltAdditionsChange()
855{
856 /* Variable flags: */
857 ULONG ulGuestAdditionsRunLevel = guest().GetAdditionsRunLevel();
858 LONG64 lLastUpdatedIgnored;
859 bool fIsGuestSupportsGraphics = guest().GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
860 == KAdditionsFacilityStatus_Active;
861 bool fIsGuestSupportsSeamless = guest().GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
862 == KAdditionsFacilityStatus_Active;
863 /* Check if something had changed: */
864 if (m_ulGuestAdditionsRunLevel != ulGuestAdditionsRunLevel ||
865 m_fIsGuestSupportsGraphics != fIsGuestSupportsGraphics ||
866 m_fIsGuestSupportsSeamless != fIsGuestSupportsSeamless)
867 {
868 /* Store new data: */
869 m_ulGuestAdditionsRunLevel = ulGuestAdditionsRunLevel;
870 m_fIsGuestSupportsGraphics = fIsGuestSupportsGraphics;
871 m_fIsGuestSupportsSeamless = fIsGuestSupportsSeamless;
872
873 /* Notify listeners about GA state really changed: */
874 LogRel(("GUI: UISession::sltAdditionsChange: GA state really changed, notifying listeners.\n"));
875 emit sigAdditionsStateActualChange();
876 }
877
878 /* Notify listeners about GA state change event came: */
879 LogRel(("GUI: UISession::sltAdditionsChange: GA state change event came, notifying listeners.\n"));
880 emit sigAdditionsStateChange();
881}
882
883UISession::UISession(UIMachine *pMachine)
884 : QObject(pMachine)
885 /* Base variables: */
886 , m_pMachine(pMachine)
887 , m_pActionPool(0)
888#ifdef VBOX_WS_MAC
889 , m_pMenuBar(0)
890#endif /* VBOX_WS_MAC */
891 /* Common variables: */
892 , m_machineStatePrevious(KMachineState_Null)
893 , m_machineState(KMachineState_Null)
894 , m_pMachineWindowIcon(0)
895 , m_requestedVisualStateType(UIVisualStateType_Invalid)
896#ifdef VBOX_WS_WIN
897 , m_alphaCursor(0)
898#endif /* VBOX_WS_WIN */
899#ifdef VBOX_WS_MAC
900 , m_pWatchdogDisplayChange(0)
901#endif /* VBOX_WS_MAC */
902 , m_defaultCloseAction(MachineCloseAction_Invalid)
903 , m_restrictedCloseActions(MachineCloseAction_Invalid)
904 , m_fAllCloseActionsRestricted(false)
905 /* Common flags: */
906 , m_fInitialized(false)
907 , m_fIsFirstTimeStarted(false)
908 , m_fIsGuestResizeIgnored(false)
909 , m_fIsAutoCaptureDisabled(false)
910 /* Guest additions flags: */
911 , m_ulGuestAdditionsRunLevel(0)
912 , m_fIsGuestSupportsGraphics(false)
913 , m_fIsGuestSupportsSeamless(false)
914 /* Mouse flags: */
915 , m_fNumLock(false)
916 , m_fCapsLock(false)
917 , m_fScrollLock(false)
918 , m_uNumLockAdaptionCnt(2)
919 , m_uCapsLockAdaptionCnt(2)
920 /* Mouse flags: */
921 , m_fIsMouseSupportsAbsolute(false)
922 , m_fIsMouseSupportsRelative(false)
923 , m_fIsMouseSupportsMultiTouch(false)
924 , m_fIsMouseHostCursorNeeded(false)
925 , m_fIsMouseCaptured(false)
926 , m_fIsMouseIntegrated(true)
927 , m_fIsValidPointerShapePresent(false)
928 , m_fIsHidingHostPointer(true)
929 /* CPU hardware virtualization features for VM: */
930 , m_fIsHWVirtExEnabled(false)
931 , m_fIsHWVirtExNestedPagingEnabled(false)
932 , m_fIsHWVirtExUXEnabled(false)
933 /* VM's effective paravirtualization provider: */
934 , m_paraVirtProvider(KParavirtProvider_None)
935{
936}
937
938UISession::~UISession()
939{
940}
941
942bool UISession::prepare()
943{
944 /* Prepare session: */
945 if (!prepareSession())
946 return false;
947
948 /* Prepare actions: */
949 prepareActions();
950
951 /* Prepare connections: */
952 prepareConnections();
953
954 /* Prepare console event-handlers: */
955 prepareConsoleEventHandlers();
956
957 /* Prepare screens: */
958 prepareScreens();
959
960 /* Prepare framebuffers: */
961 prepareFramebuffers();
962
963 /* Load settings: */
964 loadSessionSettings();
965
966#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
967 struct sigaction sa;
968 sa.sa_sigaction = &signalHandlerSIGUSR1;
969 sigemptyset(&sa.sa_mask);
970 sa.sa_flags = SA_RESTART | SA_SIGINFO;
971 sigaction(SIGUSR1, &sa, NULL);
972#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
973
974 /* True by default: */
975 return true;
976}
977
978bool UISession::prepareSession()
979{
980 /* Open session: */
981 m_session = vboxGlobal().openSession(vboxGlobal().managedVMUuid(),
982 vboxGlobal().isSeparateProcess()
983 ? KLockType_Shared : KLockType_VM);
984 if (m_session.isNull())
985 return false;
986
987 /* Get machine: */
988 m_machine = m_session.GetMachine();
989 if (m_machine.isNull())
990 return false;
991
992 /* Get console: */
993 m_console = m_session.GetConsole();
994 if (m_console.isNull())
995 return false;
996
997 /* Get display: */
998 m_display = m_console.GetDisplay();
999 if (m_display.isNull())
1000 return false;
1001
1002 /* Get guest: */
1003 m_guest = m_console.GetGuest();
1004 if (m_guest.isNull())
1005 return false;
1006
1007 /* Get mouse: */
1008 m_mouse = m_console.GetMouse();
1009 if (m_mouse.isNull())
1010 return false;
1011
1012 /* Get keyboard: */
1013 m_keyboard = m_console.GetKeyboard();
1014 if (m_keyboard.isNull())
1015 return false;
1016
1017 /* Get debugger: */
1018 m_debugger = m_console.GetDebugger();
1019 if (m_debugger.isNull())
1020 return false;
1021
1022 /* Update machine-name: */
1023 m_strMachineName = machine().GetName();
1024
1025 /* Update machine-state: */
1026 m_machineState = machine().GetState();
1027
1028 /* True by default: */
1029 return true;
1030}
1031
1032void UISession::prepareActions()
1033{
1034 /* Create action-pool: */
1035 m_pActionPool = UIActionPool::create(UIActionPoolType_Runtime);
1036 AssertPtrReturnVoid(actionPool());
1037 {
1038 /* Configure action-pool: */
1039 actionPool()->toRuntime()->setSession(this);
1040
1041 /* Update action restrictions: */
1042 updateActionRestrictions();
1043
1044#ifdef VBOX_WS_MAC
1045 /* Create Mac OS X menu-bar: */
1046 m_pMenuBar = new QMenuBar;
1047 AssertPtrReturnVoid(m_pMenuBar);
1048 {
1049 /* Configure Mac OS X menu-bar: */
1050 connect(gEDataManager, SIGNAL(sigMenuBarConfigurationChange(const QString&)),
1051 this, SLOT(sltHandleMenuBarConfigurationChange(const QString&)));
1052 /* Update Mac OS X menu-bar: */
1053 updateMenu();
1054 }
1055#endif /* VBOX_WS_MAC */
1056 }
1057}
1058
1059void UISession::prepareConnections()
1060{
1061 connect(this, SIGNAL(sigInitialized()), this, SLOT(sltMarkInitialized()));
1062
1063#ifdef VBOX_WS_MAC
1064 /* Install native display reconfiguration callback: */
1065 CGDisplayRegisterReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1066#else /* !VBOX_WS_MAC */
1067 /* Install Qt display reconfiguration callbacks: */
1068 connect(gpDesktop, SIGNAL(sigHostScreenCountChanged(int)),
1069 this, SLOT(sltHandleHostScreenCountChange()));
1070 connect(gpDesktop, SIGNAL(sigHostScreenResized(int)),
1071 this, SLOT(sltHandleHostScreenGeometryChange()));
1072# ifdef VBOX_WS_X11
1073 connect(gpDesktop, SIGNAL(sigHostScreenWorkAreaRecalculated(int)),
1074 this, SLOT(sltHandleHostScreenAvailableAreaChange()));
1075# else /* !VBOX_WS_X11 */
1076 connect(gpDesktop, SIGNAL(sigHostScreenWorkAreaResized(int)),
1077 this, SLOT(sltHandleHostScreenAvailableAreaChange()));
1078# endif /* !VBOX_WS_X11 */
1079#endif /* !VBOX_WS_MAC */
1080}
1081
1082void UISession::prepareConsoleEventHandlers()
1083{
1084 /* Create console event-handler: */
1085 UIConsoleEventHandler::create(this);
1086
1087 /* Add console event connections: */
1088 connect(gConsoleEvents, SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
1089 this, SLOT(sltMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)));
1090
1091 connect(gConsoleEvents, SIGNAL(sigMouseCapabilityChange(bool, bool, bool, bool)),
1092 this, SLOT(sltMouseCapabilityChange(bool, bool, bool, bool)));
1093
1094 connect(gConsoleEvents, SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
1095 this, SLOT(sltKeyboardLedsChangeEvent(bool, bool, bool)));
1096
1097 connect(gConsoleEvents, SIGNAL(sigStateChange(KMachineState)),
1098 this, SLOT(sltStateChange(KMachineState)));
1099
1100 connect(gConsoleEvents, SIGNAL(sigAdditionsChange()),
1101 this, SLOT(sltAdditionsChange()));
1102
1103 connect(gConsoleEvents, SIGNAL(sigVRDEChange()),
1104 this, SLOT(sltVRDEChange()));
1105
1106 connect(gConsoleEvents, SIGNAL(sigVideoCaptureChange()),
1107 this, SLOT(sltVideoCaptureChange()));
1108
1109 connect(gConsoleEvents, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
1110 this, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)));
1111
1112 connect(gConsoleEvents, SIGNAL(sigStorageDeviceChange(CMediumAttachment, bool, bool)),
1113 this, SLOT(sltHandleStorageDeviceChange(CMediumAttachment, bool, bool)));
1114
1115 connect(gConsoleEvents, SIGNAL(sigMediumChange(CMediumAttachment)),
1116 this, SIGNAL(sigMediumChange(CMediumAttachment)));
1117
1118 connect(gConsoleEvents, SIGNAL(sigUSBControllerChange()),
1119 this, SIGNAL(sigUSBControllerChange()));
1120
1121 connect(gConsoleEvents, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
1122 this, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)));
1123
1124 connect(gConsoleEvents, SIGNAL(sigSharedFolderChange()),
1125 this, SIGNAL(sigSharedFolderChange()));
1126
1127 connect(gConsoleEvents, SIGNAL(sigRuntimeError(bool, QString, QString)),
1128 this, SIGNAL(sigRuntimeError(bool, QString, QString)));
1129
1130#ifdef VBOX_WS_MAC
1131 connect(gConsoleEvents, SIGNAL(sigShowWindow()),
1132 this, SIGNAL(sigShowWindows()), Qt::QueuedConnection);
1133#endif /* VBOX_WS_MAC */
1134
1135 connect(gConsoleEvents, SIGNAL(sigCPUExecutionCapChange()),
1136 this, SIGNAL(sigCPUExecutionCapChange()));
1137
1138 connect(gConsoleEvents, SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
1139 this, SLOT(sltGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)));
1140}
1141
1142void UISession::prepareScreens()
1143{
1144 /* Recache display data: */
1145 updateHostScreenData();
1146
1147#ifdef VBOX_WS_MAC
1148 /* Prepare display-change watchdog: */
1149 m_pWatchdogDisplayChange = new QTimer(this);
1150 {
1151 m_pWatchdogDisplayChange->setInterval(500);
1152 m_pWatchdogDisplayChange->setSingleShot(true);
1153 connect(m_pWatchdogDisplayChange, SIGNAL(timeout()),
1154 this, SLOT(sltCheckIfHostDisplayChanged()));
1155 }
1156#endif /* VBOX_WS_MAC */
1157
1158 /* Prepare initial screen visibility status: */
1159 m_monitorVisibilityVector.resize(machine().GetMonitorCount());
1160 m_monitorVisibilityVector.fill(false);
1161 m_monitorVisibilityVector[0] = true;
1162
1163 /* Prepare empty last full-screen size vector: */
1164 m_monitorLastFullScreenSizeVector.resize(machine().GetMonitorCount());
1165 m_monitorLastFullScreenSizeVector.fill(QSize(-1, -1));
1166
1167 /* If machine is in 'saved' state: */
1168 if (isSaved())
1169 {
1170 /* Update screen visibility status from saved-state: */
1171 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1172 {
1173 BOOL fEnabled = true;
1174 ULONG uGuestOriginX = 0, uGuestOriginY = 0, uGuestWidth = 0, uGuestHeight = 0;
1175 machine().QuerySavedGuestScreenInfo(iScreenIndex,
1176 uGuestOriginX, uGuestOriginY,
1177 uGuestWidth, uGuestHeight, fEnabled);
1178 m_monitorVisibilityVector[iScreenIndex] = fEnabled;
1179 }
1180 /* And make sure at least one of them is visible (primary if others are hidden): */
1181 if (countOfVisibleWindows() < 1)
1182 m_monitorVisibilityVector[0] = true;
1183 }
1184 else if (vboxGlobal().isSeparateProcess())
1185 {
1186 /* Update screen visibility status from display directly: */
1187 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1188 {
1189 KGuestMonitorStatus enmStatus = KGuestMonitorStatus_Disabled;
1190 ULONG uGuestWidth = 0, uGuestHeight = 0, uBpp = 0;
1191 LONG iGuestOriginX = 0, iGuestOriginY = 0;
1192 display().GetScreenResolution(iScreenIndex,
1193 uGuestWidth, uGuestHeight, uBpp,
1194 iGuestOriginX, iGuestOriginY, enmStatus);
1195 m_monitorVisibilityVector[iScreenIndex] = ( enmStatus == KGuestMonitorStatus_Enabled
1196 || enmStatus == KGuestMonitorStatus_Blank);
1197 }
1198 /* And make sure at least one of them is visible (primary if others are hidden): */
1199 if (countOfVisibleWindows() < 1)
1200 m_monitorVisibilityVector[0] = true;
1201 }
1202
1203 /* Prepare initial screen visibility status of host-desires.
1204 * This is mostly dummy initialization as host-desires should get updated later in multi-screen layout.
1205 * By default making host-desires same as facts. */
1206 m_monitorVisibilityVectorHostDesires.resize(machine().GetMonitorCount());
1207 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1208 m_monitorVisibilityVectorHostDesires[iScreenIndex] = m_monitorVisibilityVector[iScreenIndex];
1209}
1210
1211void UISession::prepareFramebuffers()
1212{
1213 /* Each framebuffer will be really prepared on first UIMachineView creation: */
1214 m_frameBufferVector.resize(machine().GetMonitorCount());
1215}
1216
1217void UISession::loadSessionSettings()
1218{
1219 /* Load extra-data settings: */
1220 {
1221 /* Get machine ID: */
1222 const QString strMachineID = vboxGlobal().managedVMUuid();
1223
1224 /* Prepare machine-window icon: */
1225 {
1226 /* Acquire user machine-window icon: */
1227 QIcon icon = vboxGlobal().vmUserIcon(machine());
1228 /* Use the OS type icon if user one was not set: */
1229 if (icon.isNull())
1230 icon = vboxGlobal().vmGuestOSTypeIcon(machine().GetOSTypeId());
1231 /* Use the default icon if nothing else works: */
1232 if (icon.isNull())
1233 icon = QIcon(":/VirtualBox_48px.png");
1234 /* Store the icon dynamically: */
1235 m_pMachineWindowIcon = new QIcon(icon);
1236 }
1237
1238#ifndef VBOX_WS_MAC
1239 /* Load user's machine-window name postfix: */
1240 m_strMachineWindowNamePostfix = gEDataManager->machineWindowNamePostfix(strMachineID);
1241#endif
1242
1243 /* Is there should be First RUN Wizard? */
1244 m_fIsFirstTimeStarted = gEDataManager->machineFirstTimeStarted(strMachineID);
1245
1246 /* Should guest autoresize? */
1247 QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1248 pGuestAutoresizeSwitch->setChecked(gEDataManager->guestScreenAutoResizeEnabled(strMachineID));
1249
1250#ifndef VBOX_WS_MAC
1251 /* Menu-bar options: */
1252 {
1253 const bool fEnabledGlobally = !gEDataManager->guiFeatureEnabled(GUIFeatureType_NoMenuBar);
1254 const bool fEnabledForMachine = gEDataManager->menuBarEnabled(strMachineID);
1255 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1256 QAction *pActionMenuBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_S_Settings);
1257 pActionMenuBarSettings->setEnabled(fEnabled);
1258 QAction *pActionMenuBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_T_Visibility);
1259 pActionMenuBarSwitch->blockSignals(true);
1260 pActionMenuBarSwitch->setChecked(fEnabled);
1261 pActionMenuBarSwitch->blockSignals(false);
1262 }
1263#endif /* !VBOX_WS_MAC */
1264
1265 /* Status-bar options: */
1266 {
1267 const bool fEnabledGlobally = !gEDataManager->guiFeatureEnabled(GUIFeatureType_NoStatusBar);
1268 const bool fEnabledForMachine = gEDataManager->statusBarEnabled(strMachineID);
1269 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1270 QAction *pActionStatusBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_S_Settings);
1271 pActionStatusBarSettings->setEnabled(fEnabled);
1272 QAction *pActionStatusBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility);
1273 pActionStatusBarSwitch->blockSignals(true);
1274 pActionStatusBarSwitch->setChecked(fEnabled);
1275 pActionStatusBarSwitch->blockSignals(false);
1276 }
1277
1278 /* Input options: */
1279 actionPool()->action(UIActionIndexRT_M_Input_M_Mouse_T_Integration)->setChecked(isMouseIntegrated());
1280
1281 /* What is the default close action and the restricted are? */
1282 m_defaultCloseAction = gEDataManager->defaultMachineCloseAction(strMachineID);
1283 m_restrictedCloseActions = gEDataManager->restrictedMachineCloseActions(strMachineID);
1284 /* We decided to keep the Detach close-action hidden and provide the user with the separate Machine menu action instead: */
1285 m_restrictedCloseActions = static_cast<MachineCloseAction>(m_restrictedCloseActions | MachineCloseAction_Detach);
1286 m_fAllCloseActionsRestricted = (!vboxGlobal().isSeparateProcess() || (m_restrictedCloseActions & MachineCloseAction_Detach))
1287 && (m_restrictedCloseActions & MachineCloseAction_SaveState)
1288 && (m_restrictedCloseActions & MachineCloseAction_Shutdown)
1289 && (m_restrictedCloseActions & MachineCloseAction_PowerOff);
1290 // Close VM Dialog hides PowerOff_RestoringSnapshot implicitly if PowerOff is hidden..
1291 // && (m_restrictedCloseActions & MachineCloseAction_PowerOff_RestoringSnapshot);
1292 }
1293}
1294
1295void UISession::saveSessionSettings()
1296{
1297 /* Save extra-data settings: */
1298 {
1299 /* Disable First RUN Wizard: */
1300 gEDataManager->setMachineFirstTimeStarted(false, vboxGlobal().managedVMUuid());
1301
1302 /* Remember if guest should autoresize: */
1303 if (actionPool())
1304 {
1305 const QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1306 gEDataManager->setGuestScreenAutoResizeEnabled(pGuestAutoresizeSwitch->isChecked(), vboxGlobal().managedVMUuid());
1307 }
1308
1309 /* Cleanup machine-window icon: */
1310 delete m_pMachineWindowIcon;
1311 m_pMachineWindowIcon = 0;
1312 }
1313}
1314
1315void UISession::cleanupFramebuffers()
1316{
1317 /* Cleanup framebuffers finally: */
1318 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
1319 {
1320 UIFrameBuffer *pFrameBuffer = m_frameBufferVector[i];
1321 if (pFrameBuffer)
1322 {
1323 /* Mark framebuffer as unused: */
1324 pFrameBuffer->setMarkAsUnused(true);
1325 /* Detach framebuffer from Display: */
1326 pFrameBuffer->detach();
1327 /* Delete framebuffer reference: */
1328 delete pFrameBuffer;
1329 }
1330 }
1331 m_frameBufferVector.clear();
1332}
1333
1334void UISession::cleanupConsoleEventHandlers()
1335{
1336 /* Destroy console event-handler if necessary: */
1337 if (gConsoleEvents)
1338 UIConsoleEventHandler::destroy();
1339}
1340
1341void UISession::cleanupConnections()
1342{
1343#ifdef VBOX_WS_MAC
1344 /* Remove display reconfiguration callback: */
1345 CGDisplayRemoveReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1346#endif /* VBOX_WS_MAC */
1347}
1348
1349void UISession::cleanupActions()
1350{
1351#ifdef VBOX_WS_MAC
1352 /* Destroy Mac OS X menu-bar: */
1353 delete m_pMenuBar;
1354 m_pMenuBar = 0;
1355#endif /* VBOX_WS_MAC */
1356
1357 /* Destroy action-pool if necessary: */
1358 if (actionPool())
1359 UIActionPool::destroy(actionPool());
1360}
1361
1362void UISession::cleanupSession()
1363{
1364 /* Detach debugger: */
1365 if (!m_debugger.isNull())
1366 m_debugger.detach();
1367
1368 /* Detach keyboard: */
1369 if (!m_keyboard.isNull())
1370 m_keyboard.detach();
1371
1372 /* Detach mouse: */
1373 if (!m_mouse.isNull())
1374 m_mouse.detach();
1375
1376 /* Detach guest: */
1377 if (!m_guest.isNull())
1378 m_guest.detach();
1379
1380 /* Detach display: */
1381 if (!m_display.isNull())
1382 m_display.detach();
1383
1384 /* Detach console: */
1385 if (!m_console.isNull())
1386 m_console.detach();
1387
1388 /* Detach machine: */
1389 if (!m_machine.isNull())
1390 m_machine.detach();
1391
1392 /* Close session: */
1393 if (!m_session.isNull() && vboxGlobal().isVBoxSVCAvailable())
1394 {
1395 m_session.UnlockMachine();
1396 m_session.detach();
1397 }
1398}
1399
1400void UISession::cleanup()
1401{
1402#ifdef VBOX_WS_WIN
1403 /* Destroy alpha cursor: */
1404 if (m_alphaCursor)
1405 DestroyIcon(m_alphaCursor);
1406#endif /* VBOX_WS_WIN */
1407
1408 /* Save settings: */
1409 saveSessionSettings();
1410
1411 /* Cleanup framebuffers: */
1412 cleanupFramebuffers();
1413
1414 /* Cleanup console event-handlers: */
1415 cleanupConsoleEventHandlers();
1416
1417 /* Cleanup connections: */
1418 cleanupConnections();
1419
1420 /* Cleanup actions: */
1421 cleanupActions();
1422
1423 /* Cleanup session: */
1424 cleanupSession();
1425}
1426
1427#ifdef VBOX_WS_MAC
1428void UISession::updateMenu()
1429{
1430 /* Rebuild Mac OS X menu-bar: */
1431 m_pMenuBar->clear();
1432 foreach (QMenu *pMenu, actionPool()->menus())
1433 {
1434 UIMenu *pMenuUI = qobject_cast<UIMenu*>(pMenu);
1435 if (!pMenuUI->isConsumable() || !pMenuUI->isConsumed())
1436 m_pMenuBar->addMenu(pMenuUI);
1437 if (pMenuUI->isConsumable() && !pMenuUI->isConsumed())
1438 pMenuUI->setConsumed(true);
1439 }
1440}
1441#endif /* VBOX_WS_MAC */
1442
1443/** Generate a BGRA bitmap which approximates a XOR/AND mouse pointer.
1444 *
1445 * Pixels which has 1 in the AND mask and not 0 in the XOR mask are replaced by
1446 * the inverted pixel and 8 surrounding pixels with the original color.
1447 * Fort example a white pixel (W) is replaced with a black (B) pixel:
1448 * WWW
1449 * W -> WBW
1450 * WWW
1451 * The surrounding pixels are written only if the corresponding source pixel
1452 * does not affect the screen, i.e. AND bit is 1 and XOR value is 0.
1453 */
1454static void renderCursorPixels(const uint32_t *pu32XOR, const uint8_t *pu8AND,
1455 uint32_t u32Width, uint32_t u32Height,
1456 uint32_t *pu32Pixels, uint32_t cbPixels)
1457{
1458 /* Output pixels set to 0 which allow to not write transparent pixels anymore. */
1459 memset(pu32Pixels, 0, cbPixels);
1460
1461 const uint32_t *pu32XORSrc = pu32XOR; /* Iterator for source XOR pixels. */
1462 const uint8_t *pu8ANDSrcLine = pu8AND; /* The current AND mask scanline. */
1463 uint32_t *pu32Dst = pu32Pixels; /* Iterator for all destination BGRA pixels. */
1464
1465 /* Some useful constants. */
1466 const int cbANDLine = ((int)u32Width + 7) / 8;
1467
1468 int y;
1469 for (y = 0; y < (int)u32Height; ++y)
1470 {
1471 int x;
1472 for (x = 0; x < (int)u32Width; ++x)
1473 {
1474 const uint32_t u32Pixel = *pu32XORSrc; /* Current pixel at (x,y) */
1475 const uint8_t *pu8ANDSrc = pu8ANDSrcLine + x / 8; /* Byte which containt current AND bit. */
1476
1477 if ((*pu8ANDSrc << (x % 8)) & 0x80)
1478 {
1479 if (u32Pixel)
1480 {
1481 const uint32_t u32PixelInverted = ~u32Pixel;
1482
1483 /* Scan neighbor pixels and assign them if they are transparent. */
1484 int dy;
1485 for (dy = -1; dy <= 1; ++dy)
1486 {
1487 const int yn = y + dy;
1488 if (yn < 0 || yn >= (int)u32Height)
1489 continue; /* Do not cross the bounds. */
1490
1491 int dx;
1492 for (dx = -1; dx <= 1; ++dx)
1493 {
1494 const int xn = x + dx;
1495 if (xn < 0 || xn >= (int)u32Width)
1496 continue; /* Do not cross the bounds. */
1497
1498 if (dx != 0 || dy != 0)
1499 {
1500 /* Check if the neighbor pixel is transparent. */
1501 const uint32_t *pu32XORNeighborSrc = &pu32XORSrc[dy * (int)u32Width + dx];
1502 const uint8_t *pu8ANDNeighborSrc = pu8ANDSrcLine + dy * cbANDLine + xn / 8;
1503 if ( *pu32XORNeighborSrc == 0
1504 && ((*pu8ANDNeighborSrc << (xn % 8)) & 0x80) != 0)
1505 {
1506 /* Transparent neighbor pixels are replaced with the source pixel value. */
1507 uint32_t *pu32PixelNeighborDst = &pu32Dst[dy * (int)u32Width + dx];
1508 *pu32PixelNeighborDst = u32Pixel | 0xFF000000;
1509 }
1510 }
1511 else
1512 {
1513 /* The pixel itself is replaced with inverted value. */
1514 *pu32Dst = u32PixelInverted | 0xFF000000;
1515 }
1516 }
1517 }
1518 }
1519 else
1520 {
1521 /* The pixel does not affect the screen.
1522 * Do nothing. Do not touch destination which can already contain generated pixels.
1523 */
1524 }
1525 }
1526 else
1527 {
1528 /* AND bit is 0, the pixel will be just drawn. */
1529 *pu32Dst = u32Pixel | 0xFF000000;
1530 }
1531
1532 ++pu32XORSrc; /* Next source pixel. */
1533 ++pu32Dst; /* Next destination pixel. */
1534 }
1535
1536 /* Next AND scanline. */
1537 pu8ANDSrcLine += cbANDLine;
1538 }
1539}
1540
1541#ifdef VBOX_WS_WIN
1542static bool isPointer1bpp(const uint8_t *pu8XorMask,
1543 uint uWidth,
1544 uint uHeight)
1545{
1546 /* Check if the pointer has only 0 and 0xFFFFFF pixels, ignoring the alpha channel. */
1547 const uint32_t *pu32Src = (uint32_t *)pu8XorMask;
1548
1549 uint y;
1550 for (y = 0; y < uHeight ; ++y)
1551 {
1552 uint x;
1553 for (x = 0; x < uWidth; ++x)
1554 {
1555 const uint32_t u32Pixel = pu32Src[x] & UINT32_C(0xFFFFFF);
1556 if (u32Pixel != 0 && u32Pixel != UINT32_C(0xFFFFFF))
1557 return false;
1558 }
1559
1560 pu32Src += uWidth;
1561 }
1562
1563 return true;
1564}
1565#endif /* VBOX_WS_WIN */
1566
1567void UISession::setPointerShape(const uchar *pShapeData, bool fHasAlpha,
1568 uint uXHot, uint uYHot, uint uWidth, uint uHeight)
1569{
1570 AssertMsg(pShapeData, ("Shape data must not be NULL!\n"));
1571
1572 m_fIsValidPointerShapePresent = false;
1573 const uchar *srcAndMaskPtr = pShapeData;
1574 uint andMaskSize = (uWidth + 7) / 8 * uHeight;
1575 const uchar *srcShapePtr = pShapeData + ((andMaskSize + 3) & ~3);
1576 uint srcShapePtrScan = uWidth * 4;
1577
1578#if defined (VBOX_WS_WIN)
1579
1580 /* Create a ARGB image out of the shape data: */
1581
1582 /*
1583 * Qt5 QCursor recommends 32 x 32 cursor, therefore the original data is copied to
1584 * a larger QImage if necessary. Cursors like 10x16 did not work correctly (Solaris 10 guest).
1585 */
1586 uint uCursorWidth = uWidth >= 32? uWidth: 32;
1587 uint uCursorHeight = uHeight >= 32? uHeight: 32;
1588 uint x, y;
1589
1590 if (fHasAlpha)
1591 {
1592 QImage image(uCursorWidth, uCursorHeight, QImage::Format_ARGB32);
1593 memset(image.bits(), 0, image.byteCount());
1594
1595 const uint32_t *pu32SrcShapeScanline = (uint32_t *)srcShapePtr;
1596 for (y = 0; y < uHeight; ++y, pu32SrcShapeScanline += uWidth)
1597 memcpy(image.scanLine(y), pu32SrcShapeScanline, uWidth * sizeof(uint32_t));
1598
1599 m_cursor = QCursor(QPixmap::fromImage(image), uXHot, uYHot);
1600 }
1601 else
1602 {
1603 if (isPointer1bpp(srcShapePtr, uWidth, uHeight))
1604 {
1605 /* Incoming data consist of 32 bit BGR XOR mask and 1 bit AND mask.
1606 * XOR pixels contain either 0x00000000 or 0x00FFFFFF.
1607 *
1608 * Originally intended result (F denotes 0x00FFFFFF):
1609 * XOR AND
1610 * 0 0 black
1611 * F 0 white
1612 * 0 1 transparent
1613 * F 1 xor'd
1614 *
1615 * Actual Qt5 result for color table 0:0xFF000000, 1:0xFFFFFFFF
1616 * (tested on Windows 7 and 10 64 bit hosts):
1617 * Bitmap Mask
1618 * 0 0 black
1619 * 1 0 white
1620 * 0 1 xor
1621 * 1 1 transparent
1622 *
1623 */
1624
1625 QVector<QRgb> colors(2);
1626 colors[0] = UINT32_C(0xFF000000);
1627 colors[1] = UINT32_C(0xFFFFFFFF);
1628
1629 QImage bitmap(uCursorWidth, uCursorHeight, QImage::Format_Mono);
1630 bitmap.setColorTable(colors);
1631 memset(bitmap.bits(), 0xFF, bitmap.byteCount());
1632
1633 QImage mask(uCursorWidth, uCursorHeight, QImage::Format_Mono);
1634 mask.setColorTable(colors);
1635 memset(mask.bits(), 0xFF, mask.byteCount());
1636
1637 const uint8_t *pu8SrcAndScanline = srcAndMaskPtr;
1638 const uint32_t *pu32SrcShapeScanline = (uint32_t *)srcShapePtr;
1639 for (y = 0; y < uHeight; ++y)
1640 {
1641 for (x = 0; x < uWidth; ++x)
1642 {
1643 const uint8_t u8Bit = (uint8_t)(1 << (7 - x % 8));
1644
1645 const uint8_t u8SrcMaskByte = pu8SrcAndScanline[x / 8];
1646 const uint8_t u8SrcMaskBit = u8SrcMaskByte & u8Bit;
1647 const uint32_t u32SrcPixel = pu32SrcShapeScanline[x] & UINT32_C(0xFFFFFF);
1648
1649 uint8_t *pu8DstMaskByte = &mask.scanLine(y)[x / 8];
1650 uint8_t *pu8DstBitmapByte = &bitmap.scanLine(y)[x / 8];
1651
1652 if (u8SrcMaskBit == 0)
1653 {
1654 if (u32SrcPixel == 0)
1655 {
1656 /* Black: Qt Bitmap = 0, Mask = 0 */
1657 *pu8DstMaskByte &= ~u8Bit;
1658 *pu8DstBitmapByte &= ~u8Bit;
1659 }
1660 else
1661 {
1662 /* White: Qt Bitmap = 1, Mask = 0 */
1663 *pu8DstMaskByte &= ~u8Bit;
1664 *pu8DstBitmapByte |= u8Bit;
1665 }
1666 }
1667 else
1668 {
1669 if (u32SrcPixel == 0)
1670 {
1671 /* Transparent: Qt Bitmap = 1, Mask = 1 */
1672 *pu8DstMaskByte |= u8Bit;
1673 *pu8DstBitmapByte |= u8Bit;
1674 }
1675 else
1676 {
1677 /* Xor'ed: Qt Bitmap = 0, Mask = 1 */
1678 *pu8DstMaskByte |= u8Bit;
1679 *pu8DstBitmapByte &= ~u8Bit;
1680 }
1681 }
1682 }
1683
1684 pu8SrcAndScanline += (uWidth + 7) / 8;
1685 pu32SrcShapeScanline += uWidth;
1686 }
1687
1688 m_cursor = QCursor(QBitmap::fromImage(bitmap), QBitmap::fromImage(mask), uXHot, uYHot);
1689 }
1690 else
1691 {
1692 /* Assign alpha channel values according to the AND mask: 1 -> 0x00, 0 -> 0xFF: */
1693 QImage image(uCursorWidth, uCursorHeight, QImage::Format_ARGB32);
1694 memset(image.bits(), 0, image.byteCount());
1695
1696 const uint8_t *pu8SrcAndScanline = srcAndMaskPtr;
1697 const uint32_t *pu32SrcShapeScanline = (uint32_t *)srcShapePtr;
1698
1699 for (y = 0; y < uHeight; ++y)
1700 {
1701 uint32_t *pu32DstPixel = (uint32_t *)image.scanLine(y);
1702
1703 for (x = 0; x < uWidth; ++x)
1704 {
1705 const uint8_t u8Bit = (uint8_t)(1 << (7 - x % 8));
1706 const uint8_t u8SrcMaskByte = pu8SrcAndScanline[x / 8];
1707
1708 if (u8SrcMaskByte & u8Bit)
1709 *pu32DstPixel++ = pu32SrcShapeScanline[x] & UINT32_C(0x00FFFFFF);
1710 else
1711 *pu32DstPixel++ = pu32SrcShapeScanline[x] | UINT32_C(0xFF000000);
1712 }
1713
1714 pu32SrcShapeScanline += uWidth;
1715 pu8SrcAndScanline += (uWidth + 7) / 8;
1716 }
1717
1718 m_cursor = QCursor(QPixmap::fromImage(image), uXHot, uYHot);
1719 }
1720 }
1721
1722 m_fIsValidPointerShapePresent = true;
1723 NOREF(srcShapePtrScan);
1724
1725#elif defined(VBOX_WS_X11) || defined(VBOX_WS_MAC)
1726
1727 /* Create a ARGB image out of the shape data: */
1728 QImage image(uWidth, uHeight, QImage::Format_ARGB32);
1729
1730 if (fHasAlpha)
1731 {
1732 memcpy(image.bits(), srcShapePtr, uHeight * uWidth * 4);
1733 }
1734 else
1735 {
1736 renderCursorPixels((uint32_t *)srcShapePtr, srcAndMaskPtr,
1737 uWidth, uHeight,
1738 (uint32_t *)image.bits(), uHeight * uWidth * 4);
1739 }
1740
1741 /* Create cursor-pixmap from the image: */
1742 QPixmap cursorPixmap = QPixmap::fromImage(image);
1743# ifdef VBOX_WS_MAC
1744# ifdef VBOX_GUI_WITH_HIDPI
1745 /* Adjust backing-scale-factor: */
1746 /// @todo In case of multi-monitor setup check whether backing-scale factor and cursor are screen specific.
1747 /* Get screen-id of main-window: */
1748 const ulong uScreenID = machineLogic()->activeMachineWindow()->screenId();
1749 /* Get backing-scale-factor: */
1750 const double dBackingScaleFactor = frameBuffer(uScreenID)->backingScaleFactor();
1751 /* Adjust backing-scale-factor if necessary: */
1752 if (dBackingScaleFactor > 1.0 && frameBuffer(uScreenID)->useUnscaledHiDPIOutput())
1753 {
1754 uXHot /= dBackingScaleFactor;
1755 uYHot /= dBackingScaleFactor;
1756 cursorPixmap.setDevicePixelRatio(dBackingScaleFactor);
1757 }
1758# endif /* VBOX_GUI_WITH_HIDPI */
1759# endif /* VBOX_WS_MAC */
1760 /* Set the new cursor: */
1761 m_cursor = QCursor(cursorPixmap, uXHot, uYHot);
1762 m_fIsValidPointerShapePresent = true;
1763 NOREF(srcShapePtrScan);
1764
1765#else
1766
1767# warning "port me"
1768
1769#endif
1770}
1771
1772bool UISession::preprocessInitialization()
1773{
1774#ifdef VBOX_WITH_NETFLT
1775 /* Skip further checks if VM in saved state */
1776 if (isSaved())
1777 return true;
1778
1779 /* Make sure all the attached and enabled network
1780 * adapters are present on the host. This check makes sense
1781 * in two cases only - when attachement type is Bridged Network
1782 * or Host-only Interface. NOTE: Only currently enabled
1783 * attachement type is checked (incorrect parameters check for
1784 * currently disabled attachement types is skipped). */
1785 QStringList failedInterfaceNames;
1786 QStringList availableInterfaceNames;
1787
1788 /* Create host network interface names list */
1789 foreach (const CHostNetworkInterface &iface, vboxGlobal().host().GetNetworkInterfaces())
1790 {
1791 availableInterfaceNames << iface.GetName();
1792 availableInterfaceNames << iface.GetShortName();
1793 }
1794
1795 ulong cCount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine().GetChipsetType());
1796 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
1797 {
1798 CNetworkAdapter na = machine().GetNetworkAdapter(uAdapterIndex);
1799
1800 if (na.GetEnabled())
1801 {
1802 QString strIfName = QString();
1803
1804 /* Get physical network interface name for currently
1805 * enabled network attachement type */
1806 switch (na.GetAttachmentType())
1807 {
1808 case KNetworkAttachmentType_Bridged:
1809 strIfName = na.GetBridgedInterface();
1810 break;
1811 case KNetworkAttachmentType_HostOnly:
1812 strIfName = na.GetHostOnlyInterface();
1813 break;
1814 default: break; /* Shut up, MSC! */
1815 }
1816
1817 if (!strIfName.isEmpty() &&
1818 !availableInterfaceNames.contains(strIfName))
1819 {
1820 LogFlow(("Found invalid network interface: %s\n", strIfName.toStdString().c_str()));
1821 failedInterfaceNames << QString("%1 (adapter %2)").arg(strIfName).arg(uAdapterIndex + 1);
1822 }
1823 }
1824 }
1825
1826 /* Check if non-existent interfaces found */
1827 if (!failedInterfaceNames.isEmpty())
1828 {
1829 if (msgCenter().cannotStartWithoutNetworkIf(machineName(), failedInterfaceNames.join(", ")))
1830 machineLogic()->openNetworkSettingsDialog();
1831 else
1832 {
1833 LogRel(("GUI: Aborting startup due to preprocess initialization issue detected...\n"));
1834 return false;
1835 }
1836 }
1837#endif /* VBOX_WITH_NETFLT */
1838
1839 /* True by default: */
1840 return true;
1841}
1842
1843bool UISession::mountAdHocImage(KDeviceType enmDeviceType, UIMediumType enmMediumType, const QString &strMediumName)
1844{
1845 /* Get VBox: */
1846 CVirtualBox comVBox = vboxGlobal().virtualBox();
1847
1848 /* Prepare medium to mount: */
1849 UIMedium guiMedium;
1850
1851 /* The 'none' medium name means ejecting what ever is in the drive,
1852 * in that case => leave the guiMedium variable null. */
1853 if (strMediumName != "none")
1854 {
1855 /* Open the medium: */
1856 const CMedium comMedium = comVBox.OpenMedium(strMediumName, enmDeviceType, KAccessMode_ReadWrite, false /* fForceNewUuid */);
1857 if (!comVBox.isOk() || comMedium.isNull())
1858 {
1859 msgCenter().cannotOpenMedium(comVBox, enmMediumType, strMediumName);
1860 return false;
1861 }
1862
1863 /* Make sure medium ID is valid: */
1864 const QString strMediumId = comMedium.GetId();
1865 AssertReturn(!strMediumId.isNull(), false);
1866
1867 /* Try to find UIMedium among cached: */
1868 guiMedium = vboxGlobal().medium(strMediumId);
1869 if (guiMedium.isNull())
1870 {
1871 /* Cache new one if necessary: */
1872 guiMedium = UIMedium(comMedium, enmMediumType, KMediumState_Created);
1873 vboxGlobal().createMedium(guiMedium);
1874 }
1875 }
1876
1877 /* Search for a suitable storage slots: */
1878 QList<ExactStorageSlot> aFreeStorageSlots;
1879 QList<ExactStorageSlot> aBusyStorageSlots;
1880 foreach (const CStorageController &comController, machine().GetStorageControllers())
1881 {
1882 foreach (const CMediumAttachment &comAttachment, machine().GetMediumAttachmentsOfController(comController.GetName()))
1883 {
1884 /* Look for an optical devices only: */
1885 if (comAttachment.GetType() == enmDeviceType)
1886 {
1887 /* Append storage slot to corresponding list: */
1888 if (comAttachment.GetMedium().isNull())
1889 aFreeStorageSlots << ExactStorageSlot(comController.GetName(), comController.GetBus(),
1890 comAttachment.GetPort(), comAttachment.GetDevice());
1891 else
1892 aBusyStorageSlots << ExactStorageSlot(comController.GetName(), comController.GetBus(),
1893 comAttachment.GetPort(), comAttachment.GetDevice());
1894 }
1895 }
1896 }
1897
1898 /* Make sure at least one storage slot found: */
1899 QList<ExactStorageSlot> sStorageSlots = aFreeStorageSlots + aBusyStorageSlots;
1900 if (sStorageSlots.isEmpty())
1901 {
1902 msgCenter().cannotMountGuestAdditions(machineName());
1903 return false;
1904 }
1905
1906 /* Try to mount medium into first available storage slot: */
1907 while (!sStorageSlots.isEmpty())
1908 {
1909 const ExactStorageSlot storageSlot = sStorageSlots.takeFirst();
1910 machine().MountMedium(storageSlot.controller, storageSlot.port, storageSlot.device, guiMedium.medium(), false /* force */);
1911 if (machine().isOk())
1912 break;
1913 }
1914
1915 /* Show error message if necessary: */
1916 if (!machine().isOk())
1917 {
1918 msgCenter().cannotRemountMedium(machine(), guiMedium, true /* mount? */, false /* retry? */, mainMachineWindow());
1919 return false;
1920 }
1921
1922 /* Save machine settings: */
1923 machine().SaveSettings();
1924
1925 /* Show error message if necessary: */
1926 if (!machine().isOk())
1927 {
1928 msgCenter().cannotSaveMachineSettings(machine(), mainMachineWindow());
1929 return false;
1930 }
1931
1932 /* True by default: */
1933 return true;
1934}
1935
1936bool UISession::postprocessInitialization()
1937{
1938 /* Check if the required virtualization features are active. We get this info only when the session is active. */
1939 const bool fIs64BitsGuest = vboxGlobal().virtualBox().GetGuestOSType(guest().GetOSTypeId()).GetIs64Bit();
1940 const bool fRecommendVirtEx = vboxGlobal().virtualBox().GetGuestOSType(guest().GetOSTypeId()).GetRecommendedVirtEx();
1941 AssertMsg(!fIs64BitsGuest || fRecommendVirtEx, ("Virtualization support missed for 64bit guest!\n"));
1942 const bool fIsVirtActive = debugger().GetHWVirtExEnabled();
1943 if (fRecommendVirtEx && !fIsVirtActive)
1944 {
1945 /* Check whether vt-x / amd-v supported: */
1946 bool fVTxAMDVSupported = vboxGlobal().host().GetProcessorFeature(KProcessorFeature_HWVirtEx);
1947
1948 /* Pause VM: */
1949 setPause(true);
1950
1951 /* Ask the user about further actions: */
1952 bool fShouldWeClose;
1953 if (fIs64BitsGuest)
1954 fShouldWeClose = msgCenter().warnAboutVirtExInactiveFor64BitsGuest(fVTxAMDVSupported);
1955 else
1956 fShouldWeClose = msgCenter().warnAboutVirtExInactiveForRecommendedGuest(fVTxAMDVSupported);
1957
1958 /* If user asked to close VM: */
1959 if (fShouldWeClose)
1960 {
1961 /* Enable 'manual-override',
1962 * preventing automatic Runtime UI closing: */
1963 if (machineLogic())
1964 machineLogic()->setManualOverrideMode(true);
1965 /* Power off VM: */
1966 bool fServerCrashed = false;
1967 LogRel(("GUI: Aborting startup due to postprocess initialization issue detected...\n"));
1968 powerOff(false, fServerCrashed);
1969 return false;
1970 }
1971
1972 /* Resume VM: */
1973 setPause(false);
1974 }
1975
1976 /* True by default: */
1977 return true;
1978}
1979
1980bool UISession::isScreenVisibleHostDesires(ulong uScreenId) const
1981{
1982 /* Make sure index feats the bounds: */
1983 AssertReturn(uScreenId < (ulong)m_monitorVisibilityVectorHostDesires.size(), false);
1984
1985 /* Return 'actual' (host-desire) visibility status: */
1986 return m_monitorVisibilityVectorHostDesires.value((int)uScreenId);
1987}
1988
1989void UISession::setScreenVisibleHostDesires(ulong uScreenId, bool fIsMonitorVisible)
1990{
1991 /* Make sure index feats the bounds: */
1992 AssertReturnVoid(uScreenId < (ulong)m_monitorVisibilityVectorHostDesires.size());
1993
1994 /* Remember 'actual' (host-desire) visibility status: */
1995 m_monitorVisibilityVectorHostDesires[(int)uScreenId] = fIsMonitorVisible;
1996}
1997
1998bool UISession::isScreenVisible(ulong uScreenId) const
1999{
2000 /* Make sure index feats the bounds: */
2001 AssertReturn(uScreenId < (ulong)m_monitorVisibilityVector.size(), false);
2002
2003 /* Return 'actual' visibility status: */
2004 return m_monitorVisibilityVector.value((int)uScreenId);
2005}
2006
2007void UISession::setScreenVisible(ulong uScreenId, bool fIsMonitorVisible)
2008{
2009 /* Make sure index feats the bounds: */
2010 AssertReturnVoid(uScreenId < (ulong)m_monitorVisibilityVector.size());
2011
2012 /* Remember 'actual' visibility status: */
2013 m_monitorVisibilityVector[(int)uScreenId] = fIsMonitorVisible;
2014 /* Remember 'desired' visibility status: */
2015 gEDataManager->setLastGuestScreenVisibilityStatus(uScreenId, fIsMonitorVisible, vboxGlobal().managedVMUuid());
2016}
2017
2018QSize UISession::lastFullScreenSize(ulong uScreenId) const
2019{
2020 /* Make sure index fits the bounds: */
2021 AssertReturn(uScreenId < (ulong)m_monitorLastFullScreenSizeVector.size(), QSize(-1, -1));
2022
2023 /* Return last full-screen size: */
2024 return m_monitorLastFullScreenSizeVector.value((int)uScreenId);
2025}
2026
2027void UISession::setLastFullScreenSize(ulong uScreenId, QSize size)
2028{
2029 /* Make sure index fits the bounds: */
2030 AssertReturnVoid(uScreenId < (ulong)m_monitorLastFullScreenSizeVector.size());
2031
2032 /* Remember last full-screen size: */
2033 m_monitorLastFullScreenSizeVector[(int)uScreenId] = size;
2034}
2035
2036int UISession::countOfVisibleWindows()
2037{
2038 int cCountOfVisibleWindows = 0;
2039 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
2040 if (m_monitorVisibilityVector[i])
2041 ++cCountOfVisibleWindows;
2042 return cCountOfVisibleWindows;
2043}
2044
2045void UISession::loadVMSettings()
2046{
2047 /* Load CPU hardware virtualization extension: */
2048 m_fIsHWVirtExEnabled = m_debugger.GetHWVirtExEnabled();
2049 /* Load nested-paging CPU hardware virtualization extension: */
2050 m_fIsHWVirtExNestedPagingEnabled = m_debugger.GetHWVirtExNestedPagingEnabled();
2051 /* Load whether the VM is currently making use of the unrestricted execution feature of VT-x: */
2052 m_fIsHWVirtExUXEnabled = m_debugger.GetHWVirtExUXEnabled();
2053 /* Load VM's effective paravirtualization provider: */
2054 m_paraVirtProvider = m_machine.GetEffectiveParavirtProvider();
2055}
2056
2057UIFrameBuffer* UISession::frameBuffer(ulong uScreenId) const
2058{
2059 Assert(uScreenId < (ulong)m_frameBufferVector.size());
2060 return m_frameBufferVector.value((int)uScreenId, 0);
2061}
2062
2063void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer* pFrameBuffer)
2064{
2065 Assert(uScreenId < (ulong)m_frameBufferVector.size());
2066 if (uScreenId < (ulong)m_frameBufferVector.size())
2067 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
2068}
2069
2070void UISession::updateHostScreenData()
2071{
2072 m_hostScreens.clear();
2073 for (int iScreenIndex = 0; iScreenIndex < gpDesktop->screenCount(); ++iScreenIndex)
2074 m_hostScreens << gpDesktop->screenGeometry(iScreenIndex);
2075}
2076
2077void UISession::updateActionRestrictions()
2078{
2079 /* Get host and prepare restrictions: */
2080 const CHost host = vboxGlobal().host();
2081 UIExtraDataMetaDefs::RuntimeMenuMachineActionType restrictionForMachine = UIExtraDataMetaDefs::RuntimeMenuMachineActionType_Invalid;
2082 UIExtraDataMetaDefs::RuntimeMenuViewActionType restrictionForView = UIExtraDataMetaDefs::RuntimeMenuViewActionType_Invalid;
2083 UIExtraDataMetaDefs::RuntimeMenuDevicesActionType restrictionForDevices = UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Invalid;
2084
2085 /* Separate process stuff: */
2086 {
2087 /* Initialize 'Machine' menu: */
2088 if (!vboxGlobal().isSeparateProcess())
2089 restrictionForMachine = (UIExtraDataMetaDefs::RuntimeMenuMachineActionType)(restrictionForMachine | UIExtraDataMetaDefs::RuntimeMenuMachineActionType_Detach);
2090 }
2091
2092 /* VRDE server stuff: */
2093 {
2094 /* Initialize 'View' menu: */
2095 const CVRDEServer server = machine().GetVRDEServer();
2096 if (server.isNull())
2097 restrictionForView = (UIExtraDataMetaDefs::RuntimeMenuViewActionType)(restrictionForView | UIExtraDataMetaDefs::RuntimeMenuViewActionType_VRDEServer);
2098 }
2099
2100 /* Storage stuff: */
2101 {
2102 /* Initialize CD/FD menus: */
2103 int iDevicesCountCD = 0;
2104 int iDevicesCountFD = 0;
2105 foreach (const CMediumAttachment &attachment, machine().GetMediumAttachments())
2106 {
2107 if (attachment.GetType() == KDeviceType_DVD)
2108 ++iDevicesCountCD;
2109 if (attachment.GetType() == KDeviceType_Floppy)
2110 ++iDevicesCountFD;
2111 }
2112 QAction *pOpticalDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices);
2113 QAction *pFloppyDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices);
2114 pOpticalDevicesMenu->setData(iDevicesCountCD);
2115 pFloppyDevicesMenu->setData(iDevicesCountFD);
2116 if (!iDevicesCountCD)
2117 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_OpticalDevices);
2118 if (!iDevicesCountFD)
2119 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_FloppyDevices);
2120 }
2121
2122 /* Network stuff: */
2123 {
2124 /* Initialize Network menu: */
2125 bool fAtLeastOneAdapterActive = false;
2126 const KChipsetType chipsetType = machine().GetChipsetType();
2127 ULONG uSlots = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(chipsetType);
2128 for (ULONG uSlot = 0; uSlot < uSlots; ++uSlot)
2129 {
2130 const CNetworkAdapter &adapter = machine().GetNetworkAdapter(uSlot);
2131 if (adapter.GetEnabled())
2132 {
2133 fAtLeastOneAdapterActive = true;
2134 break;
2135 }
2136 }
2137 if (!fAtLeastOneAdapterActive)
2138 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Network);
2139 }
2140
2141 /* USB stuff: */
2142 {
2143 /* Check whether there is at least one USB controller with an available proxy. */
2144 const bool fUSBEnabled = !machine().GetUSBDeviceFilters().isNull()
2145 && !machine().GetUSBControllers().isEmpty()
2146 && machine().GetUSBProxyAvailable();
2147 if (!fUSBEnabled)
2148 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_USBDevices);
2149 }
2150
2151 /* WebCams stuff: */
2152 {
2153 /* Check whether there is an accessible video input devices pool: */
2154 host.GetVideoInputDevices();
2155 const bool fWebCamsEnabled = host.isOk() && !machine().GetUSBControllers().isEmpty();
2156 if (!fWebCamsEnabled)
2157 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_WebCams);
2158 }
2159
2160 /* Apply cumulative restriction for 'Machine' menu: */
2161 actionPool()->toRuntime()->setRestrictionForMenuMachine(UIActionRestrictionLevel_Session, restrictionForMachine);
2162 /* Apply cumulative restriction for 'View' menu: */
2163 actionPool()->toRuntime()->setRestrictionForMenuView(UIActionRestrictionLevel_Session, restrictionForView);
2164 /* Apply cumulative restriction for 'Devices' menu: */
2165 actionPool()->toRuntime()->setRestrictionForMenuDevices(UIActionRestrictionLevel_Session, restrictionForDevices);
2166}
2167
2168#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
2169/**
2170 * Custom signal handler. When switching VTs, we might not get release events
2171 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
2172 * be saved with modifier keys stuck. This is annoying enough for introducing
2173 * this hack.
2174 */
2175/* static */
2176static void signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
2177{
2178 /* Only SIGUSR1 is interesting: */
2179 if (sig == SIGUSR1)
2180 if (gpMachine)
2181 gpMachine->uisession()->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
2182}
2183#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
2184
Note: See TracBrowser for help on using the repository browser.

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