VirtualBox

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

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

FE/Qt: 7476: Runtime UI: Full-screen mode should avoid handling available-area-change signal (this should prevent flickering on Cinnamon).

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