VirtualBox

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

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

FE/Qt: bugref:8438: UISession::setPointerShape Qt5 fixes for Windows host.

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