VirtualBox

Changeset 46255 in vbox for trunk/src/VBox/Frontends


Ignore:
Timestamp:
May 24, 2013 12:44:24 PM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
85987
Message:

FE/Qt: 6749: Runtime UI: QImage frame-buffer: Support for embedded clipping (which required by the seamless-mode) under Win/Mac hosts.

Location:
trunk/src/VBox/Frontends/VirtualBox/src/runtime
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.h

    r46129 r46255  
    216216    virtual void resizeEvent(UIResizeEvent *pEvent) = 0;
    217217    virtual void paintEvent(QPaintEvent *pEvent) = 0;
     218    virtual void applyVisibleRegionEvent(UISetRegionEvent *pEvent) = 0;
    218219
    219220#ifdef VBOX_WITH_VIDEOHWACCEL
     
    236237    ulong m_width;
    237238    ulong m_height;
     239    QRegion m_visibleRegion;
    238240    QSize m_scaledSize;
    239241    int64_t m_WinId;
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBufferQImage.cpp

    r46120 r46255  
    3434# include "VBoxGlobal.h"
    3535# include "UISession.h"
     36# include "UIMachineLogic.h"
     37# ifdef Q_WS_X11
     38#  include "UIMachineWindow.h"
     39# endif /* Q_WS_X11 */
    3640
    3741/* COM includes: */
     
    5155void UIFrameBufferQImage::resizeEvent(UIResizeEvent *pEvent)
    5256{
    53 #if 0
    54     LogFlowFunc (("fmt=%d, vram=%p, bpp=%d, bpl=%d, width=%d, height=%d\n",
    55                   pEvent->pixelFormat(), pEvent->VRAM(),
    56                   pEvent->bitsPerPixel(), pEvent->bytesPerLine(),
    57                   pEvent->width(), pEvent->height()));
    58 #endif
     57    /* Invalidate visible-region if necessary: */
     58    if (m_width != pEvent->width() ||
     59        m_height != pEvent->height())
     60        m_visibleRegion = QRegion();
    5961
    6062    /* Remember new width/height: */
     
    156158        goFallback();
    157159
    158     /* Scaled image by default is empty: */
     160    /* Depending on visual-state type: */
     161    switch (m_pMachineView->machineLogic()->visualStateType())
     162    {
     163        case UIVisualStateType_Seamless:
     164            paintSeamless(pEvent);
     165            break;
     166        case UIVisualStateType_Scale:
     167            paintScale(pEvent);
     168            break;
     169        default:
     170            paintDefault(pEvent);
     171            break;
     172    }
     173}
     174
     175void UIFrameBufferQImage::applyVisibleRegionEvent(UISetRegionEvent *pEvent)
     176{
     177    /* Make sure visible-region changed: */
     178    if (m_visibleRegion == pEvent->region())
     179        return;
     180
     181    /* Compose viewport region to update: */
     182    QRegion toUpdate = pEvent->region() + m_visibleRegion;
     183    /* Remember new visible-region: */
     184    m_visibleRegion = pEvent->region();
     185    /* Update viewport region finally: */
     186    m_pMachineView->viewport()->update(toUpdate);
     187#ifdef Q_WS_X11
     188    /* Qt 4.8.3 under X11 has Qt::WA_TranslucentBackground window attribute broken,
     189     * so we are still have to use old one known Xshape extension wrapped by the widget setMask API: */
     190    m_pMachineView->machineWindow()->setMask(m_visibleRegion);
     191#endif /* Q_WS_X11 */
     192}
     193
     194void UIFrameBufferQImage::paintDefault(QPaintEvent *pEvent)
     195{
     196    /* Get rectangle to paint: */
     197    QRect paintRect = pEvent->rect().intersected(m_img.rect());
     198    if (paintRect.isEmpty())
     199        return;
     200
     201    /* Create painter: */
     202    QPainter painter(m_pMachineView->viewport());
     203
     204    /* Draw image rectangle depending on rectangle width: */
     205    if ((ulong)paintRect.width() < m_width * 2 / 3)
     206        drawImageRectNarrow(painter, m_img,
     207                            paintRect, m_pMachineView->contentsX(), m_pMachineView->contentsY());
     208    else
     209        drawImageRectWide(painter, m_img,
     210                          paintRect, m_pMachineView->contentsX(), m_pMachineView->contentsY());
     211}
     212
     213void UIFrameBufferQImage::paintSeamless(QPaintEvent *pEvent)
     214{
     215    /* Get rectangle to paint: */
     216    QRect paintRect = pEvent->rect().intersected(m_img.rect());
     217    if (paintRect.isEmpty())
     218        return;
     219
     220    /* Create painter: */
     221    QPainter painter(m_pMachineView->viewport());
     222
     223    /* Clear paint rectangle first: */
     224    painter.setCompositionMode(QPainter::CompositionMode_Clear);
     225    painter.eraseRect(paintRect);
     226    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
     227
     228    /* Repaint all the rectangles of visible-region: */
     229    QRegion visiblePaintRegion = m_visibleRegion & paintRect;
     230    foreach (const QRect &rect, visiblePaintRegion.rects())
     231    {
     232#ifdef Q_WS_WIN
     233        /* Replace translucent background with black one,
     234         * that is necessary for window with Qt::WA_TranslucentBackground: */
     235        painter.setCompositionMode(QPainter::CompositionMode_Source);
     236        painter.fillRect(rect, QColor(Qt::black));
     237        painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
     238#endif /* Q_WS_WIN */
     239
     240        /* Draw image rectangle depending on rectangle width: */
     241        if ((ulong)rect.width() < m_width * 2 / 3)
     242            drawImageRectNarrow(painter, m_img,
     243                                rect, m_pMachineView->contentsX(), m_pMachineView->contentsY());
     244        else
     245            drawImageRectWide(painter, m_img,
     246                              rect, m_pMachineView->contentsX(), m_pMachineView->contentsY());
     247    }
     248}
     249
     250void UIFrameBufferQImage::paintScale(QPaintEvent *pEvent)
     251{
     252    /* Scaled image is NULL by default: */
    159253    QImage scaledImage;
    160     /* If scaled-factor is set and current image is NOT null: */
     254    /* But if scaled-factor is set and current image is NOT null: */
    161255    if (m_scaledSize.isValid() && !m_img.isNull())
    162256    {
    163         /* We are doing a deep copy of image to make sure it will not be
     257        /* We are doing a deep copy of the image to make sure it will not be
    164258         * detached during scale process, otherwise we can get a frozen frame-buffer. */
    165259        scaledImage = m_img.copy();
    166         /* Scale image to scaled-factor: */
     260        /* And scaling the image to predefined scaled-factor: */
    167261        scaledImage = scaledImage.scaled(m_scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    168262    }
    169     /* Choose required image: */
    170     QImage *pSourceImage = scaledImage.isNull() ? &m_img : &scaledImage;
    171 
    172     /* Get clipping rectangle: */
    173     const QRect &r = pEvent->rect().intersected(pSourceImage->rect());
    174     if (r.isEmpty())
    175         return;
    176 
    177 #if 0
    178     LogFlowFunc (("%dx%d-%dx%d (img=%dx%d)\n", r.x(), r.y(), r.width(), r.height(), img.width(), img.height()));
    179 #endif
     263    /* Finally we are choosing image to paint from: */
     264    QImage &sourceImage = scaledImage.isNull() ? m_img : scaledImage;
     265
     266    /* Get rectangle to paint: */
     267    QRect paintRect = pEvent->rect().intersected(sourceImage.rect());
     268    if (paintRect.isEmpty())
     269        return;
    180270
    181271    /* Create painter: */
    182272    QPainter painter(m_pMachineView->viewport());
    183     if ((ulong)r.width() < m_width * 2 / 3)
    184     {
    185         /* This method is faster for narrow updates: */
    186         m_PM = QPixmap::fromImage(pSourceImage->copy(r.x() + m_pMachineView->contentsX(),
    187                                                      r.y() + m_pMachineView->contentsY(),
    188                                                      r.width(), r.height()));
    189         painter.drawPixmap(r.x(), r.y(), m_PM);
    190     }
     273
     274    /* Draw image rectangle depending on rectangle width: */
     275    if ((ulong)paintRect.width() < m_width * 2 / 3)
     276        drawImageRectNarrow(painter, sourceImage,
     277                            paintRect, m_pMachineView->contentsX(), m_pMachineView->contentsY());
    191278    else
    192     {
    193         /* This method is faster for wide updates: */
    194         m_PM = QPixmap::fromImage(QImage(pSourceImage->scanLine(r.y() + m_pMachineView->contentsY()),
    195                                          pSourceImage->width(), r.height(), pSourceImage->bytesPerLine(),
    196                                          QImage::Format_RGB32));
    197         painter.drawPixmap(r.x(), r.y(), m_PM, r.x() + m_pMachineView->contentsX(), 0, 0, 0);
    198     }
     279        drawImageRectWide(painter, sourceImage,
     280                          paintRect, m_pMachineView->contentsX(), m_pMachineView->contentsY());
     281}
     282
     283/* static */
     284void UIFrameBufferQImage::drawImageRectNarrow(QPainter &painter, const QImage &image,
     285                                              const QRect &rect, int iContentsShiftX, int iContentsShiftY)
     286{
     287    /* This method is faster for narrow updates: */
     288    QPixmap pm = QPixmap::fromImage(image.copy(rect.x() + iContentsShiftX,
     289                                               rect.y() + iContentsShiftY,
     290                                               rect.width(), rect.height()));
     291    painter.drawPixmap(rect.x(), rect.y(), pm);
     292}
     293
     294/* static */
     295void UIFrameBufferQImage::drawImageRectWide(QPainter &painter, const QImage &image,
     296                                            const QRect &rect, int iContentsShiftX, int /*iContentsShiftY*/)
     297{
     298    /* This method is faster for wide updates: */
     299    QPixmap pm = QPixmap::fromImage(QImage(image.scanLine(rect.y() + iContentsShiftX),
     300                                           image.width(), rect.height(), image.bytesPerLine(),
     301                                           QImage::Format_RGB32));
     302    painter.drawPixmap(rect.x(), rect.y(), pm, rect.x() + iContentsShiftX, 0, 0, 0);
    199303}
    200304
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBufferQImage.h

    r46064 r46255  
    4747    void resizeEvent(UIResizeEvent *pEvent);
    4848    void paintEvent(QPaintEvent *pEvent);
     49    void applyVisibleRegionEvent(UISetRegionEvent *pEvent);
    4950
    5051private:
     52
     53    /* Helpers: Visual-mode paint stuff: */
     54    void paintDefault(QPaintEvent *pEvent);
     55    void paintSeamless(QPaintEvent *pEvent);
     56    void paintScale(QPaintEvent *pEvent);
     57
     58    /* Static helpers: Drawing stuff: */
     59    static void drawImageRectNarrow(QPainter &painter, const QImage &image,
     60                                    const QRect &rect, int iContentsShiftX, int iContentsShiftY);
     61    static void drawImageRectWide(QPainter &painter, const QImage &image,
     62                                  const QRect &rect, int iContentsShiftX, int iContentsShiftY);
    5163
    5264    /* Helper: Fallback stuff: */
     
    5466
    5567    /* Variables: */
    56     QPixmap m_PM;
    5768    QImage m_img;
    5869    ulong m_uPixelFormat;
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBufferQuartz2D.cpp

    r46120 r46255  
    77
    88/*
    9  * Copyright (C) 2006-2012 Oracle Corporation
     9 * Copyright (C) 2006-2013 Oracle Corporation
    1010 *
    1111 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    463463}
    464464
     465void UIFrameBufferQuartz2D::applyVisibleRegionEvent(UISetRegionEvent *pEvent)
     466{
     467    /* Make sure visible-region changed: */
     468    if (m_visibleRegion == pEvent->region())
     469        return;
     470
     471    /* Remember new visible-region: */
     472    m_visibleRegion = pEvent->region();
     473    /* Invalidate whole the viewport: */
     474    ::darwinWindowInvalidateShape(m_pMachineView->viewport());
     475}
     476
    465477void UIFrameBufferQuartz2D::clean(bool fPreserveRegions)
    466478{
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBufferQuartz2D.h

    r46120 r46255  
    5050    void resizeEvent(UIResizeEvent *pEvent);
    5151    void paintEvent(QPaintEvent *pEvent);
     52    void applyVisibleRegionEvent(UISetRegionEvent *pEvent);
    5253
    5354#ifdef VBOX_WITH_VIDEOHWACCEL
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp

    r46225 r46255  
    8585        {
    8686            /* Apply new seamless-region: */
    87             UISetRegionEvent *pSetRegionEvent = static_cast<UISetRegionEvent*>(pEvent);
    88             m_lastVisibleRegion = pSetRegionEvent->region();
    89             machineWindow()->setMask(m_lastVisibleRegion);
     87            m_pFrameBuffer->applyVisibleRegionEvent(static_cast<UISetRegionEvent*>(pEvent));
    9088            return true;
    9189        }
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.h

    r46020 r46255  
    66
    77/*
    8  * Copyright (C) 2010-2011 Oracle Corporation
     8 * Copyright (C) 2010-2013 Oracle Corporation
    99 *
    1010 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2626{
    2727    Q_OBJECT;
    28 
    29 public:
    30 
    31     /* Public getters: */
    32     QRegion lastVisibleRegion() const { return m_lastVisibleRegion; }
    3328
    3429protected:
     
    7267    QSize calculateMaxGuestSize() const;
    7368
    74     /* Private variables: */
    75     QRegion m_lastVisibleRegion;
    76 
    7769    /* Friend classes: */
    7870    friend class UIMachineView;
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp

    r46244 r46255  
    8787    UIMachineWindow::prepareVisualState();
    8888
    89     /* This might be required to correctly mask: */
    90     centralWidget()->setAutoFillBackground(false);
     89#ifdef Q_WS_WIN
     90    /* Enable translucent background for Win host,
     91     * Mac host has it native, Qt 4.8.3 under x11 host has is broken: */
     92    setAttribute(Qt::WA_TranslucentBackground);
     93#endif /* Q_WS_WIN */
    9194
    9295#ifdef Q_WS_MAC
     
    270273#endif /* Q_WS_MAC */
    271274
    272 void UIMachineWindowSeamless::setMask(const QRegion &incomingRegion)
    273 {
    274     /* Copy region: */
    275     QRegion region(incomingRegion);
    276 
    277 #ifndef Q_WS_MAC
     275#ifdef Q_WS_WIN
     276void UIMachineWindowSeamless::showEvent(QShowEvent*)
     277{
     278    /* Following workaround allows to fix the next Qt BUG:
     279     * https://bugreports.qt-project.org/browse/QTBUG-17548
     280     * https://bugreports.qt-project.org/browse/QTBUG-30974
     281     * Widgets with Qt::WA_TranslucentBackground attribute
     282     * stops repainting after minimizing/restoring, we have to call for single update. */
     283    QApplication::postEvent(this, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
     284}
     285#endif /* Q_WS_WIN */
     286
     287#ifdef Q_WS_X11
     288void UIMachineWindowSeamless::setMask(const QRegion &region)
     289{
     290    /* Prepare mask-region: */
     291    QRegion maskRegion(region);
     292
    278293    /* Shift region if left spacer width is NOT zero or top spacer height is NOT zero: */
    279294    if (m_pLeftSpacer->geometry().width() || m_pTopSpacer->geometry().height())
    280         region.translate(m_pLeftSpacer->geometry().width(), m_pTopSpacer->geometry().height());
    281 #endif /* !Q_WS_MAC */
    282 
    283 #ifdef VBOX_GUI_USE_QUARTZ2D
    284     if (vboxGlobal().vmRenderMode() == Quartz2DMode)
    285     {
    286         /* If we are using the Quartz2D backend we have to trigger a repaint only.
    287          * All the magic clipping stuff is done in the paint engine. */
    288         ::darwinWindowInvalidateShape(m_pMachineView->viewport());
    289     }
    290 #else /* VBOX_GUI_USE_QUARTZ2D */
     295        maskRegion.translate(m_pLeftSpacer->geometry().width(), m_pTopSpacer->geometry().height());
     296
    291297    /* Seamless-window for empty region should be empty too,
    292      * but native API wrapped by the QWidget::setMask() doesn't allow this.
     298     * but the QWidget::setMask() wrapper doesn't allow this.
    293299     * Instead, we have a full painted screen of seamless-geometry size visible.
    294300     * Moreover, we can't just hide the empty seamless-window as 'hiding'
    295301     * 1. will collide with the multi-screen layout behavior and
    296302     * 2. will cause a task-bar flicker on moving window from one screen to another.
    297      * As a temporary though quite a dirty workaround we have to make sure
     303     * As a *temporary* though quite a dirty workaround we have to make sure
    298304     * region have at least one pixel. */
    299     if (region.isEmpty())
    300         region += QRect(0, 0, 1, 1);
    301     /* Make sure region had changed: */
    302     if (m_previousRegion != region)
    303     {
    304         /* Remember new region: */
    305         m_previousRegion = region;
    306         /* Assign new region: */
    307         UIMachineWindow::setMask(m_previousRegion);
    308         /* Update viewport contents: */
    309         m_pMachineView->viewport()->update();
    310     }
    311 #endif /* !VBOX_GUI_USE_QUARTZ2D */
    312 }
    313 
     305    if (maskRegion.isEmpty())
     306        maskRegion += QRect(0, 0, 1, 1);
     307    /* Make sure mask-region had changed: */
     308    if (m_maskRegion != maskRegion)
     309    {
     310        /* Compose viewport region to update: */
     311        QRegion toUpdate = m_maskRegion + maskRegion;
     312        /* Remember new mask-region: */
     313        m_maskRegion = maskRegion;
     314        /* Assign new mask-region: */
     315        UIMachineWindow::setMask(m_maskRegion);
     316        /* Update viewport region finally: */
     317        m_pMachineView->viewport()->update(toUpdate);
     318    }
     319}
     320#endif /* Q_WS_X11 */
     321
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h

    r46244 r46255  
    7979#endif /* Q_WS_MAC */
    8080
    81     /* Helpers: */
     81#ifdef Q_WS_WIN
     82    /* Handler: Translucency stuff: */
     83    void showEvent(QShowEvent *pEvent);
     84#endif /* Q_WS_WIN */
     85
     86#ifdef Q_WS_X11
     87    /* Helper: Masking stuff: */
    8288    void setMask(const QRegion &region);
     89#endif /* Q_WS_X11 */
    8390
    8491    /* Widgets: */
     
    8895#endif /* !Q_WS_MAC */
    8996
    90     /* Variables: */
    91     QRegion m_previousRegion;
     97#ifdef Q_WS_X11
     98    /* Variable: Masking stuff: */
     99    QRegion m_maskRegion;
     100#endif /* Q_WS_X11 */
    92101
    93102    /* Factory support: */
Note: See TracChangeset for help on using the changeset viewer.

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