From 6ce6b8a378b0d97ba950240ffb048a4b7e485235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 20 Jun 2011 13:29:26 +0200 Subject: Rename QWindowSurface -> QBackingStore and split into platform / public. Also get rid of GL window surface and related classes. --- examples/qpa/windows/window.cpp | 14 +- examples/qpa/windows/window.h | 1 + src/gui/kernel/qplatformintegration_qpa.cpp | 12 +- src/gui/kernel/qplatformintegration_qpa.h | 5 +- src/gui/kernel/qwindow.cpp | 10 - src/gui/kernel/qwindow.h | 4 +- src/gui/kernel/qwindow_p.h | 2 - src/gui/painting/painting.pri | 6 +- src/gui/painting/qbackingstore.cpp | 250 +++ src/gui/painting/qbackingstore.h | 90 ++ src/gui/painting/qplatformbackingstore_qpa.cpp | 155 ++ src/gui/painting/qplatformbackingstore_qpa.h | 86 + src/gui/painting/qwindowsurface.cpp | 345 ---- src/gui/painting/qwindowsurface_p.h | 140 -- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 1 - src/opengl/opengl.pro | 22 +- src/opengl/qgl.cpp | 30 - src/opengl/qgl.h | 3 - src/opengl/qgl_egl.cpp | 3 +- src/opengl/qgl_p.h | 6 - src/opengl/qglpaintdevice.cpp | 22 +- src/opengl/qglpixelbuffer.h | 1 - src/opengl/qglpixmapfilter.cpp | 1 - src/opengl/qgltexturepool.cpp | 244 --- src/opengl/qgltexturepool_p.h | 147 -- src/opengl/qpixmapdata_gl.cpp | 829 ---------- src/opengl/qpixmapdata_gl_p.h | 247 --- src/opengl/qpixmapdata_poolgl.cpp | 934 ----------- src/opengl/qpixmapdata_x11gl_egl.cpp | 403 ----- src/opengl/qpixmapdata_x11gl_p.h | 98 -- src/opengl/qwindowsurface_gl.cpp | 1104 ------------- src/opengl/qwindowsurface_gl_p.h | 127 -- src/opengl/qwindowsurface_x11gl.cpp | 213 --- src/opengl/qwindowsurface_x11gl_p.h | 83 - src/plugins/platforms/minimal/minimal.pro | 4 +- .../platforms/minimal/qminimalbackingstore.cpp | 85 + .../platforms/minimal/qminimalbackingstore.h | 67 + .../platforms/minimal/qminimalintegration.cpp | 7 +- .../platforms/minimal/qminimalintegration.h | 2 +- .../platforms/minimal/qminimalwindowsurface.cpp | 86 - .../platforms/minimal/qminimalwindowsurface.h | 68 - src/plugins/platforms/wayland/qwaylandcursor.cpp | 2 +- .../platforms/wayland/qwaylandintegration.cpp | 7 +- .../platforms/wayland/qwaylandintegration.h | 2 +- .../platforms/wayland/qwaylandshmbackingstore.cpp | 143 ++ .../platforms/wayland/qwaylandshmbackingstore.h | 83 + .../platforms/wayland/qwaylandshmsurface.cpp | 144 -- src/plugins/platforms/wayland/qwaylandshmsurface.h | 83 - src/plugins/platforms/wayland/wayland.pro | 4 +- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 284 ++++ src/plugins/platforms/xcb/qxcbbackingstore.h | 72 + src/plugins/platforms/xcb/qxcbintegration.cpp | 7 +- src/plugins/platforms/xcb/qxcbintegration.h | 2 +- src/plugins/platforms/xcb/qxcbwindow.cpp | 10 +- src/plugins/platforms/xcb/qxcbwindowsurface.cpp | 282 ---- src/plugins/platforms/xcb/qxcbwindowsurface.h | 72 - src/plugins/platforms/xcb/xcb.pro | 4 +- src/widgets/kernel/kernel.pri | 4 +- src/widgets/kernel/qapplication.cpp | 12 +- src/widgets/kernel/qbackingstore.cpp | 1665 -------------------- src/widgets/kernel/qbackingstore_p.h | 278 ---- src/widgets/kernel/qwidget.cpp | 259 +-- src/widgets/kernel/qwidget.h | 6 +- src/widgets/kernel/qwidget_p.h | 29 +- src/widgets/kernel/qwidget_qpa.cpp | 38 +- src/widgets/kernel/qwidgetbackingstore.cpp | 1396 ++++++++++++++++ src/widgets/kernel/qwidgetbackingstore_p.h | 268 ++++ tests/auto/qwidget/tst_qwidget.cpp | 10 +- 68 files changed, 3101 insertions(+), 8022 deletions(-) create mode 100644 src/gui/painting/qbackingstore.cpp create mode 100644 src/gui/painting/qbackingstore.h create mode 100644 src/gui/painting/qplatformbackingstore_qpa.cpp create mode 100644 src/gui/painting/qplatformbackingstore_qpa.h delete mode 100644 src/gui/painting/qwindowsurface.cpp delete mode 100644 src/gui/painting/qwindowsurface_p.h delete mode 100644 src/opengl/qgltexturepool.cpp delete mode 100644 src/opengl/qgltexturepool_p.h delete mode 100644 src/opengl/qpixmapdata_gl.cpp delete mode 100644 src/opengl/qpixmapdata_gl_p.h delete mode 100644 src/opengl/qpixmapdata_poolgl.cpp delete mode 100644 src/opengl/qpixmapdata_x11gl_egl.cpp delete mode 100644 src/opengl/qpixmapdata_x11gl_p.h delete mode 100644 src/opengl/qwindowsurface_gl.cpp delete mode 100644 src/opengl/qwindowsurface_gl_p.h delete mode 100644 src/opengl/qwindowsurface_x11gl.cpp delete mode 100644 src/opengl/qwindowsurface_x11gl_p.h create mode 100644 src/plugins/platforms/minimal/qminimalbackingstore.cpp create mode 100644 src/plugins/platforms/minimal/qminimalbackingstore.h delete mode 100644 src/plugins/platforms/minimal/qminimalwindowsurface.cpp delete mode 100644 src/plugins/platforms/minimal/qminimalwindowsurface.h create mode 100644 src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp create mode 100644 src/plugins/platforms/wayland/qwaylandshmbackingstore.h delete mode 100644 src/plugins/platforms/wayland/qwaylandshmsurface.cpp delete mode 100644 src/plugins/platforms/wayland/qwaylandshmsurface.h create mode 100644 src/plugins/platforms/xcb/qxcbbackingstore.cpp create mode 100644 src/plugins/platforms/xcb/qxcbbackingstore.h delete mode 100644 src/plugins/platforms/xcb/qxcbwindowsurface.cpp delete mode 100644 src/plugins/platforms/xcb/qxcbwindowsurface.h delete mode 100644 src/widgets/kernel/qbackingstore.cpp delete mode 100644 src/widgets/kernel/qbackingstore_p.h create mode 100644 src/widgets/kernel/qwidgetbackingstore.cpp create mode 100644 src/widgets/kernel/qwidgetbackingstore_p.h diff --git a/examples/qpa/windows/window.cpp b/examples/qpa/windows/window.cpp index 76bc117793..0a38d8e43d 100644 --- a/examples/qpa/windows/window.cpp +++ b/examples/qpa/windows/window.cpp @@ -1,8 +1,8 @@ #include "window.h" #include -#include +#include #include static int colorIndexId = 0; @@ -33,7 +33,7 @@ Window::Window(QWindow *parent) } create(); - QGuiApplicationPrivate::platformIntegration()->createWindowSurface(this, winId()); + m_backingStore = new QBackingStore(this); m_image = QImage(geometry().size(), QImage::Format_RGB32); m_image.fill(colorTable[m_backgroundColorIndex % (sizeof(colorTable) / sizeof(colorTable[0]))].rgba()); @@ -110,11 +110,11 @@ void Window::keyPressEvent(QKeyEvent *event) void Window::render() { QRect rect(QPoint(), geometry().size()); - surface()->resize(rect.size()); + m_backingStore->resize(rect.size()); - surface()->beginPaint(rect); + m_backingStore->beginPaint(rect); - QPaintDevice *device = surface()->paintDevice(); + QPaintDevice *device = m_backingStore->paintDevice(); QPainter p(device); p.drawImage(0, 0, m_image); @@ -125,8 +125,8 @@ void Window::render() p.setFont(font); p.drawText(rect, 0, m_text); - surface()->endPaint(rect); - surface()->flush(this, rect, QPoint()); + m_backingStore->endPaint(); + m_backingStore->flush(rect); } diff --git a/examples/qpa/windows/window.h b/examples/qpa/windows/window.h index f0b7d80531..f716145f94 100644 --- a/examples/qpa/windows/window.h +++ b/examples/qpa/windows/window.h @@ -22,4 +22,5 @@ private: QImage m_image; QPoint m_lastPos; int m_backgroundColorIndex; + QBackingStore *m_backingStore; }; diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp index d3944ab1fe..5db0366707 100644 --- a/src/gui/kernel/qplatformintegration_qpa.cpp +++ b/src/gui/kernel/qplatformintegration_qpa.cpp @@ -156,19 +156,17 @@ QPlatformNativeInterface * QPlatformIntegration::nativeInterface() const created. \sa QPlatformWindow, QPlatformWindowFormat - \sa createWindowSurface(QWindow *window, WId winId) const + \sa createPlatformBackingStore(QWindow *window) const */ /*! - \fn QWindowSurface *QPlatformIntegration::createWindowSurface(QWindow *window, WId winId) const + \fn QPlatformBackingStore *QPlatformIntegration::createPlatformBackingStore(QWindow *window) const - Factory function for QWindowSurface. The QWindow parameter is a pointer to the + Factory function for QPlatformBackingStore. The QWindow parameter is a pointer to the top level widget(tlw) the window surface is created for. A QPlatformWindow is always created - before the QWindowSurface for tlw where the widget also requires a WindowSurface. It is - possible to create top level QWindow without a QWindowSurface by specifying - QPlatformWindowFormat::setWindowSurface(false) for the tlw QPlatformWindowFormat. + before the QPlatformBackingStore for tlw where the widget also requires a backing store. - \sa QWindowSurface + \sa QBackingStore \sa createPlatformWindow(QWindow *window, WId winId = 0) const */ diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h index d9953abcc9..8263999b2d 100644 --- a/src/gui/kernel/qplatformintegration_qpa.h +++ b/src/gui/kernel/qplatformintegration_qpa.h @@ -43,7 +43,6 @@ #define QPLATFORMINTEGRATION_H #include -#include #include #include @@ -55,7 +54,7 @@ QT_MODULE(Gui) class QPlatformWindow; class QWindow; -class QBlittable; +class QPlatformBackingStore; class QPlatformFontDatabase; class QPlatformClipboard; class QPlatformNativeInterface; @@ -79,7 +78,7 @@ public: // GraphicsSystem functions virtual QPixmapData *createPixmapData(QPixmapData::PixelType type) const = 0; virtual QPlatformWindow *createPlatformWindow(QWindow *window) const = 0; - virtual QWindowSurface *createWindowSurface(QWindow *window, WId winId) const = 0; + virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const = 0; virtual QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; // Window System functions diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 2996c00391..c29bc7002d 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -426,11 +426,6 @@ QPlatformWindow *QWindow::handle() const return d->platformWindow; } -QWindowSurface *QWindow::surface() const -{ - Q_D(const QWindow); - return d->surface; -} bool QWindow::setKeyboardGrabEnabled(bool grab) { @@ -531,11 +526,6 @@ bool QWindow::event(QEvent *event) destroy(); break; - case QEvent::Expose: - if (d->surface) - d->surface->flush(this, static_cast(event)->region, QPoint()); - break; - default: return QObject::event(event); } diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index 7910c3884c..cfd251fff0 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -69,7 +69,7 @@ class QWheelEvent; class QPlatformGLSurface; class QPlatformWindow; -class QWindowSurface; +class QBackingStore; class Q_GUI_EXPORT QWindow : public QObject { @@ -146,7 +146,6 @@ public: void destroy(); QPlatformWindow *handle() const; - QWindowSurface *surface() const; bool setKeyboardGrabEnabled(bool grab); bool setMouseGrabEnabled(bool grab); @@ -192,7 +191,6 @@ private: friend class QGuiApplication; friend class QGuiApplicationPrivate; - friend class QWindowSurface; friend Q_GUI_EXPORT QWindowPrivate *qt_window_private(QWindow *window); }; diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 2f33629ccf..1c4c4bffad 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -65,7 +65,6 @@ public: , platformWindow(0) , visible(false) , glSurface(0) - , surface(0) , windowState(Qt::WindowNoState) , maximumSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX) , modality(Qt::NonModal) @@ -87,7 +86,6 @@ public: QString windowTitle; QRect geometry; QPlatformGLSurface *glSurface; - QWindowSurface *surface; Qt::WindowState windowState; QSize minimumSize; diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 4be0553843..dfc1f88d6d 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -1,6 +1,7 @@ # Qt gui library, paint module HEADERS += \ + painting/qbackingstore.h \ painting/qbezier_p.h \ painting/qbrush.h \ painting/qcolor.h \ @@ -38,11 +39,12 @@ HEADERS += \ painting/qtessellator_p.h \ painting/qtextureglyphcache_p.h \ painting/qtransform.h \ - painting/qwindowsurface_p.h \ + painting/qplatformbackingstore_qpa.h \ painting/qpaintbuffer_p.h SOURCES += \ + painting/qbackingstore.cpp \ painting/qbezier.cpp \ painting/qblendfunctions.cpp \ painting/qbrush.cpp \ @@ -74,7 +76,7 @@ SOURCES += \ painting/qtessellator.cpp \ painting/qtextureglyphcache.cpp \ painting/qtransform.cpp \ - painting/qwindowsurface.cpp \ + painting/qplatformbackingstore_qpa.cpp \ painting/qpaintbuffer.cpp SOURCES += \ diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp new file mode 100644 index 0000000000..776e33a1a8 --- /dev/null +++ b/src/gui/painting/qbackingstore.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QBackingStorePrivate +{ +public: + QBackingStorePrivate(QWindow *w) + : window(w) + { + } + + QWindow *window; + QPlatformBackingStore *platformBackingStore; + QRegion staticContents; + QSize size; +}; + +/*! + \class QBackingStore + \since 5.0 + + \brief The QBackingStore class provides the drawing area for top-level windows. +*/ + + +/*! + \fn void QBackingStore::beginPaint(const QRegion ®ion) + + This function is called before painting onto the surface begins, + with the \a region in which the painting will occur. + + \sa endPaint(), paintDevice() +*/ + +/*! + \fn void QBackingStore::endPaint(const QRegion ®ion) + + This function is called after painting onto the surface has ended, + with the \a region in which the painting was performed. + + \sa beginPaint(), paintDevice() +*/ + +/*! + \fn void QBackingStore::flush(QWindow *window, const QRegion ®ion, + const QPoint &offset) + + Flushes the given \a region from the specified \a window onto the + screen. + + Note that the \a offset parameter is currently unused. +*/ +void QBackingStore::flush(const QRegion ®ion, QWindow *win, const QPoint &offset) +{ + if (!win) + win = window(); + d_ptr->platformBackingStore->flush(win, region, offset); +} + +/*! + \fn QPaintDevice* QBackingStore::paintDevice() + + Implement this function to return the appropriate paint device. +*/ +QPaintDevice *QBackingStore::paintDevice() +{ + return d_ptr->platformBackingStore->paintDevice(); +} + +/*! + Constructs an empty surface for the given top-level \a window. +*/ +QBackingStore::QBackingStore(QWindow *window) + : d_ptr(new QBackingStorePrivate(window)) +{ + d_ptr->platformBackingStore = QGuiApplicationPrivate::platformIntegration()->createPlatformBackingStore(window); +} + +/*! + Destroys this surface. +*/ +QBackingStore::~QBackingStore() +{ + delete d_ptr->platformBackingStore; +} + +/*! + Returns a pointer to the top-level window associated with this + surface. +*/ +QWindow* QBackingStore::window() const +{ + return d_ptr->window; +} + +void QBackingStore::beginPaint(const QRegion ®ion) +{ + d_ptr->platformBackingStore->beginPaint(region); +} + +void QBackingStore::endPaint() +{ + d_ptr->platformBackingStore->endPaint(); +} + +/*! + Sets the size of the windowsurface to be \a size. + + \sa size() +*/ +void QBackingStore::resize(const QSize &size) +{ + d_ptr->size = size; + d_ptr->platformBackingStore->resize(size, d_ptr->staticContents); +} + +/*! + Returns the current size of the windowsurface. +*/ +QSize QBackingStore::size() const +{ + return d_ptr->size; +} + +/*! + Scrolls the given \a area \a dx pixels to the right and \a dy + downward; both \a dx and \a dy may be negative. + + Returns true if the area was scrolled successfully; false otherwise. +*/ +bool QBackingStore::scroll(const QRegion &area, int dx, int dy) +{ + Q_UNUSED(area); + Q_UNUSED(dx); + Q_UNUSED(dy); + + return d_ptr->platformBackingStore->scroll(area, dx, dy); +} + +void QBackingStore::setStaticContents(const QRegion ®ion) +{ + d_ptr->staticContents = region; +} + +QRegion QBackingStore::staticContents() const +{ + return d_ptr->staticContents; +} + +bool QBackingStore::hasStaticContents() const +{ + return !d_ptr->staticContents.isEmpty(); +} + +void Q_GUI_EXPORT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset) +{ + // make sure we don't detach + uchar *mem = const_cast(const_cast(img).bits()); + + int lineskip = img.bytesPerLine(); + int depth = img.depth() >> 3; + + const QRect imageRect(0, 0, img.width(), img.height()); + const QRect r = rect & imageRect & imageRect.translated(-offset); + const QPoint p = rect.topLeft() + offset; + + if (r.isEmpty()) + return; + + const uchar *src; + uchar *dest; + + if (r.top() < p.y()) { + src = mem + r.bottom() * lineskip + r.left() * depth; + dest = mem + (p.y() + r.height() - 1) * lineskip + p.x() * depth; + lineskip = -lineskip; + } else { + src = mem + r.top() * lineskip + r.left() * depth; + dest = mem + p.y() * lineskip + p.x() * depth; + } + + const int w = r.width(); + int h = r.height(); + const int bytes = w * depth; + + // overlapping segments? + if (offset.y() == 0 && qAbs(offset.x()) < w) { + do { + ::memmove(dest, src, bytes); + dest += lineskip; + src += lineskip; + } while (--h); + } else { + do { + ::memcpy(dest, src, bytes); + dest += lineskip; + src += lineskip; + } while (--h); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/painting/qbackingstore.h b/src/gui/painting/qbackingstore.h new file mode 100644 index 0000000000..3ab0264b17 --- /dev/null +++ b/src/gui/painting/qbackingstore.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBACKINGSTORE_H +#define QBACKINGSTORE_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QRegion; +class QRect; +class QPoint; +class QImage; +class QBackingStorePrivate; + +class Q_GUI_EXPORT QBackingStore +{ +public: + QBackingStore(QWindow *window); + ~QBackingStore(); + + QWindow *window() const; + + QPaintDevice *paintDevice(); + + // 'window' can be a child window, in which case 'region' is in child window coordinates and + // offset is the (child) window's offset in relation to the window surface. + void flush(const QRegion ®ion, QWindow *window = 0, const QPoint &offset = QPoint()); + + void resize(const QSize &size); + QSize size() const; + + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion &); + void endPaint(); + + void setStaticContents(const QRegion ®ion); + QRegion staticContents() const; + bool hasStaticContents() const; + +private: + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QBACKINGSTORE_H diff --git a/src/gui/painting/qplatformbackingstore_qpa.cpp b/src/gui/painting/qplatformbackingstore_qpa.cpp new file mode 100644 index 0000000000..fa85661f31 --- /dev/null +++ b/src/gui/painting/qplatformbackingstore_qpa.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QPlatformBackingStorePrivate +{ +public: + QPlatformBackingStorePrivate(QWindow *w) + : window(w) + { + } + + QWindow *window; + QSize size; +}; + +/*! + \class QPlatformBackingStore + \since 5.0 + \internal + \preliminary + \ingroup qpa + + \brief The QPlatformBackingStore class provides the drawing area for top-level + windows. +*/ + + +/*! + \fn void QPlatformBackingStore::beginPaint(const QRegion ®ion) + + This function is called before painting onto the surface begins, + with the \a region in which the painting will occur. + + \sa endPaint(), paintDevice() +*/ + +/*! + \fn void QPlatformBackingStore::endPaint(const QRegion ®ion) + + This function is called after painting onto the surface has ended, + with the \a region in which the painting was performed. + + \sa beginPaint(), paintDevice() +*/ + +/*! + \fn void QPlatformBackingStore::flush(QWindow *window, const QRegion ®ion, + const QPoint &offset) + + Flushes the given \a region from the specified \a window onto the + screen. + + Note that the \a offset parameter is currently unused. +*/ + +/*! + \fn QPaintDevice* QPlatformBackingStore::paintDevice() + + Implement this function to return the appropriate paint device. +*/ + +/*! + Constructs an empty surface for the given top-level \a window. +*/ +QPlatformBackingStore::QPlatformBackingStore(QWindow *window) + : d_ptr(new QPlatformBackingStorePrivate(window)) +{ +} + +/*! + Destroys this surface. +*/ +QPlatformBackingStore::~QPlatformBackingStore() +{ + delete d_ptr; +} + +/*! + Returns a pointer to the top-level window associated with this + surface. +*/ +QWindow* QPlatformBackingStore::window() const +{ + return d_ptr->window; +} + +void QPlatformBackingStore::beginPaint(const QRegion &) +{ +} + +void QPlatformBackingStore::endPaint() +{ +} + +/*! + Scrolls the given \a area \a dx pixels to the right and \a dy + downward; both \a dx and \a dy may be negative. + + Returns true if the area was scrolled successfully; false otherwise. +*/ +bool QPlatformBackingStore::scroll(const QRegion &area, int dx, int dy) +{ + Q_UNUSED(area); + Q_UNUSED(dx); + Q_UNUSED(dy); + + return false; +} + +QT_END_NAMESPACE diff --git a/src/gui/painting/qplatformbackingstore_qpa.h b/src/gui/painting/qplatformbackingstore_qpa.h new file mode 100644 index 0000000000..29730167b4 --- /dev/null +++ b/src/gui/painting/qplatformbackingstore_qpa.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPLATFORMBACKINGSTORE_QPA_H +#define QPLATFORMBACKINGSTORE_QPA_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QRegion; +class QRect; +class QPoint; +class QImage; +class QPlatformBackingStorePrivate; +class QPlatformWindow; + +class Q_GUI_EXPORT QPlatformBackingStore +{ +public: + QPlatformBackingStore(QWindow *window); + virtual ~QPlatformBackingStore(); + + QWindow *window() const; + + virtual QPaintDevice *paintDevice() = 0; + + // 'window' can be a child window, in which case 'region' is in child window coordinates and + // offset is the (child) window's offset in relation to the window surface. + virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) = 0; + + virtual void resize(const QSize &size, const QRegion &staticContents) = 0; + + virtual bool scroll(const QRegion &area, int dx, int dy); + + virtual void beginPaint(const QRegion &); + virtual void endPaint(); + +private: + QPlatformBackingStorePrivate *d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QPLATFORMBACKINGSTORE_QPA_H diff --git a/src/gui/painting/qwindowsurface.cpp b/src/gui/painting/qwindowsurface.cpp deleted file mode 100644 index 743621be7b..0000000000 --- a/src/gui/painting/qwindowsurface.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QWindowSurfacePrivate -{ -public: - QWindowSurfacePrivate(QWindow *w) - : window(w) - { - } - - QWindow *window; -#if !defined(Q_WS_QPA) - QRect geometry; -#else - QSize size; -#endif //Q_WS_QPA - QRegion staticContents; -}; - -/*! - \class QWindowSurface - \since 4.3 - \internal - \preliminary - \ingroup qws qpa - - \brief The QWindowSurface class provides the drawing area for top-level - windows. -*/ - - -/*! - \fn void QWindowSurface::beginPaint(const QRegion ®ion) - - This function is called before painting onto the surface begins, - with the \a region in which the painting will occur. - - \sa endPaint(), paintDevice() -*/ - -/*! - \fn void QWindowSurface::endPaint(const QRegion ®ion) - - This function is called after painting onto the surface has ended, - with the \a region in which the painting was performed. - - \sa beginPaint(), paintDevice() -*/ - -/*! - \fn void QWindowSurface::flush(QWindow *window, const QRegion ®ion, - const QPoint &offset) - - Flushes the given \a region from the specified \a window onto the - screen. - - Note that the \a offset parameter is currently unused. -*/ - -/*! - \fn QPaintDevice* QWindowSurface::paintDevice() - - Implement this function to return the appropriate paint device. -*/ - -/*! - Constructs an empty surface for the given top-level \a window. -*/ -QWindowSurface::QWindowSurface(QWindow *window, bool /*setDefaultSurface*/) - : d_ptr(new QWindowSurfacePrivate(window)) -{ - if (window) - window->d_func()->surface = this; -} - -/*! - Destroys this surface. -*/ -QWindowSurface::~QWindowSurface() -{ -// if (d_ptr->window) -// d_ptr->window->d_func()->extra->topextra->windowSurface = 0; - delete d_ptr; -} - -/*! - Returns a pointer to the top-level window associated with this - surface. -*/ -QWindow* QWindowSurface::window() const -{ - return d_ptr->window; -} - -void QWindowSurface::beginPaint(const QRegion &) -{ -} - -void QWindowSurface::endPaint(const QRegion &) -{ -} - -#if !defined(Q_WS_QPA) -/*! - Sets the currently allocated area to be the given \a rect. - - This function is called whenever area covered by the top-level - window changes. - - \sa geometry() -*/ -void QWindowSurface::setGeometry(const QRect &rect) -{ - d_ptr->geometry = rect; -} - -/*! - Returns the currently allocated area on the screen. -*/ -QRect QWindowSurface::geometry() const -{ - return d_ptr->geometry; -} -#else - -/*! - Sets the size of the windowsurface to be \a size. - - \sa size() -*/ -void QWindowSurface::resize(const QSize &size) -{ - d_ptr->size = size; -} - -/*! - Returns the current size of the windowsurface. -*/ -QSize QWindowSurface::size() const -{ - return d_ptr->size; -} -#endif //Q_WS_QPA - -/*! - Scrolls the given \a area \a dx pixels to the right and \a dy - downward; both \a dx and \a dy may be negative. - - Returns true if the area was scrolled successfully; false otherwise. -*/ -bool QWindowSurface::scroll(const QRegion &area, int dx, int dy) -{ - Q_UNUSED(area); - Q_UNUSED(dx); - Q_UNUSED(dy); - - return false; -} - -/*! - Returns a QPixmap generated from the part of the backing store - corresponding to \a window. Returns a null QPixmap if an error - occurs. The contents of the pixmap are only defined for the regions - of \a window that have received paint events since the last resize - of the backing store. - - If \a rectangle is a null rectangle (the default), the entire window - is grabbed. Otherwise, the grabbed area is limited to \a rectangle. - - The default implementation uses QWindowSurface::buffer(). - - \sa QPixmap::grabWindow() -*/ -QPixmap QWindowSurface::grabWindow(const QWindow *, const QRect &) const -{ - QPixmap result; - -#if 0 - if (window->window() != window()) - return result; - - const QImage *img = const_cast(this)->buffer(window->window()); - - if (!img || img->isNull()) - return result; - - QRect rect = rectangle.isEmpty() ? window->rect() : (window->rect() & rectangle); - - rect.translate(offset(window) - offset(window->window())); - rect &= QRect(QPoint(), img->size()); - - if (rect.isEmpty()) - return result; - - QImage subimg(img->scanLine(rect.y()) + rect.x() * img->depth() / 8, - rect.width(), rect.height(), - img->bytesPerLine(), img->format()); - subimg.detach(); //### expensive -- maybe we should have a real SubImage that shares reference count - - result = QPixmap::fromImage(subimg); -#endif - return result; -} - -/*! - Returns the offset of \a window in the coordinates of this - window surface. - */ -QPoint QWindowSurface::offset(const QWindow *) const -{ - QPoint offset; -#if 0 - QWindow *window = d_ptr->window; - QPoint offset = window->mapTo(window, QPoint()); -#endif - return offset; -} - -/*! - \fn QRect QWindowSurface::rect(const QWindow *window) const - - Returns the rectangle for \a window in the coordinates of this - window surface. -*/ - -void QWindowSurface::setStaticContents(const QRegion ®ion) -{ - d_ptr->staticContents = region; -} - -QRegion QWindowSurface::staticContents() const -{ - return d_ptr->staticContents; -} - -bool QWindowSurface::hasStaticContents() const -{ - return hasFeature(QWindowSurface::StaticContents) && !d_ptr->staticContents.isEmpty(); -} - -QWindowSurface::WindowSurfaceFeatures QWindowSurface::features() const -{ - return PartialUpdates | PreservedContents; -} - -#ifdef Q_WS_QPA -#define Q_EXPORT_SCROLLRECT Q_GUI_EXPORT -#else -#define Q_EXPORT_SCROLLRECT -#endif - -void Q_EXPORT_SCROLLRECT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset) -{ - // make sure we don't detach - uchar *mem = const_cast(const_cast(img).bits()); - - int lineskip = img.bytesPerLine(); - int depth = img.depth() >> 3; - - const QRect imageRect(0, 0, img.width(), img.height()); - const QRect r = rect & imageRect & imageRect.translated(-offset); - const QPoint p = rect.topLeft() + offset; - - if (r.isEmpty()) - return; - - const uchar *src; - uchar *dest; - - if (r.top() < p.y()) { - src = mem + r.bottom() * lineskip + r.left() * depth; - dest = mem + (p.y() + r.height() - 1) * lineskip + p.x() * depth; - lineskip = -lineskip; - } else { - src = mem + r.top() * lineskip + r.left() * depth; - dest = mem + p.y() * lineskip + p.x() * depth; - } - - const int w = r.width(); - int h = r.height(); - const int bytes = w * depth; - - // overlapping segments? - if (offset.y() == 0 && qAbs(offset.x()) < w) { - do { - ::memmove(dest, src, bytes); - dest += lineskip; - src += lineskip; - } while (--h); - } else { - do { - ::memcpy(dest, src, bytes); - dest += lineskip; - src += lineskip; - } while (--h); - } -} - -QT_END_NAMESPACE diff --git a/src/gui/painting/qwindowsurface_p.h b/src/gui/painting/qwindowsurface_p.h deleted file mode 100644 index 068df2e70f..0000000000 --- a/src/gui/painting/qwindowsurface_p.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWINDOWSURFACE_P_H -#define QWINDOWSURFACE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -class QPaintDevice; -class QRegion; -class QRect; -class QPoint; -class QImage; -class QWindowSurfacePrivate; -class QPlatformWindow; - -class Q_GUI_EXPORT QWindowSurface -{ -public: - enum WindowSurfaceFeature { - PartialUpdates = 0x00000001, // Supports doing partial updates. - PreservedContents = 0x00000002, // Supports doing flush without first doing a repaint. - StaticContents = 0x00000004, // Supports having static content regions when being resized. - AllFeatures = 0xffffffff // For convenience - }; - Q_DECLARE_FLAGS(WindowSurfaceFeatures, WindowSurfaceFeature) - - QWindowSurface(QWindow *window, bool setDefaultSurface = true); - virtual ~QWindowSurface(); - - QWindow *window() const; - - virtual QPaintDevice *paintDevice() = 0; - - // 'window' can be a child window, in which case 'region' is in child window coordinates and - // offset is the (child) window's offset in relation to the window surface. On QWS, 'offset' - // can be larger than just the offset from the top-level window as there may also be window - // decorations which are painted into the window surface. - virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) = 0; -#if !defined(Q_WS_QPA) - virtual void setGeometry(const QRect &rect); - QRect geometry() const; -#else - virtual void resize(const QSize &size); - QSize size() const; - inline QRect geometry() const { return QRect(QPoint(), size()); } //### cleanup before Qt 5 -#endif - - virtual bool scroll(const QRegion &area, int dx, int dy); - - virtual void beginPaint(const QRegion &); - virtual void endPaint(const QRegion &); - - virtual QPixmap grabWindow(const QWindow *window, const QRect& rectangle = QRect()) const; - - virtual QPoint offset(const QWindow *window) const; - inline QRect rect(const QWindow *window) const; - - bool hasFeature(WindowSurfaceFeature feature) const; - virtual WindowSurfaceFeatures features() const; - - void setStaticContents(const QRegion ®ion); - QRegion staticContents() const; - -protected: - bool hasStaticContents() const; - -private: - QWindowSurfacePrivate *d_ptr; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowSurface::WindowSurfaceFeatures) - -inline QRect QWindowSurface::rect(const QWindow *window) const -{ - return window->geometry().translated(offset(window)); -} - -inline bool QWindowSurface::hasFeature(WindowSurfaceFeature feature) const -{ - return (features() & feature) != 0; -} - -QT_END_NAMESPACE - -#endif // QWINDOWSURFACE_P_H diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 0aa2b8b202..b2f4b34b02 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -76,7 +76,6 @@ #include #include #include -#include #include #include #include diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 578ce0f660..efc00a9b66 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -57,8 +57,6 @@ SOURCES += qgl.cpp \ HEADERS += qglshaderprogram.h \ qglpixmapfilter_p.h \ qgraphicsshadereffect_p.h \ - qwindowsurface_gl_p.h \ - qpixmapdata_gl_p.h \ gl2paintengineex/qglgradientcache_p.h \ gl2paintengineex/qglengineshadermanager_p.h \ gl2paintengineex/qgl2pexvertexarray_p.h \ @@ -74,8 +72,6 @@ SOURCES += qgl.cpp \ SOURCES += qglshaderprogram.cpp \ qglpixmapfilter.cpp \ qgraphicsshadereffect.cpp \ - qwindowsurface_gl.cpp \ - qpixmapdata_gl.cpp \ gl2paintengineex/qglgradientcache.cpp \ gl2paintengineex/qglengineshadermanager.cpp \ gl2paintengineex/qgl2pexvertexarray.cpp \ @@ -96,13 +92,9 @@ x11 { contains(QT_CONFIG, egl) { SOURCES += qgl_x11egl.cpp \ qglpixelbuffer_egl.cpp \ - qgl_egl.cpp \ - qpixmapdata_x11gl_egl.cpp \ - qwindowsurface_x11gl.cpp + qgl_egl.cpp - HEADERS += qgl_egl_p.h \ - qpixmapdata_x11gl_p.h \ - qwindowsurface_x11gl_p.h + HEADERS += qgl_egl_p.h } else { SOURCES += qgl_x11.cpp \ @@ -144,16 +136,12 @@ wince*: { } symbian { - DEFINES += QGL_USE_TEXTURE_POOL QGL_NO_PRESERVED_SWAP - SOURCES -= qpixmapdata_gl.cpp + DEFINES += QGL_NO_PRESERVED_SWAP SOURCES += qgl_symbian.cpp \ - qpixmapdata_poolgl.cpp \ qglpixelbuffer_egl.cpp \ - qgl_egl.cpp \ - qgltexturepool.cpp + qgl_egl.cpp - HEADERS += qgl_egl_p.h \ - qgltexturepool_p.h + HEADERS += qgl_egl_p.h contains(QT_CONFIG, freetype) { DEFINES += QT_NO_FONTCONFIG diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index fdcfeb1864..31a4b77047 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -70,17 +70,12 @@ #if !defined(QT_OPENGL_ES_1) #include "gl2paintengineex/qpaintengineex_opengl2_p.h" -#include #endif #ifndef QT_OPENGL_ES_2 #include #endif -#ifdef Q_WS_QWS -#include -#endif - #ifdef Q_WS_QPA #include #endif @@ -90,7 +85,6 @@ #include #include -#include #include #include #include "qcolormap.h" @@ -101,9 +95,6 @@ #if defined(QT_OPENGL_ES) && !defined(QT_NO_EGL) #include #endif -#ifdef QGL_USE_TEXTURE_POOL -#include -#endif // #define QT_GL_CONTEXT_RESOURCE_DEBUG @@ -2547,18 +2538,8 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G #endif const QImage &constRef = img; // to avoid detach in bits()... -#ifdef QGL_USE_TEXTURE_POOL - QGLTexturePool::instance()->createPermanentTexture(tx_id, - target, - 0, internalFormat, - img.width(), img.height(), - externalFormat, - pixel_type, - constRef.bits()); -#else glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat, pixel_type, constRef.bits()); -#endif #if defined(QT_OPENGL_ES_2) if (genMipmap) glGenerateMipmap(target); @@ -2602,18 +2583,7 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, { Q_Q(QGLContext); QPixmapData *pd = pixmap.pixmapData(); -#if !defined(QT_OPENGL_ES_1) - if (target == GL_TEXTURE_2D && pd->classId() == QPixmapData::OpenGLClass) { - const QGLPixmapData *data = static_cast(pd); - - if (data->isValidContext(q)) { - data->bind(); - return data->texture(); - } - } -#else Q_UNUSED(pd); -#endif const qint64 key = pixmap.cacheKey(); QGLTexture *texture = textureCacheLookup(key, target); diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 7b0a237e83..f6051fa179 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -444,8 +444,6 @@ private: friend class QGL2PaintEngineEx; friend class QGL2PaintEngineExPrivate; friend class QGLEngineShaderManager; - friend class QGLWindowSurface; - friend class QGLPixmapData; friend class QGLPixmapFilterBase; friend class QGLTextureGlyphCache; friend struct QGLGlyphTexture; @@ -467,7 +465,6 @@ private: friend class QGLFBOGLPaintDevice; friend class QGLPaintDevice; friend class QGLWidgetGLPaintDevice; - friend class QX11GLPixmapData; friend class QX11GLSharedContexts; friend class QGLContextResourceBase; friend class QSGDistanceFieldGlyphCache; diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp index 4de5122a86..34b448e048 100644 --- a/src/opengl/qgl_egl.cpp +++ b/src/opengl/qgl_egl.cpp @@ -261,8 +261,7 @@ void QGLContextPrivate::destroyEglSurfaceForDevice() #if defined(Q_WS_X11) || defined(Q_OS_SYMBIAN) // Make sure we don't call eglDestroySurface on a surface which // was created for a different winId. This applies only to QGLWidget - // paint device, so make sure this is the one we're operating on - // (as opposed to a QGLWindowSurface use case). + // paint device, so make sure this is the one we're operating on. if (paintDevice && paintDevice->devType() == QInternal::Widget) { QWidget *w = static_cast(paintDevice); if (QGLWidget *wgl = qobject_cast(w)) { diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 82b6e91c5d..5b69caeb3e 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -96,10 +96,6 @@ QT_END_INCLUDE_NAMESPACE class QMacWindowChangeEvent; #endif -#ifdef Q_WS_QWS -class QWSGLWindowSurface; -#endif - #ifndef QT_NO_EGL class QEglContext; #endif @@ -212,8 +208,6 @@ public: #elif defined(Q_WS_MAC) QGLContext *olcx; void updatePaintDevice(); -#elif defined(Q_WS_QWS) - QWSGLWindowSurface *wsurf; #endif #ifdef Q_OS_SYMBIAN void recreateEglSurface(); diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp index b4e12d8b7e..08807bdd49 100644 --- a/src/opengl/qglpaintdevice.cpp +++ b/src/opengl/qglpaintdevice.cpp @@ -43,14 +43,6 @@ #include #include #include -#ifdef Q_WS_X11 -#include -#endif - -#if !defined(QT_OPENGL_ES_1) -#include -#include -#endif QT_BEGIN_NAMESPACE @@ -220,19 +212,7 @@ QGLPaintDevice* QGLPaintDevice::getDevice(QPaintDevice* pd) glpd = &(static_cast(pd)->d_func()->glDevice); break; case QInternal::Pixmap: { -#if !defined(QT_OPENGL_ES_1) - QPixmapData* pmd = static_cast(pd)->pixmapData(); - if (pmd->classId() == QPixmapData::OpenGLClass) - glpd = static_cast(pmd)->glDevice(); -#ifdef Q_WS_X11 - else if (pmd->classId() == QPixmapData::X11Class) - glpd = static_cast(pmd); -#endif - else - qWarning("Pixmap type not supported for GL rendering"); -#else - qWarning("Pixmap render targets not supported on OpenGL ES 1.x"); -#endif + qWarning("Pixmap type not supported for GL rendering"); break; } default: diff --git a/src/opengl/qglpixelbuffer.h b/src/opengl/qglpixelbuffer.h index dcd1a6ca71..1cffb0ec0b 100644 --- a/src/opengl/qglpixelbuffer.h +++ b/src/opengl/qglpixelbuffer.h @@ -109,7 +109,6 @@ private: Q_DISABLE_COPY(QGLPixelBuffer) QScopedPointer d_ptr; friend class QGLDrawable; - friend class QGLWindowSurface; friend class QGLPaintDevice; friend class QGLPBufferGLPaintDevice; friend class QGLContextPrivate; diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index c1318ffa47..c9815ec91a 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -40,7 +40,6 @@ ****************************************************************************/ #include "private/qpixmapfilter_p.h" -#include "private/qpixmapdata_gl_p.h" #include "private/qpaintengineex_opengl2_p.h" #include "private/qglengineshadermanager_p.h" #include "private/qpixmapdata_p.h" diff --git a/src/opengl/qgltexturepool.cpp b/src/opengl/qgltexturepool.cpp deleted file mode 100644 index d809328725..0000000000 --- a/src/opengl/qgltexturepool.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenVG module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgltexturepool_p.h" -#include "qpixmapdata_gl_p.h" - -QT_BEGIN_NAMESPACE - -Q_OPENGL_EXPORT extern QGLWidget* qt_gl_share_widget(); - -static QGLTexturePool *qt_gl_texture_pool = 0; - -class QGLTexturePoolPrivate -{ -public: - QGLTexturePoolPrivate() : lruFirst(0), lruLast(0) {} - - QGLPixmapData *lruFirst; - QGLPixmapData *lruLast; -}; - -QGLTexturePool::QGLTexturePool() - : d_ptr(new QGLTexturePoolPrivate()) -{ -} - -QGLTexturePool::~QGLTexturePool() -{ -} - -QGLTexturePool *QGLTexturePool::instance() -{ - if (!qt_gl_texture_pool) - qt_gl_texture_pool = new QGLTexturePool(); - return qt_gl_texture_pool; -} - -GLuint QGLTexturePool::createTextureForPixmap(GLenum target, - GLint level, - GLint internalformat, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - QGLPixmapData *data) -{ - GLuint texture; - glGenTextures(1, &texture); - glBindTexture(target, texture); - do { - glTexImage2D(target, level, internalformat, width, height, 0, format, type, 0); - GLenum error = glGetError(); - if (error == GL_NO_ERROR) { - if (data) - moveToHeadOfLRU(data); - return texture; - } else if (error != GL_OUT_OF_MEMORY) { - qWarning("QGLTexturePool: cannot create temporary texture because of invalid params"); - return 0; - } - } while (reclaimSpace(internalformat, width, height, format, type, data)); - qWarning("QGLTexturePool: cannot reclaim sufficient space for a %dx%d pixmap", - width, height); - return 0; -} - -bool QGLTexturePool::createPermanentTexture(GLuint texture, - GLenum target, - GLint level, - GLint internalformat, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - const GLvoid *data) -{ - glBindTexture(target, texture); - do { - glTexImage2D(target, level, internalformat, width, height, 0, format, type, data); - - GLenum error = glGetError(); - if (error == GL_NO_ERROR) { - return true; - } else if (error != GL_OUT_OF_MEMORY) { - qWarning("QGLTexturePool: cannot create permanent texture because of invalid params"); - return false; - } - } while (reclaimSpace(internalformat, width, height, format, type, 0)); - qWarning("QGLTexturePool: cannot reclaim sufficient space for a %dx%d pixmap", - width, height); - return 0; -} - -void QGLTexturePool::releaseTexture(QGLPixmapData *data, GLuint texture) -{ - // Very simple strategy at the moment: just destroy the texture. - if (data) - removeFromLRU(data); - - QGLWidget *shareWidget = qt_gl_share_widget(); - if (shareWidget) { - QGLShareContextScope ctx(shareWidget->context()); - glDeleteTextures(1, &texture); - } -} - -void QGLTexturePool::useTexture(QGLPixmapData *data) -{ - moveToHeadOfLRU(data); -} - -void QGLTexturePool::detachTexture(QGLPixmapData *data) -{ - removeFromLRU(data); -} - -bool QGLTexturePool::reclaimSpace(GLint internalformat, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - QGLPixmapData *data) -{ - Q_UNUSED(internalformat); // For future use in picking the best texture to eject. - Q_UNUSED(width); - Q_UNUSED(height); - Q_UNUSED(format); - Q_UNUSED(type); - - bool succeeded = false; - bool wasInLRU = false; - if (data) { - wasInLRU = data->inLRU; - moveToHeadOfLRU(data); - } - - QGLPixmapData *lrudata = pixmapLRU(); - if (lrudata && lrudata != data) { - lrudata->reclaimTexture(); - succeeded = true; - } - - if (data && !wasInLRU) - removeFromLRU(data); - - return succeeded; -} - -void QGLTexturePool::hibernate() -{ - Q_D(QGLTexturePool); - QGLPixmapData *pd = d->lruLast; - while (pd) { - QGLPixmapData *prevLRU = pd->prevLRU; - pd->inTexturePool = false; - pd->inLRU = false; - pd->nextLRU = 0; - pd->prevLRU = 0; - pd->hibernate(); - pd = prevLRU; - } - d->lruFirst = 0; - d->lruLast = 0; -} - -void QGLTexturePool::moveToHeadOfLRU(QGLPixmapData *data) -{ - Q_D(QGLTexturePool); - if (data->inLRU) { - if (!data->prevLRU) - return; // Already at the head of the list. - removeFromLRU(data); - } - data->inLRU = true; - data->nextLRU = d->lruFirst; - data->prevLRU = 0; - if (d->lruFirst) - d->lruFirst->prevLRU = data; - else - d->lruLast = data; - d->lruFirst = data; -} - -void QGLTexturePool::removeFromLRU(QGLPixmapData *data) -{ - Q_D(QGLTexturePool); - if (!data->inLRU) - return; - if (data->nextLRU) - data->nextLRU->prevLRU = data->prevLRU; - else - d->lruLast = data->prevLRU; - if (data->prevLRU) - data->prevLRU->nextLRU = data->nextLRU; - else - d->lruFirst = data->nextLRU; - data->inLRU = false; -} - -QGLPixmapData *QGLTexturePool::pixmapLRU() -{ - Q_D(QGLTexturePool); - return d->lruLast; -} - -QT_END_NAMESPACE diff --git a/src/opengl/qgltexturepool_p.h b/src/opengl/qgltexturepool_p.h deleted file mode 100644 index 27b730cbb9..0000000000 --- a/src/opengl/qgltexturepool_p.h +++ /dev/null @@ -1,147 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenVG module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGLTEXTUREPOOL_P_H -#define QGLTEXTUREPOOL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qgl.h" -#include - -QT_BEGIN_NAMESPACE - -class QGLPixmapData; -class QGLTexturePoolPrivate; - -class QGLTexturePool -{ -public: - QGLTexturePool(); - virtual ~QGLTexturePool(); - - static QGLTexturePool *instance(); - - // Create a new texture with the specified parameters and associate - // it with "data". The QGLPixmapData will be notified when the - // texture needs to be reclaimed by the pool. - // - // This function will call reclaimSpace() when texture creation fails. - GLuint createTextureForPixmap(GLenum target, - GLint level, - GLint internalformat, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - QGLPixmapData *data); - - // Create a permanent texture with the specified parameters. - // If there is insufficient space for the texture, - // then this function will call reclaimSpace() and try again. - // - // The caller is responsible for calling glDeleteTextures() - // when it no longer needs the texture, as the texture is not - // recorded in the texture pool. - bool createPermanentTexture(GLuint texture, - GLenum target, - GLint level, - GLint internalformat, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - const GLvoid *data); - - // Release a texture that is no longer required. - void releaseTexture(QGLPixmapData *data, GLuint texture); - - // Notify the pool that a QGLPixmapData object is using - // an texture again. This allows the pool to move the texture - // within a least-recently-used list of QGLPixmapData objects. - void useTexture(QGLPixmapData *data); - - // Notify the pool that the texture associated with a - // QGLPixmapData is being detached from the pool. The caller - // will become responsible for calling glDeleteTextures(). - void detachTexture(QGLPixmapData *data); - - // Reclaim space for an image allocation with the specified parameters. - // Returns true if space was reclaimed, or false if there is no - // further space that can be reclaimed. The "data" parameter - // indicates the pixmap that is trying to obtain space which should - // not itself be reclaimed. - bool reclaimSpace(GLint internalformat, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - QGLPixmapData *data); - - // Hibernate the image pool because the context is about to be - // destroyed. All textures left in the pool should be released. - void hibernate(); - -protected: - // Helper functions for managing the LRU list of QGLPixmapData objects. - void moveToHeadOfLRU(QGLPixmapData *data); - void removeFromLRU(QGLPixmapData *data); - QGLPixmapData *pixmapLRU(); - -private: - QScopedPointer d_ptr; - - Q_DECLARE_PRIVATE(QGLTexturePool) - Q_DISABLE_COPY(QGLTexturePool) -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp deleted file mode 100644 index e909ff30b9..0000000000 --- a/src/opengl/qpixmapdata_gl.cpp +++ /dev/null @@ -1,829 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qpixmap.h" -#include "qglframebufferobject.h" - -#include - -#include "qpixmapdata_gl_p.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -Q_OPENGL_EXPORT extern const QGLContext* qt_gl_share_context(); - -/*! - \class QGLFramebufferObjectPool - \since 4.6 - - \brief The QGLFramebufferObject class provides a pool of framebuffer - objects for offscreen rendering purposes. - - When requesting an FBO of a given size and format, an FBO of the same - format and a size at least as big as the requested size will be returned. - - \internal -*/ - -static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo) -{ - return qAbs(size.width() * size.height() - fbo->width() * fbo->height()); -} - -extern int qt_next_power_of_two(int v); - -static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz) -{ -#ifdef QT_OPENGL_ES_2 - QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height())); - if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height()) - return rounded; -#endif - return sz; -} - - -QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize) -{ - QGLFramebufferObject *chosen = 0; - QGLFramebufferObject *candidate = 0; - for (int i = 0; !chosen && i < m_fbos.size(); ++i) { - QGLFramebufferObject *fbo = m_fbos.at(i); - - if (strictSize) { - if (fbo->size() == requestSize && fbo->format() == requestFormat) { - chosen = fbo; - break; - } else { - continue; - } - } - - if (fbo->format() == requestFormat) { - // choose the fbo with a matching format and the closest size - if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo)) - candidate = fbo; - } - - if (candidate) { - m_fbos.removeOne(candidate); - - const QSize fboSize = candidate->size(); - QSize sz = fboSize; - - if (sz.width() < requestSize.width()) - sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5))); - if (sz.height() < requestSize.height()) - sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5))); - - // wasting too much space? - if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 4) - sz = requestSize; - - if (sz != fboSize) { - delete candidate; - candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat); - } - - chosen = candidate; - } - } - - if (!chosen) { - if (strictSize) - chosen = new QGLFramebufferObject(requestSize, requestFormat); - else - chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat); - } - - if (!chosen->isValid()) { - delete chosen; - chosen = 0; - } - - return chosen; -} - -void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo) -{ - if (fbo) - m_fbos << fbo; -} - - -QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const -{ - return data->paintEngine(); -} - -void QGLPixmapGLPaintDevice::beginPaint() -{ - if (!data->isValid()) - return; - - // QGLPaintDevice::beginPaint will store the current binding and replace - // it with m_thisFBO: - m_thisFBO = data->m_renderFbo->handle(); - QGLPaintDevice::beginPaint(); - - Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2); - - // QPixmap::fill() is deferred until now, where we actually need to do the fill: - if (data->needsFill()) { - const QColor &c = data->fillColor(); - float alpha = c.alphaF(); - glDisable(GL_SCISSOR_TEST); - glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); - glClear(GL_COLOR_BUFFER_BIT); - } - else if (!data->isUninitialized()) { - // If the pixmap (GL Texture) has valid content (it has been - // uploaded from an image or rendered into before), we need to - // copy it from the texture to the render FBO. - - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - -#if !defined(QT_OPENGL_ES_2) - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, data->width(), data->height(), 0, -999999, 999999); -#endif - - glViewport(0, 0, data->width(), data->height()); - - // Pass false to bind so it doesn't copy the FBO into the texture! - context()->drawTexture(QRect(0, 0, data->width(), data->height()), data->bind(false)); - } -} - -void QGLPixmapGLPaintDevice::endPaint() -{ - if (!data->isValid()) - return; - - data->copyBackFromRenderFbo(false); - - // Base's endPaint will restore the previous FBO binding - QGLPaintDevice::endPaint(); - - qgl_fbo_pool()->release(data->m_renderFbo); - data->m_renderFbo = 0; -} - -QGLContext* QGLPixmapGLPaintDevice::context() const -{ - data->ensureCreated(); - return data->m_ctx; -} - -QSize QGLPixmapGLPaintDevice::size() const -{ - return data->size(); -} - -bool QGLPixmapGLPaintDevice::alphaRequested() const -{ - return data->m_hasAlpha; -} - -void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d) -{ - data = d; -} - -static int qt_gl_pixmap_serial = 0; - -QGLPixmapData::QGLPixmapData(PixelType type) - : QPixmapData(type, OpenGLClass) - , m_renderFbo(0) - , m_engine(0) - , m_ctx(0) - , m_dirty(false) - , m_hasFillColor(false) - , m_hasAlpha(false) -{ - setSerialNumber(++qt_gl_pixmap_serial); - m_glDevice.setPixmapData(this); -} - -QGLPixmapData::~QGLPixmapData() -{ - const QGLContext *shareContext = qt_gl_share_context(); - if (!shareContext) - return; - - delete m_engine; - - if (m_texture.id) { - QGLShareContextScope ctx(shareContext); - glDeleteTextures(1, &m_texture.id); - } -} - -QPixmapData *QGLPixmapData::createCompatiblePixmapData() const -{ - return new QGLPixmapData(pixelType()); -} - -bool QGLPixmapData::isValid() const -{ - return w > 0 && h > 0; -} - -bool QGLPixmapData::isValidContext(const QGLContext *ctx) const -{ - if (ctx == m_ctx) - return true; - - const QGLContext *share_ctx = qt_gl_share_context(); - return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx); -} - -void QGLPixmapData::resize(int width, int height) -{ - if (width == w && height == h) - return; - - if (width <= 0 || height <= 0) { - width = 0; - height = 0; - } - - w = width; - h = height; - is_null = (w <= 0 || h <= 0); - d = pixelType() == QPixmapData::PixmapType ? 32 : 1; - - if (m_texture.id) { - QGLShareContextScope ctx(qt_gl_share_context()); - glDeleteTextures(1, &m_texture.id); - m_texture.id = 0; - } - - m_source = QImage(); - m_dirty = isValid(); - setSerialNumber(++qt_gl_pixmap_serial); -} - -void QGLPixmapData::ensureCreated() const -{ - if (!m_dirty) - return; - - m_dirty = false; - - QGLShareContextScope ctx(qt_gl_share_context()); - m_ctx = ctx; - - const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB; -#ifdef QT_OPENGL_ES_2 - const GLenum external_format = internal_format; -#else - const GLenum external_format = qt_gl_preferredTextureFormat(); -#endif - const GLenum target = GL_TEXTURE_2D; - - if (!m_texture.id) { - glGenTextures(1, &m_texture.id); - glBindTexture(target, m_texture.id); - glTexImage2D(target, 0, internal_format, w, h, 0, external_format, GL_UNSIGNED_BYTE, 0); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - - if (!m_source.isNull()) { - if (external_format == GL_RGB) { - const QImage tx = m_source.convertToFormat(QImage::Format_RGB888).mirrored(false, true); - - glBindTexture(target, m_texture.id); - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - GL_UNSIGNED_BYTE, tx.bits()); - } else { - const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format); - - glBindTexture(target, m_texture.id); - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - GL_UNSIGNED_BYTE, tx.bits()); - } - - if (useFramebufferObjects()) - m_source = QImage(); - } - - m_texture.options &= ~QGLContext::MemoryManagedBindOption; -} - -void QGLPixmapData::fromImage(const QImage &image, - Qt::ImageConversionFlags flags) -{ - QImage img = image; - createPixmapForImage(img, flags, false); -} - -void QGLPixmapData::fromImageReader(QImageReader *imageReader, - Qt::ImageConversionFlags flags) -{ - QImage image = imageReader->read(); - if (image.isNull()) - return; - - createPixmapForImage(image, flags, true); -} - -bool QGLPixmapData::fromFile(const QString &filename, const char *format, - Qt::ImageConversionFlags flags) -{ - if (pixelType() == QPixmapData::BitmapType) - return QPixmapData::fromFile(filename, format, flags); - QFile file(filename); - if (file.open(QIODevice::ReadOnly)) { - QByteArray data = file.peek(64); - bool alpha; - if (m_texture.canBindCompressedTexture - (data.constData(), data.size(), format, &alpha)) { - resize(0, 0); - data = file.readAll(); - file.close(); - QGLShareContextScope ctx(qt_gl_share_context()); - QSize size = m_texture.bindCompressedTexture - (data.constData(), data.size(), format); - if (!size.isEmpty()) { - w = size.width(); - h = size.height(); - is_null = false; - d = 32; - m_hasAlpha = alpha; - m_source = QImage(); - m_dirty = isValid(); - return true; - } - return false; - } - } - - QImage image = QImageReader(filename, format).read(); - if (image.isNull()) - return false; - - createPixmapForImage(image, flags, true); - - return !isNull(); -} - -bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, - Qt::ImageConversionFlags flags) -{ - bool alpha; - const char *buf = reinterpret_cast(buffer); - if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) { - resize(0, 0); - QGLShareContextScope ctx(qt_gl_share_context()); - QSize size = m_texture.bindCompressedTexture(buf, int(len), format); - if (!size.isEmpty()) { - w = size.width(); - h = size.height(); - is_null = false; - d = 32; - m_hasAlpha = alpha; - m_source = QImage(); - m_dirty = isValid(); - return true; - } - } - - QByteArray a = QByteArray::fromRawData(reinterpret_cast(buffer), len); - QBuffer b(&a); - b.open(QIODevice::ReadOnly); - QImage image = QImageReader(&b, format).read(); - if (image.isNull()) - return false; - - createPixmapForImage(image, flags, true); - - return !isNull(); -} - -/*! - out-of-place conversion (inPlace == false) will always detach() - */ -void QGLPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) -{ - if (image.size() == QSize(w, h)) - setSerialNumber(++qt_gl_pixmap_serial); - - resize(image.width(), image.height()); - - if (pixelType() == BitmapType) { - m_source = image.convertToFormat(QImage::Format_MonoLSB); - - } else { - QImage::Format format = QImage::Format_RGB32; - if (qApp->desktop()->depth() == 16) - format = QImage::Format_RGB16; - - if (image.hasAlphaChannel() - && ((flags & Qt::NoOpaqueDetection) - || const_cast(image).data_ptr()->checkForAlphaPixels())) - format = QImage::Format_ARGB32_Premultiplied;; - - if (inPlace && image.data_ptr()->convertInPlace(format, flags)) { - m_source = image; - } else { - m_source = image.convertToFormat(format); - - // convertToFormat won't detach the image if format stays the same. - if (image.format() == format) - m_source.detach(); - } - } - - m_dirty = true; - m_hasFillColor = false; - - m_hasAlpha = m_source.hasAlphaChannel(); - w = image.width(); - h = image.height(); - is_null = (w <= 0 || h <= 0); - d = m_source.depth(); - - if (m_texture.id) { - QGLShareContextScope ctx(qt_gl_share_context()); - glDeleteTextures(1, &m_texture.id); - m_texture.id = 0; - } -} - -bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect) -{ - Q_UNUSED(dx); - Q_UNUSED(dy); - Q_UNUSED(rect); - return false; -} - -void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect) -{ - if (data->classId() != QPixmapData::OpenGLClass || !static_cast(data)->useFramebufferObjects()) { - QPixmapData::copy(data, rect); - return; - } - - const QGLPixmapData *other = static_cast(data); - if (other->m_renderFbo) { - QGLShareContextScope ctx(qt_gl_share_context()); - - resize(rect.width(), rect.height()); - m_hasAlpha = other->m_hasAlpha; - ensureCreated(); - - if (!ctx->d_ptr->fbo) - glGenFramebuffers(1, &ctx->d_ptr->fbo); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_texture.id, 0); - - if (!other->m_renderFbo->isBound()) - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, other->m_renderFbo->handle()); - - glDisable(GL_SCISSOR_TEST); - if (ctx->d_ptr->active_engine && ctx->d_ptr->active_engine->type() == QPaintEngine::OpenGL2) - static_cast(ctx->d_ptr->active_engine)->invalidateState(); - - glBlitFramebufferEXT(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height(), - 0, 0, w, h, - GL_COLOR_BUFFER_BIT, - GL_NEAREST); - - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); - } else { - QPixmapData::copy(data, rect); - } -} - -void QGLPixmapData::fill(const QColor &color) -{ - if (!isValid()) - return; - - bool hasAlpha = color.alpha() != 255; - if (hasAlpha && !m_hasAlpha) { - if (m_texture.id) { - glDeleteTextures(1, &m_texture.id); - m_texture.id = 0; - m_dirty = true; - } - m_hasAlpha = color.alpha() != 255; - } - - if (useFramebufferObjects()) { - m_source = QImage(); - m_hasFillColor = true; - m_fillColor = color; - } else { - - if (m_source.isNull()) { - m_fillColor = color; - m_hasFillColor = true; - - } else if (m_source.depth() == 32) { - m_source.fill(PREMUL(color.rgba())); - - } else if (m_source.depth() == 1) { - if (color == Qt::color1) - m_source.fill(1); - else - m_source.fill(0); - } - } -} - -bool QGLPixmapData::hasAlphaChannel() const -{ - return m_hasAlpha; -} - -QImage QGLPixmapData::fillImage(const QColor &color) const -{ - QImage img; - if (pixelType() == BitmapType) { - img = QImage(w, h, QImage::Format_MonoLSB); - - img.setColorCount(2); - img.setColor(0, QColor(Qt::color0).rgba()); - img.setColor(1, QColor(Qt::color1).rgba()); - - if (color == Qt::color1) - img.fill(1); - else - img.fill(0); - } else { - img = QImage(w, h, - m_hasAlpha - ? QImage::Format_ARGB32_Premultiplied - : QImage::Format_RGB32); - img.fill(PREMUL(color.rgba())); - } - return img; -} - -extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha); - -QImage QGLPixmapData::toImage() const -{ - if (!isValid()) - return QImage(); - - if (m_renderFbo) { - copyBackFromRenderFbo(true); - } else if (!m_source.isNull()) { - QImageData *data = const_cast(m_source).data_ptr(); - if (data->paintEngine && data->paintEngine->isActive() - && data->paintEngine->paintDevice() == &m_source) - { - return m_source.copy(); - } - return m_source; - } else if (m_dirty || m_hasFillColor) { - return fillImage(m_fillColor); - } else { - ensureCreated(); - } - - QGLShareContextScope ctx(qt_gl_share_context()); - glBindTexture(GL_TEXTURE_2D, m_texture.id); - return qt_gl_read_texture(QSize(w, h), true, true); -} - -struct TextureBuffer -{ - QGLFramebufferObject *fbo; - QGL2PaintEngineEx *engine; -}; - -Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool) -QGLFramebufferObjectPool* qgl_fbo_pool() -{ - return _qgl_fbo_pool(); -} - -void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const -{ - if (!isValid()) - return; - - m_hasFillColor = false; - - const QGLContext *share_ctx = qt_gl_share_context(); - QGLShareContextScope ctx(share_ctx); - - ensureCreated(); - - if (!ctx->d_ptr->fbo) - glGenFramebuffers(1, &ctx->d_ptr->fbo); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_texture.id, 0); - - const int x0 = 0; - const int x1 = w; - const int y0 = 0; - const int y1 = h; - - if (!m_renderFbo->isBound()) - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle()); - - glDisable(GL_SCISSOR_TEST); - - glBlitFramebufferEXT(x0, y0, x1, y1, - x0, y0, x1, y1, - GL_COLOR_BUFFER_BIT, - GL_NEAREST); - - if (keepCurrentFboBound) { - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); - } else { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle()); - ctx->d_ptr->current_fbo = m_renderFbo->handle(); - } -} - -bool QGLPixmapData::useFramebufferObjects() const -{ - return QGLFramebufferObject::hasOpenGLFramebufferObjects() - && QGLFramebufferObject::hasOpenGLFramebufferBlit() - && qt_gl_preferGL2Engine() - && (w * h > 32*32); // avoid overhead of FBOs for small pixmaps -} - -QPaintEngine* QGLPixmapData::paintEngine() const -{ - if (!isValid()) - return 0; - - if (m_renderFbo) - return m_engine; - - if (useFramebufferObjects()) { - extern QGLWidget* qt_gl_share_widget(); - - if (!QGLContext::currentContext()) - const_cast(qt_gl_share_context())->makeCurrent(); - QGLShareContextScope ctx(qt_gl_share_context()); - - QGLFramebufferObjectFormat format; - format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); - format.setSamples(4); - format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB)); - - m_renderFbo = qgl_fbo_pool()->acquire(size(), format); - - if (m_renderFbo) { - if (!m_engine) - m_engine = new QGL2PaintEngineEx; - return m_engine; - } - - qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine"; - } - - m_dirty = true; - if (m_source.size() != size()) - m_source = QImage(size(), QImage::Format_ARGB32_Premultiplied); - if (m_hasFillColor) { - m_source.fill(PREMUL(m_fillColor.rgba())); - m_hasFillColor = false; - } - return m_source.paintEngine(); -} - -extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format); - -// If copyBack is true, bind will copy the contents of the render -// FBO to the texture (which is not bound to the texture, as it's -// a multisample FBO). -GLuint QGLPixmapData::bind(bool copyBack) const -{ - if (m_renderFbo && copyBack) { - copyBackFromRenderFbo(true); - } else { - ensureCreated(); - } - - GLuint id = m_texture.id; - glBindTexture(GL_TEXTURE_2D, id); - - if (m_hasFillColor) { - if (!useFramebufferObjects()) { - m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied); - m_source.fill(PREMUL(m_fillColor.rgba())); - } - - m_hasFillColor = false; - - GLenum format = qt_gl_preferredTextureFormat(); - QImage tx(w, h, QImage::Format_ARGB32_Premultiplied); - tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format)); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits()); - } - - return id; -} - -QGLTexture* QGLPixmapData::texture() const -{ - return &m_texture; -} - -int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const -{ - if (w == 0) - return 0; - - switch (metric) { - case QPaintDevice::PdmWidth: - return w; - case QPaintDevice::PdmHeight: - return h; - case QPaintDevice::PdmNumColors: - return 0; - case QPaintDevice::PdmDepth: - return d; - case QPaintDevice::PdmWidthMM: - return qRound(w * 25.4 / qt_defaultDpiX()); - case QPaintDevice::PdmHeightMM: - return qRound(h * 25.4 / qt_defaultDpiY()); - case QPaintDevice::PdmDpiX: - case QPaintDevice::PdmPhysicalDpiX: - return qt_defaultDpiX(); - case QPaintDevice::PdmDpiY: - case QPaintDevice::PdmPhysicalDpiY: - return qt_defaultDpiY(); - default: - qWarning("QGLPixmapData::metric(): Invalid metric"); - return 0; - } -} - -QGLPaintDevice *QGLPixmapData::glDevice() const -{ - return &m_glDevice; -} - -QT_END_NAMESPACE diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h deleted file mode 100644 index 909f264d05..0000000000 --- a/src/opengl/qpixmapdata_gl_p.h +++ /dev/null @@ -1,247 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPIXMAPDATA_GL_P_H -#define QPIXMAPDATA_GL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qgl_p.h" -#include "qgl.h" - -#include "private/qpixmapdata_p.h" -#include "private/qglpaintdevice_p.h" - -#ifdef Q_OS_SYMBIAN -#include "private/qvolatileimage_p.h" -#endif - -QT_BEGIN_NAMESPACE - -class QPaintEngine; -class QGLFramebufferObject; -class QGLFramebufferObjectFormat; -class QGLPixmapData; - -#ifdef QGL_USE_TEXTURE_POOL -void qt_gl_register_pixmap(QGLPixmapData *pd); -void qt_gl_unregister_pixmap(QGLPixmapData *pd); -void qt_gl_hibernate_pixmaps(); -#endif - -#ifdef Q_OS_SYMBIAN -class QNativeImageHandleProvider; -#endif - -class QGLFramebufferObjectPool -{ -public: - QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format, bool strictSize = false); - void release(QGLFramebufferObject *fbo); - -private: - QList m_fbos; -}; - -QGLFramebufferObjectPool* qgl_fbo_pool(); - - -class QGLPixmapGLPaintDevice : public QGLPaintDevice -{ -public: - QPaintEngine* paintEngine() const; - - void beginPaint(); - void endPaint(); - QGLContext* context() const; - QSize size() const; - bool alphaRequested() const; - - void setPixmapData(QGLPixmapData*); -private: - QGLPixmapData *data; -}; - - -class Q_OPENGL_EXPORT QGLPixmapData : public QPixmapData -{ -public: - QGLPixmapData(PixelType type); - ~QGLPixmapData(); - - QPixmapData *createCompatiblePixmapData() const; - - // Re-implemented from QPixmapData: - void resize(int width, int height); - void fromImage(const QImage &image, Qt::ImageConversionFlags flags); - void fromImageReader(QImageReader *imageReader, - Qt::ImageConversionFlags flags); - bool fromFile(const QString &filename, const char *format, - Qt::ImageConversionFlags flags); - bool fromData(const uchar *buffer, uint len, const char *format, - Qt::ImageConversionFlags flags); - void copy(const QPixmapData *data, const QRect &rect); - bool scroll(int dx, int dy, const QRect &rect); - void fill(const QColor &color); - bool hasAlphaChannel() const; - QImage toImage() const; - QPaintEngine *paintEngine() const; - int metric(QPaintDevice::PaintDeviceMetric metric) const; - - // For accessing as a target: - QGLPaintDevice *glDevice() const; - - // For accessing as a source: - bool isValidContext(const QGLContext *ctx) const; - GLuint bind(bool copyBack = true) const; - QGLTexture *texture() const; - -#ifdef QGL_USE_TEXTURE_POOL - void destroyTexture(); - // Detach this image from the image pool. - void detachTextureFromPool(); - // Release the GL resources associated with this pixmap and copy - // the pixmap's contents out of the GPU back into main memory. - // The GL resource will be automatically recreated the next time - // ensureCreated() is called. Does nothing if the pixmap cannot be - // hibernated for some reason (e.g. texture is shared with another - // process via a SgImage). - void hibernate(); - // Called when the QGLTexturePool wants to reclaim this pixmap's - // texture objects to reuse storage. - void reclaimTexture(); - void forceToImage(); -#endif - -#ifdef Q_OS_SYMBIAN - QImage::Format idealFormat(QImage &image, Qt::ImageConversionFlags flags); - void* toNativeType(NativeType type); - void fromNativeType(void* pixmap, NativeType type); - bool initFromNativeImageHandle(void *handle, const QString &type); - void createFromNativeImageHandleProvider(); - void releaseNativeImageHandle(); -#endif - -private: - bool isValid() const; - - void ensureCreated() const; - - bool isUninitialized() const { return m_dirty && m_source.isNull(); } - - bool needsFill() const { return m_hasFillColor; } - QColor fillColor() const { return m_fillColor; } - - - - QGLPixmapData(const QGLPixmapData &other); - QGLPixmapData &operator=(const QGLPixmapData &other); - - void copyBackFromRenderFbo(bool keepCurrentFboBound) const; - QSize size() const { return QSize(w, h); } - - bool useFramebufferObjects() const; - - QImage fillImage(const QColor &color) const; - - void createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace); - - mutable QGLFramebufferObject *m_renderFbo; - mutable QPaintEngine *m_engine; - mutable QGLContext *m_ctx; -#ifdef Q_OS_SYMBIAN - mutable QVolatileImage m_source; - mutable QNativeImageHandleProvider *nativeImageHandleProvider; - void *nativeImageHandle; - QString nativeImageType; -#else - mutable QImage m_source; -#endif - mutable QGLTexture m_texture; - - // the texture is not in sync with the source image - mutable bool m_dirty; - - // fill has been called and no painting has been done, so the pixmap is - // represented by a single fill color - mutable QColor m_fillColor; - mutable bool m_hasFillColor; - - mutable bool m_hasAlpha; - - mutable QGLPixmapGLPaintDevice m_glDevice; - -#ifdef QGL_USE_TEXTURE_POOL - QGLPixmapData *nextLRU; - QGLPixmapData *prevLRU; - mutable bool inLRU; - mutable bool failedToAlloc; - mutable bool inTexturePool; - - QGLPixmapData *next; - QGLPixmapData *prev; - - friend class QGLTexturePool; - - friend void qt_gl_register_pixmap(QGLPixmapData *pd); - friend void qt_gl_unregister_pixmap(QGLPixmapData *pd); - friend void qt_gl_hibernate_pixmaps(); -#endif - - friend class QGLPixmapGLPaintDevice; - friend class QMeeGoPixmapData; - friend class QMeeGoLivePixmapData; -}; - -QT_END_NAMESPACE - -#endif // QPIXMAPDATA_GL_P_H - - diff --git a/src/opengl/qpixmapdata_poolgl.cpp b/src/opengl/qpixmapdata_poolgl.cpp deleted file mode 100644 index 5dd7b09c64..0000000000 --- a/src/opengl/qpixmapdata_poolgl.cpp +++ /dev/null @@ -1,934 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qpixmap.h" -#include "qglframebufferobject.h" - -#include - -#include "qpixmapdata_gl_p.h" - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "qgltexturepool_p.h" - -QT_BEGIN_NAMESPACE - -Q_OPENGL_EXPORT extern QGLWidget* qt_gl_share_widget(); - -static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo) -{ - return qAbs(size.width() * size.height() - fbo->width() * fbo->height()); -} - -extern int qt_next_power_of_two(int v); - -static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz) -{ -#ifdef QT_OPENGL_ES_2 - QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height())); - if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height()) - return rounded; -#endif - return sz; -} - - -QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize) -{ - QGLFramebufferObject *chosen = 0; - QGLFramebufferObject *candidate = 0; - for (int i = 0; !chosen && i < m_fbos.size(); ++i) { - QGLFramebufferObject *fbo = m_fbos.at(i); - - if (strictSize) { - if (fbo->size() == requestSize && fbo->format() == requestFormat) { - chosen = fbo; - break; - } else { - continue; - } - } - - if (fbo->format() == requestFormat) { - // choose the fbo with a matching format and the closest size - if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo)) - candidate = fbo; - } - - if (candidate) { - m_fbos.removeOne(candidate); - - const QSize fboSize = candidate->size(); - QSize sz = fboSize; - - if (sz.width() < requestSize.width()) - sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5))); - if (sz.height() < requestSize.height()) - sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5))); - - // wasting too much space? - if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 4) - sz = requestSize; - - if (sz != fboSize) { - delete candidate; - candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat); - } - - chosen = candidate; - } - } - - if (!chosen) { - if (strictSize) - chosen = new QGLFramebufferObject(requestSize, requestFormat); - else - chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat); - } - - if (!chosen->isValid()) { - delete chosen; - chosen = 0; - } - - return chosen; -} - -void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo) -{ - if (fbo) - m_fbos << fbo; -} - - -QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const -{ - return data->paintEngine(); -} - -void QGLPixmapGLPaintDevice::beginPaint() -{ - if (!data->isValid()) - return; - - // QGLPaintDevice::beginPaint will store the current binding and replace - // it with m_thisFBO: - m_thisFBO = data->m_renderFbo->handle(); - QGLPaintDevice::beginPaint(); - - Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2); - - // QPixmap::fill() is deferred until now, where we actually need to do the fill: - if (data->needsFill()) { - const QColor &c = data->fillColor(); - float alpha = c.alphaF(); - glDisable(GL_SCISSOR_TEST); - glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); - glClear(GL_COLOR_BUFFER_BIT); - } - else if (!data->isUninitialized()) { - // If the pixmap (GL Texture) has valid content (it has been - // uploaded from an image or rendered into before), we need to - // copy it from the texture to the render FBO. - - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - -#if !defined(QT_OPENGL_ES_2) - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, data->width(), data->height(), 0, -999999, 999999); -#endif - - glViewport(0, 0, data->width(), data->height()); - - // Pass false to bind so it doesn't copy the FBO into the texture! - context()->drawTexture(QRect(0, 0, data->width(), data->height()), data->bind(false)); - } -} - -void QGLPixmapGLPaintDevice::endPaint() -{ - if (!data->isValid()) - return; - - data->copyBackFromRenderFbo(false); - - // Base's endPaint will restore the previous FBO binding - QGLPaintDevice::endPaint(); - - qgl_fbo_pool()->release(data->m_renderFbo); - data->m_renderFbo = 0; -} - -QGLContext* QGLPixmapGLPaintDevice::context() const -{ - data->ensureCreated(); - return data->m_ctx; -} - -QSize QGLPixmapGLPaintDevice::size() const -{ - return data->size(); -} - -bool QGLPixmapGLPaintDevice::alphaRequested() const -{ - return data->m_hasAlpha; -} - -void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d) -{ - data = d; -} - -int qt_gl_pixmap_serial = 0; - -QGLPixmapData::QGLPixmapData(PixelType type) - : QPixmapData(type, OpenGLClass) - , m_renderFbo(0) - , m_engine(0) - , m_ctx(0) - , nativeImageHandleProvider(0) - , nativeImageHandle(0) - , m_dirty(false) - , m_hasFillColor(false) - , m_hasAlpha(false) - , inLRU(false) - , failedToAlloc(false) - , inTexturePool(false) -{ - setSerialNumber(++qt_gl_pixmap_serial); - m_glDevice.setPixmapData(this); - - qt_gl_register_pixmap(this); -} - -QGLPixmapData::~QGLPixmapData() -{ - delete m_engine; - - destroyTexture(); - qt_gl_unregister_pixmap(this); -} - -void QGLPixmapData::destroyTexture() -{ - if (inTexturePool) { - QGLTexturePool *pool = QGLTexturePool::instance(); - if (m_texture.id) - pool->releaseTexture(this, m_texture.id); - } else { - if (m_texture.id) { - QGLWidget *shareWidget = qt_gl_share_widget(); - if (shareWidget) { - QGLShareContextScope ctx(shareWidget->context()); - glDeleteTextures(1, &m_texture.id); - } - } - } - m_texture.id = 0; - inTexturePool = false; - - releaseNativeImageHandle(); -} - -QPixmapData *QGLPixmapData::createCompatiblePixmapData() const -{ - return new QGLPixmapData(pixelType()); -} - -bool QGLPixmapData::isValid() const -{ - return w > 0 && h > 0; -} - -bool QGLPixmapData::isValidContext(const QGLContext *ctx) const -{ - if (ctx == m_ctx) - return true; - - const QGLContext *share_ctx = qt_gl_share_widget()->context(); - return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx); -} - -void QGLPixmapData::resize(int width, int height) -{ - if (width == w && height == h) - return; - - if (width <= 0 || height <= 0) { - width = 0; - height = 0; - } - - w = width; - h = height; - is_null = (w <= 0 || h <= 0); - d = pixelType() == QPixmapData::PixmapType ? 32 : 1; - - destroyTexture(); - - m_source = QVolatileImage(); - m_dirty = isValid(); - setSerialNumber(++qt_gl_pixmap_serial); -} - -void QGLPixmapData::ensureCreated() const -{ - if (!m_dirty) - return; - - m_dirty = false; - - if (nativeImageHandleProvider && !nativeImageHandle) - const_cast(this)->createFromNativeImageHandleProvider(); - - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - m_ctx = ctx; - - const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB; -#ifdef QT_OPENGL_ES_2 - const GLenum external_format = internal_format; -#else - const GLenum external_format = qt_gl_preferredTextureFormat(); -#endif - const GLenum target = GL_TEXTURE_2D; - - GLenum type = GL_UNSIGNED_BYTE; - // Avoid conversion when pixmap is created from CFbsBitmap of EColor64K. - if (!m_source.isNull() && m_source.format() == QImage::Format_RGB16) - type = GL_UNSIGNED_SHORT_5_6_5; - - m_texture.options &= ~QGLContext::MemoryManagedBindOption; - - if (!m_texture.id) { - m_texture.id = QGLTexturePool::instance()->createTextureForPixmap( - target, - 0, internal_format, - w, h, - external_format, - type, - const_cast(this)); - if (!m_texture.id) { - failedToAlloc = true; - return; - } - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - inTexturePool = true; - } else if (inTexturePool) { - glBindTexture(target, m_texture.id); - QGLTexturePool::instance()->useTexture(const_cast(this)); - } - - if (!m_source.isNull() && m_texture.id) { - if (external_format == GL_RGB) { - m_source.beginDataAccess(); - QImage tx; - if (type == GL_UNSIGNED_BYTE) - tx = m_source.imageRef().convertToFormat(QImage::Format_RGB888).mirrored(false, true); - else if (type == GL_UNSIGNED_SHORT_5_6_5) - tx = m_source.imageRef().mirrored(false, true); - m_source.endDataAccess(true); - - glBindTexture(target, m_texture.id); - if (!tx.isNull()) - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - type, tx.constBits()); - else - qWarning("QGLPixmapData: Failed to create GL_RGB image of size %dx%d", w, h); - } else { - // do byte swizzling ARGB -> RGBA - m_source.beginDataAccess(); - const QImage tx = ctx->d_func()->convertToGLFormat(m_source.imageRef(), true, external_format); - m_source.endDataAccess(true); - glBindTexture(target, m_texture.id); - if (!tx.isNull()) - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - type, tx.constBits()); - else - qWarning("QGLPixmapData: Failed to create GL_RGBA image of size %dx%d", w, h); - } - - if (useFramebufferObjects()) - m_source = QVolatileImage(); - } -} - - -void QGLPixmapData::fromImage(const QImage &image, - Qt::ImageConversionFlags flags) -{ - QImage img = image; - createPixmapForImage(img, flags, false); -} - -void QGLPixmapData::fromImageReader(QImageReader *imageReader, - Qt::ImageConversionFlags flags) -{ - QImage image = imageReader->read(); - if (image.isNull()) - return; - - createPixmapForImage(image, flags, true); -} - -bool QGLPixmapData::fromFile(const QString &filename, const char *format, - Qt::ImageConversionFlags flags) -{ - if (pixelType() == QPixmapData::BitmapType) - return QPixmapData::fromFile(filename, format, flags); - QFile file(filename); - if (file.open(QIODevice::ReadOnly)) { - QByteArray data = file.peek(64); - bool alpha; - if (m_texture.canBindCompressedTexture - (data.constData(), data.size(), format, &alpha)) { - resize(0, 0); - data = file.readAll(); - file.close(); - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - QSize size = m_texture.bindCompressedTexture - (data.constData(), data.size(), format); - if (!size.isEmpty()) { - w = size.width(); - h = size.height(); - is_null = false; - d = 32; - m_hasAlpha = alpha; - m_source = QVolatileImage(); - m_dirty = isValid(); - return true; - } - return false; - } - } - - QImage image = QImageReader(filename, format).read(); - if (image.isNull()) - return false; - - createPixmapForImage(image, flags, true); - - return !isNull(); -} - -bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, - Qt::ImageConversionFlags flags) -{ - bool alpha; - const char *buf = reinterpret_cast(buffer); - if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) { - resize(0, 0); - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - QSize size = m_texture.bindCompressedTexture(buf, int(len), format); - if (!size.isEmpty()) { - w = size.width(); - h = size.height(); - is_null = false; - d = 32; - m_hasAlpha = alpha; - m_source = QVolatileImage(); - m_dirty = isValid(); - return true; - } - } - - QByteArray a = QByteArray::fromRawData(reinterpret_cast(buffer), len); - QBuffer b(&a); - b.open(QIODevice::ReadOnly); - QImage image = QImageReader(&b, format).read(); - if (image.isNull()) - return false; - - createPixmapForImage(image, flags, true); - - return !isNull(); -} - -QImage::Format QGLPixmapData::idealFormat(QImage &image, Qt::ImageConversionFlags flags) -{ - QImage::Format format = QImage::Format_RGB32; - if (qApp->desktop()->depth() == 16) - format = QImage::Format_RGB16; - - if (image.hasAlphaChannel() - && ((flags & Qt::NoOpaqueDetection) - || const_cast(image).data_ptr()->checkForAlphaPixels())) - format = QImage::Format_ARGB32_Premultiplied; - - return format; -} - -void QGLPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) -{ - if (image.size() == QSize(w, h)) - setSerialNumber(++qt_gl_pixmap_serial); - - resize(image.width(), image.height()); - - if (pixelType() == BitmapType) { - QImage convertedImage = image.convertToFormat(QImage::Format_MonoLSB); - if (image.format() == QImage::Format_MonoLSB) - convertedImage.detach(); - - m_source = QVolatileImage(convertedImage); - - } else { - QImage::Format format = idealFormat(image, flags); - - if (inPlace && image.data_ptr()->convertInPlace(format, flags)) { - m_source = QVolatileImage(image); - } else { - QImage convertedImage = image.convertToFormat(format); - - // convertToFormat won't detach the image if format stays the same. - if (image.format() == format) - convertedImage.detach(); - - m_source = QVolatileImage(convertedImage); - } - } - - m_dirty = true; - m_hasFillColor = false; - - m_hasAlpha = m_source.hasAlphaChannel(); - w = image.width(); - h = image.height(); - is_null = (w <= 0 || h <= 0); - d = m_source.depth(); - - destroyTexture(); -} - -bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect) -{ - Q_UNUSED(dx); - Q_UNUSED(dy); - Q_UNUSED(rect); - return false; -} - -void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect) -{ - if (data->classId() != QPixmapData::OpenGLClass || !static_cast(data)->useFramebufferObjects()) { - QPixmapData::copy(data, rect); - return; - } - - const QGLPixmapData *other = static_cast(data); - if (other->m_renderFbo) { - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - - resize(rect.width(), rect.height()); - m_hasAlpha = other->m_hasAlpha; - ensureCreated(); - - if (!ctx->d_ptr->fbo) - glGenFramebuffers(1, &ctx->d_ptr->fbo); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_texture.id, 0); - - if (!other->m_renderFbo->isBound()) - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, other->m_renderFbo->handle()); - - glDisable(GL_SCISSOR_TEST); - if (ctx->d_ptr->active_engine && ctx->d_ptr->active_engine->type() == QPaintEngine::OpenGL2) - static_cast(ctx->d_ptr->active_engine)->invalidateState(); - - glBlitFramebufferEXT(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height(), - 0, 0, w, h, - GL_COLOR_BUFFER_BIT, - GL_NEAREST); - - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); - } else { - QPixmapData::copy(data, rect); - } -} - -void QGLPixmapData::fill(const QColor &color) -{ - if (!isValid()) - return; - - bool hasAlpha = color.alpha() != 255; - if (hasAlpha && !m_hasAlpha) { - if (m_texture.id) { - destroyTexture(); - m_dirty = true; - } - m_hasAlpha = color.alpha() != 255; - } - - if (useFramebufferObjects()) { - m_source = QVolatileImage(); - m_hasFillColor = true; - m_fillColor = color; - } else { - forceToImage(); - - if (m_source.depth() == 32) { - m_source.fill(PREMUL(color.rgba())); - - } else if (m_source.depth() == 1) { - if (color == Qt::color1) - m_source.fill(1); - else - m_source.fill(0); - } - } -} - -bool QGLPixmapData::hasAlphaChannel() const -{ - return m_hasAlpha; -} - -QImage QGLPixmapData::fillImage(const QColor &color) const -{ - QImage img; - if (pixelType() == BitmapType) { - img = QImage(w, h, QImage::Format_MonoLSB); - - img.setColorCount(2); - img.setColor(0, QColor(Qt::color0).rgba()); - img.setColor(1, QColor(Qt::color1).rgba()); - - if (color == Qt::color1) - img.fill(1); - else - img.fill(0); - } else { - img = QImage(w, h, - m_hasAlpha - ? QImage::Format_ARGB32_Premultiplied - : QImage::Format_RGB32); - img.fill(PREMUL(color.rgba())); - } - return img; -} - -extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha); - -QImage QGLPixmapData::toImage() const -{ - if (!isValid()) - return QImage(); - - if (m_renderFbo) { - copyBackFromRenderFbo(true); - } else if (!m_source.isNull()) { - // QVolatileImage::toImage() will make a copy always so no check - // for active painting is needed. - QImage img = m_source.toImage(); - if (img.format() == QImage::Format_MonoLSB) { - img.setColorCount(2); - img.setColor(0, QColor(Qt::color0).rgba()); - img.setColor(1, QColor(Qt::color1).rgba()); - } - return img; - } else if (m_dirty || m_hasFillColor) { - return fillImage(m_fillColor); - } else { - ensureCreated(); - } - - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - glBindTexture(GL_TEXTURE_2D, m_texture.id); - return qt_gl_read_texture(QSize(w, h), true, true); -} - -struct TextureBuffer -{ - QGLFramebufferObject *fbo; - QGL2PaintEngineEx *engine; -}; - -Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool) -QGLFramebufferObjectPool* qgl_fbo_pool() -{ - return _qgl_fbo_pool(); -} - -void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const -{ - if (!isValid()) - return; - - m_hasFillColor = false; - - const QGLContext *share_ctx = qt_gl_share_widget()->context(); - QGLShareContextScope ctx(share_ctx); - - ensureCreated(); - - if (!ctx->d_ptr->fbo) - glGenFramebuffers(1, &ctx->d_ptr->fbo); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_texture.id, 0); - - const int x0 = 0; - const int x1 = w; - const int y0 = 0; - const int y1 = h; - - if (!m_renderFbo->isBound()) - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle()); - - glDisable(GL_SCISSOR_TEST); - - glBlitFramebufferEXT(x0, y0, x1, y1, - x0, y0, x1, y1, - GL_COLOR_BUFFER_BIT, - GL_NEAREST); - - if (keepCurrentFboBound) { - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); - } else { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle()); - ctx->d_ptr->current_fbo = m_renderFbo->handle(); - } -} - -bool QGLPixmapData::useFramebufferObjects() const -{ -#ifdef Q_OS_SYMBIAN - // We don't want to use FBOs on Symbian - return false; -#else - return QGLFramebufferObject::hasOpenGLFramebufferObjects() - && QGLFramebufferObject::hasOpenGLFramebufferBlit() - && qt_gl_preferGL2Engine() - && (w * h > 32*32); // avoid overhead of FBOs for small pixmaps -#endif -} - -QPaintEngine* QGLPixmapData::paintEngine() const -{ - if (!isValid()) - return 0; - - if (m_renderFbo) - return m_engine; - - if (useFramebufferObjects()) { - extern QGLWidget* qt_gl_share_widget(); - - if (!QGLContext::currentContext()) - qt_gl_share_widget()->makeCurrent(); - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - - QGLFramebufferObjectFormat format; - format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); - format.setSamples(4); - format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB)); - - m_renderFbo = qgl_fbo_pool()->acquire(size(), format); - - if (m_renderFbo) { - if (!m_engine) - m_engine = new QGL2PaintEngineEx; - return m_engine; - } - - qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine"; - } - - // If the application wants to paint into the QPixmap, we first - // force it to QImage format and then paint into that. - // This is simpler than juggling multiple GL contexts. - const_cast(this)->forceToImage(); - - if (m_hasFillColor) { - m_source.fill(PREMUL(m_fillColor.rgba())); - m_hasFillColor = false; - } - return m_source.paintEngine(); -} - -extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format); - -// If copyBack is true, bind will copy the contents of the render -// FBO to the texture (which is not bound to the texture, as it's -// a multisample FBO). -GLuint QGLPixmapData::bind(bool copyBack) const -{ - if (m_renderFbo && copyBack) { - copyBackFromRenderFbo(true); - } else { - ensureCreated(); - } - - GLuint id = m_texture.id; - glBindTexture(GL_TEXTURE_2D, id); - - if (m_hasFillColor) { - if (!useFramebufferObjects()) { - m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); - m_source.fill(PREMUL(m_fillColor.rgba())); - } - - m_hasFillColor = false; - - GLenum format = qt_gl_preferredTextureFormat(); - QImage tx(w, h, QImage::Format_ARGB32_Premultiplied); - tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format)); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.constBits()); - } - - return id; -} - -QGLTexture* QGLPixmapData::texture() const -{ - return &m_texture; -} - -void QGLPixmapData::detachTextureFromPool() -{ - if (inTexturePool) { - QGLTexturePool::instance()->detachTexture(this); - inTexturePool = false; - } -} - -void QGLPixmapData::hibernate() -{ - // If the image was imported (e.g, from an SgImage under Symbian), then - // skip the hibernation, there is no sense in copying it back to main - // memory because the data is most likely shared between several processes. - bool skipHibernate = (m_texture.id && m_source.isNull()); -#if defined(Q_OS_SYMBIAN) - // However we have to proceed normally if the image was retrieved via - // a handle provider. - skipHibernate &= !nativeImageHandleProvider; -#endif - if (skipHibernate) - return; - - forceToImage(); - destroyTexture(); -} - -void QGLPixmapData::reclaimTexture() -{ - if (!inTexturePool) - return; - forceToImage(); - destroyTexture(); -} - -int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const -{ - if (w == 0) - return 0; - - switch (metric) { - case QPaintDevice::PdmWidth: - return w; - case QPaintDevice::PdmHeight: - return h; - case QPaintDevice::PdmNumColors: - return 0; - case QPaintDevice::PdmDepth: - return d; - case QPaintDevice::PdmWidthMM: - return qRound(w * 25.4 / qt_defaultDpiX()); - case QPaintDevice::PdmHeightMM: - return qRound(h * 25.4 / qt_defaultDpiY()); - case QPaintDevice::PdmDpiX: - case QPaintDevice::PdmPhysicalDpiX: - return qt_defaultDpiX(); - case QPaintDevice::PdmDpiY: - case QPaintDevice::PdmPhysicalDpiY: - return qt_defaultDpiY(); - default: - qWarning("QGLPixmapData::metric(): Invalid metric"); - return 0; - } -} - -// Force the pixmap data to be backed by some valid data. -void QGLPixmapData::forceToImage() -{ - if (!isValid()) - return; - - if (m_source.isNull()) { - QImage::Format format = QImage::Format_ARGB32_Premultiplied; - if (pixelType() == BitmapType) - format = QImage::Format_MonoLSB; - m_source = QVolatileImage(w, h, format); - } - - m_dirty = true; -} - -QGLPaintDevice *QGLPixmapData::glDevice() const -{ - return &m_glDevice; -} - -QT_END_NAMESPACE diff --git a/src/opengl/qpixmapdata_x11gl_egl.cpp b/src/opengl/qpixmapdata_x11gl_egl.cpp deleted file mode 100644 index 8a8eb38b7c..0000000000 --- a/src/opengl/qpixmapdata_x11gl_egl.cpp +++ /dev/null @@ -1,403 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include - -#include -#include -#include -#include - -#if !defined(QT_OPENGL_ES_1) -#include -#endif - -#ifndef QT_OPENGL_ES_2 -#include -#endif - -#include -#include - -#include "qpixmapdata_x11gl_p.h" - -QT_BEGIN_NAMESPACE - - -class QX11GLSharedContexts -{ -public: - QX11GLSharedContexts() - : rgbContext(0) - , argbContext(0) - , sharedQGLContext(0) - , sharePixmap(0) - { - EGLint rgbConfigId; - EGLint argbConfigId; - - do { - EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable); - EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, - QEgl::Renderable | QEgl::Translucent); - - eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId); - eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId); - - rgbContext = new QEglContext; - rgbContext->setConfig(rgbConfig); - rgbContext->createContext(); - - if (!rgbContext->isValid()) - break; - - // If the RGB & ARGB configs are the same, use the same egl context for both: - if (rgbConfig == argbConfig) - argbContext = rgbContext; - - // Otherwise, create a separate context to be used for ARGB pixmaps: - if (!argbContext) { - argbContext = new QEglContext; - argbContext->setConfig(argbConfig); - bool success = argbContext->createContext(rgbContext); - if (!success) { - qWarning("QX11GLPixmapData - RGB & ARGB contexts aren't shared"); - success = argbContext->createContext(); - if (!success) - argbContext = rgbContext; // Might work, worth a shot at least. - } - } - - if (!argbContext->isValid()) - break; - - // Create the pixmap which will be used to create the egl surface for the share QGLContext - QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); - rgbPixmapData->resize(8, 8); - rgbPixmapData->fill(Qt::red); - sharePixmap = new QPixmap(rgbPixmapData); - EGLSurface sharePixmapSurface = QEgl::createSurface(sharePixmap, rgbConfig); - rgbPixmapData->gl_surface = (void*)sharePixmapSurface; - - // Create the actual QGLContext which will be used for sharing - sharedQGLContext = new QGLContext(QX11GLPixmapData::glFormat()); - sharedQGLContext->d_func()->eglContext = rgbContext; - sharedQGLContext->d_func()->eglSurface = sharePixmapSurface; - sharedQGLContext->d_func()->valid = true; - qt_glformat_from_eglconfig(sharedQGLContext->d_func()->glFormat, rgbConfig); - - - valid = rgbContext->makeCurrent(sharePixmapSurface); - - // If the ARGB & RGB configs are different, check ARGB works too: - if (argbConfig != rgbConfig) { - QX11PixmapData *argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); - argbPixmapData->resize(8, 8); - argbPixmapData->fill(Qt::transparent); // Force ARGB - QPixmap argbPixmap(argbPixmapData); // destroys pixmap data when goes out of scope - EGLSurface argbPixmapSurface = QEgl::createSurface(&argbPixmap, argbConfig); - valid = argbContext->makeCurrent(argbPixmapSurface); - argbContext->doneCurrent(); - eglDestroySurface(QEgl::display(), argbPixmapSurface); - argbPixmapData->gl_surface = 0; - } - - if (!valid) { - qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString(); - break; - } - - // The pixmap surface destruction hooks are installed by QGLTextureCache, so we - // must make sure this is instanciated: - QGLTextureCache::instance(); - } while(0); - - if (!valid) - cleanup(); - else - qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); - - } - - ~QX11GLSharedContexts() { - cleanup(); - } - - void cleanup() { - if (sharedQGLContext) { - delete sharedQGLContext; - sharedQGLContext = 0; - } - if (argbContext && argbContext != rgbContext) - delete argbContext; - argbContext = 0; - - if (rgbContext) { - delete rgbContext; - rgbContext = 0; - } - - // Deleting the QPixmap will fire the pixmap destruction cleanup hooks which in turn - // will destroy the egl surface: - if (sharePixmap) { - delete sharePixmap; - sharePixmap = 0; - } - } - - bool isValid() { return valid;} - - // On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need - // different contexts: - QEglContext *rgbContext; - QEglContext *argbContext; - - // The share context wraps the rgbContext and is used as the master of the context share - // group. As all other contexts will have the same egl context (or a shared one if rgb != argb) - // all QGLContexts will actually be sharing and can be in the same context group. - QGLContext *sharedQGLContext; -private: - QPixmap *sharePixmap; - bool valid; -}; - -static void qt_cleanup_x11gl_share_contexts(); - -Q_GLOBAL_STATIC_WITH_INITIALIZER(QX11GLSharedContexts, qt_x11gl_share_contexts, - { - qAddPostRoutine(qt_cleanup_x11gl_share_contexts); - }) - -static void qt_cleanup_x11gl_share_contexts() -{ - qt_x11gl_share_contexts()->cleanup(); -} - - -QX11GLSharedContexts* QX11GLPixmapData::sharedContexts() -{ - return qt_x11gl_share_contexts(); -} - -bool QX11GLPixmapData::hasX11GLPixmaps() -{ - static bool checkedForX11GLPixmaps = false; - static bool haveX11GLPixmaps = false; - - if (checkedForX11GLPixmaps) - return haveX11GLPixmaps; - - haveX11GLPixmaps = qt_x11gl_share_contexts()->isValid(); - checkedForX11GLPixmaps = true; - - return haveX11GLPixmaps; -} - -QX11GLPixmapData::QX11GLPixmapData() - : QX11PixmapData(QPixmapData::PixmapType), - ctx(0) -{ -} - -QX11GLPixmapData::~QX11GLPixmapData() -{ - if (ctx) - delete ctx; -} - - -void QX11GLPixmapData::fill(const QColor &color) -{ - if (ctx) { - ctx->makeCurrent(); - glFinish(); - eglWaitClient(); - } - - QX11PixmapData::fill(color); - XSync(X11->display, False); - - if (ctx) { - ctx->makeCurrent(); - eglWaitNative(EGL_CORE_NATIVE_ENGINE); - } -} - -void QX11GLPixmapData::copy(const QPixmapData *data, const QRect &rect) -{ - if (ctx) { - ctx->makeCurrent(); - glFinish(); - eglWaitClient(); - } - - QX11PixmapData::copy(data, rect); - XSync(X11->display, False); - - if (ctx) { - ctx->makeCurrent(); - eglWaitNative(EGL_CORE_NATIVE_ENGINE); - } -} - -bool QX11GLPixmapData::scroll(int dx, int dy, const QRect &rect) -{ - if (ctx) { - ctx->makeCurrent(); - glFinish(); - eglWaitClient(); - } - - bool success = QX11PixmapData::scroll(dx, dy, rect); - XSync(X11->display, False); - - if (ctx) { - ctx->makeCurrent(); - eglWaitNative(EGL_CORE_NATIVE_ENGINE); - } - - return success; -} - -#if !defined(QT_OPENGL_ES_1) -Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_pixmap_2_engine) -#endif - -#ifndef QT_OPENGL_ES_2 -Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_pixmap_engine) -#endif - - -QPaintEngine* QX11GLPixmapData::paintEngine() const -{ - // We need to create the context before beginPaint - do it here: - if (!ctx) { - ctx = new QGLContext(glFormat()); - Q_ASSERT(ctx->d_func()->eglContext == 0); - ctx->d_func()->eglContext = hasAlphaChannel() ? sharedContexts()->argbContext : sharedContexts()->rgbContext; - - // While we use a separate QGLContext for each pixmap, the underlying QEglContext is - // the same. So we must use a "fake" QGLContext and fool the texture cache into thinking - // each pixmap's QGLContext is sharing with this central one. The only place this is - // going to fail is where we the underlying EGL RGB and ARGB contexts aren't sharing. - ctx->d_func()->sharing = true; - QGLContextGroup::addShare(ctx, sharedContexts()->sharedQGLContext); - - // Update the glFormat for the QGLContext: - qt_glformat_from_eglconfig(ctx->d_func()->glFormat, ctx->d_func()->eglContext->config()); - } - - QPaintEngine* engine; - -#if defined(QT_OPENGL_ES_1) - engine = qt_gl_pixmap_engine(); -#elif defined(QT_OPENGL_ES_2) - engine = qt_gl_pixmap_2_engine(); -#else - if (qt_gl_preferGL2Engine()) - engine = qt_gl_pixmap_2_engine(); - else - engine = qt_gl_pixmap_engine(); -#endif - - - - // Support multiple painters on multiple pixmaps simultaniously - if (engine->isActive()) { - qWarning("Pixmap paint engine already active"); - -#if defined(QT_OPENGL_ES_1) - engine = new QOpenGLPaintEngine; -#elif defined(QT_OPENGL_ES_2) - engine = new QGL2PaintEngineEx; -#else - if (qt_gl_preferGL2Engine()) - engine = new QGL2PaintEngineEx; - else - engine = new QOpenGLPaintEngine; -#endif - - engine->setAutoDestruct(true); - return engine; - } - - return engine; -} - -void QX11GLPixmapData::beginPaint() -{ -// qDebug("QX11GLPixmapData::beginPaint()"); - // TODO: Check to see if the surface is renderable - if ((EGLSurface)gl_surface == EGL_NO_SURFACE) { - QPixmap tmpPixmap(this); - EGLConfig cfg = ctx->d_func()->eglContext->config(); - Q_ASSERT(cfg != QEGL_NO_CONFIG); - -// qDebug("QX11GLPixmapData - using EGL Config ID %d", ctx->d_func()->eglContext->configAttrib(EGL_CONFIG_ID)); - EGLSurface surface = QEgl::createSurface(&tmpPixmap, cfg); - if (surface == EGL_NO_SURFACE) { - qWarning() << "Error creating EGL surface for pixmap:" << QEgl::errorString(); - return; - } - gl_surface = (void*)surface; - ctx->d_func()->eglSurface = surface; - ctx->d_func()->valid = true; - } - QGLPaintDevice::beginPaint(); -} - -QGLContext* QX11GLPixmapData::context() const -{ - return ctx; -} - -QSize QX11GLPixmapData::size() const -{ - return QSize(w, h); -} - - -QGLFormat QX11GLPixmapData::glFormat() -{ - return QGLFormat::defaultFormat(); //### -} - -QT_END_NAMESPACE diff --git a/src/opengl/qpixmapdata_x11gl_p.h b/src/opengl/qpixmapdata_x11gl_p.h deleted file mode 100644 index 0a6c4e8f2f..0000000000 --- a/src/opengl/qpixmapdata_x11gl_p.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPIXMAPDATA_X11GL_P_H -#define QPIXMAPDATA_X11GL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -#include - -#ifndef QT_NO_EGL -#include -#endif - -QT_BEGIN_NAMESPACE - -class QX11GLSharedContexts; - -class QX11GLPixmapData : public QX11PixmapData, public QGLPaintDevice -{ -public: - QX11GLPixmapData(); - virtual ~QX11GLPixmapData(); - - // Re-implemented from QX11PixmapData: - void fill(const QColor &color); - void copy(const QPixmapData *data, const QRect &rect); - bool scroll(int dx, int dy, const QRect &rect); - - // Re-implemented from QGLPaintDevice - QPaintEngine* paintEngine() const; // Also re-implements QX11PixmapData::paintEngine - void beginPaint(); - QGLContext* context() const; - QSize size() const; - - static bool hasX11GLPixmaps(); - static QGLFormat glFormat(); - static QX11GLSharedContexts* sharedContexts(); - -private: - mutable QGLContext* ctx; -}; - - -QT_END_NAMESPACE - -#endif // QPIXMAPDATA_X11GL_P_H diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp deleted file mode 100644 index d3e7e5178e..0000000000 --- a/src/opengl/qwindowsurface_gl.cpp +++ /dev/null @@ -1,1104 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "qdebug.h" - -#ifdef Q_WS_X11 -#include -#include - -#ifndef QT_OPENGL_ES -#include -#include -#endif -#endif //Q_WS_X11 - -#include -#include - -#include - -#include - -#include -#include - -#ifndef QT_OPENGL_ES_2 -#include -#endif - -#ifndef GLX_ARB_multisample -#define GLX_SAMPLE_BUFFERS_ARB 100000 -#define GLX_SAMPLES_ARB 100001 -#endif - -#ifndef QT_NO_EGL -#include -#endif - -#ifdef Q_WS_QPA -#include -#endif - -QT_BEGIN_NAMESPACE - -// -// QGLWindowSurface -// -class QGLGlobalShareWidget -{ -public: - QGLGlobalShareWidget() : firstPixmap(0), widgetRefCount(0), widget(0), initializing(false) { - created = true; - } - - QGLWidget *shareWidget() { - if (!initializing && !widget && !cleanedUp) { - initializing = true; - widget = new QGLWidget(QGLFormat(QGL::SingleBuffer | QGL::NoDepthBuffer | QGL::NoStencilBuffer)); - widget->resize(1, 1); - - // We don't need this internal widget to appear in QApplication::topLevelWidgets() - if (QWidgetPrivate::allWidgets) - QWidgetPrivate::allWidgets->remove(widget); - initializing = false; - } - return widget; - } - - // destroys the share widget and prevents recreation - void cleanup() { - QGLWidget *w = widget; - cleanedUp = true; - widget = 0; - delete w; - } - - // destroys the share widget, but allows it to be recreated later on - void destroy() { - if (cleanedUp) - return; - - QGLWidget *w = widget; - - // prevent potential recursions - cleanedUp = true; - widget = 0; - delete w; - cleanedUp = false; - } - - static bool cleanedUp; - static bool created; - - QGLPixmapData *firstPixmap; - int widgetRefCount; - -private: - QGLWidget *widget; - bool initializing; -}; - -bool QGLGlobalShareWidget::cleanedUp = false; -bool QGLGlobalShareWidget::created = false; - -static void qt_cleanup_gl_share_widget(); -Q_GLOBAL_STATIC_WITH_INITIALIZER(QGLGlobalShareWidget, _qt_gl_share_widget, - { - qAddPostRoutine(qt_cleanup_gl_share_widget); - }) - -static void qt_cleanup_gl_share_widget() -{ - if (QGLGlobalShareWidget::created) - _qt_gl_share_widget()->cleanup(); -} - -QGLWidget* qt_gl_share_widget() -{ - if (QGLGlobalShareWidget::cleanedUp) - return 0; - return _qt_gl_share_widget()->shareWidget(); -} - -void qt_destroy_gl_share_widget() -{ - if (QGLGlobalShareWidget::created) - _qt_gl_share_widget()->destroy(); -} - -const QGLContext *qt_gl_share_context() -{ - QGLWidget *widget = qt_gl_share_widget(); - if (widget) - return widget->context(); - return 0; -} - -#ifdef QGL_USE_TEXTURE_POOL -void qt_gl_register_pixmap(QGLPixmapData *pd) -{ - QGLGlobalShareWidget *shared = _qt_gl_share_widget(); - pd->next = shared->firstPixmap; - pd->prev = 0; - if (shared->firstPixmap) - shared->firstPixmap->prev = pd; - shared->firstPixmap = pd; -} - -void qt_gl_unregister_pixmap(QGLPixmapData *pd) -{ - if (pd->next) - pd->next->prev = pd->prev; - if (pd->prev) { - pd->prev->next = pd->next; - } else { - QGLGlobalShareWidget *shared = _qt_gl_share_widget(); - if (shared) - shared->firstPixmap = pd->next; - } -} - -void qt_gl_hibernate_pixmaps() -{ - QGLGlobalShareWidget *shared = _qt_gl_share_widget(); - - // Scan all QGLPixmapData objects in the system and hibernate them. - QGLPixmapData *pd = shared->firstPixmap; - while (pd != 0) { - pd->hibernate(); - pd = pd->next; - } -} -#endif - -struct QGLWindowSurfacePrivate -{ - QGLFramebufferObject *fbo; - QGLPixelBuffer *pb; - GLuint tex_id; - GLuint pb_tex_id; - - int tried_fbo : 1; - int tried_pb : 1; - int destructive_swap_buffers : 1; - int geometry_updated : 1; - int did_paint : 1; - - QGLContext *ctx; - - QList contexts; - - QRegion paintedRegion; - QSize size; - - QSize textureSize; - - QList buffers; - QGLWindowSurfaceGLPaintDevice glDevice; - QGLWindowSurface* q_ptr; - - bool swap_region_support; -}; - -QGLFormat QGLWindowSurface::surfaceFormat; -QGLWindowSurface::SwapMode QGLWindowSurface::swapBehavior = QGLWindowSurface::AutomaticSwap; - -void QGLWindowSurfaceGLPaintDevice::endPaint() -{ - glFlush(); - QGLPaintDevice::endPaint(); -} - -QSize QGLWindowSurfaceGLPaintDevice::size() const -{ - return d->size; -} - -QGLContext* QGLWindowSurfaceGLPaintDevice::context() const -{ - return d->ctx; -} - - -int QGLWindowSurfaceGLPaintDevice::metric(PaintDeviceMetric m) const -{ - QWindow *window = d->q_ptr->window(); - QPlatformScreen *screen = QPlatformScreen::platformScreenForWindow(window); - if (!screen) { - if (m == PdmDpiX || m == PdmDpiY) - return 72; - } - int val; - if (m == PdmWidth) { - val = window->geometry().width(); - } else if (m == PdmWidthMM) { - val = window->geometry().width() * screen->physicalSize().width() / screen->geometry().width(); - } else if (m == PdmHeight) { - val = window->geometry().height(); - } else if (m == PdmHeightMM) { - val = window->geometry().height() * screen->physicalSize().height() / screen->geometry().height(); - } else if (m == PdmDepth) { - val = screen->depth(); - } else if (m == PdmDpiX || m == PdmPhysicalDpiX) { - val = qRound(screen->geometry().width() / double(screen->physicalSize().width() / 25.4)); - } else if (m == PdmDpiY || m == PdmPhysicalDpiY) { - val = qRound(screen->geometry().height() / double(screen->physicalSize().height() / 25.4)); - } else { - val = 1 << qMax(24, screen->depth()); - } - return val; -} - -QPaintEngine *QGLWindowSurfaceGLPaintDevice::paintEngine() const -{ - return qt_qgl_paint_engine(); -} - -QGLWindowSurface::QGLWindowSurface(QWindow *window) - : QWindowSurface(window), d_ptr(new QGLWindowSurfacePrivate) -{ -// Q_ASSERT(window->isTopLevel()); - d_ptr->pb = 0; - d_ptr->fbo = 0; - d_ptr->ctx = 0; - d_ptr->tex_id = 0; -#if defined (QT_OPENGL_ES_2) - d_ptr->tried_fbo = true; - d_ptr->tried_pb = true; -#else - d_ptr->tried_fbo = false; - d_ptr->tried_pb = false; -#endif - d_ptr->destructive_swap_buffers = qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull(); - d_ptr->glDevice.d = d_ptr; - d_ptr->q_ptr = this; - d_ptr->geometry_updated = false; - d_ptr->did_paint = false; - d_ptr->swap_region_support = false; -} - -QGLWindowSurface::~QGLWindowSurface() -{ - if (d_ptr->ctx) - glDeleteTextures(1, &d_ptr->tex_id); -#ifndef Q_WS_QPA // Dont delete the contexts. Destroying the window does that for us - foreach(QGLContext **ctx, d_ptr->contexts) { - delete *ctx; - *ctx = 0; - } -#endif - delete d_ptr->pb; - delete d_ptr->fbo; - delete d_ptr; - - if (QGLGlobalShareWidget::cleanedUp) - return; - - --(_qt_gl_share_widget()->widgetRefCount); - -#ifdef QGL_USE_TEXTURE_POOL - if (_qt_gl_share_widget()->widgetRefCount <= 0) { - // All of the widget window surfaces have been destroyed - // but we still have GL pixmaps active. Ask them to hibernate - // to free up GPU resources until a widget is shown again. - // This may eventually cause the EGLContext to be destroyed - // because nothing in the system needs a context, which will - // free up even more GPU resources. - qt_gl_hibernate_pixmaps(); - - // Destroy the context if necessary. - if (!qt_gl_share_widget()->context()->isSharing()) - qt_destroy_gl_share_widget(); - } -#endif // QGL_USE_TEXTURE_POOL -} - -void QGLWindowSurface::deleted(QObject *object) -{ -#if 0 - QWidget *widget = qobject_cast(object); - if (widget) { - if (widget == window()) { - // Make sure that the fbo is destroyed before destroying its context. - delete d_ptr->fbo; - d_ptr->fbo = 0; - } - -#ifndef Q_WS_QPA //no need to specifically delete the QGLContext as it will be deleted by QWidget - QWidgetPrivate *widgetPrivate = widget->d_func(); - if (widgetPrivate->extraData()) { - union { QGLContext **ctxPtrPtr; void **voidPtrPtr; }; - voidPtrPtr = &widgetPrivate->extraData()->glContext; - int index = d_ptr->contexts.indexOf(ctxPtrPtr); - if (index != -1) { - delete *ctxPtrPtr; - *ctxPtrPtr = 0; - d_ptr->contexts.removeAt(index); - } - } -#endif - } -#endif -} - -void QGLWindowSurface::hijackWindow(QWindow *window) -{ -#if 0 - QWidgetPrivate *widgetPrivate = widget->d_func(); - widgetPrivate->createExtra(); - if (widgetPrivate->extraData()->glContext) - return; - - QGLContext *ctx = NULL; - - // For translucent top-level widgets we need alpha in the format. - if (widget->testAttribute(Qt::WA_TranslucentBackground)) { - QGLFormat modFormat(surfaceFormat); - modFormat.setSampleBuffers(false); - modFormat.setSamples(0); - modFormat.setAlpha(true); - ctx = new QGLContext(modFormat, widget); - } else - ctx = new QGLContext(surfaceFormat, widget); - - ctx->create(qt_gl_share_context()); - - if (widget != qt_gl_share_widget()) - ++(_qt_gl_share_widget()->widgetRefCount); - -#ifndef QT_NO_EGL - static bool checkedForNOKSwapRegion = false; - static bool haveNOKSwapRegion = false; - - if (!checkedForNOKSwapRegion) { - haveNOKSwapRegion = QEgl::hasExtension("EGL_NOK_swap_region2"); - checkedForNOKSwapRegion = true; - - if (haveNOKSwapRegion) - qDebug() << "Found EGL_NOK_swap_region2 extension. Using partial updates."; - } - - d_ptr->destructive_swap_buffers = true; - if (ctx->d_func()->eglContext->configAttrib(EGL_SURFACE_TYPE)&EGL_SWAP_BEHAVIOR_PRESERVED_BIT) { - EGLint swapBehavior; - if (eglQuerySurface(ctx->d_func()->eglContext->display(), ctx->d_func()->eglSurface - , EGL_SWAP_BEHAVIOR, &swapBehavior)) { - d_ptr->destructive_swap_buffers = (swapBehavior != EGL_BUFFER_PRESERVED); - } - } - - d_ptr->swap_region_support = haveNOKSwapRegion; -#endif - - widgetPrivate->extraData()->glContext = ctx; - - union { QGLContext **ctxPtrPtr; void **voidPtrPtr; }; - - connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(deleted(QObject*))); - - voidPtrPtr = &widgetPrivate->extraData()->glContext; - d_ptr->contexts << ctxPtrPtr; -#ifndef Q_OS_SYMBIAN - qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size(); -#endif -#endif -} - -QGLContext *QGLWindowSurface::context() const -{ - return d_ptr->ctx; -} - -QPaintDevice *QGLWindowSurface::paintDevice() -{ - updateGeometry(); - - if (d_ptr->pb) - return d_ptr->pb; - - if (d_ptr->ctx) - return &d_ptr->glDevice; - -#if 0 - QGLContext *ctx = reinterpret_cast(window()->d_func()->extraData()->glContext); - ctx->makeCurrent(); -#endif - - Q_ASSERT(d_ptr->fbo); - return d_ptr->fbo; -} - -static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &src = QRectF()); - -void QGLWindowSurface::beginPaint(const QRegion &) -{ - d_ptr->did_paint = true; - updateGeometry(); - - int clearFlags = 0; - -#if 0 - QGLContext *ctx = reinterpret_cast(window()->d_func()->extraData()->glContext); -#endif - const QGLContext *ctx = QGLContext::currentContext(); - - if (!ctx) - return; - - if (ctx->d_func()->workaround_needsFullClearOnEveryFrame) - clearFlags = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - else if (ctx->format().alpha()) - clearFlags = GL_COLOR_BUFFER_BIT; - - if (clearFlags) { - if (d_ptr->fbo) - d_ptr->fbo->bind(); - - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(clearFlags); - - if (d_ptr->fbo) - d_ptr->fbo->release(); - } -} - -void QGLWindowSurface::endPaint(const QRegion &rgn) -{ - if (context()) - d_ptr->paintedRegion |= rgn; - - d_ptr->buffers.clear(); -} - -static void blitTexture(QGLContext *ctx, GLuint texture, const QSize &viewport, const QSize &texSize, const QRect &targetRect, const QRect &sourceRect) -{ - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - - glViewport(0, 0, viewport.width(), viewport.height()); - - QGLShaderProgram *blitProgram = - QGLEngineSharedShaders::shadersForContext(ctx)->blitProgram(); - blitProgram->bind(); - blitProgram->setUniformValue("imageTexture", 0 /*QT_IMAGE_TEXTURE_UNIT*/); - - // The shader manager's blit program does not multiply the - // vertices by the pmv matrix, so we need to do the effect - // of the orthographic projection here ourselves. - QRectF r; - qreal w = viewport.width(); - qreal h = viewport.height(); - r.setLeft((targetRect.left() / w) * 2.0f - 1.0f); - if (targetRect.right() == (viewport.width() - 1)) - r.setRight(1.0f); - else - r.setRight((targetRect.right() / w) * 2.0f - 1.0f); - r.setBottom((targetRect.top() / h) * 2.0f - 1.0f); - if (targetRect.bottom() == (viewport.height() - 1)) - r.setTop(1.0f); - else - r.setTop((targetRect.bottom() / w) * 2.0f - 1.0f); - - drawTexture(r, texture, texSize, sourceRect); -} - - -void QGLWindowSurface::flush(QWindow *window, const QRegion &rgn, const QPoint &offset) -{ -#if 0 - //### Find out why d_ptr->geometry_updated isn't always false. - // flush() should not be called when d_ptr->geometry_updated is true. It assumes that either - // d_ptr->fbo or d_ptr->pb is allocated and has the correct size. - if (d_ptr->geometry_updated) - return; - - // did_paint is set to true in ::beginPaint. ::beginPaint means that we - // at least cleared the background (= painted something). In EGL API it's a - // mistake to call swapBuffers if nothing was painted unless - // EGL_BUFFER_PRESERVED is set. This check protects the flush func from - // being executed if it's for nothing. - if (!d_ptr->destructive_swap_buffers && !d_ptr->did_paint) - return; - -#ifdef Q_OS_SYMBIAN - if (window() != widget) { - // For performance reasons we don't support - // flushing native child widgets on Symbian. - // It breaks overlapping native child widget - // rendering in some cases but we prefer performance. - return; - } -#endif - - - QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget(); - Q_ASSERT(parent); - -#if !defined(Q_WS_QPA) - if (!geometry().isValid()) - return; -#else - if (!size().isValid()) - return; -#endif - - // Needed to support native child-widgets... - hijackWindow(parent); - - QRect br = rgn.boundingRect().translated(offset); - br = br.intersected(window()->rect()); - QPoint wOffset = qt_qwidget_data(parent)->wrect.topLeft(); - QRect rect = br.translated(-offset - wOffset); - - const GLenum target = GL_TEXTURE_2D; - Q_UNUSED(target); - - if (QGLWindowSurface::swapBehavior == QGLWindowSurface::KillSwap) - return; - - if (context()) { - context()->makeCurrent(); - - if (context()->format().doubleBuffer()) { -#if !defined(QT_OPENGL_ES_2) - if (d_ptr->destructive_swap_buffers) { - glBindTexture(target, d_ptr->tex_id); - - QVector rects = d_ptr->paintedRegion.rects(); - for (int i = 0; i < rects.size(); ++i) { - QRect br = rects.at(i); - if (br.isEmpty()) - continue; - - const uint bottom = window()->height() - (br.y() + br.height()); - glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height()); - } - - glBindTexture(target, 0); - - QRegion dirtyRegion = QRegion(window()->rect()) - d_ptr->paintedRegion; - - if (!dirtyRegion.isEmpty()) { - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); -#ifndef QT_OPENGL_ES - glOrtho(0, window()->width(), window()->height(), 0, -999999, 999999); -#else - glOrthof(0, window()->width(), window()->height(), 0, -999999, 999999); -#endif - glViewport(0, 0, window()->width(), window()->height()); - - QVector rects = dirtyRegion.rects(); - glColor4f(1, 1, 1, 1); - for (int i = 0; i < rects.size(); ++i) { - QRect rect = rects.at(i); - if (rect.isEmpty()) - continue; - - drawTexture(rect, d_ptr->tex_id, window()->size(), rect); - } - } - } -#endif - bool doingPartialUpdate = false; - if (d_ptr->swap_region_support) { - if (QGLWindowSurface::swapBehavior == QGLWindowSurface::AutomaticSwap) - doingPartialUpdate = br.width() * br.height() < parent->geometry().width() * parent->geometry().height() * 0.2; - else if (QGLWindowSurface::swapBehavior == QGLWindowSurface::AlwaysPartialSwap) - doingPartialUpdate = true; - } - - QGLContext *ctx = reinterpret_cast(parent->d_func()->extraData()->glContext); - if (widget != window()) { - if (initializeOffscreenTexture(window()->size())) - qWarning() << "QGLWindowSurface: Flushing to native child widget, may lead to significant performance loss"; - glBindTexture(target, d_ptr->tex_id); - - const uint bottom = window()->height() - (br.y() + br.height()); - glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height()); - - glBindTexture(target, 0); - - ctx->makeCurrent(); - if (doingPartialUpdate) - blitTexture(ctx, d_ptr->tex_id, parent->size(), window()->size(), rect, br); - else - blitTexture(ctx, d_ptr->tex_id, parent->size(), window()->size(), parent->rect(), parent->rect().translated(offset + wOffset)); - } - - if (doingPartialUpdate) - ctx->d_func()->swapRegion(br); - else - ctx->swapBuffers(); - - d_ptr->paintedRegion = QRegion(); - } else { - glFlush(); - } - return; - } - - QGLContext *previous_ctx = const_cast(QGLContext::currentContext()); - QGLContext *ctx = reinterpret_cast(parent->d_func()->extraData()->glContext); - - // QPainter::end() should have unbound the fbo, otherwise something is very wrong... - Q_ASSERT(!d_ptr->fbo || !d_ptr->fbo->isBound()); - - if (ctx != previous_ctx) { - ctx->makeCurrent(); - } - - QSize size = widget->rect().size(); - if (d_ptr->destructive_swap_buffers && ctx->format().doubleBuffer()) { - rect = parent->rect(); - br = rect.translated(wOffset + offset); - size = parent->size(); - } - - glDisable(GL_SCISSOR_TEST); - - if (d_ptr->fbo && (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit)) { - const int h = d_ptr->fbo->height(); - - const int sx0 = br.left(); - const int sx1 = br.left() + br.width(); - const int sy0 = h - (br.top() + br.height()); - const int sy1 = h - br.top(); - - const int tx0 = rect.left(); - const int tx1 = rect.left() + rect.width(); - const int ty0 = parent->height() - (rect.top() + rect.height()); - const int ty1 = parent->height() - rect.top(); - - if (window() == parent || d_ptr->fbo->format().samples() <= 1) { - if (ctx->d_ptr->current_fbo != 0) - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0); - - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle()); - - glBlitFramebufferEXT(sx0, sy0, sx1, sy1, - tx0, ty0, tx1, ty1, - GL_COLOR_BUFFER_BIT, - GL_NEAREST); - - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0); - } else { - // can't do sub-region blits with multisample FBOs - QGLFramebufferObject *temp = qgl_fbo_pool()->acquire(d_ptr->fbo->size(), QGLFramebufferObjectFormat()); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, temp->handle()); - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle()); - - glBlitFramebufferEXT(0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(), - 0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(), - GL_COLOR_BUFFER_BIT, - GL_NEAREST); - - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, temp->handle()); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0); - - glBlitFramebufferEXT(sx0, sy0, sx1, sy1, - tx0, ty0, tx1, ty1, - GL_COLOR_BUFFER_BIT, - GL_NEAREST); - - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0); - - qgl_fbo_pool()->release(temp); - } - - ctx->d_ptr->current_fbo = 0; - } -#if !defined(QT_OPENGL_ES_2) - else { - GLuint texture; - if (d_ptr->fbo) { - texture = d_ptr->fbo->texture(); - } else { - d_ptr->pb->makeCurrent(); - glBindTexture(target, d_ptr->pb_tex_id); - const uint bottom = window()->height() - (br.y() + br.height()); - glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height()); - texture = d_ptr->pb_tex_id; - glBindTexture(target, 0); - } - - glDisable(GL_DEPTH_TEST); - - if (d_ptr->fbo) { - d_ptr->fbo->release(); - } else { - ctx->makeCurrent(); - } - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); -#ifndef QT_OPENGL_ES - glOrtho(0, size.width(), size.height(), 0, -999999, 999999); -#else - glOrthof(0, size.width(), size.height(), 0, -999999, 999999); -#endif - glViewport(0, 0, size.width(), size.height()); - - glColor4f(1, 1, 1, 1); - drawTexture(rect, texture, window()->size(), br); - - if (d_ptr->fbo) - d_ptr->fbo->bind(); - } -#else - // OpenGL/ES 2.0 version of the fbo blit. - else if (d_ptr->fbo) { - Q_UNUSED(target); - - if (d_ptr->fbo->isBound()) - d_ptr->fbo->release(); - - blitTexture(ctx, d_ptr->fbo->texture(), size, window()->size(), rect, br); - } -#endif - - if (ctx->format().doubleBuffer()) - ctx->swapBuffers(); - else - glFlush(); -#endif - d_ptr->did_paint = false; -} - - -#if !defined(Q_WS_QPA) -void QGLWindowSurface::setGeometry(const QRect &rect) -{ - QWindowSurface::setGeometry(rect); - d_ptr->geometry_updated = true; -} -#else -void QGLWindowSurface::resize(const QSize &size) -{ - QWindowSurface::resize(size); - d_ptr->geometry_updated = true; -} -#endif - -void QGLWindowSurface::updateGeometry() { -#if 0 - if (!d_ptr->geometry_updated) - return; - d_ptr->geometry_updated = false; - - bool hijack(true); - QWidgetPrivate *wd = window()->d_func(); - if (wd->extraData() && wd->extraData()->glContext) { -#ifdef Q_OS_SYMBIAN // Symbian needs to recreate the context when native window size changes - if (d_ptr->size != geometry().size()) { - if (window() != qt_gl_share_widget()) - --(_qt_gl_share_widget()->widgetRefCount); - - delete wd->extraData()->glContext; - wd->extraData()->glContext = 0; - d_ptr->ctx = 0; - } - else -#endif - { - hijack = false; // we already have gl context for widget - } - } - - if (hijack) - hijackWindow(window()); - - QGLContext *ctx = reinterpret_cast(wd->extraData()->glContext); - -#ifdef Q_WS_MAC - ctx->updatePaintDevice(); -#endif - - QSize surfSize = geometry().size(); - - if (surfSize.width() <= 0 || surfSize.height() <= 0) - return; - - if (d_ptr->size == surfSize) - return; - - d_ptr->size = surfSize; - - if (d_ptr->ctx) { -#ifndef QT_OPENGL_ES_2 - if (d_ptr->destructive_swap_buffers) - initializeOffscreenTexture(surfSize); -#endif - return; - } - - const GLenum target = GL_TEXTURE_2D; - if (d_ptr->destructive_swap_buffers - && (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject) - && (d_ptr->fbo || !d_ptr->tried_fbo) - && qt_gl_preferGL2Engine()) - { - d_ptr->tried_fbo = true; - ctx->d_ptr->internal_context = true; - ctx->makeCurrent(); - delete d_ptr->fbo; - - QGLFramebufferObjectFormat format; - format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); - format.setInternalTextureFormat(GLenum(GL_RGBA)); - format.setTextureTarget(target); - - if (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit) - format.setSamples(8); - - d_ptr->fbo = new QGLFramebufferObject(surfSize, format); - - if (d_ptr->fbo->isValid()) { - qDebug() << "Created Window Surface FBO" << surfSize - << "with samples" << d_ptr->fbo->format().samples(); - return; - } else { - qDebug() << "QGLWindowSurface: Failed to create valid FBO, falling back"; - delete d_ptr->fbo; - d_ptr->fbo = 0; - } - } - -#if !defined(QT_OPENGL_ES_2) && !defined(Q_WS_QPA) //QPA doesn't support pixelbuffers - if (d_ptr->destructive_swap_buffers && (d_ptr->pb || !d_ptr->tried_pb)) { - d_ptr->tried_pb = true; - - if (d_ptr->pb) { - d_ptr->pb->makeCurrent(); - glDeleteTextures(1, &d_ptr->pb_tex_id); - } - - delete d_ptr->pb; - - d_ptr->pb = new QGLPixelBuffer(surfSize.width(), surfSize.height(), - QGLFormat(QGL::SampleBuffers | QGL::StencilBuffer | QGL::DepthBuffer), - qt_gl_share_widget()); - - if (d_ptr->pb->isValid()) { - qDebug() << "Created Window Surface Pixelbuffer, Sample buffers:" << d_ptr->pb->format().sampleBuffers(); - d_ptr->pb->makeCurrent(); - - glGenTextures(1, &d_ptr->pb_tex_id); - glBindTexture(target, d_ptr->pb_tex_id); - glTexImage2D(target, 0, GL_RGBA, surfSize.width(), surfSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - - glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindTexture(target, 0); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, d_ptr->pb->width(), d_ptr->pb->height(), 0, -999999, 999999); - - d_ptr->pb->d_ptr->qctx->d_func()->internal_context = true; - return; - } else { - qDebug() << "QGLWindowSurface: Failed to create valid pixelbuffer, falling back"; - delete d_ptr->pb; - d_ptr->pb = 0; - } - } -#endif // !defined(QT_OPENGL_ES_2) !defined(Q_WS_QPA) - - ctx->makeCurrent(); - -#ifndef QT_OPENGL_ES_2 - if (d_ptr->destructive_swap_buffers) - initializeOffscreenTexture(surfSize); -#endif -#ifndef Q_OS_SYMBIAN - qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this; -#endif - d_ptr->ctx = ctx; - d_ptr->ctx->d_ptr->internal_context = true; -#endif -} - -bool QGLWindowSurface::initializeOffscreenTexture(const QSize &size) -{ - if (size == d_ptr->textureSize) - return false; - - glGenTextures(1, &d_ptr->tex_id); - glBindTexture(GL_TEXTURE_2D, d_ptr->tex_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); - - d_ptr->textureSize = size; - return true; -} - -bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy) -{ -#if 0 - // this code randomly fails currently for unknown reasons - return false; - - if (!d_ptr->pb) - return false; - - d_ptr->pb->makeCurrent(); - - QRect br = area.boundingRect(); - -#if 0 - // ## workaround driver issue (scrolling by these deltas is unbearably slow for some reason) - // ## maybe we should use glCopyTexSubImage insteadk - if (dx == 1 || dx == -1 || dy == 1 || dy == -1 || dy == 2) - return false; - - glRasterPos2i(br.x() + dx, br.y() + br.height() + dy); - glCopyPixels(br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), GL_COLOR); - return true; -#endif - - const GLenum target = GL_TEXTURE_2D; - - glBindTexture(target, d_ptr->tex_id); - glCopyTexImage2D(target, 0, GL_RGBA, br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), 0); - glBindTexture(target, 0); - - drawTexture(br.translated(dx, dy), d_ptr->tex_id, window()->size()); -#endif - return true; -} - -static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &br) -{ - const GLenum target = GL_TEXTURE_2D; - QRectF src = br.isEmpty() - ? QRectF(QPointF(), texSize) - : QRectF(QPointF(br.x(), texSize.height() - br.bottom()), br.size()); - - if (target == GL_TEXTURE_2D) { - qreal width = texSize.width(); - qreal height = texSize.height(); - - src.setLeft(src.left() / width); - src.setRight(src.right() / width); - src.setTop(src.top() / height); - src.setBottom(src.bottom() / height); - } - - const GLfloat tx1 = src.left(); - const GLfloat tx2 = src.right(); - const GLfloat ty1 = src.top(); - const GLfloat ty2 = src.bottom(); - - GLfloat texCoordArray[4*2] = { - tx1, ty2, tx2, ty2, tx2, ty1, tx1, ty1 - }; - - GLfloat vertexArray[4*2]; - extern void qt_add_rect_to_array(const QRectF &r, GLfloat *array); // qpaintengine_opengl.cpp - qt_add_rect_to_array(rect, vertexArray); - -#if !defined(QT_OPENGL_ES_2) - glVertexPointer(2, GL_FLOAT, 0, vertexArray); - glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray); - - glBindTexture(target, tex_id); - glEnable(target); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glDisable(target); - glBindTexture(target, 0); -#else - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray); - glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, texCoordArray); - - glBindTexture(target, tex_id); - - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - - glBindTexture(target, 0); -#endif -} - -QWindowSurface::WindowSurfaceFeatures QGLWindowSurface::features() const -{ - WindowSurfaceFeatures features = 0; - if (!d_ptr->destructive_swap_buffers || d_ptr->swap_region_support) - features |= PartialUpdates; - if (!d_ptr->destructive_swap_buffers) - features |= PreservedContents; - return features; -} - -QT_END_NAMESPACE - diff --git a/src/opengl/qwindowsurface_gl_p.h b/src/opengl/qwindowsurface_gl_p.h deleted file mode 100644 index c7b0d10efa..0000000000 --- a/src/opengl/qwindowsurface_gl_p.h +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWINDOWSURFACE_GL_P_H -#define QWINDOWSURFACE_GL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the QLibrary class. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QPaintDevice; -class QPoint; -class QRegion; -class QWindow; -struct QGLWindowSurfacePrivate; - -Q_OPENGL_EXPORT QGLWidget* qt_gl_share_widget(); -Q_OPENGL_EXPORT void qt_destroy_gl_share_widget(); - -class QGLWindowSurfaceGLPaintDevice : public QGLPaintDevice -{ -public: - QPaintEngine* paintEngine() const; - void endPaint(); - QSize size() const; - int metric(PaintDeviceMetric m) const; - QGLContext* context() const; - QGLWindowSurfacePrivate* d; -}; - -class Q_OPENGL_EXPORT QGLWindowSurface : public QObject, public QWindowSurface // , public QPaintDevice -{ - Q_OBJECT -public: - QGLWindowSurface(QWindow *window); - ~QGLWindowSurface(); - - QPaintDevice *paintDevice(); - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); - -#if !defined(Q_WS_QPA) - void setGeometry(const QRect &rect); -#else - virtual void resize(const QSize &size); -#endif - - void updateGeometry(); - bool scroll(const QRegion &area, int dx, int dy); - - void beginPaint(const QRegion ®ion); - void endPaint(const QRegion ®ion); - - WindowSurfaceFeatures features() const; - - QGLContext *context() const; - - static QGLFormat surfaceFormat; - - enum SwapMode { AutomaticSwap, AlwaysFullSwap, AlwaysPartialSwap, KillSwap }; - static SwapMode swapBehavior; - -private slots: - void deleted(QObject *object); - -private: - void hijackWindow(QWindow *window); - bool initializeOffscreenTexture(const QSize &size); - - QGLWindowSurfacePrivate *d_ptr; -}; - -QT_END_NAMESPACE - -#endif // QWINDOWSURFACE_GL_P_H - diff --git a/src/opengl/qwindowsurface_x11gl.cpp b/src/opengl/qwindowsurface_x11gl.cpp deleted file mode 100644 index bec0ea7587..0000000000 --- a/src/opengl/qwindowsurface_x11gl.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include -#include - -#include "qwindowsurface_x11gl_p.h" -#include "qpixmapdata_x11gl_p.h" - -QT_BEGIN_NAMESPACE - -QX11GLWindowSurface::QX11GLWindowSurface(QWidget* window) - : QWindowSurface(window), m_windowGC(0), m_pixmapGC(0), m_window(window) -{ -} - -QX11GLWindowSurface::~QX11GLWindowSurface() -{ - if (m_windowGC) - XFree(m_windowGC); - if (m_pixmapGC) - XFree(m_pixmapGC); -} - -QPaintDevice *QX11GLWindowSurface::paintDevice() -{ - return &m_backBuffer; -} - -extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp - -void QX11GLWindowSurface::flush(QWidget *widget, const QRegion &widgetRegion, const QPoint &offset) -{ - // We don't need to know the widget which initiated the flush. Instead we just use the offset - // to translate the widgetRegion: - Q_UNUSED(widget); - - if (m_backBuffer.isNull()) { - qDebug("QX11GLWindowSurface::flush() - backBuffer is null, not flushing anything"); - return; - } - - Q_ASSERT(window()->size() != m_backBuffer.size()); - - // Wait for all GL rendering to the back buffer pixmap to complete before trying to - // copy it to the window. We do this by making sure the pixmap's context is current - // and then call eglWaitClient. The EGL 1.4 spec says eglWaitClient doesn't have to - // block, just that "All rendering calls...are guaranteed to be executed before native - // rendering calls". This makes it potentially less expensive than glFinish. - QGLContext* ctx = static_cast(m_backBuffer.data_ptr().data())->context(); - if (QGLContext::currentContext() != ctx && ctx && ctx->isValid()) - ctx->makeCurrent(); - eglWaitClient(); - - if (m_windowGC == 0) { - XGCValues attribs; - attribs.graphics_exposures = False; - m_windowGC = XCreateGC(X11->display, m_window->handle(), GCGraphicsExposures, &attribs); - } - - int rectCount; - XRectangle *rects = (XRectangle *)qt_getClipRects(widgetRegion, rectCount); - if (rectCount <= 0) - return; - - XSetClipRectangles(X11->display, m_windowGC, 0, 0, rects, rectCount, YXBanded); - - QRect dirtyRect = widgetRegion.boundingRect().translated(-offset); - XCopyArea(X11->display, m_backBuffer.handle(), m_window->handle(), m_windowGC, - dirtyRect.x(), dirtyRect.y(), dirtyRect.width(), dirtyRect.height(), - dirtyRect.x(), dirtyRect.y()); - - // Make sure the blit of the update from the back buffer to the window completes - // before allowing rendering to start again to the back buffer. Otherwise the GPU - // might start rendering to the back buffer again while the blit takes place. - eglWaitNative(EGL_CORE_NATIVE_ENGINE); -} - -void QX11GLWindowSurface::setGeometry(const QRect &rect) -{ - if (rect.width() > m_backBuffer.size().width() || rect.height() > m_backBuffer.size().height()) { - QX11GLPixmapData *pd = new QX11GLPixmapData; - QSize newSize = rect.size(); - pd->resize(newSize.width(), newSize.height()); - m_backBuffer = QPixmap(pd); - if (window()->testAttribute(Qt::WA_TranslucentBackground)) - m_backBuffer.fill(Qt::transparent); - if (m_pixmapGC) { - XFreeGC(X11->display, m_pixmapGC); - m_pixmapGC = 0; - } - } - - QWindowSurface::setGeometry(rect); -} - -bool QX11GLWindowSurface::scroll(const QRegion &area, int dx, int dy) -{ - if (m_backBuffer.isNull()) - return false; - - Q_ASSERT(m_backBuffer.data_ptr()->classId() == QPixmapData::X11Class); - - // Make sure all GL rendering is complete before starting the scroll operation: - QGLContext* ctx = static_cast(m_backBuffer.data_ptr().data())->context(); - if (QGLContext::currentContext() != ctx && ctx && ctx->isValid()) - ctx->makeCurrent(); - eglWaitClient(); - - if (!m_pixmapGC) - m_pixmapGC = XCreateGC(X11->display, m_backBuffer.handle(), 0, 0); - - foreach (const QRect& rect, area.rects()) { - XCopyArea(X11->display, m_backBuffer.handle(), m_backBuffer.handle(), m_pixmapGC, - rect.x(), rect.y(), rect.width(), rect.height(), - rect.x()+dx, rect.y()+dy); - } - - // Make sure the scroll operation is complete before allowing GL rendering to resume - eglWaitNative(EGL_CORE_NATIVE_ENGINE); - - return true; -} - - -QPixmap QX11GLWindowSurface::grabWidget(const QWidget *widget, const QRect& rect) const -{ - if (!widget || m_backBuffer.isNull()) - return QPixmap(); - - QRect srcRect; - - // make sure the rect is inside the widget & clip to widget's rect - if (!rect.isEmpty()) - srcRect = rect & widget->rect(); - else - srcRect = widget->rect(); - - if (srcRect.isEmpty()) - return QPixmap(); - - // If it's a child widget we have to translate the coordinates - if (widget != window()) - srcRect.translate(widget->mapTo(window(), QPoint(0, 0))); - - QPixmap::x11SetDefaultScreen(widget->x11Info().screen()); - - QX11PixmapData *pmd = new QX11PixmapData(QPixmapData::PixmapType); - pmd->resize(srcRect.width(), srcRect.height()); - QPixmap px(pmd); - - GC tmpGc = XCreateGC(X11->display, m_backBuffer.handle(), 0, 0); - - // Make sure all GL rendering is complete before copying the window - QGLContext* ctx = static_cast(m_backBuffer.pixmapData())->context(); - if (QGLContext::currentContext() != ctx && ctx && ctx->isValid()) - ctx->makeCurrent(); - eglWaitClient(); - - // Copy srcRect from the backing store to the new pixmap - XSetGraphicsExposures(X11->display, tmpGc, False); - XCopyArea(X11->display, m_backBuffer.handle(), px.handle(), tmpGc, - srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), 0, 0); - XFreeGC(X11->display, tmpGc); - - // Wait until the copy has finised before allowing more rendering into the back buffer - eglWaitNative(EGL_CORE_NATIVE_ENGINE); - - return px; -} - -QT_END_NAMESPACE diff --git a/src/opengl/qwindowsurface_x11gl_p.h b/src/opengl/qwindowsurface_x11gl_p.h deleted file mode 100644 index 737997b879..0000000000 --- a/src/opengl/qwindowsurface_x11gl_p.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWINDOWSURFACE_X11GL_P_H -#define QWINDOWSURFACE_X11GL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -class QX11GLWindowSurface : public QWindowSurface -{ -public: - QX11GLWindowSurface(QWidget* window); - virtual ~QX11GLWindowSurface(); - - // Inherreted from QWindowSurface - QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - void setGeometry(const QRect &rect); - bool scroll(const QRegion &area, int dx, int dy); - QPixmap grabWidget(const QWidget *widget, const QRect& rectangle = QRect()) const; - -private: - GC m_windowGC; - GC m_pixmapGC; - QPixmap m_backBuffer; - QWidget *m_window; -}; - - -QT_END_NAMESPACE - -#endif // QWINDOWSURFACE_X11GL_P_H diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro index d51b6b2ed0..53ae1b1319 100644 --- a/src/plugins/platforms/minimal/minimal.pro +++ b/src/plugins/platforms/minimal/minimal.pro @@ -6,9 +6,9 @@ DESTDIR = $$QT.gui.plugins/platforms SOURCES = main.cpp \ qminimalintegration.cpp \ - qminimalwindowsurface.cpp + qminimalbackingstore.cpp HEADERS = qminimalintegration.h \ - qminimalwindowsurface.h + qminimalbackingstore.h target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/minimal/qminimalbackingstore.cpp b/src/plugins/platforms/minimal/qminimalbackingstore.cpp new file mode 100644 index 0000000000..bd4f04dfcd --- /dev/null +++ b/src/plugins/platforms/minimal/qminimalbackingstore.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qminimalbackingstore.h" +#include +#include + +QT_BEGIN_NAMESPACE + +QMinimalBackingStore::QMinimalBackingStore(QWindow *window) + : QPlatformBackingStore(window) +{ + //qDebug() << "QMinimalBackingStore::QMinimalBackingStore:" << (long)this; +} + +QMinimalBackingStore::~QMinimalBackingStore() +{ +} + +QPaintDevice *QMinimalBackingStore::paintDevice() +{ + //qDebug() << "QMinimalBackingStore::paintDevice"; + return &mImage; +} + +void QMinimalBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(window); + Q_UNUSED(region); + Q_UNUSED(offset); + + static int c = 0; + QString filename = QString("output%1.png").arg(c++, 4, 10, QLatin1Char('0')); + qDebug() << "QMinimalBackingStore::flush() saving contents to" << filename.toLocal8Bit().constData(); + mImage.save(filename); +} + +void QMinimalBackingStore::resize(const QSize &size, const QRegion &) +{ + //qDebug() << "QMinimalBackingStore::setGeometry:" << (long)this << rect; + QImage::Format format = QGuiApplicationPrivate::platformIntegration()->screens().first()->format(); + if (mImage.size() != size) + mImage = QImage(size, format); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimal/qminimalbackingstore.h b/src/plugins/platforms/minimal/qminimalbackingstore.h new file mode 100644 index 0000000000..9b61275e9d --- /dev/null +++ b/src/plugins/platforms/minimal/qminimalbackingstore.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBACKINGSTORE_MINIMAL_H +#define QBACKINGSTORE_MINIMAL_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QMinimalBackingStore : public QPlatformBackingStore +{ +public: + QMinimalBackingStore(QWindow *window); + ~QMinimalBackingStore(); + + QPaintDevice *paintDevice(); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize(const QSize &size, const QRegion &staticContents); + +private: + QImage mImage; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp index 23bade99b6..c3300ce3b8 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.cpp +++ b/src/plugins/platforms/minimal/qminimalintegration.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include "qminimalintegration.h" -#include "qminimalwindowsurface.h" +#include "qminimalbackingstore.h" #include #include @@ -75,8 +75,7 @@ QPlatformWindow *QMinimalIntegration::createPlatformWindow(QWindow *window) cons return new QPlatformWindow(window); } -QWindowSurface *QMinimalIntegration::createWindowSurface(QWindow *window, WId winId) const +QPlatformBackingStore *QMinimalIntegration::createPlatformBackingStore(QWindow *window) const { - Q_UNUSED(winId); - return new QMinimalWindowSurface(window); + return new QMinimalBackingStore(window); } diff --git a/src/plugins/platforms/minimal/qminimalintegration.h b/src/plugins/platforms/minimal/qminimalintegration.h index 6ac45c2385..efb0f352d4 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.h +++ b/src/plugins/platforms/minimal/qminimalintegration.h @@ -73,7 +73,7 @@ public: QPixmapData *createPixmapData(QPixmapData::PixelType type) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; - QWindowSurface *createWindowSurface(QWindow *window, WId winId) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; QList screens() const { return mScreens; } diff --git a/src/plugins/platforms/minimal/qminimalwindowsurface.cpp b/src/plugins/platforms/minimal/qminimalwindowsurface.cpp deleted file mode 100644 index f28b34a000..0000000000 --- a/src/plugins/platforms/minimal/qminimalwindowsurface.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qminimalwindowsurface.h" -#include -#include - -QT_BEGIN_NAMESPACE - -QMinimalWindowSurface::QMinimalWindowSurface(QWindow *window) - : QWindowSurface(window) -{ - //qDebug() << "QMinimalWindowSurface::QMinimalWindowSurface:" << (long)this; -} - -QMinimalWindowSurface::~QMinimalWindowSurface() -{ -} - -QPaintDevice *QMinimalWindowSurface::paintDevice() -{ - //qDebug() << "QMinimalWindowSurface::paintDevice"; - return &mImage; -} - -void QMinimalWindowSurface::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(window); - Q_UNUSED(region); - Q_UNUSED(offset); - - static int c = 0; - QString filename = QString("output%1.png").arg(c++, 4, 10, QLatin1Char('0')); - qDebug() << "QMinimalWindowSurface::flush() saving contents to" << filename.toLocal8Bit().constData(); - mImage.save(filename); -} - -void QMinimalWindowSurface::resize(const QSize &size) -{ - //qDebug() << "QMinimalWindowSurface::setGeometry:" << (long)this << rect; - QWindowSurface::resize(size); - QImage::Format format = QGuiApplicationPrivate::platformIntegration()->screens().first()->format(); - if (mImage.size() != size) - mImage = QImage(size, format); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimal/qminimalwindowsurface.h b/src/plugins/platforms/minimal/qminimalwindowsurface.h deleted file mode 100644 index 943cdc43e1..0000000000 --- a/src/plugins/platforms/minimal/qminimalwindowsurface.h +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWINDOWSURFACE_MINIMAL_H -#define QWINDOWSURFACE_MINIMAL_H - -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -class QMinimalWindowSurface : public QWindowSurface -{ -public: - QMinimalWindowSurface(QWindow *window); - ~QMinimalWindowSurface(); - - QPaintDevice *paintDevice(); - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); - void resize(const QSize &size); - -private: - QImage mImage; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/platforms/wayland/qwaylandcursor.cpp b/src/plugins/platforms/wayland/qwaylandcursor.cpp index d69d618591..6612d67cb4 100644 --- a/src/plugins/platforms/wayland/qwaylandcursor.cpp +++ b/src/plugins/platforms/wayland/qwaylandcursor.cpp @@ -43,8 +43,8 @@ #include "qwaylanddisplay.h" #include "qwaylandinputdevice.h" -#include "qwaylandshmsurface.h" #include "qwaylandscreen.h" +#include "qwaylandshmbackingstore.h" #include diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp index 090edfe324..9cd79e2978 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -42,7 +42,7 @@ #include "qwaylandintegration.h" #include "qwaylanddisplay.h" -#include "qwaylandshmsurface.h" +#include "qwaylandshmbackingstore.h" #include "qwaylandshmwindow.h" #include "qwaylandnativeinterface.h" #include "qwaylandclipboard.h" @@ -116,10 +116,9 @@ QPlatformGLContext *QWaylandIntegration::createPlatformGLContext(const QGuiGLFor #endif } -QWindowSurface *QWaylandIntegration::createWindowSurface(QWindow *window, WId winId) const +QPlatformBackingStore *QWaylandIntegration::createPlatformBackingStore(QWindow *window) const { - Q_UNUSED(winId); - return new QWaylandShmWindowSurface(window); + return new QWaylandShmBackingStore(window); } QPlatformFontDatabase *QWaylandIntegration::fontDatabase() const diff --git a/src/plugins/platforms/wayland/qwaylandintegration.h b/src/plugins/platforms/wayland/qwaylandintegration.h index e55dec3229..1e22191ff7 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.h +++ b/src/plugins/platforms/wayland/qwaylandintegration.h @@ -58,7 +58,7 @@ public: QPixmapData *createPixmapData(QPixmapData::PixelType type) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; - QWindowSurface *createWindowSurface(QWindow *window, WId winId) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; QList screens() const; diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp new file mode 100644 index 0000000000..ccb50a73fb --- /dev/null +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qwaylandshmbackingstore.h" + +#include + +#include "qwaylanddisplay.h" +#include "qwaylandshmwindow.h" +#include "qwaylandscreen.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display, + const QSize &size, QImage::Format format) +{ + int stride = size.width() * 4; + int alloc = stride * size.height(); + char filename[] = "/tmp/wayland-shm-XXXXXX"; + int fd = mkstemp(filename); + if (fd < 0) + qWarning("open %s failed: %s", filename, strerror(errno)); + if (ftruncate(fd, alloc) < 0) { + qWarning("ftruncate failed: %s", strerror(errno)); + close(fd); + return; + } + uchar *data = (uchar *) + mmap(NULL, alloc, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + unlink(filename); + + if (data == (uchar *) MAP_FAILED) { + qWarning("mmap /dev/zero failed: %s", strerror(errno)); + close(fd); + return; + } + + mImage = QImage(data, size.width(), size.height(), stride, format); + mBuffer = display->createShmBuffer(fd, size.width(), size.height(), + stride, display->argbVisual()); + close(fd); +} + +QWaylandShmBuffer::~QWaylandShmBuffer(void) +{ + munmap((void *) mImage.constBits(), mImage.byteCount()); + wl_buffer_destroy(mBuffer); +} + +QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window) + : QPlatformBackingStore(window) + , mBuffer(0) + , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display()) +{ +} + +QWaylandShmBackingStore::~QWaylandShmBackingStore() +{ +} + +QPaintDevice *QWaylandShmBackingStore::paintDevice() +{ + return mBuffer->image(); +} + +void QWaylandShmBackingStore::beginPaint(const QRegion &) +{ + QWaylandShmWindow *waylandWindow = static_cast(window()->handle()); + Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); + waylandWindow->waitForFrameSync(); +} + +void QWaylandShmBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(window); + Q_UNUSED(offset); + QWaylandShmWindow *waylandWindow = static_cast(window->handle()); + Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); + waylandWindow->damage(region); +} + +void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &) +{ + QWaylandShmWindow *waylandWindow = static_cast(window()->handle()); + Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); + + QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format(); + + if (mBuffer != NULL && mBuffer->size() == size) + return; + + if (mBuffer != NULL) + delete mBuffer; + + mBuffer = new QWaylandShmBuffer(mDisplay, size, format); + + waylandWindow->attach(mBuffer); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.h b/src/plugins/platforms/wayland/qwaylandshmbackingstore.h new file mode 100644 index 0000000000..5e6959dc2f --- /dev/null +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDSHMBACKINGSTORE_H +#define QWAYLANDSHMBACKINGSTORE_H + +#include "qwaylandbuffer.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; + +class QWaylandShmBuffer : public QWaylandBuffer { +public: + QWaylandShmBuffer(QWaylandDisplay *display, + const QSize &size, QImage::Format format); + ~QWaylandShmBuffer(); + QSize size() const { return mImage.size(); } + QImage *image() { return &mImage; } +private: + QImage mImage; +}; + +class QWaylandShmBackingStore : public QPlatformBackingStore +{ +public: + QWaylandShmBackingStore(QWindow *window); + ~QWaylandShmBackingStore(); + + QPaintDevice *paintDevice(); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize(const QSize &size, const QRegion &staticContents); + void beginPaint(const QRegion &); + +private: + QWaylandShmBuffer *mBuffer; + QWaylandDisplay *mDisplay; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/wayland/qwaylandshmsurface.cpp b/src/plugins/platforms/wayland/qwaylandshmsurface.cpp deleted file mode 100644 index 520633811c..0000000000 --- a/src/plugins/platforms/wayland/qwaylandshmsurface.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "qwaylandshmsurface.h" - -#include - -#include "qwaylanddisplay.h" -#include "qwaylandshmwindow.h" -#include "qwaylandscreen.h" - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display, - const QSize &size, QImage::Format format) -{ - int stride = size.width() * 4; - int alloc = stride * size.height(); - char filename[] = "/tmp/wayland-shm-XXXXXX"; - int fd = mkstemp(filename); - if (fd < 0) - qWarning("open %s failed: %s", filename, strerror(errno)); - if (ftruncate(fd, alloc) < 0) { - qWarning("ftruncate failed: %s", strerror(errno)); - close(fd); - return; - } - uchar *data = (uchar *) - mmap(NULL, alloc, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - unlink(filename); - - if (data == (uchar *) MAP_FAILED) { - qWarning("mmap /dev/zero failed: %s", strerror(errno)); - close(fd); - return; - } - - mImage = QImage(data, size.width(), size.height(), stride, format); - mBuffer = display->createShmBuffer(fd, size.width(), size.height(), - stride, display->argbVisual()); - close(fd); -} - -QWaylandShmBuffer::~QWaylandShmBuffer(void) -{ - munmap((void *) mImage.constBits(), mImage.byteCount()); - wl_buffer_destroy(mBuffer); -} - -QWaylandShmWindowSurface::QWaylandShmWindowSurface(QWindow *window) - : QWindowSurface(window) - , mBuffer(0) - , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display()) -{ -} - -QWaylandShmWindowSurface::~QWaylandShmWindowSurface() -{ -} - -QPaintDevice *QWaylandShmWindowSurface::paintDevice() -{ - return mBuffer->image(); -} - -void QWaylandShmWindowSurface::beginPaint(const QRegion &) -{ - QWaylandShmWindow *waylandWindow = static_cast(window()->handle()); - Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); - waylandWindow->waitForFrameSync(); -} - -void QWaylandShmWindowSurface::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(window); - Q_UNUSED(offset); - QWaylandShmWindow *waylandWindow = static_cast(window->handle()); - Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); - waylandWindow->damage(region); -} - -void QWaylandShmWindowSurface::resize(const QSize &size) -{ - QWaylandShmWindow *waylandWindow = static_cast(window()->handle()); - Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); - - QWindowSurface::resize(size); - QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format(); - - if (mBuffer != NULL && mBuffer->size() == size) - return; - - if (mBuffer != NULL) - delete mBuffer; - - mBuffer = new QWaylandShmBuffer(mDisplay, size, format); - - waylandWindow->attach(mBuffer); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandshmsurface.h b/src/plugins/platforms/wayland/qwaylandshmsurface.h deleted file mode 100644 index 1045709d7c..0000000000 --- a/src/plugins/platforms/wayland/qwaylandshmsurface.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWINDOWSURFACE_WAYLAND_H -#define QWINDOWSURFACE_WAYLAND_H - -#include "qwaylandbuffer.h" -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QWaylandDisplay; - -class QWaylandShmBuffer : public QWaylandBuffer { -public: - QWaylandShmBuffer(QWaylandDisplay *display, - const QSize &size, QImage::Format format); - ~QWaylandShmBuffer(); - QSize size() const { return mImage.size(); } - QImage *image() { return &mImage; } -private: - QImage mImage; -}; - -class QWaylandShmWindowSurface : public QWindowSurface -{ -public: - QWaylandShmWindowSurface(QWindow *window); - ~QWaylandShmWindowSurface(); - - QPaintDevice *paintDevice(); - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); - void resize(const QSize &size); - void beginPaint(const QRegion &); - -private: - QWaylandShmBuffer *mBuffer; - QWaylandDisplay *mDisplay; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro index 0a2084df3b..9010439939 100644 --- a/src/plugins/platforms/wayland/wayland.pro +++ b/src/plugins/platforms/wayland/wayland.pro @@ -13,7 +13,7 @@ QT += core-private gui-private opengl-private platformsupport-private SOURCES = main.cpp \ qwaylandintegration.cpp \ qwaylandnativeinterface.cpp \ - qwaylandshmsurface.cpp \ + qwaylandshmbackingstore.cpp \ qwaylandinputdevice.cpp \ qwaylandcursor.cpp \ qwaylanddisplay.cpp \ @@ -28,7 +28,7 @@ HEADERS = qwaylandintegration.h \ qwaylanddisplay.h \ qwaylandwindow.h \ qwaylandscreen.h \ - qwaylandshmsurface.h \ + qwaylandshmbackingstore.h \ qwaylandbuffer.h \ qwaylandshmwindow.h \ qwaylandclipboard.h diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp new file mode 100644 index 0000000000..24ec65fb47 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbbackingstore.h" + +#include "qxcbconnection.h" +#include "qxcbscreen.h" +#include "qxcbwindow.h" + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +class QXcbShmImage : public QXcbObject +{ +public: + QXcbShmImage(QXcbScreen *connection, const QSize &size, uint depth, QImage::Format format); + ~QXcbShmImage() { destroy(); } + + QImage *image() { return &m_qimage; } + QSize size() const { return m_qimage.size(); } + + void put(xcb_window_t window, const QPoint &dst, const QRect &source); + void preparePaint(const QRegion ®ion); + +private: + void destroy(); + + xcb_shm_segment_info_t m_shm_info; + + xcb_image_t *m_xcb_image; + + QImage m_qimage; + + xcb_gcontext_t m_gc; + xcb_window_t m_gc_window; + + QRegion m_dirty; +}; + +QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) + : QXcbObject(screen->connection()) + , m_gc(0) + , m_gc_window(0) +{ + Q_XCB_NOOP(connection()); + m_xcb_image = xcb_image_create_native(xcb_connection(), + size.width(), + size.height(), + XCB_IMAGE_FORMAT_Z_PIXMAP, + depth, + 0, + ~0, + 0); + + const int segmentSize = m_xcb_image->stride * m_xcb_image->height; + if (!segmentSize) + return; + + int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0777); + if (id == -1) + qWarning("QXcbShmImage: shmget() failed (%d) for size %d (%dx%d)", + errno, segmentSize, size.width(), size.height()); + else + m_shm_info.shmid = id; + m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat (m_shm_info.shmid, 0, 0); + m_shm_info.shmseg = xcb_generate_id(xcb_connection()); + + xcb_generic_error_t *error = xcb_request_check(xcb_connection(), xcb_shm_attach_checked(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false)); + if (error) { + qWarning() << "QXcbBackingStore: Unable to attach to shared memory segment"; + free(error); + } + + if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) + qWarning() << "QXcbBackingStore: Error while marking the shared memory segment to be destroyed"; + + m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); +} + +void QXcbShmImage::destroy() +{ + const int segmentSize = m_xcb_image ? (m_xcb_image->stride * m_xcb_image->height) : 0; + if (segmentSize) + Q_XCB_CALL(xcb_shm_detach(xcb_connection(), m_shm_info.shmseg)); + + xcb_image_destroy(m_xcb_image); + + if (segmentSize) { + shmdt(m_shm_info.shmaddr); + shmctl(m_shm_info.shmid, IPC_RMID, 0); + } + + if (m_gc) + Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); +} + +void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &source) +{ + Q_XCB_NOOP(connection()); + if (m_gc_window != window) { + if (m_gc) + Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); + + m_gc = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_gc(xcb_connection(), m_gc, window, 0, 0)); + + m_gc_window = window; + } + + Q_XCB_NOOP(connection()); + xcb_image_shm_put(xcb_connection(), + window, + m_gc, + m_xcb_image, + m_shm_info, + source.x(), + source.y(), + target.x(), + target.y(), + source.width(), + source.height(), + false); + Q_XCB_NOOP(connection()); + + m_dirty = m_dirty | source; + + xcb_flush(xcb_connection()); + Q_XCB_NOOP(connection()); +} + +void QXcbShmImage::preparePaint(const QRegion ®ion) +{ + // to prevent X from reading from the image region while we're writing to it + if (m_dirty.intersects(region)) { + connection()->sync(); + m_dirty = QRegion(); + } +} + +QXcbBackingStore::QXcbBackingStore(QWindow *window) + : QPlatformBackingStore(window) + , m_image(0) + , m_syncingResize(false) +{ + QXcbScreen *screen = static_cast(QPlatformScreen::platformScreenForWindow(window)); + setConnection(screen->connection()); +} + +QXcbBackingStore::~QXcbBackingStore() +{ + delete m_image; +} + +QPaintDevice *QXcbBackingStore::paintDevice() +{ + return m_image->image(); +} + +void QXcbBackingStore::beginPaint(const QRegion ®ion) +{ + m_image->preparePaint(region); + +#if 0 + if (m_image->image()->hasAlphaChannel()) { + QPainter p(m_image->image()); + p.setCompositionMode(QPainter::CompositionMode_Source); + const QVector rects = region.rects(); + const QColor blank = Qt::transparent; + for (QVector::const_iterator it = rects.begin(); it != rects.end(); ++it) { + p.fillRect(*it, blank); + } + } +#endif +} + +void QXcbBackingStore::endPaint(const QRegion &) +{ +} + +void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + QRect bounds = region.boundingRect(); + + if (!m_image || m_image->size().isEmpty()) + return; + + Q_XCB_NOOP(connection()); + + QXcbWindow *platformWindow = static_cast(window->handle()); + + QVector rects = region.rects(); + for (int i = 0; i < rects.size(); ++i) + m_image->put(platformWindow->xcb_window(), rects.at(i).topLeft(), rects.at(i).translated(offset)); + + Q_XCB_NOOP(connection()); + + if (m_syncingResize) { + xcb_flush(xcb_connection()); + connection()->sync(); + m_syncingResize = false; + platformWindow->updateSyncRequestCounter(); + } +} + +void QXcbBackingStore::resize(const QSize &size, const QRegion &) +{ + if (m_image && size == m_image->size()) + return; + + Q_XCB_NOOP(connection()); + + QXcbScreen *screen = static_cast(QPlatformScreen::platformScreenForWindow(window())); + QXcbWindow* win = static_cast(window()->handle()); + + delete m_image; + m_image = new QXcbShmImage(screen, size, win->depth(), win->format()); + Q_XCB_NOOP(connection()); + + m_syncingResize = true; +} + +extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); + +bool QXcbBackingStore::scroll(const QRegion &area, int dx, int dy) +{ + if (!m_image || m_image->image()->isNull()) + return false; + + m_image->preparePaint(area); + + const QVector rects = area.rects(); + for (int i = 0; i < rects.size(); ++i) + qt_scrollRectInImage(*m_image->image(), rects.at(i), QPoint(dx, dy)); + + return true; +} + diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h new file mode 100644 index 0000000000..db94d26b09 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXCBBACKINGSTORE_H +#define QXCBBACKINGSTORE_H + +#include + +#include + +#include "qxcbobject.h" + +class QXcbShmImage; + +class QXcbBackingStore : public QXcbObject, public QPlatformBackingStore +{ +public: + QXcbBackingStore(QWindow *widget); + ~QXcbBackingStore(); + + QPaintDevice *paintDevice(); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize(const QSize &size, const QRegion &staticContents); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion &); + void endPaint(const QRegion &); + +private: + QXcbShmImage *m_image; + bool m_syncingResize; +}; + +#endif diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index a07a5a544e..72d0036a3c 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -43,7 +43,7 @@ #include "qxcbconnection.h" #include "qxcbscreen.h" #include "qxcbwindow.h" -#include "qxcbwindowsurface.h" +#include "qxcbbackingstore.h" #include "qxcbnativeinterface.h" #include "qxcbclipboard.h" #include "qxcbdrag.h" @@ -114,10 +114,9 @@ QPlatformGLContext *QXcbIntegration::createPlatformGLContext(const QGuiGLFormat #endif } -QWindowSurface *QXcbIntegration::createWindowSurface(QWindow *window, WId winId) const +QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const { - Q_UNUSED(winId); - return new QXcbWindowSurface(window); + return new QXcbBackingStore(window); } QList QXcbIntegration::screens() const diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index d931e2a787..5837be1148 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -59,7 +59,7 @@ public: QPixmapData *createPixmapData(QPixmapData::PixelType type) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; - QWindowSurface *createWindowSurface(QWindow *window, WId winId) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; QList screens() const; void moveToScreen(QWindow *window, int screen); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3cf78d00c3..547a93be0b 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -56,8 +56,8 @@ #include #include -#include +#include #include #include @@ -1053,12 +1053,8 @@ QPlatformGLSurface *QXcbWindow::createGLSurface() const void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) { - QWindowSurface *surface = window()->surface(); - if (surface) { - QRect rect(event->x, event->y, event->width, event->height); - - QWindowSystemInterface::handleExposeEvent(window(), rect); - } + QRect rect(event->x, event->y, event->width, event->height); + QWindowSystemInterface::handleExposeEvent(window(), rect); } void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *event) diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp deleted file mode 100644 index 63378515cc..0000000000 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qxcbwindowsurface.h" - -#include "qxcbconnection.h" -#include "qxcbscreen.h" -#include "qxcbwindow.h" - -#include -#include - -#include -#include - -#include -#include - -#include -#include - -class QXcbShmImage : public QXcbObject -{ -public: - QXcbShmImage(QXcbScreen *connection, const QSize &size, uint depth, QImage::Format format); - ~QXcbShmImage() { destroy(); } - - QImage *image() { return &m_qimage; } - - void put(xcb_window_t window, const QPoint &dst, const QRect &source); - void preparePaint(const QRegion ®ion); - -private: - void destroy(); - - xcb_shm_segment_info_t m_shm_info; - - xcb_image_t *m_xcb_image; - - QImage m_qimage; - - xcb_gcontext_t m_gc; - xcb_window_t m_gc_window; - - QRegion m_dirty; -}; - -QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) - : QXcbObject(screen->connection()) - , m_gc(0) - , m_gc_window(0) -{ - Q_XCB_NOOP(connection()); - m_xcb_image = xcb_image_create_native(xcb_connection(), - size.width(), - size.height(), - XCB_IMAGE_FORMAT_Z_PIXMAP, - depth, - 0, - ~0, - 0); - - const int segmentSize = m_xcb_image->stride * m_xcb_image->height; - if (!segmentSize) - return; - - int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0777); - if (id == -1) - qWarning("QXcbShmImage: shmget() failed (%d) for size %d (%dx%d)", - errno, segmentSize, size.width(), size.height()); - else - m_shm_info.shmid = id; - m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat (m_shm_info.shmid, 0, 0); - m_shm_info.shmseg = xcb_generate_id(xcb_connection()); - - xcb_generic_error_t *error = xcb_request_check(xcb_connection(), xcb_shm_attach_checked(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false)); - if (error) { - qWarning() << "QXcbWindowSurface: Unable to attach to shared memory segment"; - free(error); - } - - if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) - qWarning() << "QXcbWindowSurface: Error while marking the shared memory segment to be destroyed"; - - m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); -} - -void QXcbShmImage::destroy() -{ - const int segmentSize = m_xcb_image ? (m_xcb_image->stride * m_xcb_image->height) : 0; - if (segmentSize) - Q_XCB_CALL(xcb_shm_detach(xcb_connection(), m_shm_info.shmseg)); - - xcb_image_destroy(m_xcb_image); - - if (segmentSize) { - shmdt(m_shm_info.shmaddr); - shmctl(m_shm_info.shmid, IPC_RMID, 0); - } - - if (m_gc) - Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); -} - -void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &source) -{ - Q_XCB_NOOP(connection()); - if (m_gc_window != window) { - if (m_gc) - Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); - - m_gc = xcb_generate_id(xcb_connection()); - Q_XCB_CALL(xcb_create_gc(xcb_connection(), m_gc, window, 0, 0)); - - m_gc_window = window; - } - - Q_XCB_NOOP(connection()); - xcb_image_shm_put(xcb_connection(), - window, - m_gc, - m_xcb_image, - m_shm_info, - source.x(), - source.y(), - target.x(), - target.y(), - source.width(), - source.height(), - false); - Q_XCB_NOOP(connection()); - - m_dirty = m_dirty | source; - - xcb_flush(xcb_connection()); - Q_XCB_NOOP(connection()); -} - -void QXcbShmImage::preparePaint(const QRegion ®ion) -{ - // to prevent X from reading from the image region while we're writing to it - if (m_dirty.intersects(region)) { - connection()->sync(); - m_dirty = QRegion(); - } -} - -QXcbWindowSurface::QXcbWindowSurface(QWindow *window, bool setDefaultSurface) - : QWindowSurface(window, setDefaultSurface) - , m_image(0) - , m_syncingResize(false) -{ - QXcbScreen *screen = static_cast(QPlatformScreen::platformScreenForWindow(window)); - setConnection(screen->connection()); -} - -QXcbWindowSurface::~QXcbWindowSurface() -{ - delete m_image; -} - -QPaintDevice *QXcbWindowSurface::paintDevice() -{ - return m_image->image(); -} - -void QXcbWindowSurface::beginPaint(const QRegion ®ion) -{ - m_image->preparePaint(region); - - if (m_image->image()->hasAlphaChannel()) { - QPainter p(m_image->image()); - p.setCompositionMode(QPainter::CompositionMode_Source); - const QVector rects = region.rects(); - const QColor blank = Qt::transparent; - for (QVector::const_iterator it = rects.begin(); it != rects.end(); ++it) { - p.fillRect(*it, blank); - } - } -} - -void QXcbWindowSurface::endPaint(const QRegion &) -{ -} - -void QXcbWindowSurface::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - QRect bounds = region.boundingRect(); - - if (size().isEmpty() || !geometry().contains(bounds)) - return; - - Q_XCB_NOOP(connection()); - - QXcbWindow *platformWindow = static_cast(window->handle()); - - QVector rects = region.rects(); - for (int i = 0; i < rects.size(); ++i) - m_image->put(platformWindow->xcb_window(), rects.at(i).topLeft(), rects.at(i).translated(offset)); - - Q_XCB_NOOP(connection()); - - if (m_syncingResize) { - xcb_flush(xcb_connection()); - connection()->sync(); - m_syncingResize = false; - platformWindow->updateSyncRequestCounter(); - } -} - -void QXcbWindowSurface::resize(const QSize &size) -{ - if (size == QWindowSurface::size()) - return; - - Q_XCB_NOOP(connection()); - QWindowSurface::resize(size); - - QXcbScreen *screen = static_cast(QPlatformScreen::platformScreenForWindow(window())); - QXcbWindow* win = static_cast(window()->handle()); - - delete m_image; - m_image = new QXcbShmImage(screen, size, win->depth(), win->format()); - Q_XCB_NOOP(connection()); - - m_syncingResize = true; -} - -extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); - -bool QXcbWindowSurface::scroll(const QRegion &area, int dx, int dy) -{ - if (!m_image || m_image->image()->isNull()) - return false; - - m_image->preparePaint(area); - - const QVector rects = area.rects(); - for (int i = 0; i < rects.size(); ++i) - qt_scrollRectInImage(*m_image->image(), rects.at(i), QPoint(dx, dy)); - - return true; -} - diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.h b/src/plugins/platforms/xcb/qxcbwindowsurface.h deleted file mode 100644 index 8f401d94a3..0000000000 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.h +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QXCBWINDOWSURFACE_H -#define QXCBWINDOWSURFACE_H - -#include - -#include - -#include "qxcbobject.h" - -class QXcbShmImage; - -class QXcbWindowSurface : public QXcbObject, public QWindowSurface -{ -public: - QXcbWindowSurface(QWindow *widget, bool setDefaultSurface = true); - ~QXcbWindowSurface(); - - QPaintDevice *paintDevice(); - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); - void resize(const QSize &size); - bool scroll(const QRegion &area, int dx, int dy); - - void beginPaint(const QRegion &); - void endPaint(const QRegion &); - -private: - QXcbShmImage *m_image; - bool m_syncingResize; -}; - -#endif diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index e5d9b98bd0..8cf7ec4aff 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -14,7 +14,7 @@ SOURCES = \ qxcbdrag.cpp \ qxcbscreen.cpp \ qxcbwindow.cpp \ - qxcbwindowsurface.cpp \ + qxcbbackingstore.cpp \ qxcbwmsupport.cpp \ main.cpp \ qxcbnativeinterface.cpp \ @@ -31,7 +31,7 @@ HEADERS = \ qxcbobject.h \ qxcbscreen.h \ qxcbwindow.h \ - qxcbwindowsurface.h \ + qxcbbackingstore.h \ qxcbwmsupport.h \ qxcbnativeinterface.h \ qxcbcursor.h \ diff --git a/src/widgets/kernel/kernel.pri b/src/widgets/kernel/kernel.pri index 6be316bae9..a4754018b2 100644 --- a/src/widgets/kernel/kernel.pri +++ b/src/widgets/kernel/kernel.pri @@ -11,7 +11,7 @@ HEADERS += \ kernel/qactiongroup.h \ kernel/qapplication.h \ kernel/qapplication_p.h \ - kernel/qbackingstore_p.h \ + kernel/qwidgetbackingstore_p.h \ kernel/qboxlayout.h \ kernel/qdesktopwidget.h \ kernel/qformlayout.h \ @@ -46,7 +46,7 @@ SOURCES += \ kernel/qaction.cpp \ kernel/qactiongroup.cpp \ kernel/qapplication.cpp \ - kernel/qbackingstore.cpp \ + kernel/qwidgetbackingstore.cpp \ kernel/qboxlayout.cpp \ kernel/qformlayout.cpp \ kernel/qgridlayout.cpp \ diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index ec7c3a5712..7595290d11 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -503,17 +503,7 @@ bool qt_tabletChokeMouse = false; inline bool QApplicationPrivate::isAlien(QWidget *widget) { - if (!widget) - return false; -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) - return !widget->isWindow() -# ifdef Q_BACKINGSTORE_SUBSURFACES - && !(widget->d_func()->maybeTopData() && widget->d_func()->maybeTopData()->windowSurface) -# endif - ; -#else - return !widget->internalWinId(); -#endif + return widget && !widget->isWindow(); } // ######## move to QApplicationPrivate diff --git a/src/widgets/kernel/qbackingstore.cpp b/src/widgets/kernel/qbackingstore.cpp deleted file mode 100644 index 1d5fbbc8f9..0000000000 --- a/src/widgets/kernel/qbackingstore.cpp +++ /dev/null @@ -1,1665 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qplatformdefs.h" - -#include "qbackingstore_p.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef Q_WS_QWS -#include -#include -#endif - -QT_BEGIN_NAMESPACE - -extern QRegion qt_dirtyRegion(QWidget *); - -/* - A version of QRect::intersects() that does not normalize the rects. -*/ -static inline bool qRectIntersects(const QRect &r1, const QRect &r2) -{ - return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) - && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom())); -} - -/** - * Flushes the contents of the \a windowSurface into the screen area of \a widget. - * \a tlwOffset is the position of the top level widget relative to the window surface. - * \a region is the region to be updated in \a widget coordinates. - */ -static inline void qt_flush(QWidget *widget, const QRegion ®ion, QWindowSurface *windowSurface, - QWidget *tlw, const QPoint &tlwOffset) -{ - Q_ASSERT(widget); - Q_ASSERT(!region.isEmpty()); - Q_ASSERT(windowSurface); - Q_ASSERT(tlw); - -#if !defined(QT_NO_PAINT_DEBUG) && !defined(Q_WS_QWS) - // QWS does flush update in QWindowSurface::flush (because it needs to lock the surface etc). - static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt(); - if (flushUpdate > 0) - QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false); -#endif - - //The performance hit by doing this should be negligible. However, be aware that - //using this FPS when you have > 1 windowsurface can give you inaccurate FPS - static bool fpsDebug = qgetenv("QT_DEBUG_FPS").toInt(); - if (fpsDebug) { - static QTime time = QTime::currentTime(); - static int frames = 0; - - frames++; - - if(time.elapsed() > 5000) { - double fps = double(frames * 1000) /time.restart(); - fprintf(stderr,"FPS: %.1f\n",fps); - frames = 0; - } - } - if (widget != tlw) - windowSurface->flush(widget->windowHandle(), region, tlwOffset + widget->mapTo(tlw, QPoint())); - else - windowSurface->flush(widget->windowHandle(), region, tlwOffset); -} - -#ifndef QT_NO_PAINT_DEBUG -#ifdef Q_WS_WIN -static void showYellowThing_win(QWidget *widget, const QRegion ®ion, int msec) -{ - HBRUSH brush; - static int i = 0; - switch (i) { - case 0: - brush = CreateSolidBrush(RGB(255, 255, 0)); - break; - case 1: - brush = CreateSolidBrush(RGB(255, 200, 55)); - break; - case 2: - brush = CreateSolidBrush(RGB(200, 255, 55)); - break; - case 3: - brush = CreateSolidBrush(RGB(200, 200, 0)); - break; - } - i = (i + 1) & 3; - - HDC hdc = widget->getDC(); - - const QVector &rects = region.rects(); - foreach (QRect rect, rects) { - RECT winRect; - SetRect(&winRect, rect.left(), rect.top(), rect.right(), rect.bottom()); - FillRect(hdc, &winRect, brush); - } - - widget->releaseDC(hdc); - ::Sleep(msec); -} -#endif - -void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped) -{ -#ifdef Q_WS_QWS - Q_UNUSED(widget); - Q_UNUSED(unclipped); - static QWSYellowSurface surface(true); - surface.setDelay(msec); - surface.flush(widget, toBePainted, QPoint()); -#else - QRegion paintRegion = toBePainted; - QRect widgetRect = widget->rect(); - - if (!widget->internalWinId()) { - QWidget *nativeParent = widget->nativeParentWidget(); - const QPoint offset = widget->mapTo(nativeParent, QPoint(0, 0)); - paintRegion.translate(offset); - widgetRect.translate(offset); - widget = nativeParent; - } - -#ifdef Q_WS_WIN - Q_UNUSED(unclipped); - showYellowThing_win(widget, paintRegion, msec); -#else - //flags to fool painter - bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped); - if (unclipped && !widget->d_func()->paintOnScreen()) - widget->setAttribute(Qt::WA_PaintUnclipped); - - const bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent); - if (setFlag) - widget->setAttribute(Qt::WA_WState_InPaintEvent); - - //setup the engine - QPaintEngine *pe = widget->paintEngine(); - if (pe) { - pe->setSystemClip(paintRegion); - { - QPainter p(widget); - p.setClipRegion(paintRegion); - static int i = 0; - switch (i) { - case 0: - p.fillRect(widgetRect, QColor(255,255,0)); - break; - case 1: - p.fillRect(widgetRect, QColor(255,200,55)); - break; - case 2: - p.fillRect(widgetRect, QColor(200,255,55)); - break; - case 3: - p.fillRect(widgetRect, QColor(200,200,0)); - break; - } - i = (i+1) & 3; - p.end(); - } - } - - if (setFlag) - widget->setAttribute(Qt::WA_WState_InPaintEvent, false); - - //restore - widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped); - - if (pe) - pe->setSystemClip(QRegion()); - - QApplication::syncX(); - -#if defined(Q_OS_UNIX) - ::usleep(1000 * msec); -#endif -#endif // Q_WS_WIN -#endif // Q_WS_QWS -} - -bool QWidgetBackingStore::flushPaint(QWidget *widget, const QRegion &rgn) -{ - if (!widget) - return false; - - int delay = 0; - if (widget->testAttribute(Qt::WA_WState_InPaintEvent)) { - static int flushPaintEvent = qgetenv("QT_FLUSH_PAINT_EVENT").toInt(); - if (!flushPaintEvent) - return false; - delay = flushPaintEvent; - } else { - static int flushPaint = qgetenv("QT_FLUSH_PAINT").toInt(); - if (!flushPaint) - return false; - delay = flushPaint; - } - - QWidgetBackingStore::showYellowThing(widget, rgn, delay * 10, true); - return true; -} - -void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn) -{ - if (widget->d_func()->paintOnScreen() || rgn.isEmpty()) - return; - - QWidget *tlw = widget->window(); - QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); - if (!tlwExtra) - return; - - const QPoint offset = widget->mapTo(tlw, QPoint()); - qt_flush(widget, rgn, tlwExtra->backingStore->windowSurface, tlw, offset); -} -#endif // QT_NO_PAINT_DEBUG - -/* - Moves the whole rect by (dx, dy) in widget's coordinate system. - Doesn't generate any updates. -*/ -bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *widget) -{ - const QPoint pos(tlwOffset + widget->mapTo(tlw, rect.topLeft())); - const QRect tlwRect(QRect(pos, rect.size())); - if (fullUpdatePending || dirty.intersects(tlwRect)) - return false; // We don't want to scroll junk. - return windowSurface->scroll(tlwRect, dx, dy); -} - -void QWidgetBackingStore::releaseBuffer() -{ - if (windowSurface) -#if defined(Q_WS_QPA) - windowSurface->resize(QSize()); -#else - windowSurface->setGeometry(QRect()); -#endif -#ifdef Q_BACKINGSTORE_SUBSURFACES - for (int i = 0; i < subSurfaces.size(); ++i) - subSurfaces.at(i)->setGeometry(QRect()); -#endif -} - -/*! - Prepares the window surface to paint a\ toClean region of the \a widget and - updates the BeginPaintInfo struct accordingly. - - The \a toClean region might be clipped by the window surface. -*/ -void QWidgetBackingStore::beginPaint(QRegion &toClean, QWidget *widget, QWindowSurface *windowSurface, - BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates) -{ -#ifdef Q_WS_QWS - QWSWindowSurface *surface = static_cast(windowSurface); - QWidget *surfaceWidget = surface->window(); - - if (!surface->isValid()) { - // this looks strange but it really just releases the surface - surface->releaseSurface(); - // the old window surface is deleted in setWindowSurface, which is - // called from QWindowSurface constructor. - windowSurface = tlw->d_func()->createDefaultWindowSurface(); - surface = static_cast(windowSurface); - // createDefaultWindowSurface() will set topdata->windowSurface on the - // widget to zero. However, if this is a sub-surface, it should point - // to the widget's sub windowSurface, so we set that here: - if (!surfaceWidget->isWindow()) - surfaceWidget->d_func()->topData()->windowSurface = windowSurface; - surface->setGeometry(topLevelRect()); - returnInfo->windowSurfaceRecreated = true; - } - - const QRegion toCleanUnclipped(toClean); - - if (surfaceWidget->isWindow()) - tlwOffset = surface->painterOffset(); -#ifdef Q_BACKINGSTORE_SUBSURFACES - else if (toCleanIsInTopLevelCoordinates) - toClean &= surface->clipRegion().translated(surfaceWidget->mapTo(tlw, QPoint())); - if (!toCleanIsInTopLevelCoordinates && windowSurface == this->windowSurface) - toClean &= surface->clipRegion().translated(-widget->mapTo(surfaceWidget, QPoint())); -#else - toClean &= surface->clipRegion(); -#endif - - if (toClean.isEmpty()) { - if (surfaceWidget->isWindow()) { - dirtyFromPreviousSync += toCleanUnclipped; - hasDirtyFromPreviousSync = true; - } - - returnInfo->nothingToPaint = true; - // Nothing to repaint. However, we might have newly exposed areas on the - // screen, so we have to make sure those are flushed. - flush(); - return; - } - - if (surfaceWidget->isWindow()) { - if (toCleanUnclipped != toClean) { - dirtyFromPreviousSync += (toCleanUnclipped - surface->clipRegion()); - hasDirtyFromPreviousSync = true; - } - if (hasDirtyFromPreviousSync) { - dirtyFromPreviousSync -= toClean; - hasDirtyFromPreviousSync = !dirtyFromPreviousSync.isEmpty(); - } - } - -#endif // Q_WS_QWS - - Q_UNUSED(widget); - Q_UNUSED(toCleanIsInTopLevelCoordinates); - - // Always flush repainted areas. - dirtyOnScreen += toClean; - -#if defined(Q_WS_QWS) && !defined(Q_BACKINGSTORE_SUBSURFACES) - toClean.translate(tlwOffset); -#endif - -#ifdef QT_NO_PAINT_DEBUG - windowSurface->beginPaint(toClean); -#else - returnInfo->wasFlushed = QWidgetBackingStore::flushPaint(tlw, toClean); - // Avoid deadlock with QT_FLUSH_PAINT: the server will wait for - // the BackingStore lock, so if we hold that, the server will - // never release the Communication lock that we are waiting for in - // sendSynchronousCommand - if (!returnInfo->wasFlushed) - windowSurface->beginPaint(toClean); -#endif - - Q_UNUSED(returnInfo); -} - -void QWidgetBackingStore::endPaint(const QRegion &cleaned, QWindowSurface *windowSurface, - BeginPaintInfo *beginPaintInfo) -{ -#ifndef QT_NO_PAINT_DEBUG - if (!beginPaintInfo->wasFlushed) - windowSurface->endPaint(cleaned); - else - QWidgetBackingStore::unflushPaint(tlw, cleaned); -#else - Q_UNUSED(beginPaintInfo); - windowSurface->endPaint(cleaned); -#endif - -#ifdef Q_BACKINGSTORE_SUBSURFACES - flush(static_cast(windowSurface)->window(), windowSurface); -#else - flush(); -#endif -} - -/*! - Returns the region (in top-level coordinates) that needs repaint and/or flush. - - If the widget is non-zero, only the dirty region for the widget is returned - and the region will be in widget coordinates. -*/ -QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const -{ - const bool widgetDirty = widget && widget != tlw; - const QRect tlwRect(topLevelRect()); -#if defined(Q_WS_QPA) - const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size()); -#else - const QRect surfaceGeometry(windowSurface->geometry()); -#endif - if (fullUpdatePending || (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size())) { - if (widgetDirty) { - const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size()); - const QPoint offset(widget->mapTo(tlw, QPoint())); - const QRect dirtyWidgetRect(dirtyTlwRect & widget->rect().translated(offset)); - return dirtyWidgetRect.translated(-offset); - } - return QRect(QPoint(), tlwRect.size()); - } - - // Calculate the region that needs repaint. - QRegion r(dirty); - for (int i = 0; i < dirtyWidgets.size(); ++i) { - QWidget *w = dirtyWidgets.at(i); - if (widgetDirty && w != widget && !widget->isAncestorOf(w)) - continue; - r += w->d_func()->dirty.translated(w->mapTo(tlw, QPoint())); - } - - // Append the region that needs flush. - r += dirtyOnScreen; - - if (dirtyOnScreenWidgets) { // Only in use with native child widgets. - for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { - QWidget *w = dirtyOnScreenWidgets->at(i); - if (widgetDirty && w != widget && !widget->isAncestorOf(w)) - continue; - QWidgetPrivate *wd = w->d_func(); - Q_ASSERT(wd->needsFlush); - r += wd->needsFlush->translated(w->mapTo(tlw, QPoint())); - } - } - - if (widgetDirty) { - // Intersect with the widget geometry and translate to its coordinates. - const QPoint offset(widget->mapTo(tlw, QPoint())); - r &= widget->rect().translated(offset); - r.translate(-offset); - } - return r; -} - -/*! - Returns the static content inside the \a parent if non-zero; otherwise the static content - for the entire backing store is returned. The content will be clipped to \a withinClipRect - if non-empty. -*/ -QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const -{ - if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) { -#if defined(Q_WS_QPA) - const QSize surfaceGeometry(windowSurface->size()); -#else - const QRect surfaceGeometry(windowSurface->geometry()); -#endif - QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); - if (!withinClipRect.isEmpty()) - surfaceRect &= withinClipRect; - return QRegion(surfaceRect); - } - - QRegion region; - if (parent && parent->d_func()->children.isEmpty()) - return region; - - const bool clipToRect = !withinClipRect.isEmpty(); - const int count = staticWidgets.count(); - for (int i = 0; i < count; ++i) { - QWidget *w = staticWidgets.at(i); - QWidgetPrivate *wd = w->d_func(); - if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty() - || !w->isVisible() || (parent && !parent->isAncestorOf(w))) { - continue; - } - - QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height()); - const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint()); - if (clipToRect) - rect &= withinClipRect.translated(-offset); - if (rect.isEmpty()) - continue; - - rect &= wd->clipRect(); - if (rect.isEmpty()) - continue; - - QRegion visible(rect); - wd->clipToEffectiveMask(visible); - if (visible.isEmpty()) - continue; - wd->subtractOpaqueSiblings(visible, 0, /*alsoNonOpaque=*/true); - - visible.translate(offset); - region += visible; - } - - return region; -} - -static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) -{ - if (!widget) - return; - - if (updateImmediately) { - QEvent event(QEvent::UpdateRequest); - QApplication::sendEvent(widget, &event); - } else { - QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); - } -} - -/*! - Marks the region of the widget as dirty (if not already marked as dirty) and - posts an UpdateRequest event to the top-level widget (if not already posted). - - If updateImmediately is true, the event is sent immediately instead of posted. - - If invalidateBuffer is true, all widgets intersecting with the region will be dirty. - - If the widget paints directly on screen, the event is sent to the widget - instead of the top-level widget, and invalidateBuffer is completely ignored. - - ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). -*/ -void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately, - bool invalidateBuffer) -{ - Q_ASSERT(tlw->d_func()->extra); - Q_ASSERT(tlw->d_func()->extra->topextra); - Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); - Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); - Q_ASSERT(widget->window() == tlw); - Q_ASSERT(!rgn.isEmpty()); - -#ifndef QT_NO_GRAPHICSEFFECT - widget->d_func()->invalidateGraphicsEffectsRecursively(); -#endif //QT_NO_GRAPHICSEFFECT - - if (widget->d_func()->paintOnScreen()) { - if (widget->d_func()->dirty.isEmpty()) { - widget->d_func()->dirty = rgn; - sendUpdateRequest(widget, updateImmediately); - return; - } else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) { - if (updateImmediately) - sendUpdateRequest(widget, updateImmediately); - return; // Already dirty. - } - - const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); - widget->d_func()->dirty += rgn; - if (!eventAlreadyPosted || updateImmediately) - sendUpdateRequest(widget, updateImmediately); - return; - } - - if (fullUpdatePending) { - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); - return; - } - - if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) { - fullUpdatePending = true; - sendUpdateRequest(tlw, updateImmediately); - return; - } - - const QPoint offset = widget->mapTo(tlw, QPoint()); - const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect()); - if (qt_region_strictContains(dirty, widgetRect.translated(offset))) { - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); - return; // Already dirty. - } - - if (invalidateBuffer) { - const bool eventAlreadyPosted = !dirty.isEmpty(); -#ifndef QT_NO_GRAPHICSEFFECT - if (widget->d_func()->graphicsEffect) - dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset); - else -#endif //QT_NO_GRAPHICSEFFECT - dirty += rgn.translated(offset); - if (!eventAlreadyPosted || updateImmediately) - sendUpdateRequest(tlw, updateImmediately); - return; - } - - if (dirtyWidgets.isEmpty()) { - addDirtyWidget(widget, rgn); - sendUpdateRequest(tlw, updateImmediately); - return; - } - - if (widget->d_func()->inDirtyList) { - if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) { -#ifndef QT_NO_GRAPHICSEFFECT - if (widget->d_func()->graphicsEffect) - widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()); - else -#endif //QT_NO_GRAPHICSEFFECT - widget->d_func()->dirty += rgn; - } - } else { - addDirtyWidget(widget, rgn); - } - - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); -} - -/*! - This function is equivalent to calling markDirty(QRegion(rect), ...), but - is more efficient as it eliminates QRegion operations/allocations and can - use the rect more precisely for additional cut-offs. - - ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). -*/ -void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately, - bool invalidateBuffer) -{ - Q_ASSERT(tlw->d_func()->extra); - Q_ASSERT(tlw->d_func()->extra->topextra); - Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); - Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); - Q_ASSERT(widget->window() == tlw); - Q_ASSERT(!rect.isEmpty()); - -#ifndef QT_NO_GRAPHICSEFFECT - widget->d_func()->invalidateGraphicsEffectsRecursively(); -#endif //QT_NO_GRAPHICSEFFECT - - if (widget->d_func()->paintOnScreen()) { - if (widget->d_func()->dirty.isEmpty()) { - widget->d_func()->dirty = QRegion(rect); - sendUpdateRequest(widget, updateImmediately); - return; - } else if (qt_region_strictContains(widget->d_func()->dirty, rect)) { - if (updateImmediately) - sendUpdateRequest(widget, updateImmediately); - return; // Already dirty. - } - - const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); - widget->d_func()->dirty += rect; - if (!eventAlreadyPosted || updateImmediately) - sendUpdateRequest(widget, updateImmediately); - return; - } - - if (fullUpdatePending) { - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); - return; - } - - if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) { - fullUpdatePending = true; - sendUpdateRequest(tlw, updateImmediately); - return; - } - - const QRect widgetRect = widget->d_func()->effectiveRectFor(rect); - const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint()))); - if (qt_region_strictContains(dirty, translatedRect)) { - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); - return; // Already dirty - } - - if (invalidateBuffer) { - const bool eventAlreadyPosted = !dirty.isEmpty(); - dirty += translatedRect; - if (!eventAlreadyPosted || updateImmediately) - sendUpdateRequest(tlw, updateImmediately); - return; - } - - if (dirtyWidgets.isEmpty()) { - addDirtyWidget(widget, rect); - sendUpdateRequest(tlw, updateImmediately); - return; - } - - if (widget->d_func()->inDirtyList) { - if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) - widget->d_func()->dirty += widgetRect; - } else { - addDirtyWidget(widget, rect); - } - - if (updateImmediately) - sendUpdateRequest(tlw, updateImmediately); -} - -/*! - Marks the \a region of the \a widget as dirty on screen. The \a region will be copied from - the backing store to the \a widget's native parent next time flush() is called. - - Paint on screen widgets are ignored. -*/ -void QWidgetBackingStore::markDirtyOnScreen(const QRegion ®ion, QWidget *widget, const QPoint &topLevelOffset) -{ - if (!widget || widget->d_func()->paintOnScreen() || region.isEmpty()) - return; - -#if defined(Q_WS_QWS) || defined(Q_WS_MAC) - if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) - dirtyOnScreen += region.translated(topLevelOffset); - return; -#endif - - // Top-level. - if (widget == tlw) { - if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) - dirtyOnScreen += region; - return; - } - - // Alien widgets. - if (!widget->internalWinId() && !widget->isWindow()) { - QWidget *nativeParent = widget->nativeParentWidget(); // Alien widgets with the top-level as the native parent (common case). - if (nativeParent == tlw) { - if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) - dirtyOnScreen += region.translated(topLevelOffset); - return; - } - - // Alien widgets with native parent != tlw. - QWidgetPrivate *nativeParentPrivate = nativeParent->d_func(); - if (!nativeParentPrivate->needsFlush) - nativeParentPrivate->needsFlush = new QRegion; - const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint()); - *nativeParentPrivate->needsFlush += region.translated(nativeParentOffset); - appendDirtyOnScreenWidget(nativeParent); - return; - } - - // Native child widgets. - QWidgetPrivate *widgetPrivate = widget->d_func(); - if (!widgetPrivate->needsFlush) - widgetPrivate->needsFlush = new QRegion; - *widgetPrivate->needsFlush += region; - appendDirtyOnScreenWidget(widget); -} - -void QWidgetBackingStore::removeDirtyWidget(QWidget *w) -{ - if (!w) - return; - - dirtyWidgetsRemoveAll(w); - dirtyOnScreenWidgetsRemoveAll(w); - resetWidget(w); - - QWidgetPrivate *wd = w->d_func(); - const int n = wd->children.count(); - for (int i = 0; i < n; ++i) { - if (QWidget *child = qobject_cast(wd->children.at(i))) - removeDirtyWidget(child); - } -} - -#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) -bool QWidgetBackingStore::hasDirtyWindowDecoration() const -{ - QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); - if (tlwExtra && tlwExtra->qwsManager) - return !tlwExtra->qwsManager->d_func()->dirtyRegions.isEmpty(); - return false; -} - -void QWidgetBackingStore::paintWindowDecoration() -{ - if (!hasDirtyWindowDecoration()) - return; - - QDecoration &decoration = QApplication::qwsDecoration(); - const QRect decorationRect = tlw->rect(); - QRegion decorationRegion = decoration.region(tlw, decorationRect); - - QWSManagerPrivate *managerPrivate = tlw->d_func()->topData()->qwsManager->d_func(); - const bool doClipping = !managerPrivate->entireDecorationNeedsRepaint - && !managerPrivate->dirtyClip.isEmpty(); - - if (doClipping) { - decorationRegion &= static_cast(windowSurface)->clipRegion(); - decorationRegion &= managerPrivate->dirtyClip; - } - - if (decorationRegion.isEmpty()) - return; - - //### The QWS decorations do not always paint the pixels they promise to paint. - // This causes painting problems with QWSMemorySurface. Since none of the other - // window surfaces actually use the region, passing an empty region is a safe - // workaround. - - windowSurface->beginPaint(QRegion()); - - QPaintEngine *engine = windowSurface->paintDevice()->paintEngine(); - Q_ASSERT(engine); - const QRegion oldSystemClip(engine->systemClip()); - engine->setSystemClip(decorationRegion.translated(tlwOffset)); - - QPainter painter(windowSurface->paintDevice()); - painter.setFont(QApplication::font()); - painter.translate(tlwOffset); - - const int numDirty = managerPrivate->dirtyRegions.size(); - for (int i = 0; i < numDirty; ++i) { - const int area = managerPrivate->dirtyRegions.at(i); - - QRegion clipRegion = decoration.region(tlw, decorationRect, area); - if (!clipRegion.isEmpty()) { - // Decoration styles changes the clip and assumes the old clip is non-empty, - // so we have to set it, but in theory it shouldn't be required. - painter.setClipRegion(clipRegion); - decoration.paint(&painter, tlw, area, managerPrivate->dirtyStates.at(i)); - } - } - markDirtyOnScreen(decorationRegion, tlw, QPoint()); - - painter.end(); - windowSurface->endPaint(decorationRegion); - managerPrivate->clearDirtyRegions(); - engine->setSystemClip(oldSystemClip); -} -#endif - -void QWidgetBackingStore::updateLists(QWidget *cur) -{ - if (!cur) - return; - - QList children = cur->children(); - for (int i = 0; i < children.size(); ++i) { - QWidget *child = qobject_cast(children.at(i)); - if (!child) - continue; - - updateLists(child); - } - - if (cur->testAttribute(Qt::WA_StaticContents)) - addStaticWidget(cur); - -#ifdef Q_BACKINGSTORE_SUBSURFACES - QTLWExtra *extra = cur->d_func()->maybeTopData(); - if (extra && extra->windowSurface && cur != tlw) - subSurfaces.append(extra->windowSurface); -#endif -} - -QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) - : tlw(topLevel), dirtyOnScreenWidgets(0), hasDirtyFromPreviousSync(false) - , fullUpdatePending(0) -{ - windowSurface = tlw->windowSurface(); - if (!windowSurface) - windowSurface = topLevel->d_func()->createDefaultWindowSurface(); - - // The QWindowSurface constructor will call QWidget::setWindowSurface(), - // but automatically created surfaces should not be added to the topdata. -#ifdef Q_BACKINGSTORE_SUBSURFACES - Q_ASSERT(topLevel->d_func()->topData()->windowSurface == windowSurface); -#endif - topLevel->d_func()->topData()->windowSurface = 0; - - // Ensure all existing subsurfaces and static widgets are added to their respective lists. - updateLists(topLevel); -} - -QWidgetBackingStore::~QWidgetBackingStore() -{ - for (int c = 0; c < dirtyWidgets.size(); ++c) { - resetWidget(dirtyWidgets.at(c)); - } - - delete windowSurface; - windowSurface = 0; - delete dirtyOnScreenWidgets; - dirtyOnScreenWidgets = 0; -} - -//parent's coordinates; move whole rect; update parent and widget -//assume the screen blt has already been done, so we don't need to refresh that part -void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) -{ - Q_Q(QWidget); - if (!q->isVisible() || (dx == 0 && dy == 0)) - return; - - QWidget *tlw = q->window(); - QTLWExtra* x = tlw->d_func()->topData(); - if (x->inTopLevelResize) - return; - - static int accelEnv = -1; - if (accelEnv == -1) { - accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0; - } - - QWidget *pw = q->parentWidget(); - QPoint toplevelOffset = pw->mapTo(tlw, QPoint()); - QWidgetPrivate *pd = pw->d_func(); - QRect clipR(pd->clipRect()); -#ifdef Q_WS_QWS - QWidgetBackingStore *wbs = x->backingStore.data(); - QWSWindowSurface *surface = static_cast(wbs->windowSurface); - clipR = clipR.intersected(surface->clipRegion().translated(-toplevelOffset).boundingRect()); -#endif - const QRect newRect(rect.translated(dx, dy)); - QRect destRect = rect.intersected(clipR); - if (destRect.isValid()) - destRect = destRect.translated(dx, dy).intersected(clipR); - const QRect sourceRect(destRect.translated(-dx, -dy)); - const QRect parentRect(rect & clipR); - - bool accelerateMove = accelEnv && isOpaque -#ifndef QT_NO_GRAPHICSVIEW - // No accelerate move for proxy widgets. - && !tlw->d_func()->extra->proxyWidget -#endif - && !isOverlapped(sourceRect) && !isOverlapped(destRect); - - if (!accelerateMove) { - QRegion parentR(effectiveRectFor(parentRect)); - if (!extra || !extra->hasMask) { - parentR -= newRect; - } else { - // invalidateBuffer() excludes anything outside the mask - parentR += newRect & clipR; - } - pd->invalidateBuffer(parentR); - invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft())); - } else { - - QWidgetBackingStore *wbs = x->backingStore.data(); - QRegion childExpose(newRect & clipR); - - if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw)) - childExpose -= destRect; - - if (!pw->updatesEnabled()) - return; - - const bool childUpdatesEnabled = q->updatesEnabled(); - if (childUpdatesEnabled && !childExpose.isEmpty()) { - childExpose.translate(-data.crect.topLeft()); - wbs->markDirty(childExpose, q); - isMoved = true; - } - - QRegion parentExpose(parentRect); - parentExpose -= newRect; - if (extra && extra->hasMask) - parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft()); - - if (!parentExpose.isEmpty()) { - wbs->markDirty(parentExpose, pw); - pd->isMoved = true; - } - - if (childUpdatesEnabled) { - QRegion needsFlush(sourceRect); - needsFlush += destRect; - wbs->markDirtyOnScreen(needsFlush, pw, toplevelOffset); - } - } -} - -//widget's coordinates; scroll within rect; only update widget -void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) -{ - Q_Q(QWidget); - QWidget *tlw = q->window(); - QTLWExtra* x = tlw->d_func()->topData(); - if (x->inTopLevelResize) - return; - - QWidgetBackingStore *wbs = x->backingStore.data(); - if (!wbs) - return; - - static int accelEnv = -1; - if (accelEnv == -1) { - accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0; - } - - QRect scrollRect = rect & clipRect(); - bool overlapped = false; - bool accelerateScroll = accelEnv && isOpaque - && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft()))); - -#if defined(Q_WS_QWS) - QWSWindowSurface *surface; - surface = static_cast(wbs->windowSurface); - - if (accelerateScroll && !surface->isBuffered()) { - const QRegion surfaceClip = surface->clipRegion(); - const QRegion outsideClip = QRegion(rect) - surfaceClip; - if (!outsideClip.isEmpty()) { - const QVector clipped = (surfaceClip & rect).rects(); - if (clipped.size() < 8) { - for (int i = 0; i < clipped.size(); ++i) - this->scrollRect(clipped.at(i), dx, dy); - return; - } else { - accelerateScroll = false; - } - } - } -#endif // Q_WS_QWS - - if (!accelerateScroll) { - if (overlapped) { - QRegion region(scrollRect); - subtractOpaqueSiblings(region); - invalidateBuffer(region); - }else { - invalidateBuffer(scrollRect); - } - } else { - const QPoint toplevelOffset = q->mapTo(tlw, QPoint()); -#ifdef Q_WS_QWS - QWSWindowSurface *surface = static_cast(wbs->windowSurface); - const QRegion clip = surface->clipRegion().translated(-toplevelOffset) & scrollRect; - const QRect clipBoundingRect = clip.boundingRect(); - scrollRect &= clipBoundingRect; -#endif - const QRect destRect = scrollRect.translated(dx, dy) & scrollRect; - const QRect sourceRect = destRect.translated(-dx, -dy); - - QRegion childExpose(scrollRect); - if (sourceRect.isValid()) { - if (wbs->bltRect(sourceRect, dx, dy, q)) - childExpose -= destRect; - } - - if (inDirtyList) { - if (rect == q->rect()) { - dirty.translate(dx, dy); - } else { - QRegion dirtyScrollRegion = dirty.intersected(scrollRect); - if (!dirtyScrollRegion.isEmpty()) { - dirty -= dirtyScrollRegion; - dirtyScrollRegion.translate(dx, dy); - dirty += dirtyScrollRegion; - } - } - } - - if (!q->updatesEnabled()) - return; - - if (!childExpose.isEmpty()) { - wbs->markDirty(childExpose, q); - isScrolled = true; - } - - // Instead of using native scroll-on-screen, we copy from - // backingstore, giving only one screen update for each - // scroll, and a solid appearance - wbs->markDirtyOnScreen(destRect, q, toplevelOffset); - } -} - -static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra) -{ - if (!tlw || !tlwExtra) - return true; - -#ifdef Q_WS_X11 - // Delay the sync until we get an Expose event from X11 (initial show). - // Qt::WA_Mapped is set to true, but the actual mapping has not yet occurred. - // However, we must repaint immediately regardless of the state if someone calls repaint(). - if (tlwExtra->waitingForMapNotify && !tlwExtra->inRepaint) - return true; -#endif - - if (!tlw->testAttribute(Qt::WA_Mapped)) - return true; - - if (!tlw->isVisible() -#ifndef Q_WS_X11 - // If we're minimized on X11, WA_Mapped will be false and we - // will return in the case above. Some window managers on X11 - // sends us the PropertyNotify to change the minimized state - // *AFTER* we've received the expose event, which is baaad. - || tlw->isMinimized() -#endif - ) - return true; - - return false; -} - -/*! - Synchronizes the \a exposedRegion of the \a exposedWidget with the backing store. - - If there's nothing to repaint, the area is flushed and painting does not occur; - otherwise the area is marked as dirty on screen and will be flushed right after - we are done with all painting. -*/ -void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion) -{ - QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); - if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize) - return; - - if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible() - || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) { - return; - } - - // If there's no preserved contents support we always need - // to do a full repaint before flushing - if (!windowSurface->hasFeature(QWindowSurface::PreservedContents)) - fullUpdatePending = true; - - // Nothing to repaint. - if (!isDirty()) { - qt_flush(exposedWidget, exposedRegion, windowSurface, tlw, tlwOffset); - return; - } - - if (exposedWidget != tlw) - markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint())); - else - markDirtyOnScreen(exposedRegion, exposedWidget, QPoint()); - sync(); -} - -/*! - Synchronizes the backing store, i.e. dirty areas are repainted and flushed. -*/ -void QWidgetBackingStore::sync() -{ - QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); - if (discardSyncRequest(tlw, tlwExtra)) { - // If the top-level is minimized, it's not visible on the screen so we can delay the - // update until it's shown again. In order to do that we must keep the dirty states. - // These will be cleared when we receive the first expose after showNormal(). - // However, if the widget is not visible (isVisible() returns false), everything will - // be invalidated once the widget is shown again, so clear all dirty states. - if (!tlw->isVisible()) { - dirty = QRegion(); - for (int i = 0; i < dirtyWidgets.size(); ++i) - resetWidget(dirtyWidgets.at(i)); - dirtyWidgets.clear(); - fullUpdatePending = false; - } - return; - } - - const bool updatesDisabled = !tlw->updatesEnabled(); - bool repaintAllWidgets = false; - - const bool inTopLevelResize = tlwExtra->inTopLevelResize; - const QRect tlwRect(topLevelRect()); -#ifdef Q_WS_QPA - const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size()); -#else - const QRect surfaceGeometry(windowSurface->geometry()); -#endif - if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { - if (hasStaticContents()) { - // Repaint existing dirty area and newly visible area. - const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); - const QRegion staticRegion(staticContents(0, clipRect)); - QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height()); - newVisible -= staticRegion; - dirty += newVisible; - windowSurface->setStaticContents(staticRegion); - } else { - // Repaint everything. - dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height()); - for (int i = 0; i < dirtyWidgets.size(); ++i) - resetWidget(dirtyWidgets.at(i)); - dirtyWidgets.clear(); - repaintAllWidgets = true; - } - } - -#ifdef Q_WS_QPA - if (inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) - windowSurface->resize(tlwRect.size()); -#else - if (inTopLevelResize || surfaceGeometry != tlwRect) - windowSurface->setGeometry(tlwRect); -#endif - - if (updatesDisabled) - return; - - if (hasDirtyFromPreviousSync) - dirty += dirtyFromPreviousSync; - - // Contains everything that needs repaint. - QRegion toClean(dirty); - - // Loop through all update() widgets and remove them from the list before they are - // painted (in case someone calls update() in paintEvent). If the widget is opaque - // and does not have transparent overlapping siblings, append it to the - // opaqueNonOverlappedWidgets list and paint it directly without composition. - QVarLengthArray opaqueNonOverlappedWidgets; - for (int i = 0; i < dirtyWidgets.size(); ++i) { - QWidget *w = dirtyWidgets.at(i); - QWidgetPrivate *wd = w->d_func(); - if (wd->data.in_destructor) - continue; - - // Clip with mask() and clipRect(). - wd->dirty &= wd->clipRect(); - wd->clipToEffectiveMask(wd->dirty); - - // Subtract opaque siblings and children. - bool hasDirtySiblingsAbove = false; - // We know for sure that the widget isn't overlapped if 'isMoved' is true. - if (!wd->isMoved) - wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove); - // Scrolled and moved widgets must draw all children. - if (!wd->isScrolled && !wd->isMoved) - wd->subtractOpaqueChildren(wd->dirty, w->rect()); - - if (wd->dirty.isEmpty()) { - resetWidget(w); - continue; - } - - const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint())) - : wd->dirty); - toClean += widgetDirty; - -#ifndef QT_NO_GRAPHICSVIEW - if (tlw->d_func()->extra->proxyWidget) { - resetWidget(w); - continue; - } -#endif - - if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) { - opaqueNonOverlappedWidgets.append(w); - } else { - resetWidget(w); - dirty += widgetDirty; - } - } - dirtyWidgets.clear(); - - fullUpdatePending = false; - - if (toClean.isEmpty()) { - // Nothing to repaint. However, we might have newly exposed areas on the - // screen if this function was called from sync(QWidget *, QRegion)), so - // we have to make sure those are flushed. - flush(); - return; - } - -#ifndef QT_NO_GRAPHICSVIEW - if (tlw->d_func()->extra->proxyWidget) { - updateStaticContentsSize(); - dirty = QRegion(); - const QVector rects(toClean.rects()); - for (int i = 0; i < rects.size(); ++i) - tlw->d_func()->extra->proxyWidget->update(rects.at(i)); - return; - } -#endif - -#ifndef Q_BACKINGSTORE_SUBSURFACES - BeginPaintInfo beginPaintInfo; - beginPaint(toClean, tlw, windowSurface, &beginPaintInfo); - if (beginPaintInfo.nothingToPaint) { - for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) - resetWidget(opaqueNonOverlappedWidgets[i]); - dirty = QRegion(); - return; - } -#endif - - // Must do this before sending any paint events because - // the size may change in the paint event. - updateStaticContentsSize(); - const QRegion dirtyCopy(dirty); - dirty = QRegion(); - - // Paint opaque non overlapped widgets. - for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) { - QWidget *w = opaqueNonOverlappedWidgets[i]; - QWidgetPrivate *wd = w->d_func(); - - int flags = QWidgetPrivate::DrawRecursive; - // Scrolled and moved widgets must draw all children. - if (!wd->isScrolled && !wd->isMoved) - flags |= QWidgetPrivate::DontDrawOpaqueChildren; - if (w == tlw) - flags |= QWidgetPrivate::DrawAsRoot; - - QRegion toBePainted(wd->dirty); - resetWidget(w); - -#ifdef Q_BACKINGSTORE_SUBSURFACES - QWindowSurface *subSurface = w->windowSurface(); - BeginPaintInfo beginPaintInfo; - - QPoint off = w->mapTo(tlw, QPoint()); - toBePainted.translate(off); - beginPaint(toBePainted, w, subSurface, &beginPaintInfo, true); - toBePainted.translate(-off); - - if (beginPaintInfo.nothingToPaint) - continue; - - if (beginPaintInfo.windowSurfaceRecreated) { - // Eep the window surface has changed. The old one may have been - // deleted, in which case we will segfault on the call to - // painterOffset() below. Use the new window surface instead. - subSurface = w->windowSurface(); - } - - QPoint offset(tlwOffset); - if (subSurface == windowSurface) - offset += w->mapTo(tlw, QPoint()); - else - offset = static_cast(subSurface)->painterOffset(); - wd->drawWidget(subSurface->paintDevice(), toBePainted, offset, flags, 0, this); - - endPaint(toBePainted, subSurface, &beginPaintInfo); -#else - QPoint offset(tlwOffset); - if (w != tlw) - offset += w->mapTo(tlw, QPoint()); - wd->drawWidget(windowSurface->paintDevice(), toBePainted, offset, flags, 0, this); -#endif - } - - // Paint the rest with composition. -#ifndef Q_BACKINGSTORE_SUBSURFACES - if (repaintAllWidgets || !dirtyCopy.isEmpty()) { - const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive; - tlw->d_func()->drawWidget(windowSurface->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this); - } - - endPaint(toClean, windowSurface, &beginPaintInfo); -#else - if (!repaintAllWidgets && dirtyCopy.isEmpty()) - return; // Nothing more to paint. - - QList surfaceList(subSurfaces); - surfaceList.prepend(windowSurface); - const QRect dirtyBoundingRect(dirtyCopy.boundingRect()); - - // Loop through all window surfaces (incl. the top-level surface) and - // repaint those intersecting with the bounding rect of the dirty region. - for (int i = 0; i < surfaceList.size(); ++i) { - QWindowSurface *subSurface = surfaceList.at(i); - QWidget *w = subSurface->window(); - QWidgetPrivate *wd = w->d_func(); - - const QRect clipRect = wd->clipRect().translated(w->mapTo(tlw, QPoint())); - if (!qRectIntersects(dirtyBoundingRect, clipRect)) - continue; - - toClean = dirtyCopy; - BeginPaintInfo beginPaintInfo; - beginPaint(toClean, w, subSurface, &beginPaintInfo); - if (beginPaintInfo.nothingToPaint) - continue; - - if (beginPaintInfo.windowSurfaceRecreated) { - // Eep the window surface has changed. The old one may have been - // deleted, in which case we will segfault on the call to - // painterOffset() below. Use the new window surface instead. - subSurface = w->windowSurface(); - } - - int flags = QWidgetPrivate::DrawRecursive; - if (w == tlw) - flags |= QWidgetPrivate::DrawAsRoot; - const QPoint painterOffset = static_cast(subSurface)->painterOffset(); - wd->drawWidget(subSurface->paintDevice(), toClean, painterOffset, flags, 0, this); - - endPaint(toClean, subSurface, &beginPaintInfo); - } -#endif -} - -/*! - Flushes the contents of the backing store into the top-level widget. - If the \a widget is non-zero, the content is flushed to the \a widget. - If the \a surface is non-zero, the content of the \a surface is flushed. -*/ -void QWidgetBackingStore::flush(QWidget *widget, QWindowSurface *surface) -{ -#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) - paintWindowDecoration(); -#endif - - if (!dirtyOnScreen.isEmpty()) { - QWidget *target = widget ? widget : tlw; - QWindowSurface *source = surface ? surface : windowSurface; - qt_flush(target, dirtyOnScreen, source, tlw, tlwOffset); - dirtyOnScreen = QRegion(); - } - - if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) - return; - - for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { - QWidget *w = dirtyOnScreenWidgets->at(i); - QWidgetPrivate *wd = w->d_func(); - Q_ASSERT(wd->needsFlush); - qt_flush(w, *wd->needsFlush, windowSurface, tlw, tlwOffset); - *wd->needsFlush = QRegion(); - } - dirtyOnScreenWidgets->clear(); -} - -static inline bool discardInvalidateBufferRequest(QWidget *widget, QTLWExtra *tlwExtra) -{ - Q_ASSERT(widget); - if (QApplication::closingDown()) - return true; - - if (!tlwExtra || tlwExtra->inTopLevelResize || !tlwExtra->backingStore) - return true; - - if (!widget->isVisible() || !widget->updatesEnabled()) - return true; - - return false; -} - -/*! - Invalidates the buffer when the widget is resized. - Static areas are never invalidated unless absolutely needed. -*/ -void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize) -{ - Q_Q(QWidget); - Q_ASSERT(!q->isWindow()); - Q_ASSERT(q->parentWidget()); - - const bool staticContents = q->testAttribute(Qt::WA_StaticContents); - const bool sizeDecreased = (data.crect.width() < oldSize.width()) - || (data.crect.height() < oldSize.height()); - - const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y()); - const bool parentAreaExposed = !offset.isNull() || sizeDecreased; - const QRect newWidgetRect(q->rect()); - const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height()); - - if (!staticContents || graphicsEffect) { - QRegion staticChildren; - QWidgetBackingStore *bs = 0; - if (offset.isNull() && (bs = maybeBackingStore())) - staticChildren = bs->staticContents(q, oldWidgetRect); - const bool hasStaticChildren = !staticChildren.isEmpty(); - - if (hasStaticChildren) { - QRegion dirty(newWidgetRect); - dirty -= staticChildren; - invalidateBuffer(dirty); - } else { - // Entire widget needs repaint. - invalidateBuffer(newWidgetRect); - } - - if (!parentAreaExposed) - return; - - // Invalidate newly exposed area of the parent. - if (!graphicsEffect && extra && extra->hasMask) { - QRegion parentExpose(extra->mask.translated(oldPos)); - parentExpose &= QRect(oldPos, oldSize); - if (hasStaticChildren) - parentExpose -= data.crect; // Offset is unchanged, safe to do this. - q->parentWidget()->d_func()->invalidateBuffer(parentExpose); - } else { - if (hasStaticChildren && !graphicsEffect) { - QRegion parentExpose(QRect(oldPos, oldSize)); - parentExpose -= data.crect; // Offset is unchanged, safe to do this. - q->parentWidget()->d_func()->invalidateBuffer(parentExpose); - } else { - q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize))); - } - } - return; - } - - // Move static content to its new position. - if (!offset.isNull()) { - if (sizeDecreased) { - const QSize minSize(qMin(oldSize.width(), data.crect.width()), - qMin(oldSize.height(), data.crect.height())); - moveRect(QRect(oldPos, minSize), offset.x(), offset.y()); - } else { - moveRect(QRect(oldPos, oldSize), offset.x(), offset.y()); - } - } - - // Invalidate newly visible area of the widget. - if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) { - QRegion newVisible(newWidgetRect); - newVisible -= oldWidgetRect; - invalidateBuffer(newVisible); - } - - if (!parentAreaExposed) - return; - - // Invalidate newly exposed area of the parent. - const QRect oldRect(oldPos, oldSize); - if (extra && extra->hasMask) { - QRegion parentExpose(oldRect); - parentExpose &= extra->mask.translated(oldPos); - parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect); - q->parentWidget()->d_func()->invalidateBuffer(parentExpose); - } else { - QRegion parentExpose(oldRect); - parentExpose -= data.crect; - q->parentWidget()->d_func()->invalidateBuffer(parentExpose); - } -} - -/*! - Invalidates the \a rgn (in widget's coordinates) of the backing store, i.e. - all widgets intersecting with the region will be repainted when the backing store - is synced. - - ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). -*/ -void QWidgetPrivate::invalidateBuffer(const QRegion &rgn) -{ - Q_Q(QWidget); - - QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); - if (discardInvalidateBufferRequest(q, tlwExtra) || rgn.isEmpty()) - return; - - QRegion wrgn(rgn); - wrgn &= clipRect(); - if (!graphicsEffect && extra && extra->hasMask) - wrgn &= extra->mask; - if (wrgn.isEmpty()) - return; - - tlwExtra->backingStore->markDirty(wrgn, q, false, true); -} - -/*! - This function is equivalent to calling invalidateBuffer(QRegion(rect), ...), but - is more efficient as it eliminates QRegion operations/allocations and can - use the rect more precisely for additional cut-offs. - - ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). -*/ -void QWidgetPrivate::invalidateBuffer(const QRect &rect) -{ - Q_Q(QWidget); - - QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); - if (discardInvalidateBufferRequest(q, tlwExtra) || rect.isEmpty()) - return; - - QRect wRect(rect); - wRect &= clipRect(); - if (wRect.isEmpty()) - return; - - if (graphicsEffect || !extra || !extra->hasMask) { - tlwExtra->backingStore->markDirty(wRect, q, false, true); - return; - } - - QRegion wRgn(extra->mask); - wRgn &= wRect; - if (wRgn.isEmpty()) - return; - - tlwExtra->backingStore->markDirty(wRgn, q, false, true); -} - -void QWidgetPrivate::repaint_sys(const QRegion &rgn) -{ - if (data.in_destructor) - return; - - Q_Q(QWidget); - if (q->testAttribute(Qt::WA_StaticContents)) { - if (!extra) - createExtra(); - extra->staticContentsSize = data.crect.size(); - } - -#ifdef Q_WS_QPA //Dont even call q->p - QPaintEngine *engine = 0; -#else - QPaintEngine *engine = q->paintEngine(); -#endif - // QGLWidget does not support partial updates if: - // 1) The context is double buffered - // 2) The context is single buffered and auto-fill background is enabled. - const bool noPartialUpdateSupport = (engine && (engine->type() == QPaintEngine::OpenGL - || engine->type() == QPaintEngine::OpenGL2)) - && (usesDoubleBufferedGLContext || q->autoFillBackground()); - QRegion toBePainted(noPartialUpdateSupport ? q->rect() : rgn); - -#ifdef Q_WS_MAC - // No difference between update() and repaint() on the Mac. - update_sys(toBePainted); - return; -#endif - - toBePainted &= clipRect(); - clipToEffectiveMask(toBePainted); - if (toBePainted.isEmpty()) - return; // Nothing to repaint. - -#ifndef QT_NO_PAINT_DEBUG - bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted); -#endif - - drawWidget(q, toBePainted, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen, 0); - -#ifndef QT_NO_PAINT_DEBUG - if (flushed) - QWidgetBackingStore::unflushPaint(q, toBePainted); -#endif - - if (!q->testAttribute(Qt::WA_PaintOutsidePaintEvent) && q->paintingActive()) - qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent"); -} - - -QT_END_NAMESPACE diff --git a/src/widgets/kernel/qbackingstore_p.h b/src/widgets/kernel/qbackingstore_p.h deleted file mode 100644 index cd41af31e1..0000000000 --- a/src/widgets/kernel/qbackingstore_p.h +++ /dev/null @@ -1,278 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QBACKINGSTORE_P_H -#define QBACKINGSTORE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include -#ifdef Q_WS_QWS -#include -#endif - -QT_BEGIN_NAMESPACE - -class QWindowSurface; - -struct BeginPaintInfo { - inline BeginPaintInfo() : wasFlushed(0), nothingToPaint(0), windowSurfaceRecreated(0) {} - uint wasFlushed : 1; - uint nothingToPaint : 1; - uint windowSurfaceRecreated : 1; -}; - -class Q_AUTOTEST_EXPORT QWidgetBackingStore -{ -public: - QWidgetBackingStore(QWidget *t); - ~QWidgetBackingStore(); - - static void showYellowThing(QWidget *widget, const QRegion &rgn, int msec, bool); - - void sync(QWidget *exposedWidget, const QRegion &exposedRegion); - void sync(); - void flush(QWidget *widget = 0, QWindowSurface *surface = 0); - - inline QPoint topLevelOffset() const { return tlwOffset; } - - QWindowSurface *surface() const { return windowSurface; } - - inline bool isDirty() const - { - return !(dirtyWidgets.isEmpty() && dirty.isEmpty() && !hasDirtyFromPreviousSync - && !fullUpdatePending -#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) - && !hasDirtyWindowDecoration() -#endif - ); - } - - // ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). - void markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately = false, - bool invalidateBuffer = false); - void markDirty(const QRect &rect, QWidget *widget, bool updateImmediately = false, - bool invalidateBuffer = false); - -private: - QWidget *tlw; - QRegion dirtyOnScreen; // needsFlush - QRegion dirty; // needsRepaint - QRegion dirtyFromPreviousSync; - QVector dirtyWidgets; - QVector *dirtyOnScreenWidgets; - QList staticWidgets; - QWindowSurface *windowSurface; -#ifdef Q_BACKINGSTORE_SUBSURFACES - QList subSurfaces; -#endif - uint hasDirtyFromPreviousSync : 1; - uint fullUpdatePending : 1; - - QPoint tlwOffset; - - static bool flushPaint(QWidget *widget, const QRegion &rgn); - static void unflushPaint(QWidget *widget, const QRegion &rgn); - - bool bltRect(const QRect &rect, int dx, int dy, QWidget *widget); - void releaseBuffer(); - - void beginPaint(QRegion &toClean, QWidget *widget, QWindowSurface *windowSurface, - BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates = true); - void endPaint(const QRegion &cleaned, QWindowSurface *windowSurface, BeginPaintInfo *beginPaintInfo); - - QRegion dirtyRegion(QWidget *widget = 0) const; - QRegion staticContents(QWidget *widget = 0, const QRect &withinClipRect = QRect()) const; - - void markDirtyOnScreen(const QRegion &dirtyOnScreen, QWidget *widget, const QPoint &topLevelOffset); - - void removeDirtyWidget(QWidget *w); - -#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) - bool hasDirtyWindowDecoration() const; - void paintWindowDecoration(); -#endif - void updateLists(QWidget *widget); - - inline void addDirtyWidget(QWidget *widget, const QRegion &rgn) - { - if (widget && !widget->d_func()->inDirtyList && !widget->data->in_destructor) { - QWidgetPrivate *widgetPrivate = widget->d_func(); -#ifndef QT_NO_GRAPHICSEFFECT - if (widgetPrivate->graphicsEffect) - widgetPrivate->dirty = widgetPrivate->effectiveRectFor(rgn.boundingRect()); - else -#endif //QT_NO_GRAPHICSEFFECT - widgetPrivate->dirty = rgn; - dirtyWidgets.append(widget); - widgetPrivate->inDirtyList = true; - } - } - - inline void dirtyWidgetsRemoveAll(QWidget *widget) - { - int i = 0; - while (i < dirtyWidgets.size()) { - if (dirtyWidgets.at(i) == widget) - dirtyWidgets.remove(i); - else - ++i; - } - } - - inline void addStaticWidget(QWidget *widget) - { - if (!widget) - return; - - Q_ASSERT(widget->testAttribute(Qt::WA_StaticContents)); - if (!staticWidgets.contains(widget)) - staticWidgets.append(widget); - } - - inline void removeStaticWidget(QWidget *widget) - { staticWidgets.removeAll(widget); } - - // Move the reparented widget and all its static children from this backing store - // to the new backing store if reparented into another top-level / backing store. - inline void moveStaticWidgets(QWidget *reparented) - { - Q_ASSERT(reparented); - QWidgetBackingStore *newBs = reparented->d_func()->maybeBackingStore(); - if (newBs == this) - return; - - int i = 0; - while (i < staticWidgets.size()) { - QWidget *w = staticWidgets.at(i); - if (reparented == w || reparented->isAncestorOf(w)) { - staticWidgets.removeAt(i); - if (newBs) - newBs->addStaticWidget(w); - } else { - ++i; - } - } - } - - inline QRect topLevelRect() const - { -#ifdef Q_WS_QWS - return tlw->frameGeometry(); -#else - return tlw->data->crect; -#endif - } - - inline void appendDirtyOnScreenWidget(QWidget *widget) - { - if (!widget) - return; - - if (!dirtyOnScreenWidgets) { - dirtyOnScreenWidgets = new QVector; - dirtyOnScreenWidgets->append(widget); - } else if (!dirtyOnScreenWidgets->contains(widget)) { - dirtyOnScreenWidgets->append(widget); - } - } - - inline void dirtyOnScreenWidgetsRemoveAll(QWidget *widget) - { - if (!widget || !dirtyOnScreenWidgets) - return; - - int i = 0; - while (i < dirtyOnScreenWidgets->size()) { - if (dirtyOnScreenWidgets->at(i) == widget) - dirtyOnScreenWidgets->remove(i); - else - ++i; - } - } - - inline void resetWidget(QWidget *widget) - { - if (widget) { - widget->d_func()->inDirtyList = false; - widget->d_func()->isScrolled = false; - widget->d_func()->isMoved = false; - widget->d_func()->dirty = QRegion(); - } - } - - inline void updateStaticContentsSize() - { - for (int i = 0; i < staticWidgets.size(); ++i) { - QWidgetPrivate *wd = staticWidgets.at(i)->d_func(); - if (!wd->extra) - wd->createExtra(); - wd->extra->staticContentsSize = wd->data.crect.size(); - } - } - - inline bool hasStaticContents() const - { return !staticWidgets.isEmpty() && windowSurface->hasFeature(QWindowSurface::StaticContents); } - - friend QRegion qt_dirtyRegion(QWidget *); - friend class QWidgetPrivate; - friend class QWidget; - friend class QWSManagerPrivate; - friend class QETWidget; - friend class QWindowSurface; - friend class QWSWindowSurface; -}; - -QT_END_NAMESPACE - -#endif // QBACKINGSTORE_P_H diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 9a7ad9fc0c..9889a66aa6 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -70,12 +70,6 @@ # include "qtoolbar.h" # include #endif -#if defined(Q_WS_QWS) -# include "qwsdisplay_qws.h" -# include "qwsmanager_qws.h" -# include "qpaintengine.h" // for PorterDuff -# include "private/qwindowsurface_qws_p.h" -#endif #if defined(Q_WS_QPA) #include "qplatformwindow_qpa.h" #include "private/qwidgetwindow_qpa_p.h" @@ -100,8 +94,8 @@ #endif #include -#include -#include +#include +#include #ifdef Q_WS_MAC # include #endif @@ -137,9 +131,7 @@ QT_BEGIN_NAMESPACE -#if !defined(Q_WS_QWS) static bool qt_enable_backingstore = true; -#endif #ifdef Q_WS_X11 // for compatibility with Qt 4.0 Q_WIDGETS_EXPORT void qt_x11_set_global_double_buffer(bool enable) @@ -352,32 +344,6 @@ QWidgetPrivate::~QWidgetPrivate() #endif //QT_NO_GRAPHICSEFFECT } -class QDummyWindowSurface : public QWindowSurface -{ -public: - QDummyWindowSurface(QWindow *window) : QWindowSurface(window) {} - QPaintDevice *paintDevice() { return static_cast(window())->widget(); } - void flush(QWindow *, const QRegion &, const QPoint &) {} -}; - -QWindowSurface *QWidgetPrivate::createDefaultWindowSurface() -{ - Q_Q(QWidget); - - QWindowSurface *surface; -#ifndef QT_NO_PROPERTIES - if (q->property("_q_DummyWindowSurface").toBool()) { - surface = new QDummyWindowSurface(q->windowHandle()); - } else -#endif - { - QWindow *win = topData()->window; - surface = QGuiApplicationPrivate::platformIntegration()->createWindowSurface(win, win->winId()); - } - - return surface; -} - /*! \internal */ @@ -393,10 +359,8 @@ void QWidgetPrivate::scrollChildren(int dx, int dy) QPoint oldp = w->pos(); QRect r(w->pos() + pd, w->size()); w->data->crect = r; -#ifndef Q_WS_QWS if (w->testAttribute(Qt::WA_WState_Created)) w->d_func()->setWSGeometry(); -#endif w->d_func()->setDirtyOpaqueRegion(); QMoveEvent e(r.topLeft(), oldp); QApplication::sendEvent(w, &e); @@ -1508,9 +1472,9 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) // a real toplevel window needs a backing store if (isWindow() && windowType() != Qt::Desktop) { - d->topData()->backingStore.destroy(); + d->topData()->backingStoreTracker.destroy(); if (hasBackingStoreSupport()) - d->topData()->backingStore.create(this); + d->topData()->backingStoreTracker.create(this); } d->setModal_sys(); @@ -1625,7 +1589,7 @@ QWidget::~QWidget() else if (!internalWinId() && isVisible()) { qApp->d_func()->sendSyntheticEnterLeave(this); } -#elif defined(Q_WS_QWS) || defined(Q_WS_QPA) +#elif defined(Q_WS_QPA) else if (isVisible()) { qApp->d_func()->sendSyntheticEnterLeave(this); } @@ -1732,7 +1696,7 @@ void QWidgetPrivate::createTLExtra() QTLWExtra* x = extra->topextra = new QTLWExtra; x->icon = 0; x->iconPixmap = 0; - x->windowSurface = 0; + x->backingStore = 0; x->sharedPainter = 0; x->incw = x->inch = 0; x->basew = x->baseh = 0; @@ -1815,13 +1779,10 @@ void QWidgetPrivate::deleteExtra() #endif if (extra->topextra) { deleteTLSysExtra(); - extra->topextra->backingStore.destroy(); + extra->topextra->backingStoreTracker.destroy(); delete extra->topextra->icon; delete extra->topextra->iconPixmap; -#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) - delete extra->topextra->qwsManager; -#endif - delete extra->topextra->windowSurface; + delete extra->topextra->backingStore; delete extra->topextra; } delete extra; @@ -2212,9 +2173,7 @@ void QWidgetPrivate::clipToEffectiveMask(QRegion ®ion) const bool QWidgetPrivate::paintOnScreen() const { -#if defined(Q_WS_QWS) - return false; -#elif defined(QT_NO_BACKINGSTORE) +#if defined(QT_NO_BACKINGSTORE) return true; #else Q_Q(const QWidget); @@ -2376,10 +2335,6 @@ void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, int if ((flags & DrawAsRoot) && !(q->autoFillBackground() && autoFillBrush.isOpaque())) { const QBrush bg = q->palette().brush(QPalette::Window); -#ifdef Q_WS_QWS - if (!(flags & DontSetCompositionMode) && painter->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) - painter->setCompositionMode(QPainter::CompositionMode_Source); //copy alpha straight in -#endif fillRegion(painter, rgn, bg); } @@ -3891,19 +3846,6 @@ bool QWidgetPrivate::setMinimumSize_helper(int &minw, int &minh) { Q_Q(QWidget); -#ifdef Q_WS_QWS - if (q->isWindow()) { - const QRect maxWindowRect = QApplication::desktop()->availableGeometry(QApplication::desktop()->screenNumber(q)); - if (!maxWindowRect.isEmpty()) { - // ### This is really just a work-around. Layout shouldn't be - // asking for minimum sizes bigger than the screen. - if (minw > maxWindowRect.width()) - minw = maxWindowRect.width(); - if (minh > maxWindowRect.height()) - minh = maxWindowRect.height(); - } - } -#endif int mw = minw, mh = minh; if (mw == QWIDGETSIZE_MAX) mw = 0; @@ -4094,15 +4036,7 @@ void QWidget::setFixedSize(const QSize & s) void QWidget::setFixedSize(int w, int h) { Q_D(QWidget); -#ifdef Q_WS_QWS - // temporary fix for 4.3.x. - // Should move the embedded spesific contraints in setMinimumSize_helper into QLayout - int tmpW = w; - int tmpH = h; - bool minSizeSet = d->setMinimumSize_helper(tmpW, tmpH); -#else bool minSizeSet = d->setMinimumSize_helper(w, h); -#endif bool maxSizeSet = d->setMaximumSize_helper(w, h); if (!minSizeSet && !maxSizeSet) return; @@ -5050,7 +4984,7 @@ void QWidget::setCursor(const QCursor &cursor) { Q_D(QWidget); // On Mac we must set the cursor even if it is the ArrowCursor. -#if !defined(Q_WS_MAC) && !defined(Q_WS_QWS) +#if !defined(Q_WS_MAC) if (cursor.shape() != Qt::ArrowCursor || (d->extra && d->extra->curs)) #endif @@ -5538,7 +5472,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP //actually send the paint event QPaintEvent e(toBePainted); QCoreApplication::sendSpontaneousEvent(q, &e); -#if !defined(Q_WS_QWS) && !defined(Q_WS_QPA) +#if !defined(Q_WS_QPA) if (backingStore && !onScreen && !asRoot && (q->internalWinId() || !q->nativeParentWidget()->isWindow())) backingStore->markDirtyOnScreen(toBePainted, q, offset); #endif @@ -5587,9 +5521,6 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP if (recursive && !children.isEmpty()) { paintSiblingsRecursive(pdev, children, children.size() - 1, rgn, offset, flags & ~DrawAsRoot -#ifdef Q_BACKINGSTORE_SUBSURFACES - , q->windowSurface() -#endif , sharedPainter, backingStore); } } @@ -5661,10 +5592,6 @@ void QWidgetPrivate::render(QPaintDevice *target, const QPoint &targetOffset, else flags |= DontSubtractOpaqueChildren; -#ifdef Q_WS_QWS - flags |= DontSetCompositionMode; -#endif - if (target->devType() == QInternal::Printer) { QPainter p(target); render_helper(&p, targetOffset, paintRegion, renderFlags); @@ -5686,9 +5613,6 @@ void QWidgetPrivate::render(QPaintDevice *target, const QPoint &targetOffset, void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& siblings, int index, const QRegion &rgn, const QPoint &offset, int flags -#ifdef Q_BACKINGSTORE_SUBSURFACES - , const QWindowSurface *currentSurface -#endif , QPainter *sharedPainter, QWidgetBackingStore *backingStore) { QWidget *w = 0; @@ -5707,13 +5631,8 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis } if (qRectIntersects(boundingRect, x->d_func()->effectiveRectFor(x->data->crect))) { -#ifdef Q_BACKINGSTORE_SUBSURFACES - if (x->windowSurface() == currentSurface) -#endif - { - w = x; - break; - } + w = x; + break; } } --index; @@ -5730,9 +5649,6 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis if (wd->isOpaque) wr -= hasMask ? wd->extra->mask.translated(widgetPos) : w->data->crect; paintSiblingsRecursive(pdev, siblings, --index, wr, offset, flags -#ifdef Q_BACKINGSTORE_SUBSURFACES - , currentSurface -#endif , sharedPainter, backingStore); } @@ -7582,7 +7498,7 @@ void QWidgetPrivate::hide_helper() // next bit tries to move the focus if the focus widget is now // hidden. if (wasVisible) { -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) || defined(Q_WS_MAC) || defined(Q_WS_QPA) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QPA) qApp->d_func()->sendSyntheticEnterLeave(q); #endif @@ -7653,9 +7569,6 @@ void QWidget::setVisible(bool visible) #if defined(Q_WS_X11) if (windowType() == Qt::Window) QApplicationPrivate::applyX11SpecificCommandLineArguments(this); -#elif defined(Q_WS_QWS) - if (windowType() == Qt::Window) - QApplicationPrivate::applyQWSSpecificCommandLineArguments(this); #endif bool wasResized = testAttribute(Qt::WA_Resized); @@ -7714,7 +7627,7 @@ void QWidget::setVisible(bool visible) d->show_helper(); -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) || defined(Q_WS_MAC) || defined(Q_WS_QPA) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QPA) qApp->d_func()->sendSyntheticEnterLeave(this); #endif } @@ -7846,7 +7759,7 @@ void QWidgetPrivate::hideChildren(bool spontaneous) widget->d_func()->hide_sys(); } } -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) || defined(Q_WS_MAC) || defined(Q_WS_QPA) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QPA) qApp->d_func()->sendSyntheticEnterLeave(widget); #endif #ifndef QT_NO_ACCESSIBILITY @@ -8049,13 +7962,6 @@ QRegion QWidget::visibleRegion() const QRegion r(clipRect); d->subtractOpaqueChildren(r, clipRect); d->subtractOpaqueSiblings(r); -#ifdef Q_WS_QWS - const QWSWindowSurface *surface = static_cast(windowSurface()); - if (surface) { - const QPoint offset = mapTo(surface->window(), QPoint()); - r &= surface->clipRegion().translated(-offset); - } -#endif return r; } @@ -8807,10 +8713,6 @@ void QWidget::changeEvent(QEvent * event) updateGeometry(); if (d->layout) d->layout->invalidate(); -#ifdef Q_WS_QWS - if (isWindow()) - d->data.fstrut_dirty = true; -#endif break; } @@ -9588,31 +9490,6 @@ bool QWidget::x11Event(XEvent *) } #endif -#if defined(Q_WS_QWS) - -/*! - \fn bool QWidget::qwsEvent(QWSEvent *event) - - This special event handler can be reimplemented in a subclass to - receive native Qt for Embedded Linux events which are passed in the - \a event parameter. - - In your reimplementation of this function, if you want to stop the - event being handled by Qt, return true. If you return false, this - native event is passed back to Qt, which translates the event into - a Qt event and sends it to the widget. - - \warning This function is not portable. - - \sa QApplication::qwsEventFilter() -*/ -bool QWidget::qwsEvent(QWSEvent *) -{ - return false; -} - -#endif - /*! Ensures that the widget has been polished by QStyle (i.e., has a @@ -10132,34 +10009,18 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) focusWidget()->clearFocus(); QTLWExtra *oldTopExtra = window()->d_func()->maybeTopData(); - QWidgetBackingStoreTracker *oldBsTracker = oldTopExtra ? &oldTopExtra->backingStore : 0; + QWidgetBackingStoreTracker *oldBsTracker = oldTopExtra ? &oldTopExtra->backingStoreTracker : 0; d->setParent_sys(parent, f); QTLWExtra *topExtra = window()->d_func()->maybeTopData(); - QWidgetBackingStoreTracker *bsTracker = topExtra ? &topExtra->backingStore : 0; + QWidgetBackingStoreTracker *bsTracker = topExtra ? &topExtra->backingStoreTracker : 0; if (oldBsTracker && oldBsTracker != bsTracker) oldBsTracker->unregisterWidgetSubtree(this); if (desktopWidget) parent = 0; -#ifdef Q_BACKINGSTORE_SUBSURFACES - QTLWExtra *extra = d->maybeTopData(); - QWindowSurface *windowSurface = (extra ? extra->windowSurface : 0); - if (newParent && windowSurface) { - QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore(); - if (oldBs) - oldBs->subSurfaces.removeAll(windowSurface); - - if (parent) { - QWidgetBackingStore *newBs = parent->d_func()->maybeBackingStore(); - if (newBs) - newBs->subSurfaces.append(windowSurface); - } - } -#endif - if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) { if (newParent) oldBs->removeDirtyWidget(this); @@ -10405,7 +10266,7 @@ void QWidget::repaint(const QRect &rect) QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) { tlwExtra->inRepaint = true; - tlwExtra->backingStore->markDirty(rect, this, true); + tlwExtra->backingStoreTracker->markDirty(rect, this, true); tlwExtra->inRepaint = false; } } else { @@ -10440,7 +10301,7 @@ void QWidget::repaint(const QRegion &rgn) QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) { tlwExtra->inRepaint = true; - tlwExtra->backingStore->markDirty(rgn, this, true); + tlwExtra->backingStoreTracker->markDirty(rgn, this, true); tlwExtra->inRepaint = false; } } else { @@ -10502,7 +10363,7 @@ void QWidget::update(const QRect &rect) #endif // QT_MAC_USE_COCOA QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) - tlwExtra->backingStore->markDirty(rect, this); + tlwExtra->backingStoreTracker->markDirty(rect, this); } else { d_func()->repaint_sys(rect); } @@ -10532,7 +10393,7 @@ void QWidget::update(const QRegion &rgn) #endif // QT_MAC_USE_COCOA QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) - tlwExtra->backingStore->markDirty(rgn, this); + tlwExtra->backingStoreTracker->markDirty(rgn, this); } else { d_func()->repaint_sys(rgn); } @@ -10873,14 +10734,6 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) // from the desktop. show_sys will only update platform specific // attributes at this point. d->hide_sys(); -#ifdef Q_WS_QWS - // Release the region for this window from qws if the widget has - // been shown before the attribute was set. - if (QWSWindowSurface *surface = static_cast(windowSurface())) { - QWidget::qwsDisplay()->requestRegion(surface->winId(), surface->key(), - surface->permanentState(), QRegion()); - } -#endif d->show_sys(); } break; @@ -11029,10 +10882,8 @@ void QWidget::setWindowOpacity(qreal opacity) extra->opacity = uint(opacity * 255); setAttribute(Qt::WA_WState_WindowOpacitySet); -#ifndef Q_WS_QWS if (!testAttribute(Qt::WA_WState_Created)) return; -#endif #ifndef QT_NO_GRAPHICSVIEW if (QGraphicsProxyWidget *proxy = graphicsProxyWidget()) { @@ -11322,7 +11173,7 @@ void QWidget::setShortcutAutoRepeat(int id, bool enable) */ void QWidget::updateMicroFocus() { -#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) +#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_OS_SYMBIAN)) Q_D(QWidget); // and optimization to update input context only it has already been created. if (d->assignedInputContext() || qApp->d_func()->inputContext) { @@ -12102,83 +11953,55 @@ bool QWidgetPrivate::inTabWidget(QWidget *widget) #endif /*! - \preliminary - \since 4.2 - \obsolete + \since 5.0 + \internal - Sets the window surface to be the \a surface specified. - The QWidget takes will ownership of the \a surface. - widget itself is deleted. + Sets the backing store to be the \a store specified. + The QWidget will take ownership of the \a store. */ -void QWidget::setWindowSurface(QWindowSurface *surface) +void QWidget::setBackingStore(QBackingStore *store) { // ### createWinId() ?? -#ifndef Q_BACKINGSTORE_SUBSURFACES if (!isTopLevel()) return; -#endif Q_D(QWidget); QTLWExtra *topData = d->topData(); - if (topData->windowSurface == surface) + if (topData->backingStore == store) return; - QWindowSurface *oldSurface = topData->windowSurface; - delete topData->windowSurface; - topData->windowSurface = surface; + QBackingStore *oldStore = topData->backingStore; + delete topData->backingStore; + topData->backingStore = store; QWidgetBackingStore *bs = d->maybeBackingStore(); if (!bs) return; if (isTopLevel()) { - if (bs->windowSurface != oldSurface && bs->windowSurface != surface) - delete bs->windowSurface; - bs->windowSurface = surface; - } -#ifdef Q_BACKINGSTORE_SUBSURFACES - else { - bs->subSurfaces.append(surface); + if (bs->store != oldStore && bs->store != store) + delete bs->store; + bs->store = store; } - bs->subSurfaces.removeOne(oldSurface); -#endif } /*! - \preliminary - \since 4.2 + \since 5.0 - Returns the QWindowSurface this widget will be drawn into. + Returns the QBackingStore this widget will be drawn into. */ -QWindowSurface *QWidget::windowSurface() const +QBackingStore *QWidget::backingStore() const { Q_D(const QWidget); QTLWExtra *extra = d->maybeTopData(); - if (extra && extra->windowSurface) - return extra->windowSurface; + if (extra && extra->backingStore) + return extra->backingStore; QWidgetBackingStore *bs = d->maybeBackingStore(); -#ifdef Q_BACKINGSTORE_SUBSURFACES - if (bs && bs->subSurfaces.isEmpty()) - return bs->windowSurface; - - if (!isTopLevel()) { - const QWidget *w = parentWidget(); - while (w) { - QTLWExtra *extra = w->d_func()->maybeTopData(); - if (extra && extra->windowSurface) - return extra->windowSurface; - if (w->isTopLevel()) - break; - w = w->parentWidget(); - } - } -#endif // Q_BACKINGSTORE_SUBSURFACES - - return bs ? bs->windowSurface : 0; + return bs ? bs->store : 0; } void QWidgetPrivate::getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h index 2be5e5f52d..755feb8849 100644 --- a/src/widgets/kernel/qwidget.h +++ b/src/widgets/kernel/qwidget.h @@ -97,7 +97,7 @@ class QShowEvent; class QHideEvent; class QInputContext; class QIcon; -class QWindowSurface; +class QBackingStore; class QPlatformWindow; class QLocale; class QGraphicsProxyWidget; @@ -631,8 +631,7 @@ public: bool autoFillBackground() const; void setAutoFillBackground(bool enabled); - void setWindowSurface(QWindowSurface *surface); - QWindowSurface *windowSurface() const; + QBackingStore *backingStore() const; #if defined(Q_WS_QPA) void setWindowHandle(QWindow *window); @@ -730,6 +729,7 @@ protected: protected: QWidget(QWidgetPrivate &d, QWidget* parent, Qt::WindowFlags f); private: + void setBackingStore(QBackingStore *store); bool testAttribute_helper(Qt::WidgetAttribute) const; diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 46c5ecfe33..f3838ee3dd 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -163,8 +163,8 @@ struct QTLWExtra { // Regular pointers (keep them together to avoid gaps on 64 bits architectures). QIcon *icon; // widget icon QPixmap *iconPixmap; - QWidgetBackingStoreTracker backingStore; - QWindowSurface *windowSurface; + QWidgetBackingStoreTracker backingStoreTracker; + QBackingStore *backingStore; QPainter *sharedPainter; // Implicit pointers (shared_null). @@ -458,11 +458,8 @@ public: void paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& children, int index, - const QRegion &rgn, const QPoint &offset, int flags -#ifdef Q_BACKINGSTORE_SUBSURFACES - , const QWindowSurface *currentSurface -#endif - , QPainter *sharedPainter, QWidgetBackingStore *backingStore); + const QRegion &rgn, const QPoint &offset, int flags, + QPainter *sharedPainter, QWidgetBackingStore *backingStore); QPainter *beginSharedPainter(); @@ -470,8 +467,6 @@ public: #ifndef QT_NO_GRAPHICSVIEW static QGraphicsProxyWidget * nearestGraphicsProxyWidget(const QWidget *origin); #endif - QWindowSurface *createDefaultWindowSurface(); - QWindowSurface *createDefaultWindowSurface_sys(); void repaint_sys(const QRegion &rgn); QRect clipRect() const; @@ -884,20 +879,6 @@ public: static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *); static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool); void registerTouchWindow(bool enable = true); -#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS - void setMaxWindowState_helper(); - void setFullScreenSize_helper(); - void moveSurface(QWindowSurface *surface, const QPoint &offset); - QRegion localRequestedRegion() const; - QRegion localAllocatedRegion() const; - - friend class QWSManager; - friend class QWSManagerPrivate; - friend class QDecoration; -#ifndef QT_NO_CURSOR - void updateCursor() const; -#endif - QScreen* getScreen() const; #elif defined(Q_WS_QPA) // <--------------------------------------------------------- QPA void setMaxWindowState_helper(); void setFullScreenSize_helper(); @@ -1026,7 +1007,7 @@ inline QWidgetBackingStore *QWidgetPrivate::maybeBackingStore() const { Q_Q(const QWidget); QTLWExtra *x = q->window()->d_func()->maybeTopData(); - return x ? x->backingStore.data() : 0; + return x ? x->backingStoreTracker.data() : 0; } QT_END_NAMESPACE diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index caaa065b64..9aa7e5afb6 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -42,7 +42,7 @@ #include "QtWidgets/qwidget.h" #include "QtGui/qevent.h" #include "QtWidgets/qapplication.h" -#include "private/qbackingstore_p.h" +#include "private/qwidgetbackingstore_p.h" #include "private/qwidget_p.h" #include "private/qwidgetwindow_qpa_p.h" #include "private/qapplication_p.h" @@ -94,8 +94,6 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO if (!q->testAttribute(Qt::WA_NativeWindow) && !q->isWindow()) return; // we only care about real toplevels - QWindowSurface *surface = q->windowSurface(); - QWindow *win = topData()->window; // topData() ensures the extra is created but does not ensure 'window' is non-null // in case the extra was already valid. @@ -129,13 +127,13 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO data.window_flags = win->windowFlags(); - if (!surface ) { - if (win) { - surface = QGuiApplicationPrivate::platformIntegration()->createWindowSurface(win, win->winId()); - q->setWindowSurface(surface); - } else { - q->setAttribute(Qt::WA_PaintOnScreen,true); - } + QBackingStore *store = q->backingStore(); + + if (!store) { + if (win) + q->setBackingStore(new QBackingStore(win)); + else + q->setAttribute(Qt::WA_PaintOnScreen, true); } setWinId(win->winId()); @@ -449,12 +447,15 @@ void QWidgetPrivate::show_sys() if (windowRect != geomRect) { window->setGeometry(geomRect); } - if (QWindowSurface *surface = q->windowSurface()) { - if (windowRect.size() != geomRect.size()) { - surface->resize(geomRect.size()); + + if (QBackingStore *store = q->backingStore()) { + if (store->size() != geomRect.size()) { + store->resize(geomRect.size()); } } + invalidateBuffer(q->rect()); + if (window) window->setVisible(true); } @@ -663,9 +664,9 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) q->windowHandle()->setGeometry(QRect(posInNativeParent,r.size())); } const QWidgetBackingStore *bs = maybeBackingStore(); - if (bs->windowSurface) { + if (bs->store) { if (isResize) - bs->windowSurface->resize(r.size()); + bs->store->resize(r.size()); } if (needsShow) @@ -854,13 +855,6 @@ QPaintEngine *QWidget::paintEngine() const return 0; //##### @@@ } -QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() -{ - //This function should not be called. - Q_ASSERT(false); - return 0; -} - void QWidgetPrivate::setModal_sys() { Q_Q(QWidget); diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp new file mode 100644 index 0000000000..1cb6f51619 --- /dev/null +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -0,0 +1,1396 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qplatformdefs.h" + +#include "qwidgetbackingstore_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef Q_WS_QWS +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +extern QRegion qt_dirtyRegion(QWidget *); + +/* + A version of QRect::intersects() that does not normalize the rects. +*/ +static inline bool qRectIntersects(const QRect &r1, const QRect &r2) +{ + return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) + && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom())); +} + +/** + * Flushes the contents of the \a backingStore into the screen area of \a widget. + * \a tlwOffset is the position of the top level widget relative to the window surface. + * \a region is the region to be updated in \a widget coordinates. + */ +static inline void qt_flush(QWidget *widget, const QRegion ®ion, QBackingStore *backingStore, + QWidget *tlw, const QPoint &tlwOffset) +{ + Q_ASSERT(widget); + Q_ASSERT(!region.isEmpty()); + Q_ASSERT(backingStore); + Q_ASSERT(tlw); + +#if !defined(QT_NO_PAINT_DEBUG) + static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt(); + if (flushUpdate > 0) + QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false); +#endif + + //The performance hit by doing this should be negligible. However, be aware that + //using this FPS when you have > 1 windowsurface can give you inaccurate FPS + static bool fpsDebug = qgetenv("QT_DEBUG_FPS").toInt(); + if (fpsDebug) { + static QTime time = QTime::currentTime(); + static int frames = 0; + + frames++; + + if(time.elapsed() > 5000) { + double fps = double(frames * 1000) /time.restart(); + fprintf(stderr,"FPS: %.1f\n",fps); + frames = 0; + } + } + if (widget != tlw) + backingStore->flush(region, widget->windowHandle(), tlwOffset + widget->mapTo(tlw, QPoint())); + else + backingStore->flush(region, widget->windowHandle(), tlwOffset); +} + +#ifndef QT_NO_PAINT_DEBUG +#ifdef Q_WS_WIN +static void showYellowThing_win(QWidget *widget, const QRegion ®ion, int msec) +{ + HBRUSH brush; + static int i = 0; + switch (i) { + case 0: + brush = CreateSolidBrush(RGB(255, 255, 0)); + break; + case 1: + brush = CreateSolidBrush(RGB(255, 200, 55)); + break; + case 2: + brush = CreateSolidBrush(RGB(200, 255, 55)); + break; + case 3: + brush = CreateSolidBrush(RGB(200, 200, 0)); + break; + } + i = (i + 1) & 3; + + HDC hdc = widget->getDC(); + + const QVector &rects = region.rects(); + foreach (QRect rect, rects) { + RECT winRect; + SetRect(&winRect, rect.left(), rect.top(), rect.right(), rect.bottom()); + FillRect(hdc, &winRect, brush); + } + + widget->releaseDC(hdc); + ::Sleep(msec); +} +#endif + +void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped) +{ +#ifdef Q_WS_QWS + Q_UNUSED(widget); + Q_UNUSED(unclipped); + static QWSYellowSurface surface(true); + surface.setDelay(msec); + surface.flush(widget, toBePainted, QPoint()); +#else + QRegion paintRegion = toBePainted; + QRect widgetRect = widget->rect(); + + if (!widget->internalWinId()) { + QWidget *nativeParent = widget->nativeParentWidget(); + const QPoint offset = widget->mapTo(nativeParent, QPoint(0, 0)); + paintRegion.translate(offset); + widgetRect.translate(offset); + widget = nativeParent; + } + +#ifdef Q_WS_WIN + Q_UNUSED(unclipped); + showYellowThing_win(widget, paintRegion, msec); +#else + //flags to fool painter + bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped); + if (unclipped && !widget->d_func()->paintOnScreen()) + widget->setAttribute(Qt::WA_PaintUnclipped); + + const bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent); + if (setFlag) + widget->setAttribute(Qt::WA_WState_InPaintEvent); + + //setup the engine + QPaintEngine *pe = widget->paintEngine(); + if (pe) { + pe->setSystemClip(paintRegion); + { + QPainter p(widget); + p.setClipRegion(paintRegion); + static int i = 0; + switch (i) { + case 0: + p.fillRect(widgetRect, QColor(255,255,0)); + break; + case 1: + p.fillRect(widgetRect, QColor(255,200,55)); + break; + case 2: + p.fillRect(widgetRect, QColor(200,255,55)); + break; + case 3: + p.fillRect(widgetRect, QColor(200,200,0)); + break; + } + i = (i+1) & 3; + p.end(); + } + } + + if (setFlag) + widget->setAttribute(Qt::WA_WState_InPaintEvent, false); + + //restore + widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped); + + if (pe) + pe->setSystemClip(QRegion()); + + QApplication::syncX(); + +#if defined(Q_OS_UNIX) + ::usleep(1000 * msec); +#endif +#endif // Q_WS_WIN +#endif // Q_WS_QWS +} + +bool QWidgetBackingStore::flushPaint(QWidget *widget, const QRegion &rgn) +{ + if (!widget) + return false; + + int delay = 0; + if (widget->testAttribute(Qt::WA_WState_InPaintEvent)) { + static int flushPaintEvent = qgetenv("QT_FLUSH_PAINT_EVENT").toInt(); + if (!flushPaintEvent) + return false; + delay = flushPaintEvent; + } else { + static int flushPaint = qgetenv("QT_FLUSH_PAINT").toInt(); + if (!flushPaint) + return false; + delay = flushPaint; + } + + QWidgetBackingStore::showYellowThing(widget, rgn, delay * 10, true); + return true; +} + +void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn) +{ + if (widget->d_func()->paintOnScreen() || rgn.isEmpty()) + return; + + QWidget *tlw = widget->window(); + QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); + if (!tlwExtra) + return; + + const QPoint offset = widget->mapTo(tlw, QPoint()); + qt_flush(widget, rgn, tlwExtra->backingStoreTracker->store, tlw, offset); +} +#endif // QT_NO_PAINT_DEBUG + +/* + Moves the whole rect by (dx, dy) in widget's coordinate system. + Doesn't generate any updates. +*/ +bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *widget) +{ + const QPoint pos(tlwOffset + widget->mapTo(tlw, rect.topLeft())); + const QRect tlwRect(QRect(pos, rect.size())); + if (fullUpdatePending || dirty.intersects(tlwRect)) + return false; // We don't want to scroll junk. + return store->scroll(tlwRect, dx, dy); +} + +void QWidgetBackingStore::releaseBuffer() +{ + if (store) + store->resize(QSize()); +} + +/*! + Prepares the window surface to paint a\ toClean region of the \a widget and + updates the BeginPaintInfo struct accordingly. + + The \a toClean region might be clipped by the window surface. +*/ +void QWidgetBackingStore::beginPaint(QRegion &toClean, QWidget *widget, QBackingStore *backingStore, + BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates) +{ + Q_UNUSED(widget); + Q_UNUSED(toCleanIsInTopLevelCoordinates); + + // Always flush repainted areas. + dirtyOnScreen += toClean; + +#ifdef QT_NO_PAINT_DEBUG + backingStore->beginPaint(toClean); +#else + returnInfo->wasFlushed = QWidgetBackingStore::flushPaint(tlw, toClean); + // Avoid deadlock with QT_FLUSH_PAINT: the server will wait for + // the BackingStore lock, so if we hold that, the server will + // never release the Communication lock that we are waiting for in + // sendSynchronousCommand + if (!returnInfo->wasFlushed) + backingStore->beginPaint(toClean); +#endif + + Q_UNUSED(returnInfo); +} + +void QWidgetBackingStore::endPaint(const QRegion &cleaned, QBackingStore *backingStore, + BeginPaintInfo *beginPaintInfo) +{ +#ifndef QT_NO_PAINT_DEBUG + if (!beginPaintInfo->wasFlushed) + backingStore->endPaint(); + else + QWidgetBackingStore::unflushPaint(tlw, cleaned); +#else + Q_UNUSED(beginPaintInfo); + Q_UNUSED(cleaned); + backingStore->endPaint(); +#endif + + flush(); +} + +/*! + Returns the region (in top-level coordinates) that needs repaint and/or flush. + + If the widget is non-zero, only the dirty region for the widget is returned + and the region will be in widget coordinates. +*/ +QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const +{ + const bool widgetDirty = widget && widget != tlw; + const QRect tlwRect(topLevelRect()); + const QRect surfaceGeometry(tlwRect.topLeft(), store->size()); + if (fullUpdatePending || (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size())) { + if (widgetDirty) { + const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size()); + const QPoint offset(widget->mapTo(tlw, QPoint())); + const QRect dirtyWidgetRect(dirtyTlwRect & widget->rect().translated(offset)); + return dirtyWidgetRect.translated(-offset); + } + return QRect(QPoint(), tlwRect.size()); + } + + // Calculate the region that needs repaint. + QRegion r(dirty); + for (int i = 0; i < dirtyWidgets.size(); ++i) { + QWidget *w = dirtyWidgets.at(i); + if (widgetDirty && w != widget && !widget->isAncestorOf(w)) + continue; + r += w->d_func()->dirty.translated(w->mapTo(tlw, QPoint())); + } + + // Append the region that needs flush. + r += dirtyOnScreen; + + if (dirtyOnScreenWidgets) { // Only in use with native child widgets. + for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { + QWidget *w = dirtyOnScreenWidgets->at(i); + if (widgetDirty && w != widget && !widget->isAncestorOf(w)) + continue; + QWidgetPrivate *wd = w->d_func(); + Q_ASSERT(wd->needsFlush); + r += wd->needsFlush->translated(w->mapTo(tlw, QPoint())); + } + } + + if (widgetDirty) { + // Intersect with the widget geometry and translate to its coordinates. + const QPoint offset(widget->mapTo(tlw, QPoint())); + r &= widget->rect().translated(offset); + r.translate(-offset); + } + return r; +} + +/*! + Returns the static content inside the \a parent if non-zero; otherwise the static content + for the entire backing store is returned. The content will be clipped to \a withinClipRect + if non-empty. +*/ +QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const +{ + if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) { + const QSize surfaceGeometry(store->size()); + QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); + if (!withinClipRect.isEmpty()) + surfaceRect &= withinClipRect; + return QRegion(surfaceRect); + } + + QRegion region; + if (parent && parent->d_func()->children.isEmpty()) + return region; + + const bool clipToRect = !withinClipRect.isEmpty(); + const int count = staticWidgets.count(); + for (int i = 0; i < count; ++i) { + QWidget *w = staticWidgets.at(i); + QWidgetPrivate *wd = w->d_func(); + if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty() + || !w->isVisible() || (parent && !parent->isAncestorOf(w))) { + continue; + } + + QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height()); + const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint()); + if (clipToRect) + rect &= withinClipRect.translated(-offset); + if (rect.isEmpty()) + continue; + + rect &= wd->clipRect(); + if (rect.isEmpty()) + continue; + + QRegion visible(rect); + wd->clipToEffectiveMask(visible); + if (visible.isEmpty()) + continue; + wd->subtractOpaqueSiblings(visible, 0, /*alsoNonOpaque=*/true); + + visible.translate(offset); + region += visible; + } + + return region; +} + +static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) +{ + if (!widget) + return; + + if (updateImmediately) { + QEvent event(QEvent::UpdateRequest); + QApplication::sendEvent(widget, &event); + } else { + QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); + } +} + +/*! + Marks the region of the widget as dirty (if not already marked as dirty) and + posts an UpdateRequest event to the top-level widget (if not already posted). + + If updateImmediately is true, the event is sent immediately instead of posted. + + If invalidateBuffer is true, all widgets intersecting with the region will be dirty. + + If the widget paints directly on screen, the event is sent to the widget + instead of the top-level widget, and invalidateBuffer is completely ignored. + + ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). +*/ +void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately, + bool invalidateBuffer) +{ + Q_ASSERT(tlw->d_func()->extra); + Q_ASSERT(tlw->d_func()->extra->topextra); + Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); + Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); + Q_ASSERT(widget->window() == tlw); + Q_ASSERT(!rgn.isEmpty()); + +#ifndef QT_NO_GRAPHICSEFFECT + widget->d_func()->invalidateGraphicsEffectsRecursively(); +#endif //QT_NO_GRAPHICSEFFECT + + if (widget->d_func()->paintOnScreen()) { + if (widget->d_func()->dirty.isEmpty()) { + widget->d_func()->dirty = rgn; + sendUpdateRequest(widget, updateImmediately); + return; + } else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) { + if (updateImmediately) + sendUpdateRequest(widget, updateImmediately); + return; // Already dirty. + } + + const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); + widget->d_func()->dirty += rgn; + if (!eventAlreadyPosted || updateImmediately) + sendUpdateRequest(widget, updateImmediately); + return; + } + + if (fullUpdatePending) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + const QPoint offset = widget->mapTo(tlw, QPoint()); + const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect()); + if (qt_region_strictContains(dirty, widgetRect.translated(offset))) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; // Already dirty. + } + + if (invalidateBuffer) { + const bool eventAlreadyPosted = !dirty.isEmpty(); +#ifndef QT_NO_GRAPHICSEFFECT + if (widget->d_func()->graphicsEffect) + dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset); + else +#endif //QT_NO_GRAPHICSEFFECT + dirty += rgn.translated(offset); + if (!eventAlreadyPosted || updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (dirtyWidgets.isEmpty()) { + addDirtyWidget(widget, rgn); + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (widget->d_func()->inDirtyList) { + if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) { +#ifndef QT_NO_GRAPHICSEFFECT + if (widget->d_func()->graphicsEffect) + widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()); + else +#endif //QT_NO_GRAPHICSEFFECT + widget->d_func()->dirty += rgn; + } + } else { + addDirtyWidget(widget, rgn); + } + + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); +} + +/*! + This function is equivalent to calling markDirty(QRegion(rect), ...), but + is more efficient as it eliminates QRegion operations/allocations and can + use the rect more precisely for additional cut-offs. + + ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). +*/ +void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately, + bool invalidateBuffer) +{ + Q_ASSERT(tlw->d_func()->extra); + Q_ASSERT(tlw->d_func()->extra->topextra); + Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); + Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); + Q_ASSERT(widget->window() == tlw); + Q_ASSERT(!rect.isEmpty()); + +#ifndef QT_NO_GRAPHICSEFFECT + widget->d_func()->invalidateGraphicsEffectsRecursively(); +#endif //QT_NO_GRAPHICSEFFECT + + if (widget->d_func()->paintOnScreen()) { + if (widget->d_func()->dirty.isEmpty()) { + widget->d_func()->dirty = QRegion(rect); + sendUpdateRequest(widget, updateImmediately); + return; + } else if (qt_region_strictContains(widget->d_func()->dirty, rect)) { + if (updateImmediately) + sendUpdateRequest(widget, updateImmediately); + return; // Already dirty. + } + + const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); + widget->d_func()->dirty += rect; + if (!eventAlreadyPosted || updateImmediately) + sendUpdateRequest(widget, updateImmediately); + return; + } + + if (fullUpdatePending) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + const QRect widgetRect = widget->d_func()->effectiveRectFor(rect); + const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint()))); + if (qt_region_strictContains(dirty, translatedRect)) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; // Already dirty + } + + if (invalidateBuffer) { + const bool eventAlreadyPosted = !dirty.isEmpty(); + dirty += translatedRect; + if (!eventAlreadyPosted || updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (dirtyWidgets.isEmpty()) { + addDirtyWidget(widget, rect); + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (widget->d_func()->inDirtyList) { + if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) + widget->d_func()->dirty += widgetRect; + } else { + addDirtyWidget(widget, rect); + } + + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); +} + +/*! + Marks the \a region of the \a widget as dirty on screen. The \a region will be copied from + the backing store to the \a widget's native parent next time flush() is called. + + Paint on screen widgets are ignored. +*/ +void QWidgetBackingStore::markDirtyOnScreen(const QRegion ®ion, QWidget *widget, const QPoint &topLevelOffset) +{ + if (!widget || widget->d_func()->paintOnScreen() || region.isEmpty()) + return; + +#if defined(Q_WS_QWS) || defined(Q_WS_MAC) + if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) + dirtyOnScreen += region.translated(topLevelOffset); + return; +#endif + + // Top-level. + if (widget == tlw) { + if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) + dirtyOnScreen += region; + return; + } + + // Alien widgets. + if (!widget->internalWinId() && !widget->isWindow()) { + QWidget *nativeParent = widget->nativeParentWidget(); // Alien widgets with the top-level as the native parent (common case). + if (nativeParent == tlw) { + if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) + dirtyOnScreen += region.translated(topLevelOffset); + return; + } + + // Alien widgets with native parent != tlw. + QWidgetPrivate *nativeParentPrivate = nativeParent->d_func(); + if (!nativeParentPrivate->needsFlush) + nativeParentPrivate->needsFlush = new QRegion; + const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint()); + *nativeParentPrivate->needsFlush += region.translated(nativeParentOffset); + appendDirtyOnScreenWidget(nativeParent); + return; + } + + // Native child widgets. + QWidgetPrivate *widgetPrivate = widget->d_func(); + if (!widgetPrivate->needsFlush) + widgetPrivate->needsFlush = new QRegion; + *widgetPrivate->needsFlush += region; + appendDirtyOnScreenWidget(widget); +} + +void QWidgetBackingStore::removeDirtyWidget(QWidget *w) +{ + if (!w) + return; + + dirtyWidgetsRemoveAll(w); + dirtyOnScreenWidgetsRemoveAll(w); + resetWidget(w); + + QWidgetPrivate *wd = w->d_func(); + const int n = wd->children.count(); + for (int i = 0; i < n; ++i) { + if (QWidget *child = qobject_cast(wd->children.at(i))) + removeDirtyWidget(child); + } +} + +void QWidgetBackingStore::updateLists(QWidget *cur) +{ + if (!cur) + return; + + QList children = cur->children(); + for (int i = 0; i < children.size(); ++i) { + QWidget *child = qobject_cast(children.at(i)); + if (!child) + continue; + + updateLists(child); + } + + if (cur->testAttribute(Qt::WA_StaticContents)) + addStaticWidget(cur); +} + +QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) + : tlw(topLevel), dirtyOnScreenWidgets(0), hasDirtyFromPreviousSync(false) + , fullUpdatePending(0) +{ + store = tlw->backingStore(); + Q_ASSERT(store); + + // Ensure all existing subsurfaces and static widgets are added to their respective lists. + updateLists(topLevel); +} + +QWidgetBackingStore::~QWidgetBackingStore() +{ + for (int c = 0; c < dirtyWidgets.size(); ++c) { + resetWidget(dirtyWidgets.at(c)); + } + + delete dirtyOnScreenWidgets; + dirtyOnScreenWidgets = 0; +} + +//parent's coordinates; move whole rect; update parent and widget +//assume the screen blt has already been done, so we don't need to refresh that part +void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) +{ + Q_Q(QWidget); + if (!q->isVisible() || (dx == 0 && dy == 0)) + return; + + QWidget *tlw = q->window(); + QTLWExtra* x = tlw->d_func()->topData(); + if (x->inTopLevelResize) + return; + + static int accelEnv = -1; + if (accelEnv == -1) { + accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0; + } + + QWidget *pw = q->parentWidget(); + QPoint toplevelOffset = pw->mapTo(tlw, QPoint()); + QWidgetPrivate *pd = pw->d_func(); + QRect clipR(pd->clipRect()); +#ifdef Q_WS_QWS + QWidgetBackingStore *wbs = x->backingStore.data(); + QWSWindowSurface *surface = static_cast(wbs->windowSurface); + clipR = clipR.intersected(surface->clipRegion().translated(-toplevelOffset).boundingRect()); +#endif + const QRect newRect(rect.translated(dx, dy)); + QRect destRect = rect.intersected(clipR); + if (destRect.isValid()) + destRect = destRect.translated(dx, dy).intersected(clipR); + const QRect sourceRect(destRect.translated(-dx, -dy)); + const QRect parentRect(rect & clipR); + + bool accelerateMove = accelEnv && isOpaque +#ifndef QT_NO_GRAPHICSVIEW + // No accelerate move for proxy widgets. + && !tlw->d_func()->extra->proxyWidget +#endif + && !isOverlapped(sourceRect) && !isOverlapped(destRect); + + if (!accelerateMove) { + QRegion parentR(effectiveRectFor(parentRect)); + if (!extra || !extra->hasMask) { + parentR -= newRect; + } else { + // invalidateBuffer() excludes anything outside the mask + parentR += newRect & clipR; + } + pd->invalidateBuffer(parentR); + invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft())); + } else { + + QWidgetBackingStore *wbs = x->backingStoreTracker.data(); + QRegion childExpose(newRect & clipR); + + if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw)) + childExpose -= destRect; + + if (!pw->updatesEnabled()) + return; + + const bool childUpdatesEnabled = q->updatesEnabled(); + if (childUpdatesEnabled && !childExpose.isEmpty()) { + childExpose.translate(-data.crect.topLeft()); + wbs->markDirty(childExpose, q); + isMoved = true; + } + + QRegion parentExpose(parentRect); + parentExpose -= newRect; + if (extra && extra->hasMask) + parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft()); + + if (!parentExpose.isEmpty()) { + wbs->markDirty(parentExpose, pw); + pd->isMoved = true; + } + + if (childUpdatesEnabled) { + QRegion needsFlush(sourceRect); + needsFlush += destRect; + wbs->markDirtyOnScreen(needsFlush, pw, toplevelOffset); + } + } +} + +//widget's coordinates; scroll within rect; only update widget +void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) +{ + Q_Q(QWidget); + QWidget *tlw = q->window(); + QTLWExtra* x = tlw->d_func()->topData(); + if (x->inTopLevelResize) + return; + + QWidgetBackingStore *wbs = x->backingStoreTracker.data(); + if (!wbs) + return; + + static int accelEnv = -1; + if (accelEnv == -1) { + accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0; + } + + QRect scrollRect = rect & clipRect(); + bool overlapped = false; + bool accelerateScroll = accelEnv && isOpaque + && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft()))); + +#if defined(Q_WS_QWS) + QWSWindowSurface *surface; + surface = static_cast(wbs->windowSurface); + + if (accelerateScroll && !surface->isBuffered()) { + const QRegion surfaceClip = surface->clipRegion(); + const QRegion outsideClip = QRegion(rect) - surfaceClip; + if (!outsideClip.isEmpty()) { + const QVector clipped = (surfaceClip & rect).rects(); + if (clipped.size() < 8) { + for (int i = 0; i < clipped.size(); ++i) + this->scrollRect(clipped.at(i), dx, dy); + return; + } else { + accelerateScroll = false; + } + } + } +#endif // Q_WS_QWS + + if (!accelerateScroll) { + if (overlapped) { + QRegion region(scrollRect); + subtractOpaqueSiblings(region); + invalidateBuffer(region); + }else { + invalidateBuffer(scrollRect); + } + } else { + const QPoint toplevelOffset = q->mapTo(tlw, QPoint()); +#ifdef Q_WS_QWS + QWSWindowSurface *surface = static_cast(wbs->windowSurface); + const QRegion clip = surface->clipRegion().translated(-toplevelOffset) & scrollRect; + const QRect clipBoundingRect = clip.boundingRect(); + scrollRect &= clipBoundingRect; +#endif + const QRect destRect = scrollRect.translated(dx, dy) & scrollRect; + const QRect sourceRect = destRect.translated(-dx, -dy); + + QRegion childExpose(scrollRect); + if (sourceRect.isValid()) { + if (wbs->bltRect(sourceRect, dx, dy, q)) + childExpose -= destRect; + } + + if (inDirtyList) { + if (rect == q->rect()) { + dirty.translate(dx, dy); + } else { + QRegion dirtyScrollRegion = dirty.intersected(scrollRect); + if (!dirtyScrollRegion.isEmpty()) { + dirty -= dirtyScrollRegion; + dirtyScrollRegion.translate(dx, dy); + dirty += dirtyScrollRegion; + } + } + } + + if (!q->updatesEnabled()) + return; + + if (!childExpose.isEmpty()) { + wbs->markDirty(childExpose, q); + isScrolled = true; + } + + // Instead of using native scroll-on-screen, we copy from + // backingstore, giving only one screen update for each + // scroll, and a solid appearance + wbs->markDirtyOnScreen(destRect, q, toplevelOffset); + } +} + +static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra) +{ + if (!tlw || !tlwExtra) + return true; + +#ifdef Q_WS_X11 + // Delay the sync until we get an Expose event from X11 (initial show). + // Qt::WA_Mapped is set to true, but the actual mapping has not yet occurred. + // However, we must repaint immediately regardless of the state if someone calls repaint(). + if (tlwExtra->waitingForMapNotify && !tlwExtra->inRepaint) + return true; +#endif + + if (!tlw->testAttribute(Qt::WA_Mapped)) + return true; + + if (!tlw->isVisible() +#ifndef Q_WS_X11 + // If we're minimized on X11, WA_Mapped will be false and we + // will return in the case above. Some window managers on X11 + // sends us the PropertyNotify to change the minimized state + // *AFTER* we've received the expose event, which is baaad. + || tlw->isMinimized() +#endif + ) + return true; + + return false; +} + +/*! + Synchronizes the \a exposedRegion of the \a exposedWidget with the backing store. + + If there's nothing to repaint, the area is flushed and painting does not occur; + otherwise the area is marked as dirty on screen and will be flushed right after + we are done with all painting. +*/ +void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion) +{ + QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); + if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize) + return; + + if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible() + || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) { + return; + } + + // Nothing to repaint. + if (!isDirty()) { + qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset); + return; + } + + if (exposedWidget != tlw) + markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint())); + else + markDirtyOnScreen(exposedRegion, exposedWidget, QPoint()); + sync(); +} + +/*! + Synchronizes the backing store, i.e. dirty areas are repainted and flushed. +*/ +void QWidgetBackingStore::sync() +{ + QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); + if (discardSyncRequest(tlw, tlwExtra)) { + // If the top-level is minimized, it's not visible on the screen so we can delay the + // update until it's shown again. In order to do that we must keep the dirty states. + // These will be cleared when we receive the first expose after showNormal(). + // However, if the widget is not visible (isVisible() returns false), everything will + // be invalidated once the widget is shown again, so clear all dirty states. + if (!tlw->isVisible()) { + dirty = QRegion(); + for (int i = 0; i < dirtyWidgets.size(); ++i) + resetWidget(dirtyWidgets.at(i)); + dirtyWidgets.clear(); + fullUpdatePending = false; + } + return; + } + + const bool updatesDisabled = !tlw->updatesEnabled(); + bool repaintAllWidgets = false; + + const bool inTopLevelResize = tlwExtra->inTopLevelResize; + const QRect tlwRect(topLevelRect()); + const QRect surfaceGeometry(tlwRect.topLeft(), store->size()); + if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { + if (hasStaticContents()) { + // Repaint existing dirty area and newly visible area. + const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); + const QRegion staticRegion(staticContents(0, clipRect)); + QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height()); + newVisible -= staticRegion; + dirty += newVisible; + store->setStaticContents(staticRegion); + } else { + // Repaint everything. + dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height()); + for (int i = 0; i < dirtyWidgets.size(); ++i) + resetWidget(dirtyWidgets.at(i)); + dirtyWidgets.clear(); + repaintAllWidgets = true; + } + } + + if (inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) + store->resize(tlwRect.size()); + + if (updatesDisabled) + return; + + if (hasDirtyFromPreviousSync) + dirty += dirtyFromPreviousSync; + + // Contains everything that needs repaint. + QRegion toClean(dirty); + + // Loop through all update() widgets and remove them from the list before they are + // painted (in case someone calls update() in paintEvent). If the widget is opaque + // and does not have transparent overlapping siblings, append it to the + // opaqueNonOverlappedWidgets list and paint it directly without composition. + QVarLengthArray opaqueNonOverlappedWidgets; + for (int i = 0; i < dirtyWidgets.size(); ++i) { + QWidget *w = dirtyWidgets.at(i); + QWidgetPrivate *wd = w->d_func(); + if (wd->data.in_destructor) + continue; + + // Clip with mask() and clipRect(). + wd->dirty &= wd->clipRect(); + wd->clipToEffectiveMask(wd->dirty); + + // Subtract opaque siblings and children. + bool hasDirtySiblingsAbove = false; + // We know for sure that the widget isn't overlapped if 'isMoved' is true. + if (!wd->isMoved) + wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove); + // Scrolled and moved widgets must draw all children. + if (!wd->isScrolled && !wd->isMoved) + wd->subtractOpaqueChildren(wd->dirty, w->rect()); + + if (wd->dirty.isEmpty()) { + resetWidget(w); + continue; + } + + const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint())) + : wd->dirty); + toClean += widgetDirty; + +#ifndef QT_NO_GRAPHICSVIEW + if (tlw->d_func()->extra->proxyWidget) { + resetWidget(w); + continue; + } +#endif + + if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) { + opaqueNonOverlappedWidgets.append(w); + } else { + resetWidget(w); + dirty += widgetDirty; + } + } + dirtyWidgets.clear(); + + fullUpdatePending = false; + + if (toClean.isEmpty()) { + // Nothing to repaint. However, we might have newly exposed areas on the + // screen if this function was called from sync(QWidget *, QRegion)), so + // we have to make sure those are flushed. + flush(); + return; + } + +#ifndef QT_NO_GRAPHICSVIEW + if (tlw->d_func()->extra->proxyWidget) { + updateStaticContentsSize(); + dirty = QRegion(); + const QVector rects(toClean.rects()); + for (int i = 0; i < rects.size(); ++i) + tlw->d_func()->extra->proxyWidget->update(rects.at(i)); + return; + } +#endif + + BeginPaintInfo beginPaintInfo; + beginPaint(toClean, tlw, store, &beginPaintInfo); + if (beginPaintInfo.nothingToPaint) { + for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) + resetWidget(opaqueNonOverlappedWidgets[i]); + dirty = QRegion(); + return; + } + + // Must do this before sending any paint events because + // the size may change in the paint event. + updateStaticContentsSize(); + const QRegion dirtyCopy(dirty); + dirty = QRegion(); + + // Paint opaque non overlapped widgets. + for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) { + QWidget *w = opaqueNonOverlappedWidgets[i]; + QWidgetPrivate *wd = w->d_func(); + + int flags = QWidgetPrivate::DrawRecursive; + // Scrolled and moved widgets must draw all children. + if (!wd->isScrolled && !wd->isMoved) + flags |= QWidgetPrivate::DontDrawOpaqueChildren; + if (w == tlw) + flags |= QWidgetPrivate::DrawAsRoot; + + QRegion toBePainted(wd->dirty); + resetWidget(w); + + QPoint offset(tlwOffset); + if (w != tlw) + offset += w->mapTo(tlw, QPoint()); + wd->drawWidget(store->paintDevice(), toBePainted, offset, flags, 0, this); + } + + // Paint the rest with composition. + if (repaintAllWidgets || !dirtyCopy.isEmpty()) { + const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive; + tlw->d_func()->drawWidget(store->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this); + } + + endPaint(toClean, store, &beginPaintInfo); +} + +/*! + Flushes the contents of the backing store into the top-level widget. + If the \a widget is non-zero, the content is flushed to the \a widget. + If the \a surface is non-zero, the content of the \a surface is flushed. +*/ +void QWidgetBackingStore::flush(QWidget *widget, QBackingStore *backingStore) +{ + if (!dirtyOnScreen.isEmpty()) { + QWidget *target = widget ? widget : tlw; + QBackingStore *source = store ? store : backingStore; + qt_flush(target, dirtyOnScreen, source, tlw, tlwOffset); + dirtyOnScreen = QRegion(); + } + + if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) + return; + + for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { + QWidget *w = dirtyOnScreenWidgets->at(i); + QWidgetPrivate *wd = w->d_func(); + Q_ASSERT(wd->needsFlush); + qt_flush(w, *wd->needsFlush, backingStore, tlw, tlwOffset); + *wd->needsFlush = QRegion(); + } + dirtyOnScreenWidgets->clear(); +} + +static inline bool discardInvalidateBufferRequest(QWidget *widget, QTLWExtra *tlwExtra) +{ + Q_ASSERT(widget); + if (QApplication::closingDown()) + return true; + + if (!tlwExtra || tlwExtra->inTopLevelResize || !tlwExtra->backingStore) + return true; + + if (!widget->isVisible() || !widget->updatesEnabled()) + return true; + + return false; +} + +/*! + Invalidates the buffer when the widget is resized. + Static areas are never invalidated unless absolutely needed. +*/ +void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize) +{ + Q_Q(QWidget); + Q_ASSERT(!q->isWindow()); + Q_ASSERT(q->parentWidget()); + + const bool staticContents = q->testAttribute(Qt::WA_StaticContents); + const bool sizeDecreased = (data.crect.width() < oldSize.width()) + || (data.crect.height() < oldSize.height()); + + const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y()); + const bool parentAreaExposed = !offset.isNull() || sizeDecreased; + const QRect newWidgetRect(q->rect()); + const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height()); + + if (!staticContents || graphicsEffect) { + QRegion staticChildren; + QWidgetBackingStore *bs = 0; + if (offset.isNull() && (bs = maybeBackingStore())) + staticChildren = bs->staticContents(q, oldWidgetRect); + const bool hasStaticChildren = !staticChildren.isEmpty(); + + if (hasStaticChildren) { + QRegion dirty(newWidgetRect); + dirty -= staticChildren; + invalidateBuffer(dirty); + } else { + // Entire widget needs repaint. + invalidateBuffer(newWidgetRect); + } + + if (!parentAreaExposed) + return; + + // Invalidate newly exposed area of the parent. + if (!graphicsEffect && extra && extra->hasMask) { + QRegion parentExpose(extra->mask.translated(oldPos)); + parentExpose &= QRect(oldPos, oldSize); + if (hasStaticChildren) + parentExpose -= data.crect; // Offset is unchanged, safe to do this. + q->parentWidget()->d_func()->invalidateBuffer(parentExpose); + } else { + if (hasStaticChildren && !graphicsEffect) { + QRegion parentExpose(QRect(oldPos, oldSize)); + parentExpose -= data.crect; // Offset is unchanged, safe to do this. + q->parentWidget()->d_func()->invalidateBuffer(parentExpose); + } else { + q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize))); + } + } + return; + } + + // Move static content to its new position. + if (!offset.isNull()) { + if (sizeDecreased) { + const QSize minSize(qMin(oldSize.width(), data.crect.width()), + qMin(oldSize.height(), data.crect.height())); + moveRect(QRect(oldPos, minSize), offset.x(), offset.y()); + } else { + moveRect(QRect(oldPos, oldSize), offset.x(), offset.y()); + } + } + + // Invalidate newly visible area of the widget. + if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) { + QRegion newVisible(newWidgetRect); + newVisible -= oldWidgetRect; + invalidateBuffer(newVisible); + } + + if (!parentAreaExposed) + return; + + // Invalidate newly exposed area of the parent. + const QRect oldRect(oldPos, oldSize); + if (extra && extra->hasMask) { + QRegion parentExpose(oldRect); + parentExpose &= extra->mask.translated(oldPos); + parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect); + q->parentWidget()->d_func()->invalidateBuffer(parentExpose); + } else { + QRegion parentExpose(oldRect); + parentExpose -= data.crect; + q->parentWidget()->d_func()->invalidateBuffer(parentExpose); + } +} + +/*! + Invalidates the \a rgn (in widget's coordinates) of the backing store, i.e. + all widgets intersecting with the region will be repainted when the backing store + is synced. + + ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). +*/ +void QWidgetPrivate::invalidateBuffer(const QRegion &rgn) +{ + Q_Q(QWidget); + + QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); + if (discardInvalidateBufferRequest(q, tlwExtra) || rgn.isEmpty()) + return; + + QRegion wrgn(rgn); + wrgn &= clipRect(); + if (!graphicsEffect && extra && extra->hasMask) + wrgn &= extra->mask; + if (wrgn.isEmpty()) + return; + + tlwExtra->backingStoreTracker->markDirty(wrgn, q, false, true); +} + +/*! + This function is equivalent to calling invalidateBuffer(QRegion(rect), ...), but + is more efficient as it eliminates QRegion operations/allocations and can + use the rect more precisely for additional cut-offs. + + ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). +*/ +void QWidgetPrivate::invalidateBuffer(const QRect &rect) +{ + Q_Q(QWidget); + + QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); + if (discardInvalidateBufferRequest(q, tlwExtra) || rect.isEmpty()) + return; + + QRect wRect(rect); + wRect &= clipRect(); + if (wRect.isEmpty()) + return; + + if (graphicsEffect || !extra || !extra->hasMask) { + tlwExtra->backingStoreTracker->markDirty(wRect, q, false, true); + return; + } + + QRegion wRgn(extra->mask); + wRgn &= wRect; + if (wRgn.isEmpty()) + return; + + tlwExtra->backingStoreTracker->markDirty(wRgn, q, false, true); +} + +void QWidgetPrivate::repaint_sys(const QRegion &rgn) +{ + if (data.in_destructor) + return; + + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_StaticContents)) { + if (!extra) + createExtra(); + extra->staticContentsSize = data.crect.size(); + } + +#ifdef Q_WS_QPA //Dont even call q->p + QPaintEngine *engine = 0; +#else + QPaintEngine *engine = q->paintEngine(); +#endif + // QGLWidget does not support partial updates if: + // 1) The context is double buffered + // 2) The context is single buffered and auto-fill background is enabled. + const bool noPartialUpdateSupport = (engine && (engine->type() == QPaintEngine::OpenGL + || engine->type() == QPaintEngine::OpenGL2)) + && (usesDoubleBufferedGLContext || q->autoFillBackground()); + QRegion toBePainted(noPartialUpdateSupport ? q->rect() : rgn); + +#ifdef Q_WS_MAC + // No difference between update() and repaint() on the Mac. + update_sys(toBePainted); + return; +#endif + + toBePainted &= clipRect(); + clipToEffectiveMask(toBePainted); + if (toBePainted.isEmpty()) + return; // Nothing to repaint. + +#ifndef QT_NO_PAINT_DEBUG + bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted); +#endif + + drawWidget(q, toBePainted, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen, 0); + +#ifndef QT_NO_PAINT_DEBUG + if (flushed) + QWidgetBackingStore::unflushPaint(q, toBePainted); +#endif + + if (!q->testAttribute(Qt::WA_PaintOutsidePaintEvent) && q->paintingActive()) + qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent"); +} + + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qwidgetbackingstore_p.h b/src/widgets/kernel/qwidgetbackingstore_p.h new file mode 100644 index 0000000000..4d43a90322 --- /dev/null +++ b/src/widgets/kernel/qwidgetbackingstore_p.h @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWIDGETBACKINGSTORE_P_H +#define QWIDGETBACKINGSTORE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct BeginPaintInfo { + inline BeginPaintInfo() : wasFlushed(0), nothingToPaint(0), backingStoreRecreated(0) {} + uint wasFlushed : 1; + uint nothingToPaint : 1; + uint backingStoreRecreated : 1; +}; + +class Q_AUTOTEST_EXPORT QWidgetBackingStore +{ +public: + QWidgetBackingStore(QWidget *t); + ~QWidgetBackingStore(); + + static void showYellowThing(QWidget *widget, const QRegion &rgn, int msec, bool); + + void sync(QWidget *exposedWidget, const QRegion &exposedRegion); + void sync(); + void flush(QWidget *widget = 0, QBackingStore *store = 0); + + inline QPoint topLevelOffset() const { return tlwOffset; } + + QBackingStore *backingStore() const { return store; } + + inline bool isDirty() const + { + return !(dirtyWidgets.isEmpty() && dirty.isEmpty() && !hasDirtyFromPreviousSync + && !fullUpdatePending +#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) + && !hasDirtyWindowDecoration() +#endif + ); + } + + // ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). + void markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately = false, + bool invalidateBuffer = false); + void markDirty(const QRect &rect, QWidget *widget, bool updateImmediately = false, + bool invalidateBuffer = false); + +private: + QWidget *tlw; + QRegion dirtyOnScreen; // needsFlush + QRegion dirty; // needsRepaint + QRegion dirtyFromPreviousSync; + QVector dirtyWidgets; + QVector *dirtyOnScreenWidgets; + QList staticWidgets; + QBackingStore *store; + uint hasDirtyFromPreviousSync : 1; + uint fullUpdatePending : 1; + + QPoint tlwOffset; + + static bool flushPaint(QWidget *widget, const QRegion &rgn); + static void unflushPaint(QWidget *widget, const QRegion &rgn); + + bool bltRect(const QRect &rect, int dx, int dy, QWidget *widget); + void releaseBuffer(); + + void beginPaint(QRegion &toClean, QWidget *widget, QBackingStore *backingStore, + BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates = true); + void endPaint(const QRegion &cleaned, QBackingStore *backingStore, BeginPaintInfo *beginPaintInfo); + + QRegion dirtyRegion(QWidget *widget = 0) const; + QRegion staticContents(QWidget *widget = 0, const QRect &withinClipRect = QRect()) const; + + void markDirtyOnScreen(const QRegion &dirtyOnScreen, QWidget *widget, const QPoint &topLevelOffset); + + void removeDirtyWidget(QWidget *w); + +#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) + bool hasDirtyWindowDecoration() const; + void paintWindowDecoration(); +#endif + void updateLists(QWidget *widget); + + inline void addDirtyWidget(QWidget *widget, const QRegion &rgn) + { + if (widget && !widget->d_func()->inDirtyList && !widget->data->in_destructor) { + QWidgetPrivate *widgetPrivate = widget->d_func(); +#ifndef QT_NO_GRAPHICSEFFECT + if (widgetPrivate->graphicsEffect) + widgetPrivate->dirty = widgetPrivate->effectiveRectFor(rgn.boundingRect()); + else +#endif //QT_NO_GRAPHICSEFFECT + widgetPrivate->dirty = rgn; + dirtyWidgets.append(widget); + widgetPrivate->inDirtyList = true; + } + } + + inline void dirtyWidgetsRemoveAll(QWidget *widget) + { + int i = 0; + while (i < dirtyWidgets.size()) { + if (dirtyWidgets.at(i) == widget) + dirtyWidgets.remove(i); + else + ++i; + } + } + + inline void addStaticWidget(QWidget *widget) + { + if (!widget) + return; + + Q_ASSERT(widget->testAttribute(Qt::WA_StaticContents)); + if (!staticWidgets.contains(widget)) + staticWidgets.append(widget); + } + + inline void removeStaticWidget(QWidget *widget) + { staticWidgets.removeAll(widget); } + + // Move the reparented widget and all its static children from this backing store + // to the new backing store if reparented into another top-level / backing store. + inline void moveStaticWidgets(QWidget *reparented) + { + Q_ASSERT(reparented); + QWidgetBackingStore *newBs = reparented->d_func()->maybeBackingStore(); + if (newBs == this) + return; + + int i = 0; + while (i < staticWidgets.size()) { + QWidget *w = staticWidgets.at(i); + if (reparented == w || reparented->isAncestorOf(w)) { + staticWidgets.removeAt(i); + if (newBs) + newBs->addStaticWidget(w); + } else { + ++i; + } + } + } + + inline QRect topLevelRect() const + { +#ifdef Q_WS_QWS + return tlw->frameGeometry(); +#else + return tlw->data->crect; +#endif + } + + inline void appendDirtyOnScreenWidget(QWidget *widget) + { + if (!widget) + return; + + if (!dirtyOnScreenWidgets) { + dirtyOnScreenWidgets = new QVector; + dirtyOnScreenWidgets->append(widget); + } else if (!dirtyOnScreenWidgets->contains(widget)) { + dirtyOnScreenWidgets->append(widget); + } + } + + inline void dirtyOnScreenWidgetsRemoveAll(QWidget *widget) + { + if (!widget || !dirtyOnScreenWidgets) + return; + + int i = 0; + while (i < dirtyOnScreenWidgets->size()) { + if (dirtyOnScreenWidgets->at(i) == widget) + dirtyOnScreenWidgets->remove(i); + else + ++i; + } + } + + inline void resetWidget(QWidget *widget) + { + if (widget) { + widget->d_func()->inDirtyList = false; + widget->d_func()->isScrolled = false; + widget->d_func()->isMoved = false; + widget->d_func()->dirty = QRegion(); + } + } + + inline void updateStaticContentsSize() + { + for (int i = 0; i < staticWidgets.size(); ++i) { + QWidgetPrivate *wd = staticWidgets.at(i)->d_func(); + if (!wd->extra) + wd->createExtra(); + wd->extra->staticContentsSize = wd->data.crect.size(); + } + } + + inline bool hasStaticContents() const + { return !staticWidgets.isEmpty(); } + + friend QRegion qt_dirtyRegion(QWidget *); + friend class QWidgetPrivate; + friend class QWidget; + friend class QETWidget; + friend class QBackingStore; +}; + +QT_END_NAMESPACE + +#endif // QBACKINGSTORE_P_H diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index 12b3410d62..5d4ef00104 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -65,7 +65,7 @@ #include #include #include -#include +#include #include #include @@ -9081,7 +9081,7 @@ void tst_QWidget::destroyBackingStore() QTRY_VERIFY(w.numPaintEvents > 0); w.reset(); w.update(); - qt_widget_private(&w)->topData()->backingStore.create(&w); + qt_widget_private(&w)->topData()->backingStoreTracker.create(&w); w.update(); QApplication::processEvents(); @@ -9105,7 +9105,7 @@ QWidgetBackingStore* backingStore(QWidget &widget) QWidgetBackingStore *backingStore = 0; #ifdef QT_BUILD_INTERNAL if (QTLWExtra *topExtra = qt_widget_private(&widget)->maybeTopData()) - backingStore = topExtra->backingStore.data(); + backingStore = topExtra->backingStoreTracker.data(); #endif return backingStore; } @@ -9940,12 +9940,12 @@ class scrollWidgetWBS : public QWidget public: void deleteBackingStore() { - static_cast(d_ptr.data())->topData()->backingStore.destroy(); + static_cast(d_ptr.data())->topData()->backingStoreTracker.destroy(); } void enableBackingStore() { if (!static_cast(d_ptr.data())->maybeBackingStore()) { - static_cast(d_ptr.data())->topData()->backingStore.create(this); + static_cast(d_ptr.data())->topData()->backingStoreTracker.create(this); static_cast(d_ptr.data())->invalidateBuffer(this->rect()); repaint(); } -- cgit v1.2.3