VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp

Last change on this file was 106556, checked in by vboxsync, 7 weeks ago

FE/Qt: bugref:10513: Runtime UI / Machine-logic: At VM startup (if selected bridged adapter wasn't found) we should open Network settings dialog the modal way to pause startup for a moment while another adapter being chosen.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 121.3 KB
Line 
1/* $Id: UIMachineLogic.cpp 106556 2024-10-21 11:20:06Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMachineLogic class implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2024 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 <QActionGroup>
30#include <QApplication>
31#include <QDateTime>
32#include <QDir>
33#include <QEventLoop>
34#include <QFileInfo>
35#include <QImageWriter>
36#include <QPainter>
37#include <QRegularExpression>
38#include <QTimer>
39#ifdef VBOX_WS_MAC
40# include <QMenuBar>
41#endif /* VBOX_WS_MAC */
42
43/* GUI includes: */
44#include "QIFileDialog.h"
45#include "UIActionPoolRuntime.h"
46#include "UIAddDiskEncryptionPasswordDialog.h"
47#include "UIAdvancedSettingsDialogSpecific.h"
48#include "UIBootFailureDialog.h"
49#include "UICommon.h"
50#include "UIConverter.h"
51#include "UIDesktopWidgetWatchdog.h"
52#include "UIExtraDataManager.h"
53#include "UIFileManagerDialog.h"
54#include "UIFrameBuffer.h"
55#include "UIGlobalSession.h"
56#include "UIGuestProcessControlDialog.h"
57#include "UIHelpBrowserDialog.h"
58#include "UIHostComboEditor.h"
59#include "UIIconPool.h"
60#include "UIKeyboardHandler.h"
61#include "UILoggingDefs.h"
62#include "UIMachine.h"
63#include "UIMachineLogic.h"
64#include "UIMachineLogicFullscreen.h"
65#include "UIMachineLogicNormal.h"
66#include "UIMachineLogicSeamless.h"
67#include "UIMachineLogicScale.h"
68#include "UIMachineView.h"
69#include "UIMachineWindow.h"
70#include "UIMedium.h"
71#include "UIMediumTools.h"
72#include "UIMessageCenter.h"
73#include "UIModalWindowManager.h"
74#include "UIMouseHandler.h"
75#include "UINotificationCenter.h"
76#include "UISoftKeyboard.h"
77#include "UITranslationEventListener.h"
78#include "UITakeSnapshotDialog.h"
79#include "UIUSBTools.h"
80#include "UIVersion.h"
81#include "UIVirtualBoxEventHandler.h"
82#include "UIVMLogViewerDialog.h"
83#include "UIVMInformationDialog.h"
84#ifdef VBOX_WS_MAC
85# include "DockIconPreview.h"
86# include "UIExtraDataManager.h"
87#endif
88#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
89# include "UINetworkRequestManager.h"
90#endif
91#ifdef VBOX_WS_NIX
92# include "VBoxUtils-nix.h"
93#endif
94
95/* COM includes: */
96#include "CAudioAdapter.h"
97#include "CAudioSettings.h"
98#include "CEmulatedUSB.h"
99#include "CGraphicsAdapter.h"
100#include "CHostUSBDevice.h"
101#include "CHostVideoInputDevice.h"
102#include "CMachineDebugger.h"
103#include "CMediumAttachment.h"
104#include "CNetworkAdapter.h"
105#include "CPlatformProperties.h"
106#include "CRecordingSettings.h"
107#include "CSnapshot.h"
108#include "CStorageController.h"
109#include "CSystemProperties.h"
110#include "CUSBDevice.h"
111#include "CVirtualBoxErrorInfo.h"
112#include "CVRDEServer.h"
113
114/* Other VBox includes: */
115#include <iprt/path.h>
116
117/* VirtualBox interface declarations: */
118#include <VBox/com/VirtualBox.h>
119
120/* External / Other VBox includes: */
121#ifdef VBOX_WS_MAC
122# include "DarwinKeyboard.h"
123#endif
124#ifdef VBOX_WS_WIN
125# include "WinKeyboard.h"
126# include "VBoxUtils-win.h"
127#endif
128#ifdef VBOX_WS_NIX
129# include <XKeyboard.h>
130#endif
131
132#define VBOX_WITH_REWORKED_SESSION_INFORMATION /**< Define for reworked session-information window. @todo r-bird: What's this for? */
133
134struct USBTarget
135{
136 USBTarget() : attach(false), id(QUuid()) {}
137 USBTarget(bool fAttach, const QUuid &uId)
138 : attach(fAttach), id(uId) {}
139 bool attach;
140 QUuid id;
141};
142Q_DECLARE_METATYPE(USBTarget);
143
144/** Describes enumerated webcam item. */
145struct WebCamTarget
146{
147 WebCamTarget() : attach(false), name(QString()), path(QString()) {}
148 WebCamTarget(bool fAttach, const QString &strName, const QString &strPath)
149 : attach(fAttach), name(strName), path(strPath) {}
150 bool attach;
151 QString name;
152 QString path;
153};
154Q_DECLARE_METATYPE(WebCamTarget);
155
156/* static */
157UIMachineLogic *UIMachineLogic::create(UIMachine *pMachine,
158 UIVisualStateType enmVisualStateType)
159{
160 AssertPtrReturn(pMachine, 0);
161
162 UIMachineLogic *pLogic = 0;
163 switch (enmVisualStateType)
164 {
165 case UIVisualStateType_Normal:
166 pLogic = new UIMachineLogicNormal(pMachine);
167 break;
168 case UIVisualStateType_Fullscreen:
169 pLogic = new UIMachineLogicFullscreen(pMachine);
170 break;
171 case UIVisualStateType_Seamless:
172 pLogic = new UIMachineLogicSeamless(pMachine);
173 break;
174 case UIVisualStateType_Scale:
175 pLogic = new UIMachineLogicScale(pMachine);
176 break;
177 case UIVisualStateType_Invalid:
178 case UIVisualStateType_All:
179 break;
180 }
181 return pLogic;
182}
183
184/* static */
185void UIMachineLogic::destroy(UIMachineLogic *&pLogic)
186{
187 if (!pLogic)
188 return;
189 pLogic->cleanup();
190 delete pLogic;
191 pLogic = 0;
192}
193
194void UIMachineLogic::prepare()
195{
196 /* Prepare required features: */
197 prepareRequiredFeatures();
198
199 /* Prepare session connections: */
200 prepareSessionConnections();
201
202 /* Prepare action groups:
203 * Note: This has to be done before prepareActionConnections
204 * cause here actions/menus are recreated. */
205 prepareActionGroups();
206 /* Prepare action connections: */
207 prepareActionConnections();
208
209 /* Prepare other connections: */
210 prepareOtherConnections();
211
212 /* Prepare handlers: */
213 prepareHandlers();
214
215 /* Prepare menu: */
216 prepareMenu();
217
218 /* Prepare machine-window(s): */
219 prepareMachineWindows();
220
221#ifdef VBOX_WS_MAC
222 /* Prepare dock: */
223 prepareDock();
224#endif /* VBOX_WS_MAC */
225
226 /* Load settings: */
227 loadSettings();
228
229 /* Retranslate logic part: */
230 sltRetranslateUI();
231 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
232 this, &UIMachineLogic::sltRetranslateUI);
233}
234
235void UIMachineLogic::cleanup()
236{
237#ifdef VBOX_WITH_DEBUGGER_GUI
238 /* Cleanup debugger: */
239 cleanupDebugger();
240#endif /* VBOX_WITH_DEBUGGER_GUI */
241
242#ifdef VBOX_WS_MAC
243 /* Cleanup dock: */
244 cleanupDock();
245#endif /* VBOX_WS_MAC */
246
247 /* Cleanup menu: */
248 cleanupMenu();
249
250 /* Cleanup machine-window(s): */
251 cleanupMachineWindows();
252
253 /* Cleanup handlers: */
254 cleanupHandlers();
255
256 /* Cleanup action connections: */
257 cleanupActionConnections();
258 /* Cleanup action groups: */
259 cleanupActionGroups();
260
261 /* Cleanup session connections: */
262 cleanupSessionConnections();
263}
264
265UIActionPool *UIMachineLogic::actionPool() const
266{
267 return uimachine()->actionPool();
268}
269
270QString UIMachineLogic::machineName() const
271{
272 return uimachine()->machineName();
273}
274
275UIMachineWindow* UIMachineLogic::mainMachineWindow() const
276{
277 /* Null if machine-window(s) not yet created: */
278 if (!isMachineWindowsCreated())
279 return 0;
280
281 /* First machine-window by default: */
282 return machineWindows().value(0);
283}
284
285UIMachineWindow* UIMachineLogic::activeMachineWindow() const
286{
287 /* Null if machine-window(s) not yet created: */
288 if (!isMachineWindowsCreated())
289 return 0;
290
291 /* Check if there is an active window present: */
292 for (int i = 0; i < machineWindows().size(); ++i)
293 {
294 UIMachineWindow *pIteratedWindow = machineWindows()[i];
295 if (pIteratedWindow->isActiveWindow())
296 return pIteratedWindow;
297 }
298
299 /* Main machine-window by default: */
300 return mainMachineWindow();
301}
302
303void UIMachineLogic::adjustMachineWindowsGeometry()
304{
305 /* By default, the only thing we need is to
306 * adjust machine-view size(s) if necessary: */
307 foreach(UIMachineWindow *pMachineWindow, machineWindows())
308 pMachineWindow->adjustMachineViewSize();
309}
310
311void UIMachineLogic::sendMachineWindowsSizeHints()
312{
313 /* By default, the only thing we need is to
314 * send machine-view(s) size-hint(s) to the guest: */
315 foreach(UIMachineWindow *pMachineWindow, machineWindows())
316 pMachineWindow->sendMachineViewSizeHint();
317}
318
319void UIMachineLogic::openNetworkSettingsDialogTheModalWay()
320{
321 /* Open VM settings : Network page: */
322 openSettingsDialog("#network", QString(), true /* app modal */);
323 /* Create event loop to listen to VM settings dialog destroy signal: */
324 QEventLoop loop;
325 connect(m_settings.value(UIAdvancedSettingsDialog::Type_Machine),
326 &QObject::destroyed, &loop, &QEventLoop::quit);
327 /* Execute loop finally: */
328 loop.exec();
329}
330
331#ifdef VBOX_WS_MAC
332void UIMachineLogic::updateDockIcon()
333{
334 if (!isMachineWindowsCreated())
335 return;
336
337 if ( m_fIsDockIconEnabled
338 && m_pDockIconPreview)
339 if(UIMachineView *pView = machineWindows().at(m_DockIconPreviewMonitor)->machineView())
340 if (CGImageRef image = pView->vmContentImage())
341 {
342 m_pDockIconPreview->updateDockPreview(image);
343 CGImageRelease(image);
344 }
345}
346
347void UIMachineLogic::updateDockIconSize(int screenId, int width, int height)
348{
349 if (!isMachineWindowsCreated())
350 return;
351
352 if ( m_fIsDockIconEnabled
353 && m_pDockIconPreview
354 && m_DockIconPreviewMonitor == screenId)
355 m_pDockIconPreview->setOriginalSize(width, height);
356}
357
358UIMachineView* UIMachineLogic::dockPreviewView() const
359{
360 if ( m_fIsDockIconEnabled
361 && m_pDockIconPreview)
362 return machineWindows().at(m_DockIconPreviewMonitor)->machineView();
363 return 0;
364}
365#endif /* VBOX_WS_MAC */
366
367void UIMachineLogic::sltHandleVBoxSVCAvailabilityChange()
368{
369 /* Do nothing if VBoxSVC still availabile: */
370 if (gpGlobalSession->isVBoxSVCAvailable())
371 return;
372
373 /* Warn user about that: */
374 msgCenter().warnAboutVBoxSVCUnavailable();
375
376 /* Power VM off: */
377 LogRel(("GUI: Request to power VM off due to VBoxSVC is unavailable.\n"));
378 uimachine()->powerOff(false /* do NOT restore current snapshot */);
379}
380
381void UIMachineLogic::sltHandleMachineInitialized()
382{
383#ifdef VBOX_WITH_DEBUGGER_GUI
384 prepareDebugger();
385#endif
386 sltMachineStateChanged();
387 sltAdditionsStateChanged();
388 sltMouseCapabilityChanged();
389}
390
391void UIMachineLogic::sltChangeVisualStateToNormal()
392{
393 uimachine()->setRequestedVisualState(UIVisualStateType_Invalid);
394 uimachine()->asyncChangeVisualState(UIVisualStateType_Normal);
395}
396
397void UIMachineLogic::sltChangeVisualStateToFullscreen()
398{
399 uimachine()->setRequestedVisualState(UIVisualStateType_Invalid);
400 uimachine()->asyncChangeVisualState(UIVisualStateType_Fullscreen);
401}
402
403void UIMachineLogic::sltChangeVisualStateToSeamless()
404{
405 uimachine()->setRequestedVisualState(UIVisualStateType_Invalid);
406 uimachine()->asyncChangeVisualState(UIVisualStateType_Seamless);
407}
408
409void UIMachineLogic::sltChangeVisualStateToScale()
410{
411 uimachine()->setRequestedVisualState(UIVisualStateType_Invalid);
412 uimachine()->asyncChangeVisualState(UIVisualStateType_Scale);
413}
414
415void UIMachineLogic::sltMachineStateChanged()
416{
417 /* Get machine state: */
418 KMachineState state = uimachine()->machineState();
419
420 /* Update action groups: */
421 m_pRunningActions->setEnabled(uimachine()->isRunning());
422 m_pRunningOrPausedActions->setEnabled(uimachine()->isRunning() || uimachine()->isPaused());
423 m_pRunningOrPausedOrStuckActions->setEnabled(uimachine()->isRunning() || uimachine()->isPaused() || uimachine()->isStuck());
424
425 switch (state)
426 {
427 case KMachineState_Stuck:
428 {
429 /* Prevent machine-view from resizing: */
430 uimachine()->setGuestResizeIgnored(true);
431 /* Get log-folder: */
432 QString strLogFolder;
433 uimachine()->acquireLogFolder(strLogFolder);
434 /* Take the screenshot for debugging purposes: */
435 takeScreenshot(strLogFolder + "/VBox.png", "png");
436 /* How should we handle Guru Meditation? */
437 switch (gEDataManager->guruMeditationHandlerType(uiCommon().managedVMUuid()))
438 {
439 /* Ask how to proceed; Power off VM if proposal accepted: */
440 case GuruMeditationHandlerType_Default:
441 {
442 if (msgCenter().warnAboutGuruMeditation(QDir::toNativeSeparators(strLogFolder)))
443 {
444 LogRel(("GUI: User requested to power VM off on Guru Meditation.\n"));
445 uimachine()->powerOff(false /* do NOT restore current snapshot */);
446 }
447 break;
448 }
449 /* Power off VM silently: */
450 case GuruMeditationHandlerType_PowerOff:
451 {
452 LogRel(("GUI: Automatic request to power VM off on Guru Meditation.\n"));
453 uimachine()->powerOff(false /* do NOT restore current snapshot */);
454 break;
455 }
456 /* Just ignore it: */
457 case GuruMeditationHandlerType_Ignore:
458 default:
459 break;
460 }
461 break;
462 }
463 case KMachineState_Paused:
464 case KMachineState_TeleportingPausedVM:
465 {
466 QAction *pPauseAction = actionPool()->action(UIActionIndexRT_M_Machine_T_Pause);
467 if (!pPauseAction->isChecked())
468 {
469 /* Was paused from CSession side: */
470 pPauseAction->blockSignals(true);
471 pPauseAction->setChecked(true);
472 pPauseAction->blockSignals(false);
473 }
474 break;
475 }
476 case KMachineState_Running:
477 case KMachineState_Teleporting:
478 case KMachineState_LiveSnapshotting:
479 {
480 QAction *pPauseAction = actionPool()->action(UIActionIndexRT_M_Machine_T_Pause);
481 if (pPauseAction->isChecked())
482 {
483 /* Was resumed from CSession side: */
484 pPauseAction->blockSignals(true);
485 pPauseAction->setChecked(false);
486 pPauseAction->blockSignals(false);
487 }
488 break;
489 }
490 case KMachineState_PoweredOff:
491 case KMachineState_Saved:
492 case KMachineState_Teleported:
493 case KMachineState_Aborted:
494 case KMachineState_AbortedSaved:
495 {
496 /* Spontaneous machine-state-change ('manual-override' mode): */
497 if (!uimachine()->isManualOverrideMode())
498 {
499 /* For separate process: */
500 if (uiCommon().isSeparateProcess())
501 {
502 LogRel(("GUI: Waiting for session to be unlocked to close Runtime UI..\n"));
503 }
504 /* For embedded process: */
505 else
506 {
507 /* We just close Runtime UI: */
508 LogRel(("GUI: Request to close Runtime UI because VM is powered off.\n"));
509 uimachine()->closeRuntimeUI();
510 return;
511 }
512 }
513 break;
514 }
515 case KMachineState_Saving:
516 {
517 /* Insert a host combo release if press has been inserted: */
518 typeHostKeyComboPressRelease(false);
519 break;
520 }
521#ifdef VBOX_WS_NIX
522 case KMachineState_Starting:
523 case KMachineState_Restoring:
524 case KMachineState_TeleportingIn:
525 {
526 if (NativeWindowSubsystem::displayServerType() == VBGHDISPLAYSERVERTYPE_X11)
527 {
528 /* The keyboard handler may wish to do some release logging on startup.
529 * Tell it that the logger is now active. */
530 doXKeyboardLogging(NativeWindowSubsystem::X11GetDisplay());
531 }
532 break;
533 }
534#endif
535 default:
536 break;
537 }
538
539#ifdef VBOX_WS_MAC
540 /* Update Dock Overlay: */
541 updateDockOverlay();
542#endif /* VBOX_WS_MAC */
543}
544
545void UIMachineLogic::sltSessionStateChanged(const QUuid &uId, const KSessionState enmState)
546{
547 /* Make sure that's our signal: */
548 if (uId != uiCommon().managedVMUuid())
549 return;
550
551 switch (enmState)
552 {
553 case KSessionState_Unlocked:
554 {
555 /* Spontaneous machine-state-change ('manual-override' mode): */
556 if (!uimachine()->isManualOverrideMode())
557 {
558 /* For separate process: */
559 if (uiCommon().isSeparateProcess())
560 {
561 LogRel(("GUI: Request to close Runtime UI because session is unlocked.\n"));
562 uimachine()->closeRuntimeUI();
563 return;
564 }
565 }
566 break;
567 }
568 default:
569 break;
570 }
571}
572
573void UIMachineLogic::sltAdditionsStateChanged()
574{
575 /* Update action states: */
576 LogRel3(("GUI: UIMachineLogic::sltAdditionsStateChanged: Adjusting actions availability according to GA state.\n"));
577 actionPool()->action(UIActionIndexRT_M_View_T_Seamless)->setEnabled(uimachine()->isVisualStateAllowed(UIVisualStateType_Seamless) &&
578 uimachine()->isGuestSupportsSeamless());
579}
580
581void UIMachineLogic::sltMouseCapabilityChanged()
582{
583 /* Variable falgs: */
584 bool fIsMouseSupportsAbsolute = uimachine()->isMouseSupportsAbsolute();
585 bool fIsMouseSupportsRelative = uimachine()->isMouseSupportsRelative();
586 bool fIsMouseSupportsTouchScreen = uimachine()->isMouseSupportsTouchScreen();
587 bool fIsMouseSupportsTouchPad = uimachine()->isMouseSupportsTouchPad();
588 bool fIsMouseHostCursorNeeded = uimachine()->isMouseHostCursorNeeded();
589
590 /* For now MT stuff is not important for MI action: */
591 Q_UNUSED(fIsMouseSupportsTouchScreen);
592 Q_UNUSED(fIsMouseSupportsTouchPad);
593
594 /* Update action state: */
595 QAction *pAction = actionPool()->action(UIActionIndexRT_M_Input_M_Mouse_T_Integration);
596 pAction->setEnabled(fIsMouseSupportsAbsolute && fIsMouseSupportsRelative && !fIsMouseHostCursorNeeded);
597 if (fIsMouseHostCursorNeeded)
598 pAction->setChecked(true);
599}
600
601void UIMachineLogic::sltDisableHostScreenSaverStateChanged(bool fDisabled)
602{
603#if defined(VBOX_WS_NIX)
604 /* Find the methods once and cache them: */
605 if (m_methods.isEmpty())
606 m_methods = NativeWindowSubsystem::findDBusScrenSaverInhibitMethods();
607 NativeWindowSubsystem::toggleHostScrenSaver(fDisabled, m_methods);
608#elif defined(VBOX_WS_WIN)
609 NativeWindowSubsystem::setScreenSaverActive(fDisabled);
610#else
611 Q_UNUSED(fDisabled);
612#endif
613}
614
615void UIMachineLogic::sltKeyboardLedsChanged()
616{
617 /* Here we have to update host LED lock states using values provided by UIMachine:
618 * [bool] uimachine() -> isNumLock(), isCapsLock(), isScrollLock() can be used for that. */
619
620 if (!uimachine()->isHidLedsSyncEnabled())
621 return;
622
623 /* Check if we accidentally trying to manipulate LEDs when host LEDs state was deallocated. */
624 if (!m_pHostLedsState)
625 return;
626
627#if defined(VBOX_WS_MAC)
628 DarwinHidDevicesBroadcastLeds(m_pHostLedsState, uimachine()->isNumLock(), uimachine()->isCapsLock(), uimachine()->isScrollLock());
629#elif defined(VBOX_WS_WIN)
630 if (!winHidLedsInSync(uimachine()->isNumLock(), uimachine()->isCapsLock(), uimachine()->isScrollLock()))
631 {
632 keyboardHandler()->winSkipKeyboardEvents(true);
633 WinHidDevicesBroadcastLeds(uimachine()->isNumLock(), uimachine()->isCapsLock(), uimachine()->isScrollLock());
634 keyboardHandler()->winSkipKeyboardEvents(false);
635 }
636 else
637 LogRel2(("GUI: HID LEDs Sync: already in sync\n"));
638#else
639 LogRelFlow(("UIMachineLogic::sltKeyboardLedsChanged: Updating host LED lock states does not supported on this platform.\n"));
640#endif
641}
642
643void UIMachineLogic::sltUSBDeviceStateChange(const CUSBDevice &device, bool fIsAttached, const CVirtualBoxErrorInfo &error)
644{
645 /* Check if USB device have anything to tell us: */
646 if (!error.isNull())
647 {
648 if (fIsAttached)
649 UINotificationMessage::cannotAttachUSBDevice(error, usbDetails(device), machineName());
650 else
651 UINotificationMessage::cannotDetachUSBDevice(error, usbDetails(device), machineName());
652 }
653}
654
655void UIMachineLogic::sltRuntimeError(bool fIsFatal, const QString &strErrorId, const QString &strMessage)
656{
657 /* Preprocess known runtime error types: */
658 if (strErrorId == "DrvVD_DEKMISSING")
659 return askUserForTheDiskEncryptionPasswords();
660 else if (strErrorId == "VMBootFail")
661 {
662 if (!gEDataManager->suppressedMessages().contains(gpConverter->toInternalString(UIExtraDataMetaDefs::DialogType_BootFailure)))
663 return showBootFailureDialog();
664 else
665 return;
666 }
667
668 /* Determine current console state: */
669 const bool fPaused = uimachine()->isPaused();
670
671 /* Make sure machine is paused in case of fatal error: */
672 if (fIsFatal)
673 {
674 Assert(fPaused);
675 if (!fPaused)
676 uimachine()->pause();
677 }
678
679 /* Should the default Warning type be overridden? */
680 MessageType enmMessageType = MessageType_Warning;
681 if (fIsFatal)
682 enmMessageType = MessageType_Critical;
683 else if (fPaused)
684 enmMessageType = MessageType_Error;
685
686 /* Show runtime error: */
687 msgCenter().showRuntimeError(enmMessageType, strErrorId, strMessage);
688
689 /* Postprocessing: */
690 if (fIsFatal)
691 {
692 /* Power off after a fIsFatal error: */
693 LogRel(("GUI: Automatic request to power VM off after a fatal runtime error...\n"));
694 uimachine()->powerOff(false /* do NOT restore current snapshot */);
695 }
696}
697
698#ifdef VBOX_WS_MAC
699void UIMachineLogic::sltShowWindows()
700{
701 for (int i=0; i < machineWindows().size(); ++i)
702 UIDesktopWidgetWatchdog::restoreWidget(machineWindows().at(i));
703}
704#endif /* VBOX_WS_MAC */
705
706void UIMachineLogic::sltGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)
707{
708 LogRel(("GUI: UIMachineLogic: Guest-screen count changed\n"));
709
710 /* Make sure all machine-window(s) have proper geometry: */
711 foreach (UIMachineWindow *pMachineWindow, machineWindows())
712 pMachineWindow->showInNecessaryMode();
713
714#ifdef VBOX_WS_MAC
715 /* Update dock: */
716 updateDock();
717#endif
718}
719
720void UIMachineLogic::sltHostScreenCountChange()
721{
722#ifdef VBOX_GUI_WITH_CUSTOMIZATIONS1
723 /* Customer request to skip host-screen count change: */
724 LogRel(("GUI: UIMachineLogic: Host-screen count change skipped\n"));
725#else /* !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
726 LogRel(("GUI: UIMachineLogic: Host-screen count changed\n"));
727
728 /* Make sure all machine-window(s) have proper geometry: */
729 foreach (UIMachineWindow *pMachineWindow, machineWindows())
730 pMachineWindow->showInNecessaryMode();
731#endif /* !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
732}
733
734void UIMachineLogic::sltHostScreenGeometryChange()
735{
736#ifdef VBOX_GUI_WITH_CUSTOMIZATIONS1
737 /* Customer request to skip host-screen geometry change: */
738 LogRel(("GUI: UIMachineLogic: Host-screen geometry change skipped\n"));
739#else /* !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
740 LogRel(("GUI: UIMachineLogic: Host-screen geometry changed\n"));
741
742 /* Make sure all machine-window(s) have proper geometry: */
743 foreach (UIMachineWindow *pMachineWindow, machineWindows())
744 pMachineWindow->showInNecessaryMode();
745#endif /* !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
746}
747
748void UIMachineLogic::sltHostScreenAvailableAreaChange()
749{
750#ifdef VBOX_GUI_WITH_CUSTOMIZATIONS1
751 /* Customer request to skip host-screen available-area change: */
752 LogRel(("GUI: UIMachineLogic: Host-screen available-area change skipped\n"));
753#else /* !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
754 LogRel(("GUI: UIMachineLogic: Host-screen available-area changed\n"));
755
756 /* Make sure all machine-window(s) have proper geometry: */
757 foreach (UIMachineWindow *pMachineWindow, machineWindows())
758 pMachineWindow->showInNecessaryMode();
759#endif /* !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
760}
761
762void UIMachineLogic::sltHandleHelpRequest()
763{
764 UIHelpBrowserDialog::findManualFileAndShow();
765}
766
767UIMachineLogic::UIMachineLogic(UIMachine *pMachine)
768 : QObject(pMachine)
769 , m_pMachine(pMachine)
770 , m_pKeyboardHandler(0)
771 , m_pMouseHandler(0)
772 , m_pRunningActions(0)
773 , m_pRunningOrPausedActions(0)
774 , m_pRunningOrPausedOrStuckActions(0)
775 , m_pSharedClipboardActions(0)
776 , m_pFileTransferToggleAction(0)
777 , m_pDragAndDropActions(0)
778 , m_fIsWindowsCreated(false)
779#ifdef VBOX_WS_MAC
780 , m_fIsDockIconEnabled(true)
781 , m_pDockIconPreview(0)
782 , m_pDockPreviewSelectMonitorGroup(0)
783 , m_pDockSettingsMenuSeparator(0)
784 , m_DockIconPreviewMonitor(0)
785 , m_pDockSettingMenuAction(0)
786#endif /* VBOX_WS_MAC */
787 , m_pHostLedsState(NULL)
788 , m_pLogViewerDialog(0)
789 , m_pFileManagerDialog(0)
790 , m_pProcessControlDialog(0)
791 , m_pSoftKeyboardDialog(0)
792 , m_pVMInformationDialog(0)
793{
794}
795
796UIMachineLogic::~UIMachineLogic()
797{
798#if defined(VBOX_WS_NIX)
799 qDeleteAll(m_methods.begin(), m_methods.end());
800 m_methods.clear();
801#endif
802}
803
804void UIMachineLogic::addMachineWindow(UIMachineWindow *pMachineWindow)
805{
806 pMachineWindow->installEventFilter(this);
807 m_machineWindowsList << pMachineWindow;
808}
809
810void UIMachineLogic::setKeyboardHandler(UIKeyboardHandler *pKeyboardHandler)
811{
812 /* Set new handler: */
813 m_pKeyboardHandler = pKeyboardHandler;
814 /* Connect to uimachine: */
815 connect(m_pKeyboardHandler, &UIKeyboardHandler::sigStateChange,
816 uimachine(), &UIMachine::setKeyboardState);
817}
818
819void UIMachineLogic::setMouseHandler(UIMouseHandler *pMouseHandler)
820{
821 /* Set new handler: */
822 m_pMouseHandler = pMouseHandler;
823 /* Connect to session: */
824 connect(m_pMouseHandler, &UIMouseHandler::sigStateChange,
825 uimachine(), &UIMachine::setMouseState);
826}
827
828void UIMachineLogic::sltRetranslateUI()
829{
830#ifdef VBOX_WS_MAC
831 if (m_pDockPreviewSelectMonitorGroup)
832 {
833 const QList<QAction*> &actions = m_pDockPreviewSelectMonitorGroup->actions();
834 for (int i = 0; i < actions.size(); ++i)
835 {
836 QAction *pAction = actions.at(i);
837 pAction->setText(QApplication::translate("UIActionPool", "Preview Monitor %1").arg(pAction->data().toInt() + 1));
838 }
839 }
840#endif /* VBOX_WS_MAC */
841 /* Shared Clipboard actions: */
842 if (m_pSharedClipboardActions)
843 {
844 foreach (QAction *pAction, m_pSharedClipboardActions->actions())
845 pAction->setText(gpConverter->toString(pAction->data().value<KClipboardMode>()));
846 }
847 if (m_pDragAndDropActions)
848 {
849 foreach (QAction *pAction, m_pDragAndDropActions->actions())
850 pAction->setText(gpConverter->toString(pAction->data().value<KDnDMode>()));
851 }
852}
853
854#ifdef VBOX_WS_MAC
855void UIMachineLogic::updateDockOverlay()
856{
857 /* Only to an update to the realtime preview if this is enabled by the user
858 * & we are in an state where the framebuffer is likely valid. Otherwise to
859 * the overlay stuff only. */
860 KMachineState state = uimachine()->machineState();
861 if (m_fIsDockIconEnabled &&
862 (state == KMachineState_Running ||
863 state == KMachineState_Paused ||
864 state == KMachineState_Teleporting ||
865 state == KMachineState_LiveSnapshotting ||
866 state == KMachineState_Restoring ||
867 state == KMachineState_TeleportingPausedVM ||
868 state == KMachineState_TeleportingIn ||
869 state == KMachineState_Saving ||
870 state == KMachineState_DeletingSnapshotOnline ||
871 state == KMachineState_DeletingSnapshotPaused))
872 updateDockIcon();
873 else if (m_pDockIconPreview)
874 m_pDockIconPreview->updateDockOverlay();
875}
876#endif /* VBOX_WS_MAC */
877
878void UIMachineLogic::prepareSessionConnections()
879{
880 /* We should watch for VBoxSVC availability changes: */
881 connect(gpGlobalSession, &UIGlobalSession::sigVBoxSVCAvailabilityChange,
882 this, &UIMachineLogic::sltHandleVBoxSVCAvailabilityChange);
883
884 /* We should watch for machine UI initialization signal: */
885 connect(uimachine(), &UIMachine::sigInitialized, this, &UIMachineLogic::sltHandleMachineInitialized);
886
887 /* We should watch for requested modes: */
888 connect(uimachine(), &UIMachine::sigInitialized, this, &UIMachineLogic::sltCheckForRequestedVisualStateType, Qt::QueuedConnection);
889 connect(uimachine(), &UIMachine::sigAdditionsStateChange, this, &UIMachineLogic::sltCheckForRequestedVisualStateType);
890
891 /* We should watch for console events: */
892 connect(uimachine(), &UIMachine::sigMachineStateChange, this, &UIMachineLogic::sltMachineStateChanged);
893 connect(uimachine(), &UIMachine::sigAdditionsStateActualChange, this, &UIMachineLogic::sltAdditionsStateChanged);
894 connect(uimachine(), &UIMachine::sigMouseCapabilityChange, this, &UIMachineLogic::sltMouseCapabilityChanged);
895 connect(uimachine(), &UIMachine::sigKeyboardLedsChange, this, &UIMachineLogic::sltKeyboardLedsChanged);
896 connect(uimachine(), &UIMachine::sigUSBDeviceStateChange, this, &UIMachineLogic::sltUSBDeviceStateChange);
897 connect(uimachine(), &UIMachine::sigRuntimeError, this, &UIMachineLogic::sltRuntimeError);
898#ifdef VBOX_WS_MAC
899 connect(uimachine(), &UIMachine::sigShowWindows, this, &UIMachineLogic::sltShowWindows);
900#endif
901 connect(uimachine(), &UIMachine::sigGuestMonitorChange, this, &UIMachineLogic::sltGuestMonitorChange);
902
903 /* We should watch for host-screen-change events: */
904 connect(uimachine(), &UIMachine::sigHostScreenCountChange, this, &UIMachineLogic::sltHostScreenCountChange);
905 connect(uimachine(), &UIMachine::sigHostScreenGeometryChange, this, &UIMachineLogic::sltHostScreenGeometryChange);
906 connect(uimachine(), &UIMachine::sigHostScreenAvailableAreaChange, this, &UIMachineLogic::sltHostScreenAvailableAreaChange);
907}
908
909void UIMachineLogic::prepareActionGroups()
910{
911 /* Create group for all actions that are enabled only when the VM is running.
912 * Note that only actions whose enabled state depends exclusively on the
913 * execution state of the VM are added to this group. */
914 m_pRunningActions = new QActionGroup(this);
915 m_pRunningActions->setExclusive(false);
916
917 /* Create group for all actions that are enabled when the VM is running or paused.
918 * Note that only actions whose enabled state depends exclusively on the
919 * execution state of the VM are added to this group. */
920 m_pRunningOrPausedActions = new QActionGroup(this);
921 m_pRunningOrPausedActions->setExclusive(false);
922
923 /* Create group for all actions that are enabled when the VM is running or paused or stucked.
924 * Note that only actions whose enabled state depends exclusively on the
925 * execution state of the VM are added to this group. */
926 m_pRunningOrPausedOrStuckActions = new QActionGroup(this);
927 m_pRunningOrPausedOrStuckActions->setExclusive(false);
928
929 /* Move actions into running actions group: */
930 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_Reset));
931 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_Shutdown));
932 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_View_T_Fullscreen));
933 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_View_T_Seamless));
934 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_View_T_Scale));
935 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize));
936 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeCAD));
937#ifdef VBOX_WS_NIX
938 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeCABS));
939#endif /* VBOX_WS_NIX */
940 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeCtrlBreak));
941 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeInsert));
942 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypePrintScreen));
943 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeAltPrintScreen));
944 m_pRunningActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_T_TypeHostKeyCombo));
945
946 /* Move actions into running-n-paused actions group: */
947 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_Detach));
948 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_SaveState));
949 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_Settings));
950 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_TakeSnapshot));
951 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_ShowInformation));
952 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_ShowFileManager));
953 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_T_Pause));
954 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_ViewPopup));
955#ifndef VBOX_WS_MAC
956 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_S_MinimizeWindow));
957#endif /* !VBOX_WS_MAC */
958 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_S_AdjustWindow));
959 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_S_TakeScreenshot));
960 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_M_Recording));
961 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_M_Recording_S_Settings));
962 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_M_Recording_T_Start));
963 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer));
964 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_M_MenuBar));
965 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_S_Settings));
966#ifndef VBOX_WS_MAC
967 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_T_Visibility));
968#endif /* !VBOX_WS_MAC */
969 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_M_StatusBar));
970 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_S_Settings));
971 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility));
972 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard));
973 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_Settings));
974 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_SoftKeyboard));
975 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Mouse));
976 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Input_M_Mouse_T_Integration));
977 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_HardDrives));
978 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_HardDrives_S_Settings));
979 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices));
980 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices));
981 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_Audio));
982 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output));
983 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output));
984 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_Network));
985 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_Network_S_Settings));
986 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_USBDevices));
987 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_USBDevices_S_Settings));
988 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_WebCams));
989 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_SharedClipboard));
990 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_DragAndDrop));
991 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_SharedFolders));
992 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_M_SharedFolders_S_Settings));
993 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_S_InsertGuestAdditionsDisk));
994 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndexRT_M_Devices_S_UpgradeGuestAdditions));
995#ifdef VBOX_WS_MAC
996 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndex_M_Window));
997 m_pRunningOrPausedActions->addAction(actionPool()->action(UIActionIndex_M_Window_S_Minimize));
998#endif /* VBOX_WS_MAC */
999
1000 /* Move actions into running-n-paused-n-stuck actions group: */
1001#ifdef VBOX_WITH_DEBUGGER_GUI
1002 m_pRunningOrPausedOrStuckActions->addAction(actionPool()->action(UIActionIndexRT_M_Debug));
1003 m_pRunningOrPausedOrStuckActions->addAction(actionPool()->action(UIActionIndexRT_M_Debug_S_ShowStatistics));
1004 m_pRunningOrPausedOrStuckActions->addAction(actionPool()->action(UIActionIndexRT_M_Debug_S_ShowCommandLine));
1005 m_pRunningOrPausedOrStuckActions->addAction(actionPool()->action(UIActionIndexRT_M_Debug_T_Logging));
1006 m_pRunningOrPausedOrStuckActions->addAction(actionPool()->action(UIActionIndexRT_M_Debug_S_GuestControlConsole));
1007#endif /* VBOX_WITH_DEBUGGER_GUI */
1008 m_pRunningOrPausedOrStuckActions->addAction(actionPool()->action(UIActionIndexRT_M_Machine_S_PowerOff));
1009}
1010
1011void UIMachineLogic::prepareActionConnections()
1012{
1013 /* 'Application' actions connection: */
1014 connect(actionPool()->action(UIActionIndex_M_Application_S_Preferences), &UIAction::triggered,
1015 this, &UIMachineLogic::sltOpenPreferencesDialogDefault);
1016 connect(actionPool()->action(UIActionIndex_M_Application_S_Close), &UIAction::triggered,
1017 this, &UIMachineLogic::sltClose);
1018
1019 /* 'Machine' actions connections: */
1020 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_Settings), &UIAction::triggered,
1021 this, &UIMachineLogic::sltOpenSettingsDialogDefault);
1022 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_TakeSnapshot), &UIAction::triggered,
1023 this, &UIMachineLogic::sltTakeSnapshot);
1024 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_ShowInformation), &UIAction::triggered,
1025 this, &UIMachineLogic::sltShowInformationDialog);
1026 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_ShowFileManager), &UIAction::triggered,
1027 this, &UIMachineLogic::sltShowFileManagerDialog);
1028 connect(actionPool()->action(UIActionIndexRT_M_Machine_T_Pause), &UIAction::toggled,
1029 this, &UIMachineLogic::sltPause);
1030 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_Reset), &UIAction::triggered,
1031 this, &UIMachineLogic::sltReset);
1032 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_Detach), &UIAction::triggered,
1033 this, &UIMachineLogic::sltDetach, Qt::QueuedConnection);
1034 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_SaveState), &UIAction::triggered,
1035 this, &UIMachineLogic::sltSaveState, Qt::QueuedConnection);
1036 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_Shutdown), &UIAction::triggered,
1037 this, &UIMachineLogic::sltShutdown);
1038 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_PowerOff), &UIAction::triggered,
1039 this, &UIMachineLogic::sltPowerOff, Qt::QueuedConnection);
1040 connect(actionPool()->action(UIActionIndexRT_M_Machine_S_ShowLogDialog), &UIAction::triggered,
1041 this, &UIMachineLogic::sltShowLogDialog);
1042
1043 /* 'View' actions connections: */
1044#ifndef VBOX_WS_MAC
1045 connect(actionPool()->action(UIActionIndexRT_M_View_S_MinimizeWindow), &UIAction::triggered,
1046 this, &UIMachineLogic::sltMinimizeActiveMachineWindow, Qt::QueuedConnection);
1047#endif /* !VBOX_WS_MAC */
1048 connect(actionPool()->action(UIActionIndexRT_M_View_S_AdjustWindow), &UIAction::triggered,
1049 this, &UIMachineLogic::sltAdjustMachineWindows);
1050 connect(actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize), &UIAction::toggled,
1051 this, &UIMachineLogic::sltToggleGuestAutoresize);
1052 connect(actionPool()->action(UIActionIndexRT_M_View_S_TakeScreenshot), &UIAction::triggered,
1053 this, &UIMachineLogic::sltTakeScreenshot);
1054 connect(actionPool()->action(UIActionIndexRT_M_View_M_Recording_S_Settings), &UIAction::triggered,
1055 this, &UIMachineLogic::sltOpenRecordingOptions);
1056 connect(actionPool()->action(UIActionIndexRT_M_View_M_Recording_T_Start), &UIAction::toggled,
1057 this, &UIMachineLogic::sltToggleRecording);
1058 connect(actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer), &UIAction::toggled,
1059 this, &UIMachineLogic::sltToggleVRDE);
1060
1061 /* 'Input' actions connections: */
1062 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_Settings), &UIAction::triggered,
1063 this, &UIMachineLogic::sltShowKeyboardSettings);
1064 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_SoftKeyboard), &UIAction::triggered,
1065 this, &UIMachineLogic::sltShowSoftKeyboard);
1066 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeCAD), &UIAction::triggered,
1067 this, &UIMachineLogic::sltTypeCAD);
1068#ifdef VBOX_WS_NIX
1069 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeCABS), &UIAction::triggered,
1070 this, &UIMachineLogic::sltTypeCABS);
1071#endif /* VBOX_WS_NIX */
1072 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeCtrlBreak), &UIAction::triggered,
1073 this, &UIMachineLogic::sltTypeCtrlBreak);
1074 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeInsert), &UIAction::triggered,
1075 this, &UIMachineLogic::sltTypeInsert);
1076 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypePrintScreen), &UIAction::triggered,
1077 this, &UIMachineLogic::sltTypePrintScreen);
1078 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_S_TypeAltPrintScreen), &UIAction::triggered,
1079 this, &UIMachineLogic::sltTypeAltPrintScreen);
1080 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_T_TypeHostKeyCombo), &UIAction::toggled,
1081 this, &UIMachineLogic::sltTypeHostKeyComboPressRelease);
1082 connect(actionPool()->action(UIActionIndexRT_M_Input_M_Mouse_T_Integration), &UIAction::toggled,
1083 this, &UIMachineLogic::sltToggleMouseIntegration);
1084
1085 /* 'Devices' actions connections: */
1086 connect(actionPool(), &UIActionPool::sigNotifyAboutMenuPrepare, this, &UIMachineLogic::sltHandleMenuPrepare);
1087 connect(actionPool()->action(UIActionIndexRT_M_Devices_M_HardDrives_S_Settings), &UIAction::triggered,
1088 this, &UIMachineLogic::sltOpenSettingsDialogStorage);
1089 connect(actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Output), &UIAction::toggled,
1090 this, &UIMachineLogic::sltToggleAudioOutput);
1091 connect(actionPool()->action(UIActionIndexRT_M_Devices_M_Audio_T_Input), &UIAction::toggled,
1092 this, &UIMachineLogic::sltToggleAudioInput);
1093 connect(actionPool()->action(UIActionIndexRT_M_Devices_M_Network_S_Settings), &UIAction::triggered,
1094 this, &UIMachineLogic::sltOpenSettingsDialogNetwork);
1095 connect(actionPool()->action(UIActionIndexRT_M_Devices_M_USBDevices_S_Settings), &UIAction::triggered,
1096 this, &UIMachineLogic::sltOpenSettingsDialogUSBDevices);
1097 connect(actionPool()->action(UIActionIndexRT_M_Devices_M_SharedFolders_S_Settings), &UIAction::triggered,
1098 this, &UIMachineLogic::sltOpenSettingsDialogSharedFolders);
1099 connect(actionPool()->action(UIActionIndexRT_M_Devices_S_InsertGuestAdditionsDisk), &UIAction::triggered,
1100 this, &UIMachineLogic::sltInstallGuestAdditions);
1101 connect(actionPool()->action(UIActionIndexRT_M_Devices_S_UpgradeGuestAdditions), &UIAction::triggered,
1102 this, &UIMachineLogic::sltInstallGuestAdditions);
1103
1104 /* 'Help' menu 'Contents' action. Done here since we react differently to this action
1105 * in manager and runtime UI: */
1106 connect(actionPool()->action(UIActionIndex_Simple_Contents), &UIAction::triggered,
1107 this, &UIMachineLogic::sltHandleHelpRequest);
1108
1109#ifdef VBOX_WITH_DEBUGGER_GUI
1110 /* 'Debug' actions connections: */
1111 connect(actionPool()->action(UIActionIndexRT_M_Debug_S_ShowStatistics), &UIAction::triggered,
1112 this, &UIMachineLogic::sltShowDebugStatistics);
1113 connect(actionPool()->action(UIActionIndexRT_M_Debug_S_ShowCommandLine), &UIAction::triggered,
1114 this, &UIMachineLogic::sltShowDebugCommandLine);
1115 connect(actionPool()->action(UIActionIndexRT_M_Debug_T_Logging), &UIAction::toggled,
1116 this, &UIMachineLogic::sltLoggingToggled);
1117 connect(actionPool()->action(UIActionIndexRT_M_Debug_S_GuestControlConsole), &UIAction::triggered,
1118 this, &UIMachineLogic::sltShowGuestControlConsoleDialog);
1119#endif /* VBOX_WITH_DEBUGGER_GUI */
1120
1121#ifdef VBOX_WS_MAC
1122 /* 'Window' action connections: */
1123 connect(actionPool()->action(UIActionIndex_M_Window_S_Minimize), &UIAction::triggered,
1124 this, &UIMachineLogic::sltMinimizeActiveMachineWindow, Qt::QueuedConnection);
1125#endif /* VBOX_WS_MAC */
1126}
1127
1128void UIMachineLogic::prepareOtherConnections()
1129{
1130 /* Extra-data connections: */
1131 connect(gEDataManager, &UIExtraDataManager::sigVisualStateChange,
1132 this, &UIMachineLogic::sltHandleVisualStateChange);
1133
1134 /* UICommon connections: */
1135 connect(&uiCommon(), &UICommon::sigAskToCommitData,
1136 this, &UIMachineLogic::sltHandleCommitData);
1137
1138 /* For separate process: */
1139 if (uiCommon().isSeparateProcess())
1140 {
1141 /* Global VBox event connections: */
1142 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigSessionStateChange,
1143 this, &UIMachineLogic::sltSessionStateChanged);
1144 }
1145}
1146
1147void UIMachineLogic::prepareHandlers()
1148{
1149 /* Prepare menu update-handlers: */
1150 m_menuUpdateHandlers[UIActionIndexRT_M_Devices_M_OpticalDevices] = &UIMachineLogic::updateMenuDevicesStorage;
1151 m_menuUpdateHandlers[UIActionIndexRT_M_Devices_M_FloppyDevices] = &UIMachineLogic::updateMenuDevicesStorage;
1152 m_menuUpdateHandlers[UIActionIndexRT_M_Devices_M_Network] = &UIMachineLogic::updateMenuDevicesNetwork;
1153 m_menuUpdateHandlers[UIActionIndexRT_M_Devices_M_USBDevices] = &UIMachineLogic::updateMenuDevicesUSB;
1154 m_menuUpdateHandlers[UIActionIndexRT_M_Devices_M_WebCams] = &UIMachineLogic::updateMenuDevicesWebcams;
1155 m_menuUpdateHandlers[UIActionIndexRT_M_Devices_M_SharedClipboard] = &UIMachineLogic::updateMenuDevicesSharedClipboard;
1156 m_menuUpdateHandlers[UIActionIndexRT_M_Devices_M_DragAndDrop] = &UIMachineLogic::updateMenuDevicesDragAndDrop;
1157#ifdef VBOX_WITH_DEBUGGER_GUI
1158 m_menuUpdateHandlers[UIActionIndexRT_M_Debug] = &UIMachineLogic::updateMenuDebug;
1159#endif /* VBOX_WITH_DEBUGGER_GUI */
1160#ifdef VBOX_WS_MAC
1161 m_menuUpdateHandlers[UIActionIndex_M_Window] = &UIMachineLogic::updateMenuWindow;
1162#endif /* VBOX_WS_MAC */
1163
1164 /* Create keyboard/mouse handlers: */
1165 setKeyboardHandler(UIKeyboardHandler::create(this, visualStateType()));
1166 setMouseHandler(UIMouseHandler::create(this, visualStateType()));
1167 /* Update UI machine values with current: */
1168 uimachine()->setKeyboardState(keyboardHandler()->state());
1169 uimachine()->setMouseState(mouseHandler()->state());
1170}
1171
1172#ifdef VBOX_WS_MAC
1173void UIMachineLogic::prepareDock()
1174{
1175 QMenu *pDockMenu = actionPool()->action(UIActionIndexRT_M_Dock)->menu();
1176 /* Clear the menu to get rid of any previously added actions and separators: */
1177 pDockMenu->clear();
1178
1179 /* Add all the 'Machine' menu entries to the 'Dock' menu: */
1180 QList<QAction*> actions = actionPool()->action(UIActionIndexRT_M_Machine)->menu()->actions();
1181 m_dockMachineMenuActions.clear();
1182 for (int i=0; i < actions.size(); ++i)
1183 {
1184 /* Check if we really have correct action: */
1185 UIAction *pAction = qobject_cast<UIAction*>(actions.at(i));
1186 /* Skip incorrect actions: */
1187 if (!pAction)
1188 continue;
1189 /* Skip actions which have 'role' (to prevent consuming): */
1190 if (pAction->menuRole() != QAction::NoRole)
1191 continue;
1192 /* Skip actions which have menu (to prevent consuming): */
1193 if (qobject_cast<UIActionMenu*>(pAction))
1194 continue;
1195 if (!pAction->isAllowed())
1196 continue;
1197 pDockMenu->addAction(actions.at(i));
1198 m_dockMachineMenuActions.push_back(actions.at(i));
1199 }
1200 if (!m_dockMachineMenuActions.empty())
1201 {
1202 m_dockMachineMenuActions.push_back(pDockMenu->addSeparator());
1203 }
1204
1205 QMenu *pDockSettingsMenu = actionPool()->action(UIActionIndexRT_M_Dock_M_DockSettings)->menu();
1206 /* Clear the menu to get rid of any previously added actions and separators: */
1207 pDockSettingsMenu->clear();
1208 QActionGroup *pDockPreviewModeGroup = new QActionGroup(this);
1209 QAction *pDockDisablePreview = actionPool()->action(UIActionIndexRT_M_Dock_M_DockSettings_T_DisableMonitor);
1210 pDockPreviewModeGroup->addAction(pDockDisablePreview);
1211 QAction *pDockEnablePreviewMonitor = actionPool()->action(UIActionIndexRT_M_Dock_M_DockSettings_T_PreviewMonitor);
1212 pDockPreviewModeGroup->addAction(pDockEnablePreviewMonitor);
1213 pDockSettingsMenu->addActions(pDockPreviewModeGroup->actions());
1214
1215 connect(pDockPreviewModeGroup, &QActionGroup::triggered, this, &UIMachineLogic::sltDockPreviewModeChanged);
1216 connect(gEDataManager, &UIExtraDataManager::sigDockIconAppearanceChange, this, &UIMachineLogic::sltChangeDockIconUpdate);
1217
1218 /* Get dock icon disable overlay action: */
1219 QAction *pDockIconDisableOverlay = actionPool()->action(UIActionIndexRT_M_Dock_M_DockSettings_T_DisableOverlay);
1220 /* Prepare dock icon disable overlay action with initial data: */
1221 pDockIconDisableOverlay->setChecked(gEDataManager->dockIconDisableOverlay(uiCommon().managedVMUuid()));
1222 /* Connect dock icon disable overlay related signals: */
1223 connect(pDockIconDisableOverlay, &QAction::triggered, this, &UIMachineLogic::sltDockIconDisableOverlayChanged);
1224 connect(gEDataManager, &UIExtraDataManager::sigDockIconOverlayAppearanceChange,
1225 this, &UIMachineLogic::sltChangeDockIconOverlayAppearance);
1226 /* Add dock icon disable overlay action to the dock settings menu: */
1227 pDockSettingsMenu->addAction(pDockIconDisableOverlay);
1228
1229 /* If we have more than one visible window: */
1230 const QList<int> visibleWindowsList = uimachine()->listOfVisibleWindows();
1231 const int cVisibleGuestScreens = visibleWindowsList.size();
1232 if (cVisibleGuestScreens > 1)
1233 {
1234 /* Add separator: */
1235 m_pDockSettingsMenuSeparator = pDockSettingsMenu->addSeparator();
1236
1237 int extraDataUpdateMonitor = gEDataManager->realtimeDockIconUpdateMonitor(uiCommon().managedVMUuid());
1238 if (visibleWindowsList.contains(extraDataUpdateMonitor))
1239 m_DockIconPreviewMonitor = extraDataUpdateMonitor;
1240 else
1241 m_DockIconPreviewMonitor = visibleWindowsList.at(cVisibleGuestScreens - 1);
1242
1243 m_pDockPreviewSelectMonitorGroup = new QActionGroup(this);
1244
1245 /* And dock preview actions: */
1246 for (int i = 0; i < cVisibleGuestScreens; ++i)
1247 {
1248 QAction *pAction = new QAction(m_pDockPreviewSelectMonitorGroup);
1249 pAction->setCheckable(true);
1250 pAction->setData(visibleWindowsList.at(i));
1251 if (m_DockIconPreviewMonitor == visibleWindowsList.at(i))
1252 pAction->setChecked(true);
1253 }
1254 pDockSettingsMenu->addActions(m_pDockPreviewSelectMonitorGroup->actions());
1255 connect(m_pDockPreviewSelectMonitorGroup, &QActionGroup::triggered,
1256 this, &UIMachineLogic::sltDockPreviewMonitorChanged);
1257 }
1258
1259 m_pDockSettingMenuAction = pDockMenu->addMenu(pDockSettingsMenu);
1260
1261 /* Add it to the dock: */
1262 pDockMenu->setAsDockMenu();
1263
1264 /* Now the dock icon preview: */
1265 QPixmap pixmap;
1266 uimachine()->acquireMachinePixmap(QSize(42, 42), pixmap);
1267 m_pDockIconPreview = new UIDockIconPreview(uimachine(), pixmap);
1268
1269 /* Should the dock-icon be updated at runtime? */
1270 bool fEnabled = gEDataManager->realtimeDockIconUpdateEnabled(uiCommon().managedVMUuid());
1271 if (fEnabled)
1272 pDockEnablePreviewMonitor->setChecked(true);
1273 else
1274 {
1275 pDockDisablePreview->setChecked(true);
1276 if(m_pDockPreviewSelectMonitorGroup)
1277 m_pDockPreviewSelectMonitorGroup->setEnabled(false);
1278 }
1279 setDockIconPreviewEnabled(fEnabled);
1280 updateDockOverlay();
1281}
1282
1283void UIMachineLogic::updateDock()
1284{
1285 QMenu *pDockSettingsMenu = actionPool()->action(UIActionIndexRT_M_Dock_M_DockSettings)->menu();
1286 AssertReturnVoid(pDockSettingsMenu);
1287
1288 QMenu *pDockMenu = actionPool()->action(UIActionIndexRT_M_Dock)->menu();
1289 AssertReturnVoid(pDockMenu);
1290
1291 /* Clean previous machine menu actions: */
1292 for (int i=0; i < m_dockMachineMenuActions.size(); ++i)
1293 {
1294 pDockMenu->removeAction(m_dockMachineMenuActions.at(i));
1295 if (m_dockMachineMenuActions.at(i)->isSeparator())
1296 delete m_dockMachineMenuActions[i];
1297 }
1298 m_dockMachineMenuActions.clear();
1299
1300 /* Determine the list of actions to be inserted: */
1301 QList<QAction*> actions = actionPool()->action(UIActionIndexRT_M_Machine)->menu()->actions();
1302 QList<QAction*> allowedActions;
1303 for (int i=0; i < actions.size(); ++i)
1304 {
1305 /* Check if we really have correct action: */
1306 UIAction *pAction = qobject_cast<UIAction*>(actions.at(i));
1307 /* Skip incorrect actions: */
1308 if (!pAction)
1309 continue;
1310 /* Skip actions which have 'role' (to prevent consuming): */
1311 if (pAction->menuRole() != QAction::NoRole)
1312 continue;
1313 /* Skip actions which have menu (to prevent consuming): */
1314 if (qobject_cast<UIActionMenu*>(pAction))
1315 continue;
1316 if (!pAction->isAllowed())
1317 continue;
1318 allowedActions.push_back(actions.at(i));
1319 }
1320
1321 if (!allowedActions.empty())
1322 {
1323 QAction *pSeparator = new QAction(pDockMenu);
1324 pSeparator->setSeparator(true);
1325 allowedActions.push_back(pSeparator);
1326 pDockMenu->insertActions(m_pDockSettingMenuAction, allowedActions);
1327 m_dockMachineMenuActions = allowedActions;
1328 }
1329
1330 /* Clean the previous preview actions: */
1331 if (m_pDockPreviewSelectMonitorGroup)
1332 {
1333 QList<QAction*> previewActions = m_pDockPreviewSelectMonitorGroup->actions();
1334 foreach (QAction *pAction, previewActions)
1335 {
1336 pDockSettingsMenu->removeAction(pAction);
1337 m_pDockPreviewSelectMonitorGroup->removeAction(pAction);
1338 delete pAction;
1339 }
1340 }
1341 const QList<int> visibleWindowsList = uimachine()->listOfVisibleWindows();
1342 const int cVisibleGuestScreens = visibleWindowsList.size();
1343 if (cVisibleGuestScreens > 1)
1344 {
1345 if (!m_pDockPreviewSelectMonitorGroup)
1346 m_pDockPreviewSelectMonitorGroup = new QActionGroup(this);
1347 /* Only if currently selected monitor for icon preview is not enabled: */
1348 if (!visibleWindowsList.contains(m_DockIconPreviewMonitor))
1349 {
1350 int iExtraDataUpdateMonitor = gEDataManager->realtimeDockIconUpdateMonitor(uiCommon().managedVMUuid());
1351 if (visibleWindowsList.contains(iExtraDataUpdateMonitor))
1352 m_DockIconPreviewMonitor = iExtraDataUpdateMonitor;
1353 else
1354 m_DockIconPreviewMonitor = visibleWindowsList.at(cVisibleGuestScreens - 1);
1355 }
1356 if (!m_pDockSettingsMenuSeparator)
1357 m_pDockSettingsMenuSeparator = pDockSettingsMenu->addSeparator();
1358 for (int i=0; i < cVisibleGuestScreens; ++i)
1359 {
1360 QAction *pAction = new QAction(m_pDockPreviewSelectMonitorGroup);
1361 pAction->setCheckable(true);
1362 pAction->setData(visibleWindowsList.at(i));
1363 pAction->setText(QApplication::translate("UIActionPool", "Preview Monitor %1").arg(pAction->data().toInt() + 1));
1364 if (m_DockIconPreviewMonitor == visibleWindowsList.at(i))
1365 pAction->setChecked(true);
1366 }
1367 pDockSettingsMenu->addActions(m_pDockPreviewSelectMonitorGroup->actions());
1368 connect(m_pDockPreviewSelectMonitorGroup, &QActionGroup::triggered,
1369 this, &UIMachineLogic::sltDockPreviewMonitorChanged);
1370 }
1371 else
1372 {
1373 m_DockIconPreviewMonitor = 0;
1374 /* Remove the seperator as well: */
1375 if (m_pDockSettingsMenuSeparator)
1376 {
1377 pDockSettingsMenu->removeAction(m_pDockSettingsMenuSeparator);
1378 delete m_pDockSettingsMenuSeparator;
1379 m_pDockSettingsMenuSeparator = 0;
1380 }
1381 }
1382}
1383#endif /* VBOX_WS_MAC */
1384
1385#ifdef VBOX_WITH_DEBUGGER_GUI
1386void UIMachineLogic::prepareDebugger()
1387{
1388 if (uiCommon().isDebuggerAutoShowEnabled())
1389 {
1390 if (uiCommon().isDebuggerAutoShowStatisticsEnabled())
1391 sltShowDebugStatistics();
1392 if (uiCommon().isDebuggerAutoShowCommandLineEnabled())
1393 sltShowDebugCommandLine();
1394 }
1395}
1396#endif /* VBOX_WITH_DEBUGGER_GUI */
1397
1398void UIMachineLogic::loadSettings()
1399{
1400 /* HID LEDs sync initialization: */
1401 sltSwitchKeyboardLedsToGuestLeds();
1402
1403#if defined(VBOX_WS_NIX) || defined(VBOX_WS_WIN)
1404 connect(gEDataManager, &UIExtraDataManager::sigDisableHostScreenSaverStateChange,
1405 this, &UIMachineLogic::sltDisableHostScreenSaverStateChanged);
1406 sltDisableHostScreenSaverStateChanged(gEDataManager->disableHostScreenSaver());
1407#endif
1408}
1409
1410#ifdef VBOX_WITH_DEBUGGER_GUI
1411void UIMachineLogic::cleanupDebugger()
1412{
1413 /* Close debugger: */
1414 uimachine()->dbgDestroy();
1415}
1416#endif /* VBOX_WITH_DEBUGGER_GUI */
1417
1418#ifdef VBOX_WS_MAC
1419void UIMachineLogic::cleanupDock()
1420{
1421 if (m_pDockIconPreview)
1422 {
1423 delete m_pDockIconPreview;
1424 m_pDockIconPreview = 0;
1425 }
1426}
1427#endif /* VBOX_WS_MAC */
1428
1429void UIMachineLogic::cleanupHandlers()
1430{
1431 /* Cleanup mouse-handler: */
1432 UIMouseHandler::destroy(mouseHandler());
1433
1434 /* Cleanup keyboard-handler: */
1435 UIKeyboardHandler::destroy(keyboardHandler());
1436}
1437
1438void UIMachineLogic::cleanupSessionConnections()
1439{
1440 /* We should stop watching for VBoxSVC availability changes: */
1441 disconnect(gpGlobalSession, &UIGlobalSession::sigVBoxSVCAvailabilityChange,
1442 this, &UIMachineLogic::sltHandleVBoxSVCAvailabilityChange);
1443
1444 /* We should stop watching for machine UI initialization signal: */
1445 disconnect(uimachine(), &UIMachine::sigInitialized, this, &UIMachineLogic::sltHandleMachineInitialized);
1446
1447 /* We should stop watching for requested modes: */
1448 disconnect(uimachine(), &UIMachine::sigInitialized, this, &UIMachineLogic::sltCheckForRequestedVisualStateType);
1449 disconnect(uimachine(), &UIMachine::sigAdditionsStateChange, this, &UIMachineLogic::sltCheckForRequestedVisualStateType);
1450
1451 /* We should stop watching for console events: */
1452 disconnect(uimachine(), &UIMachine::sigMachineStateChange, this, &UIMachineLogic::sltMachineStateChanged);
1453 disconnect(uimachine(), &UIMachine::sigAdditionsStateActualChange, this, &UIMachineLogic::sltAdditionsStateChanged);
1454 disconnect(uimachine(), &UIMachine::sigMouseCapabilityChange, this, &UIMachineLogic::sltMouseCapabilityChanged);
1455 disconnect(uimachine(), &UIMachine::sigKeyboardLedsChange, this, &UIMachineLogic::sltKeyboardLedsChanged);
1456 disconnect(uimachine(), &UIMachine::sigUSBDeviceStateChange, this, &UIMachineLogic::sltUSBDeviceStateChange);
1457 disconnect(uimachine(), &UIMachine::sigRuntimeError, this, &UIMachineLogic::sltRuntimeError);
1458#ifdef VBOX_WS_MAC
1459 disconnect(uimachine(), &UIMachine::sigShowWindows, this, &UIMachineLogic::sltShowWindows);
1460#endif
1461 disconnect(uimachine(), &UIMachine::sigGuestMonitorChange, this, &UIMachineLogic::sltGuestMonitorChange);
1462
1463 /* We should stop watching for host-screen-change events: */
1464 disconnect(uimachine(), &UIMachine::sigHostScreenCountChange, this, &UIMachineLogic::sltHostScreenCountChange);
1465 disconnect(uimachine(), &UIMachine::sigHostScreenGeometryChange, this, &UIMachineLogic::sltHostScreenGeometryChange);
1466 disconnect(uimachine(), &UIMachine::sigHostScreenAvailableAreaChange, this, &UIMachineLogic::sltHostScreenAvailableAreaChange);
1467}
1468
1469bool UIMachineLogic::eventFilter(QObject *pWatched, QEvent *pEvent)
1470{
1471 /* Handle machine-window events: */
1472 if (UIMachineWindow *pMachineWindow = qobject_cast<UIMachineWindow*>(pWatched))
1473 {
1474 /* Make sure this window still registered: */
1475 if (isMachineWindowsCreated() && m_machineWindowsList.contains(pMachineWindow))
1476 {
1477 switch (pEvent->type())
1478 {
1479 /* Handle *window activated* event: */
1480 case QEvent::WindowActivate:
1481 {
1482#ifdef VBOX_WS_WIN
1483 /* We should save current lock states as *previous* and
1484 * set current lock states to guest values we have,
1485 * As we have no ipc between threads of different VMs
1486 * we are using 100ms timer as lazy sync timout: */
1487
1488 /* On Windows host we should do that only in case if sync
1489 * is enabled. Otherwise, keyboardHandler()->winSkipKeyboardEvents(false)
1490 * won't be called in sltSwitchKeyboardLedsToGuestLeds() and guest
1491 * will loose keyboard input forever. */
1492 if (uimachine()->isHidLedsSyncEnabled())
1493 {
1494 keyboardHandler()->winSkipKeyboardEvents(true);
1495 QTimer::singleShot(100, this, SLOT(sltSwitchKeyboardLedsToGuestLeds()));
1496 }
1497#else /* VBOX_WS_WIN */
1498 /* Trigger callback synchronously for now! */
1499 sltSwitchKeyboardLedsToGuestLeds();
1500#endif /* !VBOX_WS_WIN */
1501
1502 /* Notify guest about VM window now has input focus. */
1503 if (!uimachine()->notifyGuiFocusChange(true))
1504 LogRel(("GUI: Cannot notify guest about VM window in-focus event\n"));
1505 break;
1506 }
1507 /* Handle *window deactivated* event: */
1508 case QEvent::WindowDeactivate:
1509 {
1510 /* We should restore lock states to *previous* known: */
1511 sltSwitchKeyboardLedsToPreviousLeds();
1512
1513 /* Notify guest about VM window has lost input focus. */
1514 if (!uimachine()->notifyGuiFocusChange(false))
1515 LogRel(("GUI: Cannot notify guest about VM window out-of-focus event\n"));
1516 break;
1517 }
1518 /* Default: */
1519 default: break;
1520 }
1521 }
1522 }
1523 /* Call to base-class: */
1524 return QObject::eventFilter(pWatched, pEvent);
1525}
1526
1527void UIMachineLogic::sltHandleMenuPrepare(int iIndex, QMenu *pMenu)
1528{
1529 /* Update if there is update-handler: */
1530 if (m_menuUpdateHandlers.contains(iIndex))
1531 (this->*(m_menuUpdateHandlers.value(iIndex)))(pMenu);
1532}
1533
1534void UIMachineLogic::sltClosePreferencesDialog()
1535{
1536 /* Remove instance if exist: */
1537 delete m_settings.take(UIAdvancedSettingsDialog::Type_Global);
1538}
1539
1540void UIMachineLogic::sltClose()
1541{
1542 /* Do not process if window(s) missed! */
1543 if (!isMachineWindowsCreated())
1544 return;
1545 /* Do not close machine-window in 'manual-override' mode: */
1546 if (uimachine()->isManualOverrideMode())
1547 return;
1548
1549 /* Try to close active machine-window: */
1550 LogRel(("GUI: Request to close active machine-window.\n"));
1551 activeMachineWindow()->close();
1552}
1553
1554void UIMachineLogic::sltCloseSettingsDialog()
1555{
1556 /* Remove instance if exist: */
1557 delete m_settings.take(UIAdvancedSettingsDialog::Type_Machine);
1558}
1559
1560void UIMachineLogic::sltTakeSnapshot()
1561{
1562 /* Do not process if window(s) missed! */
1563 if (!isMachineWindowsCreated())
1564 return;
1565
1566 /* First of all, we should calculate amount of immutable images: */
1567 ulong cAmountOfImmutableMediums = 0;
1568 uimachine()->acquireAmountOfImmutableImages(cAmountOfImmutableMediums);
1569
1570 /* Create take-snapshot dialog: */
1571 QWidget *pDlgParent = windowManager().realParentWindow(activeMachineWindow());
1572 QPointer<UITakeSnapshotDialog> pDlg = new UITakeSnapshotDialog(pDlgParent, cAmountOfImmutableMediums);
1573 windowManager().registerNewParent(pDlg, pDlgParent);
1574
1575 /* Assign corresponding icon: */
1576 if (uimachine()->machineWindowIcon())
1577 pDlg->setIcon(*uimachine()->machineWindowIcon());
1578
1579 /* Search for the max available filter index: */
1580 const QString strNameTemplate = UITakeSnapshotDialog::tr("Snapshot %1");
1581 ulong uMaxSnapshotIndex = 0;
1582 uimachine()->acquireMaxSnapshotIndex(strNameTemplate, uMaxSnapshotIndex);
1583 pDlg->setName(strNameTemplate.arg(++uMaxSnapshotIndex));
1584
1585 /* Exec the dialog: */
1586 const bool fDialogAccepted = pDlg->exec() == QDialog::Accepted;
1587
1588 /* Make sure dialog still valid: */
1589 if (!pDlg)
1590 return;
1591
1592 /* Acquire variables: */
1593 const QString strSnapshotName = pDlg->name().trimmed();
1594 const QString strSnapshotDescription = pDlg->description();
1595
1596 /* Destroy dialog early: */
1597 delete pDlg;
1598
1599 /* Was the dialog accepted? */
1600 if (!fDialogAccepted)
1601 return;
1602
1603 /* Take snapshot finally: */
1604 uimachine()->takeSnapshot(strSnapshotName, strSnapshotDescription);
1605}
1606
1607void UIMachineLogic::sltShowInformationDialog()
1608{
1609 /* Do not process if window(s) missed! */
1610 if (!isMachineWindowsCreated())
1611 return;
1612
1613 /* Create instance if not yet created: */
1614 if (!m_pVMInformationDialog)
1615 {
1616 m_pVMInformationDialog = new UIVMInformationDialog(actionPool());
1617 connect(m_pVMInformationDialog, &UIVMInformationDialog::sigClose,
1618 this, &UIMachineLogic::sltCloseInformationDialog);
1619 }
1620
1621 /* Expose instance: */
1622 UIDesktopWidgetWatchdog::restoreWidget(m_pVMInformationDialog);
1623}
1624
1625void UIMachineLogic::sltCloseInformationDialog()
1626{
1627 delete m_pVMInformationDialog;
1628 m_pVMInformationDialog = 0;
1629}
1630
1631void UIMachineLogic::sltShowFileManagerDialog()
1632{
1633 /* Do not process if window(s) missed! */
1634 if ( !isMachineWindowsCreated()
1635 || !activeMachineWindow())
1636 return;
1637
1638 /* Create instance if not yet created: */
1639 if (!m_pFileManagerDialog)
1640 {
1641 UIFileManagerDialogFactory(actionPool(), uiCommon().managedVMUuid(), uimachine()->machineName())
1642 .prepare(m_pFileManagerDialog, activeMachineWindow());
1643 connect(m_pFileManagerDialog, &QIManagerDialog::sigClose,
1644 this, &UIMachineLogic::sltCloseFileManagerDialog);
1645 }
1646
1647 /* Expose instance: */
1648 UIDesktopWidgetWatchdog::restoreWidget(m_pFileManagerDialog);
1649}
1650
1651void UIMachineLogic::sltCloseFileManagerDialog()
1652{
1653 UIFileManagerDialogFactory().cleanup(m_pFileManagerDialog);
1654}
1655
1656void UIMachineLogic::sltShowLogDialog()
1657{
1658 /* Do not process if window(s) missed! */
1659 if ( !isMachineWindowsCreated()
1660 || !activeMachineWindow())
1661 return;
1662
1663 /* Create instance if not yet created: */
1664 if (!m_pLogViewerDialog)
1665 {
1666 const QList<QUuid> machineIDs = QList<QUuid>() << uiCommon().managedVMUuid();
1667 UIVMLogViewerDialogFactory(actionPool(), machineIDs, uimachine()->machineName())
1668 .prepare(m_pLogViewerDialog, activeMachineWindow());
1669 connect(m_pLogViewerDialog, &QIManagerDialog::sigClose,
1670 this, &UIMachineLogic::sltCloseLogDialog);
1671 }
1672
1673 /* Expose instance: */
1674 UIDesktopWidgetWatchdog::restoreWidget(m_pLogViewerDialog);
1675}
1676
1677void UIMachineLogic::sltCloseLogDialog()
1678{
1679 UIVMLogViewerDialogFactory().cleanup(m_pLogViewerDialog);
1680}
1681
1682void UIMachineLogic::sltPause(bool fOn)
1683{
1684 uimachine()->setPause(fOn);
1685}
1686
1687void UIMachineLogic::sltReset()
1688{
1689 reset(true);
1690}
1691
1692void UIMachineLogic::sltDetach()
1693{
1694 /* Make sure machine is in one of the allowed states: */
1695 if (!uimachine()->isRunning() && !uimachine()->isPaused())
1696 {
1697 AssertMsgFailed(("Invalid machine-state. Action should be prohibited!"));
1698 return;
1699 }
1700
1701 LogRel(("GUI: User requested to detach GUI.\n"));
1702 uimachine()->detachUi();
1703}
1704
1705void UIMachineLogic::sltSaveState()
1706{
1707 /* Make sure machine is in one of the allowed states: */
1708 if (!uimachine()->isRunning() && !uimachine()->isPaused())
1709 {
1710 AssertMsgFailed(("Invalid machine-state. Action should be prohibited!"));
1711 return;
1712 }
1713
1714 LogRel(("GUI: User requested to save VM state.\n"));
1715 uimachine()->saveState();
1716}
1717
1718void UIMachineLogic::sltShutdown()
1719{
1720 /* Make sure machine is in one of the allowed states: */
1721 if (!uimachine()->isRunning())
1722 {
1723 AssertMsgFailed(("Invalid machine-state. Action should be prohibited!"));
1724 return;
1725 }
1726
1727 LogRel(("GUI: User requested to shutdown VM.\n"));
1728 uimachine()->shutdown();
1729}
1730
1731void UIMachineLogic::sltPowerOff()
1732{
1733 /* Make sure machine is in one of the allowed states: */
1734 if (!uimachine()->isRunning() && !uimachine()->isPaused() && !uimachine()->isStuck())
1735 {
1736 AssertMsgFailed(("Invalid machine-state. Action should be prohibited!"));
1737 return;
1738 }
1739
1740 LogRel(("GUI: User requested to power VM off.\n"));
1741 ulong uSnapshotCount = 0;
1742 uimachine()->acquireSnapshotCount(uSnapshotCount);
1743 const bool fDiscardStateOnPowerOff = gEDataManager->discardStateOnPowerOff(uiCommon().managedVMUuid());
1744 uimachine()->powerOff(uSnapshotCount > 0 && fDiscardStateOnPowerOff);
1745}
1746
1747void UIMachineLogic::sltMinimizeActiveMachineWindow()
1748{
1749 /* Do not process if window(s) missed! */
1750 if (!isMachineWindowsCreated())
1751 return;
1752
1753 /* Minimize active machine-window: */
1754 AssertPtrReturnVoid(activeMachineWindow());
1755 activeMachineWindow()->showMinimized();
1756}
1757
1758void UIMachineLogic::sltAdjustMachineWindows()
1759{
1760 /* Do not process if window(s) missed! */
1761 if (!isMachineWindowsCreated())
1762 return;
1763
1764 /* Adjust all window(s)! */
1765 foreach(UIMachineWindow *pMachineWindow, machineWindows())
1766 {
1767 /* Exit maximized window state if actual: */
1768 if (pMachineWindow->isMaximized())
1769 pMachineWindow->showNormal();
1770
1771 /* Normalize window geometry: */
1772 pMachineWindow->normalizeGeometry(true /* adjust position */, true /* resize window to guest display size */);
1773 }
1774}
1775
1776void UIMachineLogic::sltToggleGuestAutoresize(bool fEnabled)
1777{
1778 /* Do not process if window(s) missed! */
1779 if (!isMachineWindowsCreated())
1780 return;
1781
1782 /* Toggle guest-autoresize feature for all view(s)! */
1783 foreach(UIMachineWindow *pMachineWindow, machineWindows())
1784 {
1785 pMachineWindow->machineView()->setGuestAutoresizeEnabled(fEnabled);
1786 /* Normalize machine windows if auto resize option is toggled to true. */
1787 if (fEnabled)
1788 {
1789 /* Exit maximized window state if actual: */
1790 if (pMachineWindow->isMaximized())
1791 pMachineWindow->showNormal();
1792
1793 /* Normalize window geometry: */
1794 pMachineWindow->normalizeGeometry(true /* adjust position */, true /* resize window to guest display size */);
1795 }
1796 }
1797
1798 /* Save value to extra-data finally: */
1799 gEDataManager->setGuestScreenAutoResizeEnabled(fEnabled, uiCommon().managedVMUuid());
1800}
1801
1802void UIMachineLogic::sltTakeScreenshot()
1803{
1804 /* Do not process if window(s) missed! */
1805 if (!isMachineWindowsCreated())
1806 return;
1807
1808 /* Formatting default filename for screenshot. VM folder is the default directory to save: */
1809 QString strSettingsFilePath;
1810 uimachine()->acquireSettingsFilePath(strSettingsFilePath);
1811 const QFileInfo fi(strSettingsFilePath);
1812 const QString strCurrentTime = QDateTime::currentDateTime().toString("dd_MM_yyyy_hh_mm_ss");
1813 const QString strFormatDefaultFileName = QString("VirtualBox").append("_").append(uimachine()->machineName()).append("_").append(strCurrentTime);
1814 const QString strDefaultFileName = QDir(fi.absolutePath()).absoluteFilePath(strFormatDefaultFileName);
1815
1816 /* Formatting temporary filename for screenshot. It is saved in system temporary directory if available, else in VM folder: */
1817 QString strTempFile = QDir(fi.absolutePath()).absoluteFilePath("temp").append("_").append(strCurrentTime).append(".png");
1818 if (QDir::temp().exists())
1819 strTempFile = QDir::temp().absoluteFilePath("temp").append("_").append(strCurrentTime).append(".png");
1820
1821 /* Do the screenshot: */
1822 takeScreenshot(strTempFile, "png");
1823
1824 /* Which image formats for writing does this Qt version know of? */
1825 QList<QByteArray> formats = QImageWriter::supportedImageFormats();
1826 QStringList filters;
1827 /* Build a filters list out of it: */
1828 for (int i = 0; i < formats.size(); ++i)
1829 {
1830 const QString &s = formats.at(i) + " (*." + formats.at(i).toLower() + ")";
1831 /* Check there isn't an entry already (even if it just uses another capitalization) */
1832 if (filters.indexOf(QRegularExpression(QRegularExpression::escape(s), QRegularExpression::CaseInsensitiveOption)) == -1)
1833 filters << s;
1834 }
1835 /* Try to select some common defaults: */
1836 QString strFilter;
1837 int i = filters.indexOf(QRegularExpression(".*png.*", QRegularExpression::CaseInsensitiveOption));
1838 if (i == -1)
1839 {
1840 i = filters.indexOf(QRegularExpression(".*jpe+g.*", QRegularExpression::CaseInsensitiveOption));
1841 if (i == -1)
1842 i = filters.indexOf(QRegularExpression(".*bmp.*", QRegularExpression::CaseInsensitiveOption));
1843 }
1844 if (i != -1)
1845 {
1846 filters.prepend(filters.takeAt(i));
1847 strFilter = filters.first();
1848 }
1849
1850#ifdef VBOX_WS_WIN
1851 /* Due to Qt bug, modal QFileDialog appeared above the active machine-window
1852 * does not retreive the focus from the currently focused machine-view,
1853 * as the result guest keyboard remains captured, so we should
1854 * clear the focus from this machine-view initially: */
1855 if (activeMachineWindow())
1856 activeMachineWindow()->machineView()->clearFocus();
1857#endif /* VBOX_WS_WIN */
1858
1859 /* Request the filename from the user: */
1860 const QString strFilename = QIFileDialog::getSaveFileName(strDefaultFileName,
1861 filters.join(";;"),
1862 activeMachineWindow(),
1863 tr("Select a filename for the screenshot ..."),
1864 &strFilter,
1865 true /* resolve symlinks */,
1866 true /* confirm overwrite */);
1867
1868#ifdef VBOX_WS_WIN
1869 /* Due to Qt bug, modal QFileDialog appeared above the active machine-window
1870 * does not retreive the focus from the currently focused machine-view,
1871 * as the result guest keyboard remains captured, so we already
1872 * cleared the focus from this machine-view and should return
1873 * that focus finally: */
1874 if (activeMachineWindow())
1875 activeMachineWindow()->machineView()->setFocus();
1876#endif /* VBOX_WS_WIN */
1877
1878 if (!strFilename.isEmpty())
1879 {
1880 const QString strFormat = strFilter.split(" ").value(0, "png");
1881 const QImage tmpImage(strTempFile);
1882
1883 /* On X11 Qt Filedialog returns the filepath without the filetype suffix, so adding it ourselves: */
1884#ifdef VBOX_WS_NIX
1885 /* Add filetype suffix only if user has not added it explicitly: */
1886 if (!strFilename.endsWith(QString(".%1").arg(strFormat)))
1887 tmpImage.save(QDir::toNativeSeparators(QFile::encodeName(QString("%1.%2").arg(strFilename, strFormat))),
1888 strFormat.toUtf8().constData());
1889 else
1890 tmpImage.save(QDir::toNativeSeparators(QFile::encodeName(strFilename)),
1891 strFormat.toUtf8().constData());
1892#else /* !VBOX_WS_NIX */
1893 QFile file(strFilename);
1894 if (file.open(QIODevice::WriteOnly))
1895 tmpImage.save(&file, strFormat.toUtf8().constData());
1896#endif /* !VBOX_WS_NIX */
1897 }
1898 QFile::remove(strTempFile);
1899}
1900
1901void UIMachineLogic::sltOpenRecordingOptions()
1902{
1903 /* Open VM settings : Display page : Recording tab: */
1904 openSettingsDialog("#display", "m_pCheckboxVideoCapture");
1905}
1906
1907void UIMachineLogic::sltToggleRecording(bool fEnabled)
1908{
1909 /* Do not process if window(s) missed! */
1910 if (!isMachineWindowsCreated())
1911 return;
1912
1913 /* Make sure something had changed: */
1914 bool fSettingsEnabled = false;
1915 uimachine()->acquireWhetherRecordingSettingsEnabled(fSettingsEnabled);
1916 if (fSettingsEnabled == fEnabled)
1917 return;
1918
1919 /* Update and save recording settings state,
1920 * make sure action is updated in case of failure: */
1921 if ( !uimachine()->setRecordingSettingsEnabled(fEnabled)
1922 || !uimachine()->saveSettings())
1923 return uimachine()->updateStateRecordingAction();
1924}
1925
1926void UIMachineLogic::sltToggleVRDE(bool fEnabled)
1927{
1928 /* Do not process if window(s) missed! */
1929 if (!isMachineWindowsCreated())
1930 return;
1931
1932 /* Make sure VRDE server present: */
1933 bool fServerPresent = false;
1934 uimachine()->acquireWhetherVRDEServerPresent(fServerPresent);
1935 AssertMsgReturnVoid(fServerPresent,
1936 ("VRDE server should NOT be null!\n"));
1937
1938 /* Make sure something had changed: */
1939 bool fServerEnabled = false;
1940 uimachine()->acquireWhetherVRDEServerEnabled(fServerEnabled);
1941 if (fServerEnabled == fEnabled)
1942 return;
1943
1944 /* Update and save VRDE server state,
1945 * make sure action is updated in case of failure: */
1946 if ( !uimachine()->setVRDEServerEnabled(fEnabled)
1947 || !uimachine()->saveSettings())
1948 return uimachine()->updateStateVRDEServerAction();
1949}
1950
1951void UIMachineLogic::sltShowKeyboardSettings()
1952{
1953 /* Global preferences: Input page: */
1954 openPreferencesDialog("#input", "m_pMachineTable");
1955}
1956
1957void UIMachineLogic::sltShowSoftKeyboard()
1958{
1959 /* Do not process if window(s) missed! */
1960 if ( !isMachineWindowsCreated()
1961 || !activeMachineWindow())
1962 return;
1963
1964 /* Create instance if not yet created: */
1965 if (!m_pSoftKeyboardDialog)
1966 {
1967 m_pSoftKeyboardDialog = new UISoftKeyboard(0, uimachine(), activeMachineWindow(), uimachine()->machineName());
1968 connect(m_pSoftKeyboardDialog, &UISoftKeyboard::sigClose,
1969 this, &UIMachineLogic::sltCloseSoftKeyboard);
1970 }
1971
1972 /* Expose instance: */
1973 UIDesktopWidgetWatchdog::restoreWidget(m_pSoftKeyboardDialog);
1974}
1975
1976void UIMachineLogic::sltCloseSoftKeyboard()
1977{
1978 delete m_pSoftKeyboardDialog;
1979 m_pSoftKeyboardDialog = 0;
1980}
1981
1982void UIMachineLogic::sltTypeCAD()
1983{
1984 uimachine()->putCAD();
1985}
1986
1987#ifdef VBOX_WS_NIX
1988void UIMachineLogic::sltTypeCABS()
1989{
1990 static QVector<LONG> sequence(6);
1991 sequence[0] = 0x1d; /* Ctrl down */
1992 sequence[1] = 0x38; /* Alt down */
1993 sequence[2] = 0x0E; /* Backspace down */
1994 sequence[3] = 0x0E | 0x80; /* Backspace up */
1995 sequence[4] = 0x38 | 0x80; /* Alt up */
1996 sequence[5] = 0x1d | 0x80; /* Ctrl up */
1997 uimachine()->putScancodes(sequence);
1998}
1999#endif /* VBOX_WS_NIX */
2000
2001void UIMachineLogic::sltTypeCtrlBreak()
2002{
2003 static QVector<LONG> sequence(6);
2004 sequence[0] = 0x1d; /* Ctrl down */
2005 sequence[1] = 0xe0; /* Extended flag */
2006 sequence[2] = 0x46; /* Break down */
2007 sequence[3] = 0xe0; /* Extended flag */
2008 sequence[4] = 0x46 | 0x80; /* Break up */
2009 sequence[5] = 0x1d | 0x80; /* Ctrl up */
2010 uimachine()->putScancodes(sequence);
2011}
2012
2013void UIMachineLogic::sltTypeInsert()
2014{
2015 static QVector<LONG> sequence(4);
2016 sequence[0] = 0xE0; /* Extended flag */
2017 sequence[1] = 0x52; /* Insert down */
2018 sequence[2] = 0xE0; /* Extended flag */
2019 sequence[3] = 0x52 | 0x80; /* Insert up */
2020 uimachine()->putScancodes(sequence);
2021}
2022
2023void UIMachineLogic::sltTypePrintScreen()
2024{
2025 static QVector<LONG> sequence(8);
2026 sequence[0] = 0xE0; /* Extended flag */
2027 sequence[1] = 0x2A; /* Print.. down */
2028 sequence[2] = 0xE0; /* Extended flag */
2029 sequence[3] = 0x37; /* ..Screen down */
2030 sequence[4] = 0xE0; /* Extended flag */
2031 sequence[5] = 0x37 | 0x80; /* ..Screen up */
2032 sequence[6] = 0xE0; /* Extended flag */
2033 sequence[7] = 0x2A | 0x80; /* Print.. up */
2034 uimachine()->putScancodes(sequence);
2035}
2036
2037void UIMachineLogic::sltTypeAltPrintScreen()
2038{
2039 static QVector<LONG> sequence(10);
2040 sequence[0] = 0x38; /* Alt down */
2041 sequence[1] = 0xE0; /* Extended flag */
2042 sequence[2] = 0x2A; /* Print.. down */
2043 sequence[3] = 0xE0; /* Extended flag */
2044 sequence[4] = 0x37; /* ..Screen down */
2045 sequence[5] = 0xE0; /* Extended flag */
2046 sequence[6] = 0x37 | 0x80; /* ..Screen up */
2047 sequence[7] = 0xE0; /* Extended flag */
2048 sequence[8] = 0x2A | 0x80; /* Print.. up */
2049 sequence[9] = 0x38 | 0x80; /* Alt up */
2050 uimachine()->putScancodes(sequence);
2051}
2052
2053void UIMachineLogic::sltTypeHostKeyComboPressRelease(bool fToggleSequence)
2054{
2055 if (keyboardHandler())
2056 keyboardHandler()->setHostKeyComboPressedFlag(fToggleSequence);
2057 QList<unsigned> shortCodes = UIHostCombo::modifiersToScanCodes(gEDataManager->hostKeyCombination());
2058 QVector<LONG> codes;
2059 foreach (unsigned idxCode, shortCodes)
2060 {
2061 /* Check if we need to include extended code for this key: */
2062 if (idxCode & 0x100)
2063 codes << 0xE0;
2064 if (fToggleSequence)
2065 {
2066 /* Add the press code: */
2067 codes << (idxCode & 0x7F);
2068 }
2069 else
2070 {
2071 /* Add the release code: */
2072 codes << ((idxCode & 0x7F) | 0x80);
2073 }
2074 }
2075
2076 uimachine()->putScancodes(codes);
2077}
2078
2079void UIMachineLogic::sltToggleMouseIntegration(bool fEnabled)
2080{
2081 /* Do not process if window(s) missed! */
2082 if (!isMachineWindowsCreated())
2083 return;
2084
2085 /* Disable/Enable mouse-integration for all view(s): */
2086 mouseHandler()->setMouseIntegrationEnabled(fEnabled);
2087}
2088
2089void UIMachineLogic::sltOpenSettingsDialogStorage()
2090{
2091 /* Machine settings: Storage page: */
2092 openSettingsDialog("#storage");
2093}
2094
2095void UIMachineLogic::sltMountStorageMedium()
2096{
2097 /* Sender action: */
2098 QAction *pAction = qobject_cast<QAction*>(sender());
2099 AssertMsgReturnVoid(pAction, ("This slot should only be called by menu action!\n"));
2100
2101 /* Current mount-target: */
2102 const UIMediumTarget target = pAction->data().value<UIMediumTarget>();
2103
2104 /* Update current machine mount-target: */
2105 uimachine()->updateMachineStorage(target, actionPool());
2106}
2107
2108void UIMachineLogic::sltToggleAudioOutput(bool fEnabled)
2109{
2110 /* Do not process if window(s) missed! */
2111 if (!isMachineWindowsCreated())
2112 return;
2113
2114 /* Make sure audio adapter present: */
2115 bool fAdapterPresent = false;
2116 uimachine()->acquireWhetherAudioAdapterPresent(fAdapterPresent);
2117 AssertMsgReturnVoid(fAdapterPresent,
2118 ("Audio adapter should NOT be null!\n"));
2119
2120 /* Make sure something had changed: */
2121 bool fAudioOutputEnabled = false;
2122 uimachine()->acquireWhetherAudioAdapterOutputEnabled(fAudioOutputEnabled);
2123 if (fAudioOutputEnabled == fEnabled)
2124 return;
2125
2126 /* Update and save audio adapter output state,
2127 * make sure action is updated in case of failure: */
2128 if ( !uimachine()->setAudioAdapterOutputEnabled(fEnabled)
2129 || !uimachine()->saveSettings())
2130 return uimachine()->updateStateAudioActions();
2131}
2132
2133void UIMachineLogic::sltToggleAudioInput(bool fEnabled)
2134{
2135 /* Do not process if window(s) missed! */
2136 if (!isMachineWindowsCreated())
2137 return;
2138
2139 /* Make sure audio adapter present: */
2140 bool fAdapterPresent = false;
2141 uimachine()->acquireWhetherAudioAdapterPresent(fAdapterPresent);
2142 AssertMsgReturnVoid(fAdapterPresent,
2143 ("Audio adapter should NOT be null!\n"));
2144
2145 /* Make sure something had changed: */
2146 bool fAudioInputEnabled = false;
2147 uimachine()->acquireWhetherAudioAdapterInputEnabled(fAudioInputEnabled);
2148 if (fAudioInputEnabled == fEnabled)
2149 return;
2150
2151 /* Update and save audio adapter input state,
2152 * make sure action is updated in case of failure: */
2153 if ( !uimachine()->setAudioAdapterInputEnabled(fEnabled)
2154 || !uimachine()->saveSettings())
2155 return uimachine()->updateStateAudioActions();
2156}
2157
2158void UIMachineLogic::sltOpenSettingsDialogNetwork()
2159{
2160 /* Open VM settings : Network page: */
2161 openSettingsDialog("#network");
2162}
2163
2164void UIMachineLogic::sltOpenSettingsDialogUSBDevices()
2165{
2166 /* Machine settings: Storage page: */
2167 openSettingsDialog("#usb");
2168}
2169
2170void UIMachineLogic::sltOpenSettingsDialogSharedFolders()
2171{
2172 /* Do not process if additions are not loaded! */
2173 if (!uimachine()->isGuestAdditionsActive())
2174 UINotificationMessage::remindAboutGuestAdditionsAreNotActive();
2175
2176 /* Open VM settings : Shared folders page: */
2177 openSettingsDialog("#sharedFolders");
2178}
2179
2180void UIMachineLogic::sltAttachUSBDevice()
2181{
2182 /* Get and check sender action object: */
2183 QAction *pAction = qobject_cast<QAction*>(sender());
2184 AssertMsg(pAction, ("This slot should only be called on selecting USB menu item!\n"));
2185
2186 /* Get operation target: */
2187 USBTarget target = pAction->data().value<USBTarget>();
2188
2189 /* Attach USB device: */
2190 if (target.attach)
2191 uimachine()->attachUSBDevice(target.id);
2192 /* Detach USB device: */
2193 else
2194 uimachine()->detachUSBDevice(target.id);
2195}
2196
2197void UIMachineLogic::sltAttachWebcamDevice()
2198{
2199 /* Get and check sender action object: */
2200 QAction *pAction = qobject_cast<QAction*>(sender());
2201 AssertReturnVoid(pAction);
2202
2203 /* Get operation target: */
2204 WebCamTarget target = pAction->data().value<WebCamTarget>();
2205
2206 /* Attach webcam device: */
2207 if (target.attach)
2208 uimachine()->webcamAttach(target.path, target.name);
2209 /* Detach webcam device: */
2210 else
2211 uimachine()->webcamDetach(target.path, target.name);
2212}
2213
2214void UIMachineLogic::sltChangeSharedClipboardType(QAction *pAction)
2215{
2216 /* Assign new mode (without save): */
2217 AssertPtrReturnVoid(pAction);
2218 KClipboardMode enmMode = pAction->data().value<KClipboardMode>();
2219 uimachine()->setClipboardMode(enmMode);
2220 /* Disable the file transfer action if clipboard transfers are disabled: */
2221 if (m_pFileTransferToggleAction)
2222 m_pFileTransferToggleAction->setEnabled(enmMode != KClipboardMode_Disabled);
2223}
2224
2225void UIMachineLogic::sltFileTransferToggled(bool fChecked)
2226{
2227 uimachine()->toggleClipboardFileTransfer(fChecked);
2228}
2229
2230void UIMachineLogic::sltToggleNetworkAdapterConnection(bool fChecked)
2231{
2232 /* Get and check 'the sender' action object: */
2233 QAction *pAction = qobject_cast<QAction*>(sender());
2234 AssertMsgReturnVoid(pAction, ("Sender action should NOT be null!\n"));
2235
2236 /* Acquire adapter slot: */
2237 const ulong uSlot = pAction->property("slot").toUInt();
2238
2239 /* Toggle network adapter cable connection: */
2240 uimachine()->setNetworkCableConnected(uSlot, fChecked);
2241
2242 /* Save machine-settings: */
2243 uimachine()->saveSettings();
2244}
2245
2246void UIMachineLogic::sltChangeDragAndDropType(QAction *pAction)
2247{
2248 /* Assign new mode (without save): */
2249 AssertPtrReturnVoid(pAction);
2250 uimachine()->setDnDMode(pAction->data().value<KDnDMode>());
2251}
2252
2253void UIMachineLogic::sltInstallGuestAdditions()
2254{
2255 /* Do not process if window(s) missed! */
2256 if (!isMachineWindowsCreated())
2257 return;
2258
2259 bool fOnlyMount = sender() == actionPool()->action(UIActionIndexRT_M_Devices_S_InsertGuestAdditionsDisk);
2260
2261 /* Try to acquire default additions ISO: */
2262 CSystemProperties comSystemProperties = gpGlobalSession->virtualBox().GetSystemProperties();
2263 const QString strAdditions = comSystemProperties.GetDefaultAdditionsISO();
2264 if (comSystemProperties.isOk() && !strAdditions.isEmpty())
2265 {
2266 if (fOnlyMount)
2267 return uimachine()->sltMountDVDAdHoc(strAdditions);
2268 else
2269 return uimachine()->sltInstallGuestAdditionsFrom(strAdditions);
2270 }
2271
2272 /* Check whether we have already registered image: */
2273 CVirtualBox comVBox = gpGlobalSession->virtualBox();
2274 CMediumVector comMedia = comVBox.GetDVDImages();
2275 if (!comVBox.isOk())
2276 UINotificationMessage::cannotAcquireVirtualBoxParameter(comVBox);
2277 else
2278 {
2279 const QString strName = QString("%1_%2.iso").arg(GUI_GuestAdditionsName, UIVersionInfo::vboxVersionStringNormalized());
2280 foreach (const CMedium &comMedium, comMedia)
2281 {
2282 /* Compare the name part ignoring the file case: */
2283 const QString strPath = comMedium.GetLocation();
2284 if (!comMedium.isOk())
2285 UINotificationMessage::cannotAcquireMediumParameter(comMedium);
2286 {
2287 const QString strFileName = QFileInfo(strPath).fileName();
2288 if (RTPathCompare(strName.toUtf8().constData(), strFileName.toUtf8().constData()) == 0)
2289 {
2290 if (fOnlyMount)
2291 return uimachine()->sltMountDVDAdHoc(strPath);
2292 else
2293 return uimachine()->sltInstallGuestAdditionsFrom(strPath);
2294 }
2295 }
2296 }
2297 }
2298
2299#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
2300 /* If downloader is running already: */
2301 if (UINotificationDownloaderGuestAdditions::exists())
2302 gpNotificationCenter->invoke();
2303 /* Else propose to download additions: */
2304 else if (msgCenter().confirmLookingForGuestAdditions())
2305 {
2306 /* Download guest additions: */
2307 UINotificationDownloaderGuestAdditions *pNotification = UINotificationDownloaderGuestAdditions::instance(GUI_GuestAdditionsName);
2308 /* After downloading finished => propose to install or just mount the guest additions: */
2309 if (fOnlyMount)
2310 connect(pNotification, &UINotificationDownloaderGuestAdditions::sigGuestAdditionsDownloaded,
2311 uimachine(), &UIMachine::sltMountDVDAdHoc);
2312 else
2313 connect(pNotification, &UINotificationDownloaderGuestAdditions::sigGuestAdditionsDownloaded,
2314 uimachine(), &UIMachine::sltInstallGuestAdditionsFrom);
2315 /* Append and start notification: */
2316 gpNotificationCenter->append(pNotification);
2317 }
2318#endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
2319}
2320
2321#ifdef VBOX_WITH_DEBUGGER_GUI
2322
2323void UIMachineLogic::sltShowDebugStatistics()
2324{
2325 if (uimachine()->dbgCreated(actionPool()->action(UIActionIndexRT_M_Debug)))
2326 {
2327 keyboardHandler()->setDebuggerActive();
2328 uimachine()->dbgShowStatistics();
2329 }
2330}
2331
2332void UIMachineLogic::sltShowDebugCommandLine()
2333{
2334 if (uimachine()->dbgCreated(actionPool()->action(UIActionIndexRT_M_Debug)))
2335 {
2336 keyboardHandler()->setDebuggerActive();
2337 uimachine()->dbgShowCommandLine();
2338 }
2339}
2340
2341void UIMachineLogic::sltLoggingToggled(bool fState)
2342{
2343 uimachine()->setLogEnabled(fState);
2344}
2345
2346void UIMachineLogic::sltShowGuestControlConsoleDialog()
2347{
2348 /* Do not process if window(s) missed! */
2349 if ( !isMachineWindowsCreated()
2350 || !activeMachineWindow())
2351 return;
2352
2353 /* Create instance if not yet created: */
2354 if (!m_pProcessControlDialog)
2355 {
2356 UIGuestProcessControlDialogFactory().prepare(m_pProcessControlDialog, activeMachineWindow());
2357 connect(m_pProcessControlDialog, &QIManagerDialog::sigClose,
2358 this, &UIMachineLogic::sltCloseGuestControlConsoleDialog);
2359 }
2360
2361 /* Expose instance: */
2362 UIDesktopWidgetWatchdog::restoreWidget(m_pProcessControlDialog);
2363}
2364
2365void UIMachineLogic::sltCloseGuestControlConsoleDialog()
2366{
2367 UIGuestProcessControlDialogFactory().cleanup(m_pProcessControlDialog);
2368}
2369#endif /* VBOX_WITH_DEBUGGER_GUI */
2370
2371#ifdef VBOX_WS_MAC
2372void UIMachineLogic::sltSwitchToMachineWindow()
2373{
2374 /* Acquire appropriate sender action: */
2375 const QAction *pSender = qobject_cast<QAction*>(sender());
2376 AssertReturnVoid(pSender);
2377 {
2378 /* Determine sender action index: */
2379 const int iIndex = pSender->data().toInt();
2380 AssertReturnVoid(iIndex >= 0 && iIndex < machineWindows().size());
2381 {
2382 /* Raise appropriate machine-window: */
2383 UIMachineWindow *pMachineWindow = machineWindows().at(iIndex);
2384 AssertPtrReturnVoid(pMachineWindow);
2385 {
2386 pMachineWindow->show();
2387 pMachineWindow->raise();
2388 pMachineWindow->activateWindow();
2389 }
2390 }
2391 }
2392}
2393
2394void UIMachineLogic::sltDockPreviewModeChanged(QAction *pAction)
2395{
2396 bool fEnabled = pAction != actionPool()->action(UIActionIndexRT_M_Dock_M_DockSettings_T_DisableMonitor);
2397 gEDataManager->setRealtimeDockIconUpdateEnabled(fEnabled, uiCommon().managedVMUuid());
2398 updateDockOverlay();
2399}
2400
2401void UIMachineLogic::sltDockPreviewMonitorChanged(QAction *pAction)
2402{
2403 gEDataManager->setRealtimeDockIconUpdateMonitor(pAction->data().toInt(), uiCommon().managedVMUuid());
2404 updateDockOverlay();
2405}
2406
2407void UIMachineLogic::sltChangeDockIconUpdate(bool fEnabled)
2408{
2409 if (isMachineWindowsCreated())
2410 {
2411 setDockIconPreviewEnabled(fEnabled);
2412 if (m_pDockPreviewSelectMonitorGroup)
2413 {
2414 ulong cMonitorCount = 0;
2415 uimachine()->acquireMonitorCount(cMonitorCount);
2416 m_pDockPreviewSelectMonitorGroup->setEnabled(fEnabled);
2417 m_DockIconPreviewMonitor = qMin(gEDataManager->realtimeDockIconUpdateMonitor(uiCommon().managedVMUuid()),
2418 (int)cMonitorCount - 1);
2419 }
2420 /* Resize the dock icon in the case the preview monitor has changed. */
2421 QSize size = machineWindows().at(m_DockIconPreviewMonitor)->machineView()->size();
2422 updateDockIconSize(m_DockIconPreviewMonitor, size.width(), size.height());
2423 updateDockOverlay();
2424 }
2425}
2426
2427void UIMachineLogic::sltChangeDockIconOverlayAppearance(bool fDisabled)
2428{
2429 /* Update dock icon overlay: */
2430 if (isMachineWindowsCreated())
2431 updateDockOverlay();
2432 /* Make sure to update dock icon disable overlay action state when 'GUI_DockIconDisableOverlay' changed from extra-data manager: */
2433 QAction *pDockIconDisableOverlay = actionPool()->action(UIActionIndexRT_M_Dock_M_DockSettings_T_DisableOverlay);
2434 if (fDisabled != pDockIconDisableOverlay->isChecked())
2435 {
2436 /* Block signals initially to avoid recursive loop: */
2437 pDockIconDisableOverlay->blockSignals(true);
2438 /* Update state: */
2439 pDockIconDisableOverlay->setChecked(fDisabled);
2440 /* Make sure to unblock signals again: */
2441 pDockIconDisableOverlay->blockSignals(false);
2442 }
2443}
2444
2445void UIMachineLogic::sltDockIconDisableOverlayChanged(bool fDisabled)
2446{
2447 /* Write dock icon disable overlay flag to extra-data: */
2448 gEDataManager->setDockIconDisableOverlay(fDisabled, uiCommon().managedVMUuid());
2449}
2450#endif /* VBOX_WS_MAC */
2451
2452void UIMachineLogic::sltSwitchKeyboardLedsToGuestLeds()
2453{
2454 /* Due to async nature of that feature
2455 * it can happen that this slot is called when machine-window is
2456 * minimized or not active anymore, we should ignore those cases. */
2457 QWidget *pActiveWindow = QApplication::activeWindow();
2458 if ( !pActiveWindow // no window is active anymore
2459 || !qobject_cast<UIMachineWindow*>(pActiveWindow) // window is not machine one
2460 || pActiveWindow->isMinimized()) // window is minimized
2461 {
2462 LogRel2(("GUI: HID LEDs Sync: skipping sync because active window is lost or minimized!\n"));
2463 return;
2464 }
2465
2466// /* Log statement (printf): */
2467// QString strDt = QDateTime::currentDateTime().toString("HH:mm:ss:zzz");
2468// printf("%s: UIMachineLogic: sltSwitchKeyboardLedsToGuestLeds called, machine name is {%s}\n",
2469// strDt.toUtf8().constData(),
2470// machineName().toUtf8().constData());
2471
2472 /* Here we have to store host LED lock states. */
2473
2474 /* Here we have to update host LED lock states using values provided by UIMachine registry.
2475 * [bool] uimachine() -> isNumLock(), isCapsLock(), isScrollLock() can be used for that. */
2476
2477 if (!uimachine()->isHidLedsSyncEnabled())
2478 return;
2479
2480#if defined(VBOX_WS_MAC)
2481 if (m_pHostLedsState == NULL)
2482 m_pHostLedsState = DarwinHidDevicesKeepLedsState();
2483 if (m_pHostLedsState != NULL)
2484 DarwinHidDevicesBroadcastLeds(m_pHostLedsState, uimachine()->isNumLock(), uimachine()->isCapsLock(), uimachine()->isScrollLock());
2485#elif defined(VBOX_WS_WIN)
2486 if (m_pHostLedsState == NULL)
2487 m_pHostLedsState = WinHidDevicesKeepLedsState();
2488 keyboardHandler()->winSkipKeyboardEvents(true);
2489 WinHidDevicesBroadcastLeds(uimachine()->isNumLock(), uimachine()->isCapsLock(), uimachine()->isScrollLock());
2490 keyboardHandler()->winSkipKeyboardEvents(false);
2491#else
2492 LogRelFlow(("UIMachineLogic::sltSwitchKeyboardLedsToGuestLeds: keep host LED lock states and broadcast guest's ones does not supported on this platform\n"));
2493#endif
2494}
2495
2496void UIMachineLogic::sltSwitchKeyboardLedsToPreviousLeds()
2497{
2498// /* Log statement (printf): */
2499// QString strDt = QDateTime::currentDateTime().toString("HH:mm:ss:zzz");
2500// printf("%s: UIMachineLogic: sltSwitchKeyboardLedsToPreviousLeds called, machine name is {%s}\n",
2501// strDt.toUtf8().constData(),
2502// machineName().toUtf8().constData());
2503
2504 if (!uimachine()->isHidLedsSyncEnabled())
2505 return;
2506
2507 /* Here we have to restore host LED lock states. */
2508 void *pvLedState = m_pHostLedsState;
2509 if (pvLedState)
2510 {
2511 /* bird: I've observed recursive calls here when setting m_pHostLedsState to NULL after calling
2512 WinHidDevicesApplyAndReleaseLedsState. The result is a double free(), which the CRT
2513 usually detects and I could see this->m_pHostLedsState == NULL. The windows function
2514 does dispatch loop fun, that's probably the reason for it. Hopefully not an issue on OS X. */
2515 m_pHostLedsState = NULL;
2516#if defined(VBOX_WS_MAC)
2517 DarwinHidDevicesApplyAndReleaseLedsState(pvLedState);
2518#elif defined(VBOX_WS_WIN)
2519 keyboardHandler()->winSkipKeyboardEvents(true);
2520 WinHidDevicesApplyAndReleaseLedsState(pvLedState);
2521 keyboardHandler()->winSkipKeyboardEvents(false);
2522#else
2523 LogRelFlow(("UIMachineLogic::sltSwitchKeyboardLedsToPreviousLeds: restore host LED lock states does not supported on this platform\n"));
2524#endif
2525 }
2526}
2527
2528void UIMachineLogic::sltHandleVisualStateChange()
2529{
2530 /* Check for new requested value stored in extra-data: */
2531 const UIVisualStateType enmRequestedState = gEDataManager->requestedVisualState(uiCommon().managedVMUuid());
2532 /* Check whether current value OR old requested value differs from new requested one.
2533 * That way we will NOT enter seamless mode instantly if it is already planned
2534 * but is not entered because we're waiting for a guest addition permission. */
2535 if ( visualStateType() != enmRequestedState
2536 && uimachine()->requestedVisualState() != enmRequestedState)
2537 {
2538 switch (enmRequestedState)
2539 {
2540 case UIVisualStateType_Normal: return sltChangeVisualStateToNormal();
2541 case UIVisualStateType_Fullscreen: return sltChangeVisualStateToFullscreen();
2542 case UIVisualStateType_Seamless: return sltChangeVisualStateToSeamless();
2543 case UIVisualStateType_Scale: return sltChangeVisualStateToScale();
2544 default: break;
2545 }
2546 }
2547}
2548
2549void UIMachineLogic::sltHandleCommitData()
2550{
2551#ifdef VBOX_WITH_DEBUGGER_GUI
2552 cleanupDebugger();
2553 sltCloseGuestControlConsoleDialog();
2554#endif /* VBOX_WITH_DEBUGGER_GUI */
2555 sltCloseLogDialog();
2556 activateScreenSaver();
2557 sltCloseFileManagerDialog();
2558 sltCloseInformationDialog();
2559 sltCloseSoftKeyboard();
2560 sltSwitchKeyboardLedsToPreviousLeds();
2561 sltCloseSettingsDialog();
2562 sltClosePreferencesDialog();
2563}
2564
2565void UIMachineLogic::typeHostKeyComboPressRelease(bool fToggleSequence)
2566{
2567 QAction *pHostKeyAction = actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard_T_TypeHostKeyCombo);
2568 if (!pHostKeyAction)
2569 return;
2570 /* Do nothing if we try to insert host key combo press (release) and it is already in pressed (released) state: */
2571 if (fToggleSequence == pHostKeyAction->isChecked())
2572 return;
2573 pHostKeyAction->toggle();
2574}
2575
2576void UIMachineLogic::updateMenuDevicesStorage(QMenu *pMenu)
2577{
2578 /* Clear contents: */
2579 pMenu->clear();
2580
2581 /* Determine device-type: */
2582 const QMenu *pOpticalDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices)->menu();
2583 const QMenu *pFloppyDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices)->menu();
2584 const KDeviceType enmDeviceType = pMenu == pOpticalDevicesMenu
2585 ? KDeviceType_DVD
2586 : pMenu == pFloppyDevicesMenu
2587 ? KDeviceType_Floppy
2588 : KDeviceType_Null;
2589 AssertMsgReturnVoid(enmDeviceType != KDeviceType_Null, ("Incorrect storage device-type!\n"));
2590
2591 /* Acquire device list: */
2592 QList<StorageDeviceInfo> guiStorageDevices;
2593 if (!uimachine()->storageDevices(enmDeviceType, guiStorageDevices))
2594 return;
2595
2596 /* Populate menu with host storage devices: */
2597 foreach (const StorageDeviceInfo &guiStorageDevice, guiStorageDevices)
2598 {
2599 /* Prepare current storage menu: */
2600 QMenu *pStorageMenu = 0;
2601 /* If it will be more than one storage menu: */
2602 if (pMenu->menuAction()->data().toInt() > 1)
2603 {
2604 /* We have to create sub-menu for each of them: */
2605 pStorageMenu = new QMenu(QString("%1 (%2)")
2606 .arg(guiStorageDevice.m_strControllerName)
2607 .arg(gpConverter->toString(guiStorageDevice.m_guiStorageSlot)),
2608 pMenu);
2609 pStorageMenu->setIcon(guiStorageDevice.m_icon);
2610 pMenu->addMenu(pStorageMenu);
2611 }
2612 /* Otherwise just use existing one: */
2613 else
2614 pStorageMenu = pMenu;
2615
2616 /* Fill current storage menu: */
2617 uimachine()->prepareStorageMenu(pStorageMenu,
2618 this, SLOT(sltMountStorageMedium()),
2619 guiStorageDevice.m_strControllerName, guiStorageDevice.m_guiStorageSlot);
2620 }
2621}
2622
2623void UIMachineLogic::updateMenuDevicesNetwork(QMenu *pMenu)
2624{
2625 /* Determine how many adapters we should display: */
2626 KPlatformArchitecture enmArchType = KPlatformArchitecture_None;
2627 uimachine()->acquireArchitectureType(enmArchType);
2628 KChipsetType enmChipsetType = KChipsetType_Null;
2629 uimachine()->acquireChipsetType(enmChipsetType);
2630 CPlatformProperties comProperties = gpGlobalSession->virtualBox().GetPlatformProperties(enmArchType);
2631 const ulong uCount = qMin((ulong)4, (ulong)comProperties.GetMaxNetworkAdapters(enmChipsetType));
2632
2633 /* Enumerate existing network adapters: */
2634 QMap<ulong, bool> adapterData;
2635 for (ulong uSlot = 0; uSlot < uCount; ++uSlot)
2636 {
2637 /* Skip disabled adapters: */
2638 bool fAdapterEnabled = false;
2639 uimachine()->acquireWhetherNetworkAdapterEnabled(uSlot, fAdapterEnabled);
2640 if (!fAdapterEnabled)
2641 continue;
2642
2643 /* Remember adapter data: */
2644 bool fCableConnected = false;
2645 uimachine()->acquireWhetherNetworkCableConnected(uSlot, fCableConnected);
2646 adapterData.insert(uSlot, fCableConnected);
2647 }
2648
2649 /* Make sure at least one adapter was enabled: */
2650 if (adapterData.isEmpty())
2651 return;
2652
2653 /* Add new actions: */
2654 foreach (ulong uSlot, adapterData.keys())
2655 {
2656 QAction *pAction = pMenu->addAction(UIIconPool::iconSetOnOff(":/connect_on_16px.png", ":/connect_16px.png"),
2657 adapterData.size() == 1 ? UIActionPool::tr("&Connect Network Adapter") :
2658 UIActionPool::tr("Connect Network Adapter &%1").arg(uSlot + 1),
2659 this, SLOT(sltToggleNetworkAdapterConnection(bool)));
2660 pAction->setProperty("slot", (uint)uSlot);
2661 pAction->setCheckable(true);
2662 pAction->setChecked(adapterData.value(uSlot));
2663 }
2664}
2665
2666void UIMachineLogic::updateMenuDevicesUSB(QMenu *pMenu)
2667{
2668 /* Acquire device list: */
2669 QList<USBDeviceInfo> guiUSBDevices;
2670 const bool fSuccess = uimachine()->usbDevices(guiUSBDevices);
2671
2672 /* If device list is empty: */
2673 if (!fSuccess || guiUSBDevices.isEmpty())
2674 {
2675 /* Add only one - "empty" action: */
2676 QAction *pEmptyMenuAction = pMenu->addAction(UIIconPool::iconSet(":/usb_unavailable_16px.png",
2677 ":/usb_unavailable_disabled_16px.png"),
2678 UIActionPool::tr("No USB Devices Connected"));
2679 pEmptyMenuAction->setToolTip(UIActionPool::tr("No supported devices connected to the host PC"));
2680 pEmptyMenuAction->setEnabled(false);
2681 }
2682 /* If device list is NOT empty: */
2683 else
2684 {
2685 /* Populate menu with host USB devices: */
2686 foreach (const USBDeviceInfo &guiUSBDevice, guiUSBDevices)
2687 {
2688 /* Create USB device action: */
2689 QAction *pAttachUSBAction = pMenu->addAction(guiUSBDevice.m_strName,
2690 this, SLOT(sltAttachUSBDevice()));
2691 pAttachUSBAction->setToolTip(guiUSBDevice.m_strToolTip);
2692 pAttachUSBAction->setCheckable(true);
2693 pAttachUSBAction->setChecked(guiUSBDevice.m_fIsChecked);
2694 pAttachUSBAction->setEnabled(guiUSBDevice.m_fIsEnabled);
2695 pAttachUSBAction->setData(QVariant::fromValue(USBTarget(!pAttachUSBAction->isChecked(),
2696 guiUSBDevice.m_uId)));
2697 }
2698 }
2699}
2700
2701void UIMachineLogic::updateMenuDevicesWebcams(QMenu *pMenu)
2702{
2703 /* Clear contents: */
2704 pMenu->clear();
2705
2706 /* Acquire device list: */
2707 QList<WebcamDeviceInfo> guiWebcamDevices;
2708 const bool fSuccess = uimachine()->webcamDevices(guiWebcamDevices);
2709
2710 /* If webcam list is empty: */
2711 if (!fSuccess || guiWebcamDevices.isEmpty())
2712 {
2713 /* Add only one - "empty" action: */
2714 QAction *pEmptyMenuAction = pMenu->addAction(UIIconPool::iconSet(":/web_camera_unavailable_16px.png",
2715 ":/web_camera_unavailable_disabled_16px.png"),
2716 UIActionPool::tr("No Webcams Connected"));
2717 pEmptyMenuAction->setToolTip(UIActionPool::tr("No supported webcams connected to the host PC"));
2718 pEmptyMenuAction->setEnabled(false);
2719 }
2720 /* If webcam list is NOT empty: */
2721 else
2722 {
2723 /* Populate menu with host webcams: */
2724 foreach (const WebcamDeviceInfo &guiWebcamDevice, guiWebcamDevices)
2725 {
2726 /* Create webcam device action: */
2727 QAction *pAttachWebcamAction = pMenu->addAction(guiWebcamDevice.m_strName,
2728 this, SLOT(sltAttachWebcamDevice()));
2729 pAttachWebcamAction->setToolTip(guiWebcamDevice.m_strToolTip);
2730 pAttachWebcamAction->setCheckable(true);
2731 pAttachWebcamAction->setChecked(guiWebcamDevice.m_fIsChecked);
2732 pAttachWebcamAction->setData(QVariant::fromValue(WebCamTarget(!pAttachWebcamAction->isChecked(),
2733 guiWebcamDevice.m_strName,
2734 guiWebcamDevice.m_strPath)));
2735 }
2736 }
2737}
2738
2739void UIMachineLogic::updateMenuDevicesSharedClipboard(QMenu *pMenu)
2740{
2741 /* Acquire current clipboard mode: */
2742 KClipboardMode enmCurrentMode = KClipboardMode_Disabled;
2743 uimachine()->acquireClipboardMode(enmCurrentMode);
2744
2745 /* First run: */
2746 if (!m_pSharedClipboardActions)
2747 {
2748 /* Prepare action-group: */
2749 m_pSharedClipboardActions = new QActionGroup(this);
2750 /* Load currently supported Clipboard modes: */
2751 CSystemProperties comProperties = gpGlobalSession->virtualBox().GetSystemProperties();
2752 QVector<KClipboardMode> clipboardModes = comProperties.GetSupportedClipboardModes();
2753 /* Take current clipboard mode into account: */
2754 if (!clipboardModes.contains(enmCurrentMode))
2755 clipboardModes.prepend(enmCurrentMode);
2756 /* Create action for all clipboard modes: */
2757 foreach (const KClipboardMode &enmMode, clipboardModes)
2758 {
2759 QAction *pAction = new QAction(gpConverter->toString(enmMode), m_pSharedClipboardActions);
2760 pMenu->addAction(pAction);
2761 pAction->setData(QVariant::fromValue(enmMode));
2762 pAction->setCheckable(true);
2763 pAction->setChecked(enmMode == enmCurrentMode);
2764 }
2765 /* Connect action-group trigger: */
2766 connect(m_pSharedClipboardActions, &QActionGroup::triggered, this, &UIMachineLogic::sltChangeSharedClipboardType);
2767
2768 /* Separator between the radio-buttons and the check-box: */
2769 pMenu->addSeparator();
2770
2771 /* Create checkable action for special 'clipboard file transfers' feature: */
2772 m_pFileTransferToggleAction = new QAction(UIActionPool::tr("Enable Clipboard File Transfers"));
2773 m_pFileTransferToggleAction->setCheckable(true);
2774 m_pFileTransferToggleAction->setChecked(uimachine()->isClipboardFileTransferEnabled());
2775 m_pFileTransferToggleAction->setEnabled(enmCurrentMode != KClipboardMode_Disabled);
2776 /* pMenu takes the ownership of the m_pFileTransferToggleAction. */
2777 pMenu->addAction(m_pFileTransferToggleAction);
2778 connect(m_pFileTransferToggleAction, &QAction::toggled, this, &UIMachineLogic::sltFileTransferToggled);
2779 }
2780 /* Subsequent runs: */
2781 else
2782 {
2783 if (m_pFileTransferToggleAction)
2784 {
2785 m_pFileTransferToggleAction->blockSignals(true);
2786 m_pFileTransferToggleAction->setChecked(uimachine()->isClipboardFileTransferEnabled());
2787 m_pFileTransferToggleAction->blockSignals(false);
2788 }
2789 foreach (QAction *pAction, m_pSharedClipboardActions->actions())
2790 if (pAction->data().value<KClipboardMode>() == enmCurrentMode)
2791 pAction->setChecked(true);
2792 }
2793}
2794
2795void UIMachineLogic::updateMenuDevicesDragAndDrop(QMenu *pMenu)
2796{
2797 /* Acquire current DnD mode: */
2798 KDnDMode enmCurrentMode = KDnDMode_Disabled;
2799 uimachine()->acquireDnDMode(enmCurrentMode);
2800
2801 /* First run: */
2802 if (!m_pDragAndDropActions)
2803 {
2804 /* Prepare action-group: */
2805 m_pDragAndDropActions = new QActionGroup(this);
2806 /* Load currently supported DnD modes: */
2807 CSystemProperties comProperties = gpGlobalSession->virtualBox().GetSystemProperties();
2808 QVector<KDnDMode> dndModes = comProperties.GetSupportedDnDModes();
2809 /* Take current DnD mode into account: */
2810 if (!dndModes.contains(enmCurrentMode))
2811 dndModes.prepend(enmCurrentMode);
2812 /* Create action for all clipboard modes: */
2813 foreach (const KDnDMode &enmMode, dndModes)
2814 {
2815 QAction *pAction = new QAction(gpConverter->toString(enmMode), m_pDragAndDropActions);
2816 pMenu->addAction(pAction);
2817 pAction->setData(QVariant::fromValue(enmMode));
2818 pAction->setCheckable(true);
2819 pAction->setChecked(enmMode == enmCurrentMode);
2820 }
2821 /* Connect action-group trigger: */
2822 connect(m_pDragAndDropActions, &QActionGroup::triggered, this, &UIMachineLogic::sltChangeDragAndDropType);
2823 }
2824 /* Subsequent runs: */
2825 else
2826 foreach (QAction *pAction, m_pDragAndDropActions->actions())
2827 if (pAction->data().value<KDnDMode>() == enmCurrentMode)
2828 pAction->setChecked(true);
2829}
2830
2831#ifdef VBOX_WITH_DEBUGGER_GUI
2832void UIMachineLogic::updateMenuDebug(QMenu*)
2833{
2834 bool fEnabled = false;
2835 uimachine()->acquireWhetherLogEnabled(fEnabled);
2836 actionPool()->action(UIActionIndexRT_M_Debug_T_Logging)->blockSignals(true);
2837 actionPool()->action(UIActionIndexRT_M_Debug_T_Logging)->setChecked(fEnabled);
2838 actionPool()->action(UIActionIndexRT_M_Debug_T_Logging)->blockSignals(false);
2839}
2840#endif /* VBOX_WITH_DEBUGGER_GUI */
2841
2842#ifdef VBOX_WS_MAC
2843void UIMachineLogic::updateMenuWindow(QMenu *pMenu)
2844{
2845 /* Make sure 'Switch' action(s) are allowed: */
2846 AssertPtrReturnVoid(actionPool());
2847 if (actionPool()->isAllowedInMenuWindow(UIExtraDataMetaDefs::MenuWindowActionType_Switch))
2848 {
2849 /* Append menu with actions to switch to machine-window(s): */
2850 foreach (UIMachineWindow *pMachineWindow, machineWindows())
2851 {
2852 /* Create machine-window action: */
2853 AssertPtrReturnVoid(pMachineWindow);
2854 QAction *pMachineWindowAction = pMenu->addAction(pMachineWindow->windowTitle(),
2855 this, SLOT(sltSwitchToMachineWindow()));
2856 AssertPtrReturnVoid(pMachineWindowAction);
2857 {
2858 pMachineWindowAction->setCheckable(true);
2859 pMachineWindowAction->setChecked(activeMachineWindow() == pMachineWindow);
2860 pMachineWindowAction->setData((int)pMachineWindow->screenId());
2861 }
2862 }
2863 }
2864}
2865#endif /* VBOX_WS_MAC */
2866
2867void UIMachineLogic::askUserForTheDiskEncryptionPasswords()
2868{
2869 /* Prepare the map of the encrypted media: */
2870 EncryptedMediumMap encryptedMedia;
2871 if (!uimachine()->acquireEncryptedMedia(encryptedMedia))
2872 return;
2873
2874 /* Ask for the disk encryption passwords if necessary: */
2875 EncryptionPasswordMap encryptionPasswords;
2876 if (!encryptedMedia.isEmpty())
2877 {
2878 /* Create the dialog for acquiring encryption passwords: */
2879 QWidget *pDlgParent = windowManager().realParentWindow(activeMachineWindow());
2880 QPointer<UIAddDiskEncryptionPasswordDialog> pDlg =
2881 new UIAddDiskEncryptionPasswordDialog(pDlgParent,
2882 machineName(),
2883 encryptedMedia);
2884 /* Execute the dialog: */
2885 if (pDlg->exec() == QDialog::Accepted)
2886 {
2887 /* Acquire the passwords provided: */
2888 encryptionPasswords = pDlg->encryptionPasswords();
2889
2890 /* Delete the dialog: */
2891 delete pDlg;
2892
2893 /* Make sure the passwords were really provided: */
2894 AssertReturnVoid(!encryptionPasswords.isEmpty());
2895
2896 /* Apply the disk encryption passwords: */
2897 foreach (const QString &strKey, encryptionPasswords.keys())
2898 uimachine()->addEncryptionPassword(strKey,
2899 encryptionPasswords.value(strKey),
2900 false /* do NOT clear on suspend */);
2901 }
2902 else
2903 {
2904 /* Any modal dialog can be destroyed in own event-loop
2905 * as a part of VM power-off procedure which closes GUI.
2906 * So we have to check if the dialog still valid.. */
2907
2908 /* If dialog still valid: */
2909 if (pDlg)
2910 {
2911 /* Delete the dialog: */
2912 delete pDlg;
2913
2914 /* Propose the user to close VM: */
2915 LogRel(("GUI: Request to close Runtime UI due to DEK was not provided.\n"));
2916 QMetaObject::invokeMethod(this, "sltClose", Qt::QueuedConnection);
2917 }
2918 }
2919 }
2920}
2921
2922void UIMachineLogic::openPreferencesDialog(const QString &strCategory /* = QString() */,
2923 const QString &strControl /* = QString() */,
2924 bool fAppModal /* = false */)
2925{
2926 /* Do not process if window(s) missed! */
2927 if (!isMachineWindowsCreated())
2928 return;
2929
2930 /* Create instance if not yet created: */
2931 if (!m_settings.contains(UIAdvancedSettingsDialog::Type_Global))
2932 {
2933 m_settings[UIAdvancedSettingsDialog::Type_Global] = new UIAdvancedSettingsDialogGlobal(activeMachineWindow(),
2934 strCategory,
2935 strControl);
2936 if (fAppModal)
2937 m_settings.value(UIAdvancedSettingsDialog::Type_Machine)->setWindowModality(Qt::ApplicationModal);
2938 connect(m_settings.value(UIAdvancedSettingsDialog::Type_Global), &UIAdvancedSettingsDialog::sigClose,
2939 this, &UIMachineLogic::sltClosePreferencesDialog);
2940 const bool fSuccess = m_settings.value(UIAdvancedSettingsDialog::Type_Global)->load();
2941 if (!fSuccess)
2942 {
2943 delete m_settings.take(UIAdvancedSettingsDialog::Type_Global);
2944 return;
2945 }
2946 }
2947
2948 /* Expose instance: */
2949 UIDesktopWidgetWatchdog::restoreWidget(m_settings.value(UIAdvancedSettingsDialog::Type_Global));
2950}
2951
2952void UIMachineLogic::openSettingsDialog(const QString &strCategory /* = QString() */,
2953 const QString &strControl /* = QString()*/,
2954 bool fAppModal /* = false */)
2955{
2956 /* Do not process if window(s) missed! */
2957 if (!isMachineWindowsCreated())
2958 return;
2959
2960 /* Create instance if not yet created: */
2961 if (!m_settings.contains(UIAdvancedSettingsDialog::Type_Machine))
2962 {
2963 m_settings[UIAdvancedSettingsDialog::Type_Machine] = new UIAdvancedSettingsDialogMachine(activeMachineWindow(),
2964 uiCommon().managedVMUuid(),
2965 actionPool(),
2966 strCategory,
2967 strControl);
2968 if (fAppModal)
2969 m_settings.value(UIAdvancedSettingsDialog::Type_Machine)->setWindowModality(Qt::ApplicationModal);
2970 connect(m_settings.value(UIAdvancedSettingsDialog::Type_Machine), &UIAdvancedSettingsDialog::sigClose,
2971 this, &UIMachineLogic::sltCloseSettingsDialog);
2972 const bool fSuccess = m_settings.value(UIAdvancedSettingsDialog::Type_Machine)->load();
2973 if (!fSuccess)
2974 {
2975 delete m_settings.take(UIAdvancedSettingsDialog::Type_Machine);
2976 return;
2977 }
2978 }
2979
2980 /* Expose instance: */
2981 UIDesktopWidgetWatchdog::restoreWidget(m_settings.value(UIAdvancedSettingsDialog::Type_Machine));
2982}
2983
2984void UIMachineLogic::takeScreenshot(const QString &strFile, const QString &strFormat /* = "png" */) const
2985{
2986 /* Get console: */
2987 ulong cMonitorCount = 0;
2988 uimachine()->acquireMonitorCount(cMonitorCount);
2989 QList<QImage> images;
2990 ulong uMaxWidth = 0;
2991 ulong uMaxHeight = 0;
2992 /* First create screenshots of all guest screens and save them in a list.
2993 * Also sum the width of all images and search for the biggest image height. */
2994 for (ulong uScreenIndex = 0; uScreenIndex < cMonitorCount; ++uScreenIndex)
2995 {
2996 ulong uWidth = 0, uHeight = 0, uDummy = 0;
2997 long iDummy = 0;
2998 KGuestMonitorStatus enmDummy = KGuestMonitorStatus_Disabled;
2999 uimachine()->acquireGuestScreenParameters(uScreenIndex, uWidth, uHeight, uDummy, iDummy, iDummy, enmDummy);
3000 uMaxWidth += uWidth;
3001 uMaxHeight = RT_MAX(uMaxHeight, uHeight);
3002 QImage shot = QImage(uWidth, uHeight, QImage::Format_RGB32);
3003 uimachine()->acquireScreenShot(uScreenIndex, shot.width(), shot.height(), KBitmapFormat_BGR0, shot.bits());
3004 images << shot;
3005 }
3006 /* Create a image which will hold all sub images vertically. */
3007 QImage bigImg = QImage(uMaxWidth, uMaxHeight, QImage::Format_RGB32);
3008 QPainter p(&bigImg);
3009 ULONG w = 0;
3010 /* Paint them. */
3011 for (int i = 0; i < images.size(); ++i)
3012 {
3013 p.drawImage(w, 0, images.at(i));
3014 w += images.at(i).width();
3015 }
3016 p.end();
3017
3018 /* Save the big image in the requested format: */
3019 const QFileInfo fi(strFile);
3020 const QString &strPathWithoutSuffix = QDir(fi.absolutePath()).absoluteFilePath(fi.baseName());
3021 const QString &strSuffix = fi.suffix().isEmpty() ? strFormat : fi.suffix();
3022 bigImg.save(QDir::toNativeSeparators(QFile::encodeName(QString("%1.%2").arg(strPathWithoutSuffix, strSuffix))),
3023 strFormat.toUtf8().constData());
3024}
3025
3026void UIMachineLogic::activateScreenSaver()
3027{
3028 /* Do nothing if we did not de-activated the host screen saver: */
3029 if (!gEDataManager->disableHostScreenSaver())
3030 return;
3031
3032 QVector<CMachine> machines = gpGlobalSession->virtualBox().GetMachines();
3033 bool fAnother = false;
3034 for (int i = 0; i < machines.size(); ++i)
3035 {
3036 if (machines[i].GetState() == KMachineState_Running && machines[i].GetId() != uiCommon().managedVMUuid())
3037 {
3038 fAnother = true;
3039 break;
3040 }
3041 }
3042
3043 /* Do nothing if there are other vms running.*/
3044 if (fAnother)
3045 return;
3046 sltDisableHostScreenSaverStateChanged(false);
3047}
3048
3049void UIMachineLogic::showBootFailureDialog()
3050{
3051 UIBootFailureDialog *pBootFailureDialog = new UIBootFailureDialog(activeMachineWindow());
3052 AssertPtrReturnVoid(pBootFailureDialog);
3053
3054 int iResult = pBootFailureDialog->exec(false);
3055 QString strISOPath = pBootFailureDialog->bootMediumPath();
3056
3057 delete pBootFailureDialog;
3058
3059 QFileInfo bootMediumFileInfo(strISOPath);
3060 if (bootMediumFileInfo.exists() && bootMediumFileInfo.isReadable())
3061 uimachine()->mountBootMedium(UIMediumTools::openMedium(UIMediumDeviceType_DVD, strISOPath));
3062
3063 if (iResult == static_cast<int>(UIBootFailureDialog::ReturnCode_Reset))
3064 reset(false);
3065}
3066
3067void UIMachineLogic::reset(bool fShowConfirmation)
3068{
3069 if ( !fShowConfirmation
3070 || msgCenter().confirmResetMachine(machineName()))
3071 {
3072 const bool fSuccess = uimachine()->reset();
3073 if (fSuccess)
3074 {
3075 // WORKAROUND:
3076 // On reset the additional screens didn't get a display
3077 // update. Emulate this for now until it get fixed. */
3078 ulong cMonitorCount = 0;
3079 uimachine()->acquireMonitorCount(cMonitorCount);
3080 for (ulong uScreenId = 1; uScreenId < cMonitorCount; ++uScreenId)
3081 machineWindows().at(uScreenId)->update();
3082 }
3083 }
3084}
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