VirtualBox

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

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

FE/Qt: 7468: Update to r95247: Re-integrate flag from UISession side (better for 4.3).

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