VirtualBox

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

Last change on this file since 73946 was 73946, checked in by vboxsync, 6 years ago

FE/Qt: bugref:8472. Fix for r124671.

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