Changeset 26691 in vbox
- Timestamp:
- Feb 23, 2010 3:32:44 AM (15 years ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 16 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r26655 r26691 375 375 ifdef VBOX_WITH_NEW_RUNTIME_CORE 376 376 VirtualBox_QT_MOCHDRS += \ 377 src/runtime/UISession.h \ 377 378 src/runtime/UIActionsPool.h \ 378 379 src/runtime/UIIndicatorsPool.h \ … … 496 497 ifdef VBOX_WITH_NEW_RUNTIME_CORE 497 498 VirtualBox_SOURCES += \ 499 src/runtime/UISession.cpp \ 498 500 src/runtime/UIActionsPool.cpp \ 499 501 src/runtime/UIIndicatorsPool.cpp \ -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIActionsPool.cpp
r26647 r26691 390 390 }; 391 391 392 class PerformResetAction : public UISimpleAction393 {394 Q_OBJECT;395 396 public:397 398 PerformResetAction(QObject *pParent)399 : UISimpleAction(pParent,400 ":/reset_16px.png", ":/reset_disabled_16px.png")401 {402 retranslateUi();403 }404 405 protected:406 407 void retranslateUi()408 {409 setText(VBoxGlobal::insertKeyToActionText(tr ("&Reset"), "R"));410 setStatusTip(tr("Reset the virtual machine"));411 }412 };413 414 392 class TogglePauseAction : public UIToggleAction 415 393 { … … 442 420 }; 443 421 422 class PerformResetAction : public UISimpleAction 423 { 424 Q_OBJECT; 425 426 public: 427 428 PerformResetAction(QObject *pParent) 429 : UISimpleAction(pParent, 430 ":/reset_16px.png", ":/reset_disabled_16px.png") 431 { 432 retranslateUi(); 433 } 434 435 protected: 436 437 void retranslateUi() 438 { 439 setText(VBoxGlobal::insertKeyToActionText(tr ("&Reset"), "R")); 440 setStatusTip(tr("Reset the virtual machine")); 441 } 442 }; 443 444 444 class PerformShutdownAction : public UISimpleAction 445 445 { … … 554 554 }; 555 555 556 class MenuNetworkAdaptersAction : public UIMenuAction557 {558 Q_OBJECT;559 560 public:561 562 MenuNetworkAdaptersAction(QObject *pParent)563 : UIMenuAction(pParent)564 {565 retranslateUi();566 }567 568 protected:569 570 void retranslateUi()571 {572 }573 };574 575 class ShowNetworkAdaptersDialogAction : public UISimpleAction576 {577 Q_OBJECT;578 579 public:580 581 ShowNetworkAdaptersDialogAction(QObject *pParent)582 : UISimpleAction(pParent,583 ":/nw_16px.png", ":/nw_disabled_16px.png")584 {585 retranslateUi();586 }587 588 protected:589 590 void retranslateUi()591 {592 setText(tr("&Network Adapters..."));593 setStatusTip(tr("Change the settings of network adapters"));594 }595 };596 597 class MenuSharedFoldersAction : public UIMenuAction598 {599 Q_OBJECT;600 601 public:602 603 MenuSharedFoldersAction(QObject *pParent)604 : UIMenuAction(pParent)605 {606 retranslateUi();607 }608 609 protected:610 611 void retranslateUi()612 {613 }614 };615 616 class ShowSharedFoldersDialogAction : public UISimpleAction617 {618 Q_OBJECT;619 620 public:621 622 ShowSharedFoldersDialogAction(QObject *pParent)623 : UISimpleAction(pParent,624 ":/shared_folder_16px.png", ":/shared_folder_disabled_16px.png")625 {626 retranslateUi();627 }628 629 protected:630 631 void retranslateUi()632 {633 setText(tr("&Shared Folders..."));634 setStatusTip(tr("Create or modify shared folders"));635 }636 };637 638 556 class MenuUSBDevicesAction : public UIMenuAction 639 557 { … … 654 572 { 655 573 menu()->setTitle(tr("&USB Devices")); 574 } 575 }; 576 577 class MenuNetworkAdaptersAction : public UIMenuAction 578 { 579 Q_OBJECT; 580 581 public: 582 583 MenuNetworkAdaptersAction(QObject *pParent) 584 : UIMenuAction(pParent) 585 { 586 retranslateUi(); 587 } 588 589 protected: 590 591 void retranslateUi() 592 { 593 } 594 }; 595 596 class ShowNetworkAdaptersDialogAction : public UISimpleAction 597 { 598 Q_OBJECT; 599 600 public: 601 602 ShowNetworkAdaptersDialogAction(QObject *pParent) 603 : UISimpleAction(pParent, 604 ":/nw_16px.png", ":/nw_disabled_16px.png") 605 { 606 retranslateUi(); 607 } 608 609 protected: 610 611 void retranslateUi() 612 { 613 setText(tr("&Network Adapters...")); 614 setStatusTip(tr("Change the settings of network adapters")); 615 } 616 }; 617 618 class MenuSharedFoldersAction : public UIMenuAction 619 { 620 Q_OBJECT; 621 622 public: 623 624 MenuSharedFoldersAction(QObject *pParent) 625 : UIMenuAction(pParent) 626 { 627 retranslateUi(); 628 } 629 630 protected: 631 632 void retranslateUi() 633 { 634 } 635 }; 636 637 class ShowSharedFoldersDialogAction : public UISimpleAction 638 { 639 Q_OBJECT; 640 641 public: 642 643 ShowSharedFoldersDialogAction(QObject *pParent) 644 : UISimpleAction(pParent, 645 ":/shared_folder_16px.png", ":/shared_folder_disabled_16px.png") 646 { 647 retranslateUi(); 648 } 649 650 protected: 651 652 void retranslateUi() 653 { 654 setText(tr("&Shared Folders...")); 655 setStatusTip(tr("Create or modify shared folders")); 656 656 } 657 657 }; … … 809 809 m_actionsPool[UIActionIndex_Simple_TakeSnapshot] = new PerformTakeSnapshotAction(this); 810 810 m_actionsPool[UIActionIndex_Simple_InformationDialog] = new ShowInformationDialogAction(this); 811 m_actionsPool[UIActionIndex_Toggle_Pause] = new TogglePauseAction(this); 811 812 m_actionsPool[UIActionIndex_Simple_Reset] = new PerformResetAction(this); 812 m_actionsPool[UIActionIndex_Toggle_Pause] = new TogglePauseAction(this);813 813 m_actionsPool[UIActionIndex_Simple_Shutdown] = new PerformShutdownAction(this); 814 814 m_actionsPool[UIActionIndex_Simple_Close] = new PerformCloseAction(this); … … 818 818 m_actionsPool[UIActionIndex_Menu_OpticalDevices] = new MenuOpticalDevicesAction(this); 819 819 m_actionsPool[UIActionIndex_Menu_FloppyDevices] = new MenuFloppyDevicesAction(this); 820 m_actionsPool[UIActionIndex_Menu_USBDevices] = new MenuUSBDevicesAction(this); 820 821 m_actionsPool[UIActionIndex_Menu_NetworkAdapters] = new MenuNetworkAdaptersAction(this); 821 822 m_actionsPool[UIActionIndex_Simple_NetworkAdaptersDialog] = new ShowNetworkAdaptersDialogAction(this); 822 823 m_actionsPool[UIActionIndex_Menu_SharedFolders] = new MenuSharedFoldersAction(this); 823 824 m_actionsPool[UIActionIndex_Simple_SharedFoldersDialog] = new ShowSharedFoldersDialogAction(this); 824 m_actionsPool[UIActionIndex_Menu_USBDevices] = new MenuUSBDevicesAction(this);825 825 m_actionsPool[UIActionIndex_Toggle_VRDP] = new ToggleVRDPAction(this); 826 826 m_actionsPool[UIActionIndex_Simple_InstallGuestTools] = new PerformInstallGuestToolsAction(this); -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIActionsPool.h
r26637 r26691 72 72 UIActionIndex_Simple_TakeSnapshot, 73 73 UIActionIndex_Simple_InformationDialog, 74 UIActionIndex_Toggle_Pause, 74 75 UIActionIndex_Simple_Reset, 75 UIActionIndex_Toggle_Pause,76 76 UIActionIndex_Simple_Shutdown, 77 77 UIActionIndex_Simple_Close, … … 81 81 UIActionIndex_Menu_OpticalDevices, 82 82 UIActionIndex_Menu_FloppyDevices, 83 UIActionIndex_Menu_USBDevices, 83 84 UIActionIndex_Menu_NetworkAdapters, 84 85 UIActionIndex_Simple_NetworkAdaptersDialog, 85 86 UIActionIndex_Menu_SharedFolders, 86 87 UIActionIndex_Simple_SharedFoldersDialog, 87 UIActionIndex_Menu_USBDevices,88 88 UIActionIndex_Toggle_VRDP, 89 89 UIActionIndex_Simple_InstallGuestTools, -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachine.cpp
r26637 r26691 24 24 #include "VBoxGlobal.h" 25 25 #include "UIMachine.h" 26 #include "UISession.h" 26 27 #include "UIActionsPool.h" 27 28 #include "UIMachineLogic.h" … … 33 34 public: 34 35 36 /* Visual state holder constructor: */ 35 37 UIVisualState(QObject *pParent) : QObject(pParent), m_pMachineLogic(0) 36 38 { 37 /* Connect state-change handler */39 /* Connect state-change handler: */ 38 40 connect(this, SIGNAL(sigChangeVisualState(UIVisualStateType)), parent(), SLOT(sltChangeVisualState(UIVisualStateType))); 39 41 } … … 45 47 protected: 46 48 49 /* Protected members: */ 47 50 UIMachineLogic *m_pMachineLogic; 51 52 /* Friend classes: */ 53 friend class UIMachine; 48 54 }; 49 55 … … 54 60 public: 55 61 56 UIVisualStateNormal(QObject *pParent, const CSession &session, UIActionsPool *pActionsPool) 62 /* Normal visual state holder constructor: */ 63 UIVisualStateNormal(QObject *pParent, UISession *pSession, UIActionsPool *pActionsPool) 57 64 : UIVisualState(pParent) 58 65 { 59 /* Connect action handlers */66 /* Connect action handlers: */ 60 67 connect(pActionsPool->action(UIActionIndex_Toggle_Fullscreen), SIGNAL(triggered(bool)), 61 68 this, SLOT(sltGoToFullscreenMode())); … … 63 70 this, SLOT(sltGoToSeamlessMode())); 64 71 65 /* Create state logic */66 m_pMachineLogic = UIMachineLogic::create(this, session, pActionsPool, UIVisualStateType_Normal);72 /* Create state logic: */ 73 m_pMachineLogic = UIMachineLogic::create(this, pSession, pActionsPool, UIVisualStateType_Normal); 67 74 } 68 75 … … 71 78 void sltGoToFullscreenMode() 72 79 { 80 /* Change visual state to fullscreen: */ 73 81 emit sigChangeVisualState(UIVisualStateType_Fullscreen); 74 82 } … … 76 84 void sltGoToSeamlessMode() 77 85 { 86 /* Change visual state to seamless: */ 78 87 emit sigChangeVisualState(UIVisualStateType_Seamless); 79 88 } … … 86 95 public: 87 96 88 UIVisualStateFullscreen(QObject *pParent, const CSession &session, UIActionsPool *pActionsPool) 97 /* Fullscreen visual state holder constructor: */ 98 UIVisualStateFullscreen(QObject *pParent, UISession *pSession, UIActionsPool *pActionsPool) 89 99 : UIVisualState(pParent) 90 100 { 91 /* Connect action handlers */101 /* Connect action handlers: */ 92 102 connect(pActionsPool->action(UIActionIndex_Toggle_Fullscreen), SIGNAL(triggered(bool)), 93 103 this, SLOT(sltGoToNormalMode())); … … 95 105 this, SLOT(sltGoToSeamlessMode())); 96 106 97 /* Create state logic */98 m_pMachineLogic = UIMachineLogic::create(this, session, pActionsPool, UIVisualStateType_Fullscreen);107 /* Create state logic: */ 108 m_pMachineLogic = UIMachineLogic::create(this, pSession, pActionsPool, UIVisualStateType_Fullscreen); 99 109 } 100 110 … … 103 113 void sltGoToNormalMode() 104 114 { 115 /* Change visual state to normal: */ 105 116 emit sigChangeVisualState(UIVisualStateType_Normal); 106 117 } … … 108 119 void sltGoToSeamlessMode() 109 120 { 121 /* Change visual state to seamless: */ 110 122 emit sigChangeVisualState(UIVisualStateType_Seamless); 111 123 } … … 118 130 public: 119 131 120 UIVisualStateSeamless(QObject *pParent, const CSession &session, UIActionsPool *pActionsPool) 132 /* Seamless visual state holder constructor: */ 133 UIVisualStateSeamless(QObject *pParent, UISession *pSession, UIActionsPool *pActionsPool) 121 134 : UIVisualState(pParent) 122 135 { … … 128 141 129 142 /* Create state logic */ 130 m_pMachineLogic = UIMachineLogic::create(this, session, pActionsPool, UIVisualStateType_Seamless);143 m_pMachineLogic = UIMachineLogic::create(this, pSession, pActionsPool, UIVisualStateType_Seamless); 131 144 } 132 145 … … 135 148 void sltGoToFullscreenMode() 136 149 { 150 /* Change visual state to fullscreen: */ 137 151 emit sigChangeVisualState(UIVisualStateType_Fullscreen); 138 152 } … … 140 154 void sltGoToNormalMode() 141 155 { 156 /* Change visual state to normal: */ 142 157 emit sigChangeVisualState(UIVisualStateType_Normal); 143 158 } … … 146 161 UIMachine::UIMachine(UIMachine **ppSelf, const CSession &session) 147 162 : QObject(0) 148 , m_ session(session)163 , m_pSession(new UISession(this, session)) 149 164 , m_pActionsPool(new UIActionsPool(this)) 150 165 , m_pVisualState(0) … … 152 167 /* Cache IMedium data: */ 153 168 vboxGlobal().startEnumeratingMedia(); 154 155 /* Check CSession object */156 AssertMsg(!m_session.isNull(), ("CSession is not set!\n"));157 169 158 170 /* Storing self */ … … 164 176 } 165 177 178 UIMachineLogic* UIMachine::machineLogic() const 179 { 180 return m_pVisualState->m_pMachineLogic; 181 } 182 166 183 void UIMachine::sltChangeVisualState(UIVisualStateType visualStateType) 167 184 { 168 /* Delete previous state */185 /* Delete previous state: */ 169 186 delete m_pVisualState; 170 187 m_pVisualState = 0; 171 188 172 /* Create new state */189 /* Create new state: */ 173 190 switch (visualStateType) 174 191 { 175 192 case UIVisualStateType_Normal: 176 193 { 177 m_pVisualState = new UIVisualStateNormal(this, m_session, m_pActionsPool); 194 /* Create normal visual state: */ 195 m_pVisualState = new UIVisualStateNormal(this, m_pSession, m_pActionsPool); 178 196 break; 179 197 } 180 198 case UIVisualStateType_Fullscreen: 181 199 { 182 m_pVisualState = new UIVisualStateFullscreen(this, m_session, m_pActionsPool); 200 /* Create fullscreen visual state: */ 201 m_pVisualState = new UIVisualStateFullscreen(this, m_pSession, m_pActionsPool); 183 202 break; 184 203 } 185 204 case UIVisualStateType_Seamless: 186 205 { 187 m_pVisualState = new UIVisualStateSeamless(this, m_session, m_pActionsPool); 206 /* Create seamless visual state: */ 207 m_pVisualState = new UIVisualStateSeamless(this, m_pSession, m_pActionsPool); 188 208 break; 189 209 } -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachine.h
r26637 r26691 24 24 #define __UIMachine_h__ 25 25 26 /* Global includes */ 27 #include <QObject> 28 26 29 /* Local includes */ 27 #include "COMDefs.h"28 30 #include "UIMachineDefs.h" 29 31 30 32 /* Local forwards */ 33 class UISession; 31 34 class UIActionsPool; 32 35 class UIVisualState; 36 class UIMachineLogic; 37 class CSession; 33 38 34 39 class UIMachine : public QObject … … 38 43 public: 39 44 45 /* Virtual Machine constructor: */ 40 46 UIMachine(UIMachine **ppSelf, const CSession &session); 41 47 42 48 private slots: 43 49 50 /* Visual state-change handler: */ 44 51 void sltChangeVisualState(UIVisualStateType visualStateType); 45 52 46 53 private: 47 54 55 /* Move VM to default (normal) state: */ 48 56 void enterBaseVisualState(); 49 57 50 CSession m_session; 58 /* Private getters: */ 59 UIMachineLogic* machineLogic() const; 60 61 /* Private variables: */ 62 UISession *m_pSession; 51 63 UIActionsPool *m_pActionsPool; 52 64 UIVisualState *m_pVisualState; 65 66 /* Friend classes: */ 67 friend class UISession; 53 68 }; 54 69 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
r26656 r26691 41 41 #include "QIHttp.h" 42 42 43 #include "UISession.h" 43 44 #include "UIActionsPool.h" 44 45 #include "UIMachineLogic.h" … … 65 66 #endif 66 67 67 struct M ountTarget68 { 69 M ountTarget() : name(QString("")), port(0), device(0), id(QString()), type(VBoxDefs::MediumType_Invalid) {}70 M ountTarget(const QString &strName, LONG iPort, LONG iDevice)68 struct MediumTarget 69 { 70 MediumTarget() : name(QString("")), port(0), device(0), id(QString()), type(VBoxDefs::MediumType_Invalid) {} 71 MediumTarget(const QString &strName, LONG iPort, LONG iDevice) 71 72 : name(strName), port(iPort), device(iDevice), id(QString()), type(VBoxDefs::MediumType_Invalid) {} 72 M ountTarget(const QString &strName, LONG iPort, LONG iDevice, const QString &strId)73 MediumTarget(const QString &strName, LONG iPort, LONG iDevice, const QString &strId) 73 74 : name(strName), port(iPort), device(iDevice), id(strId), type(VBoxDefs::MediumType_Invalid) {} 74 M ountTarget(const QString &strName, LONG iPort, LONG iDevice, VBoxDefs::MediumType eType)75 MediumTarget(const QString &strName, LONG iPort, LONG iDevice, VBoxDefs::MediumType eType) 75 76 : name(strName), port(iPort), device(iDevice), id(QString()), type(eType) {} 76 77 QString name; … … 80 81 VBoxDefs::MediumType type; 81 82 }; 82 Q_DECLARE_METATYPE(MountTarget); 83 Q_DECLARE_METATYPE(MediumTarget); 84 85 struct USBTarget 86 { 87 USBTarget() : attach(false), id(QString()) {} 88 USBTarget(bool bAttach, const QString &strId) 89 : attach(bAttach), id(strId) {} 90 bool attach; 91 QString id; 92 }; 93 Q_DECLARE_METATYPE(USBTarget); 83 94 84 95 class UINetworkAdaptersDialog : public QIWithRetranslateUI<QDialog> … … 331 342 332 343 UIMachineLogic* UIMachineLogic::create(QObject *pParent, 333 const CSession &session,344 UISession *pSession, 334 345 UIActionsPool *pActionsPool, 335 346 UIVisualStateType visualStateType) … … 339 350 { 340 351 case UIVisualStateType_Normal: 341 logic = new UIMachineLogicNormal(pParent, session, pActionsPool);352 logic = new UIMachineLogicNormal(pParent, pSession, pActionsPool); 342 353 break; 343 354 case UIVisualStateType_Fullscreen: 344 // logic = new UIMachineLogicFullscreen(pParent, session, pActionsPool);345 logic = new UIMachineLogicNormal(pParent, session, pActionsPool);355 // logic = new UIMachineLogicFullscreen(pParent, pSession, pActionsPool); 356 logic = new UIMachineLogicNormal(pParent, pSession, pActionsPool); 346 357 break; 347 358 case UIVisualStateType_Seamless: 348 // logic = new UIMachineLogicSeamless(pParent, session, pActionsPool);349 logic = new UIMachineLogicNormal(pParent, session, pActionsPool);359 // logic = new UIMachineLogicSeamless(pParent, pSession, pActionsPool); 360 logic = new UIMachineLogicNormal(pParent, pSession, pActionsPool); 350 361 break; 351 362 } … … 354 365 355 366 UIMachineLogic::UIMachineLogic(QObject *pParent, 356 const CSession &session,367 UISession *pSession, 357 368 UIActionsPool *pActionsPool, 358 369 UIVisualStateType visualStateType) 370 /* Initialize parent class: */ 359 371 : QObject(pParent) 372 /* Initialize protected members: */ 360 373 , m_pMachineWindowContainer(0) 361 , m_session(session) 374 /* Initialize private members: */ 375 , m_pSession(pSession) 362 376 , m_pActionsPool(pActionsPool) 363 377 , m_machineState(KMachineState_Null) 364 378 , m_visualStateType(visualStateType) 379 /* Action groups: */ 365 380 , m_pRunningActions(0) 366 381 , m_pRunningOrPausedActions(0) 382 /* Bool flags: */ 367 383 , m_bIsFirstTimeStarted(false) 368 384 , m_bIsOpenViewFinished(false) … … 376 392 UIMachineLogic::~UIMachineLogic() 377 393 { 378 #ifdef VBOX_WITH_DEBUGGER_GUI 394 #ifdef VBOX_WITH_DEBUGGER_GUI // TODO: Should we close debugger now? 379 395 /* Close debugger: */ 380 // TODO: Check that logic!381 396 //dbgDestroy(); 382 397 #endif 383 398 } 384 399 385 void UIMachineLogic::updateAppearanceOf(int iElement) 386 { 387 /* Update logic: */ 388 CMachine machine = session().GetMachine(); 389 390 bool isRunningOrPaused = machineState() == KMachineState_Running || 391 machineState() == KMachineState_Paused || 392 machineState() == KMachineState_Teleporting || 393 machineState() == KMachineState_LiveSnapshotting; 394 395 if (iElement & UIVisualElement_PauseStuff) 396 { 397 actionsPool()->action(UIActionIndex_Toggle_Pause)->setEnabled(isRunningOrPaused); 398 } 399 400 /* Update window: */ 401 machineWindowWrapper()->updateAppearanceOf(iElement); 400 void UIMachineLogic::prepareConsoleConnections() 401 { 402 connect(uisession(), SIGNAL(sigStateChange(KMachineState)), this, SLOT(sltMachineStateChanged(KMachineState))); 403 connect(uisession(), SIGNAL(sigAdditionsStateChange()), this, SLOT(sltAdditionsStateChanged())); 402 404 } 403 405 … … 416 418 m_pRunningOrPausedActions->setExclusive(false); 417 419 418 // TODO: Move actions into approprivate action groups! 420 /* Move actions into first group: */ 421 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Toggle_Fullscreen)); 422 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Toggle_Seamless)); 423 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Simple_AdjustWindow)); 424 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Simple_TypeCAD)); 425 #ifdef Q_WS_X11 426 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Simple_TypeCABS)); 427 #endif 428 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Simple_Reset)); 429 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Simple_Shutdown)); 430 #ifdef VBOX_WITH_DEBUGGER_GUI 431 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Simple_Statistics)); 432 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Simple_CommandLine)); 433 m_pRunningActions->addAction(actionsPool()->action(UIActionIndex_Toggle_Logging)); 434 #endif 435 436 /* Move actions into second group: */ 437 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Toggle_GuestAutoresize)); 438 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Menu_MouseIntegration)); 439 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Toggle_MouseIntegration)); 440 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Simple_TakeSnapshot)); 441 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Simple_InformationDialog)); 442 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Toggle_Pause)); 443 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Simple_Close)); 444 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Menu_OpticalDevices)); 445 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Menu_FloppyDevices)); 446 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Menu_USBDevices)); 447 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Menu_NetworkAdapters)); 448 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Simple_NetworkAdaptersDialog)); 449 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Menu_SharedFolders)); 450 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Simple_SharedFoldersDialog)); 451 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Toggle_VRDP)); 452 m_pRunningOrPausedActions->addAction(actionsPool()->action(UIActionIndex_Simple_InstallGuestTools)); 419 453 } 420 454 … … 422 456 { 423 457 /* "Machine" actions connections */ 458 connect(actionsPool()->action(UIActionIndex_Toggle_GuestAutoresize), SIGNAL(toggled(bool)), 459 this, SLOT(sltToggleGuestAutoresize(bool))); 424 460 connect(actionsPool()->action(UIActionIndex_Simple_AdjustWindow), SIGNAL(triggered()), 425 461 this, SLOT(sltAdjustWindow())); … … 436 472 connect(actionsPool()->action(UIActionIndex_Simple_InformationDialog), SIGNAL(triggered()), 437 473 this, SLOT(sltShowInformationDialog())); 474 connect(actionsPool()->action(UIActionIndex_Toggle_Pause), SIGNAL(toggled(bool)), 475 this, SLOT(sltPause(bool))); 438 476 connect(actionsPool()->action(UIActionIndex_Simple_Reset), SIGNAL(triggered()), 439 477 this, SLOT(sltReset())); 440 connect(actionsPool()->action(UIActionIndex_Toggle_Pause), SIGNAL(toggled(bool)),441 this, SLOT(sltPause(bool)));442 478 connect(actionsPool()->action(UIActionIndex_Simple_Shutdown), SIGNAL(triggered()), 443 479 this, SLOT(sltACPIShutdown())); … … 450 486 connect(actionsPool()->action(UIActionIndex_Menu_FloppyDevices)->menu(), SIGNAL(aboutToShow()), 451 487 this, SLOT(sltPrepareStorageMenu())); 488 connect(actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu(), SIGNAL(aboutToShow()), 489 this, SLOT(sltPrepareUSBMenu())); 452 490 connect(actionsPool()->action(UIActionIndex_Simple_NetworkAdaptersDialog), SIGNAL(triggered()), 453 491 this, SLOT(sltOpenNetworkAdaptersDialog())); 454 492 connect(actionsPool()->action(UIActionIndex_Simple_SharedFoldersDialog), SIGNAL(triggered()), 455 493 this, SLOT(sltOpenSharedFoldersDialog())); 456 connect(actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu(), SIGNAL(aboutToShow()),457 this, SLOT(sltPrepareUSBMenu()));458 494 connect(actionsPool()->action(UIActionIndex_Toggle_VRDP), SIGNAL(toggled(bool)), 459 495 this, SLOT(sltSwitchVrdp(bool))); … … 476 512 void UIMachineLogic::prepareRequiredFeatures() 477 513 { 514 /* Get current console: */ 478 515 CConsole console = session().GetConsole(); 479 516 … … 485 522 if (fRecommendVirtEx && !bIsVirtEnabled) 486 523 { 487 bool ret; 488 489 // TODO: Check that logic! 490 //sltPause(true); 524 bool result; 525 526 pause(); 491 527 492 528 bool fVTxAMDVSupported = vboxGlobal().virtualBox().GetHost().GetProcessorFeature(KProcessorFeature_HWVirtEx); 493 529 494 530 if (bIs64BitsGuest) 495 re t = vboxProblem().warnAboutVirtNotEnabled64BitsGuest(fVTxAMDVSupported);531 result = vboxProblem().warnAboutVirtNotEnabled64BitsGuest(fVTxAMDVSupported); 496 532 else 497 ret = vboxProblem().warnAboutVirtNotEnabledGuestRequired(fVTxAMDVSupported); 498 499 // TODO: Close application! 500 //if (ret == true) 501 // machineWindowWrapper()->machineWindow()->close(); 502 // TODO: Check that logic! 503 //else 504 // sltPause(false); 533 result = vboxProblem().warnAboutVirtNotEnabledGuestRequired(fVTxAMDVSupported); 534 535 if (result == true) 536 sltClose(); 537 else 538 unpause(); 505 539 } 506 540 … … 514 548 void UIMachineLogic::loadLogicSettings() 515 549 { 550 /* Get current machine: */ 516 551 CMachine machine = session().GetMachine(); 517 552 518 /* Extra-data settings */553 /* Extra-data settings: */ 519 554 { 520 555 QString strSettings; … … 533 568 } 534 569 535 /* Initial settings */570 /* Initial settings: */ 536 571 { 537 572 /* Initialize storage stuff: */ … … 552 587 } 553 588 554 /* Availability settings */589 /* Availability settings: */ 555 590 { 556 591 /* USB Stuff: */ … … 558 593 if (usbController.isNull()) 559 594 { 560 /* Hide USB _Menu: */561 actionsPool()->action(UIActionIndex_Menu_USBDevices)-> menu()->setVisible(false);595 /* Hide USB menu if controller is NULL: */ 596 actionsPool()->action(UIActionIndex_Menu_USBDevices)->setVisible(false); 562 597 } 563 598 else 564 599 { 565 /* Enable/Disable USB _Menu: */566 actionsPool()->action(UIActionIndex_Menu_USBDevices)-> menu()->setEnabled(usbController.GetEnabled());600 /* Enable/Disable USB menu depending on USB controller: */ 601 actionsPool()->action(UIActionIndex_Menu_USBDevices)->setEnabled(usbController.GetEnabled()); 567 602 } 568 603 … … 579 614 void UIMachineLogic::saveLogicSettings() 580 615 { 616 /* Get current machine: */ 581 617 CMachine machine = session().GetMachine(); 582 618 583 /* Extra-data settings */619 /* Extra-data settings: */ 584 620 { 585 621 machine.SetExtraData(VBoxDefs::GUI_AutoresizeGuest, … … 591 627 //machine.SetExtraData(VBoxDefs::GUI_MiniToolBarAutoHide, mMiniToolBar->isAutoHide() ? "on" : "off"); 592 628 } 629 } 630 631 CSession& UIMachineLogic::session() 632 { 633 return m_pSession->session(); 634 } 635 636 void UIMachineLogic::sltMachineStateChanged(KMachineState newMachineState) 637 { 638 if (m_machineState != newMachineState) 639 { 640 /* Variable flags: */ 641 bool bIsRunning = newMachineState == KMachineState_Running || 642 newMachineState == KMachineState_Teleporting || 643 newMachineState == KMachineState_LiveSnapshotting; 644 bool bIsRunningOrPaused = bIsRunning || 645 newMachineState == KMachineState_Paused; 646 647 /* Update action groups: */ 648 m_pRunningActions->setEnabled(bIsRunning); 649 m_pRunningOrPausedActions->setEnabled(bIsRunningOrPaused); 650 651 /* Do we have GURU? */ 652 bool bIsGuruMeditation = false; 653 654 switch (newMachineState) 655 { 656 case KMachineState_Stuck: 657 { 658 bIsGuruMeditation = true; 659 break; 660 } 661 case KMachineState_Paused: 662 { 663 /* Was paused from CMachine side? */ 664 QAction *pPauseAction = actionsPool()->action(UIActionIndex_Toggle_Pause); 665 if (!pPauseAction->isChecked()) 666 { 667 pPauseAction->blockSignals(true); 668 pPauseAction->setChecked(true); 669 pPauseAction->blockSignals(false); 670 } 671 break; 672 } 673 case KMachineState_Running: 674 case KMachineState_Teleporting: 675 case KMachineState_LiveSnapshotting: 676 { 677 /* Was started from CMachine side? */ 678 QAction *pPauseAction = actionsPool()->action(UIActionIndex_Toggle_Pause); 679 if (isPaused() && pPauseAction->isChecked()) 680 { 681 pPauseAction->blockSignals(true); 682 pPauseAction->setChecked(false); 683 pPauseAction->blockSignals(false); 684 } 685 break; 686 } 687 #ifdef Q_WS_X11 688 case KMachineState_Starting: 689 case KMachineState_Restoring: 690 case KMachineState_TeleportingIn: 691 { 692 /* The keyboard handler may wish to do some release logging on startup. 693 * Tell it that the logger is now active. */ 694 doXKeyboardLogging(QX11Info::display()); 695 break; 696 } 697 #endif 698 default: 699 break; 700 } 701 702 /* Now storing new state: */ 703 m_machineState = newMachineState; 704 705 /* Close VM if was closed someway: */ 706 if (m_machineState == KMachineState_PoweredOff || m_machineState == KMachineState_Saved || 707 m_machineState == KMachineState_Teleported || m_machineState == KMachineState_Aborted) 708 { 709 /* VM has been powered off or saved or aborted, no matter internally or externally. 710 * We must *safely* close the console window unless auto closure is disabled: */ 711 if (!m_bIsPreventAutoClose) 712 machineWindowWrapper()->sltTryClose(); 713 } 714 715 /* Process GURU: */ 716 if (bIsGuruMeditation) 717 { 718 if (machineWindowWrapper()->machineView()) 719 machineWindowWrapper()->machineView()->setIgnoreGuestResize(true); 720 721 CConsole console = session().GetConsole(); 722 QString strLogFolder = console.GetMachine().GetLogFolder(); 723 724 /* Take the screenshot for debugging purposes and save it */ 725 QString strFileName = strLogFolder + "/VBox.png"; 726 CDisplay display = console.GetDisplay(); 727 QImage shot = QImage(display.GetWidth(), display.GetHeight(), QImage::Format_RGB32); 728 display.TakeScreenShot(shot.bits(), shot.width(), shot.height()); 729 shot.save(QFile::encodeName(strFileName), "PNG"); 730 731 /* Warn the user about GURU: */ 732 if (vboxProblem().remindAboutGuruMeditation(console, QDir::toNativeSeparators(strLogFolder))) 733 { 734 qApp->processEvents(); 735 console.PowerDown(); 736 if (!console.isOk()) 737 vboxProblem().cannotStopMachine(console); 738 } 739 } 740 741 #ifdef Q_WS_MAC 742 /* Update Dock Overlay: */ 743 if (machineWindowWrapper()) 744 machineWindowWrapper()->updateDockOverlay(); 745 #endif 746 } 747 } 748 749 void UIMachineLogic::sltAdditionsStateChanged() 750 { 751 /* Get console guest: */ 752 CGuest guest = session().GetConsole().GetGuest(); 753 754 /* Variable flags: */ 755 bool bIsActive = guest.GetAdditionsActive(); 756 bool bIsGraphicsSupported = guest.GetSupportsGraphics(); 757 bool bIsSeamlessSupported = guest.GetSupportsSeamless(); 758 759 /* Update action groups: */ 760 actionsPool()->action(UIActionIndex_Toggle_GuestAutoresize)->setEnabled(bIsActive && bIsGraphicsSupported); 761 actionsPool()->action(UIActionIndex_Toggle_Seamless)->setEnabled(bIsActive && bIsGraphicsSupported && bIsSeamlessSupported); 762 763 /* Store new values: */ 764 m_bIsSeamlessSupported = bIsSeamlessSupported; 765 m_bIsGraphicsSupported = bIsGraphicsSupported; 766 767 #if 0 // TODO: Re-activate seamless if necessary! 768 /* If seamless mode should be enabled then check if it is enabled currently and re-enable it if open-view procedure is finished */ 769 if ((m_bIsSeamlessSupported != bIsSeamlessSupported) || (m_bIsGraphicsSupported != bIsGraphicsSupported)) 770 { 771 if (actionsPool()->action(UIActionIndex_Toggle_Seamless)->isChecked() && m_bIsOpenViewFinished && bIsGraphicsSupported && bIsSeamlessSupported) 772 toggleFullscreenMode(true, true); 773 } 774 #endif 775 776 /* Check the GA version only in case of additions are active: */ 777 if (!bIsActive) 778 return; 779 780 /* Check the Guest Additions version and warn the user about possible compatibility issues in case if the installed version is outdated. */ 781 QString strVersion = guest.GetAdditionsVersion(); 782 uint uVersion = strVersion.toUInt(); 783 /** @todo r=bird: This isn't want we want! We want the VirtualBox version of the additions, all three numbers. See @bugref{4084}.*/ 784 QString strRealVersion = QString("%1.%2").arg(RT_HIWORD(uVersion)).arg(RT_LOWORD(uVersion)); 785 QString strExpectedVersion = QString("%1.%2").arg(VMMDEV_VERSION_MAJOR).arg(VMMDEV_VERSION_MINOR); 786 if (RT_HIWORD(uVersion) < VMMDEV_VERSION_MAJOR) 787 { 788 vboxProblem().warnAboutTooOldAdditions(machineWindowWrapper()->machineWindow(), strRealVersion, strExpectedVersion); 789 } 790 else if (RT_HIWORD(uVersion) == VMMDEV_VERSION_MAJOR && RT_LOWORD(uVersion) < VMMDEV_VERSION_MINOR) 791 { 792 vboxProblem().warnAboutOldAdditions(machineWindowWrapper()->machineWindow(), strRealVersion, strExpectedVersion); 793 } 794 else if (uVersion > VMMDEV_VERSION) 795 { 796 vboxProblem().warnAboutNewAdditions(machineWindowWrapper()->machineWindow(), strRealVersion, strExpectedVersion); 797 } 798 } 799 800 void UIMachineLogic::sltToggleGuestAutoresize(bool /* bEnabled */) 801 { 802 /* Do not process if window or view is missing! */ 803 if (!machineWindowWrapper() || !machineWindowWrapper()->machineView()) 804 return; 805 806 // TODO: Enable/Disable guest-autoresize for machine view! */ 593 807 } 594 808 … … 654 868 /* Suspend the VM and ignore the close event if failed to do so. 655 869 * pause() will show the error message to the user. */ 656 if (!pause( true))870 if (!pause()) 657 871 return; 658 872 } … … 690 904 /* Restore the running state if needed. */ 691 905 if (!bWasPaused) 692 pause(false);906 unpause(); 693 907 } 694 908 … … 716 930 void UIMachineLogic::sltPause(bool aOn) 717 931 { 718 /* Do not process if window is missing! */719 932 pause(aOn); 720 721 /* Update appearance: */722 updateAppearanceOf(UIVisualElement_PauseStuff);723 933 } 724 934 … … 749 959 void UIMachineLogic::sltPrepareStorageMenu() 750 960 { 961 /* Get the sender() menu: */ 751 962 QMenu *pMenu = qobject_cast<QMenu*>(sender()); 752 963 AssertMsg(pMenu, ("This slot should only be called on hovering storage menu!\n")); 753 964 pMenu->clear(); 754 965 966 /* Short way to common storage menus: */ 755 967 QMenu *pOpticalDevicesMenu = actionsPool()->action(UIActionIndex_Menu_OpticalDevices)->menu(); 756 968 QMenu *pFloppyDevicesMenu = actionsPool()->action(UIActionIndex_Menu_FloppyDevices)->menu(); 757 969 970 /* Determine device type: */ 758 971 KDeviceType deviceType = pMenu == pOpticalDevicesMenu ? KDeviceType_DVD : 759 972 pMenu == pFloppyDevicesMenu ? KDeviceType_Floppy : … … 761 974 AssertMsg(deviceType != KDeviceType_Null, ("Incorrect storage device type!\n")); 762 975 976 /* Determine medium type: */ 763 977 VBoxDefs::MediumType mediumType = pMenu == pOpticalDevicesMenu ? VBoxDefs::MediumType_DVD : 764 978 pMenu == pFloppyDevicesMenu ? VBoxDefs::MediumType_Floppy : … … 766 980 AssertMsg(mediumType != VBoxDefs::MediumType_Invalid, ("Incorrect storage medium type!\n")); 767 981 982 /* Fill attachments menu: */ 768 983 CMachine machine = session().GetMachine(); 769 984 const CMediumAttachmentVector &attachments = machine.GetMediumAttachments(); … … 773 988 if (!controller.isNull() && (attachment.GetType() == deviceType)) 774 989 { 775 /* Attachment menu item */990 /* Attachment menu item: */ 776 991 QMenu *pAttachmentMenu = 0; 777 992 if (pMenu->menuAction()->data().toInt() > 1) … … 799 1014 else pAttachmentMenu = pMenu; 800 1015 801 /* Mount Medium actions */1016 /* Mount Medium actions: */ 802 1017 CMediumVector mediums; 803 1018 switch (mediumType) … … 815 1030 } 816 1031 1032 /* Mediums to be shown: */ 817 1033 int mediumsToBeShown = 0; 818 1034 const int maxMediumsToBeShown = 5; … … 846 1062 mountMediumAction->setCheckable(true); 847 1063 mountMediumAction->setChecked(!currentMedium.isNull() && medium.GetId() == currentId); 848 mountMediumAction->setData(QVariant::fromValue(M ountTarget(controller.GetName(),849 attachment.GetPort(),850 attachment.GetDevice(),851 medium.GetId())));1064 mountMediumAction->setData(QVariant::fromValue(MediumTarget(controller.GetName(), 1065 attachment.GetPort(), 1066 attachment.GetDevice(), 1067 medium.GetId()))); 852 1068 connect(mountMediumAction, SIGNAL(triggered(bool)), this, SLOT(sltMountStorageMedium())); 853 1069 pAttachmentMenu->addAction(mountMediumAction); … … 858 1074 } 859 1075 860 /* Virtual Media Manager action */1076 /* Virtual Media Manager action: */ 861 1077 QAction *callVMMAction = new QAction(pAttachmentMenu); 862 1078 callVMMAction->setIcon(QIcon(":/diskimage_16px.png")); 863 callVMMAction->setData(QVariant::fromValue(M ountTarget(controller.GetName(),864 attachment.GetPort(),865 attachment.GetDevice(),866 mediumType)));1079 callVMMAction->setData(QVariant::fromValue(MediumTarget(controller.GetName(), 1080 attachment.GetPort(), 1081 attachment.GetDevice(), 1082 mediumType))); 867 1083 connect(callVMMAction, SIGNAL(triggered(bool)), this, SLOT(sltMountStorageMedium())); 868 1084 pAttachmentMenu->addAction(callVMMAction); 869 1085 870 /* Separator*/1086 /* Insert separator: */ 871 1087 pAttachmentMenu->addSeparator(); 872 1088 873 /* Unmount Medium action */1089 /* Unmount Medium action: */ 874 1090 QAction *unmountMediumAction = new QAction(pAttachmentMenu); 875 1091 unmountMediumAction->setEnabled(!currentMedium.isNull()); 876 unmountMediumAction->setData(QVariant::fromValue(M ountTarget(controller.GetName(),877 attachment.GetPort(),878 attachment.GetDevice())));1092 unmountMediumAction->setData(QVariant::fromValue(MediumTarget(controller.GetName(), 1093 attachment.GetPort(), 1094 attachment.GetDevice()))); 879 1095 connect(unmountMediumAction, SIGNAL(triggered(bool)), this, SLOT(sltMountStorageMedium())); 880 1096 pAttachmentMenu->addAction(unmountMediumAction); … … 905 1121 /* Empty menu item */ 906 1122 Assert(pMenu->isEmpty()); 907 QAction * emptyMenuAction = new QAction(pMenu);908 emptyMenuAction->setEnabled(false);1123 QAction *pEmptyMenuAction = new QAction(pMenu); 1124 pEmptyMenuAction->setEnabled(false); 909 1125 switch (mediumType) 910 1126 { 911 1127 case VBoxDefs::MediumType_DVD: 912 emptyMenuAction->setText(tr("No CD/DVD Devices Attached")); 1128 pEmptyMenuAction->setText(tr("No CD/DVD Devices Attached")); 1129 pEmptyMenuAction->setToolTip(tr("No CD/DVD devices attached to that VM")); 913 1130 break; 914 1131 case VBoxDefs::MediumType_Floppy: 915 emptyMenuAction->setText(tr("No Floppy Devices Attached")); 1132 pEmptyMenuAction->setText(tr("No Floppy Devices Attached")); 1133 pEmptyMenuAction->setToolTip(tr("No floppy devices attached to that VM")); 916 1134 break; 917 1135 default: 918 1136 break; 919 1137 } 920 emptyMenuAction->setIcon(VBoxGlobal::iconSet(":/delete_16px.png", ":/delete_dis_16px.png"));921 pMenu->addAction( emptyMenuAction);1138 pEmptyMenuAction->setIcon(VBoxGlobal::iconSet(":/delete_16px.png", ":/delete_dis_16px.png")); 1139 pMenu->addAction(pEmptyMenuAction); 922 1140 } 923 1141 } … … 925 1143 void UIMachineLogic::sltMountStorageMedium() 926 1144 { 927 /* Get sender action */1145 /* Get sender action: */ 928 1146 QAction *action = qobject_cast<QAction*>(sender()); 929 1147 AssertMsg(action, ("This slot should only be called on selecting storage menu item!\n")); 930 1148 931 /* Get current machine */1149 /* Get current machine: */ 932 1150 CMachine machine = session().GetMachine(); 933 1151 934 /* Get mount-target */935 M ountTarget target = action->data().value<MountTarget>();936 937 /* Current mount-target attributes */1152 /* Get mount-target: */ 1153 MediumTarget target = action->data().value<MediumTarget>(); 1154 1155 /* Current mount-target attributes: */ 938 1156 CMediumAttachment currentAttachment = machine.GetMediumAttachment(target.name, target.port, target.device); 939 1157 CMedium currentMedium = currentAttachment.GetMedium(); 940 1158 QString currentId = currentMedium.isNull() ? QString("") : currentMedium.GetId(); 941 1159 942 /* New mount-target attributes */1160 /* New mount-target attributes: */ 943 1161 QString newId = QString(""); 944 1162 bool selectWithMediaManager = target.type != VBoxDefs::MediumType_Invalid; 945 1163 946 /* Open Virtual Media Manager to select image id */1164 /* Open Virtual Media Manager to select image id: */ 947 1165 if (selectWithMediaManager) 948 1166 { 949 /* Search for already used images */1167 /* Search for already used images: */ 950 1168 QStringList usedImages; 951 1169 foreach (const CMediumAttachment &attachment, machine.GetMediumAttachments()) … … 955 1173 usedImages << medium.GetId(); 956 1174 } 957 /* Open VMM Dialog */1175 /* Open VMM Dialog: */ 958 1176 VBoxMediaManagerDlg dlg(machineWindowWrapper()->machineWindow()); 959 1177 dlg.setup(target.type, true /* select? */, true /* refresh? */, machine, currentId, true, usedImages); … … 962 1180 else return; 963 1181 } 964 /* Use medium which was sent */1182 /* Use medium which was sent: */ 965 1183 else if (!target.id.isNull() && target.id != currentId) 966 1184 newId = target.id; … … 968 1186 bool mount = !newId.isEmpty(); 969 1187 970 /* Remount medium to the predefined port/device */1188 /* Remount medium to the predefined port/device: */ 971 1189 bool wasMounted = false; 972 1190 machine.MountMedium(target.name, target.port, target.device, newId, false /* force */); … … 975 1193 else 976 1194 { 977 /* Ask for force remounting */1195 /* Ask for force remounting: */ 978 1196 if (vboxProblem().cannotRemountMedium(machineWindowWrapper()->machineWindow(), machine, vboxGlobal().findMedium (mount ? newId : currentId), mount, true /* retry? */) == QIMessageBox::Ok) 979 1197 { 980 /* Force remount medium to the predefined port/device .*/1198 /* Force remount medium to the predefined port/device: */ 981 1199 machine.MountMedium(target.name, target.port, target.device, newId, true /* force */); 982 1200 if (machine.isOk()) … … 996 1214 } 997 1215 1216 void UIMachineLogic::sltPrepareUSBMenu() 1217 { 1218 /* Get the sender() menu: */ 1219 QMenu *pMenu = qobject_cast<QMenu*>(sender()); 1220 QMenu *pUSBDevicesMenu = actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu(); 1221 AssertMsg(pMenu == pUSBDevicesMenu, ("This slot should only be called on hovering USB menu!\n")); 1222 pMenu->clear(); 1223 1224 /* Get HOST: */ 1225 CHost host = vboxGlobal().virtualBox().GetHost(); 1226 1227 /* Get USB devices list: */ 1228 CHostUSBDeviceVector devices = host.GetUSBDevices(); 1229 1230 /* Fill USB devices menu: */ 1231 bool bIsUSBListEmpty = devices.size() == 0; 1232 if (bIsUSBListEmpty) 1233 { 1234 /* Fill USB devices menu: */ 1235 QAction *pEmptyMenuAction = new QAction(pMenu); 1236 pEmptyMenuAction->setEnabled(false); 1237 pEmptyMenuAction->setText(tr("No USB Devices Connected")); 1238 pEmptyMenuAction->setIcon(VBoxGlobal::iconSet(":/delete_16px.png", ":/delete_dis_16px.png")); 1239 pEmptyMenuAction->setToolTip(tr("No supported devices connected to the host PC")); 1240 } 1241 else 1242 { 1243 foreach (const CHostUSBDevice hostDevice, devices) 1244 { 1245 /* Get common USB device: */ 1246 CUSBDevice device(hostDevice); 1247 1248 /* Create USB device action: */ 1249 QAction *attachUSBAction = new QAction(vboxGlobal().details(device), pMenu); 1250 attachUSBAction->setCheckable(true); 1251 connect(attachUSBAction, SIGNAL(triggered(bool)), this, SLOT(sltAttachUSBDevice())); 1252 pMenu->addAction(attachUSBAction); 1253 1254 /* Check if that USB device was alread attached to this session: */ 1255 CConsole console = session().GetConsole(); 1256 CUSBDevice attachedDevice = console.FindUSBDeviceById(device.GetId()); 1257 attachUSBAction->setChecked(!attachedDevice.isNull()); 1258 attachUSBAction->setEnabled(hostDevice.GetState() != KUSBDeviceState_Unavailable); 1259 1260 /* Set USB attach data: */ 1261 attachUSBAction->setData(QVariant::fromValue(USBTarget(!attachUSBAction->isChecked(), device.GetId()))); 1262 } 1263 } 1264 } 1265 1266 void UIMachineLogic::sltAttachUSBDevice() 1267 { 1268 /* Get sender action: */ 1269 QAction *action = qobject_cast<QAction*>(sender()); 1270 AssertMsg(action, ("This slot should only be called on selecting USB menu item!\n")); 1271 1272 /* Get current console: */ 1273 CConsole console = session().GetConsole(); 1274 1275 /* Get USB target: */ 1276 USBTarget target = action->data().value<USBTarget>(); 1277 CUSBDevice device = console.FindUSBDeviceById(target.id); 1278 1279 /* Attach USB device: */ 1280 if (target.attach) 1281 { 1282 console.AttachUSBDevice(target.id); 1283 if (!console.isOk()) 1284 vboxProblem().cannotAttachUSBDevice(console, vboxGlobal().details(device)); 1285 } 1286 else 1287 { 1288 console.DetachUSBDevice(target.id); 1289 if (!console.isOk()) 1290 vboxProblem().cannotDetachUSBDevice(console, vboxGlobal().details(device)); 1291 } 1292 } 1293 998 1294 void UIMachineLogic::sltOpenNetworkAdaptersDialog() 999 1295 { … … 1018 1314 } 1019 1315 1020 void UIMachineLogic::sltPrepareUSBMenu()1021 {1022 }1023 1024 void UIMachineLogic::sltAttachUSBDevice()1025 {1026 }1027 1028 1316 void UIMachineLogic::sltSwitchVrdp(bool aOn) 1029 1317 { 1030 1318 /* Enable VRDP server if possible: */ 1031 1319 CVRDPServer server = session().GetMachine().GetVRDPServer(); 1032 AssertMsg(!server.isNull(), ("VRDP Server should not be null!\n"));1320 AssertMsg(!server.isNull(), ("VRDP server should not be null!\n")); 1033 1321 server.SetEnabled(aOn); 1034 1035 /* Update appearance: */1036 updateAppearanceOf(UIVisualElement_VRDPStuff);1037 1322 } 1038 1323 … … 1070 1355 } 1071 1356 1357 #if 0 // TODO: Rework additions downloader logic... 1072 1358 /* Download the required image */ 1073 // TODO: Rework additions downloader logic...1074 #if 01075 1359 int result = vboxProblem().cannotFindGuestAdditions(QDir::toNativeSeparators(strSrc1), QDir::toNativeSeparators(strSrc2)); 1076 1360 if (result == QIMessageBox::Yes) … … 1083 1367 //pdl->start(); 1084 1368 } 1085 1369 #endif 1086 1370 } 1087 1371 … … 1133 1417 #endif 1134 1418 1135 void UIMachineLogic::sltUpdateMachineState(KMachineState machineState) 1136 { 1137 bool bGuruMeditation = false; 1138 1139 if (machineWindowWrapper() && m_machineState != machineState) 1140 { 1141 switch (machineState) 1142 { 1143 case KMachineState_Stuck: 1144 { 1145 bGuruMeditation = true; 1146 break; 1147 } 1148 case KMachineState_Paused: 1149 { 1150 if (!actionsPool()->action(UIActionIndex_Toggle_Pause)->isChecked()) 1151 actionsPool()->action(UIActionIndex_Toggle_Pause)->setChecked(true); 1152 break; 1153 } 1154 case KMachineState_Running: 1155 case KMachineState_Teleporting: 1156 case KMachineState_LiveSnapshotting: 1157 { 1158 if ((m_machineState == KMachineState_Paused || 1159 m_machineState == KMachineState_TeleportingPausedVM) 1160 && actionsPool()->action(UIActionIndex_Toggle_Pause)->isChecked()) 1161 actionsPool()->action(UIActionIndex_Toggle_Pause)->setChecked(false); 1162 break; 1163 } 1164 #ifdef Q_WS_X11 1165 case KMachineState_Starting: 1166 case KMachineState_Restoring: 1167 case KMachineState_TeleportingIn: 1168 { 1169 /* The keyboard handler may wish to do some release logging on startup. 1170 * Tell it that the logger is now active. */ 1171 doXKeyboardLogging(QX11Info::display()); 1172 break; 1173 } 1174 #endif 1175 default: 1176 break; 1177 } 1178 1179 bool bIsRunning = machineState == KMachineState_Running || 1180 machineState == KMachineState_Teleporting || 1181 machineState == KMachineState_LiveSnapshotting; 1182 1183 bool bIsRunningOrPaused = machineState == KMachineState_Running || 1184 machineState == KMachineState_Teleporting || 1185 machineState == KMachineState_LiveSnapshotting || 1186 machineState == KMachineState_Paused; 1187 1188 m_pRunningActions->setEnabled(bIsRunning); 1189 m_pRunningOrPausedActions->setEnabled(bIsRunningOrPaused); 1190 1191 m_machineState = machineState; 1192 1193 updateAppearanceOf(UIVisualElement_WindowCaption | 1194 UIVisualElement_HDStuff | UIVisualElement_CDStuff | UIVisualElement_FDStuff | 1195 UIVisualElement_NetworkStuff | UIVisualElement_USBStuff | UIVisualElement_VRDPStuff | 1196 UIVisualElement_PauseStuff | UIVisualElement_MouseIntegrationStuff); 1197 1198 if (machineState == KMachineState_PoweredOff || 1199 machineState == KMachineState_Saved || 1200 machineState == KMachineState_Teleported || 1201 machineState == KMachineState_Aborted) 1202 { 1203 /* VM has been powered off or saved or aborted, no matter internally or externally. 1204 * We must *safely* close the console window unless auto closure is disabled: */ 1205 if (!m_bIsPreventAutoClose) 1206 machineWindowWrapper()->sltTryClose(); 1207 } 1208 } 1209 1210 if (bGuruMeditation) 1211 { 1212 machineWindowWrapper()->machineView()->setIgnoreGuestResize(true); 1213 1214 CConsole console = session().GetConsole(); 1215 QString strLogFolder = console.GetMachine().GetLogFolder(); 1216 1217 /* Take the screenshot for debugging purposes and save it */ 1218 QString strFileName = strLogFolder + "/VBox.png"; 1219 1220 CDisplay display = console.GetDisplay(); 1221 QImage shot = QImage(display.GetWidth(), display.GetHeight(), QImage::Format_RGB32); 1222 display.TakeScreenShot(shot.bits(), shot.width(), shot.height()); 1223 shot.save(QFile::encodeName(strFileName), "PNG"); 1224 1225 if (vboxProblem().remindAboutGuruMeditation(console, QDir::toNativeSeparators(strLogFolder))) 1226 { 1227 qApp->processEvents(); 1228 console.PowerDown(); 1229 if (!console.isOk()) 1230 vboxProblem().cannotStopMachine(console); 1231 } 1232 } 1233 1234 #ifdef Q_WS_MAC 1235 if (machineWindowWrapper()) 1236 machineWindowWrapper()->updateDockOverlay(); 1237 #endif 1238 } 1239 1240 void UIMachineLogic::sltUpdateAdditionsState(const QString &strVersion, bool bIsActive, 1241 bool bIsSeamlessSupported, bool bIsGraphicsSupported) 1242 { 1243 actionsPool()->action(UIActionIndex_Toggle_GuestAutoresize)->setEnabled(bIsActive && bIsGraphicsSupported); 1244 actionsPool()->action(UIActionIndex_Toggle_Seamless)->setEnabled(bIsActive && bIsGraphicsSupported && bIsSeamlessSupported); 1245 1246 if ((m_bIsSeamlessSupported != bIsSeamlessSupported) || (m_bIsGraphicsSupported != bIsGraphicsSupported)) 1247 { 1248 m_bIsSeamlessSupported = bIsSeamlessSupported; 1249 m_bIsGraphicsSupported = bIsGraphicsSupported; 1250 1251 // TODO: How should that be performed now? 1252 /* If seamless mode should be enabled then check if it is enabled currently and re-enable it if open-view procedure is finished */ 1253 //if (actionsPool()->action(UIActionIndex_Toggle_Seamless)->isChecked() && m_bIsOpenViewFinished && bIsGraphicsSupported && bIsSeamlessSupported) 1254 // toggleFullscreenMode(true, true); 1255 } 1256 1257 /* Check the GA version only in case of additions are active */ 1258 if (!bIsActive) 1259 return; 1260 1261 /* Check the Guest Additions version and warn the user about possible 1262 * compatibility issues in case if the installed version is outdated. */ 1263 uint uVersion = strVersion.toUInt(); 1264 /** @todo r=bird: This isn't want we want! We want the VirtualBox version of the additions, all three numbers. See @bugref{4084}.*/ 1265 QString strRealVersion = QString("%1.%2").arg(RT_HIWORD(uVersion)).arg(RT_LOWORD(uVersion)); 1266 QString strExpectedVersion = QString("%1.%2").arg(VMMDEV_VERSION_MAJOR).arg(VMMDEV_VERSION_MINOR); 1267 1268 if (RT_HIWORD(uVersion) < VMMDEV_VERSION_MAJOR) 1269 { 1270 vboxProblem().warnAboutTooOldAdditions(machineWindowWrapper()->machineWindow(), strRealVersion, strExpectedVersion); 1271 } 1272 else if (RT_HIWORD(uVersion) == VMMDEV_VERSION_MAJOR && RT_LOWORD(uVersion) < VMMDEV_VERSION_MINOR) 1273 { 1274 vboxProblem().warnAboutOldAdditions(machineWindowWrapper()->machineWindow(), strRealVersion, strExpectedVersion); 1275 } 1276 else if (uVersion > VMMDEV_VERSION) 1277 { 1278 vboxProblem().warnAboutNewAdditions(machineWindowWrapper()->machineWindow(), strRealVersion, strExpectedVersion); 1279 } 1280 } 1281 1282 void UIMachineLogic::sltUpdateMouseState(int iState) 1419 void UIMachineLogic::sltMouseStateChanged(int iState) 1283 1420 { 1284 1421 actionsPool()->action(UIActionIndex_Toggle_MouseIntegration)->setEnabled(iState & UIMouseStateType_MouseAbsolute); -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
r26656 r26691 35 35 36 36 /* Local forwards */ 37 class UISession; 37 38 class UIActionsPool; 38 39 class UIMachineWindow; … … 46 47 /* Factory function to create required logic sub-child: */ 47 48 static UIMachineLogic* create(QObject *pParent, 48 const CSession &session,49 UISession *pSession, 49 50 UIActionsPool *pActionsPool, 50 51 UIVisualStateType visualStateType); 51 52 52 53 /* Public getters: */ 53 CSession& session() { return m_session; }54 UISession* uisession() { return m_pSession; } 54 55 UIActionsPool* actionsPool() { return m_pActionsPool; } 56 UIVisualStateType visualStateType() const { return m_visualStateType; } 57 UIMachineWindow* machineWindowWrapper() { return m_pMachineWindowContainer; } 55 58 KMachineState machineState() const { return m_machineState; } 56 UIVisualStateType visualStateType() const { return m_visualStateType; } 57 bool isPaused() const { return m_machineState == KMachineState_Paused || m_machineState == KMachineState_TeleportingPausedVM; } 58 59 /* Public setters: */ 60 bool pause(bool bPaused); 59 bool isPaused() const { return m_machineState == KMachineState_Paused || 60 m_machineState == KMachineState_TeleportingPausedVM; } 61 61 62 62 protected: 63 63 64 /* Common machine logic constructor: */64 /* Machine logic constructor/destructor: */ 65 65 UIMachineLogic(QObject *pParent, 66 const CSession &session,66 UISession *pSession, 67 67 UIActionsPool *pActionsPool, 68 68 UIVisualStateType visualStateType); 69 /* Common machine logic destructor: */70 69 virtual ~UIMachineLogic(); 71 70 72 /* Update routines: */73 virtual void updateAppearanceOf(int iElement);74 75 71 /* Prepare helpers: */ 72 virtual void prepareConsoleConnections(); 76 73 virtual void prepareActionGroups(); 77 74 virtual void prepareActionConnections(); … … 84 81 //void cleanupActionConnections(); 85 82 //void cleanupActionGroups(); 83 //void cleanupConsoleConnections(); 86 84 87 85 /* Protected getters: */ 88 UIMachineWindow* machineWindowWrapper() { return m_pMachineWindowContainer; }86 CSession& session(); 89 87 bool isFirstTimeStarted() const { return m_bIsFirstTimeStarted; } 90 88 bool isPreventAutoClose() const { return m_bIsPreventAutoClose; } … … 95 93 void setOpenViewFinished(bool bIsOpenViewFinished) { m_bIsOpenViewFinished = bIsOpenViewFinished; } 96 94 95 /* Console related routines: */ 96 bool pause() { return pause(true); } 97 bool unpause() { return pause(false); } 98 97 99 /* Protected variables: */ 98 100 UIMachineWindow *m_pMachineWindowContainer; … … 100 102 private slots: 101 103 104 /* Console callback handlers: */ 105 void sltMachineStateChanged(KMachineState newMachineState); 106 void sltAdditionsStateChanged(); 107 102 108 /* "Machine" menu funtionality */ 109 void sltToggleGuestAutoresize(bool bEnabled); 103 110 void sltAdjustWindow(); 104 void sltToggleMouseIntegration(bool b Off);111 void sltToggleMouseIntegration(bool bDisabled); 105 112 void sltTypeCAD(); 106 113 #ifdef Q_WS_X11 … … 117 124 void sltPrepareStorageMenu(); 118 125 void sltMountStorageMedium(); 126 void sltPrepareUSBMenu(); 127 void sltAttachUSBDevice(); 119 128 void sltOpenNetworkAdaptersDialog(); 120 129 void sltOpenSharedFoldersDialog(); 121 void sltPrepareUSBMenu();122 void sltAttachUSBDevice();123 130 void sltSwitchVrdp(bool bOn); 124 131 void sltInstallGuestAdditions(); … … 131 138 #endif 132 139 133 /* Machine state change handler */ 134 void sltUpdateMachineState(KMachineState machineState); 135 /* Guest Additions state change handler */ 136 void sltUpdateAdditionsState(const QString &strVersion, bool bActive, bool bSeamlessSupported, bool bGraphicsSupported); 137 /* Mouse Integration state change handler */ 138 void sltUpdateMouseState(int iState); 140 /* Machine view handlers: */ 141 void sltMouseStateChanged(int iState); 139 142 140 143 private: 141 144 142 145 /* Utility functions: */ 146 bool pause(bool bPaused); 143 147 void installGuestAdditionsFrom(const QString &strSource); 144 static int searchMaxSnapshotIndex(const CMachine &machine, const CSnapshot &snapshot, const QString &strNameTemplate); 145 #ifdef VBOX_WITH_DEBUGGER_GUI 146 bool dbgCreated(); 147 void dbgDestroy(); 148 void dbgAdjustRelativePos(); 149 #endif 150 151 #if 0 // TODO: Where to move that? 152 # ifdef Q_WS_MAC 153 void fadeToBlack(); 154 void fadeToNormal(); 155 # endif 156 bool toggleFullscreenMode(bool aOn, bool aSeamless); 157 void switchToFullscreen(bool aOn, bool aSeamless); 158 void setViewInSeamlessMode(const QRect &aTargetRect); 159 #endif 148 static int searchMaxSnapshotIndex(const CMachine &machine, 149 const CSnapshot &snapshot, 150 const QString &strNameTemplate); 160 151 161 152 /* Private variables: */ 162 CSession m_session;153 UISession *m_pSession; 163 154 UIActionsPool *m_pActionsPool; 164 155 KMachineState m_machineState; … … 175 166 bool m_bIsPreventAutoClose : 1; 176 167 168 /* Friend classes: */ 169 friend class UIMachineWindow; 170 177 171 #ifdef VBOX_WITH_DEBUGGER_GUI 172 /* Debugger functionality: */ 173 bool dbgCreated(); 174 void dbgDestroy(); 175 void dbgAdjustRelativePos(); 178 176 /* The handle to the debugger gui: */ 179 177 PDBGGUI m_dbgGui; … … 181 179 PCDBGGUIVT m_dbgGuiVT; 182 180 #endif 181 182 #if 0 // TODO: Where to move that? 183 # ifdef Q_WS_MAC 184 void fadeToBlack(); 185 void fadeToNormal(); 186 # endif 187 bool toggleFullscreenMode(bool aOn, bool aSeamless); 188 void switchToFullscreen(bool aOn, bool aSeamless); 189 void setViewInSeamlessMode(const QRect &aTargetRect); 190 #endif 183 191 }; 184 192 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp
r26637 r26691 32 32 #include "VBoxProblemReporter.h" 33 33 #include "UIFrameBuffer.h" 34 #include "UISession.h" 34 35 #include "UIActionsPool.h" 35 36 #include "UIMachineLogic.h" … … 84 85 #endif /* defined (Q_WS_MAC) */ 85 86 86 /** Guest mouse pointer shape change event. */87 class MousePointerChangeEvent : public QEvent88 {89 public:90 91 MousePointerChangeEvent (bool visible, bool alpha, uint xhot, uint yhot, uint width, uint height, const uchar *shape)92 : QEvent((QEvent::Type)VBoxDefs::MousePointerChangeEventType)93 , vis(visible), alph(alpha), xh(xhot), yh(yhot), w(width), h(height), data(0)94 {95 uint dataSize = ((((width + 7) / 8 * height) + 3) & ~3) + width * 4 * height;96 97 if (shape)98 {99 data = new uchar[dataSize];100 memcpy((void*)data, (void*)shape, dataSize);101 }102 }103 104 ~MousePointerChangeEvent()105 {106 if (data) delete[] data;107 }108 109 bool isVisible() const { return vis; }110 bool hasAlpha() const { return alph; }111 uint xHot() const { return xh; }112 uint yHot() const { return yh; }113 uint width() const { return w; }114 uint height() const { return h; }115 const uchar *shapeData() const { return data; }116 117 private:118 119 bool vis, alph;120 uint xh, yh, w, h;121 const uchar *data;122 };123 124 /** Guest mouse absolute positioning capability change event. */125 class MouseCapabilityEvent : public QEvent126 {127 public:128 129 MouseCapabilityEvent (bool supportsAbsolute, bool needsHostCursor)130 : QEvent((QEvent::Type) VBoxDefs::MouseCapabilityEventType)131 , can_abs(supportsAbsolute), needs_host_cursor(needsHostCursor) {}132 133 bool supportsAbsolute() const { return can_abs; }134 bool needsHostCursor() const { return needs_host_cursor; }135 136 private:137 138 bool can_abs;139 bool needs_host_cursor;140 };141 142 /** Machine state change. */143 class StateChangeEvent : public QEvent144 {145 public:146 147 StateChangeEvent (KMachineState state)148 : QEvent((QEvent::Type)VBoxDefs::MachineStateChangeEventType)149 , s (state) {}150 151 KMachineState machineState() const { return s; }152 153 private:154 155 KMachineState s;156 };157 158 /** Guest Additions property changes. */159 class GuestAdditionsEvent : public QEvent160 {161 public:162 163 GuestAdditionsEvent (const QString &aOsTypeId,164 const QString &aAddVersion,165 bool aAddActive,166 bool aSupportsSeamless,167 bool aSupportsGraphics)168 : QEvent((QEvent::Type)VBoxDefs::AdditionsStateChangeEventType)169 , mOsTypeId(aOsTypeId), mAddVersion(aAddVersion)170 , mAddActive(aAddActive), mSupportsSeamless(aSupportsSeamless)171 , mSupportsGraphics (aSupportsGraphics) {}172 173 const QString &osTypeId() const { return mOsTypeId; }174 const QString &additionVersion() const { return mAddVersion; }175 bool additionActive() const { return mAddActive; }176 bool supportsSeamless() const { return mSupportsSeamless; }177 bool supportsGraphics() const { return mSupportsGraphics; }178 179 private:180 181 QString mOsTypeId;182 QString mAddVersion;183 bool mAddActive;184 bool mSupportsSeamless;185 bool mSupportsGraphics;186 };187 188 /** DVD/Floppy drive change event */189 class MediaDriveChangeEvent : public QEvent190 {191 public:192 193 MediaDriveChangeEvent(VBoxDefs::MediumType aType)194 : QEvent ((QEvent::Type) VBoxDefs::MediaDriveChangeEventType)195 , mType (aType) {}196 VBoxDefs::MediumType type() const { return mType; }197 198 private:199 200 VBoxDefs::MediumType mType;201 };202 203 87 /** Menu activation event */ 204 88 class ActivateMenuEvent : public QEvent … … 216 100 }; 217 101 218 /** VM Runtime error event */219 class RuntimeErrorEvent : public QEvent220 {221 public:222 223 RuntimeErrorEvent(bool aFatal, const QString &aErrorID, const QString &aMessage)224 : QEvent((QEvent::Type)VBoxDefs::RuntimeErrorEventType)225 , mFatal(aFatal), mErrorID(aErrorID), mMessage(aMessage) {}226 227 bool fatal() const { return mFatal; }228 QString errorID() const { return mErrorID; }229 QString message() const { return mMessage; }230 231 private:232 233 bool mFatal;234 QString mErrorID;235 QString mMessage;236 };237 238 /** Modifier key change event */239 class ModifierKeyChangeEvent : public QEvent240 {241 public:242 243 ModifierKeyChangeEvent(bool fNumLock, bool fCapsLock, bool fScrollLock)244 : QEvent((QEvent::Type)VBoxDefs::ModifierKeyChangeEventType)245 , mNumLock(fNumLock), mCapsLock(fCapsLock), mScrollLock(fScrollLock) {}246 247 bool numLock() const { return mNumLock; }248 bool capsLock() const { return mCapsLock; }249 bool scrollLock() const { return mScrollLock; }250 251 private:252 253 bool mNumLock, mCapsLock, mScrollLock;254 };255 256 /** Network adapter change event */257 class NetworkAdapterChangeEvent : public QEvent258 {259 public:260 261 NetworkAdapterChangeEvent(INetworkAdapter *aAdapter)262 : QEvent((QEvent::Type)VBoxDefs::NetworkAdapterChangeEventType)263 , mAdapter(aAdapter) {}264 265 INetworkAdapter* networkAdapter() { return mAdapter; }266 267 private:268 269 INetworkAdapter *mAdapter;270 };271 272 /** USB controller state change event */273 class USBControllerStateChangeEvent : public QEvent274 {275 public:276 277 USBControllerStateChangeEvent()278 : QEvent((QEvent::Type)VBoxDefs::USBCtlStateChangeEventType) {}279 };280 281 /** USB device state change event */282 class USBDeviceStateChangeEvent : public QEvent283 {284 public:285 286 USBDeviceStateChangeEvent(const CUSBDevice &aDevice, bool aAttached, const CVirtualBoxErrorInfo &aError)287 : QEvent((QEvent::Type)VBoxDefs::USBDeviceStateChangeEventType)288 , mDevice(aDevice), mAttached(aAttached), mError(aError) {}289 290 CUSBDevice device() const { return mDevice; }291 bool attached() const { return mAttached; }292 CVirtualBoxErrorInfo error() const { return mError; }293 294 private:295 296 CUSBDevice mDevice;297 bool mAttached;298 CVirtualBoxErrorInfo mError;299 };300 301 102 class VBoxViewport: public QWidget 302 103 { … … 317 118 } 318 119 }; 319 320 class UIConsoleCallback : VBOX_SCRIPTABLE_IMPL(IConsoleCallback)321 {322 public:323 324 UIConsoleCallback (UIMachineView *v)325 {326 #if defined (Q_WS_WIN)327 mRefCnt = 0;328 #endif329 mView = v;330 }331 332 virtual ~UIConsoleCallback() {}333 334 NS_DECL_ISUPPORTS335 336 #if defined (Q_WS_WIN)337 STDMETHOD_(ULONG, AddRef)()338 {339 return ::InterlockedIncrement(&mRefCnt);340 }341 STDMETHOD_(ULONG, Release)()342 {343 long cnt = ::InterlockedDecrement(&mRefCnt);344 if (cnt == 0)345 delete this;346 return cnt;347 }348 #endif349 VBOX_SCRIPTABLE_DISPATCH_IMPL(IConsoleCallback)350 351 STDMETHOD(OnMousePointerShapeChange) (BOOL visible, BOOL alpha,352 ULONG xhot, ULONG yhot,353 ULONG width, ULONG height,354 BYTE *shape)355 {356 QApplication::postEvent(mView, new MousePointerChangeEvent(visible, alpha, xhot, yhot, width, height, shape));357 return S_OK;358 }359 360 STDMETHOD(OnMouseCapabilityChange)(BOOL supportsAbsolute, BOOL needsHostCursor)361 {362 QApplication::postEvent(mView, new MouseCapabilityEvent (supportsAbsolute, needsHostCursor));363 return S_OK;364 }365 366 STDMETHOD(OnKeyboardLedsChange)(BOOL fNumLock, BOOL fCapsLock, BOOL fScrollLock)367 {368 QApplication::postEvent(mView, new ModifierKeyChangeEvent (fNumLock, fCapsLock, fScrollLock));369 return S_OK;370 }371 372 STDMETHOD(OnStateChange)(MachineState_T machineState)373 {374 QApplication::postEvent(mView, new StateChangeEvent ((KMachineState) machineState));375 return S_OK;376 }377 378 STDMETHOD(OnAdditionsStateChange)()379 {380 CGuest guest = mView->console().GetGuest();381 QApplication::postEvent (mView, new GuestAdditionsEvent(guest.GetOSTypeId(), guest.GetAdditionsVersion(),382 guest.GetAdditionsActive(), guest.GetSupportsSeamless(),383 guest.GetSupportsGraphics()));384 return S_OK;385 }386 387 STDMETHOD(OnNetworkAdapterChange) (INetworkAdapter *aNetworkAdapter)388 {389 QApplication::postEvent (mView, new NetworkAdapterChangeEvent (aNetworkAdapter));390 return S_OK;391 }392 393 STDMETHOD(OnStorageControllerChange) ()394 {395 //QApplication::postEvent(mView, new StorageControllerChangeEvent());396 return S_OK;397 }398 399 STDMETHOD(OnMediumChange)(IMediumAttachment *aMediumAttachment)400 {401 CMediumAttachment att(aMediumAttachment);402 switch (att.GetType())403 {404 case KDeviceType_Floppy:405 QApplication::postEvent(mView, new MediaDriveChangeEvent(VBoxDefs::MediumType_Floppy));406 break;407 case KDeviceType_DVD:408 QApplication::postEvent(mView, new MediaDriveChangeEvent(VBoxDefs::MediumType_DVD));409 break;410 default:411 break;412 }413 return S_OK;414 }415 416 STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove)417 {418 NOREF(aCPU);419 NOREF(aRemove);420 return S_OK;421 }422 423 STDMETHOD(OnSerialPortChange) (ISerialPort *aSerialPort)424 {425 NOREF(aSerialPort);426 return S_OK;427 }428 429 STDMETHOD(OnParallelPortChange) (IParallelPort *aParallelPort)430 {431 NOREF(aParallelPort);432 return S_OK;433 }434 435 STDMETHOD(OnVRDPServerChange)()436 {437 return S_OK;438 }439 440 STDMETHOD(OnRemoteDisplayInfoChange)()441 {442 return S_OK;443 }444 445 STDMETHOD(OnUSBControllerChange)()446 {447 QApplication::postEvent (mView, new USBControllerStateChangeEvent());448 return S_OK;449 }450 451 STDMETHOD(OnUSBDeviceStateChange)(IUSBDevice *aDevice, BOOL aAttached, IVirtualBoxErrorInfo *aError)452 {453 QApplication::postEvent (mView, new USBDeviceStateChangeEvent(CUSBDevice(aDevice), bool(aAttached), CVirtualBoxErrorInfo(aError)));454 return S_OK;455 }456 457 STDMETHOD(OnSharedFolderChange) (Scope_T aScope)458 {459 NOREF(aScope);460 QApplication::postEvent (mView, new QEvent((QEvent::Type)VBoxDefs::SharedFolderChangeEventType));461 return S_OK;462 }463 464 STDMETHOD(OnRuntimeError)(BOOL fatal, IN_BSTR id, IN_BSTR message)465 {466 QApplication::postEvent (mView, new RuntimeErrorEvent(!!fatal, QString::fromUtf16(id), QString::fromUtf16(message)));467 return S_OK;468 }469 470 STDMETHOD(OnCanShowWindow) (BOOL *canShow)471 {472 if (!canShow)473 return E_POINTER;474 475 *canShow = TRUE;476 return S_OK;477 }478 479 STDMETHOD(OnShowWindow) (ULONG64 *winId)480 {481 if (!winId)482 return E_POINTER;483 484 #if defined (Q_WS_MAC)485 /*486 * Let's try the simple approach first - grab the focus.487 * Getting a window out of the dock (minimized or whatever it's called)488 * needs to be done on the GUI thread, so post it a note.489 */490 *winId = 0;491 if (!mView)492 return S_OK;493 494 ProcessSerialNumber psn = { 0, kCurrentProcess };495 OSErr rc = ::SetFrontProcess (&psn);496 if (!rc)497 QApplication::postEvent(mView, new QEvent((QEvent::Type)VBoxDefs::ShowWindowEventType));498 else499 {500 /*501 * It failed for some reason, send the other process our PSN so it can try.502 * (This is just a precaution should Mac OS X start imposing the same sensible503 * focus stealing restrictions that other window managers implement.)504 */505 AssertMsgFailed(("SetFrontProcess -> %#x\n", rc));506 if (::GetCurrentProcess (&psn))507 *winId = RT_MAKE_U64(psn.lowLongOfPSN, psn.highLongOfPSN);508 }509 510 #else511 /* Return the ID of the top-level console window. */512 *winId = (ULONG64)mView->window()->winId();513 #endif514 515 return S_OK;516 }517 518 protected:519 520 UIMachineView *mView;521 522 #if defined (Q_WS_WIN)523 private:524 long mRefCnt;525 #endif526 };527 528 #if !defined (Q_WS_WIN)529 NS_DECL_CLASSINFO(UIConsoleCallback)530 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(UIConsoleCallback, IConsoleCallback)531 #endif532 120 533 121 UIMachineView* UIMachineView::create( UIMachineWindow *pMachineWindow … … 659 247 /* Private members: */ 660 248 , m_pMachineWindow(pMachineWindow) 661 , m_console(pMachineWindow->machineLogic()-> session().GetConsole())249 , m_console(pMachineWindow->machineLogic()->uisession()->session().GetConsole()) 662 250 , m_globalSettings(vboxGlobal().settings()) 663 251 , m_iLastMouseWheelDelta(0) … … 861 449 } 862 450 863 /* setup the callback */864 mCallback = CConsoleCallback(new UIConsoleCallback(this));865 m_console.RegisterCallback(mCallback);866 AssertWrapperOk(m_console);867 868 451 QPalette palette(viewport()->palette()); 869 452 palette.setColor(viewport()->backgroundRole(), Qt::black); … … 942 525 mFrameBuf = NULL; 943 526 } 944 945 m_console.UnregisterCallback(mCallback);946 527 947 528 #if defined (Q_WS_MAC) … … 1224 805 #endif 1225 806 1226 case VBoxDefs::MousePointerChangeEventType:1227 {1228 MousePointerChangeEvent *me = (MousePointerChangeEvent *) e;1229 /* change cursor shape only when mouse integration is1230 * supported (change mouse shape type event may arrive after1231 * mouse capability change that disables integration */1232 if (m_bIsMouseAbsolute)1233 setPointerShape (me);1234 else1235 /* Note: actually we should still remember the requested1236 * cursor shape. If we can't do that, at least remember1237 * the requested visiblilty. */1238 mHideHostPointer = !me->isVisible();1239 return true;1240 }1241 case VBoxDefs::MouseCapabilityEventType:1242 {1243 MouseCapabilityEvent *me = (MouseCapabilityEvent *) e;1244 if (m_bIsMouseAbsolute != me->supportsAbsolute())1245 {1246 m_bIsMouseAbsolute = me->supportsAbsolute();1247 /* correct the mouse capture state and reset the cursor1248 * to the default shape if necessary */1249 if (m_bIsMouseAbsolute)1250 {1251 CMouse mouse = m_console.GetMouse();1252 mouse.PutMouseEventAbsolute (-1, -1, 0,1253 0 /* Horizontal wheel */,1254 0);1255 captureMouse (false, false);1256 }1257 else1258 viewport()->unsetCursor();1259 emitMouseStateChanged();1260 vboxProblem().remindAboutMouseIntegration (m_bIsMouseAbsolute);1261 }1262 if (me->needsHostCursor())1263 setMouseIntegrationLocked (false);1264 else1265 setMouseIntegrationLocked (true);1266 return true;1267 }1268 1269 case VBoxDefs::ModifierKeyChangeEventType:1270 {1271 ModifierKeyChangeEvent *me = (ModifierKeyChangeEvent* )e;1272 if (me->numLock() != mNumLock)1273 muNumLockAdaptionCnt = 2;1274 if (me->capsLock() != mCapsLock)1275 muCapsLockAdaptionCnt = 2;1276 mNumLock = me->numLock();1277 mCapsLock = me->capsLock();1278 mScrollLock = me->scrollLock();1279 return true;1280 }1281 1282 case VBoxDefs::MachineStateChangeEventType:1283 {1284 StateChangeEvent *me = (StateChangeEvent *) e;1285 LogFlowFunc (("MachineStateChangeEventType: state=%d\n",1286 me->machineState()));1287 onStateChange (me->machineState());1288 emit machineStateChanged (me->machineState());1289 return true;1290 }1291 1292 case VBoxDefs::AdditionsStateChangeEventType:1293 {1294 GuestAdditionsEvent *ge = (GuestAdditionsEvent *) e;1295 LogFlowFunc (("AdditionsStateChangeEventType\n"));1296 1297 /* Always send a size hint if we are in fullscreen or seamless1298 * when the graphics capability is enabled, in case the host1299 * resolution has changed since the VM was last run. */1300 #if 01301 if (!mDoResize && !m_bIsGuestSupportsGraphics &&1302 ge->supportsGraphics() &&1303 (machineWindowWrapper()->isTrueSeamless() || machineWindowWrapper()->isTrueFullscreen()))1304 mDoResize = true;1305 #endif1306 1307 m_bIsGuestSupportsGraphics = ge->supportsGraphics();1308 1309 maybeRestrictMinimumSize();1310 1311 #if 01312 /* This will only be acted upon if mDoResize is true. */1313 doResizeHint();1314 #endif1315 1316 emit additionsStateChanged (ge->additionVersion(),1317 ge->additionActive(),1318 ge->supportsSeamless(),1319 ge->supportsGraphics());1320 return true;1321 }1322 1323 case VBoxDefs::MediaDriveChangeEventType:1324 {1325 MediaDriveChangeEvent *mce = (MediaDriveChangeEvent *) e;1326 LogFlowFunc (("MediaChangeEvent\n"));1327 1328 emit mediaDriveChanged (mce->type());1329 return true;1330 }1331 1332 807 #if 0 1333 808 case VBoxDefs::ActivateMenuEventType: … … 1350 825 } 1351 826 #endif 1352 1353 case VBoxDefs::NetworkAdapterChangeEventType:1354 {1355 /* no specific adapter information stored in this1356 * event is currently used */1357 emit networkStateChange();1358 return true;1359 }1360 1361 case VBoxDefs::USBCtlStateChangeEventType:1362 {1363 emit usbStateChange();1364 return true;1365 }1366 1367 case VBoxDefs::USBDeviceStateChangeEventType:1368 {1369 USBDeviceStateChangeEvent *ue = (USBDeviceStateChangeEvent *)e;1370 1371 bool success = ue->error().isNull();1372 1373 if (!success)1374 {1375 if (ue->attached())1376 vboxProblem().cannotAttachUSBDevice (1377 m_console,1378 vboxGlobal().details (ue->device()), ue->error());1379 else1380 vboxProblem().cannotDetachUSBDevice (1381 m_console,1382 vboxGlobal().details (ue->device()), ue->error());1383 }1384 1385 emit usbStateChange();1386 1387 return true;1388 }1389 1390 case VBoxDefs::SharedFolderChangeEventType:1391 {1392 emit sharedFoldersChanged();1393 return true;1394 }1395 1396 case VBoxDefs::RuntimeErrorEventType:1397 {1398 RuntimeErrorEvent *ee = (RuntimeErrorEvent *) e;1399 vboxProblem().showRuntimeError (m_console, ee->fatal(),1400 ee->errorID(), ee->message());1401 return true;1402 }1403 827 1404 828 case QEvent::KeyPress: … … 3474 2898 } 3475 2899 2900 #if 0 3476 2901 void UIMachineView::setPointerShape(MousePointerChangeEvent *pEvent) 3477 2902 { … … 3730 3155 mHideHostPointer = !pEvent->isVisible(); 3731 3156 } 3157 #endif 3732 3158 3733 3159 inline QRgb qRgbIntensity(QRgb rgb, int mul, int div) -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
r26637 r26691 28 28 class UIMachineWindow; 29 29 class VBoxGlobalSettings; 30 class MousePointerChangeEvent;31 30 32 31 /* Global includes */ … … 200 199 void sendChangedKeyStates(); 201 200 void updateMouseClipping(); 202 void setPointerShape(MousePointerChangeEvent *pEvent);201 //void setPointerShape(MousePointerChangeEvent *pEvent); 203 202 204 203 enum DesktopGeo { DesktopGeo_Invalid = 0, DesktopGeo_Fixed, DesktopGeo_Automatic, DesktopGeo_Any }; … … 264 263 265 264 UIFrameBuffer *mFrameBuf; 266 CConsoleCallback mCallback;267 265 268 266 QPixmap mPausedShot; … … 280 278 bool mHideHostPointer; 281 279 QCursor mLastCursor; 282 283 friend class UIConsoleCallback;284 280 }; 285 281 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
r26656 r26691 23 23 /* Global includes */ 24 24 #include <QCloseEvent> 25 #include <QTimer> 25 26 26 27 /* Local includes */ … … 29 30 #include "VBoxCloseVMDlg.h" 30 31 32 #include "UISession.h" 31 33 #include "UIMachineLogic.h" 32 34 #include "UIMachineWindow.h" … … 61 63 } 62 64 65 void UIMachineWindow::sltTryClose() 66 { 67 /* First close any open modal & popup widgets. 68 * Use a single shot with timeout 0 to allow the widgets to cleany close and test then again. 69 * If all open widgets are closed destroy ourself: */ 70 QWidget *widget = QApplication::activeModalWidget() ? 71 QApplication::activeModalWidget() : 72 QApplication::activePopupWidget() ? 73 QApplication::activePopupWidget() : 0; 74 if (widget) 75 { 76 widget->close(); 77 QTimer::singleShot(0, machineWindow(), SLOT(sltTryClose())); 78 } 79 else 80 machineWindow()->close(); 81 } 82 63 83 UIMachineWindow::UIMachineWindow(UIMachineLogic *pMachineLogic) 64 84 : m_pMachineLogic(pMachineLogic) … … 89 109 void UIMachineWindow::updateAppearanceOf(int iElement) 90 110 { 91 CMachine machine = machineLogic()->session().GetMachine();111 CMachine machine = session().GetMachine(); 92 112 93 113 if (iElement & UIVisualElement_WindowCaption) … … 119 139 #ifndef Q_WS_MAC 120 140 /* Set the VM-specific application icon except Mac OS X: */ 121 CMachine machine = machineLogic()->session().GetMachine(); 122 machineWindow()->setWindowIcon(vboxGlobal().vmGuestOSTypeIcon(machine.GetOSTypeId())); 123 #endif 141 machineWindow()->setWindowIcon(vboxGlobal().vmGuestOSTypeIcon(session().GetMachine().GetOSTypeId())); 142 #endif 143 } 144 145 void UIMachineWindow::prepareConsoleConnections() 146 { 147 QObject::connect(machineLogic()->uisession(), SIGNAL(sigStateChange(KMachineState)), 148 machineWindow(), SLOT(sltMachineStateChanged(KMachineState))); 124 149 } 125 150 … … 130 155 /* Default to true if it is an empty value */ 131 156 bool bIsDockIconEnabled = testStr.isEmpty() || testStr == "true"; 132 machineView()->setDockIconEnabled(bIsDockIconEnabled); 133 machineView()->updateDockOverlay(); 157 if (machineView()) 158 { 159 machineView()->setDockIconEnabled(bIsDockIconEnabled); 160 machineView()->updateDockOverlay(); 161 } 134 162 #endif 135 163 } … … 142 170 static const char *pstrDiscardCurState = "discardCurState"; 143 171 144 if (!machine View())172 if (!machineWindow()) 145 173 { 146 174 pEvent->accept(); … … 174 202 pEvent->ignore(); 175 203 176 bool isACPIEnabled = machineLogic()->session().GetConsole().GetGuestEnteredACPIMode();204 bool isACPIEnabled = session().GetConsole().GetGuestEnteredACPIMode(); 177 205 178 206 bool success = true; … … 185 213 /* Suspend the VM and ignore the close event if failed to do so. 186 214 * pause() will show the error message to the user. */ 187 success = machineLogic()->pause( true);215 success = machineLogic()->pause(); 188 216 } 189 217 … … 192 220 success = false; 193 221 194 CMachine machine = machineLogic()->session().GetMachine();222 CMachine machine = session().GetMachine(); 195 223 VBoxCloseVMDlg dlg(machineWindow()); 196 224 QString typeId = machine.GetOSTypeId(); … … 243 271 //m_bNoAutoClose = true; 244 272 245 CConsole console = machineLogic()->session().GetConsole();273 CConsole console = session().GetConsole(); 246 274 247 275 if (dlg.mRbSave->isChecked()) … … 264 292 { 265 293 /* Unpause the VM to let it grab the ACPI shutdown event */ 266 machineLogic()-> pause(false);294 machineLogic()->unpause(); 267 295 /* Prevent the subsequent unpause request */ 268 296 wasPaused = true; … … 364 392 /* Restore the running state if needed */ 365 393 if (!wasPaused && machineLogic()->machineState() == KMachineState_Paused) 366 machineLogic()-> pause(false);394 machineLogic()->unpause(); 367 395 } 368 396 } … … 393 421 } 394 422 } 423 424 CSession UIMachineWindow::session() 425 { 426 return m_pMachineLogic->uisession()->session(); 427 } 428 429 void UIMachineWindow::sltMachineStateChanged(KMachineState /* machineState */) 430 { 431 updateAppearanceOf(UIVisualElement_WindowCaption); 432 } -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.h
r26656 r26691 25 25 26 26 /* Local includes */ 27 #include "COMDefs.h" 27 28 #include "UIMachineDefs.h" 28 29 29 30 /* Global forwards */ 30 31 class QWidget; 32 class QCloseEvent; 31 33 32 34 /* Local forwards */ … … 43 45 44 46 /* Abstract slot to close machine window: */ 45 virtual void sltTryClose() = 0;47 virtual void sltTryClose(); 46 48 47 49 /* Public getters: */ … … 64 66 /* Prepare helpers: */ 65 67 virtual void prepareWindowIcon(); 68 virtual void prepareConsoleConnections(); 66 69 virtual void loadWindowSettings(); 67 70 68 71 /* Cleanup helpers: */ 69 72 //virtual void saveWindowSettings(); 73 //virtual void cleanupConsoleConnections(); 70 74 //virtual void cleanupWindowIcon(); 71 75 … … 74 78 75 79 /* Protected getters: */ 80 CSession session(); 76 81 const QString& defaultWindowTitle() const { return m_strWindowTitlePrefix; } 82 83 /* Protected signals: */ 84 void sltMachineStateChanged(KMachineState machineState); 77 85 78 86 /* Protected variables: */ -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
r26688 r26691 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VBoxConsoleView classimplementation4 * UISession stuff implementation 5 5 */ 6 6 7 7 /* 8 * Copyright (C) 2 2006-2007Sun Microsystems, Inc.8 * Copyright (C) 2010 Sun Microsystems, Inc. 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 */ 22 22 23 #ifdef VBOX_WITH_PRECOMPILED_HEADERS 24 # include "precomp.h" 25 #else /* !VBOX_WITH_PRECOMPILED_HEADERS */ 26 #include <VBox/VBoxVideo.h> 27 28 #include "VBoxConsoleView.h" 29 #include "VBoxConsoleWnd.h" 30 #include "VBoxUtils.h" 31 32 #include "VBoxFrameBuffer.h" 33 #include "VBoxGlobal.h" 34 #include "VBoxProblemReporter.h" 35 36 #ifdef Q_WS_PM 37 #include "QIHotKeyEdit.h" 38 #endif 39 40 /* Qt includes */ 41 #include <QMenuBar> 42 #include <QDesktopWidget> 43 #include <QTimer> 44 #include <QStatusBar> 45 #include <QPainter> 46 #include <QBitmap> 47 48 #endif /* !VBOX_WITH_PRECOMPILED_HEADERS */ /** @todo Move this further down! Requires some cleanup below though, so later. */ 49 50 #ifdef Q_WS_WIN 51 // VBox/cdefs.h defines these: 52 #undef LOWORD 53 #undef HIWORD 54 #undef LOBYTE 55 #undef HIBYTE 56 #include <windows.h> 57 #endif 58 59 #ifdef Q_WS_X11 60 #include <QX11Info> 61 // We need to capture some X11 events directly which 62 // requires the XEvent structure to be defined. However, 63 // including the Xlib header file will cause some nasty 64 // conflicts with Qt. Therefore we use the following hack 65 // to redefine those conflicting identifiers. 66 #define XK_XKB_KEYS 67 #define XK_MISCELLANY 68 #include <X11/Xlib.h> 69 #include <X11/Xutil.h> 70 #include <X11/XKBlib.h> 71 #include <X11/keysym.h> 72 #ifdef KeyPress 73 const int XFocusOut = FocusOut; 74 const int XFocusIn = FocusIn; 75 const int XKeyPress = KeyPress; 76 const int XKeyRelease = KeyRelease; 77 #undef KeyRelease 78 #undef KeyPress 79 #undef FocusOut 80 #undef FocusIn 81 #endif 82 #include "XKeyboard.h" 83 #ifndef VBOX_WITHOUT_XCURSOR 84 # include <X11/Xcursor/Xcursor.h> 85 #endif 86 #endif // Q_WS_X11 23 /* Global inclues */ 24 #include <QApplication> 25 #include <QWidget> 26 27 /* Local includes */ 28 #include "UISession.h" 29 30 #include "UIMachine.h" 31 #include "UIMachineLogic.h" 32 #include "UIMachineWindow.h" 33 34 /* Guest mouse pointer shape change event: */ 35 class UIMousePointerShapeChangeEvent : public QEvent 36 { 37 public: 38 39 UIMousePointerShapeChangeEvent(bool bIsVisible, bool bIsAlpha, uint uXHot, uint uYHot, uint uWidth, uint uHeight, const uchar *pShape) 40 : QEvent((QEvent::Type)UIConsoleEventType_MousePointerShapeChange) 41 , m_bIsVisible(bIsVisible), m_bIsAlpha(bIsAlpha), m_uXHot(uXHot), m_uYHot(uYHot), m_uWidth(uWidth), m_uHeight(uHeight), m_pData(0) 42 { 43 uint dataSize = ((((m_uWidth + 7) / 8 * m_uHeight) + 3) & ~3) + m_uWidth * 4 * m_uHeight; 44 if (pShape) 45 { 46 m_pData = new uchar[dataSize]; 47 memcpy((void*)m_pData, (void*)pShape, dataSize); 48 } 49 } 50 51 virtual ~UIMousePointerShapeChangeEvent() 52 { 53 if (m_pData) delete[] m_pData; 54 } 55 56 bool isVisible() const { return m_bIsVisible; } 57 bool hasAlpha() const { return m_bIsAlpha; } 58 uint xHot() const { return m_uXHot; } 59 uint yHot() const { return m_uYHot; } 60 uint width() const { return m_uWidth; } 61 uint height() const { return m_uHeight; } 62 const uchar *shapeData() const { return m_pData; } 63 64 private: 65 66 bool m_bIsVisible, m_bIsAlpha; 67 uint m_uXHot, m_uYHot, m_uWidth, m_uHeight; 68 const uchar *m_pData; 69 }; 70 71 /* Guest mouse absolute positioning capability change event: */ 72 class UIMouseCapabilityChangeEvent : public QEvent 73 { 74 public: 75 76 UIMouseCapabilityChangeEvent(bool bSupportsAbsolute, bool bNeedsHostCursor) 77 : QEvent((QEvent::Type)UIConsoleEventType_MouseCapabilityChange) 78 , m_bSupportsAbsolute(bSupportsAbsolute), m_bNeedsHostCursor(bNeedsHostCursor) {} 79 80 bool supportsAbsolute() const { return m_bSupportsAbsolute; } 81 bool needsHostCursor() const { return m_bNeedsHostCursor; } 82 83 private: 84 85 bool m_bSupportsAbsolute; 86 bool m_bNeedsHostCursor; 87 }; 88 89 /* Keyboard LEDs change event: */ 90 class UIKeyboardLedsChangeEvent : public QEvent 91 { 92 public: 93 94 UIKeyboardLedsChangeEvent(bool bNumLock, bool bCapsLock, bool bScrollLock) 95 : QEvent((QEvent::Type)UIConsoleEventType_KeyboardLedsChange) 96 , m_bNumLock(bNumLock), m_bCapsLock(bCapsLock), m_bScrollLock(bScrollLock) {} 97 98 bool numLock() const { return m_bNumLock; } 99 bool capsLock() const { return m_bCapsLock; } 100 bool scrollLock() const { return m_bScrollLock; } 101 102 private: 103 104 bool m_bNumLock; 105 bool m_bCapsLock; 106 bool m_bScrollLock; 107 }; 108 109 /* Machine state change event: */ 110 class UIStateChangeEvent : public QEvent 111 { 112 public: 113 114 UIStateChangeEvent(KMachineState machineState) 115 : QEvent((QEvent::Type)UIConsoleEventType_StateChange) 116 , m_machineState(machineState) {} 117 118 KMachineState machineState() const { return m_machineState; } 119 120 private: 121 122 KMachineState m_machineState; 123 }; 124 125 /* Guest Additions state change event: */ 126 class UIAdditionsStateChangeEvent : public QEvent 127 { 128 public: 129 130 UIAdditionsStateChangeEvent() 131 : QEvent((QEvent::Type)UIConsoleEventType_AdditionsStateChange) {} 132 }; 133 134 /* Network adapter change event: */ 135 class UINetworkAdapterChangeEvent : public QEvent 136 { 137 public: 138 139 UINetworkAdapterChangeEvent(const CNetworkAdapter &networkAdapter) 140 : QEvent((QEvent::Type)UIConsoleEventType_NetworkAdapterChange) 141 , m_networkAdapter(networkAdapter) {} 142 143 const CNetworkAdapter& networkAdapter() { return m_networkAdapter; } 144 145 private: 146 147 const CNetworkAdapter &m_networkAdapter; 148 }; 149 150 /* Serial port change event: */ 151 class UISerialPortChangeEvent : public QEvent 152 { 153 public: 154 155 UISerialPortChangeEvent(const CSerialPort &serialPort) 156 : QEvent((QEvent::Type)UIConsoleEventType_SerialPortChange) 157 , m_serialPort(serialPort) {} 158 159 const CSerialPort& serialPort() { return m_serialPort; } 160 161 private: 162 163 const CSerialPort &m_serialPort; 164 }; 165 166 /* Parallel port change event: */ 167 class UIParallelPortChangeEvent : public QEvent 168 { 169 public: 170 171 UIParallelPortChangeEvent(const CParallelPort ¶llelPort) 172 : QEvent((QEvent::Type)UIConsoleEventType_ParallelPortChange) 173 , m_parallelPort(parallelPort) {} 174 175 const CParallelPort& parallelPort() { return m_parallelPort; } 176 177 private: 178 179 const CParallelPort &m_parallelPort; 180 }; 181 182 /* Storage controller change event: */ 183 class UIStorageControllerChangeEvent : public QEvent 184 { 185 public: 186 187 UIStorageControllerChangeEvent() 188 : QEvent((QEvent::Type)UIConsoleEventType_StorageControllerChange) {} 189 }; 190 191 /* Storage medium change event: */ 192 class UIMediumChangeEvent : public QEvent 193 { 194 public: 195 196 UIMediumChangeEvent(const CMediumAttachment &mediumAttachment) 197 : QEvent((QEvent::Type)UIConsoleEventType_MediumChange) 198 , m_mediumAttachment(mediumAttachment) {} 199 const CMediumAttachment& mediumAttahment() { return m_mediumAttachment; } 200 201 private: 202 203 const CMediumAttachment &m_mediumAttachment; 204 }; 205 206 /* CPU change event: */ 207 class UICPUChangeEvent : public QEvent 208 { 209 public: 210 211 UICPUChangeEvent(ulong uCPU, bool bRemove) 212 : QEvent((QEvent::Type)UIConsoleEventType_CPUChange) 213 , m_uCPU(uCPU), m_bRemove(bRemove) {} 214 215 ulong cpu() const { return m_uCPU; } 216 bool remove() const { return m_bRemove; } 217 218 private: 219 220 ulong m_uCPU; 221 bool m_bRemove; 222 }; 223 224 /* VRDP server change event: */ 225 class UIVRDPServerChangeEvent : public QEvent 226 { 227 public: 228 229 UIVRDPServerChangeEvent() 230 : QEvent((QEvent::Type)UIConsoleEventType_VRDPServerChange) {} 231 }; 232 233 /* Remote display info change event: */ 234 class UIRemoteDisplayInfoChangeEvent : public QEvent 235 { 236 public: 237 238 UIRemoteDisplayInfoChangeEvent() 239 : QEvent((QEvent::Type)UIConsoleEventType_RemoteDisplayInfoChange) {} 240 }; 241 242 /* USB controller change event: */ 243 class UIUSBControllerChangeEvent : public QEvent 244 { 245 public: 246 247 UIUSBControllerChangeEvent() 248 : QEvent((QEvent::Type)UIConsoleEventType_USBControllerChange) {} 249 }; 250 251 /* USB device state change event: */ 252 class UIUSBDeviceUIStateChangeEvent : public QEvent 253 { 254 public: 255 256 UIUSBDeviceUIStateChangeEvent(const CUSBDevice &device, bool bAttached, const CVirtualBoxErrorInfo &error) 257 : QEvent((QEvent::Type)UIConsoleEventType_USBDeviceStateChange) 258 , m_device(device), m_bAttached(bAttached), m_error(error) {} 259 260 const CUSBDevice& device() const { return m_device; } 261 bool attached() const { return m_bAttached; } 262 const CVirtualBoxErrorInfo& error() const { return m_error; } 263 264 private: 265 266 const CUSBDevice &m_device; 267 bool m_bAttached; 268 const CVirtualBoxErrorInfo &m_error; 269 }; 270 271 /* Shared folder change event: */ 272 class UISharedFolderChangeEvent : public QEvent 273 { 274 public: 275 276 UISharedFolderChangeEvent() 277 : QEvent((QEvent::Type)UIConsoleEventType_SharedFolderChange) {} 278 }; 279 280 /* VM Runtime error event: */ 281 class UIRuntimeErrorEvent : public QEvent 282 { 283 public: 284 285 UIRuntimeErrorEvent(bool bFatal, const QString &strErrorID, const QString &strMessage) 286 : QEvent((QEvent::Type)UIConsoleEventType_RuntimeError) 287 , m_bFatal(bFatal), m_strErrorID(strErrorID), m_strMessage(strMessage) {} 288 289 bool fatal() const { return m_bFatal; } 290 QString errorID() const { return m_strErrorID; } 291 QString message() const { return m_strMessage; } 292 293 private: 294 295 bool m_bFatal; 296 QString m_strErrorID; 297 QString m_strMessage; 298 }; 299 300 /* Can show window event: */ 301 class UICanUIShowWindowEvent : public QEvent 302 { 303 public: 304 305 UICanUIShowWindowEvent() 306 : QEvent((QEvent::Type)UIConsoleEventType_CanShowWindow) {} 307 }; 308 309 /* Show window event: */ 310 class UIShowWindowEvent : public QEvent 311 { 312 public: 313 314 UIShowWindowEvent() 315 : QEvent((QEvent::Type)UIConsoleEventType_ShowWindow) {} 316 }; 317 318 class UIConsoleCallback : VBOX_SCRIPTABLE_IMPL(IConsoleCallback) 319 { 320 public: 321 322 UIConsoleCallback(UISession *pEventHandler) 323 : m_pEventHandler(pEventHandler) 324 #if defined (Q_WS_WIN) 325 , m_iRefCount(0) 326 #endif 327 { 328 } 329 330 virtual ~UIConsoleCallback() 331 { 332 } 333 334 NS_DECL_ISUPPORTS 335 336 #if defined (Q_WS_WIN) 337 STDMETHOD_(ULONG, AddRef)() 338 { 339 return ::InterlockedIncrement(&m_iRefCount); 340 } 341 STDMETHOD_(ULONG, Release)() 342 { 343 long iCount = ::InterlockedDecrement(&m_iRefCount); 344 if (iCount == 0) 345 delete this; 346 return iCount; 347 } 348 #endif 349 350 VBOX_SCRIPTABLE_DISPATCH_IMPL(IConsoleCallback) 351 352 STDMETHOD(OnMousePointerShapeChange)(BOOL bIsVisible, BOOL bAlpha, ULONG uXHot, ULONG uYHot, ULONG uWidth, ULONG uHeight, BYTE *pShape) 353 { 354 QApplication::postEvent(m_pEventHandler, new UIMousePointerShapeChangeEvent(bIsVisible, bAlpha, uXHot, uYHot, uWidth, uHeight, pShape)); 355 return S_OK; 356 } 357 358 STDMETHOD(OnMouseCapabilityChange)(BOOL bSupportsAbsolute, BOOL bNeedHostCursor) 359 { 360 QApplication::postEvent(m_pEventHandler, new UIMouseCapabilityChangeEvent(bSupportsAbsolute, bNeedHostCursor)); 361 return S_OK; 362 } 363 364 STDMETHOD(OnKeyboardLedsChange)(BOOL bNumLock, BOOL bCapsLock, BOOL bScrollLock) 365 { 366 QApplication::postEvent(m_pEventHandler, new UIKeyboardLedsChangeEvent(bNumLock, bCapsLock, bScrollLock)); 367 return S_OK; 368 } 369 370 STDMETHOD(OnStateChange)(MachineState_T machineState) 371 { 372 QApplication::postEvent(m_pEventHandler, new UIStateChangeEvent((KMachineState)machineState)); 373 return S_OK; 374 } 375 376 STDMETHOD(OnAdditionsStateChange)() 377 { 378 QApplication::postEvent(m_pEventHandler, new UIAdditionsStateChangeEvent); 379 return S_OK; 380 } 381 382 STDMETHOD(OnNetworkAdapterChange)(INetworkAdapter *pNetworkAdapter) 383 { 384 QApplication::postEvent(m_pEventHandler, new UINetworkAdapterChangeEvent(CNetworkAdapter(pNetworkAdapter))); 385 return S_OK; 386 } 387 388 STDMETHOD(OnSerialPortChange)(ISerialPort *pSerialPort) 389 { 390 QApplication::postEvent(m_pEventHandler, new UISerialPortChangeEvent(CSerialPort(pSerialPort))); 391 return S_OK; 392 } 393 394 STDMETHOD(OnParallelPortChange)(IParallelPort *pParallelPort) 395 { 396 QApplication::postEvent(m_pEventHandler, new UIParallelPortChangeEvent(CParallelPort(pParallelPort))); 397 return S_OK; 398 } 399 400 STDMETHOD(OnStorageControllerChange)() 401 { 402 QApplication::postEvent(m_pEventHandler, new UIStorageControllerChangeEvent); 403 return S_OK; 404 } 405 406 STDMETHOD(OnMediumChange)(IMediumAttachment *pMediumAttachment) 407 { 408 QApplication::postEvent(m_pEventHandler, new UIMediumChangeEvent(CMediumAttachment(pMediumAttachment))); 409 return S_OK; 410 } 411 412 STDMETHOD(OnCPUChange)(ULONG uCPU, BOOL bRemove) 413 { 414 QApplication::postEvent(m_pEventHandler, new UICPUChangeEvent(uCPU, bRemove)); 415 return S_OK; 416 } 417 418 STDMETHOD(OnVRDPServerChange)() 419 { 420 QApplication::postEvent(m_pEventHandler, new UIVRDPServerChangeEvent); 421 return S_OK; 422 } 423 424 STDMETHOD(OnRemoteDisplayInfoChange)() 425 { 426 QApplication::postEvent(m_pEventHandler, new UIRemoteDisplayInfoChangeEvent); 427 return S_OK; 428 } 429 430 STDMETHOD(OnUSBControllerChange)() 431 { 432 QApplication::postEvent(m_pEventHandler, new UIUSBControllerChangeEvent); 433 return S_OK; 434 } 435 436 STDMETHOD(OnUSBDeviceStateChange)(IUSBDevice *pDevice, BOOL bAttached, IVirtualBoxErrorInfo *pError) 437 { 438 QApplication::postEvent(m_pEventHandler, new UIUSBDeviceUIStateChangeEvent(CUSBDevice(pDevice), bAttached, CVirtualBoxErrorInfo(pError))); 439 return S_OK; 440 } 441 442 STDMETHOD(OnSharedFolderChange)(Scope_T scope) 443 { 444 NOREF(scope); 445 QApplication::postEvent(m_pEventHandler, new UISharedFolderChangeEvent); 446 return S_OK; 447 } 448 449 STDMETHOD(OnRuntimeError)(BOOL bFatal, IN_BSTR strId, IN_BSTR strMessage) 450 { 451 QApplication::postEvent(m_pEventHandler, new UIRuntimeErrorEvent(bFatal, QString::fromUtf16(strId), QString::fromUtf16(strMessage))); 452 return S_OK; 453 } 454 455 STDMETHOD(OnCanShowWindow)(BOOL *pbCanShow) 456 { 457 if (!pbCanShow) 458 return E_POINTER; 459 460 *pbCanShow = TRUE; 461 return S_OK; 462 } 463 464 STDMETHOD(OnShowWindow)(ULONG64 *puWinId) 465 { 466 if (!puWinId) 467 return E_POINTER; 87 468 88 469 #if defined (Q_WS_MAC) 89 # include "DockIconPreview.h" 90 # include "DarwinKeyboard.h" 91 # ifdef QT_MAC_USE_COCOA 92 # include "darwin/VBoxCocoaApplication.h" 93 # elif defined(VBOX_WITH_HACKED_QT) 94 # include "QIApplication.h" 95 # endif 96 # include <Carbon/Carbon.h> 97 # include <VBox/err.h> 98 #endif /* defined (Q_WS_MAC) */ 99 100 #if defined (Q_WS_WIN32) 101 102 static HHOOK gKbdHook = NULL; 103 static VBoxConsoleView *gView = 0; 104 105 LRESULT CALLBACK VBoxConsoleView::lowLevelKeyboardProc (int nCode, 106 WPARAM wParam, LPARAM lParam) 107 { 108 Assert (gView); 109 if (gView && nCode == HC_ACTION && 110 gView->winLowKeyboardEvent (wParam, *(KBDLLHOOKSTRUCT *) lParam)) 111 return 1; 112 113 return CallNextHookEx (NULL, nCode, wParam, lParam); 114 } 115 116 #endif 117 118 #if defined (Q_WS_MAC) 119 # if defined (QT_MAC_USE_COCOA) 120 /** 121 * Event handler callback for Mac OS X, Cocoa variant. 122 * 123 * (Registered with and called from VBoxCocoaApplication.) 124 * 125 * @returns true if the event should be dropped, false if it should be passed 126 * along. 127 * @param pvCocoaEvent The Cocoa event object. 128 * @param pvCarbonEvent The Carbon event object reference. 129 * @param pvUser The user argument. 130 */ 131 /* static */ 132 bool VBoxConsoleView::darwinEventHandlerProc (const void *pvCocoaEvent, 133 const void *pvCarbonEvent, 134 void *pvUser) 135 { 136 VBoxConsoleView *view = (VBoxConsoleView *)pvUser; 137 EventRef inEvent = (EventRef)pvCarbonEvent; 138 UInt32 eventClass = ::GetEventClass (inEvent); 139 140 #if 0 141 /* For debugging events. */ 142 if (eventClass != 'cute') 143 ::VBoxCocoaApplication_printEvent ("view: ", pvCocoaEvent); 144 #endif 145 /* Check if this is an application key combo. In that case we will not pass 146 the event to the guest, but let the host process it. */ 147 if (VBoxCocoaApplication_isApplicationCommand(pvCocoaEvent)) 148 return false; 149 150 /* 151 * All keyboard class events needs to be handled. 152 */ 153 if (eventClass == kEventClassKeyboard) 154 { 155 if (view->darwinKeyboardEvent (pvCocoaEvent, inEvent)) 156 return true; 157 } 158 /* Pass the event along. */ 159 return false; 160 } 161 162 # elif !defined (VBOX_WITH_HACKED_QT) 163 /** 164 * Event handler callback for Mac OS X. 165 */ 166 /* static */ 167 pascal OSStatus VBoxConsoleView::darwinEventHandlerProc (EventHandlerCallRef inHandlerCallRef, 168 EventRef inEvent, void *inUserData) 169 { 170 VBoxConsoleView *view = static_cast<VBoxConsoleView *> (inUserData); 171 UInt32 eventClass = ::GetEventClass (inEvent); 172 173 /* For debugging events */ 174 /* 175 if (eventClass != 'cute') 176 ::darwinDebugPrintEvent ("view: ", inEvent); 177 */ 178 179 /* Not sure but this seems an triggered event if the spotlight searchbar is 180 * displayed. So flag that the host key isn't pressed alone. */ 181 if ( eventClass == 'cgs ' 182 && view->mIsHostkeyPressed 183 && ::GetEventKind (inEvent) == 0x15) 184 view->mIsHostkeyAlone = false; 185 186 if (eventClass == kEventClassKeyboard) 187 { 188 if (view->darwinKeyboardEvent (NULL, inEvent)) 189 return 0; 190 } 191 /* 192 * Command-H and Command-Q aren't properly disabled yet, and it's still 193 * possible to use the left command key to invoke them when the keyboard 194 * is captured. We discard the events these if the keyboard is captured 195 * as a half measure to prevent unexpected behaviour. However, we don't 196 * get any key down/up events, so these combinations are dead to the guest... 197 */ 198 else if (eventClass == kEventClassCommand) 199 { 200 if (view->mKbdCaptured) 201 return 0; 202 } 203 return ::CallNextEventHandler (inHandlerCallRef, inEvent); 204 } 205 206 # else /* VBOX_WITH_HACKED_QT */ 207 /** 208 * Event handler callback for Mac OS X. 209 */ 210 /* static */ 211 bool VBoxConsoleView::macEventFilter (EventRef inEvent, void *inUserData) 212 { 213 VBoxConsoleView *view = static_cast<VBoxConsoleView *> (inUserData); 214 UInt32 eventClass = ::GetEventClass (inEvent); 215 UInt32 eventKind = ::GetEventKind (inEvent); 216 217 /* For debugging events */ 218 /* 219 if (!(eventClass == 'cute')) 220 ::darwinDebugPrintEvent ("view: ", inEvent); 221 */ 222 223 /* Not sure but this seems an triggered event if the spotlight searchbar is 224 * displayed. So flag that the host key isn't pressed alone. */ 225 if (eventClass == 'cgs ' && eventKind == 0x15 && 226 view->mIsHostkeyPressed) 227 view->mIsHostkeyAlone = false; 228 229 if (eventClass == kEventClassKeyboard) 230 { 231 if (view->darwinKeyboardEvent (NULL, inEvent)) 232 return true; 233 } 234 return false; 235 } 236 # endif /* VBOX_WITH_HACKED_QT */ 237 238 #endif /* Q_WS_MAC */ 239 240 /** Guest mouse pointer shape change event. */ 241 class MousePointerChangeEvent : public QEvent 242 { 243 public: 244 MousePointerChangeEvent (bool visible, bool alpha, uint xhot, uint yhot, 245 uint width, uint height, 246 const uchar *shape) : 247 QEvent ((QEvent::Type) VBoxDefs::MousePointerChangeEventType), 248 vis (visible), alph (alpha), xh (xhot), yh (yhot), w (width), h (height), 249 data (NULL) 250 { 251 // make a copy of shape 252 uint dataSize = ((((width + 7) / 8 * height) + 3) & ~3) + width * 4 * height; 253 254 if (shape) { 255 data = new uchar [dataSize]; 256 memcpy ((void *) data, (void *) shape, dataSize); 257 } 258 } 259 ~MousePointerChangeEvent() 260 { 261 if (data) delete[] data; 262 } 263 bool isVisible() const { return vis; } 264 bool hasAlpha() const { return alph; } 265 uint xHot() const { return xh; } 266 uint yHot() const { return yh; } 267 uint width() const { return w; } 268 uint height() const { return h; } 269 const uchar *shapeData() const { return data; } 270 private: 271 bool vis, alph; 272 uint xh, yh, w, h; 273 const uchar *data; 274 }; 275 276 /** Guest mouse absolute positioning capability change event. */ 277 class MouseCapabilityEvent : public QEvent 278 { 279 public: 280 MouseCapabilityEvent (bool supportsAbsolute, bool needsHostCursor) : 281 QEvent ((QEvent::Type) VBoxDefs::MouseCapabilityEventType), 282 can_abs (supportsAbsolute), 283 needs_host_cursor (needsHostCursor) {} 284 bool supportsAbsolute() const { return can_abs; } 285 bool needsHostCursor() const { return needs_host_cursor; } 286 private: 287 bool can_abs; 288 bool needs_host_cursor; 289 }; 290 291 /** Machine state change. */ 292 class StateChangeEvent : public QEvent 293 { 294 public: 295 StateChangeEvent (KMachineState state) : 296 QEvent ((QEvent::Type) VBoxDefs::MachineStateChangeEventType), 297 s (state) {} 298 KMachineState machineState() const { return s; } 299 private: 300 KMachineState s; 301 }; 302 303 /** Guest Additions property changes. */ 304 class GuestAdditionsEvent : public QEvent 305 { 306 public: 307 GuestAdditionsEvent (const QString &aOsTypeId, 308 const QString &aAddVersion, 309 bool aAddActive, 310 bool aSupportsSeamless, 311 bool aSupportsGraphics) : 312 QEvent ((QEvent::Type) VBoxDefs::AdditionsStateChangeEventType), 313 mOsTypeId (aOsTypeId), mAddVersion (aAddVersion), 314 mAddActive (aAddActive), mSupportsSeamless (aSupportsSeamless), 315 mSupportsGraphics (aSupportsGraphics) {} 316 const QString &osTypeId() const { return mOsTypeId; } 317 const QString &additionVersion() const { return mAddVersion; } 318 bool additionActive() const { return mAddActive; } 319 bool supportsSeamless() const { return mSupportsSeamless; } 320 bool supportsGraphics() const { return mSupportsGraphics; } 321 private: 322 QString mOsTypeId; 323 QString mAddVersion; 324 bool mAddActive; 325 bool mSupportsSeamless; 326 bool mSupportsGraphics; 327 }; 328 329 /** DVD/Floppy drive change event */ 330 class MediaDriveChangeEvent : public QEvent 331 { 332 public: 333 MediaDriveChangeEvent (VBoxDefs::MediumType aType) 334 : QEvent ((QEvent::Type) VBoxDefs::MediaDriveChangeEventType) 335 , mType (aType) {} 336 VBoxDefs::MediumType type() const { return mType; } 337 private: 338 VBoxDefs::MediumType mType; 339 }; 340 341 /** Menu activation event */ 342 class ActivateMenuEvent : public QEvent 343 { 344 public: 345 ActivateMenuEvent (QAction *aData) : 346 QEvent ((QEvent::Type) VBoxDefs::ActivateMenuEventType), 347 mAction (aData) {} 348 QAction *action() const { return mAction; } 349 private: 350 QAction *mAction; 351 }; 352 353 /** VM Runtime error event */ 354 class RuntimeErrorEvent : public QEvent 355 { 356 public: 357 RuntimeErrorEvent (bool aFatal, const QString &aErrorID, 358 const QString &aMessage) : 359 QEvent ((QEvent::Type) VBoxDefs::RuntimeErrorEventType), 360 mFatal (aFatal), mErrorID (aErrorID), mMessage (aMessage) {} 361 bool fatal() const { return mFatal; } 362 QString errorID() const { return mErrorID; } 363 QString message() const { return mMessage; } 364 private: 365 bool mFatal; 366 QString mErrorID; 367 QString mMessage; 368 }; 369 370 /** Modifier key change event */ 371 class ModifierKeyChangeEvent : public QEvent 372 { 373 public: 374 ModifierKeyChangeEvent (bool fNumLock, bool fCapsLock, bool fScrollLock) : 375 QEvent ((QEvent::Type) VBoxDefs::ModifierKeyChangeEventType), 376 mNumLock (fNumLock), mCapsLock (fCapsLock), mScrollLock (fScrollLock) {} 377 bool numLock() const { return mNumLock; } 378 bool capsLock() const { return mCapsLock; } 379 bool scrollLock() const { return mScrollLock; } 380 private: 381 bool mNumLock, mCapsLock, mScrollLock; 382 }; 383 384 /** Network adapter change event */ 385 class NetworkAdapterChangeEvent : public QEvent 386 { 387 public: 388 NetworkAdapterChangeEvent (INetworkAdapter *aAdapter) : 389 QEvent ((QEvent::Type) VBoxDefs::NetworkAdapterChangeEventType), 390 mAdapter (aAdapter) {} 391 INetworkAdapter* networkAdapter() { return mAdapter; } 392 private: 393 INetworkAdapter *mAdapter; 394 }; 395 396 /** USB controller state change event */ 397 class USBControllerStateChangeEvent : public QEvent 398 { 399 public: 400 USBControllerStateChangeEvent() 401 : QEvent ((QEvent::Type) VBoxDefs::USBCtlStateChangeEventType) {} 402 }; 403 404 /** USB device state change event */ 405 class USBDeviceStateChangeEvent : public QEvent 406 { 407 public: 408 USBDeviceStateChangeEvent (const CUSBDevice &aDevice, bool aAttached, 409 const CVirtualBoxErrorInfo &aError) : 410 QEvent ((QEvent::Type) VBoxDefs::USBDeviceStateChangeEventType), 411 mDevice (aDevice), mAttached (aAttached), mError (aError) {} 412 CUSBDevice device() const { return mDevice; } 413 bool attached() const { return mAttached; } 414 CVirtualBoxErrorInfo error() const { return mError; } 415 private: 416 CUSBDevice mDevice; 417 bool mAttached; 418 CVirtualBoxErrorInfo mError; 419 }; 420 421 // 422 // VBoxConsoleCallback class 423 ///////////////////////////////////////////////////////////////////////////// 424 425 class VBoxConsoleCallback : VBOX_SCRIPTABLE_IMPL(IConsoleCallback) 426 { 427 public: 428 429 VBoxConsoleCallback (VBoxConsoleView *v) { 430 #if defined (Q_WS_WIN) 431 mRefCnt = 0; 432 #endif 433 mView = v; 434 } 435 436 virtual ~VBoxConsoleCallback() {} 437 438 NS_DECL_ISUPPORTS 439 440 #if defined (Q_WS_WIN) 441 STDMETHOD_(ULONG, AddRef)() { 442 return ::InterlockedIncrement (&mRefCnt); 443 } 444 STDMETHOD_(ULONG, Release)() 445 { 446 long cnt = ::InterlockedDecrement (&mRefCnt); 447 if (cnt == 0) 448 delete this; 449 return cnt; 450 } 451 #endif 452 VBOX_SCRIPTABLE_DISPATCH_IMPL(IConsoleCallback) 453 454 STDMETHOD(OnMousePointerShapeChange) (BOOL visible, BOOL alpha, 455 ULONG xhot, ULONG yhot, 456 ULONG width, ULONG height, 457 BYTE *shape) 458 { 459 QApplication::postEvent (mView, 460 new MousePointerChangeEvent (visible, alpha, 461 xhot, yhot, 462 width, height, shape)); 463 return S_OK; 464 } 465 466 STDMETHOD(OnMouseCapabilityChange)(BOOL supportsAbsolute, BOOL needsHostCursor) 467 { 468 QApplication::postEvent (mView, 469 new MouseCapabilityEvent (supportsAbsolute, 470 needsHostCursor)); 471 return S_OK; 472 } 473 474 STDMETHOD(OnKeyboardLedsChange)(BOOL fNumLock, BOOL fCapsLock, BOOL fScrollLock) 475 { 476 QApplication::postEvent (mView, 477 new ModifierKeyChangeEvent (fNumLock, fCapsLock, 478 fScrollLock)); 479 return S_OK; 480 } 481 482 STDMETHOD(OnStateChange)(MachineState_T machineState) 483 { 484 LogFlowFunc (("machineState=%d\n", machineState)); 485 QApplication::postEvent (mView, 486 new StateChangeEvent ((KMachineState) machineState)); 487 return S_OK; 488 } 489 490 STDMETHOD(OnAdditionsStateChange)() 491 { 492 CGuest guest = mView->console().GetGuest(); 493 LogFlowFunc (("ver=%s, active=%d\n", 494 guest.GetAdditionsVersion().toLatin1().constData(), 495 guest.GetAdditionsActive())); 496 QApplication::postEvent (mView, 497 new GuestAdditionsEvent ( 498 guest.GetOSTypeId(), 499 guest.GetAdditionsVersion(), 500 guest.GetAdditionsActive(), 501 guest.GetSupportsSeamless(), 502 guest.GetSupportsGraphics())); 503 return S_OK; 504 } 505 506 STDMETHOD(OnNetworkAdapterChange) (INetworkAdapter *aNetworkAdapter) 507 { 508 QApplication::postEvent (mView, 509 new NetworkAdapterChangeEvent (aNetworkAdapter)); 510 return S_OK; 511 } 512 513 STDMETHOD(OnStorageControllerChange) () 514 { 515 /* @todo */ 516 //QApplication::postEvent (mView, 517 // new StorageControllerChangeEvent ()); 518 return S_OK; 519 } 520 521 STDMETHOD(OnMediumChange)(IMediumAttachment *aMediumAttachment) 522 { 523 CMediumAttachment att(aMediumAttachment); 524 switch (att.GetType()) 525 { 526 case KDeviceType_Floppy: 527 QApplication::postEvent(mView, 528 new MediaDriveChangeEvent(VBoxDefs::MediumType_Floppy)); 529 break; 530 case KDeviceType_DVD: 531 QApplication::postEvent(mView, 532 new MediaDriveChangeEvent(VBoxDefs::MediumType_DVD)); 533 break; 534 default: 535 /* @todo later add hard disk change as well */ 536 break; 537 } 538 return S_OK; 539 } 540 541 STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove) 542 { 543 NOREF(aCPU); 544 NOREF(aRemove); 545 return S_OK; 546 } 547 548 STDMETHOD(OnSerialPortChange) (ISerialPort *aSerialPort) 549 { 550 NOREF(aSerialPort); 551 return S_OK; 552 } 553 554 STDMETHOD(OnParallelPortChange) (IParallelPort *aParallelPort) 555 { 556 NOREF(aParallelPort); 557 return S_OK; 558 } 559 560 STDMETHOD(OnVRDPServerChange)() 561 { 562 return S_OK; 563 } 564 565 STDMETHOD(OnRemoteDisplayInfoChange)() 566 { 567 return S_OK; 568 } 569 570 STDMETHOD(OnUSBControllerChange)() 571 { 572 QApplication::postEvent (mView, 573 new USBControllerStateChangeEvent()); 574 return S_OK; 575 } 576 577 STDMETHOD(OnUSBDeviceStateChange)(IUSBDevice *aDevice, BOOL aAttached, 578 IVirtualBoxErrorInfo *aError) 579 { 580 QApplication::postEvent (mView, 581 new USBDeviceStateChangeEvent ( 582 CUSBDevice (aDevice), 583 bool (aAttached), 584 CVirtualBoxErrorInfo (aError))); 585 return S_OK; 586 } 587 588 STDMETHOD(OnSharedFolderChange) (Scope_T aScope) 589 { 590 NOREF(aScope); 591 QApplication::postEvent (mView, 592 new QEvent ((QEvent::Type) 593 VBoxDefs::SharedFolderChangeEventType)); 594 return S_OK; 595 } 596 597 STDMETHOD(OnRuntimeError)(BOOL fatal, IN_BSTR id, IN_BSTR message) 598 { 599 QApplication::postEvent (mView, 600 new RuntimeErrorEvent (!!fatal, 601 QString::fromUtf16 (id), 602 QString::fromUtf16 (message))); 603 return S_OK; 604 } 605 606 STDMETHOD(OnCanShowWindow) (BOOL *canShow) 607 { 608 if (!canShow) 609 return E_POINTER; 610 611 /* as long as there is VBoxConsoleView (which creates/destroys us), it 612 * can be shown */ 613 *canShow = TRUE; 614 return S_OK; 615 } 616 617 STDMETHOD(OnShowWindow) (ULONG64 *winId) 618 { 619 if (!winId) 620 return E_POINTER; 621 622 #if defined (Q_WS_MAC) 623 /* 624 * Let's try the simple approach first - grab the focus. 470 /* Let's try the simple approach first - grab the focus. 625 471 * Getting a window out of the dock (minimized or whatever it's called) 626 * needs to be done on the GUI thread, so post it a note. 627 */ 628 *winId = 0; 629 if (!mView) 472 * needs to be done on the GUI thread, so post it a note: */ 473 *puWinId = 0; 474 if (!m_pEventHandler) 630 475 return S_OK; 631 476 632 477 ProcessSerialNumber psn = { 0, kCurrentProcess }; 633 OSErr rc = ::SetFrontProcess 478 OSErr rc = ::SetFrontProcess(&psn); 634 479 if (!rc) 635 QApplication::postEvent (mView, new QEvent ((QEvent::Type)VBoxDefs::ShowWindowEventType));480 QApplication::postEvent(m_pEventHandler, new UIShowWindowEvent); 636 481 else 637 482 { 638 /* 639 * It failed for some reason, send the other process our PSN so it can try. 483 /* It failed for some reason, send the other process our PSN so it can try. 640 484 * (This is just a precaution should Mac OS X start imposing the same sensible 641 * focus stealing restrictions that other window managers implement.) 642 */ 485 * focus stealing restrictions that other window managers implement). */ 643 486 AssertMsgFailed(("SetFrontProcess -> %#x\n", rc)); 644 if (::GetCurrentProcess (&psn)) 645 *winId = RT_MAKE_U64 (psn.lowLongOfPSN, psn.highLongOfPSN); 646 } 647 487 if (::GetCurrentProcess(&psn)) 488 *puWinId = RT_MAKE_U64(psn.lowLongOfPSN, psn.highLongOfPSN); 489 } 648 490 #else 649 491 /* Return the ID of the top-level console window. */ 650 * winId = (ULONG64) mView->window()->winId();651 #endif 652 653 return S_OK; 654 } 655 656 pr otected:657 658 VBoxConsoleView *mView;492 *puWinId = m_pEventHandler->winId(); 493 #endif 494 495 return S_OK; 496 } 497 498 private: 499 500 UISession *m_pEventHandler; 659 501 660 502 #if defined (Q_WS_WIN) 661 private: 662 long mRefCnt; 503 long m_iRefCount; 663 504 #endif 664 505 }; 665 506 666 507 #if !defined (Q_WS_WIN) 667 NS_DECL_CLASSINFO (VBoxConsoleCallback) 668 NS_IMPL_THREADSAFE_ISUPPORTS1_CI (VBoxConsoleCallback, IConsoleCallback) 669 #endif 670 671 class VBoxViewport: public QWidget 672 { 673 public: 674 VBoxViewport (QWidget *aParent) 675 : QWidget (aParent) 676 { 677 /* No need for background drawing */ 678 setAttribute (Qt::WA_OpaquePaintEvent); 679 } 680 virtual QPaintEngine * paintEngine() const 681 { 682 if (testAttribute (Qt::WA_PaintOnScreen)) 683 return NULL; 684 else 685 return QWidget::paintEngine(); 686 } 687 }; 688 689 // 690 // VBoxConsoleView class 691 ///////////////////////////////////////////////////////////////////////////// 692 693 /** @class VBoxConsoleView 694 * 695 * The VBoxConsoleView class is a widget that implements a console 696 * for the running virtual machine. 697 */ 698 699 VBoxConsoleView::VBoxConsoleView (VBoxConsoleWnd *mainWnd, 700 const CConsole &console, 701 VBoxDefs::RenderMode rm, 702 #ifdef VBOX_WITH_VIDEOHWACCEL 703 bool accelerate2DVideo, 704 #endif 705 QWidget *parent) 706 : QAbstractScrollArea (parent) 707 , mMainWnd (mainWnd) 708 , mConsole (console) 709 , gs (vboxGlobal().settings()) 710 , mAttached (false) 711 , mKbdCaptured (false) 712 , mMouseCaptured (false) 713 , mMouseAbsolute (false) 714 , mMouseIntegration (true) 715 , m_iLastMouseWheelDelta(0) 716 , mDisableAutoCapture (false) 717 , mIsHostkeyPressed (false) 718 , mIsHostkeyAlone (false) 719 , mIgnoreMainwndResize (true) 720 , mAutoresizeGuest (false) 721 , mIgnoreFrameBufferResize (false) 722 , mIgnoreGuestResize (false) 723 , mDoResize (false) 724 , mGuestSupportsGraphics (false) 725 , mNumLock (false) 726 , mScrollLock (false) 727 , mCapsLock (false) 728 , muNumLockAdaptionCnt (2) 729 , muCapsLockAdaptionCnt (2) 730 , mode (rm) 731 #ifdef VBOX_WITH_VIDEOHWACCEL 732 , mAccelerate2DVideo(accelerate2DVideo) 733 #endif 734 #if defined(Q_WS_WIN) 735 , mAlphaCursor (NULL) 736 #endif 737 #if defined(Q_WS_MAC) 738 # if !defined (VBOX_WITH_HACKED_QT) && !defined (QT_MAC_USE_COCOA) 739 , mDarwinEventHandlerRef (NULL) 740 # endif 741 , mDarwinKeyModifiers (0) 742 , mKeyboardGrabbed (false) 743 , mDockIconEnabled (true) 744 #endif 745 , mDesktopGeo (DesktopGeo_Invalid) 746 , mPassCAD (false) 747 /* Don't show a hardware pointer until we have one to show */ 748 , mHideHostPointer (true) 749 { 750 Assert (!mConsole.isNull() && 751 !mConsole.GetDisplay().isNull() && 752 !mConsole.GetKeyboard().isNull() && 753 !mConsole.GetMouse().isNull()); 754 755 #ifdef Q_WS_MAC 756 /* Overlay logo for the dock icon */ 757 QString osTypeId = mConsole.GetGuest().GetOSTypeId(); 758 mDockIconPreview = new VBoxDockIconPreview (mMainWnd, vboxGlobal().vmGuestOSTypeIcon (osTypeId)); 759 760 # ifdef QT_MAC_USE_COCOA 761 /** @todo Carbon -> Cocoa */ 762 # else /* !QT_MAC_USE_COCOA */ 763 /* Install the event handler which will proceed external window handling */ 764 EventHandlerUPP eventHandler = ::NewEventHandlerUPP (::darwinOverlayWindowHandler); 765 EventTypeSpec eventTypes[] = 766 { 767 { kEventClassVBox, kEventVBoxShowWindow }, 768 { kEventClassVBox, kEventVBoxHideWindow }, 769 { kEventClassVBox, kEventVBoxMoveWindow }, 770 { kEventClassVBox, kEventVBoxResizeWindow }, 771 { kEventClassVBox, kEventVBoxDisposeWindow }, 772 { kEventClassVBox, kEventVBoxUpdateDock } 773 }; 774 775 mDarwinWindowOverlayHandlerRef = NULL; 776 ::InstallApplicationEventHandler (eventHandler, RT_ELEMENTS (eventTypes), &eventTypes[0], 777 this, &mDarwinWindowOverlayHandlerRef); 778 ::DisposeEventHandlerUPP (eventHandler); 779 # endif /* !QT_MAC_USE_COCOA */ 780 #endif /* QT_WS_MAC */ 781 782 /* No frame around the view */ 783 setFrameStyle (QFrame::NoFrame); 784 785 #ifdef VBOX_GUI_USE_QGL 786 QWidget *pViewport; 787 switch (mode) 788 { 789 case VBoxDefs::QGLMode: 790 pViewport = new VBoxGLWidget (this, this, NULL); 791 break; 792 default: 793 pViewport = new VBoxViewport (this); 794 } 795 #else 796 VBoxViewport *pViewport = new VBoxViewport (this); 797 #endif 798 setViewport (pViewport); 799 // pViewport->vboxDoInit(); 800 801 /* enable MouseMove events */ 802 viewport()->setMouseTracking (true); 803 804 /* 805 * QScrollView does the below on its own, but let's do it anyway 806 * for the case it will not do it in the future. 807 */ 808 viewport()->installEventFilter (this); 809 810 /* to fix some focus issues */ 811 mMainWnd->menuBar()->installEventFilter (this); 812 813 /* we want to be notified on some parent's events */ 814 mMainWnd->installEventFilter (this); 815 816 #ifdef Q_WS_X11 817 /* initialize the X keyboard subsystem */ 818 initMappedX11Keyboard(QX11Info::display(), 819 vboxGlobal().settings().publicProperty ("GUI/RemapScancodes")); 820 #endif 821 822 ::memset (mPressedKeys, 0, sizeof (mPressedKeys)); 823 824 /* setup rendering */ 825 826 CDisplay display = mConsole.GetDisplay(); 827 Assert (!display.isNull()); 828 829 mFrameBuf = NULL; 830 831 LogFlowFunc (("Rendering mode: %d\n", mode)); 832 833 switch (mode) 834 { 835 #if defined (VBOX_GUI_USE_QGL) 836 case VBoxDefs::QGLMode: 837 mFrameBuf = new VBoxQGLFrameBuffer (this); 838 break; 839 // case VBoxDefs::QGLOverlayMode: 840 // mFrameBuf = new VBoxQGLOverlayFrameBuffer (this); 841 // break; 842 #endif 843 #if defined (VBOX_GUI_USE_QIMAGE) 844 case VBoxDefs::QImageMode: 845 mFrameBuf = 846 #ifdef VBOX_WITH_VIDEOHWACCEL 847 mAccelerate2DVideo ? new VBoxOverlayFrameBuffer<VBoxQImageFrameBuffer> (this, &mainWnd->session()) : 848 #endif 849 new VBoxQImageFrameBuffer (this); 850 break; 851 #endif 852 #if defined (VBOX_GUI_USE_SDL) 853 case VBoxDefs::SDLMode: 854 /* Indicate that we are doing all 855 * drawing stuff ourself */ 856 pViewport->setAttribute (Qt::WA_PaintOnScreen); 857 # ifdef Q_WS_X11 858 /* This is somehow necessary to prevent strange X11 warnings on 859 * i386 and segfaults on x86_64. */ 860 XFlush(QX11Info::display()); 861 # endif 862 mFrameBuf = 863 #if defined(VBOX_WITH_VIDEOHWACCEL) && defined(DEBUG_misha) /* not tested yet */ 864 mAccelerate2DVideo ? new VBoxOverlayFrameBuffer<VBoxSDLFrameBuffer> (this, &mainWnd->session()) : 865 #endif 866 new VBoxSDLFrameBuffer (this); 867 /* 868 * disable scrollbars because we cannot correctly draw in a 869 * scrolled window using SDL 870 */ 871 horizontalScrollBar()->setEnabled (false); 872 verticalScrollBar()->setEnabled (false); 873 break; 874 #endif 875 #if defined (VBOX_GUI_USE_DDRAW) 876 case VBoxDefs::DDRAWMode: 877 mFrameBuf = new VBoxDDRAWFrameBuffer (this); 878 break; 879 #endif 880 #if defined (VBOX_GUI_USE_QUARTZ2D) 881 case VBoxDefs::Quartz2DMode: 882 /* Indicate that we are doing all 883 * drawing stuff ourself */ 884 pViewport->setAttribute (Qt::WA_PaintOnScreen); 885 mFrameBuf = 886 #ifdef VBOX_WITH_VIDEOHWACCEL 887 mAccelerate2DVideo ? new VBoxOverlayFrameBuffer<VBoxQuartz2DFrameBuffer> (this, &mainWnd->session()) : 888 #endif 889 new VBoxQuartz2DFrameBuffer (this); 890 break; 891 #endif 892 default: 893 AssertReleaseMsgFailed (("Render mode must be valid: %d\n", mode)); 894 LogRel (("Invalid render mode: %d\n", mode)); 895 qApp->exit (1); 896 break; 897 } 898 899 #if defined (VBOX_GUI_USE_DDRAW) 900 if (!mFrameBuf || mFrameBuf->address() == NULL) 901 { 902 if (mFrameBuf) 903 delete mFrameBuf; 904 mode = VBoxDefs::QImageMode; 905 mFrameBuf = new VBoxQImageFrameBuffer (this); 906 } 907 #endif 908 909 if (mFrameBuf) 910 { 911 mFrameBuf->AddRef(); 912 display.SetFramebuffer (VBOX_VIDEO_PRIMARY_SCREEN, CFramebuffer (mFrameBuf)); 913 } 914 915 /* setup the callback */ 916 mCallback = CConsoleCallback (new VBoxConsoleCallback (this)); 917 mConsole.RegisterCallback (mCallback); 918 AssertWrapperOk (mConsole); 919 920 QPalette palette (viewport()->palette()); 921 palette.setColor (viewport()->backgroundRole(), Qt::black); 922 viewport()->setPalette (palette); 923 924 setSizePolicy (QSizePolicy (QSizePolicy::Maximum, QSizePolicy::Maximum)); 925 setMaximumSize (sizeHint()); 926 927 setFocusPolicy (Qt::WheelFocus); 928 929 /* Remember the desktop geometry and register for geometry change 930 events for telling the guest about video modes we like. */ 931 932 QString desktopGeometry = vboxGlobal().settings() 933 .publicProperty ("GUI/MaxGuestResolution"); 934 if ((desktopGeometry == QString::null) || 935 (desktopGeometry == "auto")) 936 setDesktopGeometry (DesktopGeo_Automatic, 0, 0); 937 else if (desktopGeometry == "any") 938 setDesktopGeometry (DesktopGeo_Any, 0, 0); 939 else 940 { 941 int width = desktopGeometry.section (',', 0, 0).toInt(); 942 int height = desktopGeometry.section (',', 1, 1).toInt(); 943 setDesktopGeometry (DesktopGeo_Fixed, width, height); 944 } 945 connect (QApplication::desktop(), SIGNAL (resized (int)), 946 this, SLOT (doResizeDesktop (int))); 947 948 QString passCAD = mConsole.GetMachine().GetExtraData (VBoxDefs::GUI_PassCAD); 949 if (!passCAD.isEmpty() && 950 ((passCAD != "false") || (passCAD != "no")) 951 ) 952 mPassCAD = true; 953 954 #if defined (Q_WS_WIN) 955 gView = this; 956 #endif 957 958 #if defined (Q_WS_PM) 959 bool ok = VBoxHlpInstallKbdHook (0, winId(), UM_PREACCEL_CHAR); 960 Assert (ok); 961 NOREF (ok); 962 #endif 508 NS_DECL_CLASSINFO(UIConsoleCallback) 509 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(UIConsoleCallback, IConsoleCallback) 510 #endif 511 512 UISession::UISession(UIMachine *pMachine, const CSession &session) 513 : QObject(pMachine) 514 , m_pMachine(pMachine) 515 , m_session(session) 516 , m_pCallback(new UIConsoleCallback(this)) 517 , m_callback(CConsoleCallback(m_pCallback)) 518 { 519 /* Check CSession object */ 520 AssertMsg(!m_session.isNull(), ("CSession is not set!\n")); 521 522 /* Register console callback: */ 523 m_session.GetConsole().RegisterCallback(m_callback); 963 524 } 964 525 965 VBoxConsoleView::~VBoxConsoleView() 966 { 967 #if defined (Q_WS_PM) 968 bool ok = VBoxHlpUninstallKbdHook (0, winId(), UM_PREACCEL_CHAR); 969 Assert (ok); 970 NOREF (ok); 971 #endif 972 973 #if defined (Q_WS_WIN) 974 if (gKbdHook) 975 UnhookWindowsHookEx (gKbdHook); 976 gView = 0; 977 if (mAlphaCursor) 978 DestroyIcon (mAlphaCursor); 979 #endif 980 981 if (mFrameBuf) 982 { 983 /* detach our framebuffer from Display */ 984 CDisplay display = mConsole.GetDisplay(); 985 Assert (!display.isNull()); 986 display.SetFramebuffer (VBOX_VIDEO_PRIMARY_SCREEN, CFramebuffer(NULL)); 987 /* release the reference */ 988 mFrameBuf->Release(); 989 mFrameBuf = NULL; 990 } 991 992 mConsole.UnregisterCallback (mCallback); 993 994 #if defined (Q_WS_MAC) 995 # if !defined (QT_MAC_USE_COCOA) 996 if (mDarwinWindowOverlayHandlerRef) 997 { 998 ::RemoveEventHandler (mDarwinWindowOverlayHandlerRef); 999 mDarwinWindowOverlayHandlerRef = NULL; 1000 } 1001 # endif 1002 delete mDockIconPreview; 1003 mDockIconPreview = NULL; 1004 #endif 526 UISession::~UISession() 527 { 528 /* Unregister console callback: */ 529 m_session.GetConsole().UnregisterCallback(m_callback); 530 delete m_pCallback; 531 m_pCallback = 0; 1005 532 } 1006 533 1007 // 1008 // Public members 1009 ///////////////////////////////////////////////////////////////////////////// 1010 1011 QSize VBoxConsoleView::sizeHint() const 1012 { 1013 #ifdef VBOX_WITH_DEBUGGER /** @todo figure out a more proper fix. */ 1014 /* HACK ALERT! Really ugly workaround for the resizing to 9x1 done 1015 * by DevVGA if provoked before power on. */ 1016 QSize fb(mFrameBuf->width(), mFrameBuf->height()); 1017 if ( ( fb.width() < 16 1018 || fb.height() < 16) 1019 && ( vboxGlobal().isStartPausedEnabled() 1020 || vboxGlobal().isDebuggerAutoShowEnabled()) ) 1021 fb = QSize(640, 480); 1022 return QSize (fb.width() + frameWidth() * 2, 1023 fb.height() + frameWidth() * 2); 1024 #else 1025 return QSize (mFrameBuf->width() + frameWidth() * 2, 1026 mFrameBuf->height() + frameWidth() * 2); 1027 #endif 1028 } 1029 1030 /** 1031 * Attaches this console view to the managed virtual machine. 1032 * 1033 * @note This method is not really necessary these days -- the only place where 1034 * it gets called is VBoxConsole::openView(), right after powering the 1035 * VM up. We leave it as is just in case attaching/detaching will become 1036 * necessary some day (there are useful attached checks everywhere in the 1037 * code). 1038 */ 1039 void VBoxConsoleView::attach() 1040 { 1041 if (!mAttached) 1042 { 1043 mAttached = true; 1044 } 1045 } 1046 1047 /** 1048 * Detaches this console view from the VM. Must be called to indicate 1049 * that the virtual machine managed by this instance will be no more valid 1050 * after this call. 1051 * 1052 * @note This method is not really necessary these days -- the only place where 1053 * it gets called is VBoxConsole::closeView(), when the VM is powered 1054 * down, before deleting VBoxConsoleView. We leave it as is just in case 1055 * attaching/detaching will become necessary some day (there are useful 1056 * attached checks everywhere in the code). 1057 */ 1058 void VBoxConsoleView::detach() 1059 { 1060 if (mAttached) 1061 { 1062 /* reuse the focus event handler to uncapture everything */ 1063 focusEvent (false); 1064 mAttached = false; 1065 } 1066 } 1067 1068 /** 1069 * Resizes the toplevel widget to fit the console view w/o scrollbars. 1070 * If adjustPosition is true and such resize is not possible (because the 1071 * console view size is lagrer then the available screen space) the toplevel 1072 * widget is resized and moved to become as large as possible while staying 1073 * fully visible. 1074 */ 1075 void VBoxConsoleView::normalizeGeometry (bool adjustPosition /* = false */) 1076 { 1077 /* Make no normalizeGeometry in case we are in manual resize 1078 * mode or main window is maximized */ 1079 if (mMainWnd->isWindowMaximized() || mMainWnd->isWindowFullScreen()) 1080 return; 1081 1082 QWidget *tlw = window(); 1083 1084 /* calculate client window offsets */ 1085 QRect fr = tlw->frameGeometry(); 1086 QRect r = tlw->geometry(); 1087 int dl = r.left() - fr.left(); 1088 int dt = r.top() - fr.top(); 1089 int dr = fr.right() - r.right(); 1090 int db = fr.bottom() - r.bottom(); 1091 1092 /* get the best size w/o scroll bars */ 1093 QSize s = tlw->sizeHint(); 1094 1095 /* resize the frame to fit the contents */ 1096 s -= tlw->size(); 1097 fr.setRight (fr.right() + s.width()); 1098 fr.setBottom (fr.bottom() + s.height()); 1099 1100 if (adjustPosition) 1101 { 1102 QRegion ar; 1103 QDesktopWidget *dwt = QApplication::desktop(); 1104 if (dwt->isVirtualDesktop()) 1105 /* Compose complex available region */ 1106 for (int i = 0; i < dwt->numScreens(); ++ i) 1107 ar += dwt->availableGeometry (i); 1108 else 1109 /* Get just a simple available rectangle */ 1110 ar = dwt->availableGeometry (tlw->pos()); 1111 1112 fr = VBoxGlobal::normalizeGeometry ( 1113 fr, ar, mode != VBoxDefs::SDLMode /* canResize */); 1114 } 1115 1116 #if 0 1117 /* center the frame on the desktop */ 1118 fr.moveCenter (ar.center()); 1119 #endif 1120 1121 /* finally, set the frame geometry */ 1122 tlw->setGeometry (fr.left() + dl, fr.top() + dt, 1123 fr.width() - dl - dr, fr.height() - dt - db); 1124 } 1125 1126 /** 1127 * Pauses or resumes the VM execution. 1128 */ 1129 bool VBoxConsoleView::pause (bool on) 1130 { 1131 /* QAction::setOn() emits the toggled() signal, so avoid recursion when 1132 * QAction::setOn() is called from VBoxConsoleWnd::updateMachineState() */ 1133 if (isPaused() == on) 1134 return true; 1135 1136 if (on) 1137 mConsole.Pause(); 1138 else 1139 mConsole.Resume(); 1140 1141 bool ok = mConsole.isOk(); 1142 if (!ok) 1143 { 1144 if (on) 1145 vboxProblem().cannotPauseMachine (mConsole); 1146 else 1147 vboxProblem().cannotResumeMachine (mConsole); 1148 } 1149 1150 return ok; 1151 } 1152 1153 /** 1154 * Temporarily disables the mouse integration (or enables it back). 1155 */ 1156 void VBoxConsoleView::setMouseIntegrationEnabled (bool enabled) 1157 { 1158 if (mMouseIntegration == enabled) 1159 return; 1160 1161 if (mMouseAbsolute) 1162 captureMouse (!enabled, false); 1163 1164 /* Hiding host cursor in case we are entering mouse integration 1165 * mode until it's shape is set to the guest cursor shape in 1166 * OnMousePointerShapeChange event handler. 1167 * 1168 * This is necessary to avoid double-cursor issues where both the 1169 * guest and the host cursors are displayed in one place, one above the 1170 * other. 1171 * 1172 * This is a workaround because the correct decision would be to notify 1173 * the Guest Additions about we are entering the mouse integration 1174 * mode. The GuestOS should hide it's cursor to allow using of 1175 * host cursor for the guest's manipulation. 1176 * 1177 * This notification is not always possible though, as not all guests 1178 * support switching to a hardware pointer on demand. */ 1179 if (enabled) 1180 viewport()->setCursor (QCursor (Qt::BlankCursor)); 1181 1182 mMouseIntegration = enabled; 1183 1184 emitMouseStateChanged(); 1185 } 1186 1187 void VBoxConsoleView::setAutoresizeGuest (bool on) 1188 { 1189 if (mAutoresizeGuest != on) 1190 { 1191 mAutoresizeGuest = on; 1192 1193 maybeRestrictMinimumSize(); 1194 1195 if (mGuestSupportsGraphics && mAutoresizeGuest) 1196 doResizeHint(); 1197 } 1198 } 1199 1200 /** 1201 * This method is called by VBoxConsoleWnd after it does everything necessary 1202 * on its side to go to or from fullscreen, but before it is shown. 1203 */ 1204 void VBoxConsoleView::onFullscreenChange (bool /* on */) 1205 { 1206 /* Nothing to do here so far */ 1207 } 1208 1209 /** 1210 * Notify the console scroll-view about the console-window is opened. 1211 */ 1212 void VBoxConsoleView::onViewOpened() 1213 { 1214 /* Variable mIgnoreMainwndResize was initially "true" to ignore QT 1215 * initial resize event in case of auto-resize feature is on. 1216 * Currently, initial resize event is already processed, so we set 1217 * mIgnoreMainwndResize to "false" to process all further resize 1218 * events as user-initiated window resize events. */ 1219 mIgnoreMainwndResize = false; 1220 } 1221 1222 // 1223 // Protected Events 1224 ///////////////////////////////////////////////////////////////////////////// 1225 1226 bool VBoxConsoleView::event (QEvent *e) 1227 { 1228 if (mAttached) 1229 { 1230 switch (e->type()) 1231 { 1232 case QEvent::FocusIn: 534 bool UISession::event(QEvent *pEvent) 535 { 536 switch (pEvent->type()) 537 { 538 case UIConsoleEventType_MousePointerShapeChange: 539 { 540 #if 0 // TODO: Move to machine view! 541 MousePointerChangeEvent *me = (MousePointerChangeEvent*)pEvent; 542 /* Change cursor shape only when mouse integration is 543 * supported (change mouse shape type event may arrive after 544 * mouse capability change that disables integration. */ 545 if (m_bIsMouseAbsolute) 546 setPointerShape (me); 547 else 548 /* Note: actually we should still remember the requested 549 * cursor shape. If we can't do that, at least remember 550 * the requested visiblilty. */ 551 mHideHostPointer = !me->isVisible(); 552 #endif 553 UIMousePointerShapeChangeEvent *pConsoleEvent = static_cast<UIMousePointerShapeChangeEvent*>(pEvent); 554 emit sigMousePointerShapeChange(pConsoleEvent->isVisible(), pConsoleEvent->hasAlpha(), 555 pConsoleEvent->xHot(), pConsoleEvent->yHot(), 556 pConsoleEvent->width(), pConsoleEvent->height(), 557 pConsoleEvent->shapeData()); 558 return true; 559 } 560 561 case UIConsoleEventType_MouseCapabilityChange: 562 { 563 #if 0 // TODO: Move to machine view! 564 MouseCapabilityEvent *me = (MouseCapabilityEvent*)pEvent; 565 if (m_bIsMouseAbsolute != me->supportsAbsolute()) 1233 566 { 1234 if (isRunning()) 1235 focusEvent (true); 1236 break; 1237 } 1238 case QEvent::FocusOut: 1239 { 1240 if (isRunning()) 1241 focusEvent (false); 1242 else 567 m_bIsMouseAbsolute = me->supportsAbsolute(); 568 /* correct the mouse capture state and reset the cursor 569 * to the default shape if necessary */ 570 if (m_bIsMouseAbsolute) 1243 571 { 1244 /* release the host key and all other pressed keys too even 1245 * when paused (otherwise, we will get stuck keys in the 1246 * guest when doing sendChangedKeyStates() on resume because 1247 * key presses were already recorded in mPressedKeys but key 1248 * releases will most likely not reach us but the new focus 1249 * window instead). */ 1250 releaseAllPressedKeys (true /* aReleaseHostKey */); 1251 } 1252 break; 1253 } 1254 1255 case VBoxDefs::ResizeEventType: 1256 { 1257 /* Some situations require initial VGA Resize Request 1258 * to be ignored at all, leaving previous framebuffer, 1259 * console widget and vm window size preserved. */ 1260 if (mIgnoreGuestResize) 1261 return true; 1262 1263 bool oldIgnoreMainwndResize = mIgnoreMainwndResize; 1264 mIgnoreMainwndResize = true; 1265 1266 VBoxResizeEvent *re = (VBoxResizeEvent *) e; 1267 LogRelFlowFunc (("VBoxDefs::ResizeEventType: %d x %d x %d bpp\n", 1268 re->width(), re->height(), 1269 re->bitsPerPixel())); 1270 1271 bool notifyMainWnd = mFrameBuf->width() != re->width() 1272 || mFrameBuf->height() != re->height(); 1273 1274 /* Store the new size to prevent unwanted resize hints being 1275 * sent back. */ 1276 storeConsoleSize(re->width(), re->height()); 1277 /* do frame buffer dependent resize */ 1278 1279 /* restoreOverrideCursor() is broken in Qt 4.4.0 if WA_PaintOnScreen 1280 * widgets are present. This is the case on linux with SDL. As 1281 * workaround we save/restore the arrow cursor manually. See 1282 * http://trolltech.com/developer/task-tracker/index_html?id=206165&method=entry 1283 * for details. 1284 * 1285 * Moreover the current cursor, which could be set by the guest, 1286 * should be restored after resize. 1287 */ 1288 QCursor cursor; 1289 if (shouldHideHostPointer()) 1290 cursor = QCursor (Qt::BlankCursor); 1291 else 1292 cursor = viewport()->cursor(); 1293 mFrameBuf->resizeEvent (re); 1294 viewport()->setCursor (cursor); 1295 1296 #ifdef Q_WS_MAC 1297 mDockIconPreview->setOriginalSize (re->width(), re->height()); 1298 #endif /* Q_WS_MAC */ 1299 1300 /* This event appears in case of guest video was changed 1301 * for somehow even without video resolution change. 1302 * In this last case the host VM window will not be resized 1303 * according this event and the host mouse cursor which was 1304 * unset to default here will not be hidden in capture state. 1305 * So it is necessary to perform updateMouseClipping() for 1306 * the guest resize event if the mouse cursor was captured. */ 1307 if (mMouseCaptured) 1308 updateMouseClipping(); 1309 1310 /* apply maximum size restriction */ 1311 setMaximumSize (sizeHint()); 1312 1313 maybeRestrictMinimumSize(); 1314 1315 /* resize the guest canvas */ 1316 if (!mIgnoreFrameBufferResize) 1317 resize (re->width(), re->height()); 1318 updateSliders(); 1319 /* Let our toplevel widget calculate its sizeHint properly. */ 1320 #ifdef Q_WS_X11 1321 /* We use processEvents rather than sendPostedEvents & set the 1322 * time out value to max cause on X11 otherwise the layout 1323 * isn't calculated correctly. Dosn't find the bug in Qt, but 1324 * this could be triggered through the async nature of the X11 1325 * window event system. */ 1326 QCoreApplication::processEvents (QEventLoop::AllEvents, INT_MAX); 1327 #else /* Q_WS_X11 */ 1328 QCoreApplication::sendPostedEvents (0, QEvent::LayoutRequest); 1329 #endif /* Q_WS_X11 */ 1330 1331 if (!mIgnoreFrameBufferResize) 1332 normalizeGeometry (true /* adjustPosition */); 1333 1334 /* report to the VM thread that we finished resizing */ 1335 mConsole.GetDisplay().ResizeCompleted (0); 1336 1337 mIgnoreMainwndResize = oldIgnoreMainwndResize; 1338 1339 /* update geometry after entering fullscreen | seamless */ 1340 if (mMainWnd->isTrueFullscreen() || mMainWnd->isTrueSeamless()) 1341 updateGeometry(); 1342 1343 /* make sure that all posted signals are processed */ 1344 qApp->processEvents(); 1345 1346 /* emit a signal about guest was resized */ 1347 emit resizeHintDone(); 1348 1349 /* We also recalculate the desktop geometry if this is determined 1350 * automatically. In fact, we only need this on the first resize, 1351 * but it is done every time to keep the code simpler. */ 1352 calculateDesktopGeometry(); 1353 1354 /* Enable frame-buffer resize watching. */ 1355 if (mIgnoreFrameBufferResize) 1356 { 1357 mIgnoreFrameBufferResize = false; 1358 } 1359 1360 if (notifyMainWnd) 1361 mMainWnd->onDisplayResize (re->width(), re->height()); 1362 1363 return true; 1364 } 1365 1366 /* See VBox[QImage|SDL]FrameBuffer::NotifyUpdate(). */ 1367 case VBoxDefs::RepaintEventType: 1368 { 1369 VBoxRepaintEvent *re = (VBoxRepaintEvent *) e; 1370 viewport()->repaint (re->x() - contentsX(), 1371 re->y() - contentsY(), 1372 re->width(), re->height()); 1373 /* mConsole.GetDisplay().UpdateCompleted(); - the event was acked already */ 1374 return true; 1375 } 1376 1377 #ifdef VBOX_WITH_VIDEOHWACCEL 1378 case VBoxDefs::VHWACommandProcessType: 1379 { 1380 mFrameBuf->doProcessVHWACommand(e); 1381 return true; 1382 } 1383 #endif 1384 1385 case VBoxDefs::SetRegionEventType: 1386 { 1387 VBoxSetRegionEvent *sre = (VBoxSetRegionEvent*) e; 1388 if (mMainWnd->isTrueSeamless() && 1389 sre->region() != mLastVisibleRegion) 1390 { 1391 mLastVisibleRegion = sre->region(); 1392 mMainWnd->setMask (sre->region()); 1393 } 1394 else if (!mLastVisibleRegion.isEmpty() && 1395 !mMainWnd->isTrueSeamless()) 1396 mLastVisibleRegion = QRegion(); 1397 return true; 1398 } 1399 1400 case VBoxDefs::MousePointerChangeEventType: 1401 { 1402 MousePointerChangeEvent *me = (MousePointerChangeEvent *) e; 1403 /* change cursor shape only when mouse integration is 1404 * supported (change mouse shape type event may arrive after 1405 * mouse capability change that disables integration */ 1406 if (mMouseAbsolute) 1407 setPointerShape (me); 1408 else 1409 /* Note: actually we should still remember the requested 1410 * cursor shape. If we can't do that, at least remember 1411 * the requested visiblilty. */ 1412 mHideHostPointer = !me->isVisible(); 1413 return true; 1414 } 1415 case VBoxDefs::MouseCapabilityEventType: 1416 { 1417 MouseCapabilityEvent *me = (MouseCapabilityEvent *) e; 1418 if (mMouseAbsolute != me->supportsAbsolute()) 1419 { 1420 mMouseAbsolute = me->supportsAbsolute(); 1421 /* correct the mouse capture state and reset the cursor 1422 * to the default shape if necessary */ 1423 if (mMouseAbsolute) 1424 { 1425 CMouse mouse = mConsole.GetMouse(); 1426 mouse.PutMouseEventAbsolute (-1, -1, 0, 1427 0 /* Horizontal wheel */, 1428 0); 1429 captureMouse (false, false); 1430 } 1431 else 1432 viewport()->unsetCursor(); 1433 emitMouseStateChanged(); 1434 vboxProblem().remindAboutMouseIntegration (mMouseAbsolute); 1435 } 1436 if (me->needsHostCursor()) 1437 mMainWnd->setMouseIntegrationLocked (false); 1438 else 1439 mMainWnd->setMouseIntegrationLocked (true); 1440 return true; 1441 } 1442 1443 case VBoxDefs::ModifierKeyChangeEventType: 1444 { 1445 ModifierKeyChangeEvent *me = (ModifierKeyChangeEvent* )e; 1446 if (me->numLock() != mNumLock) 1447 muNumLockAdaptionCnt = 2; 1448 if (me->capsLock() != mCapsLock) 1449 muCapsLockAdaptionCnt = 2; 1450 mNumLock = me->numLock(); 1451 mCapsLock = me->capsLock(); 1452 mScrollLock = me->scrollLock(); 1453 return true; 1454 } 1455 1456 case VBoxDefs::MachineStateChangeEventType: 1457 { 1458 StateChangeEvent *me = (StateChangeEvent *) e; 1459 LogFlowFunc (("MachineStateChangeEventType: state=%d\n", 1460 me->machineState())); 1461 onStateChange (me->machineState()); 1462 emit machineStateChanged (me->machineState()); 1463 return true; 1464 } 1465 1466 case VBoxDefs::AdditionsStateChangeEventType: 1467 { 1468 GuestAdditionsEvent *ge = (GuestAdditionsEvent *) e; 1469 LogFlowFunc (("AdditionsStateChangeEventType\n")); 1470 1471 /* Always send a size hint if we are in fullscreen or seamless 1472 * when the graphics capability is enabled, in case the host 1473 * resolution has changed since the VM was last run. */ 1474 #if 0 1475 if (!mDoResize && !mGuestSupportsGraphics && 1476 ge->supportsGraphics() && 1477 (mMainWnd->isTrueSeamless() || mMainWnd->isTrueFullscreen())) 1478 mDoResize = true; 1479 #endif 1480 1481 mGuestSupportsGraphics = ge->supportsGraphics(); 1482 1483 maybeRestrictMinimumSize(); 1484 1485 #if 0 1486 /* This will only be acted upon if mDoResize is true. */ 1487 doResizeHint(); 1488 #endif 1489 1490 emit additionsStateChanged (ge->additionVersion(), 1491 ge->additionActive(), 1492 ge->supportsSeamless(), 1493 ge->supportsGraphics()); 1494 return true; 1495 } 1496 1497 case VBoxDefs::MediaDriveChangeEventType: 1498 { 1499 MediaDriveChangeEvent *mce = (MediaDriveChangeEvent *) e; 1500 LogFlowFunc (("MediaChangeEvent\n")); 1501 1502 emit mediaDriveChanged (mce->type()); 1503 return true; 1504 } 1505 1506 case VBoxDefs::ActivateMenuEventType: 1507 { 1508 ActivateMenuEvent *ame = (ActivateMenuEvent *) e; 1509 ame->action()->trigger(); 1510 1511 /* 1512 * The main window and its children can be destroyed at this 1513 * point (if, for example, the activated menu item closes the 1514 * main window). Detect this situation to prevent calls to 1515 * destroyed widgets. 1516 */ 1517 QWidgetList list = QApplication::topLevelWidgets(); 1518 bool destroyed = list.indexOf (mMainWnd) < 0; 1519 if (!destroyed && mMainWnd->statusBar()) 1520 mMainWnd->statusBar()->clearMessage(); 1521 1522 return true; 1523 } 1524 1525 case VBoxDefs::NetworkAdapterChangeEventType: 1526 { 1527 /* no specific adapter information stored in this 1528 * event is currently used */ 1529 emit networkStateChange(); 1530 return true; 1531 } 1532 1533 case VBoxDefs::USBCtlStateChangeEventType: 1534 { 1535 emit usbStateChange(); 1536 return true; 1537 } 1538 1539 case VBoxDefs::USBDeviceStateChangeEventType: 1540 { 1541 USBDeviceStateChangeEvent *ue = (USBDeviceStateChangeEvent *)e; 1542 1543 bool success = ue->error().isNull(); 1544 1545 if (!success) 1546 { 1547 if (ue->attached()) 1548 vboxProblem().cannotAttachUSBDevice ( 1549 mConsole, 1550 vboxGlobal().details (ue->device()), ue->error()); 1551 else 1552 vboxProblem().cannotDetachUSBDevice ( 1553 mConsole, 1554 vboxGlobal().details (ue->device()), ue->error()); 1555 } 1556 1557 emit usbStateChange(); 1558 1559 return true; 1560 } 1561 1562 case VBoxDefs::SharedFolderChangeEventType: 1563 { 1564 emit sharedFoldersChanged(); 1565 return true; 1566 } 1567 1568 case VBoxDefs::RuntimeErrorEventType: 1569 { 1570 RuntimeErrorEvent *ee = (RuntimeErrorEvent *) e; 1571 vboxProblem().showRuntimeError (mConsole, ee->fatal(), 1572 ee->errorID(), ee->message()); 1573 return true; 1574 } 1575 1576 case QEvent::KeyPress: 1577 case QEvent::KeyRelease: 1578 { 1579 QKeyEvent *ke = (QKeyEvent *) e; 1580 1581 #ifdef Q_WS_PM 1582 /// @todo temporary solution to send Alt+Tab and friends to 1583 // the guest. The proper solution is to write a keyboard 1584 // driver that will steal these combos from the host (it's 1585 // impossible to do so using hooks on OS/2). 1586 1587 if (mIsHostkeyPressed) 1588 { 1589 bool pressed = e->type() == QEvent::KeyPress; 1590 CKeyboard keyboard = mConsole.GetKeyboard(); 1591 1592 /* whether the host key is Shift so that it will modify 1593 * the hot key values? Note that we don't distinguish 1594 * between left and right shift here (too much hassle) */ 1595 const bool kShift = (gs.hostKey() == VK_SHIFT || 1596 gs.hostKey() == VK_LSHIFT) && 1597 (ke->state() & Qt::ShiftModifier); 1598 /* define hot keys according to the Shift state */ 1599 const int kAltTab = kShift ? Qt::Key_Exclam : Qt::Key_1; 1600 const int kAltShiftTab = kShift ? Qt::Key_At : Qt::Key_2; 1601 const int kCtrlEsc = kShift ? Qt::Key_AsciiTilde : Qt::Key_QuoteLeft; 1602 1603 /* Simulate Alt+Tab on Host+1 and Alt+Shift+Tab on Host+2 */ 1604 if (ke->key() == kAltTab || ke->key() == kAltShiftTab) 1605 { 1606 if (pressed) 1607 { 1608 /* Send the Alt press to the guest */ 1609 if (!(mPressedKeysCopy [0x38] & IsKeyPressed)) 1610 { 1611 /* store the press in *Copy to have it automatically 1612 * released when the Host key is released */ 1613 mPressedKeysCopy [0x38] |= IsKeyPressed; 1614 keyboard.PutScancode (0x38); 1615 } 1616 1617 /* Make sure Shift is pressed if it's Key_2 and released 1618 * if it's Key_1 */ 1619 if (ke->key() == kAltTab && 1620 (mPressedKeysCopy [0x2A] & IsKeyPressed)) 1621 { 1622 mPressedKeysCopy [0x2A] &= ~IsKeyPressed; 1623 keyboard.PutScancode (0xAA); 1624 } 1625 else 1626 if (ke->key() == kAltShiftTab && 1627 !(mPressedKeysCopy [0x2A] & IsKeyPressed)) 1628 { 1629 mPressedKeysCopy [0x2A] |= IsKeyPressed; 1630 keyboard.PutScancode (0x2A); 1631 } 1632 } 1633 1634 keyboard.PutScancode (pressed ? 0x0F : 0x8F); 1635 1636 ke->accept(); 1637 return true; 1638 } 1639 1640 /* Simulate Ctrl+Esc on Host+Tilde */ 1641 if (ke->key() == kCtrlEsc) 1642 { 1643 /* Send the Ctrl press to the guest */ 1644 if (pressed && !(mPressedKeysCopy [0x1d] & IsKeyPressed)) 1645 { 1646 /* store the press in *Copy to have it automatically 1647 * released when the Host key is released */ 1648 mPressedKeysCopy [0x1d] |= IsKeyPressed; 1649 keyboard.PutScancode (0x1d); 1650 } 1651 1652 keyboard.PutScancode (pressed ? 0x01 : 0x81); 1653 1654 ke->accept(); 1655 return true; 1656 } 1657 } 1658 1659 /* fall through to normal processing */ 1660 1661 #endif /* Q_WS_PM */ 1662 1663 if (mIsHostkeyPressed && e->type() == QEvent::KeyPress) 1664 { 1665 if (ke->key() >= Qt::Key_F1 && ke->key() <= Qt::Key_F12) 1666 { 1667 QVector <LONG> combo (6); 1668 combo [0] = 0x1d; /* Ctrl down */ 1669 combo [1] = 0x38; /* Alt down */ 1670 combo [4] = 0xb8; /* Alt up */ 1671 combo [5] = 0x9d; /* Ctrl up */ 1672 if (ke->key() >= Qt::Key_F1 && ke->key() <= Qt::Key_F10) 1673 { 1674 combo [2] = 0x3b + (ke->key() - Qt::Key_F1); /* F1-F10 down */ 1675 combo [3] = 0xbb + (ke->key() - Qt::Key_F1); /* F1-F10 up */ 1676 } 1677 /* some scan slice */ 1678 else if (ke->key() >= Qt::Key_F11 && ke->key() <= Qt::Key_F12) 1679 { 1680 combo [2] = 0x57 + (ke->key() - Qt::Key_F11); /* F11-F12 down */ 1681 combo [3] = 0xd7 + (ke->key() - Qt::Key_F11); /* F11-F12 up */ 1682 } 1683 else 1684 Assert (0); 1685 1686 CKeyboard keyboard = mConsole.GetKeyboard(); 1687 keyboard.PutScancodes (combo); 1688 } 1689 else if (ke->key() == Qt::Key_Home) 1690 { 1691 /* Activate the main menu */ 1692 if (mMainWnd->isTrueSeamless() || mMainWnd->isTrueFullscreen()) 1693 mMainWnd->popupMainMenu (mMouseCaptured); 1694 else 1695 { 1696 /* In Qt4 it is not enough to just set the focus to 1697 * menu-bar. So to get the menu-bar we have to send 1698 * Qt::Key_Alt press/release events directly. */ 1699 QKeyEvent e1 (QEvent::KeyPress, Qt::Key_Alt, 1700 Qt::NoModifier); 1701 QKeyEvent e2 (QEvent::KeyRelease, Qt::Key_Alt, 1702 Qt::NoModifier); 1703 QApplication::sendEvent (mMainWnd->menuBar(), &e1); 1704 QApplication::sendEvent (mMainWnd->menuBar(), &e2); 1705 } 1706 } 1707 else 1708 { 1709 /* process hot keys not processed in keyEvent() 1710 * (as in case of non-alphanumeric keys) */ 1711 processHotKey (QKeySequence (ke->key()), 1712 mMainWnd->menuBar()->actions()); 1713 } 1714 } 1715 else if (!mIsHostkeyPressed && e->type() == QEvent::KeyRelease) 1716 { 1717 /* Show a possible warning on key release which seems to 1718 * be more expected by the end user */ 1719 1720 if (isPaused()) 1721 { 1722 /* if the reminder is disabled we pass the event to 1723 * Qt to enable normal keyboard functionality 1724 * (for example, menu access with Alt+Letter) */ 1725 if (!vboxProblem().remindAboutPausedVMInput()) 1726 break; 1727 } 1728 } 1729 1730 ke->accept(); 1731 return true; 1732 } 1733 1734 #ifdef Q_WS_MAC 1735 /* posted OnShowWindow */ 1736 case VBoxDefs::ShowWindowEventType: 1737 { 1738 /* 1739 * Dunno what Qt3 thinks a window that has minimized to the dock 1740 * should be - it is not hidden, neither is it minimized. OTOH it is 1741 * marked shown and visible, but not activated. This latter isn't of 1742 * much help though, since at this point nothing is marked activated. 1743 * I might have overlooked something, but I'm buggered what if I know 1744 * what. So, I'll just always show & activate the stupid window to 1745 * make it get out of the dock when the user wishes to show a VM. 1746 */ 1747 window()->show(); 1748 window()->activateWindow(); 1749 return true; 1750 } 1751 #endif 1752 default: 1753 break; 1754 } 1755 } 1756 1757 return QAbstractScrollArea::event (e); 1758 } 1759 1760 #ifdef VBOX_WITH_VIDEOHWACCEL 1761 void VBoxConsoleView::scrollContentsBy (int dx, int dy) 1762 { 1763 if (mAttached && mFrameBuf) 1764 { 1765 mFrameBuf->viewportScrolled(dx, dy); 1766 } 1767 QAbstractScrollArea::scrollContentsBy (dx, dy); 1768 } 1769 #endif 1770 1771 1772 bool VBoxConsoleView::eventFilter (QObject *watched, QEvent *e) 1773 { 1774 if (mAttached && watched == viewport()) 1775 { 1776 switch (e->type()) 1777 { 1778 case QEvent::MouseMove: 1779 case QEvent::MouseButtonPress: 1780 case QEvent::MouseButtonDblClick: 1781 case QEvent::MouseButtonRelease: 1782 { 1783 QMouseEvent *me = (QMouseEvent *) e; 1784 m_iLastMouseWheelDelta = 0; 1785 if (mouseEvent (me->type(), me->pos(), me->globalPos(), 1786 me->buttons(), me->modifiers(), 1787 0, Qt::Horizontal)) 1788 return true; /* stop further event handling */ 1789 break; 1790 } 1791 case QEvent::Wheel: 1792 { 1793 QWheelEvent *we = (QWheelEvent *) e; 1794 /* There are pointing devices which send smaller values for the 1795 * delta than 120. Here we sum them up until we are greater 1796 * than 120. This allows to have finer control over the speed 1797 * acceleration & enables such devices to send a valid wheel 1798 * event to our guest mouse device at all. */ 1799 int iDelta = 0; 1800 m_iLastMouseWheelDelta += we->delta(); 1801 if (qAbs(m_iLastMouseWheelDelta) >= 120) 1802 { 1803 iDelta = m_iLastMouseWheelDelta; 1804 m_iLastMouseWheelDelta = m_iLastMouseWheelDelta % 120; 1805 } 1806 if (mouseEvent (we->type(), we->pos(), we->globalPos(), 1807 #ifdef QT_MAC_USE_COCOA 1808 /* Qt Cocoa is buggy. It always reports a left 1809 * button pressed when the mouse wheel event 1810 * occurs. A workaround is to ask the 1811 * application which buttons are pressed 1812 * currently. */ 1813 QApplication::mouseButtons(), 1814 #else /* QT_MAC_USE_COCOA */ 1815 we->buttons(), 1816 #endif /* QT_MAC_USE_COCOA */ 1817 we->modifiers(), 1818 iDelta, we->orientation())) 1819 return true; /* stop further event handling */ 1820 break; 1821 } 1822 #ifdef Q_WS_MAC 1823 case QEvent::Leave: 1824 { 1825 /* Enable mouse event compression if we leave the VM view. This 1826 is necessary for having smooth resizing of the VM/other 1827 windows. */ 1828 setMouseCoalescingEnabled (true); 1829 break; 1830 } 1831 case QEvent::Enter: 1832 { 1833 /* Disable mouse event compression if we enter the VM view. So 1834 all mouse events are registered in the VM. Only do this if 1835 the keyboard/mouse is grabbed (this is when we have a valid 1836 event handler). */ 1837 setMouseCoalescingEnabled (false); 1838 break; 1839 } 1840 #endif /* Q_WS_MAC */ 1841 case QEvent::Resize: 1842 { 1843 if (mMouseCaptured) 1844 updateMouseClipping(); 1845 #ifdef VBOX_WITH_VIDEOHWACCEL 1846 if (mFrameBuf) 1847 { 1848 mFrameBuf->viewportResized((QResizeEvent*)e); 1849 } 1850 #endif 1851 break; 1852 } 1853 default: 1854 break; 1855 } 1856 } 1857 else if (watched == mMainWnd) 1858 { 1859 switch (e->type()) 1860 { 1861 #if defined (Q_WS_WIN32) 1862 #if defined (VBOX_GUI_USE_DDRAW) 1863 case QEvent::Move: 1864 { 1865 /* 1866 * notification from our parent that it has moved. We need this 1867 * in order to possibly adjust the direct screen blitting. 1868 */ 1869 if (mFrameBuf) 1870 mFrameBuf->moveEvent ((QMoveEvent *) e); 1871 break; 1872 } 1873 #endif 1874 /* 1875 * install/uninstall low-level kbd hook on every 1876 * activation/deactivation to: 1877 * a) avoid excess hook calls when we're not active and 1878 * b) be always in front of any other possible hooks 1879 */ 1880 case QEvent::WindowActivate: 1881 { 1882 gKbdHook = SetWindowsHookEx (WH_KEYBOARD_LL, lowLevelKeyboardProc, 1883 GetModuleHandle (NULL), 0); 1884 AssertMsg (gKbdHook, ("SetWindowsHookEx(): err=%d", GetLastError())); 1885 break; 1886 } 1887 case QEvent::WindowDeactivate: 1888 { 1889 if (gKbdHook) 1890 { 1891 UnhookWindowsHookEx (gKbdHook); 1892 gKbdHook = NULL; 1893 } 1894 break; 1895 } 1896 #endif /* defined (Q_WS_WIN32) */ 1897 #if defined (Q_WS_MAC) 1898 /* 1899 * Install/remove the keyboard event handler. 1900 */ 1901 case QEvent::WindowActivate: 1902 darwinGrabKeyboardEvents (true); 1903 break; 1904 case QEvent::WindowDeactivate: 1905 darwinGrabKeyboardEvents (false); 1906 break; 1907 #endif /* defined (Q_WS_MAC) */ 1908 case QEvent::Resize: 1909 { 1910 /* Set the "guest needs to resize" hint. This hint is acted upon 1911 * when (and only when) the autoresize property is "true". */ 1912 mDoResize = mGuestSupportsGraphics || mMainWnd->isTrueFullscreen(); 1913 if (!mIgnoreMainwndResize && 1914 mGuestSupportsGraphics && mAutoresizeGuest) 1915 QTimer::singleShot (300, this, SLOT (doResizeHint())); 1916 break; 1917 } 1918 case QEvent::WindowStateChange: 1919 { 1920 /* During minimizing and state restoring mMainWnd gets the focus 1921 * which belongs to console view window, so returning it properly. */ 1922 QWindowStateChangeEvent *ev = static_cast <QWindowStateChangeEvent*> (e); 1923 if (ev->oldState() & Qt::WindowMinimized) 1924 { 1925 if (QApplication::focusWidget()) 1926 { 1927 QApplication::focusWidget()->clearFocus(); 1928 qApp->processEvents(); 1929 } 1930 QTimer::singleShot (0, this, SLOT (setFocus())); 1931 } 1932 break; 1933 } 1934 1935 default: 1936 break; 1937 } 1938 } 1939 else if (watched == mMainWnd->menuBar()) 1940 { 1941 /* 1942 * sometimes when we press ESC in the menu it brings the 1943 * focus away (Qt bug?) causing no widget to have a focus, 1944 * or holds the focus itself, instead of returning the focus 1945 * to the console window. here we fix this. 1946 */ 1947 switch (e->type()) 1948 { 1949 case QEvent::FocusOut: 1950 { 1951 if (qApp->focusWidget() == 0) 1952 setFocus(); 1953 break; 1954 } 1955 case QEvent::KeyPress: 1956 { 1957 QKeyEvent *ke = (QKeyEvent *) e; 1958 if (ke->key() == Qt::Key_Escape && (ke->modifiers() == Qt::NoModifier)) 1959 if (mMainWnd->menuBar()->hasFocus()) 1960 setFocus(); 1961 break; 1962 } 1963 default: 1964 break; 1965 } 1966 } 1967 1968 return QAbstractScrollArea::eventFilter (watched, e); 1969 } 1970 1971 #if defined(Q_WS_WIN32) 1972 1973 /** 1974 * Low-level keyboard event handler, 1975 * @return 1976 * true to indicate that the message is processed and false otherwise 1977 */ 1978 bool VBoxConsoleView::winLowKeyboardEvent (UINT msg, const KBDLLHOOKSTRUCT &event) 1979 { 1980 #if 0 1981 LogFlow (("### vkCode=%08X, scanCode=%08X, flags=%08X, dwExtraInfo=%08X (mKbdCaptured=%d)\n", 1982 event.vkCode, event.scanCode, event.flags, event.dwExtraInfo, mKbdCaptured)); 1983 char buf [256]; 1984 sprintf (buf, "### vkCode=%08X, scanCode=%08X, flags=%08X, dwExtraInfo=%08X", 1985 event.vkCode, event.scanCode, event.flags, event.dwExtraInfo); 1986 mMainWnd->statusBar()->message (buf); 1987 #endif 1988 1989 /* Sometimes it happens that Win inserts additional events on some key 1990 * press/release. For example, it prepends ALT_GR in German layout with 1991 * the VK_LCONTROL vkey with curious 0x21D scan code (seems to be necessary 1992 * to specially treat ALT_GR to enter additional chars to regular apps). 1993 * These events are definitely unwanted in VM, so filter them out. */ 1994 /* Note (michael): it also sometimes sends the VK_CAPITAL vkey with scan 1995 * code 0x23a. If this is not passed through then it is impossible to 1996 * cancel CapsLock on a French keyboard. I didn't find any other examples 1997 * of these strange events. Let's hope we are not missing anything else 1998 * of importance! */ 1999 if (hasFocus() && (event.scanCode & ~0xFF)) 2000 { 2001 if (event.vkCode == VK_CAPITAL) 2002 return false; 2003 else 2004 return true; 2005 } 2006 2007 if (!mKbdCaptured) 2008 return false; 2009 2010 /* it's possible that a key has been pressed while the keyboard was not 2011 * captured, but is being released under the capture. Detect this situation 2012 * and return false to let Windows process the message normally and update 2013 * its key state table (to avoid the stuck key effect). */ 2014 uint8_t what_pressed = (event.flags & 0x01) && (event.vkCode != VK_RSHIFT) 2015 ? IsExtKeyPressed 2016 : IsKeyPressed; 2017 if ((event.flags & 0x80) /* released */ && 2018 ((event.vkCode == gs.hostKey() && !hostkey_in_capture) || 2019 (mPressedKeys [event.scanCode] & (IsKbdCaptured | what_pressed)) == what_pressed)) 2020 return false; 2021 2022 MSG message; 2023 message.hwnd = winId(); 2024 message.message = msg; 2025 message.wParam = event.vkCode; 2026 message.lParam = 2027 1 | 2028 (event.scanCode & 0xFF) << 16 | 2029 (event.flags & 0xFF) << 24; 2030 2031 /* Windows sets here the extended bit when the Right Shift key is pressed, 2032 * which is totally wrong. Undo it. */ 2033 if (event.vkCode == VK_RSHIFT) 2034 message.lParam &= ~0x1000000; 2035 2036 /* we suppose here that this hook is always called on the main GUI thread */ 2037 long dummyResult; 2038 return winEvent (&message, &dummyResult); 2039 } 2040 2041 /** 2042 * Get Win32 messages before they are passed to Qt. This allows us to get 2043 * the keyboard events directly and bypass the harmful Qt translation. A 2044 * return value of @c true indicates to Qt that the event has been handled. 2045 */ 2046 bool VBoxConsoleView::winEvent (MSG *aMsg, long* /* aResult */) 2047 { 2048 if (!mAttached || ! ( 2049 aMsg->message == WM_KEYDOWN || aMsg->message == WM_SYSKEYDOWN || 2050 aMsg->message == WM_KEYUP || aMsg->message == WM_SYSKEYUP 2051 )) 2052 return false; 2053 2054 /* check for the special flag possibly set at the end of this function */ 2055 if (aMsg->lParam & (0x1 << 25)) 2056 { 2057 aMsg->lParam &= ~(0x1 << 25); 2058 return false; 2059 } 2060 2061 #if 0 2062 char buf [256]; 2063 sprintf (buf, "WM_%04X: vk=%04X rep=%05d scan=%02X ext=%01d rzv=%01X ctx=%01d prev=%01d tran=%01d", 2064 aMsg->message, aMsg->wParam, 2065 (aMsg->lParam & 0xFFFF), 2066 ((aMsg->lParam >> 16) & 0xFF), 2067 ((aMsg->lParam >> 24) & 0x1), 2068 ((aMsg->lParam >> 25) & 0xF), 2069 ((aMsg->lParam >> 29) & 0x1), 2070 ((aMsg->lParam >> 30) & 0x1), 2071 ((aMsg->lParam >> 31) & 0x1)); 2072 mMainWnd->statusBar()->message (buf); 2073 LogFlow (("%s\n", buf)); 2074 #endif 2075 2076 int scan = (aMsg->lParam >> 16) & 0x7F; 2077 /* scancodes 0x80 and 0x00 are ignored */ 2078 if (!scan) 2079 return true; 2080 2081 int vkey = aMsg->wParam; 2082 2083 /* When one of the SHIFT keys is held and one of the cursor movement 2084 * keys is pressed, Windows duplicates SHIFT press/release messages, 2085 * but with the virtual key code set to 0xFF. These virtual keys are also 2086 * sent in some other situations (Pause, PrtScn, etc.). Ignore such 2087 * messages. */ 2088 if (vkey == 0xFF) 2089 return true; 2090 2091 int flags = 0; 2092 if (aMsg->lParam & 0x1000000) 2093 flags |= KeyExtended; 2094 if (!(aMsg->lParam & 0x80000000)) 2095 flags |= KeyPressed; 2096 2097 switch (vkey) 2098 { 2099 case VK_SHIFT: 2100 case VK_CONTROL: 2101 case VK_MENU: 2102 { 2103 /* overcome stupid Win32 modifier key generalization */ 2104 int keyscan = scan; 2105 if (flags & KeyExtended) 2106 keyscan |= 0xE000; 2107 switch (keyscan) 2108 { 2109 case 0x002A: vkey = VK_LSHIFT; break; 2110 case 0x0036: vkey = VK_RSHIFT; break; 2111 case 0x001D: vkey = VK_LCONTROL; break; 2112 case 0xE01D: vkey = VK_RCONTROL; break; 2113 case 0x0038: vkey = VK_LMENU; break; 2114 case 0xE038: vkey = VK_RMENU; break; 2115 } 2116 break; 2117 } 2118 case VK_NUMLOCK: 2119 /* Win32 sets the extended bit for the NumLock key. Reset it. */ 2120 flags &= ~KeyExtended; 2121 break; 2122 case VK_SNAPSHOT: 2123 flags |= KeyPrint; 2124 break; 2125 case VK_PAUSE: 2126 flags |= KeyPause; 2127 break; 2128 } 2129 2130 bool result = keyEvent (vkey, scan, flags); 2131 if (!result && mKbdCaptured) 2132 { 2133 /* keyEvent() returned that it didn't process the message, but since the 2134 * keyboard is captured, we don't want to pass it to Windows. We just want 2135 * to let Qt process the message (to handle non-alphanumeric <HOST>+key 2136 * shortcuts for example). So send it direcltly to the window with the 2137 * special flag in the reserved area of lParam (to avoid recursion). */ 2138 ::SendMessage (aMsg->hwnd, aMsg->message, 2139 aMsg->wParam, aMsg->lParam | (0x1 << 25)); 2140 return true; 2141 } 2142 2143 /* These special keys have to be handled by Windows as well to update the 2144 * internal modifier state and to enable/disable the keyboard LED */ 2145 if (vkey == VK_NUMLOCK || vkey == VK_CAPITAL || vkey == VK_LSHIFT || vkey == VK_RSHIFT) 2146 return false; 2147 2148 return result; 2149 } 2150 2151 #elif defined (Q_WS_PM) 2152 2153 /** 2154 * Get PM messages before they are passed to Qt. This allows us to get 2155 * the keyboard events directly and bypass the harmful Qt translation. A 2156 * return value of @c true indicates to Qt that the event has been handled. 2157 */ 2158 bool VBoxConsoleView::pmEvent (QMSG *aMsg) 2159 { 2160 if (!mAttached) 2161 return false; 2162 2163 if (aMsg->msg == UM_PREACCEL_CHAR) 2164 { 2165 /* we are inside the input hook */ 2166 2167 /* let the message go through the normal system pipeline */ 2168 if (!mKbdCaptured) 2169 return false; 2170 } 2171 2172 if (aMsg->msg != WM_CHAR && 2173 aMsg->msg != UM_PREACCEL_CHAR) 2174 return false; 2175 2176 /* check for the special flag possibly set at the end of this function */ 2177 if (SHORT2FROMMP (aMsg->mp2) & 0x8000) 2178 { 2179 aMsg->mp2 = MPFROM2SHORT (SHORT1FROMMP (aMsg->mp2), 2180 SHORT2FROMMP (aMsg->mp2) & ~0x8000); 2181 return false; 2182 } 2183 2184 #if 0 2185 { 2186 char buf [256]; 2187 sprintf (buf, "*** %s: f=%04X rep=%03d scan=%02X ch=%04X vk=%04X", 2188 (aMsg->msg == WM_CHAR ? "WM_CHAR" : "UM_PREACCEL_CHAR"), 2189 SHORT1FROMMP (aMsg->mp1), CHAR3FROMMP (aMsg->mp1), 2190 CHAR4FROMMP (aMsg->mp1), SHORT1FROMMP (aMsg->mp2), 2191 SHORT2FROMMP (aMsg->mp2)); 2192 mMainWnd->statusBar()->message (buf); 2193 LogFlow (("%s\n", buf)); 2194 } 2195 #endif 2196 2197 USHORT ch = SHORT1FROMMP (aMsg->mp2); 2198 USHORT f = SHORT1FROMMP (aMsg->mp1); 2199 2200 int scan = (unsigned int) CHAR4FROMMP (aMsg->mp1); 2201 if (!scan || scan > 0x7F) 2202 return true; 2203 2204 int vkey = QIHotKeyEdit::virtualKey (aMsg); 2205 2206 int flags = 0; 2207 2208 if ((ch & 0xFF) == 0xE0) 2209 { 2210 flags |= KeyExtended; 2211 scan = ch >> 8; 2212 } 2213 else if (scan == 0x5C && (ch & 0xFF) == '/') 2214 { 2215 /* this is the '/' key on the keypad */ 2216 scan = 0x35; 2217 flags |= KeyExtended; 2218 } 2219 else 2220 { 2221 /* For some keys, the scan code passed in QMSG is a pseudo scan 2222 * code. We replace it with a real hardware scan code, according to 2223 * http://www.computer-engineering.org/ps2keyboard/scancodes1.html. 2224 * Also detect Pause and PrtScn and set flags. */ 2225 switch (vkey) 2226 { 2227 case VK_ENTER: scan = 0x1C; flags |= KeyExtended; break; 2228 case VK_CTRL: scan = 0x1D; flags |= KeyExtended; break; 2229 case VK_ALTGRAF: scan = 0x38; flags |= KeyExtended; break; 2230 case VK_LWIN: scan = 0x5B; flags |= KeyExtended; break; 2231 case VK_RWIN: scan = 0x5C; flags |= KeyExtended; break; 2232 case VK_WINMENU: scan = 0x5D; flags |= KeyExtended; break; 2233 case VK_FORWARD: scan = 0x69; flags |= KeyExtended; break; 2234 case VK_BACKWARD: scan = 0x6A; flags |= KeyExtended; break; 2235 #if 0 2236 /// @todo this would send 0xE0 0x46 0xE0 0xC6. It's not fully 2237 // clear what is more correct 2238 case VK_BREAK: scan = 0x46; flags |= KeyExtended; break; 2239 #else 2240 case VK_BREAK: scan = 0; flags |= KeyPause; break; 2241 #endif 2242 case VK_PAUSE: scan = 0; flags |= KeyPause; break; 2243 case VK_PRINTSCRN: scan = 0; flags |= KeyPrint; break; 2244 default:; 2245 } 2246 } 2247 2248 if (!(f & KC_KEYUP)) 2249 flags |= KeyPressed; 2250 2251 bool result = keyEvent (vkey, scan, flags); 2252 if (!result && mKbdCaptured) 2253 { 2254 /* keyEvent() returned that it didn't process the message, but since the 2255 * keyboard is captured, we don't want to pass it to PM. We just want 2256 * to let Qt process the message (to handle non-alphanumeric <HOST>+key 2257 * shortcuts for example). So send it direcltly to the window with the 2258 * special flag in the reserved area of lParam (to avoid recursion). */ 2259 ::WinSendMsg (aMsg->hwnd, WM_CHAR, 2260 aMsg->mp1, 2261 MPFROM2SHORT (SHORT1FROMMP (aMsg->mp2), 2262 SHORT2FROMMP (aMsg->mp2) | 0x8000)); 2263 return true; 2264 } 2265 return result; 2266 } 2267 2268 #elif defined(Q_WS_X11) 2269 2270 /** 2271 * This function is a "predicate" for XCheckIfEvent(). It will check 2272 * the XEvent passed to it to see if it is a keypress event matching 2273 * the keyrelease event in @a pvArg. 2274 * @returns True if the event matches, False otherwise 2275 * @param pEvent the event to compare, taken from the event queue 2276 * @param pvArg the keyrelease event we would like to compare against 2277 */ 2278 static Bool VBoxConsoleViewCompEvent(Display *, XEvent *pEvent, 2279 XPointer pvArg) 2280 { 2281 XEvent *pKeyEvent = (XEvent *) pvArg; 2282 if ((pEvent->type == XKeyPress) && 2283 (pEvent->xkey.keycode == pKeyEvent->xkey.keycode)) 2284 return True; 2285 else 2286 return False; 2287 } 2288 2289 /** 2290 * This routine gets X11 events before they are processed by Qt. This is 2291 * used for our platform specific keyboard implementation. A return value 2292 * of TRUE indicates that the event has been processed by us. 2293 */ 2294 bool VBoxConsoleView::x11Event (XEvent *event) 2295 { 2296 switch (event->type) 2297 { 2298 /* We have to handle XFocusOut right here as this event is not passed 2299 * to VBoxConsoleView::event(). Handling this event is important for 2300 * releasing the keyboard before the screen saver gets active. */ 2301 case XFocusOut: 2302 case XFocusIn: 2303 if (isRunning()) 2304 focusEvent (event->type == XFocusIn); 2305 return false; 2306 case XKeyPress: 2307 case XKeyRelease: 2308 if (mAttached) 2309 break; 2310 /* else fall through */ 2311 default: 2312 return false; /* pass the event to Qt */ 2313 } 2314 2315 /* Translate the keycode to a PC scan code. */ 2316 unsigned scan = handleXKeyEvent (event); 2317 2318 #if 0 2319 char buf [256]; 2320 sprintf (buf, "pr=%d kc=%08X st=%08X extended=%s scan=%04X", 2321 event->type == XKeyPress ? 1 : 0, event->xkey.keycode, 2322 event->xkey.state, scan >> 8 ? "true" : "false", scan & 0x7F); 2323 mMainWnd->statusBar()->message (buf); 2324 LogFlow (("### %s\n", buf)); 2325 #endif 2326 2327 // scancodes 0x00 (no valid translation) and 0x80 are ignored 2328 if (!scan & 0x7F) 2329 return true; 2330 2331 /* Fix for http://www.virtualbox.org/ticket/1296: 2332 * when X11 sends events for repeated keys, it always inserts an 2333 * XKeyRelease before the XKeyPress. */ 2334 XEvent returnEvent; 2335 if ((event->type == XKeyRelease) && 2336 (XCheckIfEvent(event->xkey.display, &returnEvent, 2337 VBoxConsoleViewCompEvent, (XPointer) event) == True)) { 2338 XPutBackEvent(event->xkey.display, &returnEvent); 2339 /* Discard it, don't pass it to Qt. */ 2340 return true; 2341 } 2342 2343 KeySym ks = ::XKeycodeToKeysym (event->xkey.display, event->xkey.keycode, 0); 2344 2345 int flags = 0; 2346 if (scan >> 8) 2347 flags |= KeyExtended; 2348 if (event->type == XKeyPress) 2349 flags |= KeyPressed; 2350 2351 /* Remove the extended flag */ 2352 scan &= 0x7F; 2353 2354 switch (ks) 2355 { 2356 case XK_Print: 2357 flags |= KeyPrint; 2358 break; 2359 case XK_Pause: 2360 if (event->xkey.state & ControlMask) /* Break */ 2361 { 2362 ks = XK_Break; 2363 flags |= KeyExtended; 2364 scan = 0x46; 2365 } 2366 else 2367 flags |= KeyPause; 2368 break; 2369 } 2370 2371 return keyEvent (ks, scan, flags); 2372 } 2373 2374 #elif defined (Q_WS_MAC) 2375 2376 /** 2377 * Invoked by VBoxConsoleView::darwinEventHandlerProc / VBoxConsoleView::macEventFilter when 2378 * it receives a raw keyboard event. 2379 * 2380 * @param pvCocoaEvent The Cocoa keyboard event. Can be NULL in some configs. 2381 * @param inEvent The keyboard event. 2382 * 2383 * @return true if the key was processed, false if it wasn't processed and should be passed on. 2384 */ 2385 bool VBoxConsoleView::darwinKeyboardEvent (const void *pvCocoaEvent, EventRef inEvent) 2386 { 2387 bool ret = false; 2388 UInt32 EventKind = ::GetEventKind (inEvent); 2389 if (EventKind != kEventRawKeyModifiersChanged) 2390 { 2391 /* convert keycode to set 1 scan code. */ 2392 UInt32 keyCode = ~0U; 2393 ::GetEventParameter (inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof (keyCode), NULL, &keyCode); 2394 /* The usb keyboard driver translates these codes to different virtual 2395 * key codes depending of the keyboard type. There are ANSI, ISO, JIS 2396 * and unknown. For European keyboards (ISO) the key 0xa and 0x32 have 2397 * to be switched. Here we are doing this at runtime, cause the user 2398 * can have more than one keyboard (of different type), where he may 2399 * switch at will all the time. Default is the ANSI standard as defined 2400 * in g_aDarwinToSet1. */ 2401 if ( (keyCode == 0xa || keyCode == 0x32) 2402 && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) 2403 keyCode = 0x3c - keyCode; 2404 unsigned scanCode = ::DarwinKeycodeToSet1Scancode (keyCode); 2405 if (scanCode) 2406 { 2407 /* calc flags. */ 2408 int flags = 0; 2409 if (EventKind != kEventRawKeyUp) 2410 flags |= KeyPressed; 2411 if (scanCode & VBOXKEY_EXTENDED) 2412 flags |= KeyExtended; 2413 /** @todo KeyPause, KeyPrint. */ 2414 scanCode &= VBOXKEY_SCANCODE_MASK; 2415 2416 /* get the unicode string (if present). */ 2417 AssertCompileSize (wchar_t, 2); 2418 AssertCompileSize (UniChar, 2); 2419 ByteCount cbWritten = 0; 2420 wchar_t ucs[8]; 2421 if (::GetEventParameter (inEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, 2422 sizeof (ucs), &cbWritten, &ucs[0]) != 0) 2423 cbWritten = 0; 2424 ucs[cbWritten / sizeof(wchar_t)] = 0; /* The api doesn't terminate it. */ 2425 2426 ret = keyEvent (keyCode, scanCode, flags, ucs[0] ? ucs : NULL); 2427 } 2428 } 2429 else 2430 { 2431 /* May contain multiple modifier changes, kind of annoying. */ 2432 UInt32 newMask = 0; 2433 ::GetEventParameter (inEvent, kEventParamKeyModifiers, typeUInt32, NULL, 2434 sizeof (newMask), NULL, &newMask); 2435 newMask = ::DarwinAdjustModifierMask (newMask, pvCocoaEvent); 2436 UInt32 changed = newMask ^ mDarwinKeyModifiers; 2437 if (changed) 2438 { 2439 for (UInt32 bit = 0; bit < 32; bit++) 2440 { 2441 if (!(changed & (1 << bit))) 2442 continue; 2443 unsigned scanCode = ::DarwinModifierMaskToSet1Scancode (1 << bit); 2444 if (!scanCode) 2445 continue; 2446 unsigned keyCode = ::DarwinModifierMaskToDarwinKeycode (1 << bit); 2447 Assert (keyCode); 2448 2449 if (!(scanCode & VBOXKEY_LOCK)) 2450 { 2451 unsigned flags = (newMask & (1 << bit)) ? KeyPressed : 0; 2452 if (scanCode & VBOXKEY_EXTENDED) 2453 flags |= KeyExtended; 2454 scanCode &= VBOXKEY_SCANCODE_MASK; 2455 ret |= keyEvent (keyCode, scanCode & 0xff, flags); 572 CMouse mouse = m_console.GetMouse(); 573 mouse.PutMouseEventAbsolute (-1, -1, 0, 574 0 /* Horizontal wheel */, 575 0); 576 captureMouse (false, false); 2456 577 } 2457 578 else 2458 { 2459 unsigned flags = 0; 2460 if (scanCode & VBOXKEY_EXTENDED) 2461 flags |= KeyExtended; 2462 scanCode &= VBOXKEY_SCANCODE_MASK; 2463 keyEvent (keyCode, scanCode, flags | KeyPressed); 2464 keyEvent (keyCode, scanCode, flags); 2465 } 579 viewport()->unsetCursor(); 580 emitMouseStateChanged(); 581 vboxProblem().remindAboutMouseIntegration (m_bIsMouseAbsolute); 2466 582 } 2467 } 2468 2469 mDarwinKeyModifiers = newMask; 2470 2471 /* Always return true here because we'll otherwise getting a Qt event 2472 we don't want and that will only cause the Pause warning to pop up. */ 2473 ret = true; 2474 } 2475 2476 return ret; 2477 } 2478 2479 2480 /** 2481 * Installs or removes the keyboard event handler. 2482 * 2483 * @param fGrab True if we're to grab the events, false if we're not to. 2484 */ 2485 void VBoxConsoleView::darwinGrabKeyboardEvents (bool fGrab) 2486 { 2487 mKeyboardGrabbed = fGrab; 2488 if (fGrab) 2489 { 2490 /* Disable mouse and keyboard event compression/delaying to make sure 2491 we *really* get all of the events. */ 2492 ::CGSetLocalEventsSuppressionInterval (0.0); 2493 setMouseCoalescingEnabled (false); 2494 2495 /* Register the event callback/hook and grab the keyboard. */ 2496 # ifdef QT_MAC_USE_COCOA 2497 ::VBoxCocoaApplication_setCallback (UINT32_MAX, /** @todo fix mask */ 2498 VBoxConsoleView::darwinEventHandlerProc, this); 2499 2500 # elif !defined (VBOX_WITH_HACKED_QT) 2501 EventTypeSpec eventTypes[6]; 2502 eventTypes[0].eventClass = kEventClassKeyboard; 2503 eventTypes[0].eventKind = kEventRawKeyDown; 2504 eventTypes[1].eventClass = kEventClassKeyboard; 2505 eventTypes[1].eventKind = kEventRawKeyUp; 2506 eventTypes[2].eventClass = kEventClassKeyboard; 2507 eventTypes[2].eventKind = kEventRawKeyRepeat; 2508 eventTypes[3].eventClass = kEventClassKeyboard; 2509 eventTypes[3].eventKind = kEventRawKeyModifiersChanged; 2510 /* For ignorning Command-H and Command-Q which aren't affected by the 2511 * global hotkey stuff (doesn't work well): */ 2512 eventTypes[4].eventClass = kEventClassCommand; 2513 eventTypes[4].eventKind = kEventCommandProcess; 2514 eventTypes[5].eventClass = kEventClassCommand; 2515 eventTypes[5].eventKind = kEventCommandUpdateStatus; 2516 2517 EventHandlerUPP eventHandler = ::NewEventHandlerUPP (VBoxConsoleView::darwinEventHandlerProc); 2518 2519 mDarwinEventHandlerRef = NULL; 2520 ::InstallApplicationEventHandler (eventHandler, RT_ELEMENTS (eventTypes), &eventTypes[0], 2521 this, &mDarwinEventHandlerRef); 2522 ::DisposeEventHandlerUPP (eventHandler); 2523 2524 # else /* VBOX_WITH_HACKED_QT */ 2525 ((QIApplication *)qApp)->setEventFilter (VBoxConsoleView::macEventFilter, this); 2526 # endif /* VBOX_WITH_HACKED_QT */ 2527 2528 ::DarwinGrabKeyboard (false); 2529 } 2530 else 2531 { 2532 ::DarwinReleaseKeyboard(); 2533 # ifdef QT_MAC_USE_COCOA 2534 ::VBoxCocoaApplication_unsetCallback (UINT32_MAX, /** @todo fix mask */ 2535 VBoxConsoleView::darwinEventHandlerProc, this); 2536 # elif !defined(VBOX_WITH_HACKED_QT) 2537 if (mDarwinEventHandlerRef) 2538 { 2539 ::RemoveEventHandler (mDarwinEventHandlerRef); 2540 mDarwinEventHandlerRef = NULL; 2541 } 2542 # else /* VBOX_WITH_HACKED_QT */ 2543 ((QIApplication *)qApp)->setEventFilter (NULL, NULL); 2544 # endif /* VBOX_WITH_HACKED_QT */ 2545 } 2546 } 2547 2548 #endif // defined (Q_WS_MAC) 2549 2550 // 2551 // Private members 2552 ///////////////////////////////////////////////////////////////////////////// 2553 2554 /** 2555 * Called on every focus change and also to forcibly capture/uncapture the 2556 * input in situations similar to gaining or losing focus. 2557 * 2558 * @param aHasFocus true if the window got focus and false otherwise. 2559 * @param aReleaseHostKey true to release the host key (used only when 2560 * @a aHasFocus is false. 2561 */ 2562 void VBoxConsoleView::focusEvent (bool aHasFocus, 2563 bool aReleaseHostKey /* = true */) 2564 { 2565 if (aHasFocus) 2566 { 2567 #ifdef RT_OS_WINDOWS 2568 if ( !mDisableAutoCapture && gs.autoCapture() 2569 && GetAncestor (winId(), GA_ROOT) == GetForegroundWindow()) 2570 #else 2571 if (!mDisableAutoCapture && gs.autoCapture()) 2572 #endif /* RT_OS_WINDOWS */ 2573 { 2574 captureKbd (true); 2575 /// @todo (dmik) 2576 // the below is for the mouse auto-capture. disabled for now. in order to 2577 // properly support it, we need to know when *all* mouse buttons are 2578 // released after we got focus, and grab the mouse only after then. 2579 // btw, the similar would be good the for keyboard auto-capture, too. 2580 // if (!(mMouseAbsolute && mMouseIntegration)) 2581 // captureMouse (true); 2582 } 2583 2584 /* reset the single-time disable capture flag */ 2585 if (mDisableAutoCapture) 2586 mDisableAutoCapture = false; 2587 } 2588 else 2589 { 2590 captureMouse (false); 2591 captureKbd (false, false); 2592 releaseAllPressedKeys (aReleaseHostKey); 2593 } 2594 } 2595 2596 /** 2597 * Synchronize the views of the host and the guest to the modifier keys. 2598 * This function will add up to 6 additional keycodes to codes. 2599 * 2600 * @param codes pointer to keycodes which are sent to the keyboard 2601 * @param count pointer to the keycodes counter 2602 */ 2603 void VBoxConsoleView::fixModifierState (LONG *codes, uint *count) 2604 { 2605 #if defined(Q_WS_X11) 2606 2607 Window wDummy1, wDummy2; 2608 int iDummy3, iDummy4, iDummy5, iDummy6; 2609 unsigned uMask; 2610 unsigned uKeyMaskNum = 0, uKeyMaskCaps = 0, uKeyMaskScroll = 0; 2611 2612 uKeyMaskCaps = LockMask; 2613 XModifierKeymap* map = XGetModifierMapping(QX11Info::display()); 2614 KeyCode keyCodeNum = XKeysymToKeycode(QX11Info::display(), XK_Num_Lock); 2615 KeyCode keyCodeScroll = XKeysymToKeycode(QX11Info::display(), XK_Scroll_Lock); 2616 2617 for (int i = 0; i < 8; i++) 2618 { 2619 if ( keyCodeNum != NoSymbol 2620 && map->modifiermap[map->max_keypermod * i] == keyCodeNum) 2621 uKeyMaskNum = 1 << i; 2622 else if ( keyCodeScroll != NoSymbol 2623 && map->modifiermap[map->max_keypermod * i] == keyCodeScroll) 2624 uKeyMaskScroll = 1 << i; 2625 } 2626 XQueryPointer(QX11Info::display(), DefaultRootWindow(QX11Info::display()), &wDummy1, &wDummy2, 2627 &iDummy3, &iDummy4, &iDummy5, &iDummy6, &uMask); 2628 XFreeModifiermap(map); 2629 2630 if (muNumLockAdaptionCnt && (mNumLock ^ !!(uMask & uKeyMaskNum))) 2631 { 2632 muNumLockAdaptionCnt--; 2633 codes[(*count)++] = 0x45; 2634 codes[(*count)++] = 0x45 | 0x80; 2635 } 2636 if (muCapsLockAdaptionCnt && (mCapsLock ^ !!(uMask & uKeyMaskCaps))) 2637 { 2638 muCapsLockAdaptionCnt--; 2639 codes[(*count)++] = 0x3a; 2640 codes[(*count)++] = 0x3a | 0x80; 2641 /* Some keyboard layouts require shift to be pressed to break 2642 * capslock. For simplicity, only do this if shift is not 2643 * already held down. */ 2644 if (mCapsLock && !(mPressedKeys [0x2a] & IsKeyPressed)) 2645 { 2646 codes[(*count)++] = 0x2a; 2647 codes[(*count)++] = 0x2a | 0x80; 2648 } 2649 } 2650 2651 #elif defined(Q_WS_WIN32) 2652 2653 if (muNumLockAdaptionCnt && (mNumLock ^ !!(GetKeyState(VK_NUMLOCK)))) 2654 { 2655 muNumLockAdaptionCnt--; 2656 codes[(*count)++] = 0x45; 2657 codes[(*count)++] = 0x45 | 0x80; 2658 } 2659 if (muCapsLockAdaptionCnt && (mCapsLock ^ !!(GetKeyState(VK_CAPITAL)))) 2660 { 2661 muCapsLockAdaptionCnt--; 2662 codes[(*count)++] = 0x3a; 2663 codes[(*count)++] = 0x3a | 0x80; 2664 /* Some keyboard layouts require shift to be pressed to break 2665 * capslock. For simplicity, only do this if shift is not 2666 * already held down. */ 2667 if (mCapsLock && !(mPressedKeys [0x2a] & IsKeyPressed)) 2668 { 2669 codes[(*count)++] = 0x2a; 2670 codes[(*count)++] = 0x2a | 0x80; 2671 } 2672 } 2673 2674 #elif defined (Q_WS_MAC) 2675 2676 /* if (muNumLockAdaptionCnt) ... - NumLock isn't implemented by Mac OS X so ignore it. */ 2677 if (muCapsLockAdaptionCnt && (mCapsLock ^ !!(::GetCurrentEventKeyModifiers() & alphaLock))) 2678 { 2679 muCapsLockAdaptionCnt--; 2680 codes[(*count)++] = 0x3a; 2681 codes[(*count)++] = 0x3a | 0x80; 2682 /* Some keyboard layouts require shift to be pressed to break 2683 * capslock. For simplicity, only do this if shift is not 2684 * already held down. */ 2685 if (mCapsLock && !(mPressedKeys [0x2a] & IsKeyPressed)) 2686 { 2687 codes[(*count)++] = 0x2a; 2688 codes[(*count)++] = 0x2a | 0x80; 2689 } 2690 } 2691 2692 #else 2693 2694 //#warning Adapt VBoxConsoleView::fixModifierState 2695 2696 #endif 2697 2698 2699 } 2700 2701 /** 2702 * Called on enter/exit seamless/fullscreen mode. 2703 */ 2704 void VBoxConsoleView::toggleFSMode (const QSize &aSize) 2705 { 2706 if ((mGuestSupportsGraphics && mAutoresizeGuest) || 2707 mMainWnd->isTrueSeamless() || 2708 mMainWnd->isTrueFullscreen()) 2709 { 2710 QSize newSize; 2711 if (aSize.isValid()) 2712 { 2713 mNormalSize = aSize; 2714 newSize = maximumSize(); 2715 } 2716 else 2717 newSize = mNormalSize; 2718 doResizeHint (newSize); 2719 } 2720 2721 /* Reactivate the console window to preserve the focus position. 2722 * Else focus will move to the mini-tool-bar. */ 2723 activateWindow(); 2724 } 2725 2726 /** 2727 * Get the current available desktop geometry for the console/framebuffer 2728 * 2729 * @returns the geometry. An empty rectangle means unrestricted. 2730 */ 2731 QRect VBoxConsoleView::desktopGeometry() 2732 { 2733 QRect rc; 2734 switch (mDesktopGeo) 2735 { 2736 case DesktopGeo_Fixed: 2737 case DesktopGeo_Automatic: 2738 rc = QRect (0, 0, 2739 RT_MAX (mDesktopGeometry.width(), mStoredConsoleSize.width()), 2740 RT_MAX (mDesktopGeometry.height(), mStoredConsoleSize.height())); 2741 break; 2742 case DesktopGeo_Any: 2743 rc = QRect (0, 0, 0, 0); 2744 break; 2745 default: 2746 AssertMsgFailed (("Bad geometry type %d\n", mDesktopGeo)); 2747 } 2748 return rc; 2749 } 2750 2751 QRegion VBoxConsoleView::lastVisibleRegion() const 2752 { 2753 return mLastVisibleRegion; 2754 } 2755 2756 bool VBoxConsoleView::isAutoresizeGuestActive() 2757 { 2758 return mGuestSupportsGraphics && mAutoresizeGuest; 2759 } 2760 2761 /** 2762 * Called on every key press and release (while in focus). 2763 * 2764 * @param aKey virtual scan code (virtual key on Win32 and KeySym on X11) 2765 * @param aScan hardware scan code 2766 * @param aFlags flags, a combination of Key* constants 2767 * @param aUniKey Unicode translation of the key. Optional. 2768 * 2769 * @return true to consume the event and false to pass it to Qt 2770 */ 2771 bool VBoxConsoleView::keyEvent (int aKey, uint8_t aScan, int aFlags, 2772 wchar_t *aUniKey/* = NULL*/) 2773 { 583 if (me->needsHostCursor()) 584 setMouseIntegrationLocked (false); 585 else 586 setMouseIntegrationLocked (true); 587 return true; 588 #endif 589 UIMouseCapabilityChangeEvent *pConsoleEvent = static_cast<UIMouseCapabilityChangeEvent*>(pEvent); 590 emit sigMouseCapabilityChange(pConsoleEvent->supportsAbsolute(), pConsoleEvent->needsHostCursor()); 591 return true; 592 } 593 594 case UIConsoleEventType_KeyboardLedsChange: 595 { 596 #if 0 // TODO: Move to machine view! 597 ModifierKeyChangeEvent *me = (ModifierKeyChangeEvent* )pEvent; 598 if (me->numLock() != mNumLock) 599 muNumLockAdaptionCnt = 2; 600 if (me->capsLock() != mCapsLock) 601 muCapsLockAdaptionCnt = 2; 602 mNumLock = me->numLock(); 603 mCapsLock = me->capsLock(); 604 mScrollLock = me->scrollLock(); 605 #endif 606 UIKeyboardLedsChangeEvent *pConsoleEvent = static_cast<UIKeyboardLedsChangeEvent*>(pEvent); 607 emit sigKeyboardLedsChange(pConsoleEvent->numLock(), pConsoleEvent->capsLock(), pConsoleEvent->scrollLock()); 608 return true; 609 } 610 611 case UIConsoleEventType_StateChange: 612 { 613 #if 0 // TODO: Move to machine view! 614 MachineUIStateChangeEvent *me = (MachineUIStateChangeEvent *) pEvent; 615 LogFlowFunc (("MachineUIStateChangeEventType: state=%d\n", 616 me->machineState())); 617 onStateChange (me->machineState()); 618 emit machineStateChanged (me->machineState()); 619 #endif 620 UIStateChangeEvent *pConsoleEvent = static_cast<UIStateChangeEvent*>(pEvent); 621 emit sigStateChange(pConsoleEvent->machineState()); 622 return true; 623 } 624 625 case UIConsoleEventType_AdditionsStateChange: 626 { 627 #if 0 // TODO: Move to machine view! 628 GuestAdditionsChangeEvent *ge = (GuestAdditionsChangeEvent *) pEvent; 629 LogFlowFunc (("UIAdditionsStateChangeEventType\n")); 630 /* Always send a size hint if we are in fullscreen or seamless 631 * when the graphics capability is enabled, in case the host 632 * resolution has changed since the VM was last run. */ 2774 633 #if 0 2775 { 2776 char buf [256]; 2777 sprintf (buf, "aKey=%08X aScan=%02X aFlags=%08X", 2778 aKey, aScan, aFlags); 2779 mMainWnd->statusBar()->message (buf); 2780 } 2781 #endif 2782 2783 const bool isHostKey = aKey == gs.hostKey(); 2784 2785 LONG buf [16]; 2786 LONG *codes = buf; 2787 uint count = 0; 2788 uint8_t whatPressed = 0; 2789 2790 if (!isHostKey && !mIsHostkeyPressed) 2791 { 2792 if (aFlags & KeyPrint) 2793 { 2794 static LONG PrintMake[] = { 0xE0, 0x2A, 0xE0, 0x37 }; 2795 static LONG PrintBreak[] = { 0xE0, 0xB7, 0xE0, 0xAA }; 2796 if (aFlags & KeyPressed) 634 if (!mDoResize && !m_bIsGuestSupportsGraphics && 635 ge->supportsGraphics() && 636 (machineWindowWrapper()->isTrueSeamless() || machineWindowWrapper()->isTrueFullscreen())) 637 mDoResize = true; 638 #endif 639 m_bIsGuestSupportsGraphics = ge->supportsGraphics(); 640 641 maybeRestrictMinimumSize(); 642 643 #if 0 644 /* This will only be acted upon if mDoResize is true. */ 645 doResizeHint(); 646 #endif 647 648 emit additionsStateChanged (ge->additionVersion(), 649 ge->additionActive(), 650 ge->supportsSeamless(), 651 ge->supportsGraphics()); 652 #endif 653 emit sigAdditionsStateChange(); 654 return true; 655 } 656 657 case UIConsoleEventType_NetworkAdapterChange: 658 { 659 #if 0 // TODO: Move to machine view! 660 /* no specific adapter information stored in this 661 * event is currently used */ 662 emit networkStateChange(); 663 #endif 664 UINetworkAdapterChangeEvent *pConsoleEvent = static_cast<UINetworkAdapterChangeEvent*>(pEvent); 665 emit sigNetworkAdapterChange(pConsoleEvent->networkAdapter()); 666 return true; 667 } 668 669 case UIConsoleEventType_SerialPortChange: 670 { 671 UISerialPortChangeEvent *pConsoleEvent = static_cast<UISerialPortChangeEvent*>(pEvent); 672 emit sigSerialPortChange(pConsoleEvent->serialPort()); 673 return true; 674 } 675 676 case UIConsoleEventType_ParallelPortChange: 677 { 678 UIParallelPortChangeEvent *pConsoleEvent = static_cast<UIParallelPortChangeEvent*>(pEvent); 679 emit sigParallelPortChange(pConsoleEvent->parallelPort()); 680 return true; 681 } 682 683 case UIConsoleEventType_StorageControllerChange: 684 { 685 emit sigStorageControllerChange(); 686 return true; 687 } 688 689 case UIConsoleEventType_MediumChange: 690 { 691 #if 0 // TODO: Move to machine view! 692 MediaDriveChangeEvent *mce = (MediaDriveChangeEvent *) pEvent; 693 LogFlowFunc (("MediaChangeEvent\n")); 694 695 emit mediaDriveChanged (mce->type()); 696 #endif 697 UIMediumChangeEvent *pConsoleEvent = static_cast<UIMediumChangeEvent*>(pEvent); 698 emit sigMediumChange(pConsoleEvent->mediumAttahment()); 699 return true; 700 } 701 702 case UIConsoleEventType_CPUChange: 703 { 704 UICPUChangeEvent *pConsoleEvent = static_cast<UICPUChangeEvent*>(pEvent); 705 emit sigCPUChange(pConsoleEvent->cpu(), pConsoleEvent->remove()); 706 return true; 707 } 708 709 case UIConsoleEventType_VRDPServerChange: 710 { 711 emit sigVRDPServerChange(); 712 return true; 713 } 714 715 case UIConsoleEventType_RemoteDisplayInfoChange: 716 { 717 emit sigRemoteDisplayInfoChange(); 718 return true; 719 } 720 721 case UIConsoleEventType_USBControllerChange: 722 { 723 emit sigUSBControllerChange(); 724 return true; 725 } 726 727 case UIConsoleEventType_USBDeviceStateChange: 728 { 729 #if 0 // TODO: Move to machine view! 730 UIUSBDeviceUIStateChangeEvent *ue = (UIUSBDeviceUIStateChangeEvent *)pEvent; 731 732 bool success = ue->error().isNull(); 733 734 if (!success) 2797 735 { 2798 codes = PrintMake; 2799 count = SIZEOF_ARRAY (PrintMake); 736 if (ue->attached()) 737 vboxProblem().cannotAttachUSBDevice ( 738 m_console, 739 vboxGlobal().details (ue->device()), ue->error()); 740 else 741 vboxProblem().cannotDetachUSBDevice ( 742 m_console, 743 vboxGlobal().details (ue->device()), ue->error()); 2800 744 } 2801 else 2802 { 2803 codes = PrintBreak; 2804 count = SIZEOF_ARRAY (PrintBreak); 2805 } 2806 } 2807 else if (aFlags & KeyPause) 2808 { 2809 if (aFlags & KeyPressed) 2810 { 2811 static LONG Pause[] = { 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 }; 2812 codes = Pause; 2813 count = SIZEOF_ARRAY (Pause); 2814 } 2815 else 2816 { 2817 /* Pause shall not produce a break code */ 2818 return true; 2819 } 2820 } 2821 else 2822 { 2823 if (aFlags & KeyPressed) 2824 { 2825 /* Check if the guest has the same view on the modifier keys (NumLock, 2826 * CapsLock, ScrollLock) as the X server. If not, send KeyPress events 2827 * to synchronize the state. */ 2828 fixModifierState (codes, &count); 2829 } 2830 2831 /* Check if it's C-A-D and GUI/PassCAD is not true */ 2832 if (!mPassCAD && 2833 aScan == 0x53 /* Del */ && 2834 ((mPressedKeys [0x38] & IsKeyPressed) /* Alt */ || 2835 (mPressedKeys [0x38] & IsExtKeyPressed)) && 2836 ((mPressedKeys [0x1d] & IsKeyPressed) /* Ctrl */ || 2837 (mPressedKeys [0x1d] & IsExtKeyPressed))) 2838 { 2839 /* Use the C-A-D combination as a last resort to get the 2840 * keyboard and mouse back to the host when the user forgets 2841 * the Host Key. Note that it's always possible to send C-A-D 2842 * to the guest using the Host+Del combination. BTW, it would 2843 * be preferrable to completely ignore C-A-D in guests, but 2844 * that's not possible because we cannot predict what other 2845 * keys will be pressed next when one of C, A, D is held. */ 2846 2847 if (isRunning() && mKbdCaptured) 2848 { 2849 captureKbd (false); 2850 if (!(mMouseAbsolute && mMouseIntegration)) 2851 captureMouse (false); 2852 } 2853 2854 return true; 2855 } 2856 2857 /* process the scancode and update the table of pressed keys */ 2858 whatPressed = IsKeyPressed; 2859 2860 if (aFlags & KeyExtended) 2861 { 2862 codes [count++] = 0xE0; 2863 whatPressed = IsExtKeyPressed; 2864 } 2865 2866 if (aFlags & KeyPressed) 2867 { 2868 codes [count++] = aScan; 2869 mPressedKeys [aScan] |= whatPressed; 2870 } 2871 else 2872 { 2873 /* if we haven't got this key's press message, we ignore its 2874 * release */ 2875 if (!(mPressedKeys [aScan] & whatPressed)) 2876 return true; 2877 codes [count++] = aScan | 0x80; 2878 mPressedKeys [aScan] &= ~whatPressed; 2879 } 2880 2881 if (mKbdCaptured) 2882 mPressedKeys [aScan] |= IsKbdCaptured; 2883 else 2884 mPressedKeys [aScan] &= ~IsKbdCaptured; 2885 } 2886 } 2887 else 2888 { 2889 /* currently this is used in winLowKeyboardEvent() only */ 2890 hostkey_in_capture = mKbdCaptured; 2891 } 2892 2893 bool emitSignal = false; 2894 int hotkey = 0; 2895 2896 /* process the host key */ 2897 if (aFlags & KeyPressed) 2898 { 2899 if (isHostKey) 2900 { 2901 if (!mIsHostkeyPressed) 2902 { 2903 mIsHostkeyPressed = mIsHostkeyAlone = true; 2904 if (isRunning()) 2905 saveKeyStates(); 2906 emitSignal = true; 2907 } 2908 } 2909 else 2910 { 2911 if (mIsHostkeyPressed) 2912 { 2913 if (mIsHostkeyAlone) 2914 { 2915 hotkey = aKey; 2916 mIsHostkeyAlone = false; 2917 } 2918 } 2919 } 2920 } 2921 else 2922 { 2923 if (isHostKey) 2924 { 2925 if (mIsHostkeyPressed) 2926 { 2927 mIsHostkeyPressed = false; 2928 2929 if (mIsHostkeyAlone) 2930 { 2931 if (isPaused()) 2932 { 2933 vboxProblem().remindAboutPausedVMInput(); 2934 } 2935 else 2936 if (isRunning()) 2937 { 2938 bool captured = mKbdCaptured; 2939 bool ok = true; 2940 if (!captured) 2941 { 2942 /* temporarily disable auto capture that will take 2943 * place after this dialog is dismissed because 2944 * the capture state is to be defined by the 2945 * dialog result itself */ 2946 mDisableAutoCapture = true; 2947 bool autoConfirmed = false; 2948 ok = vboxProblem().confirmInputCapture (&autoConfirmed); 2949 if (autoConfirmed) 2950 mDisableAutoCapture = false; 2951 /* otherwise, the disable flag will be reset in 2952 * the next console view's foucs in event (since 2953 * may happen asynchronously on some platforms, 2954 * after we return from this code) */ 2955 } 2956 2957 if (ok) 2958 { 2959 captureKbd (!captured, false); 2960 if (!(mMouseAbsolute && mMouseIntegration)) 2961 { 2962 #ifdef Q_WS_X11 2963 /* make sure that pending FocusOut events from the 2964 * previous message box are handled, otherwise the 2965 * mouse is immediately ungrabbed. */ 2966 qApp->processEvents(); 2967 #endif 2968 captureMouse (mKbdCaptured); 2969 } 2970 } 2971 } 2972 } 2973 2974 if (isRunning()) 2975 sendChangedKeyStates(); 2976 2977 emitSignal = true; 2978 } 2979 } 2980 else 2981 { 2982 if (mIsHostkeyPressed) 2983 mIsHostkeyAlone = false; 2984 } 2985 } 2986 2987 /* emit the keyboard state change signal */ 2988 if (emitSignal) 2989 emitKeyboardStateChanged(); 2990 2991 /* Process Host+<key> shortcuts. currently, <key> is limited to 2992 * alphanumeric chars. Other Host+<key> combinations are handled in 2993 * event(). */ 2994 if (hotkey) 2995 { 2996 bool processed = false; 2997 #if defined (Q_WS_WIN32) 2998 NOREF(aUniKey); 2999 int n = GetKeyboardLayoutList (0, NULL); 3000 Assert (n); 3001 HKL *list = new HKL [n]; 3002 GetKeyboardLayoutList (n, list); 3003 for (int i = 0; i < n && !processed; i++) 3004 { 3005 wchar_t ch; 3006 static BYTE keys [256] = {0}; 3007 if (!ToUnicodeEx (hotkey, 0, keys, &ch, 1, 0, list [i]) == 1) 3008 ch = 0; 3009 if (ch) 3010 processed = processHotKey (QKeySequence (Qt::UNICODE_ACCEL + 3011 QChar (ch).toUpper().unicode()), 3012 mMainWnd->menuBar()->actions()); 3013 } 3014 delete[] list; 3015 #elif defined (Q_WS_X11) 3016 NOREF(aUniKey); 3017 Display *display = QX11Info::display(); 3018 int keysyms_per_keycode = getKeysymsPerKeycode(); 3019 KeyCode kc = XKeysymToKeycode (display, aKey); 3020 // iterate over the first level (not shifted) keysyms in every group 3021 for (int i = 0; i < keysyms_per_keycode && !processed; i += 2) 3022 { 3023 KeySym ks = XKeycodeToKeysym (display, kc, i); 3024 char ch = 0; 3025 if (!XkbTranslateKeySym (display, &ks, 0, &ch, 1, NULL) == 1) 3026 ch = 0; 3027 if (ch) 3028 { 3029 QChar c = QString::fromLocal8Bit (&ch, 1) [0]; 3030 processed = processHotKey (QKeySequence (Qt::UNICODE_ACCEL + 3031 c.toUpper().unicode()), 3032 mMainWnd->menuBar()->actions()); 3033 } 3034 } 3035 #elif defined (Q_WS_MAC) 3036 if (aUniKey && aUniKey [0] && !aUniKey [1]) 3037 processed = processHotKey (QKeySequence (Qt::UNICODE_ACCEL + 3038 QChar (aUniKey [0]).toUpper().unicode()), 3039 mMainWnd->menuBar()->actions()); 3040 3041 /* Don't consider the hot key as pressed since the guest never saw 3042 * it. (probably a generic thing) */ 3043 mPressedKeys [aScan] &= ~whatPressed; 3044 #endif 3045 3046 /* grab the key from Qt if processed, or pass it to Qt otherwise 3047 * in order to process non-alphanumeric keys in event(), after they are 3048 * converted to Qt virtual keys. */ 3049 return processed; 3050 } 3051 3052 /* no more to do, if the host key is in action or the VM is paused */ 3053 if (mIsHostkeyPressed || isHostKey || isPaused()) 3054 { 3055 /* grab the key from Qt and from VM if it's a host key, 3056 * otherwise just pass it to Qt */ 3057 return isHostKey; 3058 } 3059 3060 CKeyboard keyboard = mConsole.GetKeyboard(); 3061 Assert (!keyboard.isNull()); 3062 3063 #if defined (Q_WS_WIN32) 3064 /* send pending WM_PAINT events */ 3065 ::UpdateWindow (viewport()->winId()); 3066 #endif 3067 3068 #if 0 3069 { 3070 char buf [256]; 3071 sprintf (buf, "*** SCANS: "); 3072 for (uint i = 0; i < count; ++ i) 3073 sprintf (buf + strlen (buf), "%02X ", codes [i]); 3074 mMainWnd->statusBar()->message (buf); 3075 LogFlow (("%s\n", buf)); 3076 } 3077 #endif 3078 3079 std::vector <LONG> scancodes(codes, &codes[count]); 3080 keyboard.PutScancodes (QVector<LONG>::fromStdVector(scancodes)); 3081 3082 /* grab the key from Qt */ 3083 return true; 3084 } 3085 3086 /** 3087 * Called on every mouse/wheel move and button press/release. 3088 * 3089 * @return true to consume the event and false to pass it to Qt 3090 */ 3091 bool VBoxConsoleView::mouseEvent (int aType, const QPoint &aPos, const QPoint &aGlobalPos, 3092 Qt::MouseButtons aButtons, Qt::KeyboardModifiers aModifiers, 3093 int aWheelDelta, Qt::Orientation aWheelDir) 3094 { 3095 #if 1 3096 3097 LogRel3(("%s: type=%03d x=%03d y=%03d btns=%08X wdelta=%03d wdir=%s\n", 3098 __PRETTY_FUNCTION__ , aType, aPos.x(), aPos.y(), 3099 (aButtons & Qt::LeftButton ? 1 : 0) 3100 | (aButtons & Qt::RightButton ? 2 : 0) 3101 | (aButtons & Qt::MidButton ? 4 : 0) 3102 | (aButtons & Qt::XButton1 ? 8 : 0) 3103 | (aButtons & Qt::XButton2 ? 16 : 0), 3104 aWheelDelta, 3105 aWheelDir == Qt::Horizontal ? "Horizontal" 3106 : aWheelDir == Qt::Vertical ? "Vertical" : "Unknown")); 3107 Q_UNUSED (aModifiers); 3108 #else 3109 Q_UNUSED (aModifiers); 3110 #endif 3111 3112 int state = 0; 3113 if (aButtons & Qt::LeftButton) 3114 state |= KMouseButtonState_LeftButton; 3115 if (aButtons & Qt::RightButton) 3116 state |= KMouseButtonState_RightButton; 3117 if (aButtons & Qt::MidButton) 3118 state |= KMouseButtonState_MiddleButton; 3119 if (aButtons & Qt::XButton1) 3120 state |= KMouseButtonState_XButton1; 3121 if (aButtons & Qt::XButton2) 3122 state |= KMouseButtonState_XButton2; 745 746 emit usbStateChange(); 747 #endif 748 UIUSBDeviceUIStateChangeEvent *pConsoleEvent = static_cast<UIUSBDeviceUIStateChangeEvent*>(pEvent); 749 emit sigUSBDeviceStateChange(pConsoleEvent->device(), pConsoleEvent->attached(), pConsoleEvent->error()); 750 return true; 751 } 752 753 case UIConsoleEventType_SharedFolderChange: 754 { 755 emit sigSharedFolderChange(); 756 return true; 757 } 758 759 case UIConsoleEventType_RuntimeError: 760 { 761 #if 0 // TODO: Move to machine view! 762 UIRuntimeErrorEvent *pConsoleEvent = (UIRuntimeErrorEvent *) pEvent; 763 vboxProblem().showRuntimeError(m_console, ee->fatal(), ee->errorID(), ee->message()); 764 #endif 765 UIRuntimeErrorEvent *pConsoleEvent = static_cast<UIRuntimeErrorEvent*>(pEvent); 766 emit sigRuntimeError(pConsoleEvent->fatal(), pConsoleEvent->errorID(), pConsoleEvent->message()); 767 return true; 768 } 3123 769 3124 770 #ifdef Q_WS_MAC 3125 /* Simulate the right click on 3126 * Host+Left Mouse */ 3127 if (mIsHostkeyPressed && 3128 mIsHostkeyAlone && 3129 state == KMouseButtonState_LeftButton) 3130 state = KMouseButtonState_RightButton; 3131 #endif /* Q_WS_MAC */ 3132 3133 int wheelVertical = 0; 3134 int wheelHorizontal = 0; 3135 if (aWheelDir == Qt::Vertical) 3136 { 3137 /* the absolute value of wheel delta is 120 units per every wheel 3138 * move; positive deltas correspond to counterclockwize rotations 3139 * (usually up), negative -- to clockwize (usually down). */ 3140 wheelVertical = - (aWheelDelta / 120); 3141 } 3142 else if (aWheelDir == Qt::Horizontal) 3143 wheelHorizontal = aWheelDelta / 120; 3144 3145 if (mMouseCaptured) 3146 { 3147 #ifdef Q_WS_WIN32 3148 /* send pending WM_PAINT events */ 3149 ::UpdateWindow (viewport()->winId()); 3150 #endif 3151 3152 CMouse mouse = mConsole.GetMouse(); 3153 mouse.PutMouseEvent (aGlobalPos.x() - mLastPos.x(), 3154 aGlobalPos.y() - mLastPos.y(), 3155 wheelVertical, wheelHorizontal, state); 3156 3157 #if defined (Q_WS_MAC) 3158 /* 3159 * Keep the mouse from leaving the widget. 3160 * 3161 * This is a bit tricky to get right because if it escapes we won't necessarily 3162 * get mouse events any longer and can warp it back. So, we keep safety zone 3163 * of up to 300 pixels around the borders of the widget to prevent this from 3164 * happening. Also, the mouse is warped back to the center of the widget. 3165 * 3166 * (Note, aPos seems to be unreliable, it caused endless recursion here at one points...) 3167 * (Note, synergy and other remote clients might not like this cursor warping.) 3168 */ 3169 QRect rect = viewport()->visibleRegion().boundingRect(); 3170 QPoint pw = viewport()->mapToGlobal (viewport()->pos()); 3171 rect.translate (pw.x(), pw.y()); 3172 3173 QRect dpRect = QApplication::desktop()->screenGeometry (viewport()); 3174 if (rect.intersects (dpRect)) 3175 rect = rect.intersect (dpRect); 3176 3177 int wsafe = rect.width() / 6; 3178 rect.setWidth (rect.width() - wsafe * 2); 3179 rect.setLeft (rect.left() + wsafe); 3180 3181 int hsafe = rect.height() / 6; 3182 rect.setWidth (rect.height() - hsafe * 2); 3183 rect.setTop (rect.top() + hsafe); 3184 3185 if (rect.contains (aGlobalPos, true)) 3186 mLastPos = aGlobalPos; 3187 else 3188 { 3189 mLastPos = rect.center(); 3190 QCursor::setPos (mLastPos); 3191 } 3192 3193 #else /* !Q_WS_MAC */ 3194 3195 /* "jerk" the mouse by bringing it to the opposite side 3196 * to simulate the endless moving */ 3197 3198 #ifdef Q_WS_WIN32 3199 int we = viewport()->width() - 1; 3200 int he = viewport()->height() - 1; 3201 QPoint p = aPos; 3202 if (aPos.x() == 0) 3203 p.setX (we - 1); 3204 else if (aPos.x() == we) 3205 p.setX (1); 3206 if (aPos.y() == 0 ) 3207 p.setY (he - 1); 3208 else if (aPos.y() == he) 3209 p.setY (1); 3210 3211 if (p != aPos) 3212 { 3213 mLastPos = viewport()->mapToGlobal (p); 3214 QCursor::setPos (mLastPos); 3215 } 3216 else 3217 { 3218 mLastPos = aGlobalPos; 3219 } 3220 #else 3221 int we = QApplication::desktop()->width() - 1; 3222 int he = QApplication::desktop()->height() - 1; 3223 QPoint p = aGlobalPos; 3224 if (aGlobalPos.x() == 0) 3225 p.setX (we - 1); 3226 else if (aGlobalPos.x() == we) 3227 p.setX( 1 ); 3228 if (aGlobalPos.y() == 0) 3229 p.setY (he - 1); 3230 else if (aGlobalPos.y() == he) 3231 p.setY (1); 3232 3233 if (p != aGlobalPos) 3234 { 3235 mLastPos = p; 3236 QCursor::setPos (mLastPos); 3237 } 3238 else 3239 { 3240 mLastPos = aGlobalPos; 3241 } 3242 #endif 3243 #endif /* !Q_WS_MAC */ 3244 return true; /* stop further event handling */ 3245 } 3246 else /* !mMouseCaptured */ 3247 { 3248 if (mMainWnd->isTrueFullscreen()) 3249 { 3250 if (mode != VBoxDefs::SDLMode) 3251 { 3252 /* try to automatically scroll the guest canvas if the 3253 * mouse is on the screen border */ 3254 /// @todo (r=dmik) better use a timer for autoscroll 3255 QRect scrGeo = QApplication::desktop()->screenGeometry (this); 3256 int dx = 0, dy = 0; 3257 if (scrGeo.width() < contentsWidth()) 3258 { 3259 if (scrGeo.left() == aGlobalPos.x()) dx = -1; 3260 if (scrGeo.right() == aGlobalPos.x()) dx = +1; 3261 } 3262 if (scrGeo.height() < contentsHeight()) 3263 { 3264 if (scrGeo.top() == aGlobalPos.y()) dy = -1; 3265 if (scrGeo.bottom() == aGlobalPos.y()) dy = +1; 3266 } 3267 if (dx || dy) 3268 scrollBy (dx, dy); 3269 } 3270 } 3271 3272 if (mMouseAbsolute && mMouseIntegration) 3273 { 3274 int cw = contentsWidth(), ch = contentsHeight(); 3275 int vw = visibleWidth(), vh = visibleHeight(); 3276 3277 if (mode != VBoxDefs::SDLMode) 3278 { 3279 /* try to automatically scroll the guest canvas if the 3280 * mouse goes outside its visible part */ 3281 3282 int dx = 0; 3283 if (aPos.x() > vw) dx = aPos.x() - vw; 3284 else if (aPos.x() < 0) dx = aPos.x(); 3285 int dy = 0; 3286 if (aPos.y() > vh) dy = aPos.y() - vh; 3287 else if (aPos.y() < 0) dy = aPos.y(); 3288 if (dx != 0 || dy != 0) scrollBy (dx, dy); 3289 } 3290 3291 QPoint cpnt = viewportToContents (aPos); 3292 if (cpnt.x() < 0) cpnt.setX (0); 3293 else if (cpnt.x() > cw) cpnt.setX (cw); 3294 if (cpnt.y() < 0) cpnt.setY (0); 3295 else if (cpnt.y() > ch) cpnt.setY (ch); 3296 3297 CMouse mouse = mConsole.GetMouse(); 3298 mouse.PutMouseEventAbsolute (cpnt.x(), cpnt.y(), wheelVertical, 3299 wheelHorizontal, state); 3300 return true; /* stop further event handling */ 3301 } 3302 else 3303 { 3304 if (hasFocus() && 3305 (aType == QEvent::MouseButtonRelease && 3306 aButtons == Qt::NoButton)) 3307 { 3308 if (isPaused()) 3309 { 3310 vboxProblem().remindAboutPausedVMInput(); 3311 } 3312 else if (isRunning()) 3313 { 3314 /* temporarily disable auto capture that will take 3315 * place after this dialog is dismissed because 3316 * the capture state is to be defined by the 3317 * dialog result itself */ 3318 mDisableAutoCapture = true; 3319 bool autoConfirmed = false; 3320 bool ok = vboxProblem().confirmInputCapture (&autoConfirmed); 3321 if (autoConfirmed) 3322 mDisableAutoCapture = false; 3323 /* otherwise, the disable flag will be reset in 3324 * the next console view's foucs in event (since 3325 * may happen asynchronously on some platforms, 3326 * after we return from this code) */ 3327 3328 if (ok) 3329 { 3330 #ifdef Q_WS_X11 3331 /* make sure that pending FocusOut events from the 3332 * previous message box are handled, otherwise the 3333 * mouse is immediately ungrabbed again */ 3334 qApp->processEvents(); 3335 #endif 3336 captureKbd (true); 3337 captureMouse (true); 3338 } 3339 } 3340 } 3341 } 3342 } 3343 3344 return false; 3345 } 3346 3347 void VBoxConsoleView::onStateChange (KMachineState state) 3348 { 3349 switch (state) 3350 { 3351 case KMachineState_Paused: 3352 case KMachineState_TeleportingPausedVM: 3353 { 3354 if ( mode != VBoxDefs::TimerMode 3355 && mFrameBuf 3356 && ( state != KMachineState_TeleportingPausedVM 3357 || mLastState != KMachineState_Teleporting) 3358 ) 3359 { 3360 /* 3361 * Take a screen snapshot. Note that TakeScreenShot() always 3362 * needs a 32bpp image 3363 */ 3364 QImage shot = QImage (mFrameBuf->width(), mFrameBuf->height(), QImage::Format_RGB32); 3365 CDisplay dsp = mConsole.GetDisplay(); 3366 dsp.TakeScreenShot (shot.bits(), shot.width(), shot.height()); 3367 /* 3368 * TakeScreenShot() may fail if, e.g. the Paused notification 3369 * was delivered after the machine execution was resumed. It's 3370 * not fatal. 3371 */ 3372 if (dsp.isOk()) 3373 { 3374 dimImage (shot); 3375 mPausedShot = QPixmap::fromImage (shot); 3376 /* fully repaint to pick up mPausedShot */ 3377 repaint(); 3378 } 3379 } 3380 /* fall through */ 3381 } 3382 case KMachineState_Stuck: 3383 { 3384 /* reuse the focus event handler to uncapture everything */ 3385 if (hasFocus()) 3386 focusEvent (false /* aHasFocus*/, false /* aReleaseHostKey */); 3387 break; 3388 } 3389 case KMachineState_Running: 3390 { 3391 if ( mLastState == KMachineState_Paused 3392 || mLastState == KMachineState_TeleportingPausedVM 3393 ) 3394 { 3395 if (mode != VBoxDefs::TimerMode && mFrameBuf) 3396 { 3397 /* reset the pixmap to free memory */ 3398 mPausedShot = QPixmap (); 3399 /* 3400 * ask for full guest display update (it will also update 3401 * the viewport through IFramebuffer::NotifyUpdate) 3402 */ 3403 CDisplay dsp = mConsole.GetDisplay(); 3404 dsp.InvalidateAndUpdate(); 3405 } 3406 } 3407 /* reuse the focus event handler to capture input */ 3408 if (hasFocus()) 3409 focusEvent (true /* aHasFocus */); 3410 break; 3411 } 771 /* posted OnShowWindow */ 772 case UIConsoleEventType_ShowWindow: 773 { 774 /* Dunno what Qt3 thinks a window that has minimized to the dock 775 * should be - it is not hidden, neither is it minimized. OTOH it is 776 * marked shown and visible, but not activated. This latter isn't of 777 * much help though, since at this point nothing is marked activated. 778 * I might have overlooked something, but I'm buggered what if I know 779 * what. So, I'll just always show & activate the stupid window to 780 * make it get out of the dock when the user wishes to show a VM. */ 781 window()->show(); 782 window()->activateWindow(); 783 return true; 784 } 785 #endif 786 3412 787 default: 3413 788 break; 3414 789 } 3415 3416 mLastState = state; 790 return QObject::event(pEvent); 3417 791 } 3418 792 3419 void VBoxConsoleView::doRefresh() 3420 { 3421 viewport()->repaint();793 qulonglong UISession::winId() const 794 { 795 return machine()->machineLogic()->machineWindowWrapper()->machineWindow()->winId(); 3422 796 } 3423 3424 void VBoxConsoleView::resizeEvent (QResizeEvent *)3425 {3426 updateSliders();3427 #if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)3428 QRect r = viewport()->geometry();3429 // printf ("qt resize: %d %d %d %d\n", r.x(), r.y(), r.width(), r.height());3430 PostBoundsChanged (r);3431 #endif /* Q_WS_MAC */3432 }3433 3434 void VBoxConsoleView::moveEvent (QMoveEvent *)3435 {3436 #if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)3437 QRect r = viewport()->geometry();3438 // printf ("qt resize: %d %d %d %d\n", r.x(), r.y(), r.width(), r.height());3439 PostBoundsChanged (r);3440 #endif /* Q_WS_MAC */3441 }3442 3443 void VBoxConsoleView::paintEvent (QPaintEvent *pe)3444 {3445 if (mPausedShot.isNull())3446 {3447 /* delegate the paint function to the VBoxFrameBuffer interface */3448 if (mFrameBuf)3449 mFrameBuf->paintEvent (pe);3450 #ifdef Q_WS_MAC3451 /* Update the dock icon if we are in the running state */3452 if (isRunning())3453 updateDockIcon();3454 #endif3455 return;3456 }3457 3458 #ifdef VBOX_GUI_USE_QUARTZ2D3459 if (mode == VBoxDefs::Quartz2DMode && mFrameBuf)3460 {3461 mFrameBuf->paintEvent (pe);3462 updateDockIcon();3463 }3464 else3465 #endif3466 {3467 /* we have a snapshot for the paused state */3468 QRect r = pe->rect().intersect (viewport()->rect());3469 /* We have to disable paint on screen if we are using the regular painter */3470 bool paintOnScreen = viewport()->testAttribute (Qt::WA_PaintOnScreen);3471 viewport()->setAttribute (Qt::WA_PaintOnScreen, false);3472 QPainter pnt (viewport());3473 pnt.drawPixmap (r.x(), r.y(), mPausedShot,3474 r.x() + contentsX(), r.y() + contentsY(),3475 r.width(), r.height());3476 /* Restore the attribute to its previous state */3477 viewport()->setAttribute (Qt::WA_PaintOnScreen, paintOnScreen);3478 #ifdef Q_WS_MAC3479 updateDockIcon();3480 #endif3481 }3482 3483 }3484 3485 /**3486 * Captures the keyboard. When captured, no keyboard input reaches the host3487 * system (including most system combinations like Alt-Tab).3488 *3489 * @param aCapture true to capture, false to uncapture.3490 * @param aEmitSignal Whether to emit keyboardStateChanged() or not.3491 */3492 void VBoxConsoleView::captureKbd (bool aCapture, bool aEmitSignal /* = true */)3493 {3494 AssertMsg (mAttached, ("Console must be attached"));3495 3496 if (mKbdCaptured == aCapture)3497 return;3498 3499 /* On Win32, keyboard grabbing is ineffective, a low-level keyboard hook is3500 * used instead. On X11, we use XGrabKey instead of XGrabKeyboard (called3501 * by QWidget::grabKeyboard()) because the latter causes problems under3502 * metacity 2.16 (in particular, due to a bug, a window cannot be moved3503 * using the mouse if it is currently grabing the keyboard). On Mac OS X,3504 * we use the Qt methods + disabling global hot keys + watching modifiers3505 * (for right/left separation). */3506 #if defined (Q_WS_WIN32)3507 /**/3508 #elif defined (Q_WS_X11)3509 if (aCapture)3510 XGrabKey (QX11Info::display(), AnyKey, AnyModifier,3511 window()->winId(), False,3512 GrabModeAsync, GrabModeAsync);3513 else3514 XUngrabKey (QX11Info::display(), AnyKey, AnyModifier,3515 window()->winId());3516 #elif defined (Q_WS_MAC)3517 if (aCapture)3518 {3519 ::DarwinDisableGlobalHotKeys (true);3520 grabKeyboard();3521 }3522 else3523 {3524 ::DarwinDisableGlobalHotKeys (false);3525 releaseKeyboard();3526 }3527 #else3528 if (aCapture)3529 grabKeyboard();3530 else3531 releaseKeyboard();3532 #endif3533 3534 mKbdCaptured = aCapture;3535 3536 if (aEmitSignal)3537 emitKeyboardStateChanged();3538 }3539 3540 /**3541 * Captures the host mouse pointer. When captured, the mouse pointer is3542 * unavailable to the host applications.3543 *3544 * @param aCapture true to capture, false to uncapture.3545 * @param aEmitSignal Whether to emit mouseStateChanged() or not.3546 */3547 void VBoxConsoleView::captureMouse (bool aCapture, bool aEmitSignal /* = true */)3548 {3549 AssertMsg (mAttached, ("Console must be attached"));3550 3551 if (mMouseCaptured == aCapture)3552 return;3553 3554 if (aCapture)3555 {3556 /* memorize the host position where the cursor was captured */3557 mCapturedPos = QCursor::pos();3558 #ifdef Q_WS_WIN323559 viewport()->setCursor (QCursor (Qt::BlankCursor));3560 /* move the mouse to the center of the visible area */3561 QCursor::setPos (mapToGlobal (visibleRegion().boundingRect().center()));3562 mLastPos = QCursor::pos();3563 #elif defined (Q_WS_MAC)3564 /* move the mouse to the center of the visible area */3565 mLastPos = mapToGlobal (visibleRegion().boundingRect().center());3566 QCursor::setPos (mLastPos);3567 /* grab all mouse events. */3568 viewport()->grabMouse();3569 #else3570 viewport()->grabMouse();3571 mLastPos = QCursor::pos();3572 #endif3573 }3574 else3575 {3576 #ifndef Q_WS_WIN323577 viewport()->releaseMouse();3578 #endif3579 /* release mouse buttons */3580 CMouse mouse = mConsole.GetMouse();3581 mouse.PutMouseEvent (0, 0, 0, 0 /* Horizontal wheel */, 0);3582 }3583 3584 mMouseCaptured = aCapture;3585 3586 updateMouseClipping();3587 3588 if (aEmitSignal)3589 emitMouseStateChanged();3590 }3591 3592 /**3593 * Searches for a menu item with a given hot key (shortcut). If the item3594 * is found, activates it and returns true. Otherwise returns false.3595 */3596 bool VBoxConsoleView::processHotKey (const QKeySequence &aKey,3597 const QList <QAction*> &aData)3598 {3599 foreach (QAction *pAction, aData)3600 {3601 if (QMenu *menu = pAction->menu())3602 {3603 /* Process recursively for each sub-menu */3604 if (processHotKey (aKey, menu->actions()))3605 return true;3606 }3607 else3608 {3609 QString hotkey = VBoxGlobal::extractKeyFromActionText (pAction->text());3610 if (pAction->isEnabled() && !hotkey.isEmpty())3611 {3612 if (aKey.matches (QKeySequence (hotkey)) == QKeySequence::ExactMatch)3613 {3614 /* We asynchronously post a special event instead of calling3615 * pAction->trigger() directly, to let key presses and3616 * releases be processed correctly by Qt first.3617 * Note: we assume that nobody will delete the menu item3618 * corresponding to the key sequence, so that the pointer to3619 * menu data posted along with the event will remain valid in3620 * the event handler, at least until the main window is closed. */3621 QApplication::postEvent (this, new ActivateMenuEvent (pAction));3622 return true;3623 }3624 }3625 }3626 }3627 3628 return false;3629 }3630 3631 /**3632 * Send the KEY BREAK code to the VM for all currently pressed keys.3633 *3634 * @param aReleaseHostKey @c true to set the host key state to unpressed.3635 */3636 void VBoxConsoleView::releaseAllPressedKeys (bool aReleaseHostKey /* = true*/)3637 {3638 AssertMsg (mAttached, ("Console must be attached"));3639 3640 CKeyboard keyboard = mConsole.GetKeyboard();3641 bool fSentRESEND = false;3642 3643 /* send a dummy scan code (RESEND) to prevent the guest OS from recognizing3644 * a single key click (for ex., Alt) and performing an unwanted action3645 * (for ex., activating the menu) when we release all pressed keys below.3646 * Note, that it's just a guess that sending RESEND will give the desired3647 * effect :), but at least it works with NT and W2k guests. */3648 3649 /// @todo Sending 0xFE is responsible for the warning3650 //3651 // ``atkbd.c: Spurious NAK on isa0060/serio0. Some program might3652 // be trying access hardware directly''3653 //3654 // on Linux guests (#1944). It might also be responsible for #1949. Don't3655 // send this command unless we really have to release any key modifier.3656 // --frank3657 3658 for (uint i = 0; i < SIZEOF_ARRAY (mPressedKeys); i++)3659 {3660 if (mPressedKeys [i] & IsKeyPressed)3661 {3662 if (!fSentRESEND)3663 {3664 keyboard.PutScancode (0xFE);3665 fSentRESEND = true;3666 }3667 keyboard.PutScancode (i | 0x80);3668 }3669 else if (mPressedKeys [i] & IsExtKeyPressed)3670 {3671 if (!fSentRESEND)3672 {3673 keyboard.PutScancode (0xFE);3674 fSentRESEND = true;3675 }3676 QVector <LONG> codes (2);3677 codes[0] = 0xE0;3678 codes[1] = i | 0x80;3679 keyboard.PutScancodes (codes);3680 }3681 mPressedKeys [i] = 0;3682 }3683 3684 if (aReleaseHostKey)3685 mIsHostkeyPressed = false;3686 3687 #ifdef Q_WS_MAC3688 /* clear most of the modifiers. */3689 mDarwinKeyModifiers &=3690 alphaLock | kEventKeyModifierNumLockMask |3691 (aReleaseHostKey ? 0 : ::DarwinKeyCodeToDarwinModifierMask (gs.hostKey()));3692 #endif3693 3694 emitKeyboardStateChanged();3695 }3696 3697 void VBoxConsoleView::saveKeyStates()3698 {3699 ::memcpy (mPressedKeysCopy, mPressedKeys, sizeof (mPressedKeys));3700 }3701 3702 void VBoxConsoleView::sendChangedKeyStates()3703 {3704 AssertMsg (mAttached, ("Console must be attached"));3705 3706 QVector <LONG> codes (2);3707 CKeyboard keyboard = mConsole.GetKeyboard();3708 for (uint i = 0; i < SIZEOF_ARRAY (mPressedKeys); ++ i)3709 {3710 uint8_t os = mPressedKeysCopy [i];3711 uint8_t ns = mPressedKeys [i];3712 if ((os & IsKeyPressed) != (ns & IsKeyPressed))3713 {3714 codes [0] = i;3715 if (!(ns & IsKeyPressed))3716 codes[0] |= 0x80;3717 keyboard.PutScancode (codes[0]);3718 }3719 else if ((os & IsExtKeyPressed) != (ns & IsExtKeyPressed))3720 {3721 codes [0] = 0xE0;3722 codes [1] = i;3723 if (!(ns & IsExtKeyPressed))3724 codes [1] |= 0x80;3725 keyboard.PutScancodes (codes);3726 }3727 }3728 }3729 3730 void VBoxConsoleView::updateMouseClipping()3731 {3732 AssertMsg (mAttached, ("Console must be attached"));3733 3734 if (mMouseCaptured)3735 {3736 viewport()->setCursor (QCursor (Qt::BlankCursor));3737 #ifdef Q_WS_WIN323738 QRect r = viewport()->rect();3739 r.moveTopLeft (viewport()->mapToGlobal (QPoint (0, 0)));3740 RECT rect = { r.left(), r.top(), r.right() + 1, r.bottom() + 1 };3741 ::ClipCursor (&rect);3742 #endif3743 }3744 else3745 {3746 #ifdef Q_WS_WIN323747 ::ClipCursor (NULL);3748 #endif3749 /* return the cursor to where it was when we captured it and show it */3750 QCursor::setPos (mCapturedPos);3751 viewport()->unsetCursor();3752 }3753 }3754 3755 void VBoxConsoleView::setPointerShape (MousePointerChangeEvent *me)3756 {3757 if (me->shapeData() != NULL)3758 {3759 bool ok = false;3760 3761 const uchar *srcAndMaskPtr = me->shapeData();3762 uint andMaskSize = (me->width() + 7) / 8 * me->height();3763 const uchar *srcShapePtr = me->shapeData() + ((andMaskSize + 3) & ~3);3764 uint srcShapePtrScan = me->width() * 4;3765 3766 #if defined (Q_WS_WIN)3767 3768 BITMAPV5HEADER bi;3769 HBITMAP hBitmap;3770 void *lpBits;3771 3772 ::ZeroMemory (&bi, sizeof (BITMAPV5HEADER));3773 bi.bV5Size = sizeof (BITMAPV5HEADER);3774 bi.bV5Width = me->width();3775 bi.bV5Height = - (LONG) me->height();3776 bi.bV5Planes = 1;3777 bi.bV5BitCount = 32;3778 bi.bV5Compression = BI_BITFIELDS;3779 // specifiy a supported 32 BPP alpha format for Windows XP3780 bi.bV5RedMask = 0x00FF0000;3781 bi.bV5GreenMask = 0x0000FF00;3782 bi.bV5BlueMask = 0x000000FF;3783 if (me->hasAlpha())3784 bi.bV5AlphaMask = 0xFF000000;3785 else3786 bi.bV5AlphaMask = 0;3787 3788 HDC hdc = GetDC (NULL);3789 3790 // create the DIB section with an alpha channel3791 hBitmap = CreateDIBSection (hdc, (BITMAPINFO *) &bi, DIB_RGB_COLORS,3792 (void **) &lpBits, NULL, (DWORD) 0);3793 3794 ReleaseDC (NULL, hdc);3795 3796 HBITMAP hMonoBitmap = NULL;3797 if (me->hasAlpha())3798 {3799 // create an empty mask bitmap3800 hMonoBitmap = CreateBitmap (me->width(), me->height(), 1, 1, NULL);3801 }3802 else3803 {3804 /* Word aligned AND mask. Will be allocated and created if necessary. */3805 uint8_t *pu8AndMaskWordAligned = NULL;3806 3807 /* Width in bytes of the original AND mask scan line. */3808 uint32_t cbAndMaskScan = (me->width() + 7) / 8;3809 3810 if (cbAndMaskScan & 1)3811 {3812 /* Original AND mask is not word aligned. */3813 3814 /* Allocate memory for aligned AND mask. */3815 pu8AndMaskWordAligned = (uint8_t *)RTMemTmpAllocZ ((cbAndMaskScan + 1) * me->height());3816 3817 Assert(pu8AndMaskWordAligned);3818 3819 if (pu8AndMaskWordAligned)3820 {3821 /* According to MSDN the padding bits must be 0.3822 * Compute the bit mask to set padding bits to 0 in the last byte of original AND mask.3823 */3824 uint32_t u32PaddingBits = cbAndMaskScan * 8 - me->width();3825 Assert(u32PaddingBits < 8);3826 uint8_t u8LastBytesPaddingMask = (uint8_t)(0xFF << u32PaddingBits);3827 3828 Log(("u8LastBytesPaddingMask = %02X, aligned w = %d, width = %d, cbAndMaskScan = %d\n",3829 u8LastBytesPaddingMask, (cbAndMaskScan + 1) * 8, me->width(), cbAndMaskScan));3830 3831 uint8_t *src = (uint8_t *)srcAndMaskPtr;3832 uint8_t *dst = pu8AndMaskWordAligned;3833 3834 unsigned i;3835 for (i = 0; i < me->height(); i++)3836 {3837 memcpy (dst, src, cbAndMaskScan);3838 3839 dst[cbAndMaskScan - 1] &= u8LastBytesPaddingMask;3840 3841 src += cbAndMaskScan;3842 dst += cbAndMaskScan + 1;3843 }3844 }3845 }3846 3847 /* create the AND mask bitmap */3848 hMonoBitmap = ::CreateBitmap (me->width(), me->height(), 1, 1,3849 pu8AndMaskWordAligned? pu8AndMaskWordAligned: srcAndMaskPtr);3850 3851 if (pu8AndMaskWordAligned)3852 {3853 RTMemTmpFree (pu8AndMaskWordAligned);3854 }3855 }3856 3857 Assert (hBitmap);3858 Assert (hMonoBitmap);3859 if (hBitmap && hMonoBitmap)3860 {3861 DWORD *dstShapePtr = (DWORD *) lpBits;3862 3863 for (uint y = 0; y < me->height(); y ++)3864 {3865 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan);3866 srcShapePtr += srcShapePtrScan;3867 dstShapePtr += me->width();3868 }3869 3870 ICONINFO ii;3871 ii.fIcon = FALSE;3872 ii.xHotspot = me->xHot();3873 ii.yHotspot = me->yHot();3874 ii.hbmMask = hMonoBitmap;3875 ii.hbmColor = hBitmap;3876 3877 HCURSOR hAlphaCursor = CreateIconIndirect (&ii);3878 Assert (hAlphaCursor);3879 if (hAlphaCursor)3880 {3881 viewport()->setCursor (QCursor (hAlphaCursor));3882 ok = true;3883 if (mAlphaCursor)3884 DestroyIcon (mAlphaCursor);3885 mAlphaCursor = hAlphaCursor;3886 }3887 }3888 3889 if (hMonoBitmap)3890 DeleteObject (hMonoBitmap);3891 if (hBitmap)3892 DeleteObject (hBitmap);3893 3894 #elif defined (Q_WS_X11) && !defined (VBOX_WITHOUT_XCURSOR)3895 3896 XcursorImage *img = XcursorImageCreate (me->width(), me->height());3897 Assert (img);3898 if (img)3899 {3900 img->xhot = me->xHot();3901 img->yhot = me->yHot();3902 3903 XcursorPixel *dstShapePtr = img->pixels;3904 3905 for (uint y = 0; y < me->height(); y ++)3906 {3907 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan);3908 3909 if (!me->hasAlpha())3910 {3911 /* convert AND mask to the alpha channel */3912 uchar byte = 0;3913 for (uint x = 0; x < me->width(); x ++)3914 {3915 if (!(x % 8))3916 byte = *(srcAndMaskPtr ++);3917 else3918 byte <<= 1;3919 3920 if (byte & 0x80)3921 {3922 /* Linux doesn't support inverted pixels (XOR ops,3923 * to be exact) in cursor shapes, so we detect such3924 * pixels and always replace them with black ones to3925 * make them visible at least over light colors */3926 if (dstShapePtr [x] & 0x00FFFFFF)3927 dstShapePtr [x] = 0xFF000000;3928 else3929 dstShapePtr [x] = 0x00000000;3930 }3931 else3932 dstShapePtr [x] |= 0xFF000000;3933 }3934 }3935 3936 srcShapePtr += srcShapePtrScan;3937 dstShapePtr += me->width();3938 }3939 3940 Cursor cur = XcursorImageLoadCursor (QX11Info::display(), img);3941 Assert (cur);3942 if (cur)3943 {3944 viewport()->setCursor (QCursor (cur));3945 ok = true;3946 }3947 3948 XcursorImageDestroy (img);3949 }3950 3951 #elif defined(Q_WS_MAC)3952 3953 /* Create a ARGB image out of the shape data. */3954 QImage image (me->width(), me->height(), QImage::Format_ARGB32);3955 const uint8_t* pbSrcMask = static_cast<const uint8_t*> (srcAndMaskPtr);3956 unsigned cbSrcMaskLine = RT_ALIGN (me->width(), 8) / 8;3957 for (unsigned int y = 0; y < me->height(); ++y)3958 {3959 for (unsigned int x = 0; x < me->width(); ++x)3960 {3961 unsigned int color = ((unsigned int*)srcShapePtr)[y*me->width()+x];3962 /* If the alpha channel isn't in the shape data, we have to3963 * create them from the and-mask. This is a bit field where 13964 * represent transparency & 0 opaque respectively. */3965 if (!me->hasAlpha())3966 {3967 if (!(pbSrcMask[x / 8] & (1 << (7 - (x % 8)))))3968 color |= 0xff000000;3969 else3970 {3971 /* This isn't quite right, but it's the best we can do I3972 * think... */3973 if (color & 0x00ffffff)3974 color = 0xff000000;3975 else3976 color = 0x00000000;3977 }3978 }3979 image.setPixel (x, y, color);3980 }3981 /* Move one scanline forward. */3982 pbSrcMask += cbSrcMaskLine;3983 }3984 /* Set the new cursor */3985 QCursor cursor (QPixmap::fromImage (image),3986 me->xHot(), me->yHot());3987 viewport()->setCursor (cursor);3988 ok = true;3989 NOREF (srcShapePtrScan);3990 3991 #else3992 3993 # warning "port me"3994 3995 #endif3996 if (ok)3997 mLastCursor = viewport()->cursor();3998 else3999 viewport()->unsetCursor();4000 }4001 else4002 {4003 /*4004 * We did not get any shape data4005 */4006 if (me->isVisible())4007 {4008 viewport()->setCursor (mLastCursor);4009 }4010 else4011 {4012 viewport()->setCursor (Qt::BlankCursor);4013 }4014 }4015 mHideHostPointer = !me->isVisible();4016 }4017 4018 inline QRgb qRgbIntensity (QRgb rgb, int mul, int div)4019 {4020 int r = qRed (rgb);4021 int g = qGreen (rgb);4022 int b = qBlue (rgb);4023 return qRgb (mul * r / div, mul * g / div, mul * b / div);4024 }4025 4026 /* static */4027 void VBoxConsoleView::dimImage (QImage &img)4028 {4029 for (int y = 0; y < img.height(); y ++) {4030 if (y % 2) {4031 if (img.depth() == 32) {4032 for (int x = 0; x < img.width(); x ++) {4033 int gray = qGray (img.pixel (x, y)) / 2;4034 img.setPixel (x, y, qRgb (gray, gray, gray));4035 // img.setPixel (x, y, qRgbIntensity (img.pixel (x, y), 1, 2));4036 }4037 } else {4038 ::memset (img.scanLine (y), 0, img.bytesPerLine());4039 }4040 } else {4041 if (img.depth() == 32) {4042 for (int x = 0; x < img.width(); x ++) {4043 int gray = (2 * qGray (img.pixel (x, y))) / 3;4044 img.setPixel (x, y, qRgb (gray, gray, gray));4045 // img.setPixel (x, y, qRgbIntensity (img.pixel(x, y), 2, 3));4046 }4047 }4048 }4049 }4050 }4051 4052 void VBoxConsoleView::doResizeHint (const QSize &aToSize)4053 {4054 if (mGuestSupportsGraphics && mAutoresizeGuest)4055 {4056 /* If this slot is invoked directly then use the passed size4057 * otherwise get the available size for the guest display.4058 * We assume here that the centralWidget() contains this view only4059 * and gives it all available space. */4060 QSize sz (aToSize.isValid() ? aToSize : mMainWnd->centralWidget()->size());4061 if (!aToSize.isValid())4062 sz -= QSize (frameWidth() * 2, frameWidth() * 2);4063 /* Do not send out useless hints. */4064 if ((sz.width() == mStoredConsoleSize.width()) &&4065 (sz.height() == mStoredConsoleSize.height()))4066 return;4067 /* We only actually send the hint if4068 * 1) the autoresize property is set to true and4069 * 2) either an explicit new size was given (e.g. if the request4070 * was triggered directly by a console resize event) or if no4071 * explicit size was specified but a resize is flagged as being4072 * needed (e.g. the autoresize was just enabled and the console4073 * was resized while it was disabled). */4074 if (mAutoresizeGuest &&4075 (aToSize.isValid() || mDoResize))4076 {4077 LogFlowFunc (("Will suggest %d x %d\n", sz.width(), sz.height()));4078 4079 /* Remember the new size. */4080 storeConsoleSize (sz.width(), sz.height());4081 4082 mConsole.GetDisplay().SetVideoModeHint (sz.width(), sz.height(), 0, 0);4083 }4084 /* we have resized now... */4085 mDoResize = false;4086 }4087 }4088 4089 4090 /* If the desktop geometry is set automatically, this will update it. */4091 void VBoxConsoleView::doResizeDesktop (int)4092 {4093 calculateDesktopGeometry();4094 }4095 4096 /**4097 * Store the current size of the console (i.e. the viewport to the guest).4098 * This has two purposes. One is to suppress unwanted resize events for4099 * which the new size is the same as the stored size. The other is to expand4100 * the maximum size to which we will let the guest resize itself. It makes4101 * no sense to forbid guest resizes which are less than the current resolution4102 * anyway.4103 *4104 * @param aWidth width of the resolution hint4105 * @param aHeight height of the resolution hint4106 */4107 void VBoxConsoleView::storeConsoleSize (int aWidth, int aHeight)4108 {4109 LogFlowThisFunc (("aWidth=%d, aHeight=%d\n", aWidth, aHeight));4110 mStoredConsoleSize = QRect (0, 0, aWidth, aHeight);4111 }4112 4113 /**4114 * Do initial setup of desktop geometry restrictions on the guest framebuffer.4115 * These determine the maximum size the guest framebuffer can take on.4116 *4117 * @note a hint from the host will always override these restrictions.4118 *4119 * @param aGeo Fixed - the guest has a fixed maximum framebuffer size4120 * Automatic - we calculate the maximum size ourselves. The4121 * calculations will not actually be done until4122 * @a calculateDesktopGeometry is called, since4123 * we don't initially have the information needed.4124 * Any - any size is allowed4125 * @param aWidth The maximum width for the guest screen or zero for no change4126 * (only used for fixed geometry)4127 * @param aHeight The maximum height for the guest screen or zero for no change4128 * (only used for fixed geometry)4129 */4130 void VBoxConsoleView::setDesktopGeometry (DesktopGeo aGeo, int aWidth, int aHeight)4131 {4132 LogFlowThisFunc (("aGeo=%s, aWidth=%d, aHeight=%d\n",4133 (aGeo == DesktopGeo_Fixed ? "Fixed" :4134 aGeo == DesktopGeo_Automatic ? "Automatic" :4135 aGeo == DesktopGeo_Any ? "Any" : "Invalid"),4136 aWidth, aHeight));4137 switch (aGeo)4138 {4139 case DesktopGeo_Fixed:4140 mDesktopGeo = DesktopGeo_Fixed;4141 if (aWidth != 0 && aHeight != 0)4142 mDesktopGeometry = QRect (0, 0, aWidth, aHeight);4143 else4144 mDesktopGeometry = QRect (0, 0, 0, 0);4145 storeConsoleSize (0, 0);4146 break;4147 case DesktopGeo_Automatic:4148 mDesktopGeo = DesktopGeo_Automatic;4149 mDesktopGeometry = QRect (0, 0, 0, 0);4150 storeConsoleSize (0, 0);4151 break;4152 case DesktopGeo_Any:4153 mDesktopGeo = DesktopGeo_Any;4154 mDesktopGeometry = QRect (0, 0, 0, 0);4155 break;4156 default:4157 AssertMsgFailed(("Invalid desktop geometry type %d\n", aGeo));4158 mDesktopGeo = DesktopGeo_Invalid;4159 }4160 }4161 4162 4163 /**4164 * If we are in automatic mode, the geometry restrictions will be recalculated.4165 * This is needed in particular on the first widget resize, as we can't4166 * calculate them correctly before that.4167 *4168 * @note a hint from the host will always override these restrictions.4169 * @note we can't do calculations on the fly when they are needed, because4170 * they require querying the X server on X11 hosts and this must be done4171 * from within the GUI thread, due to the single threadedness of Xlib.4172 */4173 void VBoxConsoleView::calculateDesktopGeometry()4174 {4175 LogFlowThisFunc (("Entering\n"));4176 /* This method should not get called until we have initially set up the */4177 Assert ((mDesktopGeo != DesktopGeo_Invalid));4178 /* If we are not doing automatic geometry calculation then there is4179 * nothing to do. */4180 if (DesktopGeo_Automatic == mDesktopGeo)4181 {4182 /* Available geometry of the desktop. If the desktop is a single4183 * screen, this will exclude space taken up by desktop taskbars4184 * and things, but this is unfortunately not true for the more4185 * complex case of a desktop spanning multiple screens. */4186 QRect desktop = availableGeometry();4187 /* The area taken up by the console window on the desktop,4188 * including window frame, title and menu bar and whatnot. */4189 QRect frame = mMainWnd->frameGeometry();4190 /* The area taken up by the console window, minus all4191 * decorations. */4192 QRect window = mMainWnd->centralWidget()->geometry();4193 /* To work out how big we can make the console window while still4194 * fitting on the desktop, we calculate desktop - frame + window.4195 * This works because the difference between frame and window4196 * (or at least its width and height) is a constant. */4197 mDesktopGeometry =4198 QRect (0, 0, desktop.width() - frame.width() + window.width(),4199 desktop.height() - frame.height() + window.height());4200 LogFlowThisFunc (("Setting %d, %d\n", mDesktopGeometry.width(),4201 mDesktopGeometry.height()));4202 }4203 }4204 4205 /**4206 * Sets the minimum size restriction depending on the auto-resize feature4207 * state and the current rendering mode.4208 *4209 * Currently, the restriction is set only in SDL mode and only when the4210 * auto-resize feature is inactive. We need to do that because we cannot4211 * correctly draw in a scrolled window in SDL mode.4212 *4213 * In all other modes, or when auto-resize is in force, this function does4214 * nothing.4215 */4216 void VBoxConsoleView::maybeRestrictMinimumSize()4217 {4218 if (mode == VBoxDefs::SDLMode)4219 {4220 if (!mGuestSupportsGraphics || !mAutoresizeGuest)4221 setMinimumSize (sizeHint());4222 else4223 setMinimumSize (0, 0);4224 }4225 }4226 4227 QRect VBoxConsoleView::availableGeometry() const4228 {4229 return mMainWnd->isWindowFullScreen() ?4230 QApplication::desktop()->screenGeometry(this) :4231 QApplication::desktop()->availableGeometry(this);4232 }4233 4234 int VBoxConsoleView::contentsWidth() const4235 {4236 return mFrameBuf->width();4237 }4238 4239 int VBoxConsoleView::contentsHeight() const4240 {4241 return mFrameBuf->height();4242 }4243 4244 void VBoxConsoleView::updateSliders()4245 {4246 QSize p = viewport()->size();4247 QSize m = maximumViewportSize();4248 4249 QSize v = QSize (mFrameBuf->width(), mFrameBuf->height());4250 /* no scroll bars needed */4251 if (m.expandedTo(v) == m)4252 p = m;4253 4254 horizontalScrollBar()->setRange(0, v.width() - p.width());4255 verticalScrollBar()->setRange(0, v.height() - p.height());4256 horizontalScrollBar()->setPageStep(p.width());4257 verticalScrollBar()->setPageStep(p.height());4258 }4259 4260 void VBoxConsoleView::requestToResize (const QSize &aSize)4261 {4262 mIgnoreFrameBufferResize = true;4263 mNormalSize = aSize;4264 }4265 4266 #if defined(Q_WS_MAC)4267 4268 void VBoxConsoleView::updateDockIcon()4269 {4270 if (mDockIconEnabled)4271 {4272 if (!mPausedShot.isNull())4273 {4274 CGImageRef pauseImg = ::darwinToCGImageRef (&mPausedShot);4275 /* Use the pause image as background */4276 mDockIconPreview->updateDockPreview (pauseImg);4277 CGImageRelease (pauseImg);4278 }4279 else4280 {4281 # if defined (VBOX_GUI_USE_QUARTZ2D)4282 if (mode == VBoxDefs::Quartz2DMode)4283 {4284 /* If the render mode is Quartz2D we could use the CGImageRef4285 * of the framebuffer for the dock icon creation. This saves4286 * some conversion time. */4287 mDockIconPreview->updateDockPreview (static_cast <VBoxQuartz2DFrameBuffer *> (mFrameBuf)->imageRef());4288 }4289 else4290 # endif4291 /* In image mode we have to create the image ref out of the4292 * framebuffer */4293 mDockIconPreview->updateDockPreview (mFrameBuf);4294 }4295 }4296 }4297 4298 void VBoxConsoleView::updateDockOverlay()4299 {4300 /* Only to an update to the realtime preview if this is enabled by the user4301 * & we are in an state where the framebuffer is likely valid. Otherwise to4302 * the overlay stuff only. */4303 if (mDockIconEnabled &&4304 (mLastState == KMachineState_Running ||4305 mLastState == KMachineState_Paused ||4306 mLastState == KMachineState_Teleporting ||4307 mLastState == KMachineState_LiveSnapshotting ||4308 mLastState == KMachineState_Restoring ||4309 mLastState == KMachineState_TeleportingPausedVM ||4310 mLastState == KMachineState_TeleportingIn ||4311 mLastState == KMachineState_Saving))4312 updateDockIcon();4313 else4314 mDockIconPreview->updateDockOverlay();4315 }4316 4317 /**4318 * Wrapper for SetMouseCoalescingEnabled().4319 *4320 * Called by eventFilter() and darwinGrabKeyboardEvents().4321 *4322 * @param aOn Switch it on (true) or off (false).4323 */4324 void VBoxConsoleView::setMouseCoalescingEnabled (bool aOn)4325 {4326 /* Enable mouse event compression if we leave the VM view. This4327 is necessary for having smooth resizing of the VM/other4328 windows.4329 Disable mouse event compression if we enter the VM view. So4330 all mouse events are registered in the VM. Only do this if4331 the keyboard/mouse is grabbed (this is when we have a valid4332 event handler). */4333 if (aOn || mKeyboardGrabbed)4334 ::darwinSetMouseCoalescingEnabled (aOn);4335 }4336 4337 #endif /* Q_WS_MAC */4338 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UISession.h
r26688 r26691 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * VBoxConsoleView class implementation4 * UISession class declaration 5 5 */ 6 6 7 7 /* 8 * Copyright (C) 2 2006-2007Sun Microsystems, Inc.8 * Copyright (C) 2010 Sun Microsystems, Inc. 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 */ 22 22 23 #ifdef VBOX_WITH_PRECOMPILED_HEADERS 24 # include "precomp.h" 25 #else /* !VBOX_WITH_PRECOMPILED_HEADERS */ 26 #include <VBox/VBoxVideo.h> 23 #ifndef ___UIConsole_h___ 24 #define ___UIConsole_h___ 27 25 28 #include "VBoxConsoleView.h" 29 #include "VBoxConsoleWnd.h" 30 #include "VBoxUtils.h" 26 /* Global includes */ 27 #include <QObject> 31 28 32 #include "VBoxFrameBuffer.h" 33 #include "VBoxGlobal.h" 34 #include "VBoxProblemReporter.h" 29 /* Local includes */ 30 #include "COMDefs.h" 35 31 36 #ifdef Q_WS_PM 37 #include "QIHotKeyEdit.h" 38 #endif 32 /* Local forwards */ 33 class UIMachine; 34 class UIConsoleCallback; 39 35 40 /* Qt includes */ 41 #include <QMenuBar> 42 #include <QDesktopWidget> 43 #include <QTimer> 44 #include <QStatusBar> 45 #include <QPainter> 46 #include <QBitmap> 47 48 #endif /* !VBOX_WITH_PRECOMPILED_HEADERS */ /** @todo Move this further down! Requires some cleanup below though, so later. */ 49 50 #ifdef Q_WS_WIN 51 // VBox/cdefs.h defines these: 52 #undef LOWORD 53 #undef HIWORD 54 #undef LOBYTE 55 #undef HIBYTE 56 #include <windows.h> 57 #endif 58 59 #ifdef Q_WS_X11 60 #include <QX11Info> 61 // We need to capture some X11 events directly which 62 // requires the XEvent structure to be defined. However, 63 // including the Xlib header file will cause some nasty 64 // conflicts with Qt. Therefore we use the following hack 65 // to redefine those conflicting identifiers. 66 #define XK_XKB_KEYS 67 #define XK_MISCELLANY 68 #include <X11/Xlib.h> 69 #include <X11/Xutil.h> 70 #include <X11/XKBlib.h> 71 #include <X11/keysym.h> 72 #ifdef KeyPress 73 const int XFocusOut = FocusOut; 74 const int XFocusIn = FocusIn; 75 const int XKeyPress = KeyPress; 76 const int XKeyRelease = KeyRelease; 77 #undef KeyRelease 78 #undef KeyPress 79 #undef FocusOut 80 #undef FocusIn 81 #endif 82 #include "XKeyboard.h" 83 #ifndef VBOX_WITHOUT_XCURSOR 84 # include <X11/Xcursor/Xcursor.h> 85 #endif 86 #endif // Q_WS_X11 87 88 #if defined (Q_WS_MAC) 89 # include "DockIconPreview.h" 90 # include "DarwinKeyboard.h" 91 # ifdef QT_MAC_USE_COCOA 92 # include "darwin/VBoxCocoaApplication.h" 93 # elif defined(VBOX_WITH_HACKED_QT) 94 # include "QIApplication.h" 95 # endif 96 # include <Carbon/Carbon.h> 97 # include <VBox/err.h> 98 #endif /* defined (Q_WS_MAC) */ 99 100 #if defined (Q_WS_WIN32) 101 102 static HHOOK gKbdHook = NULL; 103 static VBoxConsoleView *gView = 0; 104 105 LRESULT CALLBACK VBoxConsoleView::lowLevelKeyboardProc (int nCode, 106 WPARAM wParam, LPARAM lParam) 36 /* CConsole callback event types: */ 37 enum UIConsoleEventType 107 38 { 108 Assert (gView); 109 if (gView && nCode == HC_ACTION && 110 gView->winLowKeyboardEvent (wParam, *(KBDLLHOOKSTRUCT *) lParam)) 111 return 1; 112 113 return CallNextHookEx (NULL, nCode, wParam, lParam); 114 } 115 116 #endif 117 118 #if defined (Q_WS_MAC) 119 # if defined (QT_MAC_USE_COCOA) 120 /** 121 * Event handler callback for Mac OS X, Cocoa variant. 122 * 123 * (Registered with and called from VBoxCocoaApplication.) 124 * 125 * @returns true if the event should be dropped, false if it should be passed 126 * along. 127 * @param pvCocoaEvent The Cocoa event object. 128 * @param pvCarbonEvent The Carbon event object reference. 129 * @param pvUser The user argument. 130 */ 131 /* static */ 132 bool VBoxConsoleView::darwinEventHandlerProc (const void *pvCocoaEvent, 133 const void *pvCarbonEvent, 134 void *pvUser) 135 { 136 VBoxConsoleView *view = (VBoxConsoleView *)pvUser; 137 EventRef inEvent = (EventRef)pvCarbonEvent; 138 UInt32 eventClass = ::GetEventClass (inEvent); 139 140 #if 0 141 /* For debugging events. */ 142 if (eventClass != 'cute') 143 ::VBoxCocoaApplication_printEvent ("view: ", pvCocoaEvent); 144 #endif 145 /* Check if this is an application key combo. In that case we will not pass 146 the event to the guest, but let the host process it. */ 147 if (VBoxCocoaApplication_isApplicationCommand(pvCocoaEvent)) 148 return false; 149 150 /* 151 * All keyboard class events needs to be handled. 152 */ 153 if (eventClass == kEventClassKeyboard) 154 { 155 if (view->darwinKeyboardEvent (pvCocoaEvent, inEvent)) 156 return true; 157 } 158 /* Pass the event along. */ 159 return false; 160 } 161 162 # elif !defined (VBOX_WITH_HACKED_QT) 163 /** 164 * Event handler callback for Mac OS X. 165 */ 166 /* static */ 167 pascal OSStatus VBoxConsoleView::darwinEventHandlerProc (EventHandlerCallRef inHandlerCallRef, 168 EventRef inEvent, void *inUserData) 169 { 170 VBoxConsoleView *view = static_cast<VBoxConsoleView *> (inUserData); 171 UInt32 eventClass = ::GetEventClass (inEvent); 172 173 /* For debugging events */ 174 /* 175 if (eventClass != 'cute') 176 ::darwinDebugPrintEvent ("view: ", inEvent); 177 */ 178 179 /* Not sure but this seems an triggered event if the spotlight searchbar is 180 * displayed. So flag that the host key isn't pressed alone. */ 181 if ( eventClass == 'cgs ' 182 && view->mIsHostkeyPressed 183 && ::GetEventKind (inEvent) == 0x15) 184 view->mIsHostkeyAlone = false; 185 186 if (eventClass == kEventClassKeyboard) 187 { 188 if (view->darwinKeyboardEvent (NULL, inEvent)) 189 return 0; 190 } 191 /* 192 * Command-H and Command-Q aren't properly disabled yet, and it's still 193 * possible to use the left command key to invoke them when the keyboard 194 * is captured. We discard the events these if the keyboard is captured 195 * as a half measure to prevent unexpected behaviour. However, we don't 196 * get any key down/up events, so these combinations are dead to the guest... 197 */ 198 else if (eventClass == kEventClassCommand) 199 { 200 if (view->mKbdCaptured) 201 return 0; 202 } 203 return ::CallNextEventHandler (inHandlerCallRef, inEvent); 204 } 205 206 # else /* VBOX_WITH_HACKED_QT */ 207 /** 208 * Event handler callback for Mac OS X. 209 */ 210 /* static */ 211 bool VBoxConsoleView::macEventFilter (EventRef inEvent, void *inUserData) 212 { 213 VBoxConsoleView *view = static_cast<VBoxConsoleView *> (inUserData); 214 UInt32 eventClass = ::GetEventClass (inEvent); 215 UInt32 eventKind = ::GetEventKind (inEvent); 216 217 /* For debugging events */ 218 /* 219 if (!(eventClass == 'cute')) 220 ::darwinDebugPrintEvent ("view: ", inEvent); 221 */ 222 223 /* Not sure but this seems an triggered event if the spotlight searchbar is 224 * displayed. So flag that the host key isn't pressed alone. */ 225 if (eventClass == 'cgs ' && eventKind == 0x15 && 226 view->mIsHostkeyPressed) 227 view->mIsHostkeyAlone = false; 228 229 if (eventClass == kEventClassKeyboard) 230 { 231 if (view->darwinKeyboardEvent (NULL, inEvent)) 232 return true; 233 } 234 return false; 235 } 236 # endif /* VBOX_WITH_HACKED_QT */ 237 238 #endif /* Q_WS_MAC */ 239 240 /** Guest mouse pointer shape change event. */ 241 class MousePointerChangeEvent : public QEvent 242 { 243 public: 244 MousePointerChangeEvent (bool visible, bool alpha, uint xhot, uint yhot, 245 uint width, uint height, 246 const uchar *shape) : 247 QEvent ((QEvent::Type) VBoxDefs::MousePointerChangeEventType), 248 vis (visible), alph (alpha), xh (xhot), yh (yhot), w (width), h (height), 249 data (NULL) 250 { 251 // make a copy of shape 252 uint dataSize = ((((width + 7) / 8 * height) + 3) & ~3) + width * 4 * height; 253 254 if (shape) { 255 data = new uchar [dataSize]; 256 memcpy ((void *) data, (void *) shape, dataSize); 257 } 258 } 259 ~MousePointerChangeEvent() 260 { 261 if (data) delete[] data; 262 } 263 bool isVisible() const { return vis; } 264 bool hasAlpha() const { return alph; } 265 uint xHot() const { return xh; } 266 uint yHot() const { return yh; } 267 uint width() const { return w; } 268 uint height() const { return h; } 269 const uchar *shapeData() const { return data; } 270 private: 271 bool vis, alph; 272 uint xh, yh, w, h; 273 const uchar *data; 39 UIConsoleEventType_MousePointerShapeChange = QEvent::User + 1, 40 UIConsoleEventType_MouseCapabilityChange, 41 UIConsoleEventType_KeyboardLedsChange, 42 UIConsoleEventType_StateChange, 43 UIConsoleEventType_AdditionsStateChange, 44 UIConsoleEventType_NetworkAdapterChange, 45 UIConsoleEventType_SerialPortChange, 46 UIConsoleEventType_ParallelPortChange, 47 UIConsoleEventType_StorageControllerChange, 48 UIConsoleEventType_MediumChange, 49 UIConsoleEventType_CPUChange, 50 UIConsoleEventType_VRDPServerChange, 51 UIConsoleEventType_RemoteDisplayInfoChange, 52 UIConsoleEventType_USBControllerChange, 53 UIConsoleEventType_USBDeviceStateChange, 54 UIConsoleEventType_SharedFolderChange, 55 UIConsoleEventType_RuntimeError, 56 UIConsoleEventType_CanShowWindow, 57 UIConsoleEventType_ShowWindow, 58 UIConsoleEventType_MAX 274 59 }; 275 60 276 /** Guest mouse absolute positioning capability change event. */ 277 class MouseCapabilityEvent : public QEvent 61 class UISession : public QObject 278 62 { 63 Q_OBJECT; 64 279 65 public: 280 MouseCapabilityEvent (bool supportsAbsolute, bool needsHostCursor) : 281 QEvent ((QEvent::Type) VBoxDefs::MouseCapabilityEventType), 282 can_abs (supportsAbsolute), 283 needs_host_cursor (needsHostCursor) {} 284 bool supportsAbsolute() const { return can_abs; } 285 bool needsHostCursor() const { return needs_host_cursor; } 66 67 /* Machine session constructor/destructor: */ 68 UISession(UIMachine *pMachine, const CSession &session); 69 virtual ~UISession(); 70 71 /* Public getters: */ 72 CSession& session() { return m_session; } 73 74 signals: 75 76 /* Console signals: */ 77 void sigMousePointerShapeChange(bool bIsVisible, bool bHasAlpha, bool uXHot, bool uYHot, bool uWidth, bool uHeight, const uchar *pShapeData); 78 void sigMouseCapabilityChange(bool bIsSupportsAbsolute, bool bNeedsHostCursor); 79 void sigKeyboardLedsChange(bool bNumLock, bool bCapsLock, bool bScrollLock); 80 void sigStateChange(KMachineState machineState); 81 void sigAdditionsStateChange(); 82 void sigNetworkAdapterChange(const CNetworkAdapter &networkAdapter); 83 void sigSerialPortChange(const CSerialPort &serialPort); 84 void sigParallelPortChange(const CParallelPort ¶llelPort); 85 void sigStorageControllerChange(); 86 void sigMediumChange(const CMediumAttachment &mediumAttachment); 87 void sigCPUChange(ulong uCPU, bool bRemove); 88 void sigVRDPServerChange(); 89 void sigRemoteDisplayInfoChange(); 90 void sigUSBControllerChange(); 91 void sigUSBDeviceStateChange(const CUSBDevice &device, bool bIsAttached, const CVirtualBoxErrorInfo &error); 92 void sigSharedFolderChange(); 93 void sigRuntimeError(bool bIsFatal, QString strErrorId, QString strMessage); 94 286 95 private: 287 bool can_abs; 288 bool needs_host_cursor; 96 97 /* Private getters: */ 98 UIMachine* machine() const { return m_pMachine; } 99 100 /* Event handlers: */ 101 bool event(QEvent *pEvent); 102 103 /* Helper routines: */ 104 qulonglong winId() const; 105 106 /* Private variables: */ 107 UIMachine *m_pMachine; 108 CSession m_session; 109 UIConsoleCallback *m_pCallback; 110 const CConsoleCallback &m_callback; 111 112 /* Friend classes: */ 113 friend class UIConsoleCallback; 289 114 }; 290 115 291 /** Machine state change. */ 292 class StateChangeEvent : public QEvent 293 { 294 public: 295 StateChangeEvent (KMachineState state) : 296 QEvent ((QEvent::Type) VBoxDefs::MachineStateChangeEventType), 297 s (state) {} 298 KMachineState machineState() const { return s; } 299 private: 300 KMachineState s; 301 }; 302 303 /** Guest Additions property changes. */ 304 class GuestAdditionsEvent : public QEvent 305 { 306 public: 307 GuestAdditionsEvent (const QString &aOsTypeId, 308 const QString &aAddVersion, 309 bool aAddActive, 310 bool aSupportsSeamless, 311 bool aSupportsGraphics) : 312 QEvent ((QEvent::Type) VBoxDefs::AdditionsStateChangeEventType), 313 mOsTypeId (aOsTypeId), mAddVersion (aAddVersion), 314 mAddActive (aAddActive), mSupportsSeamless (aSupportsSeamless), 315 mSupportsGraphics (aSupportsGraphics) {} 316 const QString &osTypeId() const { return mOsTypeId; } 317 const QString &additionVersion() const { return mAddVersion; } 318 bool additionActive() const { return mAddActive; } 319 bool supportsSeamless() const { return mSupportsSeamless; } 320 bool supportsGraphics() const { return mSupportsGraphics; } 321 private: 322 QString mOsTypeId; 323 QString mAddVersion; 324 bool mAddActive; 325 bool mSupportsSeamless; 326 bool mSupportsGraphics; 327 }; 328 329 /** DVD/Floppy drive change event */ 330 class MediaDriveChangeEvent : public QEvent 331 { 332 public: 333 MediaDriveChangeEvent (VBoxDefs::MediumType aType) 334 : QEvent ((QEvent::Type) VBoxDefs::MediaDriveChangeEventType) 335 , mType (aType) {} 336 VBoxDefs::MediumType type() const { return mType; } 337 private: 338 VBoxDefs::MediumType mType; 339 }; 340 341 /** Menu activation event */ 342 class ActivateMenuEvent : public QEvent 343 { 344 public: 345 ActivateMenuEvent (QAction *aData) : 346 QEvent ((QEvent::Type) VBoxDefs::ActivateMenuEventType), 347 mAction (aData) {} 348 QAction *action() const { return mAction; } 349 private: 350 QAction *mAction; 351 }; 352 353 /** VM Runtime error event */ 354 class RuntimeErrorEvent : public QEvent 355 { 356 public: 357 RuntimeErrorEvent (bool aFatal, const QString &aErrorID, 358 const QString &aMessage) : 359 QEvent ((QEvent::Type) VBoxDefs::RuntimeErrorEventType), 360 mFatal (aFatal), mErrorID (aErrorID), mMessage (aMessage) {} 361 bool fatal() const { return mFatal; } 362 QString errorID() const { return mErrorID; } 363 QString message() const { return mMessage; } 364 private: 365 bool mFatal; 366 QString mErrorID; 367 QString mMessage; 368 }; 369 370 /** Modifier key change event */ 371 class ModifierKeyChangeEvent : public QEvent 372 { 373 public: 374 ModifierKeyChangeEvent (bool fNumLock, bool fCapsLock, bool fScrollLock) : 375 QEvent ((QEvent::Type) VBoxDefs::ModifierKeyChangeEventType), 376 mNumLock (fNumLock), mCapsLock (fCapsLock), mScrollLock (fScrollLock) {} 377 bool numLock() const { return mNumLock; } 378 bool capsLock() const { return mCapsLock; } 379 bool scrollLock() const { return mScrollLock; } 380 private: 381 bool mNumLock, mCapsLock, mScrollLock; 382 }; 383 384 /** Network adapter change event */ 385 class NetworkAdapterChangeEvent : public QEvent 386 { 387 public: 388 NetworkAdapterChangeEvent (INetworkAdapter *aAdapter) : 389 QEvent ((QEvent::Type) VBoxDefs::NetworkAdapterChangeEventType), 390 mAdapter (aAdapter) {} 391 INetworkAdapter* networkAdapter() { return mAdapter; } 392 private: 393 INetworkAdapter *mAdapter; 394 }; 395 396 /** USB controller state change event */ 397 class USBControllerStateChangeEvent : public QEvent 398 { 399 public: 400 USBControllerStateChangeEvent() 401 : QEvent ((QEvent::Type) VBoxDefs::USBCtlStateChangeEventType) {} 402 }; 403 404 /** USB device state change event */ 405 class USBDeviceStateChangeEvent : public QEvent 406 { 407 public: 408 USBDeviceStateChangeEvent (const CUSBDevice &aDevice, bool aAttached, 409 const CVirtualBoxErrorInfo &aError) : 410 QEvent ((QEvent::Type) VBoxDefs::USBDeviceStateChangeEventType), 411 mDevice (aDevice), mAttached (aAttached), mError (aError) {} 412 CUSBDevice device() const { return mDevice; } 413 bool attached() const { return mAttached; } 414 CVirtualBoxErrorInfo error() const { return mError; } 415 private: 416 CUSBDevice mDevice; 417 bool mAttached; 418 CVirtualBoxErrorInfo mError; 419 }; 420 421 // 422 // VBoxConsoleCallback class 423 ///////////////////////////////////////////////////////////////////////////// 424 425 class VBoxConsoleCallback : VBOX_SCRIPTABLE_IMPL(IConsoleCallback) 426 { 427 public: 428 429 VBoxConsoleCallback (VBoxConsoleView *v) { 430 #if defined (Q_WS_WIN) 431 mRefCnt = 0; 432 #endif 433 mView = v; 434 } 435 436 virtual ~VBoxConsoleCallback() {} 437 438 NS_DECL_ISUPPORTS 439 440 #if defined (Q_WS_WIN) 441 STDMETHOD_(ULONG, AddRef)() { 442 return ::InterlockedIncrement (&mRefCnt); 443 } 444 STDMETHOD_(ULONG, Release)() 445 { 446 long cnt = ::InterlockedDecrement (&mRefCnt); 447 if (cnt == 0) 448 delete this; 449 return cnt; 450 } 451 #endif 452 VBOX_SCRIPTABLE_DISPATCH_IMPL(IConsoleCallback) 453 454 STDMETHOD(OnMousePointerShapeChange) (BOOL visible, BOOL alpha, 455 ULONG xhot, ULONG yhot, 456 ULONG width, ULONG height, 457 BYTE *shape) 458 { 459 QApplication::postEvent (mView, 460 new MousePointerChangeEvent (visible, alpha, 461 xhot, yhot, 462 width, height, shape)); 463 return S_OK; 464 } 465 466 STDMETHOD(OnMouseCapabilityChange)(BOOL supportsAbsolute, BOOL needsHostCursor) 467 { 468 QApplication::postEvent (mView, 469 new MouseCapabilityEvent (supportsAbsolute, 470 needsHostCursor)); 471 return S_OK; 472 } 473 474 STDMETHOD(OnKeyboardLedsChange)(BOOL fNumLock, BOOL fCapsLock, BOOL fScrollLock) 475 { 476 QApplication::postEvent (mView, 477 new ModifierKeyChangeEvent (fNumLock, fCapsLock, 478 fScrollLock)); 479 return S_OK; 480 } 481 482 STDMETHOD(OnStateChange)(MachineState_T machineState) 483 { 484 LogFlowFunc (("machineState=%d\n", machineState)); 485 QApplication::postEvent (mView, 486 new StateChangeEvent ((KMachineState) machineState)); 487 return S_OK; 488 } 489 490 STDMETHOD(OnAdditionsStateChange)() 491 { 492 CGuest guest = mView->console().GetGuest(); 493 LogFlowFunc (("ver=%s, active=%d\n", 494 guest.GetAdditionsVersion().toLatin1().constData(), 495 guest.GetAdditionsActive())); 496 QApplication::postEvent (mView, 497 new GuestAdditionsEvent ( 498 guest.GetOSTypeId(), 499 guest.GetAdditionsVersion(), 500 guest.GetAdditionsActive(), 501 guest.GetSupportsSeamless(), 502 guest.GetSupportsGraphics())); 503 return S_OK; 504 } 505 506 STDMETHOD(OnNetworkAdapterChange) (INetworkAdapter *aNetworkAdapter) 507 { 508 QApplication::postEvent (mView, 509 new NetworkAdapterChangeEvent (aNetworkAdapter)); 510 return S_OK; 511 } 512 513 STDMETHOD(OnStorageControllerChange) () 514 { 515 /* @todo */ 516 //QApplication::postEvent (mView, 517 // new StorageControllerChangeEvent ()); 518 return S_OK; 519 } 520 521 STDMETHOD(OnMediumChange)(IMediumAttachment *aMediumAttachment) 522 { 523 CMediumAttachment att(aMediumAttachment); 524 switch (att.GetType()) 525 { 526 case KDeviceType_Floppy: 527 QApplication::postEvent(mView, 528 new MediaDriveChangeEvent(VBoxDefs::MediumType_Floppy)); 529 break; 530 case KDeviceType_DVD: 531 QApplication::postEvent(mView, 532 new MediaDriveChangeEvent(VBoxDefs::MediumType_DVD)); 533 break; 534 default: 535 /* @todo later add hard disk change as well */ 536 break; 537 } 538 return S_OK; 539 } 540 541 STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove) 542 { 543 NOREF(aCPU); 544 NOREF(aRemove); 545 return S_OK; 546 } 547 548 STDMETHOD(OnSerialPortChange) (ISerialPort *aSerialPort) 549 { 550 NOREF(aSerialPort); 551 return S_OK; 552 } 553 554 STDMETHOD(OnParallelPortChange) (IParallelPort *aParallelPort) 555 { 556 NOREF(aParallelPort); 557 return S_OK; 558 } 559 560 STDMETHOD(OnVRDPServerChange)() 561 { 562 return S_OK; 563 } 564 565 STDMETHOD(OnRemoteDisplayInfoChange)() 566 { 567 return S_OK; 568 } 569 570 STDMETHOD(OnUSBControllerChange)() 571 { 572 QApplication::postEvent (mView, 573 new USBControllerStateChangeEvent()); 574 return S_OK; 575 } 576 577 STDMETHOD(OnUSBDeviceStateChange)(IUSBDevice *aDevice, BOOL aAttached, 578 IVirtualBoxErrorInfo *aError) 579 { 580 QApplication::postEvent (mView, 581 new USBDeviceStateChangeEvent ( 582 CUSBDevice (aDevice), 583 bool (aAttached), 584 CVirtualBoxErrorInfo (aError))); 585 return S_OK; 586 } 587 588 STDMETHOD(OnSharedFolderChange) (Scope_T aScope) 589 { 590 NOREF(aScope); 591 QApplication::postEvent (mView, 592 new QEvent ((QEvent::Type) 593 VBoxDefs::SharedFolderChangeEventType)); 594 return S_OK; 595 } 596 597 STDMETHOD(OnRuntimeError)(BOOL fatal, IN_BSTR id, IN_BSTR message) 598 { 599 QApplication::postEvent (mView, 600 new RuntimeErrorEvent (!!fatal, 601 QString::fromUtf16 (id), 602 QString::fromUtf16 (message))); 603 return S_OK; 604 } 605 606 STDMETHOD(OnCanShowWindow) (BOOL *canShow) 607 { 608 if (!canShow) 609 return E_POINTER; 610 611 /* as long as there is VBoxConsoleView (which creates/destroys us), it 612 * can be shown */ 613 *canShow = TRUE; 614 return S_OK; 615 } 616 617 STDMETHOD(OnShowWindow) (ULONG64 *winId) 618 { 619 if (!winId) 620 return E_POINTER; 621 622 #if defined (Q_WS_MAC) 623 /* 624 * Let's try the simple approach first - grab the focus. 625 * Getting a window out of the dock (minimized or whatever it's called) 626 * needs to be done on the GUI thread, so post it a note. 627 */ 628 *winId = 0; 629 if (!mView) 630 return S_OK; 631 632 ProcessSerialNumber psn = { 0, kCurrentProcess }; 633 OSErr rc = ::SetFrontProcess (&psn); 634 if (!rc) 635 QApplication::postEvent (mView, new QEvent ((QEvent::Type)VBoxDefs::ShowWindowEventType)); 636 else 637 { 638 /* 639 * It failed for some reason, send the other process our PSN so it can try. 640 * (This is just a precaution should Mac OS X start imposing the same sensible 641 * focus stealing restrictions that other window managers implement.) 642 */ 643 AssertMsgFailed(("SetFrontProcess -> %#x\n", rc)); 644 if (::GetCurrentProcess (&psn)) 645 *winId = RT_MAKE_U64 (psn.lowLongOfPSN, psn.highLongOfPSN); 646 } 647 648 #else 649 /* Return the ID of the top-level console window. */ 650 *winId = (ULONG64) mView->window()->winId(); 651 #endif 652 653 return S_OK; 654 } 655 656 protected: 657 658 VBoxConsoleView *mView; 659 660 #if defined (Q_WS_WIN) 661 private: 662 long mRefCnt; 663 #endif 664 }; 665 666 #if !defined (Q_WS_WIN) 667 NS_DECL_CLASSINFO (VBoxConsoleCallback) 668 NS_IMPL_THREADSAFE_ISUPPORTS1_CI (VBoxConsoleCallback, IConsoleCallback) 669 #endif 670 671 class VBoxViewport: public QWidget 672 { 673 public: 674 VBoxViewport (QWidget *aParent) 675 : QWidget (aParent) 676 { 677 /* No need for background drawing */ 678 setAttribute (Qt::WA_OpaquePaintEvent); 679 } 680 virtual QPaintEngine * paintEngine() const 681 { 682 if (testAttribute (Qt::WA_PaintOnScreen)) 683 return NULL; 684 else 685 return QWidget::paintEngine(); 686 } 687 }; 688 689 // 690 // VBoxConsoleView class 691 ///////////////////////////////////////////////////////////////////////////// 692 693 /** @class VBoxConsoleView 694 * 695 * The VBoxConsoleView class is a widget that implements a console 696 * for the running virtual machine. 697 */ 698 699 VBoxConsoleView::VBoxConsoleView (VBoxConsoleWnd *mainWnd, 700 const CConsole &console, 701 VBoxDefs::RenderMode rm, 702 #ifdef VBOX_WITH_VIDEOHWACCEL 703 bool accelerate2DVideo, 704 #endif 705 QWidget *parent) 706 : QAbstractScrollArea (parent) 707 , mMainWnd (mainWnd) 708 , mConsole (console) 709 , gs (vboxGlobal().settings()) 710 , mAttached (false) 711 , mKbdCaptured (false) 712 , mMouseCaptured (false) 713 , mMouseAbsolute (false) 714 , mMouseIntegration (true) 715 , m_iLastMouseWheelDelta(0) 716 , mDisableAutoCapture (false) 717 , mIsHostkeyPressed (false) 718 , mIsHostkeyAlone (false) 719 , mIgnoreMainwndResize (true) 720 , mAutoresizeGuest (false) 721 , mIgnoreFrameBufferResize (false) 722 , mIgnoreGuestResize (false) 723 , mDoResize (false) 724 , mGuestSupportsGraphics (false) 725 , mNumLock (false) 726 , mScrollLock (false) 727 , mCapsLock (false) 728 , muNumLockAdaptionCnt (2) 729 , muCapsLockAdaptionCnt (2) 730 , mode (rm) 731 #ifdef VBOX_WITH_VIDEOHWACCEL 732 , mAccelerate2DVideo(accelerate2DVideo) 733 #endif 734 #if defined(Q_WS_WIN) 735 , mAlphaCursor (NULL) 736 #endif 737 #if defined(Q_WS_MAC) 738 # if !defined (VBOX_WITH_HACKED_QT) && !defined (QT_MAC_USE_COCOA) 739 , mDarwinEventHandlerRef (NULL) 740 # endif 741 , mDarwinKeyModifiers (0) 742 , mKeyboardGrabbed (false) 743 , mDockIconEnabled (true) 744 #endif 745 , mDesktopGeo (DesktopGeo_Invalid) 746 , mPassCAD (false) 747 /* Don't show a hardware pointer until we have one to show */ 748 , mHideHostPointer (true) 749 { 750 Assert (!mConsole.isNull() && 751 !mConsole.GetDisplay().isNull() && 752 !mConsole.GetKeyboard().isNull() && 753 !mConsole.GetMouse().isNull()); 754 755 #ifdef Q_WS_MAC 756 /* Overlay logo for the dock icon */ 757 QString osTypeId = mConsole.GetGuest().GetOSTypeId(); 758 mDockIconPreview = new VBoxDockIconPreview (mMainWnd, vboxGlobal().vmGuestOSTypeIcon (osTypeId)); 759 760 # ifdef QT_MAC_USE_COCOA 761 /** @todo Carbon -> Cocoa */ 762 # else /* !QT_MAC_USE_COCOA */ 763 /* Install the event handler which will proceed external window handling */ 764 EventHandlerUPP eventHandler = ::NewEventHandlerUPP (::darwinOverlayWindowHandler); 765 EventTypeSpec eventTypes[] = 766 { 767 { kEventClassVBox, kEventVBoxShowWindow }, 768 { kEventClassVBox, kEventVBoxHideWindow }, 769 { kEventClassVBox, kEventVBoxMoveWindow }, 770 { kEventClassVBox, kEventVBoxResizeWindow }, 771 { kEventClassVBox, kEventVBoxDisposeWindow }, 772 { kEventClassVBox, kEventVBoxUpdateDock } 773 }; 774 775 mDarwinWindowOverlayHandlerRef = NULL; 776 ::InstallApplicationEventHandler (eventHandler, RT_ELEMENTS (eventTypes), &eventTypes[0], 777 this, &mDarwinWindowOverlayHandlerRef); 778 ::DisposeEventHandlerUPP (eventHandler); 779 # endif /* !QT_MAC_USE_COCOA */ 780 #endif /* QT_WS_MAC */ 781 782 /* No frame around the view */ 783 setFrameStyle (QFrame::NoFrame); 784 785 #ifdef VBOX_GUI_USE_QGL 786 QWidget *pViewport; 787 switch (mode) 788 { 789 case VBoxDefs::QGLMode: 790 pViewport = new VBoxGLWidget (this, this, NULL); 791 break; 792 default: 793 pViewport = new VBoxViewport (this); 794 } 795 #else 796 VBoxViewport *pViewport = new VBoxViewport (this); 797 #endif 798 setViewport (pViewport); 799 // pViewport->vboxDoInit(); 800 801 /* enable MouseMove events */ 802 viewport()->setMouseTracking (true); 803 804 /* 805 * QScrollView does the below on its own, but let's do it anyway 806 * for the case it will not do it in the future. 807 */ 808 viewport()->installEventFilter (this); 809 810 /* to fix some focus issues */ 811 mMainWnd->menuBar()->installEventFilter (this); 812 813 /* we want to be notified on some parent's events */ 814 mMainWnd->installEventFilter (this); 815 816 #ifdef Q_WS_X11 817 /* initialize the X keyboard subsystem */ 818 initMappedX11Keyboard(QX11Info::display(), 819 vboxGlobal().settings().publicProperty ("GUI/RemapScancodes")); 820 #endif 821 822 ::memset (mPressedKeys, 0, sizeof (mPressedKeys)); 823 824 /* setup rendering */ 825 826 CDisplay display = mConsole.GetDisplay(); 827 Assert (!display.isNull()); 828 829 mFrameBuf = NULL; 830 831 LogFlowFunc (("Rendering mode: %d\n", mode)); 832 833 switch (mode) 834 { 835 #if defined (VBOX_GUI_USE_QGL) 836 case VBoxDefs::QGLMode: 837 mFrameBuf = new VBoxQGLFrameBuffer (this); 838 break; 839 // case VBoxDefs::QGLOverlayMode: 840 // mFrameBuf = new VBoxQGLOverlayFrameBuffer (this); 841 // break; 842 #endif 843 #if defined (VBOX_GUI_USE_QIMAGE) 844 case VBoxDefs::QImageMode: 845 mFrameBuf = 846 #ifdef VBOX_WITH_VIDEOHWACCEL 847 mAccelerate2DVideo ? new VBoxOverlayFrameBuffer<VBoxQImageFrameBuffer> (this, &mainWnd->session()) : 848 #endif 849 new VBoxQImageFrameBuffer (this); 850 break; 851 #endif 852 #if defined (VBOX_GUI_USE_SDL) 853 case VBoxDefs::SDLMode: 854 /* Indicate that we are doing all 855 * drawing stuff ourself */ 856 pViewport->setAttribute (Qt::WA_PaintOnScreen); 857 # ifdef Q_WS_X11 858 /* This is somehow necessary to prevent strange X11 warnings on 859 * i386 and segfaults on x86_64. */ 860 XFlush(QX11Info::display()); 861 # endif 862 mFrameBuf = 863 #if defined(VBOX_WITH_VIDEOHWACCEL) && defined(DEBUG_misha) /* not tested yet */ 864 mAccelerate2DVideo ? new VBoxOverlayFrameBuffer<VBoxSDLFrameBuffer> (this, &mainWnd->session()) : 865 #endif 866 new VBoxSDLFrameBuffer (this); 867 /* 868 * disable scrollbars because we cannot correctly draw in a 869 * scrolled window using SDL 870 */ 871 horizontalScrollBar()->setEnabled (false); 872 verticalScrollBar()->setEnabled (false); 873 break; 874 #endif 875 #if defined (VBOX_GUI_USE_DDRAW) 876 case VBoxDefs::DDRAWMode: 877 mFrameBuf = new VBoxDDRAWFrameBuffer (this); 878 break; 879 #endif 880 #if defined (VBOX_GUI_USE_QUARTZ2D) 881 case VBoxDefs::Quartz2DMode: 882 /* Indicate that we are doing all 883 * drawing stuff ourself */ 884 pViewport->setAttribute (Qt::WA_PaintOnScreen); 885 mFrameBuf = 886 #ifdef VBOX_WITH_VIDEOHWACCEL 887 mAccelerate2DVideo ? new VBoxOverlayFrameBuffer<VBoxQuartz2DFrameBuffer> (this, &mainWnd->session()) : 888 #endif 889 new VBoxQuartz2DFrameBuffer (this); 890 break; 891 #endif 892 default: 893 AssertReleaseMsgFailed (("Render mode must be valid: %d\n", mode)); 894 LogRel (("Invalid render mode: %d\n", mode)); 895 qApp->exit (1); 896 break; 897 } 898 899 #if defined (VBOX_GUI_USE_DDRAW) 900 if (!mFrameBuf || mFrameBuf->address() == NULL) 901 { 902 if (mFrameBuf) 903 delete mFrameBuf; 904 mode = VBoxDefs::QImageMode; 905 mFrameBuf = new VBoxQImageFrameBuffer (this); 906 } 907 #endif 908 909 if (mFrameBuf) 910 { 911 mFrameBuf->AddRef(); 912 display.SetFramebuffer (VBOX_VIDEO_PRIMARY_SCREEN, CFramebuffer (mFrameBuf)); 913 } 914 915 /* setup the callback */ 916 mCallback = CConsoleCallback (new VBoxConsoleCallback (this)); 917 mConsole.RegisterCallback (mCallback); 918 AssertWrapperOk (mConsole); 919 920 QPalette palette (viewport()->palette()); 921 palette.setColor (viewport()->backgroundRole(), Qt::black); 922 viewport()->setPalette (palette); 923 924 setSizePolicy (QSizePolicy (QSizePolicy::Maximum, QSizePolicy::Maximum)); 925 setMaximumSize (sizeHint()); 926 927 setFocusPolicy (Qt::WheelFocus); 928 929 /* Remember the desktop geometry and register for geometry change 930 events for telling the guest about video modes we like. */ 931 932 QString desktopGeometry = vboxGlobal().settings() 933 .publicProperty ("GUI/MaxGuestResolution"); 934 if ((desktopGeometry == QString::null) || 935 (desktopGeometry == "auto")) 936 setDesktopGeometry (DesktopGeo_Automatic, 0, 0); 937 else if (desktopGeometry == "any") 938 setDesktopGeometry (DesktopGeo_Any, 0, 0); 939 else 940 { 941 int width = desktopGeometry.section (',', 0, 0).toInt(); 942 int height = desktopGeometry.section (',', 1, 1).toInt(); 943 setDesktopGeometry (DesktopGeo_Fixed, width, height); 944 } 945 connect (QApplication::desktop(), SIGNAL (resized (int)), 946 this, SLOT (doResizeDesktop (int))); 947 948 QString passCAD = mConsole.GetMachine().GetExtraData (VBoxDefs::GUI_PassCAD); 949 if (!passCAD.isEmpty() && 950 ((passCAD != "false") || (passCAD != "no")) 951 ) 952 mPassCAD = true; 953 954 #if defined (Q_WS_WIN) 955 gView = this; 956 #endif 957 958 #if defined (Q_WS_PM) 959 bool ok = VBoxHlpInstallKbdHook (0, winId(), UM_PREACCEL_CHAR); 960 Assert (ok); 961 NOREF (ok); 962 #endif 963 } 964 965 VBoxConsoleView::~VBoxConsoleView() 966 { 967 #if defined (Q_WS_PM) 968 bool ok = VBoxHlpUninstallKbdHook (0, winId(), UM_PREACCEL_CHAR); 969 Assert (ok); 970 NOREF (ok); 971 #endif 972 973 #if defined (Q_WS_WIN) 974 if (gKbdHook) 975 UnhookWindowsHookEx (gKbdHook); 976 gView = 0; 977 if (mAlphaCursor) 978 DestroyIcon (mAlphaCursor); 979 #endif 980 981 if (mFrameBuf) 982 { 983 /* detach our framebuffer from Display */ 984 CDisplay display = mConsole.GetDisplay(); 985 Assert (!display.isNull()); 986 display.SetFramebuffer (VBOX_VIDEO_PRIMARY_SCREEN, CFramebuffer(NULL)); 987 /* release the reference */ 988 mFrameBuf->Release(); 989 mFrameBuf = NULL; 990 } 991 992 mConsole.UnregisterCallback (mCallback); 993 994 #if defined (Q_WS_MAC) 995 # if !defined (QT_MAC_USE_COCOA) 996 if (mDarwinWindowOverlayHandlerRef) 997 { 998 ::RemoveEventHandler (mDarwinWindowOverlayHandlerRef); 999 mDarwinWindowOverlayHandlerRef = NULL; 1000 } 1001 # endif 1002 delete mDockIconPreview; 1003 mDockIconPreview = NULL; 1004 #endif 1005 } 1006 1007 // 1008 // Public members 1009 ///////////////////////////////////////////////////////////////////////////// 1010 1011 QSize VBoxConsoleView::sizeHint() const 1012 { 1013 #ifdef VBOX_WITH_DEBUGGER /** @todo figure out a more proper fix. */ 1014 /* HACK ALERT! Really ugly workaround for the resizing to 9x1 done 1015 * by DevVGA if provoked before power on. */ 1016 QSize fb(mFrameBuf->width(), mFrameBuf->height()); 1017 if ( ( fb.width() < 16 1018 || fb.height() < 16) 1019 && ( vboxGlobal().isStartPausedEnabled() 1020 || vboxGlobal().isDebuggerAutoShowEnabled()) ) 1021 fb = QSize(640, 480); 1022 return QSize (fb.width() + frameWidth() * 2, 1023 fb.height() + frameWidth() * 2); 1024 #else 1025 return QSize (mFrameBuf->width() + frameWidth() * 2, 1026 mFrameBuf->height() + frameWidth() * 2); 1027 #endif 1028 } 1029 1030 /** 1031 * Attaches this console view to the managed virtual machine. 1032 * 1033 * @note This method is not really necessary these days -- the only place where 1034 * it gets called is VBoxConsole::openView(), right after powering the 1035 * VM up. We leave it as is just in case attaching/detaching will become 1036 * necessary some day (there are useful attached checks everywhere in the 1037 * code). 1038 */ 1039 void VBoxConsoleView::attach() 1040 { 1041 if (!mAttached) 1042 { 1043 mAttached = true; 1044 } 1045 } 1046 1047 /** 1048 * Detaches this console view from the VM. Must be called to indicate 1049 * that the virtual machine managed by this instance will be no more valid 1050 * after this call. 1051 * 1052 * @note This method is not really necessary these days -- the only place where 1053 * it gets called is VBoxConsole::closeView(), when the VM is powered 1054 * down, before deleting VBoxConsoleView. We leave it as is just in case 1055 * attaching/detaching will become necessary some day (there are useful 1056 * attached checks everywhere in the code). 1057 */ 1058 void VBoxConsoleView::detach() 1059 { 1060 if (mAttached) 1061 { 1062 /* reuse the focus event handler to uncapture everything */ 1063 focusEvent (false); 1064 mAttached = false; 1065 } 1066 } 1067 1068 /** 1069 * Resizes the toplevel widget to fit the console view w/o scrollbars. 1070 * If adjustPosition is true and such resize is not possible (because the 1071 * console view size is lagrer then the available screen space) the toplevel 1072 * widget is resized and moved to become as large as possible while staying 1073 * fully visible. 1074 */ 1075 void VBoxConsoleView::normalizeGeometry (bool adjustPosition /* = false */) 1076 { 1077 /* Make no normalizeGeometry in case we are in manual resize 1078 * mode or main window is maximized */ 1079 if (mMainWnd->isWindowMaximized() || mMainWnd->isWindowFullScreen()) 1080 return; 1081 1082 QWidget *tlw = window(); 1083 1084 /* calculate client window offsets */ 1085 QRect fr = tlw->frameGeometry(); 1086 QRect r = tlw->geometry(); 1087 int dl = r.left() - fr.left(); 1088 int dt = r.top() - fr.top(); 1089 int dr = fr.right() - r.right(); 1090 int db = fr.bottom() - r.bottom(); 1091 1092 /* get the best size w/o scroll bars */ 1093 QSize s = tlw->sizeHint(); 1094 1095 /* resize the frame to fit the contents */ 1096 s -= tlw->size(); 1097 fr.setRight (fr.right() + s.width()); 1098 fr.setBottom (fr.bottom() + s.height()); 1099 1100 if (adjustPosition) 1101 { 1102 QRegion ar; 1103 QDesktopWidget *dwt = QApplication::desktop(); 1104 if (dwt->isVirtualDesktop()) 1105 /* Compose complex available region */ 1106 for (int i = 0; i < dwt->numScreens(); ++ i) 1107 ar += dwt->availableGeometry (i); 1108 else 1109 /* Get just a simple available rectangle */ 1110 ar = dwt->availableGeometry (tlw->pos()); 1111 1112 fr = VBoxGlobal::normalizeGeometry ( 1113 fr, ar, mode != VBoxDefs::SDLMode /* canResize */); 1114 } 1115 1116 #if 0 1117 /* center the frame on the desktop */ 1118 fr.moveCenter (ar.center()); 1119 #endif 1120 1121 /* finally, set the frame geometry */ 1122 tlw->setGeometry (fr.left() + dl, fr.top() + dt, 1123 fr.width() - dl - dr, fr.height() - dt - db); 1124 } 1125 1126 /** 1127 * Pauses or resumes the VM execution. 1128 */ 1129 bool VBoxConsoleView::pause (bool on) 1130 { 1131 /* QAction::setOn() emits the toggled() signal, so avoid recursion when 1132 * QAction::setOn() is called from VBoxConsoleWnd::updateMachineState() */ 1133 if (isPaused() == on) 1134 return true; 1135 1136 if (on) 1137 mConsole.Pause(); 1138 else 1139 mConsole.Resume(); 1140 1141 bool ok = mConsole.isOk(); 1142 if (!ok) 1143 { 1144 if (on) 1145 vboxProblem().cannotPauseMachine (mConsole); 1146 else 1147 vboxProblem().cannotResumeMachine (mConsole); 1148 } 1149 1150 return ok; 1151 } 1152 1153 /** 1154 * Temporarily disables the mouse integration (or enables it back). 1155 */ 1156 void VBoxConsoleView::setMouseIntegrationEnabled (bool enabled) 1157 { 1158 if (mMouseIntegration == enabled) 1159 return; 1160 1161 if (mMouseAbsolute) 1162 captureMouse (!enabled, false); 1163 1164 /* Hiding host cursor in case we are entering mouse integration 1165 * mode until it's shape is set to the guest cursor shape in 1166 * OnMousePointerShapeChange event handler. 1167 * 1168 * This is necessary to avoid double-cursor issues where both the 1169 * guest and the host cursors are displayed in one place, one above the 1170 * other. 1171 * 1172 * This is a workaround because the correct decision would be to notify 1173 * the Guest Additions about we are entering the mouse integration 1174 * mode. The GuestOS should hide it's cursor to allow using of 1175 * host cursor for the guest's manipulation. 1176 * 1177 * This notification is not always possible though, as not all guests 1178 * support switching to a hardware pointer on demand. */ 1179 if (enabled) 1180 viewport()->setCursor (QCursor (Qt::BlankCursor)); 1181 1182 mMouseIntegration = enabled; 1183 1184 emitMouseStateChanged(); 1185 } 1186 1187 void VBoxConsoleView::setAutoresizeGuest (bool on) 1188 { 1189 if (mAutoresizeGuest != on) 1190 { 1191 mAutoresizeGuest = on; 1192 1193 maybeRestrictMinimumSize(); 1194 1195 if (mGuestSupportsGraphics && mAutoresizeGuest) 1196 doResizeHint(); 1197 } 1198 } 1199 1200 /** 1201 * This method is called by VBoxConsoleWnd after it does everything necessary 1202 * on its side to go to or from fullscreen, but before it is shown. 1203 */ 1204 void VBoxConsoleView::onFullscreenChange (bool /* on */) 1205 { 1206 /* Nothing to do here so far */ 1207 } 1208 1209 /** 1210 * Notify the console scroll-view about the console-window is opened. 1211 */ 1212 void VBoxConsoleView::onViewOpened() 1213 { 1214 /* Variable mIgnoreMainwndResize was initially "true" to ignore QT 1215 * initial resize event in case of auto-resize feature is on. 1216 * Currently, initial resize event is already processed, so we set 1217 * mIgnoreMainwndResize to "false" to process all further resize 1218 * events as user-initiated window resize events. */ 1219 mIgnoreMainwndResize = false; 1220 } 1221 1222 // 1223 // Protected Events 1224 ///////////////////////////////////////////////////////////////////////////// 1225 1226 bool VBoxConsoleView::event (QEvent *e) 1227 { 1228 if (mAttached) 1229 { 1230 switch (e->type()) 1231 { 1232 case QEvent::FocusIn: 1233 { 1234 if (isRunning()) 1235 focusEvent (true); 1236 break; 1237 } 1238 case QEvent::FocusOut: 1239 { 1240 if (isRunning()) 1241 focusEvent (false); 1242 else 1243 { 1244 /* release the host key and all other pressed keys too even 1245 * when paused (otherwise, we will get stuck keys in the 1246 * guest when doing sendChangedKeyStates() on resume because 1247 * key presses were already recorded in mPressedKeys but key 1248 * releases will most likely not reach us but the new focus 1249 * window instead). */ 1250 releaseAllPressedKeys (true /* aReleaseHostKey */); 1251 } 1252 break; 1253 } 1254 1255 case VBoxDefs::ResizeEventType: 1256 { 1257 /* Some situations require initial VGA Resize Request 1258 * to be ignored at all, leaving previous framebuffer, 1259 * console widget and vm window size preserved. */ 1260 if (mIgnoreGuestResize) 1261 return true; 1262 1263 bool oldIgnoreMainwndResize = mIgnoreMainwndResize; 1264 mIgnoreMainwndResize = true; 1265 1266 VBoxResizeEvent *re = (VBoxResizeEvent *) e; 1267 LogRelFlowFunc (("VBoxDefs::ResizeEventType: %d x %d x %d bpp\n", 1268 re->width(), re->height(), 1269 re->bitsPerPixel())); 1270 1271 bool notifyMainWnd = mFrameBuf->width() != re->width() 1272 || mFrameBuf->height() != re->height(); 1273 1274 /* Store the new size to prevent unwanted resize hints being 1275 * sent back. */ 1276 storeConsoleSize(re->width(), re->height()); 1277 /* do frame buffer dependent resize */ 1278 1279 /* restoreOverrideCursor() is broken in Qt 4.4.0 if WA_PaintOnScreen 1280 * widgets are present. This is the case on linux with SDL. As 1281 * workaround we save/restore the arrow cursor manually. See 1282 * http://trolltech.com/developer/task-tracker/index_html?id=206165&method=entry 1283 * for details. 1284 * 1285 * Moreover the current cursor, which could be set by the guest, 1286 * should be restored after resize. 1287 */ 1288 QCursor cursor; 1289 if (shouldHideHostPointer()) 1290 cursor = QCursor (Qt::BlankCursor); 1291 else 1292 cursor = viewport()->cursor(); 1293 mFrameBuf->resizeEvent (re); 1294 viewport()->setCursor (cursor); 1295 1296 #ifdef Q_WS_MAC 1297 mDockIconPreview->setOriginalSize (re->width(), re->height()); 1298 #endif /* Q_WS_MAC */ 1299 1300 /* This event appears in case of guest video was changed 1301 * for somehow even without video resolution change. 1302 * In this last case the host VM window will not be resized 1303 * according this event and the host mouse cursor which was 1304 * unset to default here will not be hidden in capture state. 1305 * So it is necessary to perform updateMouseClipping() for 1306 * the guest resize event if the mouse cursor was captured. */ 1307 if (mMouseCaptured) 1308 updateMouseClipping(); 1309 1310 /* apply maximum size restriction */ 1311 setMaximumSize (sizeHint()); 1312 1313 maybeRestrictMinimumSize(); 1314 1315 /* resize the guest canvas */ 1316 if (!mIgnoreFrameBufferResize) 1317 resize (re->width(), re->height()); 1318 updateSliders(); 1319 /* Let our toplevel widget calculate its sizeHint properly. */ 1320 #ifdef Q_WS_X11 1321 /* We use processEvents rather than sendPostedEvents & set the 1322 * time out value to max cause on X11 otherwise the layout 1323 * isn't calculated correctly. Dosn't find the bug in Qt, but 1324 * this could be triggered through the async nature of the X11 1325 * window event system. */ 1326 QCoreApplication::processEvents (QEventLoop::AllEvents, INT_MAX); 1327 #else /* Q_WS_X11 */ 1328 QCoreApplication::sendPostedEvents (0, QEvent::LayoutRequest); 1329 #endif /* Q_WS_X11 */ 1330 1331 if (!mIgnoreFrameBufferResize) 1332 normalizeGeometry (true /* adjustPosition */); 1333 1334 /* report to the VM thread that we finished resizing */ 1335 mConsole.GetDisplay().ResizeCompleted (0); 1336 1337 mIgnoreMainwndResize = oldIgnoreMainwndResize; 1338 1339 /* update geometry after entering fullscreen | seamless */ 1340 if (mMainWnd->isTrueFullscreen() || mMainWnd->isTrueSeamless()) 1341 updateGeometry(); 1342 1343 /* make sure that all posted signals are processed */ 1344 qApp->processEvents(); 1345 1346 /* emit a signal about guest was resized */ 1347 emit resizeHintDone(); 1348 1349 /* We also recalculate the desktop geometry if this is determined 1350 * automatically. In fact, we only need this on the first resize, 1351 * but it is done every time to keep the code simpler. */ 1352 calculateDesktopGeometry(); 1353 1354 /* Enable frame-buffer resize watching. */ 1355 if (mIgnoreFrameBufferResize) 1356 { 1357 mIgnoreFrameBufferResize = false; 1358 } 1359 1360 if (notifyMainWnd) 1361 mMainWnd->onDisplayResize (re->width(), re->height()); 1362 1363 return true; 1364 } 1365 1366 /* See VBox[QImage|SDL]FrameBuffer::NotifyUpdate(). */ 1367 case VBoxDefs::RepaintEventType: 1368 { 1369 VBoxRepaintEvent *re = (VBoxRepaintEvent *) e; 1370 viewport()->repaint (re->x() - contentsX(), 1371 re->y() - contentsY(), 1372 re->width(), re->height()); 1373 /* mConsole.GetDisplay().UpdateCompleted(); - the event was acked already */ 1374 return true; 1375 } 1376 1377 #ifdef VBOX_WITH_VIDEOHWACCEL 1378 case VBoxDefs::VHWACommandProcessType: 1379 { 1380 mFrameBuf->doProcessVHWACommand(e); 1381 return true; 1382 } 1383 #endif 1384 1385 case VBoxDefs::SetRegionEventType: 1386 { 1387 VBoxSetRegionEvent *sre = (VBoxSetRegionEvent*) e; 1388 if (mMainWnd->isTrueSeamless() && 1389 sre->region() != mLastVisibleRegion) 1390 { 1391 mLastVisibleRegion = sre->region(); 1392 mMainWnd->setMask (sre->region()); 1393 } 1394 else if (!mLastVisibleRegion.isEmpty() && 1395 !mMainWnd->isTrueSeamless()) 1396 mLastVisibleRegion = QRegion(); 1397 return true; 1398 } 1399 1400 case VBoxDefs::MousePointerChangeEventType: 1401 { 1402 MousePointerChangeEvent *me = (MousePointerChangeEvent *) e; 1403 /* change cursor shape only when mouse integration is 1404 * supported (change mouse shape type event may arrive after 1405 * mouse capability change that disables integration */ 1406 if (mMouseAbsolute) 1407 setPointerShape (me); 1408 else 1409 /* Note: actually we should still remember the requested 1410 * cursor shape. If we can't do that, at least remember 1411 * the requested visiblilty. */ 1412 mHideHostPointer = !me->isVisible(); 1413 return true; 1414 } 1415 case VBoxDefs::MouseCapabilityEventType: 1416 { 1417 MouseCapabilityEvent *me = (MouseCapabilityEvent *) e; 1418 if (mMouseAbsolute != me->supportsAbsolute()) 1419 { 1420 mMouseAbsolute = me->supportsAbsolute(); 1421 /* correct the mouse capture state and reset the cursor 1422 * to the default shape if necessary */ 1423 if (mMouseAbsolute) 1424 { 1425 CMouse mouse = mConsole.GetMouse(); 1426 mouse.PutMouseEventAbsolute (-1, -1, 0, 1427 0 /* Horizontal wheel */, 1428 0); 1429 captureMouse (false, false); 1430 } 1431 else 1432 viewport()->unsetCursor(); 1433 emitMouseStateChanged(); 1434 vboxProblem().remindAboutMouseIntegration (mMouseAbsolute); 1435 } 1436 if (me->needsHostCursor()) 1437 mMainWnd->setMouseIntegrationLocked (false); 1438 else 1439 mMainWnd->setMouseIntegrationLocked (true); 1440 return true; 1441 } 1442 1443 case VBoxDefs::ModifierKeyChangeEventType: 1444 { 1445 ModifierKeyChangeEvent *me = (ModifierKeyChangeEvent* )e; 1446 if (me->numLock() != mNumLock) 1447 muNumLockAdaptionCnt = 2; 1448 if (me->capsLock() != mCapsLock) 1449 muCapsLockAdaptionCnt = 2; 1450 mNumLock = me->numLock(); 1451 mCapsLock = me->capsLock(); 1452 mScrollLock = me->scrollLock(); 1453 return true; 1454 } 1455 1456 case VBoxDefs::MachineStateChangeEventType: 1457 { 1458 StateChangeEvent *me = (StateChangeEvent *) e; 1459 LogFlowFunc (("MachineStateChangeEventType: state=%d\n", 1460 me->machineState())); 1461 onStateChange (me->machineState()); 1462 emit machineStateChanged (me->machineState()); 1463 return true; 1464 } 1465 1466 case VBoxDefs::AdditionsStateChangeEventType: 1467 { 1468 GuestAdditionsEvent *ge = (GuestAdditionsEvent *) e; 1469 LogFlowFunc (("AdditionsStateChangeEventType\n")); 1470 1471 /* Always send a size hint if we are in fullscreen or seamless 1472 * when the graphics capability is enabled, in case the host 1473 * resolution has changed since the VM was last run. */ 1474 #if 0 1475 if (!mDoResize && !mGuestSupportsGraphics && 1476 ge->supportsGraphics() && 1477 (mMainWnd->isTrueSeamless() || mMainWnd->isTrueFullscreen())) 1478 mDoResize = true; 1479 #endif 1480 1481 mGuestSupportsGraphics = ge->supportsGraphics(); 1482 1483 maybeRestrictMinimumSize(); 1484 1485 #if 0 1486 /* This will only be acted upon if mDoResize is true. */ 1487 doResizeHint(); 1488 #endif 1489 1490 emit additionsStateChanged (ge->additionVersion(), 1491 ge->additionActive(), 1492 ge->supportsSeamless(), 1493 ge->supportsGraphics()); 1494 return true; 1495 } 1496 1497 case VBoxDefs::MediaDriveChangeEventType: 1498 { 1499 MediaDriveChangeEvent *mce = (MediaDriveChangeEvent *) e; 1500 LogFlowFunc (("MediaChangeEvent\n")); 1501 1502 emit mediaDriveChanged (mce->type()); 1503 return true; 1504 } 1505 1506 case VBoxDefs::ActivateMenuEventType: 1507 { 1508 ActivateMenuEvent *ame = (ActivateMenuEvent *) e; 1509 ame->action()->trigger(); 1510 1511 /* 1512 * The main window and its children can be destroyed at this 1513 * point (if, for example, the activated menu item closes the 1514 * main window). Detect this situation to prevent calls to 1515 * destroyed widgets. 1516 */ 1517 QWidgetList list = QApplication::topLevelWidgets(); 1518 bool destroyed = list.indexOf (mMainWnd) < 0; 1519 if (!destroyed && mMainWnd->statusBar()) 1520 mMainWnd->statusBar()->clearMessage(); 1521 1522 return true; 1523 } 1524 1525 case VBoxDefs::NetworkAdapterChangeEventType: 1526 { 1527 /* no specific adapter information stored in this 1528 * event is currently used */ 1529 emit networkStateChange(); 1530 return true; 1531 } 1532 1533 case VBoxDefs::USBCtlStateChangeEventType: 1534 { 1535 emit usbStateChange(); 1536 return true; 1537 } 1538 1539 case VBoxDefs::USBDeviceStateChangeEventType: 1540 { 1541 USBDeviceStateChangeEvent *ue = (USBDeviceStateChangeEvent *)e; 1542 1543 bool success = ue->error().isNull(); 1544 1545 if (!success) 1546 { 1547 if (ue->attached()) 1548 vboxProblem().cannotAttachUSBDevice ( 1549 mConsole, 1550 vboxGlobal().details (ue->device()), ue->error()); 1551 else 1552 vboxProblem().cannotDetachUSBDevice ( 1553 mConsole, 1554 vboxGlobal().details (ue->device()), ue->error()); 1555 } 1556 1557 emit usbStateChange(); 1558 1559 return true; 1560 } 1561 1562 case VBoxDefs::SharedFolderChangeEventType: 1563 { 1564 emit sharedFoldersChanged(); 1565 return true; 1566 } 1567 1568 case VBoxDefs::RuntimeErrorEventType: 1569 { 1570 RuntimeErrorEvent *ee = (RuntimeErrorEvent *) e; 1571 vboxProblem().showRuntimeError (mConsole, ee->fatal(), 1572 ee->errorID(), ee->message()); 1573 return true; 1574 } 1575 1576 case QEvent::KeyPress: 1577 case QEvent::KeyRelease: 1578 { 1579 QKeyEvent *ke = (QKeyEvent *) e; 1580 1581 #ifdef Q_WS_PM 1582 /// @todo temporary solution to send Alt+Tab and friends to 1583 // the guest. The proper solution is to write a keyboard 1584 // driver that will steal these combos from the host (it's 1585 // impossible to do so using hooks on OS/2). 1586 1587 if (mIsHostkeyPressed) 1588 { 1589 bool pressed = e->type() == QEvent::KeyPress; 1590 CKeyboard keyboard = mConsole.GetKeyboard(); 1591 1592 /* whether the host key is Shift so that it will modify 1593 * the hot key values? Note that we don't distinguish 1594 * between left and right shift here (too much hassle) */ 1595 const bool kShift = (gs.hostKey() == VK_SHIFT || 1596 gs.hostKey() == VK_LSHIFT) && 1597 (ke->state() & Qt::ShiftModifier); 1598 /* define hot keys according to the Shift state */ 1599 const int kAltTab = kShift ? Qt::Key_Exclam : Qt::Key_1; 1600 const int kAltShiftTab = kShift ? Qt::Key_At : Qt::Key_2; 1601 const int kCtrlEsc = kShift ? Qt::Key_AsciiTilde : Qt::Key_QuoteLeft; 1602 1603 /* Simulate Alt+Tab on Host+1 and Alt+Shift+Tab on Host+2 */ 1604 if (ke->key() == kAltTab || ke->key() == kAltShiftTab) 1605 { 1606 if (pressed) 1607 { 1608 /* Send the Alt press to the guest */ 1609 if (!(mPressedKeysCopy [0x38] & IsKeyPressed)) 1610 { 1611 /* store the press in *Copy to have it automatically 1612 * released when the Host key is released */ 1613 mPressedKeysCopy [0x38] |= IsKeyPressed; 1614 keyboard.PutScancode (0x38); 1615 } 1616 1617 /* Make sure Shift is pressed if it's Key_2 and released 1618 * if it's Key_1 */ 1619 if (ke->key() == kAltTab && 1620 (mPressedKeysCopy [0x2A] & IsKeyPressed)) 1621 { 1622 mPressedKeysCopy [0x2A] &= ~IsKeyPressed; 1623 keyboard.PutScancode (0xAA); 1624 } 1625 else 1626 if (ke->key() == kAltShiftTab && 1627 !(mPressedKeysCopy [0x2A] & IsKeyPressed)) 1628 { 1629 mPressedKeysCopy [0x2A] |= IsKeyPressed; 1630 keyboard.PutScancode (0x2A); 1631 } 1632 } 1633 1634 keyboard.PutScancode (pressed ? 0x0F : 0x8F); 1635 1636 ke->accept(); 1637 return true; 1638 } 1639 1640 /* Simulate Ctrl+Esc on Host+Tilde */ 1641 if (ke->key() == kCtrlEsc) 1642 { 1643 /* Send the Ctrl press to the guest */ 1644 if (pressed && !(mPressedKeysCopy [0x1d] & IsKeyPressed)) 1645 { 1646 /* store the press in *Copy to have it automatically 1647 * released when the Host key is released */ 1648 mPressedKeysCopy [0x1d] |= IsKeyPressed; 1649 keyboard.PutScancode (0x1d); 1650 } 1651 1652 keyboard.PutScancode (pressed ? 0x01 : 0x81); 1653 1654 ke->accept(); 1655 return true; 1656 } 1657 } 1658 1659 /* fall through to normal processing */ 1660 1661 #endif /* Q_WS_PM */ 1662 1663 if (mIsHostkeyPressed && e->type() == QEvent::KeyPress) 1664 { 1665 if (ke->key() >= Qt::Key_F1 && ke->key() <= Qt::Key_F12) 1666 { 1667 QVector <LONG> combo (6); 1668 combo [0] = 0x1d; /* Ctrl down */ 1669 combo [1] = 0x38; /* Alt down */ 1670 combo [4] = 0xb8; /* Alt up */ 1671 combo [5] = 0x9d; /* Ctrl up */ 1672 if (ke->key() >= Qt::Key_F1 && ke->key() <= Qt::Key_F10) 1673 { 1674 combo [2] = 0x3b + (ke->key() - Qt::Key_F1); /* F1-F10 down */ 1675 combo [3] = 0xbb + (ke->key() - Qt::Key_F1); /* F1-F10 up */ 1676 } 1677 /* some scan slice */ 1678 else if (ke->key() >= Qt::Key_F11 && ke->key() <= Qt::Key_F12) 1679 { 1680 combo [2] = 0x57 + (ke->key() - Qt::Key_F11); /* F11-F12 down */ 1681 combo [3] = 0xd7 + (ke->key() - Qt::Key_F11); /* F11-F12 up */ 1682 } 1683 else 1684 Assert (0); 1685 1686 CKeyboard keyboard = mConsole.GetKeyboard(); 1687 keyboard.PutScancodes (combo); 1688 } 1689 else if (ke->key() == Qt::Key_Home) 1690 { 1691 /* Activate the main menu */ 1692 if (mMainWnd->isTrueSeamless() || mMainWnd->isTrueFullscreen()) 1693 mMainWnd->popupMainMenu (mMouseCaptured); 1694 else 1695 { 1696 /* In Qt4 it is not enough to just set the focus to 1697 * menu-bar. So to get the menu-bar we have to send 1698 * Qt::Key_Alt press/release events directly. */ 1699 QKeyEvent e1 (QEvent::KeyPress, Qt::Key_Alt, 1700 Qt::NoModifier); 1701 QKeyEvent e2 (QEvent::KeyRelease, Qt::Key_Alt, 1702 Qt::NoModifier); 1703 QApplication::sendEvent (mMainWnd->menuBar(), &e1); 1704 QApplication::sendEvent (mMainWnd->menuBar(), &e2); 1705 } 1706 } 1707 else 1708 { 1709 /* process hot keys not processed in keyEvent() 1710 * (as in case of non-alphanumeric keys) */ 1711 processHotKey (QKeySequence (ke->key()), 1712 mMainWnd->menuBar()->actions()); 1713 } 1714 } 1715 else if (!mIsHostkeyPressed && e->type() == QEvent::KeyRelease) 1716 { 1717 /* Show a possible warning on key release which seems to 1718 * be more expected by the end user */ 1719 1720 if (isPaused()) 1721 { 1722 /* if the reminder is disabled we pass the event to 1723 * Qt to enable normal keyboard functionality 1724 * (for example, menu access with Alt+Letter) */ 1725 if (!vboxProblem().remindAboutPausedVMInput()) 1726 break; 1727 } 1728 } 1729 1730 ke->accept(); 1731 return true; 1732 } 1733 1734 #ifdef Q_WS_MAC 1735 /* posted OnShowWindow */ 1736 case VBoxDefs::ShowWindowEventType: 1737 { 1738 /* 1739 * Dunno what Qt3 thinks a window that has minimized to the dock 1740 * should be - it is not hidden, neither is it minimized. OTOH it is 1741 * marked shown and visible, but not activated. This latter isn't of 1742 * much help though, since at this point nothing is marked activated. 1743 * I might have overlooked something, but I'm buggered what if I know 1744 * what. So, I'll just always show & activate the stupid window to 1745 * make it get out of the dock when the user wishes to show a VM. 1746 */ 1747 window()->show(); 1748 window()->activateWindow(); 1749 return true; 1750 } 1751 #endif 1752 default: 1753 break; 1754 } 1755 } 1756 1757 return QAbstractScrollArea::event (e); 1758 } 1759 1760 #ifdef VBOX_WITH_VIDEOHWACCEL 1761 void VBoxConsoleView::scrollContentsBy (int dx, int dy) 1762 { 1763 if (mAttached && mFrameBuf) 1764 { 1765 mFrameBuf->viewportScrolled(dx, dy); 1766 } 1767 QAbstractScrollArea::scrollContentsBy (dx, dy); 1768 } 1769 #endif 1770 1771 1772 bool VBoxConsoleView::eventFilter (QObject *watched, QEvent *e) 1773 { 1774 if (mAttached && watched == viewport()) 1775 { 1776 switch (e->type()) 1777 { 1778 case QEvent::MouseMove: 1779 case QEvent::MouseButtonPress: 1780 case QEvent::MouseButtonDblClick: 1781 case QEvent::MouseButtonRelease: 1782 { 1783 QMouseEvent *me = (QMouseEvent *) e; 1784 m_iLastMouseWheelDelta = 0; 1785 if (mouseEvent (me->type(), me->pos(), me->globalPos(), 1786 me->buttons(), me->modifiers(), 1787 0, Qt::Horizontal)) 1788 return true; /* stop further event handling */ 1789 break; 1790 } 1791 case QEvent::Wheel: 1792 { 1793 QWheelEvent *we = (QWheelEvent *) e; 1794 /* There are pointing devices which send smaller values for the 1795 * delta than 120. Here we sum them up until we are greater 1796 * than 120. This allows to have finer control over the speed 1797 * acceleration & enables such devices to send a valid wheel 1798 * event to our guest mouse device at all. */ 1799 int iDelta = 0; 1800 m_iLastMouseWheelDelta += we->delta(); 1801 if (qAbs(m_iLastMouseWheelDelta) >= 120) 1802 { 1803 iDelta = m_iLastMouseWheelDelta; 1804 m_iLastMouseWheelDelta = m_iLastMouseWheelDelta % 120; 1805 } 1806 if (mouseEvent (we->type(), we->pos(), we->globalPos(), 1807 #ifdef QT_MAC_USE_COCOA 1808 /* Qt Cocoa is buggy. It always reports a left 1809 * button pressed when the mouse wheel event 1810 * occurs. A workaround is to ask the 1811 * application which buttons are pressed 1812 * currently. */ 1813 QApplication::mouseButtons(), 1814 #else /* QT_MAC_USE_COCOA */ 1815 we->buttons(), 1816 #endif /* QT_MAC_USE_COCOA */ 1817 we->modifiers(), 1818 iDelta, we->orientation())) 1819 return true; /* stop further event handling */ 1820 break; 1821 } 1822 #ifdef Q_WS_MAC 1823 case QEvent::Leave: 1824 { 1825 /* Enable mouse event compression if we leave the VM view. This 1826 is necessary for having smooth resizing of the VM/other 1827 windows. */ 1828 setMouseCoalescingEnabled (true); 1829 break; 1830 } 1831 case QEvent::Enter: 1832 { 1833 /* Disable mouse event compression if we enter the VM view. So 1834 all mouse events are registered in the VM. Only do this if 1835 the keyboard/mouse is grabbed (this is when we have a valid 1836 event handler). */ 1837 setMouseCoalescingEnabled (false); 1838 break; 1839 } 1840 #endif /* Q_WS_MAC */ 1841 case QEvent::Resize: 1842 { 1843 if (mMouseCaptured) 1844 updateMouseClipping(); 1845 #ifdef VBOX_WITH_VIDEOHWACCEL 1846 if (mFrameBuf) 1847 { 1848 mFrameBuf->viewportResized((QResizeEvent*)e); 1849 } 1850 #endif 1851 break; 1852 } 1853 default: 1854 break; 1855 } 1856 } 1857 else if (watched == mMainWnd) 1858 { 1859 switch (e->type()) 1860 { 1861 #if defined (Q_WS_WIN32) 1862 #if defined (VBOX_GUI_USE_DDRAW) 1863 case QEvent::Move: 1864 { 1865 /* 1866 * notification from our parent that it has moved. We need this 1867 * in order to possibly adjust the direct screen blitting. 1868 */ 1869 if (mFrameBuf) 1870 mFrameBuf->moveEvent ((QMoveEvent *) e); 1871 break; 1872 } 1873 #endif 1874 /* 1875 * install/uninstall low-level kbd hook on every 1876 * activation/deactivation to: 1877 * a) avoid excess hook calls when we're not active and 1878 * b) be always in front of any other possible hooks 1879 */ 1880 case QEvent::WindowActivate: 1881 { 1882 gKbdHook = SetWindowsHookEx (WH_KEYBOARD_LL, lowLevelKeyboardProc, 1883 GetModuleHandle (NULL), 0); 1884 AssertMsg (gKbdHook, ("SetWindowsHookEx(): err=%d", GetLastError())); 1885 break; 1886 } 1887 case QEvent::WindowDeactivate: 1888 { 1889 if (gKbdHook) 1890 { 1891 UnhookWindowsHookEx (gKbdHook); 1892 gKbdHook = NULL; 1893 } 1894 break; 1895 } 1896 #endif /* defined (Q_WS_WIN32) */ 1897 #if defined (Q_WS_MAC) 1898 /* 1899 * Install/remove the keyboard event handler. 1900 */ 1901 case QEvent::WindowActivate: 1902 darwinGrabKeyboardEvents (true); 1903 break; 1904 case QEvent::WindowDeactivate: 1905 darwinGrabKeyboardEvents (false); 1906 break; 1907 #endif /* defined (Q_WS_MAC) */ 1908 case QEvent::Resize: 1909 { 1910 /* Set the "guest needs to resize" hint. This hint is acted upon 1911 * when (and only when) the autoresize property is "true". */ 1912 mDoResize = mGuestSupportsGraphics || mMainWnd->isTrueFullscreen(); 1913 if (!mIgnoreMainwndResize && 1914 mGuestSupportsGraphics && mAutoresizeGuest) 1915 QTimer::singleShot (300, this, SLOT (doResizeHint())); 1916 break; 1917 } 1918 case QEvent::WindowStateChange: 1919 { 1920 /* During minimizing and state restoring mMainWnd gets the focus 1921 * which belongs to console view window, so returning it properly. */ 1922 QWindowStateChangeEvent *ev = static_cast <QWindowStateChangeEvent*> (e); 1923 if (ev->oldState() & Qt::WindowMinimized) 1924 { 1925 if (QApplication::focusWidget()) 1926 { 1927 QApplication::focusWidget()->clearFocus(); 1928 qApp->processEvents(); 1929 } 1930 QTimer::singleShot (0, this, SLOT (setFocus())); 1931 } 1932 break; 1933 } 1934 1935 default: 1936 break; 1937 } 1938 } 1939 else if (watched == mMainWnd->menuBar()) 1940 { 1941 /* 1942 * sometimes when we press ESC in the menu it brings the 1943 * focus away (Qt bug?) causing no widget to have a focus, 1944 * or holds the focus itself, instead of returning the focus 1945 * to the console window. here we fix this. 1946 */ 1947 switch (e->type()) 1948 { 1949 case QEvent::FocusOut: 1950 { 1951 if (qApp->focusWidget() == 0) 1952 setFocus(); 1953 break; 1954 } 1955 case QEvent::KeyPress: 1956 { 1957 QKeyEvent *ke = (QKeyEvent *) e; 1958 if (ke->key() == Qt::Key_Escape && (ke->modifiers() == Qt::NoModifier)) 1959 if (mMainWnd->menuBar()->hasFocus()) 1960 setFocus(); 1961 break; 1962 } 1963 default: 1964 break; 1965 } 1966 } 1967 1968 return QAbstractScrollArea::eventFilter (watched, e); 1969 } 1970 1971 #if defined(Q_WS_WIN32) 1972 1973 /** 1974 * Low-level keyboard event handler, 1975 * @return 1976 * true to indicate that the message is processed and false otherwise 1977 */ 1978 bool VBoxConsoleView::winLowKeyboardEvent (UINT msg, const KBDLLHOOKSTRUCT &event) 1979 { 1980 #if 0 1981 LogFlow (("### vkCode=%08X, scanCode=%08X, flags=%08X, dwExtraInfo=%08X (mKbdCaptured=%d)\n", 1982 event.vkCode, event.scanCode, event.flags, event.dwExtraInfo, mKbdCaptured)); 1983 char buf [256]; 1984 sprintf (buf, "### vkCode=%08X, scanCode=%08X, flags=%08X, dwExtraInfo=%08X", 1985 event.vkCode, event.scanCode, event.flags, event.dwExtraInfo); 1986 mMainWnd->statusBar()->message (buf); 1987 #endif 1988 1989 /* Sometimes it happens that Win inserts additional events on some key 1990 * press/release. For example, it prepends ALT_GR in German layout with 1991 * the VK_LCONTROL vkey with curious 0x21D scan code (seems to be necessary 1992 * to specially treat ALT_GR to enter additional chars to regular apps). 1993 * These events are definitely unwanted in VM, so filter them out. */ 1994 /* Note (michael): it also sometimes sends the VK_CAPITAL vkey with scan 1995 * code 0x23a. If this is not passed through then it is impossible to 1996 * cancel CapsLock on a French keyboard. I didn't find any other examples 1997 * of these strange events. Let's hope we are not missing anything else 1998 * of importance! */ 1999 if (hasFocus() && (event.scanCode & ~0xFF)) 2000 { 2001 if (event.vkCode == VK_CAPITAL) 2002 return false; 2003 else 2004 return true; 2005 } 2006 2007 if (!mKbdCaptured) 2008 return false; 2009 2010 /* it's possible that a key has been pressed while the keyboard was not 2011 * captured, but is being released under the capture. Detect this situation 2012 * and return false to let Windows process the message normally and update 2013 * its key state table (to avoid the stuck key effect). */ 2014 uint8_t what_pressed = (event.flags & 0x01) && (event.vkCode != VK_RSHIFT) 2015 ? IsExtKeyPressed 2016 : IsKeyPressed; 2017 if ((event.flags & 0x80) /* released */ && 2018 ((event.vkCode == gs.hostKey() && !hostkey_in_capture) || 2019 (mPressedKeys [event.scanCode] & (IsKbdCaptured | what_pressed)) == what_pressed)) 2020 return false; 2021 2022 MSG message; 2023 message.hwnd = winId(); 2024 message.message = msg; 2025 message.wParam = event.vkCode; 2026 message.lParam = 2027 1 | 2028 (event.scanCode & 0xFF) << 16 | 2029 (event.flags & 0xFF) << 24; 2030 2031 /* Windows sets here the extended bit when the Right Shift key is pressed, 2032 * which is totally wrong. Undo it. */ 2033 if (event.vkCode == VK_RSHIFT) 2034 message.lParam &= ~0x1000000; 2035 2036 /* we suppose here that this hook is always called on the main GUI thread */ 2037 long dummyResult; 2038 return winEvent (&message, &dummyResult); 2039 } 2040 2041 /** 2042 * Get Win32 messages before they are passed to Qt. This allows us to get 2043 * the keyboard events directly and bypass the harmful Qt translation. A 2044 * return value of @c true indicates to Qt that the event has been handled. 2045 */ 2046 bool VBoxConsoleView::winEvent (MSG *aMsg, long* /* aResult */) 2047 { 2048 if (!mAttached || ! ( 2049 aMsg->message == WM_KEYDOWN || aMsg->message == WM_SYSKEYDOWN || 2050 aMsg->message == WM_KEYUP || aMsg->message == WM_SYSKEYUP 2051 )) 2052 return false; 2053 2054 /* check for the special flag possibly set at the end of this function */ 2055 if (aMsg->lParam & (0x1 << 25)) 2056 { 2057 aMsg->lParam &= ~(0x1 << 25); 2058 return false; 2059 } 2060 2061 #if 0 2062 char buf [256]; 2063 sprintf (buf, "WM_%04X: vk=%04X rep=%05d scan=%02X ext=%01d rzv=%01X ctx=%01d prev=%01d tran=%01d", 2064 aMsg->message, aMsg->wParam, 2065 (aMsg->lParam & 0xFFFF), 2066 ((aMsg->lParam >> 16) & 0xFF), 2067 ((aMsg->lParam >> 24) & 0x1), 2068 ((aMsg->lParam >> 25) & 0xF), 2069 ((aMsg->lParam >> 29) & 0x1), 2070 ((aMsg->lParam >> 30) & 0x1), 2071 ((aMsg->lParam >> 31) & 0x1)); 2072 mMainWnd->statusBar()->message (buf); 2073 LogFlow (("%s\n", buf)); 2074 #endif 2075 2076 int scan = (aMsg->lParam >> 16) & 0x7F; 2077 /* scancodes 0x80 and 0x00 are ignored */ 2078 if (!scan) 2079 return true; 2080 2081 int vkey = aMsg->wParam; 2082 2083 /* When one of the SHIFT keys is held and one of the cursor movement 2084 * keys is pressed, Windows duplicates SHIFT press/release messages, 2085 * but with the virtual key code set to 0xFF. These virtual keys are also 2086 * sent in some other situations (Pause, PrtScn, etc.). Ignore such 2087 * messages. */ 2088 if (vkey == 0xFF) 2089 return true; 2090 2091 int flags = 0; 2092 if (aMsg->lParam & 0x1000000) 2093 flags |= KeyExtended; 2094 if (!(aMsg->lParam & 0x80000000)) 2095 flags |= KeyPressed; 2096 2097 switch (vkey) 2098 { 2099 case VK_SHIFT: 2100 case VK_CONTROL: 2101 case VK_MENU: 2102 { 2103 /* overcome stupid Win32 modifier key generalization */ 2104 int keyscan = scan; 2105 if (flags & KeyExtended) 2106 keyscan |= 0xE000; 2107 switch (keyscan) 2108 { 2109 case 0x002A: vkey = VK_LSHIFT; break; 2110 case 0x0036: vkey = VK_RSHIFT; break; 2111 case 0x001D: vkey = VK_LCONTROL; break; 2112 case 0xE01D: vkey = VK_RCONTROL; break; 2113 case 0x0038: vkey = VK_LMENU; break; 2114 case 0xE038: vkey = VK_RMENU; break; 2115 } 2116 break; 2117 } 2118 case VK_NUMLOCK: 2119 /* Win32 sets the extended bit for the NumLock key. Reset it. */ 2120 flags &= ~KeyExtended; 2121 break; 2122 case VK_SNAPSHOT: 2123 flags |= KeyPrint; 2124 break; 2125 case VK_PAUSE: 2126 flags |= KeyPause; 2127 break; 2128 } 2129 2130 bool result = keyEvent (vkey, scan, flags); 2131 if (!result && mKbdCaptured) 2132 { 2133 /* keyEvent() returned that it didn't process the message, but since the 2134 * keyboard is captured, we don't want to pass it to Windows. We just want 2135 * to let Qt process the message (to handle non-alphanumeric <HOST>+key 2136 * shortcuts for example). So send it direcltly to the window with the 2137 * special flag in the reserved area of lParam (to avoid recursion). */ 2138 ::SendMessage (aMsg->hwnd, aMsg->message, 2139 aMsg->wParam, aMsg->lParam | (0x1 << 25)); 2140 return true; 2141 } 2142 2143 /* These special keys have to be handled by Windows as well to update the 2144 * internal modifier state and to enable/disable the keyboard LED */ 2145 if (vkey == VK_NUMLOCK || vkey == VK_CAPITAL || vkey == VK_LSHIFT || vkey == VK_RSHIFT) 2146 return false; 2147 2148 return result; 2149 } 2150 2151 #elif defined (Q_WS_PM) 2152 2153 /** 2154 * Get PM messages before they are passed to Qt. This allows us to get 2155 * the keyboard events directly and bypass the harmful Qt translation. A 2156 * return value of @c true indicates to Qt that the event has been handled. 2157 */ 2158 bool VBoxConsoleView::pmEvent (QMSG *aMsg) 2159 { 2160 if (!mAttached) 2161 return false; 2162 2163 if (aMsg->msg == UM_PREACCEL_CHAR) 2164 { 2165 /* we are inside the input hook */ 2166 2167 /* let the message go through the normal system pipeline */ 2168 if (!mKbdCaptured) 2169 return false; 2170 } 2171 2172 if (aMsg->msg != WM_CHAR && 2173 aMsg->msg != UM_PREACCEL_CHAR) 2174 return false; 2175 2176 /* check for the special flag possibly set at the end of this function */ 2177 if (SHORT2FROMMP (aMsg->mp2) & 0x8000) 2178 { 2179 aMsg->mp2 = MPFROM2SHORT (SHORT1FROMMP (aMsg->mp2), 2180 SHORT2FROMMP (aMsg->mp2) & ~0x8000); 2181 return false; 2182 } 2183 2184 #if 0 2185 { 2186 char buf [256]; 2187 sprintf (buf, "*** %s: f=%04X rep=%03d scan=%02X ch=%04X vk=%04X", 2188 (aMsg->msg == WM_CHAR ? "WM_CHAR" : "UM_PREACCEL_CHAR"), 2189 SHORT1FROMMP (aMsg->mp1), CHAR3FROMMP (aMsg->mp1), 2190 CHAR4FROMMP (aMsg->mp1), SHORT1FROMMP (aMsg->mp2), 2191 SHORT2FROMMP (aMsg->mp2)); 2192 mMainWnd->statusBar()->message (buf); 2193 LogFlow (("%s\n", buf)); 2194 } 2195 #endif 2196 2197 USHORT ch = SHORT1FROMMP (aMsg->mp2); 2198 USHORT f = SHORT1FROMMP (aMsg->mp1); 2199 2200 int scan = (unsigned int) CHAR4FROMMP (aMsg->mp1); 2201 if (!scan || scan > 0x7F) 2202 return true; 2203 2204 int vkey = QIHotKeyEdit::virtualKey (aMsg); 2205 2206 int flags = 0; 2207 2208 if ((ch & 0xFF) == 0xE0) 2209 { 2210 flags |= KeyExtended; 2211 scan = ch >> 8; 2212 } 2213 else if (scan == 0x5C && (ch & 0xFF) == '/') 2214 { 2215 /* this is the '/' key on the keypad */ 2216 scan = 0x35; 2217 flags |= KeyExtended; 2218 } 2219 else 2220 { 2221 /* For some keys, the scan code passed in QMSG is a pseudo scan 2222 * code. We replace it with a real hardware scan code, according to 2223 * http://www.computer-engineering.org/ps2keyboard/scancodes1.html. 2224 * Also detect Pause and PrtScn and set flags. */ 2225 switch (vkey) 2226 { 2227 case VK_ENTER: scan = 0x1C; flags |= KeyExtended; break; 2228 case VK_CTRL: scan = 0x1D; flags |= KeyExtended; break; 2229 case VK_ALTGRAF: scan = 0x38; flags |= KeyExtended; break; 2230 case VK_LWIN: scan = 0x5B; flags |= KeyExtended; break; 2231 case VK_RWIN: scan = 0x5C; flags |= KeyExtended; break; 2232 case VK_WINMENU: scan = 0x5D; flags |= KeyExtended; break; 2233 case VK_FORWARD: scan = 0x69; flags |= KeyExtended; break; 2234 case VK_BACKWARD: scan = 0x6A; flags |= KeyExtended; break; 2235 #if 0 2236 /// @todo this would send 0xE0 0x46 0xE0 0xC6. It's not fully 2237 // clear what is more correct 2238 case VK_BREAK: scan = 0x46; flags |= KeyExtended; break; 2239 #else 2240 case VK_BREAK: scan = 0; flags |= KeyPause; break; 2241 #endif 2242 case VK_PAUSE: scan = 0; flags |= KeyPause; break; 2243 case VK_PRINTSCRN: scan = 0; flags |= KeyPrint; break; 2244 default:; 2245 } 2246 } 2247 2248 if (!(f & KC_KEYUP)) 2249 flags |= KeyPressed; 2250 2251 bool result = keyEvent (vkey, scan, flags); 2252 if (!result && mKbdCaptured) 2253 { 2254 /* keyEvent() returned that it didn't process the message, but since the 2255 * keyboard is captured, we don't want to pass it to PM. We just want 2256 * to let Qt process the message (to handle non-alphanumeric <HOST>+key 2257 * shortcuts for example). So send it direcltly to the window with the 2258 * special flag in the reserved area of lParam (to avoid recursion). */ 2259 ::WinSendMsg (aMsg->hwnd, WM_CHAR, 2260 aMsg->mp1, 2261 MPFROM2SHORT (SHORT1FROMMP (aMsg->mp2), 2262 SHORT2FROMMP (aMsg->mp2) | 0x8000)); 2263 return true; 2264 } 2265 return result; 2266 } 2267 2268 #elif defined(Q_WS_X11) 2269 2270 /** 2271 * This function is a "predicate" for XCheckIfEvent(). It will check 2272 * the XEvent passed to it to see if it is a keypress event matching 2273 * the keyrelease event in @a pvArg. 2274 * @returns True if the event matches, False otherwise 2275 * @param pEvent the event to compare, taken from the event queue 2276 * @param pvArg the keyrelease event we would like to compare against 2277 */ 2278 static Bool VBoxConsoleViewCompEvent(Display *, XEvent *pEvent, 2279 XPointer pvArg) 2280 { 2281 XEvent *pKeyEvent = (XEvent *) pvArg; 2282 if ((pEvent->type == XKeyPress) && 2283 (pEvent->xkey.keycode == pKeyEvent->xkey.keycode)) 2284 return True; 2285 else 2286 return False; 2287 } 2288 2289 /** 2290 * This routine gets X11 events before they are processed by Qt. This is 2291 * used for our platform specific keyboard implementation. A return value 2292 * of TRUE indicates that the event has been processed by us. 2293 */ 2294 bool VBoxConsoleView::x11Event (XEvent *event) 2295 { 2296 switch (event->type) 2297 { 2298 /* We have to handle XFocusOut right here as this event is not passed 2299 * to VBoxConsoleView::event(). Handling this event is important for 2300 * releasing the keyboard before the screen saver gets active. */ 2301 case XFocusOut: 2302 case XFocusIn: 2303 if (isRunning()) 2304 focusEvent (event->type == XFocusIn); 2305 return false; 2306 case XKeyPress: 2307 case XKeyRelease: 2308 if (mAttached) 2309 break; 2310 /* else fall through */ 2311 default: 2312 return false; /* pass the event to Qt */ 2313 } 2314 2315 /* Translate the keycode to a PC scan code. */ 2316 unsigned scan = handleXKeyEvent (event); 2317 2318 #if 0 2319 char buf [256]; 2320 sprintf (buf, "pr=%d kc=%08X st=%08X extended=%s scan=%04X", 2321 event->type == XKeyPress ? 1 : 0, event->xkey.keycode, 2322 event->xkey.state, scan >> 8 ? "true" : "false", scan & 0x7F); 2323 mMainWnd->statusBar()->message (buf); 2324 LogFlow (("### %s\n", buf)); 2325 #endif 2326 2327 // scancodes 0x00 (no valid translation) and 0x80 are ignored 2328 if (!scan & 0x7F) 2329 return true; 2330 2331 /* Fix for http://www.virtualbox.org/ticket/1296: 2332 * when X11 sends events for repeated keys, it always inserts an 2333 * XKeyRelease before the XKeyPress. */ 2334 XEvent returnEvent; 2335 if ((event->type == XKeyRelease) && 2336 (XCheckIfEvent(event->xkey.display, &returnEvent, 2337 VBoxConsoleViewCompEvent, (XPointer) event) == True)) { 2338 XPutBackEvent(event->xkey.display, &returnEvent); 2339 /* Discard it, don't pass it to Qt. */ 2340 return true; 2341 } 2342 2343 KeySym ks = ::XKeycodeToKeysym (event->xkey.display, event->xkey.keycode, 0); 2344 2345 int flags = 0; 2346 if (scan >> 8) 2347 flags |= KeyExtended; 2348 if (event->type == XKeyPress) 2349 flags |= KeyPressed; 2350 2351 /* Remove the extended flag */ 2352 scan &= 0x7F; 2353 2354 switch (ks) 2355 { 2356 case XK_Print: 2357 flags |= KeyPrint; 2358 break; 2359 case XK_Pause: 2360 if (event->xkey.state & ControlMask) /* Break */ 2361 { 2362 ks = XK_Break; 2363 flags |= KeyExtended; 2364 scan = 0x46; 2365 } 2366 else 2367 flags |= KeyPause; 2368 break; 2369 } 2370 2371 return keyEvent (ks, scan, flags); 2372 } 2373 2374 #elif defined (Q_WS_MAC) 2375 2376 /** 2377 * Invoked by VBoxConsoleView::darwinEventHandlerProc / VBoxConsoleView::macEventFilter when 2378 * it receives a raw keyboard event. 2379 * 2380 * @param pvCocoaEvent The Cocoa keyboard event. Can be NULL in some configs. 2381 * @param inEvent The keyboard event. 2382 * 2383 * @return true if the key was processed, false if it wasn't processed and should be passed on. 2384 */ 2385 bool VBoxConsoleView::darwinKeyboardEvent (const void *pvCocoaEvent, EventRef inEvent) 2386 { 2387 bool ret = false; 2388 UInt32 EventKind = ::GetEventKind (inEvent); 2389 if (EventKind != kEventRawKeyModifiersChanged) 2390 { 2391 /* convert keycode to set 1 scan code. */ 2392 UInt32 keyCode = ~0U; 2393 ::GetEventParameter (inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof (keyCode), NULL, &keyCode); 2394 /* The usb keyboard driver translates these codes to different virtual 2395 * key codes depending of the keyboard type. There are ANSI, ISO, JIS 2396 * and unknown. For European keyboards (ISO) the key 0xa and 0x32 have 2397 * to be switched. Here we are doing this at runtime, cause the user 2398 * can have more than one keyboard (of different type), where he may 2399 * switch at will all the time. Default is the ANSI standard as defined 2400 * in g_aDarwinToSet1. */ 2401 if ( (keyCode == 0xa || keyCode == 0x32) 2402 && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) 2403 keyCode = 0x3c - keyCode; 2404 unsigned scanCode = ::DarwinKeycodeToSet1Scancode (keyCode); 2405 if (scanCode) 2406 { 2407 /* calc flags. */ 2408 int flags = 0; 2409 if (EventKind != kEventRawKeyUp) 2410 flags |= KeyPressed; 2411 if (scanCode & VBOXKEY_EXTENDED) 2412 flags |= KeyExtended; 2413 /** @todo KeyPause, KeyPrint. */ 2414 scanCode &= VBOXKEY_SCANCODE_MASK; 2415 2416 /* get the unicode string (if present). */ 2417 AssertCompileSize (wchar_t, 2); 2418 AssertCompileSize (UniChar, 2); 2419 ByteCount cbWritten = 0; 2420 wchar_t ucs[8]; 2421 if (::GetEventParameter (inEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, 2422 sizeof (ucs), &cbWritten, &ucs[0]) != 0) 2423 cbWritten = 0; 2424 ucs[cbWritten / sizeof(wchar_t)] = 0; /* The api doesn't terminate it. */ 2425 2426 ret = keyEvent (keyCode, scanCode, flags, ucs[0] ? ucs : NULL); 2427 } 2428 } 2429 else 2430 { 2431 /* May contain multiple modifier changes, kind of annoying. */ 2432 UInt32 newMask = 0; 2433 ::GetEventParameter (inEvent, kEventParamKeyModifiers, typeUInt32, NULL, 2434 sizeof (newMask), NULL, &newMask); 2435 newMask = ::DarwinAdjustModifierMask (newMask, pvCocoaEvent); 2436 UInt32 changed = newMask ^ mDarwinKeyModifiers; 2437 if (changed) 2438 { 2439 for (UInt32 bit = 0; bit < 32; bit++) 2440 { 2441 if (!(changed & (1 << bit))) 2442 continue; 2443 unsigned scanCode = ::DarwinModifierMaskToSet1Scancode (1 << bit); 2444 if (!scanCode) 2445 continue; 2446 unsigned keyCode = ::DarwinModifierMaskToDarwinKeycode (1 << bit); 2447 Assert (keyCode); 2448 2449 if (!(scanCode & VBOXKEY_LOCK)) 2450 { 2451 unsigned flags = (newMask & (1 << bit)) ? KeyPressed : 0; 2452 if (scanCode & VBOXKEY_EXTENDED) 2453 flags |= KeyExtended; 2454 scanCode &= VBOXKEY_SCANCODE_MASK; 2455 ret |= keyEvent (keyCode, scanCode & 0xff, flags); 2456 } 2457 else 2458 { 2459 unsigned flags = 0; 2460 if (scanCode & VBOXKEY_EXTENDED) 2461 flags |= KeyExtended; 2462 scanCode &= VBOXKEY_SCANCODE_MASK; 2463 keyEvent (keyCode, scanCode, flags | KeyPressed); 2464 keyEvent (keyCode, scanCode, flags); 2465 } 2466 } 2467 } 2468 2469 mDarwinKeyModifiers = newMask; 2470 2471 /* Always return true here because we'll otherwise getting a Qt event 2472 we don't want and that will only cause the Pause warning to pop up. */ 2473 ret = true; 2474 } 2475 2476 return ret; 2477 } 2478 2479 2480 /** 2481 * Installs or removes the keyboard event handler. 2482 * 2483 * @param fGrab True if we're to grab the events, false if we're not to. 2484 */ 2485 void VBoxConsoleView::darwinGrabKeyboardEvents (bool fGrab) 2486 { 2487 mKeyboardGrabbed = fGrab; 2488 if (fGrab) 2489 { 2490 /* Disable mouse and keyboard event compression/delaying to make sure 2491 we *really* get all of the events. */ 2492 ::CGSetLocalEventsSuppressionInterval (0.0); 2493 setMouseCoalescingEnabled (false); 2494 2495 /* Register the event callback/hook and grab the keyboard. */ 2496 # ifdef QT_MAC_USE_COCOA 2497 ::VBoxCocoaApplication_setCallback (UINT32_MAX, /** @todo fix mask */ 2498 VBoxConsoleView::darwinEventHandlerProc, this); 2499 2500 # elif !defined (VBOX_WITH_HACKED_QT) 2501 EventTypeSpec eventTypes[6]; 2502 eventTypes[0].eventClass = kEventClassKeyboard; 2503 eventTypes[0].eventKind = kEventRawKeyDown; 2504 eventTypes[1].eventClass = kEventClassKeyboard; 2505 eventTypes[1].eventKind = kEventRawKeyUp; 2506 eventTypes[2].eventClass = kEventClassKeyboard; 2507 eventTypes[2].eventKind = kEventRawKeyRepeat; 2508 eventTypes[3].eventClass = kEventClassKeyboard; 2509 eventTypes[3].eventKind = kEventRawKeyModifiersChanged; 2510 /* For ignorning Command-H and Command-Q which aren't affected by the 2511 * global hotkey stuff (doesn't work well): */ 2512 eventTypes[4].eventClass = kEventClassCommand; 2513 eventTypes[4].eventKind = kEventCommandProcess; 2514 eventTypes[5].eventClass = kEventClassCommand; 2515 eventTypes[5].eventKind = kEventCommandUpdateStatus; 2516 2517 EventHandlerUPP eventHandler = ::NewEventHandlerUPP (VBoxConsoleView::darwinEventHandlerProc); 2518 2519 mDarwinEventHandlerRef = NULL; 2520 ::InstallApplicationEventHandler (eventHandler, RT_ELEMENTS (eventTypes), &eventTypes[0], 2521 this, &mDarwinEventHandlerRef); 2522 ::DisposeEventHandlerUPP (eventHandler); 2523 2524 # else /* VBOX_WITH_HACKED_QT */ 2525 ((QIApplication *)qApp)->setEventFilter (VBoxConsoleView::macEventFilter, this); 2526 # endif /* VBOX_WITH_HACKED_QT */ 2527 2528 ::DarwinGrabKeyboard (false); 2529 } 2530 else 2531 { 2532 ::DarwinReleaseKeyboard(); 2533 # ifdef QT_MAC_USE_COCOA 2534 ::VBoxCocoaApplication_unsetCallback (UINT32_MAX, /** @todo fix mask */ 2535 VBoxConsoleView::darwinEventHandlerProc, this); 2536 # elif !defined(VBOX_WITH_HACKED_QT) 2537 if (mDarwinEventHandlerRef) 2538 { 2539 ::RemoveEventHandler (mDarwinEventHandlerRef); 2540 mDarwinEventHandlerRef = NULL; 2541 } 2542 # else /* VBOX_WITH_HACKED_QT */ 2543 ((QIApplication *)qApp)->setEventFilter (NULL, NULL); 2544 # endif /* VBOX_WITH_HACKED_QT */ 2545 } 2546 } 2547 2548 #endif // defined (Q_WS_MAC) 2549 2550 // 2551 // Private members 2552 ///////////////////////////////////////////////////////////////////////////// 2553 2554 /** 2555 * Called on every focus change and also to forcibly capture/uncapture the 2556 * input in situations similar to gaining or losing focus. 2557 * 2558 * @param aHasFocus true if the window got focus and false otherwise. 2559 * @param aReleaseHostKey true to release the host key (used only when 2560 * @a aHasFocus is false. 2561 */ 2562 void VBoxConsoleView::focusEvent (bool aHasFocus, 2563 bool aReleaseHostKey /* = true */) 2564 { 2565 if (aHasFocus) 2566 { 2567 #ifdef RT_OS_WINDOWS 2568 if ( !mDisableAutoCapture && gs.autoCapture() 2569 && GetAncestor (winId(), GA_ROOT) == GetForegroundWindow()) 2570 #else 2571 if (!mDisableAutoCapture && gs.autoCapture()) 2572 #endif /* RT_OS_WINDOWS */ 2573 { 2574 captureKbd (true); 2575 /// @todo (dmik) 2576 // the below is for the mouse auto-capture. disabled for now. in order to 2577 // properly support it, we need to know when *all* mouse buttons are 2578 // released after we got focus, and grab the mouse only after then. 2579 // btw, the similar would be good the for keyboard auto-capture, too. 2580 // if (!(mMouseAbsolute && mMouseIntegration)) 2581 // captureMouse (true); 2582 } 2583 2584 /* reset the single-time disable capture flag */ 2585 if (mDisableAutoCapture) 2586 mDisableAutoCapture = false; 2587 } 2588 else 2589 { 2590 captureMouse (false); 2591 captureKbd (false, false); 2592 releaseAllPressedKeys (aReleaseHostKey); 2593 } 2594 } 2595 2596 /** 2597 * Synchronize the views of the host and the guest to the modifier keys. 2598 * This function will add up to 6 additional keycodes to codes. 2599 * 2600 * @param codes pointer to keycodes which are sent to the keyboard 2601 * @param count pointer to the keycodes counter 2602 */ 2603 void VBoxConsoleView::fixModifierState (LONG *codes, uint *count) 2604 { 2605 #if defined(Q_WS_X11) 2606 2607 Window wDummy1, wDummy2; 2608 int iDummy3, iDummy4, iDummy5, iDummy6; 2609 unsigned uMask; 2610 unsigned uKeyMaskNum = 0, uKeyMaskCaps = 0, uKeyMaskScroll = 0; 2611 2612 uKeyMaskCaps = LockMask; 2613 XModifierKeymap* map = XGetModifierMapping(QX11Info::display()); 2614 KeyCode keyCodeNum = XKeysymToKeycode(QX11Info::display(), XK_Num_Lock); 2615 KeyCode keyCodeScroll = XKeysymToKeycode(QX11Info::display(), XK_Scroll_Lock); 2616 2617 for (int i = 0; i < 8; i++) 2618 { 2619 if ( keyCodeNum != NoSymbol 2620 && map->modifiermap[map->max_keypermod * i] == keyCodeNum) 2621 uKeyMaskNum = 1 << i; 2622 else if ( keyCodeScroll != NoSymbol 2623 && map->modifiermap[map->max_keypermod * i] == keyCodeScroll) 2624 uKeyMaskScroll = 1 << i; 2625 } 2626 XQueryPointer(QX11Info::display(), DefaultRootWindow(QX11Info::display()), &wDummy1, &wDummy2, 2627 &iDummy3, &iDummy4, &iDummy5, &iDummy6, &uMask); 2628 XFreeModifiermap(map); 2629 2630 if (muNumLockAdaptionCnt && (mNumLock ^ !!(uMask & uKeyMaskNum))) 2631 { 2632 muNumLockAdaptionCnt--; 2633 codes[(*count)++] = 0x45; 2634 codes[(*count)++] = 0x45 | 0x80; 2635 } 2636 if (muCapsLockAdaptionCnt && (mCapsLock ^ !!(uMask & uKeyMaskCaps))) 2637 { 2638 muCapsLockAdaptionCnt--; 2639 codes[(*count)++] = 0x3a; 2640 codes[(*count)++] = 0x3a | 0x80; 2641 /* Some keyboard layouts require shift to be pressed to break 2642 * capslock. For simplicity, only do this if shift is not 2643 * already held down. */ 2644 if (mCapsLock && !(mPressedKeys [0x2a] & IsKeyPressed)) 2645 { 2646 codes[(*count)++] = 0x2a; 2647 codes[(*count)++] = 0x2a | 0x80; 2648 } 2649 } 2650 2651 #elif defined(Q_WS_WIN32) 2652 2653 if (muNumLockAdaptionCnt && (mNumLock ^ !!(GetKeyState(VK_NUMLOCK)))) 2654 { 2655 muNumLockAdaptionCnt--; 2656 codes[(*count)++] = 0x45; 2657 codes[(*count)++] = 0x45 | 0x80; 2658 } 2659 if (muCapsLockAdaptionCnt && (mCapsLock ^ !!(GetKeyState(VK_CAPITAL)))) 2660 { 2661 muCapsLockAdaptionCnt--; 2662 codes[(*count)++] = 0x3a; 2663 codes[(*count)++] = 0x3a | 0x80; 2664 /* Some keyboard layouts require shift to be pressed to break 2665 * capslock. For simplicity, only do this if shift is not 2666 * already held down. */ 2667 if (mCapsLock && !(mPressedKeys [0x2a] & IsKeyPressed)) 2668 { 2669 codes[(*count)++] = 0x2a; 2670 codes[(*count)++] = 0x2a | 0x80; 2671 } 2672 } 2673 2674 #elif defined (Q_WS_MAC) 2675 2676 /* if (muNumLockAdaptionCnt) ... - NumLock isn't implemented by Mac OS X so ignore it. */ 2677 if (muCapsLockAdaptionCnt && (mCapsLock ^ !!(::GetCurrentEventKeyModifiers() & alphaLock))) 2678 { 2679 muCapsLockAdaptionCnt--; 2680 codes[(*count)++] = 0x3a; 2681 codes[(*count)++] = 0x3a | 0x80; 2682 /* Some keyboard layouts require shift to be pressed to break 2683 * capslock. For simplicity, only do this if shift is not 2684 * already held down. */ 2685 if (mCapsLock && !(mPressedKeys [0x2a] & IsKeyPressed)) 2686 { 2687 codes[(*count)++] = 0x2a; 2688 codes[(*count)++] = 0x2a | 0x80; 2689 } 2690 } 2691 2692 #else 2693 2694 //#warning Adapt VBoxConsoleView::fixModifierState 2695 2696 #endif 2697 2698 2699 } 2700 2701 /** 2702 * Called on enter/exit seamless/fullscreen mode. 2703 */ 2704 void VBoxConsoleView::toggleFSMode (const QSize &aSize) 2705 { 2706 if ((mGuestSupportsGraphics && mAutoresizeGuest) || 2707 mMainWnd->isTrueSeamless() || 2708 mMainWnd->isTrueFullscreen()) 2709 { 2710 QSize newSize; 2711 if (aSize.isValid()) 2712 { 2713 mNormalSize = aSize; 2714 newSize = maximumSize(); 2715 } 2716 else 2717 newSize = mNormalSize; 2718 doResizeHint (newSize); 2719 } 2720 2721 /* Reactivate the console window to preserve the focus position. 2722 * Else focus will move to the mini-tool-bar. */ 2723 activateWindow(); 2724 } 2725 2726 /** 2727 * Get the current available desktop geometry for the console/framebuffer 2728 * 2729 * @returns the geometry. An empty rectangle means unrestricted. 2730 */ 2731 QRect VBoxConsoleView::desktopGeometry() 2732 { 2733 QRect rc; 2734 switch (mDesktopGeo) 2735 { 2736 case DesktopGeo_Fixed: 2737 case DesktopGeo_Automatic: 2738 rc = QRect (0, 0, 2739 RT_MAX (mDesktopGeometry.width(), mStoredConsoleSize.width()), 2740 RT_MAX (mDesktopGeometry.height(), mStoredConsoleSize.height())); 2741 break; 2742 case DesktopGeo_Any: 2743 rc = QRect (0, 0, 0, 0); 2744 break; 2745 default: 2746 AssertMsgFailed (("Bad geometry type %d\n", mDesktopGeo)); 2747 } 2748 return rc; 2749 } 2750 2751 QRegion VBoxConsoleView::lastVisibleRegion() const 2752 { 2753 return mLastVisibleRegion; 2754 } 2755 2756 bool VBoxConsoleView::isAutoresizeGuestActive() 2757 { 2758 return mGuestSupportsGraphics && mAutoresizeGuest; 2759 } 2760 2761 /** 2762 * Called on every key press and release (while in focus). 2763 * 2764 * @param aKey virtual scan code (virtual key on Win32 and KeySym on X11) 2765 * @param aScan hardware scan code 2766 * @param aFlags flags, a combination of Key* constants 2767 * @param aUniKey Unicode translation of the key. Optional. 2768 * 2769 * @return true to consume the event and false to pass it to Qt 2770 */ 2771 bool VBoxConsoleView::keyEvent (int aKey, uint8_t aScan, int aFlags, 2772 wchar_t *aUniKey/* = NULL*/) 2773 { 2774 #if 0 2775 { 2776 char buf [256]; 2777 sprintf (buf, "aKey=%08X aScan=%02X aFlags=%08X", 2778 aKey, aScan, aFlags); 2779 mMainWnd->statusBar()->message (buf); 2780 } 2781 #endif 2782 2783 const bool isHostKey = aKey == gs.hostKey(); 2784 2785 LONG buf [16]; 2786 LONG *codes = buf; 2787 uint count = 0; 2788 uint8_t whatPressed = 0; 2789 2790 if (!isHostKey && !mIsHostkeyPressed) 2791 { 2792 if (aFlags & KeyPrint) 2793 { 2794 static LONG PrintMake[] = { 0xE0, 0x2A, 0xE0, 0x37 }; 2795 static LONG PrintBreak[] = { 0xE0, 0xB7, 0xE0, 0xAA }; 2796 if (aFlags & KeyPressed) 2797 { 2798 codes = PrintMake; 2799 count = SIZEOF_ARRAY (PrintMake); 2800 } 2801 else 2802 { 2803 codes = PrintBreak; 2804 count = SIZEOF_ARRAY (PrintBreak); 2805 } 2806 } 2807 else if (aFlags & KeyPause) 2808 { 2809 if (aFlags & KeyPressed) 2810 { 2811 static LONG Pause[] = { 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 }; 2812 codes = Pause; 2813 count = SIZEOF_ARRAY (Pause); 2814 } 2815 else 2816 { 2817 /* Pause shall not produce a break code */ 2818 return true; 2819 } 2820 } 2821 else 2822 { 2823 if (aFlags & KeyPressed) 2824 { 2825 /* Check if the guest has the same view on the modifier keys (NumLock, 2826 * CapsLock, ScrollLock) as the X server. If not, send KeyPress events 2827 * to synchronize the state. */ 2828 fixModifierState (codes, &count); 2829 } 2830 2831 /* Check if it's C-A-D and GUI/PassCAD is not true */ 2832 if (!mPassCAD && 2833 aScan == 0x53 /* Del */ && 2834 ((mPressedKeys [0x38] & IsKeyPressed) /* Alt */ || 2835 (mPressedKeys [0x38] & IsExtKeyPressed)) && 2836 ((mPressedKeys [0x1d] & IsKeyPressed) /* Ctrl */ || 2837 (mPressedKeys [0x1d] & IsExtKeyPressed))) 2838 { 2839 /* Use the C-A-D combination as a last resort to get the 2840 * keyboard and mouse back to the host when the user forgets 2841 * the Host Key. Note that it's always possible to send C-A-D 2842 * to the guest using the Host+Del combination. BTW, it would 2843 * be preferrable to completely ignore C-A-D in guests, but 2844 * that's not possible because we cannot predict what other 2845 * keys will be pressed next when one of C, A, D is held. */ 2846 2847 if (isRunning() && mKbdCaptured) 2848 { 2849 captureKbd (false); 2850 if (!(mMouseAbsolute && mMouseIntegration)) 2851 captureMouse (false); 2852 } 2853 2854 return true; 2855 } 2856 2857 /* process the scancode and update the table of pressed keys */ 2858 whatPressed = IsKeyPressed; 2859 2860 if (aFlags & KeyExtended) 2861 { 2862 codes [count++] = 0xE0; 2863 whatPressed = IsExtKeyPressed; 2864 } 2865 2866 if (aFlags & KeyPressed) 2867 { 2868 codes [count++] = aScan; 2869 mPressedKeys [aScan] |= whatPressed; 2870 } 2871 else 2872 { 2873 /* if we haven't got this key's press message, we ignore its 2874 * release */ 2875 if (!(mPressedKeys [aScan] & whatPressed)) 2876 return true; 2877 codes [count++] = aScan | 0x80; 2878 mPressedKeys [aScan] &= ~whatPressed; 2879 } 2880 2881 if (mKbdCaptured) 2882 mPressedKeys [aScan] |= IsKbdCaptured; 2883 else 2884 mPressedKeys [aScan] &= ~IsKbdCaptured; 2885 } 2886 } 2887 else 2888 { 2889 /* currently this is used in winLowKeyboardEvent() only */ 2890 hostkey_in_capture = mKbdCaptured; 2891 } 2892 2893 bool emitSignal = false; 2894 int hotkey = 0; 2895 2896 /* process the host key */ 2897 if (aFlags & KeyPressed) 2898 { 2899 if (isHostKey) 2900 { 2901 if (!mIsHostkeyPressed) 2902 { 2903 mIsHostkeyPressed = mIsHostkeyAlone = true; 2904 if (isRunning()) 2905 saveKeyStates(); 2906 emitSignal = true; 2907 } 2908 } 2909 else 2910 { 2911 if (mIsHostkeyPressed) 2912 { 2913 if (mIsHostkeyAlone) 2914 { 2915 hotkey = aKey; 2916 mIsHostkeyAlone = false; 2917 } 2918 } 2919 } 2920 } 2921 else 2922 { 2923 if (isHostKey) 2924 { 2925 if (mIsHostkeyPressed) 2926 { 2927 mIsHostkeyPressed = false; 2928 2929 if (mIsHostkeyAlone) 2930 { 2931 if (isPaused()) 2932 { 2933 vboxProblem().remindAboutPausedVMInput(); 2934 } 2935 else 2936 if (isRunning()) 2937 { 2938 bool captured = mKbdCaptured; 2939 bool ok = true; 2940 if (!captured) 2941 { 2942 /* temporarily disable auto capture that will take 2943 * place after this dialog is dismissed because 2944 * the capture state is to be defined by the 2945 * dialog result itself */ 2946 mDisableAutoCapture = true; 2947 bool autoConfirmed = false; 2948 ok = vboxProblem().confirmInputCapture (&autoConfirmed); 2949 if (autoConfirmed) 2950 mDisableAutoCapture = false; 2951 /* otherwise, the disable flag will be reset in 2952 * the next console view's foucs in event (since 2953 * may happen asynchronously on some platforms, 2954 * after we return from this code) */ 2955 } 2956 2957 if (ok) 2958 { 2959 captureKbd (!captured, false); 2960 if (!(mMouseAbsolute && mMouseIntegration)) 2961 { 2962 #ifdef Q_WS_X11 2963 /* make sure that pending FocusOut events from the 2964 * previous message box are handled, otherwise the 2965 * mouse is immediately ungrabbed. */ 2966 qApp->processEvents(); 2967 #endif 2968 captureMouse (mKbdCaptured); 2969 } 2970 } 2971 } 2972 } 2973 2974 if (isRunning()) 2975 sendChangedKeyStates(); 2976 2977 emitSignal = true; 2978 } 2979 } 2980 else 2981 { 2982 if (mIsHostkeyPressed) 2983 mIsHostkeyAlone = false; 2984 } 2985 } 2986 2987 /* emit the keyboard state change signal */ 2988 if (emitSignal) 2989 emitKeyboardStateChanged(); 2990 2991 /* Process Host+<key> shortcuts. currently, <key> is limited to 2992 * alphanumeric chars. Other Host+<key> combinations are handled in 2993 * event(). */ 2994 if (hotkey) 2995 { 2996 bool processed = false; 2997 #if defined (Q_WS_WIN32) 2998 NOREF(aUniKey); 2999 int n = GetKeyboardLayoutList (0, NULL); 3000 Assert (n); 3001 HKL *list = new HKL [n]; 3002 GetKeyboardLayoutList (n, list); 3003 for (int i = 0; i < n && !processed; i++) 3004 { 3005 wchar_t ch; 3006 static BYTE keys [256] = {0}; 3007 if (!ToUnicodeEx (hotkey, 0, keys, &ch, 1, 0, list [i]) == 1) 3008 ch = 0; 3009 if (ch) 3010 processed = processHotKey (QKeySequence (Qt::UNICODE_ACCEL + 3011 QChar (ch).toUpper().unicode()), 3012 mMainWnd->menuBar()->actions()); 3013 } 3014 delete[] list; 3015 #elif defined (Q_WS_X11) 3016 NOREF(aUniKey); 3017 Display *display = QX11Info::display(); 3018 int keysyms_per_keycode = getKeysymsPerKeycode(); 3019 KeyCode kc = XKeysymToKeycode (display, aKey); 3020 // iterate over the first level (not shifted) keysyms in every group 3021 for (int i = 0; i < keysyms_per_keycode && !processed; i += 2) 3022 { 3023 KeySym ks = XKeycodeToKeysym (display, kc, i); 3024 char ch = 0; 3025 if (!XkbTranslateKeySym (display, &ks, 0, &ch, 1, NULL) == 1) 3026 ch = 0; 3027 if (ch) 3028 { 3029 QChar c = QString::fromLocal8Bit (&ch, 1) [0]; 3030 processed = processHotKey (QKeySequence (Qt::UNICODE_ACCEL + 3031 c.toUpper().unicode()), 3032 mMainWnd->menuBar()->actions()); 3033 } 3034 } 3035 #elif defined (Q_WS_MAC) 3036 if (aUniKey && aUniKey [0] && !aUniKey [1]) 3037 processed = processHotKey (QKeySequence (Qt::UNICODE_ACCEL + 3038 QChar (aUniKey [0]).toUpper().unicode()), 3039 mMainWnd->menuBar()->actions()); 3040 3041 /* Don't consider the hot key as pressed since the guest never saw 3042 * it. (probably a generic thing) */ 3043 mPressedKeys [aScan] &= ~whatPressed; 3044 #endif 3045 3046 /* grab the key from Qt if processed, or pass it to Qt otherwise 3047 * in order to process non-alphanumeric keys in event(), after they are 3048 * converted to Qt virtual keys. */ 3049 return processed; 3050 } 3051 3052 /* no more to do, if the host key is in action or the VM is paused */ 3053 if (mIsHostkeyPressed || isHostKey || isPaused()) 3054 { 3055 /* grab the key from Qt and from VM if it's a host key, 3056 * otherwise just pass it to Qt */ 3057 return isHostKey; 3058 } 3059 3060 CKeyboard keyboard = mConsole.GetKeyboard(); 3061 Assert (!keyboard.isNull()); 3062 3063 #if defined (Q_WS_WIN32) 3064 /* send pending WM_PAINT events */ 3065 ::UpdateWindow (viewport()->winId()); 3066 #endif 3067 3068 #if 0 3069 { 3070 char buf [256]; 3071 sprintf (buf, "*** SCANS: "); 3072 for (uint i = 0; i < count; ++ i) 3073 sprintf (buf + strlen (buf), "%02X ", codes [i]); 3074 mMainWnd->statusBar()->message (buf); 3075 LogFlow (("%s\n", buf)); 3076 } 3077 #endif 3078 3079 std::vector <LONG> scancodes(codes, &codes[count]); 3080 keyboard.PutScancodes (QVector<LONG>::fromStdVector(scancodes)); 3081 3082 /* grab the key from Qt */ 3083 return true; 3084 } 3085 3086 /** 3087 * Called on every mouse/wheel move and button press/release. 3088 * 3089 * @return true to consume the event and false to pass it to Qt 3090 */ 3091 bool VBoxConsoleView::mouseEvent (int aType, const QPoint &aPos, const QPoint &aGlobalPos, 3092 Qt::MouseButtons aButtons, Qt::KeyboardModifiers aModifiers, 3093 int aWheelDelta, Qt::Orientation aWheelDir) 3094 { 3095 #if 1 3096 3097 LogRel3(("%s: type=%03d x=%03d y=%03d btns=%08X wdelta=%03d wdir=%s\n", 3098 __PRETTY_FUNCTION__ , aType, aPos.x(), aPos.y(), 3099 (aButtons & Qt::LeftButton ? 1 : 0) 3100 | (aButtons & Qt::RightButton ? 2 : 0) 3101 | (aButtons & Qt::MidButton ? 4 : 0) 3102 | (aButtons & Qt::XButton1 ? 8 : 0) 3103 | (aButtons & Qt::XButton2 ? 16 : 0), 3104 aWheelDelta, 3105 aWheelDir == Qt::Horizontal ? "Horizontal" 3106 : aWheelDir == Qt::Vertical ? "Vertical" : "Unknown")); 3107 Q_UNUSED (aModifiers); 3108 #else 3109 Q_UNUSED (aModifiers); 3110 #endif 3111 3112 int state = 0; 3113 if (aButtons & Qt::LeftButton) 3114 state |= KMouseButtonState_LeftButton; 3115 if (aButtons & Qt::RightButton) 3116 state |= KMouseButtonState_RightButton; 3117 if (aButtons & Qt::MidButton) 3118 state |= KMouseButtonState_MiddleButton; 3119 if (aButtons & Qt::XButton1) 3120 state |= KMouseButtonState_XButton1; 3121 if (aButtons & Qt::XButton2) 3122 state |= KMouseButtonState_XButton2; 3123 3124 #ifdef Q_WS_MAC 3125 /* Simulate the right click on 3126 * Host+Left Mouse */ 3127 if (mIsHostkeyPressed && 3128 mIsHostkeyAlone && 3129 state == KMouseButtonState_LeftButton) 3130 state = KMouseButtonState_RightButton; 3131 #endif /* Q_WS_MAC */ 3132 3133 int wheelVertical = 0; 3134 int wheelHorizontal = 0; 3135 if (aWheelDir == Qt::Vertical) 3136 { 3137 /* the absolute value of wheel delta is 120 units per every wheel 3138 * move; positive deltas correspond to counterclockwize rotations 3139 * (usually up), negative -- to clockwize (usually down). */ 3140 wheelVertical = - (aWheelDelta / 120); 3141 } 3142 else if (aWheelDir == Qt::Horizontal) 3143 wheelHorizontal = aWheelDelta / 120; 3144 3145 if (mMouseCaptured) 3146 { 3147 #ifdef Q_WS_WIN32 3148 /* send pending WM_PAINT events */ 3149 ::UpdateWindow (viewport()->winId()); 3150 #endif 3151 3152 CMouse mouse = mConsole.GetMouse(); 3153 mouse.PutMouseEvent (aGlobalPos.x() - mLastPos.x(), 3154 aGlobalPos.y() - mLastPos.y(), 3155 wheelVertical, wheelHorizontal, state); 3156 3157 #if defined (Q_WS_MAC) 3158 /* 3159 * Keep the mouse from leaving the widget. 3160 * 3161 * This is a bit tricky to get right because if it escapes we won't necessarily 3162 * get mouse events any longer and can warp it back. So, we keep safety zone 3163 * of up to 300 pixels around the borders of the widget to prevent this from 3164 * happening. Also, the mouse is warped back to the center of the widget. 3165 * 3166 * (Note, aPos seems to be unreliable, it caused endless recursion here at one points...) 3167 * (Note, synergy and other remote clients might not like this cursor warping.) 3168 */ 3169 QRect rect = viewport()->visibleRegion().boundingRect(); 3170 QPoint pw = viewport()->mapToGlobal (viewport()->pos()); 3171 rect.translate (pw.x(), pw.y()); 3172 3173 QRect dpRect = QApplication::desktop()->screenGeometry (viewport()); 3174 if (rect.intersects (dpRect)) 3175 rect = rect.intersect (dpRect); 3176 3177 int wsafe = rect.width() / 6; 3178 rect.setWidth (rect.width() - wsafe * 2); 3179 rect.setLeft (rect.left() + wsafe); 3180 3181 int hsafe = rect.height() / 6; 3182 rect.setWidth (rect.height() - hsafe * 2); 3183 rect.setTop (rect.top() + hsafe); 3184 3185 if (rect.contains (aGlobalPos, true)) 3186 mLastPos = aGlobalPos; 3187 else 3188 { 3189 mLastPos = rect.center(); 3190 QCursor::setPos (mLastPos); 3191 } 3192 3193 #else /* !Q_WS_MAC */ 3194 3195 /* "jerk" the mouse by bringing it to the opposite side 3196 * to simulate the endless moving */ 3197 3198 #ifdef Q_WS_WIN32 3199 int we = viewport()->width() - 1; 3200 int he = viewport()->height() - 1; 3201 QPoint p = aPos; 3202 if (aPos.x() == 0) 3203 p.setX (we - 1); 3204 else if (aPos.x() == we) 3205 p.setX (1); 3206 if (aPos.y() == 0 ) 3207 p.setY (he - 1); 3208 else if (aPos.y() == he) 3209 p.setY (1); 3210 3211 if (p != aPos) 3212 { 3213 mLastPos = viewport()->mapToGlobal (p); 3214 QCursor::setPos (mLastPos); 3215 } 3216 else 3217 { 3218 mLastPos = aGlobalPos; 3219 } 3220 #else 3221 int we = QApplication::desktop()->width() - 1; 3222 int he = QApplication::desktop()->height() - 1; 3223 QPoint p = aGlobalPos; 3224 if (aGlobalPos.x() == 0) 3225 p.setX (we - 1); 3226 else if (aGlobalPos.x() == we) 3227 p.setX( 1 ); 3228 if (aGlobalPos.y() == 0) 3229 p.setY (he - 1); 3230 else if (aGlobalPos.y() == he) 3231 p.setY (1); 3232 3233 if (p != aGlobalPos) 3234 { 3235 mLastPos = p; 3236 QCursor::setPos (mLastPos); 3237 } 3238 else 3239 { 3240 mLastPos = aGlobalPos; 3241 } 3242 #endif 3243 #endif /* !Q_WS_MAC */ 3244 return true; /* stop further event handling */ 3245 } 3246 else /* !mMouseCaptured */ 3247 { 3248 if (mMainWnd->isTrueFullscreen()) 3249 { 3250 if (mode != VBoxDefs::SDLMode) 3251 { 3252 /* try to automatically scroll the guest canvas if the 3253 * mouse is on the screen border */ 3254 /// @todo (r=dmik) better use a timer for autoscroll 3255 QRect scrGeo = QApplication::desktop()->screenGeometry (this); 3256 int dx = 0, dy = 0; 3257 if (scrGeo.width() < contentsWidth()) 3258 { 3259 if (scrGeo.left() == aGlobalPos.x()) dx = -1; 3260 if (scrGeo.right() == aGlobalPos.x()) dx = +1; 3261 } 3262 if (scrGeo.height() < contentsHeight()) 3263 { 3264 if (scrGeo.top() == aGlobalPos.y()) dy = -1; 3265 if (scrGeo.bottom() == aGlobalPos.y()) dy = +1; 3266 } 3267 if (dx || dy) 3268 scrollBy (dx, dy); 3269 } 3270 } 3271 3272 if (mMouseAbsolute && mMouseIntegration) 3273 { 3274 int cw = contentsWidth(), ch = contentsHeight(); 3275 int vw = visibleWidth(), vh = visibleHeight(); 3276 3277 if (mode != VBoxDefs::SDLMode) 3278 { 3279 /* try to automatically scroll the guest canvas if the 3280 * mouse goes outside its visible part */ 3281 3282 int dx = 0; 3283 if (aPos.x() > vw) dx = aPos.x() - vw; 3284 else if (aPos.x() < 0) dx = aPos.x(); 3285 int dy = 0; 3286 if (aPos.y() > vh) dy = aPos.y() - vh; 3287 else if (aPos.y() < 0) dy = aPos.y(); 3288 if (dx != 0 || dy != 0) scrollBy (dx, dy); 3289 } 3290 3291 QPoint cpnt = viewportToContents (aPos); 3292 if (cpnt.x() < 0) cpnt.setX (0); 3293 else if (cpnt.x() > cw) cpnt.setX (cw); 3294 if (cpnt.y() < 0) cpnt.setY (0); 3295 else if (cpnt.y() > ch) cpnt.setY (ch); 3296 3297 CMouse mouse = mConsole.GetMouse(); 3298 mouse.PutMouseEventAbsolute (cpnt.x(), cpnt.y(), wheelVertical, 3299 wheelHorizontal, state); 3300 return true; /* stop further event handling */ 3301 } 3302 else 3303 { 3304 if (hasFocus() && 3305 (aType == QEvent::MouseButtonRelease && 3306 aButtons == Qt::NoButton)) 3307 { 3308 if (isPaused()) 3309 { 3310 vboxProblem().remindAboutPausedVMInput(); 3311 } 3312 else if (isRunning()) 3313 { 3314 /* temporarily disable auto capture that will take 3315 * place after this dialog is dismissed because 3316 * the capture state is to be defined by the 3317 * dialog result itself */ 3318 mDisableAutoCapture = true; 3319 bool autoConfirmed = false; 3320 bool ok = vboxProblem().confirmInputCapture (&autoConfirmed); 3321 if (autoConfirmed) 3322 mDisableAutoCapture = false; 3323 /* otherwise, the disable flag will be reset in 3324 * the next console view's foucs in event (since 3325 * may happen asynchronously on some platforms, 3326 * after we return from this code) */ 3327 3328 if (ok) 3329 { 3330 #ifdef Q_WS_X11 3331 /* make sure that pending FocusOut events from the 3332 * previous message box are handled, otherwise the 3333 * mouse is immediately ungrabbed again */ 3334 qApp->processEvents(); 3335 #endif 3336 captureKbd (true); 3337 captureMouse (true); 3338 } 3339 } 3340 } 3341 } 3342 } 3343 3344 return false; 3345 } 3346 3347 void VBoxConsoleView::onStateChange (KMachineState state) 3348 { 3349 switch (state) 3350 { 3351 case KMachineState_Paused: 3352 case KMachineState_TeleportingPausedVM: 3353 { 3354 if ( mode != VBoxDefs::TimerMode 3355 && mFrameBuf 3356 && ( state != KMachineState_TeleportingPausedVM 3357 || mLastState != KMachineState_Teleporting) 3358 ) 3359 { 3360 /* 3361 * Take a screen snapshot. Note that TakeScreenShot() always 3362 * needs a 32bpp image 3363 */ 3364 QImage shot = QImage (mFrameBuf->width(), mFrameBuf->height(), QImage::Format_RGB32); 3365 CDisplay dsp = mConsole.GetDisplay(); 3366 dsp.TakeScreenShot (shot.bits(), shot.width(), shot.height()); 3367 /* 3368 * TakeScreenShot() may fail if, e.g. the Paused notification 3369 * was delivered after the machine execution was resumed. It's 3370 * not fatal. 3371 */ 3372 if (dsp.isOk()) 3373 { 3374 dimImage (shot); 3375 mPausedShot = QPixmap::fromImage (shot); 3376 /* fully repaint to pick up mPausedShot */ 3377 repaint(); 3378 } 3379 } 3380 /* fall through */ 3381 } 3382 case KMachineState_Stuck: 3383 { 3384 /* reuse the focus event handler to uncapture everything */ 3385 if (hasFocus()) 3386 focusEvent (false /* aHasFocus*/, false /* aReleaseHostKey */); 3387 break; 3388 } 3389 case KMachineState_Running: 3390 { 3391 if ( mLastState == KMachineState_Paused 3392 || mLastState == KMachineState_TeleportingPausedVM 3393 ) 3394 { 3395 if (mode != VBoxDefs::TimerMode && mFrameBuf) 3396 { 3397 /* reset the pixmap to free memory */ 3398 mPausedShot = QPixmap (); 3399 /* 3400 * ask for full guest display update (it will also update 3401 * the viewport through IFramebuffer::NotifyUpdate) 3402 */ 3403 CDisplay dsp = mConsole.GetDisplay(); 3404 dsp.InvalidateAndUpdate(); 3405 } 3406 } 3407 /* reuse the focus event handler to capture input */ 3408 if (hasFocus()) 3409 focusEvent (true /* aHasFocus */); 3410 break; 3411 } 3412 default: 3413 break; 3414 } 3415 3416 mLastState = state; 3417 } 3418 3419 void VBoxConsoleView::doRefresh() 3420 { 3421 viewport()->repaint(); 3422 } 3423 3424 void VBoxConsoleView::resizeEvent (QResizeEvent *) 3425 { 3426 updateSliders(); 3427 #if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA) 3428 QRect r = viewport()->geometry(); 3429 // printf ("qt resize: %d %d %d %d\n", r.x(), r.y(), r.width(), r.height()); 3430 PostBoundsChanged (r); 3431 #endif /* Q_WS_MAC */ 3432 } 3433 3434 void VBoxConsoleView::moveEvent (QMoveEvent *) 3435 { 3436 #if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA) 3437 QRect r = viewport()->geometry(); 3438 // printf ("qt resize: %d %d %d %d\n", r.x(), r.y(), r.width(), r.height()); 3439 PostBoundsChanged (r); 3440 #endif /* Q_WS_MAC */ 3441 } 3442 3443 void VBoxConsoleView::paintEvent (QPaintEvent *pe) 3444 { 3445 if (mPausedShot.isNull()) 3446 { 3447 /* delegate the paint function to the VBoxFrameBuffer interface */ 3448 if (mFrameBuf) 3449 mFrameBuf->paintEvent (pe); 3450 #ifdef Q_WS_MAC 3451 /* Update the dock icon if we are in the running state */ 3452 if (isRunning()) 3453 updateDockIcon(); 3454 #endif 3455 return; 3456 } 3457 3458 #ifdef VBOX_GUI_USE_QUARTZ2D 3459 if (mode == VBoxDefs::Quartz2DMode && mFrameBuf) 3460 { 3461 mFrameBuf->paintEvent (pe); 3462 updateDockIcon(); 3463 } 3464 else 3465 #endif 3466 { 3467 /* we have a snapshot for the paused state */ 3468 QRect r = pe->rect().intersect (viewport()->rect()); 3469 /* We have to disable paint on screen if we are using the regular painter */ 3470 bool paintOnScreen = viewport()->testAttribute (Qt::WA_PaintOnScreen); 3471 viewport()->setAttribute (Qt::WA_PaintOnScreen, false); 3472 QPainter pnt (viewport()); 3473 pnt.drawPixmap (r.x(), r.y(), mPausedShot, 3474 r.x() + contentsX(), r.y() + contentsY(), 3475 r.width(), r.height()); 3476 /* Restore the attribute to its previous state */ 3477 viewport()->setAttribute (Qt::WA_PaintOnScreen, paintOnScreen); 3478 #ifdef Q_WS_MAC 3479 updateDockIcon(); 3480 #endif 3481 } 3482 3483 } 3484 3485 /** 3486 * Captures the keyboard. When captured, no keyboard input reaches the host 3487 * system (including most system combinations like Alt-Tab). 3488 * 3489 * @param aCapture true to capture, false to uncapture. 3490 * @param aEmitSignal Whether to emit keyboardStateChanged() or not. 3491 */ 3492 void VBoxConsoleView::captureKbd (bool aCapture, bool aEmitSignal /* = true */) 3493 { 3494 AssertMsg (mAttached, ("Console must be attached")); 3495 3496 if (mKbdCaptured == aCapture) 3497 return; 3498 3499 /* On Win32, keyboard grabbing is ineffective, a low-level keyboard hook is 3500 * used instead. On X11, we use XGrabKey instead of XGrabKeyboard (called 3501 * by QWidget::grabKeyboard()) because the latter causes problems under 3502 * metacity 2.16 (in particular, due to a bug, a window cannot be moved 3503 * using the mouse if it is currently grabing the keyboard). On Mac OS X, 3504 * we use the Qt methods + disabling global hot keys + watching modifiers 3505 * (for right/left separation). */ 3506 #if defined (Q_WS_WIN32) 3507 /**/ 3508 #elif defined (Q_WS_X11) 3509 if (aCapture) 3510 XGrabKey (QX11Info::display(), AnyKey, AnyModifier, 3511 window()->winId(), False, 3512 GrabModeAsync, GrabModeAsync); 3513 else 3514 XUngrabKey (QX11Info::display(), AnyKey, AnyModifier, 3515 window()->winId()); 3516 #elif defined (Q_WS_MAC) 3517 if (aCapture) 3518 { 3519 ::DarwinDisableGlobalHotKeys (true); 3520 grabKeyboard(); 3521 } 3522 else 3523 { 3524 ::DarwinDisableGlobalHotKeys (false); 3525 releaseKeyboard(); 3526 } 3527 #else 3528 if (aCapture) 3529 grabKeyboard(); 3530 else 3531 releaseKeyboard(); 3532 #endif 3533 3534 mKbdCaptured = aCapture; 3535 3536 if (aEmitSignal) 3537 emitKeyboardStateChanged(); 3538 } 3539 3540 /** 3541 * Captures the host mouse pointer. When captured, the mouse pointer is 3542 * unavailable to the host applications. 3543 * 3544 * @param aCapture true to capture, false to uncapture. 3545 * @param aEmitSignal Whether to emit mouseStateChanged() or not. 3546 */ 3547 void VBoxConsoleView::captureMouse (bool aCapture, bool aEmitSignal /* = true */) 3548 { 3549 AssertMsg (mAttached, ("Console must be attached")); 3550 3551 if (mMouseCaptured == aCapture) 3552 return; 3553 3554 if (aCapture) 3555 { 3556 /* memorize the host position where the cursor was captured */ 3557 mCapturedPos = QCursor::pos(); 3558 #ifdef Q_WS_WIN32 3559 viewport()->setCursor (QCursor (Qt::BlankCursor)); 3560 /* move the mouse to the center of the visible area */ 3561 QCursor::setPos (mapToGlobal (visibleRegion().boundingRect().center())); 3562 mLastPos = QCursor::pos(); 3563 #elif defined (Q_WS_MAC) 3564 /* move the mouse to the center of the visible area */ 3565 mLastPos = mapToGlobal (visibleRegion().boundingRect().center()); 3566 QCursor::setPos (mLastPos); 3567 /* grab all mouse events. */ 3568 viewport()->grabMouse(); 3569 #else 3570 viewport()->grabMouse(); 3571 mLastPos = QCursor::pos(); 3572 #endif 3573 } 3574 else 3575 { 3576 #ifndef Q_WS_WIN32 3577 viewport()->releaseMouse(); 3578 #endif 3579 /* release mouse buttons */ 3580 CMouse mouse = mConsole.GetMouse(); 3581 mouse.PutMouseEvent (0, 0, 0, 0 /* Horizontal wheel */, 0); 3582 } 3583 3584 mMouseCaptured = aCapture; 3585 3586 updateMouseClipping(); 3587 3588 if (aEmitSignal) 3589 emitMouseStateChanged(); 3590 } 3591 3592 /** 3593 * Searches for a menu item with a given hot key (shortcut). If the item 3594 * is found, activates it and returns true. Otherwise returns false. 3595 */ 3596 bool VBoxConsoleView::processHotKey (const QKeySequence &aKey, 3597 const QList <QAction*> &aData) 3598 { 3599 foreach (QAction *pAction, aData) 3600 { 3601 if (QMenu *menu = pAction->menu()) 3602 { 3603 /* Process recursively for each sub-menu */ 3604 if (processHotKey (aKey, menu->actions())) 3605 return true; 3606 } 3607 else 3608 { 3609 QString hotkey = VBoxGlobal::extractKeyFromActionText (pAction->text()); 3610 if (pAction->isEnabled() && !hotkey.isEmpty()) 3611 { 3612 if (aKey.matches (QKeySequence (hotkey)) == QKeySequence::ExactMatch) 3613 { 3614 /* We asynchronously post a special event instead of calling 3615 * pAction->trigger() directly, to let key presses and 3616 * releases be processed correctly by Qt first. 3617 * Note: we assume that nobody will delete the menu item 3618 * corresponding to the key sequence, so that the pointer to 3619 * menu data posted along with the event will remain valid in 3620 * the event handler, at least until the main window is closed. */ 3621 QApplication::postEvent (this, new ActivateMenuEvent (pAction)); 3622 return true; 3623 } 3624 } 3625 } 3626 } 3627 3628 return false; 3629 } 3630 3631 /** 3632 * Send the KEY BREAK code to the VM for all currently pressed keys. 3633 * 3634 * @param aReleaseHostKey @c true to set the host key state to unpressed. 3635 */ 3636 void VBoxConsoleView::releaseAllPressedKeys (bool aReleaseHostKey /* = true*/) 3637 { 3638 AssertMsg (mAttached, ("Console must be attached")); 3639 3640 CKeyboard keyboard = mConsole.GetKeyboard(); 3641 bool fSentRESEND = false; 3642 3643 /* send a dummy scan code (RESEND) to prevent the guest OS from recognizing 3644 * a single key click (for ex., Alt) and performing an unwanted action 3645 * (for ex., activating the menu) when we release all pressed keys below. 3646 * Note, that it's just a guess that sending RESEND will give the desired 3647 * effect :), but at least it works with NT and W2k guests. */ 3648 3649 /// @todo Sending 0xFE is responsible for the warning 3650 // 3651 // ``atkbd.c: Spurious NAK on isa0060/serio0. Some program might 3652 // be trying access hardware directly'' 3653 // 3654 // on Linux guests (#1944). It might also be responsible for #1949. Don't 3655 // send this command unless we really have to release any key modifier. 3656 // --frank 3657 3658 for (uint i = 0; i < SIZEOF_ARRAY (mPressedKeys); i++) 3659 { 3660 if (mPressedKeys [i] & IsKeyPressed) 3661 { 3662 if (!fSentRESEND) 3663 { 3664 keyboard.PutScancode (0xFE); 3665 fSentRESEND = true; 3666 } 3667 keyboard.PutScancode (i | 0x80); 3668 } 3669 else if (mPressedKeys [i] & IsExtKeyPressed) 3670 { 3671 if (!fSentRESEND) 3672 { 3673 keyboard.PutScancode (0xFE); 3674 fSentRESEND = true; 3675 } 3676 QVector <LONG> codes (2); 3677 codes[0] = 0xE0; 3678 codes[1] = i | 0x80; 3679 keyboard.PutScancodes (codes); 3680 } 3681 mPressedKeys [i] = 0; 3682 } 3683 3684 if (aReleaseHostKey) 3685 mIsHostkeyPressed = false; 3686 3687 #ifdef Q_WS_MAC 3688 /* clear most of the modifiers. */ 3689 mDarwinKeyModifiers &= 3690 alphaLock | kEventKeyModifierNumLockMask | 3691 (aReleaseHostKey ? 0 : ::DarwinKeyCodeToDarwinModifierMask (gs.hostKey())); 3692 #endif 3693 3694 emitKeyboardStateChanged(); 3695 } 3696 3697 void VBoxConsoleView::saveKeyStates() 3698 { 3699 ::memcpy (mPressedKeysCopy, mPressedKeys, sizeof (mPressedKeys)); 3700 } 3701 3702 void VBoxConsoleView::sendChangedKeyStates() 3703 { 3704 AssertMsg (mAttached, ("Console must be attached")); 3705 3706 QVector <LONG> codes (2); 3707 CKeyboard keyboard = mConsole.GetKeyboard(); 3708 for (uint i = 0; i < SIZEOF_ARRAY (mPressedKeys); ++ i) 3709 { 3710 uint8_t os = mPressedKeysCopy [i]; 3711 uint8_t ns = mPressedKeys [i]; 3712 if ((os & IsKeyPressed) != (ns & IsKeyPressed)) 3713 { 3714 codes [0] = i; 3715 if (!(ns & IsKeyPressed)) 3716 codes[0] |= 0x80; 3717 keyboard.PutScancode (codes[0]); 3718 } 3719 else if ((os & IsExtKeyPressed) != (ns & IsExtKeyPressed)) 3720 { 3721 codes [0] = 0xE0; 3722 codes [1] = i; 3723 if (!(ns & IsExtKeyPressed)) 3724 codes [1] |= 0x80; 3725 keyboard.PutScancodes (codes); 3726 } 3727 } 3728 } 3729 3730 void VBoxConsoleView::updateMouseClipping() 3731 { 3732 AssertMsg (mAttached, ("Console must be attached")); 3733 3734 if (mMouseCaptured) 3735 { 3736 viewport()->setCursor (QCursor (Qt::BlankCursor)); 3737 #ifdef Q_WS_WIN32 3738 QRect r = viewport()->rect(); 3739 r.moveTopLeft (viewport()->mapToGlobal (QPoint (0, 0))); 3740 RECT rect = { r.left(), r.top(), r.right() + 1, r.bottom() + 1 }; 3741 ::ClipCursor (&rect); 3742 #endif 3743 } 3744 else 3745 { 3746 #ifdef Q_WS_WIN32 3747 ::ClipCursor (NULL); 3748 #endif 3749 /* return the cursor to where it was when we captured it and show it */ 3750 QCursor::setPos (mCapturedPos); 3751 viewport()->unsetCursor(); 3752 } 3753 } 3754 3755 void VBoxConsoleView::setPointerShape (MousePointerChangeEvent *me) 3756 { 3757 if (me->shapeData() != NULL) 3758 { 3759 bool ok = false; 3760 3761 const uchar *srcAndMaskPtr = me->shapeData(); 3762 uint andMaskSize = (me->width() + 7) / 8 * me->height(); 3763 const uchar *srcShapePtr = me->shapeData() + ((andMaskSize + 3) & ~3); 3764 uint srcShapePtrScan = me->width() * 4; 3765 3766 #if defined (Q_WS_WIN) 3767 3768 BITMAPV5HEADER bi; 3769 HBITMAP hBitmap; 3770 void *lpBits; 3771 3772 ::ZeroMemory (&bi, sizeof (BITMAPV5HEADER)); 3773 bi.bV5Size = sizeof (BITMAPV5HEADER); 3774 bi.bV5Width = me->width(); 3775 bi.bV5Height = - (LONG) me->height(); 3776 bi.bV5Planes = 1; 3777 bi.bV5BitCount = 32; 3778 bi.bV5Compression = BI_BITFIELDS; 3779 // specifiy a supported 32 BPP alpha format for Windows XP 3780 bi.bV5RedMask = 0x00FF0000; 3781 bi.bV5GreenMask = 0x0000FF00; 3782 bi.bV5BlueMask = 0x000000FF; 3783 if (me->hasAlpha()) 3784 bi.bV5AlphaMask = 0xFF000000; 3785 else 3786 bi.bV5AlphaMask = 0; 3787 3788 HDC hdc = GetDC (NULL); 3789 3790 // create the DIB section with an alpha channel 3791 hBitmap = CreateDIBSection (hdc, (BITMAPINFO *) &bi, DIB_RGB_COLORS, 3792 (void **) &lpBits, NULL, (DWORD) 0); 3793 3794 ReleaseDC (NULL, hdc); 3795 3796 HBITMAP hMonoBitmap = NULL; 3797 if (me->hasAlpha()) 3798 { 3799 // create an empty mask bitmap 3800 hMonoBitmap = CreateBitmap (me->width(), me->height(), 1, 1, NULL); 3801 } 3802 else 3803 { 3804 /* Word aligned AND mask. Will be allocated and created if necessary. */ 3805 uint8_t *pu8AndMaskWordAligned = NULL; 3806 3807 /* Width in bytes of the original AND mask scan line. */ 3808 uint32_t cbAndMaskScan = (me->width() + 7) / 8; 3809 3810 if (cbAndMaskScan & 1) 3811 { 3812 /* Original AND mask is not word aligned. */ 3813 3814 /* Allocate memory for aligned AND mask. */ 3815 pu8AndMaskWordAligned = (uint8_t *)RTMemTmpAllocZ ((cbAndMaskScan + 1) * me->height()); 3816 3817 Assert(pu8AndMaskWordAligned); 3818 3819 if (pu8AndMaskWordAligned) 3820 { 3821 /* According to MSDN the padding bits must be 0. 3822 * Compute the bit mask to set padding bits to 0 in the last byte of original AND mask. 3823 */ 3824 uint32_t u32PaddingBits = cbAndMaskScan * 8 - me->width(); 3825 Assert(u32PaddingBits < 8); 3826 uint8_t u8LastBytesPaddingMask = (uint8_t)(0xFF << u32PaddingBits); 3827 3828 Log(("u8LastBytesPaddingMask = %02X, aligned w = %d, width = %d, cbAndMaskScan = %d\n", 3829 u8LastBytesPaddingMask, (cbAndMaskScan + 1) * 8, me->width(), cbAndMaskScan)); 3830 3831 uint8_t *src = (uint8_t *)srcAndMaskPtr; 3832 uint8_t *dst = pu8AndMaskWordAligned; 3833 3834 unsigned i; 3835 for (i = 0; i < me->height(); i++) 3836 { 3837 memcpy (dst, src, cbAndMaskScan); 3838 3839 dst[cbAndMaskScan - 1] &= u8LastBytesPaddingMask; 3840 3841 src += cbAndMaskScan; 3842 dst += cbAndMaskScan + 1; 3843 } 3844 } 3845 } 3846 3847 /* create the AND mask bitmap */ 3848 hMonoBitmap = ::CreateBitmap (me->width(), me->height(), 1, 1, 3849 pu8AndMaskWordAligned? pu8AndMaskWordAligned: srcAndMaskPtr); 3850 3851 if (pu8AndMaskWordAligned) 3852 { 3853 RTMemTmpFree (pu8AndMaskWordAligned); 3854 } 3855 } 3856 3857 Assert (hBitmap); 3858 Assert (hMonoBitmap); 3859 if (hBitmap && hMonoBitmap) 3860 { 3861 DWORD *dstShapePtr = (DWORD *) lpBits; 3862 3863 for (uint y = 0; y < me->height(); y ++) 3864 { 3865 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan); 3866 srcShapePtr += srcShapePtrScan; 3867 dstShapePtr += me->width(); 3868 } 3869 3870 ICONINFO ii; 3871 ii.fIcon = FALSE; 3872 ii.xHotspot = me->xHot(); 3873 ii.yHotspot = me->yHot(); 3874 ii.hbmMask = hMonoBitmap; 3875 ii.hbmColor = hBitmap; 3876 3877 HCURSOR hAlphaCursor = CreateIconIndirect (&ii); 3878 Assert (hAlphaCursor); 3879 if (hAlphaCursor) 3880 { 3881 viewport()->setCursor (QCursor (hAlphaCursor)); 3882 ok = true; 3883 if (mAlphaCursor) 3884 DestroyIcon (mAlphaCursor); 3885 mAlphaCursor = hAlphaCursor; 3886 } 3887 } 3888 3889 if (hMonoBitmap) 3890 DeleteObject (hMonoBitmap); 3891 if (hBitmap) 3892 DeleteObject (hBitmap); 3893 3894 #elif defined (Q_WS_X11) && !defined (VBOX_WITHOUT_XCURSOR) 3895 3896 XcursorImage *img = XcursorImageCreate (me->width(), me->height()); 3897 Assert (img); 3898 if (img) 3899 { 3900 img->xhot = me->xHot(); 3901 img->yhot = me->yHot(); 3902 3903 XcursorPixel *dstShapePtr = img->pixels; 3904 3905 for (uint y = 0; y < me->height(); y ++) 3906 { 3907 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan); 3908 3909 if (!me->hasAlpha()) 3910 { 3911 /* convert AND mask to the alpha channel */ 3912 uchar byte = 0; 3913 for (uint x = 0; x < me->width(); x ++) 3914 { 3915 if (!(x % 8)) 3916 byte = *(srcAndMaskPtr ++); 3917 else 3918 byte <<= 1; 3919 3920 if (byte & 0x80) 3921 { 3922 /* Linux doesn't support inverted pixels (XOR ops, 3923 * to be exact) in cursor shapes, so we detect such 3924 * pixels and always replace them with black ones to 3925 * make them visible at least over light colors */ 3926 if (dstShapePtr [x] & 0x00FFFFFF) 3927 dstShapePtr [x] = 0xFF000000; 3928 else 3929 dstShapePtr [x] = 0x00000000; 3930 } 3931 else 3932 dstShapePtr [x] |= 0xFF000000; 3933 } 3934 } 3935 3936 srcShapePtr += srcShapePtrScan; 3937 dstShapePtr += me->width(); 3938 } 3939 3940 Cursor cur = XcursorImageLoadCursor (QX11Info::display(), img); 3941 Assert (cur); 3942 if (cur) 3943 { 3944 viewport()->setCursor (QCursor (cur)); 3945 ok = true; 3946 } 3947 3948 XcursorImageDestroy (img); 3949 } 3950 3951 #elif defined(Q_WS_MAC) 3952 3953 /* Create a ARGB image out of the shape data. */ 3954 QImage image (me->width(), me->height(), QImage::Format_ARGB32); 3955 const uint8_t* pbSrcMask = static_cast<const uint8_t*> (srcAndMaskPtr); 3956 unsigned cbSrcMaskLine = RT_ALIGN (me->width(), 8) / 8; 3957 for (unsigned int y = 0; y < me->height(); ++y) 3958 { 3959 for (unsigned int x = 0; x < me->width(); ++x) 3960 { 3961 unsigned int color = ((unsigned int*)srcShapePtr)[y*me->width()+x]; 3962 /* If the alpha channel isn't in the shape data, we have to 3963 * create them from the and-mask. This is a bit field where 1 3964 * represent transparency & 0 opaque respectively. */ 3965 if (!me->hasAlpha()) 3966 { 3967 if (!(pbSrcMask[x / 8] & (1 << (7 - (x % 8))))) 3968 color |= 0xff000000; 3969 else 3970 { 3971 /* This isn't quite right, but it's the best we can do I 3972 * think... */ 3973 if (color & 0x00ffffff) 3974 color = 0xff000000; 3975 else 3976 color = 0x00000000; 3977 } 3978 } 3979 image.setPixel (x, y, color); 3980 } 3981 /* Move one scanline forward. */ 3982 pbSrcMask += cbSrcMaskLine; 3983 } 3984 /* Set the new cursor */ 3985 QCursor cursor (QPixmap::fromImage (image), 3986 me->xHot(), me->yHot()); 3987 viewport()->setCursor (cursor); 3988 ok = true; 3989 NOREF (srcShapePtrScan); 3990 3991 #else 3992 3993 # warning "port me" 3994 3995 #endif 3996 if (ok) 3997 mLastCursor = viewport()->cursor(); 3998 else 3999 viewport()->unsetCursor(); 4000 } 4001 else 4002 { 4003 /* 4004 * We did not get any shape data 4005 */ 4006 if (me->isVisible()) 4007 { 4008 viewport()->setCursor (mLastCursor); 4009 } 4010 else 4011 { 4012 viewport()->setCursor (Qt::BlankCursor); 4013 } 4014 } 4015 mHideHostPointer = !me->isVisible(); 4016 } 4017 4018 inline QRgb qRgbIntensity (QRgb rgb, int mul, int div) 4019 { 4020 int r = qRed (rgb); 4021 int g = qGreen (rgb); 4022 int b = qBlue (rgb); 4023 return qRgb (mul * r / div, mul * g / div, mul * b / div); 4024 } 4025 4026 /* static */ 4027 void VBoxConsoleView::dimImage (QImage &img) 4028 { 4029 for (int y = 0; y < img.height(); y ++) { 4030 if (y % 2) { 4031 if (img.depth() == 32) { 4032 for (int x = 0; x < img.width(); x ++) { 4033 int gray = qGray (img.pixel (x, y)) / 2; 4034 img.setPixel (x, y, qRgb (gray, gray, gray)); 4035 // img.setPixel (x, y, qRgbIntensity (img.pixel (x, y), 1, 2)); 4036 } 4037 } else { 4038 ::memset (img.scanLine (y), 0, img.bytesPerLine()); 4039 } 4040 } else { 4041 if (img.depth() == 32) { 4042 for (int x = 0; x < img.width(); x ++) { 4043 int gray = (2 * qGray (img.pixel (x, y))) / 3; 4044 img.setPixel (x, y, qRgb (gray, gray, gray)); 4045 // img.setPixel (x, y, qRgbIntensity (img.pixel(x, y), 2, 3)); 4046 } 4047 } 4048 } 4049 } 4050 } 4051 4052 void VBoxConsoleView::doResizeHint (const QSize &aToSize) 4053 { 4054 if (mGuestSupportsGraphics && mAutoresizeGuest) 4055 { 4056 /* If this slot is invoked directly then use the passed size 4057 * otherwise get the available size for the guest display. 4058 * We assume here that the centralWidget() contains this view only 4059 * and gives it all available space. */ 4060 QSize sz (aToSize.isValid() ? aToSize : mMainWnd->centralWidget()->size()); 4061 if (!aToSize.isValid()) 4062 sz -= QSize (frameWidth() * 2, frameWidth() * 2); 4063 /* Do not send out useless hints. */ 4064 if ((sz.width() == mStoredConsoleSize.width()) && 4065 (sz.height() == mStoredConsoleSize.height())) 4066 return; 4067 /* We only actually send the hint if 4068 * 1) the autoresize property is set to true and 4069 * 2) either an explicit new size was given (e.g. if the request 4070 * was triggered directly by a console resize event) or if no 4071 * explicit size was specified but a resize is flagged as being 4072 * needed (e.g. the autoresize was just enabled and the console 4073 * was resized while it was disabled). */ 4074 if (mAutoresizeGuest && 4075 (aToSize.isValid() || mDoResize)) 4076 { 4077 LogFlowFunc (("Will suggest %d x %d\n", sz.width(), sz.height())); 4078 4079 /* Remember the new size. */ 4080 storeConsoleSize (sz.width(), sz.height()); 4081 4082 mConsole.GetDisplay().SetVideoModeHint (sz.width(), sz.height(), 0, 0); 4083 } 4084 /* we have resized now... */ 4085 mDoResize = false; 4086 } 4087 } 4088 4089 4090 /* If the desktop geometry is set automatically, this will update it. */ 4091 void VBoxConsoleView::doResizeDesktop (int) 4092 { 4093 calculateDesktopGeometry(); 4094 } 4095 4096 /** 4097 * Store the current size of the console (i.e. the viewport to the guest). 4098 * This has two purposes. One is to suppress unwanted resize events for 4099 * which the new size is the same as the stored size. The other is to expand 4100 * the maximum size to which we will let the guest resize itself. It makes 4101 * no sense to forbid guest resizes which are less than the current resolution 4102 * anyway. 4103 * 4104 * @param aWidth width of the resolution hint 4105 * @param aHeight height of the resolution hint 4106 */ 4107 void VBoxConsoleView::storeConsoleSize (int aWidth, int aHeight) 4108 { 4109 LogFlowThisFunc (("aWidth=%d, aHeight=%d\n", aWidth, aHeight)); 4110 mStoredConsoleSize = QRect (0, 0, aWidth, aHeight); 4111 } 4112 4113 /** 4114 * Do initial setup of desktop geometry restrictions on the guest framebuffer. 4115 * These determine the maximum size the guest framebuffer can take on. 4116 * 4117 * @note a hint from the host will always override these restrictions. 4118 * 4119 * @param aGeo Fixed - the guest has a fixed maximum framebuffer size 4120 * Automatic - we calculate the maximum size ourselves. The 4121 * calculations will not actually be done until 4122 * @a calculateDesktopGeometry is called, since 4123 * we don't initially have the information needed. 4124 * Any - any size is allowed 4125 * @param aWidth The maximum width for the guest screen or zero for no change 4126 * (only used for fixed geometry) 4127 * @param aHeight The maximum height for the guest screen or zero for no change 4128 * (only used for fixed geometry) 4129 */ 4130 void VBoxConsoleView::setDesktopGeometry (DesktopGeo aGeo, int aWidth, int aHeight) 4131 { 4132 LogFlowThisFunc (("aGeo=%s, aWidth=%d, aHeight=%d\n", 4133 (aGeo == DesktopGeo_Fixed ? "Fixed" : 4134 aGeo == DesktopGeo_Automatic ? "Automatic" : 4135 aGeo == DesktopGeo_Any ? "Any" : "Invalid"), 4136 aWidth, aHeight)); 4137 switch (aGeo) 4138 { 4139 case DesktopGeo_Fixed: 4140 mDesktopGeo = DesktopGeo_Fixed; 4141 if (aWidth != 0 && aHeight != 0) 4142 mDesktopGeometry = QRect (0, 0, aWidth, aHeight); 4143 else 4144 mDesktopGeometry = QRect (0, 0, 0, 0); 4145 storeConsoleSize (0, 0); 4146 break; 4147 case DesktopGeo_Automatic: 4148 mDesktopGeo = DesktopGeo_Automatic; 4149 mDesktopGeometry = QRect (0, 0, 0, 0); 4150 storeConsoleSize (0, 0); 4151 break; 4152 case DesktopGeo_Any: 4153 mDesktopGeo = DesktopGeo_Any; 4154 mDesktopGeometry = QRect (0, 0, 0, 0); 4155 break; 4156 default: 4157 AssertMsgFailed(("Invalid desktop geometry type %d\n", aGeo)); 4158 mDesktopGeo = DesktopGeo_Invalid; 4159 } 4160 } 4161 4162 4163 /** 4164 * If we are in automatic mode, the geometry restrictions will be recalculated. 4165 * This is needed in particular on the first widget resize, as we can't 4166 * calculate them correctly before that. 4167 * 4168 * @note a hint from the host will always override these restrictions. 4169 * @note we can't do calculations on the fly when they are needed, because 4170 * they require querying the X server on X11 hosts and this must be done 4171 * from within the GUI thread, due to the single threadedness of Xlib. 4172 */ 4173 void VBoxConsoleView::calculateDesktopGeometry() 4174 { 4175 LogFlowThisFunc (("Entering\n")); 4176 /* This method should not get called until we have initially set up the */ 4177 Assert ((mDesktopGeo != DesktopGeo_Invalid)); 4178 /* If we are not doing automatic geometry calculation then there is 4179 * nothing to do. */ 4180 if (DesktopGeo_Automatic == mDesktopGeo) 4181 { 4182 /* Available geometry of the desktop. If the desktop is a single 4183 * screen, this will exclude space taken up by desktop taskbars 4184 * and things, but this is unfortunately not true for the more 4185 * complex case of a desktop spanning multiple screens. */ 4186 QRect desktop = availableGeometry(); 4187 /* The area taken up by the console window on the desktop, 4188 * including window frame, title and menu bar and whatnot. */ 4189 QRect frame = mMainWnd->frameGeometry(); 4190 /* The area taken up by the console window, minus all 4191 * decorations. */ 4192 QRect window = mMainWnd->centralWidget()->geometry(); 4193 /* To work out how big we can make the console window while still 4194 * fitting on the desktop, we calculate desktop - frame + window. 4195 * This works because the difference between frame and window 4196 * (or at least its width and height) is a constant. */ 4197 mDesktopGeometry = 4198 QRect (0, 0, desktop.width() - frame.width() + window.width(), 4199 desktop.height() - frame.height() + window.height()); 4200 LogFlowThisFunc (("Setting %d, %d\n", mDesktopGeometry.width(), 4201 mDesktopGeometry.height())); 4202 } 4203 } 4204 4205 /** 4206 * Sets the minimum size restriction depending on the auto-resize feature 4207 * state and the current rendering mode. 4208 * 4209 * Currently, the restriction is set only in SDL mode and only when the 4210 * auto-resize feature is inactive. We need to do that because we cannot 4211 * correctly draw in a scrolled window in SDL mode. 4212 * 4213 * In all other modes, or when auto-resize is in force, this function does 4214 * nothing. 4215 */ 4216 void VBoxConsoleView::maybeRestrictMinimumSize() 4217 { 4218 if (mode == VBoxDefs::SDLMode) 4219 { 4220 if (!mGuestSupportsGraphics || !mAutoresizeGuest) 4221 setMinimumSize (sizeHint()); 4222 else 4223 setMinimumSize (0, 0); 4224 } 4225 } 4226 4227 QRect VBoxConsoleView::availableGeometry() const 4228 { 4229 return mMainWnd->isWindowFullScreen() ? 4230 QApplication::desktop()->screenGeometry(this) : 4231 QApplication::desktop()->availableGeometry(this); 4232 } 4233 4234 int VBoxConsoleView::contentsWidth() const 4235 { 4236 return mFrameBuf->width(); 4237 } 4238 4239 int VBoxConsoleView::contentsHeight() const 4240 { 4241 return mFrameBuf->height(); 4242 } 4243 4244 void VBoxConsoleView::updateSliders() 4245 { 4246 QSize p = viewport()->size(); 4247 QSize m = maximumViewportSize(); 4248 4249 QSize v = QSize (mFrameBuf->width(), mFrameBuf->height()); 4250 /* no scroll bars needed */ 4251 if (m.expandedTo(v) == m) 4252 p = m; 4253 4254 horizontalScrollBar()->setRange(0, v.width() - p.width()); 4255 verticalScrollBar()->setRange(0, v.height() - p.height()); 4256 horizontalScrollBar()->setPageStep(p.width()); 4257 verticalScrollBar()->setPageStep(p.height()); 4258 } 4259 4260 void VBoxConsoleView::requestToResize (const QSize &aSize) 4261 { 4262 mIgnoreFrameBufferResize = true; 4263 mNormalSize = aSize; 4264 } 4265 4266 #if defined(Q_WS_MAC) 4267 4268 void VBoxConsoleView::updateDockIcon() 4269 { 4270 if (mDockIconEnabled) 4271 { 4272 if (!mPausedShot.isNull()) 4273 { 4274 CGImageRef pauseImg = ::darwinToCGImageRef (&mPausedShot); 4275 /* Use the pause image as background */ 4276 mDockIconPreview->updateDockPreview (pauseImg); 4277 CGImageRelease (pauseImg); 4278 } 4279 else 4280 { 4281 # if defined (VBOX_GUI_USE_QUARTZ2D) 4282 if (mode == VBoxDefs::Quartz2DMode) 4283 { 4284 /* If the render mode is Quartz2D we could use the CGImageRef 4285 * of the framebuffer for the dock icon creation. This saves 4286 * some conversion time. */ 4287 mDockIconPreview->updateDockPreview (static_cast <VBoxQuartz2DFrameBuffer *> (mFrameBuf)->imageRef()); 4288 } 4289 else 4290 # endif 4291 /* In image mode we have to create the image ref out of the 4292 * framebuffer */ 4293 mDockIconPreview->updateDockPreview (mFrameBuf); 4294 } 4295 } 4296 } 4297 4298 void VBoxConsoleView::updateDockOverlay() 4299 { 4300 /* Only to an update to the realtime preview if this is enabled by the user 4301 * & we are in an state where the framebuffer is likely valid. Otherwise to 4302 * the overlay stuff only. */ 4303 if (mDockIconEnabled && 4304 (mLastState == KMachineState_Running || 4305 mLastState == KMachineState_Paused || 4306 mLastState == KMachineState_Teleporting || 4307 mLastState == KMachineState_LiveSnapshotting || 4308 mLastState == KMachineState_Restoring || 4309 mLastState == KMachineState_TeleportingPausedVM || 4310 mLastState == KMachineState_TeleportingIn || 4311 mLastState == KMachineState_Saving)) 4312 updateDockIcon(); 4313 else 4314 mDockIconPreview->updateDockOverlay(); 4315 } 4316 4317 /** 4318 * Wrapper for SetMouseCoalescingEnabled(). 4319 * 4320 * Called by eventFilter() and darwinGrabKeyboardEvents(). 4321 * 4322 * @param aOn Switch it on (true) or off (false). 4323 */ 4324 void VBoxConsoleView::setMouseCoalescingEnabled (bool aOn) 4325 { 4326 /* Enable mouse event compression if we leave the VM view. This 4327 is necessary for having smooth resizing of the VM/other 4328 windows. 4329 Disable mouse event compression if we enter the VM view. So 4330 all mouse events are registered in the VM. Only do this if 4331 the keyboard/mouse is grabbed (this is when we have a valid 4332 event handler). */ 4333 if (aOn || mKeyboardGrabbed) 4334 ::darwinSetMouseCoalescingEnabled (aOn); 4335 } 4336 4337 #endif /* Q_WS_MAC */ 4338 116 #endif // !___UIConsole_h___ -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineLogicNormal.cpp
r26656 r26691 31 31 #include "UIFirstRunWzd.h" 32 32 33 #include "UISession.h" 33 34 #include "UIActionsPool.h" 34 35 #include "UIMachineLogicNormal.h" … … 36 37 #include "UIMachineView.h" 37 38 38 UIMachineLogicNormal::UIMachineLogicNormal(QObject *pParent, const CSession &session, UIActionsPool *pActionsPool) 39 : UIMachineLogic(pParent, session, pActionsPool, UIVisualStateType_Normal) 40 { 39 UIMachineLogicNormal::UIMachineLogicNormal(QObject *pParent, UISession *pSession, UIActionsPool *pActionsPool) 40 : UIMachineLogic(pParent, pSession, pActionsPool, UIVisualStateType_Normal) 41 { 42 /* Prepare console connections: */ 43 prepareConsoleConnections(); 44 41 45 /* Prepare action groups: */ 42 46 prepareActionGroups(); … … 53 57 /* Load common logic settings: */ 54 58 loadLogicSettings(); 55 56 /* Update all the elements: */57 updateAppearanceOf(UIVisualElement_AllStuff);58 59 } 59 60 … … 83 84 } 84 85 85 void UIMachineLogicNormal::updateAppearanceOf(int iElement) 86 { 87 /* Update parent-class elements: */ 88 UIMachineLogic::updateAppearanceOf(iElement); 86 void UIMachineLogicNormal::sltPrepareMouseIntegrationMenu() 87 { 88 QMenu *menu = qobject_cast<QMenu*>(sender()); 89 AssertMsg(menu, ("This slot should be called only on Mouse Integration Menu show!\n")); 90 menu->clear(); 91 menu->addAction(actionsPool()->action(UIActionIndex_Toggle_MouseIntegration)); 89 92 } 90 93 … … 99 102 connect(actionsPool()->action(UIActionIndex_Menu_SharedFolders)->menu(), SIGNAL(aboutToShow()), 100 103 this, SLOT(sltPrepareSharedFoldersMenu())); 104 connect(actionsPool()->action(UIActionIndex_Menu_MouseIntegration)->menu(), SIGNAL(aboutToShow()), 105 this, SLOT(sltPrepareMouseIntegrationMenu())); 101 106 } 102 107 … … 120 125 setMachineState(session().GetConsole().GetState()); 121 126 122 /* Notify user about mouse&keyboard auto-capturing: */ 123 if (vboxGlobal().settings().autoCapture()) 124 vboxProblem().remindAboutAutoCapture(); 125 126 bool saved = machineState() == KMachineState_Saved; 127 128 CMachine machine = session().GetMachine(); 129 CConsole console = session().GetConsole(); 130 131 /* Shows first run wizard if necessary: */ 132 if (isFirstTimeStarted()) 127 bool bIsSaved = machineState() == KMachineState_Saved; 128 bool bIsRunning = machineState() == KMachineState_Running || 129 machineState() == KMachineState_Teleporting || 130 machineState() == KMachineState_LiveSnapshotting; 131 bool bIsRunningOrPaused = bIsRunning || 132 machineState() == KMachineState_Paused; 133 134 /* If we are not started yet: */ 135 if (!bIsRunningOrPaused) 133 136 { 134 UIFirstRunWzd wzd(machineWindowWrapper()->machineWindow(), machine); 135 wzd.exec(); 136 machine.SetExtraData(VBoxDefs::GUI_FirstRun, QString()); 137 } 138 139 140 // TODO: Do not start VM yet! 141 return; 142 143 144 /* Start VM: */ 145 CProgress progress = vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled() ? 146 console.PowerUpPaused() : console.PowerUp(); 147 /* Check for an immediate failure */ 148 if (!console.isOk()) 149 { 150 vboxProblem().cannotStartMachine(console); 151 machineWindowWrapper()->machineWindow()->close(); 152 return; 153 } 154 155 /* Disable auto closure because we want to have a chance to show the error dialog on startup failure: */ 156 setPreventAutoClose(true); 157 158 /* Show "Starting/Restoring" progress dialog: */ 159 if (saved) 160 vboxProblem().showModalProgressDialog(progress, machine.GetName(), machineWindowWrapper()->machineView(), 0); 161 else 162 vboxProblem().showModalProgressDialog(progress, machine.GetName(), machineWindowWrapper()->machineView()); 163 164 /* Check for an progress failure */ 165 if (progress.GetResultCode() != 0) 166 { 167 vboxProblem().cannotStartMachine(progress); 168 machineWindowWrapper()->machineWindow()->close(); 169 return; 170 } 171 172 /* Enable auto closure again: */ 173 setPreventAutoClose(false); 174 175 /* Check if we missed a really quick termination after successful startup, and process it if we did: */ 176 if (machineState() == KMachineState_PoweredOff || machineState() == KMachineState_Saved || 177 machineState() == KMachineState_Teleported || machineState() == KMachineState_Aborted) 178 { 179 machineWindowWrapper()->machineWindow()->close(); 180 return; 181 } 137 /* Get current machine/console: */ 138 CMachine machine = session().GetMachine(); 139 CConsole console = session().GetConsole(); 140 141 /* Notify user about mouse&keyboard auto-capturing: */ 142 if (vboxGlobal().settings().autoCapture()) 143 vboxProblem().remindAboutAutoCapture(); 144 145 /* Shows first run wizard if necessary: */ 146 if (isFirstTimeStarted()) 147 { 148 UIFirstRunWzd wzd(machineWindowWrapper()->machineWindow(), machine); 149 wzd.exec(); 150 } 151 152 /* Start VM: */ 153 CProgress progress = vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled() ? 154 console.PowerUpPaused() : console.PowerUp(); 155 /* Check for an immediate failure */ 156 if (!console.isOk()) 157 { 158 vboxProblem().cannotStartMachine(console); 159 machineWindowWrapper()->machineWindow()->close(); 160 return; 161 } 162 163 /* Disable auto closure because we want to have a chance to show the error dialog on startup failure: */ 164 setPreventAutoClose(true); 165 166 /* Show "Starting/Restoring" progress dialog: */ 167 if (bIsSaved) 168 vboxProblem().showModalProgressDialog(progress, machine.GetName(), machineWindowWrapper()->machineWindow(), 0); 169 else 170 vboxProblem().showModalProgressDialog(progress, machine.GetName(), machineWindowWrapper()->machineWindow()); 171 172 /* Check for an progress failure */ 173 if (progress.GetResultCode() != 0) 174 { 175 vboxProblem().cannotStartMachine(progress); 176 machineWindowWrapper()->machineWindow()->close(); 177 return; 178 } 179 180 /* Process pending events: */ 181 qApp->processEvents(); 182 183 /* Enable auto closure again: */ 184 setPreventAutoClose(false); 185 186 /* Check if we missed a really quick termination after successful startup, and process it if we did: */ 187 if (machineState() == KMachineState_PoweredOff || machineState() == KMachineState_Saved || 188 machineState() == KMachineState_Teleported || machineState() == KMachineState_Aborted) 189 { 190 machineWindowWrapper()->machineWindow()->close(); 191 return; 192 } 182 193 183 194 #if 0 // TODO: Rework debugger logic! 184 195 # ifdef VBOX_WITH_DEBUGGER_GUI 185 /* Open the debugger in "full screen" mode requested by the user. */186 else if (vboxGlobal().isDebuggerAutoShowEnabled())187 {188 /* console in upper left corner of the desktop. */189 QRect rct (0, 0, 0, 0);190 QDesktopWidget *desktop = QApplication::desktop();191 if (desktop)192 rct = desktop->availableGeometry(pos());193 move (QPoint (rct.x(), rct.y()));194 195 if (vboxGlobal().isDebuggerAutoShowStatisticsEnabled())196 sltShowDebugStatistics();197 if (vboxGlobal().isDebuggerAutoShowCommandLineEnabled())198 sltShowDebugCommandLine();199 200 if (!vboxGlobal().isStartPausedEnabled())201 machineWindowWrapper()->machineView()->pause (false);202 }196 /* Open the debugger in "full screen" mode requested by the user. */ 197 else if (vboxGlobal().isDebuggerAutoShowEnabled()) 198 { 199 /* console in upper left corner of the desktop. */ 200 QRect rct (0, 0, 0, 0); 201 QDesktopWidget *desktop = QApplication::desktop(); 202 if (desktop) 203 rct = desktop->availableGeometry(pos()); 204 move (QPoint (rct.x(), rct.y())); 205 206 if (vboxGlobal().isDebuggerAutoShowStatisticsEnabled()) 207 sltShowDebugStatistics(); 208 if (vboxGlobal().isDebuggerAutoShowCommandLineEnabled()) 209 sltShowDebugCommandLine(); 210 211 if (!vboxGlobal().isStartPausedEnabled()) 212 machineWindowWrapper()->machineView()->pause (false); 213 } 203 214 # endif 204 215 #endif 205 216 206 setOpenViewFinished(true);207 208 217 #ifdef VBOX_WITH_UPDATE_REQUEST 209 /* Check for updates if necessary: */210 vboxGlobal().showUpdateDialog(false /* aForce */);218 /* Check for updates if necessary: */ 219 vboxGlobal().showUpdateDialog(false /* aForce */); 211 220 #endif 221 } 212 222 213 223 /* Configure view connections: */ 214 224 if (machineWindowWrapper()->machineView()) 215 225 { 216 connect(machineWindowWrapper()->machineView(), SIGNAL(machineStateChanged(KMachineState)),217 this, SLOT(sltUpdateMachineState(KMachineState)));218 connect(machineWindowWrapper()->machineView(), SIGNAL(additionsStateChanged(const QString&, bool, bool, bool)),219 this, SLOT(sltUpdateAdditionsState(const QString &, bool, bool, bool)));220 226 connect(machineWindowWrapper()->machineView(), SIGNAL(mouseStateChanged(int)), 221 this, SLOT(slt UpdateMouseState(int)));227 this, SLOT(sltMouseStateChanged(int))); 222 228 } 229 230 /* Set what view opened: */ 231 setOpenViewFinished(true); 223 232 } 224 233 … … 232 241 UIMachineWindow::destroy(m_pMachineWindowContainer); 233 242 m_pMachineWindowContainer = 0; 234 235 // TODO: What should be done on window destruction? 236 //machineWindowWrapper()->machineView()->detach(); 237 //m_session.Close(); 238 //m_session.detach(); 239 } 243 } -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineLogicNormal.h
r26656 r26691 36 36 protected: 37 37 38 /* Normal machine logic constructor : */38 /* Normal machine logic constructor/destructor: */ 39 39 UIMachineLogicNormal(QObject *pParent, 40 const CSession &session,40 UISession *pSession, 41 41 UIActionsPool *pActionsPool); 42 /* Normal machine logic destructor: */43 42 virtual ~UIMachineLogicNormal(); 44 43 45 44 private slots: 46 45 47 /* Status-bar LEDfuntionality: */46 /* Windowed mode funtionality: */ 48 47 void sltPrepareNetworkAdaptersMenu(); 49 48 void sltPrepareSharedFoldersMenu(); 49 void sltPrepareMouseIntegrationMenu(); 50 50 51 51 private: 52 53 /* Update routines: */54 void updateAppearanceOf(int);55 52 56 53 /* Prepare helpers: */ … … 64 61 //void cleanupActionConnections(); 65 62 63 /* Friend classes: */ 66 64 friend class UIMachineLogic; 67 65 }; -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
r26637 r26691 45 45 ) 46 46 { 47 /* Connect actions to view: */48 connect(machineWindowWrapper()->machineLogic()->actionsPool()->action(UIActionIndex_Toggle_GuestAutoresize),49 SIGNAL(toggled(bool)), this, SLOT(sltToggleGuestAutoresize(bool)));50 51 47 /* Connect view to handlers */ 52 48 connect(this, SIGNAL(additionsStateChanged(const QString&, bool, bool, bool)), -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp
r26656 r26691 32 32 #include "VBoxVMInformationDlg.h" 33 33 34 #include "UISession.h" 34 35 #include "UIActionsPool.h" 35 36 #include "UIIndicatorsPool.h" … … 54 55 prepareWindowIcon(); 55 56 57 /* Prepare console connections: */ 58 prepareConsoleConnections(); 59 56 60 /* Prepare menu: */ 57 61 prepareMenu(); … … 90 94 void UIMachineWindowNormal::sltTryClose() 91 95 { 92 // TODO: Could be moved to parent class? 93 94 /* First close any open modal & popup widgets. 95 * Use a single shot with timeout 0 to allow the widgets to cleany close and test then again. 96 * If all open widgets are closed destroy ourself: */ 97 QWidget *widget = QApplication::activeModalWidget() ? 98 QApplication::activeModalWidget() : 99 QApplication::activePopupWidget() ? 100 QApplication::activePopupWidget() : 0; 101 if (widget) 102 { 103 widget->close(); 104 QTimer::singleShot(0, this, SLOT(sltTryClose())); 105 } 106 else 107 close(); 96 UIMachineWindow::sltTryClose(); 97 } 98 99 void UIMachineWindowNormal::sltMachineStateChanged(KMachineState machineState) 100 { 101 UIMachineWindow::sltMachineStateChanged(machineState); 102 } 103 104 void UIMachineWindowNormal::sltMediumChange(const CMediumAttachment &attachment) 105 { 106 KDeviceType type = attachment.GetType(); 107 Assert(type == KDeviceType_DVD || type == KDeviceType_Floppy); 108 updateAppearanceOf(type == KDeviceType_DVD ? UIVisualElement_CDStuff : 109 type == KDeviceType_Floppy ? UIVisualElement_FDStuff : 110 UIVisualElement_AllStuff); 111 } 112 113 void UIMachineWindowNormal::sltUSBControllerChange() 114 { 115 updateAppearanceOf(UIVisualElement_USBStuff); 116 } 117 118 void UIMachineWindowNormal::sltUSBDeviceStateChange() 119 { 120 updateAppearanceOf(UIVisualElement_USBStuff); 121 } 122 123 void UIMachineWindowNormal::sltNetworkAdapterChange() 124 { 125 updateAppearanceOf(UIVisualElement_NetworkStuff); 126 } 127 128 void UIMachineWindowNormal::sltSharedFolderChange() 129 { 130 updateAppearanceOf(UIVisualElement_SharedFolderStuff); 108 131 } 109 132 … … 132 155 menu->addAction(machineLogic()->actionsPool()->action(UIActionIndex_Simple_InformationDialog)); 133 156 menu->addSeparator(); 157 menu->addAction(machineLogic()->actionsPool()->action(UIActionIndex_Toggle_Pause)); 134 158 menu->addAction(machineLogic()->actionsPool()->action(UIActionIndex_Simple_Reset)); 135 menu->addAction(machineLogic()->actionsPool()->action(UIActionIndex_Toggle_Pause));136 159 menu->addAction(machineLogic()->actionsPool()->action(UIActionIndex_Simple_Shutdown)); 137 160 #ifndef Q_WS_MAC … … 152 175 menu->addMenu(machineLogic()->actionsPool()->action(UIActionIndex_Menu_OpticalDevices)->menu()); 153 176 menu->addMenu(machineLogic()->actionsPool()->action(UIActionIndex_Menu_FloppyDevices)->menu()); 177 menu->addMenu(machineLogic()->actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu()); 154 178 menu->addAction(machineLogic()->actionsPool()->action(UIActionIndex_Simple_NetworkAdaptersDialog)); 155 179 menu->addAction(machineLogic()->actionsPool()->action(UIActionIndex_Simple_SharedFoldersDialog)); 156 menu->addMenu(machineLogic()->actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu());157 180 menu->addSeparator(); 158 181 menu->addAction(machineLogic()->actionsPool()->action(UIActionIndex_Toggle_VRDP)); … … 179 202 void UIMachineWindowNormal::sltUpdateIndicators() 180 203 { 181 CConsole console = machineLogic()->session().GetConsole();204 CConsole console = session().GetConsole(); 182 205 QIStateIndicator *pStateIndicator = 0; 183 206 … … 196 219 pStateIndicator->setState(state); 197 220 } 221 pStateIndicator = indicatorsPool()->indicator(UIIndicatorIndex_USBDevices); 222 if (pStateIndicator->state() != KDeviceActivity_Null) 223 { 224 int state = console.GetDeviceActivity(KDeviceType_USB); 225 if (pStateIndicator->state() != state) 226 pStateIndicator->setState(state); 227 } 198 228 pStateIndicator = indicatorsPool()->indicator(UIIndicatorIndex_NetworkAdapters); 199 229 if (pStateIndicator->state() != KDeviceActivity_Null) … … 203 233 pStateIndicator->setState(state); 204 234 } 205 pStateIndicator = indicatorsPool()->indicator(UIIndicatorIndex_USBDevices);206 if (pStateIndicator->state() != KDeviceActivity_Null)207 {208 int state = console.GetDeviceActivity(KDeviceType_USB);209 if (pStateIndicator->state() != state)210 pStateIndicator->setState(state);211 }212 235 pStateIndicator = indicatorsPool()->indicator(UIIndicatorIndex_SharedFolders); 213 236 if (pStateIndicator->state() != KDeviceActivity_Null) … … 223 246 if (pIndicator == indicatorsPool()->indicator(UIIndicatorIndex_OpticalDisks)) 224 247 { 225 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_OpticalDevices)-> menu()->isEnabled())248 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_OpticalDevices)->isEnabled()) 226 249 machineLogic()->actionsPool()->action(UIActionIndex_Menu_OpticalDevices)->menu()->exec(pEvent->globalPos()); 227 250 } 251 else if (pIndicator == indicatorsPool()->indicator(UIIndicatorIndex_USBDevices)) 252 { 253 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_USBDevices)->isEnabled()) 254 machineLogic()->actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu()->exec(pEvent->globalPos()); 255 } 228 256 else if (pIndicator == indicatorsPool()->indicator(UIIndicatorIndex_NetworkAdapters)) 229 257 { 230 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_NetworkAdapters)-> menu()->isEnabled())258 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_NetworkAdapters)->isEnabled()) 231 259 machineLogic()->actionsPool()->action(UIActionIndex_Menu_NetworkAdapters)->menu()->exec(pEvent->globalPos()); 232 260 } 233 else if (pIndicator == indicatorsPool()->indicator(UIIndicatorIndex_USBDevices))234 {235 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu()->isEnabled())236 machineLogic()->actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu()->exec(pEvent->globalPos());237 }238 261 else if (pIndicator == indicatorsPool()->indicator(UIIndicatorIndex_SharedFolders)) 239 262 { 240 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_SharedFolders)-> menu()->isEnabled())263 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_SharedFolders)->isEnabled()) 241 264 machineLogic()->actionsPool()->action(UIActionIndex_Menu_SharedFolders)->menu()->exec(pEvent->globalPos()); 242 265 } 243 266 else if (pIndicator == indicatorsPool()->indicator(UIIndicatorIndex_Mouse)) 244 267 { 245 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_MouseIntegration)-> menu()->isEnabled())268 if (machineLogic()->actionsPool()->action(UIActionIndex_Menu_MouseIntegration)->isEnabled()) 246 269 machineLogic()->actionsPool()->action(UIActionIndex_Menu_MouseIntegration)->menu()->exec(pEvent->globalPos()); 247 270 } … … 251 274 { 252 275 m_pNameHostkey->setText(QIHotKeyEdit::keyName(vboxGlobal().settings().hostKey())); 253 }254 255 void UIMachineWindowNormal::sltUpdateMediaDriveState(VBoxDefs::MediumType type)256 {257 Assert(type == VBoxDefs::MediumType_DVD || type == VBoxDefs::MediumType_Floppy);258 updateAppearanceOf(type == VBoxDefs::MediumType_DVD ? UIVisualElement_CDStuff :259 type == VBoxDefs::MediumType_Floppy ? UIVisualElement_FDStuff :260 UIVisualElement_AllStuff);261 }262 263 void UIMachineWindowNormal::sltUpdateNetworkAdaptersState()264 {265 updateAppearanceOf(UIVisualElement_NetworkStuff);266 }267 268 void UIMachineWindowNormal::sltUpdateUsbState()269 {270 updateAppearanceOf(UIVisualElement_USBStuff);271 }272 273 void UIMachineWindowNormal::sltUpdateSharedFoldersState()274 {275 updateAppearanceOf(UIVisualElement_SharedFolderStuff);276 276 } 277 277 … … 305 305 306 306 /* Update that machine window: */ 307 CMachine machine = machineLogic()->session().GetMachine(); 308 CConsole console = machineLogic()->session().GetConsole(); 309 bool bIsStrictRunningOrPaused = machineLogic()->machineState() == KMachineState_Running || 310 machineLogic()->machineState() == KMachineState_Paused; 307 CMachine machine = session().GetMachine(); 308 CConsole console = session().GetConsole(); 311 309 312 310 if (iElement & UIVisualElement_HDStuff) … … 376 374 indicatorsPool()->indicator(UIIndicatorIndex_OpticalDisks)->setState(bAttachmentsPresent ? KDeviceActivity_Idle : KDeviceActivity_Null); 377 375 } 378 if (iElement & UIVisualElement_NetworkStuff)379 {380 ulong uMaxCount = vboxGlobal().virtualBox().GetSystemProperties().GetNetworkAdapterCount();381 ulong uCount = 0;382 for (ulong uSlot = 0; uSlot < uMaxCount; ++ uSlot)383 if (machine.GetNetworkAdapter(uSlot).GetEnabled())384 ++ uCount;385 indicatorsPool()->indicator(UIIndicatorIndex_NetworkAdapters)->setState(uCount > 0 ? KDeviceActivity_Idle : KDeviceActivity_Null);386 387 machineLogic()->actionsPool()->action(UIActionIndex_Simple_NetworkAdaptersDialog)->setEnabled(bIsStrictRunningOrPaused && uCount > 0);388 machineLogic()->actionsPool()->action(UIActionIndex_Menu_NetworkAdapters)->setEnabled(bIsStrictRunningOrPaused && uCount > 0);389 390 QString strToolTip = tr("<p style='white-space:pre'><nobr>Indicates the activity of the "391 "network interfaces:</nobr>%1</p>", "Network adapters tooltip");392 QString strFullData;393 394 for (ulong uSlot = 0; uSlot < uMaxCount; ++ uSlot)395 {396 CNetworkAdapter adapter = machine.GetNetworkAdapter(uSlot);397 if (adapter.GetEnabled())398 strFullData += tr("<br><nobr><b>Adapter %1 (%2)</b>: cable %3</nobr>", "Network adapters tooltip")399 .arg(uSlot + 1)400 .arg(vboxGlobal().toString(adapter.GetAttachmentType()))401 .arg(adapter.GetCableConnected() ?402 tr("connected", "Network adapters tooltip") :403 tr("disconnected", "Network adapters tooltip"));404 }405 406 if (strFullData.isNull())407 strFullData = tr("<br><nobr><b>All network adapters are disabled</b></nobr>", "Network adapters tooltip");408 409 indicatorsPool()->indicator(UIIndicatorIndex_NetworkAdapters)->setToolTip(strToolTip.arg(strFullData));410 }411 376 if (iElement & UIVisualElement_USBStuff) 412 377 { … … 420 385 if (!usbctl.isNull() && usbctl.GetEnabled()) 421 386 { 422 machineLogic()->actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu()->setEnabled(bIsStrictRunningOrPaused);423 424 387 CUSBDeviceVector devsvec = console.GetUSBDevices(); 425 388 for (int i = 0; i < devsvec.size(); ++ i) … … 433 396 else 434 397 { 435 machineLogic()->actionsPool()->action(UIActionIndex_Menu_USBDevices)->menu()->setEnabled(false);436 398 strFullData = tr("<br><nobr><b>USB Controller is disabled</b></nobr>", "USB device tooltip"); 437 399 } … … 440 402 } 441 403 } 442 if (iElement & UIVisualElement_VRDPStuff) 443 { 444 CVRDPServer vrdpsrv = machineLogic()->session().GetMachine().GetVRDPServer(); 445 if (!vrdpsrv.isNull()) 446 { 447 /* Update menu&status icon state */ 448 bool isVRDPEnabled = vrdpsrv.GetEnabled(); 449 machineLogic()->actionsPool()->action(UIActionIndex_Toggle_VRDP)->setChecked(isVRDPEnabled); 450 } 404 if (iElement & UIVisualElement_NetworkStuff) 405 { 406 ulong uMaxCount = vboxGlobal().virtualBox().GetSystemProperties().GetNetworkAdapterCount(); 407 ulong uCount = 0; 408 for (ulong uSlot = 0; uSlot < uMaxCount; ++ uSlot) 409 if (machine.GetNetworkAdapter(uSlot).GetEnabled()) 410 ++ uCount; 411 indicatorsPool()->indicator(UIIndicatorIndex_NetworkAdapters)->setState(uCount > 0 ? KDeviceActivity_Idle : KDeviceActivity_Null); 412 413 QString strToolTip = tr("<p style='white-space:pre'><nobr>Indicates the activity of the " 414 "network interfaces:</nobr>%1</p>", "Network adapters tooltip"); 415 QString strFullData; 416 417 for (ulong uSlot = 0; uSlot < uMaxCount; ++ uSlot) 418 { 419 CNetworkAdapter adapter = machine.GetNetworkAdapter(uSlot); 420 if (adapter.GetEnabled()) 421 strFullData += tr("<br><nobr><b>Adapter %1 (%2)</b>: cable %3</nobr>", "Network adapters tooltip") 422 .arg(uSlot + 1) 423 .arg(vboxGlobal().toString(adapter.GetAttachmentType())) 424 .arg(adapter.GetCableConnected() ? 425 tr("connected", "Network adapters tooltip") : 426 tr("disconnected", "Network adapters tooltip")); 427 } 428 429 if (strFullData.isNull()) 430 strFullData = tr("<br><nobr><b>All network adapters are disabled</b></nobr>", "Network adapters tooltip"); 431 432 indicatorsPool()->indicator(UIIndicatorIndex_NetworkAdapters)->setToolTip(strToolTip.arg(strFullData)); 451 433 } 452 434 if (iElement & UIVisualElement_SharedFolderStuff) … … 457 439 QString strFullData; 458 440 QMap<QString, QString> sfs; 459 460 machineLogic()->actionsPool()->action(UIActionIndex_Menu_SharedFolders)->menu()->setEnabled(true);461 441 462 442 /* Permanent folders */ … … 493 473 494 474 indicatorsPool()->indicator(UIIndicatorIndex_SharedFolders)->setToolTip(strToolTip.arg(strFullData)); 475 } 476 if (iElement & UIVisualElement_VRDPStuff) 477 { 478 CVRDPServer vrdpsrv = session().GetMachine().GetVRDPServer(); 479 if (!vrdpsrv.isNull()) 480 { 481 /* Update menu&status icon state */ 482 bool isVRDPEnabled = vrdpsrv.GetEnabled(); 483 machineLogic()->actionsPool()->action(UIActionIndex_Toggle_VRDP)->setChecked(isVRDPEnabled); 484 } 495 485 } 496 486 if (iElement & UIVisualElement_VirtualizationStuff) … … 582 572 #endif 583 573 574 void UIMachineWindowNormal::prepareConsoleConnections() 575 { 576 /* Parent class connections: */ 577 UIMachineWindow::prepareConsoleConnections(); 578 /* Other console connections: */ 579 connect(machineLogic()->uisession(), SIGNAL(sigMediumChange(const CMediumAttachment &)), 580 this, SLOT(sltMediumChange(const CMediumAttachment &))); 581 connect(machineLogic()->uisession(), SIGNAL(sigUSBControllerChange()), 582 this, SLOT(sltUSBControllerChange())); 583 connect(machineLogic()->uisession(), SIGNAL(sigUSBDeviceStateChange(const CUSBDevice &, bool, const CVirtualBoxErrorInfo &)), 584 this, SLOT(sltUSBDeviceStateChange())); 585 connect(machineLogic()->uisession(), SIGNAL(sigNetworkAdapterChange(const CNetworkAdapter &)), 586 this, SLOT(sltNetworkAdapterChange())); 587 connect(machineLogic()->uisession(), SIGNAL(sigSharedFolderChange()), 588 this, SLOT(sltSharedFolderChange())); 589 } 590 584 591 void UIMachineWindowNormal::prepareMenu() 585 592 { … … 622 629 this, SLOT(sltShowIndicatorsContextMenu(QIStateIndicator*, QContextMenuEvent*))); 623 630 631 /* USB Devices: */ 632 QIStateIndicator *pLedUSBDevices = indicatorsPool()->indicator(UIIndicatorIndex_USBDevices); 633 pIndicatorBoxHLayout->addWidget(pLedUSBDevices); 634 connect(pLedUSBDevices, SIGNAL(contextMenuRequested(QIStateIndicator*, QContextMenuEvent*)), 635 this, SLOT(sltShowIndicatorsContextMenu(QIStateIndicator*, QContextMenuEvent*))); 636 624 637 /* Network Adapters: */ 625 638 QIStateIndicator *pLedNetworkAdapters = indicatorsPool()->indicator(UIIndicatorIndex_NetworkAdapters); 626 639 pIndicatorBoxHLayout->addWidget(pLedNetworkAdapters); 627 640 connect(pLedNetworkAdapters, SIGNAL(contextMenuRequested(QIStateIndicator*, QContextMenuEvent*)), 628 this, SLOT(sltShowIndicatorsContextMenu(QIStateIndicator*, QContextMenuEvent*)));629 630 /* USB Devices: */631 QIStateIndicator *pLedUSBDevices = indicatorsPool()->indicator(UIIndicatorIndex_USBDevices);632 pIndicatorBoxHLayout->addWidget(pLedUSBDevices);633 connect(pLedUSBDevices, SIGNAL(contextMenuRequested(QIStateIndicator*, QContextMenuEvent*)),634 641 this, SLOT(sltShowIndicatorsContextMenu(QIStateIndicator*, QContextMenuEvent*))); 635 642 … … 689 696 return; // TODO: Do not create view for now! 690 697 691 CMachine machine = machineLogic()->session().GetMachine();698 CMachine machine = session().GetMachine(); 692 699 693 700 #ifdef VBOX_WITH_VIDEOHWACCEL … … 707 714 connect(machineView(), SIGNAL(keyboardStateChanged(int)), 708 715 indicatorsPool()->indicator(UIIndicatorIndex_Hostkey), SLOT(setState(int))); 709 // TODO: Update these 5 indicators through indicators pool!710 connect(machineView(), SIGNAL(mediaDriveChanged(VBoxDefs::MediumType)),711 this, SLOT(sltUpdateMediaDriveState(VBoxDefs::MediumType)));712 connect(machineView(), SIGNAL(networkStateChange()), this, SLOT(sltUpdateNetworkAdaptersState()));713 connect(machineView(), SIGNAL(usbStateChange()), this, SLOT(sltUpdateUsbState()));714 connect(machineView(), SIGNAL(sharedFoldersChanged()), this, SLOT(sltUpdateSharedFoldersState()));715 716 connect(machineView(), SIGNAL(mouseStateChanged(int)), this, SLOT(sltUpdateMouseState(int))); 716 717 } … … 722 723 723 724 /* Load this class settings: */ 724 CMachine machine = machineLogic()->session().GetMachine();725 CMachine machine = session().GetMachine(); 725 726 726 727 /* Extra-data settings */ … … 796 797 void UIMachineWindowNormal::saveWindowSettings() 797 798 { 798 CMachine machine = machineLogic()->session().GetMachine();799 CMachine machine = session().GetMachine(); 799 800 800 801 /* Extra-data settings */ -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.h
r26637 r26691 53 53 void sltTryClose(); 54 54 55 void sltMachineStateChanged(KMachineState machineState); 56 void sltMediumChange(const CMediumAttachment &attachment); 57 void sltUSBControllerChange(); 58 void sltUSBDeviceStateChange(); 59 void sltNetworkAdapterChange(); 60 void sltSharedFolderChange(); 61 55 62 void sltPrepareMenuMachine(); 56 63 void sltPrepareMenuDevices(); … … 64 71 void sltProcessGlobalSettingChange(const char *aPublicName, const char *aName); 65 72 66 void sltUpdateMediaDriveState(VBoxDefs::MediumType type);67 void sltUpdateNetworkAdaptersState();68 void sltUpdateUsbState();69 void sltUpdateSharedFoldersState();70 73 void sltUpdateMouseState(int iState); 71 74 … … 88 91 89 92 /* Prepare helpers: */ 93 void prepareConsoleConnections(); 90 94 void prepareMenu(); 91 95 void prepareStatusBar(); … … 100 104 void cleanupStatusBar(); 101 105 //void cleanupMenu(); 106 void cleanupConsoleConnections(); 102 107 103 108 /* Indicators pool: */
Note:
See TracChangeset
for help on using the changeset viewer.