VirtualBox

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

Last change on this file since 43138 was 43138, checked in by vboxsync, 13 years ago

BUGZ:3965 Allow user to change network configuration on VM start if any of involved physical network interfaces missing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.0 KB
Line 
1/* $Id: UISession.cpp 43138 2012-08-31 13:26:04Z 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 <QNetworkInterface>
23#include <QWidget>
24#include <QTimer>
25
26/* GUI includes: */
27#include "VBoxGlobal.h"
28#include "UISession.h"
29#include "UIMachine.h"
30#include "UIActionPoolRuntime.h"
31#include "UIMachineLogic.h"
32#include "UIMachineWindow.h"
33#include "UIMachineMenuBar.h"
34#include "UIMessageCenter.h"
35#include "UIWizardFirstRun.h"
36#include "UIConsoleEventHandler.h"
37#include "UIFrameBuffer.h"
38#ifdef VBOX_WITH_VIDEOHWACCEL
39# include "VBoxFBOverlay.h"
40#endif /* VBOX_WITH_VIDEOHWACCEL */
41
42#ifdef Q_WS_X11
43# include <QX11Info>
44# include <X11/Xlib.h>
45# include <X11/Xutil.h>
46# ifndef VBOX_WITHOUT_XCURSOR
47# include <X11/Xcursor/Xcursor.h>
48# endif /* VBOX_WITHOUT_XCURSOR */
49#endif /* Q_WS_X11 */
50
51#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
52# include "UIKeyboardHandler.h"
53# include <signal.h>
54#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
55
56/* COM includes: */
57#include "CConsole.h"
58#include "CSystemProperties.h"
59#include "CMachineDebugger.h"
60#include "CGuest.h"
61#include "CStorageController.h"
62#include "CMediumAttachment.h"
63#include "CDisplay.h"
64#include "CFramebuffer.h"
65#include "CNetworkAdapter.h"
66#include "CVRDEServer.h"
67#include "CUSBController.h"
68
69UISession::UISession(UIMachine *pMachine, CSession &sessionReference)
70 : QObject(pMachine)
71 /* Base variables: */
72 , m_pMachine(pMachine)
73 , m_session(sessionReference)
74 /* Common variables: */
75 , m_pMenuPool(0)
76 , m_machineState(session().GetMachine().GetState())
77#ifdef Q_WS_WIN
78 , m_alphaCursor(0)
79#endif /* Q_WS_WIN */
80 /* Common flags: */
81 , m_fIsFirstTimeStarted(false)
82 , m_fIsIgnoreRuntimeMediumsChanging(false)
83 , m_fIsGuestResizeIgnored(false)
84 , m_fIsSeamlessModeRequested(false)
85 , m_fIsAutoCaptureDisabled(false)
86 /* Guest additions flags: */
87 , m_ulGuestAdditionsRunLevel(0)
88 , m_fIsGuestSupportsGraphics(false)
89 , m_fIsGuestSupportsSeamless(false)
90 /* Mouse flags: */
91 , m_fNumLock(false)
92 , m_fCapsLock(false)
93 , m_fScrollLock(false)
94 , m_uNumLockAdaptionCnt(2)
95 , m_uCapsLockAdaptionCnt(2)
96 /* Mouse flags: */
97 , m_fIsMouseSupportsAbsolute(false)
98 , m_fIsMouseSupportsRelative(false)
99 , m_fIsMouseHostCursorNeeded(false)
100 , m_fIsMouseCaptured(false)
101 , m_fIsMouseIntegrated(true)
102 , m_fIsValidPointerShapePresent(false)
103 , m_fIsHidingHostPointer(true)
104{
105 /* Prepare console event-handlers: */
106 prepareConsoleEventHandlers();
107
108 /* Prepare screens: */
109 prepareScreens();
110
111 /* Prepare framebuffers: */
112 prepareFramebuffers();
113
114 /* Prepare main-menu: */
115 prepareMenuPool();
116
117 /* Load settings: */
118 loadSessionSettings();
119
120#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
121 struct sigaction sa;
122 sa.sa_sigaction = &signalHandlerSIGUSR1;
123 sigemptyset(&sa.sa_mask);
124 sa.sa_flags = SA_RESTART | SA_SIGINFO;
125 sigaction(SIGUSR1, &sa, NULL);
126#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
127}
128
129UISession::~UISession()
130{
131 /* Save settings: */
132 saveSessionSettings();
133
134 /* Cleanup main-menu: */
135 cleanupMenuPool();
136
137 /* Cleanup framebuffers: */
138 cleanupFramebuffers();
139
140 /* Cleanup console event-handlers: */
141 cleanupConsoleEventHandlers();
142
143#ifdef Q_WS_WIN
144 /* Destroy alpha cursor: */
145 if (m_alphaCursor)
146 DestroyIcon(m_alphaCursor);
147#endif /* Q_WS_WIN */
148}
149
150void UISession::powerUp()
151{
152 /* Do nothing if we had started already: */
153 if (isRunning() || isPaused())
154 return;
155
156 /* Prepare powerup: */
157 bool fPrepared = preparePowerUp();
158 if (!fPrepared)
159 return;
160
161 /* Get current machine/console: */
162 CMachine machine = session().GetMachine();
163 CConsole console = session().GetConsole();
164
165 /* Apply debug settings from the command line. */
166 CMachineDebugger debugger = console.GetDebugger();
167 if (debugger.isOk())
168 {
169 if (vboxGlobal().isPatmDisabled())
170 debugger.SetPATMEnabled(false);
171 if (vboxGlobal().isCsamDisabled())
172 debugger.SetCSAMEnabled(false);
173 if (vboxGlobal().isSupervisorCodeExecedRecompiled())
174 debugger.SetRecompileSupervisor(true);
175 if (vboxGlobal().isUserCodeExecedRecompiled())
176 debugger.SetRecompileUser(true);
177 if (!vboxGlobal().isDefaultWarpPct())
178 debugger.SetVirtualTimeRate(vboxGlobal().getWarpPct());
179 }
180
181 /* Power UP machine: */
182 CProgress progress = vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled(machine) ?
183 console.PowerUpPaused() : console.PowerUp();
184
185 /* Check for immediate failure: */
186 if (!console.isOk())
187 {
188 if (vboxGlobal().showStartVMErrors())
189 msgCenter().cannotStartMachine(console);
190 QTimer::singleShot(0, this, SLOT(sltCloseVirtualSession()));
191 return;
192 }
193
194 /* Guard progressbar warnings from auto-closing: */
195 if (uimachine()->machineLogic())
196 uimachine()->machineLogic()->setPreventAutoClose(true);
197
198 /* Show "Starting/Restoring" progress dialog: */
199 if (isSaved())
200 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_restore_90px.png", mainMachineWindow(), true, 0);
201 else
202 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_start_90px.png", mainMachineWindow(), true);
203
204 /* Check for a progress failure: */
205 if (progress.GetResultCode() != 0)
206 {
207 if (vboxGlobal().showStartVMErrors())
208 msgCenter().cannotStartMachine(progress);
209 QTimer::singleShot(0, this, SLOT(sltCloseVirtualSession()));
210 return;
211 }
212
213 /* Allow further auto-closing: */
214 if (uimachine()->machineLogic())
215 uimachine()->machineLogic()->setPreventAutoClose(false);
216
217 /* Check if we missed a really quick termination after successful startup, and process it if we did: */
218 if (isTurnedOff())
219 {
220 QTimer::singleShot(0, this, SLOT(sltCloseVirtualSession()));
221 return;
222 }
223
224 /* Check if the required virtualization features are active. We get this
225 * info only when the session is active. */
226 bool fIs64BitsGuest = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetIs64Bit();
227 bool fRecommendVirtEx = vboxGlobal().virtualBox().GetGuestOSType(console.GetGuest().GetOSTypeId()).GetRecommendedVirtEx();
228 AssertMsg(!fIs64BitsGuest || fRecommendVirtEx, ("Virtualization support missed for 64bit guest!\n"));
229 bool fIsVirtEnabled = console.GetDebugger().GetHWVirtExEnabled();
230 if (fRecommendVirtEx && !fIsVirtEnabled)
231 {
232 bool fShouldWeClose;
233
234 bool fVTxAMDVSupported = vboxGlobal().host().GetProcessorFeature(KProcessorFeature_HWVirtEx);
235
236 QApplication::processEvents();
237 setPause(true);
238
239 if (fIs64BitsGuest)
240 fShouldWeClose = msgCenter().warnAboutVirtNotEnabled64BitsGuest(fVTxAMDVSupported);
241 else
242 fShouldWeClose = msgCenter().warnAboutVirtNotEnabledGuestRequired(fVTxAMDVSupported);
243
244 if (fShouldWeClose)
245 {
246 /* At this point the console is powered up. So we have to close
247 * this session again. */
248 CProgress progress = console.PowerDown();
249 if (console.isOk())
250 {
251 /* Guard progressbar warnings from auto-closing: */
252 if (uimachine()->machineLogic())
253 uimachine()->machineLogic()->setPreventAutoClose(true);
254 /* Show the power down progress dialog */
255 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_poweroff_90px.png", mainMachineWindow(), true);
256 if (progress.GetResultCode() != 0)
257 msgCenter().cannotStopMachine(progress);
258 /* Allow further auto-closing: */
259 if (uimachine()->machineLogic())
260 uimachine()->machineLogic()->setPreventAutoClose(false);
261 }
262 else
263 msgCenter().cannotStopMachine(console);
264 /* Now signal the destruction of the rest. */
265 QTimer::singleShot(0, this, SLOT(sltCloseVirtualSession()));
266 return;
267 }
268
269 setPause(false);
270 }
271
272#ifdef VBOX_WITH_VIDEOHWACCEL
273 LogRel(("2D video acceleration is %s.\n",
274 machine.GetAccelerate2DVideoEnabled() && VBoxGlobal::isAcceleration2DVideoAvailable()
275 ? "enabled"
276 : "disabled"));
277#endif
278
279#ifdef VBOX_GUI_WITH_PIDFILE
280 vboxGlobal().createPidfile();
281#endif
282
283 /* Warn listeners about machine was started: */
284 emit sigMachineStarted();
285}
286
287UIMachineLogic* UISession::machineLogic() const
288{
289 return uimachine()->machineLogic();
290}
291
292QWidget* UISession::mainMachineWindow() const
293{
294 return machineLogic()->mainMachineWindow();
295}
296
297QMenu* UISession::newMenu(UIMainMenuType fOptions /* = UIMainMenuType_ALL */)
298{
299 /* Create new menu: */
300 QMenu *pMenu = m_pMenuPool->createMenu(fOptions);
301
302 /* Re-init menu pool for the case menu were recreated: */
303 reinitMenuPool();
304
305 /* Return newly created menu: */
306 return pMenu;
307}
308
309QMenuBar* UISession::newMenuBar(UIMainMenuType fOptions /* = UIMainMenuType_ALL */)
310{
311 /* Create new menubar: */
312 QMenuBar *pMenuBar = m_pMenuPool->createMenuBar(fOptions);
313
314 /* Re-init menu pool for the case menu were recreated: */
315 reinitMenuPool();
316
317 /* Return newly created menubar: */
318 return pMenuBar;
319}
320
321bool UISession::setPause(bool fOn)
322{
323 CConsole console = session().GetConsole();
324
325 if (fOn)
326 console.Pause();
327 else
328 console.Resume();
329
330 bool ok = console.isOk();
331 if (!ok)
332 {
333 if (fOn)
334 msgCenter().cannotPauseMachine(console);
335 else
336 msgCenter().cannotResumeMachine(console);
337 }
338
339 return ok;
340}
341
342void UISession::sltInstallGuestAdditionsFrom(const QString &strSource)
343{
344 CMachine machine = session().GetMachine();
345 CVirtualBox vbox = vboxGlobal().virtualBox();
346
347 /*
348 * Flag indicating whether we want to do the usual .ISO mounting or not.
349 * First try updating the Guest Additions directly without mounting the .ISO.
350 */
351 bool fDoMount = false;
352 /* Auto-update in GUI currently is disabled. */
353#ifndef VBOX_WITH_ADDITIONS_AUTOUPDATE_UI
354 fDoMount = true;
355#else
356 CGuest guest = session().GetConsole().GetGuest();
357 QVector<KAdditionsUpdateFlag> flagsUpdate;
358 CProgress progressInstall = guest.UpdateGuestAdditions(strSource, flagsUpdate);
359 bool fResult = guest.isOk();
360 if (fResult)
361 {
362 msgCenter().showModalProgressDialog(progressInstall, tr("Updating Guest Additions"), ":/progress_install_guest_additions_90px.png",
363 mainMachineWindow(), true, 500 /* 500ms delay. */);
364 if (progressInstall.GetCanceled())
365 return;
366
367 HRESULT rc = progressInstall.GetResultCode();
368 if (!progressInstall.isOk() || rc != S_OK)
369 {
370 /* If we got back a VBOX_E_NOT_SUPPORTED we don't complain (guest OS
371 * simply isn't supported yet), so silently fall back to "old" .ISO
372 * mounting method. */
373 if ( !SUCCEEDED_WARNING(rc)
374 && rc != VBOX_E_NOT_SUPPORTED)
375 {
376 msgCenter().cannotUpdateGuestAdditions(progressInstall, mainMachineWindow());
377
378 /* Log the error message in the release log. */
379 QString strErr = progressInstall.GetErrorInfo().GetText();
380 if (!strErr.isEmpty())
381 LogRel(("%s\n", strErr.toLatin1().constData()));
382 }
383 fDoMount = true; /* Since automatic updating failed, fall back to .ISO mounting. */
384 }
385 }
386#endif /* VBOX_WITH_ADDITIONS_AUTOUPDATE_UI */
387
388 if (fDoMount) /* Fallback to only mounting the .ISO file. */
389 {
390 QString strUuid;
391 CMedium image = vbox.OpenMedium(strSource, KDeviceType_DVD, KAccessMode_ReadWrite, false /* fForceNewUuid */);
392 if (image.isNull())
393 {
394 image = vbox.OpenMedium(strSource, KDeviceType_DVD, KAccessMode_ReadWrite, false /* fForceNewUuid */);
395 if (vbox.isOk())
396 strUuid = image.GetId();
397 }
398 else
399 strUuid = image.GetId();
400
401 if (!vbox.isOk())
402 {
403 msgCenter().cannotOpenMedium(0, vbox, UIMediumType_DVD, strSource);
404 return;
405 }
406
407 AssertMsg(!strUuid.isNull(), ("Guest Additions image UUID should be valid!\n"));
408
409 QString strCntName;
410 LONG iCntPort = -1, iCntDevice = -1;
411 /* Searching for the first suitable slot */
412 {
413 CStorageControllerVector controllers = machine.GetStorageControllers();
414 int i = 0;
415 while (i < controllers.size() && strCntName.isNull())
416 {
417 CStorageController controller = controllers[i];
418 CMediumAttachmentVector attachments = machine.GetMediumAttachmentsOfController(controller.GetName());
419 int j = 0;
420 while (j < attachments.size() && strCntName.isNull())
421 {
422 CMediumAttachment attachment = attachments[j];
423 if (attachment.GetType() == KDeviceType_DVD)
424 {
425 strCntName = controller.GetName();
426 iCntPort = attachment.GetPort();
427 iCntDevice = attachment.GetDevice();
428 }
429 ++ j;
430 }
431 ++ i;
432 }
433 }
434
435 if (!strCntName.isNull())
436 {
437 /* Create a new UIMedium: */
438 UIMedium vboxMedium(image, UIMediumType_DVD, KMediumState_Created);
439 /* Register it in GUI internal list: */
440 vboxGlobal().addMedium(vboxMedium);
441
442 /* Mount medium to the predefined port/device: */
443 machine.MountMedium(strCntName, iCntPort, iCntDevice, vboxMedium.medium(), false /* force */);
444 if (!machine.isOk())
445 {
446 /* Ask for force mounting: */
447 if (msgCenter().cannotRemountMedium(0, machine, vboxMedium, true /* mount? */, true /* retry? */) == QIMessageBox::Ok)
448 {
449 /* Force mount medium to the predefined port/device: */
450 machine.MountMedium(strCntName, iCntPort, iCntDevice, vboxMedium.medium(), true /* force */);
451 if (!machine.isOk())
452 msgCenter().cannotRemountMedium(0, machine, vboxMedium, true /* mount? */, false /* retry? */);
453 }
454 }
455 }
456 else
457 msgCenter().cannotMountGuestAdditions(machine.GetName());
458 }
459}
460
461void UISession::sltCloseVirtualSession()
462{
463 /* First, we have to close/hide any opened modal & popup application widgets.
464 * We have to make sure such window is hidden even if close-event was rejected.
465 * We are re-throwing this slot if any widget present to test again.
466 * If all opened widgets are closed/hidden, we can try to close machine-window: */
467 QWidget *pWidget = QApplication::activeModalWidget() ? QApplication::activeModalWidget() :
468 QApplication::activePopupWidget() ? QApplication::activePopupWidget() : 0;
469 if (pWidget)
470 {
471 /* Closing/hiding all we found: */
472 pWidget->close();
473 if (!pWidget->isHidden())
474 pWidget->hide();
475 QTimer::singleShot(0, this, SLOT(sltCloseVirtualSession()));
476 return;
477 }
478
479 /* Recursively close all the opened warnings... */
480 if (msgCenter().isAnyWarningShown())
481 {
482 msgCenter().closeAllWarnings();
483 QTimer::singleShot(0, this, SLOT(sltCloseVirtualSession()));
484 return;
485 }
486
487 /* Finally, ask for closing virtual machine: */
488 QTimer::singleShot(0, m_pMachine, SLOT(sltCloseVirtualMachine()));
489}
490
491void UISession::sltMousePointerShapeChange(bool fVisible, bool fAlpha, QPoint hotCorner, QSize size, QVector<uint8_t> shape)
492{
493 /* In case of shape data is present: */
494 if (shape.size() > 0)
495 {
496 /* We are ignoring visibility flag: */
497 m_fIsHidingHostPointer = false;
498
499 /* And updating current cursor shape: */
500 setPointerShape(shape.data(), fAlpha,
501 hotCorner.x(), hotCorner.y(),
502 size.width(), size.height());
503 }
504 /* In case of shape data is NOT present: */
505 else
506 {
507 /* Remember if we should hide the cursor: */
508 m_fIsHidingHostPointer = !fVisible;
509 }
510
511 /* Notify listeners about mouse capability changed: */
512 emit sigMousePointerShapeChange();
513
514}
515
516void UISession::sltMouseCapabilityChange(bool fSupportsAbsolute, bool fSupportsRelative, bool fNeedsHostCursor)
517{
518 /* Check if something had changed: */
519 if ( m_fIsMouseSupportsAbsolute != fSupportsAbsolute
520 || m_fIsMouseSupportsRelative != fSupportsRelative
521 || m_fIsMouseHostCursorNeeded != fNeedsHostCursor)
522 {
523 /* Store new data: */
524 m_fIsMouseSupportsAbsolute = fSupportsAbsolute;
525 m_fIsMouseSupportsRelative = fSupportsRelative;
526 m_fIsMouseHostCursorNeeded = fNeedsHostCursor;
527
528 /* Notify listeners about mouse capability changed: */
529 emit sigMouseCapabilityChange();
530 }
531}
532
533void UISession::sltKeyboardLedsChangeEvent(bool fNumLock, bool fCapsLock, bool fScrollLock)
534{
535 /* Check if something had changed: */
536 if ( m_fNumLock != fNumLock
537 || m_fCapsLock != fCapsLock
538 || m_fScrollLock != fScrollLock)
539 {
540 /* Store new num lock data: */
541 if (m_fNumLock != fNumLock)
542 {
543 m_fNumLock = fNumLock;
544 m_uNumLockAdaptionCnt = 2;
545 }
546
547 /* Store new caps lock data: */
548 if (m_fCapsLock != fCapsLock)
549 {
550 m_fCapsLock = fCapsLock;
551 m_uCapsLockAdaptionCnt = 2;
552 }
553
554 /* Store new scroll lock data: */
555 if (m_fScrollLock != fScrollLock)
556 {
557 m_fScrollLock = fScrollLock;
558 }
559
560 /* Notify listeners about mouse capability changed: */
561 emit sigKeyboardLedsChange();
562 }
563}
564
565void UISession::sltStateChange(KMachineState state)
566{
567 /* Check if something had changed: */
568 if (m_machineState != state)
569 {
570 /* Store new data: */
571 m_machineState = state;
572
573 /* Notify listeners about machine state changed: */
574 emit sigMachineStateChange();
575 }
576}
577
578void UISession::sltVRDEChange()
579{
580 /* Get machine: */
581 const CMachine &machine = session().GetMachine();
582 /* Get VRDE server: */
583 const CVRDEServer &server = machine.GetVRDEServer();
584 bool fIsVRDEServerAvailable = !server.isNull();
585 /* Show/Hide VRDE action depending on VRDE server availability status: */
586 gActionPool->action(UIActionIndexRuntime_Toggle_VRDEServer)->setVisible(fIsVRDEServerAvailable);
587 /* Check/Uncheck VRDE action depending on VRDE server activity status: */
588 if (fIsVRDEServerAvailable)
589 gActionPool->action(UIActionIndexRuntime_Toggle_VRDEServer)->setChecked(server.GetEnabled());
590 /* Notify listeners about VRDE change: */
591 emit sigVRDEChange();
592}
593
594void UISession::sltAdditionsChange()
595{
596 /* Get our guest: */
597 CGuest guest = session().GetConsole().GetGuest();
598
599 /* Variable flags: */
600 ULONG ulGuestAdditionsRunLevel = guest.GetAdditionsRunLevel();
601 LONG64 lLastUpdatedIgnored;
602 bool fIsGuestSupportsGraphics = guest.GetFacilityStatus(KAdditionsFacilityType_Graphics, lLastUpdatedIgnored)
603 == KAdditionsFacilityStatus_Active;
604 bool fIsGuestSupportsSeamless = guest.GetFacilityStatus(KAdditionsFacilityType_Seamless, lLastUpdatedIgnored)
605 == KAdditionsFacilityStatus_Active;
606 /* Check if something had changed: */
607 if (m_ulGuestAdditionsRunLevel != ulGuestAdditionsRunLevel ||
608 m_fIsGuestSupportsGraphics != fIsGuestSupportsGraphics ||
609 m_fIsGuestSupportsSeamless != fIsGuestSupportsSeamless)
610 {
611 /* Store new data: */
612 m_ulGuestAdditionsRunLevel = ulGuestAdditionsRunLevel;
613 m_fIsGuestSupportsGraphics = fIsGuestSupportsGraphics;
614 m_fIsGuestSupportsSeamless = fIsGuestSupportsSeamless;
615
616 /* Notify listeners about guest additions state changed: */
617 emit sigAdditionsStateChange();
618 }
619}
620
621void UISession::prepareConsoleEventHandlers()
622{
623 /* Initialize console event-handler: */
624 UIConsoleEventHandler::instance(this);
625
626 /* Add console event connections: */
627 connect(gConsoleEvents, SIGNAL(sigMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)),
628 this, SLOT(sltMousePointerShapeChange(bool, bool, QPoint, QSize, QVector<uint8_t>)));
629
630 connect(gConsoleEvents, SIGNAL(sigMouseCapabilityChange(bool, bool, bool)),
631 this, SLOT(sltMouseCapabilityChange(bool, bool, bool)));
632
633 connect(gConsoleEvents, SIGNAL(sigKeyboardLedsChangeEvent(bool, bool, bool)),
634 this, SLOT(sltKeyboardLedsChangeEvent(bool, bool, bool)));
635
636 connect(gConsoleEvents, SIGNAL(sigStateChange(KMachineState)),
637 this, SLOT(sltStateChange(KMachineState)));
638
639 connect(gConsoleEvents, SIGNAL(sigAdditionsChange()),
640 this, SLOT(sltAdditionsChange()));
641
642 connect(gConsoleEvents, SIGNAL(sigVRDEChange()),
643 this, SLOT(sltVRDEChange()));
644
645 connect(gConsoleEvents, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)),
646 this, SIGNAL(sigNetworkAdapterChange(CNetworkAdapter)));
647
648 connect(gConsoleEvents, SIGNAL(sigMediumChange(CMediumAttachment)),
649 this, SIGNAL(sigMediumChange(CMediumAttachment)));
650
651 connect(gConsoleEvents, SIGNAL(sigUSBControllerChange()),
652 this, SIGNAL(sigUSBControllerChange()));
653
654 connect(gConsoleEvents, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)),
655 this, SIGNAL(sigUSBDeviceStateChange(CUSBDevice, bool, CVirtualBoxErrorInfo)));
656
657 connect(gConsoleEvents, SIGNAL(sigSharedFolderChange()),
658 this, SIGNAL(sigSharedFolderChange()));
659
660 connect(gConsoleEvents, SIGNAL(sigRuntimeError(bool, QString, QString)),
661 this, SIGNAL(sigRuntimeError(bool, QString, QString)));
662
663#ifdef Q_WS_MAC
664 connect(gConsoleEvents, SIGNAL(sigShowWindow()),
665 this, SIGNAL(sigShowWindows()), Qt::QueuedConnection);
666#endif /* Q_WS_MAC */
667
668 connect(gConsoleEvents, SIGNAL(sigCPUExecutionCapChange()),
669 this, SIGNAL(sigCPUExecutionCapChange()));
670
671 connect(gConsoleEvents, SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)),
672 this, SIGNAL(sigGuestMonitorChange(KGuestMonitorChangedEventType, ulong, QRect)));
673}
674
675void UISession::prepareScreens()
676{
677 /* Get machine: */
678 CMachine machine = m_session.GetMachine();
679
680 /* Prepare initial screen visibility status: */
681 m_monitorVisibilityVector.resize(machine.GetMonitorCount());
682 m_monitorVisibilityVector.fill(false);
683 m_monitorVisibilityVector[0] = true;
684
685 /* If machine is in 'saved' state: */
686 if (isSaved())
687 {
688 /* Update screen visibility status from saved-state: */
689 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
690 {
691 BOOL fEnabled = true;
692 ULONG guestOriginX = 0, guestOriginY = 0, guestWidth = 0, guestHeight = 0;
693 machine.QuerySavedGuestScreenInfo(i, guestOriginX, guestOriginY, guestWidth, guestHeight, fEnabled);
694 m_monitorVisibilityVector[i] = fEnabled;
695 }
696 /* And make sure at least one of them is visible (primary if others are hidden): */
697 if (countOfVisibleWindows() < 1)
698 m_monitorVisibilityVector[0] = true;
699 }
700}
701
702void UISession::prepareFramebuffers()
703{
704 /* Each framebuffer will be really prepared on first UIMachineView creation: */
705 m_frameBufferVector.resize(m_session.GetMachine().GetMonitorCount());
706}
707
708void UISession::prepareMenuPool()
709{
710 m_pMenuPool = new UIMachineMenuBar;
711}
712
713void UISession::loadSessionSettings()
714{
715 /* Get uisession machine: */
716 CMachine machine = session().GetConsole().GetMachine();
717
718 /* Load extra-data settings: */
719 {
720 /* Temporary: */
721 QString strSettings;
722
723 /* Is there should be First RUN Wizard? */
724 strSettings = machine.GetExtraData(GUI_FirstRun);
725 if (strSettings == "yes")
726 m_fIsFirstTimeStarted = true;
727
728 /* Ignore mediums mounted at runtime? */
729 strSettings = machine.GetExtraData(GUI_SaveMountedAtRuntime);
730 if (strSettings == "no")
731 m_fIsIgnoreRuntimeMediumsChanging = true;
732
733 /* Should guest autoresize? */
734 strSettings = machine.GetExtraData(GUI_AutoresizeGuest);
735 QAction *pGuestAutoresizeSwitch = gActionPool->action(UIActionIndexRuntime_Toggle_GuestAutoresize);
736 pGuestAutoresizeSwitch->setChecked(strSettings != "off");
737
738#if 0 /* Disabled for now! */
739# ifdef Q_WS_WIN
740 /* Disable host screen-saver if requested: */
741 if (vboxGlobal().settings().hostScreenSaverDisabled())
742 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, false, 0, 0);
743# endif /* Q_WS_WIN */
744#endif
745 }
746}
747
748void UISession::saveSessionSettings()
749{
750 /* Get uisession machine: */
751 CMachine machine = session().GetConsole().GetMachine();
752
753 /* Save extra-data settings: */
754 {
755 /* Disable First RUN Wizard for the since now: */
756 machine.SetExtraData(GUI_FirstRun, QString());
757
758 /* Remember if guest should autoresize: */
759 machine.SetExtraData(GUI_AutoresizeGuest,
760 gActionPool->action(UIActionIndexRuntime_Toggle_GuestAutoresize)->isChecked() ?
761 QString() : "off");
762
763#if 0 /* Disabled for now! */
764# ifdef Q_WS_WIN
765 /* Restore screen-saver activity to system default: */
766 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, true, 0, 0);
767# endif /* Q_WS_WIN */
768#endif
769 }
770}
771
772void UISession::cleanupMenuPool()
773{
774 delete m_pMenuPool;
775 m_pMenuPool = 0;
776}
777
778void UISession::cleanupFramebuffers()
779{
780 /* Cleanup framebuffers finally: */
781 for (int i = m_frameBufferVector.size() - 1; i >= 0; --i)
782 {
783 UIFrameBuffer *pFb = m_frameBufferVector[i];
784 if (pFb)
785 {
786 /* Warn framebuffer about its no more necessary: */
787 pFb->setDeleted(true);
788 /* Detach framebuffer from Display: */
789 CDisplay display = session().GetConsole().GetDisplay();
790 display.SetFramebuffer(i, CFramebuffer(NULL));
791 /* Release the reference: */
792 pFb->Release();
793 }
794 }
795 m_frameBufferVector.clear();
796}
797
798void UISession::cleanupConsoleEventHandlers()
799{
800 /* Destroy console event-handler: */
801 UIConsoleEventHandler::destroy();
802}
803
804WId UISession::winId() const
805{
806 return mainMachineWindow()->winId();
807}
808
809void UISession::setPointerShape(const uchar *pShapeData, bool fHasAlpha,
810 uint uXHot, uint uYHot, uint uWidth, uint uHeight)
811{
812 AssertMsg(pShapeData, ("Shape data must not be NULL!\n"));
813
814 m_fIsValidPointerShapePresent = false;
815 const uchar *srcAndMaskPtr = pShapeData;
816 uint andMaskSize = (uWidth + 7) / 8 * uHeight;
817 const uchar *srcShapePtr = pShapeData + ((andMaskSize + 3) & ~3);
818 uint srcShapePtrScan = uWidth * 4;
819
820#if defined (Q_WS_WIN)
821
822 BITMAPV5HEADER bi;
823 HBITMAP hBitmap;
824 void *lpBits;
825
826 ::ZeroMemory(&bi, sizeof (BITMAPV5HEADER));
827 bi.bV5Size = sizeof(BITMAPV5HEADER);
828 bi.bV5Width = uWidth;
829 bi.bV5Height = - (LONG)uHeight;
830 bi.bV5Planes = 1;
831 bi.bV5BitCount = 32;
832 bi.bV5Compression = BI_BITFIELDS;
833 bi.bV5RedMask = 0x00FF0000;
834 bi.bV5GreenMask = 0x0000FF00;
835 bi.bV5BlueMask = 0x000000FF;
836 if (fHasAlpha)
837 bi.bV5AlphaMask = 0xFF000000;
838 else
839 bi.bV5AlphaMask = 0;
840
841 HDC hdc = GetDC(NULL);
842
843 /* Create the DIB section with an alpha channel: */
844 hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD) 0);
845
846 ReleaseDC(NULL, hdc);
847
848 HBITMAP hMonoBitmap = NULL;
849 if (fHasAlpha)
850 {
851 /* Create an empty mask bitmap: */
852 hMonoBitmap = CreateBitmap(uWidth, uHeight, 1, 1, NULL);
853 }
854 else
855 {
856 /* Word aligned AND mask. Will be allocated and created if necessary. */
857 uint8_t *pu8AndMaskWordAligned = NULL;
858
859 /* Width in bytes of the original AND mask scan line. */
860 uint32_t cbAndMaskScan = (uWidth + 7) / 8;
861
862 if (cbAndMaskScan & 1)
863 {
864 /* Original AND mask is not word aligned. */
865
866 /* Allocate memory for aligned AND mask. */
867 pu8AndMaskWordAligned = (uint8_t *)RTMemTmpAllocZ((cbAndMaskScan + 1) * uHeight);
868
869 Assert(pu8AndMaskWordAligned);
870
871 if (pu8AndMaskWordAligned)
872 {
873 /* According to MSDN the padding bits must be 0.
874 * Compute the bit mask to set padding bits to 0 in the last byte of original AND mask. */
875 uint32_t u32PaddingBits = cbAndMaskScan * 8 - uWidth;
876 Assert(u32PaddingBits < 8);
877 uint8_t u8LastBytesPaddingMask = (uint8_t)(0xFF << u32PaddingBits);
878
879 Log(("u8LastBytesPaddingMask = %02X, aligned w = %d, width = %d, cbAndMaskScan = %d\n",
880 u8LastBytesPaddingMask, (cbAndMaskScan + 1) * 8, uWidth, cbAndMaskScan));
881
882 uint8_t *src = (uint8_t *)srcAndMaskPtr;
883 uint8_t *dst = pu8AndMaskWordAligned;
884
885 unsigned i;
886 for (i = 0; i < uHeight; i++)
887 {
888 memcpy(dst, src, cbAndMaskScan);
889
890 dst[cbAndMaskScan - 1] &= u8LastBytesPaddingMask;
891
892 src += cbAndMaskScan;
893 dst += cbAndMaskScan + 1;
894 }
895 }
896 }
897
898 /* Create the AND mask bitmap: */
899 hMonoBitmap = ::CreateBitmap(uWidth, uHeight, 1, 1,
900 pu8AndMaskWordAligned? pu8AndMaskWordAligned: srcAndMaskPtr);
901
902 if (pu8AndMaskWordAligned)
903 {
904 RTMemTmpFree(pu8AndMaskWordAligned);
905 }
906 }
907
908 Assert(hBitmap);
909 Assert(hMonoBitmap);
910 if (hBitmap && hMonoBitmap)
911 {
912 DWORD *dstShapePtr = (DWORD *) lpBits;
913
914 for (uint y = 0; y < uHeight; y ++)
915 {
916 memcpy(dstShapePtr, srcShapePtr, srcShapePtrScan);
917 srcShapePtr += srcShapePtrScan;
918 dstShapePtr += uWidth;
919 }
920
921 ICONINFO ii;
922 ii.fIcon = FALSE;
923 ii.xHotspot = uXHot;
924 ii.yHotspot = uYHot;
925 ii.hbmMask = hMonoBitmap;
926 ii.hbmColor = hBitmap;
927
928 HCURSOR hAlphaCursor = CreateIconIndirect(&ii);
929 Assert(hAlphaCursor);
930 if (hAlphaCursor)
931 {
932 /* Set the new cursor: */
933 m_cursor = QCursor(hAlphaCursor);
934 if (m_alphaCursor)
935 DestroyIcon(m_alphaCursor);
936 m_alphaCursor = hAlphaCursor;
937 m_fIsValidPointerShapePresent = true;
938 }
939 }
940
941 if (hMonoBitmap)
942 DeleteObject(hMonoBitmap);
943 if (hBitmap)
944 DeleteObject(hBitmap);
945
946#elif defined (Q_WS_X11) && !defined (VBOX_WITHOUT_XCURSOR)
947
948 XcursorImage *img = XcursorImageCreate(uWidth, uHeight);
949 Assert(img);
950 if (img)
951 {
952 img->xhot = uXHot;
953 img->yhot = uYHot;
954
955 XcursorPixel *dstShapePtr = img->pixels;
956
957 for (uint y = 0; y < uHeight; y ++)
958 {
959 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan);
960
961 if (!fHasAlpha)
962 {
963 /* Convert AND mask to the alpha channel: */
964 uchar byte = 0;
965 for (uint x = 0; x < uWidth; x ++)
966 {
967 if (!(x % 8))
968 byte = *(srcAndMaskPtr ++);
969 else
970 byte <<= 1;
971
972 if (byte & 0x80)
973 {
974 /* Linux doesn't support inverted pixels (XOR ops,
975 * to be exact) in cursor shapes, so we detect such
976 * pixels and always replace them with black ones to
977 * make them visible at least over light colors */
978 if (dstShapePtr [x] & 0x00FFFFFF)
979 dstShapePtr [x] = 0xFF000000;
980 else
981 dstShapePtr [x] = 0x00000000;
982 }
983 else
984 dstShapePtr [x] |= 0xFF000000;
985 }
986 }
987
988 srcShapePtr += srcShapePtrScan;
989 dstShapePtr += uWidth;
990 }
991
992 /* Set the new cursor: */
993 m_cursor = QCursor(XcursorImageLoadCursor(QX11Info::display(), img));
994 m_fIsValidPointerShapePresent = true;
995
996 XcursorImageDestroy(img);
997 }
998
999#elif defined(Q_WS_MAC)
1000
1001 /* Create a ARGB image out of the shape data. */
1002 QImage image (uWidth, uHeight, QImage::Format_ARGB32);
1003 const uint8_t* pbSrcMask = static_cast<const uint8_t*> (srcAndMaskPtr);
1004 unsigned cbSrcMaskLine = RT_ALIGN (uWidth, 8) / 8;
1005 for (unsigned int y = 0; y < uHeight; ++y)
1006 {
1007 for (unsigned int x = 0; x < uWidth; ++x)
1008 {
1009 unsigned int color = ((unsigned int*)srcShapePtr)[y*uWidth+x];
1010 /* If the alpha channel isn't in the shape data, we have to
1011 * create them from the and-mask. This is a bit field where 1
1012 * represent transparency & 0 opaque respectively. */
1013 if (!fHasAlpha)
1014 {
1015 if (!(pbSrcMask[x / 8] & (1 << (7 - (x % 8)))))
1016 color |= 0xff000000;
1017 else
1018 {
1019 /* This isn't quite right, but it's the best we can do I think... */
1020 if (color & 0x00ffffff)
1021 color = 0xff000000;
1022 else
1023 color = 0x00000000;
1024 }
1025 }
1026 image.setPixel (x, y, color);
1027 }
1028 /* Move one scanline forward. */
1029 pbSrcMask += cbSrcMaskLine;
1030 }
1031
1032 /* Set the new cursor: */
1033 m_cursor = QCursor(QPixmap::fromImage(image), uXHot, uYHot);
1034 m_fIsValidPointerShapePresent = true;
1035 NOREF(srcShapePtrScan);
1036
1037#else
1038
1039# warning "port me"
1040
1041#endif
1042}
1043
1044void UISession::reinitMenuPool()
1045{
1046 /* Get uisession machine: */
1047 const CMachine &machine = session().GetConsole().GetMachine();
1048
1049 /* Storage stuff: */
1050 {
1051 /* Initialize CD/FD menus: */
1052 int iDevicesCountCD = 0;
1053 int iDevicesCountFD = 0;
1054 const CMediumAttachmentVector &attachments = machine.GetMediumAttachments();
1055 for (int i = 0; i < attachments.size(); ++i)
1056 {
1057 const CMediumAttachment &attachment = attachments[i];
1058 if (attachment.GetType() == KDeviceType_DVD)
1059 ++iDevicesCountCD;
1060 if (attachment.GetType() == KDeviceType_Floppy)
1061 ++iDevicesCountFD;
1062 }
1063 QAction *pOpticalDevicesMenu = gActionPool->action(UIActionIndexRuntime_Menu_OpticalDevices);
1064 QAction *pFloppyDevicesMenu = gActionPool->action(UIActionIndexRuntime_Menu_FloppyDevices);
1065 pOpticalDevicesMenu->setData(iDevicesCountCD);
1066 pOpticalDevicesMenu->setVisible(iDevicesCountCD);
1067 pFloppyDevicesMenu->setData(iDevicesCountFD);
1068 pFloppyDevicesMenu->setVisible(iDevicesCountFD);
1069 }
1070
1071 /* Network stuff: */
1072 {
1073 bool fAtLeastOneAdapterActive = false;
1074 ULONG uSlots = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3);
1075 for (ULONG uSlot = 0; uSlot < uSlots; ++uSlot)
1076 {
1077 const CNetworkAdapter &adapter = machine.GetNetworkAdapter(uSlot);
1078 if (adapter.GetEnabled())
1079 {
1080 fAtLeastOneAdapterActive = true;
1081 break;
1082 }
1083 }
1084 /* Show/Hide Network Adapters action depending on overall adapters activity status: */
1085 gActionPool->action(UIActionIndexRuntime_Simple_NetworkAdaptersDialog)->setVisible(fAtLeastOneAdapterActive);
1086 }
1087
1088 /* USB stuff: */
1089 {
1090 /* Get USB controller: */
1091 const CUSBController &usbController = machine.GetUSBController();
1092 bool fUSBControllerEnabled = !usbController.isNull() && usbController.GetEnabled() && usbController.GetProxyAvailable();
1093 /* Show/Hide USB menu depending on controller availability, activity and USB-proxy presence: */
1094 gActionPool->action(UIActionIndexRuntime_Menu_USBDevices)->setVisible(fUSBControllerEnabled);
1095 }
1096}
1097
1098bool UISession::preparePowerUp()
1099{
1100 /* Notify user about mouse&keyboard auto-capturing: */
1101 if (vboxGlobal().settings().autoCapture())
1102 msgCenter().remindAboutAutoCapture();
1103
1104 /* Shows First Run wizard if necessary: */
1105 const CMachine &machine = session().GetMachine();
1106 /* Check if we are in teleportation waiting mode.
1107 * In that case no first run wizard is necessary. */
1108 m_machineState = machine.GetState();
1109 if ( isFirstTimeStarted()
1110 && !(( m_machineState == KMachineState_PoweredOff
1111 || m_machineState == KMachineState_Aborted
1112 || m_machineState == KMachineState_Teleported)
1113 && machine.GetTeleporterEnabled()))
1114 {
1115 UIWizardFirstRun wzd(mainMachineWindow(), session().GetMachine());
1116 wzd.exec();
1117 }
1118
1119 /* Skip further checks if VM in saved state */
1120 if (isSaved())
1121 return true;
1122
1123 /* Make sure all the attached and enabled network
1124 * adapters are present on the host. This check makes sense
1125 * in two cases only - when attachement type is Bridged Network
1126 * or Host-only Interface. NOTE: Only currently enabled
1127 * attachement type is checked (incorrect parameters check for
1128 * currently disabled attachement types is skipped). */
1129 QStringList failedInterfaceNames;
1130 ulong cCount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine.GetChipsetType());
1131 for (ulong uAdapterIndex = 0; uAdapterIndex < cCount; ++uAdapterIndex)
1132 {
1133 CNetworkAdapter na = machine.GetNetworkAdapter(uAdapterIndex);
1134 if (na.GetEnabled() &&
1135 (na.GetAttachmentType() == KNetworkAttachmentType_Bridged ||
1136 na.GetAttachmentType() == KNetworkAttachmentType_HostOnly))
1137 {
1138 QStringList ifNames;
1139 ifNames << na.GetBridgedInterface()
1140 << na.GetHostOnlyInterface();
1141
1142 foreach (const QString &strIfName, ifNames)
1143 {
1144 if (!strIfName.isEmpty() &&
1145 !QNetworkInterface::interfaceFromName(strIfName).isValid())
1146 {
1147 LogFlow(("Found invalid network interface: %s\n", strIfName.toStdString().c_str()));
1148 failedInterfaceNames << QString("%1 (adapter %2)").arg(strIfName).arg(uAdapterIndex + 1);
1149 break;
1150 }
1151 }
1152 }
1153 }
1154 /* Check failed? */
1155 if (!failedInterfaceNames.isEmpty())
1156 {
1157 if (msgCenter().UIMessageCenter::cannotStartWithoutNetworkIf(machine.GetName(), failedInterfaceNames.join(", ")))
1158 machineLogic()->openNetworkAdaptersDialog();
1159 else
1160 {
1161 QTimer::singleShot(0, this, SLOT(sltCloseVirtualSession()));
1162 return false;
1163 }
1164 }
1165
1166 return true;
1167}
1168
1169bool UISession::isScreenVisible(ulong uScreenId) const
1170{
1171 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1172 return m_monitorVisibilityVector.value((int)uScreenId, false);
1173}
1174
1175void UISession::setScreenVisible(ulong uScreenId, bool fIsMonitorVisible)
1176{
1177 Assert(uScreenId < (ulong)m_monitorVisibilityVector.size());
1178 if (uScreenId < (ulong)m_monitorVisibilityVector.size())
1179 m_monitorVisibilityVector[(int)uScreenId] = fIsMonitorVisible;
1180}
1181
1182int UISession::countOfVisibleWindows()
1183{
1184 int cCountOfVisibleWindows = 0;
1185 for (int i = 0; i < m_monitorVisibilityVector.size(); ++i)
1186 if (m_monitorVisibilityVector[i])
1187 ++cCountOfVisibleWindows;
1188 return cCountOfVisibleWindows;
1189}
1190
1191UIFrameBuffer* UISession::frameBuffer(ulong uScreenId) const
1192{
1193 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1194 return m_frameBufferVector.value((int)uScreenId, 0);
1195}
1196
1197void UISession::setFrameBuffer(ulong uScreenId, UIFrameBuffer* pFrameBuffer)
1198{
1199 Assert(uScreenId < (ulong)m_frameBufferVector.size());
1200 if (uScreenId < (ulong)m_frameBufferVector.size())
1201 m_frameBufferVector[(int)uScreenId] = pFrameBuffer;
1202}
1203
1204#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
1205/**
1206 * Custom signal handler. When switching VTs, we might not get release events
1207 * for Ctrl-Alt and in case a savestate is performed on the new VT, the VM will
1208 * be saved with modifier keys stuck. This is annoying enough for introducing
1209 * this hack.
1210 */
1211/* static */
1212void UISession::signalHandlerSIGUSR1(int sig, siginfo_t * /* pInfo */, void * /*pSecret */)
1213{
1214 /* only SIGUSR1 is interesting */
1215 if (sig == SIGUSR1)
1216 if (UIMachine *pMachine = vboxGlobal().virtualMachine())
1217 pMachine->uisession()->machineLogic()->keyboardHandler()->releaseAllPressedKeys();
1218}
1219#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
1220
Note: See TracBrowser for help on using the repository browser.

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