VirtualBox

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

Last change on this file was 104393, checked in by vboxsync, 10 days ago

FE/Qt. bugref:10622. Using new UITranslationEventListener in the UIActionPool class.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use