VirtualBox

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

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

FE/Qt: 7462: Runtime UI: Menu-bar, menu cleanup/rework (part 04).

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