VirtualBox

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

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

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.9 KB
Line 
1/* $Id: UISession.cpp 52203 2014-07-25 23:46:23Z 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 "UIMenuBar.h"
47# include "VBoxUtils-darwin.h"
48#endif /* Q_WS_MAC */
49
50#ifdef Q_WS_X11
51# include <QX11Info>
52# include <X11/Xlib.h>
53# include <X11/Xutil.h>
54# ifndef VBOX_WITHOUT_XCURSOR
55# include <X11/Xcursor/Xcursor.h>
56# endif /* VBOX_WITHOUT_XCURSOR */
57#endif /* Q_WS_X11 */
58
59#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
60# include "UIKeyboardHandler.h"
61# include <signal.h>
62#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
63
64/* COM includes: */
65#include "CConsole.h"
66#include "CSystemProperties.h"
67#include "CMachineDebugger.h"
68#include "CGuest.h"
69#include "CStorageController.h"
70#include "CMediumAttachment.h"
71#include "CDisplay.h"
72#include "CNetworkAdapter.h"
73#include "CHostNetworkInterface.h"
74#include "CVRDEServer.h"
75#include "CUSBController.h"
76#include "CUSBDeviceFilters.h"
77#include "CHostVideoInputDevice.h"
78#include "CSnapshot.h"
79#include "CMedium.h"
80
81#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
82static void signalHandlerSIGUSR1(int sig, siginfo_t *, void *);
83#endif
84
85#ifdef Q_WS_MAC
86/**
87 * MacOS X: Application Services: Core Graphics: Display reconfiguration callback.
88 *
89 * Notifies UISession about @a display configuration change.
90 * Corresponding change described by Core Graphics @a flags.
91 * Uses UISession @a pHandler to process this change.
92 *
93 * @note Last argument (@a pHandler) must always be valid pointer to UISession object.
94 * @note Calls for UISession::sltHandleHostDisplayAboutToChange() slot if display configuration changed.
95 */
96void cgDisplayReconfigurationCallback(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *pHandler)
97{
98 /* Which flags we are handling? */
99 int iHandledFlags = kCGDisplayAddFlag /* display added */
100 | kCGDisplayRemoveFlag /* display removed */
101 | kCGDisplaySetModeFlag /* display mode changed */;
102
103 /* Handle 'display-add' case: */
104 if (flags & kCGDisplayAddFlag)
105 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display added.\n"));
106 /* Handle 'display-remove' case: */
107 else if (flags & kCGDisplayRemoveFlag)
108 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display removed.\n"));
109 /* Handle 'mode-set' case: */
110 else if (flags & kCGDisplaySetModeFlag)
111 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display mode changed.\n"));
112
113 /* Ask handler to process our callback: */
114 if (flags & iHandledFlags)
115 QTimer::singleShot(0, static_cast<UISession*>(pHandler),
116 SLOT(sltHandleHostDisplayAboutToChange()));
117
118 Q_UNUSED(display);
119}
120#endif /* Q_WS_MAC */
121
122UISession::UISession(UIMachine *pMachine, CSession &sessionReference)
123 : QObject(pMachine)
124 /* Base variables: */
125 , m_pMachine(pMachine)
126 , m_session(sessionReference)
127 , m_pActionPool(0)
128#ifdef Q_WS_MAC
129 , m_pMenuBar(0)
130#endif /* Q_WS_MAC */
131 /* Common variables: */
132 , m_machineStatePrevious(KMachineState_Null)
133 , m_machineState(session().GetMachine().GetState())
134#ifndef Q_WS_MAC
135 , m_pMachineWindowIcon(0)
136#endif /* !Q_WS_MAC */
137 , m_mouseCapturePolicy(MouseCapturePolicy_Default)
138 , m_guruMeditationHandlerType(GuruMeditationHandlerType_Default)
139 , m_hiDPIOptimizationType(HiDPIOptimizationType_None)
140 , m_requestedVisualStateType(UIVisualStateType_Invalid)
141#ifdef Q_WS_WIN
142 , m_alphaCursor(0)
143#endif /* Q_WS_WIN */
144#ifdef Q_WS_MAC
145 , m_pWatchdogDisplayChange(0)
146#endif /* Q_WS_MAC */
147 , m_defaultCloseAction(MachineCloseAction_Invalid)
148 , m_restrictedCloseActions(MachineCloseAction_Invalid)
149 , m_fAllCloseActionsRestricted(false)
150 /* Common flags: */
151 , m_fIsStarted(false)
152 , m_fIsFirstTimeStarted(false)
153 , m_fIsGuestResizeIgnored(false)
154 , m_fIsAutoCaptureDisabled(false)
155 /* Guest additions flags: */
156 , m_ulGuestAdditionsRunLevel(0)
157 , m_fIsGuestSupportsGraphics(false)
158 , m_fIsGuestSupportsSeamless(false)
159 /* Mouse flags: */
160 , m_fNumLock(false)
161 , m_fCapsLock(false)
162 , m_fScrollLock(false)
163 , m_uNumLockAdaptionCnt(2)
164 , m_uCapsLockAdaptionCnt(2)
165 /* Mouse flags: */
166 , m_fIsMouseSupportsAbsolute(false)
167 , m_fIsMouseSupportsRelative(false)
168 , m_fIsMouseSupportsMultiTouch(false)
169 , m_fIsMouseHostCursorNeeded(false)
170 , m_fIsMouseCaptured(false)
171 , m_fIsMouseIntegrated(true)
172 , m_fIsValidPointerShapePresent(false)
173 , m_fIsHidingHostPointer(true)
174{
175 /* Prepare actions: */
176 prepareActions();
177
178 /* Prepare connections: */
179 prepareConnections();
180
181 /* Prepare console event-handlers: */
182 prepareConsoleEventHandlers();
183
184 /* Prepare screens: */
185 prepareScreens();
186
187 /* Prepare framebuffers: */
188 prepareFramebuffers();
189
190 /* Load settings: */
191 loadSessionSettings();
192
193#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
194 struct sigaction sa;
195 sa.sa_sigaction = &signalHandlerSIGUSR1;
196 sigemptyset(&sa.sa_mask);
197 sa.sa_flags = SA_RESTART | SA_SIGINFO;
198 sigaction(SIGUSR1, &sa, NULL);
199#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
200}
201
202UISession::~UISession()
203{
204#ifdef Q_WS_WIN
205 /* Destroy alpha cursor: */
206 if (m_alphaCursor)
207 DestroyIcon(m_alphaCursor);
208#endif /* Q_WS_WIN */
209
210 /* Save settings: */
211 saveSessionSettings();
212
213 /* Cleanup framebuffers: */
214 cleanupFramebuffers();
215
216 /* Cleanup console event-handlers: */
217 cleanupConsoleEventHandlers();
218
219 /* Cleanup connections: */
220 cleanupConnections();
221
222 /* Cleanup actions: */
223 cleanupActions();
224}
225
226void UISession::powerUp()
227{
228 /* Do nothing if we had started already: */
229 if (isRunning() || isPaused())
230 return;
231
232 /* Prepare powerup: */
233 bool fPrepared = preparePowerUp();
234 if (!fPrepared)
235 return;
236
237 /* Get current machine/console: */
238 CMachine machine = session().GetMachine();
239 CConsole console = session().GetConsole();
240
241 /* Apply debug settings from the command line. */
242 CMachineDebugger debugger = console.GetDebugger();
243 if (debugger.isOk())
244 {
245 if (vboxGlobal().isPatmDisabled())
246 debugger.SetPATMEnabled(false);
247 if (vboxGlobal().isCsamDisabled())
248 debugger.SetCSAMEnabled(false);
249 if (vboxGlobal().isSupervisorCodeExecedRecompiled())
250 debugger.SetRecompileSupervisor(true);
251 if (vboxGlobal().isUserCodeExecedRecompiled())
252 debugger.SetRecompileUser(true);
253 if (vboxGlobal().areWeToExecuteAllInIem())
254 debugger.SetExecuteAllInIEM(true);
255 if (!vboxGlobal().isDefaultWarpPct())
256 debugger.SetVirtualTimeRate(vboxGlobal().getWarpPct());
257 }
258
259 /* Power UP machine: */
260#ifdef VBOX_WITH_DEBUGGER_GUI
261 CProgress progress = vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled() ?
262 console.PowerUpPaused() : console.PowerUp();
263#else /* !VBOX_WITH_DEBUGGER_GUI */
264 CProgress progress = console.PowerUp();
265#endif /* !VBOX_WITH_DEBUGGER_GUI */
266
267 /* Check for immediate failure: */
268 if (!console.isOk())
269 {
270 if (vboxGlobal().showStartVMErrors())
271 msgCenter().cannotStartMachine(console, machine.GetName());
272 closeRuntimeUI();
273 return;
274 }
275
276 /* Guard progressbar warnings from auto-closing: */
277 if (uimachine()->machineLogic())
278 uimachine()->machineLogic()->setPreventAutoClose(true);
279
280 /* Show "Starting/Restoring" progress dialog: */
281 if (isSaved())
282 {
283 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_restore_90px.png", 0, 0);
284 /* After restoring from 'saved' state, guest screen size should be adjusted: */
285 machineLogic()->maybeAdjustGuestScreenSize();
286 }
287 else
288 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_start_90px.png");
289
290 /* Check for a progress failure: */
291 if (!progress.isOk() || progress.GetResultCode() != 0)
292 {
293 if (vboxGlobal().showStartVMErrors())
294 msgCenter().cannotStartMachine(progress, machine.GetName());
295 closeRuntimeUI();
296 return;
297 }
298
299 /* Allow further auto-closing: */
300 if (uimachine()->machineLogic())
301 uimachine()->machineLogic()->setPreventAutoClose(false);
302
303 /* Check if we missed a really quick termination after successful startup, and process it if we did: */
304 if (isTurnedOff())
305 {
306 closeRuntimeUI();
307 return;
308 }
309
310 /* Check if the required virtualization features are active. We get this
311 * info only when the session is active. */
312 bool fIs64BitsGuest = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetIs64Bit();
313 bool fRecommendVirtEx = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetRecommendedVirtEx();
314 AssertMsg(!fIs64BitsGuest || fRecommendVirtEx, ("Virtualization support missed for 64bit guest!\n"));
315 bool fIsVirtEnabled = console.GetDebugger().GetHWVirtExEnabled();
316 if (fRecommendVirtEx && !fIsVirtEnabled)
317 {
318 bool fShouldWeClose;
319
320 bool fVTxAMDVSupported = vboxGlobal().host().GetProcessorFeature(KProcessorFeature_HWVirtEx);
321
322 QApplication::processEvents();
323 setPause(true);
324
325 if (fIs64BitsGuest)
326 fShouldWeClose = msgCenter().warnAboutVirtNotEnabled64BitsGuest(fVTxAMDVSupported);
327 else
328 fShouldWeClose = msgCenter().warnAboutVirtNotEnabledGuestRequired(fVTxAMDVSupported);
329
330 if (fShouldWeClose)
331 {
332 /* At this point the console is powered up. So we have to close
333 * this session again. */
334 CProgress progress = console.PowerDown();
335 if (console.isOk())
336 {
337 /* Guard progressbar warnings from auto-closing: */
338 if (uimachine()->machineLogic())
339 uimachine()->machineLogic()->setPreventAutoClose(true);
340 /* Show the power down progress dialog */
341 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_poweroff_90px.png");
342 if (!progress.isOk() || progress.GetResultCode() != 0)
343 msgCenter().cannotPowerDownMachine(progress, machine.GetName());
344 /* Allow further auto-closing: */
345 if (uimachine()->machineLogic())
346 uimachine()->machineLogic()->setPreventAutoClose(false);
347 }
348 else
349 msgCenter().cannotPowerDownMachine(console);
350 closeRuntimeUI();
351 return;
352 }
353
354 setPause(false);
355 }
356
357#ifdef VBOX_WITH_VIDEOHWACCEL
358 LogRel(("2D video acceleration is %s.\n",
359 machine.GetAccelerate2DVideoEnabled() && VBoxGlobal::isAcceleration2DVideoAvailable()
360 ? "enabled"
361 : "disabled"));
362#endif
363
364/* Check if HID LEDs sync is enabled and add a log message about it. */
365#if defined(Q_WS_MAC) || defined(Q_WS_WIN)
366 if(uimachine()->machineLogic()->isHidLedsSyncEnabled())
367 LogRel(("HID LEDs sync is enabled.\n"));
368 else
369 LogRel(("HID LEDs sync is disabled.\n"));
370#else
371 LogRel(("HID LEDs sync is not supported on this platform.\n"));
372#endif
373
374#ifdef VBOX_GUI_WITH_PIDFILE
375 vboxGlobal().createPidfile();
376#endif
377
378 /* Warn listeners about machine was started: */
379 emit sigStarted();
380}
381
382bool UISession::saveState()
383{
384 /* Prepare the saving progress: */
385 CMachine machine = m_session.GetMachine();
386 CConsole console = m_session.GetConsole();
387 CProgress progress = console.SaveState();
388 if (console.isOk())
389 {
390 /* Show the saving progress: */
391 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_save_90px.png");
392 if (!progress.isOk() || progress.GetResultCode() != 0)
393 {
394 /* Failed in progress: */
395 msgCenter().cannotSaveMachineState(progress, machine.GetName());
396 return false;
397 }
398 }
399 else
400 {
401 /* Failed in console: */
402 msgCenter().cannotSaveMachineState(console);
403 return false;
404 }
405 /* Passed: */
406 return true;
407}
408
409bool UISession::shutdown()
410{
411 /* Send ACPI shutdown signal if possible: */
412 CConsole console = m_session.GetConsole();
413 console.PowerButton();
414 if (!console.isOk())
415 {
416 /* Failed in console: */
417 msgCenter().cannotACPIShutdownMachine(console);
418 return false;
419 }
420 /* Passed: */
421 return true;
422}
423
424bool UISession::powerOff(bool fIncludingDiscard, bool &fServerCrashed)
425{
426 /* Prepare the power-off progress: */
427 CMachine machine = m_session.GetMachine();
428 CConsole console = m_session.GetConsole();
429 CProgress progress = console.PowerDown();
430 if (console.isOk())
431 {
432 /* Show the power-off progress: */
433 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_poweroff_90px.png");
434 if (progress.isOk() && progress.GetResultCode() == 0)
435 {
436 /* Discard the current state if requested: */
437 if (fIncludingDiscard)
438 {
439 /* Prepare the snapshot-discard progress: */
440 CSnapshot snapshot = machine.GetCurrentSnapshot();
441 CProgress progress = console.RestoreSnapshot(snapshot);
442 if (!console.isOk())
443 return msgCenter().cannotRestoreSnapshot(console, snapshot.GetName(), machine.GetName());
444
445 /* Show the snapshot-discard progress: */
446 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_snapshot_discard_90px.png");
447 if (progress.GetResultCode() != 0)
448 return msgCenter().cannotRestoreSnapshot(progress, snapshot.GetName(), machine.GetName());
449 }
450 }
451 else
452 {
453 /* Failed in progress: */
454 msgCenter().cannotPowerDownMachine(progress, machine.GetName());
455 return false;
456 }
457 }
458 else
459 {
460 /* Failed in console: */
461 COMResult res(console);
462 /* This can happen if VBoxSVC is not running: */
463 if (FAILED_DEAD_INTERFACE(res.rc()))
464 fServerCrashed = true;
465 else
466 msgCenter().cannotPowerDownMachine(console);
467 return false;
468 }
469 /* Passed: */
470 return true;
471}
472
473void UISession::closeRuntimeUI()
474{
475 /* Start corresponding slot asynchronously: */
476 emit sigCloseRuntimeUI();
477}
478
479UIMachineLogic* UISession::machineLogic() const
480{
481 return uimachine()->machineLogic();
482}
483
484QWidget* UISession::mainMachineWindow() const
485{
486 return machineLogic()->mainMachineWindow();
487}
488
489bool UISession::isVisualStateAllowed(UIVisualStateType state) const
490{
491 return m_pMachine->isVisualStateAllowed(state);
492}
493
494void UISession::changeVisualState(UIVisualStateType visualStateType)
495{
496 m_pMachine->asyncChangeVisualState(visualStateType);
497}
498
499bool UISession::setPause(bool fOn)
500{
501 CConsole console = session().GetConsole();
502
503 if (fOn)
504 console.Pause();
505 else
506 console.Resume();
507
508 bool ok = console.isOk();
509 if (!ok)
510 {
511 if (fOn)
512 msgCenter().cannotPauseMachine(console);
513 else
514 msgCenter().cannotResumeMachine(console);
515 }
516
517 return ok;
518}
519
520void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
521{
522 /* This flag indicates whether we want to do the usual .ISO mounting or not.
523 * First try updating the Guest Additions directly without mounting the .ISO. */
524 bool fDoMount = false;
525
526 /* Auto-update in GUI currently is disabled. */
527#ifndef VBOX_WITH_ADDITIONS_AUTOUPDATE_UI
528 fDoMount = true;
529#else /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
530 CGuest guest = session().GetConsole().GetGuest();
531 QVector<KAdditionsUpdateFlag> aFlagsUpdate;
532 QVector<QString> aArgs;
533 CProgress progressInstall = guest.UpdateGuestAdditions(strSource,
534 aArgs, aFlagsUpdate);
535 bool fResult = guest.isOk();
536 if (fResult)
537 {
538 msgCenter().showModalProgressDialog(progressInstall, tr("Updating Guest Additions"),
539 ":/progress_install_guest_additions_90px.png",
540 0, 500 /* 500ms delay. */);
541 if (progressInstall.GetCanceled())
542 return;
543
544 HRESULT rc = progressInstall.GetResultCode();
545 if (!progressInstall.isOk() || rc != S_OK)
546 {
547 /* If we got back a VBOX_E_NOT_SUPPORTED we don't complain (guest OS
548 * simply isn't supported yet), so silently fall back to "old" .ISO
549 * mounting method. */
550 if ( !SUCCEEDED_WARNING(rc)
551 && rc != VBOX_E_NOT_SUPPORTED)
552 {
553 msgCenter().cannotUpdateGuestAdditions(progressInstall);
554
555 /* Log the error message in the release log. */
556 QString strErr = progressInstall.GetErrorInfo().GetText();
557 if (!strErr.isEmpty())
558 LogRel(("%s\n", strErr.toLatin1().constData()));
559 }
560 fDoMount = true; /* Since automatic updating failed, fall back to .ISO mounting. */
561 }
562 }
563#endif /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
564
565 /* Do we still want mounting? */
566 if (!fDoMount)
567 return;
568
569 /* Open corresponding medium: */
570 QString strMediumID;
571 CVirtualBox vbox = vboxGlobal().virtualBox();
572 CMedium image = vbox.OpenMedium(strSource, KDeviceType_DVD, KAccessMode_ReadWrite, false /* fForceNewUuid */);
573 if (vbox.isOk() && !image.isNull())
574 strMediumID = image.GetId();
575 else
576 {
577 msgCenter().cannotOpenMedium(vbox, UIMediumType_DVD, strSource, mainMachineWindow());
578 return;
579 }
580
581 /* Make sure GA medium ID is valid: */
582 AssertReturnVoid(!strMediumID.isNull());
583
584 /* Get machine: */
585 CMachine machine = session().GetMachine();
586
587 /* Searching for the first suitable controller/slot: */
588 QString strControllerName;
589 LONG iCntPort = -1, iCntDevice = -1;
590 foreach (const CStorageController &controller, machine.GetStorageControllers())
591 {
592 foreach (const CMediumAttachment &attachment, machine.GetMediumAttachmentsOfController(controller.GetName()))
593 {
594 if (attachment.GetType() == KDeviceType_DVD)
595 {
596 strControllerName = controller.GetName();
597 iCntPort = attachment.GetPort();
598 iCntDevice = attachment.GetDevice();
599 break;
600 }
601 }
602 if (!strControllerName.isNull())
603 break;
604 }
605
606 /* Make sure suitable controller/slot were found: */
607 if (strControllerName.isNull())
608 {
609 msgCenter().cannotMountGuestAdditions(machine.GetName());
610 return;
611 }
612
613 /* Try to find UIMedium among cached: */
614 UIMedium medium = vboxGlobal().medium(strMediumID);
615 if (medium.isNull())
616 {
617 /* Create new one if necessary: */
618 medium = UIMedium(image, UIMediumType_DVD, KMediumState_Created);
619 vboxGlobal().createMedium(medium);
620 }
621
622 /* Mount medium to corresponding controller/slot: */
623 machine.MountMedium(strControllerName, iCntPort, iCntDevice, medium.medium(), false /* force */);
624 if (!machine.isOk())
625 {
626 /* Ask for force mounting: */
627 if (msgCenter().cannotRemountMedium(machine, medium, true /* mount? */,
628 true /* retry? */, mainMachineWindow()))
629 {
630 /* Force mount medium to the predefined port/device: */
631 machine.MountMedium(strControllerName, iCntPort, iCntDevice, medium.medium(), true /* force */);
632 if (!machine.isOk())
633 msgCenter().cannotRemountMedium(machine, medium, true /* mount? */,
634 false /* retry? */, mainMachineWindow());
635 }
636 }
637}
638
639void UISession::sltCloseRuntimeUI()
640{
641 /* First, we have to hide any opened modal/popup widgets.
642 * They then should unlock their event-loops synchronously.
643 * If all such loops are unlocked, we can close Runtime UI: */
644 if (QWidget *pWidget = QApplication::activeModalWidget() ?
645 QApplication::activeModalWidget() :
646 QApplication::activePopupWidget() ?
647 QApplication::activePopupWidget() : 0)
648 {
649 /* First we should try to close this widget: */
650 pWidget->close();
651 /* If widget rejected the 'close-event' we can
652 * still hide it and hope it will behave correctly
653 * and unlock his event-loop if any: */
654 if (!pWidget->isHidden())
655 pWidget->hide();
656 /* Restart this slot asynchronously: */
657 emit sigCloseRuntimeUI();
658 return;
659 }
660
661 /* Finally close the Runtime UI: */
662 m_pMachine->deleteLater();
663}
664
665void UISession::sltMousePointerShapeChange(bool fVisible, bool fAlpha, QPoint hotCorner, QSize size, QVector<uint8_t> shape)
666{
667 /* In case of shape data is present: */
668 if (shape.size() > 0)
669 {
670 /* We are ignoring visibility flag: */
671 m_fIsHidingHostPointer = false;
672
673 /* And updating current cursor shape: */
674 setPointerShape(shape.data(), fAlpha,
675 hotCorner.x(), hotCorner.y(),
676 size.width(), size.height());
677 }
678 /* In case of shape data is NOT present: */
679 else
680 {
681 /* Remember if we should hide the cursor: */
682 m_fIsHidingHostPointer = !fVisible;
683 }
684
685 /* Notify listeners about mouse capability changed: */
686 emit sigMousePointerShapeChange();
687
688}
689
690void UISession::sltMouseCapabilityChange(bool fSupportsAbsolute, bool fSupportsRelative, bool fSupportsMultiTouch, bool fNeedsHostCursor)
691{
692 LogRelFlow(("UISession::sltMouseCapabilityChange: "
693 "Supports absolute: %s, Supports relative: %s, "
694 "Supports multi-touch: %s, Needs host cursor: %s\n",
695 fSupportsAbsolute ? "TRUE" : "FALSE", fSupportsRelative ? "TRUE" : "FALSE",
696 fSupportsMultiTouch ? "TRUE" : "FALSE", fNeedsHostCursor ? "TRUE" : "FALSE"));
697
698 /* Check if something had changed: */
699 if ( m_fIsMouseSupportsAbsolute != fSupportsAbsolute
700 || m_fIsMouseSupportsRelative != fSupportsRelative
701 || m_fIsMouseSupportsMultiTouch != fSupportsMultiTouch
702 || m_fIsMouseHostCursorNeeded != fNeedsHostCursor)
703 {
704 /* Store new data: */
705 m_fIsMouseSupportsAbsolute = fSupportsAbsolute;
706 m_fIsMouseSupportsRelative = fSupportsRelative;
707 m_fIsMouseSupportsMultiTouch = fSupportsMultiTouch;
708 m_fIsMouseHostCursorNeeded = fNeedsHostCursor;
709
710 /* Notify listeners about mouse capability changed: */
711 emit sigMouseCapabilityChange();
712 }
713}
714
715void UISession::sltKeyboardLedsChangeEvent(bool fNumLock, bool fCapsLock, bool fScrollLock)
716{
717 /* Check if something had changed: */
718 if ( m_fNumLock != fNumLock
719 || m_fCapsLock != fCapsLock
720 || m_fScrollLock != fScrollLock)
721 {
722 /* Store new num lock data: */
723 if (m_fNumLock != fNumLock)
724 {
725 m_fNumLock = fNumLock;
726 m_uNumLockAdaptionCnt = 2;
727 }
728
729 /* Store new caps lock data: */
730 if (m_fCapsLock != fCapsLock)
731 {
732 m_fCapsLock = fCapsLock;
733 m_uCapsLockAdaptionCnt = 2;
734 }
735
736 /* Store new scroll lock data: */
737 if (m_fScrollLock != fScrollLock)
738 {
739 m_fScrollLock = fScrollLock;
740 }
741
742 /* Notify listeners about mouse capability changed: */
743 emit sigKeyboardLedsChange();
744 }
745}
746
747void UISession::sltStateChange(KMachineState state)
748{
749 /* Check if something had changed: */
750 if (m_machineState != state)
751 {
752 /* Store new data: */
753 m_machineStatePrevious = m_machineState;
754 m_machineState = state;
755
756 /* Notify listeners about machine state changed: */
757 emit sigMachineStateChange();
758 }
759}
760
761void UISession::sltVRDEChange()
762{
763 /* Get machine: */
764 const CMachine machine = session().GetMachine();
765 /* Get VRDE server: */
766 const CVRDEServer &server = machine.GetVRDEServer();
767 bool fIsVRDEServerAvailable = !server.isNull();
768 /* Show/Hide VRDE action depending on VRDE server availability status: */
769 // TODO: Is this status can be changed at runtime?
770 // Because if no => the place for that stuff is in prepareActions().
771 actionPool()->action(UIActionIndexRT_M_Devices_T_VRDEServer)->setVisible(fIsVRDEServerAvailable);
772 /* Check/Uncheck VRDE action depending on VRDE server activity status: */
773 if (fIsVRDEServerAvailable)
774 actionPool()->action(UIActionIndexRT_M_Devices_T_VRDEServer)->setChecked(server.GetEnabled());
775 /* Notify listeners about VRDE change: */
776 emit sigVRDEChange();
777}
778
779void UISession::sltVideoCaptureChange()
780{
781 /* Get machine: */
782 const CMachine machine = session().GetMachine();
783 /* Check/Uncheck Video Capture action depending on feature status: */
784 actionPool()->action(UIActionIndexRT_M_Devices_M_VideoCapture_T_Start)->setChecked(machine.GetVideoCaptureEnabled());
785 /* Notify listeners about Video Capture change: */
786 emit sigVideoCaptureChange();
787}
788
789void UISession::sltGuestMonitorChange(KGuestMonitorChangedEventType changeType, ulong uScreenId, QRect screenGeo)
790{
791 /* Ignore KGuestMonitorChangedEventType_NewOrigin change event: */
792 if (changeType == KGuestMonitorChangedEventType_NewOrigin)
793 return;
794 /* Ignore KGuestMonitorChangedEventType_Disabled event for primary screen: */
795 AssertMsg(countOfVisibleWindows() > 0, ("All machine windows are hidden!"));
796 if (changeType == KGuestMonitorChangedEventType_Disabled && uScreenId == 0)
797 return;
798
799 /* Process KGuestMonitorChangedEventType_Enabled change event: */
800 if ( !isScreenVisible(uScreenId)
801 && changeType == KGuestMonitorChangedEventType_Enabled)
802 setScreenVisible(uScreenId, true);
803 /* Process KGuestMonitorChangedEventType_Disabled change event: */
804 else if ( isScreenVisible(uScreenId)
805 && changeType == KGuestMonitorChangedEventType_Disabled)
806 setScreenVisible(uScreenId, false);
807
808 /* Notify listeners about the change: */
809 emit sigGuestMonitorChange(changeType, uScreenId, screenGeo);
810}
811
812#ifdef RT_OS_DARWIN
813/**
814 * MacOS X: Restarts display-reconfiguration watchdog timer from the beginning.
815 * @note Watchdog is trying to determine display reconfiguration in
816 * UISession::sltCheckIfHostDisplayChanged() slot every 500ms for 40 tries.
817 */
818void UISession::sltHandleHostDisplayAboutToChange()
819{
820 LogRelFlow(("UISession::sltHandleHostDisplayAboutToChange()\n"));
821
822 if (m_pWatchdogDisplayChange->isActive())
823 m_pWatchdogDisplayChange->stop();
824 m_pWatchdogDisplayChange->setProperty("tryNumber", 1);
825 m_pWatchdogDisplayChange->start();
826}
827
828/**
829 * MacOS X: Determines display reconfiguration.
830 * @note Calls for UISession::sltHandleHostScreenCountChange() if screen count changed.
831 * @note Calls for UISession::sltHandleHostScreenGeometryChange() if screen geometry changed.
832 */
833void UISession::sltCheckIfHostDisplayChanged()
834{
835 LogRelFlow(("UISession::sltCheckIfHostDisplayChanged()\n"));
836
837 /* Acquire desktop wrapper: */
838 QDesktopWidget *pDesktop = QApplication::desktop();
839
840 /* Check if display count changed: */
841 if (pDesktop->screenCount() != m_screens.size())
842 {
843 /* Recache display data: */
844 recacheDisplayData();
845 /* Reset watchdog: */
846 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
847 /* Notify listeners about screen-count changed: */
848 return sltHandleHostScreenCountChange();
849 }
850 else
851 {
852 /* Check if at least one display geometry changed: */
853 for (int iScreenIndex = 0; iScreenIndex < pDesktop->screenCount(); ++iScreenIndex)
854 {
855 if (pDesktop->screenGeometry(iScreenIndex) != m_screens.at(iScreenIndex))
856 {
857 /* Recache display data: */
858 recacheDisplayData();
859 /* Reset watchdog: */
860 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
861 /* Notify listeners about screen-geometry changed: */
862 return sltHandleHostScreenGeometryChange();
863 }
864 }
865 }
866
867 /* Check if watchdog expired, restart if not: */
868 int cTryNumber = m_pWatchdogDisplayChange->property("tryNumber").toInt();
869 if (cTryNumber > 0 && cTryNumber < 40)
870 {
871 /* Restart watchdog again: */
872 m_pWatchdogDisplayChange->setProperty("tryNumber", ++cTryNumber);
873 m_pWatchdogDisplayChange->start();
874 }
875 else
876 {
877 /* Reset watchdog: */
878 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
879 }
880}
881#endif /* RT_OS_DARWIN */
882
883void UISession::sltHandleHostScreenCountChange()
884{
885 LogRelFlow(("UISession: Host-screen count changed.\n"));
886
887 /* Notify current machine-logic: */
888 emit sigHostScreenCountChanged();
889}
890
891void UISession::sltHandleHostScreenGeometryChange()
892{
893 LogRelFlow(("UISession: Host-screen geometry changed.\n"));
894
895 /* Notify current machine-logic: */
896 emit sigHostScreenGeometryChanged();
897}
898
899void UISession::sltAdditionsChange()
900{
901 /* Get our guest: */
902 CGuest guest = session().GetConsole().GetGuest();
903
904 /* Variable flags: */
905 ULONG ulGuestAdditionsRunLevel = guest.GetAdditionsRunLevel();
906 LONG64 lLastUpdatedIgnored;
907 bool fIsGuestSupportsGraphics = guest.GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
908 == KAdditionsFacilityStatus_Active;
909 bool fIsGuestSupportsSeamless = guest.GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
910 == KAdditionsFacilityStatus_Active;
911 /* Check if something had changed: */
912 if (m_ulGuestAdditionsRunLevel != ulGuestAdditionsRunLevel ||
913 m_fIsGuestSupportsGraphics != fIsGuestSupportsGraphics ||
914 m_fIsGuestSupportsSeamless != fIsGuestSupportsSeamless)
915 {
916 /* Store new data: */
917 m_ulGuestAdditionsRunLevel = ulGuestAdditionsRunLevel;
918 m_fIsGuestSupportsGraphics = fIsGuestSupportsGraphics;
919 m_fIsGuestSupportsSeamless = fIsGuestSupportsSeamless;
920
921 /* Notify listeners about guest additions state changed: */
922 emit sigAdditionsStateChange();
923 }
924}
925
926void UISession::prepareConsoleEventHandlers()
927{
928 /* Initialize console event-handler: */
929 UIConsoleEventHandler::instance(this);
930
931 /* Add console event connections: */
932 connect(gConsoleEvents, SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
933 this, SLOT(sltMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)));
934
935 connect(gConsoleEvents, SIGNAL(sigMouseCapabilityChange(bool, bool, bool, bool)),
936 this, SLOT(sltMouseCapabilityChange(bool, bool, bool, bool)));
937
938 connect(gConsoleEvents, SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
939 this, SLOT(sltKeyboardLedsChangeEvent(bool, bool, bool)));
940
941 connect(gConsoleEvents, SIGNAL(sigStateChange(KMachineState)),
942 this, SLOT(sltStateChange(KMachineState)));
943
944 connect(gConsoleEvents, SIGNAL(sigAdditionsChange()),
945 this, SLOT(sltAdditionsChange()));
946
947 connect(gConsoleEvents, SIGNAL(sigVRDEChange()),
948 this, SLOT(sltVRDEChange()));
949
950 connect(gConsoleEvents, SIGNAL(sigVideoCaptureChange()),
951 this, SLOT(sltVideoCaptureChange()));
952
953 connect(gConsoleEvents, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
954 this, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)));
955
956 connect(gConsoleEvents, SIGNAL(sigMediumChange(CMediumAttachment)),
957 this, SIGNAL(sigMediumChange(CMediumAttachment)));
958
959 connect(gConsoleEvents, SIGNAL(sigUSBControllerChange()),
960 this, SIGNAL(sigUSBControllerChange()));
961
962 connect(gConsoleEvents, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
963 this, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)));
964
965 connect(gConsoleEvents, SIGNAL(sigSharedFolderChange()),
966 this, SIGNAL(sigSharedFolderChange()));
967
968 connect(gConsoleEvents, SIGNAL(sigRuntimeError(bool, QString, QString)),
969 this, SIGNAL(sigRuntimeError(bool, QString, QString)));
970
971#ifdef Q_WS_MAC
972 connect(gConsoleEvents, SIGNAL(sigShowWindow()),
973 this, SIGNAL(sigShowWindows()), Qt::QueuedConnection);
974#endif /* Q_WS_MAC */
975
976 connect(gConsoleEvents, SIGNAL(sigCPUExecutionCapChange()),
977 this, SIGNAL(sigCPUExecutionCapChange()));
978
979 connect(gConsoleEvents, SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
980 this, SLOT(sltGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)));
981}
982
983void UISession::prepareActions()
984{
985 /* Create action-pool: */
986 m_pActionPool = UIActionPool::create(UIActionPoolType_Runtime);
987
988 /* Get host/machine: */
989 const CHost host = vboxGlobal().host();
990 const CMachine machine = session().GetConsole().GetMachine();
991 RuntimeMenuDevicesActionType restriction = RuntimeMenuDevicesActionType_Invalid;
992
993 /* Storage stuff: */
994 {
995 /* Initialize CD/FD menus: */
996 int iDevicesCountCD = 0;
997 int iDevicesCountFD = 0;
998 foreach (const CMediumAttachment &attachment, machine.GetMediumAttachments())
999 {
1000 if (attachment.GetType() == KDeviceType_DVD)
1001 ++iDevicesCountCD;
1002 if (attachment.GetType() == KDeviceType_Floppy)
1003 ++iDevicesCountFD;
1004 }
1005 QAction *pOpticalDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices);
1006 QAction *pFloppyDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices);
1007 pOpticalDevicesMenu->setData(iDevicesCountCD);
1008 pFloppyDevicesMenu->setData(iDevicesCountFD);
1009 if (!iDevicesCountCD)
1010 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_OpticalDevices);
1011 if (!iDevicesCountFD)
1012 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_FloppyDevices);
1013 }
1014
1015 /* Network stuff: */
1016 {
1017 /* Initialize Network menu: */
1018 bool fAtLeastOneAdapterActive = false;
1019 const KChipsetType chipsetType = machine.GetChipsetType();
1020 ULONG uSlots = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(chipsetType);
1021 for (ULONG uSlot = 0; uSlot < uSlots; ++uSlot)
1022 {
1023 const CNetworkAdapter &adapter = machine.GetNetworkAdapter(uSlot);
1024 if (adapter.GetEnabled())
1025 {
1026 fAtLeastOneAdapterActive = true;
1027 break;
1028 }
1029 }
1030 if (!fAtLeastOneAdapterActive)
1031 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_Network);
1032 }
1033
1034 /* USB stuff: */
1035 {
1036 /* Check whether there is at least one USB controller with an available proxy. */
1037 const bool fUSBEnabled = !machine.GetUSBDeviceFilters().isNull()
1038 && !machine.GetUSBControllers().isEmpty()
1039 && machine.GetUSBProxyAvailable();
1040 if (!fUSBEnabled)
1041 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_USBDevices);
1042 }
1043
1044 /* WebCams stuff: */
1045 {
1046 /* Check whether there is an accessible video input devices pool: */
1047 host.GetVideoInputDevices();
1048 const bool fWebCamsEnabled = host.isOk() && !machine.GetUSBControllers().isEmpty();
1049 if (!fWebCamsEnabled)
1050 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_WebCams);
1051 }
1052
1053 /* Apply cumulative restriction: */
1054 actionPool()->toRuntime()->setRestrictionForMenuDevices(UIActionRestrictionLevel_Session, restriction);
1055
1056#ifdef Q_WS_MAC
1057 /* Create Mac OS X menu-bar: */
1058 m_pMenuBar = new UIMenuBar;
1059 AssertPtrReturnVoid(m_pMenuBar);
1060 {
1061 /* Prepare menu-bar: */
1062 foreach (QMenu *pMenu, actionPool()->menus())
1063 m_pMenuBar->addMenu(pMenu);
1064 }
1065#endif /* Q_WS_MAC */
1066}
1067
1068void UISession::prepareConnections()
1069{
1070 connect(this, SIGNAL(sigStarted()), this, SLOT(sltMarkStarted()));
1071 connect(this, SIGNAL(sigCloseRuntimeUI()), this, SLOT(sltCloseRuntimeUI()));
1072
1073#ifdef Q_WS_MAC
1074 /* Install native display reconfiguration callback: */
1075 CGDisplayRegisterReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1076#else /* !Q_WS_MAC */
1077 /* Install Qt display reconfiguration callbacks: */
1078 connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)),
1079 this, SLOT(sltHandleHostScreenCountChange()));
1080 connect(QApplication::desktop(), SIGNAL(resized(int)),
1081 this, SLOT(sltHandleHostScreenGeometryChange()));
1082 connect(QApplication::desktop(), SIGNAL(workAreaResized(int)),
1083 this, SLOT(sltHandleHostScreenGeometryChange()));
1084#endif /* !Q_WS_MAC */
1085}
1086
1087void UISession::prepareScreens()
1088{
1089#ifdef Q_WS_MAC
1090 /* Recache display data: */
1091 recacheDisplayData();
1092 /* Prepare display-change watchdog: */
1093 m_pWatchdogDisplayChange = new QTimer(this);
1094 {
1095 m_pWatchdogDisplayChange->setInterval(500);
1096 m_pWatchdogDisplayChange->setSingleShot(true);
1097 connect(m_pWatchdogDisplayChange, SIGNAL(timeout()),
1098 this, SLOT(sltCheckIfHostDisplayChanged()));
1099 }
1100#endif /* Q_WS_MAC */
1101
1102 /* Get machine: */
1103 CMachine machine = m_session.GetMachine();
1104
1105 /* Prepare initial screen visibility status: */
1106 m_monitorVisibilityVector.resize(machine.GetMonitorCount());
1107 m_monitorVisibilityVector.fill(false);
1108 m_monitorVisibilityVector[0] = true;
1109
1110 /* If machine is in 'saved' state: */
1111 if (isSaved())
1112 {
1113 /* Update screen visibility status from saved-state: */
1114 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
1115 {
1116 BOOL fEnabled = true;
1117 ULONG guestOriginX = 0, guestOriginY = 0, guestWidth = 0, guestHeight = 0;
1118 machine.QuerySavedGuestScreenInfo(i, guestOriginX, guestOriginY, guestWidth, guestHeight, fEnabled);
1119 m_monitorVisibilityVector[i] = fEnabled;
1120 }
1121 /* And make sure at least one of them is visible (primary if others are hidden): */
1122 if (countOfVisibleWindows() < 1)
1123 m_monitorVisibilityVector[0] = true;
1124 }
1125}
1126
1127void UISession::prepareFramebuffers()
1128{
1129 /* Each framebuffer will be really prepared on first UIMachineView creation: */
1130 const ULONG uMonitorCount = m_session.GetMachine().GetMonitorCount();
1131 m_frameBufferVector.resize(uMonitorCount);
1132 QVector<QSize> sizes(uMonitorCount);
1133 actionPool()->toRuntime()->setCurrentFrameBufferSizes(sizes.toList(), true);
1134}
1135
1136void UISession::loadSessionSettings()
1137{
1138 /* Load extra-data settings: */
1139 {
1140 /* Get machine ID: */
1141 const QString strMachineID = vboxGlobal().managedVMUuid();
1142
1143#ifndef Q_WS_MAC
1144 /* Load/prepare user's machine-window icon: */
1145 QIcon icon;
1146 foreach (const QString &strIconName, gEDataManager->machineWindowIconNames(strMachineID))
1147 if (!strIconName.isEmpty())
1148 icon.addFile(strIconName);
1149 if (!icon.isNull())
1150 m_pMachineWindowIcon = new QIcon(icon);
1151
1152 /* Load user's machine-window name postfix: */
1153 m_strMachineWindowNamePostfix = gEDataManager->machineWindowNamePostfix(strMachineID);
1154#endif /* !Q_WS_MAC */
1155
1156 /* Determine mouse-capture policy: */
1157 m_mouseCapturePolicy = gEDataManager->mouseCapturePolicy(strMachineID);
1158
1159 /* Determine Guru Meditation handler type: */
1160 m_guruMeditationHandlerType = gEDataManager->guruMeditationHandlerType(strMachineID);
1161
1162 /* Determine HiDPI optimization type: */
1163 m_hiDPIOptimizationType = gEDataManager->hiDPIOptimizationType(strMachineID);
1164
1165 /* Is there should be First RUN Wizard? */
1166 m_fIsFirstTimeStarted = gEDataManager->machineFirstTimeStarted(strMachineID);
1167
1168 /* Should guest autoresize? */
1169 QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1170 pGuestAutoresizeSwitch->setChecked(gEDataManager->guestScreenAutoResizeEnabled(strMachineID));
1171
1172 /* Status-bar options: */
1173 const bool fEnabledGlobally = !vboxGlobal().settings().isFeatureActive("noStatusBar");
1174 const bool fEnabledForMachine = gEDataManager->statusBarEnabled(strMachineID);
1175 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1176 QAction *pActionStatusBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_S_Settings);
1177 pActionStatusBarSettings->setEnabled(fEnabled);
1178 QAction *pActionStatusBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility);
1179 pActionStatusBarSwitch->blockSignals(true);
1180 pActionStatusBarSwitch->setChecked(fEnabled);
1181 pActionStatusBarSwitch->blockSignals(false);
1182
1183 /* What is the default close action and the restricted are? */
1184 m_defaultCloseAction = gEDataManager->defaultMachineCloseAction(strMachineID);
1185 m_restrictedCloseActions = gEDataManager->restrictedMachineCloseActions(strMachineID);
1186 m_fAllCloseActionsRestricted = (m_restrictedCloseActions & MachineCloseAction_SaveState)
1187 && (m_restrictedCloseActions & MachineCloseAction_Shutdown)
1188 && (m_restrictedCloseActions & MachineCloseAction_PowerOff);
1189 // Close VM Dialog hides PowerOff_RestoringSnapshot implicitly if PowerOff is hidden..
1190 // && (m_restrictedCloseActions & MachineCloseAction_PowerOff_RestoringSnapshot);
1191 }
1192}
1193
1194void UISession::saveSessionSettings()
1195{
1196 /* Save extra-data settings: */
1197 {
1198 /* Disable First RUN Wizard: */
1199 gEDataManager->setMachineFirstTimeStarted(false, vboxGlobal().managedVMUuid());
1200
1201 /* Remember if guest should autoresize: */
1202 gEDataManager->setGuestScreenAutoResizeEnabled(actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize)->isChecked(), vboxGlobal().managedVMUuid());
1203
1204#ifndef Q_WS_MAC
1205 /* Cleanup user's machine-window icon: */
1206 delete m_pMachineWindowIcon;
1207 m_pMachineWindowIcon = 0;
1208#endif /* !Q_WS_MAC */
1209 }
1210}
1211
1212void UISession::cleanupFramebuffers()
1213{
1214 /* Cleanup framebuffers finally: */
1215 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
1216 {
1217 UIFrameBuffer *pFb = m_frameBufferVector[i];
1218 if (pFb)
1219 {
1220 /* Mark framebuffer as unused: */
1221 pFb->setMarkAsUnused(true);
1222 /* Detach framebuffer from Display: */
1223 CDisplay display = session().GetConsole().GetDisplay();
1224 display.DetachFramebuffer(i);
1225 /* Release framebuffer reference: */
1226 m_frameBufferVector[i].setNull();
1227 }
1228 }
1229 m_frameBufferVector.clear();
1230}
1231
1232void UISession::cleanupConsoleEventHandlers()
1233{
1234 /* Destroy console event-handler: */
1235 UIConsoleEventHandler::destroy();
1236}
1237
1238void UISession::cleanupConnections()
1239{
1240#ifdef Q_WS_MAC
1241 /* Remove display reconfiguration callback: */
1242 CGDisplayRemoveReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1243#endif /* Q_WS_MAC */
1244}
1245
1246void UISession::cleanupActions()
1247{
1248#ifdef Q_WS_MAC
1249 delete m_pMenuBar;
1250 m_pMenuBar = 0;
1251#endif /* Q_WS_MAC */
1252
1253 /* Destroy action-pool: */
1254 UIActionPool::destroy(m_pActionPool);
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
1497bool UISession::preparePowerUp()
1498{
1499 /* Notify user about mouse&keyboard auto-capturing: */
1500 if (vboxGlobal().settings().autoCapture())
1501 popupCenter().remindAboutAutoCapture(machineLogic()->activeMachineWindow());
1502
1503 /* Shows First Run wizard if necessary: */
1504 const CMachine &machine = session().GetMachine();
1505 /* Check if we are in teleportation waiting mode.
1506 * In that case no first run wizard is necessary. */
1507 m_machineState = machine.GetState();
1508 if ( isFirstTimeStarted()
1509 && !(( m_machineState == KMachineState_PoweredOff
1510 || m_machineState == KMachineState_Aborted
1511 || m_machineState == KMachineState_Teleported)
1512 && machine.GetTeleporterEnabled()))
1513 {
1514 UISafePointerWizard pWizard = new UIWizardFirstRun(mainMachineWindow(), session().GetMachine());
1515 pWizard->prepare();
1516 pWizard->exec();
1517 if (pWizard)
1518 delete pWizard;
1519 }
1520
1521#ifdef VBOX_WITH_NETFLT
1522
1523 /* Skip further checks if VM in saved state */
1524 if (isSaved())
1525 return true;
1526
1527 /* Make sure all the attached and enabled network
1528 * adapters are present on the host. This check makes sense
1529 * in two cases only - when attachement type is Bridged Network
1530 * or Host-only Interface. NOTE: Only currently enabled
1531 * attachement type is checked (incorrect parameters check for
1532 * currently disabled attachement types is skipped). */
1533 QStringList failedInterfaceNames;
1534 QStringList availableInterfaceNames;
1535
1536 /* Create host network interface names list */
1537 foreach (const CHostNetworkInterface &iface, vboxGlobal().host().GetNetworkInterfaces())
1538 {
1539 availableInterfaceNames << iface.GetName();
1540 availableInterfaceNames << iface.GetShortName();
1541 }
1542
1543 ulong cCount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine.GetChipsetType());
1544 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
1545 {
1546 CNetworkAdapter na = machine.GetNetworkAdapter(uAdapterIndex);
1547
1548 if (na.GetEnabled())
1549 {
1550 QString strIfName = QString();
1551
1552 /* Get physical network interface name for currently
1553 * enabled network attachement type */
1554 switch (na.GetAttachmentType())
1555 {
1556 case KNetworkAttachmentType_Bridged:
1557 strIfName = na.GetBridgedInterface();
1558 break;
1559 case KNetworkAttachmentType_HostOnly:
1560 strIfName = na.GetHostOnlyInterface();
1561 break;
1562 }
1563
1564 if (!strIfName.isEmpty() &&
1565 !availableInterfaceNames.contains(strIfName))
1566 {
1567 LogFlow(("Found invalid network interface: %s\n", strIfName.toStdString().c_str()));
1568 failedInterfaceNames << QString("%1 (adapter %2)").arg(strIfName).arg(uAdapterIndex + 1);
1569 }
1570 }
1571 }
1572
1573 /* Check if non-existent interfaces found */
1574 if (!failedInterfaceNames.isEmpty())
1575 {
1576 if (msgCenter().UIMessageCenter::cannotStartWithoutNetworkIf(machine.GetName(), failedInterfaceNames.join(", ")))
1577 machineLogic()->openNetworkSettingsDialog();
1578 else
1579 {
1580 closeRuntimeUI();
1581 return false;
1582 }
1583 }
1584
1585#endif
1586
1587 return true;
1588}
1589
1590bool UISession::isScreenVisible(ulong uScreenId) const
1591{
1592 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1593 return m_monitorVisibilityVector.value((int)uScreenId, false);
1594}
1595
1596void UISession::setScreenVisible(ulong uScreenId, bool fIsMonitorVisible)
1597{
1598 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1599 if (uScreenId < (ulong)m_monitorVisibilityVector.size())
1600 m_monitorVisibilityVector[(int)uScreenId] = fIsMonitorVisible;
1601}
1602
1603int UISession::countOfVisibleWindows()
1604{
1605 int cCountOfVisibleWindows = 0;
1606 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
1607 if (m_monitorVisibilityVector[i])
1608 ++cCountOfVisibleWindows;
1609 return cCountOfVisibleWindows;
1610}
1611
1612UIFrameBuffer* UISession::frameBuffer(ulong uScreenId) const
1613{
1614 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1615 return m_frameBufferVector.value((int)uScreenId, 0);
1616}
1617
1618void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer* pFrameBuffer)
1619{
1620 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1621 if (uScreenId < (ulong)m_frameBufferVector.size())
1622 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
1623}
1624
1625#ifdef Q_WS_MAC
1626/** MacOS X: Recaches display-configuration data. */
1627void UISession::recacheDisplayData()
1628{
1629 /* Recache display data: */
1630 m_screens.clear();
1631 QDesktopWidget *pDesktop = QApplication::desktop();
1632 for (int iScreenIndex = 0; iScreenIndex < pDesktop->screenCount(); ++iScreenIndex)
1633 m_screens << pDesktop->screenGeometry(iScreenIndex);
1634}
1635#endif /* Q_WS_MAC */
1636
1637#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
1638/**
1639 * Custom signal handler. When switching VTs, we might not get release events
1640 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
1641 * be saved with modifier keys stuck. This is annoying enough for introducing
1642 * this hack.
1643 */
1644/* static */
1645static void signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
1646{
1647 /* only SIGUSR1 is interesting */
1648 if (sig == SIGUSR1)
1649 if (UIMachine *pMachine = vboxGlobal().virtualMachine())
1650 pMachine->uisession()->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
1651}
1652#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
1653
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