/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qdirectfbwindowsurface.h" #include "qdirectfbscreen.h" #include "qdirectfbpaintengine.h" #include #include #include #include #ifndef QT_NO_QWS_DIRECTFB QT_BEGIN_NAMESPACE QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr) : QDirectFBPaintDevice(scr) , sibling(0) #ifndef QT_NO_DIRECTFB_WM , dfbWindow(0) #endif , flipFlags(flip) , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip) { #ifdef QT_NO_DIRECTFB_WM mode = Offscreen; #endif setSurfaceFlags(Opaque | Buffered); #ifdef QT_DIRECTFB_TIMING frames = 0; timer.start(); #endif } QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget) : QWSWindowSurface(widget), QDirectFBPaintDevice(scr) , sibling(0) #ifndef QT_NO_DIRECTFB_WM , dfbWindow(0) #endif , flipFlags(flip) , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip) { #ifdef QT_NO_DIRECTFB_WM if (widget && widget->testAttribute(Qt::WA_PaintOnScreen)) { setSurfaceFlags(Opaque | RegionReserved); mode = Primary; } else { mode = Offscreen; setSurfaceFlags(Opaque | Buffered); } #else setSurfaceFlags(Opaque | Buffered); #endif #ifdef QT_DIRECTFB_TIMING frames = 0; timer.start(); #endif } QDirectFBWindowSurface::~QDirectFBWindowSurface() { releaseSurface(); // these are not tracked by QDirectFBScreen so we don't want QDirectFBPaintDevice to release it } bool QDirectFBWindowSurface::isValid() const { return true; } #ifdef QT_DIRECTFB_WM void QDirectFBWindowSurface::raise() { if (dfbWindow) { dfbWindow->RaiseToTop(dfbWindow); } else if (sibling && (!sibling->sibling || sibling->dfbWindow)) { sibling->raise(); } } void QDirectFBWindowSurface::createWindow(const QRect &rect) { IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer(); if (!layer) qFatal("QDirectFBWindowSurface: Unable to get primary display layer!"); DFBWindowDescription description; description.caps = DWCAPS_NODECORATION|DWCAPS_DOUBLEBUFFER; description.flags = DWDESC_CAPS|DWDESC_SURFACE_CAPS|DWDESC_PIXELFORMAT|DWDESC_HEIGHT|DWDESC_WIDTH|DWDESC_POSX|DWDESC_POSY; description.posx = rect.x(); description.posy = rect.y(); description.width = rect.width(); description.height = rect.height(); description.surface_caps = DSCAPS_NONE; if (screen->directFBFlags() & QDirectFBScreen::VideoOnly) description.surface_caps |= DSCAPS_VIDEOONLY; const QImage::Format format = screen->pixelFormat(); description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(format); if (QDirectFBScreen::isPremultiplied(format)) description.surface_caps = DSCAPS_PREMULTIPLIED; DFBResult result = layer->CreateWindow(layer, &description, &dfbWindow); if (result != DFB_OK) DirectFBErrorFatal("QDirectFBWindowSurface::createWindow", result); if (dfbSurface) dfbSurface->Release(dfbSurface); dfbWindow->GetSurface(dfbWindow, &dfbSurface); updateFormat(); } static DFBResult setWindowGeometry(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 // QT_NO_DIRECTFB_WM void QDirectFBWindowSurface::setGeometry(const QRect &rect) { IDirectFBSurface *oldSurface = dfbSurface; #ifdef QT_NO_DIRECTFB_WM IDirectFBSurface *primarySurface = screen->primarySurface(); Q_ASSERT(primarySurface); #endif if (rect.isNull()) { #ifndef QT_NO_DIRECTFB_WM if (dfbWindow) { dfbWindow->Release(dfbWindow); dfbWindow = 0; } #endif if (dfbSurface) { #ifdef QT_NO_DIRECTFB_WM if (dfbSurface != primarySurface) #endif 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 #ifdef QT_DIRECTFB_WM if (!dfbWindow) { createWindow(rect); } else { setWindowGeometry(dfbWindow, oldRect, rect); } #else if (mode == Primary) { if (dfbSurface && dfbSurface != primarySurface) dfbSurface->Release(dfbSurface); if (rect == screen->region().boundingRect()) { dfbSurface = primarySurface; } else { const DFBRectangle r = { rect.x(), rect.y(), rect.width(), rect.height() }; result = primarySurface->GetSubSurface(primarySurface, &r, &dfbSurface); } } else { if (!dfbSurface || oldRect.size() != rect.size()) { if (dfbSurface) dfbSurface->Release(dfbSurface); dfbSurface = screen->createDFBSurface(rect.size(), screen->pixelFormat(), QDirectFBScreen::DontTrackSurface); } const QRegion region = QRegion(oldRect.isEmpty() ? screen->region() : QRegion(oldRect)).subtracted(rect); screen->erase(region); screen->flipSurface(primarySurface, flipFlags, region, QPoint()); } #endif if (size() != geometry().size()) { delete engine; engine = 0; } if (result != DFB_OK) DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result); } if (oldSurface != dfbSurface) updateFormat(); QWSWindowSurface::setGeometry(rect); } QByteArray QDirectFBWindowSurface::permanentState() const { QByteArray state(sizeof(this), 0); *reinterpret_cast(state.data()) = this; return state; } void QDirectFBWindowSurface::setPermanentState(const QByteArray &state) { if (state.size() == sizeof(this)) { sibling = *reinterpret_cast(state.constData()); } } static inline void scrollSurface(IDirectFBSurface *surface, const QRect &r, int dx, int dy) { const DFBRectangle rect = { r.x(), r.y(), r.width(), r.height() }; 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()) return false; dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); if (region.numRects() == 1) { scrollSurface(dfbSurface, region.boundingRect(), dx, dy); } else { const QVector rects = region.rects(); const int n = rects.size(); for (int i=0; itestAttribute(Qt::WA_OpaquePaintEvent) || w->testAttribute(Qt::WA_PaintOnScreen)) return true; const QPalette &pal = w->palette(); if (w->autoFillBackground()) { const QBrush &autoFillBrush = pal.brush(w->backgroundRole()); if (autoFillBrush.style() != Qt::NoBrush && autoFillBrush.isOpaque()) return true; } if (!w->testAttribute(Qt::WA_NoSystemBackground)) { const QBrush &windowBrush = w->palette().brush(QPalette::Window); if (windowBrush.style() != Qt::NoBrush && windowBrush.isOpaque()) return true; } return false; } void QDirectFBWindowSurface::flush(QWidget *, const QRegion ®ion, const QPoint &offset) { // hw: make sure opacity information is updated before compositing 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; if (dfbWindow) { dfbWindow->GetOpacity(dfbWindow, &opacity); if (winOpacity != opacity) dfbWindow->SetOpacity(dfbWindow, winOpacity); } #endif } const QRect windowGeometry = QDirectFBWindowSurface::geometry(); #ifdef QT_NO_DIRECTFB_WM IDirectFBSurface *primarySurface = screen->primarySurface(); if (mode == Offscreen) { primarySurface->SetBlittingFlags(primarySurface, DSBLIT_NOFX); const QRect windowRect(0, 0, windowGeometry.width(), windowGeometry.height()); const int n = region.numRects(); if (n == 1 || boundingRectFlip ) { 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 rects = region.rects(); QVarLengthArray dfbRectangles(n); QVarLengthArray dfbPoints(n); for (int i=0; iBatchBlit(primarySurface, dfbSurface, dfbRectangles.constData(), dfbPoints.constData(), n); } } #ifdef QT_NO_DIRECTFB_CURSOR 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, image.format(), 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 } } #endif if (mode == Offscreen) { screen->flipSurface(primarySurface, flipFlags, region, offset + windowGeometry.topLeft()); } else #endif screen->flipSurface(dfbSurface, flipFlags, region, offset); #ifdef QT_DIRECTFB_TIMING enum { Secs = 3 }; ++frames; if (timer.elapsed() >= Secs * 1000) { qDebug("%d fps", int(double(frames) / double(Secs))); frames = 0; timer.restart(); } #endif } void QDirectFBWindowSurface::beginPaint(const QRegion &) { if (!engine) engine = new QDirectFBPaintEngine(this); } void QDirectFBWindowSurface::endPaint(const QRegion &) { #ifdef QT_NO_DIRECTFB_SUBSURFACE unlockSurface(); #endif } IDirectFBSurface *QDirectFBWindowSurface::directFBSurface() const { if (!dfbSurface && sibling && sibling->dfbSurface) return sibling->dfbSurface; return dfbSurface; } IDirectFBSurface *QDirectFBWindowSurface::surfaceForWidget(const QWidget *widget, QRect *rect) const { Q_ASSERT(widget); if (!dfbSurface) { if (sibling && (!sibling->sibling || sibling->dfbSurface)) return sibling->surfaceForWidget(widget, rect); return 0; } QWidget *win = window(); Q_ASSERT(win); if (rect) { if (win == widget) { *rect = widget->rect(); } else { *rect = QRect(widget->mapTo(win, QPoint(0, 0)), widget->size()); } } Q_ASSERT(win == widget || widget->isAncestorOf(win)); return dfbSurface; } void QDirectFBWindowSurface::updateFormat() { imageFormat = dfbSurface ? QDirectFBScreen::getImageFormat(dfbSurface) : QImage::Format_Invalid; } void QDirectFBWindowSurface::releaseSurface() { if (dfbSurface) { #ifdef QT_NO_DIRECTFB_SUBSURFACE if (lockFlgs) unlockSurface(); #endif #ifdef QT_NO_DIRECTFB_WM Q_ASSERT(screen->primarySurface()); if (dfbSurface != screen->primarySurface()) #endif dfbSurface->Release(dfbSurface); dfbSurface = 0; } } QT_END_NAMESPACE #endif // QT_NO_QWS_DIRECTFB