From 3f1245aabc125c416f26028a12923f9055765e4f Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Wed, 20 Nov 2013 12:05:49 +0100 Subject: Enforce window rendering in sequence on llvmpipe. When rendering multiple windows in parallel on llvmpipe we end up with crashes deep inside llvmpipe as multiple threads seem to access unprotected resources. Work around this bug by enforcing that scene graph rendering happens on one window at a time. Task-number: QTCREATORBUG-10666 Change-Id: I2f734e8f653b2a9b4108eb189280ab922581e2c0 Reviewed-by: Kai Koehne --- src/quick/scenegraph/qsgcontext.cpp | 12 ++++++++++++ src/quick/scenegraph/qsgcontext_p.h | 1 + 2 files changed, 13 insertions(+) diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index fa095b8165..afde7939f2 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -340,6 +340,7 @@ QSGRenderContext::QSGRenderContext(QSGContext *context) , m_depthStencilManager(0) , m_distanceFieldCacheManager(0) , m_brokenIBOs(false) + , m_serializedRender(false) { } @@ -348,8 +349,13 @@ QSGRenderContext::~QSGRenderContext() invalidate(); } +static QBasicMutex qsg_framerender_mutex; + void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) { + if (m_serializedRender) + qsg_framerender_mutex.lock(); + if (fboId) { QSGBindableFboId bindable(fboId); renderer->renderScene(bindable); @@ -357,6 +363,9 @@ void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) renderer->renderScene(); } + if (m_serializedRender) + qsg_framerender_mutex.unlock(); + } /*! @@ -442,6 +451,9 @@ void QSGRenderContext::initialize(QOpenGLContext *context) const char *vendor = (const char *) glGetString(GL_VENDOR); if (strstr(vendor, "nouveau")) m_brokenIBOs = true; + const char *renderer = (const char *) glGetString(GL_RENDERER); + if (strstr(renderer, "llvmpipe")) + m_serializedRender = true; #endif emit initialized(); diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index 270f108373..c562a909c5 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -132,6 +132,7 @@ protected: QSet m_fontEnginesToClean; bool m_brokenIBOs; + bool m_serializedRender; }; -- cgit v1.2.3 From 61cf2b0633e8af564d1368dc377da0b6869fb4c9 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 18 Nov 2013 15:57:08 +0100 Subject: qml tool on OSX: wait for a timeout before exiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Double-clicking to open a QML file was not working because it would exit if no files are given on the command line. It needs to wait a while for the QFileOpenEvent. Task-number: QTBUG-34926 Change-Id: Icb585a777b0438db85120c62e7717f0f6eafffb1 Reviewed-by: Gabriel de Dietrich Reviewed-by: Alan Alpert Reviewed-by: Morten Johan Sørvig --- tools/qml/main.cpp | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index ddcd259ae0..804241f023 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -72,8 +72,11 @@ #define VERSION_MIN 0 #define VERSION_STR "1.0" +#define FILE_OPEN_EVENT_WAIT_TIME 3000 // ms + static Config *conf = 0; static QQmlApplicationEngine *qae = 0; +static int exitTimerId = -1; static void loadConf(const QString &override, bool quiet) // Terminates app on failure { @@ -138,6 +141,8 @@ void contain(QObject *o, const QUrl &containPath) #ifdef QT_GUI_LIB +void noFilesGiven(); + // Loads qml after receiving a QFileOpenEvent class LoaderApplication : public QGuiApplication { @@ -146,12 +151,21 @@ public: bool event(QEvent *ev) { - if (ev->type() == QEvent::FileOpen) + if (ev->type() == QEvent::FileOpen) { + if (exitTimerId >= 0) { + killTimer(exitTimerId); + exitTimerId = -1; + } qae->load(static_cast(ev)->url()); + } else return QGuiApplication::event(ev); return true; } + + void timerEvent(QTimerEvent *) { + noFilesGiven(); + } }; #endif // QT_GUI_LIB @@ -274,6 +288,13 @@ void printUsage() exit(0); } +void noFilesGiven() +{ + if (!quietMode) + printf("qml: No files specified. Terminating.\n"); + exit(1); +} + //Called before application initialization, removes arguments it uses void getAppFlags(int &argc, char **argv) { @@ -462,9 +483,12 @@ int main(int argc, char *argv[]) qInstallMessageHandler(quietMessageHandler); if (files.count() <= 0) { - if (!quietMode) - printf("qml: No files specified. Terminating.\n"); - exit(1); +#if defined(Q_OS_MAC) + if (applicationType == QmlApplicationTypeGui) + exitTimerId = static_cast(app)->startTimer(FILE_OPEN_EVENT_WAIT_TIME); + else +#endif + noFilesGiven(); } qae = &e; -- cgit v1.2.3 From 88262738a8109f393f5e34d5898d1610d490e6f6 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Wed, 20 Nov 2013 17:17:01 +0100 Subject: V4 Use getrlimit on Darwin to get the stack size for the main thread Turns out pthread_get_size does not return the correct size when it is called from the main thread, so to workaround you call getrlimit instead Without this change, most QML applications are broken on iOS. Change-Id: I9a61494de26caa3d7be7e46a991e6d6d0514ce17 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4engine.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 84be89d31a..8cd059dd2b 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -95,7 +95,14 @@ quintptr getStackLimit() pthread_t thread_self = pthread_self(); void *stackTop = pthread_get_stackaddr_np(thread_self); stackLimit = reinterpret_cast(stackTop); - stackLimit -= pthread_get_stacksize_np(thread_self); + quintptr size = 0; + if (pthread_main_np()) { + rlimit limit; + getrlimit(RLIMIT_STACK, &limit); + size = limit.rlim_cur; + } else + size = pthread_get_stacksize_np(thread_self); + stackLimit -= size; # else void* stackBottom = 0; pthread_attr_t attr; -- cgit v1.2.3 From 802921d40b8b48239958c6035c74d986fe606860 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 21 Nov 2013 11:06:24 +0100 Subject: TextInput: add editingFinished signal Autotest is included. Task-number: QTBUG-34780 [ChangeLog][QtDeclarative][TextInput] add editingFinished signal Change-Id: Ib633daee67cd4e5f15739a6004adbe882ab3d3fc Reviewed-by: Lars Knoll Reviewed-by: J-P Nurmi Reviewed-by: Thomas Hartmann Reviewed-by: Jens Bache-Wiig Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com> --- src/quick/items/qquickitemsmodule.cpp | 1 + src/quick/items/qquicktextinput.cpp | 15 ++++++++ src/quick/items/qquicktextinput_p.h | 1 + .../data/signal_editingfinished.qml | 13 +++++++ .../quick/qquicktextinput/tst_qquicktextinput.cpp | 45 ++++++++++++++++++++++ 5 files changed, 75 insertions(+) create mode 100644 tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index ebc32c89eb..a5b78b28e1 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -188,6 +188,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(uri,major,minor,"TextEdit"); qmlRegisterType(uri,2,1,"TextEdit"); qmlRegisterType(uri,major,minor,"TextInput"); + qmlRegisterType(uri,2,2,"TextInput"); qmlRegisterType(uri,major,minor,"ViewSection"); qmlRegisterType(); diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 93ea677d2c..b46387ba47 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -1212,6 +1212,17 @@ bool QQuickTextInput::hasAcceptableInput() const state. */ +/*! + \qmlsignal QtQuick::TextInput::onEditingFinished() + \since 5.2 + + This handler is called when the Return or Enter key is pressed or + the text input loses focus. Note that if there is a validator or + inputMask set on the text input and enter/return is pressed, this + handler will only be called if the input follows + the inputMask and the validator returns an acceptable state. +*/ + #ifndef QT_NO_IM Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const { @@ -2522,6 +2533,9 @@ void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event) && !persistentSelection) deselect(); + if (hasAcceptableInput(m_text) || fixup()) + emit q->editingFinished(); + #ifndef QT_NO_IM q->disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)), q, SLOT(q_updateAlignment())); @@ -4105,6 +4119,7 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { if (hasAcceptableInput(m_text) || fixup()) { emit q->accepted(); + emit q->editingFinished(); } event->ignore(); return; diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index 2b72afb9dc..5f0250aaf1 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -284,6 +284,7 @@ Q_SIGNALS: void selectedTextChanged(); void accepted(); void acceptableInputChanged(); + Q_REVISION(2) void editingFinished(); void colorChanged(); void selectionColorChanged(); void selectedTextColorChanged(); diff --git a/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml b/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml new file mode 100644 index 0000000000..2ec5ce6676 --- /dev/null +++ b/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml @@ -0,0 +1,13 @@ +import QtQuick 2.2 + +Item { + property variant input1: input1 + property variant input2: input2 + + width: 800; height: 600; + + Column{ + TextInput { id: input1; } + TextInput { id: input2; } + } +} diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index 1c2ab4d948..80726720e4 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -146,6 +146,8 @@ private slots: void validators(); void inputMethods(); + void signal_editingfinished(); + void passwordCharacter(); void cursorDelegate_data(); void cursorDelegate(); @@ -2303,6 +2305,49 @@ void tst_qquicktextinput::inputMethods() QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), false); } +void tst_qquicktextinput::signal_editingfinished() +{ + QQuickView window(testFileUrl("signal_editingfinished.qml")); + window.show(); + window.requestActivate(); + QTest::qWaitForWindowActive(&window); + + QVERIFY(window.rootObject() != 0); + + QQuickTextInput *input1 = qobject_cast(qvariant_cast(window.rootObject()->property("input1"))); + QVERIFY(input1); + QQuickTextInput *input2 = qobject_cast(qvariant_cast(window.rootObject()->property("input2"))); + QVERIFY(input2); + QSignalSpy input1Spy(input1, SIGNAL(editingFinished())); + + input1->setFocus(true); + QTRY_VERIFY(input1->hasActiveFocus()); + QTRY_VERIFY(!input2->hasActiveFocus()); + + QTest::keyPress(&window, Qt::Key_A); + QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier); + QTRY_COMPARE(input1->text(), QLatin1String("a")); + + QTest::keyPress(&window, Qt::Key_Enter); + QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier); + QTRY_COMPARE(input1Spy.count(), 1); + + QSignalSpy input2Spy(input2, SIGNAL(editingFinished())); + + input2->setFocus(true); + QTRY_VERIFY(!input1->hasActiveFocus()); + QTRY_VERIFY(input2->hasActiveFocus()); + + QTest::keyPress(&window, Qt::Key_A); + QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier); + QTRY_COMPARE(input2->text(), QLatin1String("a")); + + input1->setFocus(true); + QTRY_VERIFY(input1->hasActiveFocus()); + QTRY_VERIFY(!input2->hasActiveFocus()); + QTRY_COMPARE(input2Spy.count(), 1); +} + /* TextInput element should only handle left/right keys until the cursor reaches the extent of the text, then they should ignore the keys. -- cgit v1.2.3 From 475879b6fe994ba93423317204c05cb377df357c Mon Sep 17 00:00:00 2001 From: Alan Alpert <416365416c@gmail.com> Date: Wed, 20 Nov 2013 13:34:19 -0800 Subject: Don't store the QSGNode pointer The QSGNode subtree may be cleared at any time. Get the subtree via the node pointer passed in updatePaintNode, to ensure that the subtree is still valid each update. Some references are still being stored but invalidated when a new subtree is created. QTBUG-34994 has been created to track fixing that. Task-number: QTBUG-33553 Change-Id: I2115aff931d42b613d207553c636be7d80c405bb Reviewed-by: Gunnar Sletta --- src/particles/qquickimageparticle.cpp | 42 +++++++++++++++++------------------ src/particles/qquickimageparticle_p.h | 6 ++--- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index 0bea3a87af..e5845f4c62 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -715,7 +715,6 @@ QQuickImageParticle::QQuickImageParticle(QQuickItem* parent) , m_sizeTable(0) , m_opacityTable(0) , m_color_variation(0.0) - , m_rootNode(0) , m_material(0) , m_alphaVariation(0.0) , m_alpha(1.0) @@ -757,7 +756,6 @@ QQmlListProperty QQuickImageParticle::sprites() void QQuickImageParticle::sceneGraphInvalidated() { m_nodes.clear(); - m_rootNode = 0; m_material = 0; } @@ -1209,24 +1207,25 @@ void QQuickImageParticle::mainThreadFetchImageData() m_startedImageLoading = 2; } -void QQuickImageParticle::buildParticleNodes() +void QQuickImageParticle::buildParticleNodes(QSGNode** passThrough) { // Starts async parts, like loading images, on gui thread // Not on individual properties, because we delay until system is running - if (m_rootNode || loadingSomething()) + if (*passThrough || loadingSomething()) return; if (m_startedImageLoading == 0) { m_startedImageLoading = 1; + //stage 1 is in gui thread QQuickImageParticle::staticMetaObject.invokeMethod(this, "mainThreadFetchImageData", Qt::QueuedConnection); - } else if (m_startedImageLoading == 2) { //stage 1 is in gui thread - finishBuildParticleNodes(); //rest happens in render thread + } else if (m_startedImageLoading == 2) { + finishBuildParticleNodes(passThrough); //rest happens in render thread } //No mutex, because it's slow and a compare that fails due to a race condition means just a dropped frame } -void QQuickImageParticle::finishBuildParticleNodes() +void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) { #ifdef QT_OPENGL_ES_2 if (m_count * 4 > 0xffff) { @@ -1456,17 +1455,18 @@ void QQuickImageParticle::finishBuildParticleNodes() (*(m_nodes.begin()))->appendChildNode(node); } - m_rootNode = *(m_nodes.begin()); + *node = *(m_nodes.begin()); update(); } -QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *) +QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) { if (m_pleaseReset){ - m_lastLevel = perfLevel; + if (node) + delete node; + node = 0; - delete m_rootNode;//Automatically deletes children, and SG manages material lifetime - m_rootNode = 0; + m_lastLevel = perfLevel; m_nodes.clear(); m_idxStarts.clear(); @@ -1480,23 +1480,23 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *) } if (m_system && m_system->isRunning() && !m_system->isPaused()){ - prepareNextFrame(); - if (m_rootNode) { + prepareNextFrame(&node); + if (node) { update(); - foreach (QSGGeometryNode* node, m_nodes) - node->markDirty(QSGNode::DirtyGeometry); + foreach (QSGGeometryNode* n, m_nodes) + n->markDirty(QSGNode::DirtyGeometry); } else if (m_startedImageLoading < 2) { update();//To call prepareNextFrame() again from the renderThread } } - return m_rootNode; + return node; } -void QQuickImageParticle::prepareNextFrame() +void QQuickImageParticle::prepareNextFrame(QSGNode **node) { - if (m_rootNode == 0){//TODO: Staggered loading (as emitted) - buildParticleNodes(); + if (*node == 0){//TODO: Staggered loading (as emitted) + buildParticleNodes(node); if (m_debugMode) { qDebug() << "QQuickImageParticle Feature level: " << perfLevel; qDebug() << "QQuickImageParticle Nodes: "; @@ -1507,7 +1507,7 @@ void QQuickImageParticle::prepareNextFrame() } qDebug() << "Total count: " << count; } - if (m_rootNode == 0) + if (*node == 0) return; } qint64 timeStamp = m_system->systemSync(this); diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h index 3a5d72e727..e9328d79e5 100644 --- a/src/particles/qquickimageparticle_p.h +++ b/src/particles/qquickimageparticle_p.h @@ -343,8 +343,8 @@ protected: virtual void commit(int gIdx, int pIdx); QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - void prepareNextFrame(); - void buildParticleNodes(); + void prepareNextFrame(QSGNode**); + void buildParticleNodes(QSGNode**); void sceneGraphInvalidated(); @@ -354,7 +354,7 @@ private Q_SLOTS: void spriteAdvance(int spriteIndex); void spritesUpdate(qreal time = 0 ); void mainThreadFetchImageData(); - void finishBuildParticleNodes(); + void finishBuildParticleNodes(QSGNode **n); private: struct ImageData { QUrl source; -- cgit v1.2.3 From 2c7bf3992ba079a632f0f5fdef64e6ca10eaf13f Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 22 Nov 2013 15:37:08 +0100 Subject: Avoid symbol clashes when linking QtDeclarative and QtScript statically Re-define the three symbols we actually implement (as stubs). Task-number: QTBUG-35041 Change-Id: Ie9511207440fa23645e52643881f5993177a4368 Reviewed-by: Andy Shaw Reviewed-by: Lars Knoll --- src/3rdparty/masm/masm-defs.pri | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri index 34c2e9f8de..95f1f60031 100644 --- a/src/3rdparty/masm/masm-defs.pri +++ b/src/3rdparty/masm/masm-defs.pri @@ -2,6 +2,11 @@ DEFINES += WTF_EXPORT_PRIVATE="" JS_EXPORT_PRIVATE="" +# Avoid symbol clashes with QtScript during static linking +DEFINES += WTFReportAssertionFailure=qmlWTFReportAssertionFailure +DEFINES += WTFReportBacktrace=qmlWTFReportBacktrace +DEFINES += WTFInvokeCrashHook=qmlWTFInvokeCrashHook + win*: DEFINES += NOMINMAX DEFINES += ENABLE_LLINT=0 -- cgit v1.2.3 From 8eca830fab1f8a27d62602f2725afc7cdc3561aa Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Wed, 20 Nov 2013 13:27:02 +0100 Subject: Safeguard the threaded renderloop against incorrectly exposed windows. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Mac we had a situation where we got expose events for windows which were either 0x24 in size or completely off the screen. These would result in makeCurrent failing and lead to crashes later on in the scene graph. Safeguard against invalid dimensions during initialization and abort after a call to makeCurrent if any of them fail. Task-number: QTCREATORBUG-10814 Change-Id: I9063ea4d078eea3914666e4c155d141a1502e2ff Reviewed-by: Tor Arne Vestbø --- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 0c46747e53..2de9827ab1 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -506,7 +506,10 @@ void QSGRenderThread::sync() Q_ASSERT_X(wm->m_locked, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked..."); - if (windowSize.width() > 0 && windowSize.height() > 0) { + bool current = false; + if (windowSize.width() > 0 && windowSize.height() > 0) + current = gl->makeCurrent(window); + if (current) { gl->makeCurrent(window); QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); bool hadRenderer = d->renderer != 0; @@ -578,8 +581,10 @@ void QSGRenderThread::syncAndRender() d->animationController->unlock(); } - if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0) { - gl->makeCurrent(window); + bool current = false; + if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0) + current = gl->makeCurrent(window); + if (current) { d->renderSceneGraph(windowSize); #ifndef QSG_NO_RENDER_TIMING if (profileFrames) @@ -654,10 +659,8 @@ void QSGRenderThread::run() while (active) { if (window) { - if (!sgrc->openglContext()) { - gl->makeCurrent(window); + if (!sgrc->openglContext() && windowSize.width() > 0 && windowSize.height() > 0 && gl->makeCurrent(window)) sgrc->initialize(gl); - } syncAndRender(); } -- cgit v1.2.3 From 1b8795e4bbae8cde791707bb8b44600dcd96eda9 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 11 Nov 2013 21:41:47 +0100 Subject: QtQuick.Dialogs MessageDialog docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ic229a26c395be0542409ba3e13739e55b6ffb521 Reviewed-by: Topi Reiniö --- src/imports/dialogs/doc/images/critical.png | Bin 0 -> 253 bytes src/imports/dialogs/doc/images/information.png | Bin 0 -> 254 bytes src/imports/dialogs/doc/images/question.png | Bin 0 -> 257 bytes src/imports/dialogs/doc/images/replacefile.png | Bin 0 -> 4304 bytes src/imports/dialogs/doc/images/warning.png | Bin 0 -> 224 bytes .../dialogs/qquickplatformmessagedialog.cpp | 218 +++++++++++++++++++-- 6 files changed, 203 insertions(+), 15 deletions(-) create mode 100644 src/imports/dialogs/doc/images/critical.png create mode 100644 src/imports/dialogs/doc/images/information.png create mode 100644 src/imports/dialogs/doc/images/question.png create mode 100644 src/imports/dialogs/doc/images/replacefile.png create mode 100644 src/imports/dialogs/doc/images/warning.png diff --git a/src/imports/dialogs/doc/images/critical.png b/src/imports/dialogs/doc/images/critical.png new file mode 100644 index 0000000000..dc9c5aebf4 Binary files /dev/null and b/src/imports/dialogs/doc/images/critical.png differ diff --git a/src/imports/dialogs/doc/images/information.png b/src/imports/dialogs/doc/images/information.png new file mode 100644 index 0000000000..0a2eb87d10 Binary files /dev/null and b/src/imports/dialogs/doc/images/information.png differ diff --git a/src/imports/dialogs/doc/images/question.png b/src/imports/dialogs/doc/images/question.png new file mode 100644 index 0000000000..2dd92fd791 Binary files /dev/null and b/src/imports/dialogs/doc/images/question.png differ diff --git a/src/imports/dialogs/doc/images/replacefile.png b/src/imports/dialogs/doc/images/replacefile.png new file mode 100644 index 0000000000..d1479fa944 Binary files /dev/null and b/src/imports/dialogs/doc/images/replacefile.png differ diff --git a/src/imports/dialogs/doc/images/warning.png b/src/imports/dialogs/doc/images/warning.png new file mode 100644 index 0000000000..cba78f6bea Binary files /dev/null and b/src/imports/dialogs/doc/images/warning.png differ diff --git a/src/imports/dialogs/qquickplatformmessagedialog.cpp b/src/imports/dialogs/qquickplatformmessagedialog.cpp index 00c750a66d..65114100d2 100644 --- a/src/imports/dialogs/qquickplatformmessagedialog.cpp +++ b/src/imports/dialogs/qquickplatformmessagedialog.cpp @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE The most basic use case for a MessageDialog is a popup alert. It also allows the user to respond in various ways depending on which buttons are enabled. The dialog is initially invisible. You need to set the properties - as desired first, then set \l visible to true or call \l open(). + as desired first, then set \l visible to \c true or call \l open(). Here is a minimal example to show an alert and exit after the user responds: @@ -81,6 +81,11 @@ QT_BEGIN_NAMESPACE } \endqml + There are several possible handlers depending on which \l standardButtons + the dialog has and the \l {QMessageBox::ButtonRole} {ButtonRole} of each. + For example, the \l {rejected} {onRejected} handler will be called if the + user presses a \gui Cancel, \gui Close or \gui Abort button. + A MessageDialog window is automatically transient for its parent window. So whether you declare the dialog inside an \l Item or inside a \l Window, the dialog will appear centered over the window containing the item, or over @@ -89,25 +94,73 @@ QT_BEGIN_NAMESPACE The implementation of MessageDialog will be a platform message dialog if possible. If that isn't possible, then it will try to instantiate a \l QMessageBox. If that also isn't possible, then it will fall back to a QML - implementation, DefaultMessageDialog.qml. In that case you can customize the - appearance by editing this file. DefaultMessageDialog.qml contains a Rectangle - to hold the dialog's contents, because certain embedded systems do not - support multiple top-level windows. When the dialog becomes visible, it - will automatically be wrapped in a Window if possible, or simply reparented - on top of the main window if there can only be one window. + implementation, \c DefaultMessageDialog.qml. In that case you can customize + the appearance by editing this file. \c DefaultMessageDialog.qml contains a + \l Rectangle to hold the dialog's contents, because certain embedded systems + do not support multiple top-level windows. When the dialog becomes visible, + it will automatically be wrapped in a \l Window if possible, or simply + reparented on top of the main window if there can only be one window. +*/ + +/*! + \qmlsignal MessageDialog::accepted() + + This handler is called when the user has pressed any button which has the + \l {QMessageBox::AcceptRole} {AcceptRole}: \gui OK, \gui Open, \gui Save, + \gui {Save All}, \gui Retry or \gui Ignore. */ /*! - \qmlsignal QtQuick::Dialogs::MessageDialog::accepted + \qmlsignal MessageDialog::rejected() - This handler is called when the user has pressed OK. + This handler is called when the user has dismissed the dialog, by closing + the dialog window, by pressing a \gui Cancel, \gui Close or \gui Abort + button on the dialog, or by pressing the back button or the escape key. */ /*! - \qmlsignal QtQuick::Dialogs::MessageDialog::rejected + \qmlsignal MessageDialog::discard() - This handler is called when the user has dismissed the dialog, - either by closing the dialog window or by pressing the Cancel button. + This handler is called when the user has pressed the \gui Discard button. +*/ + +/*! + \qmlsignal MessageDialog::help() + + This handler is called when the user has pressed the \gui Help button. + Depending on platform, the dialog may not be automatically dismissed + because the help that your application provides may need to be relevant to + the text shown in this dialog in order to assist the user in making a + decision. However on other platforms it's not possible to show a dialog and + a help window at the same time. If you want to be sure that the dialog will + close, you can set \l visible to \c false in your handler. +*/ + +/*! + \qmlsignal MessageDialog::yes() + + This handler is called when the user has pressed any button which has + the \l {QMessageBox::YesRole} {YesRole}: \gui Yes or \gui {Yes to All}. +*/ + +/*! + \qmlsignal MessageDialog::no() + + This handler is called when the user has pressed any button which has + the \l {QMessageBox::NoRole} {NoRole}: \gui No or \gui {No to All}. +*/ + +/*! + \qmlsignal MessageDialog::apply() + + This handler is called when the user has pressed the \gui Apply button. +*/ + +/*! + \qmlsignal MessageDialog::reset() + + This handler is called when the user has pressed any button which has + the \l {QMessageBox::ResetRole} {ResetRole}: \gui Reset or \gui {Restore Defaults}. */ /*! @@ -168,7 +221,7 @@ QPlatformMessageDialogHelper *QQuickPlatformMessageDialog::helper() \qmlproperty bool MessageDialog::visible This property holds whether the dialog is visible. By default this is - false. + \c false. \sa modality */ @@ -185,14 +238,14 @@ QPlatformMessageDialogHelper *QQuickPlatformMessageDialog::helper() Modality does not mean that there are any blocking calls to wait for the dialog to be accepted or rejected; it's only that the user will be prevented from interacting with the parent window and/or the application - windows at the same time. + windows until the dialog is dismissed. */ /*! \qmlmethod void MessageDialog::open() Shows the dialog to the user. It is equivalent to setting \l visible to - true. + \c true. */ /*! @@ -207,4 +260,139 @@ QPlatformMessageDialogHelper *QQuickPlatformMessageDialog::helper() The title of the dialog window. */ +/*! + \qmlproperty string MessageDialog::text + + The primary text to be displayed. +*/ + +/*! + \qmlproperty string MessageDialog::informativeText + + The informative text that provides a fuller description for the message. + + Informative text can be used to supplement the \c text to give more + information to the user. Depending on the platform, it may appear in a + smaller font below the text, or simply appended to the text. + + \sa {MessageDialog::text}{text} +*/ + +/*! + \qmlproperty string MessageDialog::detailedText + + The text to be displayed in the details area, which is hidden by default. + The user will then be able to press the \gui {Show Details...} button to + make it visible. + + \sa {MessageDialog::text}{text} +*/ + +/*! + \enum QQuickStandardIcon::Icon + + This enum specifies a standard icon to be used on a dialog. +*/ + +/*! + \qmlproperty QQuickStandardIcon::Icon MessageDialog::icon + + The icon of the message box can be specified with one of these values: + + \table + \row + \li no icon + \li \l StandardIcon.NoIcon + \li For an unadorned text alert. + \row + \li \inlineimage ../images/question.png "Question icon" + \li \l StandardIcon.Question + \li For asking a question during normal operations. + \row + \li \image information.png + \li \l StandardIcon.Information + \li For reporting information about normal operations. + \row + \li \image warning.png + \li \l StandardIcon.Warning + \li For reporting non-critical errors. + \row + \li \image critical.png + \li \l StandardIcon.Critical + \li For reporting critical errors. + \endtable + + The default is \c StandardIcon.NoIcon. + + The enum values are the same as in \l QMessageBox::Icon. +*/ + +// TODO after QTBUG-35019 is fixed: fix links to this module's enums +// rather than linking to those in QMessageBox +/*! + \enum QQuickStandardButton::StandardButton + + This enum specifies a button with a standard label to be used on a dialog. +*/ + +/*! + \qmlproperty StandardButtons MessageDialog::standardButtons + + The MessageDialog has a row of buttons along the bottom, each of which has + a \l {QMessageBox::ButtonRole} {ButtonRole} that determines which signal + will be emitted when the button is pressed. You can also find out which + specific button was pressed after the fact via the \l clickedButton + property. You can control which buttons are available by setting + standardButtons to a bitwise-or combination of the following flags: + + \table + \row \li StandardButton.Ok \li An \gui OK button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}. + \row \li StandardButton.Open \li An \gui Open button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}. + \row \li StandardButton.Save \li A \gui Save button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}. + \row \li StandardButton.Cancel \li A \gui Cancel button defined with the \l {QMessageBox::RejectRole} {RejectRole}. + \row \li StandardButton.Close \li A \gui Close button defined with the \l {QMessageBox::RejectRole} {RejectRole}. + \row \li StandardButton.Discard \li A \gui Discard or \gui {Don't Save} button, depending on the platform, + defined with the \l {QMessageBox::DestructiveRole} {DestructiveRole}. + \row \li StandardButton.Apply \li An \gui Apply button defined with the \l {QMessageBox::ApplyRole} {ApplyRole}. + \row \li StandardButton.Reset \li A \gui Reset button defined with the \l {QMessageBox::ResetRole} {ResetRole}. + \row \li StandardButton.RestoreDefaults \li A \gui {Restore Defaults} button defined with the \l {QMessageBox::ResetRole} {ResetRole}. + \row \li StandardButton.Help \li A \gui Help button defined with the \l {QMessageBox::HelpRole} {HelpRole}. + \row \li StandardButton.SaveAll \li A \gui {Save All} button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}. + \row \li StandardButton.Yes \li A \gui Yes button defined with the \l {QMessageBox::YesRole} {YesRole}. + \row \li StandardButton.YesToAll \li A \gui {Yes to All} button defined with the \l {QMessageBox::YesRole} {YesRole}. + \row \li StandardButton.No \li A \gui No button defined with the \l {QMessageBox::NoRole} {NoRole}. + \row \li StandardButton.NoToAll \li A \gui {No to All} button defined with the \l {QMessageBox::NoRole} {NoRole}. + \row \li StandardButton.Abort \li An \gui Abort button defined with the \l {QMessageBox::RejectRole} {RejectRole}. + \row \li StandardButton.Retry \li A \gui Retry button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}. + \row \li StandardButton.Ignore \li An \gui Ignore button defined with the \l {QMessageBox::AcceptRole} {AcceptRole}. + \endtable + + For example the following dialog will ask a question with 5 possible answers: + + \qml + import QtQuick 2.2 + import QtQuick.Dialogs 1.1 + + MessageDialog { + title: "Overwrite?" + icon: StandardIcon.Question + text: "file.txt already exists. Replace?" + detailedText: "To replace a file means that its existing contents will be lost. " + + "The file that you are copying now will be copied over it instead." + standardButtons: StandardButton.Yes | StandardButton.YesToAll | + StandardButton.No | StandardButton.NoToAll | StandardButton.Abort + Component.onCompleted: visible = true + onYes: console.log("copied") + onNo: console.log("didn't copy") + onRejected: console.log("aborted") + } + \endqml + + \image replacefile.png + + The default is \c StandardButton.Ok. + + The enum values are the same as in \l QMessageBox::StandardButtons. +*/ + QT_END_NAMESPACE -- cgit v1.2.3 From 99480d5420c0beea6771be582c039b550a4461f5 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 21 Nov 2013 14:13:07 +0100 Subject: Be even more tolerant towards broken platform behavior. When the platform (Mac in particular) sends us exposes for windows which are not renderable, we store it for later and fake expose events when we get resized. Task-number: QTCREATORBUG-10814 Change-Id: I909bb5a920550589322afd97ae1834884754cf81 Reviewed-by: Lars Knoll --- src/quick/designer/designerwindowmanager.cpp | 4 ---- src/quick/designer/designerwindowmanager_p.h | 1 - src/quick/items/qquickwindow.cpp | 1 + src/quick/scenegraph/qsgrenderloop_p.h | 1 + src/quick/scenegraph/qsgthreadedrenderloop.cpp | 21 +++++++++++++++++++++ src/quick/scenegraph/qsgthreadedrenderloop_p.h | 2 ++ src/quick/scenegraph/qsgwindowsrenderloop_p.h | 2 -- 7 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/quick/designer/designerwindowmanager.cpp b/src/quick/designer/designerwindowmanager.cpp index c4a95d254b..25ea5e7f93 100644 --- a/src/quick/designer/designerwindowmanager.cpp +++ b/src/quick/designer/designerwindowmanager.cpp @@ -90,10 +90,6 @@ QImage DesignerWindowManager::grab(QQuickWindow *) return QImage(); } -void DesignerWindowManager::resize(QQuickWindow *, const QSize &) -{ -} - void DesignerWindowManager::maybeUpdate(QQuickWindow *) { } diff --git a/src/quick/designer/designerwindowmanager_p.h b/src/quick/designer/designerwindowmanager_p.h index 1bab8c8508..7414f4e3ba 100644 --- a/src/quick/designer/designerwindowmanager_p.h +++ b/src/quick/designer/designerwindowmanager_p.h @@ -82,7 +82,6 @@ public: void makeOpenGLContext(QQuickWindow *window); void exposureChanged(QQuickWindow *window); QImage grab(QQuickWindow *window); - void resize(QQuickWindow *window, const QSize &size); void maybeUpdate(QQuickWindow *window); void update(QQuickWindow *window); // identical for this implementation. diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 41a1781394..796ddcfbe4 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -216,6 +216,7 @@ void QQuickWindow::exposeEvent(QExposeEvent *) /*! \reimp */ void QQuickWindow::resizeEvent(QResizeEvent *) { + d_func()->windowManager->resize(this); } /*! \reimp */ diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index 7b06399f08..72bad16c63 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -61,6 +61,7 @@ public: virtual void show(QQuickWindow *window) = 0; virtual void hide(QQuickWindow *window) = 0; + virtual void resize(QQuickWindow *) {}; virtual void windowDestroyed(QQuickWindow *window) = 0; diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 2de9827ab1..e50d034529 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -817,6 +817,7 @@ void QSGThreadedRenderLoop::show(QQuickWindow *window) win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context); win.timerId = 0; win.updateDuringSync = false; + win.gotBrokenExposeFromPlatformPlugin = false; m_windows << win; } @@ -882,6 +883,17 @@ void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window) } } +void QSGThreadedRenderLoop::resize(QQuickWindow *window) +{ + Window *w = windowFor(m_windows, window); + if (w->gotBrokenExposeFromPlatformPlugin + && window->width() > 0 && window->height() > 0 + && w->window->geometry().intersects(w->window->screen()->availableGeometry())) { + w->gotBrokenExposeFromPlatformPlugin = false; + handleExposure(w); + } +} + /*! Will post an event to the render thread that this window should @@ -891,6 +903,15 @@ void QSGThreadedRenderLoop::handleExposure(Window *w) { QSG_GUI_DEBUG(w->window, "handleExposure"); + if (w->window->width() <= 0 || w->window->height() <= 0 + || !w->window->geometry().intersects(w->window->screen()->availableGeometry())) { +#ifndef QT_NO_DEBUG + qWarning("QSGThreadedRenderLoop: expose event received for window with invalid geometry."); +#endif + w->gotBrokenExposeFromPlatformPlugin = true; + return; + } + // Because we are going to bind a GL context to it, make sure it // is created. if (!w->window->handle()) diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h index 5943d0bd08..844d180788 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h +++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h @@ -60,6 +60,7 @@ public: void show(QQuickWindow *window); void hide(QQuickWindow *window); + void resize(QQuickWindow *window); void windowDestroyed(QQuickWindow *window); void exposureChanged(QQuickWindow *window); @@ -89,6 +90,7 @@ private: QSGRenderThread *thread; int timerId; uint updateDuringSync : 1; + uint gotBrokenExposeFromPlatformPlugin : 1; }; friend class QSGRenderThread; diff --git a/src/quick/scenegraph/qsgwindowsrenderloop_p.h b/src/quick/scenegraph/qsgwindowsrenderloop_p.h index ff5529646b..e4ee688c9f 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop_p.h +++ b/src/quick/scenegraph/qsgwindowsrenderloop_p.h @@ -81,8 +81,6 @@ public: void render(); void renderWindow(QQuickWindow *window); - void resize(QQuickWindow *, const QSize &) { } - bool event(QEvent *event); bool anyoneShowing() const; -- cgit v1.2.3 From 51da186db0d4596b6b31b6353ac9f11343cc984f Mon Sep 17 00:00:00 2001 From: Daniel Teske Date: Wed, 20 Nov 2013 16:54:16 +0100 Subject: Android: Add qmltooling plugins to apk Task-number: QTCREATORBUG-10560 Change-Id: Ifabe6a74552dbc74b1de3030f8d60efda865f84a Reviewed-by: Aurindam Jana Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/qml/qml.pro | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 6d26d9cb38..08bda0bce7 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -7,6 +7,9 @@ win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000 win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 +MODULE_PLUGIN_TYPES = \ + qmltooling + exists("qqml_enable_gcov") { QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors LIBS += -lgcov -- cgit v1.2.3 From c962cc45711e09dddc5690d581bee29bf52f8cf9 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 25 Nov 2013 08:25:21 +0100 Subject: Do not crash when resizing invisible (non-tracked) windows. Change-Id: I776c21a0f675d2dbe831325cef2c1c2a103e03e5 Reviewed-by: Simon Hausmann --- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index e50d034529..bca7736e79 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -886,9 +886,10 @@ void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window) void QSGThreadedRenderLoop::resize(QQuickWindow *window) { Window *w = windowFor(m_windows, window); - if (w->gotBrokenExposeFromPlatformPlugin - && window->width() > 0 && window->height() > 0 - && w->window->geometry().intersects(w->window->screen()->availableGeometry())) { + if (w + && w->gotBrokenExposeFromPlatformPlugin + && window->width() > 0 && window->height() > 0 + && w->window->geometry().intersects(w->window->screen()->availableGeometry())) { w->gotBrokenExposeFromPlatformPlugin = false; handleExposure(w); } -- cgit v1.2.3 From 26350b5ceafa0ade1328037f6234a7d288eb8f48 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 25 Nov 2013 10:11:10 +0100 Subject: Allow for QtQml and QtDeclarative to co-exist at run-time This patch changes QQmlData to share the very first bit with QDeclarativeData, to indicate if the QObject in question is exposed in the QML1 or QML2 run-time. Task-number: QTBUG-35006 Change-Id: I3aa1d7c99038792011afd9f481ad30d9b981721f Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/qml/qml/qqmldata_p.h | 5 +++-- src/qml/qml/qqmlengine.cpp | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 76d03f011e..621b3d3c2e 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -79,7 +79,7 @@ class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData { public: QQmlData() - : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), + : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), hasTaintedV8Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), hasVMEMetaObject(false), parentFrozen(false), notifyList(0), context(0), outerContext(0), bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0), @@ -113,6 +113,7 @@ public: if (!explicitIndestructibleSet) indestructible = false; } + quint32 ownedByQml1:1; // This bit is shared with QML1's QDeclarativeData. quint32 ownMemory:1; quint32 ownContext:1; quint32 indestructible:1; @@ -126,7 +127,7 @@ public: quint32 rootObjectInCreation:1; quint32 hasVMEMetaObject:1; quint32 parentFrozen:1; - quint32 dummy:23; + quint32 dummy:22; struct NotifyList { quint64 connectionMask; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 81ccec3571..d082b9a8fd 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -615,12 +615,18 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o) { - static_cast(d)->destroyed(o); + QQmlData *ddata = static_cast(d); + if (ddata->ownedByQml1) + return; + ddata->destroyed(o); } void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p) { - static_cast(d)->parentChanged(o, p); + QQmlData *ddata = static_cast(d); + if (ddata->ownedByQml1) + return; + ddata->parentChanged(o, p); } class QQmlThreadNotifierProxyObject : public QObject @@ -649,6 +655,7 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in { QQmlData *ddata = QQmlData::get(object, false); if (!ddata) return; // Probably being deleted + if (ddata->ownedByQml1) return; // In general, QML only supports QObject's that live on the same thread as the QQmlEngine // that they're exposed to. However, to make writing "worker objects" that calculate data @@ -706,12 +713,18 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index) { - return static_cast(d)->endpointCount(index); + QQmlData *ddata = static_cast(d); + if (ddata->ownedByQml1) + return 0; + return ddata->endpointCount(index); } bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d, const QObject *, int index) { - return static_cast(d)->signalHasEndpoint(index); + QQmlData *ddata = static_cast(d); + if (ddata->ownedByQml1) + return false; + return ddata->signalHasEndpoint(index); } int QQmlData::endpointCount(int index) -- cgit v1.2.3 From 70c37506e9e7c7228ca823cff0f75a5813f3bcb7 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 25 Nov 2013 15:58:36 +0100 Subject: Fix memory corruption in QML expression compilation We store QQmlPropertyData pointers in our IR for Qt meta-object property resolution at compile time. As it turns out however, it is possible that these pointers change after retrieval from the QQmlPropertyCache, as the cache may change later in the compilation process. Therefore we must do what also QQmlCompiler does by storing a copy of the QQmlPropertyData. For the JS IR we can do that conveniently through the IR memory pool. A side-effect of this bug was that QQmlPropertyData pointers were re-used and so the identity check in the isel later such as _function->contextObjectDependencies.contains(m->property) for dependency tracking failed. In the example given in the bug report it was determined that the window.contentWidth property wouldn't need a property capture, and therefore the binding was not re-evaluated as window.contentWidth later in the binding evaluation phase received its correct value. This patch also fixes the incorrect debug output names assigned to JS binding expressions, where the index used to look up the name is per compiled object, not per QML component. Task-number: QTBUG-35063 Change-Id: I3e5bbfaac11e5c122a2ed15a3e486a93988e1b6e Reviewed-by: J-P Nurmi Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlcodegenerator.cpp | 9 ++++++++- src/qml/compiler/qqmlcodegenerator_p.h | 2 ++ src/qml/qml/qqmlcompiler.cpp | 6 ++---- src/qml/qml/qqmlcompiler_p.h | 1 + 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index c16dd5daea..2215551b95 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -1292,7 +1292,7 @@ QVector JSCodeGen::generateJSCodeForFunctionsAndBindings(const QListisAllowedInRevision(pd)) pd = 0; + // Return a copy allocated from our memory pool. Property data pointers can change + // otherwise when the QQmlPropertyCache changes later in the QML type compilation process. + if (pd) { + QQmlPropertyData *copy = pd; + pd = _function->New(); + *pd = *copy; + } return pd; } diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h index 1cc5b1e2f6..a5fec65111 100644 --- a/src/qml/compiler/qqmlcodegenerator_p.h +++ b/src/qml/compiler/qqmlcodegenerator_p.h @@ -371,6 +371,8 @@ protected: virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col); private: + QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup = 0); + QQmlEnginePrivate *engine; QString sourceCode; QQmlJS::Engine *jsEngine; // needed for memory pool diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 7b33849e67..93ec2516c8 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -3630,8 +3630,6 @@ bool QQmlCompiler::completeComponentBuild() QQmlJS::Engine *jsEngine = parser.jsEngine(); QQmlJS::MemoryPool *pool = jsEngine->pool(); - QHash expressionNames; - for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) { JSBindingReference &binding = *b; @@ -3648,7 +3646,7 @@ bool QQmlCompiler::completeComponentBuild() ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[b->bindingContext.object]; cd->functionsToCompile.append(node); binding.compiledIndex = cd->functionsToCompile.count() - 1; - expressionNames.insert(binding.compiledIndex, binding.property->name().toString().prepend(QStringLiteral("expression for "))); + cd->expressionNames.insert(binding.compiledIndex, binding.property->name().toString().prepend(QStringLiteral("expression for "))); if (componentStats) componentStats->componentStat.scriptBindings.append(b->value->location); @@ -3681,7 +3679,7 @@ bool QQmlCompiler::completeComponentBuild() jsCodeGen.beginObjectScope(scopeObject->metatype); - cd->runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(cd->functionsToCompile, expressionNames); + cd->runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(cd->functionsToCompile, cd->expressionNames); QList errors = jsCodeGen.errors(); if (!errors.isEmpty()) { exceptions << errors; diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index 2e3e6b8f4c..3ca4566e41 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -315,6 +315,7 @@ namespace QQmlCompilerTypes { QList functionsToCompile; QVector runtimeFunctionIndices; QVector compiledMetaMethods; + QHash expressionNames; }; QHash jsCompileData; }; -- cgit v1.2.3 From 0d1e1ddbf5732f1755d31020f82c540f2a69f756 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 22 Nov 2013 19:13:20 +0100 Subject: No assert when the focus changes and a window has no active focus item. [ChangeLog][QtQuick] Fix crash when showing and hiding a window that has no active focus item. QtQuickControls hit the situation where a popup window was shown without ever having an active focus item. When then closing the popup, clearFocusInScope would assume it had to always modify the old focus, but in this case the focus would be on the window itself, so there is nothing to update. Task-number: QTBUG-35057 Change-Id: Ifbde4689d39f98b13e6f90573cb22e28bb86f2c4 Reviewed-by: J-P Nurmi Reviewed-by: Liang Qi --- src/quick/items/qquickwindow.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 796ddcfbe4..848eeca2a6 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -771,23 +771,24 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, oldActiveFocusItem = activeFocusItem; newActiveFocusItem = scope; - Q_ASSERT(oldActiveFocusItem); - #ifndef QT_NO_IM qApp->inputMethod()->commit(); #endif activeFocusItem = 0; - QFocusEvent event(QEvent::FocusOut, reason); - q->sendEvent(oldActiveFocusItem, &event); - QQuickItem *afi = oldActiveFocusItem; - while (afi && afi != scope) { - if (QQuickItemPrivate::get(afi)->activeFocus) { - QQuickItemPrivate::get(afi)->activeFocus = false; - changed << afi; + if (oldActiveFocusItem) { + QFocusEvent event(QEvent::FocusOut, reason); + q->sendEvent(oldActiveFocusItem, &event); + + QQuickItem *afi = oldActiveFocusItem; + while (afi && afi != scope) { + if (QQuickItemPrivate::get(afi)->activeFocus) { + QQuickItemPrivate::get(afi)->activeFocus = false; + changed << afi; + } + afi = afi->parentItem(); } - afi = afi->parentItem(); } } -- cgit v1.2.3 From c81632df3e9d52011487cfe0bd2e40ba5c5f2d54 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 25 Nov 2013 10:06:36 +0100 Subject: Fix rendering of Flipable content. When a batch is merged in the renderer, we use the z component to stack the item front to back. This works because each item is guaranteed to have a z-range of 0->1. However, when a projective matrix is used, we need to compensate for the implicit [x,y,z]/w, which GL applies to gl_Position after the vertex stage completes, so that this guarantee still holds. Task-number: QTBUG-35020 Change-Id: I254a3d4dc9ad22f53717160ec6ad8f3a27b43d1c Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp index 909def2c19..2849eff304 100644 --- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp +++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp @@ -222,7 +222,7 @@ QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat braceDepth--; if (braceDepth == 0) { result += QByteArray::fromRawData(voidPos, tok.pos - 1 - voidPos); - result += QByteArrayLiteral(" gl_Position.z = gl_Position.z * _qt_zRange + _qt_order;\n"); + result += QByteArrayLiteral(" gl_Position.z = (gl_Position.z * _qt_zRange + _qt_order) * gl_Position.w;\n"); result += QByteArray(tok.pos - 1); return result; } -- cgit v1.2.3 From 2331a5ef5765d1b99472cd05e1af4b84d59c0177 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 25 Nov 2013 11:40:12 +0100 Subject: Stop render thread regardless when the window is being destroyed When a window is shown and quickly hidden again we can get to a state, on a asynchronous windowing system API, where the isExposed=true event has been pushed to the event queue but not yet processed at the time the user calls hide(). As hide() immediately sets isVisible() to false, we end up with isExposed=true and isVisible=false which prevent the WM_Obscure event to be sent to render loop which means the render thread thought the window was still on screen when we reched the shutdown in WM_TryRelease. Changed WM_TryRelease handling to disregard window state when the window is being deleted. This forces SG and GL cleanup and stops the thread. Task-number: QTBUG-35055 Change-Id: Ibac5aa27354d6450f30a61450214cb785ab855bf Reviewed-by: J-P Nurmi Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index bca7736e79..850a463c3e 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -402,8 +402,8 @@ bool QSGRenderThread::event(QEvent *e) case WM_TryRelease: { QSG_RT_DEBUG("WM_TryRelease"); mutex.lock(); - if (!window) { - WMTryReleaseEvent *wme = static_cast(e); + WMTryReleaseEvent *wme = static_cast(e); + if (!window || wme->inDestructor) { QSG_RT_DEBUG(" - setting exit flag and invalidating GL"); invalidateOpenGL(wme->window, wme->inDestructor); active = gl; -- cgit v1.2.3 From 87da2a2526aa03dd43254730a6e675e83c7c1342 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 22 Nov 2013 18:52:22 +0100 Subject: Use QFontDatabase to check if a font is scalable. The flag set in QFontEngine was not always correctly set, use QFontDatabase instead which is slower but should always be correct. We fallback to native font rendering when the font is not scalable. Change-Id: Ie9a2397abd42890d0fb05bc2f9c46a60040296f2 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/items/qquicktextnode.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp index dd314c892d..18ee1a479d 100644 --- a/src/quick/items/qquicktextnode.cpp +++ b/src/quick/items/qquicktextnode.cpp @@ -143,10 +143,13 @@ QSGGlyphNode *QQuickTextNode::addGlyphs(const QPointF &position, const QGlyphRun QSGNode *parentNode) { QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext(); - QRawFontPrivate *fontP = QRawFontPrivate::get(glyphs.rawFont()); - QSGGlyphNode *node = m_useNativeRenderer || !fontP->fontEngine->smoothScalable + QRawFont font = glyphs.rawFont(); + bool smoothScalable = QFontDatabase().isSmoothlyScalable(font.familyName(), + font.styleName()); + QSGGlyphNode *node = m_useNativeRenderer || !smoothScalable ? sg->sceneGraphContext()->createNativeGlyphNode(sg) : sg->sceneGraphContext()->createGlyphNode(sg); + node->setOwnerElement(m_ownerElement); node->setGlyphs(position + QPointF(0, glyphs.rawFont().ascent()), glyphs); node->setStyle(style); -- cgit v1.2.3 From ce38c71b1c300f700a9ff004b7c163cc290ecae9 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 25 Nov 2013 09:21:27 +0100 Subject: Fix out of bounds array access when index is integer and negative When the index is a double, the branchTruncateDoubleToUInt takes care of branching when the index is negative, but when it's an integer we need to perform that check ourselves. Without the patch it's rather easy to cause the application to crash. Change-Id: If908923ddc2077b3fb3dd42350f038ff0072e8e1 Reviewed-by: Mitch Curtis Reviewed-by: Lars Knoll --- src/qml/compiler/qv4isel_masm.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 9d470c417d..a999dd4da1 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -1039,10 +1039,13 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR: _as->and32(Assembler::TrustedImm32(QV4::Managed::SimpleArray), Assembler::ReturnValueRegister); Assembler::Jump notSimple = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0)); + bool needNegativeCheck = false; Assembler::Jump fallback, fallback2; if (tindex->kind == V4IR::Temp::PhysicalRegister) { if (tindex->type == V4IR::SInt32Type) { + fallback = _as->branch32(Assembler::LessThan, (Assembler::RegisterID)tindex->index, Assembler::TrustedImm32(0)); _as->move((Assembler::RegisterID) tindex->index, Assembler::ScratchRegister); + needNegativeCheck = true; } else { // double, convert and check if it's a int fallback2 = _as->branchTruncateDoubleToUint32((Assembler::FPRegisterID) tindex->index, Assembler::ScratchRegister); @@ -1068,13 +1071,17 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR: isInteger.link(_as); _as->or32(Assembler::TrustedImm32(0), Assembler::ScratchRegister); + needNegativeCheck = true; } // get data, ScratchRegister holds index addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase); _as->load64(addr, Assembler::ReturnValueRegister); Address arrayDataLen(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayDataLen)); - Assembler::Jump outOfRange = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, arrayDataLen); + Assembler::Jump outOfRange; + if (needNegativeCheck) + outOfRange = _as->branch32(Assembler::LessThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); + Assembler::Jump outOfRange2 = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, arrayDataLen); Address arrayData(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData)); _as->load64(arrayData, Assembler::ReturnValueRegister); Q_ASSERT(sizeof(Property) == (1<<4)); @@ -1092,7 +1099,9 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR: Assembler::Jump done = _as->jump(); emptyValue.link(_as); - outOfRange.link(_as); + if (outOfRange.isSet()) + outOfRange.link(_as); + outOfRange2.link(_as); if (fallback.isSet()) fallback.link(_as); if (fallback2.isSet()) -- cgit v1.2.3