qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(asyncify_exec)
add_subdirectory(eventloop_auto)
add_subdirectory(main_exec)
add_subdirectory(main_noexec)
add_subdirectory(thread_exec)
if(QT_FEATURE_widgets)
add_subdirectory(dialog_exec)
endif()

View File

@ -0,0 +1,15 @@
Event loop exec() and main() on Qt for WebAssembly
==================================================
These examples demonstrate how QEventLoop::exec() works on
Qt for WebAssembly, and also shows how to implement main()
without calling QApplication::exec().
Contents
========
main_exec Standard Qt main(), where QApplication::exec() does not return
main_noexec Qt main() without QApplication::exec()
dialog_exec Shows how QDialog::exec() also does not return
thread_exec Shows how to use QThread::exec()
eventloop_auto Event loop autotest (manually run)

View File

@ -0,0 +1,12 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_manual_test(asyncify_exec
SOURCES
main.cpp
LIBRARIES
Qt::Core
)
# Enable asyncify for this test. Also enable optimizations in order to reduce the binary size.
target_link_options(asyncify_exec PUBLIC -sASYNCIFY -Os)

View File

@ -0,0 +1,25 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtCore>
// This test shows how to use asyncify to enable blocking the main
// thread on QEventLoop::exec(), while event processing continues.
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QTimer::singleShot(1000, []() {
QEventLoop loop;
QTimer::singleShot(2000, [&loop]() {
qDebug() << "Calling QEventLoop::quit()";
loop.quit();
});
qDebug() << "Calling QEventLoop::exec()";
loop.exec();
qDebug() << "Returned from QEventLoop::exec()";
});
app.exec();
}

View File

@ -0,0 +1,12 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_manual_test(dialog_exec
GUI
SOURCES
main.cpp
LIBRARIES
Qt::Core
Qt::Gui
Qt::Widgets
)

View File

@ -0,0 +1,48 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtGui>
#include <QtWidgets>
// This example show how calling QDialog::exec() shows the dialog,
// but does not return.
class ClickWindow: public QRasterWindow
{
public:
ClickWindow() {
qDebug() << "ClickWindow constructor";
}
~ClickWindow() {
qDebug() << "ClickWindow destructor";
}
void paintEvent(QPaintEvent *ev) override {
QPainter p(this);
p.fillRect(ev->rect(), QColorConstants::Svg::deepskyblue);
p.drawText(50, 100, "Application has started. See the developer tools console for debug output");
}
void mousePressEvent(QMouseEvent *) override {
qDebug() << "mousePressEvent(): calling QMessageBox::exec()";
QMessageBox messageBox;
messageBox.setText("Hello! This is a message box.");
connect(&messageBox, &QMessageBox::buttonClicked, [](QAbstractButton *button) {
qDebug() << "Button Clicked" << button;
});
messageBox.exec(); // <-- does not return
qDebug() << "mousePressEvent(): done"; // <--- will not be printed
}
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
ClickWindow window;
window.show();
return app.exec();
}

View File

@ -0,0 +1,43 @@
include_directories(../../qtwasmtestlib/)
# default buid
qt_internal_add_manual_test(eventloop_auto
SOURCES
main.cpp
../../qtwasmtestlib/qtwasmtestlib.cpp
LIBRARIES
Qt::Core
Qt::CorePrivate
)
add_custom_command(
TARGET eventloop_auto POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/eventloop_auto.html
${CMAKE_CURRENT_BINARY_DIR}/eventloop_auto.html)
add_custom_command(
TARGET eventloop_auto POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/../../qtwasmtestlib/qtwasmtestlib.js
${CMAKE_CURRENT_BINARY_DIR}/qtwasmtestlib.js)
# asyncify enabled build
qt_internal_add_manual_test(eventloop_auto_asyncify
SOURCES
main.cpp
../../qtwasmtestlib/qtwasmtestlib.cpp
LIBRARIES
Qt::Core
Qt::CorePrivate
)
target_link_options(eventloop_auto_asyncify PRIVATE -sASYNCIFY -Os)
add_custom_command(
TARGET eventloop_auto_asyncify POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/eventloop_auto_asyncify.html
${CMAKE_CURRENT_BINARY_DIR}/eventloop_auto_asyncify.html)

View File

@ -0,0 +1,10 @@
<!doctype html>
<script type="text/javascript" src="qtwasmtestlib.js"></script>
<script type="text/javascript" src="eventloop_auto.js"></script>
<script>
window.onload = () => {
runTestCase(document.getElementById("log"));
};
</script>
<p>Running event dispatcher auto test.</p>
<div id="log"></div>

