diff options
author | Anders Bakken <anders.bakken@nokia.com> | 2009-07-22 16:50:49 (GMT) |
---|---|---|
committer | Anders Bakken <anders.bakken@nokia.com> | 2009-07-22 17:34:19 (GMT) |
commit | eb6fa7e03a5c91e3da93d0c6203d9bad52dfcbb9 (patch) | |
tree | 3b2bd86168318f29cf5966468a2729255f02492e /src/plugins | |
parent | 95baddfc2f5dc719188f52519c95206959983206 (diff) | |
download | Qt-eb6fa7e03a5c91e3da93d0c6203d9bad52dfcbb9.zip Qt-eb6fa7e03a5c91e3da93d0c6203d9bad52dfcbb9.tar.gz Qt-eb6fa7e03a5c91e3da93d0c6203d9bad52dfcbb9.tar.bz2 |
Fix dfbwindowsurface handling for offscreen mode
This patch vastly simplifies the geometry handling (setGeometry/move)
It also implements a mode in which DirectFB implementations that do not
support windows can use an offscreen buffer as its backing store.
Previously the only way to do this was to paint directly on the primary
surface. This didn't work when the dfb driver didn't support an
accelerated mouse cursor.
It also detects the situation when the cursor isn't accelerated and
takes care of painting it manually when needed.
Reviewed-by: Donald <qt-info@nokia.com>
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp | 268 | ||||
-rw-r--r-- | src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h | 10 |
2 files changed, 151 insertions, 127 deletions
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index 7dcf398..ed4b2d9 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -44,10 +44,10 @@ #include "qdirectfbpaintengine.h" #include <qwidget.h> +#include <qwindowsystem_qws.h> #include <qpaintdevice.h> #include <qvarlengtharray.h> - //#define QT_DIRECTFB_DEBUG_SURFACES 1 QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr) @@ -59,6 +59,11 @@ QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirect , flipFlags(flip) , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip) { +#ifdef QT_NO_DIRECTFB_WM + mode = Offscreen; +#else + mode = Window; +#endif setSurfaceFlags(Opaque | Buffered); #ifdef QT_DIRECTFB_TIMING frames = 0; @@ -75,11 +80,17 @@ QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirect , flipFlags(flip) , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip) { - onscreen = widget->testAttribute(Qt::WA_PaintOnScreen); - if (onscreen) + if (widget && widget->testAttribute(Qt::WA_PaintOnScreen)) { setSurfaceFlags(Opaque | RegionReserved); - else + mode = Primary; + } else { +#ifdef QT_NO_DIRECTFB_WM + mode = Offscreen; +#else + mode = Window; +#endif setSurfaceFlags(Opaque | Buffered); + } #ifdef QT_DIRECTFB_TIMING frames = 0; timer.start(); @@ -99,7 +110,7 @@ bool QDirectFBWindowSurface::isValid() const void QDirectFBWindowSurface::createWindow() { #ifdef QT_NO_DIRECTFB_LAYER -#warning QT_NO_DIRECTFB_LAYER requires QT_NO_DIRECTFB_WM +#error QT_NO_DIRECTFB_LAYER requires QT_NO_DIRECTFB_WM #else IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer(); if (!layer) @@ -129,8 +140,40 @@ void QDirectFBWindowSurface::createWindow() } #endif // QT_NO_DIRECTFB_WM -void QDirectFBWindowSurface::setGeometry(const QRect &rect, const QRegion &mask) +#ifndef QT_NO_DIRECTFB_WM +static DFBResult setGeometry(IDirectFBWindow *dfbWindow, const QRect &old, const QRect &rect) +{ + DFBResult result = DFB_OK; + const bool isMove = old.isEmpty() || rect.topLeft() != old.topLeft(); + const bool isResize = rect.size() != old.size(); + +#if (Q_DIRECTFB_VERSION >= 0x010000) + if (isResize && isMove) { + result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(), + rect.width(), rect.height()); + } else if (isResize) { + result = dfbWindow->Resize(dfbWindow, + rect.width(), rect.height()); + } else if (isMove) { + result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y()); + } +#else + if (isResize) { + result = dfbWindow->Resize(dfbWindow, + rect.width(), rect.height()); + } + if (isMove) { + result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y()); + } +#endif + return result; +} +#endif + +void QDirectFBWindowSurface::setGeometry(const QRect &rect) { + IDirectFBSurface *primarySurface = screen->dfbSurface(); + Q_ASSERT(primarySurface); if (rect.isNull()) { #ifndef QT_NO_DIRECTFB_WM if (dfbWindow) { @@ -138,22 +181,21 @@ void QDirectFBWindowSurface::setGeometry(const QRect &rect, const QRegion &mask) dfbWindow = 0; } #endif - if (dfbSurface && dfbSurface != screen->dfbSurface()) { - dfbSurface->Release(dfbSurface); + if (dfbSurface) { + if (dfbSurface != primarySurface) { + dfbSurface->Release(dfbSurface); + } dfbSurface = 0; } } else if (rect != geometry()) { + const QRect oldRect = geometry(); DFBResult result = DFB_OK; - // If we're in a resize, the surface shouldn't be locked Q_ASSERT((lockedImage == 0) || (rect.size() == geometry().size())); - - if (onscreen) { - IDirectFBSurface *primarySurface = screen->dfbSurface(); - Q_ASSERT(primarySurface); + switch (mode) { + case Primary: if (dfbSurface && dfbSurface != primarySurface) dfbSurface->Release(dfbSurface); - if (rect == screen->region().boundingRect()) { dfbSurface = primarySurface; } else { @@ -161,58 +203,32 @@ void QDirectFBWindowSurface::setGeometry(const QRect &rect, const QRegion &mask) rect.width(), rect.height() }; result = primarySurface->GetSubSurface(primarySurface, &r, &dfbSurface); } - } else { - const bool isResize = rect.size() != geometry().size(); -#ifdef QT_NO_DIRECTFB_WM - if (isResize) { + break; + case Window: +#ifndef QT_NO_DIRECTFB_WM + if (!dfbWindow) + createWindow(); + ::setGeometry(dfbWindow, oldRect, rect); + // ### do I need to release and get the surface again here? +#endif + break; + case Offscreen: { + if (!dfbSurface || oldRect.size() != rect.size()) { if (dfbSurface) dfbSurface->Release(dfbSurface); - - IDirectFB *dfb = screen->dfb(); - if (!dfb) { - qFatal("QDirectFBWindowSurface::setGeometry(): " - "Unable to get DirectFB handle!"); - } - dfbSurface = screen->createDFBSurface(rect.size(), screen->pixelFormat(), QDirectFBScreen::DontTrackSurface); - } else { - Q_ASSERT(dfbSurface); - } -#else - const QRect oldRect = geometry(); - const bool isMove = oldRect.isEmpty() || - rect.topLeft() != oldRect.topLeft(); - - if (!dfbWindow) - createWindow(); - -#if (Q_DIRECTFB_VERSION >= 0x010000) - if (isResize && isMove) { - result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(), - rect.width(), rect.height()); - } else if (isResize) { - result = dfbWindow->Resize(dfbWindow, - rect.width(), rect.height()); - } else if (isMove) { - result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y()); - } -#else - if (isResize) { - result = dfbWindow->Resize(dfbWindow, - rect.width(), rect.height()); } - if (isMove) { - result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y()); - } -#endif -#endif + const QRegion region = QRegion(oldRect.isEmpty() ? screen->region() : QRegion(oldRect)).subtracted(rect); + screen->erase(region); + screen->flipSurface(primarySurface, flipFlags, region, QPoint()); + break; } } if (result != DFB_OK) DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result); } - QWSWindowSurface::setGeometry(rect, mask); + QWSWindowSurface::setGeometry(rect); } QByteArray QDirectFBWindowSurface::permanentState() const @@ -254,7 +270,6 @@ static inline void scrollSurface(IDirectFBSurface *surface, const QRect &r, int surface->Blit(surface, surface, &rect, r.x() + dx, r.y() + dy); } - bool QDirectFBWindowSurface::scroll(const QRegion ®ion, int dx, int dy) { if (!dfbSurface || !(flipFlags & DSFLIP_BLIT) || region.isEmpty()) @@ -272,35 +287,13 @@ bool QDirectFBWindowSurface::scroll(const QRegion ®ion, int dx, int dy) return true; } -bool QDirectFBWindowSurface::move(const QPoint &offset) -{ - QWSWindowSurface::move(offset); - -#ifdef QT_NO_DIRECTFB_WM - return true; // buffered -#else - if (!dfbWindow) - return false; - - DFBResult status = dfbWindow->Move(dfbWindow, offset.x(), offset.y()); - return (status == DFB_OK); -#endif -} - -QRegion QDirectFBWindowSurface::move(const QPoint &offset, const QRegion &newClip) +bool QDirectFBWindowSurface::move(const QPoint &moveBy) { -#ifdef QT_NO_DIRECTFB_WM - return QWSWindowSurface::move(offset, newClip); -#else - Q_UNUSED(offset); - Q_UNUSED(newClip); - - // DirectFB handles the entire move, so there's no need to blit. - return QRegion(); -#endif + setGeometry(geometry().translated(moveBy)); + return true; } -QPaintEngine* QDirectFBWindowSurface::paintEngine() const +QPaintEngine *QDirectFBWindowSurface::paintEngine() const { if (!engine) { QDirectFBWindowSurface *that = const_cast<QDirectFBWindowSurface*>(this); @@ -333,57 +326,86 @@ inline bool isWidgetOpaque(const QWidget *w) return false; } -void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion ®ion, + +void QDirectFBWindowSurface::flush(QWidget *, const QRegion ®ion, const QPoint &offset) { - Q_UNUSED(widget); -#ifdef QT_NO_DIRECTFB_WM - Q_UNUSED(region); - Q_UNUSED(offset); -#endif - - QWidget *win = window(); - // hw: make sure opacity information is updated before compositing - const bool opaque = isWidgetOpaque(win); - if (opaque != isOpaque()) { - SurfaceFlags flags = Buffered; - if (opaque) - flags |= Opaque; - setSurfaceFlags(flags); - } + if (QWidget *win = window()) { + + const bool opaque = isWidgetOpaque(win); + if (opaque != isOpaque()) { + SurfaceFlags flags = surfaceFlags(); + if (opaque) { + flags |= Opaque; + } else { + flags &= ~Opaque; + } + setSurfaceFlags(flags); + } #ifndef QT_NO_DIRECTFB_WM - const quint8 winOpacity = quint8(win->windowOpacity() * 255); - quint8 opacity; + const quint8 winOpacity = quint8(win->windowOpacity() * 255); + quint8 opacity; - if (dfbWindow) { - dfbWindow->GetOpacity(dfbWindow, &opacity); - if (winOpacity != opacity) - dfbWindow->SetOpacity(dfbWindow, winOpacity); - } + if (dfbWindow) { + dfbWindow->GetOpacity(dfbWindow, &opacity); + if (winOpacity != opacity) + dfbWindow->SetOpacity(dfbWindow, winOpacity); + } #endif - if (!(flipFlags & DSFLIP_BLIT)) { - dfbSurface->Flip(dfbSurface, 0, flipFlags); - } else { - if (!boundingRectFlip && region.numRects() > 1) { + } + + if (mode == Offscreen) { + IDirectFBSurface *primarySurface = screen->dfbSurface(); + primarySurface->SetBlittingFlags(primarySurface, DSBLIT_NOFX); + const QRect windowGeometry = QDirectFBWindowSurface::geometry(); + const QRect windowRect(0, 0, windowGeometry.width(), windowGeometry.height()); + if (boundingRectFlip || region.numRects() == 1) { + const QRect regionBoundingRect = region.boundingRect().translated(offset); + const QRect source = windowRect & regionBoundingRect; + const DFBRectangle rect = { + source.x(), source.y(), source.width(), source.height() + }; + primarySurface->Blit(primarySurface, dfbSurface, &rect, + windowGeometry.x() + source.x(), + windowGeometry.y() + source.y()); + } else { const QVector<QRect> rects = region.rects(); - const DFBSurfaceFlipFlags nonWaitFlags = flipFlags & ~DSFLIP_WAIT; - for (int i=0; i<rects.size(); ++i) { - const QRect &r = rects.at(i); - const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(), - r.x() + r.width() + offset.x(), - r.y() + r.height() + offset.y() }; - dfbSurface->Flip(dfbSurface, &dfbReg, i + 1 < rects.size() ? nonWaitFlags : flipFlags); + const int count = rects.size(); + for (int i=0; i<count; ++i) { + const QRect &r = rects.at(i).translated(offset); + const QRect source = windowRect & r; + const DFBRectangle rect = { + source.x(), source.y(), source.width(), source.height() + }; + primarySurface->Blit(primarySurface, dfbSurface, &rect, + windowGeometry.x() + source.x(), + windowGeometry.y() + source.y()); } - } else { - const QRect r = region.boundingRect(); - const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(), - r.x() + r.width() + offset.x(), - r.y() + r.height() + offset.y() }; - dfbSurface->Flip(dfbSurface, &dfbReg, flipFlags); } + if (QScreenCursor *cursor = QScreenCursor::instance()) { + const QRect cursorRectangle = cursor->boundingRect(); + if (cursor->isVisible() && !cursor->isAccelerated() + && region.intersects(cursorRectangle.translated(-(offset + windowGeometry.topLeft())))) { + const QImage image = cursor->image(); + + IDirectFBSurface *surface = screen->createDFBSurface(image, QDirectFBScreen::DontTrackSurface); + primarySurface->SetBlittingFlags(primarySurface, DSBLIT_BLEND_ALPHACHANNEL); + primarySurface->Blit(primarySurface, surface, 0, cursorRectangle.x(), cursorRectangle.y()); + surface->Release(surface); +#if (Q_DIRECTFB_VERSION >= 0x010000) + primarySurface->ReleaseSource(primarySurface); +#endif + } + } + + screen->flipSurface(primarySurface, flipFlags, region, offset + windowGeometry.topLeft()); + } else { + screen->flipSurface(dfbSurface, flipFlags, region, offset); } + + #ifdef QT_DIRECTFB_TIMING enum { Secs = 3 }; ++frames; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h index 7885b73..c46d93b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h @@ -67,7 +67,7 @@ public: bool isValid() const; - void setGeometry(const QRect &rect, const QRegion &mask); + void setGeometry(const QRect &rect); QString key() const { return QLatin1String("directfb"); } QByteArray permanentState() const; @@ -76,7 +76,6 @@ public: bool scroll(const QRegion &area, int dx, int dy); bool move(const QPoint &offset); - QRegion move(const QPoint &offset, const QRegion &newClip); QImage image() const { return QImage(); } QPaintDevice *paintDevice() { return this; } @@ -88,7 +87,6 @@ public: void endPaint(const QRegion &); QImage *buffer(const QWidget *widget); - private: #ifndef QT_NO_DIRECTFB_WM void createWindow(); @@ -96,7 +94,11 @@ private: #endif QDirectFBPaintEngine *engine; - bool onscreen; + enum Mode { + Primary, + Offscreen, + Window + } mode; QList<QImage*> bufferImages; DFBSurfaceFlipFlags flipFlags; |