VirtualBox

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

Last change on this file since 41689 was 41689, checked in by vboxsync, 12 years ago

FE/Qt: VBoxDefs renamed to UIDefs and reworked into namespace. Corresponding files which were using VBoxDefs updated.

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