VirtualBox

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

Last change on this file since 63602 was 63602, checked in by vboxsync, 8 years ago

FE/Qt: when logging the Qt version, do it later in case we are a VM window because the release log file is created in Console::i_powerUp()

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