VirtualBox

Ignore:
Timestamp:
Jun 24, 2014 2:04:57 PM (11 years ago)
Author:
vboxsync
Message:

FE/Qt: 7423: Selector UI: VM preview should keep guest-screen aspect ratio size bounded by preview frame.

Location:
trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.cpp

    r51531 r51708  
    131131void UIGMachinePreview::sltRecreatePreview()
    132132{
    133     /* Only do this if we are visible: */
     133    /* Skip invisible preview: */
    134134    if (!isVisible())
    135135        return;
    136136
    137     /* Cleanup preview first: */
     137    /* Cleanup previous image: */
    138138    if (m_pPreviewImg)
    139139    {
     
    142142    }
    143143
    144     /* Fetch the latest machine-state: */
    145     KMachineState machineState = m_machine.isNull() ? KMachineState_Null : m_machine.GetState();
     144    /* Fetch actual machine-state: */
     145    const KMachineState machineState = m_machine.isNull() ? KMachineState_Null : m_machine.GetState();
    146146
    147147    /* We are creating preview only for assigned and accessible VMs: */
     
    149149        m_vRect.width() > 0 && m_vRect.height() > 0)
    150150    {
    151         QImage image(size().toSize(), QImage::Format_ARGB32);
    152         image.fill(Qt::transparent);
    153         QPainter painter(&image);
    154         bool fDone = false;
    155 
    156         /* Preview enabled? */
     151        /* Prepare image: */
     152        QImage image;
     153
     154        /* Preview update enabled? */
    157155        if (m_pUpdateTimer->interval() > 0)
    158156        {
    159             /* Use the image which may be included in the save state. */
    160             if (machineState == KMachineState_Saved || machineState == KMachineState_Restoring)
     157            /* Depending on machine state: */
     158            switch (machineState)
    161159            {
    162                 ULONG width = 0, height = 0;
    163                 QVector<BYTE> screenData = m_machine.ReadSavedScreenshotPNGToArray(0, width, height);
    164                 if (screenData.size() != 0)
     160                /* If machine is in SAVED/RESTORING state: */
     161                case KMachineState_Saved:
     162                case KMachineState_Restoring:
    165163                {
    166                     QImage shot = QImage::fromData(screenData.data(), screenData.size(), "PNG")
    167                                   .scaled(m_vRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    168                     dimImage(shot);
    169                     painter.drawImage(m_vRect.x(), m_vRect.y(), shot);
    170                     fDone = true;
     164                    /* Use the screenshot from saved-state if possible: */
     165                    ULONG uWidth = 0, uHeight = 0;
     166                    QVector<BYTE> screenData = m_machine.ReadSavedScreenshotPNGToArray(0, uWidth, uHeight);
     167                    if (m_machine.isOk() && !screenData.isEmpty())
     168                    {
     169                        /* Create image based on shallow copy or screenshot data,
     170                         * scale image down if necessary to the size possible to reflect: */
     171                        image = QImage::fromData(screenData.data(), screenData.size(), "PNG")
     172                                .scaled(imageAspectRatioSize(m_vRect.size(), QSize(uWidth, uHeight)),
     173                                        Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
     174                        /* Dim image to give it required look: */
     175                        dimImage(image);
     176                    }
     177                    break;
    171178                }
    172             }
    173             /* Use the current VM output. */
    174             else if (machineState == KMachineState_Running || machineState == KMachineState_Paused)
    175             {
    176                 if (m_session.GetState() == KSessionState_Locked)
     179                /* If machine is in RUNNING/PAUSED state: */
     180                case KMachineState_Running:
     181                case KMachineState_Paused:
    177182                {
    178                     CVirtualBox vbox = vboxGlobal().virtualBox();
    179                     if (vbox.isOk())
     183                    /* Make sure session state is Locked: */
     184                    if (m_session.GetState() != KSessionState_Locked)
     185                        break;
     186
     187                    /* Make sure console is OK: */
     188                    CConsole console = m_session.GetConsole();
     189                    if (!m_session.isOk() || console.isNull())
     190                        break;
     191                    /* Make sure display is OK: */
     192                    CDisplay display = console.GetDisplay();
     193                    if (!console.isOk() || display.isNull())
     194                        break;
     195
     196                    /* Calculate aspect-ratio size: */
     197                    ULONG uGuestWidth, uGuestHeight, uBpp;
     198                    LONG iOriginX, iOriginY;
     199                    display.GetScreenResolution(0, uGuestWidth, uGuestHeight, uBpp, iOriginX, iOriginY);
     200                    const QSize size = imageAspectRatioSize(m_vRect.size(), QSize(uGuestWidth, uGuestHeight));
     201
     202                    /* Use direct VM content: */
     203                    QVector<BYTE> screenData = display.TakeScreenShotToArray(0, size.width(), size.height());
     204                    if (display.isOk() && !screenData.isEmpty())
    180205                    {
    181                         const CConsole& console = m_session.GetConsole();
    182                         if (!console.isNull())
     206                        /* Unfortunately we have to reorder the pixel data,
     207                         * cause the VBox API returns RGBA data,
     208                         * which is not a format QImage understand. */
     209                        uint32_t *pData = (uint32_t*)screenData.data();
     210                        for (int i = 0; i < screenData.size() / 4; ++i)
    183211                        {
    184                             CDisplay display = console.GetDisplay();
    185                             /* Todo: correct aspect radio */
    186 //                            ULONG w, h, bpp;
    187 //                            LONG xOrigin, yOrigin;
    188 //                            display.GetScreenResolution(0, w, h, bpp, xOrigin, yOrigin);
    189 //                            QImage shot = QImage(w, h, QImage::Format_RGB32);
    190 //                            shot.fill(Qt::black);
    191 //                            display.TakeScreenShot(0, shot.bits(), shot.width(), shot.height());
    192                             QVector<BYTE> screenData = display.TakeScreenShotToArray(0, m_vRect.width(), m_vRect.height());
    193                             if (display.isOk() && screenData.size() != 0)
    194                             {
    195                                 /* Unfortunately we have to reorder the pixel
    196                                  * data, cause the VBox API returns RGBA data,
    197                                  * which is not a format QImage understand.
    198                                  * Todo: check for 32bit alignment, for both
    199                                  * the data and the scanlines. Maybe we need to
    200                                  * copy the data in any case. */
    201                                 uint32_t *d = (uint32_t*)screenData.data();
    202                                 for (int i = 0; i < screenData.size() / 4; ++i)
    203                                 {
    204                                     uint32_t e = d[i];
    205                                     d[i] = RT_MAKE_U32_FROM_U8(RT_BYTE3(e), RT_BYTE2(e), RT_BYTE1(e), RT_BYTE4(e));
    206                                 }
    207 
    208                                 QImage shot = QImage((uchar*)d, m_vRect.width(), m_vRect.height(), QImage::Format_RGB32);
    209 
    210                                 if (machineState == KMachineState_Paused)
    211                                     dimImage(shot);
    212                                 painter.drawImage(m_vRect.x(), m_vRect.y(), shot);
    213                                 fDone = true;
    214                             }
     212                            uint32_t e = pData[i];
     213                            pData[i] = RT_MAKE_U32_FROM_U8(RT_BYTE3(e), RT_BYTE2(e), RT_BYTE1(e), RT_BYTE4(e));
    215214                        }
     215                        /* Create image based on shallow copy or reordered data: */
     216                        image = QImage((uchar*)pData, size.width(), size.height(), QImage::Format_RGB32);
     217                        /* Dim image to give it required look for PAUSED state: */
     218                        if (machineState == KMachineState_Paused)
     219                            dimImage(image);
    216220                    }
     221                    break;
    217222                }
     223                default:
     224                    break;
    218225            }
    219226        }
    220227
    221         if (fDone)
     228        /* If image initialized: */
     229        if (!image.isNull())
     230        {
     231            /* Shallow copy that image: */
    222232            m_pPreviewImg = new QImage(image);
    223     }
    224 
    225     /* Redraw preview in any case! */
     233            /* And detach that copy: */
     234            m_pPreviewImg->bits();
     235        }
     236    }
     237
     238    /* Redraw preview in any case: */
    226239    update();
    227240}
     
    285298    if (m_pPreviewImg)
    286299    {
    287         /* Draw empty background: */
     300        /* Draw black background: */
     301        pPainter->fillRect(m_vRect, Qt::black);
     302
     303        /* Draw empty monitor frame: */
    288304        pPainter->drawPixmap(cr.x() + m_iMargin, cr.y() + m_iMargin, *m_pbgEmptyImage);
    289305
    290         /* Draw that image: */
    291         pPainter->drawImage(0, 0, *m_pPreviewImg);
     306        /* Move image to viewport center: */
     307        QRect imageRect(QPoint(0, 0), m_pPreviewImg->size());
     308        imageRect.moveCenter(m_vRect.center());
     309        /* Draw preview image: */
     310        pPainter->drawImage(imageRect.topLeft(), *m_pPreviewImg);
    292311    }
    293312    else
    294313    {
    295         /* Draw full background: */
     314        /* Draw full monitor frame: */
    296315        pPainter->drawPixmap(cr.x() + m_iMargin, cr.y() + m_iMargin, *m_pbgFullImage);
    297316
     
    386405}
    387406
     407/* static */
     408QSize UIGMachinePreview::imageAspectRatioSize(const QSize &hostSize, const QSize &guestSize)
     409{
     410    /* Calculate host/guest aspect-ratio: */
     411    const double dHostAspectRatio = (double)hostSize.width() / hostSize.height();
     412    const double dGuestAspectRatio = (double)guestSize.width() / guestSize.height();
     413    int iWidth = 0, iHeight = 0;
     414    /* Guest-screen more thin by vertical than host-screen: */
     415    if (dGuestAspectRatio >= dHostAspectRatio)
     416    {
     417        /* Get host width: */
     418        iWidth = hostSize.width();
     419        /* And calculate height based on guest aspect ratio: */
     420        iHeight = (double)iWidth / dGuestAspectRatio;
     421        /* But no more than host height: */
     422        iHeight = qMin(iHeight, hostSize.height());
     423    }
     424    /* Host-screen more thin by vertical than guest-screen: */
     425    else
     426    {
     427        /* Get host height: */
     428        iHeight = hostSize.height();
     429        /* And calculate width based on guest aspect ratio: */
     430        iWidth = (double)iHeight * dGuestAspectRatio;
     431        /* But no more than host width: */
     432        iWidth = qMin(iWidth, hostSize.width());
     433    }
     434    /* Return actual size: */
     435    return QSize(iWidth, iHeight);
     436}
     437
  • trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.h

    r51531 r51708  
    9090    void stop();
    9191
     92    /** Calculates image size suitable to passed @a hostSize and @a guestSize. */
     93    static QSize imageAspectRatioSize(const QSize &hostSize, const QSize &guestSize);
     94
    9295    /* Variables: */
    9396    CSession m_session;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette