src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the plugins of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qdirectfbwindowsurface.h"
       
    43 #include "qdirectfbscreen.h"
       
    44 #include "qdirectfbpaintengine.h"
       
    45 
       
    46 #include <private/qwidget_p.h>
       
    47 #include <qwidget.h>
       
    48 #include <qwindowsystem_qws.h>
       
    49 #include <qpaintdevice.h>
       
    50 #include <qvarlengtharray.h>
       
    51 
       
    52 #ifndef QT_NO_QWS_DIRECTFB
       
    53 
       
    54 QT_BEGIN_NAMESPACE
       
    55 
       
    56 QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr)
       
    57     : QDirectFBPaintDevice(scr)
       
    58     , sibling(0)
       
    59 #ifndef QT_NO_DIRECTFB_WM
       
    60     , dfbWindow(0)
       
    61 #endif
       
    62     , flipFlags(flip)
       
    63     , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
       
    64 {
       
    65 #ifdef QT_NO_DIRECTFB_WM
       
    66     mode = Offscreen;
       
    67 #endif
       
    68     setSurfaceFlags(Opaque | Buffered);
       
    69 #ifdef QT_DIRECTFB_TIMING
       
    70     frames = 0;
       
    71     timer.start();
       
    72 #endif
       
    73 }
       
    74 
       
    75 QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget)
       
    76     : QWSWindowSurface(widget), QDirectFBPaintDevice(scr)
       
    77     , sibling(0)
       
    78 #ifndef QT_NO_DIRECTFB_WM
       
    79     , dfbWindow(0)
       
    80 #endif
       
    81     , flipFlags(flip)
       
    82     , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
       
    83 {
       
    84     SurfaceFlags flags = 0;
       
    85     if (!widget || widget->window()->windowOpacity() == 0xff)
       
    86         flags |= Opaque;
       
    87 #ifdef QT_NO_DIRECTFB_WM
       
    88     if (widget && widget->testAttribute(Qt::WA_PaintOnScreen)) {
       
    89         flags = RegionReserved;
       
    90         mode = Primary;
       
    91     } else {
       
    92         mode = Offscreen;
       
    93         flags = Buffered;
       
    94     }
       
    95 #else
       
    96     noSystemBackground = widget && widget->testAttribute(Qt::WA_NoSystemBackground);
       
    97     if (noSystemBackground)
       
    98         flags &= ~Opaque;
       
    99 #endif
       
   100     setSurfaceFlags(flags);
       
   101 #ifdef QT_DIRECTFB_TIMING
       
   102     frames = 0;
       
   103     timer.start();
       
   104 #endif
       
   105 }
       
   106 
       
   107 QDirectFBWindowSurface::~QDirectFBWindowSurface()
       
   108 {
       
   109     releaseSurface();
       
   110     // these are not tracked by QDirectFBScreen so we don't want QDirectFBPaintDevice to release it
       
   111 }
       
   112 
       
   113 bool QDirectFBWindowSurface::isValid() const
       
   114 {
       
   115     return true;
       
   116 }
       
   117 
       
   118 #ifdef QT_DIRECTFB_WM
       
   119 void QDirectFBWindowSurface::raise()
       
   120 {
       
   121     if (IDirectFBWindow *window = directFBWindow()) {
       
   122         window->RaiseToTop(window);
       
   123     }
       
   124 }
       
   125 
       
   126 IDirectFBWindow *QDirectFBWindowSurface::directFBWindow() const
       
   127 {
       
   128     return (dfbWindow ? dfbWindow : (sibling ? sibling->dfbWindow : 0));
       
   129 }
       
   130 
       
   131 
       
   132 void QDirectFBWindowSurface::createWindow(const QRect &rect)
       
   133 {
       
   134     IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer();
       
   135     if (!layer)
       
   136         qFatal("QDirectFBWindowSurface: Unable to get primary display layer!");
       
   137 
       
   138     DFBWindowDescription description;
       
   139     memset(&description, 0, sizeof(DFBWindowDescription));
       
   140 
       
   141     description.caps = DWCAPS_NODECORATION|DWCAPS_DOUBLEBUFFER;
       
   142     description.flags = DWDESC_CAPS|DWDESC_SURFACE_CAPS|DWDESC_PIXELFORMAT|DWDESC_HEIGHT|DWDESC_WIDTH|DWDESC_POSX|DWDESC_POSY;
       
   143 #if (Q_DIRECTFB_VERSION >= 0x010200)
       
   144     description.flags |= DWDESC_OPTIONS;
       
   145 #endif
       
   146 
       
   147     if (noSystemBackground) {
       
   148         description.caps |= DWCAPS_ALPHACHANNEL;
       
   149 #if (Q_DIRECTFB_VERSION >= 0x010200)
       
   150         description.options |= DWOP_ALPHACHANNEL;
       
   151 #endif
       
   152     }
       
   153 
       
   154     description.posx = rect.x();
       
   155     description.posy = rect.y();
       
   156     description.width = rect.width();
       
   157     description.height = rect.height();
       
   158     description.surface_caps = DSCAPS_NONE;
       
   159     if (screen->directFBFlags() & QDirectFBScreen::VideoOnly)
       
   160         description.surface_caps |= DSCAPS_VIDEOONLY;
       
   161     const QImage::Format format = (noSystemBackground ? screen->alphaPixmapFormat() : screen->pixelFormat());
       
   162     description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(format);
       
   163     if (QDirectFBScreen::isPremultiplied(format))
       
   164         description.surface_caps = DSCAPS_PREMULTIPLIED;
       
   165 
       
   166     DFBResult result = layer->CreateWindow(layer, &description, &dfbWindow);
       
   167 
       
   168     if (result != DFB_OK)
       
   169         DirectFBErrorFatal("QDirectFBWindowSurface::createWindow", result);
       
   170 
       
   171     if (window()) {
       
   172         DFBWindowID winid;
       
   173         result = dfbWindow->GetID(dfbWindow, &winid);
       
   174         if (result != DFB_OK) {
       
   175             DirectFBError("QDirectFBWindowSurface::createWindow. Can't get ID", result);
       
   176         } else {
       
   177             window()->setProperty("_q_DirectFBWindowID", winid);
       
   178         }
       
   179     }
       
   180 
       
   181     Q_ASSERT(!dfbSurface);
       
   182     dfbWindow->GetSurface(dfbWindow, &dfbSurface);
       
   183     updateFormat();
       
   184 }
       
   185 
       
   186 static DFBResult setWindowGeometry(IDirectFBWindow *dfbWindow, const QRect &old, const QRect &rect)
       
   187 {
       
   188     DFBResult result = DFB_OK;
       
   189     const bool isMove = old.isEmpty() || rect.topLeft() != old.topLeft();
       
   190     const bool isResize = rect.size() != old.size();
       
   191 
       
   192 #if (Q_DIRECTFB_VERSION >= 0x010000)
       
   193     if (isResize && isMove) {
       
   194         result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(),
       
   195                                       rect.width(), rect.height());
       
   196     } else if (isResize) {
       
   197         result = dfbWindow->Resize(dfbWindow,
       
   198                                    rect.width(), rect.height());
       
   199     } else if (isMove) {
       
   200         result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
       
   201     }
       
   202 #else
       
   203     if (isResize) {
       
   204         result = dfbWindow->Resize(dfbWindow,
       
   205                                    rect.width(), rect.height());
       
   206     }
       
   207     if (isMove) {
       
   208         result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
       
   209     }
       
   210 #endif
       
   211     return result;
       
   212 }
       
   213 #endif // QT_NO_DIRECTFB_WM
       
   214 
       
   215 void QDirectFBWindowSurface::setGeometry(const QRect &rect)
       
   216 {
       
   217     const QRect oldRect = geometry();
       
   218     if (oldRect == rect)
       
   219         return;
       
   220 
       
   221     IDirectFBSurface *oldSurface = dfbSurface;
       
   222     const bool sizeChanged = oldRect.size() != rect.size();
       
   223     if (sizeChanged) {
       
   224         delete engine;
       
   225         engine = 0;
       
   226         releaseSurface();
       
   227         Q_ASSERT(!dfbSurface);
       
   228     }
       
   229 
       
   230     if (rect.isNull()) {
       
   231 #ifndef QT_NO_DIRECTFB_WM
       
   232         if (dfbWindow) {
       
   233             if (window())
       
   234                 window()->setProperty("_q_DirectFBWindowID", QVariant());
       
   235 
       
   236             dfbWindow->Release(dfbWindow);
       
   237             dfbWindow = 0;
       
   238         }
       
   239 #endif
       
   240         Q_ASSERT(!dfbSurface);
       
   241 #ifdef QT_DIRECTFB_SUBSURFACE
       
   242         Q_ASSERT(!subSurface);
       
   243 #endif
       
   244     } else {
       
   245 #ifdef QT_DIRECTFB_WM
       
   246         if (!dfbWindow) {
       
   247             createWindow(rect);
       
   248         } else {
       
   249             setWindowGeometry(dfbWindow, oldRect, rect);
       
   250             Q_ASSERT(!sizeChanged || !dfbSurface);
       
   251             if (sizeChanged)
       
   252                 dfbWindow->GetSurface(dfbWindow, &dfbSurface);
       
   253         }
       
   254 #else
       
   255         IDirectFBSurface *primarySurface = screen->primarySurface();
       
   256         DFBResult result = DFB_OK;
       
   257         if (mode == Primary) {
       
   258             Q_ASSERT(primarySurface);
       
   259             if (rect == screen->region().boundingRect()) {
       
   260                 dfbSurface = primarySurface;
       
   261             } else {
       
   262                 const DFBRectangle r = { rect.x(), rect.y(),
       
   263                                          rect.width(), rect.height() };
       
   264                 result = primarySurface->GetSubSurface(primarySurface, &r, &dfbSurface);
       
   265             }
       
   266         } else { // mode == Offscreen
       
   267             if (!dfbSurface) {
       
   268                 dfbSurface = screen->createDFBSurface(rect.size(), screen->pixelFormat(), QDirectFBScreen::DontTrackSurface);
       
   269             }
       
   270         }
       
   271         if (result != DFB_OK)
       
   272             DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result);
       
   273 #endif
       
   274     }
       
   275     if (oldSurface != dfbSurface)
       
   276         updateFormat();
       
   277 
       
   278     if (oldRect.size() != rect.size()) {
       
   279         QWSWindowSurface::setGeometry(rect);
       
   280     } else {
       
   281         QWindowSurface::setGeometry(rect);
       
   282     }
       
   283 }
       
   284 
       
   285 QByteArray QDirectFBWindowSurface::permanentState() const
       
   286 {
       
   287     QByteArray state(sizeof(this), 0);
       
   288     *reinterpret_cast<const QDirectFBWindowSurface**>(state.data()) = this;
       
   289     return state;
       
   290 }
       
   291 
       
   292 void QDirectFBWindowSurface::setPermanentState(const QByteArray &state)
       
   293 {
       
   294     if (state.size() == sizeof(this)) {
       
   295         sibling = *reinterpret_cast<QDirectFBWindowSurface *const*>(state.constData());
       
   296         Q_ASSERT(sibling);
       
   297         sibling->setSurfaceFlags(surfaceFlags());
       
   298     }
       
   299 }
       
   300 
       
   301 static inline void scrollSurface(IDirectFBSurface *surface, const QRect &r, int dx, int dy)
       
   302 {
       
   303     const DFBRectangle rect = { r.x(), r.y(), r.width(), r.height() };
       
   304     surface->Blit(surface, surface, &rect, r.x() + dx, r.y() + dy);
       
   305     const DFBRegion region = { rect.x + dx, rect.y + dy, r.right() + dx, r.bottom() + dy };
       
   306     surface->Flip(surface, &region, DSFLIP_BLIT);
       
   307 }
       
   308 
       
   309 bool QDirectFBWindowSurface::scroll(const QRegion &region, int dx, int dy)
       
   310 {
       
   311     if (!dfbSurface || !(flipFlags & DSFLIP_BLIT) || region.isEmpty())
       
   312         return false;
       
   313     dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
       
   314     if (region.numRects() == 1) {
       
   315         scrollSurface(dfbSurface, region.boundingRect(), dx, dy);
       
   316     } else {
       
   317         const QVector<QRect> rects = region.rects();
       
   318         const int n = rects.size();
       
   319         for (int i=0; i<n; ++i) {
       
   320             scrollSurface(dfbSurface, rects.at(i), dx, dy);
       
   321         }
       
   322     }
       
   323     return true;
       
   324 }
       
   325 
       
   326 bool QDirectFBWindowSurface::move(const QPoint &moveBy)
       
   327 {
       
   328     setGeometry(geometry().translated(moveBy));
       
   329     return true;
       
   330 }
       
   331 
       
   332 void QDirectFBWindowSurface::setOpaque(bool opaque)
       
   333 {
       
   334     SurfaceFlags flags = surfaceFlags();
       
   335     if (opaque != (flags & Opaque)) {
       
   336         if (opaque) {
       
   337             flags |= Opaque;
       
   338         } else {
       
   339             flags &= ~Opaque;
       
   340         }
       
   341         setSurfaceFlags(flags);
       
   342     }
       
   343 }
       
   344 
       
   345 
       
   346 void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion &region,
       
   347                                    const QPoint &offset)
       
   348 {
       
   349     QWidget *win = window();
       
   350     if (!win)
       
   351         return;
       
   352 
       
   353     QWExtra *extra = qt_widget_private(widget)->extraData();
       
   354     if (extra && extra->proxyWidget)
       
   355         return;
       
   356 
       
   357     const quint8 windowOpacity = quint8(win->windowOpacity() * 0xff);
       
   358     const QRect windowGeometry = geometry();
       
   359 #ifdef QT_DIRECTFB_WM
       
   360     const bool wasNoSystemBackground = noSystemBackground;
       
   361     noSystemBackground = win->testAttribute(Qt::WA_NoSystemBackground);
       
   362     quint8 currentOpacity;
       
   363     Q_ASSERT(dfbWindow);
       
   364     dfbWindow->GetOpacity(dfbWindow, &currentOpacity);
       
   365     if (currentOpacity != windowOpacity) {
       
   366         dfbWindow->SetOpacity(dfbWindow, windowOpacity);
       
   367     }
       
   368 
       
   369     setOpaque(noSystemBackground || windowOpacity != 0xff);
       
   370     if (wasNoSystemBackground != noSystemBackground) {
       
   371         releaseSurface();
       
   372         dfbWindow->Release(dfbWindow);
       
   373         dfbWindow = 0;
       
   374         createWindow(windowGeometry);
       
   375         win->update();
       
   376         return;
       
   377     }
       
   378     screen->flipSurface(dfbSurface, flipFlags, region, offset);
       
   379     if (noSystemBackground) {
       
   380         dfbSurface->Clear(dfbSurface, 0, 0, 0, 0);
       
   381     }
       
   382 #else
       
   383     setOpaque(windowOpacity != 0xff);
       
   384     if (mode == Offscreen) {
       
   385         screen->exposeRegion(region.translated(offset + geometry().topLeft()), 0);
       
   386     } else {
       
   387         screen->flipSurface(dfbSurface, flipFlags, region, offset);
       
   388     }
       
   389 #endif
       
   390 
       
   391 #ifdef QT_DIRECTFB_TIMING
       
   392     enum { Secs = 3 };
       
   393     ++frames;
       
   394     if (timer.elapsed() >= Secs * 1000) {
       
   395         qDebug("%d fps", int(double(frames) / double(Secs)));
       
   396         frames = 0;
       
   397         timer.restart();
       
   398     }
       
   399 #endif
       
   400 }
       
   401 
       
   402 void QDirectFBWindowSurface::beginPaint(const QRegion &)
       
   403 {
       
   404     if (!engine) {
       
   405         engine = new QDirectFBPaintEngine(this);
       
   406     }
       
   407 }
       
   408 
       
   409 void QDirectFBWindowSurface::endPaint(const QRegion &)
       
   410 {
       
   411 #ifdef QT_NO_DIRECTFB_SUBSURFACE
       
   412     unlockSurface();
       
   413 #endif
       
   414 }
       
   415 
       
   416 IDirectFBSurface *QDirectFBWindowSurface::directFBSurface() const
       
   417 {
       
   418     if (!dfbSurface && sibling && sibling->dfbSurface)
       
   419         return sibling->dfbSurface;
       
   420     return dfbSurface;
       
   421 }
       
   422 
       
   423 
       
   424 IDirectFBSurface *QDirectFBWindowSurface::surfaceForWidget(const QWidget *widget, QRect *rect) const
       
   425 {
       
   426     Q_ASSERT(widget);
       
   427     if (!dfbSurface) {
       
   428         if (sibling && (!sibling->sibling || sibling->dfbSurface))
       
   429             return sibling->surfaceForWidget(widget, rect);
       
   430         return 0;
       
   431     }
       
   432     QWidget *win = window();
       
   433     Q_ASSERT(win);
       
   434     if (rect) {
       
   435         if (win == widget) {
       
   436             *rect = widget->rect();
       
   437         } else {
       
   438             *rect = QRect(widget->mapTo(win, QPoint(0, 0)), widget->size());
       
   439         }
       
   440     }
       
   441 
       
   442     Q_ASSERT(win == widget || win->isAncestorOf(widget));
       
   443     return dfbSurface;
       
   444 }
       
   445 
       
   446 void QDirectFBWindowSurface::updateFormat()
       
   447 {
       
   448     imageFormat = dfbSurface ? QDirectFBScreen::getImageFormat(dfbSurface) : QImage::Format_Invalid;
       
   449 }
       
   450 
       
   451 void QDirectFBWindowSurface::releaseSurface()
       
   452 {
       
   453     if (dfbSurface) {
       
   454 #ifdef QT_DIRECTFB_SUBSURFACE
       
   455         releaseSubSurface();
       
   456 #else
       
   457         unlockSurface();
       
   458 #endif
       
   459 #ifdef QT_NO_DIRECTFB_WM
       
   460         Q_ASSERT(screen->primarySurface());
       
   461         if (dfbSurface != screen->primarySurface())
       
   462 #endif
       
   463 
       
   464             dfbSurface->Release(dfbSurface);
       
   465         dfbSurface = 0;
       
   466     }
       
   467 }
       
   468 
       
   469 
       
   470 QT_END_NAMESPACE
       
   471 
       
   472 #endif // QT_NO_QWS_DIRECTFB
       
   473 
       
   474