VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp@ 54732

Last change on this file since 54732 was 54732, checked in by vboxsync, 10 years ago

FE/Qt: 7676: Runtime UI: Disk Encryption (DE) support: Ups, forgot the condition in r98900.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.1 KB
Line 
1/* $Id: UISession.cpp 54732 2015-03-12 15:20:21Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISession class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifdef VBOX_WITH_PRECOMPILED_HEADERS
19# include <precomp.h>
20#else /* !VBOX_WITH_PRECOMPILED_HEADERS */
21
22/* Qt includes: */
23# include <QApplication>
24# include <QDesktopWidget>
25# include <QWidget>
26# ifdef Q_WS_MAC
27# include <QTimer>
28# endif /* Q_WS_MAC */
29
30/* GUI includes: */
31# include "VBoxGlobal.h"
32# include "UIExtraDataManager.h"
33# include "UISession.h"
34# include "UIMachine.h"
35# include "UIMedium.h"
36# include "UIActionPoolRuntime.h"
37# include "UIMachineLogic.h"
38# include "UIMachineView.h"
39# include "UIMachineWindow.h"
40# include "UIMessageCenter.h"
41# include "UIPopupCenter.h"
42# include "UIWizardFirstRun.h"
43# include "UIConsoleEventHandler.h"
44# include "UIFrameBuffer.h"
45# include "UISettingsDialogSpecific.h"
46# ifdef VBOX_WITH_VIDEOHWACCEL
47# include "VBoxFBOverlay.h"
48# endif /* VBOX_WITH_VIDEOHWACCEL */
49# ifdef Q_WS_MAC
50# include "UIMenuBar.h"
51# include "VBoxUtils-darwin.h"
52# endif /* Q_WS_MAC */
53
54# ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
55# include "UIKeyboardHandler.h"
56# include <signal.h>
57# endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
58
59/* COM includes: */
60# include "CSystemProperties.h"
61# include "CStorageController.h"
62# include "CMediumAttachment.h"
63# include "CNetworkAdapter.h"
64# include "CHostNetworkInterface.h"
65# include "CVRDEServer.h"
66# include "CUSBController.h"
67# include "CUSBDeviceFilters.h"
68# include "CHostVideoInputDevice.h"
69# include "CSnapshot.h"
70# include "CMedium.h"
71
72#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
73
74#ifdef Q_WS_X11
75# include <QX11Info>
76# include <X11/Xlib.h>
77# include <X11/Xutil.h>
78# ifndef VBOX_WITHOUT_XCURSOR
79# include <X11/Xcursor/Xcursor.h>
80# endif /* VBOX_WITHOUT_XCURSOR */
81#endif /* Q_WS_X11 */
82
83
84/* Qt includes: */
85#include <QDialog>
86#include <QVBoxLayout>
87#include <QLineEdit>
88#include <QTableView>
89#include <QHeaderView>
90#include <QItemEditorFactory>
91#include <QAbstractTableModel>
92#include <QStandardItemEditorCreator>
93/* GUI includes: */
94#include "QILabel.h"
95#include "QIDialogButtonBox.h"
96#include "QIWithRetranslateUI.h"
97#include "QIStyledItemDelegate.h"
98
99/* Type definitions: */
100typedef QMap<QString, QString> EncryptionPasswordsMap;
101typedef QMultiMap<QString, QString> EncryptedMediumsMap;
102
103/** Encryption-data table field indexes.
104 * @todo To be moved into separate file.. */
105enum UIEncryptionTableSection
106{
107 UIEncryptionTableSection_Id,
108 UIEncryptionTableSection_Password,
109 UIEncryptionTableSection_Max
110};
111
112/** QLineEdit implementation allowing to enter
113 * disk encryption password for particular password id.
114 * @todo To be moved into separate file.. */
115class UILineEdit : public QLineEdit
116{
117 Q_OBJECT;
118 Q_PROPERTY(QString password READ password WRITE setPassword USER true);
119
120signals:
121
122 /** Notifies listener about data should be committed. */
123 void sigCommitData(QWidget *pThis);
124
125public:
126
127 /** Constructor.
128 * @param pParent being passed to the base-class. */
129 UILineEdit(QWidget *pParent)
130 : QLineEdit(pParent)
131 {
132 /* Prepare: */
133 prepare();
134 }
135
136public slots:
137
138 /** Handles @s strText changes. */
139 void sltTextChanged(const QString &strText)
140 {
141 Q_UNUSED(strText);
142 /* Commit data to the listener: */
143 emit sigCommitData(this);
144 }
145
146private:
147
148 /** Prepare routine. */
149 void prepare()
150 {
151 /* Set alignment: */
152 setAlignment(Qt::AlignCenter);
153 /* Set echo mode: */
154 setEchoMode(QLineEdit::Password);
155 /* Listen for the text changes: */
156 connect(this, SIGNAL(textChanged(const QString&)),
157 this, SLOT(sltTextChanged(const QString&)));
158 }
159
160 /** Returns the password from the editor. */
161 QString password() const { return QLineEdit::text(); }
162 /** Defines the @a strPassword to the editor. */
163 void setPassword(const QString &strPassword) { QLineEdit::setText(strPassword); }
164};
165
166/** QAbstractTableModel implementation reflecting
167 * disk encryption passwords for particular password ids.
168 * @todo To be moved into separate file.. */
169class UIEncryptionDataModel : public QAbstractTableModel
170{
171 Q_OBJECT;
172
173public:
174
175 /** Constructor.
176 * @param pParent being passed to the base-class,
177 * @param encryptedMediums contains the lists of medium ids (values) encrypted with passwords with ids (keys). */
178 UIEncryptionDataModel(QObject *pParent, const EncryptedMediumsMap &encryptedMediums)
179 : QAbstractTableModel(pParent)
180 , m_encryptedMediums(encryptedMediums)
181 {
182 /* Prepare: */
183 prepare();
184 }
185
186 /** Returns encryption passwords. */
187 EncryptionPasswordsMap encryptionPasswords() const { return m_encryptionPasswords; }
188
189 /** Returns the @a index flags. */
190 virtual Qt::ItemFlags flags(const QModelIndex &index) const
191 {
192 /* Check index validness: */
193 if (!index.isValid())
194 return Qt::NoItemFlags;
195 /* Depending on column index: */
196 switch (index.column())
197 {
198 case UIEncryptionTableSection_Id: return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
199 case UIEncryptionTableSection_Password: return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
200 default: break;
201 }
202 /* No flags by default: */
203 return Qt::NoItemFlags;
204 }
205
206 /** Returns the row count. Provide optional @a parent instead of root if necessary. */
207 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const
208 {
209 Q_UNUSED(parent);
210 return m_encryptionPasswords.size();
211 }
212
213 /** Returns the column count. Provide optional @a parent instead of root if necessary. */
214 virtual int columnCount(const QModelIndex &parent = QModelIndex()) const
215 {
216 Q_UNUSED(parent);
217 return UIEncryptionTableSection_Max;
218 }
219
220 /** Returns header data for @a iSection, @a orientation and @a iRole. */
221 virtual QVariant headerData(int iSection, Qt::Orientation orientation, int iRole) const
222 {
223 /* Check argument validness: */
224 if (iRole != Qt::DisplayRole || orientation != Qt::Horizontal)
225 return QVariant();
226 /* Depending on column index: */
227 switch (iSection)
228 {
229 case UIEncryptionTableSection_Id: return tr("Password ID");
230 case UIEncryptionTableSection_Password: return tr("Password");
231 default: break;
232 }
233 /* Null value by default: */
234 return QVariant();
235 }
236
237 /** Returns @a index data for @a iRole. */
238 virtual QVariant data(const QModelIndex &index, int iRole /* = Qt::DisplayRole */) const
239 {
240 /* Check index validness: */
241 if (!index.isValid())
242 return QVariant();
243 /* Depending on role: */
244 switch (iRole)
245 {
246 case Qt::DisplayRole:
247 {
248 /* Depending on column index: */
249 switch (index.column())
250 {
251 case UIEncryptionTableSection_Id:
252 return m_encryptionPasswords.keys().at(index.row());
253 case UIEncryptionTableSection_Password:
254 return QString().fill('*', m_encryptionPasswords.value(m_encryptionPasswords.keys().at(index.row())).size());
255 default:
256 return QVariant();
257 }
258 break;
259 }
260 case Qt::EditRole:
261 {
262 /* Depending on column index: */
263 switch (index.column())
264 {
265 case UIEncryptionTableSection_Password:
266 return m_encryptionPasswords.value(m_encryptionPasswords.keys().at(index.row()));
267 default:
268 return QVariant();
269 }
270 break;
271 }
272 case Qt::TextAlignmentRole:
273 {
274 /* Depending on column index: */
275 switch (index.column())
276 {
277 case UIEncryptionTableSection_Password:
278 return Qt::AlignCenter;
279 default: return QVariant();
280 }
281 break;
282 }
283 default:
284 break;
285 }
286 /* Null value by default: */
287 return QVariant();
288 }
289
290 /** Defines @a index data for @a iRole as @a value. */
291 virtual bool setData(const QModelIndex &index, const QVariant &value, int iRole /* = Qt::EditRole */)
292 {
293 /* Check index validness: */
294 if (!index.isValid())
295 return false;
296 /* Check argument validness: */
297 if (iRole != Qt::EditRole)
298 return false;
299 /* Depending on column index: */
300 switch (index.column())
301 {
302 case UIEncryptionTableSection_Password: m_encryptionPasswords[m_encryptionPasswords.keys().at(index.row())] = value.toString(); break;
303 default: break;
304 }
305 /* Nothing to set by default: */
306 return false;
307 }
308
309private:
310
311 /** Prepare routine. */
312 void prepare()
313 {
314 /* Populate the map of passwords. */
315 foreach (const QString &strPasswordId, m_encryptedMediums.keys())
316 m_encryptionPasswords.insert(strPasswordId, QString());
317 }
318
319 /** Holds the encrypted medium map reference. */
320 const EncryptedMediumsMap &m_encryptedMediums;
321
322 /** Holds the encrypted password id map. */
323 EncryptionPasswordsMap m_encryptionPasswords;
324};
325
326/** QTableView implementation allowing to enter
327 * disk encryption passwords for particular password ids.
328 * @todo To be moved into separate file.. */
329class UIEncryptionDataTable : public QTableView
330{
331 Q_OBJECT;
332
333public:
334
335 /** Constructor.
336 * @param pParent being passed to the base-class. */
337 UIEncryptionDataTable(const EncryptedMediumsMap &encryptedMediums)
338 : m_encryptedMediums(encryptedMediums)
339 , m_pModelEncryptionData(0)
340 {
341 /* Prepare: */
342 prepare();
343 }
344
345 /** Returns encryption passwords. */
346 EncryptionPasswordsMap encryptionPasswords() const
347 {
348 AssertPtrReturn(m_pModelEncryptionData, EncryptionPasswordsMap());
349 return m_pModelEncryptionData->encryptionPasswords();
350 }
351
352private:
353
354 /** Prepare routine. */
355 void prepare()
356 {
357 /* Create encryption-data model: */
358 m_pModelEncryptionData = new UIEncryptionDataModel(this, m_encryptedMediums);
359 AssertPtrReturnVoid(m_pModelEncryptionData);
360 {
361 /* Assign configured model to table: */
362 setModel(m_pModelEncryptionData);
363 }
364
365 /* Create item delegate: */
366 QIStyledItemDelegate *pStyledItemDelegate = new QIStyledItemDelegate(this);
367 AssertPtrReturnVoid(pStyledItemDelegate);
368 {
369 /* Create item editor factory: */
370 QItemEditorFactory *pNewItemEditorFactory = new QItemEditorFactory;
371 AssertPtrReturnVoid(pNewItemEditorFactory);
372 {
373 /* Create item editor creator: */
374 QStandardItemEditorCreator<UILineEdit> *pQStringItemEditorCreator = new QStandardItemEditorCreator<UILineEdit>();
375 AssertPtrReturnVoid(pQStringItemEditorCreator);
376 {
377 /* Register UILineEdit as the QString editor: */
378 pNewItemEditorFactory->registerEditor(QVariant::String, pQStringItemEditorCreator);
379 }
380 /* Assign configured item editor factory to table delegate: */
381 pStyledItemDelegate->setItemEditorFactory(pNewItemEditorFactory);
382 }
383 /* Assign configured item delegate to table: */
384 delete itemDelegate();
385 setItemDelegate(pStyledItemDelegate);
386 }
387
388 /* Configure table: */
389 setTabKeyNavigation(false);
390 setContextMenuPolicy(Qt::CustomContextMenu);
391 setSelectionBehavior(QAbstractItemView::SelectRows);
392 setSelectionMode(QAbstractItemView::SingleSelection);
393 setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::SelectedClicked);
394
395 /* Configure headers: */
396 verticalHeader()->hide();
397 verticalHeader()->setDefaultSectionSize((int)(verticalHeader()->minimumSectionSize() * 1.33));
398 horizontalHeader()->setStretchLastSection(false);
399 horizontalHeader()->setResizeMode(UIEncryptionTableSection_Id, QHeaderView::Interactive);
400 horizontalHeader()->setResizeMode(UIEncryptionTableSection_Password, QHeaderView::Stretch);
401 }
402
403 /** Holds the encrypted medium map reference. */
404 const EncryptedMediumsMap &m_encryptedMediums;
405
406 /** Holds the encryption-data model. */
407 UIEncryptionDataModel *m_pModelEncryptionData;
408};
409
410/** QDialog implementation allowing to enter
411 * disk encryption passwords for particular password ids.
412 * @todo To be moved into separate files.. */
413class UIAddDiskEncryptionPasswordDialog : public QIWithRetranslateUI<QDialog>
414{
415 Q_OBJECT;
416
417public:
418
419 /** Constructor.
420 * @param pParent being passed to the base-class,
421 * @param encryptedMediums contains the lists of medium ids (values) encrypted with passwords with ids (keys). */
422 UIAddDiskEncryptionPasswordDialog(QWidget *pParent, const EncryptedMediumsMap &encryptedMediums)
423 : QIWithRetranslateUI<QDialog>(pParent)
424 , m_encryptedMediums(encryptedMediums)
425 , m_pLabelDescription(0)
426 , m_pTableEncryptionData(0)
427 {
428 /* Prepare: */
429 prepare();
430 /* Retranslate: */
431 retranslateUi();
432 }
433
434 /** Returns encryption passwords. */
435 EncryptionPasswordsMap encryptionPasswords() const
436 {
437 AssertPtrReturn(m_pTableEncryptionData, EncryptionPasswordsMap());
438 return m_pTableEncryptionData->encryptionPasswords();
439 }
440
441private:
442
443 /** Prepare routine. */
444 void prepare()
445 {
446 /* Create main-layout: */
447 QVBoxLayout *pMainLayout = new QVBoxLayout(this);
448 AssertPtrReturnVoid(pMainLayout);
449 {
450 /* Create input-layout: */
451 QVBoxLayout *pInputLayout = new QVBoxLayout;
452 AssertPtrReturnVoid(pInputLayout);
453 {
454 /* Create description label: */
455 m_pLabelDescription = new QILabel;
456 m_pLabelDescription->useSizeHintForWidth(450);
457 m_pLabelDescription->updateGeometry();
458 AssertPtrReturnVoid(m_pLabelDescription);
459 {
460 /* Configure description label: */
461 m_pLabelDescription->setWordWrap(true);
462 /* Add label into layout: */
463 pInputLayout->addWidget(m_pLabelDescription);
464 }
465 /* Create encryption-data table: */
466 m_pTableEncryptionData = new UIEncryptionDataTable(m_encryptedMediums);
467 AssertPtrReturnVoid(m_pTableEncryptionData);
468 {
469 /* Add label into layout: */
470 pInputLayout->addWidget(m_pTableEncryptionData);
471 }
472 /* Add layout into parent: */
473 pMainLayout->addLayout(pInputLayout);
474 }
475 /* Create button-box: */
476 QIDialogButtonBox *pButtonBox = new QIDialogButtonBox;
477 AssertPtrReturnVoid(pButtonBox);
478 {
479 /* Configure button-box: */
480 pButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
481 connect(pButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
482 connect(pButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
483 /* Add button-box into layout: */
484 pMainLayout->addWidget(pButtonBox);
485 }
486 }
487 }
488
489 /** Translation routine. */
490 void retranslateUi()
491 {
492 AssertPtrReturnVoid(m_pLabelDescription);
493 m_pLabelDescription->setText(tr("This virtual machine is password protected. "
494 "Please enter the %n encryption password(s) below.",
495 "This text is never used with n == 0. "
496 "Feel free to drop the %n where possible, "
497 "we only included it because of problems with Qt Linguist "
498 "(but the user can see how many passwords are in the list "
499 "and doesn't need to be told).",
500 m_encryptedMediums.size()));
501 }
502
503 /** Holds the encrypted medium map reference. */
504 const EncryptedMediumsMap &m_encryptedMediums;
505
506 /** Holds the description label. */
507 QILabel *m_pLabelDescription;
508 /** Holds the encryption-data table. */
509 UIEncryptionDataTable *m_pTableEncryptionData;
510};
511
512
513#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
514static void signalHandlerSIGUSR1(int sig, siginfo_t *, void *);
515#endif
516
517#ifdef Q_WS_MAC
518/**
519 * MacOS X: Application Services: Core Graphics: Display reconfiguration callback.
520 *
521 * Notifies UISession about @a display configuration change.
522 * Corresponding change described by Core Graphics @a flags.
523 * Uses UISession @a pHandler to process this change.
524 *
525 * @note Last argument (@a pHandler) must always be valid pointer to UISession object.
526 * @note Calls for UISession::sltHandleHostDisplayAboutToChange() slot if display configuration changed.
527 */
528void cgDisplayReconfigurationCallback(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *pHandler)
529{
530 /* Which flags we are handling? */
531 int iHandledFlags = kCGDisplayAddFlag /* display added */
532 | kCGDisplayRemoveFlag /* display removed */
533 | kCGDisplaySetModeFlag /* display mode changed */;
534
535 /* Handle 'display-add' case: */
536 if (flags & kCGDisplayAddFlag)
537 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display added.\n"));
538 /* Handle 'display-remove' case: */
539 else if (flags & kCGDisplayRemoveFlag)
540 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display removed.\n"));
541 /* Handle 'mode-set' case: */
542 else if (flags & kCGDisplaySetModeFlag)
543 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display mode changed.\n"));
544
545 /* Ask handler to process our callback: */
546 if (flags & iHandledFlags)
547 QTimer::singleShot(0, static_cast<UISession*>(pHandler),
548 SLOT(sltHandleHostDisplayAboutToChange()));
549
550 Q_UNUSED(display);
551}
552#endif /* Q_WS_MAC */
553
554/* static */
555bool UISession::create(UISession *&pSession, UIMachine *pMachine)
556{
557 /* Make sure null pointer passed: */
558 AssertReturn(pSession == 0, false);
559
560 /* Create session UI: */
561 pSession = new UISession(pMachine);
562 /* Make sure it's prepared: */
563 if (!pSession->prepare())
564 {
565 /* Destroy session UI otherwise: */
566 destroy(pSession);
567 /* False in that case: */
568 return false;
569 }
570 /* True by default: */
571 return true;
572}
573
574/* static */
575void UISession::destroy(UISession *&pSession)
576{
577 /* Make sure valid pointer passed: */
578 AssertReturnVoid(pSession != 0);
579
580 /* Cleanup session UI: */
581 pSession->cleanup();
582 /* Destroy session: */
583 delete pSession;
584 pSession = 0;
585}
586
587bool UISession::initialize()
588{
589 /* Preprocess initialization: */
590 if (!preprocessInitialization())
591 return false;
592
593 /* Notify user about mouse&keyboard auto-capturing: */
594 if (vboxGlobal().settings().autoCapture())
595 popupCenter().remindAboutAutoCapture(machineLogic()->activeMachineWindow());
596
597 /* Check if we are in teleportation waiting mode.
598 * In that case no first run wizard is necessary. */
599 m_machineState = machine().GetState();
600 if ( isFirstTimeStarted()
601 && !(( m_machineState == KMachineState_PoweredOff
602 || m_machineState == KMachineState_Aborted
603 || m_machineState == KMachineState_Teleported)
604 && machine().GetTeleporterEnabled()))
605 {
606 UISafePointerWizard pWizard = new UIWizardFirstRun(mainMachineWindow(), machine());
607 pWizard->prepare();
608 pWizard->exec();
609 if (pWizard)
610 delete pWizard;
611 }
612
613 /* Apply debug settings from the command line. */
614 if (!debugger().isNull() && debugger().isOk())
615 {
616 if (vboxGlobal().isPatmDisabled())
617 debugger().SetPATMEnabled(false);
618 if (vboxGlobal().isCsamDisabled())
619 debugger().SetCSAMEnabled(false);
620 if (vboxGlobal().isSupervisorCodeExecedRecompiled())
621 debugger().SetRecompileSupervisor(true);
622 if (vboxGlobal().isUserCodeExecedRecompiled())
623 debugger().SetRecompileUser(true);
624 if (vboxGlobal().areWeToExecuteAllInIem())
625 debugger().SetExecuteAllInIEM(true);
626 if (!vboxGlobal().isDefaultWarpPct())
627 debugger().SetVirtualTimeRate(vboxGlobal().getWarpPct());
628 }
629
630 /* Power UP if this is NOT separate process: */
631 if (!vboxGlobal().isSeparateProcess())
632 if (!powerUp())
633 return false;
634
635 /* Check if we missed a really quick termination after successful startup: */
636 if (isTurnedOff())
637 return false;
638
639 /* Postprocess initialization: */
640 if (!postprocessInitialization())
641 return false;
642
643 /* Fetch corresponding states: */
644 if (vboxGlobal().isSeparateProcess())
645 {
646 m_fIsMouseSupportsAbsolute = mouse().GetAbsoluteSupported();
647 m_fIsMouseSupportsRelative = mouse().GetRelativeSupported();
648 m_fIsMouseSupportsMultiTouch = mouse().GetMultiTouchSupported();
649 m_fIsMouseHostCursorNeeded = mouse().GetNeedsHostCursor();
650 sltAdditionsChange();
651 }
652 machineLogic()->initializePostPowerUp();
653
654#ifdef VBOX_WITH_VIDEOHWACCEL
655 /* Log whether 2D video acceleration is enabled: */
656 LogRel(("2D video acceleration is %s.\n",
657 machine().GetAccelerate2DVideoEnabled() && VBoxGlobal::isAcceleration2DVideoAvailable()
658 ? "enabled" : "disabled"));
659#endif /* VBOX_WITH_VIDEOHWACCEL */
660
661/* Log whether HID LEDs sync is enabled: */
662#if defined(Q_WS_MAC) || defined(Q_WS_WIN)
663 LogRel(("HID LEDs sync is %s.\n",
664 uimachine()->machineLogic()->isHidLedsSyncEnabled()
665 ? "enabled" : "disabled"));
666#else /* !Q_WS_MAC && !Q_WS_WIN */
667 LogRel(("HID LEDs sync is not supported on this platform.\n"));
668#endif /* !Q_WS_MAC && !Q_WS_WIN */
669
670#ifdef VBOX_GUI_WITH_PIDFILE
671 vboxGlobal().createPidfile();
672#endif /* VBOX_GUI_WITH_PIDFILE */
673
674 /* Warn listeners about we are initialized: */
675 emit sigInitialized();
676
677 /* True by default: */
678 return true;
679}
680
681bool UISession::powerUp()
682{
683 /* Prepare map of the encrypted ids: */
684 EncryptedMediumsMap encryptedPasswordIds;
685 foreach (const CMediumAttachment &attachment, machine().GetMediumAttachments())
686 {
687 /* Acquire hard-drives only: */
688 if (attachment.GetType() == KDeviceType_HardDisk)
689 {
690 /* Get attachment medium: */
691 const CMedium medium = attachment.GetMedium();
692 /* Append our map if this medium has encryption: */
693 const QString strKeyId = medium.GetProperty("CRYPT/KeyId");
694 if (!strKeyId.isNull())
695 encryptedPasswordIds.insert(strKeyId, medium.GetId());
696 }
697 }
698 /* Ask for disk encryption passwords if necessary: */
699 EncryptionPasswordsMap encryptionPasswords;
700 if (!encryptedPasswordIds.isEmpty())
701 {
702 QPointer<UIAddDiskEncryptionPasswordDialog> pDlg =
703 new UIAddDiskEncryptionPasswordDialog(machineLogic()->activeMachineWindow(),
704 encryptedPasswordIds);
705 if (pDlg->exec() == QDialog::Accepted)
706 encryptionPasswords = pDlg->encryptionPasswords();
707 if (pDlg)
708 delete pDlg;
709 }
710
711 /* Power UP machine: */
712#ifdef VBOX_WITH_DEBUGGER_GUI
713 CProgress progress = vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled() ?
714 console().PowerUpPaused() : console().PowerUp();
715#else /* !VBOX_WITH_DEBUGGER_GUI */
716 CProgress progress = console().PowerUp();
717#endif /* !VBOX_WITH_DEBUGGER_GUI */
718
719 /* Check for immediate failure: */
720 if (!console().isOk() || progress.isNull())
721 {
722 if (vboxGlobal().showStartVMErrors())
723 msgCenter().cannotStartMachine(console(), machineName());
724 return false;
725 }
726
727 /* Guard progressbar warnings from auto-closing: */
728 if (uimachine()->machineLogic())
729 uimachine()->machineLogic()->setPreventAutoClose(true);
730
731 /* Show "Starting/Restoring" progress dialog: */
732 if (isSaved())
733 {
734 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_state_restore_90px.png", 0, 0);
735 /* After restoring from 'saved' state, machine-window(s) geometry should be adjusted: */
736 machineLogic()->adjustMachineWindowsGeometry();
737 }
738 else
739 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_start_90px.png");
740
741 /* Check for progress failure: */
742 if (!progress.isOk() || progress.GetResultCode() != 0)
743 {
744 if (vboxGlobal().showStartVMErrors())
745 msgCenter().cannotStartMachine(progress, machineName());
746 return false;
747 }
748
749 /* Add the disk encryption passwords: */
750 if (!encryptionPasswords.isEmpty())
751 {
752 foreach (const QString &strKey, encryptionPasswords.keys())
753 {
754 console().AddDiskEncryptionPassword(strKey, encryptionPasswords.value(strKey), true);
755 if (!console().isOk())
756 msgCenter().cannotAddDiskEncryptionPassword(console());
757 }
758 }
759
760 /* Allow further auto-closing: */
761 if (uimachine()->machineLogic())
762 uimachine()->machineLogic()->setPreventAutoClose(false);
763
764 /* True by default: */
765 return true;
766}
767
768bool UISession::saveState()
769{
770 /* Prepare the saving progress: */
771 CProgress progress = console().SaveState();
772 if (console().isOk())
773 {
774 /* Show the saving progress: */
775 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_state_save_90px.png");
776 if (!progress.isOk() || progress.GetResultCode() != 0)
777 {
778 /* Failed in progress: */
779 msgCenter().cannotSaveMachineState(progress, machineName());
780 return false;
781 }
782 }
783 else
784 {
785 /* Failed in console: */
786 msgCenter().cannotSaveMachineState(console());
787 return false;
788 }
789 /* Passed: */
790 return true;
791}
792
793bool UISession::shutdown()
794{
795 /* Send ACPI shutdown signal if possible: */
796 console().PowerButton();
797 if (!console().isOk())
798 {
799 /* Failed in console: */
800 msgCenter().cannotACPIShutdownMachine(console());
801 return false;
802 }
803 /* Passed: */
804 return true;
805}
806
807bool UISession::powerOff(bool fIncludingDiscard, bool &fServerCrashed)
808{
809 /* Prepare the power-off progress: */
810 CProgress progress = console().PowerDown();
811 if (console().isOk())
812 {
813 /* Show the power-off progress: */
814 msgCenter().showModalProgressDialog(progress, machineName(), ":/progress_poweroff_90px.png");
815 if (progress.isOk() && progress.GetResultCode() == 0)
816 {
817 /* Discard the current state if requested: */
818 if (fIncludingDiscard)
819 return restoreCurrentSnapshot();
820 }
821 else
822 {
823 /* Failed in progress: */
824 msgCenter().cannotPowerDownMachine(progress, machineName());
825 return false;
826 }
827 }
828 else
829 {
830 /* Check the machine state, it might be already gone: */
831 if (!console().isNull())
832 {
833 /* Failed in console: */
834 COMResult res(console());
835 /* This can happen if VBoxSVC is not running: */
836 if (FAILED_DEAD_INTERFACE(res.rc()))
837 fServerCrashed = true;
838 else
839 msgCenter().cannotPowerDownMachine(console());
840 return false;
841 }
842 }
843 /* Passed: */
844 return true;
845}
846
847bool UISession::restoreCurrentSnapshot()
848{
849 /* Prepare result: */
850 bool fResult = false;
851
852 /* Simulate try-catch block: */
853 do
854 {
855 /* Search for corresponding VM: */
856 CVirtualBox vbox = vboxGlobal().virtualBox();
857 const QString strMachineID = vboxGlobal().managedVMUuid();
858 const CMachine mach = vbox.FindMachine(strMachineID);
859 if (!vbox.isOk() || mach.isNull())
860 {
861 /* Unable to find VM: */
862 msgCenter().cannotFindMachineById(vbox, strMachineID);
863 break;
864 }
865
866 /* Open a direct session to modify that VM: */
867 CSession sess = vboxGlobal().openSession(vboxGlobal().managedVMUuid(),
868 vboxGlobal().isSeparateProcess()
869 ? KLockType_Write : KLockType_Shared);
870 if (sess.isNull())
871 {
872 /* Unable to open session: */
873 break;
874 }
875
876 /* Simulate try-catch block: */
877 do
878 {
879 /* Acquire console for this session: */
880 CConsole cons = sess.GetConsole();
881 if (cons.isNull())
882 {
883 /* Unable to acquire console: */
884 break;
885 }
886
887 /* Prepare the snapshot-discard progress: */
888 const CSnapshot snap = mach.GetCurrentSnapshot();
889 CProgress prog = cons.RestoreSnapshot(snap);
890 if (!cons.isOk() || prog.isNull())
891 {
892 /* Unable to restore snapshot: */
893 msgCenter().cannotRestoreSnapshot(cons, snap.GetName(), machineName());
894 break;
895 }
896
897 /* Show the snapshot-discard progress: */
898 msgCenter().showModalProgressDialog(prog, mach.GetName(), ":/progress_snapshot_discard_90px.png");
899 if (prog.GetResultCode() != 0)
900 {
901 /* Unable to restore snapshot: */
902 msgCenter().cannotRestoreSnapshot(prog, snap.GetName(), mach.GetName());
903 break;
904 }
905
906 /* Success: */
907 fResult = true;
908 }
909 while (0);
910
911 /* Unlock machine finally: */
912 sess.UnlockMachine();
913 }
914 while (0);
915
916 /* Return result: */
917 return fResult;
918}
919
920void UISession::closeRuntimeUI()
921{
922 /* Start corresponding slot asynchronously: */
923 emit sigCloseRuntimeUI();
924}
925
926UIMachineLogic* UISession::machineLogic() const
927{
928 return uimachine() ? uimachine()->machineLogic() : 0;
929}
930
931QWidget* UISession::mainMachineWindow() const
932{
933 return machineLogic() ? machineLogic()->mainMachineWindow() : 0;
934}
935
936bool UISession::isVisualStateAllowed(UIVisualStateType state) const
937{
938 return m_pMachine->isVisualStateAllowed(state);
939}
940
941void UISession::changeVisualState(UIVisualStateType visualStateType)
942{
943 m_pMachine->asyncChangeVisualState(visualStateType);
944}
945
946bool UISession::setPause(bool fOn)
947{
948 if (fOn)
949 console().Pause();
950 else
951 console().Resume();
952
953 bool ok = console().isOk();
954 if (!ok)
955 {
956 if (fOn)
957 msgCenter().cannotPauseMachine(console());
958 else
959 msgCenter().cannotResumeMachine(console());
960 }
961
962 return ok;
963}
964
965void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
966{
967 /* This flag indicates whether we want to do the usual .ISO mounting or not.
968 * First try updating the Guest Additions directly without mounting the .ISO. */
969 bool fDoMount = false;
970
971 /* Auto-update in GUI currently is disabled. */
972#ifndef VBOX_WITH_ADDITIONS_AUTOUPDATE_UI
973 fDoMount = true;
974#else /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
975 QVector<KAdditionsUpdateFlag> aFlagsUpdate;
976 QVector<QString> aArgs;
977 CProgress progressInstall = guest().UpdateGuestAdditions(strSource,
978 aArgs, aFlagsUpdate);
979 bool fResult = guest().isOk();
980 if (fResult)
981 {
982 msgCenter().showModalProgressDialog(progressInstall, tr("Updating Guest Additions"),
983 ":/progress_install_guest_additions_90px.png",
984 0, 500 /* 500ms delay. */);
985 if (progressInstall.GetCanceled())
986 return;
987
988 HRESULT rc = progressInstall.GetResultCode();
989 if (!progressInstall.isOk() || rc != S_OK)
990 {
991 /* If we got back a VBOX_E_NOT_SUPPORTED we don't complain (guest OS
992 * simply isn't supported yet), so silently fall back to "old" .ISO
993 * mounting method. */
994 if ( !SUCCEEDED_WARNING(rc)
995 && rc != VBOX_E_NOT_SUPPORTED)
996 {
997 msgCenter().cannotUpdateGuestAdditions(progressInstall);
998
999 /* Log the error message in the release log. */
1000 QString strErr = progressInstall.GetErrorInfo().GetText();
1001 if (!strErr.isEmpty())
1002 LogRel(("%s\n", strErr.toLatin1().constData()));
1003 }
1004 fDoMount = true; /* Since automatic updating failed, fall back to .ISO mounting. */
1005 }
1006 }
1007#endif /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
1008
1009 /* Do we still want mounting? */
1010 if (!fDoMount)
1011 return;
1012
1013 /* Open corresponding medium: */
1014 QString strMediumID;
1015 CVirtualBox vbox = vboxGlobal().virtualBox();
1016 CMedium image = vbox.OpenMedium(strSource, KDeviceType_DVD, KAccessMode_ReadWrite, false /* fForceNewUuid */);
1017 if (vbox.isOk() && !image.isNull())
1018 strMediumID = image.GetId();
1019 else
1020 {
1021 msgCenter().cannotOpenMedium(vbox, UIMediumType_DVD, strSource, mainMachineWindow());
1022 return;
1023 }
1024
1025 /* Make sure GA medium ID is valid: */
1026 AssertReturnVoid(!strMediumID.isNull());
1027
1028 /* Searching for the first suitable controller/slot: */
1029 QString strControllerName;
1030 LONG iCntPort = -1, iCntDevice = -1;
1031 foreach (const CStorageController &controller, machine().GetStorageControllers())
1032 {
1033 foreach (const CMediumAttachment &attachment, machine().GetMediumAttachmentsOfController(controller.GetName()))
1034 {
1035 if (attachment.GetType() == KDeviceType_DVD)
1036 {
1037 strControllerName = controller.GetName();
1038 iCntPort = attachment.GetPort();
1039 iCntDevice = attachment.GetDevice();
1040 break;
1041 }
1042 }
1043 if (!strControllerName.isNull())
1044 break;
1045 }
1046
1047 /* Make sure suitable controller/slot were found: */
1048 if (strControllerName.isNull())
1049 {
1050 msgCenter().cannotMountGuestAdditions(machineName());
1051 return;
1052 }
1053
1054 /* Try to find UIMedium among cached: */
1055 UIMedium medium = vboxGlobal().medium(strMediumID);
1056 if (medium.isNull())
1057 {
1058 /* Create new one if necessary: */
1059 medium = UIMedium(image, UIMediumType_DVD, KMediumState_Created);
1060 vboxGlobal().createMedium(medium);
1061 }
1062
1063 /* Mount medium to corresponding controller/slot: */
1064 machine().MountMedium(strControllerName, iCntPort, iCntDevice, medium.medium(), false /* force */);
1065 if (!machine().isOk())
1066 {
1067 /* Ask for force mounting: */
1068 if (msgCenter().cannotRemountMedium(machine(), medium, true /* mount? */,
1069 true /* retry? */, mainMachineWindow()))
1070 {
1071 /* Force mount medium to the predefined port/device: */
1072 machine().MountMedium(strControllerName, iCntPort, iCntDevice, medium.medium(), true /* force */);
1073 if (!machine().isOk())
1074 msgCenter().cannotRemountMedium(machine(), medium, true /* mount? */,
1075 false /* retry? */, mainMachineWindow());
1076 }
1077 }
1078}
1079
1080void UISession::sltCloseRuntimeUI()
1081{
1082 /* First, we have to hide any opened modal/popup widgets.
1083 * They then should unlock their event-loops synchronously.
1084 * If all such loops are unlocked, we can close Runtime UI: */
1085 if (QWidget *pWidget = QApplication::activeModalWidget() ?
1086 QApplication::activeModalWidget() :
1087 QApplication::activePopupWidget() ?
1088 QApplication::activePopupWidget() : 0)
1089 {
1090 /* First we should try to close this widget: */
1091 pWidget->close();
1092 /* If widget rejected the 'close-event' we can
1093 * still hide it and hope it will behave correctly
1094 * and unlock his event-loop if any: */
1095 if (!pWidget->isHidden())
1096 pWidget->hide();
1097 /* Restart this slot: */
1098 emit sigCloseRuntimeUI();
1099 return;
1100 }
1101
1102 /* Finally close the Runtime UI: */
1103 UIMachine::destroy();
1104}
1105
1106#ifdef RT_OS_DARWIN
1107void UISession::sltHandleMenuBarConfigurationChange(const QString &strMachineID)
1108{
1109 /* Skip unrelated machine IDs: */
1110 if (vboxGlobal().managedVMUuid() != strMachineID)
1111 return;
1112
1113 /* Update Mac OS X menu-bar: */
1114 updateMenu();
1115}
1116#endif /* RT_OS_DARWIN */
1117
1118void UISession::sltMousePointerShapeChange(bool fVisible, bool fAlpha, QPoint hotCorner, QSize size, QVector<uint8_t> shape)
1119{
1120 /* In case of shape data is present: */
1121 if (shape.size() > 0)
1122 {
1123 /* We are ignoring visibility flag: */
1124 m_fIsHidingHostPointer = false;
1125
1126 /* And updating current cursor shape: */
1127 setPointerShape(shape.data(), fAlpha,
1128 hotCorner.x(), hotCorner.y(),
1129 size.width(), size.height());
1130 }
1131 /* In case of shape data is NOT present: */
1132 else
1133 {
1134 /* Remember if we should hide the cursor: */
1135 m_fIsHidingHostPointer = !fVisible;
1136 }
1137
1138 /* Notify listeners about mouse capability changed: */
1139 emit sigMousePointerShapeChange();
1140
1141}
1142
1143void UISession::sltMouseCapabilityChange(bool fSupportsAbsolute, bool fSupportsRelative, bool fSupportsMultiTouch, bool fNeedsHostCursor)
1144{
1145 LogRelFlow(("UISession::sltMouseCapabilityChange: "
1146 "Supports absolute: %s, Supports relative: %s, "
1147 "Supports multi-touch: %s, Needs host cursor: %s\n",
1148 fSupportsAbsolute ? "TRUE" : "FALSE", fSupportsRelative ? "TRUE" : "FALSE",
1149 fSupportsMultiTouch ? "TRUE" : "FALSE", fNeedsHostCursor ? "TRUE" : "FALSE"));
1150
1151 /* Check if something had changed: */
1152 if ( m_fIsMouseSupportsAbsolute != fSupportsAbsolute
1153 || m_fIsMouseSupportsRelative != fSupportsRelative
1154 || m_fIsMouseSupportsMultiTouch != fSupportsMultiTouch
1155 || m_fIsMouseHostCursorNeeded != fNeedsHostCursor)
1156 {
1157 /* Store new data: */
1158 m_fIsMouseSupportsAbsolute = fSupportsAbsolute;
1159 m_fIsMouseSupportsRelative = fSupportsRelative;
1160 m_fIsMouseSupportsMultiTouch = fSupportsMultiTouch;
1161 m_fIsMouseHostCursorNeeded = fNeedsHostCursor;
1162
1163 /* Notify listeners about mouse capability changed: */
1164 emit sigMouseCapabilityChange();
1165 }
1166}
1167
1168void UISession::sltKeyboardLedsChangeEvent(bool fNumLock, bool fCapsLock, bool fScrollLock)
1169{
1170 /* Check if something had changed: */
1171 if ( m_fNumLock != fNumLock
1172 || m_fCapsLock != fCapsLock
1173 || m_fScrollLock != fScrollLock)
1174 {
1175 /* Store new num lock data: */
1176 if (m_fNumLock != fNumLock)
1177 {
1178 m_fNumLock = fNumLock;
1179 m_uNumLockAdaptionCnt = 2;
1180 }
1181
1182 /* Store new caps lock data: */
1183 if (m_fCapsLock != fCapsLock)
1184 {
1185 m_fCapsLock = fCapsLock;
1186 m_uCapsLockAdaptionCnt = 2;
1187 }
1188
1189 /* Store new scroll lock data: */
1190 if (m_fScrollLock != fScrollLock)
1191 {
1192 m_fScrollLock = fScrollLock;
1193 }
1194
1195 /* Notify listeners about mouse capability changed: */
1196 emit sigKeyboardLedsChange();
1197 }
1198}
1199
1200void UISession::sltStateChange(KMachineState state)
1201{
1202 /* Check if something had changed: */
1203 if (m_machineState != state)
1204 {
1205 /* Store new data: */
1206 m_machineStatePrevious = m_machineState;
1207 m_machineState = state;
1208
1209 /* Notify listeners about machine state changed: */
1210 emit sigMachineStateChange();
1211 }
1212}
1213
1214void UISession::sltVRDEChange()
1215{
1216 /* Make sure VRDE server is present: */
1217 const CVRDEServer server = machine().GetVRDEServer();
1218 AssertMsgReturnVoid(machine().isOk() && !server.isNull(),
1219 ("VRDE server should NOT be null!\n"));
1220
1221 /* Check/Uncheck VRDE Server action depending on feature status: */
1222 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->blockSignals(true);
1223 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->setChecked(server.GetEnabled());
1224 actionPool()->action(UIActionIndexRT_M_View_T_VRDEServer)->blockSignals(false);
1225
1226 /* Notify listeners about VRDE change: */
1227 emit sigVRDEChange();
1228}
1229
1230void UISession::sltVideoCaptureChange()
1231{
1232 /* Check/Uncheck Video Capture action depending on feature status: */
1233 actionPool()->action(UIActionIndexRT_M_View_M_VideoCapture_T_Start)->blockSignals(true);
1234 actionPool()->action(UIActionIndexRT_M_View_M_VideoCapture_T_Start)->setChecked(machine().GetVideoCaptureEnabled());
1235 actionPool()->action(UIActionIndexRT_M_View_M_VideoCapture_T_Start)->blockSignals(false);
1236
1237 /* Notify listeners about Video Capture change: */
1238 emit sigVideoCaptureChange();
1239}
1240
1241void UISession::sltGuestMonitorChange(KGuestMonitorChangedEventType changeType, ulong uScreenId, QRect screenGeo)
1242{
1243 /* Ignore KGuestMonitorChangedEventType_NewOrigin change event: */
1244 if (changeType == KGuestMonitorChangedEventType_NewOrigin)
1245 return;
1246 /* Ignore KGuestMonitorChangedEventType_Disabled event for primary screen: */
1247 AssertMsg(countOfVisibleWindows() > 0, ("All machine windows are hidden!"));
1248 if (changeType == KGuestMonitorChangedEventType_Disabled && uScreenId == 0)
1249 return;
1250
1251 /* Process KGuestMonitorChangedEventType_Enabled change event: */
1252 if ( !isScreenVisible(uScreenId)
1253 && changeType == KGuestMonitorChangedEventType_Enabled)
1254 setScreenVisible(uScreenId, true);
1255 /* Process KGuestMonitorChangedEventType_Disabled change event: */
1256 else if ( isScreenVisible(uScreenId)
1257 && changeType == KGuestMonitorChangedEventType_Disabled)
1258 setScreenVisible(uScreenId, false);
1259
1260 /* Notify listeners about the change: */
1261 emit sigGuestMonitorChange(changeType, uScreenId, screenGeo);
1262}
1263
1264#ifdef RT_OS_DARWIN
1265/**
1266 * MacOS X: Restarts display-reconfiguration watchdog timer from the beginning.
1267 * @note Watchdog is trying to determine display reconfiguration in
1268 * UISession::sltCheckIfHostDisplayChanged() slot every 500ms for 40 tries.
1269 */
1270void UISession::sltHandleHostDisplayAboutToChange()
1271{
1272 LogRelFlow(("UISession::sltHandleHostDisplayAboutToChange()\n"));
1273
1274 if (m_pWatchdogDisplayChange->isActive())
1275 m_pWatchdogDisplayChange->stop();
1276 m_pWatchdogDisplayChange->setProperty("tryNumber", 1);
1277 m_pWatchdogDisplayChange->start();
1278}
1279
1280/**
1281 * MacOS X: Determines display reconfiguration.
1282 * @note Calls for UISession::sltHandleHostScreenCountChange() if screen count changed.
1283 * @note Calls for UISession::sltHandleHostScreenGeometryChange() if screen geometry changed.
1284 */
1285void UISession::sltCheckIfHostDisplayChanged()
1286{
1287 LogRelFlow(("UISession::sltCheckIfHostDisplayChanged()\n"));
1288
1289 /* Acquire desktop wrapper: */
1290 QDesktopWidget *pDesktop = QApplication::desktop();
1291
1292 /* Check if display count changed: */
1293 if (pDesktop->screenCount() != m_hostScreens.size())
1294 {
1295 /* Reset watchdog: */
1296 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
1297 /* Notify listeners about screen-count changed: */
1298 return sltHandleHostScreenCountChange();
1299 }
1300 else
1301 {
1302 /* Check if at least one display geometry changed: */
1303 for (int iScreenIndex = 0; iScreenIndex < pDesktop->screenCount(); ++iScreenIndex)
1304 {
1305 if (pDesktop->screenGeometry(iScreenIndex) != m_hostScreens.at(iScreenIndex))
1306 {
1307 /* Reset watchdog: */
1308 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
1309 /* Notify listeners about screen-geometry changed: */
1310 return sltHandleHostScreenGeometryChange();
1311 }
1312 }
1313 }
1314
1315 /* Check if watchdog expired, restart if not: */
1316 int cTryNumber = m_pWatchdogDisplayChange->property("tryNumber").toInt();
1317 if (cTryNumber > 0 && cTryNumber < 40)
1318 {
1319 /* Restart watchdog again: */
1320 m_pWatchdogDisplayChange->setProperty("tryNumber", ++cTryNumber);
1321 m_pWatchdogDisplayChange->start();
1322 }
1323 else
1324 {
1325 /* Reset watchdog: */
1326 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
1327 }
1328}
1329#endif /* RT_OS_DARWIN */
1330
1331void UISession::sltHandleHostScreenCountChange()
1332{
1333 LogRelFlow(("UISession: Host-screen count changed.\n"));
1334
1335 /* Recache display data: */
1336 updateHostScreenData();
1337
1338 /* Notify current machine-logic: */
1339 emit sigHostScreenCountChange();
1340}
1341
1342void UISession::sltHandleHostScreenGeometryChange()
1343{
1344 LogRelFlow(("UISession: Host-screen geometry changed.\n"));
1345
1346 /* Recache display data: */
1347 updateHostScreenData();
1348
1349 /* Notify current machine-logic: */
1350 emit sigHostScreenGeometryChange();
1351}
1352
1353void UISession::sltHandleHostScreenAvailableAreaChange()
1354{
1355 LogRelFlow(("UISession: Host-screen available-area changed.\n"));
1356
1357 /* Notify current machine-logic: */
1358 emit sigHostScreenAvailableAreaChange();
1359}
1360
1361void UISession::sltAdditionsChange()
1362{
1363 /* Variable flags: */
1364 ULONG ulGuestAdditionsRunLevel = guest().GetAdditionsRunLevel();
1365 LONG64 lLastUpdatedIgnored;
1366 bool fIsGuestSupportsGraphics = guest().GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
1367 == KAdditionsFacilityStatus_Active;
1368 bool fIsGuestSupportsSeamless = guest().GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
1369 == KAdditionsFacilityStatus_Active;
1370 /* Check if something had changed: */
1371 if (m_ulGuestAdditionsRunLevel != ulGuestAdditionsRunLevel ||
1372 m_fIsGuestSupportsGraphics != fIsGuestSupportsGraphics ||
1373 m_fIsGuestSupportsSeamless != fIsGuestSupportsSeamless)
1374 {
1375 /* Store new data: */
1376 m_ulGuestAdditionsRunLevel = ulGuestAdditionsRunLevel;
1377 m_fIsGuestSupportsGraphics = fIsGuestSupportsGraphics;
1378 m_fIsGuestSupportsSeamless = fIsGuestSupportsSeamless;
1379
1380 /* Notify listeners about guest additions state really changed: */
1381 emit sigAdditionsStateActualChange();
1382 }
1383
1384 /* Notify listeners about guest additions state event came: */
1385 emit sigAdditionsStateChange();
1386}
1387
1388UISession::UISession(UIMachine *pMachine)
1389 : QObject(pMachine)
1390 /* Base variables: */
1391 , m_pMachine(pMachine)
1392 , m_pActionPool(0)
1393#ifdef Q_WS_MAC
1394 , m_pMenuBar(0)
1395#endif /* Q_WS_MAC */
1396 /* Common variables: */
1397 , m_machineStatePrevious(KMachineState_Null)
1398 , m_machineState(KMachineState_Null)
1399#ifndef Q_WS_MAC
1400 , m_pMachineWindowIcon(0)
1401#endif /* !Q_WS_MAC */
1402 , m_mouseCapturePolicy(MouseCapturePolicy_Default)
1403 , m_guruMeditationHandlerType(GuruMeditationHandlerType_Default)
1404 , m_hiDPIOptimizationType(HiDPIOptimizationType_None)
1405 , m_requestedVisualStateType(UIVisualStateType_Invalid)
1406#ifdef Q_WS_WIN
1407 , m_alphaCursor(0)
1408#endif /* Q_WS_WIN */
1409#ifdef Q_WS_MAC
1410 , m_pWatchdogDisplayChange(0)
1411#endif /* Q_WS_MAC */
1412 , m_defaultCloseAction(MachineCloseAction_Invalid)
1413 , m_restrictedCloseActions(MachineCloseAction_Invalid)
1414 , m_fAllCloseActionsRestricted(false)
1415 /* Common flags: */
1416 , m_fInitialized(false)
1417 , m_fIsFirstTimeStarted(false)
1418 , m_fIsGuestResizeIgnored(false)
1419 , m_fIsAutoCaptureDisabled(false)
1420 /* Guest additions flags: */
1421 , m_ulGuestAdditionsRunLevel(0)
1422 , m_fIsGuestSupportsGraphics(false)
1423 , m_fIsGuestSupportsSeamless(false)
1424 /* Mouse flags: */
1425 , m_fNumLock(false)
1426 , m_fCapsLock(false)
1427 , m_fScrollLock(false)
1428 , m_uNumLockAdaptionCnt(2)
1429 , m_uCapsLockAdaptionCnt(2)
1430 /* Mouse flags: */
1431 , m_fIsMouseSupportsAbsolute(false)
1432 , m_fIsMouseSupportsRelative(false)
1433 , m_fIsMouseSupportsMultiTouch(false)
1434 , m_fIsMouseHostCursorNeeded(false)
1435 , m_fIsMouseCaptured(false)
1436 , m_fIsMouseIntegrated(true)
1437 , m_fIsValidPointerShapePresent(false)
1438 , m_fIsHidingHostPointer(true)
1439{
1440}
1441
1442UISession::~UISession()
1443{
1444}
1445
1446bool UISession::prepare()
1447{
1448 /* Prepare session: */
1449 if (!prepareSession())
1450 return false;
1451
1452 /* Prepare actions: */
1453 prepareActions();
1454
1455 /* Prepare connections: */
1456 prepareConnections();
1457
1458 /* Prepare console event-handlers: */
1459 prepareConsoleEventHandlers();
1460
1461 /* Prepare screens: */
1462 prepareScreens();
1463
1464 /* Prepare framebuffers: */
1465 prepareFramebuffers();
1466
1467 /* Load settings: */
1468 loadSessionSettings();
1469
1470#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
1471 struct sigaction sa;
1472 sa.sa_sigaction = &signalHandlerSIGUSR1;
1473 sigemptyset(&sa.sa_mask);
1474 sa.sa_flags = SA_RESTART | SA_SIGINFO;
1475 sigaction(SIGUSR1, &sa, NULL);
1476#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
1477
1478 /* True by default: */
1479 return true;
1480}
1481
1482bool UISession::prepareSession()
1483{
1484 /* Open session: */
1485 m_session = vboxGlobal().openSession(vboxGlobal().managedVMUuid(),
1486 vboxGlobal().isSeparateProcess()
1487 ? KLockType_Shared : KLockType_VM);
1488 if (m_session.isNull())
1489 return false;
1490
1491 /* Get machine: */
1492 m_machine = m_session.GetMachine();
1493 if (m_machine.isNull())
1494 return false;
1495
1496 /* Get console: */
1497 m_console = m_session.GetConsole();
1498 if (m_console.isNull())
1499 return false;
1500
1501 /* Get display: */
1502 m_display = m_console.GetDisplay();
1503 if (m_display.isNull())
1504 return false;
1505
1506 /* Get guest: */
1507 m_guest = m_console.GetGuest();
1508 if (m_guest.isNull())
1509 return false;
1510
1511 /* Get mouse: */
1512 m_mouse = m_console.GetMouse();
1513 if (m_mouse.isNull())
1514 return false;
1515
1516 /* Get keyboard: */
1517 m_keyboard = m_console.GetKeyboard();
1518 if (m_keyboard.isNull())
1519 return false;
1520
1521 /* Get debugger: */
1522 m_debugger = m_console.GetDebugger();
1523 if (m_debugger.isNull())
1524 return false;
1525
1526 /* Update machine-name: */
1527 m_strMachineName = machine().GetName();
1528
1529 /* Update machine-state: */
1530 m_machineState = machine().GetState();
1531
1532 /* True by default: */
1533 return true;
1534}
1535
1536void UISession::prepareActions()
1537{
1538 /* Create action-pool: */
1539 m_pActionPool = UIActionPool::create(UIActionPoolType_Runtime);
1540 AssertPtrReturnVoid(actionPool());
1541 {
1542 /* Configure action-pool: */
1543 actionPool()->toRuntime()->setSession(this);
1544
1545 /* Get host: */
1546 const CHost host = vboxGlobal().host();
1547 UIExtraDataMetaDefs::RuntimeMenuViewActionType restrictionForView = UIExtraDataMetaDefs::RuntimeMenuViewActionType_Invalid;
1548 UIExtraDataMetaDefs::RuntimeMenuDevicesActionType restrictionForDevices = UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Invalid;
1549
1550 /* VRDE server stuff: */
1551 {
1552 /* Initialize 'View' menu: */
1553 const CVRDEServer server = machine().GetVRDEServer();
1554 if (server.isNull())
1555 restrictionForView = (UIExtraDataMetaDefs::RuntimeMenuViewActionType)(restrictionForView | UIExtraDataMetaDefs::RuntimeMenuViewActionType_VRDEServer);
1556 }
1557
1558 /* Storage stuff: */
1559 {
1560 /* Initialize CD/FD menus: */
1561 int iDevicesCountCD = 0;
1562 int iDevicesCountFD = 0;
1563 foreach (const CMediumAttachment &attachment, machine().GetMediumAttachments())
1564 {
1565 if (attachment.GetType() == KDeviceType_DVD)
1566 ++iDevicesCountCD;
1567 if (attachment.GetType() == KDeviceType_Floppy)
1568 ++iDevicesCountFD;
1569 }
1570 QAction *pOpticalDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices);
1571 QAction *pFloppyDevicesMenu = actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices);
1572 pOpticalDevicesMenu->setData(iDevicesCountCD);
1573 pFloppyDevicesMenu->setData(iDevicesCountFD);
1574 if (!iDevicesCountCD)
1575 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_OpticalDevices);
1576 if (!iDevicesCountFD)
1577 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_FloppyDevices);
1578 }
1579
1580 /* Network stuff: */
1581 {
1582 /* Initialize Network menu: */
1583 bool fAtLeastOneAdapterActive = false;
1584 const KChipsetType chipsetType = machine().GetChipsetType();
1585 ULONG uSlots = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(chipsetType);
1586 for (ULONG uSlot = 0; uSlot < uSlots; ++uSlot)
1587 {
1588 const CNetworkAdapter &adapter = machine().GetNetworkAdapter(uSlot);
1589 if (adapter.GetEnabled())
1590 {
1591 fAtLeastOneAdapterActive = true;
1592 break;
1593 }
1594 }
1595 if (!fAtLeastOneAdapterActive)
1596 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_Network);
1597 }
1598
1599 /* USB stuff: */
1600 {
1601 /* Check whether there is at least one USB controller with an available proxy. */
1602 const bool fUSBEnabled = !machine().GetUSBDeviceFilters().isNull()
1603 && !machine().GetUSBControllers().isEmpty()
1604 && machine().GetUSBProxyAvailable();
1605 if (!fUSBEnabled)
1606 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_USBDevices);
1607 }
1608
1609 /* WebCams stuff: */
1610 {
1611 /* Check whether there is an accessible video input devices pool: */
1612 host.GetVideoInputDevices();
1613 const bool fWebCamsEnabled = host.isOk() && !machine().GetUSBControllers().isEmpty();
1614 if (!fWebCamsEnabled)
1615 restrictionForDevices = (UIExtraDataMetaDefs::RuntimeMenuDevicesActionType)(restrictionForDevices | UIExtraDataMetaDefs::RuntimeMenuDevicesActionType_WebCams);
1616 }
1617
1618 /* Apply cumulative restriction for 'View' menu: */
1619 actionPool()->toRuntime()->setRestrictionForMenuView(UIActionRestrictionLevel_Session, restrictionForView);
1620 /* Apply cumulative restriction for 'Devices' menu: */
1621 actionPool()->toRuntime()->setRestrictionForMenuDevices(UIActionRestrictionLevel_Session, restrictionForDevices);
1622
1623#ifdef Q_WS_MAC
1624 /* Create Mac OS X menu-bar: */
1625 m_pMenuBar = new UIMenuBar;
1626 AssertPtrReturnVoid(m_pMenuBar);
1627 {
1628 /* Configure Mac OS X menu-bar: */
1629 connect(gEDataManager, SIGNAL(sigMenuBarConfigurationChange(const QString&)),
1630 this, SLOT(sltHandleMenuBarConfigurationChange(const QString&)));
1631 /* Update Mac OS X menu-bar: */
1632 updateMenu();
1633 }
1634#endif /* Q_WS_MAC */
1635 }
1636}
1637
1638void UISession::prepareConnections()
1639{
1640 connect(this, SIGNAL(sigInitialized()), this, SLOT(sltMarkInitialized()));
1641 connect(this, SIGNAL(sigCloseRuntimeUI()), this, SLOT(sltCloseRuntimeUI()));
1642
1643#ifdef Q_WS_MAC
1644 /* Install native display reconfiguration callback: */
1645 CGDisplayRegisterReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1646#else /* !Q_WS_MAC */
1647 /* Install Qt display reconfiguration callbacks: */
1648 connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)),
1649 this, SLOT(sltHandleHostScreenCountChange()));
1650 connect(QApplication::desktop(), SIGNAL(resized(int)),
1651 this, SLOT(sltHandleHostScreenGeometryChange()));
1652 connect(QApplication::desktop(), SIGNAL(workAreaResized(int)),
1653 this, SLOT(sltHandleHostScreenAvailableAreaChange()));
1654#endif /* !Q_WS_MAC */
1655}
1656
1657void UISession::prepareConsoleEventHandlers()
1658{
1659 /* Create console event-handler: */
1660 UIConsoleEventHandler::create(this);
1661
1662 /* Add console event connections: */
1663 connect(gConsoleEvents, SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
1664 this, SLOT(sltMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)));
1665
1666 connect(gConsoleEvents, SIGNAL(sigMouseCapabilityChange(bool, bool, bool, bool)),
1667 this, SLOT(sltMouseCapabilityChange(bool, bool, bool, bool)));
1668
1669 connect(gConsoleEvents, SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
1670 this, SLOT(sltKeyboardLedsChangeEvent(bool, bool, bool)));
1671
1672 connect(gConsoleEvents, SIGNAL(sigStateChange(KMachineState)),
1673 this, SLOT(sltStateChange(KMachineState)));
1674
1675 connect(gConsoleEvents, SIGNAL(sigAdditionsChange()),
1676 this, SLOT(sltAdditionsChange()));
1677
1678 connect(gConsoleEvents, SIGNAL(sigVRDEChange()),
1679 this, SLOT(sltVRDEChange()));
1680
1681 connect(gConsoleEvents, SIGNAL(sigVideoCaptureChange()),
1682 this, SLOT(sltVideoCaptureChange()));
1683
1684 connect(gConsoleEvents, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
1685 this, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)));
1686
1687 connect(gConsoleEvents, SIGNAL(sigMediumChange(CMediumAttachment)),
1688 this, SIGNAL(sigMediumChange(CMediumAttachment)));
1689
1690 connect(gConsoleEvents, SIGNAL(sigUSBControllerChange()),
1691 this, SIGNAL(sigUSBControllerChange()));
1692
1693 connect(gConsoleEvents, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
1694 this, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)));
1695
1696 connect(gConsoleEvents, SIGNAL(sigSharedFolderChange()),
1697 this, SIGNAL(sigSharedFolderChange()));
1698
1699 connect(gConsoleEvents, SIGNAL(sigRuntimeError(bool, QString, QString)),
1700 this, SIGNAL(sigRuntimeError(bool, QString, QString)));
1701
1702#ifdef Q_WS_MAC
1703 connect(gConsoleEvents, SIGNAL(sigShowWindow()),
1704 this, SIGNAL(sigShowWindows()), Qt::QueuedConnection);
1705#endif /* Q_WS_MAC */
1706
1707 connect(gConsoleEvents, SIGNAL(sigCPUExecutionCapChange()),
1708 this, SIGNAL(sigCPUExecutionCapChange()));
1709
1710 connect(gConsoleEvents, SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
1711 this, SLOT(sltGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)));
1712}
1713
1714void UISession::prepareScreens()
1715{
1716 /* Recache display data: */
1717 updateHostScreenData();
1718
1719#ifdef Q_WS_MAC
1720 /* Prepare display-change watchdog: */
1721 m_pWatchdogDisplayChange = new QTimer(this);
1722 {
1723 m_pWatchdogDisplayChange->setInterval(500);
1724 m_pWatchdogDisplayChange->setSingleShot(true);
1725 connect(m_pWatchdogDisplayChange, SIGNAL(timeout()),
1726 this, SLOT(sltCheckIfHostDisplayChanged()));
1727 }
1728#endif /* Q_WS_MAC */
1729
1730 /* Prepare initial screen visibility status: */
1731 m_monitorVisibilityVector.resize(machine().GetMonitorCount());
1732 m_monitorVisibilityVector.fill(false);
1733 m_monitorVisibilityVector[0] = true;
1734
1735 /* If machine is in 'saved' state: */
1736 if (isSaved())
1737 {
1738 /* Update screen visibility status from saved-state: */
1739 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1740 {
1741 BOOL fEnabled = true;
1742 ULONG uGuestOriginX = 0, uGuestOriginY = 0, uGuestWidth = 0, uGuestHeight = 0;
1743 machine().QuerySavedGuestScreenInfo(iScreenIndex,
1744 uGuestOriginX, uGuestOriginY,
1745 uGuestWidth, uGuestHeight, fEnabled);
1746 m_monitorVisibilityVector[iScreenIndex] = fEnabled;
1747 }
1748 /* And make sure at least one of them is visible (primary if others are hidden): */
1749 if (countOfVisibleWindows() < 1)
1750 m_monitorVisibilityVector[0] = true;
1751 }
1752 else if (vboxGlobal().isSeparateProcess())
1753 {
1754 /* Update screen visibility status from display directly: */
1755 for (int iScreenIndex = 0; iScreenIndex < m_monitorVisibilityVector.size(); ++iScreenIndex)
1756 {
1757 KGuestMonitorStatus enmStatus = KGuestMonitorStatus_Disabled;
1758 ULONG uGuestWidth = 0, uGuestHeight = 0, uBpp = 0;
1759 LONG iGuestOriginX = 0, iGuestOriginY = 0;
1760 display().GetScreenResolution(iScreenIndex,
1761 uGuestWidth, uGuestHeight, uBpp,
1762 iGuestOriginX, iGuestOriginY, enmStatus);
1763 m_monitorVisibilityVector[iScreenIndex] = (enmStatus == KGuestMonitorStatus_Enabled);
1764 }
1765 /* And make sure at least one of them is visible (primary if others are hidden): */
1766 if (countOfVisibleWindows() < 1)
1767 m_monitorVisibilityVector[0] = true;
1768 }
1769}
1770
1771void UISession::prepareFramebuffers()
1772{
1773 /* Each framebuffer will be really prepared on first UIMachineView creation: */
1774 m_frameBufferVector.resize(machine().GetMonitorCount());
1775}
1776
1777void UISession::loadSessionSettings()
1778{
1779 /* Load extra-data settings: */
1780 {
1781 /* Get machine ID: */
1782 const QString strMachineID = vboxGlobal().managedVMUuid();
1783
1784#ifndef Q_WS_MAC
1785 /* Load/prepare user's machine-window icon: */
1786 QIcon icon;
1787 foreach (const QString &strIconName, gEDataManager->machineWindowIconNames(strMachineID))
1788 if (!strIconName.isEmpty())
1789 icon.addFile(strIconName);
1790 if (!icon.isNull())
1791 m_pMachineWindowIcon = new QIcon(icon);
1792
1793 /* Load user's machine-window name postfix: */
1794 m_strMachineWindowNamePostfix = gEDataManager->machineWindowNamePostfix(strMachineID);
1795#endif /* !Q_WS_MAC */
1796
1797 /* Determine mouse-capture policy: */
1798 m_mouseCapturePolicy = gEDataManager->mouseCapturePolicy(strMachineID);
1799
1800 /* Determine Guru Meditation handler type: */
1801 m_guruMeditationHandlerType = gEDataManager->guruMeditationHandlerType(strMachineID);
1802
1803 /* Determine HiDPI optimization type: */
1804 m_hiDPIOptimizationType = gEDataManager->hiDPIOptimizationType(strMachineID);
1805
1806 /* Is there should be First RUN Wizard? */
1807 m_fIsFirstTimeStarted = gEDataManager->machineFirstTimeStarted(strMachineID);
1808
1809 /* Should guest autoresize? */
1810 QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1811 pGuestAutoresizeSwitch->setChecked(gEDataManager->guestScreenAutoResizeEnabled(strMachineID));
1812
1813#ifndef Q_WS_MAC
1814 /* Menu-bar options: */
1815 {
1816 const bool fEnabledGlobally = !vboxGlobal().settings().isFeatureActive("noMenuBar");
1817 const bool fEnabledForMachine = gEDataManager->menuBarEnabled(strMachineID);
1818 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1819 QAction *pActionMenuBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_S_Settings);
1820 pActionMenuBarSettings->setEnabled(fEnabled);
1821 QAction *pActionMenuBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_T_Visibility);
1822 pActionMenuBarSwitch->blockSignals(true);
1823 pActionMenuBarSwitch->setChecked(fEnabled);
1824 pActionMenuBarSwitch->blockSignals(false);
1825 }
1826#endif /* !Q_WS_MAC */
1827
1828 /* Status-bar options: */
1829 {
1830 const bool fEnabledGlobally = !vboxGlobal().settings().isFeatureActive("noStatusBar");
1831 const bool fEnabledForMachine = gEDataManager->statusBarEnabled(strMachineID);
1832 const bool fEnabled = fEnabledGlobally && fEnabledForMachine;
1833 QAction *pActionStatusBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_S_Settings);
1834 pActionStatusBarSettings->setEnabled(fEnabled);
1835 QAction *pActionStatusBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility);
1836 pActionStatusBarSwitch->blockSignals(true);
1837 pActionStatusBarSwitch->setChecked(fEnabled);
1838 pActionStatusBarSwitch->blockSignals(false);
1839 }
1840
1841 /* Input options: */
1842 actionPool()->action(UIActionIndexRT_M_Input_M_Mouse_T_Integration)->setChecked(isMouseIntegrated());
1843
1844 /* What is the default close action and the restricted are? */
1845 m_defaultCloseAction = gEDataManager->defaultMachineCloseAction(strMachineID);
1846 m_restrictedCloseActions = gEDataManager->restrictedMachineCloseActions(strMachineID);
1847 m_fAllCloseActionsRestricted = (!vboxGlobal().isSeparateProcess() || (m_restrictedCloseActions & MachineCloseAction_Detach))
1848 && (m_restrictedCloseActions & MachineCloseAction_SaveState)
1849 && (m_restrictedCloseActions & MachineCloseAction_Shutdown)
1850 && (m_restrictedCloseActions & MachineCloseAction_PowerOff);
1851 // Close VM Dialog hides PowerOff_RestoringSnapshot implicitly if PowerOff is hidden..
1852 // && (m_restrictedCloseActions & MachineCloseAction_PowerOff_RestoringSnapshot);
1853 }
1854}
1855
1856void UISession::saveSessionSettings()
1857{
1858 /* Save extra-data settings: */
1859 {
1860 /* Disable First RUN Wizard: */
1861 gEDataManager->setMachineFirstTimeStarted(false, vboxGlobal().managedVMUuid());
1862
1863 /* Remember if guest should autoresize: */
1864 if (actionPool())
1865 {
1866 const QAction *pGuestAutoresizeSwitch = actionPool()->action(UIActionIndexRT_M_View_T_GuestAutoresize);
1867 gEDataManager->setGuestScreenAutoResizeEnabled(pGuestAutoresizeSwitch->isChecked(), vboxGlobal().managedVMUuid());
1868 }
1869
1870#ifndef Q_WS_MAC
1871 /* Cleanup user's machine-window icon: */
1872 delete m_pMachineWindowIcon;
1873 m_pMachineWindowIcon = 0;
1874#endif /* !Q_WS_MAC */
1875 }
1876}
1877
1878void UISession::cleanupFramebuffers()
1879{
1880 /* Cleanup framebuffers finally: */
1881 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
1882 {
1883 UIFrameBuffer *pFrameBuffer = m_frameBufferVector[i];
1884 if (pFrameBuffer)
1885 {
1886 /* Mark framebuffer as unused: */
1887 pFrameBuffer->setMarkAsUnused(true);
1888 /* Detach framebuffer from Display: */
1889 pFrameBuffer->detach();
1890 /* Delete framebuffer reference: */
1891 delete pFrameBuffer;
1892 }
1893 }
1894 m_frameBufferVector.clear();
1895}
1896
1897void UISession::cleanupConsoleEventHandlers()
1898{
1899 /* Destroy console event-handler if necessary: */
1900 if (gConsoleEvents)
1901 UIConsoleEventHandler::destroy();
1902}
1903
1904void UISession::cleanupConnections()
1905{
1906#ifdef Q_WS_MAC
1907 /* Remove display reconfiguration callback: */
1908 CGDisplayRemoveReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1909#endif /* Q_WS_MAC */
1910}
1911
1912void UISession::cleanupActions()
1913{
1914#ifdef Q_WS_MAC
1915 /* Destroy Mac OS X menu-bar: */
1916 delete m_pMenuBar;
1917 m_pMenuBar = 0;
1918#endif /* Q_WS_MAC */
1919
1920 /* Destroy action-pool if necessary: */
1921 if (actionPool())
1922 UIActionPool::destroy(actionPool());
1923}
1924
1925void UISession::cleanupSession()
1926{
1927 /* Detach debugger: */
1928 if (!m_debugger.isNull())
1929 m_debugger.detach();
1930
1931 /* Detach keyboard: */
1932 if (!m_keyboard.isNull())
1933 m_keyboard.detach();
1934
1935 /* Detach mouse: */
1936 if (!m_mouse.isNull())
1937 m_mouse.detach();
1938
1939 /* Detach guest: */
1940 if (!m_guest.isNull())
1941 m_guest.detach();
1942
1943 /* Detach display: */
1944 if (!m_display.isNull())
1945 m_display.detach();
1946
1947 /* Detach console: */
1948 if (!m_console.isNull())
1949 m_console.detach();
1950
1951 /* Detach machine: */
1952 if (!m_machine.isNull())
1953 m_machine.detach();
1954
1955 /* Close session: */
1956 if (!m_session.isNull() && vboxGlobal().isVBoxSVCAvailable())
1957 {
1958 m_session.UnlockMachine();
1959 m_session.detach();
1960 }
1961}
1962
1963void UISession::cleanup()
1964{
1965#ifdef Q_WS_WIN
1966 /* Destroy alpha cursor: */
1967 if (m_alphaCursor)
1968 DestroyIcon(m_alphaCursor);
1969#endif /* Q_WS_WIN */
1970
1971 /* Save settings: */
1972 saveSessionSettings();
1973
1974 /* Cleanup framebuffers: */
1975 cleanupFramebuffers();
1976
1977 /* Cleanup console event-handlers: */
1978 cleanupConsoleEventHandlers();
1979
1980 /* Cleanup connections: */
1981 cleanupConnections();
1982
1983 /* Cleanup actions: */
1984 cleanupActions();
1985
1986 /* Cleanup session: */
1987 cleanupSession();
1988}
1989
1990#ifdef Q_WS_MAC
1991void UISession::updateMenu()
1992{
1993 /* Rebuild Mac OS X menu-bar: */
1994 m_pMenuBar->clear();
1995 foreach (QMenu *pMenu, actionPool()->menus())
1996 {
1997 UIMenu *pMenuUI = qobject_cast<UIMenu*>(pMenu);
1998 if (!pMenuUI->isConsumable() || !pMenuUI->isConsumed())
1999 m_pMenuBar->addMenu(pMenuUI);
2000 if (pMenuUI->isConsumable() && !pMenuUI->isConsumed())
2001 pMenuUI->setConsumed(true);
2002 }
2003}
2004#endif /* Q_WS_MAC */
2005
2006WId UISession::winId() const
2007{
2008 return mainMachineWindow()->winId();
2009}
2010
2011void UISession::setPointerShape(const uchar *pShapeData, bool fHasAlpha,
2012 uint uXHot, uint uYHot, uint uWidth, uint uHeight)
2013{
2014 AssertMsg(pShapeData, ("Shape data must not be NULL!\n"));
2015
2016 m_fIsValidPointerShapePresent = false;
2017 const uchar *srcAndMaskPtr = pShapeData;
2018 uint andMaskSize = (uWidth + 7) / 8 * uHeight;
2019 const uchar *srcShapePtr = pShapeData + ((andMaskSize + 3) & ~3);
2020 uint srcShapePtrScan = uWidth * 4;
2021
2022#if defined (Q_WS_WIN)
2023
2024 BITMAPV5HEADER bi;
2025 HBITMAP hBitmap;
2026 void *lpBits;
2027
2028 ::ZeroMemory(&bi, sizeof (BITMAPV5HEADER));
2029 bi.bV5Size = sizeof(BITMAPV5HEADER);
2030 bi.bV5Width = uWidth;
2031 bi.bV5Height = - (LONG)uHeight;
2032 bi.bV5Planes = 1;
2033 bi.bV5BitCount = 32;
2034 bi.bV5Compression = BI_BITFIELDS;
2035 bi.bV5RedMask = 0x00FF0000;
2036 bi.bV5GreenMask = 0x0000FF00;
2037 bi.bV5BlueMask = 0x000000FF;
2038 if (fHasAlpha)
2039 bi.bV5AlphaMask = 0xFF000000;
2040 else
2041 bi.bV5AlphaMask = 0;
2042
2043 HDC hdc = GetDC(NULL);
2044
2045 /* Create the DIB section with an alpha channel: */
2046 hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD) 0);
2047
2048 ReleaseDC(NULL, hdc);
2049
2050 HBITMAP hMonoBitmap = NULL;
2051 if (fHasAlpha)
2052 {
2053 /* Create an empty mask bitmap: */
2054 hMonoBitmap = CreateBitmap(uWidth, uHeight, 1, 1, NULL);
2055 }
2056 else
2057 {
2058 /* Word aligned AND mask. Will be allocated and created if necessary. */
2059 uint8_t *pu8AndMaskWordAligned = NULL;
2060
2061 /* Width in bytes of the original AND mask scan line. */
2062 uint32_t cbAndMaskScan = (uWidth + 7) / 8;
2063
2064 if (cbAndMaskScan & 1)
2065 {
2066 /* Original AND mask is not word aligned. */
2067
2068 /* Allocate memory for aligned AND mask. */
2069 pu8AndMaskWordAligned = (uint8_t *)RTMemTmpAllocZ((cbAndMaskScan + 1) * uHeight);
2070
2071 Assert(pu8AndMaskWordAligned);
2072
2073 if (pu8AndMaskWordAligned)
2074 {
2075 /* According to MSDN the padding bits must be 0.
2076 * Compute the bit mask to set padding bits to 0 in the last byte of original AND mask. */
2077 uint32_t u32PaddingBits = cbAndMaskScan * 8 - uWidth;
2078 Assert(u32PaddingBits < 8);
2079 uint8_t u8LastBytesPaddingMask = (uint8_t)(0xFF << u32PaddingBits);
2080
2081 Log(("u8LastBytesPaddingMask = %02X, aligned w = %d, width = %d, cbAndMaskScan = %d\n",
2082 u8LastBytesPaddingMask, (cbAndMaskScan + 1) * 8, uWidth, cbAndMaskScan));
2083
2084 uint8_t *src = (uint8_t *)srcAndMaskPtr;
2085 uint8_t *dst = pu8AndMaskWordAligned;
2086
2087 unsigned i;
2088 for (i = 0; i < uHeight; i++)
2089 {
2090 memcpy(dst, src, cbAndMaskScan);
2091
2092 dst[cbAndMaskScan - 1] &= u8LastBytesPaddingMask;
2093
2094 src += cbAndMaskScan;
2095 dst += cbAndMaskScan + 1;
2096 }
2097 }
2098 }
2099
2100 /* Create the AND mask bitmap: */
2101 hMonoBitmap = ::CreateBitmap(uWidth, uHeight, 1, 1,
2102 pu8AndMaskWordAligned? pu8AndMaskWordAligned: srcAndMaskPtr);
2103
2104 if (pu8AndMaskWordAligned)
2105 {
2106 RTMemTmpFree(pu8AndMaskWordAligned);
2107 }
2108 }
2109
2110 Assert(hBitmap);
2111 Assert(hMonoBitmap);
2112 if (hBitmap && hMonoBitmap)
2113 {
2114 DWORD *dstShapePtr = (DWORD *) lpBits;
2115
2116 for (uint y = 0; y < uHeight; y ++)
2117 {
2118 memcpy(dstShapePtr, srcShapePtr, srcShapePtrScan);
2119 srcShapePtr += srcShapePtrScan;
2120 dstShapePtr += uWidth;
2121 }
2122
2123 ICONINFO ii;
2124 ii.fIcon = FALSE;
2125 ii.xHotspot = uXHot;
2126 ii.yHotspot = uYHot;
2127 ii.hbmMask = hMonoBitmap;
2128 ii.hbmColor = hBitmap;
2129
2130 HCURSOR hAlphaCursor = CreateIconIndirect(&ii);
2131 Assert(hAlphaCursor);
2132 if (hAlphaCursor)
2133 {
2134 /* Set the new cursor: */
2135 m_cursor = QCursor(hAlphaCursor);
2136 if (m_alphaCursor)
2137 DestroyIcon(m_alphaCursor);
2138 m_alphaCursor = hAlphaCursor;
2139 m_fIsValidPointerShapePresent = true;
2140 }
2141 }
2142
2143 if (hMonoBitmap)
2144 DeleteObject(hMonoBitmap);
2145 if (hBitmap)
2146 DeleteObject(hBitmap);
2147
2148#elif defined (Q_WS_X11) && !defined (VBOX_WITHOUT_XCURSOR)
2149
2150 XcursorImage *img = XcursorImageCreate(uWidth, uHeight);
2151 Assert(img);
2152 if (img)
2153 {
2154 img->xhot = uXHot;
2155 img->yhot = uYHot;
2156
2157 XcursorPixel *dstShapePtr = img->pixels;
2158
2159 for (uint y = 0; y < uHeight; y ++)
2160 {
2161 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan);
2162
2163 if (!fHasAlpha)
2164 {
2165 /* Convert AND mask to the alpha channel: */
2166 uchar byte = 0;
2167 for (uint x = 0; x < uWidth; x ++)
2168 {
2169 if (!(x % 8))
2170 byte = *(srcAndMaskPtr ++);
2171 else
2172 byte <<= 1;
2173
2174 if (byte & 0x80)
2175 {
2176 /* Linux doesn't support inverted pixels (XOR ops,
2177 * to be exact) in cursor shapes, so we detect such
2178 * pixels and always replace them with black ones to
2179 * make them visible at least over light colors */
2180 if (dstShapePtr [x] & 0x00FFFFFF)
2181 dstShapePtr [x] = 0xFF000000;
2182 else
2183 dstShapePtr [x] = 0x00000000;
2184 }
2185 else
2186 dstShapePtr [x] |= 0xFF000000;
2187 }
2188 }
2189
2190 srcShapePtr += srcShapePtrScan;
2191 dstShapePtr += uWidth;
2192 }
2193
2194 /* Set the new cursor: */
2195 m_cursor = QCursor(XcursorImageLoadCursor(QX11Info::display(), img));
2196 m_fIsValidPointerShapePresent = true;
2197
2198 XcursorImageDestroy(img);
2199 }
2200
2201#elif defined(Q_WS_MAC)
2202
2203 /* Create a ARGB image out of the shape data. */
2204 QImage image (uWidth, uHeight, QImage::Format_ARGB32);
2205 const uint8_t* pbSrcMask = static_cast<const uint8_t*> (srcAndMaskPtr);
2206 unsigned cbSrcMaskLine = RT_ALIGN (uWidth, 8) / 8;
2207 for (unsigned int y = 0; y < uHeight; ++y)
2208 {
2209 for (unsigned int x = 0; x < uWidth; ++x)
2210 {
2211 unsigned int color = ((unsigned int*)srcShapePtr)[y*uWidth+x];
2212 /* If the alpha channel isn't in the shape data, we have to
2213 * create them from the and-mask. This is a bit field where 1
2214 * represent transparency & 0 opaque respectively. */
2215 if (!fHasAlpha)
2216 {
2217 if (!(pbSrcMask[x / 8] & (1 << (7 - (x % 8)))))
2218 color |= 0xff000000;
2219 else
2220 {
2221 /* This isn't quite right, but it's the best we can do I think... */
2222 if (color & 0x00ffffff)
2223 color = 0xff000000;
2224 else
2225 color = 0x00000000;
2226 }
2227 }
2228 image.setPixel (x, y, color);
2229 }
2230 /* Move one scanline forward. */
2231 pbSrcMask += cbSrcMaskLine;
2232 }
2233
2234 /* Set the new cursor: */
2235 m_cursor = QCursor(QPixmap::fromImage(image), uXHot, uYHot);
2236 m_fIsValidPointerShapePresent = true;
2237 NOREF(srcShapePtrScan);
2238
2239#else
2240
2241# warning "port me"
2242
2243#endif
2244}
2245
2246bool UISession::preprocessInitialization()
2247{
2248#ifdef VBOX_WITH_NETFLT
2249 /* Skip further checks if VM in saved state */
2250 if (isSaved())
2251 return true;
2252
2253 /* Make sure all the attached and enabled network
2254 * adapters are present on the host. This check makes sense
2255 * in two cases only - when attachement type is Bridged Network
2256 * or Host-only Interface. NOTE: Only currently enabled
2257 * attachement type is checked (incorrect parameters check for
2258 * currently disabled attachement types is skipped). */
2259 QStringList failedInterfaceNames;
2260 QStringList availableInterfaceNames;
2261
2262 /* Create host network interface names list */
2263 foreach (const CHostNetworkInterface &iface, vboxGlobal().host().GetNetworkInterfaces())
2264 {
2265 availableInterfaceNames << iface.GetName();
2266 availableInterfaceNames << iface.GetShortName();
2267 }
2268
2269 ulong cCount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine().GetChipsetType());
2270 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
2271 {
2272 CNetworkAdapter na = machine().GetNetworkAdapter(uAdapterIndex);
2273
2274 if (na.GetEnabled())
2275 {
2276 QString strIfName = QString();
2277
2278 /* Get physical network interface name for currently
2279 * enabled network attachement type */
2280 switch (na.GetAttachmentType())
2281 {
2282 case KNetworkAttachmentType_Bridged:
2283 strIfName = na.GetBridgedInterface();
2284 break;
2285 case KNetworkAttachmentType_HostOnly:
2286 strIfName = na.GetHostOnlyInterface();
2287 break;
2288 }
2289
2290 if (!strIfName.isEmpty() &&
2291 !availableInterfaceNames.contains(strIfName))
2292 {
2293 LogFlow(("Found invalid network interface: %s\n", strIfName.toStdString().c_str()));
2294 failedInterfaceNames << QString("%1 (adapter %2)").arg(strIfName).arg(uAdapterIndex + 1);
2295 }
2296 }
2297 }
2298
2299 /* Check if non-existent interfaces found */
2300 if (!failedInterfaceNames.isEmpty())
2301 {
2302 if (msgCenter().cannotStartWithoutNetworkIf(machineName(), failedInterfaceNames.join(", ")))
2303 machineLogic()->openNetworkSettingsDialog();
2304 else
2305 return false;
2306 }
2307#endif /* VBOX_WITH_NETFLT */
2308
2309 /* True by default: */
2310 return true;
2311}
2312
2313bool UISession::postprocessInitialization()
2314{
2315 /* Check if the required virtualization features are active. We get this info only when the session is active. */
2316 const bool fIs64BitsGuest = vboxGlobal().virtualBox().GetGuestOSType(guest().GetOSTypeId()).GetIs64Bit();
2317 const bool fRecommendVirtEx = vboxGlobal().virtualBox().GetGuestOSType(guest().GetOSTypeId()).GetRecommendedVirtEx();
2318 AssertMsg(!fIs64BitsGuest || fRecommendVirtEx, ("Virtualization support missed for 64bit guest!\n"));
2319 const bool fIsVirtActive = debugger().GetHWVirtExEnabled();
2320 if (fRecommendVirtEx && !fIsVirtActive)
2321 {
2322 /* Check whether vt-x / amd-v supported: */
2323 bool fVTxAMDVSupported = vboxGlobal().host().GetProcessorFeature(KProcessorFeature_HWVirtEx);
2324
2325 /* Pause VM: */
2326 setPause(true);
2327
2328 /* Ask the user about further actions: */
2329 bool fShouldWeClose;
2330 if (fIs64BitsGuest)
2331 fShouldWeClose = msgCenter().warnAboutVirtExInactiveFor64BitsGuest(fVTxAMDVSupported);
2332 else
2333 fShouldWeClose = msgCenter().warnAboutVirtExInactiveForRecommendedGuest(fVTxAMDVSupported);
2334
2335 /* If user asked to close VM: */
2336 if (fShouldWeClose)
2337 {
2338 /* Prevent auto-closure during power off sequence: */
2339 machineLogic()->setPreventAutoClose(true);
2340 /* Power off VM: */
2341 bool fServerCrashed = false;
2342 powerOff(false, fServerCrashed);
2343 return false;
2344 }
2345
2346 /* Resume VM: */
2347 setPause(false);
2348 }
2349
2350 /* True by default: */
2351 return true;
2352}
2353
2354bool UISession::isScreenVisible(ulong uScreenId) const
2355{
2356 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
2357 return m_monitorVisibilityVector.value((int)uScreenId, false);
2358}
2359
2360void UISession::setScreenVisible(ulong uScreenId, bool fIsMonitorVisible)
2361{
2362 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
2363 if (uScreenId < (ulong)m_monitorVisibilityVector.size())
2364 m_monitorVisibilityVector[(int)uScreenId] = fIsMonitorVisible;
2365}
2366
2367int UISession::countOfVisibleWindows()
2368{
2369 int cCountOfVisibleWindows = 0;
2370 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
2371 if (m_monitorVisibilityVector[i])
2372 ++cCountOfVisibleWindows;
2373 return cCountOfVisibleWindows;
2374}
2375
2376UIFrameBuffer* UISession::frameBuffer(ulong uScreenId) const
2377{
2378 Assert(uScreenId < (ulong)m_frameBufferVector.size());
2379 return m_frameBufferVector.value((int)uScreenId, 0);
2380}
2381
2382void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer* pFrameBuffer)
2383{
2384 Assert(uScreenId < (ulong)m_frameBufferVector.size());
2385 if (uScreenId < (ulong)m_frameBufferVector.size())
2386 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
2387}
2388
2389void UISession::updateHostScreenData()
2390{
2391 m_hostScreens.clear();
2392 QDesktopWidget *pDesktop = QApplication::desktop();
2393 for (int iScreenIndex = 0; iScreenIndex < pDesktop->screenCount(); ++iScreenIndex)
2394 m_hostScreens << pDesktop->screenGeometry(iScreenIndex);
2395}
2396
2397#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
2398/**
2399 * Custom signal handler. When switching VTs, we might not get release events
2400 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
2401 * be saved with modifier keys stuck. This is annoying enough for introducing
2402 * this hack.
2403 */
2404/* static */
2405static void signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
2406{
2407 /* only SIGUSR1 is interesting */
2408 if (sig == SIGUSR1)
2409 if (UIMachine *pMachine = vboxGlobal().virtualMachine())
2410 pMachine->uisession()->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
2411}
2412#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
2413
2414#include "UISession.moc"
2415
Note: See TracBrowser for help on using the repository browser.

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