VirtualBox

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

Last change on this file was 104290, checked in by vboxsync, 9 days ago

FE/Qt. bugref:10622. Using new UITranslationEventListener in the runtime UI related classes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use