summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt1
-rw-r--r--src/plugins/platforms/wasm/qwasmdom.cpp79
-rw-r--r--src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp157
-rw-r--r--src/plugins/platforms/wasm/qwasmfiledialoghelper.h49
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.cpp13
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.h3
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp2
8 files changed, 270 insertions, 36 deletions
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt
index 03cb0d52ca1..7e9beb7e832 100644
--- a/src/plugins/platforms/wasm/CMakeLists.txt
+++ b/src/plugins/platforms/wasm/CMakeLists.txt
@@ -33,6 +33,7 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h
qwasminputcontext.cpp qwasminputcontext.h
qwasmwindowstack.h
+ qwasmfiledialoghelper.cpp qwasmfiledialoghelper.h
DEFINES
QT_EGL_NO_X11
QT_NO_FOREACH
diff --git a/src/plugins/platforms/wasm/qwasmdom.cpp b/src/plugins/platforms/wasm/qwasmdom.cpp
index 71efcee7887..eefd18154aa 100644
--- a/src/plugins/platforms/wasm/qwasmdom.cpp
+++ b/src/plugins/platforms/wasm/qwasmdom.cpp
@@ -10,6 +10,7 @@
#include <QtCore/qrect.h>
#include <QtGui/qimage.h>
#include <private/qstdweb_p.h>
+#include <private/qwasmlocalfileengine_p.h>
#include <QtCore/qurl.h>
#include <utility>
@@ -112,11 +113,14 @@ void DataTransfer::toMimeDataWithFile(std::function<void(QMimeData *)> callback)
m_callback(mimeData);
- // Delete files; we expect that the user callback reads/copies
- // file content before returning.
- // Fixme: tie file lifetime to lifetime of the QMimeData?
- for (QUrl fileUrl: fileUrls)
- QFile(fileUrl.toLocalFile()).remove();
+ // Delete temporary files; we expect that the user callback reads/copies
+ // file content before returning.// Fixme: tie file lifetime to lifetime of the QMimeData?
+ // Note: QWasmFileEngine files (weblocalfile://) are managed by QWasmFileEngine
+ // and are not deleted here
+ for (QUrl fileUrl: fileUrls) {
+ if (!QWasmFileEngineHandler::isWasmFileName(fileUrl.toString()))
+ QFile(fileUrl.toLocalFile()).remove();
+ }
delete this;
}
@@ -144,49 +148,56 @@ void DataTransfer::toMimeDataWithFile(std::function<void(QMimeData *)> callback)
case ItemKind::File: {
qstdweb::File webfile(item.call<emscripten::val>("getAsFile"));
- if (webfile.size() > 1e+9) { // limit file size to 1 GB
- qWarning() << "File is too large (> 1GB) and will be skipped. File size is" << webfile.size();
+ // Add a file access url for the local file. If asyncify is available,
+ // add a QWasmFileEngine managed url. Else fall back to placing a copy
+ // of the file at /tmp on Emsripten's in-memory file system.
+ if (qstdweb::haveAsyncify()) {
+ QUrl fileUrl(QWasmFileEngineHandler::addFile(webfile));
+ mimeContext->fileUrls.append(fileUrl);
mimeContext->deref();
- continue;
- }
+ } else {
+ // Limit in-memory file size to 1 GB
+ if (webfile.size() > 1e+9) {
+ qWarning() << "File is too large (> 1GB) and will be skipped. File size is" << webfile.size();
+ mimeContext->deref();
+ continue;
+ }
- QString mimeFormat = QString::fromStdString(webfile.type());
- QString fileName = QString::fromStdString(webfile.name());
+ // Read file content
+ QByteArray fileContent(webfile.size(), Qt::Uninitialized);
+ webfile.stream(fileContent.data(), [=]() {
+ QDir qtTmpDir("/qt/tmp/"); // "tmp": indicate that these files won't stay around
+ qtTmpDir.mkpath(qtTmpDir.path());
+
+ QUrl fileUrl = QUrl::fromLocalFile(qtTmpDir.filePath(QString::fromStdString(webfile.name())));
+ mimeContext->fileUrls.append(fileUrl);
+
+ QFile file(fileUrl.toLocalFile());
+ if (!file.open(QFile::WriteOnly)) {
+ qWarning() << "File was not opened";
+ mimeContext->deref();
+ return;
+ }
+ if (file.write(fileContent) < 0)
+ qWarning() << "Write failed";
+ file.close();
+ mimeContext->deref();
+ });
- // there's a file, now read it
- QByteArray fileContent(webfile.size(), Qt::Uninitialized);
- webfile.stream(fileContent.data(), [=]() {
-
// If we get a single file, and that file is an image, then
// try to decode the image data. This handles the case where
// image data (i.e. not an image file) is pasted. The browsers
// will then create a fake "image.png" file which has the image
- // data. As a side effect Qt will also decode the image for
+ // data. As a side effect Qt will also decode the image for
// single-image-file drops, since there is no way to differentiate
// the fake "image.png" from a real one.
+ QString mimeFormat = QString::fromStdString(webfile.type());
if (fileCount == 1 && mimeFormat.contains("image/")) {
QImage image;
if (image.loadFromData(fileContent))
mimeContext->mimeData->setImageData(image);
}
-
- QDir qtTmpDir("/qt/tmp/"); // "tmp": indicate that these files won't stay around
- qtTmpDir.mkpath(qtTmpDir.path());
-
- QUrl fileUrl = QUrl::fromLocalFile(qtTmpDir.filePath(QString::fromStdString(webfile.name())));
- mimeContext->fileUrls.append(fileUrl);
-
- QFile file(fileUrl.toLocalFile());
- if (!file.open(QFile::WriteOnly)) {
- qWarning() << "File was not opened";
- mimeContext->deref();
- return;
- }
- if (file.write(fileContent) < 0)
- qWarning() << "Write failed";
- file.close();
- mimeContext->deref();
- });
+ }
break;
}
case ItemKind::String:
diff --git a/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp b/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp
new file mode 100644
index 00000000000..1e6e2b1f644
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp
@@ -0,0 +1,157 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmfiledialoghelper.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QUrl>
+#include <QtGui/private/qwasmlocalfileaccess_p.h>
+#include <QtCore/private/qwasmlocalfileengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QWasmFileDialogHelper::QWasmFileDialogHelper()
+ : m_eventLoop(nullptr)
+{
+
+}
+
+QWasmFileDialogHelper::~QWasmFileDialogHelper()
+{
+
+}
+
+bool QWasmFileDialogHelper::defaultNameFilterDisables() const
+{
+ return false;
+}
+
+void QWasmFileDialogHelper::setDirectory(const QUrl &directory)
+{
+ Q_UNUSED(directory)
+}
+
+QUrl QWasmFileDialogHelper::directory() const
+{
+ return QUrl();
+}
+
+void QWasmFileDialogHelper::selectFile(const QUrl &file)
+{
+ m_selectedFiles.clear();
+ m_selectedFiles.append(file);
+}
+
+QList<QUrl> QWasmFileDialogHelper::selectedFiles() const
+{
+ return m_selectedFiles;
+}
+
+void QWasmFileDialogHelper::setFilter()
+{
+
+}
+
+void QWasmFileDialogHelper::selectNameFilter(const QString &filter)
+{
+ Q_UNUSED(filter);
+ // TODO
+}
+
+QString QWasmFileDialogHelper::selectedNameFilter() const
+{
+ return QString();
+}
+
+void QWasmFileDialogHelper::exec()
+{
+ QEventLoop eventLoop;
+ m_eventLoop = &eventLoop;
+ eventLoop.exec();
+ m_eventLoop = nullptr;
+}
+
+bool QWasmFileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ Q_UNUSED(flags)
+ Q_UNUSED(modality)
+ Q_UNUSED(parent)
+ showFileDialog();
+ return true;
+}
+
+void QWasmFileDialogHelper::hide()
+{
+
+}
+
+void QWasmFileDialogHelper::showFileDialog()
+{
+ if (options()->acceptMode() == QFileDialogOptions::AcceptOpen) {
+ // Use name filters from options
+ QString nameFilter = options()->nameFilters().join(";;");
+ if (nameFilter.isEmpty())
+ nameFilter = "*";
+
+ QWasmLocalFileAccess::showOpenFileDialog(nameFilter.toStdString(), [this](bool accepted, std::vector<qstdweb::File> files) {
+ onOpenDialogClosed(accepted, files);
+ });
+ } else if (options()->acceptMode() == QFileDialogOptions::AcceptSave) {
+ QString suggestion = m_selectedFiles.isEmpty() ? QString() : QUrl(m_selectedFiles.first()).fileName();
+ m_selectedFiles.clear();
+
+ QWasmLocalFileAccess::showSaveFileDialog(suggestion.toStdString(), [this](bool accepted, qstdweb::FileSystemFileHandle file){
+ onSaveDialogClosed(accepted, file);
+ });
+ }
+}
+
+void QWasmFileDialogHelper::onOpenDialogClosed(bool accepted, std::vector<qstdweb::File> files)
+{
+ m_selectedFiles.clear();
+
+ if (!accepted) {
+ emit reject();
+ return;
+ }
+
+ // Track opened files
+ for (const auto &file : files) {
+ QString wasmFileName = QWasmFileEngineHandler::addFile(file);
+ QUrl fileUrl(wasmFileName);
+ m_selectedFiles.append(fileUrl);
+ }
+
+ // Emit signals
+ if (m_selectedFiles.size() > 0) {
+ emit fileSelected(m_selectedFiles.first());
+ emit filesSelected(m_selectedFiles);
+ }
+ emit accept();
+
+ // exit exec() if in exec()
+ if (m_eventLoop)
+ m_eventLoop->quit();
+}
+
+void QWasmFileDialogHelper::onSaveDialogClosed(bool accepted, qstdweb::FileSystemFileHandle file)
+{
+ if (!accepted) {
+ emit reject();
+ return;
+ }
+
+ // Track save file
+ QString wasmFileName = QWasmFileEngineHandler::addFile(file);
+ QUrl fileUrl(wasmFileName);
+ m_selectedFiles.append(fileUrl);
+
+ // Emit signals
+ emit fileSelected(m_selectedFiles.first());
+ emit accept();
+
+ if (m_eventLoop)
+ m_eventLoop->quit();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmfiledialoghelper.h b/src/plugins/platforms/wasm/qwasmfiledialoghelper.h
new file mode 100644
index 00000000000..c5a5b57e518
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmfiledialoghelper.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMFILEDIALOGHELPER_H
+#define QWASMFILEDIALOGHELPER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QUrl>
+#include <QtCore/QEventLoop>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+#include <QtGui/private/qwasmlocalfileaccess_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmFileDialogHelper : public QPlatformFileDialogHelper
+{
+ Q_OBJECT
+public:
+ QWasmFileDialogHelper();
+ ~QWasmFileDialogHelper();
+public:
+ virtual void exec() override;
+ virtual bool show(Qt::WindowFlags windowFlags,
+ Qt::WindowModality windowModality,
+ QWindow *parent) override;
+ virtual void hide() override;
+ virtual bool defaultNameFilterDisables() const override;
+ virtual void setDirectory(const QUrl &directory) override;
+ virtual QUrl directory() const override;
+ virtual void selectFile(const QUrl &filename) override;
+ virtual QList<QUrl> selectedFiles() const override;
+ virtual void setFilter() override;
+ virtual void selectNameFilter(const QString &filter) override;
+ virtual QString selectedNameFilter() const override;
+ static QStringList cleanFilterList(const QString &filter);
+signals:
+ void fileDone(const QUrl &);
+private:
+ void showFileDialog();
+ void onOpenDialogClosed(bool accepted, std::vector<qstdweb::File> files);
+ void onSaveDialogClosed(bool accepted, qstdweb::FileSystemFileHandle file);
+
+ QList<QUrl> m_selectedFiles;
+ QEventLoop *m_eventLoop;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMFILEDIALOGHELPER_H
diff --git a/src/plugins/platforms/wasm/qwasmtheme.cpp b/src/plugins/platforms/wasm/qwasmtheme.cpp
index b9340f31275..b1e5c208c6c 100644
--- a/src/plugins/platforms/wasm/qwasmtheme.cpp
+++ b/src/plugins/platforms/wasm/qwasmtheme.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmtheme.h"
+#include "qwasmfiledialoghelper.h"
#include <QtCore/qvariant.h>
#include <QFontDatabase>
#include <QList>
@@ -127,6 +128,18 @@ const QFont *QWasmTheme::font(Font type) const
return nullptr;
}
+bool QWasmTheme::usePlatformNativeDialog(DialogType type) const
+{
+ return (type == DialogType::FileDialog);
+}
+
+QPlatformDialogHelper *QWasmTheme::createPlatformDialogHelper(DialogType type) const
+{
+ if (type == DialogType::FileDialog)
+ return new QWasmFileDialogHelper();
+ return nullptr;
+}
+
void QWasmTheme::onColorSchemeChange()
{
auto colorScheme = getColorSchemeFromMedia();
diff --git a/src/plugins/platforms/wasm/qwasmtheme.h b/src/plugins/platforms/wasm/qwasmtheme.h
index 4eaad874c76..8b8dd6ebd97 100644
--- a/src/plugins/platforms/wasm/qwasmtheme.h
+++ b/src/plugins/platforms/wasm/qwasmtheme.h
@@ -57,6 +57,9 @@ public:
Qt::ContrastPreference contrastPreference() const override;
QVariant themeHint(ThemeHint hint) const override;
const QFont *font(Font type) const override;
+ bool usePlatformNativeDialog(DialogType type) const override;
+ QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
+
QFont *fixedFont = nullptr;
void onColorSchemeChange();
diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp
index 6e8bd46ca58..7f1dd7eb34c 100644
--- a/src/plugins/platforms/wasm/qwasmwindow.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -925,7 +925,7 @@ bool QWasmWindow::deliverPointerEvent(const PointerEvent &event)
std::back_inserter(touchPointList),
[](const QWindowSystemInterface::TouchPoint &val) { return val; });
- if (event.type == EventType::PointerUp)
+ if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
m_pointerIdToTouchPoints.remove(event.pointerId);
return event.type == EventType::PointerCancel
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 2816982b1a8..9459e8bdfd3 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -848,7 +848,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
// make mouse events fall through this window
// NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
if (flagsIn & Qt::WindowTransparentForInput)
- exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
+ exStyle |= WS_EX_TRANSPARENT;
// Currently only compatible with D3D surfaces, use it with care.
if (qEnvironmentVariableIntValue("QT_QPA_DISABLE_REDIRECTION_SURFACE"))