VirtualBox

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

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

FE/Qt4: special signal handler for reseting pressed keys

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

© 2023 Oracle
ContactPrivacy policyTerms of Use