summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/CMakeLists.txt1
-rw-r--r--src/corelib/Qt6AndroidGradleHelpers.cmake2
-rw-r--r--src/corelib/doc/images/modelindex-no-parent.svg99
-rw-r--r--src/corelib/doc/src/cmake/cmake-properties.qdoc4
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.cpp2
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm.cpp12
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm_p.h2
-rw-r--r--src/corelib/platform/wasm/qwasmlocalfileengine.cpp422
-rw-r--r--src/corelib/platform/wasm/qwasmlocalfileengine_p.h102
-rw-r--r--src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp7
-rw-r--r--src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h10
11 files changed, 656 insertions, 7 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 539ad753ca6..e50838730cb 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -1533,6 +1533,7 @@ qt_internal_extend_target(Core CONDITION WASM
platform/wasm/qstdweb.cpp platform/wasm/qstdweb_p.h
platform/wasm/qwasmsocket.cpp platform/wasm/qwasmsocket_p.h
platform/wasm/qwasmsuspendresumecontrol.cpp platform/wasm/qwasmsuspendresumecontrol_p.h
+ platform/wasm/qwasmlocalfileengine.cpp platform/wasm/qwasmlocalfileengine_p.h
kernel/qeventdispatcher_wasm.cpp kernel/qeventdispatcher_wasm_p.h
)
diff --git a/src/corelib/Qt6AndroidGradleHelpers.cmake b/src/corelib/Qt6AndroidGradleHelpers.cmake
index f71bac4e08a..fc8e009b9da 100644
--- a/src/corelib/Qt6AndroidGradleHelpers.cmake
+++ b/src/corelib/Qt6AndroidGradleHelpers.cmake
@@ -193,7 +193,7 @@ function(_qt_internal_android_generate_target_build_gradle target)
QT_ANDROID_MIN_SDK_VERSION "28")
_qt_internal_android_get_gradle_property(target_sdk_version ${target}
- QT_ANDROID_TARGET_SDK_VERSION "34")
+ QT_ANDROID_TARGET_SDK_VERSION "36")
set(target_abis "$<TARGET_PROPERTY:${target},_qt_android_abis>")
set(target_abi_list "$<JOIN:${target_abis};${CMAKE_ANDROID_ARCH_ABI},'$<COMMA> '>")
diff --git a/src/corelib/doc/images/modelindex-no-parent.svg b/src/corelib/doc/images/modelindex-no-parent.svg
new file mode 100644
index 00000000000..4ce4b86b1f2
--- /dev/null
+++ b/src/corelib/doc/images/modelindex-no-parent.svg
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="300"
+ height="160"
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+
+<style>
+ svg .line-style { stroke: black; fill: none }
+ svg .fill-style { stroke: black; fill: #c0c0c0 }
+ svg .text-style { font: 12px arial; fill: black }
+ svg .italic-style { font: 12px arial; fill: black; font-style: italic }
+ svg .bold-style { font: 12px arial; fill: black; font-weight: bold }
+
+ svg.dark .line-style { stroke: #f2f2f2; fill: none }
+ svg.dark .fill-style { stroke: #f2f2f2; fill: #606060 }
+ svg.dark .text-style { font: 12px arial; fill: #f2f2f2 }
+ svg.dark .italic-style { font: 12px arial; fill: #f2f2f2; font-style: italic }
+ svg.dark .bold-style { font: 12px arial; fill: #f2f2f2; font-weight: bold }
+
+ [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none }
+ [data-theme="dark"] svg .fill-style { stroke: #f2f2f2; fill: #606060 }
+ [data-theme="dark"] svg .text-style { font: 12px arial; fill: #f2f2f2 }
+ [data-theme="dark"] svg .italic-style { font: 12px arial; fill: #f2f2f2; font-style: italic }
+ [data-theme="dark"] svg .bold-style { font: 12px arial; fill: #f2f2f2; font-weight: bold }
+
+ [data-theme="light"] svg .line-style { stroke: black; fill: none }
+ [data-theme="light"] svg .fill-style { stroke: black; fill: #c0c0c0 }
+ [data-theme="light"] svg .text-style { font: 12px arial; fill: black }
+ [data-theme="light"] svg .italic-style { font: 12px arial; fill: black; font-style: italic }
+ [data-theme="light"] svg .bold-style { font: 12px arial; fill: black; font-weight: bold }
+</style>
+
+<text x="25" y="49" font-family="arial" font-size="12px"
+ class="text-style">0</text>
+<text x="25" y="79" font-family="arial" font-size="12px"
+ class="text-style">1</text>
+<text x="25" y="109" font-family="arial" font-size="12px"
+ class="text-style">2</text>
+<g transform="translate(30,139)">
+<text x="0" y="0" font-family="arial" font-size="12px"
+ class="text-style" transform="rotate(270)">...</text>
+</g>
+
+<path d="m 40.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" />
+<path d="m 70.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" />
+<path d="m 100.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" />
+<path d="m 130.5,30.5 h 30 v 30" stroke="black" fill="none"
+ class="line-style" stroke-dasharray="3, 3" />
+<path d="m 40.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" />
+<path d="m 70.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" />
+<path d="m 100.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="#c0c0c0"
+ class="fill-style" />
+<path d="m 130.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" stroke-dasharray="3, 3" />
+<path d="m 40.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" />
+<path d="m 70.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" />
+<path d="m 100.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" />
+<path d="m 70.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" stroke-dasharray="3, 3" />
+<path d="m 40.5,120.5 v 30 h 30" stroke="black" fill="none"
+ class="line-style" stroke-dasharray="3, 3" />
+<path d="m 100.5,150.5 h 30" stroke="black"
+ class="line-style" stroke-dasharray="3, 3" />
+<path d="m 130.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="none"
+ class="line-style" stroke-dasharray="3, 3" />
+<path d="m 160.5,90.5 v 30" stroke="black"
+ class="line-style" stroke-dasharray="3, 3" />
+
+<text x="50" y="20" font-family="arial" font-size="12px"
+ class="text-style">0</text>
+<text x="80" y="20" font-family="arial" font-size="12px"
+ class="text-style">1</text>
+<text x="110" y="20" font-family="arial" font-size="12px"
+ class="text-style">2</text>
+<text x="140" y="20" font-family="arial" font-size="12px"
+ class="text-style">...</text>
+
+<text x="190" y="55" font-family="arial" font-size="12px" font-weight="bold"
+ class="bold-style">Model index</text>
+<rect x="185.5" y="60.5" width="77" height="37" stroke="black" fill="none"
+ class="line-style" />
+<text x="190" y="75" font-family="arial" font-size="12px"
+ class="text-style">row = 1</text>
+<text x="190" y="92" font-family="arial" font-size="12px"
+ class="text-style">column = 2</text>
+
+<path d="m 185.5,85.5 c -35,0 -35,-10 -70,-10" stroke="black" fill="none"
+ stroke-dasharray="2, 2" class="line-style" />
+</svg>
diff --git a/src/corelib/doc/src/cmake/cmake-properties.qdoc b/src/corelib/doc/src/cmake/cmake-properties.qdoc
index c7b1a27a4b4..310debf7edc 100644
--- a/src/corelib/doc/src/cmake/cmake-properties.qdoc
+++ b/src/corelib/doc/src/cmake/cmake-properties.qdoc
@@ -239,7 +239,7 @@ precedence over this CMake property.
\badcode
set_target_properties(${target} PROPERTIES
- QT_ANDROID_COMPILE_SDK_VERSION 35
+ QT_ANDROID_COMPILE_SDK_VERSION 36
)
\endcode
@@ -247,7 +247,7 @@ The following format also works:
\badcode
set_target_properties(${target} PROPERTIES
- QT_ANDROID_COMPILE_SDK_VERSION "android-35"
+ QT_ANDROID_COMPILE_SDK_VERSION "android-36"
)
\endcode
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp
index 58a057009ff..8b0a05ee6ed 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.cpp
+++ b/src/corelib/itemmodels/qabstractitemmodel.cpp
@@ -1390,7 +1390,7 @@ void QAbstractItemModel::resetInternalData()
simple table of rows and columns. Each item has a unique index specified by
a QModelIndex.
- \image modelindex-no-parent.png {Screenshot showing a 3x3 grid with numbered
+ \image modelindex-no-parent.svg {Diagram showing a 3x3 grid with numbered
rows and columns that shows the cell at row 1, column 2 highlighted.}
Every item of data that can be accessed via a model has an associated model
diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp
index f7edf3285f8..25a27a0c22b 100644
--- a/src/corelib/kernel/qeventdispatcher_wasm.cpp
+++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp
@@ -150,6 +150,18 @@ bool QEventDispatcherWasm::isValidEventDispatcherPointer(QEventDispatcherWasm *e
bool QEventDispatcherWasm::processEvents(QEventLoop::ProcessEventsFlags flags)
{
+ // Accept the current event if event handling recurses / event loop is reentered,
+ // to prevent the browser from propagating it to other event handlers.
+ if (useAsyncify() && isMainThreadEventDispatcher()) {
+ auto control = QWasmSuspendResumeControl::get();
+ auto currentEvent = control->currentEvent();
+ if (!currentEvent.isUndefined() && currentEvent.instanceof(emscripten::val::global("Event"))) {
+ currentEvent.call<void>("preventDefault");
+ currentEvent.call<void>("stopPropagation");
+ control->setCurrentEvent(emscripten::val::undefined());
+ }
+ }
+
emit awake();
if (!useAsyncify() && isMainThreadEventDispatcher())
diff --git a/src/corelib/kernel/qeventdispatcher_wasm_p.h b/src/corelib/kernel/qeventdispatcher_wasm_p.h
index 674af85dac2..1946bf63ede 100644
--- a/src/corelib/kernel/qeventdispatcher_wasm_p.h
+++ b/src/corelib/kernel/qeventdispatcher_wasm_p.h
@@ -40,7 +40,6 @@ public:
~QEventDispatcherWasm();
bool processEvents(QEventLoop::ProcessEventsFlags flags) override;
- bool sendAllEvents(QEventLoop::ProcessEventsFlags flag);
void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType,
QObject *object) override final;
@@ -69,6 +68,7 @@ protected:
virtual bool sendPostedEvents();
private:
+ bool sendAllEvents(QEventLoop::ProcessEventsFlags flag);
bool isMainThreadEventDispatcher();
bool isSecondaryThreadEventDispatcher();
bool isValidEventDispatcher();
diff --git a/src/corelib/platform/wasm/qwasmlocalfileengine.cpp b/src/corelib/platform/wasm/qwasmlocalfileengine.cpp
new file mode 100644
index 00000000000..58e662d5fde
--- /dev/null
+++ b/src/corelib/platform/wasm/qwasmlocalfileengine.cpp
@@ -0,0 +1,422 @@
+// Copyright (C) 2025 Qt Group
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qwasmlocalfileengine_p.h"
+#include <QtCore/QDebug>
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+// Custom URL scheme for files handled by this file engine. A complete file URL can
+// look like
+//
+// "weblocalfile:/n/file.ext"
+//
+// where n is a counter to ensure uniqueness, needed since web platform gives us the file name only
+// and does not provide the file path.
+//
+// The scheme may be visible to end users if the application displays it, so
+// we avoid using "wasm" and instead say "web", which should be more recognizable.
+static constexpr QLatin1StringView wasmlocalfileScheme = "weblocalfile"_L1;
+
+// Instantiate the engine, the system will pick it up automatically
+// Never destroy it to avoid problems with static destruction.
+// The OS will reclaim the memory anyway,
+// TODO: cleanup on QApplication destruction and re-init on QApplication re-creation.
+static QWasmFileEngineHandler *singleton = new QWasmFileEngineHandler();
+
+QWasmFileEngineHandler::QWasmFileEngineHandler()
+{
+}
+
+QWasmFileEngineHandler::~QWasmFileEngineHandler()
+{
+}
+
+std::unique_ptr<QAbstractFileEngine> QWasmFileEngineHandler::create(const QString &fileName) const
+{
+ if (!QWasmFileEngineHandler::isWasmFileName(fileName))
+ return {};
+
+ // Check if it's a File or FileSystemFileHandle
+ if (singleton->m_files.contains(fileName)) {
+ qstdweb::File file = singleton->m_files.value(fileName);
+ return std::make_unique<QWasmFileEngine>(fileName, file);
+ } else if (singleton->m_fileSystemFiles.contains(fileName)) {
+ qstdweb::FileSystemFileHandle file = singleton->m_fileSystemFiles.value(fileName);
+ return std::make_unique<QWasmFileEngine>(fileName, file);
+ }
+
+ // Not an error, this function will be called with partial paths like "weblocalfile:/1/"
+ return {};
+}
+
+// Check if this is a wasm filename by checking the URL scheme.
+bool QWasmFileEngineHandler::isWasmFileName(const QString& fileName)
+{
+ return QUrl(fileName).scheme() == wasmlocalfileScheme;
+}
+
+// Creates a wasm filename using the custom URL scheme and a counter.
+QString QWasmFileEngineHandler::makeWasmFileName(const QString &nativeFileName)
+{
+ static std::atomic<uint64_t> sid = 0;
+ const uint64_t id = ++sid;
+ return wasmlocalfileScheme + QStringLiteral(":/%1/%2").arg(id).arg(nativeFileName);
+}
+
+// Extracts the native filename from the custom URL (removes scheme and counter).
+QString QWasmFileEngineHandler::nativeFileName(const QString &wasmFileName)
+{
+ QUrl url(wasmFileName);
+ if (url.scheme() == wasmlocalfileScheme) {
+ QString path = url.path();
+ // Path is "/n/filename", find the second '/' and extract the filename
+ const qsizetype idx = path.indexOf(u'/', 1);
+ if (idx != -1)
+ return path.mid(idx + 1);
+ }
+ return wasmFileName;
+}
+
+// Adds a File to the set of open files. Returns a prefixed wasm file name.
+QString QWasmFileEngineHandler::addFile(qstdweb::File file)
+{
+ QString nativeFileName = QString::fromStdString(file.name());
+ QString wasmFileName = makeWasmFileName(nativeFileName);
+ singleton->m_files.insert(wasmFileName, file);
+ return wasmFileName;
+}
+
+// Adds a FileSystemFileHandle to the set of open files. Returns a prefixed wasm file name.
+QString QWasmFileEngineHandler::addFile(qstdweb::FileSystemFileHandle file)
+{
+ QString nativeFileName = QString::fromStdString(file.name());
+ QString wasmFileName = makeWasmFileName(nativeFileName);
+ singleton->m_fileSystemFiles.insert(wasmFileName, file);
+ return wasmFileName;
+}
+
+// Removes a File or FileSystemFileHandle from the set of open file handlers
+void QWasmFileEngineHandler::removeFile(const QString fileName)
+{
+ singleton->m_files.remove(fileName);
+ singleton->m_fileSystemFiles.remove(fileName);
+}
+
+qstdweb::File QWasmFileEngineHandler::getFile(const QString fileName)
+{
+ return singleton->m_files.value(fileName);
+}
+
+qstdweb::FileSystemFileHandle QWasmFileEngineHandler::getFileSystemFile(const QString fileName)
+{
+ return singleton->m_fileSystemFiles.value(fileName);
+}
+
+/*!
+ \class QWasmFileEngine
+ \brief The QWasmFileEngine class provides a QAbstractFileEngine
+ for files that has the prefix ':weblocalfile/'.
+*/
+
+// Constructs a QWasmFileEngine with a File for read-only access
+QWasmFileEngine::QWasmFileEngine(const QString &fileName, qstdweb::File file)
+ : m_fileName(fileName),
+ m_blobDevice(std::make_unique<qstdweb::BlobIODevice>(file.slice(0, file.size())))
+{
+ // TODO use m_blobDevice in unbuffered mode? if there is already a buffer higher up.
+}
+
+// Constructs a QWasmFileEngine with a FileSystemFileHandle for read-write access
+QWasmFileEngine::QWasmFileEngine(const QString &fileName, qstdweb::FileSystemFileHandle file)
+ : m_fileName(fileName),
+ m_fileDevice(std::make_unique<qstdweb::FileSystemFileIODevice>(file))
+{
+
+}
+
+QWasmFileEngine::~QWasmFileEngine()
+{
+ close();
+}
+
+bool QWasmFileEngine::open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions)
+{
+ Q_UNUSED(permissions);
+ m_openMode = openMode;
+
+ if (m_fileDevice)
+ return m_fileDevice->open(openMode);
+ else if (m_blobDevice)
+ return m_blobDevice->open(openMode);
+
+ return false;
+}
+
+bool QWasmFileEngine::close()
+{
+ if (m_openMode == QIODevice::NotOpen)
+ return false;
+
+ bool success = true;
+ if (m_fileDevice) {
+ m_fileDevice->close();
+ }
+ if (m_blobDevice) {
+ m_blobDevice->close();
+ }
+
+ m_openMode = QIODevice::NotOpen;
+ return success;
+}
+
+bool QWasmFileEngine::flush()
+{
+ return true;
+}
+
+bool QWasmFileEngine::syncToDisk()
+{
+ return true;
+}
+
+qint64 QWasmFileEngine::size() const
+{
+ if (m_fileDevice)
+ return m_fileDevice->size();
+ if (m_blobDevice)
+ return m_blobDevice->size();
+ return 0;
+}
+
+qint64 QWasmFileEngine::pos() const
+{
+ if (m_fileDevice)
+ return m_fileDevice->pos();
+ if (m_blobDevice)
+ return m_blobDevice->pos();
+ return 0;
+}
+
+bool QWasmFileEngine::seek(qint64 pos)
+{
+ if (m_fileDevice)
+ return m_fileDevice->seek(pos);
+ if (m_blobDevice)
+ return m_blobDevice->seek(pos);
+ return false;
+}
+
+bool QWasmFileEngine::isSequential() const
+{
+ return false;
+}
+
+bool QWasmFileEngine::remove()
+{
+ return false;
+}
+
+bool QWasmFileEngine::copy(const QString &newName)
+{
+ Q_UNUSED(newName);
+ return false;
+}
+
+bool QWasmFileEngine::rename(const QString &newName)
+{
+ Q_UNUSED(newName);
+ return false;
+}
+
+bool QWasmFileEngine::renameOverwrite(const QString &newName)
+{
+ Q_UNUSED(newName);
+ return false;
+}
+
+bool QWasmFileEngine::link(const QString &newName)
+{
+ Q_UNUSED(newName);
+ return false;
+}
+
+bool QWasmFileEngine::mkdir(const QString &dirName, bool createParentDirectories,
+ std::optional<QFile::Permissions> permissions) const
+{
+ Q_UNUSED(dirName);
+ Q_UNUSED(createParentDirectories);
+ Q_UNUSED(permissions);
+ return false;
+}
+
+bool QWasmFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
+{
+ Q_UNUSED(dirName);
+ Q_UNUSED(recurseParentDirectories);
+ return false;
+}
+
+bool QWasmFileEngine::setSize(qint64 size)
+{
+ Q_UNUSED(size);
+ return false;
+}
+
+bool QWasmFileEngine::caseSensitive() const
+{
+ return true;
+}
+
+bool QWasmFileEngine::isRelativePath() const
+{
+ return false;
+}
+
+
+QAbstractFileEngine::FileFlags QWasmFileEngine::fileFlags(FileFlags type) const
+{
+ return type & (QAbstractFileEngine::FileFlag::ExistsFlag |
+ QAbstractFileEngine::FileFlag::FileType |
+ QAbstractFileEngine::FileFlag::ReadOwnerPerm |
+ QAbstractFileEngine::FileFlag::WriteOwnerPerm);
+}
+
+bool QWasmFileEngine::setPermissions(uint perms)
+{
+ Q_UNUSED(perms);
+ return false;
+}
+
+QByteArray QWasmFileEngine::id() const
+{
+ return {};
+}
+
+QString QWasmFileEngine::fileName(FileName file) const
+{
+ switch (file) {
+ case DefaultName:
+ case AbsoluteName:
+ case CanonicalName:
+ return m_fileName;
+ case BaseName: {
+ QString native = QWasmFileEngineHandler::nativeFileName(m_fileName);
+ QFileInfo info(native);
+ return info.fileName();
+ }
+ case PathName:
+ case AbsolutePathName:
+ case CanonicalPathName: {
+ QString native = QWasmFileEngineHandler::nativeFileName(m_fileName);
+ QFileInfo info(native);
+ QString path = info.path();
+ return path.isEmpty() ? "."_L1 : path;
+ }
+ default:
+ return QString();
+ }
+}
+
+uint QWasmFileEngine::ownerId(FileOwner) const
+{
+ return 0;
+}
+
+QString QWasmFileEngine::owner(FileOwner) const
+{
+ return {};
+}
+
+bool QWasmFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
+{
+ Q_UNUSED(newDate);
+ Q_UNUSED(time);
+ return false;
+}
+
+QDateTime QWasmFileEngine::fileTime(QFile::FileTime time) const
+{
+ Q_UNUSED(time);
+ return {};
+}
+
+void QWasmFileEngine::setFileName(const QString &file)
+{
+ if (m_fileName == file)
+ return;
+ close();
+ m_fileName = file;
+}
+
+int QWasmFileEngine::handle() const
+{
+ return -1;
+}
+
+QAbstractFileEngine::TriStateResult QWasmFileEngine::cloneTo(QAbstractFileEngine *target)
+{
+ Q_UNUSED(target);
+ return QAbstractFileEngine::TriStateResult::NotSupported;
+}
+
+QAbstractFileEngine::IteratorUniquePtr QWasmFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters,
+ const QStringList &filterNames)
+{
+ Q_UNUSED(path);
+ Q_UNUSED(filters);
+ Q_UNUSED(filterNames);
+ return nullptr;
+}
+
+qint64 QWasmFileEngine::read(char *data, qint64 maxlen)
+{
+ if (!(m_openMode & QIODevice::ReadOnly))
+ return -1;
+
+ if (m_fileDevice)
+ return m_fileDevice->read(data, maxlen);
+ if (m_blobDevice)
+ return m_blobDevice->read(data, maxlen);
+ return -1;
+}
+
+qint64 QWasmFileEngine::readLine(char *data, qint64 maxlen)
+{
+ if (!(m_openMode & QIODevice::ReadOnly))
+ return -1;
+
+ if (m_fileDevice)
+ return m_fileDevice->readLine(data, maxlen);
+ if (m_blobDevice)
+ return m_blobDevice->readLine(data, maxlen);
+ return -1;
+}
+
+qint64 QWasmFileEngine::write(const char *data, qint64 len)
+{
+ if (!(m_openMode & QIODevice::WriteOnly))
+ return -1;
+
+ if (m_fileDevice)
+ return m_fileDevice->write(data, len);
+ return -1;
+}
+
+bool QWasmFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
+{
+ Q_UNUSED(extension);
+ Q_UNUSED(option);
+ Q_UNUSED(output);
+ return false;
+}
+
+bool QWasmFileEngine::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension);
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/platform/wasm/qwasmlocalfileengine_p.h b/src/corelib/platform/wasm/qwasmlocalfileengine_p.h
new file mode 100644
index 00000000000..dd82788dd90
--- /dev/null
+++ b/src/corelib/platform/wasm/qwasmlocalfileengine_p.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2024 Qt Group
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QWASMLOCALFILEENGINE_P_H
+#define QWASMLOCALFILEENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qabstractfileengine_p.h>
+#include <QtCore/private/qstdweb_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmFileEngine;
+
+class QWasmFileEngineHandler: public QAbstractFileEngineHandler
+{
+public:
+ Q_DISABLE_COPY_MOVE(QWasmFileEngineHandler)
+
+ QWasmFileEngineHandler();
+ virtual ~QWasmFileEngineHandler() override;
+ virtual std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const override;
+
+ static bool isWasmFileName(const QString& fileName);
+ static QString makeWasmFileName(const QString &fileName);
+ static QString nativeFileName(const QString &wasmFileName);
+
+ static QString addFile(qstdweb::File file);
+ static QString addFile(qstdweb::FileSystemFileHandle file);
+ static void removeFile(const QString fileName);
+ qstdweb::File getFile(const QString fileName);
+ qstdweb::FileSystemFileHandle getFileSystemFile(const QString fileName);
+
+private:
+ QHash<QString, qstdweb::File> m_files;
+ QHash<QString, qstdweb::FileSystemFileHandle> m_fileSystemFiles;
+};
+
+class QWasmFileEngine: public QAbstractFileEngine
+{
+public:
+ explicit QWasmFileEngine(const QString &fileName, qstdweb::File file);
+ explicit QWasmFileEngine(const QString &fileName, qstdweb::FileSystemFileHandle file);
+ ~QWasmFileEngine() override;
+
+ virtual bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override;
+ virtual bool close() override;
+ virtual bool flush() override;
+ virtual bool syncToDisk() override;
+ virtual qint64 size() const override;
+ virtual qint64 pos() const override;
+ virtual bool seek(qint64 pos) override;
+ virtual bool isSequential() const override;
+ virtual bool remove() override;
+ virtual bool copy(const QString &newName) override;
+ virtual bool rename(const QString &newName) override;
+ virtual bool renameOverwrite(const QString &newName) override;
+ virtual bool link(const QString &newName) override;
+ virtual bool mkdir(const QString &dirName, bool createParentDirectories,
+ std::optional<QFile::Permissions> permissions = std::nullopt) const override;
+ virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const override;
+ virtual bool setSize(qint64 size) override;
+ virtual bool caseSensitive() const override;
+ virtual bool isRelativePath() const override;
+ virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const override;
+ virtual bool setPermissions(uint perms) override;
+ virtual QByteArray id() const override;
+ virtual QString fileName(FileName file = DefaultName) const override;
+ virtual uint ownerId(FileOwner) const override;
+ virtual QString owner(FileOwner) const override;
+ virtual bool setFileTime(const QDateTime &newDate, QFile::FileTime time) override;
+ virtual QDateTime fileTime(QFile::FileTime time) const override;
+ virtual void setFileName(const QString &file) override;
+ virtual int handle() const override;
+ virtual TriStateResult cloneTo(QAbstractFileEngine *target) override;
+ virtual IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters,
+ const QStringList &filterNames) override;
+ virtual qint64 read(char *data, qint64 maxlen) override;
+ virtual qint64 readLine(char *data, qint64 maxlen) override;
+ virtual qint64 write(const char *data, qint64 len) override;
+ virtual bool extension(Extension extension, const ExtensionOption *option = nullptr,
+ ExtensionReturn *output = nullptr) override;
+ virtual bool supportsExtension(Extension extension) const override;
+
+private:
+ QString m_fileName;
+ QIODevice::OpenMode m_openMode = QIODevice::NotOpen;
+ std::unique_ptr<qstdweb::BlobIODevice> m_blobDevice;
+ std::unique_ptr<qstdweb::FileSystemFileIODevice> m_fileDevice;
+};
+
+QT_END_NAMESPACE
+#endif // QWASMFILEENGINEHANDLER_H
diff --git a/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp b/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp
index a4bc7843380..85358d1daf4 100644
--- a/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp
+++ b/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp
@@ -225,8 +225,11 @@ int QWasmSuspendResumeControl::sendPendingEvents()
pendingEvents.call<void>("splice", i, 1);
auto it = m_eventHandlers.find(event["index"].as<int>());
- if (it != m_eventHandlers.end())
- it->second(event["arg"]);
+ if (it != m_eventHandlers.end()) {
+ setCurrentEvent(event["arg"]);
+ it->second(currentEvent());
+ setCurrentEvent(emscripten::val::undefined());
+ }
++count;
}
}
diff --git a/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h b/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h
index ff97ff3d7ea..4e75d5674be 100644
--- a/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h
+++ b/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h
@@ -42,12 +42,22 @@ public:
void suspendExclusive(QList<uint32_t> eventHandlerIndices);
int sendPendingEvents();
+ emscripten::val currentEvent() const
+ {
+ return m_currentEvent;
+ }
+ void setCurrentEvent(emscripten::val currentEvent)
+ {
+ m_currentEvent = currentEvent;
+ }
+
private:
friend void qtSendPendingEvents();
static QWasmSuspendResumeControl *s_suspendResumeControl;
std::map<int, std::function<void(emscripten::val)>> m_eventHandlers;
std::function<bool(int)> m_eventFilter = [](int) { return true; };
+ emscripten::val m_currentEvent = emscripten::val::undefined();
};
class Q_CORE_EXPORT QWasmEventHandler