VirtualBox

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

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

FE/Qt: 6660: Advanced extra-data management framework: Integrate GUI_FirstRun.

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