VirtualBox

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

Last change on this file since 52902 was 52902, checked in by vboxsync, 10 years ago

FE/Qt: Runtime UI rework/cleanup for 7115 (part #1): Cleanup for code touched by r96322.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.6 KB
Line 
1/* $Id: UISession.cpp 52902 2014-09-30 15:38:46Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISession class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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 <QDesktopWidget>
25# include <QWidget>
26# ifdef Q_WS_MAC
27# include <QTimer>
28# endif /* Q_WS_MAC */
29
30/* GUI includes: */
31# include "VBoxGlobal.h"
32# include "UIExtraDataManager.h"
33# include "UISession.h"
34# include "UIMachine.h"
35# include "UIMedium.h"
36# include "UIActionPoolRuntime.h"
37# include "UIMachineLogic.h"
38# include "UIMachineView.h"
39# include "UIMachineWindow.h"
40# include "UIMessageCenter.h"
41# include "UIPopupCenter.h"
42# include "UIWizardFirstRun.h"
43# include "UIConsoleEventHandler.h"
44# include "UIFrameBuffer.h"
45# include "UISettingsDialogSpecific.h"
46# ifdef VBOX_WITH_VIDEOHWACCEL
47# include "VBoxFBOverlay.h"
48# endif /* VBOX_WITH_VIDEOHWACCEL */
49# ifdef Q_WS_MAC
50# include "UIMenuBar.h"
51# include "VBoxUtils-darwin.h"
52# endif /* Q_WS_MAC */
53
54# ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
55# include "UIKeyboardHandler.h"
56# include <signal.h>
57# endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
58
59/* COM includes: */
60# include "CConsole.h"
61# include "CSystemProperties.h"
62# include "CMachineDebugger.h"
63# include "CGuest.h"
64# include "CStorageController.h"
65# include "CMediumAttachment.h"
66# include "CDisplay.h"
67# include "CMouse.h"
68# include "CNetworkAdapter.h"
69# include "CHostNetworkInterface.h"
70# include "CVRDEServer.h"
71# include "CUSBController.h"
72# include "CUSBDeviceFilters.h"
73# include "CHostVideoInputDevice.h"
74# include "CSnapshot.h"
75# include "CMedium.h"
76
77#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
78
79#ifdef Q_WS_X11
80# include <QX11Info>
81# include <X11/Xlib.h>
82# include <X11/Xutil.h>
83# ifndef VBOX_WITHOUT_XCURSOR
84# include <X11/Xcursor/Xcursor.h>
85# endif /* VBOX_WITHOUT_XCURSOR */
86#endif /* Q_WS_X11 */
87
88
89#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
90static void signalHandlerSIGUSR1(int sig, siginfo_t *, void *);
91#endif
92
93#ifdef Q_WS_MAC
94/**
95 * MacOS X: Application Services: Core Graphics: Display reconfiguration callback.
96 *
97 * Notifies UISession about @a display configuration change.
98 * Corresponding change described by Core Graphics @a flags.
99 * Uses UISession @a pHandler to process this change.
100 *
101 * @note Last argument (@a pHandler) must always be valid pointer to UISession object.
102 * @note Calls for UISession::sltHandleHostDisplayAboutToChange() slot if display configuration changed.
103 */
104void cgDisplayReconfigurationCallback(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *pHandler)
105{
106 /* Which flags we are handling? */
107 int iHandledFlags = kCGDisplayAddFlag /* display added */
108 | kCGDisplayRemoveFlag /* display removed */
109 | kCGDisplaySetModeFlag /* display mode changed */;
110
111 /* Handle 'display-add' case: */
112 if (flags & kCGDisplayAddFlag)
113 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display added.\n"));
114 /* Handle 'display-remove' case: */
115 else if (flags & kCGDisplayRemoveFlag)
116 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display removed.\n"));
117 /* Handle 'mode-set' case: */
118 else if (flags & kCGDisplaySetModeFlag)
119 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display mode changed.\n"));
120
121 /* Ask handler to process our callback: */
122 if (flags & iHandledFlags)
123 QTimer::singleShot(0, static_cast<UISession*>(pHandler),
124 SLOT(sltHandleHostDisplayAboutToChange()));
125
126 Q_UNUSED(display);
127}
128#endif /* Q_WS_MAC */
129
130UISession::UISession(UIMachine *pMachine, CSession &sessionReference)
131 : QObject(pMachine)
132 /* Base variables: */
133 , m_pMachine(pMachine)
134 , m_session(sessionReference)
135 , m_pActionPool(0)
136#ifdef Q_WS_MAC
137 , m_pMenuBar(0)
138#endif /* Q_WS_MAC */
139 /* Common variables: */
140 , m_machineStatePrevious(KMachineState_Null)
141 , m_machineState(session().GetMachine().GetState())
142#ifndef Q_WS_MAC
143 , m_pMachineWindowIcon(0)
144#endif /* !Q_WS_MAC */
145 , m_mouseCapturePolicy(MouseCapturePolicy_Default)
146 , m_guruMeditationHandlerType(GuruMeditationHandlerType_Default)
147 , m_hiDPIOptimizationType(HiDPIOptimizationType_None)
148 , m_requestedVisualStateType(UIVisualStateType_Invalid)
149#ifdef Q_WS_WIN
150 , m_alphaCursor(0)
151#endif /* Q_WS_WIN */
152#ifdef Q_WS_MAC
153 , m_pWatchdogDisplayChange(0)
154#endif /* Q_WS_MAC */
155 , m_defaultCloseAction(MachineCloseAction_Invalid)
156 , m_restrictedCloseActions(MachineCloseAction_Invalid)
157 , m_fAllCloseActionsRestricted(false)
158 /* Common flags: */
159 , m_fIsStarted(false)
160 , m_fIsFirstTimeStarted(false)
161 , m_fIsGuestResizeIgnored(false)
162 , m_fIsAutoCaptureDisabled(false)
163 /* Guest additions flags: */
164 , m_ulGuestAdditionsRunLevel(0)
165 , m_fIsGuestSupportsGraphics(false)
166 , m_fIsGuestSupportsSeamless(false)
167 /* Mouse flags: */
168 , m_fNumLock(false)
169 , m_fCapsLock(false)
170 , m_fScrollLock(false)
171 , m_uNumLockAdaptionCnt(2)
172 , m_uCapsLockAdaptionCnt(2)
173 /* Mouse flags: */
174 , m_fIsMouseSupportsAbsolute(false)
175 , m_fIsMouseSupportsRelative(false)
176 , m_fIsMouseSupportsMultiTouch(false)
177 , m_fIsMouseHostCursorNeeded(false)
178 , m_fIsMouseCaptured(false)
179 , m_fIsMouseIntegrated(true)
180 , m_fIsValidPointerShapePresent(false)
181 , m_fIsHidingHostPointer(true)
182{
183 /* Prepare actions: */
184 prepareActions();
185
186 /* Prepare connections: */
187 prepareConnections();
188
189 /* Prepare console event-handlers: */
190 prepareConsoleEventHandlers();
191
192 /* Prepare screens: */
193 prepareScreens();
194
195 /* Prepare framebuffers: */
196 prepareFramebuffers();
197
198 /* Load settings: */
199 loadSessionSettings();
200
201#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
202 struct sigaction sa;
203 sa.sa_sigaction = &signalHandlerSIGUSR1;
204 sigemptyset(&sa.sa_mask);
205 sa.sa_flags = SA_RESTART | SA_SIGINFO;
206 sigaction(SIGUSR1, &sa, NULL);
207#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
208}
209
210UISession::~UISession()
211{
212#ifdef Q_WS_WIN
213 /* Destroy alpha cursor: */
214 if (m_alphaCursor)
215 DestroyIcon(m_alphaCursor);
216#endif /* Q_WS_WIN */
217
218 /* Save settings: */
219 saveSessionSettings();
220
221 /* Cleanup framebuffers: */
222 cleanupFramebuffers();
223
224 /* Cleanup console event-handlers: */
225 cleanupConsoleEventHandlers();
226
227 /* Cleanup connections: */
228 cleanupConnections();
229
230 /* Cleanup actions: */
231 cleanupActions();
232}
233
234void UISession::powerUp()
235{
236 /* Prepare powerup: */
237 bool fPrepared = preparePowerUp();
238 if (!fPrepared)
239 return;
240
241 /* Get current machine/console: */
242 CMachine machine = session().GetMachine();
243 CConsole console = session().GetConsole();
244
245 /* Apply debug settings from the command line. */
246 CMachineDebugger debugger = console.GetDebugger();
247 if (debugger.isOk())
248 {
249 if (vboxGlobal().isPatmDisabled())
250 debugger.SetPATMEnabled(false);
251 if (vboxGlobal().isCsamDisabled())
252 debugger.SetCSAMEnabled(false);
253 if (vboxGlobal().isSupervisorCodeExecedRecompiled())
254 debugger.SetRecompileSupervisor(true);
255 if (vboxGlobal().isUserCodeExecedRecompiled())
256 debugger.SetRecompileUser(true);
257 if (vboxGlobal().areWeToExecuteAllInIem())
258 debugger.SetExecuteAllInIEM(true);
259 if (!vboxGlobal().isDefaultWarpPct())
260 debugger.SetVirtualTimeRate(vboxGlobal().getWarpPct());
261 }
262
263 if (!vboxGlobal().isSeparateProcess())
264 {
265 /* Power UP machine: */
266#ifdef VBOX_WITH_DEBUGGER_GUI
267 CProgress progress = vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled() ?
268 console.PowerUpPaused() : console.PowerUp();
269#else /* !VBOX_WITH_DEBUGGER_GUI */
270 CProgress progress = console.PowerUp();
271#endif /* !VBOX_WITH_DEBUGGER_GUI */
272
273 /* Check for immediate failure: */
274 if (!console.isOk())
275 {
276 if (vboxGlobal().showStartVMErrors())
277 msgCenter().cannotStartMachine(console, machine.GetName());
278 closeRuntimeUI();
279 return;
280 }
281
282 /* Guard progressbar warnings from auto-closing: */
283 if (uimachine()->machineLogic())
284 uimachine()->machineLogic()->setPreventAutoClose(true);
285
286 /* Show "Starting/Restoring" progress dialog: */
287 if (isSaved())
288 {
289 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_restore_90px.png", 0, 0);
290 /* After restoring from 'saved' state, machine-window(s) geometry should be adjusted: */
291 machineLogic()->adjustMachineWindowsGeometry();
292 }
293 else
294 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_start_90px.png");
295
296 /* Check for a progress failure: */
297 if (!progress.isOk() || progress.GetResultCode() != 0)
298 {
299 if (vboxGlobal().showStartVMErrors())
300 msgCenter().cannotStartMachine(progress, machine.GetName());
301 closeRuntimeUI();
302 return;
303 }
304
305 /* Allow further auto-closing: */
306 if (uimachine()->machineLogic())
307 uimachine()->machineLogic()->setPreventAutoClose(false);
308 }
309 else
310 {
311 /* Fetch the current state: */
312 CMouse mouse = console.GetMouse();
313 m_fIsMouseSupportsAbsolute = mouse.GetAbsoluteSupported();
314 m_fIsMouseSupportsRelative = mouse.GetRelativeSupported();
315 m_fIsMouseSupportsMultiTouch = mouse.GetMultiTouchSupported();
316 m_fIsMouseHostCursorNeeded = mouse.GetNeedsHostCursor();
317
318 sltAdditionsChange();
319 }
320
321 /* Check if we missed a really quick termination after successful startup, and process it if we did: */
322 if (isTurnedOff())
323 {
324 closeRuntimeUI();
325 return;
326 }
327
328 /* Check if the required virtualization features are active. We get this
329 * info only when the session is active. */
330 bool fIs64BitsGuest = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetIs64Bit();
331 bool fRecommendVirtEx = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetRecommendedVirtEx();
332 AssertMsg(!fIs64BitsGuest || fRecommendVirtEx, ("Virtualization support missed for 64bit guest!\n"));
333 bool fIsVirtEnabled = console.GetDebugger().GetHWVirtExEnabled();
334 if (fRecommendVirtEx && !fIsVirtEnabled)
335 {
336 bool fShouldWeClose;
337
338 bool fVTxAMDVSupported = vboxGlobal().host().GetProcessorFeature(KProcessorFeature_HWVirtEx);
339
340 QApplication::processEvents();
341 setPause(true);
342
343 if (fIs64BitsGuest)
344 fShouldWeClose = msgCenter().warnAboutVirtNotEnabled64BitsGuest(fVTxAMDVSupported);
345 else
346 fShouldWeClose = msgCenter().warnAboutVirtNotEnabledGuestRequired(fVTxAMDVSupported);
347
348 if (fShouldWeClose)
349 {
350 /* At this point the console is powered up. So we have to close
351 * this session again. */
352 CProgress progress = console.PowerDown();
353 if (console.isOk())
354 {
355 /* Guard progressbar warnings from auto-closing: */
356 if (uimachine()->machineLogic())
357 uimachine()->machineLogic()->setPreventAutoClose(true);
358 /* Show the power down progress dialog */
359 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_poweroff_90px.png");
360 if (!progress.isOk() || progress.GetResultCode() != 0)
361 msgCenter().cannotPowerDownMachine(progress, machine.GetName());
362 /* Allow further auto-closing: */
363 if (uimachine()->machineLogic())
364 uimachine()->machineLogic()->setPreventAutoClose(false);
365 }
366 else
367 msgCenter().cannotPowerDownMachine(console);
368 closeRuntimeUI();
369 return;
370 }
371
372 setPause(false);
373 }
374
375#ifdef VBOX_WITH_VIDEOHWACCEL
376 LogRel(("2D video acceleration is %s.\n",
377 machine.GetAccelerate2DVideoEnabled() && VBoxGlobal::isAcceleration2DVideoAvailable()
378 ? "enabled"
379 : "disabled"));
380#endif
381
382/* Check if HID LEDs sync is enabled and add a log message about it. */
383#if defined(Q_WS_MAC) || defined(Q_WS_WIN)
384 if(uimachine()->machineLogic()->isHidLedsSyncEnabled())
385 LogRel(("HID LEDs sync is enabled.\n"));
386 else
387 LogRel(("HID LEDs sync is disabled.\n"));
388#else
389 LogRel(("HID LEDs sync is not supported on this platform.\n"));
390#endif
391
392#ifdef VBOX_GUI_WITH_PIDFILE
393 vboxGlobal().createPidfile();
394#endif
395
396 /* Warn listeners about machine was started: */
397 emit sigStarted();
398}
399
400bool UISession::saveState()
401{
402 /* Prepare the saving progress: */
403 CMachine machine = m_session.GetMachine();
404 CConsole console = m_session.GetConsole();
405 CProgress progress = console.SaveState();
406 if (console.isOk())
407 {
408 /* Show the saving progress: */
409 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_save_90px.png");
410 if (!progress.isOk() || progress.GetResultCode() != 0)
411 {
412 /* Failed in progress: */
413 msgCenter().cannotSaveMachineState(progress, machine.GetName());
414 return false;
415 }
416 }
417 else
418 {
419 /* Failed in console: */
420 msgCenter().cannotSaveMachineState(console);
421 return false;
422 }
423 /* Passed: */
424 return true;
425}
426
427bool UISession::shutdown()
428{
429 /* Send ACPI shutdown signal if possible: */
430 CConsole console = m_session.GetConsole();
431 console.PowerButton();
432 if (!console.isOk())
433 {
434 /* Failed in console: */
435 msgCenter().cannotACPIShutdownMachine(console);
436 return false;
437 }
438 /* Passed: */
439 return true;
440}
441
442bool UISession::powerOff(bool fIncludingDiscard, bool &fServerCrashed)
443{
444 /* Prepare the power-off progress: */
445 CMachine machine = m_session.GetMachine();
446 CConsole console = m_session.GetConsole();
447 CProgress progress = console.PowerDown();
448 if (console.isOk())
449 {
450 /* Show the power-off progress: */
451 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_poweroff_90px.png");
452 if (progress.isOk() && progress.GetResultCode() == 0)
453 {
454 /* Discard the current state if requested: */
455 if (fIncludingDiscard)
456 {
457 /* Prepare the snapshot-discard progress: */
458 CSnapshot snapshot = machine.GetCurrentSnapshot();
459 CProgress progress = console.RestoreSnapshot(snapshot);
460 if (!console.isOk())
461 return msgCenter().cannotRestoreSnapshot(console, snapshot.GetName(), machine.GetName());
462
463 /* Show the snapshot-discard progress: */
464 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_snapshot_discard_90px.png");
465 if (progress.GetResultCode() != 0)
466 return msgCenter().cannotRestoreSnapshot(progress, snapshot.GetName(), machine.GetName());
467 }
468 }
469 else
470 {
471 /* Failed in progress: */
472 msgCenter().cannotPowerDownMachine(progress, machine.GetName());
473 return false;
474 }
475 }
476 else
477 {
478 /* Check the machine state, it might be already gone: */
479 if (!console.isNull())
480 {
481 /* Failed in console: */
482 COMResult res(console);
483 /* This can happen if VBoxSVC is not running: */
484 if (FAILED_DEAD_INTERFACE(res.rc()))
485 fServerCrashed = true;
486 else
487 msgCenter().cannotPowerDownMachine(console);
488 return false;
489 }
490 }
491 /* Passed: */
492 return true;
493}
494
495void UISession::closeRuntimeUI()
496{
497 /* Start corresponding slot asynchronously: */
498 emit sigCloseRuntimeUI();
499}
500
501UIMachineLogic* UISession::machineLogic() const
502{
503 return uimachine()->machineLogic();
504}
505
506QWidget* UISession::mainMachineWindow() const
507{
508 return machineLogic()->mainMachineWindow();
509}
510
511bool UISession::isVisualStateAllowed(UIVisualStateType state) const
512{
513 return m_pMachine->isVisualStateAllowed(state);
514}
515
516void UISession::changeVisualState(UIVisualStateType visualStateType)
517{
518 m_pMachine->asyncChangeVisualState(visualStateType);
519}
520
521bool UISession::setPause(bool fOn)
522{
523 CConsole console = session().GetConsole();
524 if (console.isNull())
525 return true;
526
527 if (fOn)
528 console.Pause();
529 else
530 console.Resume();
531
532 bool ok = console.isOk();
533 if (!ok)
534 {
535 if (fOn)
536 msgCenter().cannotPauseMachine(console);
537 else
538 msgCenter().cannotResumeMachine(console);
539 }
540
541 return ok;
542}
543
544void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
545{
546 /* This flag indicates whether we want to do the usual .ISO mounting or not.
547 * First try updating the Guest Additions directly without mounting the .ISO. */
548 bool fDoMount = false;
549
550 /* Auto-update in GUI currently is disabled. */
551#ifndef VBOX_WITH_ADDITIONS_AUTOUPDATE_UI
552 fDoMount = true;
553#else /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
554 CGuest guest = session().GetConsole().GetGuest();
555 QVector<KAdditionsUpdateFlag> aFlagsUpdate;
556 QVector<QString> aArgs;
557 CProgress progressInstall = guest.UpdateGuestAdditions(strSource,
558 aArgs, aFlagsUpdate);
559 bool fResult = guest.isOk();
560 if (fResult)
561 {
562 msgCenter().showModalProgressDialog(progressInstall, tr("Updating Guest Additions"),
563 ":/progress_install_guest_additions_90px.png",
564 0, 500 /* 500ms delay. */);
565 if (progressInstall.GetCanceled())
566 return;
567
568 HRESULT rc = progressInstall.GetResultCode();
569 if (!progressInstall.isOk() || rc != S_OK)
570 {
571 /* If we got back a VBOX_E_NOT_SUPPORTED we don't complain (guest OS
572 * simply isn't supported yet), so silently fall back to "old" .ISO
573 * mounting method. */
574 if ( !SUCCEEDED_WARNING(rc)
575 && rc != VBOX_E_NOT_SUPPORTED)
576 {
577 msgCenter().cannotUpdateGuestAdditions(progressInstall);
578
579 /* Log the error message in the release log. */
580 QString strErr = progressInstall.GetErrorInfo().GetText();
581 if (!strErr.isEmpty())
582 LogRel(("%s\n", strErr.toLatin1().constData()));
583 }
584 fDoMount = true; /* Since automatic updating failed, fall back to .ISO mounting. */
585 }
586 }
587#endif /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
588
589 /* Do we still want mounting? */
590 if (!fDoMount)
591 return;
592
593 /* Open corresponding medium: */
594 QString strMediumID;
595 CVirtualBox vbox = vboxGlobal().virtualBox();
596 CMedium image = vbox.OpenMedium(strSource, KDeviceType_DVD, KAccessMode_ReadWrite, false /* fForceNewUuid */);
597 if (vbox.isOk() && !image.isNull())
598 strMediumID = image.GetId();
599 else
600 {
601 msgCenter().cannotOpenMedium(vbox, UIMediumType_DVD, strSource, mainMachineWindow());
602 return;
603 }
604
605 /* Make sure GA medium ID is valid: */
606 AssertReturnVoid(!strMediumID.isNull());
607
608 /* Get machine: */
609 CMachine machine = session().GetMachine();
610
611 /* Searching for the first suitable controller/slot: */
612 QString strControllerName;
613 LONG iCntPort = -1, iCntDevice = -1;
614 foreach (const CStorageController &controller, machine.GetStorageControllers())
615 {
616 foreach (const CMediumAttachment &attachment, machine.GetMediumAttachmentsOfController(controller.GetName()))
617 {
618 if (attachment.GetType() == KDeviceType_DVD)
619 {
620 strControllerName = controller.GetName();
621 iCntPort = attachment.GetPort();
622 iCntDevice = attachment.GetDevice();
623 break;
624 }
625 }
626 if (!strControllerName.isNull())
627 break;
628 }
629
630 /* Make sure suitable controller/slot were found: */
631 if (strControllerName.isNull())
632 {
633 msgCenter().cannotMountGuestAdditions(machine.GetName());
634 return;
635 }
636
637 /* Try to find UIMedium among cached: */
638 UIMedium medium = vboxGlobal().medium(strMediumID);
639 if (medium.isNull())
640 {
641 /* Create new one if necessary: */
642 medium = UIMedium(image, UIMediumType_DVD, KMediumState_Created);
643 vboxGlobal().createMedium(medium);
644 }
645
646 /* Mount medium to corresponding controller/slot: */
647 machine.MountMedium(strControllerName, iCntPort, iCntDevice, medium.medium(), false /* force */);
648 if (!machine.isOk())
649 {
650 /* Ask for force mounting: */
651 if (msgCenter().cannotRemountMedium(machine, medium, true /* mount? */,
652 true /* retry? */, mainMachineWindow()))
653 {
654 /* Force mount medium to the predefined port/device: */
655 machine.MountMedium(strControllerName, iCntPort, iCntDevice, medium.medium(), true /* force */);
656 if (!machine.isOk())
657 msgCenter().cannotRemountMedium(machine, medium, true /* mount? */,
658 false /* retry? */, mainMachineWindow());
659 }
660 }
661}
662
663void UISession::sltCloseRuntimeUI()
664{
665 /* First, we have to hide any opened modal/popup widgets.
666 * They then should unlock their event-loops synchronously.
667 * If all such loops are unlocked, we can close Runtime UI: */
668 if (QWidget *pWidget = QApplication::activeModalWidget() ?
669 QApplication::activeModalWidget() :
670 QApplication::activePopupWidget() ?
671 QApplication::activePopupWidget() : 0)
672 {
673 /* First we should try to close this widget: */
674 pWidget->close();
675 /* If widget rejected the 'close-event' we can
676 * still hide it and hope it will behave correctly
677 * and unlock his event-loop if any: */
678 if (!pWidget->isHidden())
679 pWidget->hide();
680 /* Restart this slot asynchronously: */
681 emit sigCloseRuntimeUI();
682 return;
683 }
684
685 /* Finally close the Runtime UI: */
686 m_pMachine->deleteLater();
687}
688
689#ifdef RT_OS_DARWIN
690void UISession::sltHandleMenuBarConfigurationChange()
691{
692 /* Update Mac OS X menu-bar: */
693 updateMenu();
694}
695#endif /* RT_OS_DARWIN */
696
697void UISession::sltMousePointerShapeChange(bool fVisible, bool fAlpha, QPoint hotCorner, QSize size, QVector<uint8_t> shape)
698{
699 /* In case of shape data is present: */
700 if (shape.size() > 0)
701 {
702 /* We are ignoring visibility flag: */
703 m_fIsHidingHostPointer = false;
704
705 /* And updating current cursor shape: */
706 setPointerShape(shape.data(), fAlpha,
707 hotCorner.x(), hotCorner.y(),
708 size.width(), size.height());
709 }
710 /* In case of shape data is NOT present: */
711 else
712 {
713 /* Remember if we should hide the cursor: */
714 m_fIsHidingHostPointer = !fVisible;
715 }
716
717 /* Notify listeners about mouse capability changed: */
718 emit sigMousePointerShapeChange();
719
720}
721
722void UISession::sltMouseCapabilityChange(bool fSupportsAbsolute, bool fSupportsRelative, bool fSupportsMultiTouch, bool fNeedsHostCursor)
723{
724 LogRelFlow(("UISession::sltMouseCapabilityChange: "
725 "Supports absolute: %s, Supports relative: %s, "
726 "Supports multi-touch: %s, Needs host cursor: %s\n",
727 fSupportsAbsolute ? "TRUE" : "FALSE", fSupportsRelative ? "TRUE" : "FALSE",
728 fSupportsMultiTouch ? "TRUE" : "FALSE", fNeedsHostCursor ? "TRUE" : "FALSE"));
729
730 /* Check if something had changed: */
731 if ( m_fIsMouseSupportsAbsolute != fSupportsAbsolute
732 || m_fIsMouseSupportsRelative != fSupportsRelative
733 || m_fIsMouseSupportsMultiTouch != fSupportsMultiTouch
734 || m_fIsMouseHostCursorNeeded != fNeedsHostCursor)
735 {
736 /* Store new data: */
737 m_fIsMouseSupportsAbsolute = fSupportsAbsolute;
738 m_fIsMouseSupportsRelative = fSupportsRelative;
739 m_fIsMouseSupportsMultiTouch = fSupportsMultiTouch;
740 m_fIsMouseHostCursorNeeded = fNeedsHostCursor;
741
742 /* Notify listeners about mouse capability changed: */
743 emit sigMouseCapabilityChange();
744 }
745}
746
747void UISession::sltKeyboardLedsChangeEvent(bool fNumLock, bool fCapsLock, bool fScrollLock)
748{
749 /* Check if something had changed: */
750 if ( m_fNumLock != fNumLock
751 || m_fCapsLock != fCapsLock
752 || m_fScrollLock != fScrollLock)
753 {
754 /* Store new num lock data: */
755 if (m_fNumLock != fNumLock)
756 {
757 m_fNumLock = fNumLock;
758 m_uNumLockAdaptionCnt = 2;
759 }
760
761 /* Store new caps lock data: */
762 if (m_fCapsLock != fCapsLock)
763 {
764 m_fCapsLock = fCapsLock;
765 m_uCapsLockAdaptionCnt = 2;
766 }
767
768 /* Store new scroll lock data: */
769 if (m_fScrollLock != fScrollLock)
770 {
771 m_fScrollLock = fScrollLock;
772 }
773
774 /* Notify listeners about mouse capability changed: */
775 emit sigKeyboardLedsChange();
776 }
777}
778
779void UISession::sltStateChange(KMachineState state)
780{
781 /* Check if something had changed: */
782 if (m_machineState != state)
783 {
784 /* Store new data: */
785 m_machineStatePrevious = m_machineState;
786 m_machineState = state;
787
788 /* Notify listeners about machine state changed: */
789 emit sigMachineStateChange();
790 }
791}
792
793void UISession::sltVRDEChange()
794{
795 /* Get machine: */
796 const CMachine machine = session().GetMachine();
797 /* Get VRDE server: */
798 const CVRDEServer &server = machine.GetVRDEServer();
799 bool fIsVRDEServerAvailable = !server.isNull();
800 /* Show/Hide VRDE action depending on VRDE server availability status: */
801 // TODO: Is this status can be changed at runtime?
802 // Because if no => the place for that stuff is in prepareActions().
803 actionPool()->action(UIActionIndexRT_M_Devices_T_VRDEServer)->setVisible(fIsVRDEServerAvailable);
804 /* Check/Uncheck VRDE action depending on VRDE server activity status: */
805 if (fIsVRDEServerAvailable)
806 actionPool()->action(UIActionIndexRT_M_Devices_T_VRDEServer)->setChecked(server.GetEnabled());
807 /* Notify listeners about VRDE change: */
808 emit sigVRDEChange();
809}
810
811void UISession::sltVideoCaptureChange()
812{
813 /* Get machine: */
814 const CMachine machine = session().GetMachine();
815 /* Check/Uncheck Video Capture action depending on feature status: */
816 actionPool()->action(UIActionIndexRT_M_Devices_M_VideoCapture_T_Start)->setChecked(machine.GetVideoCaptureEnabled());
817 /* Notify listeners about Video Capture change: */
818 emit sigVideoCaptureChange();
819}
820
821void UISession::sltGuestMonitorChange(KGuestMonitorChangedEventType changeType, ulong uScreenId, QRect screenGeo)
822{
823 /* Ignore KGuestMonitorChangedEventType_NewOrigin change event: */
824 if (changeType == KGuestMonitorChangedEventType_NewOrigin)
825 return;
826 /* Ignore KGuestMonitorChangedEventType_Disabled event for primary screen: */
827 AssertMsg(countOfVisibleWindows() > 0, ("All machine windows are hidden!"));
828 if (changeType == KGuestMonitorChangedEventType_Disabled && uScreenId == 0)
829 return;
830
831 /* Process KGuestMonitorChangedEventType_Enabled change event: */
832 if ( !isScreenVisible(uScreenId)
833 && changeType == KGuestMonitorChangedEventType_Enabled)
834 setScreenVisible(uScreenId, true);
835 /* Process KGuestMonitorChangedEventType_Disabled change event: */
836 else if ( isScreenVisible(uScreenId)
837 && changeType == KGuestMonitorChangedEventType_Disabled)
838 setScreenVisible(uScreenId, false);
839
840 /* Notify listeners about the change: */
841 emit sigGuestMonitorChange(changeType, uScreenId, screenGeo);
842}
843
844#ifdef RT_OS_DARWIN
845/**
846 * MacOS X: Restarts display-reconfiguration watchdog timer from the beginning.
847 * @note Watchdog is trying to determine display reconfiguration in
848 * UISession::sltCheckIfHostDisplayChanged() slot every 500ms for 40 tries.
849 */
850void UISession::sltHandleHostDisplayAboutToChange()
851{
852 LogRelFlow(("UISession::sltHandleHostDisplayAboutToChange()\n"));
853
854 if (m_pWatchdogDisplayChange->isActive())
855 m_pWatchdogDisplayChange->stop();
856 m_pWatchdogDisplayChange->setProperty("tryNumber", 1);
857 m_pWatchdogDisplayChange->start();
858}
859
860/**
861 * MacOS X: Determines display reconfiguration.
862 * @note Calls for UISession::sltHandleHostScreenCountChange() if screen count changed.
863 * @note Calls for UISession::sltHandleHostScreenGeometryChange() if screen geometry changed.
864 */
865void UISession::sltCheckIfHostDisplayChanged()
866{
867 LogRelFlow(("UISession::sltCheckIfHostDisplayChanged()\n"));
868
869 /* Acquire desktop wrapper: */
870 QDesktopWidget *pDesktop = QApplication::desktop();
871
872 /* Check if display count changed: */
873 if (pDesktop->screenCount() != m_hostScreens.size())
874 {
875 /* Reset watchdog: */
876 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
877 /* Notify listeners about screen-count changed: */
878 return sltHandleHostScreenCountChange();
879 }
880 else
881 {
882 /* Check if at least one display geometry changed: */
883 for (int iScreenIndex = 0; iScreenIndex < pDesktop->screenCount(); ++iScreenIndex)
884 {
885 if (pDesktop->screenGeometry(iScreenIndex) != m_hostScreens.at(iScreenIndex))
886 {
887 /* Reset watchdog: */
888 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
889 /* Notify listeners about screen-geometry changed: */
890 return sltHandleHostScreenGeometryChange();
891 }
892 }
893 }
894
895 /* Check if watchdog expired, restart if not: */
896 int cTryNumber = m_pWatchdogDisplayChange->property("tryNumber").toInt();
897 if (cTryNumber > 0 && cTryNumber < 40)
898 {
899 /* Restart watchdog again: */
900 m_pWatchdogDisplayChange->setProperty("tryNumber", ++cTryNumber);
901 m_pWatchdogDisplayChange->start();
902 }
903 else
904 {
905 /* Reset watchdog: */
906 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
907 }
908}
909#endif /* RT_OS_DARWIN */
910
911void UISession::sltHandleHostScreenCountChange()
912{
913 LogRelFlow(("UISession: Host-screen count changed.\n"));
914
915 /* Recache display data: */
916 updateHostScreenData();
917
918 /* Notify current machine-logic: */
919 emit sigHostScreenCountChange();
920}
921
922void UISession::sltHandleHostScreenGeometryChange()
923{
924 LogRelFlow(("UISession: Host-screen geometry changed.\n"));
925
926 /* Recache display data: */
927 updateHostScreenData();
928
929 /* Notify current machine-logic: */
930 emit sigHostScreenGeometryChange();
931}
932
933void UISession::sltHandleHostScreenAvailableAreaChange()
934{
935 LogRelFlow(("UISession: Host-screen available-area changed.\n"));
936
937 /* Notify current machine-logic: */
938 emit sigHostScreenAvailableAreaChange();
939}
940
941void UISession::sltAdditionsChange()
942{
943 /* Get our guest: */
944 CGuest guest = session().GetConsole().GetGuest();
945
946 /* Variable flags: */
947 ULONG ulGuestAdditionsRunLevel = guest.GetAdditionsRunLevel();
948 LONG64 lLastUpdatedIgnored;
949 bool fIsGuestSupportsGraphics = guest.GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
950 == KAdditionsFacilityStatus_Active;
951 bool fIsGuestSupportsSeamless = guest.GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
952 == KAdditionsFacilityStatus_Active;
953 /* Check if something had changed: */
954 if (m_ulGuestAdditionsRunLevel != ulGuestAdditionsRunLevel ||
955 m_fIsGuestSupportsGraphics != fIsGuestSupportsGraphics ||
956 m_fIsGuestSupportsSeamless != fIsGuestSupportsSeamless)
957 {
958 /* Store new data: */
959 m_ulGuestAdditionsRunLevel = ulGuestAdditionsRunLevel;
960 m_fIsGuestSupportsGraphics = fIsGuestSupportsGraphics;
961 m_fIsGuestSupportsSeamless = fIsGuestSupportsSeamless;
962
963 /* Notify listeners about guest additions state changed: */
964 emit sigAdditionsStateChange();
965 }
966}
967
968void UISession::prepareConsoleEventHandlers()
969{
970 /* Initialize console event-handler: */
971 UIConsoleEventHandler::instance(this);
972
973 /* Add console event connections: */
974 connect(gConsoleEvents, SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
975 this, SLOT(sltMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)));
976
977 connect(gConsoleEvents, SIGNAL(sigMouseCapabilityChange(bool, bool, bool, bool)),
978 this, SLOT(sltMouseCapabilityChange(bool, bool, bool, bool)));
979
980 connect(gConsoleEvents, SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
981 this, SLOT(sltKeyboardLedsChangeEvent(bool, bool, bool)));
982
983 connect(gConsoleEvents, SIGNAL(sigStateChange(KMachineState)),
984 this, SLOT(sltStateChange(KMachineState)));
985
986 connect(gConsoleEvents, SIGNAL(sigAdditionsChange()),
987 this, SLOT(sltAdditionsChange()));
988
989 connect(gConsoleEvents, SIGNAL(sigVRDEChange()),
990 this, SLOT(sltVRDEChange()));
991
992 connect(gConsoleEvents, SIGNAL(sigVideoCaptureChange()),
993 this, SLOT(sltVideoCaptureChange()));
994
995 connect(gConsoleEvents, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
996 this, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)));
997
998 connect(gConsoleEvents, SIGNAL(sigMediumChange(CMediumAttachment)),
999 this, SIGNAL(sigMediumChange(CMediumAttachment)));
1000
1001 connect(gConsoleEvents, SIGNAL(sigUSBControllerChange()),
1002 this, SIGNAL(sigUSBControllerChange()));
1003
1004 connect(gConsoleEvents, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
1005 this, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)));
1006
1007 connect(gConsoleEvents, SIGNAL(sigSharedFolderChange()),
1008 this, SIGNAL(sigSharedFolderChange()));
1009
1010 connect(gConsoleEvents, SIGNAL(sigRuntimeError(bool, QString, QString)),
1011 this, SIGNAL(sigRuntimeError(bool, QString, QString)));
1012
1013#ifdef Q_WS_MAC
1014 connect(gConsoleEvents, SIGNAL(sigShowWindow()),
1015 this, SIGNAL(sigShowWindows()), Qt::QueuedConnection);
1016#endif /* Q_WS_MAC */
1017
1018 connect(gConsoleEvents, SIGNAL(sigCPUExecutionCapChange()),
1019 this, SIGNAL(sigCPUExecutionCapChange()));
1020
1021 connect(gConsoleEvents, SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
1022 this, SLOT(sltGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)));
1023}
1024
1025void UISession::prepareActions()
1026{
1027 /* Create action-pool: */
1028 m_pActionPool = UIActionPool::create(UIActionPoolType_Runtime);
1029 m_pActionPool->toRuntime()->setSession(this);
1030
1031 /* Get host/machine: */
1032 const CHost host = vboxGlobal().host();
1033 const CMachine machine = session().GetConsole().GetMachine();
1034 UIExtraDataMetaDefs::RuntimeMenuDevicesActionType restriction = UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Invalid;
1035
1036 /* Storage stuff: */
1037 {
1038 /* Initialize CD/FD menus: */
1039 int iDevicesCountCD = 0;
1040 int iDevicesCountFD = 0;
1041 foreach (const CMediumAttachment &attachment, machine.GetMediumAttachments())
1042 {
1043 if (attachment.GetType() == KDeviceType_DVD)
1044 ++iDevicesCountCD;
1045 if (attachment.GetType() == KDeviceType_Floppy)
1046 ++iDevicesCountFD;
1047 }
1048 QAction *pOpticalDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices);
1049 QAction *pFloppyDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices);
1050 pOpticalDevicesMenu->setData(iDevicesCountCD);
1051 pFloppyDevicesMenu->setData(iDevicesCountFD);
1052 if (!iDevicesCountCD)
1053 restriction = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restriction | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_OpticalDevices);
1054 if (!iDevicesCountFD)
1055 restriction = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restriction | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_FloppyDevices);
1056 }
1057
1058 /* Network stuff: */
1059 {
1060 /* Initialize Network menu: */
1061 bool fAtLeastOneAdapterActive = false;
1062 const KChipsetType chipsetType = machine.GetChipsetType();
1063 ULONG uSlots = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(chipsetType);
1064 for (ULONG uSlot = 0; uSlot < uSlots; ++uSlot)
1065 {
1066 const CNetworkAdapter &adapter = machine.GetNetworkAdapter(uSlot);
1067 if (adapter.GetEnabled())
1068 {
1069 fAtLeastOneAdapterActive = true;
1070 break;
1071 }
1072 }
1073 if (!fAtLeastOneAdapterActive)
1074 restriction = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restriction | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Network);
1075 }
1076
1077 /* USB stuff: */
1078 {
1079 /* Check whether there is at least one USB controller with an available proxy. */
1080 const bool fUSBEnabled = !machine.GetUSBDeviceFilters().isNull()
1081 && !machine.GetUSBControllers().isEmpty()
1082 && machine.GetUSBProxyAvailable();
1083 if (!fUSBEnabled)
1084 restriction = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restriction | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_USBDevices);
1085 }
1086
1087 /* WebCams stuff: */
1088 {
1089 /* Check whether there is an accessible video input devices pool: */
1090 host.GetVideoInputDevices();
1091 const bool fWebCamsEnabled = host.isOk() && !machine.GetUSBControllers().isEmpty();
1092 if (!fWebCamsEnabled)
1093 restriction = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restriction | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_WebCams);
1094 }
1095
1096 /* Apply cumulative restriction: */
1097 actionPool()->toRuntime()->setRestrictionForMenuDevices(UIActionRestrictionLevel_Session, restriction);
1098
1099#ifdef Q_WS_MAC
1100 /* Create Mac OS X menu-bar: */
1101 m_pMenuBar = new UIMenuBar;
1102 AssertPtrReturnVoid(m_pMenuBar);
1103 {
1104 /* Configure Mac OS X menu-bar: */
1105 connect(gEDataManager, SIGNAL(sigMenuBarConfigurationChange()),
1106 this, SLOT(sltHandleMenuBarConfigurationChange()));
1107 /* Update Mac OS X menu-bar: */
1108 updateMenu();
1109 }
1110#endif /* Q_WS_MAC */
1111}
1112
1113void UISession::prepareConnections()
1114{
1115 connect(this, SIGNAL(sigStarted()), this, SLOT(sltMarkStarted()));
1116 connect(this, SIGNAL(sigCloseRuntimeUI()), this, SLOT(sltCloseRuntimeUI()));
1117
1118#ifdef Q_WS_MAC
1119 /* Install native display reconfiguration callback: */
1120 CGDisplayRegisterReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1121#else /* !Q_WS_MAC */
1122 /* Install Qt display reconfiguration callbacks: */
1123 connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)),
1124 this, SLOT(sltHandleHostScreenCountChange()));
1125 connect(QApplication::desktop(), SIGNAL(resized(int)),
1126 this, SLOT(sltHandleHostScreenGeometryChange()));
1127 connect(QApplication::desktop(), SIGNAL(workAreaResized(int)),
1128 this, SLOT(sltHandleHostScreenAvailableAreaChange()));
1129#endif /* !Q_WS_MAC */
1130}
1131
1132void UISession::prepareScreens()
1133{
1134 /* Recache display data: */
1135 updateHostScreenData();
1136
1137#ifdef Q_WS_MAC
1138 /* Prepare display-change watchdog: */
1139 m_pWatchdogDisplayChange = new QTimer(this);
1140 {
1141 m_pWatchdogDisplayChange->setInterval(500);
1142 m_pWatchdogDisplayChange->setSingleShot(true);
1143 connect(m_pWatchdogDisplayChange, SIGNAL(timeout()),
1144 this, SLOT(sltCheckIfHostDisplayChanged()));
1145 }
1146#endif /* Q_WS_MAC */
1147
1148 /* Get machine: */
1149 CMachine machine = m_session.GetMachine();
1150
1151 /* Prepare initial screen visibility status: */
1152 m_monitorVisibilityVector.resize(machine.GetMonitorCount());
1153 m_monitorVisibilityVector.fill(false);
1154 m_monitorVisibilityVector[0] = true;
1155
1156 /* If machine is in 'saved' state: */
1157 if (isSaved())
1158 {
1159 /* Update screen visibility status from saved-state: */
1160 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
1161 {
1162 BOOL fEnabled = true;
1163 ULONG guestOriginX = 0, guestOriginY = 0, guestWidth = 0, guestHeight = 0;
1164 machine.QuerySavedGuestScreenInfo(i, guestOriginX, guestOriginY, guestWidth, guestHeight, fEnabled);
1165 m_monitorVisibilityVector[i] = fEnabled;
1166 }
1167 /* And make sure at least one of them is visible (primary if others are hidden): */
1168 if (countOfVisibleWindows() < 1)
1169 m_monitorVisibilityVector[0] = true;
1170 }
1171}
1172
1173void UISession::prepareFramebuffers()
1174{
1175 /* Each framebuffer will be really prepared on first UIMachineView creation: */
1176 m_frameBufferVector.resize(m_session.GetMachine().GetMonitorCount());
1177}
1178
1179void UISession::loadSessionSettings()
1180{
1181 /* Load extra-data settings: */
1182 {
1183 /* Get machine ID: */
1184 const QString strMachineID = vboxGlobal().managedVMUuid();
1185
1186#ifndef Q_WS_MAC
1187 /* Load/prepare user's machine-window icon: */
1188 QIcon icon;
1189 foreach (const QString &strIconName, gEDataManager->machineWindowIconNames(strMachineID))
1190 if (!strIconName.isEmpty())
1191 icon.addFile(strIconName);
1192 if (!icon.isNull())
1193 m_pMachineWindowIcon = new QIcon(icon);
1194
1195 /* Load user's machine-window name postfix: */
1196 m_strMachineWindowNamePostfix = gEDataManager->machineWindowNamePostfix(strMachineID);
1197#endif /* !Q_WS_MAC */
1198
1199 /* Determine mouse-capture policy: */
1200 m_mouseCapturePolicy = gEDataManager->mouseCapturePolicy(strMachineID);
1201
1202 /* Determine Guru Meditation handler type: */
1203 m_guruMeditationHandlerType = gEDataManager->guruMeditationHandlerType(strMachineID);
1204
1205 /* Determine HiDPI optimization type: */
1206 m_hiDPIOptimizationType = gEDataManager->hiDPIOptimizationType(strMachineID);
1207
1208 /* Is there should be First RUN Wizard? */
1209 m_fIsFirstTimeStarted = gEDataManager->machineFirstTimeStarted(strMachineID);
1210
1211 /* Should guest autoresize? */
1212 QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1213 pGuestAutoresizeSwitch->setChecked(gEDataManager->guestScreenAutoResizeEnabled(strMachineID));
1214
1215 /* Menu-bar options: */
1216 {
1217 const bool fEnabledGlobally = !vboxGlobal().settings().isFeatureActive("noMenuBar");
1218 const bool fEnabledForMachine = gEDataManager->menuBarEnabled(strMachineID);
1219 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1220 QAction *pActionMenuBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_S_Settings);
1221 pActionMenuBarSettings->setEnabled(fEnabled);
1222 QAction *pActionMenuBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_T_Visibility);
1223 pActionMenuBarSwitch->blockSignals(true);
1224 pActionMenuBarSwitch->setChecked(fEnabled);
1225 pActionMenuBarSwitch->blockSignals(false);
1226 }
1227
1228 /* Status-bar options: */
1229 {
1230 const bool fEnabledGlobally = !vboxGlobal().settings().isFeatureActive("noStatusBar");
1231 const bool fEnabledForMachine = gEDataManager->statusBarEnabled(strMachineID);
1232 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1233 QAction *pActionStatusBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_S_Settings);
1234 pActionStatusBarSettings->setEnabled(fEnabled);
1235 QAction *pActionStatusBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility);
1236 pActionStatusBarSwitch->blockSignals(true);
1237 pActionStatusBarSwitch->setChecked(fEnabled);
1238 pActionStatusBarSwitch->blockSignals(false);
1239 }
1240
1241 /* What is the default close action and the restricted are? */
1242 m_defaultCloseAction = gEDataManager->defaultMachineCloseAction(strMachineID);
1243 m_restrictedCloseActions = gEDataManager->restrictedMachineCloseActions(strMachineID);
1244 m_fAllCloseActionsRestricted = (m_restrictedCloseActions & MachineCloseAction_SaveState)
1245 && (m_restrictedCloseActions & MachineCloseAction_Shutdown)
1246 && (m_restrictedCloseActions & MachineCloseAction_PowerOff);
1247 // Close VM Dialog hides PowerOff_RestoringSnapshot implicitly if PowerOff is hidden..
1248 // && (m_restrictedCloseActions & MachineCloseAction_PowerOff_RestoringSnapshot);
1249 }
1250}
1251
1252void UISession::saveSessionSettings()
1253{
1254 /* Save extra-data settings: */
1255 {
1256 /* Disable First RUN Wizard: */
1257 gEDataManager->setMachineFirstTimeStarted(false, vboxGlobal().managedVMUuid());
1258
1259 /* Remember if guest should autoresize: */
1260 gEDataManager->setGuestScreenAutoResizeEnabled(actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize)->isChecked(), vboxGlobal().managedVMUuid());
1261
1262#ifndef Q_WS_MAC
1263 /* Cleanup user's machine-window icon: */
1264 delete m_pMachineWindowIcon;
1265 m_pMachineWindowIcon = 0;
1266#endif /* !Q_WS_MAC */
1267 }
1268}
1269
1270void UISession::cleanupFramebuffers()
1271{
1272 /* Cleanup framebuffers finally: */
1273 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
1274 {
1275 UIFrameBuffer *pFb = m_frameBufferVector[i];
1276 if (pFb)
1277 {
1278 /* Mark framebuffer as unused: */
1279 pFb->setMarkAsUnused(true);
1280 /* Detach framebuffer from Display: */
1281 CDisplay display = session().GetConsole().GetDisplay();
1282 if (!display.isNull())
1283 display.DetachFramebuffer(i);
1284 /* Release framebuffer reference: */
1285 m_frameBufferVector[i].setNull();
1286 }
1287 }
1288 m_frameBufferVector.clear();
1289}
1290
1291void UISession::cleanupConsoleEventHandlers()
1292{
1293 /* Destroy console event-handler: */
1294 UIConsoleEventHandler::destroy();
1295}
1296
1297void UISession::cleanupConnections()
1298{
1299#ifdef Q_WS_MAC
1300 /* Remove display reconfiguration callback: */
1301 CGDisplayRemoveReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1302#endif /* Q_WS_MAC */
1303}
1304
1305void UISession::cleanupActions()
1306{
1307#ifdef Q_WS_MAC
1308 delete m_pMenuBar;
1309 m_pMenuBar = 0;
1310#endif /* Q_WS_MAC */
1311
1312 /* Destroy action-pool: */
1313 UIActionPool::destroy(m_pActionPool);
1314}
1315
1316#ifdef Q_WS_MAC
1317void UISession::updateMenu()
1318{
1319 /* Rebuild Mac OS X menu-bar: */
1320 m_pMenuBar->clear();
1321 foreach (QMenu *pMenu, actionPool()->menus())
1322 {
1323 UIMenu *pMenuUI = qobject_cast<UIMenu*>(pMenu);
1324 if (!pMenuUI->isConsumable() || !pMenuUI->isConsumed())
1325 m_pMenuBar->addMenu(pMenuUI);
1326 if (pMenuUI->isConsumable() && !pMenuUI->isConsumed())
1327 pMenuUI->setConsumed(true);
1328 }
1329}
1330#endif /* Q_WS_MAC */
1331
1332WId UISession::winId() const
1333{
1334 return mainMachineWindow()->winId();
1335}
1336
1337void UISession::setPointerShape(const uchar *pShapeData, bool fHasAlpha,
1338 uint uXHot, uint uYHot, uint uWidth, uint uHeight)
1339{
1340 AssertMsg(pShapeData, ("Shape data must not be NULL!\n"));
1341
1342 m_fIsValidPointerShapePresent = false;
1343 const uchar *srcAndMaskPtr = pShapeData;
1344 uint andMaskSize = (uWidth + 7) / 8 * uHeight;
1345 const uchar *srcShapePtr = pShapeData + ((andMaskSize + 3) & ~3);
1346 uint srcShapePtrScan = uWidth * 4;
1347
1348#if defined (Q_WS_WIN)
1349
1350 BITMAPV5HEADER bi;
1351 HBITMAP hBitmap;
1352 void *lpBits;
1353
1354 ::ZeroMemory(&bi, sizeof (BITMAPV5HEADER));
1355 bi.bV5Size = sizeof(BITMAPV5HEADER);
1356 bi.bV5Width = uWidth;
1357 bi.bV5Height = - (LONG)uHeight;
1358 bi.bV5Planes = 1;
1359 bi.bV5BitCount = 32;
1360 bi.bV5Compression = BI_BITFIELDS;
1361 bi.bV5RedMask = 0x00FF0000;
1362 bi.bV5GreenMask = 0x0000FF00;
1363 bi.bV5BlueMask = 0x000000FF;
1364 if (fHasAlpha)
1365 bi.bV5AlphaMask = 0xFF000000;
1366 else
1367 bi.bV5AlphaMask = 0;
1368
1369 HDC hdc = GetDC(NULL);
1370
1371 /* Create the DIB section with an alpha channel: */
1372 hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD) 0);
1373
1374 ReleaseDC(NULL, hdc);
1375
1376 HBITMAP hMonoBitmap = NULL;
1377 if (fHasAlpha)
1378 {
1379 /* Create an empty mask bitmap: */
1380 hMonoBitmap = CreateBitmap(uWidth, uHeight, 1, 1, NULL);
1381 }
1382 else
1383 {
1384 /* Word aligned AND mask. Will be allocated and created if necessary. */
1385 uint8_t *pu8AndMaskWordAligned = NULL;
1386
1387 /* Width in bytes of the original AND mask scan line. */
1388 uint32_t cbAndMaskScan = (uWidth + 7) / 8;
1389
1390 if (cbAndMaskScan & 1)
1391 {
1392 /* Original AND mask is not word aligned. */
1393
1394 /* Allocate memory for aligned AND mask. */
1395 pu8AndMaskWordAligned = (uint8_t *)RTMemTmpAllocZ((cbAndMaskScan + 1) * uHeight);
1396
1397 Assert(pu8AndMaskWordAligned);
1398
1399 if (pu8AndMaskWordAligned)
1400 {
1401 /* According to MSDN the padding bits must be 0.
1402 * Compute the bit mask to set padding bits to 0 in the last byte of original AND mask. */
1403 uint32_t u32PaddingBits = cbAndMaskScan * 8 - uWidth;
1404 Assert(u32PaddingBits < 8);
1405 uint8_t u8LastBytesPaddingMask = (uint8_t)(0xFF << u32PaddingBits);
1406
1407 Log(("u8LastBytesPaddingMask = %02X, aligned w = %d, width = %d, cbAndMaskScan = %d\n",
1408 u8LastBytesPaddingMask, (cbAndMaskScan + 1) * 8, uWidth, cbAndMaskScan));
1409
1410 uint8_t *src = (uint8_t *)srcAndMaskPtr;
1411 uint8_t *dst = pu8AndMaskWordAligned;
1412
1413 unsigned i;
1414 for (i = 0; i < uHeight; i++)
1415 {
1416 memcpy(dst, src, cbAndMaskScan);
1417
1418 dst[cbAndMaskScan - 1] &= u8LastBytesPaddingMask;
1419
1420 src += cbAndMaskScan;
1421 dst += cbAndMaskScan + 1;
1422 }
1423 }
1424 }
1425
1426 /* Create the AND mask bitmap: */
1427 hMonoBitmap = ::CreateBitmap(uWidth, uHeight, 1, 1,
1428 pu8AndMaskWordAligned? pu8AndMaskWordAligned: srcAndMaskPtr);
1429
1430 if (pu8AndMaskWordAligned)
1431 {
1432 RTMemTmpFree(pu8AndMaskWordAligned);
1433 }
1434 }
1435
1436 Assert(hBitmap);
1437 Assert(hMonoBitmap);
1438 if (hBitmap && hMonoBitmap)
1439 {
1440 DWORD *dstShapePtr = (DWORD *) lpBits;
1441
1442 for (uint y = 0; y < uHeight; y ++)
1443 {
1444 memcpy(dstShapePtr, srcShapePtr, srcShapePtrScan);
1445 srcShapePtr += srcShapePtrScan;
1446 dstShapePtr += uWidth;
1447 }
1448
1449 ICONINFO ii;
1450 ii.fIcon = FALSE;
1451 ii.xHotspot = uXHot;
1452 ii.yHotspot = uYHot;
1453 ii.hbmMask = hMonoBitmap;
1454 ii.hbmColor = hBitmap;
1455
1456 HCURSOR hAlphaCursor = CreateIconIndirect(&ii);
1457 Assert(hAlphaCursor);
1458 if (hAlphaCursor)
1459 {
1460 /* Set the new cursor: */
1461 m_cursor = QCursor(hAlphaCursor);
1462 if (m_alphaCursor)
1463 DestroyIcon(m_alphaCursor);
1464 m_alphaCursor = hAlphaCursor;
1465 m_fIsValidPointerShapePresent = true;
1466 }
1467 }
1468
1469 if (hMonoBitmap)
1470 DeleteObject(hMonoBitmap);
1471 if (hBitmap)
1472 DeleteObject(hBitmap);
1473
1474#elif defined (Q_WS_X11) && !defined (VBOX_WITHOUT_XCURSOR)
1475
1476 XcursorImage *img = XcursorImageCreate(uWidth, uHeight);
1477 Assert(img);
1478 if (img)
1479 {
1480 img->xhot = uXHot;
1481 img->yhot = uYHot;
1482
1483 XcursorPixel *dstShapePtr = img->pixels;
1484
1485 for (uint y = 0; y < uHeight; y ++)
1486 {
1487 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan);
1488
1489 if (!fHasAlpha)
1490 {
1491 /* Convert AND mask to the alpha channel: */
1492 uchar byte = 0;
1493 for (uint x = 0; x < uWidth; x ++)
1494 {
1495 if (!(x % 8))
1496 byte = *(srcAndMaskPtr ++);
1497 else
1498 byte <<= 1;
1499
1500 if (byte & 0x80)
1501 {
1502 /* Linux doesn't support inverted pixels (XOR ops,
1503 * to be exact) in cursor shapes, so we detect such
1504 * pixels and always replace them with black ones to
1505 * make them visible at least over light colors */
1506 if (dstShapePtr [x] & 0x00FFFFFF)
1507 dstShapePtr [x] = 0xFF000000;
1508 else
1509 dstShapePtr [x] = 0x00000000;
1510 }
1511 else
1512 dstShapePtr [x] |= 0xFF000000;
1513 }
1514 }
1515
1516 srcShapePtr += srcShapePtrScan;
1517 dstShapePtr += uWidth;
1518 }
1519
1520 /* Set the new cursor: */
1521 m_cursor = QCursor(XcursorImageLoadCursor(QX11Info::display(), img));
1522 m_fIsValidPointerShapePresent = true;
1523
1524 XcursorImageDestroy(img);
1525 }
1526
1527#elif defined(Q_WS_MAC)
1528
1529 /* Create a ARGB image out of the shape data. */
1530 QImage image (uWidth, uHeight, QImage::Format_ARGB32);
1531 const uint8_t* pbSrcMask = static_cast<const uint8_t*> (srcAndMaskPtr);
1532 unsigned cbSrcMaskLine = RT_ALIGN (uWidth, 8) / 8;
1533 for (unsigned int y = 0; y < uHeight; ++y)
1534 {
1535 for (unsigned int x = 0; x < uWidth; ++x)
1536 {
1537 unsigned int color = ((unsigned int*)srcShapePtr)[y*uWidth+x];
1538 /* If the alpha channel isn't in the shape data, we have to
1539 * create them from the and-mask. This is a bit field where 1
1540 * represent transparency & 0 opaque respectively. */
1541 if (!fHasAlpha)
1542 {
1543 if (!(pbSrcMask[x / 8] & (1 << (7 - (x % 8)))))
1544 color |= 0xff000000;
1545 else
1546 {
1547 /* This isn't quite right, but it's the best we can do I think... */
1548 if (color & 0x00ffffff)
1549 color = 0xff000000;
1550 else
1551 color = 0x00000000;
1552 }
1553 }
1554 image.setPixel (x, y, color);
1555 }
1556 /* Move one scanline forward. */
1557 pbSrcMask += cbSrcMaskLine;
1558 }
1559
1560 /* Set the new cursor: */
1561 m_cursor = QCursor(QPixmap::fromImage(image), uXHot, uYHot);
1562 m_fIsValidPointerShapePresent = true;
1563 NOREF(srcShapePtrScan);
1564
1565#else
1566
1567# warning "port me"
1568
1569#endif
1570}
1571
1572bool UISession::preparePowerUp()
1573{
1574 /* Notify user about mouse&keyboard auto-capturing: */
1575 if (vboxGlobal().settings().autoCapture())
1576 popupCenter().remindAboutAutoCapture(machineLogic()->activeMachineWindow());
1577
1578 /* Shows First Run wizard if necessary: */
1579 const CMachine &machine = session().GetMachine();
1580 /* Check if we are in teleportation waiting mode.
1581 * In that case no first run wizard is necessary. */
1582 m_machineState = machine.GetState();
1583 if ( isFirstTimeStarted()
1584 && !(( m_machineState == KMachineState_PoweredOff
1585 || m_machineState == KMachineState_Aborted
1586 || m_machineState == KMachineState_Teleported)
1587 && machine.GetTeleporterEnabled()))
1588 {
1589 UISafePointerWizard pWizard = new UIWizardFirstRun(mainMachineWindow(), session().GetMachine());
1590 pWizard->prepare();
1591 pWizard->exec();
1592 if (pWizard)
1593 delete pWizard;
1594 }
1595
1596#ifdef VBOX_WITH_NETFLT
1597
1598 /* Skip further checks if VM in saved state */
1599 if (isSaved())
1600 return true;
1601
1602 /* Make sure all the attached and enabled network
1603 * adapters are present on the host. This check makes sense
1604 * in two cases only - when attachement type is Bridged Network
1605 * or Host-only Interface. NOTE: Only currently enabled
1606 * attachement type is checked (incorrect parameters check for
1607 * currently disabled attachement types is skipped). */
1608 QStringList failedInterfaceNames;
1609 QStringList availableInterfaceNames;
1610
1611 /* Create host network interface names list */
1612 foreach (const CHostNetworkInterface &iface, vboxGlobal().host().GetNetworkInterfaces())
1613 {
1614 availableInterfaceNames << iface.GetName();
1615 availableInterfaceNames << iface.GetShortName();
1616 }
1617
1618 ulong cCount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine.GetChipsetType());
1619 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
1620 {
1621 CNetworkAdapter na = machine.GetNetworkAdapter(uAdapterIndex);
1622
1623 if (na.GetEnabled())
1624 {
1625 QString strIfName = QString();
1626
1627 /* Get physical network interface name for currently
1628 * enabled network attachement type */
1629 switch (na.GetAttachmentType())
1630 {
1631 case KNetworkAttachmentType_Bridged:
1632 strIfName = na.GetBridgedInterface();
1633 break;
1634 case KNetworkAttachmentType_HostOnly:
1635 strIfName = na.GetHostOnlyInterface();
1636 break;
1637 }
1638
1639 if (!strIfName.isEmpty() &&
1640 !availableInterfaceNames.contains(strIfName))
1641 {
1642 LogFlow(("Found invalid network interface: %s\n", strIfName.toStdString().c_str()));
1643 failedInterfaceNames << QString("%1 (adapter %2)").arg(strIfName).arg(uAdapterIndex + 1);
1644 }
1645 }
1646 }
1647
1648 /* Check if non-existent interfaces found */
1649 if (!failedInterfaceNames.isEmpty())
1650 {
1651 if (msgCenter().UIMessageCenter::cannotStartWithoutNetworkIf(machine.GetName(), failedInterfaceNames.join(", ")))
1652 machineLogic()->openNetworkSettingsDialog();
1653 else
1654 {
1655 closeRuntimeUI();
1656 return false;
1657 }
1658 }
1659
1660#endif
1661
1662 return true;
1663}
1664
1665bool UISession::isScreenVisible(ulong uScreenId) const
1666{
1667 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1668 return m_monitorVisibilityVector.value((int)uScreenId, false);
1669}
1670
1671void UISession::setScreenVisible(ulong uScreenId, bool fIsMonitorVisible)
1672{
1673 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1674 if (uScreenId < (ulong)m_monitorVisibilityVector.size())
1675 m_monitorVisibilityVector[(int)uScreenId] = fIsMonitorVisible;
1676}
1677
1678int UISession::countOfVisibleWindows()
1679{
1680 int cCountOfVisibleWindows = 0;
1681 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
1682 if (m_monitorVisibilityVector[i])
1683 ++cCountOfVisibleWindows;
1684 return cCountOfVisibleWindows;
1685}
1686
1687UIFrameBuffer* UISession::frameBuffer(ulong uScreenId) const
1688{
1689 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1690 return m_frameBufferVector.value((int)uScreenId, 0);
1691}
1692
1693void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer* pFrameBuffer)
1694{
1695 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1696 if (uScreenId < (ulong)m_frameBufferVector.size())
1697 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
1698}
1699
1700void UISession::updateHostScreenData()
1701{
1702 m_hostScreens.clear();
1703 QDesktopWidget *pDesktop = QApplication::desktop();
1704 for (int iScreenIndex = 0; iScreenIndex < pDesktop->screenCount(); ++iScreenIndex)
1705 m_hostScreens << pDesktop->screenGeometry(iScreenIndex);
1706}
1707
1708#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
1709/**
1710 * Custom signal handler. When switching VTs, we might not get release events
1711 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
1712 * be saved with modifier keys stuck. This is annoying enough for introducing
1713 * this hack.
1714 */
1715/* static */
1716static void signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
1717{
1718 /* only SIGUSR1 is interesting */
1719 if (sig == SIGUSR1)
1720 if (UIMachine *pMachine = vboxGlobal().virtualMachine())
1721 pMachine->uisession()->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
1722}
1723#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
1724
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