From dc789e34bd2ff519024af077bebdf09c85e138e0 Mon Sep 17 00:00:00 2001 From: Trond Kjernaasen Date: Mon, 2 Mar 2009 13:17:40 +0100 Subject: Fixes: Crash in QPixmap under X11. Task: 246446 RevBy: Olivier AutoTest: tst_qpixmap::test_246446() Details: The new QX11PixmapData object wasn't referenced (e.g. the ref count would be 0) after calling setMask() on a 32 bit QPixmap when Xrender was used. --- src/gui/image/qpixmap_x11.cpp | 6 ++++++ src/gui/image/qpixmapdata_p.h | 1 + tests/auto/qpixmap/tst_qpixmap.cpp | 16 ++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp index d758221..ff7c1b6 100644 --- a/src/gui/image/qpixmap_x11.cpp +++ b/src/gui/image/qpixmap_x11.cpp @@ -1288,6 +1288,12 @@ void QX11PixmapData::setMask(const QBitmap &newmask) 0, 0, 0, 0, 0, 0, w, h); release(); *this = newData; + // the new QX11PixmapData object isn't referenced yet, so + // ref it + ref.ref(); + + // the below is to make sure the QX11PixmapData destructor + // doesn't delete our newly created render picture newData.hd = 0; newData.x11_mask = 0; newData.picture = 0; diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h index 2e4da40..7296426 100644 --- a/src/gui/image/qpixmapdata_p.h +++ b/src/gui/image/qpixmapdata_p.h @@ -109,6 +109,7 @@ protected: private: friend class QPixmap; friend class QGLContextPrivate; + friend class QX11PixmapData; QAtomicInt ref; int detach_no; diff --git a/tests/auto/qpixmap/tst_qpixmap.cpp b/tests/auto/qpixmap/tst_qpixmap.cpp index 2b337da..ba117d8 100644 --- a/tests/auto/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/qpixmap/tst_qpixmap.cpp @@ -103,6 +103,7 @@ private slots: void grabWidget(); void grabWindow(); void isNull(); + void task_246446(); #ifdef Q_WS_QWS void convertFromImageNoDetach(); @@ -1015,5 +1016,20 @@ void tst_QPixmap::fromData() QCOMPARE(img.pixel(0, 1), QRgb(0xff000000)); } +void tst_QPixmap::task_246446() +{ + // This crashed without the bugfix in 246446 + QPixmap pm(10, 10); + pm.fill(Qt::transparent); // force 32-bit depth + QBitmap bm; + pm.setMask(bm); + { + QPixmap pm2(pm); + } + QVERIFY(pm.width() == 10); + QVERIFY(pm.mask().isNull()); +} + + QTEST_MAIN(tst_QPixmap) #include "tst_qpixmap.moc" -- cgit v0.12 From 629548a4513f1c2892c781224fcc2a451e032df3 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 24 Mar 2009 11:38:27 +1000 Subject: Fixes compile on win32 with MinGW. Reviewed-by: Lorn Potter --- src/gui/painting/qregion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index f728f9d..8169ef8 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qregion.h" +#include "qpainterpath.h" #include "qpolygon.h" #include "qbuffer.h" #include "qdatastream.h" @@ -49,7 +50,6 @@ #include #if defined(Q_OS_UNIX) || defined(Q_OS_WINCE) -#include "qpainterpath.h" #include "qimage.h" #include "qbitmap.h" #include -- cgit v0.12 From 8d9b0179a56f4ee5afc3ac6300d6bd97089eff96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 24 Mar 2009 10:01:22 +0100 Subject: Rendering error (one pixel offset) when drawing ARGB32_PM on RGB16. Missing increments in the blend function's tail code. Task-number: 247492 Reviewed-by: Paul --- src/gui/painting/qblendfunctions.cpp | 2 + tests/auto/qpainter/tst_qpainter.cpp | 74 ++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index d2f4ab7..6589439 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -535,6 +535,8 @@ static void qt_blend_argb32_on_rgb16(uchar *destPixels, int dbpl, s += BYTE_MUL_RGB16(*dst, 255 - alpha); *dst = s; } + ++dst; + ++src; } dst += dstExtraStride; src += srcExtraStride; diff --git a/tests/auto/qpainter/tst_qpainter.cpp b/tests/auto/qpainter/tst_qpainter.cpp index 5a15683..2e1335c 100644 --- a/tests/auto/qpainter/tst_qpainter.cpp +++ b/tests/auto/qpainter/tst_qpainter.cpp @@ -204,6 +204,9 @@ private slots: void drawImage_task217400(); void drawRect_task215378(); + void drawImage_data(); + void drawImage(); + void clippedImage(); void stateResetBetweenQPainters(); @@ -3586,6 +3589,77 @@ void tst_QPainter::drawRect_task215378() QVERIFY(img.pixel(0, 0) != img.pixel(1, 1)); } +void tst_QPainter::drawImage_data() +{ + QTest::addColumn("x"); + QTest::addColumn("y"); + QTest::addColumn("w"); + QTest::addColumn("h"); + QTest::addColumn("srcFormat"); + QTest::addColumn("dstFormat"); + + for (int srcFormat = QImage::Format_Mono; srcFormat < QImage::NImageFormats; ++srcFormat) { + for (int dstFormat = QImage::Format_Mono; dstFormat < QImage::NImageFormats; ++dstFormat) { + if (dstFormat == QImage::Format_Indexed8) + continue; + for (int odd_x = 0; odd_x <= 1; ++odd_x) { + for (int odd_width = 0; odd_width <= 1; ++odd_width) { + QString description = + QString("srcFormat %1, dstFormat %2, odd x: %3, odd width: %4") + .arg(srcFormat).arg(dstFormat).arg(odd_x).arg(odd_width); + + QTest::newRow(description) << (10 + odd_x) << 10 << (20 + odd_width) << 20 + << QImage::Format(srcFormat) + << QImage::Format(dstFormat); + } + } + } + } +} + +bool verifyImage(const QImage &img, int x, int y, int w, int h, uint background) +{ + int imgWidth = img.width(); + int imgHeight = img.height(); + for (int i = 0; i < imgHeight; ++i) { + for (int j = 0; j < imgWidth; ++j) { + uint pixel = img.pixel(j, i); + bool outside = j < x || j >= (x + w) || i < y || i >= (y + h); + if (outside != (pixel == background)) { + //printf("%d %d, expected %x, got %x, outside: %d\n", x, y, background, pixel, outside); + return false; + } + } + } + + return true; +} + +void tst_QPainter::drawImage() +{ + QFETCH(int, x); + QFETCH(int, y); + QFETCH(int, w); + QFETCH(int, h); + QFETCH(QImage::Format, srcFormat); + QFETCH(QImage::Format, dstFormat); + + QImage dst(40, 40, QImage::Format_RGB32); + dst.fill(0xffffffff); + + dst = dst.convertToFormat(dstFormat); + uint background = dst.pixel(0, 0); + + QImage src(w, h, QImage::Format_RGB32); + src.fill(0xff000000); + src = src.convertToFormat(srcFormat); + + QPainter p(&dst); + p.drawImage(x, y, src); + p.end(); + + QVERIFY(verifyImage(dst, x, y, w, h, background)); +} void tst_QPainter::imageCoordinateLimit() { -- cgit v0.12 From 4fe23655d3fbf141e3a2c0406c7d1a929166c30f Mon Sep 17 00:00:00 2001 From: Trenton Schulz Date: Tue, 24 Mar 2009 10:11:29 +0100 Subject: Compile in Snow Leopard GCC 4.2 needs to have this extern (and likely every compiler != gcc 4. Reviewed-by: Trust Me --- src/gui/widgets/qcocoamenu_mac.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/widgets/qcocoamenu_mac.mm b/src/gui/widgets/qcocoamenu_mac.mm index c5977e4..c92dfc0 100644 --- a/src/gui/widgets/qcocoamenu_mac.mm +++ b/src/gui/widgets/qcocoamenu_mac.mm @@ -56,6 +56,10 @@ QT_FORWARD_DECLARE_CLASS(QAction) QT_FORWARD_DECLARE_CLASS(QWidget) QT_FORWARD_DECLARE_CLASS(QApplication) +QT_BEGIN_NAMESPACE +extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); //qapplication.cpp +QT_END_NAMESPACE + @implementation QT_MANGLE_NAMESPACE(QCocoaMenu) - (id)initWithQMenu:(QMenu*)menu -- cgit v0.12 From e773b0486a4784994a900c03a2620baf2775ac9d Mon Sep 17 00:00:00 2001 From: Norwegian Rock Cat Date: Tue, 24 Mar 2009 10:32:49 +0100 Subject: Handle monochrome CGColors as well. It seems that snow leopard is storing some colors as grayscale. This means that we need to handle them or otherwise things go very black. It's an easy case to do as well, so just do it. Reviewed-by: Bradley T. Hughes --- src/gui/kernel/qt_mac.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/kernel/qt_mac.cpp b/src/gui/kernel/qt_mac.cpp index b462b13..4703475 100644 --- a/src/gui/kernel/qt_mac.cpp +++ b/src/gui/kernel/qt_mac.cpp @@ -93,6 +93,8 @@ static QColor qcolorFromCGColor(CGColorRef cgcolor) pc.setRgbF(components[0], components[1], components[2], components[3]); } else if (model == kCGColorSpaceModelCMYK) { pc.setCmykF(components[0], components[1], components[2], components[3]); + } else if (model == kCGColorSpaceModelMonochrome) { + pc.setRgbF(components[0], components[0], components[0], components[1]); } else { // Colorspace we can't deal with. qWarning("Qt: qcolorFromCGColor: cannot convert from colorspace model: %d", model); -- cgit v0.12 From 22d472c17167c4ca8df5678842768ab63b7baadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Tue, 24 Mar 2009 10:39:52 +0100 Subject: Do not cache the sizeHint() while we're in QGraphicsWidget's constructor. Do not send a QFontChange event before the item has been polished. This is because we cannot call a virtual function while we're in the ctor. This is basically the same as how we do it in QWidget. Task-number: 246215 Reviewed-by: alexis --- src/gui/graphicsview/qgraphicswidget.cpp | 2 + src/gui/graphicsview/qgraphicswidget_p.cpp | 2 + src/gui/graphicsview/qgraphicswidget_p.h | 2 + tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp | 64 ++++++++++++---------- 4 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 5cc18f9..64ec0e7 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -1269,6 +1269,8 @@ bool QGraphicsWidget::event(QEvent *event) break; case QEvent::Polish: polishEvent(); + d->polished = true; + d->updateFont(d->font); break; case QEvent::WindowActivate: case QEvent::WindowDeactivate: diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp index 641409d..789f8da 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.cpp +++ b/src/gui/graphicsview/qgraphicswidget_p.cpp @@ -274,6 +274,8 @@ void QGraphicsWidgetPrivate::updateFont(const QFont &font) } } + if (!polished) + return; // Notify change. QEvent event(QEvent::FontChange); QApplication::sendEvent(q, &event); diff --git a/src/gui/graphicsview/qgraphicswidget_p.h b/src/gui/graphicsview/qgraphicswidget_p.h index afa6812..455a129 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.h +++ b/src/gui/graphicsview/qgraphicswidget_p.h @@ -85,6 +85,7 @@ public: inheritedPaletteResolveMask(0), inheritedFontResolveMask(0), inSetGeometry(0), + polished(0), focusPolicy(Qt::NoFocus), focusNext(0), focusPrev(0), @@ -193,6 +194,7 @@ public: } quint32 attributes : 10; quint32 inSetGeometry : 1; + quint32 polished: 1; // Focus Qt::FocusPolicy focusPolicy; diff --git a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp index 86d1acb..f25a079 100644 --- a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp +++ b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp @@ -259,6 +259,35 @@ void tst_QGraphicsWidget::cleanup() { } +class SizeHinter : public QGraphicsWidget +{ +public: + SizeHinter(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0, + const QSizeF &min = QSizeF(5,5), + const QSizeF &pref = QSizeF(50, 50), + const QSizeF &max = QSizeF(500, 500)) + : QGraphicsWidget(parent, wFlags) + { + m_sizes[Qt::MinimumSize] = min; + m_sizes[Qt::PreferredSize] = pref; + m_sizes[Qt::MaximumSize] = max; + + } + void setSizeHint(Qt::SizeHint which, const QSizeF &newSizeHint) + { + m_sizes[which] = newSizeHint; + } + +protected: + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const + { + Q_UNUSED(constraint); + return m_sizes[which]; + } +private: + QSizeF m_sizes[4]; +}; + void tst_QGraphicsWidget::qgraphicswidget() { SubQGraphicsWidget widget; @@ -282,6 +311,12 @@ void tst_QGraphicsWidget::qgraphicswidget() QCOMPARE(widget.type(), (int)QGraphicsWidget::Type); QCOMPARE(widget.call_propertyChange(QString(), QVariant()), QVariant()); widget.call_sizeHint(Qt::PreferredSize, QSizeF()); + + QGraphicsScene scene; + QGraphicsWidget *parent = new QGraphicsWidget; + SizeHinter *child = new SizeHinter(parent); + + QCOMPARE(child->minimumSize(), QSizeF(5, 5)); } void tst_QGraphicsWidget::activation() @@ -1516,35 +1551,6 @@ enum WhichSize { None, }; -class SizeHinter : public QGraphicsWidget -{ -public: - SizeHinter(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0, - const QSizeF &min = QSizeF(5,5), - const QSizeF &pref = QSizeF(50, 50), - const QSizeF &max = QSizeF(500, 500)) - : QGraphicsWidget(parent, wFlags) - { - m_sizes[Qt::MinimumSize] = min; - m_sizes[Qt::PreferredSize] = pref; - m_sizes[Qt::MaximumSize] = max; - - } - void setSizeHint(Qt::SizeHint which, const QSizeF &newSizeHint) - { - m_sizes[which] = newSizeHint; - } - -protected: - QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const - { - Q_UNUSED(constraint); - return m_sizes[which]; - } -private: - QSizeF m_sizes[4]; -}; - typedef QPair Inst; Q_DECLARE_METATYPE(Inst) -- cgit v0.12 From 0df19648d2777c021e7bfe3031e097016a159e8e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 24 Mar 2009 12:52:16 +0100 Subject: Add documentation about how to create shared libraries. Reviewed-by: Paul Reviewed-by: Kavindra Devi Palaraja --- doc/src/deployment.qdoc | 5 +- doc/src/designer-manual.qdoc | 43 ++++++++++ doc/src/sharedlibrary.qdoc | 186 +++++++++++++++++++++++++++++++++++++++++ src/corelib/global/qglobal.cpp | 20 +++++ 4 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 doc/src/sharedlibrary.qdoc diff --git a/doc/src/deployment.qdoc b/doc/src/deployment.qdoc index d2c7a9e..7e02f1a 100644 --- a/doc/src/deployment.qdoc +++ b/doc/src/deployment.qdoc @@ -89,8 +89,9 @@ of Qt, you get Qt as a shared library. The disadvantage with the shared library approach is that you - will get more files to deploy. - + will get more files to deploy. For more information, see + \l{sharedlibrary.html}{Creating Shared Libraries}. + \section1 Deploying Qt's Libraries \table diff --git a/doc/src/designer-manual.qdoc b/doc/src/designer-manual.qdoc index 9eb43b7..46d3b3b 100644 --- a/doc/src/designer-manual.qdoc +++ b/doc/src/designer-manual.qdoc @@ -2443,6 +2443,10 @@ pixmap property in the property editor. \target BuildingandInstallingthePlugin \section1 Building and Installing the Plugin + \section2 A Simple Plugin + + The \l{Custom Widget Plugin Example} demonstrates a simple \QD plugin. + The \c{.pro} file for a plugin must specify the headers and sources for both the custom widget and the plugin interface. Typically, this file only has to specify that the plugin's project is to be built as a library, but @@ -2477,6 +2481,45 @@ pixmap property in the property editor. See QCoreApplication::libraryPaths() for more information about customizing paths for libraries and plugins with Qt applications. + \section2 Splitting up the Plugin + + In a real world scenario, you do not want to have dependencies of the + application making use of the custom widgets to the \QD headers and + libraries as introduced by the simple approach explained above. + + There are two ways to resolve this: + + \list + \i Create a \c{.pri} file that contains the headers sources and sources + of the custom widget: + + \code + INCLUDEPATH += $$PWD + HEADERS += $$PWD/analogclock.h + SOURCES += $$PWD/analogclock.cpp + \endcode + + This file would then be included by the \c{.pro} file of the plugin and + the application: + + \code + include(customwidget.pri) + \endcode + + Running \c{qmake -Wall} on the \c{.pro} files causes a warning to be + printed if an included \c{.pri} file cannot be found. + + \i Create a standalone shared library containing the custom widgets only + as described in + \l{sharedlibrary.html}{Creating Shared Libraries}. + + This library would then be used by the application as well as by the + \QD plugin. Care must be taken to ensure that the plugin can locate + the library at runtime. + \endlist + + + \omit \section1 Using Qt Script to Aid in Building Forms diff --git a/doc/src/sharedlibrary.qdoc b/doc/src/sharedlibrary.qdoc new file mode 100644 index 0000000..3febb8f --- /dev/null +++ b/doc/src/sharedlibrary.qdoc @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the documentation 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 qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt GUI Toolkit. +** EDITIONS: FREE, PROFESSIONAL, ENTERPRISE +** +****************************************************************************/ + +/*! + \group deployment + \page sharedlibrary.html + \ingroup buildsystem + + \title Creating Shared Libraries + The following sections list certain things that should be taken into + account when creating shared libraries. + + \section1 Using Symbols from Shared Libraries + + Symbols - functions, variables or classes - contained in shared libraries + intended to be used by \e{clients}, such as applications or other + libraries, must be marked in a special way. These symbols are called + \e{public symbols} that are \e{exported} or made publicly visible. + + The remaining symbols should not be visible from the outside. On most + platforms, compilers will hide them by default. On some platforms, a + special compiler option is required to hide these symbols. + + When compiling a shared library, it must be marked for \e{export}. To use + the shared library from a client, some platforms may require a special + \e{import} declaration as well. + + Depending on your target platform, Qt provides special macros that contain + the necessary definitions: + \list + \o \c{Q_DECL_EXPORT} must be added to the declarations of symbols used + when compiling a shared library. + \o \c{Q_DECL_IMPORT} must be added to the declarations of symbols used + when compiling a client that uses the shared library. + \endlist + + Now, we need to ensure that the right macro is invoked -- whether we + compile a share library itself, or just the client using the shared + library. + Typically, this can be solved by adding a special header. + + Let us assume we want to create a shared library called \e{mysharedlib}. + A special header for this library, \c{mysharedlib_global.h}, looks like + this: + + \code + #include + + #if defined(MYSHAREDLIB_LIBRARY) + # define MYSHAREDLIB_EXPORT Q_DECL_EXPORT + #else + # define MYSHAREDLIB_EXPORT Q_DECL_IMPORT + #endif + \endcode + + In the \c{.pro} file of the shared library, we add: + + \code + DEFINES += MYSHAREDLIB_LIBRARY + \endcode + + In each header of the library, we specify the following: + + \code + #include "mysharedlib_global.h" + + MYSHAREDLIB_EXPORT void foo(); + class MYSHAREDLIB_EXPORT MyClass... + \endcode + This ensures that the right macro is seen by both library and clients. We + also use this technique in Qt's sources. + + + \section1 Header File Considerations + + Typically, clients will include only the public header files of shared + libraries. These libraries might be installed in a different location, when + deployed. Therefore, it is important to exclude other internal header files + that were used when building the shared library. + + For example, the library might provide a class that wraps a hardware device + and contains a handle to that device, provided by some 3rd-party library: + + \code + #include + + class MyDevice { + private: + FOOTRONICS_DEVICE_HANDLE handle; + }; + \endcode + + A similar situation arises with forms created by Qt Designer when using + aggregation or multiple inheritance: + + \code + #include "ui_widget.h" + + class MyWidget : public QWidget { + private: + Ui::MyWidget m_ui; + }; + \endcode + + When deploying the library, there should be no dependency to the internal + headers \c{footronics/device.h} or \c{ui_widget.h}. + + This can be avoided by making use of the \e{Pointer to implementation} + idiom described in various C++ programming books. For classes with + \e{value semantics}, consider using QSharedDataPointer. + + + \section1 Binary compatibility + + For clients loading a shared library, to work correctly, the memory + layout of the classes being used must match exactly the memory layout of + the library version that was used to compile the client. In other words, + the library found by the client at runtime must be \e{binary compatible} + with the version used at compile time. + + This is usually not a problem if the client is a self-contained software + package that ships all the libraries it needs. + + However, if the client application relies on a shared library that belongs + to a different installation package or to the operating system, then we + need to think of a versioning scheme for shared libraries and decide at + which level \e{Binary compatibility} is to be maintained. For example, Qt + libraries of the same \e{major version number} are guaranteed to be binary + compatible. + + Maintaining \e{Binary compatibility} places some restrictions on the changes + you can make to the classes. A good explanation can be found at + \l{http://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++} + {KDE - Policies/Binary Compatibility Issues With C++}. These issues should + be considered right from the start of library design. + We recommend that the principle of \e{Information hiding} and the + \e{Pointer to implementation} technique be used wherever possible. +*/ diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index b9c2bee..9f4af50 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -2961,4 +2961,24 @@ bool QInternal::callFunction(InternalFunction func, void **args) \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 4 */ +/*! + \macro Q_DECL_EXPORT + \relates + + This macro marks a symbol for shared library export (see + \l{sharedlibrary.html}{Creating Shared Libraries}). + + \sa Q_DECL_IMPORT +*/ + +/*! + \macro Q_DECL_IMPORT + \relates + + This macro declares a symbol to be an import from a shared library (see + \l{sharedlibrary.html}{Creating Shared Libraries}). + + \sa Q_DECL_EXPORT +*/ + QT_END_NAMESPACE -- cgit v0.12 From 680bed3dfd50ee888874b5d322899243e0143ff6 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 24 Mar 2009 12:41:03 +0100 Subject: Make sure QSortFilterProxyModel::sort always sort when DynamicSort is not used Task-number: 248868 (part 1) Reviewed-by: Thierry --- src/gui/itemviews/qsortfilterproxymodel.cpp | 2 +- .../tst_qsortfilterproxymodel.cpp | 60 ++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index b3993c7..b6fb598 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -1893,7 +1893,7 @@ QSize QSortFilterProxyModel::span(const QModelIndex &index) const void QSortFilterProxyModel::sort(int column, Qt::SortOrder order) { Q_D(QSortFilterProxyModel); - if (d->proxy_sort_column == column && d->sort_order == order) + if (d->dynamic_sortfilter && d->proxy_sort_column == column && d->sort_order == order) return; d->sort_order = order; d->proxy_sort_column = column; diff --git a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 9f92c37..2f44239 100644 --- a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -129,6 +129,7 @@ private slots: void task236755_hiddenColumns(); void task247867_insertRowsSort(); + void task248868_staticSorting(); protected: void buildHierarchy(const QStringList &data, QAbstractItemModel *model); @@ -2479,5 +2480,64 @@ void tst_QSortFilterProxyModel::task247867_insertRowsSort() QCOMPARE(proxyModel.sortColumn(), 0); } +void tst_QSortFilterProxyModel::task248868_staticSorting() +{ + QStandardItemModel model(0, 1); + QSortFilterProxyModel proxy; + proxy.setSourceModel(&model); + proxy.setDynamicSortFilter(false); + QStringList initial = QString("bateau avion dragon hirondelle flamme camion elephant").split(" "); + + // prepare model + QStandardItem *root = model.invisibleRootItem (); + QList items; + for (int i = 0; i < initial.count(); ++i) { + items.append(new QStandardItem(initial.at(i))); + } + root->insertRows(0, items); + QCOMPARE(model.rowCount(QModelIndex()), initial.count()); + QCOMPARE(model.columnCount(QModelIndex()), 1); + + // make sure the proxy is unsorted + QCOMPARE(proxy.columnCount(QModelIndex()), 1); + QCOMPARE(proxy.rowCount(QModelIndex()), initial.count()); + for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) { + QModelIndex index = proxy.index(row, 0, QModelIndex()); + QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), initial.at(row)); + } + + // sort + proxy.sort(0); + + QStringList expected = initial; + expected.sort(); + // make sure the proxy is sorted + for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) { + QModelIndex index = proxy.index(row, 0, QModelIndex()); + QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row)); + } + + //update one item. + model.setItem(0, 0, new QStandardItem("girafe")); + + // make sure the proxy is updated but not sorted + expected.replaceInStrings("bateau", "girafe"); + for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) { + QModelIndex index = proxy.index(row, 0, QModelIndex()); + QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row)); + } + + // sort again + proxy.sort(0); + expected.sort(); + + // make sure the proxy is sorted + for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) { + QModelIndex index = proxy.index(row, 0, QModelIndex()); + QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row)); + } + +} + QTEST_MAIN(tst_QSortFilterProxyModel) #include "tst_qsortfilterproxymodel.moc" -- cgit v0.12 From dd7b1f11fa4b682d4283274d1fcba8a801fa10f1 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 24 Mar 2009 14:43:21 +0100 Subject: Make sure the sorting is updated when dynamic sorting is enabled and the model is reset Task-number: 248868 (part 2) Reviewed-by: Thierry --- src/gui/itemviews/qsortfilterproxymodel.cpp | 5 +++ .../tst_qsortfilterproxymodel.cpp | 52 ++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index b6fb598..10bcb9a 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -1103,6 +1103,8 @@ void QSortFilterProxyModelPrivate::_q_sourceReset() // All internal structures are deleted in clear() q->reset(); update_source_sort_column(); + if (dynamic_sortfilter) + sort(); } void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged() @@ -1495,6 +1497,7 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) d->clear_mapping(); reset(); + d->update_source_sort_column(); } /*! @@ -2107,6 +2110,8 @@ void QSortFilterProxyModel::setDynamicSortFilter(bool enable) { Q_D(QSortFilterProxyModel); d->dynamic_sortfilter = enable; + if (enable) + d->sort(); } /*! diff --git a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 2f44239..0a48066 100644 --- a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -130,6 +130,7 @@ private slots: void task236755_hiddenColumns(); void task247867_insertRowsSort(); void task248868_staticSorting(); + void task248868_dynamicSorting(); protected: void buildHierarchy(const QStringList &data, QAbstractItemModel *model); @@ -2539,5 +2540,56 @@ void tst_QSortFilterProxyModel::task248868_staticSorting() } +void tst_QSortFilterProxyModel::task248868_dynamicSorting() +{ + QStringListModel model1; + const QStringList initial = QString("bateau avion dragon hirondelle flamme camion elephant").split(" "); + model1.setStringList(initial); + QSortFilterProxyModel proxy1; + proxy1.sort(0); + proxy1.setSourceModel(&model1); + + QCOMPARE(proxy1.columnCount(QModelIndex()), 1); + //the model should not be sorted because sorting has not been set to dynamic yet. + QCOMPARE(proxy1.rowCount(QModelIndex()), initial.count()); + for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) { + QModelIndex index = proxy1.index(row, 0, QModelIndex()); + QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), initial.at(row)); + } + + proxy1.setDynamicSortFilter(true); + + //now the model should be sorted. + QStringList expected = initial; + expected.sort(); + for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) { + QModelIndex index = proxy1.index(row, 0, QModelIndex()); + QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected.at(row)); + } + + QStringList initial2 = initial; + initial2.replaceInStrings("bateau", "girafe"); + model1.setStringList(initial2); //this will cause a reset + + QStringList expected2 = initial2; + expected2.sort(); + + //now the model should still be sorted. + for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) { + QModelIndex index = proxy1.index(row, 0, QModelIndex()); + QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected2.at(row)); + } + + QStringListModel model2(initial); + proxy1.setSourceModel(&model2); + + //the model should again be sorted + for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) { + QModelIndex index = proxy1.index(row, 0, QModelIndex()); + QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected.at(row)); + } +} + + QTEST_MAIN(tst_QSortFilterProxyModel) #include "tst_qsortfilterproxymodel.moc" -- cgit v0.12 From 2b9e47e4ce09802f00fa2ca39c0cd877f59ae4d9 Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Tue, 24 Mar 2009 16:02:02 +0100 Subject: Fix some extra file system stats that we were doing in the model. This patch basically ensure that we share the same QFileinfo all over the place for each nodes (then we benefit of the cache). It fix also an extra stat due of a bugfix that was not optimal. Task-number: 247645 Reviewed-by: jasplin --- src/gui/dialogs/qfileinfogatherer.cpp | 20 ++++++++++++++------ src/gui/dialogs/qfileinfogatherer_p.h | 1 + src/gui/dialogs/qfilesystemmodel.cpp | 18 ++++++++++++------ src/gui/dialogs/qfilesystemmodel_p.h | 4 ++-- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/gui/dialogs/qfileinfogatherer.cpp b/src/gui/dialogs/qfileinfogatherer.cpp index 3fe64ff..23a2cbc 100644 --- a/src/gui/dialogs/qfileinfogatherer.cpp +++ b/src/gui/dialogs/qfileinfogatherer.cpp @@ -168,6 +168,20 @@ void QFileInfoGatherer::clear() } /* + Remove a \a path from the watcher + + \sa listed() +*/ +void QFileInfoGatherer::removePath(const QString &path) +{ +#ifndef QT_NO_FILESYSTEMWATCHER + mutex.lock(); + watcher->removePath(path); + mutex.unlock(); +#endif +} + +/* List all files in \a directoryPath \sa listed() @@ -286,15 +300,9 @@ QString QFileInfoGatherer::translateDriveName(const QFileInfo &drive) const void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &files) { #ifndef QT_NO_FILESYSTEMWATCHER - //### We test here if the path still exist before adding it in the watcher - //### because sometime the file is deleted just before enter here so QStringList files is not up to date - //### It is not a proper fix, perhaps in 4.6 we should have a better way to avoid that - //### to ensure the gatherer have fresh information - QFileInfo info(path); if (files.isEmpty() && !watcher->directories().contains(path) && !path.isEmpty() - && info.exists() && !path.startsWith(QLatin1String("//")) /*don't watch UNC path*/) { watcher->addPath(path); } diff --git a/src/gui/dialogs/qfileinfogatherer_p.h b/src/gui/dialogs/qfileinfogatherer_p.h index eac0d46..60b9d5f 100644 --- a/src/gui/dialogs/qfileinfogatherer_p.h +++ b/src/gui/dialogs/qfileinfogatherer_p.h @@ -161,6 +161,7 @@ public: ~QFileInfoGatherer(); void clear(); + void removePath(const QString &path); QExtendedInformation getInfo(const QFileInfo &info) const; public Q_SLOTS: diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index 51d3314..c7b3137 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -166,6 +166,8 @@ bool QFileSystemModel::remove(const QModelIndex &aindex) const { //### TODO optim QString path = filePath(aindex); + QFileSystemModelPrivate * d = const_cast(d_func()); + d->fileInfoGatherer.removePath(path); QDirIterator it(path, QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); @@ -375,7 +377,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS if (!info.exists()) return rootNode; QFileSystemModelPrivate *p = const_cast(this); - p->addNode(rootNode, host); + p->addNode(rootNode, host,info); p->addVisibleFiles(rootNode, QStringList(host)); } r = rootNode->visibleLocation(host); @@ -395,6 +397,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS #endif QFileSystemModelPrivate::QFileSystemNode *parent = node(index); + for (int i = 0; i < pathElements.count(); ++i) { QString element = pathElements.at(i); #ifdef Q_OS_WIN @@ -423,7 +426,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS if (!info.exists()) return const_cast(&root); QFileSystemModelPrivate *p = const_cast(this); - node = p->addNode(parent, element); + node = p->addNode(parent, element,info); #ifndef QT_NO_FILESYSTEMWATCHER node->populate(fileInfoGatherer.getInfo(info)); #endif @@ -843,7 +846,7 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in QFileSystemModelPrivate::QFileSystemNode *parentNode = indexNode->parent; int visibleLocation = parentNode->visibleLocation(parentNode->children.value(indexNode->fileName)->fileName); - d->addNode(parentNode, newName); + d->addNode(parentNode, newName,indexNode->info->fileInfo()); parentNode->visibleChildren.removeAt(visibleLocation); QFileSystemModelPrivate::QFileSystemNode * oldValue = parentNode->children.value(oldName); parentNode->children[newName] = oldValue; @@ -1282,7 +1285,7 @@ QModelIndex QFileSystemModel::mkdir(const QModelIndex &parent, const QString &na if (!dir.mkdir(name)) return QModelIndex(); QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent); - d->addNode(parentNode, name); + d->addNode(parentNode, name, QFileInfo()); Q_ASSERT(parentNode->children.contains(name)); QFileSystemModelPrivate::QFileSystemNode *node = parentNode->children[name]; node->populate(d->fileInfoGatherer.getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name))); @@ -1601,10 +1604,13 @@ void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, cons *WARNING* this will change the count of children */ -QFileSystemModelPrivate::QFileSystemNode* QFileSystemModelPrivate::addNode(QFileSystemNode *parentNode, const QString &fileName) +QFileSystemModelPrivate::QFileSystemNode* QFileSystemModelPrivate::addNode(QFileSystemNode *parentNode, const QString &fileName, const QFileInfo& info) { // In the common case, itemLocation == count() so check there first QFileSystemModelPrivate::QFileSystemNode *node = new QFileSystemModelPrivate::QFileSystemNode(fileName, parentNode); +#ifndef QT_NO_FILESYSTEMWATCHER + node->populate(info); +#endif parentNode->children.insert(fileName, node); return node; } @@ -1722,7 +1728,7 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QL QExtendedInformation info = fileInfoGatherer.getInfo(updates.at(i).second); bool previouslyHere = parentNode->children.contains(fileName); if (!previouslyHere) { - addNode(parentNode, fileName); + addNode(parentNode, fileName, info.fileInfo()); } QFileSystemModelPrivate::QFileSystemNode * node = parentNode->children.value(fileName); bool isCaseSensitive = parentNode->caseSensitive(); diff --git a/src/gui/dialogs/qfilesystemmodel_p.h b/src/gui/dialogs/qfilesystemmodel_p.h index f1e798b..77c35a2 100644 --- a/src/gui/dialogs/qfilesystemmodel_p.h +++ b/src/gui/dialogs/qfilesystemmodel_p.h @@ -182,7 +182,7 @@ public: QList visibleChildren; QFileSystemNode *parent; - private: + QExtendedInformation *info; }; @@ -216,7 +216,7 @@ public: bool filtersAcceptsNode(const QFileSystemNode *node) const; bool passNameFilters(const QFileSystemNode *node) const; void removeNode(QFileSystemNode *parentNode, const QString &name); - QFileSystemNode* addNode(QFileSystemNode *parentNode, const QString &fileName); + QFileSystemNode* addNode(QFileSystemNode *parentNode, const QString &fileName, const QFileInfo &info); void addVisibleFiles(QFileSystemNode *parentNode, const QStringList &newFiles); void removeVisibleFile(QFileSystemNode *parentNode, int visibleLocation); void sortChildren(int column, const QModelIndex &parent); -- cgit v0.12 From 7f147cf30e8c72ed4c452de31f4b5f853dbe9e4f Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Mon, 23 Mar 2009 13:13:43 +0100 Subject: Don't commit an empty string to the widget when it looses focus. When a wiget that accepts keyboard input looses focus and the input context is resetted we should clear the old preedit string by sending an empty commit string only if the widget received non-empty pre-edit string before. Reviewed-by: Brad --- src/gui/inputmethod/qximinputcontext_p.h | 1 + src/gui/inputmethod/qximinputcontext_x11.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/gui/inputmethod/qximinputcontext_p.h b/src/gui/inputmethod/qximinputcontext_p.h index ca2103b..3773122 100644 --- a/src/gui/inputmethod/qximinputcontext_p.h +++ b/src/gui/inputmethod/qximinputcontext_p.h @@ -98,6 +98,7 @@ public: QString text; QBitArray selectedChars; bool composing; + bool preeditEmpty; void clear(); }; diff --git a/src/gui/inputmethod/qximinputcontext_x11.cpp b/src/gui/inputmethod/qximinputcontext_x11.cpp index 48a96b1..1c8560f 100644 --- a/src/gui/inputmethod/qximinputcontext_x11.cpp +++ b/src/gui/inputmethod/qximinputcontext_x11.cpp @@ -264,6 +264,7 @@ extern "C" { qic->standardFormat(QInputContext::PreeditFormat)); attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, sellen ? 0 : 1, QVariant()); QInputMethodEvent e(data->text, attrs); + data->preeditEmpty = data->text.isEmpty(); qic->sendEvent(e); return 0; @@ -286,6 +287,7 @@ void QXIMInputContext::ICData::clear() text = QString(); selectedChars.clear(); composing = false; + preeditEmpty = true; } QXIMInputContext::ICData *QXIMInputContext::icData() const @@ -537,9 +539,12 @@ void QXIMInputContext::reset() if (mb) { e.setCommitString(QString::fromLocal8Bit(mb)); XFree(mb); + data->preeditEmpty = false; // force sending an event + } + if (!data->preeditEmpty) { + sendEvent(e); + update(); } - sendEvent(e); - update(); } data->clear(); } @@ -686,6 +691,7 @@ QXIMInputContext::ICData *QXIMInputContext::createICData(QWidget *w) { ICData *data = new ICData; data->widget = w; + data->preeditEmpty = true; XVaNestedList preedit_attr = 0; XIMCallback startcallback, drawcallback, donecallback; -- cgit v0.12 From e18eac95ad4b69ebe53e51c65416f1c94275e10a Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Tue, 24 Mar 2009 11:10:06 +0100 Subject: Fixes a focusWidget when showing a toplevel that accepts keyboard input. When a toplevel window is the widget that can accept keyboard input, it doesn't get focus when shown. The fix is to check if the toplevel is activated and noone has focus, then give focus to the toplevel itself. Reviewed-by: Brad Task-number: 244607 --- src/gui/kernel/qapplication.cpp | 4 +++- tests/auto/qwidget/tst_qwidget.cpp | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 1bbb019..7e59fad 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -2461,7 +2461,9 @@ void QApplication::setActiveWindow(QWidget* act) } else { // If the focus widget is not in the activate_window, clear the focus w = QApplicationPrivate::focus_widget; - if (w && !QApplicationPrivate::active_window->isAncestorOf(w)) + if (!w && QApplicationPrivate::active_window->focusPolicy() != Qt::NoFocus) + QApplicationPrivate::setFocusWidget(QApplicationPrivate::active_window, Qt::ActiveWindowFocusReason); + else if (!QApplicationPrivate::active_window->isAncestorOf(w)) QApplicationPrivate::setFocusWidget(0, Qt::ActiveWindowFocusReason); } } diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index 42f496a..dfd0792 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -343,6 +343,7 @@ private slots: void paintOutsidePaintEvent(); #endif void updateOnDestroyedSignal(); + void toplevelLineEditFocus(); private: bool ensureScreenSize(int width, int height); @@ -8727,5 +8728,18 @@ void tst_QWidget::updateOnDestroyedSignal() QTest::qWait(200); } +void tst_QWidget::toplevelLineEditFocus() +{ + testWidget->hide(); + + QLineEdit w; + w.show(); + qt_x11_wait_for_window_manager(&w); + QTest::qWait(200); + + QCOMPARE(QApplication::activeWindow(), &w); + QCOMPARE(QApplication::focusWidget(), &w); +} + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" -- cgit v0.12