VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp@ 33579

Last change on this file since 33579 was 33579, checked in by vboxsync, 14 years ago

FE/Qt4: shadow var

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

© 2023 Oracle
ContactPrivacy policyTerms of Use