VirtualBox

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

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

FE/Qt: Runtime UI: Reworking frame-buffer synchronization logic.

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