VirtualBox

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

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

FE/Qt: 7037: Runtime UI: One more fix related to r90326.

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