VirtualBox

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

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

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.8 KB
Line 
1/* $Id: UISession.cpp 52238 2014-07-30 18:54:51Z 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 m_pActionPool->toRuntime()->setSession(this);
988
989 /* Get host/machine: */
990 const CHost host = vboxGlobal().host();
991 const CMachine machine = session().GetConsole().GetMachine();
992 RuntimeMenuDevicesActionType restriction = RuntimeMenuDevicesActionType_Invalid;
993
994 /* Storage stuff: */
995 {
996 /* Initialize CD/FD menus: */
997 int iDevicesCountCD = 0;
998 int iDevicesCountFD = 0;
999 foreach (const CMediumAttachment &attachment, machine.GetMediumAttachments())
1000 {
1001 if (attachment.GetType() == KDeviceType_DVD)
1002 ++iDevicesCountCD;
1003 if (attachment.GetType() == KDeviceType_Floppy)
1004 ++iDevicesCountFD;
1005 }
1006 QAction *pOpticalDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices);
1007 QAction *pFloppyDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices);
1008 pOpticalDevicesMenu->setData(iDevicesCountCD);
1009 pFloppyDevicesMenu->setData(iDevicesCountFD);
1010 if (!iDevicesCountCD)
1011 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_OpticalDevices);
1012 if (!iDevicesCountFD)
1013 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_FloppyDevices);
1014 }
1015
1016 /* Network stuff: */
1017 {
1018 /* Initialize Network menu: */
1019 bool fAtLeastOneAdapterActive = false;
1020 const KChipsetType chipsetType = machine.GetChipsetType();
1021 ULONG uSlots = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(chipsetType);
1022 for (ULONG uSlot = 0; uSlot < uSlots; ++uSlot)
1023 {
1024 const CNetworkAdapter &adapter = machine.GetNetworkAdapter(uSlot);
1025 if (adapter.GetEnabled())
1026 {
1027 fAtLeastOneAdapterActive = true;
1028 break;
1029 }
1030 }
1031 if (!fAtLeastOneAdapterActive)
1032 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_Network);
1033 }
1034
1035 /* USB stuff: */
1036 {
1037 /* Check whether there is at least one USB controller with an available proxy. */
1038 const bool fUSBEnabled = !machine.GetUSBDeviceFilters().isNull()
1039 && !machine.GetUSBControllers().isEmpty()
1040 && machine.GetUSBProxyAvailable();
1041 if (!fUSBEnabled)
1042 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_USBDevices);
1043 }
1044
1045 /* WebCams stuff: */
1046 {
1047 /* Check whether there is an accessible video input devices pool: */
1048 host.GetVideoInputDevices();
1049 const bool fWebCamsEnabled = host.isOk() && !machine.GetUSBControllers().isEmpty();
1050 if (!fWebCamsEnabled)
1051 restriction = (RuntimeMenuDevicesActionType)(restriction | RuntimeMenuDevicesActionType_WebCams);
1052 }
1053
1054 /* Apply cumulative restriction: */
1055 actionPool()->toRuntime()->setRestrictionForMenuDevices(UIActionRestrictionLevel_Session, restriction);
1056
1057#ifdef Q_WS_MAC
1058 /* Create Mac OS X menu-bar: */
1059 m_pMenuBar = new UIMenuBar;
1060 AssertPtrReturnVoid(m_pMenuBar);
1061 {
1062 /* Prepare menu-bar: */
1063 foreach (QMenu *pMenu, actionPool()->menus())
1064 m_pMenuBar->addMenu(pMenu);
1065 }
1066#endif /* Q_WS_MAC */
1067}
1068
1069void UISession::prepareConnections()
1070{
1071 connect(this, SIGNAL(sigStarted()), this, SLOT(sltMarkStarted()));
1072 connect(this, SIGNAL(sigCloseRuntimeUI()), this, SLOT(sltCloseRuntimeUI()));
1073
1074#ifdef Q_WS_MAC
1075 /* Install native display reconfiguration callback: */
1076 CGDisplayRegisterReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1077#else /* !Q_WS_MAC */
1078 /* Install Qt display reconfiguration callbacks: */
1079 connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)),
1080 this, SLOT(sltHandleHostScreenCountChange()));
1081 connect(QApplication::desktop(), SIGNAL(resized(int)),
1082 this, SLOT(sltHandleHostScreenGeometryChange()));
1083 connect(QApplication::desktop(), SIGNAL(workAreaResized(int)),
1084 this, SLOT(sltHandleHostScreenGeometryChange()));
1085#endif /* !Q_WS_MAC */
1086}
1087
1088void UISession::prepareScreens()
1089{
1090#ifdef Q_WS_MAC
1091 /* Recache display data: */
1092 recacheDisplayData();
1093 /* Prepare display-change watchdog: */
1094 m_pWatchdogDisplayChange = new QTimer(this);
1095 {
1096 m_pWatchdogDisplayChange->setInterval(500);
1097 m_pWatchdogDisplayChange->setSingleShot(true);
1098 connect(m_pWatchdogDisplayChange, SIGNAL(timeout()),
1099 this, SLOT(sltCheckIfHostDisplayChanged()));
1100 }
1101#endif /* Q_WS_MAC */
1102
1103 /* Get machine: */
1104 CMachine machine = m_session.GetMachine();
1105
1106 /* Prepare initial screen visibility status: */
1107 m_monitorVisibilityVector.resize(machine.GetMonitorCount());
1108 m_monitorVisibilityVector.fill(false);
1109 m_monitorVisibilityVector[0] = true;
1110
1111 /* If machine is in 'saved' state: */
1112 if (isSaved())
1113 {
1114 /* Update screen visibility status from saved-state: */
1115 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
1116 {
1117 BOOL fEnabled = true;
1118 ULONG guestOriginX = 0, guestOriginY = 0, guestWidth = 0, guestHeight = 0;
1119 machine.QuerySavedGuestScreenInfo(i, guestOriginX, guestOriginY, guestWidth, guestHeight, fEnabled);
1120 m_monitorVisibilityVector[i] = fEnabled;
1121 }
1122 /* And make sure at least one of them is visible (primary if others are hidden): */
1123 if (countOfVisibleWindows() < 1)
1124 m_monitorVisibilityVector[0] = true;
1125 }
1126}
1127
1128void UISession::prepareFramebuffers()
1129{
1130 /* Each framebuffer will be really prepared on first UIMachineView creation: */
1131 m_frameBufferVector.resize(m_session.GetMachine().GetMonitorCount());
1132}
1133
1134void UISession::loadSessionSettings()
1135{
1136 /* Load extra-data settings: */
1137 {
1138 /* Get machine ID: */
1139 const QString strMachineID = vboxGlobal().managedVMUuid();
1140
1141#ifndef Q_WS_MAC
1142 /* Load/prepare user's machine-window icon: */
1143 QIcon icon;
1144 foreach (const QString &strIconName, gEDataManager->machineWindowIconNames(strMachineID))
1145 if (!strIconName.isEmpty())
1146 icon.addFile(strIconName);
1147 if (!icon.isNull())
1148 m_pMachineWindowIcon = new QIcon(icon);
1149
1150 /* Load user's machine-window name postfix: */
1151 m_strMachineWindowNamePostfix = gEDataManager->machineWindowNamePostfix(strMachineID);
1152#endif /* !Q_WS_MAC */
1153
1154 /* Determine mouse-capture policy: */
1155 m_mouseCapturePolicy = gEDataManager->mouseCapturePolicy(strMachineID);
1156
1157 /* Determine Guru Meditation handler type: */
1158 m_guruMeditationHandlerType = gEDataManager->guruMeditationHandlerType(strMachineID);
1159
1160 /* Determine HiDPI optimization type: */
1161 m_hiDPIOptimizationType = gEDataManager->hiDPIOptimizationType(strMachineID);
1162
1163 /* Is there should be First RUN Wizard? */
1164 m_fIsFirstTimeStarted = gEDataManager->machineFirstTimeStarted(strMachineID);
1165
1166 /* Should guest autoresize? */
1167 QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1168 pGuestAutoresizeSwitch->setChecked(gEDataManager->guestScreenAutoResizeEnabled(strMachineID));
1169
1170 /* Status-bar options: */
1171 const bool fEnabledGlobally = !vboxGlobal().settings().isFeatureActive("noStatusBar");
1172 const bool fEnabledForMachine = gEDataManager->statusBarEnabled(strMachineID);
1173 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1174 QAction *pActionStatusBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_S_Settings);
1175 pActionStatusBarSettings->setEnabled(fEnabled);
1176 QAction *pActionStatusBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility);
1177 pActionStatusBarSwitch->blockSignals(true);
1178 pActionStatusBarSwitch->setChecked(fEnabled);
1179 pActionStatusBarSwitch->blockSignals(false);
1180
1181 /* What is the default close action and the restricted are? */
1182 m_defaultCloseAction = gEDataManager->defaultMachineCloseAction(strMachineID);
1183 m_restrictedCloseActions = gEDataManager->restrictedMachineCloseActions(strMachineID);
1184 m_fAllCloseActionsRestricted = (m_restrictedCloseActions & MachineCloseAction_SaveState)
1185 && (m_restrictedCloseActions & MachineCloseAction_Shutdown)
1186 && (m_restrictedCloseActions & MachineCloseAction_PowerOff);
1187 // Close VM Dialog hides PowerOff_RestoringSnapshot implicitly if PowerOff is hidden..
1188 // && (m_restrictedCloseActions & MachineCloseAction_PowerOff_RestoringSnapshot);
1189 }
1190}
1191
1192void UISession::saveSessionSettings()
1193{
1194 /* Save extra-data settings: */
1195 {
1196 /* Disable First RUN Wizard: */
1197 gEDataManager->setMachineFirstTimeStarted(false, vboxGlobal().managedVMUuid());
1198
1199 /* Remember if guest should autoresize: */
1200 gEDataManager->setGuestScreenAutoResizeEnabled(actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize)->isChecked(), vboxGlobal().managedVMUuid());
1201
1202#ifndef Q_WS_MAC
1203 /* Cleanup user's machine-window icon: */
1204 delete m_pMachineWindowIcon;
1205 m_pMachineWindowIcon = 0;
1206#endif /* !Q_WS_MAC */
1207 }
1208}
1209
1210void UISession::cleanupFramebuffers()
1211{
1212 /* Cleanup framebuffers finally: */
1213 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
1214 {
1215 UIFrameBuffer *pFb = m_frameBufferVector[i];
1216 if (pFb)
1217 {
1218 /* Mark framebuffer as unused: */
1219 pFb->setMarkAsUnused(true);
1220 /* Detach framebuffer from Display: */
1221 CDisplay display = session().GetConsole().GetDisplay();
1222 display.DetachFramebuffer(i);
1223 /* Release framebuffer reference: */
1224 m_frameBufferVector[i].setNull();
1225 }
1226 }
1227 m_frameBufferVector.clear();
1228}
1229
1230void UISession::cleanupConsoleEventHandlers()
1231{
1232 /* Destroy console event-handler: */
1233 UIConsoleEventHandler::destroy();
1234}
1235
1236void UISession::cleanupConnections()
1237{
1238#ifdef Q_WS_MAC
1239 /* Remove display reconfiguration callback: */
1240 CGDisplayRemoveReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1241#endif /* Q_WS_MAC */
1242}
1243
1244void UISession::cleanupActions()
1245{
1246#ifdef Q_WS_MAC
1247 delete m_pMenuBar;
1248 m_pMenuBar = 0;
1249#endif /* Q_WS_MAC */
1250
1251 /* Destroy action-pool: */
1252 UIActionPool::destroy(m_pActionPool);
1253}
1254
1255WId UISession::winId() const
1256{
1257 return mainMachineWindow()->winId();
1258}
1259
1260void UISession::setPointerShape(const uchar *pShapeData, bool fHasAlpha,
1261 uint uXHot, uint uYHot, uint uWidth, uint uHeight)
1262{
1263 AssertMsg(pShapeData, ("Shape data must not be NULL!\n"));
1264
1265 m_fIsValidPointerShapePresent = false;
1266 const uchar *srcAndMaskPtr = pShapeData;
1267 uint andMaskSize = (uWidth + 7) / 8 * uHeight;
1268 const uchar *srcShapePtr = pShapeData + ((andMaskSize + 3) & ~3);
1269 uint srcShapePtrScan = uWidth * 4;
1270
1271#if defined (Q_WS_WIN)
1272
1273 BITMAPV5HEADER bi;
1274 HBITMAP hBitmap;
1275 void *lpBits;
1276
1277 ::ZeroMemory(&bi, sizeof (BITMAPV5HEADER));
1278 bi.bV5Size = sizeof(BITMAPV5HEADER);
1279 bi.bV5Width = uWidth;
1280 bi.bV5Height = - (LONG)uHeight;
1281 bi.bV5Planes = 1;
1282 bi.bV5BitCount = 32;
1283 bi.bV5Compression = BI_BITFIELDS;
1284 bi.bV5RedMask = 0x00FF0000;
1285 bi.bV5GreenMask = 0x0000FF00;
1286 bi.bV5BlueMask = 0x000000FF;
1287 if (fHasAlpha)
1288 bi.bV5AlphaMask = 0xFF000000;
1289 else
1290 bi.bV5AlphaMask = 0;
1291
1292 HDC hdc = GetDC(NULL);
1293
1294 /* Create the DIB section with an alpha channel: */
1295 hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD) 0);
1296
1297 ReleaseDC(NULL, hdc);
1298
1299 HBITMAP hMonoBitmap = NULL;
1300 if (fHasAlpha)
1301 {
1302 /* Create an empty mask bitmap: */
1303 hMonoBitmap = CreateBitmap(uWidth, uHeight, 1, 1, NULL);
1304 }
1305 else
1306 {
1307 /* Word aligned AND mask. Will be allocated and created if necessary. */
1308 uint8_t *pu8AndMaskWordAligned = NULL;
1309
1310 /* Width in bytes of the original AND mask scan line. */
1311 uint32_t cbAndMaskScan = (uWidth + 7) / 8;
1312
1313 if (cbAndMaskScan & 1)
1314 {
1315 /* Original AND mask is not word aligned. */
1316
1317 /* Allocate memory for aligned AND mask. */
1318 pu8AndMaskWordAligned = (uint8_t *)RTMemTmpAllocZ((cbAndMaskScan + 1) * uHeight);
1319
1320 Assert(pu8AndMaskWordAligned);
1321
1322 if (pu8AndMaskWordAligned)
1323 {
1324 /* According to MSDN the padding bits must be 0.
1325 * Compute the bit mask to set padding bits to 0 in the last byte of original AND mask. */
1326 uint32_t u32PaddingBits = cbAndMaskScan * 8 - uWidth;
1327 Assert(u32PaddingBits < 8);
1328 uint8_t u8LastBytesPaddingMask = (uint8_t)(0xFF << u32PaddingBits);
1329
1330 Log(("u8LastBytesPaddingMask = %02X, aligned w = %d, width = %d, cbAndMaskScan = %d\n",
1331 u8LastBytesPaddingMask, (cbAndMaskScan + 1) * 8, uWidth, cbAndMaskScan));
1332
1333 uint8_t *src = (uint8_t *)srcAndMaskPtr;
1334 uint8_t *dst = pu8AndMaskWordAligned;
1335
1336 unsigned i;
1337 for (i = 0; i < uHeight; i++)
1338 {
1339 memcpy(dst, src, cbAndMaskScan);
1340
1341 dst[cbAndMaskScan - 1] &= u8LastBytesPaddingMask;
1342
1343 src += cbAndMaskScan;
1344 dst += cbAndMaskScan + 1;
1345 }
1346 }
1347 }
1348
1349 /* Create the AND mask bitmap: */
1350 hMonoBitmap = ::CreateBitmap(uWidth, uHeight, 1, 1,
1351 pu8AndMaskWordAligned? pu8AndMaskWordAligned: srcAndMaskPtr);
1352
1353 if (pu8AndMaskWordAligned)
1354 {
1355 RTMemTmpFree(pu8AndMaskWordAligned);
1356 }
1357 }
1358
1359 Assert(hBitmap);
1360 Assert(hMonoBitmap);
1361 if (hBitmap && hMonoBitmap)
1362 {
1363 DWORD *dstShapePtr = (DWORD *) lpBits;
1364
1365 for (uint y = 0; y < uHeight; y ++)
1366 {
1367 memcpy(dstShapePtr, srcShapePtr, srcShapePtrScan);
1368 srcShapePtr += srcShapePtrScan;
1369 dstShapePtr += uWidth;
1370 }
1371
1372 ICONINFO ii;
1373 ii.fIcon = FALSE;
1374 ii.xHotspot = uXHot;
1375 ii.yHotspot = uYHot;
1376 ii.hbmMask = hMonoBitmap;
1377 ii.hbmColor = hBitmap;
1378
1379 HCURSOR hAlphaCursor = CreateIconIndirect(&ii);
1380 Assert(hAlphaCursor);
1381 if (hAlphaCursor)
1382 {
1383 /* Set the new cursor: */
1384 m_cursor = QCursor(hAlphaCursor);
1385 if (m_alphaCursor)
1386 DestroyIcon(m_alphaCursor);
1387 m_alphaCursor = hAlphaCursor;
1388 m_fIsValidPointerShapePresent = true;
1389 }
1390 }
1391
1392 if (hMonoBitmap)
1393 DeleteObject(hMonoBitmap);
1394 if (hBitmap)
1395 DeleteObject(hBitmap);
1396
1397#elif defined (Q_WS_X11) && !defined (VBOX_WITHOUT_XCURSOR)
1398
1399 XcursorImage *img = XcursorImageCreate(uWidth, uHeight);
1400 Assert(img);
1401 if (img)
1402 {
1403 img->xhot = uXHot;
1404 img->yhot = uYHot;
1405
1406 XcursorPixel *dstShapePtr = img->pixels;
1407
1408 for (uint y = 0; y < uHeight; y ++)
1409 {
1410 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan);
1411
1412 if (!fHasAlpha)
1413 {
1414 /* Convert AND mask to the alpha channel: */
1415 uchar byte = 0;
1416 for (uint x = 0; x < uWidth; x ++)
1417 {
1418 if (!(x % 8))
1419 byte = *(srcAndMaskPtr ++);
1420 else
1421 byte <<= 1;
1422
1423 if (byte & 0x80)
1424 {
1425 /* Linux doesn't support inverted pixels (XOR ops,
1426 * to be exact) in cursor shapes, so we detect such
1427 * pixels and always replace them with black ones to
1428 * make them visible at least over light colors */
1429 if (dstShapePtr [x] & 0x00FFFFFF)
1430 dstShapePtr [x] = 0xFF000000;
1431 else
1432 dstShapePtr [x] = 0x00000000;
1433 }
1434 else
1435 dstShapePtr [x] |= 0xFF000000;
1436 }
1437 }
1438
1439 srcShapePtr += srcShapePtrScan;
1440 dstShapePtr += uWidth;
1441 }
1442
1443 /* Set the new cursor: */
1444 m_cursor = QCursor(XcursorImageLoadCursor(QX11Info::display(), img));
1445 m_fIsValidPointerShapePresent = true;
1446
1447 XcursorImageDestroy(img);
1448 }
1449
1450#elif defined(Q_WS_MAC)
1451
1452 /* Create a ARGB image out of the shape data. */
1453 QImage image (uWidth, uHeight, QImage::Format_ARGB32);
1454 const uint8_t* pbSrcMask = static_cast<const uint8_t*> (srcAndMaskPtr);
1455 unsigned cbSrcMaskLine = RT_ALIGN (uWidth, 8) / 8;
1456 for (unsigned int y = 0; y < uHeight; ++y)
1457 {
1458 for (unsigned int x = 0; x < uWidth; ++x)
1459 {
1460 unsigned int color = ((unsigned int*)srcShapePtr)[y*uWidth+x];
1461 /* If the alpha channel isn't in the shape data, we have to
1462 * create them from the and-mask. This is a bit field where 1
1463 * represent transparency & 0 opaque respectively. */
1464 if (!fHasAlpha)
1465 {
1466 if (!(pbSrcMask[x / 8] & (1 << (7 - (x % 8)))))
1467 color |= 0xff000000;
1468 else
1469 {
1470 /* This isn't quite right, but it's the best we can do I think... */
1471 if (color & 0x00ffffff)
1472 color = 0xff000000;
1473 else
1474 color = 0x00000000;
1475 }
1476 }
1477 image.setPixel (x, y, color);
1478 }
1479 /* Move one scanline forward. */
1480 pbSrcMask += cbSrcMaskLine;
1481 }
1482
1483 /* Set the new cursor: */
1484 m_cursor = QCursor(QPixmap::fromImage(image), uXHot, uYHot);
1485 m_fIsValidPointerShapePresent = true;
1486 NOREF(srcShapePtrScan);
1487
1488#else
1489
1490# warning "port me"
1491
1492#endif
1493}
1494
1495bool UISession::preparePowerUp()
1496{
1497 /* Notify user about mouse&keyboard auto-capturing: */
1498 if (vboxGlobal().settings().autoCapture())
1499 popupCenter().remindAboutAutoCapture(machineLogic()->activeMachineWindow());
1500
1501 /* Shows First Run wizard if necessary: */
1502 const CMachine &machine = session().GetMachine();
1503 /* Check if we are in teleportation waiting mode.
1504 * In that case no first run wizard is necessary. */
1505 m_machineState = machine.GetState();
1506 if ( isFirstTimeStarted()
1507 && !(( m_machineState == KMachineState_PoweredOff
1508 || m_machineState == KMachineState_Aborted
1509 || m_machineState == KMachineState_Teleported)
1510 && machine.GetTeleporterEnabled()))
1511 {
1512 UISafePointerWizard pWizard = new UIWizardFirstRun(mainMachineWindow(), session().GetMachine());
1513 pWizard->prepare();
1514 pWizard->exec();
1515 if (pWizard)
1516 delete pWizard;
1517 }
1518
1519#ifdef VBOX_WITH_NETFLT
1520
1521 /* Skip further checks if VM in saved state */
1522 if (isSaved())
1523 return true;
1524
1525 /* Make sure all the attached and enabled network
1526 * adapters are present on the host. This check makes sense
1527 * in two cases only - when attachement type is Bridged Network
1528 * or Host-only Interface. NOTE: Only currently enabled
1529 * attachement type is checked (incorrect parameters check for
1530 * currently disabled attachement types is skipped). */
1531 QStringList failedInterfaceNames;
1532 QStringList availableInterfaceNames;
1533
1534 /* Create host network interface names list */
1535 foreach (const CHostNetworkInterface &iface, vboxGlobal().host().GetNetworkInterfaces())
1536 {
1537 availableInterfaceNames << iface.GetName();
1538 availableInterfaceNames << iface.GetShortName();
1539 }
1540
1541 ulong cCount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine.GetChipsetType());
1542 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
1543 {
1544 CNetworkAdapter na = machine.GetNetworkAdapter(uAdapterIndex);
1545
1546 if (na.GetEnabled())
1547 {
1548 QString strIfName = QString();
1549
1550 /* Get physical network interface name for currently
1551 * enabled network attachement type */
1552 switch (na.GetAttachmentType())
1553 {
1554 case KNetworkAttachmentType_Bridged:
1555 strIfName = na.GetBridgedInterface();
1556 break;
1557 case KNetworkAttachmentType_HostOnly:
1558 strIfName = na.GetHostOnlyInterface();
1559 break;
1560 }
1561
1562 if (!strIfName.isEmpty() &&
1563 !availableInterfaceNames.contains(strIfName))
1564 {
1565 LogFlow(("Found invalid network interface: %s\n", strIfName.toStdString().c_str()));
1566 failedInterfaceNames << QString("%1 (adapter %2)").arg(strIfName).arg(uAdapterIndex + 1);
1567 }
1568 }
1569 }
1570
1571 /* Check if non-existent interfaces found */
1572 if (!failedInterfaceNames.isEmpty())
1573 {
1574 if (msgCenter().UIMessageCenter::cannotStartWithoutNetworkIf(machine.GetName(), failedInterfaceNames.join(", ")))
1575 machineLogic()->openNetworkSettingsDialog();
1576 else
1577 {
1578 closeRuntimeUI();
1579 return false;
1580 }
1581 }
1582
1583#endif
1584
1585 return true;
1586}
1587
1588bool UISession::isScreenVisible(ulong uScreenId) const
1589{
1590 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1591 return m_monitorVisibilityVector.value((int)uScreenId, false);
1592}
1593
1594void UISession::setScreenVisible(ulong uScreenId, bool fIsMonitorVisible)
1595{
1596 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1597 if (uScreenId < (ulong)m_monitorVisibilityVector.size())
1598 m_monitorVisibilityVector[(int)uScreenId] = fIsMonitorVisible;
1599}
1600
1601int UISession::countOfVisibleWindows()
1602{
1603 int cCountOfVisibleWindows = 0;
1604 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
1605 if (m_monitorVisibilityVector[i])
1606 ++cCountOfVisibleWindows;
1607 return cCountOfVisibleWindows;
1608}
1609
1610UIFrameBuffer* UISession::frameBuffer(ulong uScreenId) const
1611{
1612 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1613 return m_frameBufferVector.value((int)uScreenId, 0);
1614}
1615
1616void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer* pFrameBuffer)
1617{
1618 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1619 if (uScreenId < (ulong)m_frameBufferVector.size())
1620 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
1621}
1622
1623#ifdef Q_WS_MAC
1624/** MacOS X: Recaches display-configuration data. */
1625void UISession::recacheDisplayData()
1626{
1627 /* Recache display data: */
1628 m_screens.clear();
1629 QDesktopWidget *pDesktop = QApplication::desktop();
1630 for (int iScreenIndex = 0; iScreenIndex < pDesktop->screenCount(); ++iScreenIndex)
1631 m_screens << pDesktop->screenGeometry(iScreenIndex);
1632}
1633#endif /* Q_WS_MAC */
1634
1635#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
1636/**
1637 * Custom signal handler. When switching VTs, we might not get release events
1638 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
1639 * be saved with modifier keys stuck. This is annoying enough for introducing
1640 * this hack.
1641 */
1642/* static */
1643static void signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
1644{
1645 /* only SIGUSR1 is interesting */
1646 if (sig == SIGUSR1)
1647 if (UIMachine *pMachine = vboxGlobal().virtualMachine())
1648 pMachine->uisession()->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
1649}
1650#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
1651
Note: See TracBrowser for help on using the repository browser.

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