View File

@ -0,0 +1,10 @@
<!doctype html>
<script type="text/javascript" src="qtwasmtestlib.js"></script>
<script type="text/javascript" src="eventloop_auto_asyncify.js"></script>
<script>
window.onload = () => {
runTestCase(document.getElementById("log"));
};
</script>
<p>Running event dispatcher auto test.</p>
<div id="log"></div>

View File

@ -0,0 +1,327 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/QCoreApplication>
#include <QtCore/QEvent>
#include <QtCore/QMutex>
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QTimer>
#include <QtCore/private/qstdweb_p.h>
#include <qtwasmtestlib.h>
#include "emscripten.h"
const int timerTimeout = 10;
class WasmEventDispatcherTest: public QObject
{
Q_OBJECT
private slots:
void postEventMainThread();
void timerMainThread();
void timerMainThreadMultiple();
#if QT_CONFIG(thread)
void postEventSecondaryThread();
void postEventSecondaryThreads();
void postEventToSecondaryThread();
void timerSecondaryThread();
#endif
void postEventAsyncify();
void timerAsyncify();
void postEventAsyncifyLoop();
private:
// Disabled test function: Asyncify wait on pthread_join is not supported,
// see https://github.com/emscripten-core/emscripten/issues/9910
#if QT_CONFIG(thread)
void threadAsyncifyWait();
#endif
};
class EventTarget : public QObject
{
Q_OBJECT
public:
static EventTarget *create(std::function<void()> callback)
{
return new EventTarget(callback);
}
static QEvent *createEvent()
{
return new QEvent(QEvent::User);
}
protected:
EventTarget(std::function<void()> callback)
: m_callback(callback) { }
bool event(QEvent *evt)
{
if (evt->type() == QEvent::User) {
m_callback();
deleteLater();
return true;
}
return QObject::event(evt);
}
private:
std::function<void()> m_callback;
};
class CompleteTestFunctionRefGuard {
public:
CompleteTestFunctionRefGuard(CompleteTestFunctionRefGuard const&) = delete;
CompleteTestFunctionRefGuard& operator=(CompleteTestFunctionRefGuard const&) = delete;
static CompleteTestFunctionRefGuard *create() {
return new CompleteTestFunctionRefGuard();
}
void ref() {
QMutexLocker lock(&mutex);
++m_counter;
}
void deref() {
const bool finalDeref = [this] {
QMutexLocker lock(&mutex);
return --m_counter == 0;
}();
if (finalDeref)
QtWasmTest::completeTestFunction();
}
private:
CompleteTestFunctionRefGuard() { };
QMutex mutex;
int m_counter = 0;
};
#if QT_CONFIG(thread)
class TestThread : public QThread
{
public:
static QThread *create(std::function<void()> started, std::function<void()> finished)
{
TestThread *thread = new TestThread();
connect(thread, &QThread::started, [started]() {
started();
});
connect(thread, &QThread::finished, [thread, finished]() {
finished();
thread->deleteLater();
});
thread->start();
return thread;
}
};
#endif
// Post event to the main thread and verify that it is processed.
void WasmEventDispatcherTest::postEventMainThread()
{
QCoreApplication::postEvent(EventTarget::create([](){
QtWasmTest::completeTestFunction();
}), EventTarget::createEvent());
}
// Create a timer on the main thread and verify that it fires
void WasmEventDispatcherTest::timerMainThread()
{
QTimer::singleShot(timerTimeout, [](){
QtWasmTest::completeTestFunction();
});
}
void WasmEventDispatcherTest::timerMainThreadMultiple()
{
CompleteTestFunctionRefGuard *completeGuard = CompleteTestFunctionRefGuard::create();
int timers = 10;
for (int i = 0; i < timers; ++i) {
completeGuard->ref();
QTimer::singleShot(timerTimeout * i, [completeGuard](){
completeGuard->deref();
});
}
}
#if QT_CONFIG(thread)
// Post event on a secondary thread and verify that it is processed.
void WasmEventDispatcherTest::postEventSecondaryThread()
{
auto started = [](){
QCoreApplication::postEvent(EventTarget::create([](){
QThread::currentThread()->quit();
}), EventTarget::createEvent());
};
auto finished = [](){
QtWasmTest::completeTestFunction();
};
TestThread::create(started, finished);
}
// Post event _to_ a secondary thread and verify that it is processed.
void WasmEventDispatcherTest::postEventToSecondaryThread()
{
auto started = [](){};
auto finished = [](){
QtWasmTest::completeTestFunction();
};
QThread *t = TestThread::create(started, finished);
EventTarget *target = EventTarget::create([](){
QThread::currentThread()->quit();
});
target->moveToThread(t);
QCoreApplication::postEvent(target, EventTarget::createEvent());
}
// Post events to many secondary threads and verify that they are processed.
void WasmEventDispatcherTest::postEventSecondaryThreads()
{
// This test completes afer all threads has finished
CompleteTestFunctionRefGuard *completeGuard = CompleteTestFunctionRefGuard::create();
completeGuard->ref(); // including this thread
auto started = [](){
QCoreApplication::postEvent(EventTarget::create([](){
QThread::currentThread()->quit();
}), EventTarget::createEvent());
};
auto finished = [completeGuard](){
completeGuard->deref();
};
// Start a nymber of threads in parallel, keeping in mind that the browser
// has some max number of concurrent web workers (maybe 20), and that starting
// a new web worker requires completing a GET network request for the worker's JS.
const int numThreads = 10;
for (int i = 0; i < numThreads; ++i) {
completeGuard->ref();
TestThread::create(started, finished);
}
completeGuard->deref();
}
// Create a timer a secondary thread and verify that it fires
void WasmEventDispatcherTest::timerSecondaryThread()
{
auto started = [](){
QTimer::singleShot(timerTimeout, [](){
QThread::currentThread()->quit();
});
};
auto finished = [](){
QtWasmTest::completeTestFunction();
};
TestThread::create(started, finished);
}
#endif
// Post an event to the main thread and asyncify wait for it
void WasmEventDispatcherTest::postEventAsyncify()
{
if (!qstdweb::haveAsyncify()) {
QtWasmTest::completeTestFunction(QtWasmTest::TestResult::Skip, "requires asyncify");
return;
}
QEventLoop loop;
QCoreApplication::postEvent(EventTarget::create([&loop](){
loop.quit();
}), EventTarget::createEvent());
loop.exec();
QtWasmTest::completeTestFunction();
}
// Create a timer on the main thread and asyncify wait for it
void WasmEventDispatcherTest::timerAsyncify()
{
if (!qstdweb::haveAsyncify()) {
QtWasmTest::completeTestFunction(QtWasmTest::TestResult::Skip, "requires asyncify");
return;
}
QEventLoop loop;
QTimer::singleShot(timerTimeout, [&loop](){
loop.quit();
});
loop.exec();
QtWasmTest::completeTestFunction();
}
// Asyncify wait in a loop
void WasmEventDispatcherTest::postEventAsyncifyLoop()
{
if (!qstdweb::haveAsyncify()) {
QtWasmTest::completeTestFunction(QtWasmTest::TestResult::Skip, "requires asyncify");
return;
}
for (int i = 0; i < 10; ++i) {
QEventLoop loop;
QCoreApplication::postEvent(EventTarget::create([&loop]() {
loop.quit();
}), EventTarget::createEvent());
loop.exec();
}
QtWasmTest::completeTestFunction();
}
#if QT_CONFIG(thread)
// Asyncify wait for QThread::wait() / pthread_join()
void WasmEventDispatcherTest::threadAsyncifyWait()
{
if (!qstdweb::haveAsyncify())
QtWasmTest::completeTestFunction(QtWasmTest::TestResult::Skip, "requires asyncify");
const int threadCount = 15;
QVector<QThread *> threads;
threads.reserve(threadCount);
for (int i = 0; i < threadCount; ++i) {
QThread *thread = new QThread();
threads.push_back(thread);
thread->start();
}
for (int i = 0; i < threadCount; ++i) {
QThread *thread = threads[i];
thread->wait();
delete thread;
}
QtWasmTest::completeTestFunction();
}
#endif
int main(int argc, char **argv)
{
auto testObject = std::make_shared<WasmEventDispatcherTest>();
QtWasmTest::initTestCase<QCoreApplication>(argc, argv, testObject);
return 0;
}
#include "main.moc"

