VirtualBox

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

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

FE/Qt: UICommon: Move versioning related functionality to UIVersion / UIVersionInfo; Rework user cases accordingly.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use