VirtualBox

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

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

FE/Qt: VideoCapture -> Recording renaming.

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