VirtualBox

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

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

FE/Qt: bugref:9049: Detach VBoxGlobal from VBoxQGLOverlay stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 80.2 KB
Line 
1/* $Id: UISession.cpp 71368 2018-03-16 14:32:33Z 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 "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() && VBoxQGLOverlay::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 m_fAllCloseActionsRestricted = (!vboxGlobal().isSeparateProcess() || (m_restrictedCloseActions & MachineCloseAction_Detach))
1320 && (m_restrictedCloseActions & MachineCloseAction_SaveState)
1321 && (m_restrictedCloseActions & MachineCloseAction_Shutdown)
1322 && (m_restrictedCloseActions & MachineCloseAction_PowerOff);
1323 // Close VM Dialog hides PowerOff_RestoringSnapshot implicitly if PowerOff is hidden..
1324 // && (m_restrictedCloseActions & MachineCloseAction_PowerOff_RestoringSnapshot);
1325 }
1326}
1327
1328void UISession::saveSessionSettings()
1329{
1330 /* Save extra-data settings: */
1331 {
1332 /* Disable First RUN Wizard: */
1333 gEDataManager->setMachineFirstTimeStarted(false, vboxGlobal().managedVMUuid());
1334
1335 /* Remember if guest should autoresize: */
1336 if (actionPool())
1337 {
1338 const QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1339 gEDataManager->setGuestScreenAutoResizeEnabled(pGuestAutoresizeSwitch->isChecked(), vboxGlobal().managedVMUuid());
1340 }
1341
1342 /* Cleanup machine-window icon: */
1343 delete m_pMachineWindowIcon;
1344 m_pMachineWindowIcon = 0;
1345 }
1346}
1347
1348void UISession::cleanupFramebuffers()
1349{
1350 /* Cleanup framebuffers finally: */
1351 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
1352 {
1353 UIFrameBuffer *pFrameBuffer = m_frameBufferVector[i];
1354 if (pFrameBuffer)
1355 {
1356 /* Mark framebuffer as unused: */
1357 pFrameBuffer->setMarkAsUnused(true);
1358 /* Detach framebuffer from Display: */
1359 pFrameBuffer->detach();
1360 /* Delete framebuffer reference: */
1361 delete pFrameBuffer;
1362 }
1363 }
1364 m_frameBufferVector.clear();
1365}
1366
1367void UISession::cleanupConsoleEventHandlers()
1368{
1369 /* Destroy console event-handler if necessary: */
1370 if (gConsoleEvents)
1371 UIConsoleEventHandler::destroy();
1372}
1373
1374void UISession::cleanupConnections()
1375{
1376#ifdef VBOX_WS_MAC
1377 /* Remove display reconfiguration callback: */
1378 CGDisplayRemoveReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1379#endif /* VBOX_WS_MAC */
1380}
1381
1382void UISession::cleanupActions()
1383{
1384#ifdef VBOX_WS_MAC
1385 /* Destroy Mac OS X menu-bar: */
1386 delete m_pMenuBar;
1387 m_pMenuBar = 0;
1388#endif /* VBOX_WS_MAC */
1389
1390 /* Destroy action-pool if necessary: */
1391 if (actionPool())
1392 UIActionPool::destroy(actionPool());
1393}
1394
1395void UISession::cleanupSession()
1396{
1397 /* Detach debugger: */
1398 if (!m_debugger.isNull())
1399 m_debugger.detach();
1400
1401 /* Detach keyboard: */
1402 if (!m_keyboard.isNull())
1403 m_keyboard.detach();
1404
1405 /* Detach mouse: */
1406 if (!m_mouse.isNull())
1407 m_mouse.detach();
1408
1409 /* Detach guest: */
1410 if (!m_guest.isNull())
1411 m_guest.detach();
1412
1413 /* Detach display: */
1414 if (!m_display.isNull())
1415 m_display.detach();
1416
1417 /* Detach console: */
1418 if (!m_console.isNull())
1419 m_console.detach();
1420
1421 /* Detach machine: */
1422 if (!m_machine.isNull())
1423 m_machine.detach();
1424
1425 /* Close session: */
1426 if (!m_session.isNull() && vboxGlobal().isVBoxSVCAvailable())
1427 {
1428 m_session.UnlockMachine();
1429 m_session.detach();
1430 }
1431}
1432
1433void UISession::cleanup()
1434{
1435#ifdef VBOX_WS_WIN
1436 /* Destroy alpha cursor: */
1437 if (m_alphaCursor)
1438 DestroyIcon(m_alphaCursor);
1439#endif /* VBOX_WS_WIN */
1440
1441 /* Save settings: */
1442 saveSessionSettings();
1443
1444 /* Cleanup framebuffers: */
1445 cleanupFramebuffers();
1446
1447 /* Cleanup console event-handlers: */
1448 cleanupConsoleEventHandlers();
1449
1450 /* Cleanup connections: */
1451 cleanupConnections();
1452
1453 /* Cleanup actions: */
1454 cleanupActions();
1455
1456 /* Cleanup session: */
1457 cleanupSession();
1458}
1459
1460#ifdef VBOX_WS_MAC
1461void UISession::updateMenu()
1462{
1463 /* Rebuild Mac OS X menu-bar: */
1464 m_pMenuBar->clear();
1465 foreach (QMenu *pMenu, actionPool()->menus())
1466 {
1467 UIMenu *pMenuUI = qobject_cast<UIMenu*>(pMenu);
1468 if (!pMenuUI->isConsumable() || !pMenuUI->isConsumed())
1469 m_pMenuBar->addMenu(pMenuUI);
1470 if (pMenuUI->isConsumable() && !pMenuUI->isConsumed())
1471 pMenuUI->setConsumed(true);
1472 }
1473 /* Update the dock menu as well: */
1474 if (machineLogic())
1475 machineLogic()->updateDock();
1476}
1477#endif /* VBOX_WS_MAC */
1478
1479/** Generate a BGRA bitmap which approximates a XOR/AND mouse pointer.
1480 *
1481 * Pixels which has 1 in the AND mask and not 0 in the XOR mask are replaced by
1482 * the inverted pixel and 8 surrounding pixels with the original color.
1483 * Fort example a white pixel (W) is replaced with a black (B) pixel:
1484 * WWW
1485 * W -> WBW
1486 * WWW
1487 * The surrounding pixels are written only if the corresponding source pixel
1488 * does not affect the screen, i.e. AND bit is 1 and XOR value is 0.
1489 */
1490static void renderCursorPixels(const uint32_t *pu32XOR, const uint8_t *pu8AND,
1491 uint32_t u32Width, uint32_t u32Height,
1492 uint32_t *pu32Pixels, uint32_t cbPixels)
1493{
1494 /* Output pixels set to 0 which allow to not write transparent pixels anymore. */
1495 memset(pu32Pixels, 0, cbPixels);
1496
1497 const uint32_t *pu32XORSrc = pu32XOR; /* Iterator for source XOR pixels. */
1498 const uint8_t *pu8ANDSrcLine = pu8AND; /* The current AND mask scanline. */
1499 uint32_t *pu32Dst = pu32Pixels; /* Iterator for all destination BGRA pixels. */
1500
1501 /* Some useful constants. */
1502 const int cbANDLine = ((int)u32Width + 7) / 8;
1503
1504 int y;
1505 for (y = 0; y < (int)u32Height; ++y)
1506 {
1507 int x;
1508 for (x = 0; x < (int)u32Width; ++x)
1509 {
1510 const uint32_t u32Pixel = *pu32XORSrc; /* Current pixel at (x,y) */
1511 const uint8_t *pu8ANDSrc = pu8ANDSrcLine + x / 8; /* Byte which containt current AND bit. */
1512
1513 if ((*pu8ANDSrc << (x % 8)) & 0x80)
1514 {
1515 if (u32Pixel)
1516 {
1517 const uint32_t u32PixelInverted = ~u32Pixel;
1518
1519 /* Scan neighbor pixels and assign them if they are transparent. */
1520 int dy;
1521 for (dy = -1; dy <= 1; ++dy)
1522 {
1523 const int yn = y + dy;
1524 if (yn < 0 || yn >= (int)u32Height)
1525 continue; /* Do not cross the bounds. */
1526
1527 int dx;
1528 for (dx = -1; dx <= 1; ++dx)
1529 {
1530 const int xn = x + dx;
1531 if (xn < 0 || xn >= (int)u32Width)
1532 continue; /* Do not cross the bounds. */
1533
1534 if (dx != 0 || dy != 0)
1535 {
1536 /* Check if the neighbor pixel is transparent. */
1537 const uint32_t *pu32XORNeighborSrc = &pu32XORSrc[dy * (int)u32Width + dx];
1538 const uint8_t *pu8ANDNeighborSrc = pu8ANDSrcLine + dy * cbANDLine + xn / 8;
1539 if ( *pu32XORNeighborSrc == 0
1540 && ((*pu8ANDNeighborSrc << (xn % 8)) & 0x80) != 0)
1541 {
1542 /* Transparent neighbor pixels are replaced with the source pixel value. */
1543 uint32_t *pu32PixelNeighborDst = &pu32Dst[dy * (int)u32Width + dx];
1544 *pu32PixelNeighborDst = u32Pixel | 0xFF000000;
1545 }
1546 }
1547 else
1548 {
1549 /* The pixel itself is replaced with inverted value. */
1550 *pu32Dst = u32PixelInverted | 0xFF000000;
1551 }
1552 }
1553 }
1554 }
1555 else
1556 {
1557 /* The pixel does not affect the screen.
1558 * Do nothing. Do not touch destination which can already contain generated pixels.
1559 */
1560 }
1561 }
1562 else
1563 {
1564 /* AND bit is 0, the pixel will be just drawn. */
1565 *pu32Dst = u32Pixel | 0xFF000000;
1566 }
1567
1568 ++pu32XORSrc; /* Next source pixel. */
1569 ++pu32Dst; /* Next destination pixel. */
1570 }
1571
1572 /* Next AND scanline. */
1573 pu8ANDSrcLine += cbANDLine;
1574 }
1575}
1576
1577#ifdef VBOX_WS_WIN
1578static bool isPointer1bpp(const uint8_t *pu8XorMask,
1579 uint uWidth,
1580 uint uHeight)
1581{
1582 /* Check if the pointer has only 0 and 0xFFFFFF pixels, ignoring the alpha channel. */
1583 const uint32_t *pu32Src = (uint32_t *)pu8XorMask;
1584
1585 uint y;
1586 for (y = 0; y < uHeight ; ++y)
1587 {
1588 uint x;
1589 for (x = 0; x < uWidth; ++x)
1590 {
1591 const uint32_t u32Pixel = pu32Src[x] & UINT32_C(0xFFFFFF);
1592 if (u32Pixel != 0 && u32Pixel != UINT32_C(0xFFFFFF))
1593 return false;
1594 }
1595
1596 pu32Src += uWidth;
1597 }
1598
1599 return true;
1600}
1601#endif /* VBOX_WS_WIN */
1602
1603void UISession::setPointerShape(const uchar *pShapeData, bool fHasAlpha,
1604 uint uXHot, uint uYHot, uint uWidth, uint uHeight)
1605{
1606 AssertMsg(pShapeData, ("Shape data must not be NULL!\n"));
1607
1608 m_fIsValidPointerShapePresent = false;
1609 const uchar *srcAndMaskPtr = pShapeData;
1610 uint andMaskSize = (uWidth + 7) / 8 * uHeight;
1611 const uchar *srcShapePtr = pShapeData + ((andMaskSize + 3) & ~3);
1612 uint srcShapePtrScan = uWidth * 4;
1613
1614#if defined (VBOX_WS_WIN)
1615
1616 /* Create a ARGB image out of the shape data: */
1617
1618 /*
1619 * Qt5 QCursor recommends 32 x 32 cursor, therefore the original data is copied to
1620 * a larger QImage if necessary. Cursors like 10x16 did not work correctly (Solaris 10 guest).
1621 */
1622 uint uCursorWidth = uWidth >= 32? uWidth: 32;
1623 uint uCursorHeight = uHeight >= 32? uHeight: 32;
1624 uint x, y;
1625
1626 if (fHasAlpha)
1627 {
1628 QImage image(uCursorWidth, uCursorHeight, QImage::Format_ARGB32);
1629 memset(image.bits(), 0, image.byteCount());
1630
1631 const uint32_t *pu32SrcShapeScanline = (uint32_t *)srcShapePtr;
1632 for (y = 0; y < uHeight; ++y, pu32SrcShapeScanline += uWidth)
1633 memcpy(image.scanLine(y), pu32SrcShapeScanline, uWidth * sizeof(uint32_t));
1634
1635 m_cursor = QCursor(QPixmap::fromImage(image), uXHot, uYHot);
1636 }
1637 else
1638 {
1639 if (isPointer1bpp(srcShapePtr, uWidth, uHeight))
1640 {
1641 /* Incoming data consist of 32 bit BGR XOR mask and 1 bit AND mask.
1642 * XOR pixels contain either 0x00000000 or 0x00FFFFFF.
1643 *
1644 * Originally intended result (F denotes 0x00FFFFFF):
1645 * XOR AND
1646 * 0 0 black
1647 * F 0 white
1648 * 0 1 transparent
1649 * F 1 xor'd
1650 *
1651 * Actual Qt5 result for color table 0:0xFF000000, 1:0xFFFFFFFF
1652 * (tested on Windows 7 and 10 64 bit hosts):
1653 * Bitmap Mask
1654 * 0 0 black
1655 * 1 0 white
1656 * 0 1 xor
1657 * 1 1 transparent
1658 *
1659 */
1660
1661 QVector<QRgb> colors(2);
1662 colors[0] = UINT32_C(0xFF000000);
1663 colors[1] = UINT32_C(0xFFFFFFFF);
1664
1665 QImage bitmap(uCursorWidth, uCursorHeight, QImage::Format_Mono);
1666 bitmap.setColorTable(colors);
1667 memset(bitmap.bits(), 0xFF, bitmap.byteCount());
1668
1669 QImage mask(uCursorWidth, uCursorHeight, QImage::Format_Mono);
1670 mask.setColorTable(colors);
1671 memset(mask.bits(), 0xFF, mask.byteCount());
1672
1673 const uint8_t *pu8SrcAndScanline = srcAndMaskPtr;
1674 const uint32_t *pu32SrcShapeScanline = (uint32_t *)srcShapePtr;
1675 for (y = 0; y < uHeight; ++y)
1676 {
1677 for (x = 0; x < uWidth; ++x)
1678 {
1679 const uint8_t u8Bit = (uint8_t)(1 << (7 - x % 8));
1680
1681 const uint8_t u8SrcMaskByte = pu8SrcAndScanline[x / 8];
1682 const uint8_t u8SrcMaskBit = u8SrcMaskByte & u8Bit;
1683 const uint32_t u32SrcPixel = pu32SrcShapeScanline[x] & UINT32_C(0xFFFFFF);
1684
1685 uint8_t *pu8DstMaskByte = &mask.scanLine(y)[x / 8];
1686 uint8_t *pu8DstBitmapByte = &bitmap.scanLine(y)[x / 8];
1687
1688 if (u8SrcMaskBit == 0)
1689 {
1690 if (u32SrcPixel == 0)
1691 {
1692 /* Black: Qt Bitmap = 0, Mask = 0 */
1693 *pu8DstMaskByte &= ~u8Bit;
1694 *pu8DstBitmapByte &= ~u8Bit;
1695 }
1696 else
1697 {
1698 /* White: Qt Bitmap = 1, Mask = 0 */
1699 *pu8DstMaskByte &= ~u8Bit;
1700 *pu8DstBitmapByte |= u8Bit;
1701 }
1702 }
1703 else
1704 {
1705 if (u32SrcPixel == 0)
1706 {
1707 /* Transparent: Qt Bitmap = 1, Mask = 1 */
1708 *pu8DstMaskByte |= u8Bit;
1709 *pu8DstBitmapByte |= u8Bit;
1710 }
1711 else
1712 {
1713 /* Xor'ed: Qt Bitmap = 0, Mask = 1 */
1714 *pu8DstMaskByte |= u8Bit;
1715 *pu8DstBitmapByte &= ~u8Bit;
1716 }
1717 }
1718 }
1719
1720 pu8SrcAndScanline += (uWidth + 7) / 8;
1721 pu32SrcShapeScanline += uWidth;
1722 }
1723
1724 m_cursor = QCursor(QBitmap::fromImage(bitmap), QBitmap::fromImage(mask), uXHot, uYHot);
1725 }
1726 else
1727 {
1728 /* Assign alpha channel values according to the AND mask: 1 -> 0x00, 0 -> 0xFF: */
1729 QImage image(uCursorWidth, uCursorHeight, QImage::Format_ARGB32);
1730 memset(image.bits(), 0, image.byteCount());
1731
1732 const uint8_t *pu8SrcAndScanline = srcAndMaskPtr;
1733 const uint32_t *pu32SrcShapeScanline = (uint32_t *)srcShapePtr;
1734
1735 for (y = 0; y < uHeight; ++y)
1736 {
1737 uint32_t *pu32DstPixel = (uint32_t *)image.scanLine(y);
1738
1739 for (x = 0; x < uWidth; ++x)
1740 {
1741 const uint8_t u8Bit = (uint8_t)(1 << (7 - x % 8));
1742 const uint8_t u8SrcMaskByte = pu8SrcAndScanline[x / 8];
1743
1744 if (u8SrcMaskByte & u8Bit)
1745 *pu32DstPixel++ = pu32SrcShapeScanline[x] & UINT32_C(0x00FFFFFF);
1746 else
1747 *pu32DstPixel++ = pu32SrcShapeScanline[x] | UINT32_C(0xFF000000);
1748 }
1749
1750 pu32SrcShapeScanline += uWidth;
1751 pu8SrcAndScanline += (uWidth + 7) / 8;
1752 }
1753
1754 m_cursor = QCursor(QPixmap::fromImage(image), uXHot, uYHot);
1755 }
1756 }
1757
1758 m_fIsValidPointerShapePresent = true;
1759 NOREF(srcShapePtrScan);
1760
1761#elif defined(VBOX_WS_X11) || defined(VBOX_WS_MAC)
1762
1763 /* Create a ARGB image out of the shape data: */
1764 QImage image(uWidth, uHeight, QImage::Format_ARGB32);
1765
1766 if (fHasAlpha)
1767 {
1768 memcpy(image.bits(), srcShapePtr, uHeight * uWidth * 4);
1769 }
1770 else
1771 {
1772 renderCursorPixels((uint32_t *)srcShapePtr, srcAndMaskPtr,
1773 uWidth, uHeight,
1774 (uint32_t *)image.bits(), uHeight * uWidth * 4);
1775 }
1776
1777 /* Create cursor-pixmap from the image: */
1778 QPixmap cursorPixmap = QPixmap::fromImage(image);
1779
1780# if defined(VBOX_WS_MAC)
1781 /* Adjust device-pixel-ratio: */
1782 /// @todo In case of multi-monitor setup check whether device-pixel-ratio and cursor are screen specific.
1783 /* Get screen-id of main-window: */
1784 const ulong uScreenID = machineLogic()->activeMachineWindow()->screenId();
1785 /* Get device-pixel-ratio: */
1786 const double dDevicePixelRatio = frameBuffer(uScreenID)->devicePixelRatio();
1787 /* Adjust device-pixel-ratio if necessary: */
1788 if (dDevicePixelRatio > 1.0 && frameBuffer(uScreenID)->useUnscaledHiDPIOutput())
1789 {
1790 uXHot /= dDevicePixelRatio;
1791 uYHot /= dDevicePixelRatio;
1792 cursorPixmap.setDevicePixelRatio(dDevicePixelRatio);
1793 }
1794# elif defined(VBOX_WS_X11)
1795 /* Adjust device-pixel-ratio: */
1796 /// @todo In case of multi-monitor setup check whether device-pixel-ratio and cursor are screen specific.
1797 /* Get screen-id of main-window: */
1798 const ulong uScreenID = machineLogic()->activeMachineWindow()->screenId();
1799 /* Get device-pixel-ratio: */
1800 const double dDevicePixelRatio = frameBuffer(uScreenID)->devicePixelRatio();
1801 /* Adjust device-pixel-ratio if necessary: */
1802 if (dDevicePixelRatio > 1.0 && !frameBuffer(uScreenID)->useUnscaledHiDPIOutput())
1803 {
1804 uXHot *= dDevicePixelRatio;
1805 uYHot *= dDevicePixelRatio;
1806 cursorPixmap = cursorPixmap.scaled(cursorPixmap.width() * dDevicePixelRatio, cursorPixmap.height() * dDevicePixelRatio,
1807 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1808 }
1809# endif /* VBOX_WS_X11 */
1810
1811 /* Set the new cursor: */
1812 m_cursor = QCursor(cursorPixmap, uXHot, uYHot);
1813 m_fIsValidPointerShapePresent = true;
1814 NOREF(srcShapePtrScan);
1815
1816#else
1817
1818# warning "port me"
1819
1820#endif
1821}
1822
1823bool UISession::preprocessInitialization()
1824{
1825#ifdef VBOX_WITH_NETFLT
1826 /* Skip further checks if VM in saved state */
1827 if (isSaved())
1828 return true;
1829
1830 /* Make sure all the attached and enabled network
1831 * adapters are present on the host. This check makes sense
1832 * in two cases only - when attachement type is Bridged Network
1833 * or Host-only Interface. NOTE: Only currently enabled
1834 * attachement type is checked (incorrect parameters check for
1835 * currently disabled attachement types is skipped). */
1836 QStringList failedInterfaceNames;
1837 QStringList availableInterfaceNames;
1838
1839 /* Create host network interface names list */
1840 foreach (const CHostNetworkInterface &iface, vboxGlobal().host().GetNetworkInterfaces())
1841 {
1842 availableInterfaceNames << iface.GetName();
1843 availableInterfaceNames << iface.GetShortName();
1844 }
1845
1846 ulong cCount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine().GetChipsetType());
1847 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
1848 {
1849 CNetworkAdapter na = machine().GetNetworkAdapter(uAdapterIndex);
1850
1851 if (na.GetEnabled())
1852 {
1853 QString strIfName = QString();
1854
1855 /* Get physical network interface name for currently
1856 * enabled network attachement type */
1857 switch (na.GetAttachmentType())
1858 {
1859 case KNetworkAttachmentType_Bridged:
1860 strIfName = na.GetBridgedInterface();
1861 break;
1862 case KNetworkAttachmentType_HostOnly:
1863 strIfName = na.GetHostOnlyInterface();
1864 break;
1865 default: break; /* Shut up, MSC! */
1866 }
1867
1868 if (!strIfName.isEmpty() &&
1869 !availableInterfaceNames.contains(strIfName))
1870 {
1871 LogFlow(("Found invalid network interface: %s\n", strIfName.toStdString().c_str()));
1872 failedInterfaceNames << QString("%1 (adapter %2)").arg(strIfName).arg(uAdapterIndex + 1);
1873 }
1874 }
1875 }
1876
1877 /* Check if non-existent interfaces found */
1878 if (!failedInterfaceNames.isEmpty())
1879 {
1880 if (msgCenter().cannotStartWithoutNetworkIf(machineName(), failedInterfaceNames.join(", ")))
1881 machineLogic()->openNetworkSettingsDialog();
1882 else
1883 {
1884 LogRel(("GUI: Aborting startup due to preprocess initialization issue detected...\n"));
1885 return false;
1886 }
1887 }
1888#endif /* VBOX_WITH_NETFLT */
1889
1890 /* True by default: */
1891 return true;
1892}
1893
1894bool UISession::mountAdHocImage(KDeviceType enmDeviceType, UIMediumType enmMediumType, const QString &strMediumName)
1895{
1896 /* Get VBox: */
1897 CVirtualBox comVBox = vboxGlobal().virtualBox();
1898
1899 /* Prepare medium to mount: */
1900 UIMedium guiMedium;
1901
1902 /* The 'none' medium name means ejecting what ever is in the drive,
1903 * in that case => leave the guiMedium variable null. */
1904 if (strMediumName != "none")
1905 {
1906 /* Open the medium: */
1907 const CMedium comMedium = comVBox.OpenMedium(strMediumName, enmDeviceType, KAccessMode_ReadWrite, false /* fForceNewUuid */);
1908 if (!comVBox.isOk() || comMedium.isNull())
1909 {
1910 popupCenter().cannotOpenMedium(machineLogic()->activeMachineWindow(), comVBox, enmMediumType, strMediumName);
1911 return false;
1912 }
1913
1914 /* Make sure medium ID is valid: */
1915 const QString strMediumId = comMedium.GetId();
1916 AssertReturn(!strMediumId.isNull(), false);
1917
1918 /* Try to find UIMedium among cached: */
1919 guiMedium = vboxGlobal().medium(strMediumId);
1920 if (guiMedium.isNull())
1921 {
1922 /* Cache new one if necessary: */
1923 guiMedium = UIMedium(comMedium, enmMediumType, KMediumState_Created);
1924 vboxGlobal().createMedium(guiMedium);
1925 }
1926 }
1927
1928 /* Search for a suitable storage slots: */
1929 QList<ExactStorageSlot> aFreeStorageSlots;
1930 QList<ExactStorageSlot> aBusyStorageSlots;
1931 foreach (const CStorageController &comController, machine().GetStorageControllers())
1932 {
1933 foreach (const CMediumAttachment &comAttachment, machine().GetMediumAttachmentsOfController(comController.GetName()))
1934 {
1935 /* Look for an optical devices only: */
1936 if (comAttachment.GetType() == enmDeviceType)
1937 {
1938 /* Append storage slot to corresponding list: */
1939 if (comAttachment.GetMedium().isNull())
1940 aFreeStorageSlots << ExactStorageSlot(comController.GetName(), comController.GetBus(),
1941 comAttachment.GetPort(), comAttachment.GetDevice());
1942 else
1943 aBusyStorageSlots << ExactStorageSlot(comController.GetName(), comController.GetBus(),
1944 comAttachment.GetPort(), comAttachment.GetDevice());
1945 }
1946 }
1947 }
1948
1949 /* Make sure at least one storage slot found: */
1950 QList<ExactStorageSlot> sStorageSlots = aFreeStorageSlots + aBusyStorageSlots;
1951 if (sStorageSlots.isEmpty())
1952 {
1953 popupCenter().cannotMountImage(machineLogic()->activeMachineWindow(), machineName(), strMediumName);
1954 return false;
1955 }
1956
1957 /* Try to mount medium into first available storage slot: */
1958 while (!sStorageSlots.isEmpty())
1959 {
1960 const ExactStorageSlot storageSlot = sStorageSlots.takeFirst();
1961 machine().MountMedium(storageSlot.controller, storageSlot.port, storageSlot.device, guiMedium.medium(), false /* force */);
1962 if (machine().isOk())
1963 break;
1964 }
1965
1966 /* Show error message if necessary: */
1967 if (!machine().isOk())
1968 {
1969 msgCenter().cannotRemountMedium(machine(), guiMedium, true /* mount? */, false /* retry? */, mainMachineWindow());
1970 return false;
1971 }
1972
1973 /* Save machine settings: */
1974 machine().SaveSettings();
1975
1976 /* Show error message if necessary: */
1977 if (!machine().isOk())
1978 {
1979 popupCenter().cannotSaveMachineSettings(machineLogic()->activeMachineWindow(), machine());
1980 return false;
1981 }
1982
1983 /* True by default: */
1984 return true;
1985}
1986
1987bool UISession::postprocessInitialization()
1988{
1989 /* Check if the required virtualization features are active. We get this info only when the session is active. */
1990 const bool fIs64BitsGuest = vboxGlobal().virtualBox().GetGuestOSType(guest().GetOSTypeId()).GetIs64Bit();
1991 const bool fRecommendVirtEx = vboxGlobal().virtualBox().GetGuestOSType(guest().GetOSTypeId()).GetRecommendedVirtEx();
1992 AssertMsg(!fIs64BitsGuest || fRecommendVirtEx, ("Virtualization support missed for 64bit guest!\n"));
1993 const bool fIsVirtActive = debugger().GetHWVirtExEnabled();
1994 if (fRecommendVirtEx && !fIsVirtActive)
1995 {
1996 /* Check whether vt-x / amd-v supported: */
1997 bool fVTxAMDVSupported = vboxGlobal().host().GetProcessorFeature(KProcessorFeature_HWVirtEx);
1998
1999 /* Pause VM: */
2000 setPause(true);
2001
2002 /* Ask the user about further actions: */
2003 bool fShouldWeClose;
2004 if (fIs64BitsGuest)
2005 fShouldWeClose = msgCenter().warnAboutVirtExInactiveFor64BitsGuest(fVTxAMDVSupported);
2006 else
2007 fShouldWeClose = msgCenter().warnAboutVirtExInactiveForRecommendedGuest(fVTxAMDVSupported);
2008
2009 /* If user asked to close VM: */
2010 if (fShouldWeClose)
2011 {
2012 /* Enable 'manual-override',
2013 * preventing automatic Runtime UI closing: */
2014 if (machineLogic())
2015 machineLogic()->setManualOverrideMode(true);
2016 /* Power off VM: */
2017 bool fServerCrashed = false;
2018 LogRel(("GUI: Aborting startup due to postprocess initialization issue detected...\n"));
2019 powerOff(false, fServerCrashed);
2020 return false;
2021 }
2022
2023 /* Resume VM: */
2024 setPause(false);
2025 }
2026
2027 /* True by default: */
2028 return true;
2029}
2030
2031bool UISession::isScreenVisibleHostDesires(ulong uScreenId) const
2032{
2033 /* Make sure index feats the bounds: */
2034 AssertReturn(uScreenId < (ulong)m_monitorVisibilityVectorHostDesires.size(), false);
2035
2036 /* Return 'actual' (host-desire) visibility status: */
2037 return m_monitorVisibilityVectorHostDesires.value((int)uScreenId);
2038}
2039
2040void UISession::setScreenVisibleHostDesires(ulong uScreenId, bool fIsMonitorVisible)
2041{
2042 /* Make sure index feats the bounds: */
2043 AssertReturnVoid(uScreenId < (ulong)m_monitorVisibilityVectorHostDesires.size());
2044
2045 /* Remember 'actual' (host-desire) visibility status: */
2046 m_monitorVisibilityVectorHostDesires[(int)uScreenId] = fIsMonitorVisible;
2047}
2048
2049bool UISession::isScreenVisible(ulong uScreenId) const
2050{
2051 /* Make sure index feats the bounds: */
2052 AssertReturn(uScreenId < (ulong)m_monitorVisibilityVector.size(), false);
2053
2054 /* Return 'actual' visibility status: */
2055 return m_monitorVisibilityVector.value((int)uScreenId);
2056}
2057
2058void UISession::setScreenVisible(ulong uScreenId, bool fIsMonitorVisible)
2059{
2060 /* Make sure index feats the bounds: */
2061 AssertReturnVoid(uScreenId < (ulong)m_monitorVisibilityVector.size());
2062
2063 /* Remember 'actual' visibility status: */
2064 m_monitorVisibilityVector[(int)uScreenId] = fIsMonitorVisible;
2065 /* Remember 'desired' visibility status: */
2066 gEDataManager->setLastGuestScreenVisibilityStatus(uScreenId, fIsMonitorVisible, vboxGlobal().managedVMUuid());
2067}
2068
2069QSize UISession::lastFullScreenSize(ulong uScreenId) const
2070{
2071 /* Make sure index fits the bounds: */
2072 AssertReturn(uScreenId < (ulong)m_monitorLastFullScreenSizeVector.size(), QSize(-1, -1));
2073
2074 /* Return last full-screen size: */
2075 return m_monitorLastFullScreenSizeVector.value((int)uScreenId);
2076}
2077
2078void UISession::setLastFullScreenSize(ulong uScreenId, QSize size)
2079{
2080 /* Make sure index fits the bounds: */
2081 AssertReturnVoid(uScreenId < (ulong)m_monitorLastFullScreenSizeVector.size());
2082
2083 /* Remember last full-screen size: */
2084 m_monitorLastFullScreenSizeVector[(int)uScreenId] = size;
2085}
2086
2087int UISession::countOfVisibleWindows()
2088{
2089 int cCountOfVisibleWindows = 0;
2090 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
2091 if (m_monitorVisibilityVector[i])
2092 ++cCountOfVisibleWindows;
2093 return cCountOfVisibleWindows;
2094}
2095
2096QList<int> UISession::listOfVisibleWindows() const
2097{
2098 QList<int> visibleWindows;
2099 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
2100 if (m_monitorVisibilityVector.at(i))
2101 visibleWindows.push_back(i);
2102 return visibleWindows;
2103}
2104
2105void UISession::loadVMSettings()
2106{
2107 /* Load CPU hardware virtualization extension: */
2108 m_fIsHWVirtExEnabled = m_debugger.GetHWVirtExEnabled();
2109 /* Load nested-paging CPU hardware virtualization extension: */
2110 m_fIsHWVirtExNestedPagingEnabled = m_debugger.GetHWVirtExNestedPagingEnabled();
2111 /* Load whether the VM is currently making use of the unrestricted execution feature of VT-x: */
2112 m_fIsHWVirtExUXEnabled = m_debugger.GetHWVirtExUXEnabled();
2113 /* Load VM's effective paravirtualization provider: */
2114 m_paraVirtProvider = m_machine.GetEffectiveParavirtProvider();
2115}
2116
2117UIFrameBuffer* UISession::frameBuffer(ulong uScreenId) const
2118{
2119 Assert(uScreenId < (ulong)m_frameBufferVector.size());
2120 return m_frameBufferVector.value((int)uScreenId, 0);
2121}
2122
2123void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer* pFrameBuffer)
2124{
2125 Assert(uScreenId < (ulong)m_frameBufferVector.size());
2126 if (uScreenId < (ulong)m_frameBufferVector.size())
2127 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
2128}
2129
2130void UISession::updateHostScreenData()
2131{
2132 m_hostScreens.clear();
2133 for (int iScreenIndex = 0; iScreenIndex < gpDesktop->screenCount(); ++iScreenIndex)
2134 m_hostScreens << gpDesktop->screenGeometry(iScreenIndex);
2135}
2136
2137void UISession::updateActionRestrictions()
2138{
2139 /* Get host and prepare restrictions: */
2140 const CHost host = vboxGlobal().host();
2141 UIExtraDataMetaDefs::RuntimeMenuMachineActionType restrictionForMachine = UIExtraDataMetaDefs::RuntimeMenuMachineActionType_Invalid;
2142 UIExtraDataMetaDefs::RuntimeMenuViewActionType restrictionForView = UIExtraDataMetaDefs::RuntimeMenuViewActionType_Invalid;
2143 UIExtraDataMetaDefs::RuntimeMenuDevicesActionType restrictionForDevices = UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Invalid;
2144
2145 /* Separate process stuff: */
2146 {
2147 /* Initialize 'Machine' menu: */
2148 if (!vboxGlobal().isSeparateProcess())
2149 restrictionForMachine = (UIExtraDataMetaDefs::RuntimeMenuMachineActionType)(restrictionForMachine | UIExtraDataMetaDefs::RuntimeMenuMachineActionType_Detach);
2150 }
2151
2152 /* VRDE server stuff: */
2153 {
2154 /* Initialize 'View' menu: */
2155 const CVRDEServer server = machine().GetVRDEServer();
2156 if (server.isNull())
2157 restrictionForView = (UIExtraDataMetaDefs::RuntimeMenuViewActionType)(restrictionForView | UIExtraDataMetaDefs::RuntimeMenuViewActionType_VRDEServer);
2158 }
2159
2160 /* Storage stuff: */
2161 {
2162 /* Initialize CD/FD menus: */
2163 int iDevicesCountCD = 0;
2164 int iDevicesCountFD = 0;
2165 foreach (const CMediumAttachment &attachment, machine().GetMediumAttachments())
2166 {
2167 if (attachment.GetType() == KDeviceType_DVD)
2168 ++iDevicesCountCD;
2169 if (attachment.GetType() == KDeviceType_Floppy)
2170 ++iDevicesCountFD;
2171 }
2172 QAction *pOpticalDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices);
2173 QAction *pFloppyDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices);
2174 pOpticalDevicesMenu->setData(iDevicesCountCD);
2175 pFloppyDevicesMenu->setData(iDevicesCountFD);
2176 if (!iDevicesCountCD)
2177 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_OpticalDevices);
2178 if (!iDevicesCountFD)
2179 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_FloppyDevices);
2180 }
2181
2182 /* Audio stuff: */
2183 {
2184 /* Check whether audio controller is enabled. */
2185 const CAudioAdapter &comAdapter = machine().GetAudioAdapter();
2186 if (comAdapter.isNull() || !comAdapter.GetEnabled())
2187 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Audio);
2188 }
2189
2190 /* Network stuff: */
2191 {
2192 /* Initialize Network menu: */
2193 bool fAtLeastOneAdapterActive = false;
2194 const KChipsetType chipsetType = machine().GetChipsetType();
2195 ULONG uSlots = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(chipsetType);
2196 for (ULONG uSlot = 0; uSlot < uSlots; ++uSlot)
2197 {
2198 const CNetworkAdapter &adapter = machine().GetNetworkAdapter(uSlot);
2199 if (adapter.GetEnabled())
2200 {
2201 fAtLeastOneAdapterActive = true;
2202 break;
2203 }
2204 }
2205 if (!fAtLeastOneAdapterActive)
2206 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Network);
2207 }
2208
2209 /* USB stuff: */
2210 {
2211 /* Check whether there is at least one USB controller with an available proxy. */
2212 const bool fUSBEnabled = !machine().GetUSBDeviceFilters().isNull()
2213 && !machine().GetUSBControllers().isEmpty()
2214 && machine().GetUSBProxyAvailable();
2215 if (!fUSBEnabled)
2216 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_USBDevices);
2217 }
2218
2219 /* WebCams stuff: */
2220 {
2221 /* Check whether there is an accessible video input devices pool: */
2222 host.GetVideoInputDevices();
2223 const bool fWebCamsEnabled = host.isOk() && !machine().GetUSBControllers().isEmpty();
2224 if (!fWebCamsEnabled)
2225 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_WebCams);
2226 }
2227
2228 /* Apply cumulative restriction for 'Machine' menu: */
2229 actionPool()->toRuntime()->setRestrictionForMenuMachine(UIActionRestrictionLevel_Session, restrictionForMachine);
2230 /* Apply cumulative restriction for 'View' menu: */
2231 actionPool()->toRuntime()->setRestrictionForMenuView(UIActionRestrictionLevel_Session, restrictionForView);
2232 /* Apply cumulative restriction for 'Devices' menu: */
2233 actionPool()->toRuntime()->setRestrictionForMenuDevices(UIActionRestrictionLevel_Session, restrictionForDevices);
2234}
2235
2236#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
2237/**
2238 * Custom signal handler. When switching VTs, we might not get release events
2239 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
2240 * be saved with modifier keys stuck. This is annoying enough for introducing
2241 * this hack.
2242 */
2243/* static */
2244static void signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
2245{
2246 /* Only SIGUSR1 is interesting: */
2247 if (sig == SIGUSR1)
2248 if (gpMachine)
2249 gpMachine->uisession()->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
2250}
2251#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
2252
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