VirtualBox

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

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

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

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