VirtualBox

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

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

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

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