UIMachineView.cpp revision 2dd7b4388106de88d20f33a8aa6c85c8babf507b
4eaea66423ca58dfd7cfd1099ed902d7c81d8622Lennart Poettering * VBox frontends: Qt GUI ("VirtualBox"):
4eaea66423ca58dfd7cfd1099ed902d7c81d8622Lennart Poettering * UIMachineView class implementation
dd4d2c1cd1eb7c1f3163f6f922362af3189df0a3Tom Gundersen * Copyright (C) 2010 Sun Microsystems, Inc.
dd4d2c1cd1eb7c1f3163f6f922362af3189df0a3Tom Gundersen * This file is part of VirtualBox Open Source Edition (OSE), as
dd4d2c1cd1eb7c1f3163f6f922362af3189df0a3Tom Gundersen * available from http://www.virtualbox.org. This file is free software;
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poettering * you can redistribute it and/or modify it under the terms of the GNU
0737984f6910fdffdf6494f20c1c64a027806273David Herrmann * General Public License (GPL) as published by the Free Software
* Clara, CA 95054 USA or visit http://www.sun.com if you need
#include <QDesktopWidget>
#include <QTimer>
#include <QPainter>
#include <QScrollBar>
#include "VBoxGlobal.h"
#include "VBoxProblemReporter.h"
#include "UIFrameBuffer.h"
#include "UIFrameBufferQGL.h"
#include "UIFrameBufferQImage.h"
#include "UIFrameBufferQuartz2D.h"
#include "UIFrameBufferSDL.h"
#include "VBoxFBOverlay.h"
#include "UISession.h"
#include "UIActionsPool.h"
#include "UIMachineLogic.h"
#include "UIMachineWindow.h"
#include "UIMachineView.h"
#include "UIMachineWindowNormal.h"
#include "UIMachineWindowFullscreen.h"
#include "UIMachineWindowSeamless.h"
#include "UIMachineViewNormal.h"
#include "UIMachineViewFullscreen.h"
#include "UIMachineViewSeamless.h"
#ifdef Q_WS_PM
# include "QIHotKeyEdit.h"
#ifdef Q_WS_WIN
#include <windows.h>
#ifdef Q_WS_X11
# include <QX11Info>
# define XK_XKB_KEYS
# define XK_MISCELLANY
# ifdef KeyPress
# include "XKeyboard.h"
#ifdef Q_WS_MAC
# include "DockIconPreview.h"
# include "DarwinKeyboard.h"
# include "darwin/VBoxCocoaApplication.h"
return NULL;
#ifdef VBOX_WITH_VIDEOHWACCEL
, bool bAccelerate2DVideo
switch (visualStateType)
case UIVisualStateType_Normal:
#ifdef VBOX_WITH_VIDEOHWACCEL
, uScreenId);
#ifdef VBOX_WITH_VIDEOHWACCEL
, uScreenId);
#ifdef VBOX_WITH_VIDEOHWACCEL
, uScreenId);
return view;
delete pWhichView;
#ifdef VBOX_WITH_VIDEOHWACCEL
, bool bAccelerate2DVideo
, m_pFrameBuffer(0)
, m_bIsAutoCaptureDisabled(false)
, m_bIsKeyboardCaptured(false)
, m_bIsHostkeyPressed(false)
, m_bIsHostkeyAlone (false)
, m_bIsHostkeyInCapture(false)
, m_bIsMachineWindowResizeIgnored(false)
, m_fPassCAD(false)
#ifdef VBOX_WITH_VIDEOHWACCEL
#ifdef Q_WS_MAC
, m_darwinKeyModifiers(0)
, m_fKeyboardGrabbed (false)
#ifdef VBOX_WITH_DEBUGGER
/* HACK ALERT! Really ugly workaround for the resizing to 9x1 done by DevVGA if provoked before power on. */
if ((fb.width() < 16 || fb.height() < 16) && (vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled()))
return QSize(m_pFrameBuffer->width() + frameWidth() * 2, m_pFrameBuffer->height() + frameWidth() * 2);
switch (m_desktopGeometryType)
case DesktopGeo_Fixed:
case DesktopGeo_Automatic:
case DesktopGeo_Any:
return geometry;
bool ok = true;
if (ok)
if (ok)
return sizeHint;
switch (geometry)
case DesktopGeo_Fixed:
storeConsoleSize(0, 0);
case DesktopGeo_Automatic:
storeConsoleSize(0, 0);
case DesktopGeo_Any:
#ifdef Q_WS_WIN32
if (m.expandedTo(v) == m)
#ifdef VBOX_GUI_USE_QGLFB
switch (mode())
switch (mode())
#ifdef VBOX_GUI_USE_QIMAGE
# ifdef VBOX_WITH_VIDEOHWACCEL
if (m_fAccelerate2DVideo)
if (pFramebuffer)
pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferQImage, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId());
#ifdef VBOX_GUI_USE_QGLFB
#ifdef VBOX_GUI_USE_SDL
# ifdef Q_WS_X11
if (m_fAccelerate2DVideo)
if (pFramebuffer)
pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferSDL, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId());
#ifdef VBOX_GUI_USE_DDRAW
if (m_pFrameBuffer)
delete m_pFrameBuffer;
#ifdef VBOX_GUI_USE_QUARTZ2D
# ifdef VBOX_WITH_VIDEOHWACCEL
if (m_fAccelerate2DVideo)
if (pFramebuffer)
pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferQuartz2D, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId());
if (m_pFrameBuffer)
#ifdef VBOX_WITH_VIDEOHWACCEL
if (m_fAccelerate2DVideo)
if (fb.raw() != m_pFrameBuffer) /* <-this will evaluate to true iff m_fAccelerate2DVideo is disabled or iff no framebuffer is yet assigned */
#if defined Q_WS_WIN
gView = this;
#if defined Q_WS_PM
connect(uisession(), SIGNAL(sigMousePointerShapeChange()), this, SLOT(sltMousePointerShapeChanged()));
connect(uisession(), SIGNAL(sigMouseCapturedStatusChanged()), this, SLOT(sltMouseCapturedStatusChanged()));
#ifdef Q_WS_X11
initMappedX11Keyboard(QX11Info::display(), vboxGlobal().settings().publicProperty("GUI/RemapScancodes"));
m_fPassCAD = true;
#ifdef Q_WS_PM
#ifdef Q_WS_WIN
if (gKbdHook)
gView = 0;
#ifdef Q_WS_MAC
if (m_fKeyboardGrabbed)
darwinGrabKeyboardEvents (false);
if (m_pFrameBuffer)
#ifdef VBOX_WITH_VIDEOHWACCEL
if (m_fAccelerate2DVideo)
focusEvent(true);
focusEvent(false);
#ifdef Q_WS_X11
/* We use processEvents rather than sendPostedEvents & set the time out value to max cause on X11 otherwise
* the layout isn't calculated correctly. Dosn't find the bug in Qt, but this could be triggered through
#ifdef Q_WS_MAC
#ifdef Q_WS_WIN32
#ifdef VBOX_WITH_VIDEOHWACCEL
#ifdef Q_WS_PM
if (m_bIsHostkeyPressed)
if (pressed)
Assert(0);
machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence(pKeyEvent->key()));
#ifdef Q_WS_MAC
* show & activate the stupid window to make it get out of the dock when the user wishes to show a VM: */
if (pMachineWindow)
int iDelta = 0;
#ifdef QT_MAC_USE_COCOA
#ifdef Q_WS_MAC
setMouseCoalescingEnabled(true);
setMouseCoalescingEnabled(false);
#ifdef Q_WS_WIN32
#ifdef VBOX_WITH_VIDEOHWACCEL
if (m_pFrameBuffer)
#if defined (Q_WS_WIN32)
/* Install/uninstall low-level kbd hook on every activation/deactivation to:
if (gKbdHook)
#ifdef Q_WS_MAC
darwinGrabKeyboardEvents(true);
darwinGrabKeyboardEvents(false);
switch (state)
case KMachineState_Paused:
case KMachineState_Stuck:
if (hasFocus())
case KMachineState_Running:
if (hasFocus())
captureMouse(false, false);
#ifndef Q_WS_WIN32
#ifdef Q_WS_WIN32
if (fHasFocus)
#ifdef Q_WS_WIN32
if (!m_bIsAutoCaptureDisabled && m_globalSettings.autoCapture() && GetAncestor(winId(), GA_ROOT) == GetForegroundWindow())
captureKbd(true);
m_bIsAutoCaptureDisabled = false;
captureMouse(false);
captureKbd(false, false);
if (!m_fPassCAD &&
captureKbd(false);
captureMouse(false);
bool emitSignal = false;
int hotkey = 0;
if (isHostKey)
if (!m_bIsHostkeyPressed)
emitSignal = true;
if (m_bIsHostkeyPressed)
if (m_bIsHostkeyAlone)
m_bIsHostkeyAlone = false;
if (isHostKey)
if (m_bIsHostkeyPressed)
m_bIsHostkeyPressed = false;
if (m_bIsHostkeyAlone)
bool ok = true;
if (!captured)
m_bIsAutoCaptureDisabled = true;
bool autoConfirmed = false;
if (autoConfirmed)
m_bIsAutoCaptureDisabled = false;
if (ok)
#ifdef Q_WS_X11
emitSignal = true;
if (m_bIsHostkeyPressed)
m_bIsHostkeyAlone = false;
if (emitSignal)
if (hotkey)
bool processed = false;
#if defined (Q_WS_WIN32)
Assert (n);
for (int i = 0; i < n && !processed; i++)
wchar_t ch;
ch = 0;
if (ch)
processed = machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence((Qt::UNICODE_ACCEL + QChar(ch).toUpper().unicode())));
delete[] list;
char ch = 0;
ch = 0;
if (ch)
processed = machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence(Qt::UNICODE_ACCEL + QChar(pUniKey[0]).toUpper().unicode()));
return processed;
return isHostKey;
#if defined (Q_WS_WIN32)
int state = 0;
#ifdef Q_WS_MAC
if (m_bIsHostkeyPressed &&
int wheelVertical = 0;
int wheelHorizontal = 0;
#ifdef Q_WS_WIN32
#if defined (Q_WS_MAC)
# ifdef Q_WS_WIN32
if (aPos.x() == 0)
if (aPos.y() == 0 )
if (p != aPos)
if (aGlobalPos.x() == 0)
if (aGlobalPos.y() == 0)
if (p != aGlobalPos)
m_lastMousePos = p;
int dx = 0;
int dy = 0;
// AssertMsgFailed(("x=%d, y=%d", cpnt.x(), cpnt.y())); // this shows what absolute coordinates are correct!
m_bIsAutoCaptureDisabled = true;
bool autoConfirmed = false;
if (autoConfirmed)
m_bIsAutoCaptureDisabled = false;
if (ok)
#ifdef Q_WS_X11
captureKbd(true);
captureMouse(true);
if (m_pFrameBuffer)
#ifdef Q_WS_MAC
#ifdef VBOX_GUI_USE_QUARTZ2D
pnt.drawPixmap(r.x(), r.y(), m_pauseShot, r.x() + contentsX(), r.y() + contentsY(), r.width(), r.height());
#ifdef Q_WS_MAC
#if defined(Q_WS_WIN32)
if (!m_bIsKeyboardCaptured)
uint8_t what_pressed = (event.flags & 0x01) && (event.vkCode != VK_RSHIFT) ? IsExtKeyPressed : IsKeyPressed;
long dummyResult;
if (!scan)
int flags = 0;
switch (vkey)
case VK_SHIFT:
case VK_CONTROL:
case VK_MENU:
switch (keyscan)
case VK_NUMLOCK:
case VK_SNAPSHOT:
case VK_PAUSE:
return result;
if (!m_bIsKeyboardCaptured)
int flags = 0;
switch (vkey)
if (!(f & KC_KEYUP))
return result;
return True;
return False;
case XFocusOut:
case XFocusIn:
case XKeyPress:
case XKeyRelease:
/* Fix for http://www.virtualbox.org/ticket/1296:
int flags = 0;
switch (ks)
case XK_Print:
case XK_Pause:
bool ret = false;
::GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof (keyCode), NULL, &keyCode);
if (scanCode)
int flags = 0;
cbWritten = 0;
if (changed)
if (!scanCode)
unsigned flags = 0;
ret = true;
return ret;
if (fGrab)
/* Disable mouse and keyboard event compression/delaying to make sure we *really* get all of the events. */
setMouseCoalescingEnabled(false);
# ifdef QT_MAC_USE_COCOA
this, &m_darwinEventHandlerRef);
::DarwinGrabKeyboard (false);
# ifdef QT_MAC_USE_COCOA
# ifdef QT_MAC_USE_COCOA
bool UIMachineView::darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser)
pascal OSStatus UIMachineView::darwinEventHandlerProc(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
#if defined(Q_WS_X11)
unsigned uMask;
if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(GetKeyState(VK_CAPITAL))))
/* if (uisession()->numLockAdaptionCnt()) ... - NumLock isn't implemented by Mac OS X so ignore it. */
if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(::GetCurrentEventKeyModifiers() & alphaLock)))
#ifdef VBOX_WITH_VIDEOHWACCEL
if (m_pFrameBuffer)
#if defined(Q_WS_WIN32)
if (fCapture)
XGrabKey(QX11Info::display(), AnyKey, AnyModifier, window()->winId(), False, GrabModeAsync, GrabModeAsync);
if (fCapture)
::DarwinDisableGlobalHotKeys(true);
grabKeyboard();
::DarwinDisableGlobalHotKeys(false);
if (fCapture)
grabKeyboard();
if (fEmitSignal)
if (fCapture)
#ifdef Q_WS_WIN32
if (fEmitSignal)
bool fSentRESEND = false;
if (!fSentRESEND)
fSentRESEND = true;
if (!fSentRESEND)
fSentRESEND = true;
m_pressedKeys[i] = 0;
if (aReleaseHostKey)
m_bIsHostkeyPressed = false;
#ifdef Q_WS_MAC
codes[0] = i;
#ifdef Q_WS_MAC
return pauseImg;
# ifdef VBOX_GUI_USE_QUARTZ2D
return image;
CGDataProviderRef dp = CGDataProviderCreateWithData(pFrameBuffer, pFrameBuffer->address(), pFrameBuffer->bitsPerPixel() / 8 * pFrameBuffer->width() * pFrameBuffer->height(), NULL);
CGImageRef ir = CGImageCreate(pFrameBuffer->width(), pFrameBuffer->height(), 8, 32, pFrameBuffer->bytesPerLine(), cs,
return ir;