VirtualBox

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

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

FE/Qt: 5820: Show/hide VM windows when the count changes within the guest.

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