VirtualBox

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

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

FE/Qt: Moving some more messages to UIPopupCenter

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