VirtualBox

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

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

FE/Qt: Runtime UI: Geometry adjustment code refactoring (better encapsulation for that mess, renaming to more logical names); Mini-toolbar update bug-fix on machine-window geometry adjustment.

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

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