VirtualBox

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

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

FE/Qt: 6660: Advanced extra-data management framework: Taking extra-data stuff from VBoxGlobal.

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