VirtualBox

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

Last change on this file since 98547 was 98547, checked in by vboxsync, 2 years ago

FE/Qt: bugref:10322: Runtime UI: Reworking CDisplay wrapper usage step-by-step; This one is about CDisplay::SetVideoModeHint/GetVideoModeHint stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.0 KB
Line 
1/* $Id: UISession.cpp 98547 2023-02-13 13:46:34Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISession class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QApplication>
30#include <QWidget>
31#ifdef VBOX_WS_WIN
32# include <iprt/win/windows.h> /* Workaround for compile errors if included directly by QtWin. */
33# include <QtWin>
34#endif
35
36/* GUI includes: */
37#include "UIActionPoolRuntime.h"
38#include "UICommon.h"
39#include "UIConsoleEventHandler.h"
40#include "UIDetailsGenerator.h"
41#include "UIExtraDataManager.h"
42#include "UIFrameBuffer.h"
43#include "UIMachine.h"
44#include "UIMachineLogic.h"
45#include "UIMachineView.h"
46#include "UIMachineWindow.h"
47#include "UIMedium.h"
48#include "UIMessageCenter.h"
49#include "UIMousePointerShapeData.h"
50#include "UINotificationCenter.h"
51#include "UISession.h"
52#include "UISettingsDialogSpecific.h"
53#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
54# include "UIKeyboardHandler.h"
55# include <signal.h>
56#endif
57
58/* COM includes: */
59#include "CGraphicsAdapter.h"
60#include "CHostNetworkInterface.h"
61#include "CHostUSBDevice.h"
62#include "CMedium.h"
63#include "CMediumAttachment.h"
64#include "CSnapshot.h"
65#include "CStorageController.h"
66#include "CSystemProperties.h"
67#include "CUSBController.h"
68#include "CUSBDeviceFilter.h"
69#include "CUSBDeviceFilters.h"
70#ifdef VBOX_WITH_NETFLT
71# include "CNetworkAdapter.h"
72#endif
73
74/* External includes: */
75#ifdef VBOX_WS_X11
76# include <X11/Xlib.h>
77# include <X11/Xutil.h>
78#endif
79
80
81#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
82static void signalHandlerSIGUSR1(int sig, siginfo_t *, void *);
83#endif
84
85/* static */
86bool UISession::create(UISession *&pSession, UIMachine *pMachine)
87{
88 /* Make sure NULL pointer passed: */
89 AssertReturn(!pSession, false);
90
91 /* Create session UI: */
92 pSession = new UISession(pMachine);
93 AssertPtrReturn(pSession, false);
94
95 /* Make sure it's prepared: */
96 if (!pSession->prepare())
97 {
98 /* Destroy session UI otherwise: */
99 destroy(pSession);
100 /* False in that case: */
101 return false;
102 }
103
104 /* True by default: */
105 return true;
106}
107
108/* static */
109void UISession::destroy(UISession *&pSession)
110{
111 /* Make sure valid pointer passed: */
112 AssertPtrReturnVoid(pSession);
113
114 /* Delete session: */
115 delete pSession;
116 pSession = 0;
117}
118
119bool UISession::initialize()
120{
121 /* Preprocess initialization: */
122 if (!preprocessInitialization())
123 return false;
124
125 /* Notify user about mouse&keyboard auto-capturing: */
126 if (gEDataManager->autoCaptureEnabled())
127 UINotificationMessage::remindAboutAutoCapture();
128
129 m_enmMachineState = machine().GetState();
130
131 /* Apply debug settings from the command line. */
132 if (!debugger().isNull() && debugger().isOk())
133 {
134 if (uiCommon().areWeToExecuteAllInIem())
135 debugger().SetExecuteAllInIEM(true);
136 if (!uiCommon().isDefaultWarpPct())
137 debugger().SetVirtualTimeRate(uiCommon().getWarpPct());
138 }
139
140 /* Apply ad-hoc reconfigurations from the command line: */
141 if (uiCommon().hasFloppyImageToMount())
142 mountAdHocImage(KDeviceType_Floppy, UIMediumDeviceType_Floppy, uiCommon().getFloppyImage().toString());
143 if (uiCommon().hasDvdImageToMount())
144 mountAdHocImage(KDeviceType_DVD, UIMediumDeviceType_DVD, uiCommon().getDvdImage().toString());
145
146 /* Power UP if this is NOT separate process: */
147 if (!uiCommon().isSeparateProcess())
148 if (!powerUp())
149 return false;
150
151 /* Make sure all the pending Console events converted to signals
152 * during the powerUp() progress above reached their destinations.
153 * That is necessary to make sure all the pending machine state change events processed.
154 * We can't just use the machine state directly acquired from IMachine because there
155 * will be few places which are using stale machine state, not just this one. */
156 QApplication::sendPostedEvents(0, QEvent::MetaCall);
157
158 /* Check if we missed a really quick termination after successful startup: */
159 if (isTurnedOff())
160 {
161 LogRel(("GUI: Aborting startup due to invalid machine state detected: %d\n", machineState()));
162 return false;
163 }
164
165 /* Fetch corresponding states: */
166 if (uiCommon().isSeparateProcess())
167 {
168 sltAdditionsChange();
169 }
170 machineLogic()->initializePostPowerUp();
171
172#ifdef VBOX_GUI_WITH_PIDFILE
173 uiCommon().createPidfile();
174#endif /* VBOX_GUI_WITH_PIDFILE */
175
176 /* True by default: */
177 return true;
178}
179
180bool UISession::powerUp()
181{
182 /* Power UP machine: */
183 CProgress comProgress = uiCommon().shouldStartPaused() ? console().PowerUpPaused() : console().PowerUp();
184
185 /* Check for immediate failure: */
186 if (!console().isOk() || comProgress.isNull())
187 {
188 if (uiCommon().showStartVMErrors())
189 msgCenter().cannotStartMachine(console(), machineName());
190 LogRel(("GUI: Aborting startup due to power up issue detected...\n"));
191 return false;
192 }
193
194 /* Some logging right after we powered up: */
195 LogRel(("GUI: Qt version: %s\n", UICommon::qtRTVersionString().toUtf8().constData()));
196#ifdef VBOX_WS_X11
197 LogRel(("GUI: X11 Window Manager code: %d\n", (int)uiCommon().typeOfWindowManager()));
198#endif
199#if defined(VBOX_WS_MAC) || defined(VBOX_WS_WIN)
200 LogRel(("GUI: HID LEDs sync is %s\n", uimachine()->isHidLedsSyncEnabled() ? "enabled" : "disabled"));
201#else
202 LogRel(("GUI: HID LEDs sync is not supported on this platform\n"));
203#endif
204
205 /* Enable 'manual-override',
206 * preventing automatic Runtime UI closing
207 * and visual representation mode changes: */
208 uimachine()->setManualOverrideMode(true);
209
210 /* Show "Starting/Restoring" progress dialog: */
211 if (isSaved())
212 {
213 msgCenter().showModalProgressDialog(comProgress, machineName(), ":/progress_state_restore_90px.png", 0, 0);
214 /* After restoring from 'saved' state, machine-window(s) geometry should be adjusted: */
215 machineLogic()->adjustMachineWindowsGeometry();
216 }
217 else
218 {
219#ifdef VBOX_IS_QT6_OR_LATER /** @todo why is this any problem on qt6? */
220 msgCenter().showModalProgressDialog(comProgress, machineName(), ":/progress_start_90px.png", 0, 0);
221#else
222 msgCenter().showModalProgressDialog(comProgress, machineName(), ":/progress_start_90px.png");
223#endif
224 /* After VM start, machine-window(s) size-hint(s) should be sent: */
225 machineLogic()->sendMachineWindowsSizeHints();
226 }
227
228 /* Check for progress failure: */
229 if (!comProgress.isOk() || comProgress.GetResultCode() != 0)
230 {
231 if (uiCommon().showStartVMErrors())
232 msgCenter().cannotStartMachine(comProgress, machineName());
233 LogRel(("GUI: Aborting startup due to power up progress issue detected...\n"));
234 return false;
235 }
236
237 /* Disable 'manual-override' finally: */
238 uimachine()->setManualOverrideMode(false);
239
240 /* True by default: */
241 return true;
242}
243
244WId UISession::mainMachineWindowId() const
245{
246 return mainMachineWindow() ? mainMachineWindow()->winId() : 0;
247}
248
249bool UISession::setPause(bool fPause)
250{
251 if (fPause)
252 console().Pause();
253 else
254 console().Resume();
255
256 const bool fOk = console().isOk();
257 if (!fOk)
258 {
259 if (fPause)
260 UINotificationMessage::cannotPauseMachine(console());
261 else
262 UINotificationMessage::cannotResumeMachine(console());
263 }
264
265 return fOk;
266}
267
268void UISession::putScancode(LONG iCode)
269{
270 CKeyboard comKeyboard = keyboard();
271 comKeyboard.PutScancode(iCode);
272 if (!comKeyboard.isOk())
273 UINotificationMessage::cannotChangeKeyboardParameter(comKeyboard);
274}
275
276void UISession::putScancodes(const QVector<LONG> &codes)
277{
278 CKeyboard comKeyboard = keyboard();
279 comKeyboard.PutScancodes(codes);
280 if (!comKeyboard.isOk())
281 UINotificationMessage::cannotChangeKeyboardParameter(comKeyboard);
282}
283
284void UISession::putCad()
285{
286 CKeyboard comKeyboard = keyboard();
287 comKeyboard.PutCAD();
288 if (!comKeyboard.isOk())
289 UINotificationMessage::cannotChangeKeyboardParameter(comKeyboard);
290}
291
292void UISession::releaseKeys()
293{
294 CKeyboard comKeyboard = keyboard();
295 comKeyboard.ReleaseKeys();
296 if (!comKeyboard.isOk())
297 UINotificationMessage::cannotChangeKeyboardParameter(comKeyboard);
298}
299
300void UISession::putUsageCode(LONG iUsageCode, LONG iUsagePage, BOOL fKeyRelease)
301{
302 CKeyboard comKeyboard = keyboard();
303 comKeyboard.PutUsageCode(iUsageCode, iUsagePage, fKeyRelease);
304 if (!comKeyboard.isOk())
305 UINotificationMessage::cannotChangeKeyboardParameter(comKeyboard);
306}
307
308BOOL UISession::getAbsoluteSupported()
309{
310 return mouse().GetAbsoluteSupported();
311}
312
313BOOL UISession::getRelativeSupported()
314{
315 return mouse().GetRelativeSupported();
316}
317
318BOOL UISession::getTouchScreenSupported()
319{
320 return mouse().GetTouchScreenSupported();
321}
322
323BOOL UISession::getTouchPadSupported()
324{
325 return mouse().GetTouchPadSupported();
326}
327
328BOOL UISession::getNeedsHostCursor()
329{
330 return mouse().GetNeedsHostCursor();
331}
332
333void UISession::putMouseEvent(LONG iDx, LONG iDy, LONG iDz, LONG iDw, LONG iButtonState)
334{
335 CMouse comMouse = mouse();
336 comMouse.PutMouseEvent(iDx, iDy, iDz, iDw, iButtonState);
337 if (!comMouse.isOk())
338 UINotificationMessage::cannotChangeMouseParameter(comMouse);
339}
340
341void UISession::putMouseEventAbsolute(LONG iX, LONG iY, LONG iDz, LONG iDw, LONG iButtonState)
342{
343 CMouse comMouse = mouse();
344 comMouse.PutMouseEventAbsolute(iX, iY, iDz, iDw, iButtonState);
345 if (!comMouse.isOk())
346 UINotificationMessage::cannotChangeMouseParameter(comMouse);
347}
348
349void UISession::putEventMultiTouch(LONG iCount, const QVector<LONG64> &contacts, BOOL fIsTouchScreen, ULONG uScanTime)
350{
351 CMouse comMouse = mouse();
352 comMouse.PutEventMultiTouch(iCount, contacts, fIsTouchScreen, uScanTime);
353 if (!comMouse.isOk())
354 UINotificationMessage::cannotChangeMouseParameter(comMouse);
355}
356
357bool UISession::guestAdditionsUpgradable()
358{
359 if (!machine().isOk())
360 return false;
361
362 /* Auto GA update is currently for Windows and Linux guests only */
363 const CGuestOSType osType = uiCommon().vmGuestOSType(machine().GetOSTypeId());
364 if (!osType.isOk())
365 return false;
366
367 const QString strGuestFamily = osType.GetFamilyId();
368 bool fIsWindowOrLinux = strGuestFamily.contains("windows", Qt::CaseInsensitive) || strGuestFamily.contains("linux", Qt::CaseInsensitive);
369
370 if (!fIsWindowOrLinux)
371 return false;
372
373 /* Also check whether we have something to update automatically: */
374 if (m_ulGuestAdditionsRunLevel < (ULONG)KAdditionsRunLevelType_Userland)
375 return false;
376
377 return true;
378}
379
380UIFrameBuffer *UISession::frameBuffer(ulong uScreenId) const
381{
382 Assert(uScreenId < (ulong)m_frameBufferVector.size());
383 return m_frameBufferVector.value((int)uScreenId, 0);
384}
385
386void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer *pFrameBuffer)
387{
388 Assert(uScreenId < (ulong)m_frameBufferVector.size());
389 if (uScreenId < (ulong)m_frameBufferVector.size())
390 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
391}
392
393QSize UISession::frameBufferSize(ulong uScreenId) const
394{
395 UIFrameBuffer *pFramebuffer = frameBuffer(uScreenId);
396 return pFramebuffer ? QSize(pFramebuffer->width(), pFramebuffer->height()) : QSize();
397}
398
399bool UISession::acquireGuestScreenParameters(ulong uScreenId,
400 ulong &uWidth, ulong &uHeight, ulong &uBitsPerPixel,
401 long &xOrigin, long &yOrigin, KGuestMonitorStatus &enmMonitorStatus)
402{
403 CDisplay comDisplay = display();
404 ULONG uGuestWidth = 0, uGuestHeight = 0, uGuestBitsPerPixel = 0;
405 LONG iGuestXOrigin = 0, iGuestYOrigin = 0;
406 KGuestMonitorStatus enmGuestMonitorStatus = KGuestMonitorStatus_Disabled;
407 comDisplay.GetScreenResolution(uScreenId, uGuestWidth, uGuestHeight, uGuestBitsPerPixel,
408 iGuestXOrigin, iGuestYOrigin, enmGuestMonitorStatus);
409 const bool fSuccess = comDisplay.isOk();
410 if (!fSuccess)
411 UINotificationMessage::cannotAcquireDisplayParameter(comDisplay);
412 uWidth = uGuestWidth;
413 uHeight = uGuestHeight;
414 uBitsPerPixel = uGuestBitsPerPixel;
415 xOrigin = iGuestXOrigin;
416 yOrigin = iGuestYOrigin;
417 enmMonitorStatus = enmGuestMonitorStatus;
418 return fSuccess;
419}
420
421bool UISession::setVideoModeHint(ulong uScreenId, bool fEnabled, bool fChangeOrigin, long xOrigin, long yOrigin,
422 ulong uWidth, ulong uHeight, ulong uBitsPerPixel, bool fNotify)
423{
424 CDisplay comDisplay = display();
425 comDisplay.SetVideoModeHint(uScreenId, fEnabled, fChangeOrigin, xOrigin, yOrigin,
426 uWidth, uHeight, uBitsPerPixel, fNotify);
427 const bool fSuccess = comDisplay.isOk();
428 if (!fSuccess)
429 UINotificationMessage::cannotChangeDisplayParameter(comDisplay);
430 return fSuccess;
431}
432
433bool UISession::acquireVideoModeHint(ulong uScreenId, bool &fEnabled, bool &fChangeOrigin,
434 long &xOrigin, long &yOrigin, ulong &uWidth, ulong &uHeight,
435 ulong &uBitsPerPixel)
436{
437 CDisplay comDisplay = display();
438 BOOL fGuestEnabled = false, fGuestChangeOrigin = false;
439 LONG iGuestXOrigin = 0, iGuestYOrigin = 0;
440 ULONG uGuestWidth = 0, uGuestHeight = 0, uGuestBitsPerPixel = 0;
441 comDisplay.GetVideoModeHint(uScreenId, fGuestEnabled, fGuestChangeOrigin,
442 iGuestXOrigin, iGuestYOrigin, uGuestWidth, uGuestHeight,
443 uGuestBitsPerPixel);
444 const bool fSuccess = comDisplay.isOk();
445 if (!fSuccess)
446 UINotificationMessage::cannotAcquireDisplayParameter(comDisplay);
447 fEnabled = fGuestEnabled;
448 fChangeOrigin = fGuestChangeOrigin;
449 xOrigin = iGuestXOrigin;
450 yOrigin = iGuestYOrigin;
451 uWidth = uGuestWidth;
452 uHeight = uGuestHeight;
453 uBitsPerPixel = uGuestBitsPerPixel;
454 return fSuccess;
455}
456
457void UISession::acquireDeviceActivity(const QVector<KDeviceType> &deviceTypes, QVector<KDeviceActivity> &states)
458{
459 CConsole comConsole = console();
460 states = comConsole.GetDeviceActivity(deviceTypes);
461 if (!comConsole.isOk())
462 UINotificationMessage::cannotAcquireConsoleParameter(comConsole);
463}
464
465void UISession::acquireHardDiskStatusInfo(QString &strInfo, bool &fAttachmentsPresent)
466{
467 CMachine comMachine = machine();
468 UIDetailsGenerator::acquireHardDiskStatusInfo(comMachine, strInfo, fAttachmentsPresent);
469}
470
471void UISession::acquireOpticalDiskStatusInfo(QString &strInfo, bool &fAttachmentsPresent, bool &fAttachmentsMounted)
472{
473 CMachine comMachine = machine();
474 UIDetailsGenerator::acquireOpticalDiskStatusInfo(comMachine, strInfo, fAttachmentsPresent, fAttachmentsMounted);
475}
476
477void UISession::acquireFloppyDiskStatusInfo(QString &strInfo, bool &fAttachmentsPresent, bool &fAttachmentsMounted)
478{
479 CMachine comMachine = machine();
480 UIDetailsGenerator::acquireFloppyDiskStatusInfo(comMachine, strInfo, fAttachmentsPresent, fAttachmentsMounted);
481}
482
483void UISession::acquireAudioStatusInfo(QString &strInfo, bool &fAudioEnabled, bool &fEnabledOutput, bool &fEnabledInput)
484{
485 CMachine comMachine = machine();
486 UIDetailsGenerator::acquireAudioStatusInfo(comMachine, strInfo, fAudioEnabled, fEnabledOutput, fEnabledInput);
487}
488
489void UISession::acquireNetworkStatusInfo(QString &strInfo, bool &fAdaptersPresent, bool &fCablesDisconnected)
490{
491 CMachine comMachine = machine();
492 UIDetailsGenerator::acquireNetworkStatusInfo(comMachine, strInfo, fAdaptersPresent, fCablesDisconnected);
493}
494
495void UISession::acquireUsbStatusInfo(QString &strInfo, bool &fUsbEnableds)
496{
497 CMachine comMachine = machine();
498 CConsole comConsole = console();
499 UIDetailsGenerator::acquireUsbStatusInfo(comMachine, comConsole, strInfo, fUsbEnableds);
500}
501
502void UISession::acquireSharedFoldersStatusInfo(QString &strInfo, bool &fFoldersPresent)
503{
504 CMachine comMachine = machine();
505 CConsole comConsole = console();
506 CGuest comGuest = guest();
507 UIDetailsGenerator::acquireSharedFoldersStatusInfo(comMachine, comConsole, comGuest, strInfo, fFoldersPresent);
508}
509
510void UISession::acquireDisplayStatusInfo(QString &strInfo, bool &fAcceleration3D)
511{
512 CMachine comMachine = machine();
513 UIDetailsGenerator::acquireDisplayStatusInfo(comMachine, strInfo, fAcceleration3D);
514}
515
516void UISession::acquireRecordingStatusInfo(QString &strInfo, bool &fRecordingEnabled, bool &fMachinePaused)
517{
518 CMachine comMachine = machine();
519 fMachinePaused = isPaused();
520 UIDetailsGenerator::acquireRecordingStatusInfo(comMachine, strInfo, fRecordingEnabled);
521}
522
523void UISession::acquireFeaturesStatusInfo(QString &strInfo, KVMExecutionEngine &enmEngine,
524 bool fNestedPagingEnabled, bool fUxEnabled,
525 KParavirtProvider enmProvider)
526{
527 CMachine comMachine = machine();
528 UIDetailsGenerator::acquireFeaturesStatusInfo(comMachine, strInfo,
529 enmEngine,
530 fNestedPagingEnabled, fUxEnabled,
531 enmProvider);
532}
533
534void UISession::setLogEnabled(bool fEnabled)
535{
536 CMachineDebugger comDebugger = debugger();
537 comDebugger.SetLogEnabled(fEnabled ? TRUE : FALSE);
538 if (!comDebugger.isOk())
539 UINotificationMessage::cannotChangeMachineDebuggerParameter(comDebugger);
540}
541
542bool UISession::isLogEnabled()
543{
544 CMachineDebugger comDebugger = debugger();
545 const BOOL fEnabled = comDebugger.GetLogEnabled();
546 if (!comDebugger.isOk())
547 UINotificationMessage::cannotAcquireMachineDebuggerParameter(comDebugger);
548 return fEnabled == TRUE;
549}
550
551KVMExecutionEngine UISession::executionEngineType()
552{
553 CMachineDebugger comDebugger = debugger();
554 const KVMExecutionEngine enmEngine = comDebugger.GetExecutionEngine();
555 if (!comDebugger.isOk())
556 UINotificationMessage::cannotAcquireMachineDebuggerParameter(comDebugger);
557 return enmEngine;
558}
559
560bool UISession::isHwVirtExNestedPagingEnabled()
561{
562 CMachineDebugger comDebugger = debugger();
563 const BOOL fEnabled = comDebugger.GetHWVirtExNestedPagingEnabled();
564 if (!comDebugger.isOk())
565 UINotificationMessage::cannotAcquireMachineDebuggerParameter(comDebugger);
566 return fEnabled == TRUE;
567}
568
569bool UISession::isHwVirtExUXEnabled()
570{
571 CMachineDebugger comDebugger = debugger();
572 const BOOL fEnabled = comDebugger.GetHWVirtExUXEnabled();
573 if (!comDebugger.isOk())
574 UINotificationMessage::cannotAcquireMachineDebuggerParameter(comDebugger);
575 return fEnabled == TRUE;
576}
577
578int UISession::cpuLoadPercentage()
579{
580 CMachineDebugger comDebugger = debugger();
581 ULONG uPctExecuting;
582 ULONG uPctHalted;
583 ULONG uPctOther;
584 comDebugger.GetCPULoad(0x7fffffff, uPctExecuting, uPctHalted, uPctOther);
585 if (!comDebugger.isOk())
586 UINotificationMessage::cannotAcquireMachineDebuggerParameter(comDebugger);
587 return uPctExecuting + uPctOther;
588}
589
590bool UISession::prepareToBeSaved()
591{
592 return isPaused()
593 || (isRunning() && pause());
594}
595
596bool UISession::prepareToBeShutdowned()
597{
598 const bool fValidMode = console().GetGuestEnteredACPIMode();
599 if (!fValidMode)
600 UINotificationMessage::cannotSendACPIToMachine();
601 return fValidMode;
602}
603
604void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
605{
606 if (!guestAdditionsUpgradable())
607 return sltMountDVDAdHoc(strSource);
608
609 /* Update guest additions automatically: */
610 UINotificationProgressGuestAdditionsInstall *pNotification =
611 new UINotificationProgressGuestAdditionsInstall(guest(), strSource);
612 connect(pNotification, &UINotificationProgressGuestAdditionsInstall::sigGuestAdditionsInstallationFailed,
613 this, &UISession::sltMountDVDAdHoc);
614 gpNotificationCenter->append(pNotification);
615}
616
617void UISession::sltMountDVDAdHoc(const QString &strSource)
618{
619 mountAdHocImage(KDeviceType_DVD, UIMediumDeviceType_DVD, strSource);
620}
621
622void UISession::sltDetachCOM()
623{
624 /* Cleanup everything COM related: */
625 cleanupFramebuffers();
626 cleanupConsoleEventHandlers();
627 cleanupNotificationCenter();
628 cleanupSession();
629}
630
631void UISession::sltStateChange(KMachineState enmState)
632{
633 /* Check if something had changed: */
634 if (m_enmMachineState != enmState)
635 {
636 /* Store new data: */
637 m_enmMachineStatePrevious = m_enmMachineState;
638 m_enmMachineState = enmState;
639
640 /* Notify listeners about machine state changed: */
641 emit sigMachineStateChange();
642 }
643}
644
645void UISession::sltAdditionsChange()
646{
647 /* Acquire actual states: */
648 const ULONG ulGuestAdditionsRunLevel = guest().GetAdditionsRunLevel();
649 LONG64 lLastUpdatedIgnored;
650 const bool fIsGuestSupportsGraphics = guest().GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
651 == KAdditionsFacilityStatus_Active;
652 const bool fIsGuestSupportsSeamless = guest().GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
653 == KAdditionsFacilityStatus_Active;
654
655 /* Check if something had changed: */
656 if ( m_ulGuestAdditionsRunLevel != ulGuestAdditionsRunLevel
657 || m_fIsGuestSupportsGraphics != fIsGuestSupportsGraphics
658 || m_fIsGuestSupportsSeamless != fIsGuestSupportsSeamless)
659 {
660 /* Store new data: */
661 m_ulGuestAdditionsRunLevel = ulGuestAdditionsRunLevel;
662 m_fIsGuestSupportsGraphics = fIsGuestSupportsGraphics;
663 m_fIsGuestSupportsSeamless = fIsGuestSupportsSeamless;
664
665 /* Notify listeners about GA state really changed: */
666 LogRel(("GUI: UISession::sltAdditionsChange: GA state really changed, notifying listeners.\n"));
667 emit sigAdditionsStateActualChange();
668 }
669 else
670 LogRel(("GUI: UISession::sltAdditionsChange: GA state doesn't really changed, still notifying listeners.\n"));
671
672 /* Notify listeners about GA state change event came: */
673 emit sigAdditionsStateChange();
674}
675
676UISession::UISession(UIMachine *pMachine)
677 : QObject(pMachine)
678 /* Base variables: */
679 , m_pMachine(pMachine)
680 , m_pConsoleEventhandler(0)
681 /* Common variables: */
682 , m_enmMachineStatePrevious(KMachineState_Null)
683 , m_enmMachineState(KMachineState_Null)
684 /* Guest additions flags: */
685 , m_ulGuestAdditionsRunLevel(0)
686 , m_fIsGuestSupportsGraphics(false)
687 , m_fIsGuestSupportsSeamless(false)
688{
689}
690
691UISession::~UISession()
692{
693}
694
695bool UISession::prepare()
696{
697 /* Prepare COM stuff: */
698 if (!prepareSession())
699 return false;
700
701 /* Cache media early if requested: */
702 if (uiCommon().agressiveCaching())
703 recacheMachineMedia();
704
705 /* Prepare GUI stuff: */
706 prepareNotificationCenter();
707 prepareConsoleEventHandlers();
708 prepareFramebuffers();
709 prepareConnections();
710 prepareSignalHandling();
711
712 /* True by default: */
713 return true;
714}
715
716bool UISession::prepareSession()
717{
718 /* Open session: */
719 m_comSession = uiCommon().openSession(uiCommon().managedVMUuid(),
720 uiCommon().isSeparateProcess()
721 ? KLockType_Shared
722 : KLockType_VM);
723 if (m_comSession.isNull())
724 return false;
725
726 /* Get machine: */
727 m_comMachine = m_comSession.GetMachine();
728 if (m_comMachine.isNull())
729 return false;
730
731 /* Get console: */
732 m_comConsole = m_comSession.GetConsole();
733 if (m_comConsole.isNull())
734 return false;
735
736 /* Get display: */
737 m_comDisplay = m_comConsole.GetDisplay();
738 if (m_comDisplay.isNull())
739 return false;
740
741 /* Get guest: */
742 m_comGuest = m_comConsole.GetGuest();
743 if (m_comGuest.isNull())
744 return false;
745
746 /* Get mouse: */
747 m_comMouse = m_comConsole.GetMouse();
748 if (m_comMouse.isNull())
749 return false;
750
751 /* Get keyboard: */
752 m_comKeyboard = m_comConsole.GetKeyboard();
753 if (m_comKeyboard.isNull())
754 return false;
755
756 /* Get debugger: */
757 m_comDebugger = m_comConsole.GetDebugger();
758 if (m_comDebugger.isNull())
759 return false;
760
761 /* Update machine-name: */
762 m_strMachineName = machine().GetName();
763
764 /* Update machine-state: */
765 m_enmMachineState = machine().GetState();
766
767 /* True by default: */
768 return true;
769}
770
771void UISession::prepareNotificationCenter()
772{
773 UINotificationCenter::create();
774}
775
776void UISession::prepareConsoleEventHandlers()
777{
778 /* Create console event-handler: */
779 m_pConsoleEventhandler = new UIConsoleEventHandler(this);
780
781 /* Console event connections: */
782 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigAdditionsChange,
783 this, &UISession::sltAdditionsChange);
784 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigAudioAdapterChange,
785 this, &UISession::sigAudioAdapterChange);
786 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigClipboardModeChange,
787 this, &UISession::sigClipboardModeChange);
788 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigCPUExecutionCapChange,
789 this, &UISession::sigCPUExecutionCapChange);
790 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigDnDModeChange,
791 this, &UISession::sigDnDModeChange);
792 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigGuestMonitorChange,
793 this, &UISession::sigGuestMonitorChange);
794 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigMediumChange,
795 this, &UISession::sigMediumChange);
796 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigNetworkAdapterChange,
797 this, &UISession::sigNetworkAdapterChange);
798 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigRecordingChange,
799 this, &UISession::sigRecordingChange);
800 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigSharedFolderChange,
801 this, &UISession::sigSharedFolderChange);
802 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigStateChange,
803 this, &UISession::sltStateChange);
804 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigStorageDeviceChange,
805 this, &UISession::sigStorageDeviceChange);
806 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigUSBControllerChange,
807 this, &UISession::sigUSBControllerChange);
808 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigUSBDeviceStateChange,
809 this, &UISession::sigUSBDeviceStateChange);
810 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigVRDEChange,
811 this, &UISession::sigVRDEChange);
812 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigRuntimeError,
813 this, &UISession::sigRuntimeError);
814
815#ifdef VBOX_WS_MAC
816 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigShowWindow,
817 this, &UISession::sigShowWindows, Qt::QueuedConnection);
818#endif
819
820 /* Console keyboard connections: */
821 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigKeyboardLedsChange,
822 this, &UISession::sigKeyboardLedsChange);
823
824 /* Console mouse connections: */
825 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigMousePointerShapeChange,
826 this, &UISession::sigMousePointerShapeChange);
827 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigMouseCapabilityChange,
828 this, &UISession::sigMouseCapabilityChange);
829 connect(m_pConsoleEventhandler, &UIConsoleEventHandler::sigCursorPositionChange,
830 this, &UISession::sigCursorPositionChange);
831}
832
833void UISession::prepareFramebuffers()
834{
835 /* Each framebuffer will be really prepared on first UIMachineView creation: */
836 m_frameBufferVector.resize(machine().GetGraphicsAdapter().GetMonitorCount());
837}
838
839void UISession::prepareConnections()
840{
841 /* UICommon connections: */
842 connect(&uiCommon(), &UICommon::sigAskToDetachCOM, this, &UISession::sltDetachCOM);
843}
844
845void UISession::prepareSignalHandling()
846{
847#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
848 struct sigaction sa;
849 sa.sa_sigaction = &signalHandlerSIGUSR1;
850 sigemptyset(&sa.sa_mask);
851 sa.sa_flags = SA_RESTART | SA_SIGINFO;
852 sigaction(SIGUSR1, &sa, NULL);
853#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
854}
855
856void UISession::cleanupFramebuffers()
857{
858 /* Cleanup framebuffers finally: */
859 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
860 {
861 UIFrameBuffer *pFrameBuffer = m_frameBufferVector[i];
862 if (pFrameBuffer)
863 {
864 /* Mark framebuffer as unused: */
865 pFrameBuffer->setMarkAsUnused(true);
866 /* Detach framebuffer from Display: */
867 pFrameBuffer->detach();
868 /* Delete framebuffer reference: */
869 delete pFrameBuffer;
870 }
871 }
872 m_frameBufferVector.clear();
873}
874
875void UISession::cleanupConsoleEventHandlers()
876{
877 /* Destroy console event-handler: */
878 delete m_pConsoleEventhandler;
879 m_pConsoleEventhandler = 0;
880}
881
882void UISession::cleanupNotificationCenter()
883{
884 UINotificationCenter::destroy();
885}
886
887void UISession::cleanupSession()
888{
889 /* Detach debugger: */
890 if (!m_comDebugger.isNull())
891 m_comDebugger.detach();
892
893 /* Detach keyboard: */
894 if (!m_comKeyboard.isNull())
895 m_comKeyboard.detach();
896
897 /* Detach mouse: */
898 if (!m_comMouse.isNull())
899 m_comMouse.detach();
900
901 /* Detach guest: */
902 if (!m_comGuest.isNull())
903 m_comGuest.detach();
904
905 /* Detach display: */
906 if (!m_comDisplay.isNull())
907 m_comDisplay.detach();
908
909 /* Detach console: */
910 if (!m_comConsole.isNull())
911 m_comConsole.detach();
912
913 /* Detach machine: */
914 if (!m_comMachine.isNull())
915 m_comMachine.detach();
916
917 /* Close session: */
918 if (!m_comSession.isNull() && uiCommon().isVBoxSVCAvailable())
919 {
920 m_comSession.UnlockMachine();
921 m_comSession.detach();
922 }
923}
924
925UIMachineLogic *UISession::machineLogic() const
926{
927 return uimachine() ? uimachine()->machineLogic() : 0;
928}
929
930UIMachineWindow *UISession::activeMachineWindow() const
931{
932 return machineLogic() ? machineLogic()->activeMachineWindow() : 0;
933}
934
935QWidget *UISession::mainMachineWindow() const
936{
937 return machineLogic() ? machineLogic()->mainMachineWindow() : 0;
938}
939
940bool UISession::preprocessInitialization()
941{
942#ifdef VBOX_WITH_NETFLT
943 /* Skip network interface name checks if VM in saved state: */
944 if (!isSaved())
945 {
946 /* Make sure all the attached and enabled network
947 * adapters are present on the host. This check makes sense
948 * in two cases only - when attachement type is Bridged Network
949 * or Host-only Interface. NOTE: Only currently enabled
950 * attachement type is checked (incorrect parameters check for
951 * currently disabled attachement types is skipped). */
952 QStringList failedInterfaceNames;
953 QStringList availableInterfaceNames;
954
955 /* Create host network interface names list: */
956 foreach (const CHostNetworkInterface &comNetIface, uiCommon().host().GetNetworkInterfaces())
957 {
958 availableInterfaceNames << comNetIface.GetName();
959 availableInterfaceNames << comNetIface.GetShortName();
960 }
961
962 /* Enumerate all the virtual network adapters: */
963 const ulong cCount = uiCommon().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine().GetChipsetType());
964 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
965 {
966 CNetworkAdapter comNetworkAdapter = machine().GetNetworkAdapter(uAdapterIndex);
967 if (comNetworkAdapter.GetEnabled())
968 {
969 /* Get physical network interface name for
970 * currently enabled network attachement type: */
971 QString strInterfaceName;
972 switch (comNetworkAdapter.GetAttachmentType())
973 {
974 case KNetworkAttachmentType_Bridged:
975 strInterfaceName = comNetworkAdapter.GetBridgedInterface();
976 break;
977#ifndef VBOX_WITH_VMNET
978 case KNetworkAttachmentType_HostOnly:
979 strInterfaceName = comNetworkAdapter.GetHostOnlyInterface();
980 break;
981#endif /* !VBOX_WITH_VMNET */
982 default:
983 break;
984 }
985
986 if ( !strInterfaceName.isEmpty()
987 && !availableInterfaceNames.contains(strInterfaceName))
988 {
989 LogRel(("GUI: Invalid network interface found: %s\n", strInterfaceName.toUtf8().constData()));
990 failedInterfaceNames << QString("%1 (adapter %2)").arg(strInterfaceName).arg(uAdapterIndex + 1);
991 }
992 }
993 }
994
995 /* Check if non-existent interfaces found: */
996 if (!failedInterfaceNames.isEmpty())
997 {
998 if (msgCenter().warnAboutNetworkInterfaceNotFound(machineName(), failedInterfaceNames.join(", ")))
999 machineLogic()->openNetworkSettingsDialog();
1000 else
1001 {
1002 LogRel(("GUI: Aborting startup due to preprocess initialization issue detected...\n"));
1003 return false;
1004 }
1005 }
1006 }
1007#endif /* VBOX_WITH_NETFLT */
1008
1009 /* Check for USB enumeration warning. Don't return false even if we have a warning: */
1010 CHost comHost = uiCommon().host();
1011 if (comHost.GetUSBDevices().isEmpty() && comHost.isWarning())
1012 {
1013 /* Do not bitch if USB disabled: */
1014 if (!machine().GetUSBControllers().isEmpty())
1015 {
1016 /* Do not bitch if there are no filters (check if enabled too?): */
1017 if (!machine().GetUSBDeviceFilters().GetDeviceFilters().isEmpty())
1018 UINotificationMessage::cannotEnumerateHostUSBDevices(comHost);
1019 }
1020 }
1021
1022 /* True by default: */
1023 return true;
1024}
1025
1026bool UISession::mountAdHocImage(KDeviceType enmDeviceType, UIMediumDeviceType enmMediumType, const QString &strMediumName)
1027{
1028 /* Get VBox: */
1029 CVirtualBox comVBox = uiCommon().virtualBox();
1030
1031 /* Prepare medium to mount: */
1032 UIMedium guiMedium;
1033
1034 /* The 'none' medium name means ejecting what ever is in the drive,
1035 * in that case => leave the guiMedium variable null. */
1036 if (strMediumName != "none")
1037 {
1038 /* Open the medium: */
1039 const CMedium comMedium = comVBox.OpenMedium(strMediumName, enmDeviceType, KAccessMode_ReadWrite, false /* fForceNewUuid */);
1040 if (!comVBox.isOk() || comMedium.isNull())
1041 {
1042 UINotificationMessage::cannotOpenMedium(comVBox, strMediumName);
1043 return false;
1044 }
1045
1046 /* Make sure medium ID is valid: */
1047 const QUuid uMediumId = comMedium.GetId();
1048 AssertReturn(!uMediumId.isNull(), false);
1049
1050 /* Try to find UIMedium among cached: */
1051 guiMedium = uiCommon().medium(uMediumId);
1052 if (guiMedium.isNull())
1053 {
1054 /* Cache new one if necessary: */
1055 guiMedium = UIMedium(comMedium, enmMediumType, KMediumState_Created);
1056 uiCommon().createMedium(guiMedium);
1057 }
1058 }
1059
1060 /* Search for a suitable storage slots: */
1061 QList<ExactStorageSlot> aFreeStorageSlots;
1062 QList<ExactStorageSlot> aBusyStorageSlots;
1063 foreach (const CStorageController &comController, machine().GetStorageControllers())
1064 {
1065 foreach (const CMediumAttachment &comAttachment, machine().GetMediumAttachmentsOfController(comController.GetName()))
1066 {
1067 /* Look for an optical devices only: */
1068 if (comAttachment.GetType() == enmDeviceType)
1069 {
1070 /* Append storage slot to corresponding list: */
1071 if (comAttachment.GetMedium().isNull())
1072 aFreeStorageSlots << ExactStorageSlot(comController.GetName(), comController.GetBus(),
1073 comAttachment.GetPort(), comAttachment.GetDevice());
1074 else
1075 aBusyStorageSlots << ExactStorageSlot(comController.GetName(), comController.GetBus(),
1076 comAttachment.GetPort(), comAttachment.GetDevice());
1077 }
1078 }
1079 }
1080
1081 /* Make sure at least one storage slot found: */
1082 QList<ExactStorageSlot> sStorageSlots = aFreeStorageSlots + aBusyStorageSlots;
1083 if (sStorageSlots.isEmpty())
1084 {
1085 UINotificationMessage::cannotMountImage(machineName(), strMediumName);
1086 return false;
1087 }
1088
1089 /* Try to mount medium into first available storage slot: */
1090 while (!sStorageSlots.isEmpty())
1091 {
1092 const ExactStorageSlot storageSlot = sStorageSlots.takeFirst();
1093 machine().MountMedium(storageSlot.controller, storageSlot.port, storageSlot.device, guiMedium.medium(), false /* force */);
1094 if (machine().isOk())
1095 break;
1096 }
1097
1098 /* Show error message if necessary: */
1099 if (!machine().isOk())
1100 {
1101 msgCenter().cannotRemountMedium(machine(), guiMedium, true /* mount? */, false /* retry? */, activeMachineWindow());
1102 return false;
1103 }
1104
1105 /* Save machine settings: */
1106 machine().SaveSettings();
1107
1108 /* Show error message if necessary: */
1109 if (!machine().isOk())
1110 {
1111 UINotificationMessage::cannotSaveMachineSettings(machine());
1112 return false;
1113 }
1114
1115 /* True by default: */
1116 return true;
1117}
1118
1119void UISession::recacheMachineMedia()
1120{
1121 /* Compose a list of machine media: */
1122 CMediumVector comMedia;
1123
1124 /* Enumerate all the controllers: */
1125 foreach (const CStorageController &comController, machine().GetStorageControllers())
1126 {
1127 /* Enumerate all the attachments: */
1128 foreach (const CMediumAttachment &comAttachment, machine().GetMediumAttachmentsOfController(comController.GetName()))
1129 {
1130 /* Skip unrelated device types: */
1131 const KDeviceType enmDeviceType = comAttachment.GetType();
1132 if ( enmDeviceType != KDeviceType_HardDisk
1133 && enmDeviceType != KDeviceType_Floppy
1134 && enmDeviceType != KDeviceType_DVD)
1135 continue;
1136 if ( comAttachment.GetIsEjected()
1137 || comAttachment.GetMedium().isNull())
1138 continue;
1139 comMedia.append(comAttachment.GetMedium());
1140 }
1141 }
1142
1143 /* Start media enumeration: */
1144 uiCommon().enumerateMedia(comMedia);
1145}
1146
1147#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
1148/**
1149 * Custom signal handler. When switching VTs, we might not get release events
1150 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
1151 * be saved with modifier keys stuck. This is annoying enough for introducing
1152 * this hack.
1153 */
1154/* static */
1155static void signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
1156{
1157 /* Only SIGUSR1 is interesting: */
1158 if (sig == SIGUSR1)
1159 if (gpMachine)
1160 gpMachine->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
1161}
1162#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
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