VirtualBox

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

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

BUGZ:6387 fixed typo: adjust VM window position only in case of Normal and Scale mode; fixed coding style.

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