View File

@ -0,0 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_manual_test(main_exec
GUI
SOURCES
main.cpp
LIBRARIES
Qt::Core
Qt::Gui
)

View File

@ -0,0 +1,67 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtGui>
// This example demonstrates how the standard Qt main()
// pattern works on Emscripten/WebAssambly, where exec()
// does not return.
class ClickWindow: public QRasterWindow
{
public:
ClickWindow() {
qDebug() << "ClickWindow constructor";
}
~ClickWindow() {
qDebug() << "ClickWindow destructor";
}
void paintEvent(QPaintEvent *ev) override {
QPainter p(this);
p.fillRect(ev->rect(), QColorConstants::Svg::deepskyblue);
p.drawText(50, 100, "Application has started. See the developer tools console for debug output");
}
void mousePressEvent(QMouseEvent *) override {
qDebug() << "mousePressEvent(): calling QGuiApplication::quit()";
QGuiApplication::quit();
}
};
int main(int argc, char **argv)
{
qDebug() << "main(): Creating QGuiApplication object";
QGuiApplication app(argc, argv);
QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){
qDebug() << "QCoreApplication::aboutToQuit";
});
ClickWindow window;
window.show();
qDebug() << "main(): calling exec()";
app.exec();
// The exec() call above never returns; instead, a JavaScript exception
// is thrown such that control returns to the browser while preserving
// the C++ stack.
// This means that the window object above is not destroyed, and that
// shutdown code after exec() does not run.
qDebug() << "main(): after exit"; // <- will not be printed
}
// Global variables are created before main() as usual, but not destroyed
class Global
{
public:
Global() {
qDebug() << "Global constructor";
}
~Global() {
qDebug() << "Global destructor"; // <- will not be printed
}
};
Global global;

