VirtualBox

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

Last change on this file since 49505 was 49505, checked in by vboxsync, 11 years ago

FE/Qt: Runtime UI: UIVisualState framework cleanup: Moving most of unrelated stuff into corresponding places.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.4 KB
Line 
1/* $Id: UISession.cpp 49505 2013-11-15 14:01:16Z 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/* Qt includes: */
19#include <QApplication>
20#include <QDesktopWidget>
21#include <QWidget>
22#ifdef Q_WS_MAC
23# include <QTimer>
24#endif /* Q_WS_MAC */
25
26/* GUI includes: */
27#include "VBoxGlobal.h"
28#include "UISession.h"
29#include "UIMachine.h"
30#include "UIMedium.h"
31#include "UIActionPoolRuntime.h"
32#include "UIMachineLogic.h"
33#include "UIMachineView.h"
34#include "UIMachineWindow.h"
35#include "UIMachineMenuBar.h"
36#include "UIMessageCenter.h"
37#include "UIPopupCenter.h"
38#include "UIWizardFirstRun.h"
39#include "UIConsoleEventHandler.h"
40#include "UIFrameBuffer.h"
41#ifdef VBOX_WITH_VIDEOHWACCEL
42# include "VBoxFBOverlay.h"
43#endif /* VBOX_WITH_VIDEOHWACCEL */
44#ifdef Q_WS_MAC
45# include "VBoxUtils-darwin.h"
46#endif /* Q_WS_MAC */
47
48#ifdef Q_WS_X11
49# include <QX11Info>
50# include <X11/Xlib.h>
51# include <X11/Xutil.h>
52# ifndef VBOX_WITHOUT_XCURSOR
53# include <X11/Xcursor/Xcursor.h>
54# endif /* VBOX_WITHOUT_XCURSOR */
55#endif /* Q_WS_X11 */
56
57#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
58# include "UIKeyboardHandler.h"
59# include <signal.h>
60#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
61
62/* COM includes: */
63#include "CConsole.h"
64#include "CSystemProperties.h"
65#include "CMachineDebugger.h"
66#include "CGuest.h"
67#include "CStorageController.h"
68#include "CMediumAttachment.h"
69#include "CDisplay.h"
70#include "CFramebuffer.h"
71#include "CNetworkAdapter.h"
72#include "CHostNetworkInterface.h"
73#include "CVRDEServer.h"
74#include "CUSBController.h"
75#include "CUSBDeviceFilters.h"
76#include "CHostVideoInputDevice.h"
77#include "CSnapshot.h"
78#include "CMedium.h"
79
80#ifdef Q_WS_MAC
81/**
82 * MacOS X: Application Services: Core Graphics: Display reconfiguration callback.
83 *
84 * Notifies UISession about @a display configuration change.
85 * Corresponding change described by Core Graphics @a flags.
86 * Uses UISession @a pHandler to process this change.
87 *
88 * @note Last argument (@a pHandler) must always be valid pointer to UISession object.
89 * @note Calls for UISession::sltHandleHostDisplayAboutToChange() slot if display configuration changed.
90 */
91void cgDisplayReconfigurationCallback(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *pHandler)
92{
93 /* Which flags we are handling? */
94 int iHandledFlags = kCGDisplayAddFlag /* display added */
95 | kCGDisplayRemoveFlag /* display removed */
96 | kCGDisplaySetModeFlag /* display mode changed */;
97
98 /* Handle 'display-add' case: */
99 if (flags & kCGDisplayAddFlag)
100 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display added.\n"));
101 /* Handle 'display-remove' case: */
102 else if (flags & kCGDisplayRemoveFlag)
103 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display removed.\n"));
104 /* Handle 'mode-set' case: */
105 else if (flags & kCGDisplaySetModeFlag)
106 LogRelFlow(("UISession::cgDisplayReconfigurationCallback: Display mode changed.\n"));
107
108 /* Ask handler to process our callback: */
109 if (flags & iHandledFlags)
110 QTimer::singleShot(0, static_cast<UISession*>(pHandler),
111 SLOT(sltHandleHostDisplayAboutToChange()));
112
113 Q_UNUSED(display);
114}
115#endif /* Q_WS_MAC */
116
117UISession::UISession(UIMachine *pMachine, CSession &sessionReference)
118 : QObject(pMachine)
119 /* Base variables: */
120 , m_pMachine(pMachine)
121 , m_session(sessionReference)
122 /* Common variables: */
123 , m_pMenuPool(0)
124 , m_machineStatePrevious(KMachineState_Null)
125 , m_machineState(session().GetMachine().GetState())
126#ifdef Q_WS_WIN
127 , m_alphaCursor(0)
128#endif /* Q_WS_WIN */
129#ifdef Q_WS_MAC
130 , m_pWatchdogDisplayChange(0)
131#endif /* Q_WS_MAC */
132 , m_defaultCloseAction(MachineCloseAction_Invalid)
133 , m_restrictedCloseActions(MachineCloseAction_Invalid)
134 , m_fAllCloseActionsRestricted(false)
135 , m_fSnapshotOperationsAllowed(true)
136 /* Common flags: */
137 , m_fIsFirstTimeStarted(false)
138 , m_fIsIgnoreRuntimeMediumsChanging(false)
139 , m_fIsGuestResizeIgnored(false)
140 , m_fIsSeamlessModeRequested(false)
141 , m_fIsAutoCaptureDisabled(false)
142 , m_fReconfigurable(false)
143 /* Guest additions flags: */
144 , m_ulGuestAdditionsRunLevel(0)
145 , m_fIsGuestSupportsGraphics(false)
146 , m_fIsGuestSupportsSeamless(false)
147 /* Mouse flags: */
148 , m_fNumLock(false)
149 , m_fCapsLock(false)
150 , m_fScrollLock(false)
151 , m_uNumLockAdaptionCnt(2)
152 , m_uCapsLockAdaptionCnt(2)
153 /* Mouse flags: */
154 , m_fIsMouseSupportsAbsolute(false)
155 , m_fIsMouseSupportsRelative(false)
156 , m_fIsMouseSupportsMultiTouch(false)
157 , m_fIsMouseHostCursorNeeded(false)
158 , m_fIsMouseCaptured(false)
159 , m_fIsMouseIntegrated(true)
160 , m_fIsValidPointerShapePresent(false)
161 , m_fIsHidingHostPointer(true)
162{
163 /* Prepare connections: */
164 prepareConnections();
165
166 /* Prepare console event-handlers: */
167 prepareConsoleEventHandlers();
168
169 /* Prepare screens: */
170 prepareScreens();
171
172 /* Prepare framebuffers: */
173 prepareFramebuffers();
174
175 /* Prepare main-menu: */
176 prepareMenuPool();
177
178 /* Load settings: */
179 loadSessionSettings();
180
181#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
182 struct sigaction sa;
183 sa.sa_sigaction = &signalHandlerSIGUSR1;
184 sigemptyset(&sa.sa_mask);
185 sa.sa_flags = SA_RESTART | SA_SIGINFO;
186 sigaction(SIGUSR1, &sa, NULL);
187#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
188}
189
190UISession::~UISession()
191{
192 /* Save settings: */
193 saveSessionSettings();
194
195 /* Cleanup main-menu: */
196 cleanupMenuPool();
197
198 /* Cleanup framebuffers: */
199 cleanupFramebuffers();
200
201 /* Cleanup console event-handlers: */
202 cleanupConsoleEventHandlers();
203
204#ifdef Q_WS_WIN
205 /* Destroy alpha cursor: */
206 if (m_alphaCursor)
207 DestroyIcon(m_alphaCursor);
208#endif /* Q_WS_WIN */
209}
210
211void UISession::powerUp()
212{
213 /* Do nothing if we had started already: */
214 if (isRunning() || isPaused())
215 return;
216
217 /* Prepare powerup: */
218 bool fPrepared = preparePowerUp();
219 if (!fPrepared)
220 return;
221
222 /* Get current machine/console: */
223 CMachine machine = session().GetMachine();
224 CConsole console = session().GetConsole();
225
226 /* Apply debug settings from the command line. */
227 CMachineDebugger debugger = console.GetDebugger();
228 if (debugger.isOk())
229 {
230 if (vboxGlobal().isPatmDisabled())
231 debugger.SetPATMEnabled(false);
232 if (vboxGlobal().isCsamDisabled())
233 debugger.SetCSAMEnabled(false);
234 if (vboxGlobal().isSupervisorCodeExecedRecompiled())
235 debugger.SetRecompileSupervisor(true);
236 if (vboxGlobal().isUserCodeExecedRecompiled())
237 debugger.SetRecompileUser(true);
238 if (vboxGlobal().areWeToExecuteAllInIem())
239 debugger.SetExecuteAllInIEM(true);
240 if (!vboxGlobal().isDefaultWarpPct())
241 debugger.SetVirtualTimeRate(vboxGlobal().getWarpPct());
242 }
243
244 /* Power UP machine: */
245 CProgress progress = vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled(machine) ?
246 console.PowerUpPaused() : console.PowerUp();
247
248 /* Check for immediate failure: */
249 if (!console.isOk())
250 {
251 if (vboxGlobal().showStartVMErrors())
252 msgCenter().cannotStartMachine(console, machine.GetName());
253 closeRuntimeUI();
254 return;
255 }
256
257 /* Guard progressbar warnings from auto-closing: */
258 if (uimachine()->machineLogic())
259 uimachine()->machineLogic()->setPreventAutoClose(true);
260
261 /* Show "Starting/Restoring" progress dialog: */
262 if (isSaved())
263 {
264 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_restore_90px.png", 0, 0);
265 /* After restoring from 'saved' state, guest screen size should be adjusted: */
266 machineLogic()->maybeAdjustGuestScreenSize();
267 }
268 else
269 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_start_90px.png");
270
271 /* Check for a progress failure: */
272 if (!progress.isOk() || progress.GetResultCode() != 0)
273 {
274 if (vboxGlobal().showStartVMErrors())
275 msgCenter().cannotStartMachine(progress, machine.GetName());
276 closeRuntimeUI();
277 return;
278 }
279
280 /* Allow further auto-closing: */
281 if (uimachine()->machineLogic())
282 uimachine()->machineLogic()->setPreventAutoClose(false);
283
284 /* Check if we missed a really quick termination after successful startup, and process it if we did: */
285 if (isTurnedOff())
286 {
287 closeRuntimeUI();
288 return;
289 }
290
291 /* Check if the required virtualization features are active. We get this
292 * info only when the session is active. */
293 bool fIs64BitsGuest = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetIs64Bit();
294 bool fRecommendVirtEx = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetRecommendedVirtEx();
295 AssertMsg(!fIs64BitsGuest || fRecommendVirtEx, ("Virtualization support missed for 64bit guest!\n"));
296 bool fIsVirtEnabled = console.GetDebugger().GetHWVirtExEnabled();
297 if (fRecommendVirtEx && !fIsVirtEnabled)
298 {
299 bool fShouldWeClose;
300
301 bool fVTxAMDVSupported = vboxGlobal().host().GetProcessorFeature(KProcessorFeature_HWVirtEx);
302
303 QApplication::processEvents();
304 setPause(true);
305
306 if (fIs64BitsGuest)
307 fShouldWeClose = msgCenter().warnAboutVirtNotEnabled64BitsGuest(fVTxAMDVSupported);
308 else
309 fShouldWeClose = msgCenter().warnAboutVirtNotEnabledGuestRequired(fVTxAMDVSupported);
310
311 if (fShouldWeClose)
312 {
313 /* At this point the console is powered up. So we have to close
314 * this session again. */
315 CProgress progress = console.PowerDown();
316 if (console.isOk())
317 {
318 /* Guard progressbar warnings from auto-closing: */
319 if (uimachine()->machineLogic())
320 uimachine()->machineLogic()->setPreventAutoClose(true);
321 /* Show the power down progress dialog */
322 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_poweroff_90px.png");
323 if (!progress.isOk() || progress.GetResultCode() != 0)
324 msgCenter().cannotPowerDownMachine(progress, machine.GetName());
325 /* Allow further auto-closing: */
326 if (uimachine()->machineLogic())
327 uimachine()->machineLogic()->setPreventAutoClose(false);
328 }
329 else
330 msgCenter().cannotPowerDownMachine(console);
331 closeRuntimeUI();
332 return;
333 }
334
335 setPause(false);
336 }
337
338#ifdef VBOX_WITH_VIDEOHWACCEL
339 LogRel(("2D video acceleration is %s.\n",
340 machine.GetAccelerate2DVideoEnabled() && VBoxGlobal::isAcceleration2DVideoAvailable()
341 ? "enabled"
342 : "disabled"));
343#endif
344
345#ifdef VBOX_GUI_WITH_PIDFILE
346 vboxGlobal().createPidfile();
347#endif
348
349 /* Warn listeners about machine was started: */
350 emit sigMachineStarted();
351}
352
353bool UISession::saveState()
354{
355 /* Prepare the saving progress: */
356 CMachine machine = m_session.GetMachine();
357 CConsole console = m_session.GetConsole();
358 CProgress progress = console.SaveState();
359 if (console.isOk())
360 {
361 /* Show the saving progress: */
362 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_save_90px.png");
363 if (!progress.isOk() || progress.GetResultCode() != 0)
364 {
365 /* Failed in progress: */
366 msgCenter().cannotSaveMachineState(progress, machine.GetName());
367 return false;
368 }
369 }
370 else
371 {
372 /* Failed in console: */
373 msgCenter().cannotSaveMachineState(console);
374 return false;
375 }
376 /* Passed: */
377 return true;
378}
379
380bool UISession::shutdown()
381{
382 /* Send ACPI shutdown signal if possible: */
383 CConsole console = m_session.GetConsole();
384 console.PowerButton();
385 if (!console.isOk())
386 {
387 /* Failed in console: */
388 msgCenter().cannotACPIShutdownMachine(console);
389 return false;
390 }
391 /* Passed: */
392 return true;
393}
394
395bool UISession::powerOff(bool fIncludingDiscard, bool &fServerCrashed)
396{
397 /* Prepare the power-off progress: */
398 CMachine machine = m_session.GetMachine();
399 CConsole console = m_session.GetConsole();
400 CProgress progress = console.PowerDown();
401 if (console.isOk())
402 {
403 /* Show the power-off progress: */
404 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_poweroff_90px.png");
405 if (progress.isOk() && progress.GetResultCode() == 0)
406 {
407 /* Discard the current state if requested: */
408 if (fIncludingDiscard)
409 {
410 /* Prepare the snapshot-discard progress: */
411 CSnapshot snapshot = machine.GetCurrentSnapshot();
412 CProgress progress = console.RestoreSnapshot(snapshot);
413 if (!console.isOk())
414 return msgCenter().cannotRestoreSnapshot(console, snapshot.GetName(), machine.GetName());
415
416 /* Show the snapshot-discard progress: */
417 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_snapshot_discard_90px.png");
418 if (progress.GetResultCode() != 0)
419 return msgCenter().cannotRestoreSnapshot(progress, snapshot.GetName(), machine.GetName());
420 }
421 }
422 else
423 {
424 /* Failed in progress: */
425 msgCenter().cannotPowerDownMachine(progress, machine.GetName());
426 return false;
427 }
428 }
429 else
430 {
431 /* Failed in console: */
432 COMResult res(console);
433 /* This can happen if VBoxSVC is not running: */
434 if (FAILED_DEAD_INTERFACE(res.rc()))
435 fServerCrashed = true;
436 else
437 msgCenter().cannotPowerDownMachine(console);
438 return false;
439 }
440 /* Passed: */
441 return true;
442}
443
444void UISession::closeRuntimeUI()
445{
446 /* Start corresponding slot asynchronously: */
447 emit sigCloseRuntimeUI();
448}
449
450UIMachineLogic* UISession::machineLogic() const
451{
452 return uimachine()->machineLogic();
453}
454
455QWidget* UISession::mainMachineWindow() const
456{
457 return machineLogic()->mainMachineWindow();
458}
459
460QMenu* UISession::newMenu(RuntimeMenuType fOptions /* = RuntimeMenuType_ALL */)
461{
462 /* Create new menu: */
463 QMenu *pMenu = m_pMenuPool->createMenu(fOptions);
464
465 /* Re-init menu pool for the case menu were recreated: */
466 reinitMenuPool();
467
468 /* Return newly created menu: */
469 return pMenu;
470}
471
472QMenuBar* UISession::newMenuBar(RuntimeMenuType fOptions /* = RuntimeMenuType_ALL */)
473{
474 /* Create new menubar: */
475 QMenuBar *pMenuBar = m_pMenuPool->createMenuBar(fOptions);
476
477 /* Re-init menu pool for the case menu were recreated: */
478 reinitMenuPool();
479
480 /* Return newly created menubar: */
481 return pMenuBar;
482}
483
484bool UISession::isVisualStateAllowedFullscreen() const
485{
486 return m_pMachine->isVisualStateAllowedFullscreen();
487}
488
489bool UISession::isVisualStateAllowedSeamless() const
490{
491 return m_pMachine->isVisualStateAllowedSeamless();
492}
493
494bool UISession::isVisualStateAllowedScale() const
495{
496 return m_pMachine->isVisualStateAllowedScale();
497}
498
499void UISession::changeVisualState(UIVisualStateType visualStateType)
500{
501 m_pMachine->asyncChangeVisualState(visualStateType);
502}
503
504bool UISession::setPause(bool fOn)
505{
506 CConsole console = session().GetConsole();
507
508 if (fOn)
509 console.Pause();
510 else
511 console.Resume();
512
513 bool ok = console.isOk();
514 if (!ok)
515 {
516 if (fOn)
517 msgCenter().cannotPauseMachine(console);
518 else
519 msgCenter().cannotResumeMachine(console);
520 }
521
522 return ok;
523}
524
525void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
526{
527 CMachine machine = session().GetMachine();
528 CVirtualBox vbox = vboxGlobal().virtualBox();
529
530 /*
531 * Flag indicating whether we want to do the usual .ISO mounting or not.
532 * First try updating the Guest Additions directly without mounting the .ISO.
533 */
534 bool fDoMount = false;
535 /* Auto-update in GUI currently is disabled. */
536#ifndef VBOX_WITH_ADDITIONS_AUTOUPDATE_UI
537 fDoMount = true;
538#else
539 CGuest guest = session().GetConsole().GetGuest();
540 QVector<KAdditionsUpdateFlag> aFlagsUpdate;
541 QVector<QString> aArgs;
542 CProgress progressInstall = guest.UpdateGuestAdditions(strSource,
543 aArgs, aFlagsUpdate);
544 bool fResult = guest.isOk();
545 if (fResult)
546 {
547 msgCenter().showModalProgressDialog(progressInstall, tr("Updating Guest Additions"),
548 ":/progress_install_guest_additions_90px.png",
549 0, 500 /* 500ms delay. */);
550 if (progressInstall.GetCanceled())
551 return;
552
553 HRESULT rc = progressInstall.GetResultCode();
554 if (!progressInstall.isOk() || rc != S_OK)
555 {
556 /* If we got back a VBOX_E_NOT_SUPPORTED we don't complain (guest OS
557 * simply isn't supported yet), so silently fall back to "old" .ISO
558 * mounting method. */
559 if ( !SUCCEEDED_WARNING(rc)
560 && rc != VBOX_E_NOT_SUPPORTED)
561 {
562 msgCenter().cannotUpdateGuestAdditions(progressInstall);
563
564 /* Log the error message in the release log. */
565 QString strErr = progressInstall.GetErrorInfo().GetText();
566 if (!strErr.isEmpty())
567 LogRel(("%s\n", strErr.toLatin1().constData()));
568 }
569 fDoMount = true; /* Since automatic updating failed, fall back to .ISO mounting. */
570 }
571 }
572#endif /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
573
574 if (fDoMount) /* Fallback to only mounting the .ISO file. */
575 {
576 QString strUuid;
577 CMedium image = vbox.OpenMedium(strSource, KDeviceType_DVD, KAccessMode_ReadWrite, false /* fForceNewUuid */);
578 if (image.isNull())
579 {
580 image = vbox.OpenMedium(strSource, KDeviceType_DVD, KAccessMode_ReadWrite, false /* fForceNewUuid */);
581 if (vbox.isOk())
582 strUuid = image.GetId();
583 }
584 else
585 strUuid = image.GetId();
586
587 if (!vbox.isOk())
588 {
589 msgCenter().cannotOpenMedium(vbox, UIMediumType_DVD, strSource, mainMachineWindow());
590 return;
591 }
592
593 AssertMsg(!strUuid.isNull(), ("Guest Additions image UUID should be valid!\n"));
594
595 QString strCntName;
596 LONG iCntPort = -1, iCntDevice = -1;
597 /* Searching for the first suitable slot */
598 {
599 CStorageControllerVector controllers = machine.GetStorageControllers();
600 int i = 0;
601 while (i < controllers.size() && strCntName.isNull())
602 {
603 CStorageController controller = controllers[i];
604 CMediumAttachmentVector attachments = machine.GetMediumAttachmentsOfController(controller.GetName());
605 int j = 0;
606 while (j < attachments.size() && strCntName.isNull())
607 {
608 CMediumAttachment attachment = attachments[j];
609 if (attachment.GetType() == KDeviceType_DVD)
610 {
611 strCntName = controller.GetName();
612 iCntPort = attachment.GetPort();
613 iCntDevice = attachment.GetDevice();
614 }
615 ++ j;
616 }
617 ++ i;
618 }
619 }
620
621 if (!strCntName.isNull())
622 {
623 /* Create new UIMedium: */
624 UIMedium medium(image, UIMediumType_DVD, KMediumState_Created);
625
626 /* Inform VBoxGlobal about it: */
627 vboxGlobal().createMedium(medium);
628
629 /* Mount medium to the predefined port/device: */
630 machine.MountMedium(strCntName, iCntPort, iCntDevice, medium.medium(), false /* force */);
631 if (!machine.isOk())
632 {
633 /* Ask for force mounting: */
634 if (msgCenter().cannotRemountMedium(machine, medium, true /* mount? */,
635 true /* retry? */, mainMachineWindow()))
636 {
637 /* Force mount medium to the predefined port/device: */
638 machine.MountMedium(strCntName, iCntPort, iCntDevice, medium.medium(), true /* force */);
639 if (!machine.isOk())
640 msgCenter().cannotRemountMedium(machine, medium, true /* mount? */,
641 false /* retry? */, mainMachineWindow());
642 }
643 }
644 }
645 else
646 msgCenter().cannotMountGuestAdditions(machine.GetName());
647 }
648}
649
650void UISession::sltChangeVisualStateToNormal()
651{
652 /* Reset requests: */
653 setSeamlessModeRequested(false);
654 /* Request change: */
655 m_pMachine->asyncChangeVisualState(UIVisualStateType_Normal);
656}
657
658void UISession::sltChangeVisualStateToFullscreen()
659{
660 /* Reset requests: */
661 setSeamlessModeRequested(false);
662 /* Request change: */
663 m_pMachine->asyncChangeVisualState(UIVisualStateType_Fullscreen);
664}
665
666void UISession::sltChangeVisualStateToSeamless()
667{
668 /* Reset requests: */
669 setSeamlessModeRequested(false);
670 /* Request change: */
671 m_pMachine->asyncChangeVisualState(UIVisualStateType_Seamless);
672}
673
674void UISession::sltChangeVisualStateToScale()
675{
676 /* Reset requests: */
677 setSeamlessModeRequested(false);
678 /* Request change: */
679 m_pMachine->asyncChangeVisualState(UIVisualStateType_Scale);
680}
681
682void UISession::sltCloseRuntimeUI()
683{
684 /* First, we have to hide any opened modal/popup widgets.
685 * They then should unlock their event-loops synchronously.
686 * If all such loops are unlocked, we can close Runtime UI: */
687 if (QWidget *pWidget = QApplication::activeModalWidget() ?
688 QApplication::activeModalWidget() :
689 QApplication::activePopupWidget() ?
690 QApplication::activePopupWidget() : 0)
691 {
692 /* First we should try to close this widget: */
693 pWidget->close();
694 /* If widget rejected the 'close-event' we can
695 * still hide it and hope it will behave correctly
696 * and unlock his event-loop if any: */
697 if (!pWidget->isHidden())
698 pWidget->hide();
699 /* Restart this slot asynchronously: */
700 emit sigCloseRuntimeUI();
701 return;
702 }
703
704 /* Finally close the Runtime UI: */
705 m_pMachine->deleteLater();
706}
707
708void UISession::sltMousePointerShapeChange(bool fVisible, bool fAlpha, QPoint hotCorner, QSize size, QVector<uint8_t> shape)
709{
710 /* In case of shape data is present: */
711 if (shape.size() > 0)
712 {
713 /* We are ignoring visibility flag: */
714 m_fIsHidingHostPointer = false;
715
716 /* And updating current cursor shape: */
717 setPointerShape(shape.data(), fAlpha,
718 hotCorner.x(), hotCorner.y(),
719 size.width(), size.height());
720 }
721 /* In case of shape data is NOT present: */
722 else
723 {
724 /* Remember if we should hide the cursor: */
725 m_fIsHidingHostPointer = !fVisible;
726 }
727
728 /* Notify listeners about mouse capability changed: */
729 emit sigMousePointerShapeChange();
730
731}
732
733void UISession::sltMouseCapabilityChange(bool fSupportsAbsolute, bool fSupportsRelative, bool fSupportsMultiTouch, bool fNeedsHostCursor)
734{
735 LogRelFlow(("UISession::sltMouseCapabilityChange: "
736 "Supports absolute: %s, Supports relative: %s, "
737 "Supports multi-touch: %s, Needs host cursor: %s\n",
738 fSupportsAbsolute ? "TRUE" : "FALSE", fSupportsRelative ? "TRUE" : "FALSE",
739 fSupportsMultiTouch ? "TRUE" : "FALSE", fNeedsHostCursor ? "TRUE" : "FALSE"));
740
741 /* Check if something had changed: */
742 if ( m_fIsMouseSupportsAbsolute != fSupportsAbsolute
743 || m_fIsMouseSupportsRelative != fSupportsRelative
744 || m_fIsMouseSupportsMultiTouch != fSupportsMultiTouch
745 || m_fIsMouseHostCursorNeeded != fNeedsHostCursor)
746 {
747 /* Store new data: */
748 m_fIsMouseSupportsAbsolute = fSupportsAbsolute;
749 m_fIsMouseSupportsRelative = fSupportsRelative;
750 m_fIsMouseSupportsMultiTouch = fSupportsMultiTouch;
751 m_fIsMouseHostCursorNeeded = fNeedsHostCursor;
752
753 /* Notify listeners about mouse capability changed: */
754 emit sigMouseCapabilityChange();
755 }
756}
757
758void UISession::sltKeyboardLedsChangeEvent(bool fNumLock, bool fCapsLock, bool fScrollLock)
759{
760 /* Check if something had changed: */
761 if ( m_fNumLock != fNumLock
762 || m_fCapsLock != fCapsLock
763 || m_fScrollLock != fScrollLock)
764 {
765 /* Store new num lock data: */
766 if (m_fNumLock != fNumLock)
767 {
768 m_fNumLock = fNumLock;
769 m_uNumLockAdaptionCnt = 2;
770 }
771
772 /* Store new caps lock data: */
773 if (m_fCapsLock != fCapsLock)
774 {
775 m_fCapsLock = fCapsLock;
776 m_uCapsLockAdaptionCnt = 2;
777 }
778
779 /* Store new scroll lock data: */
780 if (m_fScrollLock != fScrollLock)
781 {
782 m_fScrollLock = fScrollLock;
783 }
784
785 /* Notify listeners about mouse capability changed: */
786 emit sigKeyboardLedsChange();
787 }
788}
789
790void UISession::sltStateChange(KMachineState state)
791{
792 /* Check if something had changed: */
793 if (m_machineState != state)
794 {
795 /* Store new data: */
796 m_machineStatePrevious = m_machineState;
797 m_machineState = state;
798
799 /* Update session settings: */
800 updateSessionSettings();
801
802 /* Notify listeners about machine state changed: */
803 emit sigMachineStateChange();
804 }
805}
806
807void UISession::sltVRDEChange()
808{
809 /* Get machine: */
810 const CMachine machine = session().GetMachine();
811 /* Get VRDE server: */
812 const CVRDEServer &server = machine.GetVRDEServer();
813 bool fIsVRDEServerAvailable = !server.isNull();
814 /* Show/Hide VRDE action depending on VRDE server availability status: */
815 gActionPool->action(UIActionIndexRuntime_Toggle_VRDEServer)->setVisible(fIsVRDEServerAvailable);
816 /* Check/Uncheck VRDE action depending on VRDE server activity status: */
817 if (fIsVRDEServerAvailable)
818 gActionPool->action(UIActionIndexRuntime_Toggle_VRDEServer)->setChecked(server.GetEnabled());
819 /* Notify listeners about VRDE change: */
820 emit sigVRDEChange();
821}
822
823void UISession::sltVideoCaptureChange()
824{
825 /* Get machine: */
826 const CMachine machine = session().GetMachine();
827 /* Check/Uncheck Video Capture action depending on feature status: */
828 gActionPool->action(UIActionIndexRuntime_Toggle_VideoCapture)->setChecked(machine.GetVideoCaptureEnabled());
829 /* Notify listeners about Video Capture change: */
830 emit sigVideoCaptureChange();
831}
832
833void UISession::sltGuestMonitorChange(KGuestMonitorChangedEventType changeType, ulong uScreenId, QRect screenGeo)
834{
835 /* Ignore KGuestMonitorChangedEventType_NewOrigin change event: */
836 if (changeType == KGuestMonitorChangedEventType_NewOrigin)
837 return;
838 /* Ignore KGuestMonitorChangedEventType_Disabled event if there is only one window visible: */
839 AssertMsg(countOfVisibleWindows() > 0, ("All machine windows are hidden!"));
840 if ( changeType == KGuestMonitorChangedEventType_Disabled
841 && countOfVisibleWindows() == 1
842 && isScreenVisible(uScreenId))
843 return;
844
845 /* Process KGuestMonitorChangedEventType_Enabled change event: */
846 if ( !isScreenVisible(uScreenId)
847 && changeType == KGuestMonitorChangedEventType_Enabled)
848 setScreenVisible(uScreenId, true);
849 /* Process KGuestMonitorChangedEventType_Disabled change event: */
850 else if ( isScreenVisible(uScreenId)
851 && changeType == KGuestMonitorChangedEventType_Disabled)
852 setScreenVisible(uScreenId, false);
853
854 /* Notify listeners about the change: */
855 emit sigGuestMonitorChange(changeType, uScreenId, screenGeo);
856}
857
858#ifdef RT_OS_DARWIN
859/**
860 * MacOS X: Restarts display-reconfiguration watchdog timer from the beginning.
861 * @note Watchdog is trying to determine display reconfiguration in
862 * UISession::sltCheckIfHostDisplayChanged() slot every 500ms for 40 tries.
863 */
864void UISession::sltHandleHostDisplayAboutToChange()
865{
866 LogRelFlow(("UISession::sltHandleHostDisplayAboutToChange()\n"));
867
868 if (m_pWatchdogDisplayChange->isActive())
869 m_pWatchdogDisplayChange->stop();
870 m_pWatchdogDisplayChange->setProperty("tryNumber", 1);
871 m_pWatchdogDisplayChange->start();
872}
873
874/**
875 * MacOS X: Determines display reconfiguration.
876 * @note Calls for UISession::sltHandleHostScreenCountChange() if screen count changed.
877 * @note Calls for UISession::sltHandleHostScreenGeometryChange() if screen geometry changed.
878 */
879void UISession::sltCheckIfHostDisplayChanged()
880{
881 LogRelFlow(("UISession::sltCheckIfHostDisplayChanged()\n"));
882
883 /* Acquire desktop wrapper: */
884 QDesktopWidget *pDesktop = QApplication::desktop();
885
886 /* Check if display count changed: */
887 if (pDesktop->screenCount() != m_screens.size())
888 {
889 /* Recache display data: */
890 recacheDisplayData();
891 /* Reset watchdog: */
892 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
893 /* Notify listeners about screen-count changed: */
894 return sltHandleHostScreenCountChange();
895 }
896 else
897 {
898 /* Check if at least one display geometry changed: */
899 for (int iScreenIndex = 0; iScreenIndex < pDesktop->screenCount(); ++iScreenIndex)
900 {
901 if (pDesktop->screenGeometry(iScreenIndex) != m_screens.at(iScreenIndex))
902 {
903 /* Recache display data: */
904 recacheDisplayData();
905 /* Reset watchdog: */
906 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
907 /* Notify listeners about screen-geometry changed: */
908 return sltHandleHostScreenGeometryChange();
909 }
910 }
911 }
912
913 /* Check if watchdog expired, restart if not: */
914 int cTryNumber = m_pWatchdogDisplayChange->property("tryNumber").toInt();
915 if (cTryNumber > 0 && cTryNumber < 40)
916 {
917 /* Restart watchdog again: */
918 m_pWatchdogDisplayChange->setProperty("tryNumber", ++cTryNumber);
919 m_pWatchdogDisplayChange->start();
920 }
921 else
922 {
923 /* Reset watchdog: */
924 m_pWatchdogDisplayChange->setProperty("tryNumber", 0);
925 }
926}
927#endif /* RT_OS_DARWIN */
928
929void UISession::sltHandleHostScreenCountChange()
930{
931 LogRelFlow(("UISession: Host-screen count changed.\n"));
932
933 /* Notify current machine-logic: */
934 emit sigHostScreenCountChanged();
935}
936
937void UISession::sltHandleHostScreenGeometryChange()
938{
939 LogRelFlow(("UISession: Host-screen geometry changed.\n"));
940
941 /* Notify current machine-logic: */
942 emit sigHostScreenGeometryChanged();
943}
944
945void UISession::sltAdditionsChange()
946{
947 /* Get our guest: */
948 CGuest guest = session().GetConsole().GetGuest();
949
950 /* Variable flags: */
951 ULONG ulGuestAdditionsRunLevel = guest.GetAdditionsRunLevel();
952 LONG64 lLastUpdatedIgnored;
953 bool fIsGuestSupportsGraphics = guest.GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
954 == KAdditionsFacilityStatus_Active;
955 bool fIsGuestSupportsSeamless = guest.GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
956 == KAdditionsFacilityStatus_Active;
957 /* Check if something had changed: */
958 if (m_ulGuestAdditionsRunLevel != ulGuestAdditionsRunLevel ||
959 m_fIsGuestSupportsGraphics != fIsGuestSupportsGraphics ||
960 m_fIsGuestSupportsSeamless != fIsGuestSupportsSeamless)
961 {
962 /* Store new data: */
963 m_ulGuestAdditionsRunLevel = ulGuestAdditionsRunLevel;
964 m_fIsGuestSupportsGraphics = fIsGuestSupportsGraphics;
965 m_fIsGuestSupportsSeamless = fIsGuestSupportsSeamless;
966
967 /* Notify listeners about guest additions state changed: */
968 emit sigAdditionsStateChange();
969 }
970}
971
972void UISession::prepareConsoleEventHandlers()
973{
974 /* Initialize console event-handler: */
975 UIConsoleEventHandler::instance(this);
976
977 /* Add console event connections: */
978 connect(gConsoleEvents, SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
979 this, SLOT(sltMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)));
980
981 connect(gConsoleEvents, SIGNAL(sigMouseCapabilityChange(bool, bool, bool, bool)),
982 this, SLOT(sltMouseCapabilityChange(bool, bool, bool, bool)));
983
984 connect(gConsoleEvents, SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
985 this, SLOT(sltKeyboardLedsChangeEvent(bool, bool, bool)));
986
987 connect(gConsoleEvents, SIGNAL(sigStateChange(KMachineState)),
988 this, SLOT(sltStateChange(KMachineState)));
989
990 connect(gConsoleEvents, SIGNAL(sigAdditionsChange()),
991 this, SLOT(sltAdditionsChange()));
992
993 connect(gConsoleEvents, SIGNAL(sigVRDEChange()),
994 this, SLOT(sltVRDEChange()));
995
996 connect(gConsoleEvents, SIGNAL(sigVideoCaptureChange()),
997 this, SLOT(sltVideoCaptureChange()));
998
999 connect(gConsoleEvents, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
1000 this, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)));
1001
1002 connect(gConsoleEvents, SIGNAL(sigMediumChange(CMediumAttachment)),
1003 this, SIGNAL(sigMediumChange(CMediumAttachment)));
1004
1005 connect(gConsoleEvents, SIGNAL(sigUSBControllerChange()),
1006 this, SIGNAL(sigUSBControllerChange()));
1007
1008 connect(gConsoleEvents, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
1009 this, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)));
1010
1011 connect(gConsoleEvents, SIGNAL(sigSharedFolderChange()),
1012 this, SIGNAL(sigSharedFolderChange()));
1013
1014 connect(gConsoleEvents, SIGNAL(sigRuntimeError(bool, QString, QString)),
1015 this, SIGNAL(sigRuntimeError(bool, QString, QString)));
1016
1017#ifdef Q_WS_MAC
1018 connect(gConsoleEvents, SIGNAL(sigShowWindow()),
1019 this, SIGNAL(sigShowWindows()), Qt::QueuedConnection);
1020#endif /* Q_WS_MAC */
1021
1022 connect(gConsoleEvents, SIGNAL(sigCPUExecutionCapChange()),
1023 this, SIGNAL(sigCPUExecutionCapChange()));
1024
1025 connect(gConsoleEvents, SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
1026 this, SLOT(sltGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)));
1027}
1028
1029void UISession::prepareConnections()
1030{
1031 connect(this, SIGNAL(sigCloseRuntimeUI()), this, SLOT(sltCloseRuntimeUI()));
1032
1033#ifdef Q_WS_MAC
1034 /* Install native display reconfiguration callback: */
1035 CGDisplayRegisterReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1036#else /* !Q_WS_MAC */
1037 /* Install Qt display reconfiguration callbacks: */
1038 connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)),
1039 this, SLOT(sltHandleHostScreenCountChange()));
1040 connect(QApplication::desktop(), SIGNAL(resized(int)),
1041 this, SLOT(sltHandleHostScreenGeometryChange()));
1042 connect(QApplication::desktop(), SIGNAL(workAreaResized(int)),
1043 this, SLOT(sltHandleHostScreenGeometryChange()));
1044#endif /* !Q_WS_MAC */
1045}
1046
1047void UISession::prepareScreens()
1048{
1049#ifdef Q_WS_MAC
1050 /* Recache display data: */
1051 recacheDisplayData();
1052 /* Prepare display-change watchdog: */
1053 m_pWatchdogDisplayChange = new QTimer(this);
1054 {
1055 m_pWatchdogDisplayChange->setInterval(500);
1056 m_pWatchdogDisplayChange->setSingleShot(true);
1057 connect(m_pWatchdogDisplayChange, SIGNAL(timeout()),
1058 this, SLOT(sltCheckIfHostDisplayChanged()));
1059 }
1060#endif /* Q_WS_MAC */
1061
1062 /* Get machine: */
1063 CMachine machine = m_session.GetMachine();
1064
1065 /* Prepare initial screen visibility status: */
1066 m_monitorVisibilityVector.resize(machine.GetMonitorCount());
1067 m_monitorVisibilityVector.fill(false);
1068 m_monitorVisibilityVector[0] = true;
1069
1070 /* If machine is in 'saved' state: */
1071 if (isSaved())
1072 {
1073 /* Update screen visibility status from saved-state: */
1074 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
1075 {
1076 BOOL fEnabled = true;
1077 ULONG guestOriginX = 0, guestOriginY = 0, guestWidth = 0, guestHeight = 0;
1078 machine.QuerySavedGuestScreenInfo(i, guestOriginX, guestOriginY, guestWidth, guestHeight, fEnabled);
1079 m_monitorVisibilityVector[i] = fEnabled;
1080 }
1081 /* And make sure at least one of them is visible (primary if others are hidden): */
1082 if (countOfVisibleWindows() < 1)
1083 m_monitorVisibilityVector[0] = true;
1084 }
1085}
1086
1087void UISession::prepareFramebuffers()
1088{
1089 /* Each framebuffer will be really prepared on first UIMachineView creation: */
1090 m_frameBufferVector.resize(m_session.GetMachine().GetMonitorCount());
1091}
1092
1093void UISession::prepareMenuPool()
1094{
1095 m_pMenuPool = new UIMachineMenuBar(this);
1096}
1097
1098void UISession::loadSessionSettings()
1099{
1100 /* Get uisession machine: */
1101 CMachine machine = session().GetConsole().GetMachine();
1102
1103 /* Load extra-data settings: */
1104 {
1105 /* Temporary: */
1106 QString strSettings;
1107
1108 /* Is there should be First RUN Wizard? */
1109 strSettings = machine.GetExtraData(GUI_FirstRun);
1110 if (strSettings == "yes")
1111 m_fIsFirstTimeStarted = true;
1112
1113 /* Ignore mediums mounted at runtime? */
1114 strSettings = machine.GetExtraData(GUI_SaveMountedAtRuntime);
1115 if (strSettings == "no")
1116 m_fIsIgnoreRuntimeMediumsChanging = true;
1117
1118 /* Should guest autoresize? */
1119 strSettings = machine.GetExtraData(GUI_AutoresizeGuest);
1120 QAction *pGuestAutoresizeSwitch = gActionPool->action(UIActionIndexRuntime_Toggle_GuestAutoresize);
1121 pGuestAutoresizeSwitch->setChecked(strSettings != "off");
1122
1123 /* Should we allow reconfiguration? */
1124 m_fReconfigurable = VBoxGlobal::shouldWeAllowMachineReconfiguration(machine);
1125 updateSessionSettings();
1126
1127 /* What is the default close action and the restricted are? */
1128 m_defaultCloseAction = vboxGlobal().defaultMachineCloseAction(machine);
1129 m_restrictedCloseActions = vboxGlobal().restrictedMachineCloseActions(machine);
1130 m_fAllCloseActionsRestricted = (m_restrictedCloseActions & MachineCloseAction_SaveState)
1131 && (m_restrictedCloseActions & MachineCloseAction_Shutdown)
1132 && (m_restrictedCloseActions & MachineCloseAction_PowerOff);
1133 // Close VM Dialog hides PowerOff_RestoringSnapshot implicitly if PowerOff is hidden..
1134 // && (m_restrictedCloseActions & MachineCloseAction_PowerOff_RestoringSnapshot);
1135
1136 /* Should we allow snapshot operations? */
1137 m_fSnapshotOperationsAllowed = vboxGlobal().shouldWeAllowSnapshotOperations(machine);
1138
1139#if 0 /* Disabled for now! */
1140# ifdef Q_WS_WIN
1141 /* Disable host screen-saver if requested: */
1142 if (vboxGlobal().settings().hostScreenSaverDisabled())
1143 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, false, 0, 0);
1144# endif /* Q_WS_WIN */
1145#endif
1146 }
1147}
1148
1149void UISession::saveSessionSettings()
1150{
1151 /* Get uisession machine: */
1152 CMachine machine = session().GetConsole().GetMachine();
1153
1154 /* Save extra-data settings: */
1155 {
1156 /* Disable First RUN Wizard for the since now: */
1157 machine.SetExtraData(GUI_FirstRun, QString());
1158
1159 /* Remember if guest should autoresize: */
1160 machine.SetExtraData(GUI_AutoresizeGuest,
1161 gActionPool->action(UIActionIndexRuntime_Toggle_GuestAutoresize)->isChecked() ?
1162 QString() : "off");
1163
1164#if 0 /* Disabled for now! */
1165# ifdef Q_WS_WIN
1166 /* Restore screen-saver activity to system default: */
1167 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, true, 0, 0);
1168# endif /* Q_WS_WIN */
1169#endif
1170 }
1171}
1172
1173void UISession::cleanupMenuPool()
1174{
1175 delete m_pMenuPool;
1176 m_pMenuPool = 0;
1177}
1178
1179void UISession::cleanupFramebuffers()
1180{
1181 /* Cleanup framebuffers finally: */
1182 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
1183 {
1184 UIFrameBuffer *pFb = m_frameBufferVector[i];
1185 if (pFb)
1186 {
1187 /* Mark framebuffer as unused: */
1188 pFb->setMarkAsUnused(true);
1189 /* Detach framebuffer from Display: */
1190 CDisplay display = session().GetConsole().GetDisplay();
1191 display.SetFramebuffer(i, CFramebuffer(NULL));
1192 /* Release framebuffer reference: */
1193 pFb->Release();
1194 }
1195 }
1196 m_frameBufferVector.clear();
1197}
1198
1199void UISession::cleanupConsoleEventHandlers()
1200{
1201 /* Destroy console event-handler: */
1202 UIConsoleEventHandler::destroy();
1203}
1204
1205void UISession::cleanupConnections()
1206{
1207#ifdef Q_WS_MAC
1208 /* Remove display reconfiguration callback: */
1209 CGDisplayRemoveReconfigurationCallback(cgDisplayReconfigurationCallback, this);
1210#endif /* Q_WS_MAC */
1211}
1212
1213void UISession::updateSessionSettings()
1214{
1215 bool fAllowReconfiguration = m_machineState != KMachineState_Stuck && m_fReconfigurable;
1216 gActionPool->action(UIActionIndexRuntime_Simple_SettingsDialog)->setEnabled(fAllowReconfiguration);
1217 gActionPool->action(UIActionIndexRuntime_Simple_SharedFoldersSettings)->setEnabled(fAllowReconfiguration);
1218 gActionPool->action(UIActionIndexRuntime_Simple_VideoCaptureSettings)->setEnabled(fAllowReconfiguration);
1219 gActionPool->action(UIActionIndexRuntime_Simple_NetworkSettings)->setEnabled(fAllowReconfiguration);
1220}
1221
1222WId UISession::winId() const
1223{
1224 return mainMachineWindow()->winId();
1225}
1226
1227void UISession::setPointerShape(const uchar *pShapeData, bool fHasAlpha,
1228 uint uXHot, uint uYHot, uint uWidth, uint uHeight)
1229{
1230 AssertMsg(pShapeData, ("Shape data must not be NULL!\n"));
1231
1232 m_fIsValidPointerShapePresent = false;
1233 const uchar *srcAndMaskPtr = pShapeData;
1234 uint andMaskSize = (uWidth + 7) / 8 * uHeight;
1235 const uchar *srcShapePtr = pShapeData + ((andMaskSize + 3) & ~3);
1236 uint srcShapePtrScan = uWidth * 4;
1237
1238#if defined (Q_WS_WIN)
1239
1240 BITMAPV5HEADER bi;
1241 HBITMAP hBitmap;
1242 void *lpBits;
1243
1244 ::ZeroMemory(&bi, sizeof (BITMAPV5HEADER));
1245 bi.bV5Size = sizeof(BITMAPV5HEADER);
1246 bi.bV5Width = uWidth;
1247 bi.bV5Height = - (LONG)uHeight;
1248 bi.bV5Planes = 1;
1249 bi.bV5BitCount = 32;
1250 bi.bV5Compression = BI_BITFIELDS;
1251 bi.bV5RedMask = 0x00FF0000;
1252 bi.bV5GreenMask = 0x0000FF00;
1253 bi.bV5BlueMask = 0x000000FF;
1254 if (fHasAlpha)
1255 bi.bV5AlphaMask = 0xFF000000;
1256 else
1257 bi.bV5AlphaMask = 0;
1258
1259 HDC hdc = GetDC(NULL);
1260
1261 /* Create the DIB section with an alpha channel: */
1262 hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD) 0);
1263
1264 ReleaseDC(NULL, hdc);
1265
1266 HBITMAP hMonoBitmap = NULL;
1267 if (fHasAlpha)
1268 {
1269 /* Create an empty mask bitmap: */
1270 hMonoBitmap = CreateBitmap(uWidth, uHeight, 1, 1, NULL);
1271 }
1272 else
1273 {
1274 /* Word aligned AND mask. Will be allocated and created if necessary. */
1275 uint8_t *pu8AndMaskWordAligned = NULL;
1276
1277 /* Width in bytes of the original AND mask scan line. */
1278 uint32_t cbAndMaskScan = (uWidth + 7) / 8;
1279
1280 if (cbAndMaskScan & 1)
1281 {
1282 /* Original AND mask is not word aligned. */
1283
1284 /* Allocate memory for aligned AND mask. */
1285 pu8AndMaskWordAligned = (uint8_t *)RTMemTmpAllocZ((cbAndMaskScan + 1) * uHeight);
1286
1287 Assert(pu8AndMaskWordAligned);
1288
1289 if (pu8AndMaskWordAligned)
1290 {
1291 /* According to MSDN the padding bits must be 0.
1292 * Compute the bit mask to set padding bits to 0 in the last byte of original AND mask. */
1293 uint32_t u32PaddingBits = cbAndMaskScan * 8 - uWidth;
1294 Assert(u32PaddingBits < 8);
1295 uint8_t u8LastBytesPaddingMask = (uint8_t)(0xFF << u32PaddingBits);
1296
1297 Log(("u8LastBytesPaddingMask = %02X, aligned w = %d, width = %d, cbAndMaskScan = %d\n",
1298 u8LastBytesPaddingMask, (cbAndMaskScan + 1) * 8, uWidth, cbAndMaskScan));
1299
1300 uint8_t *src = (uint8_t *)srcAndMaskPtr;
1301 uint8_t *dst = pu8AndMaskWordAligned;
1302
1303 unsigned i;
1304 for (i = 0; i < uHeight; i++)
1305 {
1306 memcpy(dst, src, cbAndMaskScan);
1307
1308 dst[cbAndMaskScan - 1] &= u8LastBytesPaddingMask;
1309
1310 src += cbAndMaskScan;
1311 dst += cbAndMaskScan + 1;
1312 }
1313 }
1314 }
1315
1316 /* Create the AND mask bitmap: */
1317 hMonoBitmap = ::CreateBitmap(uWidth, uHeight, 1, 1,
1318 pu8AndMaskWordAligned? pu8AndMaskWordAligned: srcAndMaskPtr);
1319
1320 if (pu8AndMaskWordAligned)
1321 {
1322 RTMemTmpFree(pu8AndMaskWordAligned);
1323 }
1324 }
1325
1326 Assert(hBitmap);
1327 Assert(hMonoBitmap);
1328 if (hBitmap && hMonoBitmap)
1329 {
1330 DWORD *dstShapePtr = (DWORD *) lpBits;
1331
1332 for (uint y = 0; y < uHeight; y ++)
1333 {
1334 memcpy(dstShapePtr, srcShapePtr, srcShapePtrScan);
1335 srcShapePtr += srcShapePtrScan;
1336 dstShapePtr += uWidth;
1337 }
1338
1339 ICONINFO ii;
1340 ii.fIcon = FALSE;
1341 ii.xHotspot = uXHot;
1342 ii.yHotspot = uYHot;
1343 ii.hbmMask = hMonoBitmap;
1344 ii.hbmColor = hBitmap;
1345
1346 HCURSOR hAlphaCursor = CreateIconIndirect(&ii);
1347 Assert(hAlphaCursor);
1348 if (hAlphaCursor)
1349 {
1350 /* Set the new cursor: */
1351 m_cursor = QCursor(hAlphaCursor);
1352 if (m_alphaCursor)
1353 DestroyIcon(m_alphaCursor);
1354 m_alphaCursor = hAlphaCursor;
1355 m_fIsValidPointerShapePresent = true;
1356 }
1357 }
1358
1359 if (hMonoBitmap)
1360 DeleteObject(hMonoBitmap);
1361 if (hBitmap)
1362 DeleteObject(hBitmap);
1363
1364#elif defined (Q_WS_X11) && !defined (VBOX_WITHOUT_XCURSOR)
1365
1366 XcursorImage *img = XcursorImageCreate(uWidth, uHeight);
1367 Assert(img);
1368 if (img)
1369 {
1370 img->xhot = uXHot;
1371 img->yhot = uYHot;
1372
1373 XcursorPixel *dstShapePtr = img->pixels;
1374
1375 for (uint y = 0; y < uHeight; y ++)
1376 {
1377 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan);
1378
1379 if (!fHasAlpha)
1380 {
1381 /* Convert AND mask to the alpha channel: */
1382 uchar byte = 0;
1383 for (uint x = 0; x < uWidth; x ++)
1384 {
1385 if (!(x % 8))
1386 byte = *(srcAndMaskPtr ++);
1387 else
1388 byte <<= 1;
1389
1390 if (byte & 0x80)
1391 {
1392 /* Linux doesn't support inverted pixels (XOR ops,
1393 * to be exact) in cursor shapes, so we detect such
1394 * pixels and always replace them with black ones to
1395 * make them visible at least over light colors */
1396 if (dstShapePtr [x] & 0x00FFFFFF)
1397 dstShapePtr [x] = 0xFF000000;
1398 else
1399 dstShapePtr [x] = 0x00000000;
1400 }
1401 else
1402 dstShapePtr [x] |= 0xFF000000;
1403 }
1404 }
1405
1406 srcShapePtr += srcShapePtrScan;
1407 dstShapePtr += uWidth;
1408 }
1409
1410 /* Set the new cursor: */
1411 m_cursor = QCursor(XcursorImageLoadCursor(QX11Info::display(), img));
1412 m_fIsValidPointerShapePresent = true;
1413
1414 XcursorImageDestroy(img);
1415 }
1416
1417#elif defined(Q_WS_MAC)
1418
1419 /* Create a ARGB image out of the shape data. */
1420 QImage image (uWidth, uHeight, QImage::Format_ARGB32);
1421 const uint8_t* pbSrcMask = static_cast<const uint8_t*> (srcAndMaskPtr);
1422 unsigned cbSrcMaskLine = RT_ALIGN (uWidth, 8) / 8;
1423 for (unsigned int y = 0; y < uHeight; ++y)
1424 {
1425 for (unsigned int x = 0; x < uWidth; ++x)
1426 {
1427 unsigned int color = ((unsigned int*)srcShapePtr)[y*uWidth+x];
1428 /* If the alpha channel isn't in the shape data, we have to
1429 * create them from the and-mask. This is a bit field where 1
1430 * represent transparency & 0 opaque respectively. */
1431 if (!fHasAlpha)
1432 {
1433 if (!(pbSrcMask[x / 8] & (1 << (7 - (x % 8)))))
1434 color |= 0xff000000;
1435 else
1436 {
1437 /* This isn't quite right, but it's the best we can do I think... */
1438 if (color & 0x00ffffff)
1439 color = 0xff000000;
1440 else
1441 color = 0x00000000;
1442 }
1443 }
1444 image.setPixel (x, y, color);
1445 }
1446 /* Move one scanline forward. */
1447 pbSrcMask += cbSrcMaskLine;
1448 }
1449
1450 /* Set the new cursor: */
1451 m_cursor = QCursor(QPixmap::fromImage(image), uXHot, uYHot);
1452 m_fIsValidPointerShapePresent = true;
1453 NOREF(srcShapePtrScan);
1454
1455#else
1456
1457# warning "port me"
1458
1459#endif
1460}
1461
1462void UISession::reinitMenuPool()
1463{
1464 /* Get host: */
1465 const CHost &host = vboxGlobal().host();
1466
1467 /* Get uisession machine: */
1468 const CMachine &machine = session().GetConsole().GetMachine();
1469
1470 /* Storage stuff: */
1471 {
1472 /* Initialize CD/FD menus: */
1473 int iDevicesCountCD = 0;
1474 int iDevicesCountFD = 0;
1475 const CMediumAttachmentVector &attachments = machine.GetMediumAttachments();
1476 for (int i = 0; i < attachments.size(); ++i)
1477 {
1478 const CMediumAttachment &attachment = attachments[i];
1479 if (attachment.GetType() == KDeviceType_DVD)
1480 ++iDevicesCountCD;
1481 if (attachment.GetType() == KDeviceType_Floppy)
1482 ++iDevicesCountFD;
1483 }
1484 QAction *pOpticalDevicesMenu = gActionPool->action(UIActionIndexRuntime_Menu_OpticalDevices);
1485 QAction *pFloppyDevicesMenu = gActionPool->action(UIActionIndexRuntime_Menu_FloppyDevices);
1486 pOpticalDevicesMenu->setData(iDevicesCountCD);
1487 pOpticalDevicesMenu->setVisible(iDevicesCountCD);
1488 pFloppyDevicesMenu->setData(iDevicesCountFD);
1489 pFloppyDevicesMenu->setVisible(iDevicesCountFD);
1490 }
1491
1492 /* Network stuff: */
1493 {
1494 bool fAtLeastOneAdapterActive = false;
1495 ULONG uSlots = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3);
1496 for (ULONG uSlot = 0; uSlot < uSlots; ++uSlot)
1497 {
1498 const CNetworkAdapter &adapter = machine.GetNetworkAdapter(uSlot);
1499 if (adapter.GetEnabled())
1500 {
1501 fAtLeastOneAdapterActive = true;
1502 break;
1503 }
1504 }
1505
1506 /* Show/Hide Network Adapters action depending on overall adapters activity status: */
1507 gActionPool->action(UIActionIndexRuntime_Simple_NetworkSettings)->setVisible(fAtLeastOneAdapterActive);
1508 }
1509
1510 /* USB stuff: */
1511 {
1512 /* Check whether there is at least one OHCI USB controllers with an available proxy. */
1513 const CUSBDeviceFilters &filters = machine.GetUSBDeviceFilters();
1514 ULONG cOhciCtls = machine.GetUSBControllerCountByType(KUSBControllerType_OHCI);
1515 bool fUSBEnabled = !filters.isNull() && cOhciCtls && machine.GetUSBProxyAvailable();
1516
1517 /* Show/Hide USB menu depending on controller availability, activity and USB-proxy presence: */
1518 gActionPool->action(UIActionIndexRuntime_Menu_USBDevices)->setVisible(fUSBEnabled);
1519 }
1520
1521 /* WebCams stuff: */
1522 {
1523 /* Check whether there is an accessible video input devices pool: */
1524 const CHostVideoInputDeviceVector &webcams = host.GetVideoInputDevices(); Q_UNUSED(webcams);
1525 ULONG cOhciCtls = machine.GetUSBControllerCountByType(KUSBControllerType_OHCI);
1526 bool fWebCamsEnabled = host.isOk() && cOhciCtls;
1527
1528 /* Show/Hide WebCams menu depending on ExtPack availability: */
1529 gActionPool->action(UIActionIndexRuntime_Menu_WebCams)->setVisible(fWebCamsEnabled);
1530 }
1531}
1532
1533bool UISession::preparePowerUp()
1534{
1535 /* Notify user about mouse&keyboard auto-capturing: */
1536 if (vboxGlobal().settings().autoCapture())
1537 popupCenter().remindAboutAutoCapture(machineLogic()->activeMachineWindow());
1538
1539 /* Shows First Run wizard if necessary: */
1540 const CMachine &machine = session().GetMachine();
1541 /* Check if we are in teleportation waiting mode.
1542 * In that case no first run wizard is necessary. */
1543 m_machineState = machine.GetState();
1544 if ( isFirstTimeStarted()
1545 && !(( m_machineState == KMachineState_PoweredOff
1546 || m_machineState == KMachineState_Aborted
1547 || m_machineState == KMachineState_Teleported)
1548 && machine.GetTeleporterEnabled()))
1549 {
1550 UISafePointerWizard pWizard = new UIWizardFirstRun(mainMachineWindow(), session().GetMachine());
1551 pWizard->prepare();
1552 pWizard->exec();
1553 if (pWizard)
1554 delete pWizard;
1555 }
1556
1557#ifdef VBOX_WITH_NETFLT
1558
1559 /* Skip further checks if VM in saved state */
1560 if (isSaved())
1561 return true;
1562
1563 /* Make sure all the attached and enabled network
1564 * adapters are present on the host. This check makes sense
1565 * in two cases only - when attachement type is Bridged Network
1566 * or Host-only Interface. NOTE: Only currently enabled
1567 * attachement type is checked (incorrect parameters check for
1568 * currently disabled attachement types is skipped). */
1569 QStringList failedInterfaceNames;
1570 QStringList availableInterfaceNames;
1571
1572 /* Create host network interface names list */
1573 foreach (const CHostNetworkInterface &iface, vboxGlobal().host().GetNetworkInterfaces())
1574 {
1575 availableInterfaceNames << iface.GetName();
1576 availableInterfaceNames << iface.GetShortName();
1577 }
1578
1579 ulong cCount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine.GetChipsetType());
1580 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
1581 {
1582 CNetworkAdapter na = machine.GetNetworkAdapter(uAdapterIndex);
1583
1584 if (na.GetEnabled())
1585 {
1586 QString strIfName = QString();
1587
1588 /* Get physical network interface name for currently
1589 * enabled network attachement type */
1590 switch (na.GetAttachmentType())
1591 {
1592 case KNetworkAttachmentType_Bridged:
1593 strIfName = na.GetBridgedInterface();
1594 break;
1595 case KNetworkAttachmentType_HostOnly:
1596 strIfName = na.GetHostOnlyInterface();
1597 break;
1598 }
1599
1600 if (!strIfName.isEmpty() &&
1601 !availableInterfaceNames.contains(strIfName))
1602 {
1603 LogFlow(("Found invalid network interface: %s\n", strIfName.toStdString().c_str()));
1604 failedInterfaceNames << QString("%1 (adapter %2)").arg(strIfName).arg(uAdapterIndex + 1);
1605 }
1606 }
1607 }
1608
1609 /* Check if non-existent interfaces found */
1610 if (!failedInterfaceNames.isEmpty())
1611 {
1612 if (msgCenter().UIMessageCenter::cannotStartWithoutNetworkIf(machine.GetName(), failedInterfaceNames.join(", ")))
1613 machineLogic()->openNetworkAdaptersDialog();
1614 else
1615 {
1616 closeRuntimeUI();
1617 return false;
1618 }
1619 }
1620
1621#endif
1622
1623 return true;
1624}
1625
1626bool UISession::isScreenVisible(ulong uScreenId) const
1627{
1628 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1629 return m_monitorVisibilityVector.value((int)uScreenId, false);
1630}
1631
1632void UISession::setScreenVisible(ulong uScreenId, bool fIsMonitorVisible)
1633{
1634 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1635 if (uScreenId < (ulong)m_monitorVisibilityVector.size())
1636 m_monitorVisibilityVector[(int)uScreenId] = fIsMonitorVisible;
1637}
1638
1639int UISession::countOfVisibleWindows()
1640{
1641 int cCountOfVisibleWindows = 0;
1642 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
1643 if (m_monitorVisibilityVector[i])
1644 ++cCountOfVisibleWindows;
1645 return cCountOfVisibleWindows;
1646}
1647
1648UIFrameBuffer* UISession::frameBuffer(ulong uScreenId) const
1649{
1650 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1651 return m_frameBufferVector.value((int)uScreenId, 0);
1652}
1653
1654void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer* pFrameBuffer)
1655{
1656 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1657 if (uScreenId < (ulong)m_frameBufferVector.size())
1658 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
1659}
1660
1661#ifdef Q_WS_MAC
1662/** MacOS X: Recaches display-configuration data. */
1663void UISession::recacheDisplayData()
1664{
1665 /* Recache display data: */
1666 m_screens.clear();
1667 QDesktopWidget *pDesktop = QApplication::desktop();
1668 for (int iScreenIndex = 0; iScreenIndex < pDesktop->screenCount(); ++iScreenIndex)
1669 m_screens << pDesktop->screenGeometry(iScreenIndex);
1670}
1671#endif /* Q_WS_MAC */
1672
1673#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
1674/**
1675 * Custom signal handler. When switching VTs, we might not get release events
1676 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
1677 * be saved with modifier keys stuck. This is annoying enough for introducing
1678 * this hack.
1679 */
1680/* static */
1681void UISession::signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
1682{
1683 /* only SIGUSR1 is interesting */
1684 if (sig == SIGUSR1)
1685 if (UIMachine *pMachine = vboxGlobal().virtualMachine())
1686 pMachine->uisession()->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
1687}
1688#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
1689
Note: See TracBrowser for help on using the repository browser.

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