Changeset 30549 in vbox
- Timestamp:
- Jul 1, 2010 1:01:39 AM (15 years ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox/src/runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp
r30544 r30549 49 49 #ifdef Q_WS_PM 50 50 # include "QIHotKeyEdit.h" 51 #endif /* defined (Q_WS_PM)*/51 #endif /* Q_WS_PM */ 52 52 53 53 #ifdef Q_WS_WIN … … 59 59 static UIMachineView *gView = 0; 60 60 static HHOOK gKbdHook = 0; 61 #endif /* defined (Q_WS_WIN)*/61 #endif /* Q_WS_WIN */ 62 62 63 63 #ifdef Q_WS_X11 … … 78 78 # endif 79 79 # include "XKeyboard.h" 80 #endif /* defined (Q_WS_X11)*/80 #endif /* Q_WS_X11 */ 81 81 82 82 #ifdef Q_WS_MAC … … 115 115 #ifdef VBOX_WITH_VIDEOHWACCEL 116 116 , bool bAccelerate2DVideo 117 #endif 117 #endif /* VBOX_WITH_VIDEOHWACCEL */ 118 118 ) 119 119 { … … 126 126 #ifdef VBOX_WITH_VIDEOHWACCEL 127 127 , bAccelerate2DVideo 128 #endif 128 #endif /* VBOX_WITH_VIDEOHWACCEL */ 129 129 ); 130 130 break; … … 134 134 #ifdef VBOX_WITH_VIDEOHWACCEL 135 135 , bAccelerate2DVideo 136 #endif 136 #endif /* VBOX_WITH_VIDEOHWACCEL */ 137 137 ); 138 138 break; … … 142 142 #ifdef VBOX_WITH_VIDEOHWACCEL 143 143 , bAccelerate2DVideo 144 #endif 144 #endif /* VBOX_WITH_VIDEOHWACCEL */ 145 145 ); 146 146 break; … … 160 160 return (m_bIsKeyboardCaptured ? UIViewStateType_KeyboardCaptured : 0) | 161 161 (m_bIsHostkeyPressed ? UIViewStateType_HostKeyPressed : 0); 162 } 163 164 void UIMachineView::sltMachineStateChanged() 165 { 166 /* Get machine state: */ 167 KMachineState state = uisession()->machineState(); 168 switch (state) 169 { 170 case KMachineState_Paused: 171 case KMachineState_TeleportingPausedVM: 172 { 173 if (vboxGlobal().vmRenderMode() != VBoxDefs::TimerMode && m_pFrameBuffer && 174 (state != KMachineState_TeleportingPausedVM || m_previousState != KMachineState_Teleporting)) 175 { 176 /* Take a screen snapshot. Note that TakeScreenShot() always needs a 32bpp image: */ 177 QImage shot = QImage(m_pFrameBuffer->width(), m_pFrameBuffer->height(), QImage::Format_RGB32); 178 /* If TakeScreenShot fails or returns no image, just show a black image. */ 179 shot.fill(0); 180 CDisplay dsp = session().GetConsole().GetDisplay(); 181 dsp.TakeScreenShot(screenId(), shot.bits(), shot.width(), shot.height()); 182 /* TakeScreenShot() may fail if, e.g. the Paused notification was delivered 183 * after the machine execution was resumed. It's not fatal: */ 184 if (dsp.isOk()) 185 { 186 dimImage(shot); 187 } 188 m_pauseShot = QPixmap::fromImage(shot); 189 /* Fully repaint to pick up m_pauseShot: */ 190 viewport()->repaint(); 191 } 192 /* Reuse the focus event handler to uncapture keyboard: */ 193 if (hasFocus()) 194 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */); 195 break; 196 } 197 case KMachineState_Stuck: 198 { 199 /* Reuse the focus event handler to uncapture keyboard: */ 200 if (hasFocus()) 201 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */); 202 break; 203 } 204 case KMachineState_Running: 205 { 206 if ( m_previousState == KMachineState_Paused 207 || m_previousState == KMachineState_TeleportingPausedVM 208 || m_previousState == KMachineState_Restoring) 209 { 210 if (vboxGlobal().vmRenderMode() != VBoxDefs::TimerMode && m_pFrameBuffer) 211 { 212 /* Reset the pixmap to free memory: */ 213 m_pauseShot = QPixmap(); 214 /* Ask for full guest display update (it will also update 215 * the viewport through IFramebuffer::NotifyUpdate): */ 216 CDisplay dsp = session().GetConsole().GetDisplay(); 217 dsp.InvalidateAndUpdate(); 218 } 219 } 220 /* Reuse the focus event handler to capture keyboard: */ 221 if (hasFocus()) 222 focusEvent(true /* aHasFocus */); 223 break; 224 } 225 default: 226 break; 227 } 228 229 m_previousState = state; 162 230 } 163 231 … … 166 234 #ifdef VBOX_WITH_VIDEOHWACCEL 167 235 , bool bAccelerate2DVideo 168 #endif 236 #endif /* VBOX_WITH_VIDEOHWACCEL */ 169 237 ) 170 238 : QAbstractScrollArea(pMachineWindow->machineWindow()) … … 195 263 } 196 264 197 UISession* UIMachineView::uisession() const198 {199 return machineLogic()->uisession();200 }201 202 CSession& UIMachineView::session()203 {204 return uisession()->session();205 }206 207 QSize UIMachineView::sizeHint() const208 {209 #ifdef VBOX_WITH_DEBUGGER210 // TODO: Fix all DEBUGGER stuff!211 /* HACK ALERT! Really ugly workaround for the resizing to 9x1 done by DevVGA if provoked before power on. */212 QSize fb(m_pFrameBuffer->width(), m_pFrameBuffer->height());213 if ((fb.width() < 16 || fb.height() < 16) && (vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled()))214 fb = QSize(640, 480);215 return QSize(fb.width() + frameWidth() * 2, fb.height() + frameWidth() * 2);216 #else217 return QSize(m_pFrameBuffer->width() + frameWidth() * 2, m_pFrameBuffer->height() + frameWidth() * 2);218 #endif219 }220 221 int UIMachineView::contentsX() const222 {223 return horizontalScrollBar()->value();224 }225 226 int UIMachineView::contentsY() const227 {228 return verticalScrollBar()->value();229 }230 231 int UIMachineView::contentsWidth() const232 {233 return m_pFrameBuffer->width();234 }235 236 int UIMachineView::contentsHeight() const237 {238 return m_pFrameBuffer->height();239 }240 241 int UIMachineView::visibleWidth() const242 {243 return horizontalScrollBar()->pageStep();244 }245 246 int UIMachineView::visibleHeight() const247 {248 return verticalScrollBar()->pageStep();249 }250 251 UIMachineLogic* UIMachineView::machineLogic() const252 {253 return machineWindowWrapper()->machineLogic();254 }255 256 QSize UIMachineView::desktopGeometry() const257 {258 QSize geometry;259 switch (m_desktopGeometryType)260 {261 case DesktopGeo_Fixed:262 case DesktopGeo_Automatic:263 geometry = QSize(qMax(m_desktopGeometry.width(), m_storedConsoleSize.width()),264 qMax(m_desktopGeometry.height(), m_storedConsoleSize.height()));265 break;266 case DesktopGeo_Any:267 geometry = QSize(0, 0);268 break;269 default:270 AssertMsgFailed(("Bad geometry type %d!\n", m_desktopGeometryType));271 }272 return geometry;273 }274 275 QSize UIMachineView::guestSizeHint()276 {277 /* Result: */278 QSize sizeHint;279 280 /* Get current machine: */281 CMachine machine = session().GetMachine();282 283 /* Load machine view hint: */284 QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) :285 QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId);286 QString strValue = machine.GetExtraData(strKey);287 288 bool ok = true;289 int width = 0, height = 0;290 if (ok)291 width = strValue.section(',', 0, 0).toInt(&ok);292 if (ok)293 height = strValue.section(',', 1, 1).toInt(&ok);294 295 if (ok /* If previous parameters were read correctly! */)296 {297 /* Compose guest size hint from loaded values: */298 sizeHint = QSize(width, height);299 }300 else301 {302 /* Compose guest size hint from default attributes: */303 sizeHint = QSize(800, 600);304 }305 306 /* Return result: */307 return sizeHint;308 }309 310 void UIMachineView::setDesktopGeometry(DesktopGeo geometry, int aWidth, int aHeight)311 {312 switch (geometry)313 {314 case DesktopGeo_Fixed:315 m_desktopGeometryType = DesktopGeo_Fixed;316 if (aWidth != 0 && aHeight != 0)317 m_desktopGeometry = QSize(aWidth, aHeight);318 else319 m_desktopGeometry = QSize(0, 0);320 storeConsoleSize(0, 0);321 break;322 case DesktopGeo_Automatic:323 m_desktopGeometryType = DesktopGeo_Automatic;324 m_desktopGeometry = QSize(0, 0);325 storeConsoleSize(0, 0);326 break;327 case DesktopGeo_Any:328 m_desktopGeometryType = DesktopGeo_Any;329 m_desktopGeometry = QSize(0, 0);330 break;331 default:332 AssertMsgFailed(("Invalid desktop geometry type %d\n", geometry));333 m_desktopGeometryType = DesktopGeo_Invalid;334 }335 }336 337 void UIMachineView::storeConsoleSize(int iWidth, int iHeight)338 {339 m_storedConsoleSize = QSize(iWidth, iHeight);340 }341 342 void UIMachineView::storeGuestSizeHint(const QSize &sizeHint)343 {344 /* Get current machine: */345 CMachine machine = session().GetMachine();346 347 /* Save machine view hint: */348 QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) :349 QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId);350 QString strValue = QString("%1,%2").arg(sizeHint.width()).arg(sizeHint.height());351 machine.SetExtraData(strKey, strValue);352 }353 354 void UIMachineView::updateSliders()355 {356 QSize p = viewport()->size();357 QSize m = maximumViewportSize();358 359 QSize v = QSize(frameBuffer()->width(), frameBuffer()->height());360 /* No scroll bars needed: */361 if (m.expandedTo(v) == m)362 p = m;363 364 horizontalScrollBar()->setRange(0, v.width() - p.width());365 verticalScrollBar()->setRange(0, v.height() - p.height());366 horizontalScrollBar()->setPageStep(p.width());367 verticalScrollBar()->setPageStep(p.height());368 }369 370 265 void UIMachineView::prepareFrameBuffer() 371 266 { … … 381 276 pViewport = new VBoxViewport(this); 382 277 } 383 #else 278 #else /* VBOX_GUI_USE_QGLFB */ 384 279 VBoxViewport *pViewport = new VBoxViewport(this); 385 #endif 280 #endif /* !VBOX_GUI_USE_QGLFB */ 386 281 setViewport(pViewport); 387 282 … … 411 306 else 412 307 m_pFrameBuffer = new UIFrameBufferQImage(this); 413 # else 308 # else /* VBOX_WITH_VIDEOHWACCEL */ 414 309 m_pFrameBuffer = new UIFrameBufferQImage(this); 415 # endif 310 # endif /* !VBOX_WITH_VIDEOHWACCEL */ 416 311 break; 417 312 #endif /* VBOX_GUI_USE_QIMAGE */ … … 432 327 /* This is somehow necessary to prevent strange X11 warnings on i386 and segfaults on x86_64: */ 433 328 XFlush(QX11Info::display()); 434 # endif 329 # endif /* Q_WS_X11 */ 435 330 # if defined(VBOX_WITH_VIDEOHWACCEL) && defined(DEBUG_misha) /* not tested yet */ 436 331 if (m_fAccelerate2DVideo) … … 493 388 else 494 389 m_pFrameBuffer = new UIFrameBufferQuartz2D(this); 495 # else 390 # else /* VBOX_WITH_VIDEOHWACCEL */ 496 391 m_pFrameBuffer = new UIFrameBufferQuartz2D(this); 497 # endif 392 # endif /* !VBOX_WITH_VIDEOHWACCEL */ 498 393 break; 499 394 #endif /* VBOX_GUI_USE_QUARTZ2D */ … … 517 412 } 518 413 if (fb.raw() != m_pFrameBuffer) /* <-this will evaluate to true iff m_fAccelerate2DVideo is disabled or iff no framebuffer is yet assigned */ 519 #endif 414 #endif /* VBOX_WITH_VIDEOHWACCEL */ 520 415 { 521 416 m_pFrameBuffer->AddRef(); … … 558 453 Assert(ok); 559 454 NOREF(ok); 560 #endif 455 #endif /* Q_WS_PM */ 561 456 } 562 457 … … 587 482 /* Initialize the X keyboard subsystem: */ 588 483 initMappedX11Keyboard(QX11Info::display(), vboxGlobal().settings().publicProperty("GUI/RemapScancodes")); 589 #endif 484 #endif /* Q_WS_X11 */ 590 485 591 486 /* Remember the desktop geometry and register for geometry … … 651 546 } 652 547 else 653 #endif 548 #endif /* VBOX_WITH_VIDEOHWACCEL */ 654 549 { 655 550 /* Warn framebuffer about its no more necessary: */ … … 666 561 } 667 562 563 UIMachineLogic* UIMachineView::machineLogic() const 564 { 565 return machineWindowWrapper()->machineLogic(); 566 } 567 568 UISession* UIMachineView::uisession() const 569 { 570 return machineLogic()->uisession(); 571 } 572 573 CSession& UIMachineView::session() 574 { 575 return uisession()->session(); 576 } 577 578 QSize UIMachineView::sizeHint() const 579 { 580 #ifdef VBOX_WITH_DEBUGGER 581 // TODO: Fix all DEBUGGER stuff! 582 /* HACK ALERT! Really ugly workaround for the resizing to 9x1 done by DevVGA if provoked before power on. */ 583 QSize fb(m_pFrameBuffer->width(), m_pFrameBuffer->height()); 584 if ((fb.width() < 16 || fb.height() < 16) && (vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled())) 585 fb = QSize(640, 480); 586 return QSize(fb.width() + frameWidth() * 2, fb.height() + frameWidth() * 2); 587 #else /* VBOX_WITH_DEBUGGER */ 588 return QSize(m_pFrameBuffer->width() + frameWidth() * 2, m_pFrameBuffer->height() + frameWidth() * 2); 589 #endif /* !VBOX_WITH_DEBUGGER */ 590 } 591 592 int UIMachineView::contentsX() const 593 { 594 return horizontalScrollBar()->value(); 595 } 596 597 int UIMachineView::contentsY() const 598 { 599 return verticalScrollBar()->value(); 600 } 601 602 int UIMachineView::contentsWidth() const 603 { 604 return m_pFrameBuffer->width(); 605 } 606 607 int UIMachineView::contentsHeight() const 608 { 609 return m_pFrameBuffer->height(); 610 } 611 612 int UIMachineView::visibleWidth() const 613 { 614 return horizontalScrollBar()->pageStep(); 615 } 616 617 int UIMachineView::visibleHeight() const 618 { 619 return verticalScrollBar()->pageStep(); 620 } 621 622 QSize UIMachineView::desktopGeometry() const 623 { 624 QSize geometry; 625 switch (m_desktopGeometryType) 626 { 627 case DesktopGeo_Fixed: 628 case DesktopGeo_Automatic: 629 geometry = QSize(qMax(m_desktopGeometry.width(), m_storedConsoleSize.width()), 630 qMax(m_desktopGeometry.height(), m_storedConsoleSize.height())); 631 break; 632 case DesktopGeo_Any: 633 geometry = QSize(0, 0); 634 break; 635 default: 636 AssertMsgFailed(("Bad geometry type %d!\n", m_desktopGeometryType)); 637 } 638 return geometry; 639 } 640 641 QSize UIMachineView::guestSizeHint() 642 { 643 /* Result: */ 644 QSize sizeHint; 645 646 /* Get current machine: */ 647 CMachine machine = session().GetMachine(); 648 649 /* Load machine view hint: */ 650 QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) : 651 QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId); 652 QString strValue = machine.GetExtraData(strKey); 653 654 bool ok = true; 655 int width = 0, height = 0; 656 if (ok) 657 width = strValue.section(',', 0, 0).toInt(&ok); 658 if (ok) 659 height = strValue.section(',', 1, 1).toInt(&ok); 660 661 if (ok /* If previous parameters were read correctly! */) 662 { 663 /* Compose guest size hint from loaded values: */ 664 sizeHint = QSize(width, height); 665 } 666 else 667 { 668 /* Compose guest size hint from default attributes: */ 669 sizeHint = QSize(800, 600); 670 } 671 672 /* Return result: */ 673 return sizeHint; 674 } 675 676 void UIMachineView::setDesktopGeometry(DesktopGeo geometry, int aWidth, int aHeight) 677 { 678 switch (geometry) 679 { 680 case DesktopGeo_Fixed: 681 m_desktopGeometryType = DesktopGeo_Fixed; 682 if (aWidth != 0 && aHeight != 0) 683 m_desktopGeometry = QSize(aWidth, aHeight); 684 else 685 m_desktopGeometry = QSize(0, 0); 686 storeConsoleSize(0, 0); 687 break; 688 case DesktopGeo_Automatic: 689 m_desktopGeometryType = DesktopGeo_Automatic; 690 m_desktopGeometry = QSize(0, 0); 691 storeConsoleSize(0, 0); 692 break; 693 case DesktopGeo_Any: 694 m_desktopGeometryType = DesktopGeo_Any; 695 m_desktopGeometry = QSize(0, 0); 696 break; 697 default: 698 AssertMsgFailed(("Invalid desktop geometry type %d\n", geometry)); 699 m_desktopGeometryType = DesktopGeo_Invalid; 700 } 701 } 702 703 void UIMachineView::storeConsoleSize(int iWidth, int iHeight) 704 { 705 m_storedConsoleSize = QSize(iWidth, iHeight); 706 } 707 708 void UIMachineView::storeGuestSizeHint(const QSize &sizeHint) 709 { 710 /* Get current machine: */ 711 CMachine machine = session().GetMachine(); 712 713 /* Save machine view hint: */ 714 QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) : 715 QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId); 716 QString strValue = QString("%1,%2").arg(sizeHint.width()).arg(sizeHint.height()); 717 machine.SetExtraData(strKey, strValue); 718 } 719 720 void UIMachineView::updateSliders() 721 { 722 QSize p = viewport()->size(); 723 QSize m = maximumViewportSize(); 724 725 QSize v = QSize(frameBuffer()->width(), frameBuffer()->height()); 726 /* No scroll bars needed: */ 727 if (m.expandedTo(v) == m) 728 p = m; 729 730 horizontalScrollBar()->setRange(0, v.width() - p.width()); 731 verticalScrollBar()->setRange(0, v.height() - p.height()); 732 horizontalScrollBar()->setPageStep(p.width()); 733 verticalScrollBar()->setPageStep(p.height()); 734 } 735 736 void UIMachineView::fixModifierState(LONG *piCodes, uint *puCount) 737 { 738 /* Synchronize the views of the host and the guest to the modifier keys. 739 * This function will add up to 6 additional keycodes to codes. */ 740 741 #if defined(Q_WS_X11) 742 743 Window wDummy1, wDummy2; 744 int iDummy3, iDummy4, iDummy5, iDummy6; 745 unsigned uMask; 746 unsigned uKeyMaskNum = 0, uKeyMaskCaps = 0, uKeyMaskScroll = 0; 747 748 uKeyMaskCaps = LockMask; 749 XModifierKeymap* map = XGetModifierMapping(QX11Info::display()); 750 KeyCode keyCodeNum = XKeysymToKeycode(QX11Info::display(), XK_Num_Lock); 751 KeyCode keyCodeScroll = XKeysymToKeycode(QX11Info::display(), XK_Scroll_Lock); 752 753 for (int i = 0; i < 8; ++ i) 754 { 755 if (keyCodeNum != NoSymbol && map->modifiermap[map->max_keypermod * i] == keyCodeNum) 756 uKeyMaskNum = 1 << i; 757 else if (keyCodeScroll != NoSymbol && map->modifiermap[map->max_keypermod * i] == keyCodeScroll) 758 uKeyMaskScroll = 1 << i; 759 } 760 XQueryPointer(QX11Info::display(), DefaultRootWindow(QX11Info::display()), &wDummy1, &wDummy2, 761 &iDummy3, &iDummy4, &iDummy5, &iDummy6, &uMask); 762 XFreeModifiermap(map); 763 764 if (uisession()->numLockAdaptionCnt() && (uisession()->isNumLock() ^ !!(uMask & uKeyMaskNum))) 765 { 766 uisession()->setNumLockAdaptionCnt(uisession()->numLockAdaptionCnt() - 1); 767 piCodes[(*puCount)++] = 0x45; 768 piCodes[(*puCount)++] = 0x45 | 0x80; 769 } 770 if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(uMask & uKeyMaskCaps))) 771 { 772 uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1); 773 piCodes[(*puCount)++] = 0x3a; 774 piCodes[(*puCount)++] = 0x3a | 0x80; 775 /* Some keyboard layouts require shift to be pressed to break 776 * capslock. For simplicity, only do this if shift is not 777 * already held down. */ 778 if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed)) 779 { 780 piCodes[(*puCount)++] = 0x2a; 781 piCodes[(*puCount)++] = 0x2a | 0x80; 782 } 783 } 784 785 #elif defined(Q_WS_WIN) 786 787 if (uisession()->numLockAdaptionCnt() && (uisession()->isNumLock() ^ !!(GetKeyState(VK_NUMLOCK)))) 788 { 789 uisession()->setNumLockAdaptionCnt(uisession()->numLockAdaptionCnt() - 1); 790 piCodes[(*puCount)++] = 0x45; 791 piCodes[(*puCount)++] = 0x45 | 0x80; 792 } 793 if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(GetKeyState(VK_CAPITAL)))) 794 { 795 uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1); 796 piCodes[(*puCount)++] = 0x3a; 797 piCodes[(*puCount)++] = 0x3a | 0x80; 798 /* Some keyboard layouts require shift to be pressed to break 799 * capslock. For simplicity, only do this if shift is not 800 * already held down. */ 801 if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed)) 802 { 803 piCodes[(*puCount)++] = 0x2a; 804 piCodes[(*puCount)++] = 0x2a | 0x80; 805 } 806 } 807 808 #elif defined(Q_WS_MAC) 809 810 /* if (uisession()->numLockAdaptionCnt()) ... - NumLock isn't implemented by Mac OS X so ignore it. */ 811 if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(::GetCurrentEventKeyModifiers() & alphaLock))) 812 { 813 uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1); 814 piCodes[(*puCount)++] = 0x3a; 815 piCodes[(*puCount)++] = 0x3a | 0x80; 816 /* Some keyboard layouts require shift to be pressed to break 817 * capslock. For simplicity, only do this if shift is not 818 * already held down. */ 819 if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed)) 820 { 821 piCodes[(*puCount)++] = 0x2a; 822 piCodes[(*puCount)++] = 0x2a | 0x80; 823 } 824 } 825 826 #else 827 828 //#warning Adapt UIMachineView::fixModifierState 829 830 #endif 831 } 832 833 QPoint UIMachineView::viewportToContents(const QPoint &vp) const 834 { 835 return QPoint(vp.x() + contentsX(), vp.y() + contentsY()); 836 } 837 838 void UIMachineView::scrollBy(int dx, int dy) 839 { 840 horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dx); 841 verticalScrollBar()->setValue(verticalScrollBar()->value() + dy); 842 } 843 844 void UIMachineView::emitKeyboardStateChanged() 845 { 846 emit keyboardStateChanged(keyboardState()); 847 } 848 849 void UIMachineView::captureKbd(bool fCapture, bool fEmitSignal /* = true */) 850 { 851 if (m_bIsKeyboardCaptured == fCapture) 852 return; 853 854 #if defined(Q_WS_WIN) 855 /* On Win32, keyboard grabbing is ineffective, a low-level keyboard hook is used instead. */ 856 #elif defined(Q_WS_X11) 857 /* On X11, we are using passive XGrabKey for normal (windowed) mode 858 * instead of XGrabKeyboard (called by QWidget::grabKeyboard()) 859 * because XGrabKeyboard causes a problem under metacity - a window cannot be moved 860 * using the mouse if it is currently actively grabing the keyboard; 861 * For static modes we are using usual (active) keyboard grabbing. */ 862 switch (machineLogic()->visualStateType()) 863 { 864 /* If window is moveable we are making passive keyboard grab: */ 865 case UIVisualStateType_Normal: 866 { 867 if (fCapture) 868 XGrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync); 869 else 870 XUngrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId()); 871 break; 872 } 873 /* If window is NOT moveable we are making active keyboard grab: */ 874 case UIVisualStateType_Fullscreen: 875 case UIVisualStateType_Seamless: 876 { 877 if (fCapture) 878 { 879 /* Keyboard grabbing can fail because of some keyboard shortcut is still grabbed by window manager. 880 * We can't be sure this shortcut will be released at all, so we will retry to grab keyboard for 50 times, 881 * and after we will just ignore that issue: */ 882 int cTriesLeft = 50; 883 while (cTriesLeft && XGrabKeyboard(QX11Info::display(), machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync, CurrentTime)) { --cTriesLeft; } 884 } 885 else 886 XUngrabKeyboard(QX11Info::display(), CurrentTime); 887 break; 888 } 889 /* Should we try to grab keyboard in default case? I think - NO. */ 890 default: 891 break; 892 } 893 #elif defined(Q_WS_MAC) 894 /* On Mac OS X, we use the Qt methods + disabling global hot keys + watching modifiers 895 * (for right/left separation). */ 896 if (fCapture) 897 { 898 ::DarwinDisableGlobalHotKeys(true); 899 grabKeyboard(); 900 } 901 else 902 { 903 ::DarwinDisableGlobalHotKeys(false); 904 releaseKeyboard(); 905 } 906 #else 907 if (fCapture) 908 grabKeyboard(); 909 else 910 releaseKeyboard(); 911 #endif 912 913 m_bIsKeyboardCaptured = fCapture; 914 915 if (fEmitSignal) 916 emitKeyboardStateChanged(); 917 } 918 919 void UIMachineView::saveKeyStates() 920 { 921 ::memcpy(m_pressedKeysCopy, m_pressedKeys, sizeof(m_pressedKeys)); 922 } 923 924 void UIMachineView::releaseAllPressedKeys(bool aReleaseHostKey /* = true */) 925 { 926 CKeyboard keyboard = session().GetConsole().GetKeyboard(); 927 bool fSentRESEND = false; 928 929 /* Send a dummy scan code (RESEND) to prevent the guest OS from recognizing 930 * a single key click (for ex., Alt) and performing an unwanted action 931 * (for ex., activating the menu) when we release all pressed keys below. 932 * Note, that it's just a guess that sending RESEND will give the desired 933 * effect :), but at least it works with NT and W2k guests. */ 934 for (uint i = 0; i < SIZEOF_ARRAY (m_pressedKeys); i++) 935 { 936 if (m_pressedKeys[i] & IsKeyPressed) 937 { 938 if (!fSentRESEND) 939 { 940 keyboard.PutScancode (0xFE); 941 fSentRESEND = true; 942 } 943 keyboard.PutScancode(i | 0x80); 944 } 945 else if (m_pressedKeys[i] & IsExtKeyPressed) 946 { 947 if (!fSentRESEND) 948 { 949 keyboard.PutScancode(0xFE); 950 fSentRESEND = true; 951 } 952 QVector <LONG> codes(2); 953 codes[0] = 0xE0; 954 codes[1] = i | 0x80; 955 keyboard.PutScancodes(codes); 956 } 957 m_pressedKeys[i] = 0; 958 } 959 960 if (aReleaseHostKey) 961 m_bIsHostkeyPressed = false; 962 963 #ifdef Q_WS_MAC 964 /* Clear most of the modifiers: */ 965 m_darwinKeyModifiers &= 966 alphaLock | kEventKeyModifierNumLockMask | 967 (aReleaseHostKey ? 0 : ::DarwinKeyCodeToDarwinModifierMask (m_globalSettings.hostKey())); 968 #endif /* Q_WS_MAC */ 969 970 emitKeyboardStateChanged(); 971 } 972 973 void UIMachineView::sendChangedKeyStates() 974 { 975 QVector <LONG> codes(2); 976 CKeyboard keyboard = session().GetConsole().GetKeyboard(); 977 for (uint i = 0; i < SIZEOF_ARRAY(m_pressedKeys); ++ i) 978 { 979 uint8_t os = m_pressedKeysCopy[i]; 980 uint8_t ns = m_pressedKeys[i]; 981 if ((os & IsKeyPressed) != (ns & IsKeyPressed)) 982 { 983 codes[0] = i; 984 if (!(ns & IsKeyPressed)) 985 codes[0] |= 0x80; 986 keyboard.PutScancode(codes[0]); 987 } 988 else if ((os & IsExtKeyPressed) != (ns & IsExtKeyPressed)) 989 { 990 codes[0] = 0xE0; 991 codes[1] = i; 992 if (!(ns & IsExtKeyPressed)) 993 codes[1] |= 0x80; 994 keyboard.PutScancodes(codes); 995 } 996 } 997 } 998 999 void UIMachineView::dimImage(QImage &img) 1000 { 1001 for (int y = 0; y < img.height(); ++ y) 1002 { 1003 if (y % 2) 1004 { 1005 if (img.depth() == 32) 1006 { 1007 for (int x = 0; x < img.width(); ++ x) 1008 { 1009 int gray = qGray(img.pixel (x, y)) / 2; 1010 img.setPixel(x, y, qRgb (gray, gray, gray)); 1011 } 1012 } 1013 else 1014 { 1015 ::memset(img.scanLine (y), 0, img.bytesPerLine()); 1016 } 1017 } 1018 else 1019 { 1020 if (img.depth() == 32) 1021 { 1022 for (int x = 0; x < img.width(); ++ x) 1023 { 1024 int gray = (2 * qGray (img.pixel (x, y))) / 3; 1025 img.setPixel(x, y, qRgb (gray, gray, gray)); 1026 } 1027 } 1028 } 1029 } 1030 } 1031 1032 #ifdef VBOX_WITH_VIDEOHWACCEL 1033 void UIMachineView::scrollContentsBy(int dx, int dy) 1034 { 1035 if (m_pFrameBuffer) 1036 { 1037 m_pFrameBuffer->viewportScrolled(dx, dy); 1038 } 1039 QAbstractScrollArea::scrollContentsBy(dx, dy); 1040 } 1041 #endif /* VBOX_WITH_VIDEOHWACCEL */ 1042 1043 #ifdef Q_WS_MAC 1044 void UIMachineView::updateDockIcon() 1045 { 1046 machineLogic()->updateDockIcon(); 1047 } 1048 1049 CGImageRef UIMachineView::vmContentImage() 1050 { 1051 if (!m_pauseShot.isNull()) 1052 { 1053 CGImageRef pauseImg = ::darwinToCGImageRef(&m_pauseShot); 1054 /* Use the pause image as background */ 1055 return pauseImg; 1056 } 1057 else 1058 { 1059 # ifdef VBOX_GUI_USE_QUARTZ2D 1060 if (vboxGlobal().vmRenderMode() == VBoxDefs::Quartz2DMode) 1061 { 1062 /* If the render mode is Quartz2D we could use the CGImageRef 1063 * of the framebuffer for the dock icon creation. This saves 1064 * some conversion time. */ 1065 CGImageRef image = static_cast<UIFrameBufferQuartz2D*>(m_pFrameBuffer)->imageRef(); 1066 CGImageRetain(image); /* Retain it, cause the consumer will release it. */ 1067 return image; 1068 } 1069 else 1070 # endif /* VBOX_GUI_USE_QUARTZ2D */ 1071 /* In image mode we have to create the image ref out of the 1072 * framebuffer */ 1073 return frameBuffertoCGImageRef(m_pFrameBuffer); 1074 } 1075 return 0; 1076 } 1077 1078 CGImageRef UIMachineView::frameBuffertoCGImageRef(UIFrameBuffer *pFrameBuffer) 1079 { 1080 CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); 1081 Assert(cs); 1082 /* Create the image copy of the framebuffer */ 1083 CGDataProviderRef dp = CGDataProviderCreateWithData(pFrameBuffer, pFrameBuffer->address(), pFrameBuffer->bitsPerPixel() / 8 * pFrameBuffer->width() * pFrameBuffer->height(), NULL); 1084 Assert(dp); 1085 CGImageRef ir = CGImageCreate(pFrameBuffer->width(), pFrameBuffer->height(), 8, 32, pFrameBuffer->bytesPerLine(), cs, 1086 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host, dp, 0, false, 1087 kCGRenderingIntentDefault); 1088 Assert(ir); 1089 CGDataProviderRelease(dp); 1090 CGColorSpaceRelease(cs); 1091 1092 return ir; 1093 } 1094 #endif /* Q_WS_MAC */ 1095 668 1096 bool UIMachineView::event(QEvent *pEvent) 669 1097 { … … 706 1134 return true; 707 1135 } 708 #endif 1136 #endif /* VBOX_WITH_VIDEOHWACCEL */ 709 1137 710 1138 case QEvent::KeyPress: … … 849 1277 return true; 850 1278 } 851 #endif 1279 #endif /* Q_WS_MAC */ 852 1280 853 1281 default: … … 936 1364 } 937 1365 938 void UIMachineView::sltMachineStateChanged()939 {940 /* Get machine state: */941 KMachineState state = uisession()->machineState();942 switch (state)943 {944 case KMachineState_Paused:945 case KMachineState_TeleportingPausedVM:946 {947 if (vboxGlobal().vmRenderMode() != VBoxDefs::TimerMode && m_pFrameBuffer &&948 (state != KMachineState_TeleportingPausedVM || m_previousState != KMachineState_Teleporting))949 {950 /* Take a screen snapshot. Note that TakeScreenShot() always needs a 32bpp image: */951 QImage shot = QImage(m_pFrameBuffer->width(), m_pFrameBuffer->height(), QImage::Format_RGB32);952 /* If TakeScreenShot fails or returns no image, just show a black image. */953 shot.fill(0);954 CDisplay dsp = session().GetConsole().GetDisplay();955 dsp.TakeScreenShot(screenId(), shot.bits(), shot.width(), shot.height());956 /* TakeScreenShot() may fail if, e.g. the Paused notification was delivered957 * after the machine execution was resumed. It's not fatal: */958 if (dsp.isOk())959 {960 dimImage(shot);961 }962 m_pauseShot = QPixmap::fromImage(shot);963 /* Fully repaint to pick up m_pauseShot: */964 viewport()->repaint();965 }966 /* Reuse the focus event handler to uncapture keyboard: */967 if (hasFocus())968 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */);969 break;970 }971 case KMachineState_Stuck:972 {973 /* Reuse the focus event handler to uncapture keyboard: */974 if (hasFocus())975 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */);976 break;977 }978 case KMachineState_Running:979 {980 if ( m_previousState == KMachineState_Paused981 || m_previousState == KMachineState_TeleportingPausedVM982 || m_previousState == KMachineState_Restoring)983 {984 if (vboxGlobal().vmRenderMode() != VBoxDefs::TimerMode && m_pFrameBuffer)985 {986 /* Reset the pixmap to free memory: */987 m_pauseShot = QPixmap();988 /* Ask for full guest display update (it will also update989 * the viewport through IFramebuffer::NotifyUpdate): */990 CDisplay dsp = session().GetConsole().GetDisplay();991 dsp.InvalidateAndUpdate();992 }993 }994 /* Reuse the focus event handler to capture keyboard: */995 if (hasFocus())996 focusEvent(true /* aHasFocus */);997 break;998 }999 default:1000 break;1001 }1002 1003 m_previousState = state;1004 }1005 1006 1366 void UIMachineView::focusEvent(bool fHasFocus, bool fReleaseHostKey /* = true */) 1007 1367 { 1008 1368 if (fHasFocus) 1009 1369 { 1010 #ifdef Q_WS_WIN 321370 #ifdef Q_WS_WIN 1011 1371 if (!uisession()->isAutoCaptureDisabled() && m_globalSettings.autoCapture() && GetAncestor(winId(), GA_ROOT) == GetForegroundWindow()) 1012 #else 1372 #else /* Q_WS_WIN */ 1013 1373 if (!uisession()->isAutoCaptureDisabled() && m_globalSettings.autoCapture()) 1014 #endif 1374 #endif /* !Q_WS_WIN */ 1015 1375 { 1016 1376 captureKbd(true); … … 1211 1571 * mouse is immediately ungrabbed. */ 1212 1572 qApp->processEvents(); 1213 #endif 1573 #endif /* Q_WS_X11 */ 1214 1574 if (m_bIsKeyboardCaptured) 1215 1575 machineLogic()->mouseHandler()->captureMouse(screenId()); … … 1244 1604 { 1245 1605 bool processed = false; 1246 #if defined (Q_WS_WIN 32)1606 #if defined (Q_WS_WIN) 1247 1607 NOREF(pUniKey); 1248 1608 int n = GetKeyboardLayoutList(0, NULL); … … 1300 1660 Assert(!keyboard.isNull()); 1301 1661 1302 #if defined (Q_WS_WIN32)1662 #ifdef Q_WS_WIN 1303 1663 /* send pending WM_PAINT events */ 1304 1664 ::UpdateWindow(viewport()->winId()); 1305 #endif 1665 #endif /* Q_WS_WIN */ 1306 1666 1307 1667 std::vector <LONG> scancodes(codes, &codes[count]); … … 1362 1722 } 1363 1723 1364 #if defined(Q_WS_WIN 32)1724 #if defined(Q_WS_WIN) 1365 1725 1366 1726 LRESULT CALLBACK UIMachineView::lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) … … 1686 2046 #elif defined(Q_WS_MAC) 1687 2047 2048 void UIMachineView::darwinGrabKeyboardEvents(bool fGrab) 2049 { 2050 m_fKeyboardGrabbed = fGrab; 2051 if (fGrab) 2052 { 2053 /* Disable mouse and keyboard event compression/delaying to make sure we *really* get all of the events. */ 2054 ::CGSetLocalEventsSuppressionInterval(0.0); 2055 machineLogic()->mouseHandler()->setMouseCoalescingEnabled(false); 2056 2057 /* Register the event callback/hook and grab the keyboard. */ 2058 UICocoaApplication::instance()->registerForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown | NSKeyUp | | NSFlagsChanged */, 2059 UIMachineView::darwinEventHandlerProc, this); 2060 2061 ::DarwinGrabKeyboard (false); 2062 } 2063 else 2064 { 2065 ::DarwinReleaseKeyboard(); 2066 UICocoaApplication::instance()->unregisterForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown | NSKeyUp | | NSFlagsChanged */, 2067 UIMachineView::darwinEventHandlerProc, this); 2068 } 2069 } 2070 2071 bool UIMachineView::darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser) 2072 { 2073 UIMachineView *view = (UIMachineView*)pvUser; 2074 EventRef inEvent = (EventRef)pvCarbonEvent; 2075 UInt32 eventClass = ::GetEventClass(inEvent); 2076 2077 /* Check if this is an application key combo. In that case we will not pass 2078 * the event to the guest, but let the host process it. */ 2079 if (::darwinIsApplicationCommand(pvCocoaEvent)) 2080 return false; 2081 2082 /* All keyboard class events needs to be handled. */ 2083 if (eventClass == kEventClassKeyboard) 2084 { 2085 if (view->darwinKeyboardEvent (pvCocoaEvent, inEvent)) 2086 return true; 2087 } 2088 /* Pass the event along. */ 2089 return false; 2090 } 2091 1688 2092 bool UIMachineView::darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent) 1689 2093 { … … 1770 2174 } 1771 2175 1772 void UIMachineView::darwinGrabKeyboardEvents(bool fGrab)1773 {1774 m_fKeyboardGrabbed = fGrab;1775 if (fGrab)1776 {1777 /* Disable mouse and keyboard event compression/delaying to make sure we *really* get all of the events. */1778 ::CGSetLocalEventsSuppressionInterval(0.0);1779 machineLogic()->mouseHandler()->setMouseCoalescingEnabled(false);1780 1781 /* Register the event callback/hook and grab the keyboard. */1782 UICocoaApplication::instance()->registerForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown | NSKeyUp | | NSFlagsChanged */,1783 UIMachineView::darwinEventHandlerProc, this);1784 1785 ::DarwinGrabKeyboard (false);1786 }1787 else1788 {1789 ::DarwinReleaseKeyboard();1790 UICocoaApplication::instance()->unregisterForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown | NSKeyUp | | NSFlagsChanged */,1791 UIMachineView::darwinEventHandlerProc, this);1792 }1793 }1794 1795 bool UIMachineView::darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser)1796 {1797 UIMachineView *view = (UIMachineView*)pvUser;1798 EventRef inEvent = (EventRef)pvCarbonEvent;1799 UInt32 eventClass = ::GetEventClass(inEvent);1800 1801 /* Check if this is an application key combo. In that case we will not pass1802 * the event to the guest, but let the host process it. */1803 if (::darwinIsApplicationCommand(pvCocoaEvent))1804 return false;1805 1806 /* All keyboard class events needs to be handled. */1807 if (eventClass == kEventClassKeyboard)1808 {1809 if (view->darwinKeyboardEvent (pvCocoaEvent, inEvent))1810 return true;1811 }1812 /* Pass the event along. */1813 return false;1814 }1815 1816 2176 #endif 1817 2177 1818 void UIMachineView::fixModifierState(LONG *piCodes, uint *puCount)1819 {1820 /* Synchronize the views of the host and the guest to the modifier keys.1821 * This function will add up to 6 additional keycodes to codes. */1822 1823 #if defined(Q_WS_X11)1824 1825 Window wDummy1, wDummy2;1826 int iDummy3, iDummy4, iDummy5, iDummy6;1827 unsigned uMask;1828 unsigned uKeyMaskNum = 0, uKeyMaskCaps = 0, uKeyMaskScroll = 0;1829 1830 uKeyMaskCaps = LockMask;1831 XModifierKeymap* map = XGetModifierMapping(QX11Info::display());1832 KeyCode keyCodeNum = XKeysymToKeycode(QX11Info::display(), XK_Num_Lock);1833 KeyCode keyCodeScroll = XKeysymToKeycode(QX11Info::display(), XK_Scroll_Lock);1834 1835 for (int i = 0; i < 8; ++ i)1836 {1837 if (keyCodeNum != NoSymbol && map->modifiermap[map->max_keypermod * i] == keyCodeNum)1838 uKeyMaskNum = 1 << i;1839 else if (keyCodeScroll != NoSymbol && map->modifiermap[map->max_keypermod * i] == keyCodeScroll)1840 uKeyMaskScroll = 1 << i;1841 }1842 XQueryPointer(QX11Info::display(), DefaultRootWindow(QX11Info::display()), &wDummy1, &wDummy2,1843 &iDummy3, &iDummy4, &iDummy5, &iDummy6, &uMask);1844 XFreeModifiermap(map);1845 1846 if (uisession()->numLockAdaptionCnt() && (uisession()->isNumLock() ^ !!(uMask & uKeyMaskNum)))1847 {1848 uisession()->setNumLockAdaptionCnt(uisession()->numLockAdaptionCnt() - 1);1849 piCodes[(*puCount)++] = 0x45;1850 piCodes[(*puCount)++] = 0x45 | 0x80;1851 }1852 if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(uMask & uKeyMaskCaps)))1853 {1854 uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1);1855 piCodes[(*puCount)++] = 0x3a;1856 piCodes[(*puCount)++] = 0x3a | 0x80;1857 /* Some keyboard layouts require shift to be pressed to break1858 * capslock. For simplicity, only do this if shift is not1859 * already held down. */1860 if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed))1861 {1862 piCodes[(*puCount)++] = 0x2a;1863 piCodes[(*puCount)++] = 0x2a | 0x80;1864 }1865 }1866 1867 #elif defined(Q_WS_WIN32)1868 1869 if (uisession()->numLockAdaptionCnt() && (uisession()->isNumLock() ^ !!(GetKeyState(VK_NUMLOCK))))1870 {1871 uisession()->setNumLockAdaptionCnt(uisession()->numLockAdaptionCnt() - 1);1872 piCodes[(*puCount)++] = 0x45;1873 piCodes[(*puCount)++] = 0x45 | 0x80;1874 }1875 if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(GetKeyState(VK_CAPITAL))))1876 {1877 uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1);1878 piCodes[(*puCount)++] = 0x3a;1879 piCodes[(*puCount)++] = 0x3a | 0x80;1880 /* Some keyboard layouts require shift to be pressed to break1881 * capslock. For simplicity, only do this if shift is not1882 * already held down. */1883 if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed))1884 {1885 piCodes[(*puCount)++] = 0x2a;1886 piCodes[(*puCount)++] = 0x2a | 0x80;1887 }1888 }1889 1890 #elif defined(Q_WS_MAC)1891 1892 /* if (uisession()->numLockAdaptionCnt()) ... - NumLock isn't implemented by Mac OS X so ignore it. */1893 if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(::GetCurrentEventKeyModifiers() & alphaLock)))1894 {1895 uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1);1896 piCodes[(*puCount)++] = 0x3a;1897 piCodes[(*puCount)++] = 0x3a | 0x80;1898 /* Some keyboard layouts require shift to be pressed to break1899 * capslock. For simplicity, only do this if shift is not1900 * already held down. */1901 if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed))1902 {1903 piCodes[(*puCount)++] = 0x2a;1904 piCodes[(*puCount)++] = 0x2a | 0x80;1905 }1906 }1907 1908 #else1909 1910 //#warning Adapt UIMachineView::fixModifierState1911 1912 #endif1913 }1914 1915 QPoint UIMachineView::viewportToContents(const QPoint &vp) const1916 {1917 return QPoint(vp.x() + contentsX(), vp.y() + contentsY());1918 }1919 1920 void UIMachineView::scrollBy(int dx, int dy)1921 {1922 horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dx);1923 verticalScrollBar()->setValue(verticalScrollBar()->value() + dy);1924 }1925 1926 #ifdef VBOX_WITH_VIDEOHWACCEL1927 void UIMachineView::scrollContentsBy(int dx, int dy)1928 {1929 if (m_pFrameBuffer)1930 {1931 m_pFrameBuffer->viewportScrolled(dx, dy);1932 }1933 QAbstractScrollArea::scrollContentsBy(dx, dy);1934 }1935 #endif1936 1937 void UIMachineView::emitKeyboardStateChanged()1938 {1939 emit keyboardStateChanged(keyboardState());1940 }1941 1942 void UIMachineView::captureKbd(bool fCapture, bool fEmitSignal /* = true */)1943 {1944 if (m_bIsKeyboardCaptured == fCapture)1945 return;1946 1947 #if defined(Q_WS_WIN32)1948 /* On Win32, keyboard grabbing is ineffective, a low-level keyboard hook is used instead. */1949 #elif defined(Q_WS_X11)1950 /* On X11, we are using passive XGrabKey for normal (windowed) mode1951 * instead of XGrabKeyboard (called by QWidget::grabKeyboard())1952 * because XGrabKeyboard causes a problem under metacity - a window cannot be moved1953 * using the mouse if it is currently actively grabing the keyboard;1954 * For static modes we are using usual (active) keyboard grabbing. */1955 switch (machineLogic()->visualStateType())1956 {1957 /* If window is moveable we are making passive keyboard grab: */1958 case UIVisualStateType_Normal:1959 {1960 if (fCapture)1961 XGrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync);1962 else1963 XUngrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId());1964 break;1965 }1966 /* If window is NOT moveable we are making active keyboard grab: */1967 case UIVisualStateType_Fullscreen:1968 case UIVisualStateType_Seamless:1969 {1970 if (fCapture)1971 {1972 /* Keyboard grabbing can fail because of some keyboard shortcut is still grabbed by window manager.1973 * We can't be sure this shortcut will be released at all, so we will retry to grab keyboard for 50 times,1974 * and after we will just ignore that issue: */1975 int cTriesLeft = 50;1976 while (cTriesLeft && XGrabKeyboard(QX11Info::display(), machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync, CurrentTime)) { --cTriesLeft; }1977 }1978 else1979 XUngrabKeyboard(QX11Info::display(), CurrentTime);1980 break;1981 }1982 /* Should we try to grab keyboard in default case? I think - NO. */1983 default:1984 break;1985 }1986 #elif defined(Q_WS_MAC)1987 /* On Mac OS X, we use the Qt methods + disabling global hot keys + watching modifiers1988 * (for right/left separation). */1989 if (fCapture)1990 {1991 ::DarwinDisableGlobalHotKeys(true);1992 grabKeyboard();1993 }1994 else1995 {1996 ::DarwinDisableGlobalHotKeys(false);1997 releaseKeyboard();1998 }1999 #else2000 if (fCapture)2001 grabKeyboard();2002 else2003 releaseKeyboard();2004 #endif2005 2006 m_bIsKeyboardCaptured = fCapture;2007 2008 if (fEmitSignal)2009 emitKeyboardStateChanged();2010 }2011 2012 void UIMachineView::saveKeyStates()2013 {2014 ::memcpy(m_pressedKeysCopy, m_pressedKeys, sizeof(m_pressedKeys));2015 }2016 2017 void UIMachineView::releaseAllPressedKeys(bool aReleaseHostKey /* = true */)2018 {2019 CKeyboard keyboard = session().GetConsole().GetKeyboard();2020 bool fSentRESEND = false;2021 2022 /* Send a dummy scan code (RESEND) to prevent the guest OS from recognizing2023 * a single key click (for ex., Alt) and performing an unwanted action2024 * (for ex., activating the menu) when we release all pressed keys below.2025 * Note, that it's just a guess that sending RESEND will give the desired2026 * effect :), but at least it works with NT and W2k guests. */2027 for (uint i = 0; i < SIZEOF_ARRAY (m_pressedKeys); i++)2028 {2029 if (m_pressedKeys[i] & IsKeyPressed)2030 {2031 if (!fSentRESEND)2032 {2033 keyboard.PutScancode (0xFE);2034 fSentRESEND = true;2035 }2036 keyboard.PutScancode(i | 0x80);2037 }2038 else if (m_pressedKeys[i] & IsExtKeyPressed)2039 {2040 if (!fSentRESEND)2041 {2042 keyboard.PutScancode(0xFE);2043 fSentRESEND = true;2044 }2045 QVector <LONG> codes(2);2046 codes[0] = 0xE0;2047 codes[1] = i | 0x80;2048 keyboard.PutScancodes(codes);2049 }2050 m_pressedKeys[i] = 0;2051 }2052 2053 if (aReleaseHostKey)2054 m_bIsHostkeyPressed = false;2055 2056 #ifdef Q_WS_MAC2057 /* Clear most of the modifiers: */2058 m_darwinKeyModifiers &=2059 alphaLock | kEventKeyModifierNumLockMask |2060 (aReleaseHostKey ? 0 : ::DarwinKeyCodeToDarwinModifierMask (m_globalSettings.hostKey()));2061 #endif2062 2063 emitKeyboardStateChanged();2064 }2065 2066 void UIMachineView::sendChangedKeyStates()2067 {2068 QVector <LONG> codes(2);2069 CKeyboard keyboard = session().GetConsole().GetKeyboard();2070 for (uint i = 0; i < SIZEOF_ARRAY(m_pressedKeys); ++ i)2071 {2072 uint8_t os = m_pressedKeysCopy[i];2073 uint8_t ns = m_pressedKeys[i];2074 if ((os & IsKeyPressed) != (ns & IsKeyPressed))2075 {2076 codes[0] = i;2077 if (!(ns & IsKeyPressed))2078 codes[0] |= 0x80;2079 keyboard.PutScancode(codes[0]);2080 }2081 else if ((os & IsExtKeyPressed) != (ns & IsExtKeyPressed))2082 {2083 codes[0] = 0xE0;2084 codes[1] = i;2085 if (!(ns & IsExtKeyPressed))2086 codes[1] |= 0x80;2087 keyboard.PutScancodes(codes);2088 }2089 }2090 }2091 2092 void UIMachineView::dimImage(QImage &img)2093 {2094 for (int y = 0; y < img.height(); ++ y)2095 {2096 if (y % 2)2097 {2098 if (img.depth() == 32)2099 {2100 for (int x = 0; x < img.width(); ++ x)2101 {2102 int gray = qGray(img.pixel (x, y)) / 2;2103 img.setPixel(x, y, qRgb (gray, gray, gray));2104 }2105 }2106 else2107 {2108 ::memset(img.scanLine (y), 0, img.bytesPerLine());2109 }2110 }2111 else2112 {2113 if (img.depth() == 32)2114 {2115 for (int x = 0; x < img.width(); ++ x)2116 {2117 int gray = (2 * qGray (img.pixel (x, y))) / 3;2118 img.setPixel(x, y, qRgb (gray, gray, gray));2119 }2120 }2121 }2122 }2123 }2124 2125 #ifdef Q_WS_MAC2126 CGImageRef UIMachineView::vmContentImage()2127 {2128 if (!m_pauseShot.isNull())2129 {2130 CGImageRef pauseImg = ::darwinToCGImageRef(&m_pauseShot);2131 /* Use the pause image as background */2132 return pauseImg;2133 }2134 else2135 {2136 # ifdef VBOX_GUI_USE_QUARTZ2D2137 if (vboxGlobal().vmRenderMode() == VBoxDefs::Quartz2DMode)2138 {2139 /* If the render mode is Quartz2D we could use the CGImageRef2140 * of the framebuffer for the dock icon creation. This saves2141 * some conversion time. */2142 CGImageRef image = static_cast<UIFrameBufferQuartz2D*>(m_pFrameBuffer)->imageRef();2143 CGImageRetain(image); /* Retain it, cause the consumer will release it. */2144 return image;2145 }2146 else2147 # endif /* VBOX_GUI_USE_QUARTZ2D */2148 /* In image mode we have to create the image ref out of the2149 * framebuffer */2150 return frameBuffertoCGImageRef(m_pFrameBuffer);2151 }2152 return 0;2153 }2154 2155 CGImageRef UIMachineView::frameBuffertoCGImageRef(UIFrameBuffer *pFrameBuffer)2156 {2157 CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();2158 Assert(cs);2159 /* Create the image copy of the framebuffer */2160 CGDataProviderRef dp = CGDataProviderCreateWithData(pFrameBuffer, pFrameBuffer->address(), pFrameBuffer->bitsPerPixel() / 8 * pFrameBuffer->width() * pFrameBuffer->height(), NULL);2161 Assert(dp);2162 CGImageRef ir = CGImageCreate(pFrameBuffer->width(), pFrameBuffer->height(), 8, 32, pFrameBuffer->bytesPerLine(), cs,2163 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host, dp, 0, false,2164 kCGRenderingIntentDefault);2165 Assert(ir);2166 CGDataProviderRelease(dp);2167 CGColorSpaceRelease(cs);2168 2169 return ir;2170 }2171 2172 void UIMachineView::updateDockIcon()2173 {2174 machineLogic()->updateDockIcon();2175 }2176 #endif /* Q_WS_MAC */2177 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
r30548 r30549 54 54 #ifdef VBOX_WITH_VIDEOHWACCEL 55 55 , bool bAccelerate2DVideo 56 #endif 56 #endif /* VBOX_WITH_VIDEOHWACCEL */ 57 57 ); 58 58 /* Factory function to destroy required machine-view: */ … … 68 68 virtual void normalizeGeometry(bool /* bAdjustPosition = false */) = 0; 69 69 70 protected slots: 71 72 /* Console callback handlers: */ 73 virtual void sltMachineStateChanged(); 74 70 75 signals: 71 76 … … 83 88 #ifdef VBOX_WITH_VIDEOHWACCEL 84 89 , bool bAccelerate2DVideo 85 #endif 90 #endif /* VBOX_WITH_VIDEOHWACCEL */ 86 91 ); 87 92 /* Machine-view destructor: */ 88 93 virtual ~UIMachineView(); 89 94 95 /* Prepare routines: */ 96 virtual void prepareFrameBuffer(); 97 virtual void prepareCommon(); 98 virtual void prepareFilters(); 99 virtual void prepareConsoleConnections(); 100 virtual void loadMachineViewSettings(); 101 102 /* Cleanup routines: */ 103 //virtual void saveMachineViewSettings() {} 104 //virtual void cleanupConsoleConnections() {} 105 //virtual void cleanupFilters() {} 106 virtual void cleanupCommon(); 107 virtual void cleanupFrameBuffer(); 108 90 109 /* Protected getters: */ 110 UIMachineWindow* machineWindowWrapper() const { return m_pMachineWindow; } 111 UIMachineLogic* machineLogic() const; 91 112 UISession* uisession() const; 92 113 CSession& session(); … … 100 121 ulong screenId() const { return m_uScreenId; } 101 122 UIFrameBuffer* frameBuffer() const { return m_pFrameBuffer; } 102 UIMachineWindow* machineWindowWrapper() const { return m_pMachineWindow; }103 UIMachineLogic* machineLogic() const;104 123 bool isHostKeyPressed() const { return m_bIsHostkeyPressed; } 105 124 bool isMachineWindowResizeIgnored() const { return m_bIsMachineWindowResizeIgnored; } … … 126 145 virtual void maybeRestrictMinimumSize() = 0; 127 146 virtual void updateSliders(); 128 147 void fixModifierState(LONG *piCodes, uint *puCount); 148 QPoint viewportToContents(const QPoint &vp) const; 149 void scrollBy(int dx, int dy); 150 void emitKeyboardStateChanged(); 151 void captureKbd(bool fCapture, bool fEmitSignal = true); 152 void saveKeyStates(); 153 void releaseAllPressedKeys(bool aReleaseHostKey = true); 154 void sendChangedKeyStates(); 155 static void dimImage(QImage &img); 156 #ifdef VBOX_WITH_VIDEOHWACCEL 157 void scrollContentsBy(int dx, int dy); 158 #endif /* VBOX_WITH_VIDEOHWACCEL */ 129 159 #ifdef Q_WS_MAC 130 160 void updateDockIcon(); … … 133 163 #endif /* Q_WS_MAC */ 134 164 135 /* Prepare routines: */136 virtual void prepareFrameBuffer();137 virtual void prepareCommon();138 virtual void prepareFilters();139 virtual void prepareConsoleConnections();140 virtual void loadMachineViewSettings();141 142 /* Cleanup routines: */143 //virtual void saveMachineViewSettings() {}144 //virtual void cleanupConsoleConnections() {}145 //virtual void cleanupFilters() {}146 virtual void cleanupCommon();147 virtual void cleanupFrameBuffer();148 149 165 /* Cross-platforms event processors: */ 150 166 bool event(QEvent *pEvent); 151 167 bool eventFilter(QObject *pWatched, QEvent *pEvent); 152 153 /* Protected variables: */154 QSize m_desktopGeometry;155 156 protected slots:157 158 /* Console callback handlers: */159 virtual void sltMachineStateChanged();160 161 private:162 163 /* Cross-platforms event processors: */164 168 void focusEvent(bool aHasFocus, bool aReleaseHostKey = true); 165 169 bool keyEvent(int aKey, uint8_t aScan, int aFlags, wchar_t *aUniKey = NULL); … … 169 173 170 174 /* Platform specific event processors: */ 171 #if defined(Q_WS_WIN 32)175 #if defined(Q_WS_WIN) 172 176 static LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); 173 177 bool winLowKeyboardEvent(UINT msg, const KBDLLHOOKSTRUCT &event); … … 178 182 bool x11Event(XEvent *event); 179 183 #elif defined(Q_WS_MAC) 180 bool darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent);181 184 void darwinGrabKeyboardEvents(bool fGrab); 182 185 static bool darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser); 186 bool darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent); 183 187 #endif 184 185 /* Private helpers: */186 void fixModifierState(LONG *piCodes, uint *puCount);187 QPoint viewportToContents(const QPoint &vp) const;188 void scrollBy(int dx, int dy);189 #ifdef VBOX_WITH_VIDEOHWACCEL190 void scrollContentsBy(int dx, int dy);191 #endif192 void emitKeyboardStateChanged();193 void captureKbd(bool fCapture, bool fEmitSignal = true);194 void saveKeyStates();195 void releaseAllPressedKeys(bool aReleaseHostKey = true);196 void sendChangedKeyStates();197 198 static void dimImage(QImage &img);199 188 200 189 /* Private members: */ … … 206 195 207 196 DesktopGeo m_desktopGeometryType; 197 QSize m_desktopGeometry; 208 198 QSize m_storedConsoleSize; 209 199 … … 218 208 bool m_fPassCAD : 1; 219 209 #ifdef VBOX_WITH_VIDEOHWACCEL 220 bool m_fAccelerate2DVideo ;221 #endif 210 bool m_fAccelerate2DVideo : 1; 211 #endif /* VBOX_WITH_VIDEOHWACCEL */ 222 212 223 213 #ifdef Q_WS_MAC
Note:
See TracChangeset
for help on using the changeset viewer.