VirtualBox

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

Last change on this file since 51252 was 51252, checked in by vboxsync, 11 years ago

FE/Qt: Mac OS X: Runtime UI: Native Full Screen: Additional handling for NSWindowDidFailToEnterFullScreenNotification: Push mode-change directly if session started already.

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