VirtualBox

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

Last change on this file since 74942 was 74942, checked in by vboxsync, 6 years ago

FE/Qt: bugref:9261: fixed variable names and doxygen description according to code guidlines

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.5 KB
Line 
1/* $Id: UIMachineView.cpp 74942 2018-10-19 12:51:20Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMachineView class implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifdef VBOX_WITH_PRECOMPILED_HEADERS
19# include <precomp.h>
20#else /* !VBOX_WITH_PRECOMPILED_HEADERS */
21
22/* Qt includes: */
23# include <QMainWindow>
24# include <QPainter>
25# include <QScrollBar>
26# include <QTimer>
27
28/* GUI includes: */
29# include "VBoxGlobal.h"
30# include "UIDesktopWidgetWatchdog.h"
31# include "UIExtraDataManager.h"
32# include "UIMessageCenter.h"
33# include "UISession.h"
34# include "UIMachineLogic.h"
35# include "UIMachineWindow.h"
36# include "UIMachineViewNormal.h"
37# include "UIMachineViewFullscreen.h"
38# include "UIMachineViewSeamless.h"
39# include "UIMachineViewScale.h"
40# include "UIKeyboardHandler.h"
41# include "UIMouseHandler.h"
42# include "UIFrameBuffer.h"
43# include "VBoxFBOverlay.h"
44# ifdef VBOX_WS_MAC
45# include "UICocoaApplication.h"
46# endif /* VBOX_WS_MAC */
47# ifdef VBOX_WITH_DRAG_AND_DROP
48# include "UIDnDHandler.h"
49# endif /* VBOX_WITH_DRAG_AND_DROP */
50
51/* VirtualBox interface declarations: */
52# ifndef VBOX_WITH_XPCOM
53# include "VirtualBox.h"
54# else /* VBOX_WITH_XPCOM */
55# include "VirtualBox_XPCOM.h"
56# endif /* VBOX_WITH_XPCOM */
57
58/* COM includes: */
59# include "CConsole.h"
60# include "CDisplay.h"
61# include "CSession.h"
62# ifdef VBOX_WITH_DRAG_AND_DROP
63# include "CDnDSource.h"
64# include "CDnDTarget.h"
65# include "CGuest.h"
66# endif /* VBOX_WITH_DRAG_AND_DROP */
67
68/* Other VBox includes: */
69# include <iprt/asm.h>
70
71#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
72
73/* Qt includes: */
74# include <QAbstractNativeEventFilter>
75
76/* GUI includes: */
77#ifdef VBOX_WS_MAC
78# include "DarwinKeyboard.h"
79# include "DockIconPreview.h"
80#endif /* VBOX_WS_MAC */
81
82/* COM includes: */
83#include "CFramebuffer.h"
84#ifdef VBOX_WITH_DRAG_AND_DROP
85# include "CGuestDnDSource.h"
86# include "CGuestDnDTarget.h"
87#endif /* VBOX_WITH_DRAG_AND_DROP */
88
89/* Other VBox includes: */
90#include <VBox/VBoxOGL.h>
91#include <VBoxVideo.h>
92#ifdef VBOX_WS_MAC
93# include <VBox/err.h>
94#endif /* VBOX_WS_MAC */
95
96/* External includes: */
97#include <math.h>
98#ifdef VBOX_WS_MAC
99# include <Carbon/Carbon.h>
100#endif
101#ifdef VBOX_WS_X11
102# include <xcb/xcb.h>
103#endif
104
105#ifdef DEBUG_andy
106/* Macro for debugging drag and drop actions which usually would
107 * go to Main's logging group. */
108# define DNDDEBUG(x) LogFlowFunc(x)
109#else
110# define DNDDEBUG(x)
111#endif
112
113
114/** QAbstractNativeEventFilter extension
115 * allowing to pre-process native platform events. */
116class UINativeEventFilter : public QAbstractNativeEventFilter
117{
118public:
119
120 /** Constructs native event filter storing @a pParent to redirect events to. */
121 UINativeEventFilter(UIMachineView *pParent)
122 : m_pParent(pParent)
123 {}
124
125 /** Redirects all the native events to parent. */
126 bool nativeEventFilter(const QByteArray &eventType, void *pMessage, long * /* pResult */)
127 {
128 return m_pParent->nativeEventPreprocessor(eventType, pMessage);
129 }
130
131private:
132
133 /** Holds the passed parent reference. */
134 UIMachineView *m_pParent;
135};
136
137
138/* static */
139UIMachineView* UIMachineView::create( UIMachineWindow *pMachineWindow
140 , ulong uScreenId
141 , UIVisualStateType visualStateType
142#ifdef VBOX_WITH_VIDEOHWACCEL
143 , bool bAccelerate2DVideo
144#endif /* VBOX_WITH_VIDEOHWACCEL */
145 )
146{
147 UIMachineView *pMachineView = 0;
148 switch (visualStateType)
149 {
150 case UIVisualStateType_Normal:
151 pMachineView = new UIMachineViewNormal( pMachineWindow
152 , uScreenId
153#ifdef VBOX_WITH_VIDEOHWACCEL
154 , bAccelerate2DVideo
155#endif /* VBOX_WITH_VIDEOHWACCEL */
156 );
157 break;
158 case UIVisualStateType_Fullscreen:
159 pMachineView = new UIMachineViewFullscreen( pMachineWindow
160 , uScreenId
161#ifdef VBOX_WITH_VIDEOHWACCEL
162 , bAccelerate2DVideo
163#endif /* VBOX_WITH_VIDEOHWACCEL */
164 );
165 break;
166 case UIVisualStateType_Seamless:
167 pMachineView = new UIMachineViewSeamless( pMachineWindow
168 , uScreenId
169#ifdef VBOX_WITH_VIDEOHWACCEL
170 , bAccelerate2DVideo
171#endif /* VBOX_WITH_VIDEOHWACCEL */
172 );
173 break;
174 case UIVisualStateType_Scale:
175 pMachineView = new UIMachineViewScale( pMachineWindow
176 , uScreenId
177#ifdef VBOX_WITH_VIDEOHWACCEL
178 , bAccelerate2DVideo
179#endif
180 );
181 break;
182 default:
183 break;
184 }
185
186 /* Load machine-view settings: */
187 pMachineView->loadMachineViewSettings();
188
189 /* Prepare viewport: */
190 pMachineView->prepareViewport();
191
192 /* Prepare frame-buffer: */
193 pMachineView->prepareFrameBuffer();
194
195 /* Prepare common things: */
196 pMachineView->prepareCommon();
197
198 /* Prepare event-filters: */
199 pMachineView->prepareFilters();
200
201 /* Prepare connections: */
202 pMachineView->prepareConnections();
203
204 /* Prepare console connections: */
205 pMachineView->prepareConsoleConnections();
206
207 /* Initialization: */
208 pMachineView->sltMachineStateChanged();
209 /** @todo Can we move the call to sltAdditionsStateChanged() from the
210 * subclass constructors here too? It is called for Normal and Seamless,
211 * but not for Fullscreen and Scale. However for Scale it is a no op.,
212 * so it would not hurt. Would it hurt for fullscreen? */
213
214 /* Set a preliminary maximum size: */
215 pMachineView->setMaxGuestSize();
216
217 /* Resend the last resize hint finally: */
218 pMachineView->resendSizeHint();
219
220 /* Return the created view: */
221 return pMachineView;
222}
223
224/* static */
225void UIMachineView::destroy(UIMachineView *pMachineView)
226{
227 if (!pMachineView)
228 return;
229
230 /* Cleanup frame-buffer: */
231 pMachineView->cleanupFrameBuffer();
232
233#ifdef VBOX_WITH_DRAG_AND_DROP
234 if (pMachineView->m_pDnDHandler)
235 {
236 delete pMachineView->m_pDnDHandler;
237 pMachineView->m_pDnDHandler = NULL;
238 }
239#endif
240
241 /* Cleanup native filters: */
242 pMachineView->cleanupNativeFilters();
243
244 delete pMachineView;
245}
246
247void UIMachineView::applyMachineViewScaleFactor()
248{
249 /* Acquire selected scale-factor: */
250 double dScaleFactor = gEDataManager->scaleFactor(vboxGlobal().managedVMUuid(), m_uScreenId);
251
252 /* Take the device-pixel-ratio into account: */
253 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
254 const bool fUseUnscaledHiDPIOutput = dScaleFactor != dDevicePixelRatioActual;
255 dScaleFactor = fUseUnscaledHiDPIOutput ? dScaleFactor : 1.0;
256
257 /* Assign frame-buffer with new values: */
258 frameBuffer()->setScaleFactor(dScaleFactor);
259 frameBuffer()->setUseUnscaledHiDPIOutput(fUseUnscaledHiDPIOutput);
260
261 /* Propagate the scale-factor related attributes to 3D service if necessary: */
262 if (machine().GetAccelerate3DEnabled() && vboxGlobal().is3DAvailable())
263 {
264 double dScaleFactorFor3D = dScaleFactor;
265#if defined(VBOX_WS_WIN) || defined(VBOX_WS_X11)
266 // WORKAROUND:
267 // On Windows and Linux opposing to macOS it's only Qt which can auto scale up,
268 // not 3D overlay itself, so for auto scale-up mode we have to take that into account.
269 if (!fUseUnscaledHiDPIOutput)
270 dScaleFactorFor3D *= frameBuffer()->devicePixelRatioActual();
271#endif /* VBOX_WS_WIN || VBOX_WS_X11 */
272 display().NotifyScaleFactorChange(m_uScreenId,
273 (uint32_t)(dScaleFactorFor3D * VBOX_OGL_SCALE_FACTOR_MULTIPLIER),
274 (uint32_t)(dScaleFactorFor3D * VBOX_OGL_SCALE_FACTOR_MULTIPLIER));
275 display().NotifyHiDPIOutputPolicyChange(fUseUnscaledHiDPIOutput);
276 }
277
278 /* Perform frame-buffer rescaling: */
279 frameBuffer()->performRescale();
280
281 /* Update console's display viewport and 3D overlay: */
282 updateViewport();
283}
284
285double UIMachineView::aspectRatio() const
286{
287 return frameBuffer() ? (double)(frameBuffer()->width()) / frameBuffer()->height() : 0;
288}
289
290void UIMachineView::updateViewport()
291{
292 display().ViewportChanged(screenId(), contentsX(), contentsY(), visibleWidth(), visibleHeight());
293}
294
295void UIMachineView::sltPerformGuestResize(const QSize &toSize)
296{
297 /* If this slot is invoked directly then use the passed size otherwise get
298 * the available size for the guest display. We assume here that centralWidget()
299 * contains this view only and gives it all available space: */
300 QSize size(toSize.isValid() ? toSize : machineWindow()->centralWidget()->size());
301 AssertMsg(size.isValid(), ("Size should be valid!\n"));
302
303 /* Take the scale-factor(s) into account: */
304 size = scaledBackward(size);
305
306 /* Expand current limitations: */
307 setMaxGuestSize(size);
308
309 /* Send new size-hint to the guest: */
310 LogRel(("GUI: UIMachineView::sltPerformGuestResize: "
311 "Sending guest size-hint to screen %d as %dx%d if necessary\n",
312 (int)screenId(), size.width(), size.height()));
313
314 /* If auto-mount of guest-screens (auto-pilot) enabled: */
315 if (gEDataManager->autoMountGuestScreensEnabled(vboxGlobal().managedVMUuid()))
316 {
317 /* Do not send a hint if nothing has changed to prevent the guest being notified about its own changes: */
318 if ( (int)m_pFrameBuffer->width() != size.width() || (int)m_pFrameBuffer->height() != size.height()
319 || uisession()->isScreenVisible(screenId()) != uisession()->isScreenVisibleHostDesires(screenId()))
320 {
321 /* If host and guest have same opinion about guest-screen visibility: */
322 if (uisession()->isScreenVisible(screenId()) == uisession()->isScreenVisibleHostDesires(screenId()))
323 display().SetVideoModeHint(screenId(),
324 uisession()->isScreenVisible(screenId()),
325 false, 0, 0, size.width(), size.height(), 0);
326 /* If host desires to have guest-screen disabled and guest-screen is enabled, retrying: */
327 else if (!uisession()->isScreenVisibleHostDesires(screenId()))
328 display().SetVideoModeHint(screenId(), false, false, 0, 0, 0, 0, 0);
329 /* If host desires to have guest-screen enabled and guest-screen is disabled, retrying: */
330 else if (uisession()->isScreenVisibleHostDesires(screenId()))
331 display().SetVideoModeHint(screenId(), true, false, 0, 0, size.width(), size.height(), 0);
332 }
333 }
334 /* If auto-mount of guest-screens (auto-pilot) disabled: */
335 else
336 {
337 /* Do not send a hint if nothing has changed to prevent the guest being notified about its own changes: */
338 if ((int)m_pFrameBuffer->width() != size.width() || (int)m_pFrameBuffer->height() != size.height())
339 display().SetVideoModeHint(screenId(),
340 uisession()->isScreenVisible(screenId()),
341 false, 0, 0, size.width(), size.height(), 0);
342 }
343}
344
345void UIMachineView::sltHandleNotifyChange(int iWidth, int iHeight)
346{
347 LogRel(("GUI: UIMachineView::sltHandleNotifyChange: Screen=%d, Size=%dx%d\n",
348 (unsigned long)m_uScreenId, iWidth, iHeight));
349
350 /* Some situations require frame-buffer resize-events to be ignored at all,
351 * leaving machine-window, machine-view and frame-buffer sizes preserved: */
352 if (uisession()->isGuestResizeIgnored())
353 return;
354
355 /* In some situations especially in some VM states, guest-screen is not drawable: */
356 if (uisession()->isGuestScreenUnDrawable())
357 return;
358
359 /* Get old frame-buffer size: */
360 const QSize frameBufferSizeOld = QSize(frameBuffer()->width(),
361 frameBuffer()->height());
362
363 /* Perform frame-buffer mode-change: */
364 frameBuffer()->handleNotifyChange(iWidth, iHeight);
365
366 /* Get new frame-buffer size: */
367 const QSize frameBufferSizeNew = QSize(frameBuffer()->width(),
368 frameBuffer()->height());
369
370 /* For 'scale' mode: */
371 if (visualStateType() == UIVisualStateType_Scale)
372 {
373 /* Assign new frame-buffer logical-size: */
374 QSize scaledSize = size();
375 const double dDevicePixelRatioFormal = frameBuffer()->devicePixelRatio();
376 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
377 scaledSize *= dDevicePixelRatioFormal;
378 if (!frameBuffer()->useUnscaledHiDPIOutput())
379 scaledSize /= dDevicePixelRatioActual;
380 frameBuffer()->setScaledSize(scaledSize);
381
382 /* Forget the last full-screen size: */
383 uisession()->setLastFullScreenSize(screenId(), QSize(-1, -1));
384 }
385 /* For other than 'scale' mode: */
386 else
387 {
388 /* Adjust maximum-size restriction for machine-view: */
389 setMaximumSize(sizeHint());
390
391 /* Disable the resize hint override hack and forget the last full-screen size: */
392 m_sizeHintOverride = QSize(-1, -1);
393 if (visualStateType() == UIVisualStateType_Normal)
394 uisession()->setLastFullScreenSize(screenId(), QSize(-1, -1));
395
396 /* Force machine-window update own layout: */
397 QCoreApplication::sendPostedEvents(0, QEvent::LayoutRequest);
398
399 /* Update machine-view sliders: */
400 updateSliders();
401
402 /* By some reason Win host forgets to update machine-window central-widget
403 * after main-layout was updated, let's do it for all the hosts: */
404 machineWindow()->centralWidget()->update();
405
406 /* Normalize 'normal' machine-window geometry if necessary: */
407 if (visualStateType() == UIVisualStateType_Normal &&
408 frameBufferSizeNew != frameBufferSizeOld)
409 machineWindow()->normalizeGeometry(true /* adjust position */);
410 }
411
412 /* Perform frame-buffer rescaling: */
413 frameBuffer()->performRescale();
414
415#ifdef VBOX_WS_MAC
416 /* Update MacOS X dock icon size: */
417 machineLogic()->updateDockIconSize(screenId(), iWidth, iHeight);
418#endif /* VBOX_WS_MAC */
419
420 /* Notify frame-buffer resize: */
421 emit sigFrameBufferResize();
422
423 /* Ask for just required guest display update (it will also update
424 * the viewport through IFramebuffer::NotifyUpdate): */
425 display().InvalidateAndUpdateScreen(m_uScreenId);
426
427 /* If we are in normal or scaled mode and if GA are active,
428 * remember the guest-screen size to be able to restore it when necessary: */
429 if (!isFullscreenOrSeamless() && uisession()->isGuestSupportsGraphics())
430 storeGuestSizeHint(QSize(iWidth, iHeight));
431
432 LogRelFlow(("GUI: UIMachineView::sltHandleNotifyChange: Complete for Screen=%d, Size=%dx%d\n",
433 (unsigned long)m_uScreenId, iWidth, iHeight));
434}
435
436void UIMachineView::sltHandleNotifyUpdate(int iX, int iY, int iWidth, int iHeight)
437{
438 /* Prepare corresponding viewport part: */
439 QRect rect(iX, iY, iWidth, iHeight);
440
441 /* Take the scaling into account: */
442 const double dScaleFactor = frameBuffer()->scaleFactor();
443 const QSize scaledSize = frameBuffer()->scaledSize();
444 if (scaledSize.isValid())
445 {
446 /* Calculate corresponding scale-factors: */
447 const double xScaleFactor = visualStateType() == UIVisualStateType_Scale ?
448 (double)scaledSize.width() / frameBuffer()->width() : dScaleFactor;
449 const double yScaleFactor = visualStateType() == UIVisualStateType_Scale ?
450 (double)scaledSize.height() / frameBuffer()->height() : dScaleFactor;
451 /* Adjust corresponding viewport part: */
452 rect.moveTo((int)floor((double)rect.x() * xScaleFactor) - 1,
453 (int)floor((double)rect.y() * yScaleFactor) - 1);
454 rect.setSize(QSize((int)ceil((double)rect.width() * xScaleFactor) + 2,
455 (int)ceil((double)rect.height() * yScaleFactor) + 2));
456 }
457
458 /* Shift has to be scaled by the device-pixel-ratio
459 * but not scaled by the scale-factor. */
460 rect.translate(-contentsX(), -contentsY());
461
462 /* Take the device-pixel-ratio into account: */
463 const double dDevicePixelRatioFormal = frameBuffer()->devicePixelRatio();
464 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
465 if (!frameBuffer()->useUnscaledHiDPIOutput() && dDevicePixelRatioActual != 1.0)
466 {
467 rect.moveTo((int)floor((double)rect.x() * dDevicePixelRatioActual) - 1,
468 (int)floor((double)rect.y() * dDevicePixelRatioActual) - 1);
469 rect.setSize(QSize((int)ceil((double)rect.width() * dDevicePixelRatioActual) + 2,
470 (int)ceil((double)rect.height() * dDevicePixelRatioActual) + 2));
471 }
472 if (dDevicePixelRatioFormal != 1.0)
473 {
474 rect.moveTo((int)floor((double)rect.x() / dDevicePixelRatioFormal) - 1,
475 (int)floor((double)rect.y() / dDevicePixelRatioFormal) - 1);
476 rect.setSize(QSize((int)ceil((double)rect.width() / dDevicePixelRatioFormal) + 2,
477 (int)ceil((double)rect.height() / dDevicePixelRatioFormal) + 2));
478 }
479
480 /* Limit the resulting part by the viewport rectangle: */
481 rect &= viewport()->rect();
482
483 /* Update corresponding viewport part: */
484 viewport()->update(rect);
485}
486
487void UIMachineView::sltHandleSetVisibleRegion(QRegion region)
488{
489 /* Used only in seamless-mode. */
490 Q_UNUSED(region);
491}
492
493void UIMachineView::sltHandle3DOverlayVisibilityChange(bool fVisible)
494{
495 machineLogic()->notifyAbout3DOverlayVisibilityChange(fVisible);
496}
497
498void UIMachineView::sltDesktopResized()
499{
500 setMaxGuestSize();
501}
502
503void UIMachineView::sltHandleScaleFactorChange(const QUuid &uMachineID)
504{
505 /* Skip unrelated machine IDs: */
506 if (uMachineID != vboxGlobal().managedVMUuid())
507 return;
508
509 /* Acquire selected scale-factor: */
510 double dScaleFactor = gEDataManager->scaleFactor(vboxGlobal().managedVMUuid(), m_uScreenId);
511
512 /* Take the device-pixel-ratio into account: */
513 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
514 const bool fUseUnscaledHiDPIOutput = dScaleFactor != dDevicePixelRatioActual;
515 dScaleFactor = fUseUnscaledHiDPIOutput ? dScaleFactor : 1.0;
516
517 /* Assign frame-buffer with new values: */
518 frameBuffer()->setScaleFactor(dScaleFactor);
519 frameBuffer()->setUseUnscaledHiDPIOutput(fUseUnscaledHiDPIOutput);
520
521 /* Propagate the scale-factor related attributes to 3D service if necessary: */
522 if (machine().GetAccelerate3DEnabled() && vboxGlobal().is3DAvailable())
523 {
524 double dScaleFactorFor3D = dScaleFactor;
525#if defined(VBOX_WS_WIN) || defined(VBOX_WS_X11)
526 // WORKAROUND:
527 // On Windows and Linux opposing to macOS it's only Qt which can auto scale up,
528 // not 3D overlay itself, so for auto scale-up mode we have to take that into account.
529 if (!fUseUnscaledHiDPIOutput)
530 dScaleFactorFor3D *= frameBuffer()->devicePixelRatioActual();
531#endif /* VBOX_WS_WIN || VBOX_WS_X11 */
532 display().NotifyScaleFactorChange(m_uScreenId,
533 (uint32_t)(dScaleFactorFor3D * VBOX_OGL_SCALE_FACTOR_MULTIPLIER),
534 (uint32_t)(dScaleFactorFor3D * VBOX_OGL_SCALE_FACTOR_MULTIPLIER));
535 display().NotifyHiDPIOutputPolicyChange(fUseUnscaledHiDPIOutput);
536 }
537
538 /* Handle scale attributes change: */
539 handleScaleChange();
540 /* Adjust guest-screen size: */
541 adjustGuestScreenSize();
542
543 /* Update scaled pause pixmap, if necessary: */
544 updateScaledPausePixmap();
545 viewport()->update();
546
547 /* Update console's display viewport and 3D overlay: */
548 updateViewport();
549}
550
551void UIMachineView::sltHandleScalingOptimizationChange(const QUuid &uMachineID)
552{
553 /* Skip unrelated machine IDs: */
554 if (uMachineID != vboxGlobal().managedVMUuid())
555 return;
556
557 /* Take the scaling-optimization type into account: */
558 frameBuffer()->setScalingOptimizationType(gEDataManager->scalingOptimizationType(vboxGlobal().managedVMUuid()));
559
560 /* Update viewport: */
561 viewport()->update();
562}
563
564void UIMachineView::sltMachineStateChanged()
565{
566 /* Get machine state: */
567 KMachineState state = uisession()->machineState();
568 switch (state)
569 {
570 case KMachineState_Paused:
571 case KMachineState_TeleportingPausedVM:
572 {
573 if ( m_pFrameBuffer
574 && ( state != KMachineState_TeleportingPausedVM
575 || m_previousState != KMachineState_Teleporting))
576 {
577 /* Take live pause-pixmap: */
578 takePausePixmapLive();
579 /* Fully repaint to pick up pause-pixmap: */
580 viewport()->update();
581 }
582 break;
583 }
584 case KMachineState_Restoring:
585 {
586 /* Only works with the primary screen currently. */
587 if (screenId() == 0)
588 {
589 /* Take snapshot pause-pixmap: */
590 takePausePixmapSnapshot();
591 /* Fully repaint to pick up pause-pixmap: */
592 viewport()->update();
593 }
594 break;
595 }
596 case KMachineState_Running:
597 {
598 if (m_previousState == KMachineState_Paused ||
599 m_previousState == KMachineState_TeleportingPausedVM ||
600 m_previousState == KMachineState_Restoring)
601 {
602 if (m_pFrameBuffer)
603 {
604 /* Reset pause-pixmap: */
605 resetPausePixmap();
606 /* Ask for full guest display update (it will also update
607 * the viewport through IFramebuffer::NotifyUpdate): */
608 display().InvalidateAndUpdate();
609 }
610 }
611 /* Reapply machine-view scale-factor if necessary: */
612 if (m_pFrameBuffer)
613 applyMachineViewScaleFactor();
614 break;
615 }
616 default:
617 break;
618 }
619
620 m_previousState = state;
621}
622
623UIMachineView::UIMachineView( UIMachineWindow *pMachineWindow
624 , ulong uScreenId
625#ifdef VBOX_WITH_VIDEOHWACCEL
626 , bool bAccelerate2DVideo
627#endif /* VBOX_WITH_VIDEOHWACCEL */
628 )
629 : QAbstractScrollArea(pMachineWindow->centralWidget())
630 , m_pMachineWindow(pMachineWindow)
631 , m_uScreenId(uScreenId)
632 , m_pFrameBuffer(0)
633 , m_previousState(KMachineState_Null)
634 , m_iHostScreenNumber(0)
635 , m_maxGuestSizePolicy(MaxGuestResolutionPolicy_Automatic)
636 , m_u64MaxGuestSize(0)
637#ifdef VBOX_WITH_VIDEOHWACCEL
638 , m_fAccelerate2DVideo(bAccelerate2DVideo)
639#endif /* VBOX_WITH_VIDEOHWACCEL */
640#ifdef VBOX_WITH_DRAG_AND_DROP_GH
641 , m_fIsDraggingFromGuest(false)
642#endif
643 , m_pNativeEventFilter(0)
644{
645}
646
647void UIMachineView::loadMachineViewSettings()
648{
649 /* Global settings: */
650 {
651 /* Remember the maximum guest size policy for
652 * telling the guest about video modes we like: */
653 m_maxGuestSizePolicy = gEDataManager->maxGuestResolutionPolicy();
654 if (m_maxGuestSizePolicy == MaxGuestResolutionPolicy_Fixed)
655 m_fixedMaxGuestSize = gEDataManager->maxGuestResolutionForPolicyFixed();
656 }
657}
658
659void UIMachineView::prepareViewport()
660{
661 /* Prepare viewport: */
662 AssertPtrReturnVoid(viewport());
663 {
664 /* Enable manual painting: */
665 viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
666 /* Enable multi-touch support: */
667 viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
668 }
669}
670
671void UIMachineView::prepareFrameBuffer()
672{
673 /* Check whether we already have corresponding frame-buffer: */
674 UIFrameBuffer *pFrameBuffer = uisession()->frameBuffer(screenId());
675
676 /* If we do: */
677 if (pFrameBuffer)
678 {
679 /* Assign it's view: */
680 pFrameBuffer->setView(this);
681 /* Mark frame-buffer as used again: */
682 LogRelFlow(("GUI: UIMachineView::prepareFrameBuffer: Start EMT callbacks accepting for screen: %d\n", screenId()));
683 pFrameBuffer->setMarkAsUnused(false);
684 /* And remember our choice: */
685 m_pFrameBuffer = pFrameBuffer;
686 }
687 /* If we do not: */
688 else
689 {
690#ifdef VBOX_WITH_VIDEOHWACCEL
691 /* Create new frame-buffer: */
692 m_pFrameBuffer = new UIFrameBuffer(m_fAccelerate2DVideo);
693 m_pFrameBuffer->init(this);
694#else /* VBOX_WITH_VIDEOHWACCEL */
695 /* Create new frame-buffer: */
696 m_pFrameBuffer = new UIFrameBuffer;
697 m_pFrameBuffer->init(this);
698#endif /* !VBOX_WITH_VIDEOHWACCEL */
699
700 /* Take scaling optimization type into account: */
701 m_pFrameBuffer->setScalingOptimizationType(gEDataManager->scalingOptimizationType(vboxGlobal().managedVMUuid()));
702
703 /* Acquire selected scale-factor: */
704 double dScaleFactor = gEDataManager->scaleFactor(vboxGlobal().managedVMUuid(), m_uScreenId);
705
706 /* Take the device-pixel-ratio into account: */
707 const double dDevicePixelRatioFormal = gpDesktop->devicePixelRatio(machineWindow());
708 const double dDevicePixelRatioActual = gpDesktop->devicePixelRatioActual(machineWindow());
709 const bool fUseUnscaledHiDPIOutput = dScaleFactor != dDevicePixelRatioActual;
710 dScaleFactor = fUseUnscaledHiDPIOutput ? dScaleFactor : 1.0;
711
712 /* Assign frame-buffer with new values: */
713 m_pFrameBuffer->setDevicePixelRatio(dDevicePixelRatioFormal);
714 m_pFrameBuffer->setDevicePixelRatioActual(dDevicePixelRatioActual);
715 m_pFrameBuffer->setScaleFactor(dScaleFactor);
716 m_pFrameBuffer->setUseUnscaledHiDPIOutput(fUseUnscaledHiDPIOutput);
717
718 /* Propagate the scale-factor related attributes to 3D service if necessary: */
719 if (machine().GetAccelerate3DEnabled() && vboxGlobal().is3DAvailable())
720 {
721 double dScaleFactorFor3D = dScaleFactor;
722#if defined(VBOX_WS_WIN) || defined(VBOX_WS_X11)
723 // WORKAROUND:
724 // On Windows and Linux opposing to macOS it's only Qt which can auto scale up,
725 // not 3D overlay itself, so for auto scale-up mode we have to take that into account.
726 if (!fUseUnscaledHiDPIOutput)
727 dScaleFactorFor3D *= dDevicePixelRatioActual;
728#endif /* VBOX_WS_WIN || VBOX_WS_X11 */
729 display().NotifyScaleFactorChange(m_uScreenId,
730 (uint32_t)(dScaleFactorFor3D * VBOX_OGL_SCALE_FACTOR_MULTIPLIER),
731 (uint32_t)(dScaleFactorFor3D * VBOX_OGL_SCALE_FACTOR_MULTIPLIER));
732 display().NotifyHiDPIOutputPolicyChange(fUseUnscaledHiDPIOutput);
733 }
734
735 /* Perform frame-buffer rescaling: */
736 m_pFrameBuffer->performRescale();
737
738 /* Associate uisession with frame-buffer finally: */
739 uisession()->setFrameBuffer(screenId(), m_pFrameBuffer);
740 }
741
742 /* Make sure frame-buffer was prepared: */
743 AssertReturnVoid(m_pFrameBuffer);
744
745 /* Reattach to IDisplay: */
746 m_pFrameBuffer->detach();
747 m_pFrameBuffer->attach();
748
749 /* Calculate frame-buffer size: */
750 QSize size;
751 {
752#ifdef VBOX_WS_X11
753 /* Processing pseudo resize-event to synchronize frame-buffer with stored framebuffer size.
754 * On X11 this will be additional done when the machine state was 'saved'. */
755 if (machine().GetState() == KMachineState_Saved)
756 size = guestScreenSizeHint();
757#endif /* VBOX_WS_X11 */
758
759 /* If there is a preview image saved,
760 * we will resize the framebuffer to the size of that image: */
761 ULONG uWidth = 0, uHeight = 0;
762 QVector<KBitmapFormat> formats = machine().QuerySavedScreenshotInfo(0, uWidth, uHeight);
763 if (formats.size() > 0)
764 {
765 /* Init with the screenshot size: */
766 size = QSize(uWidth, uHeight);
767 /* Try to get the real guest dimensions from the save-state: */
768 ULONG uGuestOriginX = 0, uGuestOriginY = 0, uGuestWidth = 0, uGuestHeight = 0;
769 BOOL fEnabled = true;
770 machine().QuerySavedGuestScreenInfo(m_uScreenId, uGuestOriginX, uGuestOriginY, uGuestWidth, uGuestHeight, fEnabled);
771 if (uGuestWidth > 0 && uGuestHeight > 0)
772 size = QSize(uGuestWidth, uGuestHeight);
773 }
774
775 /* If we have a valid size, resize/rescale the frame-buffer. */
776 if (size.width() > 0 && size.height() > 0)
777 {
778 frameBuffer()->performResize(size.width(), size.height());
779 frameBuffer()->performRescale();
780 }
781 }
782}
783
784void UIMachineView::prepareCommon()
785{
786 /* Prepare view frame: */
787 setFrameStyle(QFrame::NoFrame);
788
789 /* Setup palette: */
790 QPalette palette(viewport()->palette());
791 palette.setColor(viewport()->backgroundRole(), Qt::black);
792 viewport()->setPalette(palette);
793
794 /* Setup focus policy: */
795 setFocusPolicy(Qt::WheelFocus);
796
797#ifdef VBOX_WITH_DRAG_AND_DROP
798 /* Enable drag & drop: */
799 setAcceptDrops(true);
800
801 /* Create the drag and drop handler instance: */
802 m_pDnDHandler = new UIDnDHandler(uisession(), this /* pParent */);
803#endif /* VBOX_WITH_DRAG_AND_DROP */
804}
805
806void UIMachineView::prepareFilters()
807{
808 /* Enable MouseMove events: */
809 viewport()->setMouseTracking(true);
810
811 /* We have to watch for own events too: */
812 installEventFilter(this);
813
814 /* QScrollView does the below on its own, but let's
815 * do it anyway for the case it will not do it in the future: */
816 viewport()->installEventFilter(this);
817
818 /* We want to be notified on some parent's events: */
819 machineWindow()->installEventFilter(this);
820}
821
822void UIMachineView::prepareConnections()
823{
824 /* Desktop resolution change (e.g. monitor hotplug): */
825 connect(gpDesktop, SIGNAL(sigHostScreenResized(int)), this,
826 SLOT(sltDesktopResized()));
827 /* Scale-factor change: */
828 connect(gEDataManager, SIGNAL(sigScaleFactorChange(const QUuid &)),
829 this, SLOT(sltHandleScaleFactorChange(const QUuid &)));
830 /* Scaling-optimization change: */
831 connect(gEDataManager, SIGNAL(sigScalingOptimizationTypeChange(const QUuid &)),
832 this, SLOT(sltHandleScalingOptimizationChange(const QUuid &)));
833}
834
835void UIMachineView::prepareConsoleConnections()
836{
837 /* Machine state-change updater: */
838 connect(uisession(), SIGNAL(sigMachineStateChange()), this, SLOT(sltMachineStateChanged()));
839}
840
841void UIMachineView::cleanupFrameBuffer()
842{
843 /* Make sure proper framebuffer assigned: */
844 AssertReturnVoid(m_pFrameBuffer);
845 AssertReturnVoid(m_pFrameBuffer == uisession()->frameBuffer(screenId()));
846
847 /* Mark framebuffer as unused: */
848 LogRelFlow(("GUI: UIMachineView::cleanupFrameBuffer: Stop EMT callbacks accepting for screen: %d\n", screenId()));
849 m_pFrameBuffer->setMarkAsUnused(true);
850
851 /* Process pending framebuffer events: */
852 QApplication::sendPostedEvents(this, QEvent::MetaCall);
853
854#ifdef VBOX_WITH_VIDEOHWACCEL
855 if (m_fAccelerate2DVideo)
856 QApplication::sendPostedEvents(this, VHWACommandProcessType);
857#endif /* VBOX_WITH_VIDEOHWACCEL */
858
859 /* Temporarily detach the framebuffer from IDisplay before detaching
860 * from view in order to respect the thread synchonisation logic (see UIFrameBuffer.h).
861 * Note: VBOX_WITH_CROGL additionally requires us to call DetachFramebuffer
862 * to ensure 3D gets notified of view being destroyed... */
863 if (console().isOk() && !display().isNull())
864 m_pFrameBuffer->detach();
865
866 /* Detach framebuffer from view: */
867 m_pFrameBuffer->setView(NULL);
868}
869
870void UIMachineView::cleanupNativeFilters()
871{
872 /* If native event filter exists: */
873 if (m_pNativeEventFilter)
874 {
875 /* Uninstall/destroy existing native event filter: */
876 qApp->removeNativeEventFilter(m_pNativeEventFilter);
877 delete m_pNativeEventFilter;
878 m_pNativeEventFilter = 0;
879 }
880}
881
882UISession* UIMachineView::uisession() const
883{
884 return machineWindow()->uisession();
885}
886
887CSession& UIMachineView::session() const
888{
889 return uisession()->session();
890}
891
892CMachine& UIMachineView::machine() const
893{
894 return uisession()->machine();
895}
896
897CConsole& UIMachineView::console() const
898{
899 return uisession()->console();
900}
901
902CDisplay& UIMachineView::display() const
903{
904 return uisession()->display();
905}
906
907CGuest& UIMachineView::guest() const
908{
909 return uisession()->guest();
910}
911
912UIActionPool* UIMachineView::actionPool() const
913{
914 return machineWindow()->actionPool();
915}
916
917UIMachineLogic* UIMachineView::machineLogic() const
918{
919 return machineWindow()->machineLogic();
920}
921
922QSize UIMachineView::sizeHint() const
923{
924 /* Temporarily restrict the size to prevent a brief resize to the
925 * frame-buffer dimensions when we exit full-screen. This is only
926 * applied if the frame-buffer is at full-screen dimensions and
927 * until the first machine view resize. */
928
929 /* Get the frame-buffer dimensions: */
930 QSize frameBufferSize(frameBuffer()->width(), frameBuffer()->height());
931 /* Take the scale-factor(s) into account: */
932 frameBufferSize = scaledForward(frameBufferSize);
933 /* Check against the last full-screen size. */
934 if (frameBufferSize == uisession()->lastFullScreenSize(screenId()) && m_sizeHintOverride.isValid())
935 return m_sizeHintOverride;
936
937 /* Get frame-buffer size-hint: */
938 QSize size(m_pFrameBuffer->width(), m_pFrameBuffer->height());
939
940 /* Take the scale-factor(s) into account: */
941 size = scaledForward(size);
942
943#ifdef VBOX_WITH_DEBUGGER_GUI
944 /// @todo Fix all DEBUGGER stuff!
945 /* HACK ALERT! Really ugly workaround for the resizing to 9x1 done by DevVGA if provoked before power on. */
946 if (size.width() < 16 || size.height() < 16)
947 if (vboxGlobal().shouldStartPaused() || vboxGlobal().isDebuggerAutoShowEnabled())
948 size = QSize(640, 480);
949#endif /* !VBOX_WITH_DEBUGGER_GUI */
950
951 /* Return the resulting size-hint: */
952 return QSize(size.width() + frameWidth() * 2, size.height() + frameWidth() * 2);
953}
954
955int UIMachineView::contentsX() const
956{
957 return horizontalScrollBar()->value();
958}
959
960int UIMachineView::contentsY() const
961{
962 return verticalScrollBar()->value();
963}
964
965int UIMachineView::contentsWidth() const
966{
967 return m_pFrameBuffer->width();
968}
969
970int UIMachineView::contentsHeight() const
971{
972 return m_pFrameBuffer->height();
973}
974
975int UIMachineView::visibleWidth() const
976{
977 return horizontalScrollBar()->pageStep();
978}
979
980int UIMachineView::visibleHeight() const
981{
982 return verticalScrollBar()->pageStep();
983}
984
985void UIMachineView::setMaxGuestSize(const QSize &minimumSizeHint /* = QSize() */)
986{
987 QSize maxSize;
988 switch (m_maxGuestSizePolicy)
989 {
990 case MaxGuestResolutionPolicy_Fixed:
991 maxSize = m_fixedMaxGuestSize;
992 break;
993 case MaxGuestResolutionPolicy_Automatic:
994 maxSize = calculateMaxGuestSize().expandedTo(minimumSizeHint);
995 break;
996 case MaxGuestResolutionPolicy_Any:
997 /* (0, 0) means any of course. */
998 maxSize = QSize(0, 0);
999 }
1000 ASMAtomicWriteU64(&m_u64MaxGuestSize,
1001 RT_MAKE_U64(maxSize.height(), maxSize.width()));
1002}
1003
1004QSize UIMachineView::maxGuestSize()
1005{
1006 uint64_t u64Size = ASMAtomicReadU64(&m_u64MaxGuestSize);
1007 return QSize(int(RT_HI_U32(u64Size)), int(RT_LO_U32(u64Size)));
1008}
1009
1010bool UIMachineView::guestScreenVisibilityStatus() const
1011{
1012 /* Always 'true' for primary guest-screen: */
1013 if (m_uScreenId == 0)
1014 return true;
1015
1016 /* Actual value for other guest-screens: */
1017 return gEDataManager->lastGuestScreenVisibilityStatus(m_uScreenId, vboxGlobal().managedVMUuid());
1018}
1019
1020QSize UIMachineView::guestScreenSizeHint() const
1021{
1022 /* Load guest-screen size-hint: */
1023 QSize sizeHint = gEDataManager->lastGuestScreenSizeHint(m_uScreenId, vboxGlobal().managedVMUuid());
1024
1025 /* Invent the default if necessary: */
1026 if (!sizeHint.isValid())
1027 sizeHint = QSize(800, 600);
1028
1029 /* Take the scale-factor(s) into account: */
1030 sizeHint = scaledForward(sizeHint);
1031
1032 /* Return size-hint: */
1033 return sizeHint;
1034}
1035
1036void UIMachineView::storeGuestSizeHint(const QSize &sizeHint)
1037{
1038 /* Save guest-screen size-hint: */
1039 LogRel(("GUI: UIMachineView::storeGuestSizeHint: "
1040 "Storing guest-screen size-hint for screen %d as %dx%d\n",
1041 (int)screenId(), sizeHint.width(), sizeHint.height()));
1042 gEDataManager->setLastGuestScreenSizeHint(m_uScreenId, sizeHint, vboxGlobal().managedVMUuid());
1043}
1044
1045void UIMachineView::handleScaleChange()
1046{
1047 LogRel(("GUI: UIMachineView::handleScaleChange: Screen=%d\n",
1048 (unsigned long)m_uScreenId));
1049
1050 /* If machine-window is visible: */
1051 if (uisession()->isScreenVisible(m_uScreenId))
1052 {
1053 /* For 'scale' mode: */
1054 if (visualStateType() == UIVisualStateType_Scale)
1055 {
1056 /* Assign new frame-buffer logical-size: */
1057 QSize scaledSize = size();
1058 const double dDevicePixelRatioFormal = frameBuffer()->devicePixelRatio();
1059 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
1060 scaledSize *= dDevicePixelRatioFormal;
1061 if (!frameBuffer()->useUnscaledHiDPIOutput())
1062 scaledSize /= dDevicePixelRatioActual;
1063 frameBuffer()->setScaledSize(scaledSize);
1064 }
1065 /* For other than 'scale' mode: */
1066 else
1067 {
1068 /* Adjust maximum-size restriction for machine-view: */
1069 setMaximumSize(sizeHint());
1070
1071 /* Force machine-window update own layout: */
1072 QCoreApplication::sendPostedEvents(0, QEvent::LayoutRequest);
1073
1074 /* Update machine-view sliders: */
1075 updateSliders();
1076
1077 /* By some reason Win host forgets to update machine-window central-widget
1078 * after main-layout was updated, let's do it for all the hosts: */
1079 machineWindow()->centralWidget()->update();
1080
1081 /* Normalize 'normal' machine-window geometry: */
1082 if (visualStateType() == UIVisualStateType_Normal)
1083 machineWindow()->normalizeGeometry(true /* adjust position */);
1084 }
1085
1086 /* Perform frame-buffer rescaling: */
1087 frameBuffer()->performRescale();
1088 }
1089
1090 LogRelFlow(("GUI: UIMachineView::handleScaleChange: Complete for Screen=%d\n",
1091 (unsigned long)m_uScreenId));
1092}
1093
1094void UIMachineView::resetPausePixmap()
1095{
1096 /* Reset pixmap(s): */
1097 m_pausePixmap = QPixmap();
1098 m_pausePixmapScaled = QPixmap();
1099}
1100
1101void UIMachineView::takePausePixmapLive()
1102{
1103 /* Prepare a screen-shot: */
1104 QImage screenShot = QImage(m_pFrameBuffer->width(), m_pFrameBuffer->height(), QImage::Format_RGB32);
1105 /* Which will be a 'black image' by default. */
1106 screenShot.fill(0);
1107
1108 /* For separate process: */
1109 if (vboxGlobal().isSeparateProcess())
1110 {
1111 /* Take screen-data to array: */
1112 const QVector<BYTE> screenData = display().TakeScreenShotToArray(screenId(), screenShot.width(), screenShot.height(), KBitmapFormat_BGR0);
1113 /* And copy that data to screen-shot if it is Ok: */
1114 if (display().isOk() && !screenData.isEmpty())
1115 memcpy(screenShot.bits(), screenData.data(), screenShot.width() * screenShot.height() * 4);
1116 }
1117 /* For the same process: */
1118 else
1119 {
1120 /* Take the screen-shot directly: */
1121 display().TakeScreenShot(screenId(), screenShot.bits(), screenShot.width(), screenShot.height(), KBitmapFormat_BGR0);
1122 }
1123
1124 /* Take the device-pixel-ratio into account: */
1125 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
1126 if (!frameBuffer()->useUnscaledHiDPIOutput() && dDevicePixelRatioActual != 1.0)
1127 screenShot = screenShot.scaled(screenShot.size() * dDevicePixelRatioActual,
1128 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1129
1130 /* Dim screen-shot if it is Ok: */
1131 if (display().isOk() && !screenShot.isNull())
1132 dimImage(screenShot);
1133
1134 /* Finally copy the screen-shot to pause-pixmap: */
1135 m_pausePixmap = QPixmap::fromImage(screenShot);
1136
1137 /* Take the device-pixel-ratio into account: */
1138 m_pausePixmap.setDevicePixelRatio(frameBuffer()->devicePixelRatio());
1139
1140 /* Update scaled pause pixmap: */
1141 updateScaledPausePixmap();
1142}
1143
1144void UIMachineView::takePausePixmapSnapshot()
1145{
1146 /* Acquire the screen-data from the saved-state: */
1147 ULONG uWidth = 0, uHeight = 0;
1148 const QVector<BYTE> screenData = machine().ReadSavedScreenshotToArray(0, KBitmapFormat_PNG, uWidth, uHeight);
1149
1150 /* Make sure there is saved-state screen-data: */
1151 if (screenData.isEmpty())
1152 return;
1153
1154 /* Acquire the screen-data properties from the saved-state: */
1155 ULONG uGuestOriginX = 0, uGuestOriginY = 0, uGuestWidth = 0, uGuestHeight = 0;
1156 BOOL fEnabled = true;
1157 machine().QuerySavedGuestScreenInfo(m_uScreenId, uGuestOriginX, uGuestOriginY, uGuestWidth, uGuestHeight, fEnabled);
1158
1159 /* Calculate effective size: */
1160 QSize effectiveSize = uGuestWidth > 0 ? QSize(uGuestWidth, uGuestHeight) : guestScreenSizeHint();
1161
1162 /* Take the device-pixel-ratio into account: */
1163 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
1164 if (!frameBuffer()->useUnscaledHiDPIOutput() && dDevicePixelRatioActual != 1.0)
1165 effectiveSize *= dDevicePixelRatioActual;
1166
1167 /* Create a screen-shot on the basis of the screen-data we have in saved-state: */
1168 QImage screenShot = QImage::fromData(screenData.data(), screenData.size(), "PNG").scaled(effectiveSize);
1169
1170 /* Dim screen-shot if it is Ok: */
1171 if (machine().isOk() && !screenShot.isNull())
1172 dimImage(screenShot);
1173
1174 /* Finally copy the screen-shot to pause-pixmap: */
1175 m_pausePixmap = QPixmap::fromImage(screenShot);
1176
1177 /* Take the device-pixel-ratio into account: */
1178 m_pausePixmap.setDevicePixelRatio(frameBuffer()->devicePixelRatio());
1179
1180 /* Update scaled pause pixmap: */
1181 updateScaledPausePixmap();
1182}
1183
1184void UIMachineView::updateScaledPausePixmap()
1185{
1186 /* Make sure pause pixmap is not null: */
1187 if (pausePixmap().isNull())
1188 return;
1189
1190 /* Make sure scaled-size is not null: */
1191 QSize scaledSize = frameBuffer()->scaledSize();
1192 if (!scaledSize.isValid())
1193 return;
1194
1195 /* Take the device-pixel-ratio into account: */
1196 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
1197 if (!frameBuffer()->useUnscaledHiDPIOutput() && dDevicePixelRatioActual != 1.0)
1198 scaledSize *= dDevicePixelRatioActual;
1199
1200 /* Update pause pixmap finally: */
1201 m_pausePixmapScaled = pausePixmap().scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1202
1203 /* Take the device-pixel-ratio into account: */
1204 m_pausePixmapScaled.setDevicePixelRatio(frameBuffer()->devicePixelRatio());
1205}
1206
1207void UIMachineView::updateSliders()
1208{
1209 /* Get current viewport size: */
1210 QSize curViewportSize = viewport()->size();
1211 /* Get maximum viewport size: */
1212 const QSize maxViewportSize = maximumViewportSize();
1213 /* Get current frame-buffer size: */
1214 QSize frameBufferSize = QSize(frameBuffer()->width(), frameBuffer()->height());
1215
1216 /* Take the scale-factor(s) into account: */
1217 frameBufferSize = scaledForward(frameBufferSize);
1218
1219 /* If maximum viewport size can cover whole frame-buffer => no scroll-bars required: */
1220 if (maxViewportSize.expandedTo(frameBufferSize) == maxViewportSize)
1221 curViewportSize = maxViewportSize;
1222
1223 /* What length we want scroll-bars of? */
1224 int xRange = frameBufferSize.width() - curViewportSize.width();
1225 int yRange = frameBufferSize.height() - curViewportSize.height();
1226
1227 /* Take the device-pixel-ratio into account: */
1228 const double dDevicePixelRatioFormal = frameBuffer()->devicePixelRatio();
1229 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
1230 xRange *= dDevicePixelRatioFormal;
1231 yRange *= dDevicePixelRatioFormal;
1232 if (!frameBuffer()->useUnscaledHiDPIOutput())
1233 {
1234 xRange /= dDevicePixelRatioActual;
1235 yRange /= dDevicePixelRatioActual;
1236 }
1237
1238 /* Configure scroll-bars: */
1239 horizontalScrollBar()->setRange(0, xRange);
1240 verticalScrollBar()->setRange(0, yRange);
1241 horizontalScrollBar()->setPageStep(curViewportSize.width());
1242 verticalScrollBar()->setPageStep(curViewportSize.height());
1243}
1244
1245QPoint UIMachineView::viewportToContents(const QPoint &vp) const
1246{
1247 /* Get physical contents shifts of scroll-bars: */
1248 int iContentsX = contentsX();
1249 int iContentsY = contentsY();
1250
1251 /* Take the device-pixel-ratio into account: */
1252 const double dDevicePixelRatioFormal = frameBuffer()->devicePixelRatio();
1253 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
1254 if (!frameBuffer()->useUnscaledHiDPIOutput())
1255 {
1256 iContentsX *= dDevicePixelRatioActual;
1257 iContentsY *= dDevicePixelRatioActual;
1258 }
1259 iContentsX /= dDevicePixelRatioFormal;
1260 iContentsY /= dDevicePixelRatioFormal;
1261
1262 /* Return point shifted according scroll-bars: */
1263 return QPoint(vp.x() + iContentsX, vp.y() + iContentsY);
1264}
1265
1266void UIMachineView::scrollBy(int dx, int dy)
1267{
1268 horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dx);
1269 verticalScrollBar()->setValue(verticalScrollBar()->value() + dy);
1270}
1271
1272void UIMachineView::dimImage(QImage &img)
1273{
1274 for (int y = 0; y < img.height(); ++ y)
1275 {
1276 if (y % 2)
1277 {
1278 if (img.depth() == 32)
1279 {
1280 for (int x = 0; x < img.width(); ++ x)
1281 {
1282 int gray = qGray(img.pixel (x, y)) / 2;
1283 img.setPixel(x, y, qRgb (gray, gray, gray));
1284 }
1285 }
1286 else
1287 {
1288 ::memset(img.scanLine (y), 0, img.bytesPerLine());
1289 }
1290 }
1291 else
1292 {
1293 if (img.depth() == 32)
1294 {
1295 for (int x = 0; x < img.width(); ++ x)
1296 {
1297 int gray = (2 * qGray (img.pixel (x, y))) / 3;
1298 img.setPixel(x, y, qRgb (gray, gray, gray));
1299 }
1300 }
1301 }
1302 }
1303}
1304
1305void UIMachineView::scrollContentsBy(int dx, int dy)
1306{
1307#ifdef VBOX_WITH_VIDEOHWACCEL
1308 if (m_pFrameBuffer)
1309 {
1310 m_pFrameBuffer->viewportScrolled(dx, dy);
1311 }
1312#endif /* VBOX_WITH_VIDEOHWACCEL */
1313 QAbstractScrollArea::scrollContentsBy(dx, dy);
1314
1315 /* Update console's display viewport and 3D overlay: */
1316 updateViewport();
1317}
1318
1319#ifdef VBOX_WS_MAC
1320void UIMachineView::updateDockIcon()
1321{
1322 machineLogic()->updateDockIcon();
1323}
1324
1325CGImageRef UIMachineView::vmContentImage()
1326{
1327 /* Use pause-image if exists: */
1328 if (!pausePixmap().isNull())
1329 return darwinToCGImageRef(&pausePixmap());
1330
1331 /* Create the image ref out of the frame-buffer: */
1332 return frameBuffertoCGImageRef(m_pFrameBuffer);
1333}
1334
1335CGImageRef UIMachineView::frameBuffertoCGImageRef(UIFrameBuffer *pFrameBuffer)
1336{
1337 CGImageRef ir = 0;
1338 CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
1339 if (cs)
1340 {
1341 /* Create the image copy of the framebuffer */
1342 CGDataProviderRef dp = CGDataProviderCreateWithData(pFrameBuffer, pFrameBuffer->address(), pFrameBuffer->bitsPerPixel() / 8 * pFrameBuffer->width() * pFrameBuffer->height(), NULL);
1343 if (dp)
1344 {
1345 ir = CGImageCreate(pFrameBuffer->width(), pFrameBuffer->height(), 8, 32, pFrameBuffer->bytesPerLine(), cs,
1346 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host, dp, 0, false,
1347 kCGRenderingIntentDefault);
1348 CGDataProviderRelease(dp);
1349 }
1350 CGColorSpaceRelease(cs);
1351 }
1352 return ir;
1353}
1354#endif /* VBOX_WS_MAC */
1355
1356UIVisualStateType UIMachineView::visualStateType() const
1357{
1358 return machineLogic()->visualStateType();
1359}
1360
1361bool UIMachineView::isFullscreenOrSeamless() const
1362{
1363 return visualStateType() == UIVisualStateType_Fullscreen
1364 || visualStateType() == UIVisualStateType_Seamless;
1365}
1366
1367bool UIMachineView::event(QEvent *pEvent)
1368{
1369 switch ((UIEventType)pEvent->type())
1370 {
1371#ifdef VBOX_WS_MAC
1372 /* Event posted OnShowWindow: */
1373 case ShowWindowEventType:
1374 {
1375 /* Dunno what Qt3 thinks a window that has minimized to the dock should be - it is not hidden,
1376 * neither is it minimized. OTOH it is marked shown and visible, but not activated.
1377 * This latter isn't of much help though, since at this point nothing is marked activated.
1378 * I might have overlooked something, but I'm buggered what if I know what. So, I'll just always
1379 * show & activate the stupid window to make it get out of the dock when the user wishes to show a VM: */
1380 window()->show();
1381 window()->activateWindow();
1382 return true;
1383 }
1384#endif /* VBOX_WS_MAC */
1385
1386#ifdef VBOX_WITH_VIDEOHWACCEL
1387 case VHWACommandProcessType:
1388 {
1389 m_pFrameBuffer->doProcessVHWACommand(pEvent);
1390 return true;
1391 }
1392#endif /* VBOX_WITH_VIDEOHWACCEL */
1393
1394 default:
1395 break;
1396 }
1397
1398 return QAbstractScrollArea::event(pEvent);
1399}
1400
1401bool UIMachineView::eventFilter(QObject *pWatched, QEvent *pEvent)
1402{
1403 if (pWatched == viewport())
1404 {
1405 switch (pEvent->type())
1406 {
1407 case QEvent::Resize:
1408 {
1409#ifdef VBOX_WITH_VIDEOHWACCEL
1410 QResizeEvent* pResizeEvent = static_cast<QResizeEvent*>(pEvent);
1411 if (m_pFrameBuffer)
1412 m_pFrameBuffer->viewportResized(pResizeEvent);
1413#endif /* VBOX_WITH_VIDEOHWACCEL */
1414 /* Update console's display viewport and 3D overlay: */
1415 updateViewport();
1416 break;
1417 }
1418 default:
1419 break;
1420 }
1421 }
1422
1423 if (pWatched == this)
1424 {
1425 switch (pEvent->type())
1426 {
1427 case QEvent::Move:
1428 {
1429 /* Update console's display viewport and 3D overlay: */
1430 updateViewport();
1431 break;
1432 }
1433 default:
1434 break;
1435 }
1436 }
1437
1438 if (pWatched == machineWindow())
1439 {
1440 switch (pEvent->type())
1441 {
1442 case QEvent::WindowStateChange:
1443 {
1444 /* During minimizing and state restoring machineWindow() gets
1445 * the focus which belongs to console view window, so returning it properly. */
1446 QWindowStateChangeEvent *pWindowEvent = static_cast<QWindowStateChangeEvent*>(pEvent);
1447 if (pWindowEvent->oldState() & Qt::WindowMinimized)
1448 {
1449 if (QApplication::focusWidget())
1450 {
1451 QApplication::focusWidget()->clearFocus();
1452 qApp->processEvents();
1453 }
1454 QTimer::singleShot(0, this, SLOT(setFocus()));
1455 }
1456 break;
1457 }
1458 case QEvent::Move:
1459 {
1460 /* Get current host-screen number: */
1461 const int iCurrentHostScreenNumber = gpDesktop->screenNumber(this);
1462 if (m_iHostScreenNumber != iCurrentHostScreenNumber)
1463 {
1464 /* Recache current host screen: */
1465 m_iHostScreenNumber = iCurrentHostScreenNumber;
1466
1467 /* Update frame-buffer arguments: */
1468 if (m_pFrameBuffer)
1469 {
1470 /* Update device-pixel-ratio for underlying frame-buffer: */
1471 m_pFrameBuffer->setDevicePixelRatio(gpDesktop->devicePixelRatio(machineWindow()));
1472 m_pFrameBuffer->setDevicePixelRatioActual(gpDesktop->devicePixelRatioActual(machineWindow()));
1473 /* Perform frame-buffer rescaling: */
1474 m_pFrameBuffer->performRescale();
1475 }
1476
1477 /* Update console's display viewport and 3D overlay: */
1478 updateViewport();
1479 }
1480 break;
1481 }
1482 default:
1483 break;
1484 }
1485 }
1486
1487 return QAbstractScrollArea::eventFilter(pWatched, pEvent);
1488}
1489
1490void UIMachineView::resizeEvent(QResizeEvent *pEvent)
1491{
1492 updateSliders();
1493 return QAbstractScrollArea::resizeEvent(pEvent);
1494}
1495
1496void UIMachineView::moveEvent(QMoveEvent *pEvent)
1497{
1498 return QAbstractScrollArea::moveEvent(pEvent);
1499}
1500
1501void UIMachineView::paintEvent(QPaintEvent *pPaintEvent)
1502{
1503 /* Use pause-image if exists: */
1504 if (!pausePixmap().isNull())
1505 {
1506 /* We have a snapshot for the paused state: */
1507 QRect rect = pPaintEvent->rect().intersected(viewport()->rect());
1508 QPainter painter(viewport());
1509 /* Take the scale-factor into account: */
1510 if (frameBuffer()->scaleFactor() == 1.0 && !frameBuffer()->scaledSize().isValid())
1511 painter.drawPixmap(rect.topLeft(), pausePixmap());
1512 else
1513 painter.drawPixmap(rect.topLeft(), pausePixmapScaled());
1514#ifdef VBOX_WS_MAC
1515 /* Update the dock icon: */
1516 updateDockIcon();
1517#endif /* VBOX_WS_MAC */
1518 return;
1519 }
1520
1521 /* Delegate the paint function to the UIFrameBuffer interface: */
1522 if (m_pFrameBuffer)
1523 m_pFrameBuffer->handlePaintEvent(pPaintEvent);
1524#ifdef VBOX_WS_MAC
1525 /* Update the dock icon if we are in the running state: */
1526 if (uisession()->isRunning())
1527 updateDockIcon();
1528#endif /* VBOX_WS_MAC */
1529}
1530
1531void UIMachineView::focusInEvent(QFocusEvent *pEvent)
1532{
1533 /* Call to base-class: */
1534 QAbstractScrollArea::focusInEvent(pEvent);
1535
1536 /* If native event filter isn't exists: */
1537 if (!m_pNativeEventFilter)
1538 {
1539 /* Create/install new native event filter: */
1540 m_pNativeEventFilter = new UINativeEventFilter(this);
1541 qApp->installNativeEventFilter(m_pNativeEventFilter);
1542 }
1543}
1544
1545void UIMachineView::focusOutEvent(QFocusEvent *pEvent)
1546{
1547 /* If native event filter exists: */
1548 if (m_pNativeEventFilter)
1549 {
1550 /* Uninstall/destroy existing native event filter: */
1551 qApp->removeNativeEventFilter(m_pNativeEventFilter);
1552 delete m_pNativeEventFilter;
1553 m_pNativeEventFilter = 0;
1554 }
1555
1556 /* Call to base-class: */
1557 QAbstractScrollArea::focusOutEvent(pEvent);
1558}
1559
1560#ifdef VBOX_WITH_DRAG_AND_DROP
1561bool UIMachineView::dragAndDropCanAccept(void) const
1562{
1563 bool fAccept = m_pDnDHandler
1564#ifdef VBOX_WITH_DRAG_AND_DROP_GH
1565 && !m_fIsDraggingFromGuest
1566#endif
1567 && machine().GetDnDMode() != KDnDMode_Disabled;
1568 return fAccept;
1569}
1570
1571bool UIMachineView::dragAndDropIsActive(void) const
1572{
1573 return ( m_pDnDHandler
1574 && machine().GetDnDMode() != KDnDMode_Disabled);
1575}
1576
1577void UIMachineView::dragEnterEvent(QDragEnterEvent *pEvent)
1578{
1579 AssertPtrReturnVoid(pEvent);
1580
1581 int rc = dragAndDropCanAccept() ? VINF_SUCCESS : VERR_ACCESS_DENIED;
1582 if (RT_SUCCESS(rc))
1583 {
1584 /* Get mouse-pointer location. */
1585 const QPoint &cpnt = viewportToContents(pEvent->pos());
1586
1587 /* Ask the target for starting a DnD event. */
1588 Qt::DropAction result = m_pDnDHandler->dragEnter(screenId(),
1589 frameBuffer()->convertHostXTo(cpnt.x()),
1590 frameBuffer()->convertHostYTo(cpnt.y()),
1591 pEvent->proposedAction(),
1592 pEvent->possibleActions(),
1593 pEvent->mimeData());
1594
1595 /* Set the DnD action returned by the guest. */
1596 pEvent->setDropAction(result);
1597 pEvent->accept();
1598 }
1599
1600 DNDDEBUG(("DnD: dragEnterEvent ended with rc=%Rrc\n", rc));
1601}
1602
1603void UIMachineView::dragMoveEvent(QDragMoveEvent *pEvent)
1604{
1605 AssertPtrReturnVoid(pEvent);
1606
1607 int rc = dragAndDropCanAccept() ? VINF_SUCCESS : VERR_ACCESS_DENIED;
1608 if (RT_SUCCESS(rc))
1609 {
1610 /* Get mouse-pointer location. */
1611 const QPoint &cpnt = viewportToContents(pEvent->pos());
1612
1613 /* Ask the guest for moving the drop cursor. */
1614 Qt::DropAction result = m_pDnDHandler->dragMove(screenId(),
1615 frameBuffer()->convertHostXTo(cpnt.x()),
1616 frameBuffer()->convertHostYTo(cpnt.y()),
1617 pEvent->proposedAction(),
1618 pEvent->possibleActions(),
1619 pEvent->mimeData());
1620
1621 /* Set the DnD action returned by the guest. */
1622 pEvent->setDropAction(result);
1623 pEvent->accept();
1624 }
1625
1626 DNDDEBUG(("DnD: dragMoveEvent ended with rc=%Rrc\n", rc));
1627}
1628
1629void UIMachineView::dragLeaveEvent(QDragLeaveEvent *pEvent)
1630{
1631 AssertPtrReturnVoid(pEvent);
1632
1633 int rc = dragAndDropCanAccept() ? VINF_SUCCESS : VERR_ACCESS_DENIED;
1634 if (RT_SUCCESS(rc))
1635 {
1636 m_pDnDHandler->dragLeave(screenId());
1637
1638 pEvent->accept();
1639 }
1640
1641 DNDDEBUG(("DnD: dragLeaveEvent ended with rc=%Rrc\n", rc));
1642}
1643
1644int UIMachineView::dragCheckPending(void)
1645{
1646 int rc;
1647
1648 if (!dragAndDropIsActive())
1649 rc = VERR_ACCESS_DENIED;
1650#ifdef VBOX_WITH_DRAG_AND_DROP_GH
1651 else if (!m_fIsDraggingFromGuest)
1652 {
1653 /// @todo Add guest->guest DnD functionality here by getting
1654 // the source of guest B (when copying from B to A).
1655 rc = m_pDnDHandler->dragCheckPending(screenId());
1656 if (RT_SUCCESS(rc))
1657 m_fIsDraggingFromGuest = true;
1658 }
1659 else /* Already dragging, so report success. */
1660 rc = VINF_SUCCESS;
1661#else
1662 rc = VERR_NOT_SUPPORTED;
1663#endif
1664
1665 DNDDEBUG(("DnD: dragCheckPending ended with rc=%Rrc\n", rc));
1666 return rc;
1667}
1668
1669int UIMachineView::dragStart(void)
1670{
1671 int rc;
1672
1673 if (!dragAndDropIsActive())
1674 rc = VERR_ACCESS_DENIED;
1675#ifdef VBOX_WITH_DRAG_AND_DROP_GH
1676 else if (!m_fIsDraggingFromGuest)
1677 rc = VERR_WRONG_ORDER;
1678 else
1679 {
1680 /// @todo Add guest->guest DnD functionality here by getting
1681 // the source of guest B (when copying from B to A).
1682 rc = m_pDnDHandler->dragStart(screenId());
1683
1684 m_fIsDraggingFromGuest = false;
1685 }
1686#else
1687 rc = VERR_NOT_SUPPORTED;
1688#endif
1689
1690 DNDDEBUG(("DnD: dragStart ended with rc=%Rrc\n", rc));
1691 return rc;
1692}
1693
1694int UIMachineView::dragStop(void)
1695{
1696 int rc;
1697
1698 if (!dragAndDropIsActive())
1699 rc = VERR_ACCESS_DENIED;
1700#ifdef VBOX_WITH_DRAG_AND_DROP_GH
1701 else if (!m_fIsDraggingFromGuest)
1702 rc = VERR_WRONG_ORDER;
1703 else
1704 rc = m_pDnDHandler->dragStop(screenId());
1705#else
1706 rc = VERR_NOT_SUPPORTED;
1707#endif
1708
1709 DNDDEBUG(("DnD: dragStop ended with rc=%Rrc\n", rc));
1710 return rc;
1711}
1712
1713void UIMachineView::dropEvent(QDropEvent *pEvent)
1714{
1715 AssertPtrReturnVoid(pEvent);
1716
1717 int rc = dragAndDropCanAccept() ? VINF_SUCCESS : VERR_ACCESS_DENIED;
1718 if (RT_SUCCESS(rc))
1719 {
1720 /* Get mouse-pointer location. */
1721 const QPoint &cpnt = viewportToContents(pEvent->pos());
1722
1723 /* Ask the guest for dropping data. */
1724 Qt::DropAction result = m_pDnDHandler->dragDrop(screenId(),
1725 frameBuffer()->convertHostXTo(cpnt.x()),
1726 frameBuffer()->convertHostYTo(cpnt.y()),
1727 pEvent->proposedAction(),
1728 pEvent->possibleActions(),
1729 pEvent->mimeData());
1730
1731 /* Set the DnD action returned by the guest. */
1732 pEvent->setDropAction(result);
1733 pEvent->accept();
1734 }
1735
1736 DNDDEBUG(("DnD: dropEvent ended with rc=%Rrc\n", rc));
1737}
1738#endif /* VBOX_WITH_DRAG_AND_DROP */
1739
1740bool UIMachineView::nativeEventPreprocessor(const QByteArray &eventType, void *pMessage)
1741{
1742 /* Check if some event should be filtered out.
1743 * Returning @c true means filtering-out,
1744 * Returning @c false means passing event to Qt. */
1745
1746# if defined(VBOX_WS_MAC)
1747
1748 /* Make sure it's generic NSEvent: */
1749 if (eventType != "mac_generic_NSEvent")
1750 return false;
1751 EventRef event = static_cast<EventRef>(darwinCocoaToCarbonEvent(pMessage));
1752
1753 switch (::GetEventClass(event))
1754 {
1755 // Keep in mind that this stuff should not be enabled while we are still using
1756 // own native keyboard filter installed through cocoa API, to be reworked.
1757 // S.a. registerForNativeEvents call in UIKeyboardHandler implementation.
1758#if 0
1759 /* Watch for keyboard-events: */
1760 case kEventClassKeyboard:
1761 {
1762 switch (::GetEventKind(event))
1763 {
1764 /* Watch for key-events: */
1765 case kEventRawKeyDown:
1766 case kEventRawKeyRepeat:
1767 case kEventRawKeyUp:
1768 case kEventRawKeyModifiersChanged:
1769 {
1770 /* Delegate key-event handling to the keyboard-handler: */
1771 return machineLogic()->keyboardHandler()->nativeEventFilter(pMessage, screenId());
1772 }
1773 default:
1774 break;
1775 }
1776 break;
1777 }
1778#endif
1779 /* Watch for mouse-events: */
1780 case kEventClassMouse:
1781 {
1782 switch (::GetEventKind(event))
1783 {
1784 /* Watch for button-events: */
1785 case kEventMouseDown:
1786 case kEventMouseUp:
1787 {
1788 /* Delegate button-event handling to the mouse-handler: */
1789 return machineLogic()->mouseHandler()->nativeEventFilter(pMessage, screenId());
1790 }
1791 default:
1792 break;
1793 }
1794 break;
1795 }
1796 default:
1797 break;
1798 }
1799
1800# elif defined(VBOX_WS_WIN)
1801
1802 /* Make sure it's generic MSG event: */
1803 if (eventType != "windows_generic_MSG")
1804 return false;
1805 MSG *pEvent = static_cast<MSG*>(pMessage);
1806
1807 switch (pEvent->message)
1808 {
1809 /* Watch for key-events: */
1810 case WM_KEYDOWN:
1811 case WM_SYSKEYDOWN:
1812 case WM_KEYUP:
1813 case WM_SYSKEYUP:
1814 {
1815 // WORKAROUND:
1816 // There is an issue in the Windows Qt5 event processing sequence
1817 // causing QAbstractNativeEventFilter to receive Windows native events
1818 // coming not just to the top-level window but to actual target as well.
1819 // They are calling one - "global event" and another one - "context event".
1820 // That way native events are always duplicated with almost no possibility
1821 // to distinguish copies except the fact that synthetic event always have
1822 // time set to 0 (actually that field was not initialized at all, we had
1823 // fixed that in our private Qt tool). We should skip such events instantly.
1824 if (pEvent->time == 0)
1825 return false;
1826
1827 /* Delegate key-event handling to the keyboard-handler: */
1828 return machineLogic()->keyboardHandler()->nativeEventFilter(pMessage, screenId());
1829 }
1830 default:
1831 break;
1832 }
1833
1834# elif defined(VBOX_WS_X11)
1835
1836 /* Make sure it's generic XCB event: */
1837 if (eventType != "xcb_generic_event_t")
1838 return false;
1839 xcb_generic_event_t *pEvent = static_cast<xcb_generic_event_t*>(pMessage);
1840
1841 switch (pEvent->response_type & ~0x80)
1842 {
1843 /* Watch for key-events: */
1844 case XCB_KEY_PRESS:
1845 case XCB_KEY_RELEASE:
1846 {
1847 /* Delegate key-event handling to the keyboard-handler: */
1848 return machineLogic()->keyboardHandler()->nativeEventFilter(pMessage, screenId());
1849 }
1850 /* Watch for button-events: */
1851 case XCB_BUTTON_PRESS:
1852 case XCB_BUTTON_RELEASE:
1853 {
1854 /* Delegate button-event handling to the mouse-handler: */
1855 return machineLogic()->mouseHandler()->nativeEventFilter(pMessage, screenId());
1856 }
1857 default:
1858 break;
1859 }
1860
1861# else
1862
1863# warning "port me!"
1864
1865# endif
1866
1867 /* Filter nothing by default: */
1868 return false;
1869}
1870
1871QSize UIMachineView::scaledForward(QSize size) const
1872{
1873 /* Take the scale-factor into account: */
1874 const double dScaleFactor = frameBuffer()->scaleFactor();
1875 if (dScaleFactor != 1.0)
1876 size = QSize((int)(size.width() * dScaleFactor), (int)(size.height() * dScaleFactor));
1877
1878 /* Take the device-pixel-ratio into account: */
1879 const double dDevicePixelRatioFormal = frameBuffer()->devicePixelRatio();
1880 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
1881 if (!frameBuffer()->useUnscaledHiDPIOutput())
1882 size = QSize(size.width() * dDevicePixelRatioActual, size.height() * dDevicePixelRatioActual);
1883 size = QSize(size.width() / dDevicePixelRatioFormal, size.height() / dDevicePixelRatioFormal);
1884
1885 /* Return result: */
1886 return size;
1887}
1888
1889QSize UIMachineView::scaledBackward(QSize size) const
1890{
1891 /* Take the device-pixel-ratio into account: */
1892 const double dDevicePixelRatioFormal = frameBuffer()->devicePixelRatio();
1893 const double dDevicePixelRatioActual = frameBuffer()->devicePixelRatioActual();
1894 size = QSize(size.width() * dDevicePixelRatioFormal, size.height() * dDevicePixelRatioFormal);
1895 if (!frameBuffer()->useUnscaledHiDPIOutput())
1896 size = QSize(size.width() / dDevicePixelRatioActual, size.height() / dDevicePixelRatioActual);
1897
1898 /* Take the scale-factor into account: */
1899 const double dScaleFactor = frameBuffer()->scaleFactor();
1900 if (dScaleFactor != 1.0)
1901 size = QSize((int)(size.width() / dScaleFactor), (int)(size.height() / dScaleFactor));
1902
1903 /* Return result: */
1904 return size;
1905}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use