VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 weeks ago

Copyright year updates by scm.

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

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