[26709] | 1 | /* $Id: UIMachineView.cpp 35247 2010-12-20 14:19:48Z vboxsync $ */
|
---|
[382] | 2 | /** @file
|
---|
| 3 | *
|
---|
| 4 | * VBox frontends: Qt GUI ("VirtualBox"):
|
---|
[26637] | 5 | * UIMachineView class implementation
|
---|
[382] | 6 | */
|
---|
| 7 |
|
---|
| 8 | /*
|
---|
[28800] | 9 | * Copyright (C) 2010 Oracle Corporation
|
---|
[382] | 10 | *
|
---|
| 11 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
| 12 | * available from http://www.virtualbox.org. This file is free software;
|
---|
| 13 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
[5999] | 14 | * General Public License (GPL) as published by the Free Software
|
---|
| 15 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
| 16 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
| 17 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
[382] | 18 | */
|
---|
| 19 |
|
---|
[26637] | 20 | /* Global includes */
|
---|
| 21 | #include <QDesktopWidget>
|
---|
| 22 | #include <QTimer>
|
---|
| 23 | #include <QPainter>
|
---|
| 24 | #include <QScrollBar>
|
---|
[19817] | 25 | #include <VBox/VBoxVideo.h>
|
---|
| 26 |
|
---|
[26637] | 27 | /* Local includes */
|
---|
[382] | 28 | #include "VBoxGlobal.h"
|
---|
| 29 | #include "VBoxProblemReporter.h"
|
---|
[26637] | 30 | #include "UIFrameBuffer.h"
|
---|
[26797] | 31 | #include "UIFrameBufferQGL.h"
|
---|
[26823] | 32 | #include "UIFrameBufferQImage.h"
|
---|
[26781] | 33 | #include "UIFrameBufferQuartz2D.h"
|
---|
[26822] | 34 | #include "UIFrameBufferSDL.h"
|
---|
[27682] | 35 | #include "VBoxFBOverlay.h"
|
---|
[26691] | 36 | #include "UISession.h"
|
---|
[26637] | 37 | #include "UIActionsPool.h"
|
---|
[30637] | 38 | #include "UIKeyboardHandler.h"
|
---|
[30408] | 39 | #include "UIMouseHandler.h"
|
---|
[26637] | 40 | #include "UIMachineLogic.h"
|
---|
| 41 | #include "UIMachineWindow.h"
|
---|
| 42 | #include "UIMachineViewNormal.h"
|
---|
[26889] | 43 | #include "UIMachineViewFullscreen.h"
|
---|
[27012] | 44 | #include "UIMachineViewSeamless.h"
|
---|
[30753] | 45 | #include "UIMachineViewScale.h"
|
---|
[382] | 46 |
|
---|
| 47 | #ifdef Q_WS_X11
|
---|
[26637] | 48 | # include <QX11Info>
|
---|
| 49 | # include <X11/XKBlib.h>
|
---|
| 50 | # ifdef KeyPress
|
---|
[382] | 51 | const int XFocusOut = FocusOut;
|
---|
| 52 | const int XFocusIn = FocusIn;
|
---|
| 53 | const int XKeyPress = KeyPress;
|
---|
| 54 | const int XKeyRelease = KeyRelease;
|
---|
[26637] | 55 | # undef KeyRelease
|
---|
| 56 | # undef KeyPress
|
---|
| 57 | # undef FocusOut
|
---|
| 58 | # undef FocusIn
|
---|
| 59 | # endif
|
---|
[30549] | 60 | #endif /* Q_WS_X11 */
|
---|
[382] | 61 |
|
---|
[26998] | 62 | #ifdef Q_WS_MAC
|
---|
[24377] | 63 | # include "DockIconPreview.h"
|
---|
[1285] | 64 | # include "DarwinKeyboard.h"
|
---|
[30114] | 65 | # include "UICocoaApplication.h"
|
---|
[1391] | 66 | # include <VBox/err.h>
|
---|
[29816] | 67 | # include <Carbon/Carbon.h>
|
---|
[27215] | 68 | #endif /* Q_WS_MAC */
|
---|
[1285] | 69 |
|
---|
[30551] | 70 | class UIViewport: public QWidget
|
---|
[26637] | 71 | {
|
---|
| 72 | public:
|
---|
[382] | 73 |
|
---|
[30551] | 74 | UIViewport(QWidget *pParent) : QWidget(pParent)
|
---|
[26637] | 75 | {
|
---|
[26773] | 76 | /* No need for background drawing: */
|
---|
[26637] | 77 | setAttribute(Qt::WA_OpaquePaintEvent);
|
---|
| 78 | }
|
---|
| 79 |
|
---|
| 80 | QPaintEngine *paintEngine() const
|
---|
| 81 | {
|
---|
| 82 | if (testAttribute(Qt::WA_PaintOnScreen))
|
---|
| 83 | return NULL;
|
---|
| 84 | else
|
---|
| 85 | return QWidget::paintEngine();
|
---|
| 86 | }
|
---|
| 87 | };
|
---|
| 88 |
|
---|
| 89 | UIMachineView* UIMachineView::create( UIMachineWindow *pMachineWindow
|
---|
[30544] | 90 | , ulong uScreenId
|
---|
| 91 | , UIVisualStateType visualStateType
|
---|
[26637] | 92 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
| 93 | , bool bAccelerate2DVideo
|
---|
[30549] | 94 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[30544] | 95 | )
|
---|
[7590] | 96 | {
|
---|
[30551] | 97 | UIMachineView *pMachineView = 0;
|
---|
[26637] | 98 | switch (visualStateType)
|
---|
[7590] | 99 | {
|
---|
[26637] | 100 | case UIVisualStateType_Normal:
|
---|
[30551] | 101 | pMachineView = new UIMachineViewNormal( pMachineWindow
|
---|
| 102 | , uScreenId
|
---|
[26637] | 103 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
[30551] | 104 | , bAccelerate2DVideo
|
---|
[30549] | 105 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[30551] | 106 | );
|
---|
[26637] | 107 | break;
|
---|
| 108 | case UIVisualStateType_Fullscreen:
|
---|
[30551] | 109 | pMachineView = new UIMachineViewFullscreen( pMachineWindow
|
---|
| 110 | , uScreenId
|
---|
[26637] | 111 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
[30551] | 112 | , bAccelerate2DVideo
|
---|
[30549] | 113 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[30551] | 114 | );
|
---|
[26637] | 115 | break;
|
---|
| 116 | case UIVisualStateType_Seamless:
|
---|
[30551] | 117 | pMachineView = new UIMachineViewSeamless( pMachineWindow
|
---|
| 118 | , uScreenId
|
---|
[26637] | 119 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
[30551] | 120 | , bAccelerate2DVideo
|
---|
[30549] | 121 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[30551] | 122 | );
|
---|
[26637] | 123 | break;
|
---|
[30753] | 124 | case UIVisualStateType_Scale:
|
---|
| 125 | pMachineView = new UIMachineViewScale( pMachineWindow
|
---|
| 126 | , uScreenId
|
---|
| 127 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
| 128 | , bAccelerate2DVideo
|
---|
| 129 | #endif
|
---|
| 130 | );
|
---|
| 131 | break;
|
---|
[26637] | 132 | default:
|
---|
| 133 | break;
|
---|
[7590] | 134 | }
|
---|
[30551] | 135 | return pMachineView;
|
---|
[26637] | 136 | }
|
---|
| 137 |
|
---|
[30544] | 138 | void UIMachineView::destroy(UIMachineView *pMachineView)
|
---|
[26878] | 139 | {
|
---|
[30544] | 140 | delete pMachineView;
|
---|
[26878] | 141 | }
|
---|
| 142 |
|
---|
[35247] | 143 | double UIMachineView::aspectRatio() const
|
---|
| 144 | {
|
---|
| 145 | return frameBuffer() ? (double)(frameBuffer()->width()) / frameBuffer()->height() : 0;
|
---|
| 146 | }
|
---|
| 147 |
|
---|
[30549] | 148 | void UIMachineView::sltMachineStateChanged()
|
---|
| 149 | {
|
---|
| 150 | /* Get machine state: */
|
---|
| 151 | KMachineState state = uisession()->machineState();
|
---|
| 152 | switch (state)
|
---|
| 153 | {
|
---|
| 154 | case KMachineState_Paused:
|
---|
| 155 | case KMachineState_TeleportingPausedVM:
|
---|
| 156 | {
|
---|
[31341] | 157 | if ( vboxGlobal().vmRenderMode() != VBoxDefs::TimerMode
|
---|
| 158 | && m_pFrameBuffer
|
---|
| 159 | &&
|
---|
| 160 | ( state != KMachineState_TeleportingPausedVM
|
---|
| 161 | || m_previousState != KMachineState_Teleporting))
|
---|
[30549] | 162 | {
|
---|
[31341] | 163 | takePauseShotLive();
|
---|
[30549] | 164 | /* Fully repaint to pick up m_pauseShot: */
|
---|
[30673] | 165 | viewport()->update();
|
---|
[30549] | 166 | }
|
---|
| 167 | break;
|
---|
| 168 | }
|
---|
[31341] | 169 | case KMachineState_Restoring:
|
---|
| 170 | {
|
---|
| 171 | /* Only works with the primary screen currently. */
|
---|
| 172 | if (screenId() == 0)
|
---|
| 173 | {
|
---|
| 174 | takePauseShotSnapshot();
|
---|
| 175 | /* Fully repaint to pick up m_pauseShot: */
|
---|
| 176 | viewport()->update();
|
---|
| 177 | }
|
---|
| 178 | break;
|
---|
| 179 | }
|
---|
[30549] | 180 | case KMachineState_Running:
|
---|
| 181 | {
|
---|
| 182 | if ( m_previousState == KMachineState_Paused
|
---|
| 183 | || m_previousState == KMachineState_TeleportingPausedVM
|
---|
| 184 | || m_previousState == KMachineState_Restoring)
|
---|
| 185 | {
|
---|
| 186 | if (vboxGlobal().vmRenderMode() != VBoxDefs::TimerMode && m_pFrameBuffer)
|
---|
| 187 | {
|
---|
| 188 | /* Reset the pixmap to free memory: */
|
---|
[31341] | 189 | resetPauseShot();
|
---|
[30549] | 190 | /* Ask for full guest display update (it will also update
|
---|
| 191 | * the viewport through IFramebuffer::NotifyUpdate): */
|
---|
| 192 | CDisplay dsp = session().GetConsole().GetDisplay();
|
---|
| 193 | dsp.InvalidateAndUpdate();
|
---|
| 194 | }
|
---|
| 195 | }
|
---|
| 196 | break;
|
---|
| 197 | }
|
---|
| 198 | default:
|
---|
| 199 | break;
|
---|
| 200 | }
|
---|
[31341] | 201 |
|
---|
[30549] | 202 | m_previousState = state;
|
---|
| 203 | }
|
---|
| 204 |
|
---|
[26637] | 205 | UIMachineView::UIMachineView( UIMachineWindow *pMachineWindow
|
---|
[30544] | 206 | , ulong uScreenId
|
---|
[22816] | 207 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
[26637] | 208 | , bool bAccelerate2DVideo
|
---|
[30549] | 209 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[30544] | 210 | )
|
---|
[26637] | 211 | : QAbstractScrollArea(pMachineWindow->machineWindow())
|
---|
| 212 | , m_pMachineWindow(pMachineWindow)
|
---|
[26921] | 213 | , m_uScreenId(uScreenId)
|
---|
[26754] | 214 | , m_pFrameBuffer(0)
|
---|
[26816] | 215 | , m_previousState(KMachineState_Null)
|
---|
[27012] | 216 | , m_desktopGeometryType(DesktopGeo_Invalid)
|
---|
[26878] | 217 | , m_bIsMachineWindowResizeIgnored(false)
|
---|
[22816] | 218 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
[26754] | 219 | , m_fAccelerate2DVideo(bAccelerate2DVideo)
|
---|
[27215] | 220 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[382] | 221 | {
|
---|
[26730] | 222 | }
|
---|
[382] | 223 |
|
---|
[26730] | 224 | UIMachineView::~UIMachineView()
|
---|
| 225 | {
|
---|
| 226 | }
|
---|
[14397] | 227 |
|
---|
[30752] | 228 | void UIMachineView::prepareViewport()
|
---|
[26730] | 229 | {
|
---|
[26858] | 230 | /* Prepare viewport: */
|
---|
[27682] | 231 | #ifdef VBOX_GUI_USE_QGLFB
|
---|
[30551] | 232 | QWidget *pViewport = 0;
|
---|
[30347] | 233 | switch (vboxGlobal().vmRenderMode())
|
---|
[26858] | 234 | {
|
---|
| 235 | case VBoxDefs::QGLMode:
|
---|
[26862] | 236 | pViewport = new VBoxGLWidget(session().GetConsole(), this, NULL);
|
---|
[26858] | 237 | break;
|
---|
| 238 | default:
|
---|
[30551] | 239 | pViewport = new UIViewport(this);
|
---|
[26858] | 240 | }
|
---|
[30549] | 241 | #else /* VBOX_GUI_USE_QGLFB */
|
---|
[30551] | 242 | UIViewport *pViewport = new UIViewport(this);
|
---|
[30549] | 243 | #endif /* !VBOX_GUI_USE_QGLFB */
|
---|
[26858] | 244 | setViewport(pViewport);
|
---|
[30752] | 245 | }
|
---|
[26858] | 246 |
|
---|
[30752] | 247 | void UIMachineView::prepareFrameBuffer()
|
---|
| 248 | {
|
---|
| 249 | /* Prepare frame-buffer depending on render-mode: */
|
---|
[30347] | 250 | switch (vboxGlobal().vmRenderMode())
|
---|
[382] | 251 | {
|
---|
[26822] | 252 | #ifdef VBOX_GUI_USE_QIMAGE
|
---|
[382] | 253 | case VBoxDefs::QImageMode:
|
---|
[27682] | 254 | # ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
[27697] | 255 | if (m_fAccelerate2DVideo)
|
---|
| 256 | {
|
---|
[27768] | 257 | UIFrameBuffer* pFramebuffer = uisession()->frameBuffer(screenId());
|
---|
[27757] | 258 | if (pFramebuffer)
|
---|
| 259 | pFramebuffer->setView(this);
|
---|
| 260 | else
|
---|
| 261 | {
|
---|
| 262 | /* these two additional template args is a workaround to this [VBox|UI] duplication
|
---|
| 263 | * @todo: they are to be removed once VBox stuff is gone */
|
---|
[27839] | 264 | pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferQImage, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId());
|
---|
[27768] | 265 | uisession()->setFrameBuffer(screenId(), pFramebuffer);
|
---|
[27757] | 266 | }
|
---|
| 267 | m_pFrameBuffer = pFramebuffer;
|
---|
[27697] | 268 | }
|
---|
| 269 | else
|
---|
| 270 | m_pFrameBuffer = new UIFrameBufferQImage(this);
|
---|
[30549] | 271 | # else /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[26754] | 272 | m_pFrameBuffer = new UIFrameBufferQImage(this);
|
---|
[30549] | 273 | # endif /* !VBOX_WITH_VIDEOHWACCEL */
|
---|
[382] | 274 | break;
|
---|
[26822] | 275 | #endif /* VBOX_GUI_USE_QIMAGE */
|
---|
[27682] | 276 | #ifdef VBOX_GUI_USE_QGLFB
|
---|
[26730] | 277 | case VBoxDefs::QGLMode:
|
---|
[26797] | 278 | m_pFrameBuffer = new UIFrameBufferQGL(this);
|
---|
[26730] | 279 | break;
|
---|
[26797] | 280 | // case VBoxDefs::QGLOverlayMode:
|
---|
| 281 | // m_pFrameBuffer = new UIQGLOverlayFrameBuffer(this);
|
---|
| 282 | // break;
|
---|
[27682] | 283 | #endif /* VBOX_GUI_USE_QGLFB */
|
---|
[26822] | 284 | #ifdef VBOX_GUI_USE_SDL
|
---|
[382] | 285 | case VBoxDefs::SDLMode:
|
---|
[26730] | 286 | /* Indicate that we are doing all drawing stuff ourself: */
|
---|
[26822] | 287 | // TODO_NEW_CORE
|
---|
| 288 | viewport()->setAttribute(Qt::WA_PaintOnScreen);
|
---|
[6059] | 289 | # ifdef Q_WS_X11
|
---|
[26730] | 290 | /* This is somehow necessary to prevent strange X11 warnings on i386 and segfaults on x86_64: */
|
---|
[7407] | 291 | XFlush(QX11Info::display());
|
---|
[30549] | 292 | # endif /* Q_WS_X11 */
|
---|
[27682] | 293 | # if defined(VBOX_WITH_VIDEOHWACCEL) && defined(DEBUG_misha) /* not tested yet */
|
---|
[27758] | 294 | if (m_fAccelerate2DVideo)
|
---|
| 295 | {
|
---|
[27769] | 296 | class UIFrameBuffer* pFramebuffer = uisession()->frameBuffer(screenId());
|
---|
[27758] | 297 | if (pFramebuffer)
|
---|
| 298 | pFramebuffer->setView(this);
|
---|
| 299 | else
|
---|
| 300 | {
|
---|
| 301 | /* these two additional template args is a workaround to this [VBox|UI] duplication
|
---|
| 302 | * @todo: they are to be removed once VBox stuff is gone */
|
---|
[27839] | 303 | pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferSDL, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId());
|
---|
[27769] | 304 | uisession()->setFrameBuffer(screenId(), pFramebuffer);
|
---|
[27758] | 305 | }
|
---|
| 306 | m_pFrameBuffer = pFramebuffer;
|
---|
| 307 | }
|
---|
| 308 | else
|
---|
| 309 | m_pFrameBuffer = new UIFrameBufferSDL(this);
|
---|
[27682] | 310 | # else
|
---|
[26822] | 311 | m_pFrameBuffer = new UIFrameBufferSDL(this);
|
---|
[27682] | 312 | # endif
|
---|
[26730] | 313 | /* Disable scrollbars because we cannot correctly draw in a scrolled window using SDL: */
|
---|
[26637] | 314 | horizontalScrollBar()->setEnabled(false);
|
---|
| 315 | verticalScrollBar()->setEnabled(false);
|
---|
[382] | 316 | break;
|
---|
[26822] | 317 | #endif /* VBOX_GUI_USE_SDL */
|
---|
[26730] | 318 | #if 0 // TODO: Enable DDraw frame buffer!
|
---|
[26822] | 319 | #ifdef VBOX_GUI_USE_DDRAW
|
---|
[382] | 320 | case VBoxDefs::DDRAWMode:
|
---|
[26754] | 321 | m_pFrameBuffer = new UIDDRAWFrameBuffer(this);
|
---|
| 322 | if (!m_pFrameBuffer || m_pFrameBuffer->address() == NULL)
|
---|
[26730] | 323 | {
|
---|
[26754] | 324 | if (m_pFrameBuffer)
|
---|
| 325 | delete m_pFrameBuffer;
|
---|
| 326 | m_mode = VBoxDefs::QImageMode;
|
---|
| 327 | m_pFrameBuffer = new UIFrameBufferQImage(this);
|
---|
[26730] | 328 | }
|
---|
[382] | 329 | break;
|
---|
[26822] | 330 | #endif /* VBOX_GUI_USE_DDRAW */
|
---|
[382] | 331 | #endif
|
---|
[26822] | 332 | #ifdef VBOX_GUI_USE_QUARTZ2D
|
---|
[6645] | 333 | case VBoxDefs::Quartz2DMode:
|
---|
[26730] | 334 | /* Indicate that we are doing all drawing stuff ourself: */
|
---|
[26859] | 335 | viewport()->setAttribute(Qt::WA_PaintOnScreen);
|
---|
[27682] | 336 | # ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
[27758] | 337 | if (m_fAccelerate2DVideo)
|
---|
| 338 | {
|
---|
[27769] | 339 | UIFrameBuffer* pFramebuffer = uisession()->frameBuffer(screenId());
|
---|
[27758] | 340 | if (pFramebuffer)
|
---|
| 341 | pFramebuffer->setView(this);
|
---|
| 342 | else
|
---|
| 343 | {
|
---|
| 344 | /* these two additional template args is a workaround to this [VBox|UI] duplication
|
---|
| 345 | * @todo: they are to be removed once VBox stuff is gone */
|
---|
[27839] | 346 | pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferQuartz2D, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId());
|
---|
[27769] | 347 | uisession()->setFrameBuffer(screenId(), pFramebuffer);
|
---|
[27758] | 348 | }
|
---|
| 349 | m_pFrameBuffer = pFramebuffer;
|
---|
| 350 | }
|
---|
| 351 | else
|
---|
| 352 | m_pFrameBuffer = new UIFrameBufferQuartz2D(this);
|
---|
[30549] | 353 | # else /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[26754] | 354 | m_pFrameBuffer = new UIFrameBufferQuartz2D(this);
|
---|
[30549] | 355 | # endif /* !VBOX_WITH_VIDEOHWACCEL */
|
---|
[6645] | 356 | break;
|
---|
[26822] | 357 | #endif /* VBOX_GUI_USE_QUARTZ2D */
|
---|
[382] | 358 | default:
|
---|
[30347] | 359 | AssertReleaseMsgFailed(("Render mode must be valid: %d\n", vboxGlobal().vmRenderMode()));
|
---|
| 360 | LogRel(("Invalid render mode: %d\n", vboxGlobal().vmRenderMode()));
|
---|
[26730] | 361 | qApp->exit(1);
|
---|
[382] | 362 | break;
|
---|
| 363 | }
|
---|
[30752] | 364 |
|
---|
| 365 | /* If frame-buffer was prepared: */
|
---|
[26754] | 366 | if (m_pFrameBuffer)
|
---|
[382] | 367 | {
|
---|
[30752] | 368 | /* Prepare display: */
|
---|
| 369 | CDisplay display = session().GetConsole().GetDisplay();
|
---|
| 370 | Assert(!display.isNull());
|
---|
[27760] | 371 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
| 372 | CFramebuffer fb(NULL);
|
---|
| 373 | if (m_fAccelerate2DVideo)
|
---|
| 374 | {
|
---|
| 375 | LONG XOrigin, YOrigin;
|
---|
[30752] | 376 | /* Check if the framebuffer is already assigned;
|
---|
| 377 | * in this case we do not need to re-assign it neither do we need to AddRef. */
|
---|
[27760] | 378 | display.GetFramebuffer(m_uScreenId, fb, XOrigin, YOrigin);
|
---|
| 379 | }
|
---|
| 380 | if (fb.raw() != m_pFrameBuffer) /* <-this will evaluate to true iff m_fAccelerate2DVideo is disabled or iff no framebuffer is yet assigned */
|
---|
[30549] | 381 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[27760] | 382 | {
|
---|
| 383 | m_pFrameBuffer->AddRef();
|
---|
| 384 | }
|
---|
[30752] | 385 | /* Always perform SetFramebuffer to ensure 3D gets notified: */
|
---|
[28291] | 386 | display.SetFramebuffer(m_uScreenId, CFramebuffer(m_pFrameBuffer));
|
---|
[382] | 387 | }
|
---|
[29558] | 388 |
|
---|
[31341] | 389 | QSize size;
|
---|
[29558] | 390 | #ifdef Q_WS_X11
|
---|
[31341] | 391 | /* Processing pseudo resize-event to synchronize frame-buffer with stored
|
---|
| 392 | * framebuffer size. On X11 this will be additional done when the machine
|
---|
| 393 | * state was 'saved'. */
|
---|
| 394 | if (session().GetMachine().GetState() == KMachineState_Saved)
|
---|
[33579] | 395 | size = guestSizeHint();
|
---|
[31341] | 396 | #endif /* Q_WS_X11 */
|
---|
| 397 | /* If there is a preview image saved, we will resize the framebuffer to the
|
---|
| 398 | * size of that image. */
|
---|
| 399 | ULONG buffer = 0, width = 0, height = 0;
|
---|
| 400 | CMachine machine = session().GetMachine();
|
---|
| 401 | machine.QuerySavedScreenshotPNGSize(0, buffer, width, height);
|
---|
| 402 | if (buffer > 0)
|
---|
[32407] | 403 | {
|
---|
| 404 | /* Init with the screenshot size */
|
---|
| 405 | size = QSize(width, height);
|
---|
| 406 | /* Try to get the real guest dimensions from the save state */
|
---|
| 407 | ULONG guestWidth = 0, guestHeight = 0;
|
---|
| 408 | machine.QuerySavedGuestSize(0, guestWidth, guestHeight);
|
---|
| 409 | if ( guestWidth > 0
|
---|
| 410 | && guestHeight > 0)
|
---|
| 411 | size = QSize(guestWidth, guestHeight);
|
---|
| 412 | }
|
---|
[31341] | 413 | /* If we have a valid size, resize the framebuffer. */
|
---|
| 414 | if ( size.width() > 0
|
---|
| 415 | && size.height() > 0)
|
---|
| 416 | {
|
---|
| 417 | UIResizeEvent event(FramebufferPixelFormat_Opaque, NULL, 0, 0, size.width(), size.height());
|
---|
| 418 | frameBuffer()->resizeEvent(&event);
|
---|
| 419 | }
|
---|
[26730] | 420 | }
|
---|
[382] | 421 |
|
---|
[26730] | 422 | void UIMachineView::prepareCommon()
|
---|
| 423 | {
|
---|
| 424 | /* Prepare view frame: */
|
---|
[26889] | 425 | setFrameStyle(QFrame::NoFrame);
|
---|
[26730] | 426 |
|
---|
| 427 | /* Setup palette: */
|
---|
[26637] | 428 | QPalette palette(viewport()->palette());
|
---|
| 429 | palette.setColor(viewport()->backgroundRole(), Qt::black);
|
---|
| 430 | viewport()->setPalette(palette);
|
---|
[382] | 431 |
|
---|
[26730] | 432 | /* Setup focus policy: */
|
---|
[26637] | 433 | setFocusPolicy(Qt::WheelFocus);
|
---|
[382] | 434 | }
|
---|
| 435 |
|
---|
[26730] | 436 | void UIMachineView::prepareFilters()
|
---|
[382] | 437 | {
|
---|
[26730] | 438 | /* Enable MouseMove events: */
|
---|
| 439 | viewport()->setMouseTracking(true);
|
---|
| 440 |
|
---|
| 441 | /* QScrollView does the below on its own, but let's
|
---|
| 442 | * do it anyway for the case it will not do it in the future: */
|
---|
| 443 | viewport()->installEventFilter(this);
|
---|
| 444 |
|
---|
| 445 | /* We want to be notified on some parent's events: */
|
---|
| 446 | machineWindowWrapper()->machineWindow()->installEventFilter(this);
|
---|
| 447 | }
|
---|
| 448 |
|
---|
[26754] | 449 | void UIMachineView::prepareConsoleConnections()
|
---|
| 450 | {
|
---|
[26773] | 451 | /* Machine state-change updater: */
|
---|
[26878] | 452 | connect(uisession(), SIGNAL(sigMachineStateChange()), this, SLOT(sltMachineStateChanged()));
|
---|
[26754] | 453 | }
|
---|
| 454 |
|
---|
[26730] | 455 | void UIMachineView::loadMachineViewSettings()
|
---|
| 456 | {
|
---|
| 457 | /* Global settings: */
|
---|
| 458 | {
|
---|
[26889] | 459 | /* Remember the desktop geometry and register for geometry
|
---|
| 460 | * change events for telling the guest about video modes we like: */
|
---|
| 461 | QString desktopGeometry = vboxGlobal().settings().publicProperty("GUI/MaxGuestResolution");
|
---|
| 462 | if ((desktopGeometry == QString::null) || (desktopGeometry == "auto"))
|
---|
| 463 | setDesktopGeometry(DesktopGeo_Automatic, 0, 0);
|
---|
| 464 | else if (desktopGeometry == "any")
|
---|
| 465 | setDesktopGeometry(DesktopGeo_Any, 0, 0);
|
---|
| 466 | else
|
---|
| 467 | {
|
---|
| 468 | int width = desktopGeometry.section(',', 0, 0).toInt();
|
---|
| 469 | int height = desktopGeometry.section(',', 1, 1).toInt();
|
---|
| 470 | setDesktopGeometry(DesktopGeo_Fixed, width, height);
|
---|
| 471 | }
|
---|
[26730] | 472 | }
|
---|
| 473 | }
|
---|
| 474 |
|
---|
| 475 | void UIMachineView::cleanupFrameBuffer()
|
---|
[26637] | 476 | {
|
---|
[26754] | 477 | if (m_pFrameBuffer)
|
---|
[26637] | 478 | {
|
---|
[27454] | 479 | /* Process pending frame-buffer resize events: */
|
---|
| 480 | QApplication::sendPostedEvents(this, VBoxDefs::ResizeEventType);
|
---|
[27757] | 481 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
| 482 | if (m_fAccelerate2DVideo)
|
---|
| 483 | {
|
---|
| 484 | /* When 2D is enabled we do not re-create Framebuffers. This is done to
|
---|
| 485 | * 1. avoid 2D command loss during the time slot when no framebuffer is assigned to the display
|
---|
| 486 | * 2. make it easier to preserve the current 2D state */
|
---|
[27768] | 487 | Assert(m_pFrameBuffer == uisession()->frameBuffer(screenId()));
|
---|
[27757] | 488 | m_pFrameBuffer->setView(NULL);
|
---|
| 489 | }
|
---|
| 490 | else
|
---|
[30549] | 491 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
[27757] | 492 | {
|
---|
[27760] | 493 | /* Warn framebuffer about its no more necessary: */
|
---|
| 494 | m_pFrameBuffer->setDeleted(true);
|
---|
| 495 | /* Detach framebuffer from Display: */
|
---|
| 496 | CDisplay display = session().GetConsole().GetDisplay();
|
---|
| 497 | display.SetFramebuffer(m_uScreenId, CFramebuffer(NULL));
|
---|
| 498 | /* Release the reference: */
|
---|
| 499 | m_pFrameBuffer->Release();
|
---|
| 500 | // delete m_pFrameBuffer; // TODO_NEW_CORE: possibly necessary to really cleanup
|
---|
| 501 | m_pFrameBuffer = NULL;
|
---|
[27757] | 502 | }
|
---|
[26637] | 503 | }
|
---|
| 504 | }
|
---|
[382] | 505 |
|
---|
[30549] | 506 | UIMachineLogic* UIMachineView::machineLogic() const
|
---|
| 507 | {
|
---|
| 508 | return machineWindowWrapper()->machineLogic();
|
---|
| 509 | }
|
---|
| 510 |
|
---|
| 511 | UISession* UIMachineView::uisession() const
|
---|
| 512 | {
|
---|
| 513 | return machineLogic()->uisession();
|
---|
| 514 | }
|
---|
| 515 |
|
---|
| 516 | CSession& UIMachineView::session()
|
---|
| 517 | {
|
---|
| 518 | return uisession()->session();
|
---|
| 519 | }
|
---|
| 520 |
|
---|
| 521 | QSize UIMachineView::sizeHint() const
|
---|
| 522 | {
|
---|
| 523 | #ifdef VBOX_WITH_DEBUGGER
|
---|
| 524 | // TODO: Fix all DEBUGGER stuff!
|
---|
| 525 | /* HACK ALERT! Really ugly workaround for the resizing to 9x1 done by DevVGA if provoked before power on. */
|
---|
| 526 | QSize fb(m_pFrameBuffer->width(), m_pFrameBuffer->height());
|
---|
[33579] | 527 | if (fb.width() < 16 || fb.height() < 16)
|
---|
[32741] | 528 | {
|
---|
| 529 | CMachine machine = uisession()->session().GetMachine();
|
---|
[33579] | 530 | if ( vboxGlobal().isStartPausedEnabled()
|
---|
[32741] | 531 | || vboxGlobal().isDebuggerAutoShowEnabled(machine))
|
---|
[30549] | 532 | fb = QSize(640, 480);
|
---|
[32741] | 533 | }
|
---|
[30549] | 534 | return QSize(fb.width() + frameWidth() * 2, fb.height() + frameWidth() * 2);
|
---|
| 535 | #else /* VBOX_WITH_DEBUGGER */
|
---|
| 536 | return QSize(m_pFrameBuffer->width() + frameWidth() * 2, m_pFrameBuffer->height() + frameWidth() * 2);
|
---|
| 537 | #endif /* !VBOX_WITH_DEBUGGER */
|
---|
| 538 | }
|
---|
| 539 |
|
---|
| 540 | int UIMachineView::contentsX() const
|
---|
| 541 | {
|
---|
| 542 | return horizontalScrollBar()->value();
|
---|
| 543 | }
|
---|
| 544 |
|
---|
| 545 | int UIMachineView::contentsY() const
|
---|
| 546 | {
|
---|
| 547 | return verticalScrollBar()->value();
|
---|
| 548 | }
|
---|
| 549 |
|
---|
| 550 | int UIMachineView::contentsWidth() const
|
---|
| 551 | {
|
---|
| 552 | return m_pFrameBuffer->width();
|
---|
| 553 | }
|
---|
| 554 |
|
---|
| 555 | int UIMachineView::contentsHeight() const
|
---|
| 556 | {
|
---|
| 557 | return m_pFrameBuffer->height();
|
---|
| 558 | }
|
---|
| 559 |
|
---|
| 560 | int UIMachineView::visibleWidth() const
|
---|
| 561 | {
|
---|
| 562 | return horizontalScrollBar()->pageStep();
|
---|
| 563 | }
|
---|
| 564 |
|
---|
| 565 | int UIMachineView::visibleHeight() const
|
---|
| 566 | {
|
---|
| 567 | return verticalScrollBar()->pageStep();
|
---|
| 568 | }
|
---|
| 569 |
|
---|
| 570 | QSize UIMachineView::desktopGeometry() const
|
---|
| 571 | {
|
---|
| 572 | QSize geometry;
|
---|
| 573 | switch (m_desktopGeometryType)
|
---|
| 574 | {
|
---|
| 575 | case DesktopGeo_Fixed:
|
---|
| 576 | case DesktopGeo_Automatic:
|
---|
| 577 | geometry = QSize(qMax(m_desktopGeometry.width(), m_storedConsoleSize.width()),
|
---|
| 578 | qMax(m_desktopGeometry.height(), m_storedConsoleSize.height()));
|
---|
| 579 | break;
|
---|
| 580 | case DesktopGeo_Any:
|
---|
| 581 | geometry = QSize(0, 0);
|
---|
| 582 | break;
|
---|
| 583 | default:
|
---|
| 584 | AssertMsgFailed(("Bad geometry type %d!\n", m_desktopGeometryType));
|
---|
| 585 | }
|
---|
| 586 | return geometry;
|
---|
| 587 | }
|
---|
| 588 |
|
---|
| 589 | QSize UIMachineView::guestSizeHint()
|
---|
| 590 | {
|
---|
| 591 | /* Result: */
|
---|
| 592 | QSize sizeHint;
|
---|
| 593 |
|
---|
| 594 | /* Get current machine: */
|
---|
| 595 | CMachine machine = session().GetMachine();
|
---|
| 596 |
|
---|
| 597 | /* Load machine view hint: */
|
---|
| 598 | QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) :
|
---|
| 599 | QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId);
|
---|
| 600 | QString strValue = machine.GetExtraData(strKey);
|
---|
| 601 |
|
---|
| 602 | bool ok = true;
|
---|
| 603 | int width = 0, height = 0;
|
---|
| 604 | if (ok)
|
---|
| 605 | width = strValue.section(',', 0, 0).toInt(&ok);
|
---|
| 606 | if (ok)
|
---|
| 607 | height = strValue.section(',', 1, 1).toInt(&ok);
|
---|
| 608 |
|
---|
| 609 | if (ok /* If previous parameters were read correctly! */)
|
---|
| 610 | {
|
---|
| 611 | /* Compose guest size hint from loaded values: */
|
---|
| 612 | sizeHint = QSize(width, height);
|
---|
| 613 | }
|
---|
| 614 | else
|
---|
| 615 | {
|
---|
| 616 | /* Compose guest size hint from default attributes: */
|
---|
| 617 | sizeHint = QSize(800, 600);
|
---|
| 618 | }
|
---|
| 619 |
|
---|
| 620 | /* Return result: */
|
---|
| 621 | return sizeHint;
|
---|
| 622 | }
|
---|
| 623 |
|
---|
| 624 | void UIMachineView::setDesktopGeometry(DesktopGeo geometry, int aWidth, int aHeight)
|
---|
| 625 | {
|
---|
| 626 | switch (geometry)
|
---|
| 627 | {
|
---|
| 628 | case DesktopGeo_Fixed:
|
---|
| 629 | m_desktopGeometryType = DesktopGeo_Fixed;
|
---|
| 630 | if (aWidth != 0 && aHeight != 0)
|
---|
| 631 | m_desktopGeometry = QSize(aWidth, aHeight);
|
---|
| 632 | else
|
---|
| 633 | m_desktopGeometry = QSize(0, 0);
|
---|
| 634 | storeConsoleSize(0, 0);
|
---|
| 635 | break;
|
---|
| 636 | case DesktopGeo_Automatic:
|
---|
| 637 | m_desktopGeometryType = DesktopGeo_Automatic;
|
---|
| 638 | m_desktopGeometry = QSize(0, 0);
|
---|
| 639 | storeConsoleSize(0, 0);
|
---|
| 640 | break;
|
---|
| 641 | case DesktopGeo_Any:
|
---|
| 642 | m_desktopGeometryType = DesktopGeo_Any;
|
---|
| 643 | m_desktopGeometry = QSize(0, 0);
|
---|
| 644 | break;
|
---|
| 645 | default:
|
---|
| 646 | AssertMsgFailed(("Invalid desktop geometry type %d\n", geometry));
|
---|
| 647 | m_desktopGeometryType = DesktopGeo_Invalid;
|
---|
| 648 | }
|
---|
| 649 | }
|
---|
| 650 |
|
---|
| 651 | void UIMachineView::storeConsoleSize(int iWidth, int iHeight)
|
---|
| 652 | {
|
---|
| 653 | m_storedConsoleSize = QSize(iWidth, iHeight);
|
---|
| 654 | }
|
---|
| 655 |
|
---|
| 656 | void UIMachineView::storeGuestSizeHint(const QSize &sizeHint)
|
---|
| 657 | {
|
---|
| 658 | /* Get current machine: */
|
---|
| 659 | CMachine machine = session().GetMachine();
|
---|
| 660 |
|
---|
| 661 | /* Save machine view hint: */
|
---|
| 662 | QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) :
|
---|
| 663 | QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId);
|
---|
| 664 | QString strValue = QString("%1,%2").arg(sizeHint.width()).arg(sizeHint.height());
|
---|
| 665 | machine.SetExtraData(strKey, strValue);
|
---|
| 666 | }
|
---|
| 667 |
|
---|
[31341] | 668 | void UIMachineView::takePauseShotLive()
|
---|
| 669 | {
|
---|
| 670 | /* Take a screen snapshot. Note that TakeScreenShot() always needs a 32bpp image: */
|
---|
| 671 | QImage shot = QImage(m_pFrameBuffer->width(), m_pFrameBuffer->height(), QImage::Format_RGB32);
|
---|
| 672 | /* If TakeScreenShot fails or returns no image, just show a black image. */
|
---|
| 673 | shot.fill(0);
|
---|
| 674 | CDisplay dsp = session().GetConsole().GetDisplay();
|
---|
| 675 | dsp.TakeScreenShot(screenId(), shot.bits(), shot.width(), shot.height());
|
---|
| 676 | /* TakeScreenShot() may fail if, e.g. the Paused notification was delivered
|
---|
| 677 | * after the machine execution was resumed. It's not fatal: */
|
---|
| 678 | if (dsp.isOk())
|
---|
| 679 | dimImage(shot);
|
---|
| 680 | m_pauseShot = QPixmap::fromImage(shot);
|
---|
| 681 | }
|
---|
| 682 |
|
---|
| 683 | void UIMachineView::takePauseShotSnapshot()
|
---|
| 684 | {
|
---|
| 685 | CMachine machine = session().GetMachine();
|
---|
| 686 | ULONG width = 0, height = 0;
|
---|
| 687 | QVector<BYTE> screenData = machine.ReadSavedScreenshotPNGToArray(0, width, height);
|
---|
| 688 | if (screenData.size() != 0)
|
---|
| 689 | {
|
---|
[32407] | 690 | ULONG guestWidth = 0, guestHeight = 0;
|
---|
| 691 | machine.QuerySavedGuestSize(0, guestWidth, guestHeight);
|
---|
| 692 | QImage shot = QImage::fromData(screenData.data(), screenData.size(), "PNG").scaled(guestWidth > 0 ? QSize(guestWidth, guestHeight) : guestSizeHint());
|
---|
[31341] | 693 | dimImage(shot);
|
---|
| 694 | m_pauseShot = QPixmap::fromImage(shot);
|
---|
| 695 | }
|
---|
| 696 | }
|
---|
| 697 |
|
---|
[30549] | 698 | void UIMachineView::updateSliders()
|
---|
| 699 | {
|
---|
| 700 | QSize p = viewport()->size();
|
---|
| 701 | QSize m = maximumViewportSize();
|
---|
| 702 |
|
---|
| 703 | QSize v = QSize(frameBuffer()->width(), frameBuffer()->height());
|
---|
| 704 | /* No scroll bars needed: */
|
---|
| 705 | if (m.expandedTo(v) == m)
|
---|
| 706 | p = m;
|
---|
| 707 |
|
---|
| 708 | horizontalScrollBar()->setRange(0, v.width() - p.width());
|
---|
| 709 | verticalScrollBar()->setRange(0, v.height() - p.height());
|
---|
| 710 | horizontalScrollBar()->setPageStep(p.width());
|
---|
| 711 | verticalScrollBar()->setPageStep(p.height());
|
---|
| 712 | }
|
---|
| 713 |
|
---|
| 714 | QPoint UIMachineView::viewportToContents(const QPoint &vp) const
|
---|
| 715 | {
|
---|
| 716 | return QPoint(vp.x() + contentsX(), vp.y() + contentsY());
|
---|
| 717 | }
|
---|
| 718 |
|
---|
| 719 | void UIMachineView::scrollBy(int dx, int dy)
|
---|
| 720 | {
|
---|
| 721 | horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dx);
|
---|
| 722 | verticalScrollBar()->setValue(verticalScrollBar()->value() + dy);
|
---|
| 723 | }
|
---|
| 724 |
|
---|
| 725 | void UIMachineView::dimImage(QImage &img)
|
---|
| 726 | {
|
---|
| 727 | for (int y = 0; y < img.height(); ++ y)
|
---|
| 728 | {
|
---|
| 729 | if (y % 2)
|
---|
| 730 | {
|
---|
| 731 | if (img.depth() == 32)
|
---|
| 732 | {
|
---|
| 733 | for (int x = 0; x < img.width(); ++ x)
|
---|
| 734 | {
|
---|
| 735 | int gray = qGray(img.pixel (x, y)) / 2;
|
---|
| 736 | img.setPixel(x, y, qRgb (gray, gray, gray));
|
---|
| 737 | }
|
---|
| 738 | }
|
---|
| 739 | else
|
---|
| 740 | {
|
---|
| 741 | ::memset(img.scanLine (y), 0, img.bytesPerLine());
|
---|
| 742 | }
|
---|
| 743 | }
|
---|
| 744 | else
|
---|
| 745 | {
|
---|
| 746 | if (img.depth() == 32)
|
---|
| 747 | {
|
---|
| 748 | for (int x = 0; x < img.width(); ++ x)
|
---|
| 749 | {
|
---|
| 750 | int gray = (2 * qGray (img.pixel (x, y))) / 3;
|
---|
| 751 | img.setPixel(x, y, qRgb (gray, gray, gray));
|
---|
| 752 | }
|
---|
| 753 | }
|
---|
| 754 | }
|
---|
| 755 | }
|
---|
| 756 | }
|
---|
| 757 |
|
---|
| 758 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
| 759 | void UIMachineView::scrollContentsBy(int dx, int dy)
|
---|
| 760 | {
|
---|
| 761 | if (m_pFrameBuffer)
|
---|
| 762 | {
|
---|
| 763 | m_pFrameBuffer->viewportScrolled(dx, dy);
|
---|
| 764 | }
|
---|
| 765 | QAbstractScrollArea::scrollContentsBy(dx, dy);
|
---|
| 766 | }
|
---|
| 767 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
| 768 |
|
---|
| 769 | #ifdef Q_WS_MAC
|
---|
| 770 | void UIMachineView::updateDockIcon()
|
---|
| 771 | {
|
---|
| 772 | machineLogic()->updateDockIcon();
|
---|
| 773 | }
|
---|
| 774 |
|
---|
| 775 | CGImageRef UIMachineView::vmContentImage()
|
---|
| 776 | {
|
---|
| 777 | if (!m_pauseShot.isNull())
|
---|
| 778 | {
|
---|
| 779 | CGImageRef pauseImg = ::darwinToCGImageRef(&m_pauseShot);
|
---|
| 780 | /* Use the pause image as background */
|
---|
| 781 | return pauseImg;
|
---|
| 782 | }
|
---|
| 783 | else
|
---|
| 784 | {
|
---|
| 785 | # ifdef VBOX_GUI_USE_QUARTZ2D
|
---|
| 786 | if (vboxGlobal().vmRenderMode() == VBoxDefs::Quartz2DMode)
|
---|
| 787 | {
|
---|
| 788 | /* If the render mode is Quartz2D we could use the CGImageRef
|
---|
| 789 | * of the framebuffer for the dock icon creation. This saves
|
---|
| 790 | * some conversion time. */
|
---|
| 791 | CGImageRef image = static_cast<UIFrameBufferQuartz2D*>(m_pFrameBuffer)->imageRef();
|
---|
| 792 | CGImageRetain(image); /* Retain it, cause the consumer will release it. */
|
---|
| 793 | return image;
|
---|
| 794 | }
|
---|
| 795 | else
|
---|
| 796 | # endif /* VBOX_GUI_USE_QUARTZ2D */
|
---|
| 797 | /* In image mode we have to create the image ref out of the
|
---|
| 798 | * framebuffer */
|
---|
| 799 | return frameBuffertoCGImageRef(m_pFrameBuffer);
|
---|
| 800 | }
|
---|
| 801 | return 0;
|
---|
| 802 | }
|
---|
| 803 |
|
---|
| 804 | CGImageRef UIMachineView::frameBuffertoCGImageRef(UIFrameBuffer *pFrameBuffer)
|
---|
| 805 | {
|
---|
| 806 | CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
|
---|
| 807 | Assert(cs);
|
---|
| 808 | /* Create the image copy of the framebuffer */
|
---|
| 809 | CGDataProviderRef dp = CGDataProviderCreateWithData(pFrameBuffer, pFrameBuffer->address(), pFrameBuffer->bitsPerPixel() / 8 * pFrameBuffer->width() * pFrameBuffer->height(), NULL);
|
---|
| 810 | Assert(dp);
|
---|
| 811 | CGImageRef ir = CGImageCreate(pFrameBuffer->width(), pFrameBuffer->height(), 8, 32, pFrameBuffer->bytesPerLine(), cs,
|
---|
| 812 | kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host, dp, 0, false,
|
---|
| 813 | kCGRenderingIntentDefault);
|
---|
| 814 | Assert(ir);
|
---|
| 815 | CGDataProviderRelease(dp);
|
---|
| 816 | CGColorSpaceRelease(cs);
|
---|
| 817 |
|
---|
| 818 | return ir;
|
---|
| 819 | }
|
---|
| 820 | #endif /* Q_WS_MAC */
|
---|
| 821 |
|
---|
[26754] | 822 | bool UIMachineView::event(QEvent *pEvent)
|
---|
[2835] | 823 | {
|
---|
[26754] | 824 | switch (pEvent->type())
|
---|
[382] | 825 | {
|
---|
[26754] | 826 | case VBoxDefs::RepaintEventType:
|
---|
| 827 | {
|
---|
| 828 | UIRepaintEvent *pPaintEvent = static_cast<UIRepaintEvent*>(pEvent);
|
---|
[31248] | 829 | viewport()->update(pPaintEvent->x() - contentsX(), pPaintEvent->y() - contentsY(),
|
---|
[26754] | 830 | pPaintEvent->width(), pPaintEvent->height());
|
---|
| 831 | return true;
|
---|
| 832 | }
|
---|
[25505] | 833 |
|
---|
[2968] | 834 | #ifdef Q_WS_MAC
|
---|
[30551] | 835 | /* Event posted OnShowWindow: */
|
---|
[26754] | 836 | case VBoxDefs::ShowWindowEventType:
|
---|
| 837 | {
|
---|
| 838 | /* Dunno what Qt3 thinks a window that has minimized to the dock should be - it is not hidden,
|
---|
| 839 | * neither is it minimized. OTOH it is marked shown and visible, but not activated.
|
---|
| 840 | * This latter isn't of much help though, since at this point nothing is marked activated.
|
---|
| 841 | * I might have overlooked something, but I'm buggered what if I know what. So, I'll just always
|
---|
| 842 | * show & activate the stupid window to make it get out of the dock when the user wishes to show a VM: */
|
---|
| 843 | window()->show();
|
---|
| 844 | window()->activateWindow();
|
---|
| 845 | return true;
|
---|
| 846 | }
|
---|
[30549] | 847 | #endif /* Q_WS_MAC */
|
---|
[26754] | 848 |
|
---|
[30551] | 849 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
| 850 | case VBoxDefs::VHWACommandProcessType:
|
---|
| 851 | {
|
---|
| 852 | m_pFrameBuffer->doProcessVHWACommand(pEvent);
|
---|
| 853 | return true;
|
---|
| 854 | }
|
---|
| 855 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
| 856 |
|
---|
[26754] | 857 | default:
|
---|
| 858 | break;
|
---|
[382] | 859 | }
|
---|
| 860 |
|
---|
[26754] | 861 | return QAbstractScrollArea::event(pEvent);
|
---|
[382] | 862 | }
|
---|
| 863 |
|
---|
[26754] | 864 | bool UIMachineView::eventFilter(QObject *pWatched, QEvent *pEvent)
|
---|
[22834] | 865 | {
|
---|
[30408] | 866 | #ifdef VBOX_WITH_VIDEOHWACCEL
|
---|
[26754] | 867 | if (pWatched == viewport())
|
---|
[22834] | 868 | {
|
---|
[26754] | 869 | switch (pEvent->type())
|
---|
[382] | 870 | {
|
---|
| 871 | case QEvent::Resize:
|
---|
| 872 | {
|
---|
[26754] | 873 | if (m_pFrameBuffer)
|
---|
| 874 | m_pFrameBuffer->viewportResized(static_cast<QResizeEvent*>(pEvent));
|
---|
[15642] | 875 | break;
|
---|
[382] | 876 | }
|
---|
| 877 | default:
|
---|
| 878 | break;
|
---|
| 879 | }
|
---|
| 880 | }
|
---|
[30408] | 881 | #endif /* VBOX_WITH_VIDEOHWACCEL */
|
---|
| 882 | if (pWatched == machineWindowWrapper()->machineWindow())
|
---|
[382] | 883 | {
|
---|
[26754] | 884 | switch (pEvent->type())
|
---|
[382] | 885 | {
|
---|
[26754] | 886 | case QEvent::WindowStateChange:
|
---|
| 887 | {
|
---|
[26878] | 888 | /* During minimizing and state restoring machineWindowWrapper() gets
|
---|
| 889 | * the focus which belongs to console view window, so returning it properly. */
|
---|
[26754] | 890 | QWindowStateChangeEvent *pWindowEvent = static_cast<QWindowStateChangeEvent*>(pEvent);
|
---|
| 891 | if (pWindowEvent->oldState() & Qt::WindowMinimized)
|
---|
| 892 | {
|
---|
| 893 | if (QApplication::focusWidget())
|
---|
| 894 | {
|
---|
| 895 | QApplication::focusWidget()->clearFocus();
|
---|
| 896 | qApp->processEvents();
|
---|
| 897 | }
|
---|
| 898 | QTimer::singleShot(0, this, SLOT(setFocus()));
|
---|
| 899 | }
|
---|
| 900 | break;
|
---|
| 901 | }
|
---|
[382] | 902 | default:
|
---|
| 903 | break;
|
---|
| 904 | }
|
---|
| 905 | }
|
---|
[26878] | 906 |
|
---|
[30551] | 907 | return QAbstractScrollArea::eventFilter(pWatched, pEvent);
|
---|
[26878] | 908 | }
|
---|
| 909 |
|
---|
[26754] | 910 | void UIMachineView::resizeEvent(QResizeEvent *pEvent)
|
---|
[382] | 911 | {
|
---|
[26637] | 912 | updateSliders();
|
---|
[26754] | 913 | return QAbstractScrollArea::resizeEvent(pEvent);
|
---|
[26637] | 914 | }
|
---|
| 915 |
|
---|
[26754] | 916 | void UIMachineView::moveEvent(QMoveEvent *pEvent)
|
---|
[26637] | 917 | {
|
---|
[26754] | 918 | return QAbstractScrollArea::moveEvent(pEvent);
|
---|
[26637] | 919 | }
|
---|
| 920 |
|
---|
[26754] | 921 | void UIMachineView::paintEvent(QPaintEvent *pPaintEvent)
|
---|
[26637] | 922 | {
|
---|
[26754] | 923 | if (m_pauseShot.isNull())
|
---|
[26637] | 924 | {
|
---|
[26754] | 925 | /* Delegate the paint function to the VBoxFrameBuffer interface: */
|
---|
[31283] | 926 | if (m_pFrameBuffer && !uisession()->isTurnedOff())
|
---|
[26754] | 927 | m_pFrameBuffer->paintEvent(pPaintEvent);
|
---|
[26637] | 928 | #ifdef Q_WS_MAC
|
---|
| 929 | /* Update the dock icon if we are in the running state */
|
---|
[27215] | 930 | if (uisession()->isRunning())
|
---|
| 931 | updateDockIcon();
|
---|
| 932 | #endif /* Q_WS_MAC */
|
---|
[26637] | 933 | return;
|
---|
| 934 | }
|
---|
| 935 |
|
---|
| 936 | #ifdef VBOX_GUI_USE_QUARTZ2D
|
---|
[30347] | 937 | if (vboxGlobal().vmRenderMode() == VBoxDefs::Quartz2DMode && m_pFrameBuffer)
|
---|
[27071] | 938 | {
|
---|
| 939 | m_pFrameBuffer->paintEvent(pPaintEvent);
|
---|
[27215] | 940 | updateDockIcon();
|
---|
[27071] | 941 | }
|
---|
| 942 | else
|
---|
[27215] | 943 | #endif /* VBOX_GUI_USE_QUARTZ2D */
|
---|
[27071] | 944 | {
|
---|
[26929] | 945 | /* We have a snapshot for the paused state: */
|
---|
| 946 | QRect r = pPaintEvent->rect().intersect(viewport()->rect());
|
---|
| 947 | /* We have to disable paint on screen if we are using the regular painter: */
|
---|
| 948 | bool paintOnScreen = viewport()->testAttribute(Qt::WA_PaintOnScreen);
|
---|
| 949 | viewport()->setAttribute(Qt::WA_PaintOnScreen, false);
|
---|
| 950 | QPainter pnt(viewport());
|
---|
[31341] | 951 | pnt.drawPixmap(r, m_pauseShot, QRect(r.x() + contentsX(), r.y() + contentsY(), r.width(), r.height()));
|
---|
[26929] | 952 | /* Restore the attribute to its previous state: */
|
---|
| 953 | viewport()->setAttribute(Qt::WA_PaintOnScreen, paintOnScreen);
|
---|
[26637] | 954 | #ifdef Q_WS_MAC
|
---|
[27215] | 955 | updateDockIcon();
|
---|
| 956 | #endif /* Q_WS_MAC */
|
---|
[27071] | 957 | }
|
---|
[26637] | 958 | }
|
---|
| 959 |
|
---|
[30549] | 960 | #if defined(Q_WS_WIN)
|
---|
[26754] | 961 |
|
---|
[30637] | 962 | bool UIMachineView::winEvent(MSG *pMsg, long* /* piResult */)
|
---|
[26754] | 963 | {
|
---|
[30637] | 964 | /* Check if some system event should be filtered-out.
|
---|
| 965 | * Returning 'true' means filtering-out,
|
---|
| 966 | * Returning 'false' means passing event to Qt. */
|
---|
| 967 | bool fResult = false; /* Pass to Qt by default: */
|
---|
| 968 | switch (pMsg->message)
|
---|
[26754] | 969 | {
|
---|
[30637] | 970 | case WM_KEYDOWN:
|
---|
| 971 | case WM_KEYUP:
|
---|
| 972 | case WM_SYSKEYDOWN:
|
---|
| 973 | case WM_SYSKEYUP:
|
---|
[26754] | 974 | {
|
---|
[30637] | 975 | /* Filter using keyboard-filter: */
|
---|
| 976 | bool fKeyboardFilteringResult = machineLogic()->keyboardHandler()->winEventFilter(pMsg, screenId());
|
---|
| 977 | /* Keyboard filter rules the result: */
|
---|
| 978 | fResult = fKeyboardFilteringResult;
|
---|
[26754] | 979 | break;
|
---|
| 980 | }
|
---|
[30637] | 981 | default:
|
---|
[26754] | 982 | break;
|
---|
| 983 | }
|
---|
[30637] | 984 | /* Return result: */
|
---|
| 985 | return fResult;
|
---|
[26754] | 986 | }
|
---|
| 987 |
|
---|
| 988 | #elif defined(Q_WS_X11)
|
---|
| 989 |
|
---|
| 990 | bool UIMachineView::x11Event(XEvent *pEvent)
|
---|
| 991 | {
|
---|
[30637] | 992 | /* Check if some system event should be filtered-out.
|
---|
| 993 | * Returning 'true' means filtering-out,
|
---|
| 994 | * Returning 'false' means passing event to Qt. */
|
---|
| 995 | bool fResult = false; /* Pass to Qt by default: */
|
---|
[26754] | 996 | switch (pEvent->type)
|
---|
| 997 | {
|
---|
| 998 | case XFocusOut:
|
---|
| 999 | case XFocusIn:
|
---|
| 1000 | case XKeyPress:
|
---|
| 1001 | case XKeyRelease:
|
---|
[30637] | 1002 | {
|
---|
| 1003 | /* Filter using keyboard-filter: */
|
---|
| 1004 | bool fKeyboardFilteringResult = machineLogic()->keyboardHandler()->x11EventFilter(pEvent, screenId());
|
---|
| 1005 | /* Filter using mouse-filter: */
|
---|
| 1006 | bool fMouseFilteringResult = machineLogic()->mouseHandler()->x11EventFilter(pEvent, screenId());
|
---|
| 1007 | /* If at least one of filters wants to filter event out then the result is 'true': */
|
---|
| 1008 | fResult = fKeyboardFilteringResult || fMouseFilteringResult;
|
---|
[26754] | 1009 | break;
|
---|
[30637] | 1010 | }
|
---|
[26754] | 1011 | default:
|
---|
| 1012 | break;
|
---|
| 1013 | }
|
---|
[30637] | 1014 | /* Return result: */
|
---|
| 1015 | return fResult;
|
---|
[26754] | 1016 | }
|
---|
| 1017 |
|
---|
| 1018 | #endif
|
---|