VirtualBox

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

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

FE/Qt: X11: LogRel for WM code.

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