View File

@ -0,0 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_manual_test(main_noexec
GUI
SOURCES
main.cpp
LIBRARIES
Qt::Core
Qt::Gui
)

View File

@ -0,0 +1,66 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtGui>
// This example demonstrates how to create QGuiApplication
// without calling exec(), and then exiting main() without
// shutting down the Qt event loop.
class ClickWindow: public QRasterWindow
{
public:
ClickWindow() {
qDebug() << "ClickWindow constructor";
}
~ClickWindow() {
qDebug() << "ClickWindow destructor";
}
void paintEvent(QPaintEvent *ev) override {
QPainter p(this);
p.fillRect(ev->rect(), QColorConstants::Svg::deepskyblue);
p.drawText(50, 100, "Application has started. See the developer tools console for debug output");
}
void mousePressEvent(QMouseEvent *) override {
qDebug() << "mousePressEvent(): calling QGuiApplication::quit()";
QGuiApplication::quit();
}
};
int main(int argc, char **argv)
{
qDebug() << "main(): Creating QGuiApplication object";
QGuiApplication *app = new QGuiApplication(argc, argv);
QObject::connect(app, &QCoreApplication::aboutToQuit, [](){
qDebug() << "QCoreApplication::aboutToQuit";
});
qDebug() << "main(): Creating ClickWindow object";
ClickWindow *window = new ClickWindow();
window->show();
// We can exit main; the Qt event loop and the emscripten runtime
// will keep running, as long as Emscriptens EXIT_RUNTIME option
// has not been enabled.
qDebug() << "main(): exit";
}
// Global variables are created before main() as usual, but not destroyed
class Global
{
public:
Global() {
qDebug() << "Global constructor";
}
~Global() {
qDebug() << "Global destructor"; // <- will not be printed
}
};
Global global;

View File

@ -0,0 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_manual_test(thread_exec
GUI
SOURCES
main.cpp
LIBRARIES
Qt::Core
Qt::Gui
)

View File

@ -0,0 +1,75 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtGui>
class EventTarget : public QObject
{
Q_OBJECT
protected:
bool event(QEvent *evt)
{
if (evt->type() == QEvent::User) {
qDebug() << "User event on thread" << QThread::currentThread();
return true;
}
return QObject::event(evt);
}
};
class EventPosterWindow: public QRasterWindow
{
public:
EventPosterWindow(EventTarget *target)
:m_target(target)
{ }
void paintEvent(QPaintEvent *ev) override {
QPainter p(this);
p.fillRect(ev->rect(), QColorConstants::Svg::deepskyblue);
p.drawText(50, 100, "Application has started. Click to post events.\n See the developer tools console for debug output");
}
void mousePressEvent(QMouseEvent *) override {
qDebug() << "Posting events from thread" << QThread::currentThread();
QGuiApplication::postEvent(m_target, new QEvent(QEvent::User));
QTimer::singleShot(500, m_target, []() {
qDebug() << "Timer event on secondary thread" << QThread::currentThread();
});
}
public:
EventTarget *m_target;
};
class SecondaryThread : public QThread
{
public:
void run() override {
qDebug() << "exec on secondary thread" << QThread::currentThread();
exec();
}
};
// This example demonstrates how to start a secondary thread event loop
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
EventTarget eventTarget;
EventPosterWindow window(&eventTarget);
window.show();
SecondaryThread thread;
eventTarget.moveToThread(&thread);
#if QT_CONFIG(thread)
thread.start();
#else
qDebug() << "Warning: This test requires a multithreaded build of Qt for WebAssembly";
#endif
return app.exec();
}
#include "main.moc"