VirtualBox

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

Last change on this file since 80576 was 80576, checked in by vboxsync, 5 years ago

FE/Qt: bugref:8938. Converting connection syntax of console events.

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