diff options
28 files changed, 670 insertions, 758 deletions
diff --git a/config.tests/unix/openssl/openssl.pri b/config.tests/unix/openssl/openssl.pri index bc95479..f069396 100644 --- a/config.tests/unix/openssl/openssl.pri +++ b/config.tests/unix/openssl/openssl.pri @@ -1,9 +1,3 @@ -!cross_compile { - TRY_INCLUDEPATHS = /include /usr/include /usr/local/include $$QMAKE_INCDIR $$INCLUDEPATH - # LSB doesn't allow using headers from /include or /usr/include - linux-lsb-g++:TRY_INCLUDEPATHS = $$QMAKE_INCDIR $$INCLUDEPATH - for(p, TRY_INCLUDEPATHS) { - pp = $$join(p, "", "", "/openssl") - exists($$pp):INCLUDEPATH *= $$p - } -} +# Empty file since Qt 4.6 +# I'm too lazy to find all places where this file is included + diff --git a/dist/changes-4.6.0 b/dist/changes-4.6.0 index 383c6b7..7a6decf 100644 --- a/dist/changes-4.6.0 +++ b/dist/changes-4.6.0 @@ -34,9 +34,15 @@ information about a particular change. - Significant external contribution from Milan Burda for planned removal of (non-unicode) Windows 9x/ME support. + - QRegion is no longer a GDI object by default. This means it is no + longer subjuect to gui-thread only nor does it potentially impact + the 10.000 GDI object limit per process. By explicitly calling + .handle() a GDI object will be created and memory managed by + QRegion. The native handle is for reading out only. Any GDI calls + made on the HRGN handle will not affect the QRegion. **************************************************************************** -* Important Behavior Changes * +* Important Behavior Changes * **************************************************************************** - The experimental Direct3D paint engine has been removed. The reason for @@ -71,33 +77,32 @@ information about a particular change. QGraphicsItem::ItemSendsGeometryChanges (which is enabled by default by QGraphicsWidget and QGraphicsProxyWidget). -- QDesktopWidget on X11 no longer emits the resized(int) signal when screens - are added or removed. This was not done on other platforms. Use the - screenCountChanged signal instead - -- QUrl's parser is more strict when for hostnames in URLs. QUrl now - enforces STD 3 rules: - - * each individual hostname section (between dots) must be at most - 63 ASCII characters in length; - - * only letters, digits, and the hyphen character are allowed in the - ASCII range; letters outside the ASCII range follow the normal - IDN rules - - That means QUrl no longer accepts some URLs that were invalid - before, but weren't interpreted as such. - -- The Unix configure-time check for STL is stricter now in Qt - 4.6.0. This means some legacy STL implementations may fail to pass - the test and, therefore, Qt will automatically disable STL support. - - This is a binary-compatible change: existing code will continue to - work without being recompiled. However, it affects the source code, - since some STL-compatibility API will not be enabled. - - Platforms affected by this change: - * solaris-cc-* with the default (Cstd) C++ STL library - recommendation: use -library=stlport4 - See Sun Studio's documentation for the effects of this option - + - QDesktopWidget on X11 no longer emits the resized(int) signal when screens + are added or removed. This was not done on other platforms. Use the + screenCountChanged signal instead + + - QUrl's parser is more strict when for hostnames in URLs. QUrl now + enforces STD 3 rules: + + * each individual hostname section (between dots) must be at most + 63 ASCII characters in length; + + * only letters, digits, and the hyphen character are allowed in the + ASCII range; letters outside the ASCII range follow the normal + IDN rules + + That means QUrl no longer accepts some URLs that were invalid + before, but weren't interpreted as such. + + - The Unix configure-time check for STL is stricter now in Qt + 4.6.0. This means some legacy STL implementations may fail to pass + the test and, therefore, Qt will automatically disable STL support. + + This is a binary-compatible change: existing code will continue to + work without being recompiled. However, it affects the source code, + since some STL-compatibility API will not be enabled. + + Platforms affected by this change: + * solaris-cc-* with the default (Cstd) C++ STL library + recommendation: use -library=stlport4 + See Sun Studio's documentation for the effects of this option diff --git a/examples/script/customclass/bytearrayclass.cpp b/examples/script/customclass/bytearrayclass.cpp index 81a0b8a..2044a16 100644 --- a/examples/script/customclass/bytearrayclass.cpp +++ b/examples/script/customclass/bytearrayclass.cpp @@ -100,7 +100,7 @@ ByteArrayClass::ByteArrayClass(QScriptEngine *engine) QScriptValue global = engine->globalObject(); proto.setPrototype(global.property("Object").property("prototype")); - ctor = engine->newFunction(construct); + ctor = engine->newFunction(construct, proto); ctor.setData(qScriptValueFromValue(engine, this)); } //! [0] @@ -224,7 +224,10 @@ QScriptValue ByteArrayClass::construct(QScriptContext *ctx, QScriptEngine *) ByteArrayClass *cls = qscriptvalue_cast<ByteArrayClass*>(ctx->callee().data()); if (!cls) return QScriptValue(); - int size = ctx->argument(0).toInt32(); + QScriptValue arg = ctx->argument(0); + if (arg.instanceOf(ctx->callee())) + return cls->newInstance(qscriptvalue_cast<QByteArray>(arg)); + int size = arg.toInt32(); return cls->newInstance(size); } //! [2] @@ -240,7 +243,7 @@ QScriptValue ByteArrayClass::toScriptValue(QScriptEngine *eng, const QByteArray void ByteArrayClass::fromScriptValue(const QScriptValue &obj, QByteArray &ba) { - ba = qscriptvalue_cast<QByteArray>(obj.data()); + ba = qvariant_cast<QByteArray>(obj.data().toVariant()); } diff --git a/examples/script/customclass/main.cpp b/examples/script/customclass/main.cpp index 05aefd5..3b98f5c 100644 --- a/examples/script/customclass/main.cpp +++ b/examples/script/customclass/main.cpp @@ -52,6 +52,7 @@ int main(int argc, char **argv) eng.globalObject().setProperty("ByteArray", baClass->constructor()); qDebug() << "ba = new ByteArray(4):" << eng.evaluate("ba = new ByteArray(4)").toString(); + qDebug() << "ba instanceof ByteArray:" << eng.evaluate("ba instanceof ByteArray").toBool(); qDebug() << "ba.length:" << eng.evaluate("ba.length").toNumber(); qDebug() << "ba[1] = 123; ba[1]:" << eng.evaluate("ba[1] = 123; ba[1]").toNumber(); qDebug() << "ba[7] = 224; ba.length:" << eng.evaluate("ba[7] = 224; ba.length").toNumber(); @@ -65,6 +66,9 @@ int main(int argc, char **argv) qDebug() << "ba.toBase64().toLatin1String():" << eng.evaluate("b64.toLatin1String()").toString(); qDebug() << "ba.valueOf():" << eng.evaluate("ba.valueOf()").toString(); qDebug() << "ba.chop(2); ba.length:" << eng.evaluate("ba.chop(2); ba.length").toNumber(); + qDebug() << "ba2 = new ByteArray(ba):" << eng.evaluate("ba2 = new ByteArray(ba)").toString(); + qDebug() << "ba2.equals(ba):" << eng.evaluate("ba2.equals(ba)").toBool(); + qDebug() << "ba2.equals(new ByteArray()):" << eng.evaluate("ba2.equals(new ByteArray())").toBool(); return 0; } diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp index 89d9d1b..ebdac9a 100644 --- a/src/gui/egl/qegl.cpp +++ b/src/gui/egl/qegl.cpp @@ -400,4 +400,15 @@ void QEglContext::dumpAllConfigs() delete [] configs; } +QString QEglContext::extensions() +{ + const char* exts = eglQueryString(dpy, EGL_EXTENSIONS); + return QString(QLatin1String(exts)); +} + +bool QEglContext::hasExtension(const char* extensionName) +{ + return extensions().contains(QLatin1String(extensionName)); +} + QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h index ddf7d27..3ae1489 100644 --- a/src/gui/egl/qegl_p.h +++ b/src/gui/egl/qegl_p.h @@ -122,6 +122,9 @@ public: void dumpAllConfigs(); + QString extensions(); + bool hasExtension(const char* extensionName); + private: QEgl::API apiType; EGLDisplay dpy; diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index bf348af..b9c36dc 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -25,7 +25,9 @@ HEADERS += \ image/qpixmapcache_p.h \ image/qpixmapdata_p.h \ image/qpixmapdatafactory_p.h \ - image/qpixmapfilter_p.h + image/qpixmapfilter_p.h \ + image/qimagepixmapcleanuphooks_p.h \ + SOURCES += \ image/qbitmap.cpp \ @@ -47,6 +49,8 @@ SOURCES += \ image/qmovie.cpp \ image/qpixmap_raster.cpp \ image/qnativeimage.cpp \ + image/qimagepixmapcleanuphooks.cpp \ + win32 { SOURCES += image/qpixmap_win.cpp diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index e8ca7a9..bb77fb5 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -49,6 +49,7 @@ #include "qimagewriter.h" #include "qstringlist.h" #include "qvariant.h" +#include "qimagepixmapcleanuphooks_p.h" #include <ctype.h> #include <stdlib.h> #include <limits.h> @@ -106,14 +107,6 @@ static inline bool checkPixelSize(const QImage::Format format) } -// ### Qt 5: remove -typedef void (*_qt_image_cleanup_hook)(int); -Q_GUI_EXPORT _qt_image_cleanup_hook qt_image_cleanup_hook = 0; - -// ### Qt 5: rename -typedef void (*_qt_image_cleanup_hook_64)(qint64); -Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64 = 0; - static QImage rotated90(const QImage &src); static QImage rotated180(const QImage &src); static QImage rotated270(const QImage &src); @@ -257,8 +250,8 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format, int nu QImageData::~QImageData() { - if (is_cached && qt_image_cleanup_hook_64) - qt_image_cleanup_hook_64((((qint64) ser_no) << 32) | ((qint64) detach_no)); + if (is_cached) + QImagePixmapCleanupHooks::executeImageHooks((((qint64) ser_no) << 32) | ((qint64) detach_no)); delete paintEngine; if (data && own_data) free(data); @@ -1342,8 +1335,8 @@ QImage::operator QVariant() const void QImage::detach() { if (d) { - if (d->is_cached && qt_image_cleanup_hook_64 && d->ref == 1) - qt_image_cleanup_hook_64(cacheKey()); + if (d->is_cached && d->ref == 1) + QImagePixmapCleanupHooks::executeImageHooks(cacheKey()); if (d->ref != 1 || d->ro_data) *this = copy(); diff --git a/src/gui/image/qimagepixmapcleanuphooks.cpp b/src/gui/image/qimagepixmapcleanuphooks.cpp new file mode 100644 index 0000000..7d1c5fb --- /dev/null +++ b/src/gui/image/qimagepixmapcleanuphooks.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qimagepixmapcleanuphooks_p.h" +#include "qpixmapdata_p.h" + + +// Legacy, single instance hooks: ### Qt 5: remove +typedef void (*_qt_pixmap_cleanup_hook)(int); +typedef void (*_qt_pixmap_cleanup_hook_64)(qint64); +typedef void (*_qt_image_cleanup_hook)(int); +Q_GUI_EXPORT _qt_pixmap_cleanup_hook qt_pixmap_cleanup_hook = 0; +Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64 = 0; +Q_GUI_EXPORT _qt_image_cleanup_hook qt_image_cleanup_hook = 0; +Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64 = 0; + + +QImagePixmapCleanupHooks* qt_image_and_pixmap_cleanup_hooks = 0; + + +QImagePixmapCleanupHooks::QImagePixmapCleanupHooks() +{ + qt_image_and_pixmap_cleanup_hooks = this; +} + +QImagePixmapCleanupHooks *QImagePixmapCleanupHooks::instance() +{ + if (!qt_image_and_pixmap_cleanup_hooks) + qt_image_and_pixmap_cleanup_hooks = new QImagePixmapCleanupHooks; + return qt_image_and_pixmap_cleanup_hooks; +} + +void QImagePixmapCleanupHooks::addPixmapHook(_qt_pixmap_cleanup_hook_pm hook) +{ + pixmapHooks.append(hook); +} + +void QImagePixmapCleanupHooks::addImageHook(_qt_image_cleanup_hook_64 hook) +{ + imageHooks.append(hook); +} + +void QImagePixmapCleanupHooks::removePixmapHook(_qt_pixmap_cleanup_hook_pm hook) +{ + pixmapHooks.removeAll(hook); +} + +void QImagePixmapCleanupHooks::removeImageHook(_qt_image_cleanup_hook_64 hook) +{ + imageHooks.removeAll(hook); +} + + +void QImagePixmapCleanupHooks::executePixmapHooks(QPixmap* pm) +{ + for (int i = 0; i < qt_image_and_pixmap_cleanup_hooks->pixmapHooks.count(); ++i) + qt_image_and_pixmap_cleanup_hooks->pixmapHooks[i](pm); + + if (qt_pixmap_cleanup_hook_64) + qt_pixmap_cleanup_hook_64(pm->cacheKey()); +} + + +void QImagePixmapCleanupHooks::executeImageHooks(qint64 key) +{ + for (int i = 0; i < qt_image_and_pixmap_cleanup_hooks->imageHooks.count(); ++i) + qt_image_and_pixmap_cleanup_hooks->imageHooks[i](key); + + if (qt_image_cleanup_hook_64) + qt_image_cleanup_hook_64(key); +} + diff --git a/src/gui/painting/qregion_wince.cpp b/src/gui/image/qimagepixmapcleanuphooks_p.h index 9c33123..e765e69 100644 --- a/src/gui/painting/qregion_wince.cpp +++ b/src/gui/image/qimagepixmapcleanuphooks_p.h @@ -39,81 +39,51 @@ ** ****************************************************************************/ -#include "qatomic.h" -#include "qbitmap.h" -#include "qbuffer.h" -#include "qimage.h" -#include "qpolygon.h" -#include "qregion.h" -#include "qt_windows.h" -#include "qpainterpath.h" -#include "qguifunctions_wince.h" +#ifndef QIMAGEPIXMAP_CLEANUPHOOKS_P_H +#define QIMAGEPIXMAP_CLEANUPHOOKS_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 <QtGui/qpixmap.h> QT_BEGIN_NAMESPACE -QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 }; +typedef void (*_qt_image_cleanup_hook_64)(qint64); +typedef void (*_qt_pixmap_cleanup_hook_pm)(QPixmap*); -HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom) -{ - const int tries = 10; - for (int i = 0; i < tries; ++i) { - HRGN region; - switch (type) { - case QRegion::Rectangle: - region = CreateRectRgn(left, top, right, bottom); - break; - case QRegion::Ellipse: -#ifndef Q_OS_WINCE - region = CreateEllipticRgn(left, top, right, bottom); -#endif - break; - } - if (region) { - if (GetRegionData(region, 0, 0)) - return region; - else - DeleteObject(region); - } - } - return 0; -} +class QImagePixmapCleanupHooks; +extern QImagePixmapCleanupHooks* qt_image_and_pixmap_cleanup_hooks; -void qt_win_dispose_rgn(HRGN r) +class Q_GUI_EXPORT QImagePixmapCleanupHooks { - if (r) - DeleteObject(r); -} +public: + QImagePixmapCleanupHooks(); -static void qt_add_rect(HRGN &winRegion, QRect r) -{ - HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height()); - if (rgn) { - HRGN dest = CreateRectRgn(0,0,0,0); - int result = CombineRgn(dest, winRegion, rgn, RGN_OR); - if (result) { - DeleteObject(winRegion); - winRegion = dest; - } - } -} + static QImagePixmapCleanupHooks *instance(); -void QRegion::ensureHandle() const -{ - if (d->rgn) - DeleteObject(d->rgn); - d->rgn = CreateRectRgn(0,0,0,0); - if (d->qt_rgn) { - if (d->qt_rgn->numRects == 1) { - QRect r = d->qt_rgn->extents; - qt_add_rect(d->rgn, r); - return; - } - for (int i = 0;i < d->qt_rgn->numRects;i++) { - QRect r = d->qt_rgn->rects.at(i); - qt_add_rect(d->rgn, r); - } - } -} + void addPixmapHook(_qt_pixmap_cleanup_hook_pm); + void addImageHook(_qt_image_cleanup_hook_64); + + void removePixmapHook(_qt_pixmap_cleanup_hook_pm); + void removeImageHook(_qt_image_cleanup_hook_64); + static void executePixmapHooks(QPixmap*); + static void executeImageHooks(qint64 key); + +private: + QList<_qt_image_cleanup_hook_64> imageHooks; + QList<_qt_pixmap_cleanup_hook_pm> pixmapHooks; +}; QT_END_NAMESPACE + +#endif // QIMAGEPIXMAP_CLEANUPHOOKS_P_H diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 18829f4..82835d5 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -43,6 +43,7 @@ #include "qpixmap.h" #include "qpixmapdata_p.h" +#include "qimagepixmapcleanuphooks_p.h" #include "qbitmap.h" #include "qcolormap.h" @@ -81,14 +82,6 @@ QT_BEGIN_NAMESPACE // ### Qt 5: remove -typedef void (*_qt_pixmap_cleanup_hook)(int); -Q_GUI_EXPORT _qt_pixmap_cleanup_hook qt_pixmap_cleanup_hook = 0; - -// ### Qt 5: rename -typedef void (*_qt_pixmap_cleanup_hook_64)(qint64); -Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64 = 0; - -// ### Qt 5: remove Q_GUI_EXPORT qint64 qt_pixmap_id(const QPixmap &pixmap) { return pixmap.cacheKey(); @@ -656,7 +649,7 @@ void QPixmap::resize_helper(const QSize &s) QX11PixmapData *x11Data = data->classId() == QPixmapData::X11Class ? static_cast<QX11PixmapData*>(data) : 0; if (x11Data) { pm.x11SetScreen(x11Data->xinfo.screen()); - uninit = x11Data->uninit; + uninit = x11Data->flags & QX11PixmapData::Uninitialized; } #elif defined(Q_WS_MAC) QMacPixmapData *macData = data->classId() == QPixmapData::MacClass ? static_cast<QMacPixmapData*>(data) : 0; @@ -1357,8 +1350,8 @@ bool QPixmap::isDetached() const void QPixmap::deref() { if (data && !data->ref.deref()) { // Destroy image if last ref - if (data->is_cached && qt_pixmap_cleanup_hook_64) - qt_pixmap_cleanup_hook_64(cacheKey()); + if (data->is_cached) + QImagePixmapCleanupHooks::executePixmapHooks(this); delete data; data = 0; } @@ -1897,9 +1890,6 @@ int QPixmap::defaultDepth() #endif } -typedef void (*_qt_pixmap_cleanup_hook_64)(qint64); -extern _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64; - /*! Detaches the pixmap from shared pixmap data. @@ -1925,8 +1915,8 @@ void QPixmap::detach() rasterData->image.detach(); } - if (data->is_cached && qt_pixmap_cleanup_hook_64 && data->ref == 1) - qt_pixmap_cleanup_hook_64(cacheKey()); + if (data->is_cached && data->ref == 1) + QImagePixmapCleanupHooks::executePixmapHooks(this); #if defined(Q_WS_MAC) QMacPixmapData *macData = id == QPixmapData::MacClass ? static_cast<QMacPixmapData*>(data) : 0; @@ -1946,7 +1936,7 @@ void QPixmap::detach() #if defined(Q_WS_X11) if (data->classId() == QPixmapData::X11Class) { QX11PixmapData *d = static_cast<QX11PixmapData*>(data); - d->uninit = false; + d->flags &= ~QX11PixmapData::Uninitialized; // reset the cache data if (d->hd2) { diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp index 86cf515..be3d070 100644 --- a/src/gui/image/qpixmap_x11.cpp +++ b/src/gui/image/qpixmap_x11.cpp @@ -313,7 +313,7 @@ int Q_GUI_EXPORT qt_x11_preferred_pixmap_depth = 0; QX11PixmapData::QX11PixmapData(PixelType type) : QPixmapData(type, X11Class), hd(0), - uninit(true), read_only(false), x11_mask(0), picture(0), mask_picture(0), hd2(0), + flags(Uninitialized), x11_mask(0), picture(0), mask_picture(0), hd2(0), gl_surface(0), share_mode(QPixmap::ImplicitlyShared), pengine(0) { } @@ -1217,7 +1217,7 @@ void QX11PixmapData::release() XFreePixmap(xinfo.display(), hd2); hd2 = 0; } - if (!read_only) + if (!(flags & Readonly)) XFreePixmap(xinfo.display(), hd); hd = 0; } @@ -1876,7 +1876,7 @@ QPixmap QX11PixmapData::transformed(const QTransform &transform, } else { // color pixmap QPixmap pm; QX11PixmapData *x11Data = static_cast<QX11PixmapData*>(pm.data); - x11Data->uninit = false; + x11Data->flags &= ~QX11PixmapData::Uninitialized; x11Data->xinfo = xinfo; x11Data->d = d; x11Data->w = w; @@ -2018,7 +2018,7 @@ QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h) QPixmap pm(data); - data->uninit = false; + data->flags &= ~QX11PixmapData::Uninitialized; pm.x11SetScreen(scr); GC gc = XCreateGC(dpy, pm.handle(), 0, 0); @@ -2060,7 +2060,7 @@ QPaintEngine* QX11PixmapData::paintEngine() const { QX11PixmapData *that = const_cast<QX11PixmapData*>(this); - if (read_only && share_mode == QPixmap::ImplicitlyShared) { + if ((flags & Readonly) && share_mode == QPixmap::ImplicitlyShared) { // if someone wants to draw onto us, copy the shared contents // and turn it into a fully fledged QPixmap ::Pixmap hd_copy = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()), @@ -2082,7 +2082,7 @@ QPaintEngine* QX11PixmapData::paintEngine() const XFreeGC(X11->display, gc); } that->hd = hd_copy; - that->read_only = false; + that->flags &= ~QX11PixmapData::Readonly; } if (!that->pengine) @@ -2133,7 +2133,7 @@ void QX11PixmapData::copy(const QPixmapData *data, const QRect &rect) setSerialNumber(++qt_pixmap_serial); - uninit = false; + flags &= ~Uninitialized; xinfo = x11Data->xinfo; d = x11Data->d; w = rect.width(); @@ -2201,7 +2201,7 @@ void QX11PixmapData::convertToARGB32(bool preserveContents) return; // Q_ASSERT(count == 1); - if (read_only && share_mode == QPixmap::ExplicitlyShared) + if ((flags & Readonly) && share_mode == QPixmap::ExplicitlyShared) return; Pixmap pm = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()), @@ -2211,10 +2211,10 @@ void QX11PixmapData::convertToARGB32(bool preserveContents) if (picture) { if (preserveContents) XRenderComposite(X11->display, PictOpSrc, picture, 0, p, 0, 0, 0, 0, 0, 0, w, h); - if (!read_only) + if (!(flags & Readonly)) XRenderFreePicture(X11->display, picture); } - if (hd && !read_only) + if (hd && !(flags & Readonly)) XFreePixmap(X11->display, hd); if (x11_mask) { XFreePixmap(X11->display, x11_mask); @@ -2252,9 +2252,8 @@ QPixmap QPixmap::fromX11Pixmap(Qt::HANDLE pixmap, QPixmap::ShareMode mode) QX11PixmapData *data = new QX11PixmapData(depth == 1 ? QPixmapData::BitmapType : QPixmapData::PixmapType); data->setSerialNumber(++qt_pixmap_serial); - data->read_only = true; + data->flags = QX11PixmapData::Readonly; data->share_mode = mode; - data->uninit = false; data->w = width; data->h = height; data->is_null = (width <= 0 || height <= 0); diff --git a/src/gui/image/qpixmap_x11_p.h b/src/gui/image/qpixmap_x11_p.h index 3de9a0f..835fea4 100644 --- a/src/gui/image/qpixmap_x11_p.h +++ b/src/gui/image/qpixmap_x11_p.h @@ -99,6 +99,7 @@ private: friend class QX11PaintEngine; friend class QX11WindowSurface; friend class QRasterWindowSurface; + friend class QGLContextPrivate; // Needs to access xinfo, gl_surface & flags void release(); @@ -108,14 +109,21 @@ private: Qt::HANDLE hd; - uint uninit : 1; - uint read_only : 1; + enum Flag { + NoFlags = 0x0, + Uninitialized = 0x1, + Readonly = 0x2, + InvertedWhenBoundToTexture = 0x4, + GlSurfaceCreatedWithAlpha = 0x8 + }; + uint flags; QX11Info xinfo; Qt::HANDLE x11_mask; Qt::HANDLE picture; Qt::HANDLE mask_picture; Qt::HANDLE hd2; // sorted in the default display depth + Qt::HANDLE gl_surface; #ifndef QT_NO_XRENDER void convertToARGB32(bool preserveContents = true); #endif diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h index 29dafaf..32b419e 100644 --- a/src/gui/image/qpixmapdata_p.h +++ b/src/gui/image/qpixmapdata_p.h @@ -116,6 +116,7 @@ private: friend class QPixmap; friend class QGLContextPrivate; friend class QX11PixmapData; + friend class QGLTextureCache; //Needs to check the reference count QAtomicInt ref; int detach_no; diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 5181689..109ceb1 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -179,11 +179,11 @@ QApplicationPrivate::~QApplicationPrivate() QApplication contains the main event loop, where all events from the window system and other sources are processed and dispatched. It also handles the - application's initialization and finalization, and provides session - management. In addition, it handles most system-wide and application-wide - settings. + application's initialization, finalization, and provides session + management. In addition, QApplication handles most of the system-wide and + application-wide settings. - For any GUI application using Qt, there is precisely one QApplication + For any GUI application using Qt, there is precisely \bold one QApplication object, no matter whether the application has 0, 1, 2 or more windows at any given time. For non-GUI Qt applications, use QCoreApplication instead, as it does not depend on the \l QtGui library. @@ -239,9 +239,9 @@ QApplicationPrivate::~QApplicationPrivate() saveState() for details. \endlist - The QApplication object does so much initialization. Hence, it \e{must} be + Since the QApplication object does so much initialization, it \e{must} be created before any other objects related to the user interface are created. - Since QApplication also deals with common command line arguments, it is + QApplication also deals with common command line arguments. Hence, it is usually a good idea to create it \e before any interpretation or modification of \c argv is done in the application itself. diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 34d1779..d226be2 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -100,8 +100,8 @@ win32 { painting/qcolormap_win.cpp \ painting/qpaintdevice_win.cpp \ painting/qprintengine_win.cpp \ - painting/qprinterinfo_win.cpp \ - painting/qregion_win.cpp + painting/qprinterinfo_win.cpp + !win32-borland:!wince*:LIBS += -lmsimg32 } @@ -126,10 +126,6 @@ embedded { painting/qwindowsurface_raster.cpp \ } -wince* { - SOURCES -= painting/qregion_win.cpp -} - unix:x11 { HEADERS += \ painting/qpaintengine_x11_p.h diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 762e9e0..d59f3ff 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -49,7 +49,7 @@ #include <qdebug.h> -#if defined(Q_OS_UNIX) || defined(Q_OS_WINCE) +#if defined(Q_OS_UNIX) || defined(Q_WS_WIN) #include "qimage.h" #include "qbitmap.h" #include <stdlib.h> @@ -545,7 +545,7 @@ QRegion& QRegion::operator|=(const QRegion &r) \sa intersected() */ -#if !defined (Q_OS_UNIX) && !defined (Q_OS_WINCE) +#if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN) QRegion& QRegion::operator+=(const QRect &r) { return operator+=(QRegion(r)); @@ -561,16 +561,14 @@ QRegion& QRegion::operator+=(const QRect &r) \sa intersected() */ -#if !defined(Q_WS_WIN) || defined(Q_OS_WINCE) QRegion& QRegion::operator&=(const QRegion &r) { return *this = *this & r; } -#endif /*! \overload \since 4.4 */ -#if defined (Q_OS_UNIX) || defined (Q_OS_WINCE) +#if defined (Q_OS_UNIX) || defined (Q_WS_WIN) QRegion& QRegion::operator&=(const QRect &r) { return *this = *this & r; @@ -591,10 +589,8 @@ QRegion& QRegion::operator&=(const QRect &r) \sa subtracted() */ -#if !defined(Q_WS_WIN) || defined(Q_OS_WINCE) QRegion& QRegion::operator-=(const QRegion &r) { return *this = *this - r; } -#endif /*! Applies the xored() function to this region and \a r and @@ -731,7 +727,7 @@ bool QRegion::intersects(const QRect &rect) const return false; } -#if !defined (Q_OS_UNIX) && !defined (Q_OS_WINCE) +#if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN) /*! \overload \since 4.4 @@ -1086,7 +1082,7 @@ Q_AUTOTEST_EXPORT QPainterPath qt_regionToPath(const QRegion ®ion) return result; } -#if defined(Q_OS_UNIX) || defined(Q_OS_WINCE) +#if defined(Q_OS_UNIX) || defined(Q_WS_WIN) //#define QT_REGION_DEBUG /* @@ -1627,9 +1623,9 @@ QT_END_INCLUDE_NAMESPACE QT_BEGIN_INCLUDE_NAMESPACE # include "qregion_mac.cpp" QT_END_INCLUDE_NAMESPACE -#elif defined(Q_OS_WINCE) +#elif defined(Q_WS_WIN) QT_BEGIN_INCLUDE_NAMESPACE -# include "qregion_wince.cpp" +# include "qregion_win.cpp" QT_END_INCLUDE_NAMESPACE #elif defined(Q_WS_QWS) static QRegionPrivate qrp; @@ -3829,7 +3825,7 @@ QRegion::QRegion(const QRect &r, RegionType t) #if defined(Q_WS_X11) d->rgn = 0; d->xrectangles = 0; -#elif defined(Q_OS_WINCE) +#elif defined(Q_WS_WIN) d->rgn = 0; #endif if (t == Rectangle) { @@ -3851,7 +3847,7 @@ QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule) #if defined(Q_WS_X11) d->rgn = 0; d->xrectangles = 0; -#elif defined(Q_OS_WINCE) +#elif defined(Q_WS_WIN) d->rgn = 0; #endif d->qt_rgn = PolygonRegion(a.constData(), a.size(), @@ -3881,7 +3877,7 @@ QRegion::QRegion(const QBitmap &bm) #if defined(Q_WS_X11) d->rgn = 0; d->xrectangles = 0; -#elif defined(Q_OS_WINCE) +#elif defined(Q_WS_WIN) d->rgn = 0; #endif d->qt_rgn = qt_bitmapToRegion(bm); @@ -3896,7 +3892,7 @@ void QRegion::cleanUp(QRegion::QRegionData *x) XDestroyRegion(x->rgn); if (x->xrectangles) free(x->xrectangles); -#elif defined(Q_OS_WINCE) +#elif defined(Q_WS_WIN) if (x->rgn) qt_win_dispose_rgn(x->rgn); #endif @@ -3932,7 +3928,7 @@ QRegion QRegion::copy() const #if defined(Q_WS_X11) x->rgn = 0; x->xrectangles = 0; -#elif defined(Q_OS_WINCE) +#elif defined(Q_WS_WIN) x->rgn = 0; #endif if (d->qt_rgn) diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index 6dfdc83..84024ce 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -59,7 +59,7 @@ QT_MODULE(Gui) template <class T> class QVector; class QVariant; -#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) +#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) struct QRegionPrivate; #endif @@ -200,7 +200,7 @@ private: #elif defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA) mutable RgnHandle unused; // Here for binary compatability reasons. ### Qt 5 remove. #endif -#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) +#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) QRegionPrivate *qt_rgn; #endif }; diff --git a/src/gui/painting/qregion_win.cpp b/src/gui/painting/qregion_win.cpp index 249b1a6..2d5e76b 100644 --- a/src/gui/painting/qregion_win.cpp +++ b/src/gui/painting/qregion_win.cpp @@ -39,27 +39,25 @@ ** ****************************************************************************/ +#include "qatomic.h" #include "qbitmap.h" #include "qbuffer.h" #include "qimage.h" #include "qpolygon.h" #include "qregion.h" #include "qt_windows.h" +#include "qpainterpath.h" +#include "qguifunctions_wince.h" QT_BEGIN_NAMESPACE +QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 }; -/* - In Windows versions before Windows Vista CreateRectRgn - when called in a multi-threaded - environment - might return an invalid handle. This function works around this limitation - by verifying the handle with a quick GetRegionData() call and re-creates the region - if necessary. -*/ HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom) { const int tries = 10; for (int i = 0; i < tries; ++i) { - HRGN region = 0; + HRGN region; switch (type) { case QRegion::Rectangle: region = CreateRectRgn(left, top, right, bottom); @@ -80,497 +78,73 @@ HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, return 0; } -#ifndef Q_OS_WINCE -HRGN qt_tryCreatePolygonRegion(const QPolygon &a, Qt::FillRule fillRule) -{ - const int tries = 10; - for (int i = 0; i < tries; ++i) { - HRGN region = CreatePolygonRgn(reinterpret_cast<const POINT*>(a.data()), a.size(), - fillRule == Qt::OddEvenFill ? ALTERNATE : WINDING); - if (region) { - if (GetRegionData(region, 0, 0)) - return region; - else - DeleteObject(region); - } - } - return 0; -} -#endif - -QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0 }; - -QRegion::QRegion() - : d(&shared_empty) -{ - d->ref.ref(); -} - -#ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp -QRegion::QRegion(const QRect &r, RegionType t) -{ - if (r.isEmpty()) { - d = &shared_empty; - d->ref.ref(); - } else { - d = new QRegionData; - d->ref = 1; - if (t == Rectangle) - d->rgn = qt_tryCreateRegion(t, r.left(), r.top(), r.x() + r.width(), r.y() + r.height()); - else if (t == Ellipse) { - // need to add 1 to width/height for the ellipse to have correct boundingrect. - d->rgn = qt_tryCreateRegion(t, r.x(), r.y(), r.x() + r.width() + 1, r.y() + r.height() + 1); - } - } -} -#endif - -#ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp -QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule) -{ - if (a.size() < 3) { - d = &shared_empty; - d->ref.ref(); - } else { - d = new QRegionData; - d->ref = 1; - d->rgn = qt_tryCreatePolygonRegion(a, fillRule); - } -} -#endif - -QRegion::QRegion(const QRegion &r) -{ - d = r.d; - d->ref.ref(); -} - -HRGN qt_win_bitmapToRegion(const QBitmap& bitmap) -{ - HRGN region=0; - QImage image = bitmap.toImage(); - const int MAXRECT = 256; - struct RData { - RGNDATAHEADER header; - RECT rect[MAXRECT]; - }; - RData data; - -#define FlushSpans \ - { \ - data.header.dwSize = sizeof(RGNDATAHEADER); \ - data.header.iType = RDH_RECTANGLES; \ - data.header.nCount = n; \ - data.header.nRgnSize = 0; \ - data.header.rcBound.bottom = y; \ - HRGN r = ExtCreateRegion(0, \ - sizeof(RGNDATAHEADER)+n*sizeof(RECT),(RGNDATA*)&data); \ - if (region) { \ - CombineRgn(region, region, r, RGN_OR); \ - DeleteObject(r); \ - } else { \ - region = r; \ - } \ - data.header.rcBound.top = y; \ - } - -#define AddSpan \ - { \ - data.rect[n].left=prev1; \ - data.rect[n].top=y; \ - data.rect[n].right=x-1+1; \ - data.rect[n].bottom=y+1; \ - n++; \ - if (n == MAXRECT) { \ - FlushSpans \ - n=0; \ - } \ - } - - data.header.rcBound.top = 0; - data.header.rcBound.left = 0; - data.header.rcBound.right = image.width()-1; - int n = 0; - - int zero = 0x00; - - int x, y; - for (y = 0; y < image.height(); ++y) { - uchar *line = image.scanLine(y); - int w = image.width(); - uchar all=zero; - int prev1 = -1; - for (x = 0; x < w;) { - uchar byte = line[x/8]; - if (x > w - 8 || byte != all) { - for (int b = 8; b > 0 && x < w; --b) { - if (!(byte & 0x01) == !all) { - // More of the same - } else { - // A change. - if (all != zero) { - AddSpan; - all = zero; - } else { - prev1 = x; - all = ~zero; - } - } - byte >>= 1; - ++x; - } - } else { - x += 8; - } - } - if (all != zero) { - AddSpan; - } - } - if (n) { - FlushSpans; - } - - if (!region) { - // Surely there is some better way. - region = qt_tryCreateRegion(QRegion::Rectangle, 0,0,1,1); - CombineRgn(region, region, region, RGN_XOR); - } - return region; -} - -#ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp -QRegion::QRegion(const QBitmap &bm) -{ - if (bm.isNull()) { - d = &shared_empty; - d->ref.ref(); - } else { - d = new QRegionData; - d->ref = 1; - d->rgn = qt_win_bitmapToRegion(bm); - } -} -#endif - -void QRegion::cleanUp(QRegion::QRegionData *x) -{ - if (x->rgn) - DeleteObject(x->rgn); - delete x; -} - -QRegion::~QRegion() -{ - if (!d->ref.deref()) - cleanUp(d); -} - -QRegion &QRegion::operator=(const QRegion &r) -{ - r.d->ref.ref(); - if (!d->ref.deref()) - cleanUp(d); - d = r.d; - return *this; -} - - -QRegion QRegion::copy() const -{ - QRegion r; - QRegionData *x = new QRegionData; - x->ref = 1; - if (d->rgn) { - x->rgn = qt_tryCreateRegion(QRegion::Rectangle, 0, 0, 2, 2); - CombineRgn(x->rgn, d->rgn, 0, RGN_COPY); - } else { - x->rgn = 0; - } - if (!r.d->ref.deref()) - cleanUp(r.d); - r.d = x; - return r; -} - -bool QRegion::isEmpty() const -{ - return (d == &shared_empty || boundingRect().isEmpty()); -} - - -bool QRegion::contains(const QPoint &p) const -{ - return d->rgn ? PtInRegion(d->rgn, p.x(), p.y()) : false; -} - -bool QRegion::contains(const QRect &r) const -{ - if (!d->rgn) - return false; - RECT rect; - SetRect(&rect, r.left(), r.top(), r.right(), r.bottom()); - return RectInRegion(d->rgn, &rect); -} - - -void QRegion::translate(int dx, int dy) -{ - if (!d->rgn || (dx == 0 && dy == 0)) - return; - detach(); - OffsetRgn(d->rgn, dx, dy); -} - - -#define RGN_NOP -1 - -// Duplicates of those in qregion.cpp -#define QRGN_OR 6 -#define QRGN_AND 7 -#define QRGN_SUB 8 -#define QRGN_XOR 9 - -/* - Performs the actual OR, AND, SUB and XOR operation between regions. - Sets the resulting region handle to 0 to indicate an empty region. -*/ - -QRegion QRegion::winCombine(const QRegion &r, int op) const +QRegion qt_region_from_HRGN(HRGN rgn) { - int both=RGN_NOP, - left=RGN_NOP, - right=RGN_NOP; - switch (op) { - case QRGN_OR: - both = RGN_OR; - left = right = RGN_COPY; - break; - case QRGN_AND: - both = RGN_AND; - break; - case QRGN_SUB: - both = RGN_DIFF; - left = RGN_COPY; - break; - case QRGN_XOR: - both = RGN_XOR; - left = right = RGN_COPY; - break; - default: - qWarning("QRegion: Internal error in winCombine"); - } - - int allCombineRgnResults = NULLREGION; - QRegion result; - result.detach(); - result.d->rgn = qt_tryCreateRegion(QRegion::Rectangle, 0, 0, 0, 0); - if (d->rgn && r.d->rgn) - allCombineRgnResults = CombineRgn(result.d->rgn, d->rgn, r.d->rgn, both); - else if (d->rgn && left != RGN_NOP) - allCombineRgnResults = CombineRgn(result.d->rgn, d->rgn, d->rgn, left); - else if (r.d->rgn && right != RGN_NOP) - allCombineRgnResults = CombineRgn(result.d->rgn, r.d->rgn, r.d->rgn, right); - - if (allCombineRgnResults == NULLREGION || allCombineRgnResults == ERROR) - result = QRegion(); - - //##### do not delete this. A null pointer is different from an empty region in SelectClipRgn in qpainter_win! (M) -// if (allCombineRgnResults == NULLREGION) { -// if (result.data->rgn) -// DeleteObject(result.data->rgn); -// result.data->rgn = 0; // empty region -// } - return result; -} - -QRegion QRegion::unite(const QRegion &r) const -{ - if (!d->rgn) - return r; - if (!r.d->rgn) - return *this; - return winCombine(r, QRGN_OR); -} - -QRegion QRegion::unite(const QRect &r) const -{ - return unite(QRegion(r)); -} - -QRegion QRegion::intersect(const QRegion &r) const -{ - if (!r.d->rgn || !d->rgn) - return QRegion(); - return winCombine(r, QRGN_AND); -} - -QRegion QRegion::subtract(const QRegion &r) const -{ - if (!r.d->rgn || !d->rgn) - return *this; - return winCombine(r, QRGN_SUB); -} - -QRegion QRegion::eor(const QRegion &r) const -{ - if (!d->rgn) - return r; - if (!r.d->rgn) - return *this; - return winCombine(r, QRGN_XOR); -} - - -QRect QRegion::boundingRect() const -{ - if (!d->rgn) - return QRect(); - RECT r; - if (GetRgnBox(d->rgn, &r) == NULLREGION) - return QRect(); - else - return QRect(r.left, r.top, r.right - r.left, r.bottom - r.top); -} - -QVector<QRect> QRegion::rects() const -{ - if (d->rgn == 0) - return QVector<QRect>(); - - int numBytes = GetRegionData(d->rgn, 0, 0); + int numBytes = GetRegionData(rgn, 0, 0); if (numBytes == 0) - return QVector<QRect>(); + return QRegion(); char *buf = new char[numBytes]; if (buf == 0) - return QVector<QRect>(); + return QRegion(); RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf); - if (GetRegionData(d->rgn, numBytes, rd) == 0) { + if (GetRegionData(rgn, numBytes, rd) == 0) { delete [] buf; - return QVector<QRect>(); + return QRegion(); } - QVector<QRect> a(rd->rdh.nCount); + QRegion region; RECT *r = reinterpret_cast<RECT*>(rd->Buffer); - for (int i = 0; i < a.size(); ++i) { - a[i].setCoords(r->left, r->top, r->right - 1, r->bottom - 1); + for (int i = 0; i < rd->rdh.nCount; ++i) { + QRect rect; + rect.setCoords(r->left, r->top, r->right - 1, r->bottom - 1); ++r; + region |= rect; } delete [] buf; - return a; -} - -void QRegion::setRects(const QRect *rects, int num) -{ - *this = QRegion(); - if (!rects || num == 0 || (num == 1 && rects->isEmpty())) - return; - for (int i = 0; i < num; ++i) - *this |= rects[i]; -} - -int QRegion::numRects() const -{ - if (d->rgn == 0) - return 0; - - const int numBytes = GetRegionData(d->rgn, 0, 0); - if (numBytes == 0) - return 0; - - char *buf = new char[numBytes]; - if (buf == 0) - return 0; - - RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf); - if (GetRegionData(d->rgn, numBytes, rd) == 0) { - delete[] buf; - return 0; - } - - const int n = rd->rdh.nCount; - delete[] buf; - return n; + return region; } -bool QRegion::operator==(const QRegion &r) const +void qt_win_dispose_rgn(HRGN r) { - if (d == r.d) - return true; - if ((d->rgn == 0) ^ (r.d->rgn == 0)) // one is empty, not both - return false; - return d->rgn == 0 ? true // both empty - : EqualRgn(d->rgn, r.d->rgn); // both non-empty + if (r) + DeleteObject(r); } -QRegion& QRegion::operator+=(const QRegion &r) +static void qt_add_rect(HRGN &winRegion, QRect r) { - if (!r.d->rgn) - return *this; - - if (!d->rgn) { - *this = r; - return *this; + HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height()); + if (rgn) { + HRGN dest = CreateRectRgn(0,0,0,0); + int result = CombineRgn(dest, winRegion, rgn, RGN_OR); + if (result) { + DeleteObject(winRegion); + winRegion = dest; + } + DeleteObject(rgn); } - - detach(); - - int result; - result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_OR); - if (result == NULLREGION || result == ERROR) - *this = QRegion(); - - return *this; -} - -QRegion& QRegion::operator-=(const QRegion &r) -{ - if (!r.d->rgn || !d->rgn) - return *this; - - detach(); - - int result; - result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_DIFF); - if (result == NULLREGION || result == ERROR) - *this = QRegion(); - - return *this; } -QRegion& QRegion::operator&=(const QRegion &r) +void QRegion::ensureHandle() const { - if (!d->rgn) - return *this; - - if (!r.d->rgn) { - *this = QRegion(); - return *this; + if (d->rgn) + DeleteObject(d->rgn); + d->rgn = CreateRectRgn(0,0,0,0); + if (d->qt_rgn) { + if (d->qt_rgn->numRects == 1) { + QRect r = d->qt_rgn->extents; + qt_add_rect(d->rgn, r); + return; + } + for (int i = 0;i < d->qt_rgn->numRects;i++) { + QRect r = d->qt_rgn->rects.at(i); + qt_add_rect(d->rgn, r); + } } - - detach(); - - int result; - result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_AND); - if (result == NULLREGION || result == ERROR) - *this = QRegion(); - - return *this; -} - -bool qt_region_strictContains(const QRegion ®ion, const QRect &rect) -{ - Q_UNUSED(region); - Q_UNUSED(rect); - return false; } -void QRegion::ensureHandle() const -{ -} QT_END_NAMESPACE diff --git a/src/gui/painting/qwindowsurface_x11.cpp b/src/gui/painting/qwindowsurface_x11.cpp index d8b0d9e..95f6ce3 100644 --- a/src/gui/painting/qwindowsurface_x11.cpp +++ b/src/gui/painting/qwindowsurface_x11.cpp @@ -154,7 +154,7 @@ void QX11WindowSurface::setGeometry(const QRect &rect) QX11PixmapData *oldData = static_cast<QX11PixmapData *>(d_ptr->device.pixmapData()); Q_ASSERT(oldData); - if (!oldData->uninit && hasStaticContents()) { + if (!(oldData->flags & QX11PixmapData::Uninitialized) && hasStaticContents()) { // Copy the content of the old pixmap into the new one. QX11PixmapData *newData = new QX11PixmapData(QPixmapData::PixmapType); newData->resize(size.width(), size.height()); @@ -175,7 +175,7 @@ void QX11WindowSurface::setGeometry(const QRect &rect) dx, dy, qMin(boundingRect.width(), size.width()), qMin(boundingRect.height(), size.height()), dx, dy); XFreeGC(X11->display, tmpGc); - newData->uninit = false; + newData->flags &= ~QX11PixmapData::Uninitialized; d_ptr->device = QPixmap(newData); } else { diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp index 9560c4b..ad87354 100644 --- a/src/gui/styles/qwindowsxpstyle.cpp +++ b/src/gui/styles/qwindowsxpstyle.cpp @@ -134,6 +134,7 @@ static const int windowsRightBorder = 12; // right border on windows // External function calls extern Q_GUI_EXPORT HDC qt_win_display_dc(); +extern QRegion qt_region_from_HRGN(HRGN rgn); @@ -445,6 +446,7 @@ bool QWindowsXPStylePrivate::isTransparent(XPThemeData &themeData) themeData.stateId); } + /*! \internal Returns a QRegion of the region of the part */ @@ -456,12 +458,18 @@ QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData) themeData.stateId, &rect, &hRgn))) return QRegion(); - QRegion rgn = QRegion(0,0,1,1); - const bool success = CombineRgn(rgn.handle(), hRgn, 0, RGN_COPY) != ERROR; - DeleteObject(hRgn); + HRGN dest = CreateRectRgn(0, 0, 0, 0); + const bool success = CombineRgn(dest, hRgn, 0, RGN_COPY) != ERROR; + + QRegion region; + if (success) - return rgn; - return QRegion(); + region = qt_region_from_HRGN(dest); + + DeleteObject(hRgn); + DeleteObject(dest); + + return region; } /*! \internal diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index f6bfcbe..48d09ce 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -86,6 +86,7 @@ #include <private/qpixmapdata_gl_p.h> #include <private/qglpixelbuffer_p.h> #include <private/qwindowsurface_gl_p.h> +#include <private/qimagepixmapcleanuphooks_p.h> #include "qcolormap.h" #include "qfile.h" #include "qlibrary.h" @@ -1407,15 +1408,17 @@ QGLTextureCache::QGLTextureCache() { Q_ASSERT(qt_gl_texture_cache == 0); qt_gl_texture_cache = this; - qt_pixmap_cleanup_hook_64 = cleanupHook; - qt_image_cleanup_hook_64 = cleanupHook; + + QImagePixmapCleanupHooks::instance()->addPixmapHook(pixmapCleanupHook); + QImagePixmapCleanupHooks::instance()->addImageHook(imageCleanupHook); } QGLTextureCache::~QGLTextureCache() { qt_gl_texture_cache = 0; - qt_pixmap_cleanup_hook_64 = 0; - qt_image_cleanup_hook_64 = 0; + + QImagePixmapCleanupHooks::instance()->removePixmapHook(pixmapCleanupHook); + QImagePixmapCleanupHooks::instance()->removeImageHook(imageCleanupHook); } void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost) @@ -1471,7 +1474,7 @@ QGLTextureCache* QGLTextureCache::instance() a hook that removes textures from the cache when a pixmap/image is deref'ed */ -void QGLTextureCache::cleanupHook(qint64 cacheKey) +void QGLTextureCache::imageCleanupHook(qint64 cacheKey) { // ### remove when the GL texture cache becomes thread-safe if (qApp->thread() != QThread::currentThread()) @@ -1481,6 +1484,24 @@ void QGLTextureCache::cleanupHook(qint64 cacheKey) instance()->remove(cacheKey); } + +void QGLTextureCache::pixmapCleanupHook(QPixmap* pixmap) +{ + // ### remove when the GL texture cache becomes thread-safe + if (qApp->thread() == QThread::currentThread()) { + const qint64 cacheKey = pixmap->cacheKey(); + QGLTexture *texture = instance()->getTexture(cacheKey); + if (texture && texture->clean) + instance()->remove(cacheKey); + } +#if defined(Q_WS_X11) + QPixmapData *pd = pixmap->data_ptr(); + // Only need to delete the gl surface if the pixmap is about to be deleted + if (pd->ref == 0) + QGLContextPrivate::destroyGlSurfaceForPixmap(pd); +#endif +} + void QGLTextureCache::deleteIfEmpty() { if (instance()->size() == 0) @@ -2021,11 +2042,11 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, #if defined(Q_WS_X11) // Try to use texture_from_pixmap if (pd->classId() == QPixmapData::X11Class) { - QPixmap *thatPixmap = const_cast<QPixmap*>(&pixmap); - texture = bindTextureFromNativePixmap(thatPixmap, key, canInvert); + texture = bindTextureFromNativePixmap(pd, key, canInvert); if (texture) { texture->clean = clean; - boundPixmaps.insert(thatPixmap->data_ptr(), QPixmap(pixmap)); + texture->boundPixmap = pd; + boundPixmaps.insert(pd, QPixmap(pixmap)); } } #endif diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 85dae0d..f21ab93 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -241,7 +241,9 @@ public: quint32 gpm; int screen; QHash<QPixmapData*, QPixmap> boundPixmaps; - QGLTexture *bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool internal); + QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key, bool canInvert); + static void destroyGlSurfaceForPixmap(QPixmapData*); + static void unbindPixmapFromTexture(QPixmapData*); #endif #if defined(Q_WS_MAC) bool update; @@ -423,7 +425,8 @@ public: // is a current context - the context the pixmap was bound to a texture in. // Otherwise the release doesn't do anything and you get BadDrawable errors // when you come to delete the context. - deleteBoundPixmap(); + if (boundPixmap) + QGLContextPrivate::unbindPixmapFromTexture(boundPixmap); #endif glDeleteTextures(1, &id); if (switch_context && current) @@ -437,9 +440,9 @@ public: bool clean; bool yInverted; // NOTE: Y-Inverted textures are for internal use only! #if defined(Q_WS_X11) - Qt::HANDLE boundPixmap; - void deleteBoundPixmap(); // in qgl_x11.cpp/qgl_x11egl.cpp + QPixmapData* boundPixmap; #endif + }; class QGLTextureCache { @@ -458,7 +461,8 @@ public: static QGLTextureCache *instance(); static void deleteIfEmpty(); - static void cleanupHook(qint64 cacheKey); + static void imageCleanupHook(qint64 cacheKey); + static void pixmapCleanupHook(QPixmap* pixmap); private: QCache<qint64, QGLTexture> m_cache; diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index cf70991..4509a64 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -58,11 +58,16 @@ #include <private/qglpixelbuffer_p.h> #endif +// We always define GLX_EXT_texture_from_pixmap ourselves because +// we can't trust system headers to do it properly +#define GLX_EXT_texture_from_pixmap 1 + #define INT8 dummy_INT8 #define INT32 dummy_INT32 #include <GL/glx.h> #undef INT8 #undef INT32 + #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xos.h> @@ -90,7 +95,7 @@ extern const QX11Info *qt_x11Info(const QPaintDevice *pd); #define GLX_SAMPLES_ARB 100001 #endif -#ifndef GLX_EXT_texture_from_pixmap +#ifndef GLX_TEXTURE_2D_BIT_EXT #define GLX_TEXTURE_2D_BIT_EXT 0x00000002 #define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004 #define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0 @@ -1548,38 +1553,26 @@ void QGLExtensions::init() } } -#if !defined(glXBindTexImageEXT) +// Solaris defines glXBindTexImageEXT as part of the GL library +#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) typedef void (*qt_glXBindTexImageEXT)(Display*, GLXDrawable, int, const int*); -static qt_glXBindTexImageEXT glXBindTexImageEXT = 0; -#endif -#if !defined(glXReleaseTexImageEXT) typedef void (*qt_glXReleaseTexImageEXT)(Display*, GLXDrawable, int); +static qt_glXBindTexImageEXT glXBindTexImageEXT = 0; static qt_glXReleaseTexImageEXT glXReleaseTexImageEXT = 0; -#endif -static bool qt_resolved_texture_from_pixmap = false; -QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool canInvert) +bool qt_resolveTextureFromPixmap() { -#if !defined(Q_OS_LINUX) - return 0; -#else - Q_Q(QGLContext); - - if (pm->data_ptr()->classId() != QPixmapData::X11Class) - return 0; - QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pm->data_ptr()); - const QX11Info *x11Info = qt_x11Info(pm); + static bool resolvedTextureFromPixmap = false; + if (!resolvedTextureFromPixmap) { + resolvedTextureFromPixmap = true; - // Check to see if we have NPOT texture support - // TODO: Use GLX_TEXTURE_RECTANGLE_EXT texture target on systems without npot textures - if ( !(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) && - !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)) - return 0; - - - if (!qt_resolved_texture_from_pixmap) { - qt_resolved_texture_from_pixmap = true; + // Check to see if we have NPOT texture support + if ( !(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) && + !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)) + { + return false; // Can't use TFP without NPOT + } QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); if (glxExt.contains(QLatin1String("GLX_EXT_texture_from_pixmap"))) { @@ -1601,81 +1594,139 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qi } } - if (!glXBindTexImageEXT) - return 0; + return glXBindTexImageEXT && glXReleaseTexImageEXT; +} +#endif //defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) + +QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, const qint64 key, bool canInvert) +{ #if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX) return 0; #else - GLXFBConfig *configList = 0; - GLXFBConfig glxPixmapConfig; - int configCount = 0; - bool hasAlpha = pixmapData->hasAlphaChannel(); - - int configAttribs[] = { - hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True, - GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, - GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, - // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can: - GLX_Y_INVERTED_EXT, canInvert ? GLX_DONT_CARE : False, - XNone -// GLX_BIND_TO_MIPMAP_TEXTURE_EXT, False, -// GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_1D_BIT_EXT or GLX_TEXTURE_2D_BIT_EXT or GLX_TEXTURE_RECTANGLE_BIT_EXT - }; - configList = glXChooseFBConfig(x11Info->display(), x11Info->screen(), configAttribs, &configCount); - if (!configList) - return 0; - glxPixmapConfig = configList[0]; - XFree(configList); - - GLXPixmap glxPixmap; - int pixmapAttribs[] = { - GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT, - GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, - GLX_MIPMAP_TEXTURE_EXT, False, - XNone -// GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT or GLX_TEXTURE_FORMAT_RGB_EXT or GLX_TEXTURE_FORMAT_NONE_EXT, -// GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT or GLX_TEXTURE_RECTANGLE_EXT, -// GLX_MIPMAP_TEXTURE_EXT, True or False, - }; + Q_Q(QGLContext); - // Wrap the X Pixmap into a GLXPixmap: - glxPixmap = glXCreatePixmap(x11Info->display(), glxPixmapConfig, pixmapData->handle(), pixmapAttribs); + Q_ASSERT(pmd->classId() == QPixmapData::X11Class); - if (!glxPixmap) + if (!qt_resolveTextureFromPixmap()) return 0; - int yInverted; - glXGetFBConfigAttrib(x11Info->display(), glxPixmapConfig, GLX_Y_INVERTED_EXT, &yInverted); + QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd); + const QX11Info &x11Info = pixmapData->xinfo; + + // Store the configs (Can be static because configs aren't dependent on current context) + static GLXFBConfig glxRGBPixmapConfig = 0; + static bool RGBConfigInverted = false; + static GLXFBConfig glxRGBAPixmapConfig = 0; + static bool RGBAConfigInverted = false; + + bool hasAlpha = pixmapData->hasAlphaChannel(); + + // Check to see if we need a config + if ( (hasAlpha && !glxRGBAPixmapConfig) || (!hasAlpha && !glxRGBPixmapConfig) ) { + GLXFBConfig *configList = 0; + int configCount = 0; + + int configAttribs[] = { + hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True, + GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, + GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, + // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can: + GLX_Y_INVERTED_EXT, canInvert ? GLX_DONT_CARE : False, + XNone + }; + configList = glXChooseFBConfig(x11Info.display(), x11Info.screen(), configAttribs, &configCount); + if (!configList) + return 0; + + int yInv; + glXGetFBConfigAttrib(x11Info.display(), configList[0], GLX_Y_INVERTED_EXT, &yInv); + + if (hasAlpha) { + glxRGBAPixmapConfig = configList[0]; + RGBAConfigInverted = yInv; + } + else { + glxRGBPixmapConfig = configList[0]; + RGBConfigInverted = yInv; + } + + XFree(configList); + } + + // Check to see if the surface is still valid + if (pixmapData->gl_surface && + hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) + { + // Surface is invalid! + destroyGlSurfaceForPixmap(pixmapData); + } + + // Check to see if we need a surface + if (!pixmapData->gl_surface) { + GLXPixmap glxPixmap; + int pixmapAttribs[] = { + GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT, + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + GLX_MIPMAP_TEXTURE_EXT, False, // Maybe needs to be don't care + XNone + }; + + // Wrap the X Pixmap into a GLXPixmap: + glxPixmap = glXCreatePixmap(x11Info.display(), + hasAlpha ? glxRGBAPixmapConfig : glxRGBPixmapConfig, + pixmapData->handle(), pixmapAttribs); + + if (!glxPixmap) + return 0; + + pixmapData->gl_surface = (Qt::HANDLE)glxPixmap; + + // Make sure the cleanup hook gets called so we can delete the glx pixmap + pixmapData->is_cached = true; + } GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); - glXBindTexImageEXT(x11Info->display(), glxPixmap, GLX_FRONT_LEFT_EXT, 0); + glXBindTexImageEXT(x11Info.display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT, 0); glBindTexture(GL_TEXTURE_2D, textureId); - QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, yInverted); - texture->boundPixmap = glxPixmap; + QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, false); + texture->yInverted = (hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted); + if (texture->yInverted) + pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture; // We assume the cost of bound pixmaps is zero QGLTextureCache::instance()->insert(q, key, texture, 0); return texture; #endif //!defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX) -#endif //!defined(Q_OS_LINUX } -void QGLTexture::deleteBoundPixmap() + +void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd) { -#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) && defined(Q_OS_LINUX) - if (boundPixmap) { - glXReleaseTexImageEXT(QX11Info::display(), boundPixmap, GLX_FRONT_LEFT_EXT); - glXDestroyPixmap(QX11Info::display(), boundPixmap); - boundPixmap = 0; +#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) + Q_ASSERT(pmd->classId() == QPixmapData::X11Class); + QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd); + if (pixmapData->gl_surface) { + glXDestroyPixmap(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface); + pixmapData->gl_surface = 0; } #endif } +void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd) +{ +#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) + Q_ASSERT(pmd->classId() == QPixmapData::X11Class); + Q_ASSERT(QGLContext::currentContext()); + QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd); + if (pixmapData->gl_surface) + glXReleaseTexImageEXT(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT); +#endif +} QT_END_NAMESPACE diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index c6904fe..5ab3647 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -41,15 +41,16 @@ #include "qgl.h" #include <private/qt_x11_p.h> +#include <private/qpixmap_x11_p.h> #include <private/qgl_p.h> #include <private/qpaintengine_opengl_p.h> #include "qgl_egl_p.h" #include "qcolormap.h" +#include <QDebug> QT_BEGIN_NAMESPACE - bool QGLFormat::hasOpenGL() { return true; @@ -486,15 +487,175 @@ void QGLWidgetPrivate::recreateEglSurface(bool force) } } -QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool canInvert) + +QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key, bool canInvert) { - // TODO - return 0; + Q_Q(QGLContext); + + Q_ASSERT(pd->classId() == QPixmapData::X11Class); + + static bool checkedForTFP = false; + static bool haveTFP = false; + + if (!checkedForTFP) { + // Check for texture_from_pixmap egl extension + checkedForTFP = true; + if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") || + eglContext->hasExtension("EGL_EXT_texture_from_pixmap")) + { + qDebug("Found texture_from_pixmap EGL extension!"); + haveTFP = true; + } + } + + if (!haveTFP) + return 0; + + QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd); + + bool hasAlpha = pixmapData->hasAlphaChannel(); + + // Check to see if the surface is still valid + if (pixmapData->gl_surface && + hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) + { + // Surface is invalid! + destroyGlSurfaceForPixmap(pixmapData); + } + + EGLint pixmapAttribs[] = { + EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, + EGL_TEXTURE_FORMAT, hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB, + EGL_NONE + }; + Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure! + if (pixmapData->gl_surface == 0) + pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE; + EGLSurface pixmapSurface = (EGLSurface)pixmapData->gl_surface; + static EGLConfig pixmapRGBConfig = 0; + static EGLConfig pixmapRGBAConfig = 0; + + // Check to see if we need to find a config + if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) { + const EGLint configAttribs[] = { + EGL_SURFACE_TYPE, EGL_PIXMAP_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_DEPTH_SIZE, 0, + hasAlpha ? EGL_BIND_TO_TEXTURE_RGBA : EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE, + EGL_NONE + }; + + EGLint configCount = 0; + eglChooseConfig(eglContext->display(), configAttribs, 0, 256, &configCount); + if (configCount == 0) { + haveTFP = false; + qWarning("bindTextureFromNativePixmap() - Couldn't find a suitable config"); + return 0; + } + + EGLConfig *configList = new EGLConfig[configCount]; + eglChooseConfig(eglContext->display(), configAttribs, configList, configCount, &configCount); + Q_ASSERT(configCount); + + // Try to create a pixmap surface for each config until one works + for (int i = 0; i < configCount; ++i) { + pixmapSurface = eglCreatePixmapSurface(eglContext->display(), configList[i], + (EGLNativePixmapType) pixmapData->handle(), + pixmapAttribs); + if (pixmapSurface != EGL_NO_SURFACE) { + // Got one! + qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") + << "config (" << int(configList[i]) << ") to create a pixmap surface"; + if (hasAlpha) + pixmapRGBAConfig = configList[i]; + else + pixmapRGBConfig = configList[i]; + pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface; + break; + } + } + delete configList; + + if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) { + qDebug("Couldn't create a pixmap surface with any of the provided configs"); + haveTFP = false; + return 0; + } + } + + if (pixmapSurface == EGL_NO_SURFACE) { + pixmapSurface = eglCreatePixmapSurface(eglContext->display(), + hasAlpha? pixmapRGBAConfig : pixmapRGBConfig, + (EGLNativePixmapType) pixmapData->handle(), + pixmapAttribs); + if (pixmapSurface == EGL_NO_SURFACE) { + qWarning("Failed to create a pixmap surface using config %d", + (int)(hasAlpha? pixmapRGBAConfig : pixmapRGBConfig)); + haveTFP = false; + return 0; + } + pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface; + } + + // Make sure the cleanup hook gets called so we can delete the glx pixmap + pixmapData->is_cached = true; + Q_ASSERT(pixmapData->gl_surface); + + GLuint textureId; + glGenTextures(1, &textureId); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, textureId); + + // bind the egl pixmap surface to a texture + EGLBoolean success; + success = eglBindTexImage(eglContext->display(), pixmapSurface, EGL_BACK_BUFFER); + if (success == EGL_FALSE) { + qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError()); + eglDestroySurface(eglContext->display(), pixmapSurface); + pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE; + haveTFP = false; + return 0; + } + + QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, true); + pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture; + + // We assume the cost of bound pixmaps is zero + QGLTextureCache::instance()->insert(q, key, texture, 0); + + glBindTexture(GL_TEXTURE_2D, textureId); + return texture; } -void QGLTexture::deleteBoundPixmap() +void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd) { - //TODO + Q_ASSERT(pmd->classId() == QPixmapData::X11Class); + QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd); + if (pixmapData->gl_surface) { + EGLBoolean success; + success = eglDestroySurface(QEglContext::defaultDisplay(0), (EGLSurface)pixmapData->gl_surface); + if (success == EGL_FALSE) { + qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: " + << QEglContext::errorString(eglGetError()); + } + pixmapData->gl_surface = 0; + } +} + +void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd) +{ + Q_ASSERT(pmd->classId() == QPixmapData::X11Class); + QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd); + if (pixmapData->gl_surface) { + EGLBoolean success; + success = eglReleaseTexImage(QEglContext::defaultDisplay(0), + (EGLSurface)pixmapData->gl_surface, + EGL_BACK_BUFFER); + if (success == EGL_FALSE) { + qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: " + << QEglContext::errorString(eglGetError()); + } + } } QT_END_NAMESPACE diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index b264ac0..2ed890b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -53,6 +53,7 @@ #include <qmath.h> #include <private/qpixmapdata_p.h> #include <private/qpixmap_raster_p.h> +#include <private/qimagepixmapcleanuphooks_p.h> class SurfaceCache; class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate @@ -699,9 +700,7 @@ void QDirectFBPaintEngine::initImageCache(int size) { Q_ASSERT(size >= 0); imageCache.setMaxCost(size); - typedef void (*_qt_image_cleanup_hook_64)(qint64); - extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64; - qt_image_cleanup_hook_64 = ::cachedImageCleanupHook; + QImagePixmapCleanupHooks::instance()->addImageHook(cachedImageCleanupHook); } #endif // QT_DIRECTFB_IMAGECACHE diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 797595f..0ba7d53 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -429,7 +429,7 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) { def->isVirtual = false; //skip modifiers and attributes - while (test(INLINE) || test(STATIC) || + while (test(EXPLICIT) || test(INLINE) || test(STATIC) || (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual || testFunctionAttribute(def)) {} bool tilde = test(TILDE); diff --git a/tests/auto/moc/tst_moc.cpp b/tests/auto/moc/tst_moc.cpp index d66791f..488f068 100644 --- a/tests/auto/moc/tst_moc.cpp +++ b/tests/auto/moc/tst_moc.cpp @@ -1157,6 +1157,13 @@ void tst_Moc::constructors() QObject *o3 = mo->newInstance(Q_ARG(QString, str)); QVERIFY(o3 != 0); QCOMPARE(qobject_cast<CtorTestClass*>(o3)->m_str, str); + + { + //explicit constructor + QObject *o = QObject::staticMetaObject.newInstance(); + QVERIFY(o); + delete o; + } } #include "task234909.h" |