xcb: support nested paint operations in remote scenarios

Recent changes to the xcb platform plugin added logic to paint to a
server-side X Pixmap when the MIT-SHM extension is unavailable. Those
changes also added logic to keep track of the dirty areas that need to
be flushed to the server from the backing store when the backing store
is flushed to a window.

Because a single QRegion was used to track those areas, nested paint
operations no longer accurately tracked all the dirty areas. Consider:

void Widget::paintEvent(QPaintEvent *) {
    QPainter p1(this);

    for (int i = 0; longRunningOperationInProgress(); i++) {
        QPixmap pixmap(size());
        QPainter p2(&pixmap);
        p2.drawText(pixmap.rect(), i & 1 ? "Working." : "Working..");
        p2.end();
        QBackingStore *bs = backingStore();
        bs->beginPaint(rect());
        p1.drawPixmap(0, 0, pixmap);
        bs->endPaint();
        bs->flush(rect(), windowHandle());
    }

    p1.fillRect(rect(), Qt::red);
    p1.drawText(rect(), "Done!");
}

While this code could be restructured, it is a common pattern in legacy
Qt applications which cannot be easily changed.

Change-Id: I3b919266abe41c96a584cb02f41cafac3f9d1d7c
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
bb10
Louai Al-Khanji 2016-04-28 10:24:38 -07:00 committed by Louai Al-Khanji
parent cd1eff1e1e
commit a1fd5d02bd
2 changed files with 14 additions and 5 deletions

View File

@ -525,13 +525,13 @@ void QXcbBackingStore::beginPaint(const QRegion &region)
if (!m_image)
return;
m_paintRegion = region;
m_image->preparePaint(m_paintRegion);
m_paintRegions.push(region);
m_image->preparePaint(region);
if (m_image->hasAlpha()) {
QPainter p(paintDevice());
p.setCompositionMode(QPainter::CompositionMode_Source);
const QVector<QRect> rects = m_paintRegion.rects();
const QVector<QRect> rects = region.rects();
const QColor blank = Qt::transparent;
for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
p.fillRect(*it, blank);
@ -541,13 +541,21 @@ void QXcbBackingStore::beginPaint(const QRegion &region)
void QXcbBackingStore::endPaint()
{
if (Q_UNLIKELY(m_paintRegions.isEmpty())) {
qWarning("%s: paint regions empty!", Q_FUNC_INFO);
return;
}
const QRegion region = m_paintRegions.pop();
m_image->preparePaint(region);
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window()->handle());
if (!platformWindow || !platformWindow->imageNeedsRgbSwap())
return;
// Slow path: the paint device was m_rgbImage. Now copy with swapping red
// and blue into m_image.
const QVector<QRect> rects = m_paintRegion.rects();
const QVector<QRect> rects = region.rects();
if (rects.isEmpty())
return;
QPainter p(m_image->image());

View File

@ -41,6 +41,7 @@
#define QXCBBACKINGSTORE_H
#include <qpa/qplatformbackingstore.h>
#include <QtCore/QStack>
#include <xcb/xcb.h>
@ -75,7 +76,7 @@ public:
private:
QXcbShmImage *m_image;
QRegion m_paintRegion;
QStack<QRegion> m_paintRegions;
QImage m_rgbImage;
};