VirtualBox

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

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

FE/Qt: Runtime UI: 7118: Make sure corresponding Devices menu action (VRDE Server) is disabled if extension-pack is not installed/usable.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette