UIMachineView.cpp revision 1910146bc46e3eee5b8668806da594107fe9aabf
/* $Id$ */
/** @file
*
* VBox frontends: Qt GUI ("VirtualBox"):
* UIMachineView class implementation
*/
/*
* Copyright (C) 2010 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/* Global includes */
#include <QDesktopWidget>
#include <QTimer>
#include <QPainter>
#include <QScrollBar>
#include <VBox/VBoxVideo.h>
/* Local includes */
#include "VBoxGlobal.h"
#include "VBoxProblemReporter.h"
#include "UIFrameBuffer.h"
#include "UIFrameBufferQGL.h"
#include "UIFrameBufferQImage.h"
#include "UIFrameBufferQuartz2D.h"
#include "UIFrameBufferSDL.h"
#include "UISession.h"
#include "UIActionsPool.h"
#include "UIMachineLogic.h"
#include "UIMachineWindow.h"
#include "UIMachineView.h"
#include "UIMachineViewNormal.h"
#include "UIMachineViewFullscreen.h"
#ifdef Q_WS_PM
# include "QIHotKeyEdit.h"
#endif
#ifdef Q_WS_WIN
#include <windows.h>
#endif
#ifdef Q_WS_X11
# include <QX11Info>
# define XK_XKB_KEYS
# define XK_MISCELLANY
# ifdef KeyPress
const int XKeyRelease = KeyRelease;
# endif
# include "XKeyboard.h"
#endif
#if defined (Q_WS_MAC)
# include "DockIconPreview.h"
# include "DarwinKeyboard.h"
# ifdef QT_MAC_USE_COCOA
# include "darwin/VBoxCocoaApplication.h"
# else /* QT_MAC_USE_COCOA */
# endif /* !QT_MAC_USE_COCOA */
#endif /* defined (Q_WS_MAC) */
class VBoxViewport: public QWidget
{
public:
{
/* No need for background drawing: */
}
QPaintEngine *paintEngine() const
{
return NULL;
else
return QWidget::paintEngine();
}
};
#ifdef VBOX_WITH_VIDEOHWACCEL
, bool bAccelerate2DVideo
#endif
{
UIMachineView *view = 0;
switch (visualStateType)
{
case UIVisualStateType_Normal:
#ifdef VBOX_WITH_VIDEOHWACCEL
#endif
);
break;
#ifdef VBOX_WITH_VIDEOHWACCEL
#endif
);
break;
#ifdef VBOX_WITH_VIDEOHWACCEL
#endif
);
break;
default:
break;
}
return view;
}
{
delete pWhichView;
}
int UIMachineView::keyboardState() const
{
return (m_bIsKeyboardCaptured ? UIViewStateType_KeyboardCaptured : 0) |
}
int UIMachineView::mouseState() const
{
}
{
return;
if (uisession()->isMouseSupportsAbsolute())
captureMouse(!bEnabled, false);
/* Hiding host cursor in case we are entering mouse integration
* mode until it's shape is set to the guest cursor shape. */
if (bEnabled)
}
#include <QMainWindow>
#ifdef VBOX_WITH_VIDEOHWACCEL
, bool bAccelerate2DVideo
#endif
)
// TODO_NEW_CORE: really think of if this is right
// : QAbstractScrollArea(((QMainWindow*)pMachineWindow->machineWindow())->centralWidget())
, m_mode(renderMode)
, m_pFrameBuffer(0)
, m_bIsAutoCaptureDisabled(false)
, m_bIsKeyboardCaptured(false)
, m_bIsHostkeyPressed(false)
, m_bIsHostkeyAlone (false)
, m_bIsHostkeyInCapture(false)
, m_bIsMachineWindowResizeIgnored(false)
, m_bIsFrameBufferResizeIgnored(false)
, m_fPassCAD(false)
#ifdef VBOX_WITH_VIDEOHWACCEL
#endif
#if defined(Q_WS_MAC)
# ifndef QT_MAC_USE_COCOA
# endif /* !QT_MAC_USE_COCOA */
, m_darwinKeyModifiers(0)
, m_fKeyboardGrabbed (false)
, mDockIconEnabled(true)
#endif
{
}
{
}
{
}
{
}
{
#ifdef VBOX_WITH_DEBUGGER
// TODO: Fix all DEBUGGER stuff!
/* 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()))
#else
return QSize(m_pFrameBuffer->width() + frameWidth() * 2, m_pFrameBuffer->height() + frameWidth() * 2);
#endif
}
int UIMachineView::contentsX() const
{
return horizontalScrollBar()->value();
}
int UIMachineView::contentsY() const
{
return verticalScrollBar()->value();
}
int UIMachineView::contentsWidth() const
{
return m_pFrameBuffer->width();
}
int UIMachineView::contentsHeight() const
{
return m_pFrameBuffer->height();
}
int UIMachineView::visibleWidth() const
{
return horizontalScrollBar()->pageStep();
}
int UIMachineView::visibleHeight() const
{
return verticalScrollBar()->pageStep();
}
void UIMachineView::updateMouseClipping()
{
if (uisession()->isMouseCaptured())
{
#ifdef Q_WS_WIN32
::ClipCursor(&rect);
#endif
}
else
{
#ifdef Q_WS_WIN32
::ClipCursor(NULL);
#endif
/* return the cursor to where it was when we captured it and show it */
viewport()->unsetCursor();
}
}
void UIMachineView::updateSliders()
{
QSize m = maximumViewportSize();
/* no scroll bars needed */
if (m.expandedTo(v) == m)
p = m;
}
void UIMachineView::prepareFrameBuffer()
{
/* Prepare viewport: */
#ifdef VBOX_GUI_USE_QGL
switch (mode())
{
break;
default:
pViewport = new VBoxViewport(this);
}
#else
#endif
switch (mode())
{
#ifdef VBOX_GUI_USE_QIMAGE
case VBoxDefs::QImageMode:
//# ifdef VBOX_WITH_VIDEOHWACCEL
// m_pFrameBuffer = m_fAccelerate2DVideo ? new VBoxOverlayFrameBuffer<UIFrameBufferQImage>(this, &machineWindowWrapper()->session()) : new UIFrameBufferQImage(this);
//# else
m_pFrameBuffer = new UIFrameBufferQImage(this);
//# endif
break;
#endif /* VBOX_GUI_USE_QIMAGE */
#ifdef VBOX_GUI_USE_QGL
m_pFrameBuffer = new UIFrameBufferQGL(this);
break;
// case VBoxDefs::QGLOverlayMode:
// m_pFrameBuffer = new UIQGLOverlayFrameBuffer(this);
// break;
#endif /* VBOX_GUI_USE_QGL */
#ifdef VBOX_GUI_USE_SDL
/* Indicate that we are doing all drawing stuff ourself: */
// TODO_NEW_CORE
# ifdef Q_WS_X11
/* This is somehow necessary to prevent strange X11 warnings on i386 and segfaults on x86_64: */
# endif
//# if defined(VBOX_WITH_VIDEOHWACCEL) && defined(DEBUG_misha) /* not tested yet */
// m_pFrameBuffer = m_fAccelerate2DVideo ? new VBoxOverlayFrameBuffer<UISDLFrameBuffer> (this, &machineWindowWrapper()->session()) : new UISDLFrameBuffer(this);
//# else
m_pFrameBuffer = new UIFrameBufferSDL(this);
//# endif
/* Disable scrollbars because we cannot correctly draw in a scrolled window using SDL: */
horizontalScrollBar()->setEnabled(false);
verticalScrollBar()->setEnabled(false);
break;
#endif /* VBOX_GUI_USE_SDL */
#if 0 // TODO: Enable DDraw frame buffer!
#ifdef VBOX_GUI_USE_DDRAW
m_pFrameBuffer = new UIDDRAWFrameBuffer(this);
{
if (m_pFrameBuffer)
delete m_pFrameBuffer;
m_pFrameBuffer = new UIFrameBufferQImage(this);
}
break;
#endif /* VBOX_GUI_USE_DDRAW */
#endif
#ifdef VBOX_GUI_USE_QUARTZ2D
case VBoxDefs::Quartz2DMode:
/* Indicate that we are doing all drawing stuff ourself: */
//# ifdef VBOX_WITH_VIDEOHWACCEL
// m_pFrameBuffer = m_fAccelerate2DVideo ? new VBoxOverlayFrameBuffer<VBoxQuartz2DFrameBuffer>(this, &machineWindowWrapper()->session()) : new UIFrameBufferQuartz2D(this);
//# else
m_pFrameBuffer = new UIFrameBufferQuartz2D(this);
//# endif
break;
#endif /* VBOX_GUI_USE_QUARTZ2D */
default:
break;
}
if (m_pFrameBuffer)
{
m_pFrameBuffer->AddRef();
}
}
void UIMachineView::prepareCommon()
{
/* Prepare view frame: */
/* Pressed keys: */
/* Setup palette: */
/* Setup size-policy: */
/* Setup focus policy: */
#if defined Q_WS_WIN
gView = this;
#endif
#if defined Q_WS_PM
#endif
#if defined Q_WS_MAC
/* Dock icon update connection */
/* Presentation Mode connection */
/* Overlay logo for the dock icon */
//mVirtualBoxLogo = ::darwinToCGImageRef("VirtualBox_cube_42px.png");
// TODO_NEW_CORE
// mDockIconPreview = new VBoxDockIconPreview(machineWindowWrapper(), vboxGlobal().vmGuestOSTypeIcon (osTypeId));
# ifdef QT_MAC_USE_COCOA
/** @todo Carbon -> Cocoa */
# else /* !QT_MAC_USE_COCOA */
/* Install the event handler which will proceed external window handling */
{
};
::InstallApplicationEventHandler(eventHandler, RT_ELEMENTS (eventTypes), &eventTypes[0], this, &mDarwinWindowOverlayHandlerRef);
# endif /* !QT_MAC_USE_COCOA */
#endif
}
void UIMachineView::prepareFilters()
{
/* Enable MouseMove events: */
viewport()->setMouseTracking(true);
/* QScrollView does the below on its own, but let's
* do it anyway for the case it will not do it in the future: */
viewport()->installEventFilter(this);
/* We want to be notified on some parent's events: */
}
{
/* Machine state-change updater: */
/* Mouse pointer shape state-change updater: */
connect(uisession(), SIGNAL(sigMousePointerShapeChange()), this, SLOT(sltMousePointerShapeChanged()));
/* Mouse capability state-change updater: */
}
void UIMachineView::loadMachineViewSettings()
{
/* Global settings: */
{
#ifdef Q_WS_X11
/* Initialize the X keyboard subsystem: */
initMappedX11Keyboard(QX11Info::display(), vboxGlobal().settings().publicProperty("GUI/RemapScancodes"));
#endif
/* Remember the desktop geometry and register for geometry
* change events for telling the guest about video modes we like: */
else if (desktopGeometry == "any")
setDesktopGeometry(DesktopGeo_Any, 0, 0);
else
{
}
}
/* Exatra data settings: */
{
/* CAD settings: */
m_fPassCAD = true;
}
#ifdef Q_WS_MAC
QString strSettings = vboxGlobal().virtualBox().GetExtraData(VBoxDefs::GUI_RealtimeDockIconUpdateEnabled).toLower();
/* Default to true if it is an empty value: */
#endif
}
{
switch (m_desktopGeometryType)
{
case DesktopGeo_Fixed:
case DesktopGeo_Automatic:
break;
case DesktopGeo_Any:
break;
default:
}
return geometry;
}
{
switch (geometry)
{
case DesktopGeo_Fixed:
else
m_desktopGeometry = QSize(0, 0);
storeConsoleSize(0, 0);
break;
case DesktopGeo_Automatic:
m_desktopGeometry = QSize(0, 0);
storeConsoleSize(0, 0);
break;
case DesktopGeo_Any:
m_desktopGeometry = QSize(0, 0);
break;
default:
}
}
{
/* This method should not get called until we have initially set up the m_desktopGeometryType: */
/* If we are not doing automatic geometry calculation then there is nothing to do: */
{
/* Available geometry of the desktop. If the desktop is a single
* screen, this will exclude space taken up by desktop taskbars
* and things, but this is unfortunately not true for the more
* complex case of a desktop spanning multiple screens: */
/* The area taken up by the machine window on the desktop,
* including window frame, title and menu bar and whatnot: */
/* The area taken up by the machine view, so excluding all decorations: */
/* To work out how big we can make the console window while still
* fitting on the desktop, we calculate desktop - frame + window.
* This works because the difference between frame and window
* (or at least its width and height) is a constant. */
}
}
{
}
void UIMachineView::cleanupCommon()
{
#if defined (Q_WS_PM)
#endif
#if defined (Q_WS_WIN)
if (gKbdHook)
gView = 0;
if (m_alphaCursor)
#endif
#if defined (Q_WS_MAC)
# if !defined (QT_MAC_USE_COCOA)
{
}
# endif
// TODO_NEW_CORE
// delete mDockIconPreview;
#endif
}
void UIMachineView::cleanupFrameBuffer()
{
if (m_pFrameBuffer)
{
/* Detach framebuffer from Display: */
/* Release the reference: */
}
}
{
{
{
focusEvent(true);
break;
}
{
focusEvent(false);
else
{
/* Release the host key and all other pressed keys too even when paused (otherwise, we will get stuck
* keys in the guest when doing sendChangedKeyStates() on resume because key presses were already
* recorded in m_pressedKeys but key releases will most likely not reach us but the new focus window instead): */
releaseAllPressedKeys(true /* fReleaseHostKey */);
}
break;
}
case VBoxDefs::RepaintEventType:
{
/* session().GetConsole().GetDisplay().UpdateCompleted(); - the event was acked already */
return true;
}
#ifdef VBOX_WITH_VIDEOHWACCEL
case VBoxDefs::VHWACommandProcessType:
{
return true;
}
#endif
#if 0 // TODO: Move that to seamless mode event hadler!
case VBoxDefs::SetRegionEventType:
{
{
}
return true;
}
#endif
case QEvent::KeyRelease:
{
#ifdef Q_WS_PM
// TODO: that a temporary solution to send Alt+Tab and friends to the guest.
// The proper solution is to write a keyboard driver that will steal these combos from the host
// (it's impossible to do so using hooks on OS/2):
if (m_bIsHostkeyPressed)
{
/* Whether the host key is Shift so that it will modify the hot key values?
* Note that we don't distinguish between left and right shift here (too much hassle): */
/* define hot keys according to the Shift state */
/* Simulate Alt+Tab on Host+1 and Alt+Shift+Tab on Host+2 */
{
if (pressed)
{
/* Send the Alt press to the guest */
{
/* Store the press in *Copy to have it automatically
* released when the Host key is released: */
}
/* Make sure Shift is pressed if it's Key_2 and released if it's Key_1: */
{
}
else
{
}
}
return true;
}
/* Simulate Ctrl+Esc on Host+Tilde */
{
/* Send the Ctrl press to the guest */
{
/* store the press in *Copy to have it automatically
* released when the Host key is released */
}
return true;
}
}
#endif /* Q_WS_PM */
{
/* Passing F1-F12 keys to the guest: */
{
{
}
/* some scan slice */
{
}
else
Assert(0);
}
{
#if 0 // TODO: Divide tha code to specific parts of fullscreen & seamless and move it there:
/* Activate the main menu */
#endif
}
else
{
/* Process hot keys not processed in keyEvent() (as in case of non-alphanumeric keys): */
machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence (pKeyEvent->key()));
}
}
{
/* Show a possible warning on key release which seems to be more expected by the end user: */
{
/* Iif the reminder is disabled we pass the event to Qt to enable normal
* keyboard functionality (for example, menu access with Alt+Letter): */
if (!vboxProblem().remindAboutPausedVMInput())
break;
}
}
return true;
}
#ifdef Q_WS_MAC
/* posted OnShowWindow */
case VBoxDefs::ShowWindowEventType:
{
/* Dunno what Qt3 thinks a window that has minimized to the dock should be - it is not hidden,
* neither is it minimized. OTOH it is marked shown and visible, but not activated.
* This latter isn't of much help though, since at this point nothing is marked activated.
* I might have overlooked something, but I'm buggered what if I know what. So, I'll just always
* show & activate the stupid window to make it get out of the dock when the user wishes to show a VM: */
window()->activateWindow();
return true;
}
#endif
default:
break;
}
}
{
{
{
case QEvent::MouseButtonPress:
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonRelease:
{
return true;
break;
}
{
/* There are pointing devices which send smaller values for the delta than 120.
* Here we sum them up until we are greater than 120. This allows to have finer control
* over the speed acceleration & enables such devices to send a valid wheel event to our
* guest mouse device at all: */
int iDelta = 0;
{
}
#ifdef QT_MAC_USE_COCOA
/* Qt Cocoa is buggy. It always reports a left button pressed when the
* mouse wheel event occurs. A workaround is to ask the application which
* buttons are pressed currently: */
#else /* QT_MAC_USE_COCOA */
pWheelEvent->buttons(),
#endif /* QT_MAC_USE_COCOA */
pWheelEvent->modifiers(),
return true;
break;
}
#ifdef Q_WS_MAC
{
/* Enable mouse event compression if we leave the VM view. This is necessary for
setMouseCoalescingEnabled(true);
break;
}
{
/* Disable mouse event compression if we enter the VM view. So all mouse events are
* we have a valid event handler): */
setMouseCoalescingEnabled (false);
break;
}
#endif /* Q_WS_MAC */
{
if (uisession()->isMouseCaptured())
#ifdef VBOX_WITH_VIDEOHWACCEL
if (m_pFrameBuffer)
{
}
#endif
break;
}
default:
break;
}
}
{
{
case QEvent::WindowStateChange:
{
/* During minimizing and state restoring machineWindowWrapper() gets
* the focus which belongs to console view window, so returning it properly. */
{
if (QApplication::focusWidget())
{
qApp->processEvents();
}
}
break;
}
#if defined (Q_WS_WIN32)
/* Install/uninstall low-level kbd hook on every activation/deactivation to:
* a) avoid excess hook calls when we're not active and
* b) be always in front of any other possible hooks */
case QEvent::WindowActivate:
{
break;
}
case QEvent::WindowDeactivate:
{
if (gKbdHook)
{
}
break;
}
#endif /* defined (Q_WS_WIN32) */
#if defined (Q_WS_MAC)
case QEvent::WindowActivate:
darwinGrabKeyboardEvents(true);
break;
case QEvent::WindowDeactivate:
darwinGrabKeyboardEvents(false);
break;
#endif /* defined (Q_WS_MAC) */
default:
break;
}
}
}
void UIMachineView::sltMachineStateChanged()
{
/* Get machine state: */
switch (state)
{
case KMachineState_Paused:
{
{
/* Take a screen snapshot. Note that TakeScreenShot() always needs a 32bpp image: */
/* TakeScreenShot() may fail if, e.g. the Paused notification was delivered
* after the machine execution was resumed. It's not fatal: */
{
/* Fully repaint to pick up m_pauseShot: */
repaint();
}
}
}
case KMachineState_Stuck:
{
/* Reuse the focus event handler to uncapture everything: */
if (hasFocus())
break;
}
case KMachineState_Running:
{
if (m_previousState == KMachineState_Paused || m_previousState == KMachineState_TeleportingPausedVM)
{
{
/* Reset the pixmap to free memory: */
m_pauseShot = QPixmap();
/* Ask for full guest display update (it will also update
* the viewport through IFramebuffer::NotifyUpdate): */
}
}
/* Reuse the focus event handler to capture input: */
if (hasFocus())
focusEvent(true /* aHasFocus */);
break;
}
default:
break;
}
#ifdef Q_WS_MAC
/* Update Dock Overlay: */
#endif /* Q_WS_MAC */
}
{
if (uisession()->isMouseSupportsAbsolute())
{
if (uisession()->isHidingHostPointer())
else
}
}
{
/* Correct the mouse capture state and reset the cursor to the default shape if necessary: */
if (uisession()->isMouseSupportsAbsolute())
{
captureMouse(false, false);
}
else
viewport()->unsetCursor();
/* Notify user about mouse integration state: */
/* Notify all listeners: */
}
#ifdef Q_WS_MAC
{
}
# ifdef QT_MAC_USE_COCOA
{
// TODO_NEW_CORE
// this is full screen related
#if 0
if (mIsFullscreen)
{
/* First check if we are on the primary screen, only than the presentation mode have to be changed. */
{
QString testStr = vboxGlobal().virtualBox().GetExtraData(VBoxDefs::GUI_PresentationModeEnabled).toLower();
/* Default to false if it is an empty value */
else
}
}
else
#endif
}
# endif /* QT_MAC_USE_COCOA */
#endif
{
if (fHasFocus)
{
#ifdef Q_WS_WIN32
if (!m_bIsAutoCaptureDisabled && m_globalSettings.autoCapture() && GetAncestor(winId(), GA_ROOT) == GetForegroundWindow())
#else
#endif
{
captureKbd(true);
}
/* Reset the single-time disable capture flag: */
m_bIsAutoCaptureDisabled = false;
}
else
{
captureMouse(false);
captureKbd(false, false);
}
}
{
uint8_t whatPressed = 0;
if (!isHostKey && !m_bIsHostkeyPressed)
{
{
if (fFlags & KeyPressed)
{
}
else
{
codes = PrintBreak;
}
}
{
if (fFlags & KeyPressed)
{
}
else
{
/* Pause shall not produce a break code */
return true;
}
}
else
{
if (fFlags & KeyPressed)
{
/* Check if the guest has the same view on the modifier keys (NumLock,
* CapsLock, ScrollLock) as the X server. If not, send KeyPress events
* to synchronize the state. */
}
if (!m_fPassCAD &&
{
/* Use the C-A-D combination as a last resort to get the
* keyboard and mouse back to the host when the user forgets
* the Host Key. Note that it's always possible to send C-A-D
* to the guest using the Host+Del combination. BTW, it would
* be preferrable to completely ignore C-A-D in guests, but
* that's not possible because we cannot predict what other
* keys will be pressed next when one of C, A, D is held. */
{
captureKbd (false);
captureMouse (false);
}
return true;
}
/* Process the scancode and update the table of pressed keys: */
if (fFlags & KeyExtended)
{
}
if (fFlags & KeyPressed)
{
}
else
{
/* If we haven't got this key's press message, we ignore its release: */
return true;
}
else
}
}
else
{
/* Currently this is used in winLowKeyboardEvent() only: */
}
bool emitSignal = false;
int hotkey = 0;
/* Process the host key: */
if (fFlags & KeyPressed)
{
if (isHostKey)
{
if (!m_bIsHostkeyPressed)
{
m_bIsHostkeyPressed = m_bIsHostkeyAlone = true;
emitSignal = true;
}
}
else
{
if (m_bIsHostkeyPressed)
{
if (m_bIsHostkeyAlone)
{
m_bIsHostkeyAlone = false;
}
}
}
}
else
{
if (isHostKey)
{
if (m_bIsHostkeyPressed)
{
m_bIsHostkeyPressed = false;
if (m_bIsHostkeyAlone)
{
{
}
{
bool captured = m_bIsKeyboardCaptured;
bool ok = true;
if (!captured)
{
/* temporarily disable auto capture that will take
* place after this dialog is dismissed because
* the capture state is to be defined by the
* dialog result itself */
m_bIsAutoCaptureDisabled = true;
bool autoConfirmed = false;
if (autoConfirmed)
m_bIsAutoCaptureDisabled = false;
/* otherwise, the disable flag will be reset in
* the next console view's foucs in event (since
* may happen asynchronously on some platforms,
* after we return from this code) */
}
if (ok)
{
captureKbd (!captured, false);
{
#ifdef Q_WS_X11
/* make sure that pending FocusOut events from the
* previous message box are handled, otherwise the
* mouse is immediately ungrabbed. */
qApp->processEvents();
#endif
}
}
}
}
emitSignal = true;
}
}
else
{
if (m_bIsHostkeyPressed)
m_bIsHostkeyAlone = false;
}
}
/* emit the keyboard state change signal */
if (emitSignal)
/* Process Host+<key> shortcuts. currently, <key> is limited to
* alphanumeric chars. Other Host+<key> combinations are handled in
* event(). */
if (hotkey)
{
bool processed = false;
#if defined (Q_WS_WIN32)
int n = GetKeyboardLayoutList(0, NULL);
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;
int keysyms_per_keycode = getKeysymsPerKeycode();
{
char ch = 0;
ch = 0;
if (ch)
}
// TODO_NEW_CORE
processed = machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence(Qt::UNICODE_ACCEL + QChar(pUniKey[0]).toUpper().unicode()));
/* Don't consider the hot key as pressed since the guest never saw
* it. (probably a generic thing) */
#endif
/* Grab the key from Qt if processed, or pass it to Qt otherwise
* in order to process non-alphanumeric keys in event(), after they are
* converted to Qt virtual keys. */
return processed;
}
/* No more to do, if the host key is in action or the VM is paused: */
{
/* Grab the key from Qt and from VM if it's a host key,
* otherwise just pass it to Qt */
return isHostKey;
}
#if defined (Q_WS_WIN32)
/* send pending WM_PAINT events */
#endif
/* Grab the key from Qt: */
return true;
}
{
int state = 0;
#ifdef Q_WS_MAC
/* Simulate the right click on Host+Left Mouse: */
if (m_bIsHostkeyPressed &&
#endif /* Q_WS_MAC */
int wheelVertical = 0;
int wheelHorizontal = 0;
{
/* the absolute value of wheel delta is 120 units per every wheel
* move; positive deltas correspond to counterclockwize rotations
* (usually up), negative -- to clockwize (usually down). */
}
if (uisession()->isMouseCaptured())
{
#ifdef Q_WS_WIN32
/* send pending WM_PAINT events */
#endif
aGlobalPos.y() - m_lastMousePos.y(),
#if defined (Q_WS_MAC)
/*
* Keep the mouse from leaving the widget.
*
* This is a bit tricky to get right because if it escapes we won't necessarily
* get mouse events any longer and can warp it back. So, we keep safety zone
* of up to 300 pixels around the borders of the widget to prevent this from
* happening. Also, the mouse is warped back to the center of the widget.
*
* (Note, aPos seems to be unreliable, it caused endless recursion here at one points...)
* (Note, synergy and other remote clients might not like this cursor warping.)
*/
else
{
}
#else /* !Q_WS_MAC */
/* "jerk" the mouse by bringing it to the opposite side
* to simulate the endless moving */
# ifdef Q_WS_WIN32
if (aPos.x() == 0)
p.setX (1);
if (aPos.y() == 0 )
p.setY (1);
if (p != aPos)
{
}
else
{
}
# else
QPoint p = aGlobalPos;
if (aGlobalPos.x() == 0)
else if (aGlobalPos.x() == we)
p.setX( 1 );
if (aGlobalPos.y() == 0)
else if (aGlobalPos.y() == he)
p.setY (1);
if (p != aGlobalPos)
{
m_lastMousePos = p;
}
else
{
}
# endif
#endif /* !Q_WS_MAC */
return true; /* stop further event handling */
}
else /* !uisession()->isMouseCaptured() */
{
#if 0 // TODO: Move that to fullscreen event-hjadler:
{
/* try to automatically scroll the guest canvas if the
* mouse is on the screen border */
/// @todo (r=dmik) better use a timer for autoscroll
{
}
{
}
}
#endif
{
{
/* Try to automatically scroll the guest canvas if the
* mouse goes outside its visible part: */
int dx = 0;
int dy = 0;
}
return true;
}
else
{
{
{
}
{
/* Temporarily disable auto capture that will take place after this dialog is dismissed because
* the capture state is to be defined by the dialog result itself: */
m_bIsAutoCaptureDisabled = true;
bool autoConfirmed = false;
if (autoConfirmed)
m_bIsAutoCaptureDisabled = false;
/* Otherwise, the disable flag will be reset in the next console view's foucs in event (since
* may happen asynchronously on some platforms, after we return from this code): */
if (ok)
{
#ifdef Q_WS_X11
/* Make sure that pending FocusOut events from the previous message box are handled,
* otherwise the mouse is immediately ungrabbed again: */
qApp->processEvents();
#endif
captureKbd(true);
captureMouse(true);
}
}
}
}
}
return false;
}
{
#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
#endif /* Q_WS_MAC */
}
{
#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
PostBoundsChanged (r);
#endif /* Q_WS_MAC */
}
{
if (m_pauseShot.isNull())
{
/* Delegate the paint function to the VBoxFrameBuffer interface: */
if (m_pFrameBuffer)
#ifdef Q_WS_MAC
/* Update the dock icon if we are in the running state */
// TODO_NEW_CORE
// if (uisession()->isRunning())
// updateDockIcon();
#endif
return;
}
#ifdef VBOX_GUI_USE_QUARTZ2D
// TODO_NEW_CORE
// if (mode() == VBoxDefs::Quartz2DMode && m_pFrameBuffer)
// {
// m_pFrameBuffer->paintEvent(pPaintEvent);
// updateDockIcon();
// }
// else
#endif
// {
// /* We have a snapshot for the paused state: */
// QRect r = pPaintEvent->rect().intersect (viewport()->rect());
// /* We have to disable paint on screen if we are using the regular painter */
// bool paintOnScreen = viewport()->testAttribute(Qt::WA_PaintOnScreen);
// viewport()->setAttribute(Qt::WA_PaintOnScreen, false);
// QPainter pnt(viewport());
// pnt.drawPixmap(r.x(), r.y(), m_pauseShot, r.x() + contentsX(), r.y() + contentsY(), r.width(), r.height());
// /* Restore the attribute to its previous state */
// viewport()->setAttribute(Qt::WA_PaintOnScreen, paintOnScreen);
#ifdef Q_WS_MAC
// updateDockIcon();
#endif
// }
}
#if defined(Q_WS_WIN32)
static UIMachineView *gView = 0;
{
return 1;
}
{
/* Sometimes it happens that Win inserts additional events on some key
* the VK_LCONTROL vkey with curious 0x21D scan code (seems to be necessary
* to specially treat ALT_GR to enter additional chars to regular apps).
* These events are definitely unwanted in VM, so filter them out. */
/* Note (michael): it also sometimes sends the VK_CAPITAL vkey with scan
* code 0x23a. If this is not passed through then it is impossible to
* cancel CapsLock on a French keyboard. I didn't find any other examples
* of these strange events. Let's hope we are not missing anything else
* of importance! */
{
return false;
else
return true;
}
if (!m_bIsKeyboardCaptured)
return false;
/* it's possible that a key has been pressed while the keyboard was not
* captured, but is being released under the capture. Detect this situation
* and return false to let Windows process the message normally and update
* its key state table (to avoid the stuck key effect). */
uint8_t what_pressed = (event.flags & 0x01) && (event.vkCode != VK_RSHIFT) ? IsExtKeyPressed : IsKeyPressed;
return false;
/* Windows sets here the extended bit when the Right Shift key is pressed,
* which is totally wrong. Undo it. */
/* we suppose here that this hook is always called on the main GUI thread */
long dummyResult;
}
{
return false;
/* Check for the special flag possibly set at the end of this function */
{
return false;
}
/* scancodes 0x80 and 0x00 are ignored */
if (!scan)
return true;
/* When one of the SHIFT keys is held and one of the cursor movement
* but with the virtual key code set to 0xFF. These virtual keys are also
* sent in some other situations (Pause, PrtScn, etc.). Ignore such
* messages. */
if (vkey == 0xFF)
return true;
int flags = 0;
flags |= KeyExtended;
flags |= KeyPressed;
switch (vkey)
{
case VK_SHIFT:
case VK_CONTROL:
case VK_MENU:
{
/* overcome stupid Win32 modifier key generalization */
if (flags & KeyExtended)
keyscan |= 0xE000;
switch (keyscan)
{
}
break;
}
case VK_NUMLOCK:
/* Win32 sets the extended bit for the NumLock key. Reset it. */
flags &= ~KeyExtended;
break;
case VK_SNAPSHOT:
break;
case VK_PAUSE:
break;
}
if (!result && m_bIsKeyboardCaptured)
{
/* keyEvent() returned that it didn't process the message, but since the
* keyboard is captured, we don't want to pass it to Windows. We just want
* to let Qt process the message (to handle non-alphanumeric <HOST>+key
* shortcuts for example). So send it direcltly to the window with the
* special flag in the reserved area of lParam (to avoid recursion). */
return true;
}
/* These special keys have to be handled by Windows as well to update the
return false;
return result;
}
{
{
/* We are inside the input hook
* let the message go through the normal system pipeline. */
if (!m_bIsKeyboardCaptured)
return false;
}
return false;
/* check for the special flag possibly set at the end of this function */
{
return false;
}
return true;
int flags = 0;
{
flags |= KeyExtended;
}
{
/* this is the '/' key on the keypad */
scan = 0x35;
flags |= KeyExtended;
}
else
{
/* For some keys, the scan code passed in QMSG is a pseudo scan
* code. We replace it with a real hardware scan code, according to
* Also detect Pause and PrtScn and set flags. */
switch (vkey)
{
#if 0
/// @todo this would send 0xE0 0x46 0xE0 0xC6. It's not fully
// clear what is more correct
#else
#endif
default:;
}
}
if (!(f & KC_KEYUP))
flags |= KeyPressed;
if (!result && m_bIsKeyboardCaptured)
{
/* keyEvent() returned that it didn't process the message, but since the
* keyboard is captured, we don't want to pass it to PM. We just want
* to let Qt process the message (to handle non-alphanumeric <HOST>+key
* shortcuts for example). So send it direcltly to the window with the
* special flag in the reserved area of lParam (to avoid recursion). */
return true;
}
return result;
}
{
return True;
else
return False;
}
{
{
/* We have to handle XFocusOut right here as this event is not passed
* to UIMachineView::event(). Handling this event is important for
* releasing the keyboard before the screen saver gets active. */
case XFocusOut:
case XFocusIn:
return false;
case XKeyPress:
case XKeyRelease:
break;
default:
return false; /* pass the event to Qt */
}
/* Translate the keycode to a PC scan code. */
/* scancodes 0x00 (no valid translation) and 0x80 are ignored */
if (!scan & 0x7F)
return true;
/* Fix for http://www.virtualbox.org/ticket/1296:
* when X11 sends events for repeated keys, it always inserts an
* XKeyRelease before the XKeyPress. */
{
/* Discard it, don't pass it to Qt. */
return true;
}
int flags = 0;
if (scan >> 8)
flags |= KeyExtended;
flags |= KeyPressed;
/* Remove the extended flag */
scan &= 0x7F;
switch (ks)
{
case XK_Print:
break;
case XK_Pause:
break;
}
}
{
bool ret = false;
{
/* convert keycode to set 1 scan code. */
::GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof (keyCode), NULL, &keyCode);
if (scanCode)
{
/* calc flags. */
int flags = 0;
if (EventKind != kEventRawKeyUp)
flags |= KeyPressed;
if (scanCode & VBOXKEY_EXTENDED)
flags |= KeyExtended;
/** @todo KeyPause, KeyPrint. */
/* get the unicode string (if present). */
AssertCompileSize(wchar_t, 2);
wchar_t ucs[8];
cbWritten = 0;
}
}
else
{
/* May contain multiple modifier changes, kind of annoying. */
if (changed)
{
{
continue;
if (!scanCode)
continue;
if (!(scanCode & VBOXKEY_LOCK))
{
if (scanCode & VBOXKEY_EXTENDED)
flags |= KeyExtended;
}
else
{
unsigned flags = 0;
if (scanCode & VBOXKEY_EXTENDED)
flags |= KeyExtended;
}
}
}
/* Always return true here because we'll otherwise getting a Qt event
we don't want and that will only cause the Pause warning to pop up. */
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
UIMachineView::darwinEventHandlerProc, this);
# else /* QT_MAC_USE_COCOA */
/* For ignorning Command-H and Command-Q which aren't affected by the
* global hotkey stuff (doesn't work well): */
this, &m_darwinEventHandlerRef);
# endif /* !QT_MAC_USE_COCOA */
::DarwinGrabKeyboard (false);
}
else
{
# ifdef QT_MAC_USE_COCOA
UIMachineView::darwinEventHandlerProc, this);
# else /* QT_MAC_USE_COCOA */
{
}
# endif /* !QT_MAC_USE_COCOA */
}
}
# ifdef QT_MAC_USE_COCOA
bool UIMachineView::darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser)
{
/* Check if this is an application key combo. In that case we will not pass
* the event to the guest, but let the host process it. */
return false;
/* All keyboard class events needs to be handled. */
if (eventClass == kEventClassKeyboard)
{
return true;
}
/* Pass the event along. */
return false;
}
# else /* QT_MAC_USE_COCOA */
pascal OSStatus UIMachineView::darwinEventHandlerProc(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
{
/* Not sure but this seems an triggered event if the spotlight searchbar is
* displayed. So flag that the host key isn't pressed alone. */
view->m_bIsHostkeyAlone = false;
if (eventClass == kEventClassKeyboard)
{
return 0;
}
/*
* Command-H and Command-Q aren't properly disabled yet, and it's still
* possible to use the left command key to invoke them when the keyboard
* is captured. We discard the events these if the keyboard is captured
* as a half measure to prevent unexpected behaviour. However, we don't
*/
else if (eventClass == kEventClassCommand)
{
if (view->m_bIsKeyboardCaptured)
return 0;
}
}
# endif /* !QT_MAC_USE_COCOA */
#endif
{
/* Synchronize the views of the host and the guest to the modifier keys.
* This function will add up to 6 additional keycodes to codes. */
#if defined(Q_WS_X11)
unsigned uMask;
for (int i = 0; i < 8; ++ i)
{
uKeyMaskNum = 1 << i;
uKeyMaskScroll = 1 << i;
}
{
}
{
/* Some keyboard layouts require shift to be pressed to break
* capslock. For simplicity, only do this if shift is not
* already held down. */
{
}
}
#elif defined(Q_WS_WIN32)
{
}
if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(GetKeyState(VK_CAPITAL))))
{
/* Some keyboard layouts require shift to be pressed to break
* capslock. For simplicity, only do this if shift is not
* already held down. */
{
}
}
/* if (uisession()->numLockAdaptionCnt()) ... - NumLock isn't implemented by Mac OS X so ignore it. */
if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(::GetCurrentEventKeyModifiers() & alphaLock)))
{
/* Some keyboard layouts require shift to be pressed to break
* capslock. For simplicity, only do this if shift is not
* already held down. */
{
}
}
#else
//#warning Adapt UIMachineView::fixModifierState
#endif
}
{
}
{
}
#ifdef VBOX_WITH_VIDEOHWACCEL
{
if (m_pFrameBuffer)
{
}
}
#endif
{
}
void UIMachineView::emitMouseStateChanged()
{
}
{
if (m_bIsKeyboardCaptured == fCapture)
return;
/* On Win32, keyboard grabbing is ineffective, a low-level keyboard hook is used instead.
* On X11, we use XGrabKey instead of XGrabKeyboard (called by QWidget::grabKeyboard())
* because the latter causes problems under metacity 2.16 (in particular, due to a bug,
* a window cannot be moved using the mouse if it is currently grabing the keyboard).
* On Mac OS X, we use the Qt methods + disabling global hot keys + watching modifiers
#if defined(Q_WS_WIN32)
/**/
if (fCapture)
XGrabKey(QX11Info::display(), AnyKey, AnyModifier, window()->winId(), False, GrabModeAsync, GrabModeAsync);
else
if (fCapture)
{
::DarwinDisableGlobalHotKeys(true);
grabKeyboard();
}
else
{
::DarwinDisableGlobalHotKeys(false);
}
#else
if (fCapture)
grabKeyboard();
else
#endif
if (fEmitSignal)
}
{
return;
if (fCapture)
{
/* Memorize the host position where the cursor was captured: */
#ifdef Q_WS_WIN32
/* Move the mouse to the center of the visible area: */
/* Move the mouse to the center of the visible area: */
/* Grab all mouse events: */
#else
#endif
}
else
{
#ifndef Q_WS_WIN32
viewport()->releaseMouse();
#endif
/* Release mouse buttons: */
}
if (fEmitSignal)
}
void UIMachineView::saveKeyStates()
{
}
{
bool fSentRESEND = false;
/* Send a dummy scan code (RESEND) to prevent the guest OS from recognizing
* a single key click (for ex., Alt) and performing an unwanted action
* (for ex., activating the menu) when we release all pressed keys below.
* Note, that it's just a guess that sending RESEND will give the desired
* effect :), but at least it works with NT and W2k guests. */
{
if (m_pressedKeys[i] & IsKeyPressed)
{
if (!fSentRESEND)
{
fSentRESEND = true;
}
}
else if (m_pressedKeys[i] & IsExtKeyPressed)
{
if (!fSentRESEND)
{
fSentRESEND = true;
}
codes[0] = 0xE0;
}
m_pressedKeys[i] = 0;
}
if (aReleaseHostKey)
m_bIsHostkeyPressed = false;
#ifdef Q_WS_MAC
/* Clear most of the modifiers: */
#endif
}
void UIMachineView::sendChangedKeyStates()
{
{
{
codes[0] = i;
if (!(ns & IsKeyPressed))
codes[0] |= 0x80;
}
{
codes[0] = 0xE0;
codes[1] = i;
if (!(ns & IsExtKeyPressed))
}
}
}
{
{
if (y % 2)
{
{
{
}
}
else
{
}
}
else
{
{
{
}
}
}
}
}
#if defined(Q_WS_MAC)
void UIMachineView::updateDockIcon()
{
// TODO_NEW_CORE
// if (mDockIconEnabled)
// {
// if (!m_pauseShot.isNull())
// {
// CGImageRef pauseImg = ::darwinToCGImageRef (&m_pauseShot);
// /* Use the pause image as background */
// mDockIconPreview->updateDockPreview (pauseImg);
// CGImageRelease (pauseImg);
// }
// else
// {
//# if defined (VBOX_GUI_USE_QUARTZ2D)
// if (mode() == VBoxDefs::Quartz2DMode)
// {
// /* If the render mode is Quartz2D we could use the CGImageRef
// * of the framebuffer for the dock icon creation. This saves
// * some conversion time. */
// mDockIconPreview->updateDockPreview(static_cast<UIFrameBufferQuartz2D*>(m_pFrameBuffer)->imageRef());
// }
// else
//# endif
// /* In image mode we have to create the image ref out of the
// * framebuffer */
// mDockIconPreview->updateDockPreview(m_pFrameBuffer);
// }
// }
}
void UIMachineView::updateDockOverlay()
{
/* Only to an update to the realtime preview if this is enabled by the user
* & we are in an state where the framebuffer is likely valid. Otherwise to
* the overlay stuff only. */
// TODO_NEW_CORE
// if (mDockIconEnabled &&
// (machineState() == KMachineState_Running ||
// machineState() == KMachineState_Paused ||
// machineState() == KMachineState_Teleporting ||
// machineState() == KMachineState_LiveSnapshotting ||
// machineState() == KMachineState_Restoring ||
// machineState() == KMachineState_TeleportingPausedVM ||
// machineState() == KMachineState_TeleportingIn ||
// machineState() == KMachineState_Saving))
// updateDockIcon();
// else
// mDockIconPreview->updateDockOverlay();
}
{
/* Enable mouse event compression if we leave the VM view. This
windows.
Disable mouse event compression if we enter the VM view. So
all mouse events are registered in the VM. Only do this if
event handler). */
if (aOn || m_fKeyboardGrabbed)
}
#endif /* Q_WS_MAC */