diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-03-20 01:00:08 +0100 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2019-03-20 14:09:30 +0100 |
commit | 6893919b0c4cddfbd82ebf963cc7bebde816b1b3 (patch) | |
tree | 9bfa1b57707fe609f9401c5b3bd5cd85ec1ae777 | |
parent | Wasm: Build with Qt's freetype, png and zlib (diff) | |
parent | Don't quit when last QWindow is destroyed, wait for it to close (diff) | |
download | qtbase-6893919b0c4cddfbd82ebf963cc7bebde816b1b3.tar.xz qtbase-6893919b0c4cddfbd82ebf963cc7bebde816b1b3.zip |
Merge remote-tracking branch 'origin/5.12' into 5.13
Conflicts:
src/gui/kernel/qplatformintegration.cpp
src/gui/kernel/qplatformintegration.h
src/plugins/platforms/wasm/qwasmintegration.cpp
src/plugins/platforms/xcb/qxcbconnection_screens.cpp
Change-Id: I15063d42e9a1e226d9d2d2d372f75141b84c5c1b
81 files changed, 1321 insertions, 359 deletions
diff --git a/dist/changes-5.12.2 b/dist/changes-5.12.2 new file mode 100644 index 0000000000..dc61d135a7 --- /dev/null +++ b/dist/changes-5.12.2 @@ -0,0 +1,105 @@ +Qt 5.12.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + - QtTestLib: + * [QTBUG-72928] Blacklisting of tests will be taken into account for + XPASS and XFAIL. A blacklisted test that causes an XPASS will no + longer be a fail. + +**************************************************************************** +* QtCore * +**************************************************************************** + + - [QTBUG-72885] Fixed a number of warnings with Clang or Clang-Tidy in + Qt headers related to alignment of Qt private classes. + + - QDate, QTime and QDateTime; + * [QTBUG-51208] Corrected documentation of how non-placeholder + characters are handled in format patterns passed to toString(). + + - QCoreApplication: + * [QTBUG-57171] Fixed an out-of-bounds access if the translatable + string passed to tr() ended in '%'. + + - QFileInfo: + * [QTBUG-72644] Fixed a bug that would cause QFileInfo to report an + link incorrectly as a non-link. + + - QLocale: + * Fixed a crash if qDebug() is used after main() has exited. + * [QTBUG-73403] Fixed a race condition in getting the system locale + (possible regression from Qt 5.11.x) + + - QSysInfo: + * Fixed a bug on BSD systems in getting the machineUniqueId(). + * Fixed a bug on Windows in 32-bit applications getting the + machineUniqueId() when the OS is 64-bit. + + - QWaitCondition: + * Fixed handling of wait(QDeadlineTimer::Forever) on 32-bit platforms. + +**************************************************************************** +* QtWidgets * +**************************************************************************** + + - ItemViews: + * Fixed a regression with wrongly drawn centered/right aligned item + texts + +**************************************************************************** +* Third-Party Code * +**************************************************************************** + + - libpng was updated to version 1.6.36 + +**************************************************************************** +* Freetype * +**************************************************************************** + + - Upgraded bundled Freetype version to 2.9.1. This also adds support for + the latest emoji font in use on Android 9. + +**************************************************************************** +* Android * +**************************************************************************** + + - Added the --no-strip command line option to androiddeployqt. + + - qmake: + * Can now set the version name and code for Android using + ANDROID_VERSION_NAME and ANDROID_VERSION_CODE respectively in the pro + file. + +**************************************************************************** +* Windows * +**************************************************************************** + + - Fixed an issue where loading fonts from files or data would sometimes + mistakenly classify them as oblique. + +**************************************************************************** +* qmake * +**************************************************************************** + + - [QTBUG-27079] A new feature "cmdline" was added that implies "CONFIG += + console" and "CONFIG -= app_bundle". diff --git a/examples/widgets/desktop/systray/main.cpp b/examples/widgets/desktop/systray/main.cpp index 4e3e628767..2d91e4ac36 100644 --- a/examples/widgets/desktop/systray/main.cpp +++ b/examples/widgets/desktop/systray/main.cpp @@ -59,6 +59,8 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(systray); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QApplication app(argc, argv); if (!QSystemTrayIcon::isSystemTrayAvailable()) { diff --git a/examples/widgets/dialogs/classwizard/main.cpp b/examples/widgets/dialogs/classwizard/main.cpp index 72eb1ae6ec..03ffe97a23 100644 --- a/examples/widgets/dialogs/classwizard/main.cpp +++ b/examples/widgets/dialogs/classwizard/main.cpp @@ -59,6 +59,8 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(classwizard); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QApplication app(argc, argv); #ifndef QT_NO_TRANSLATION diff --git a/examples/widgets/dialogs/licensewizard/main.cpp b/examples/widgets/dialogs/licensewizard/main.cpp index 025b79243c..ed46e792d0 100644 --- a/examples/widgets/dialogs/licensewizard/main.cpp +++ b/examples/widgets/dialogs/licensewizard/main.cpp @@ -59,6 +59,8 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(licensewizard); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QApplication app(argc, argv); #ifndef QT_NO_TRANSLATION diff --git a/examples/widgets/dialogs/standarddialogs/main.cpp b/examples/widgets/dialogs/standarddialogs/main.cpp index 150d07318e..a0cded4f47 100644 --- a/examples/widgets/dialogs/standarddialogs/main.cpp +++ b/examples/widgets/dialogs/standarddialogs/main.cpp @@ -59,6 +59,7 @@ int main(int argc, char *argv[]) { + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication app(argc, argv); QGuiApplication::setApplicationDisplayName(Dialog::tr("Standard Dialogs")); diff --git a/examples/widgets/dialogs/trivialwizard/trivialwizard.cpp b/examples/widgets/dialogs/trivialwizard/trivialwizard.cpp index fe49bf6304..ce13a59b0c 100644 --- a/examples/widgets/dialogs/trivialwizard/trivialwizard.cpp +++ b/examples/widgets/dialogs/trivialwizard/trivialwizard.cpp @@ -123,6 +123,8 @@ QWizardPage *createConclusionPage() int main(int argc, char *argv[]) //! [9] //! [11] { + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QApplication app(argc, argv); #ifndef QT_NO_TRANSLATION diff --git a/mkspecs/features/resources.prf b/mkspecs/features/resources.prf index bb2a55b93d..fa8ff1fb58 100644 --- a/mkspecs/features/resources.prf +++ b/mkspecs/features/resources.prf @@ -28,6 +28,7 @@ for(resource, RESOURCES) { !exists($$absolute_path($$resource, $$_PRO_FILE_PWD_)): \ warning("Failure to find: $$resource") qmake_immediate.files += $$resource + OTHER_FILES *= $$resource } RESOURCES -= $$resource next() @@ -57,6 +58,7 @@ for(resource, RESOURCES) { alias = $$relative_path($$file, $$abs_base) resource_file_content += \ "<file alias=\"$$xml_escape($$alias)\">$$xml_escape($$file)</file>" + OTHER_FILES *= $$file } } @@ -73,9 +75,11 @@ for(resource, RESOURCES) { } !isEmpty(RESOURCES):contains(TEMPLATE, .*lib):plugin:static { - resource_init_function = $$lower($$basename(TARGET))_plugin_resource_init + pluginBaseName = $$basename(TARGET) + pluginName = $$lower($$replace(pluginBaseName, [-], _)) + resource_init_function = $${pluginName}_plugin_resource_init DEFINES += "QT_PLUGIN_RESOURCE_INIT_FUNCTION=$$resource_init_function" - RESOURCE_INIT_CPP = $$OUT_PWD/$$lower($$basename(TARGET))_plugin_resources.cpp + RESOURCE_INIT_CPP = $$OUT_PWD/$${pluginName}_plugin_resources.cpp GENERATED_SOURCES += $$RESOURCE_INIT_CPP QMAKE_DISTCLEAN += $$RESOURCE_INIT_CPP diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp index f638beda58..84f7936feb 100644 --- a/src/3rdparty/angle/src/libANGLE/Context.cpp +++ b/src/3rdparty/angle/src/libANGLE/Context.cpp @@ -451,7 +451,8 @@ egl::Error Context::onDestroy(const egl::Display *display) for (auto &zeroTexture : mZeroTextures) { - ANGLE_TRY(zeroTexture.second->onDestroy(this)); + auto result = zeroTexture.second->onDestroy(this); + ANGLE_TRY(egl::Error(result)); zeroTexture.second.set(this, nullptr); } mZeroTextures.clear(); diff --git a/src/3rdparty/angle/src/libANGLE/Stream.cpp b/src/3rdparty/angle/src/libANGLE/Stream.cpp index 68279976b7..e384c7d486 100644 --- a/src/3rdparty/angle/src/libANGLE/Stream.cpp +++ b/src/3rdparty/angle/src/libANGLE/Stream.cpp @@ -192,8 +192,9 @@ Error Stream::consumerAcquire(const gl::Context *context) { if (mPlanes[i].texture != nullptr) { - ANGLE_TRY(mPlanes[i].texture->acquireImageFromStream( - context, mProducerImplementation->getGLFrameDescription(i))); + auto result = mPlanes[i].texture->acquireImageFromStream( + context, mProducerImplementation->getGLFrameDescription(i)); + ANGLE_TRY(Error(result)); } } @@ -213,7 +214,8 @@ Error Stream::consumerRelease(const gl::Context *context) { if (mPlanes[i].texture != nullptr) { - ANGLE_TRY(mPlanes[i].texture->releaseImageFromStream(context)); + auto result = mPlanes[i].texture->releaseImageFromStream(context); + ANGLE_TRY(Error(result)); } } diff --git a/src/3rdparty/angle/src/libANGLE/Texture.cpp b/src/3rdparty/angle/src/libANGLE/Texture.cpp index da92e65916..7447604fe6 100644 --- a/src/3rdparty/angle/src/libANGLE/Texture.cpp +++ b/src/3rdparty/angle/src/libANGLE/Texture.cpp @@ -550,7 +550,8 @@ Error Texture::onDestroy(const Context *context) { if (mBoundSurface) { - ANGLE_TRY(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER)); + auto result = mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER); + ANGLE_TRY(Error(result)); mBoundSurface = nullptr; } if (mBoundStream) diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp index 75c6298868..b583273641 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp @@ -376,7 +376,8 @@ egl::Error Renderer9::initializeDevice() ASSERT(!mBlit); mBlit = new Blit9(this); - ANGLE_TRY(mBlit->initialize()); + auto result = mBlit->initialize(); + ANGLE_TRY(egl::Error(result)); ASSERT(!mVertexDataManager && !mIndexDataManager); mVertexDataManager = new VertexDataManager(this); diff --git a/src/angle/patches/0013-Fix-compilation-with-icc-converting-between-egl-s-an.patch b/src/angle/patches/0013-Fix-compilation-with-icc-converting-between-egl-s-an.patch new file mode 100644 index 0000000000..6d3b1cac08 --- /dev/null +++ b/src/angle/patches/0013-Fix-compilation-with-icc-converting-between-egl-s-an.patch @@ -0,0 +1,93 @@ +From 2d8118620d4871f74a3ddca233529ff540384477 Mon Sep 17 00:00:00 2001 +From: Yuhang Zhao <2546789017@qq.com> +Date: Wed, 13 Feb 2019 23:26:55 +0800 +Subject: [PATCH] Fix compilation with icc, converting between egl's and gl's + Error types + +Each has two constructors from the other, one copying the other +moving; and this leads to an ambiguous overload when converting +Texture::onDestroy()'s gl::error to the egl::Error that +gl::Context::onDestroy() returns. Passing the value through a +temporary prevents the move-constructor from being attempted and saves +the day. Thanks to Ville Voutilainen for suggesting the fix. + +Fixes: QTBUG-73698 +Change-Id: I628173399a73cee2e253201bc3e8d3e6477a2fbf +--- + src/3rdparty/angle/src/libANGLE/Context.cpp | 3 ++- + src/3rdparty/angle/src/libANGLE/Stream.cpp | 8 +++++--- + src/3rdparty/angle/src/libANGLE/Texture.cpp | 3 ++- + .../angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp | 3 ++- + 4 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp +index f638beda58..84f7936feb 100644 +--- a/src/3rdparty/angle/src/libANGLE/Context.cpp ++++ b/src/3rdparty/angle/src/libANGLE/Context.cpp +@@ -451,7 +451,8 @@ egl::Error Context::onDestroy(const egl::Display *display) + + for (auto &zeroTexture : mZeroTextures) + { +- ANGLE_TRY(zeroTexture.second->onDestroy(this)); ++ auto result = zeroTexture.second->onDestroy(this); ++ ANGLE_TRY(egl::Error(result)); + zeroTexture.second.set(this, nullptr); + } + mZeroTextures.clear(); +diff --git a/src/3rdparty/angle/src/libANGLE/Stream.cpp b/src/3rdparty/angle/src/libANGLE/Stream.cpp +index 68279976b7..e384c7d486 100644 +--- a/src/3rdparty/angle/src/libANGLE/Stream.cpp ++++ b/src/3rdparty/angle/src/libANGLE/Stream.cpp +@@ -192,8 +192,9 @@ Error Stream::consumerAcquire(const gl::Context *context) + { + if (mPlanes[i].texture != nullptr) + { +- ANGLE_TRY(mPlanes[i].texture->acquireImageFromStream( +- context, mProducerImplementation->getGLFrameDescription(i))); ++ auto result = mPlanes[i].texture->acquireImageFromStream( ++ context, mProducerImplementation->getGLFrameDescription(i)); ++ ANGLE_TRY(Error(result)); + } + } + +@@ -213,7 +214,8 @@ Error Stream::consumerRelease(const gl::Context *context) + { + if (mPlanes[i].texture != nullptr) + { +- ANGLE_TRY(mPlanes[i].texture->releaseImageFromStream(context)); ++ auto result = mPlanes[i].texture->releaseImageFromStream(context); ++ ANGLE_TRY(Error(result)); + } + } + +diff --git a/src/3rdparty/angle/src/libANGLE/Texture.cpp b/src/3rdparty/angle/src/libANGLE/Texture.cpp +index da92e65916..7447604fe6 100644 +--- a/src/3rdparty/angle/src/libANGLE/Texture.cpp ++++ b/src/3rdparty/angle/src/libANGLE/Texture.cpp +@@ -550,7 +550,8 @@ Error Texture::onDestroy(const Context *context) + { + if (mBoundSurface) + { +- ANGLE_TRY(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER)); ++ auto result = mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER); ++ ANGLE_TRY(Error(result)); + mBoundSurface = nullptr; + } + if (mBoundStream) +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp +index 75c6298868..b583273641 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp +@@ -376,7 +376,8 @@ egl::Error Renderer9::initializeDevice() + + ASSERT(!mBlit); + mBlit = new Blit9(this); +- ANGLE_TRY(mBlit->initialize()); ++ auto result = mBlit->initialize(); ++ ANGLE_TRY(egl::Error(result)); + + ASSERT(!mVertexDataManager && !mIndexDataManager); + mVertexDataManager = new VertexDataManager(this); +-- +2.20.1.windows.1 + diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 35bb465a04..ced08a9a87 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -908,8 +908,8 @@ QTemporaryFile *QTemporaryFile::createNativeFile(QFile &file) qint64 old_off = 0; if(wasOpen) old_off = file.pos(); - else - file.open(QIODevice::ReadOnly); + else if (!file.open(QIODevice::ReadOnly)) + return nullptr; //dump data QTemporaryFile *ret = new QTemporaryFile; if (ret->open()) { diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index dc39490ab0..a2111a084f 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -66,6 +66,7 @@ #endif #include <stdlib.h> +#include <new> #include "qobject_p.h" @@ -585,7 +586,7 @@ bool QTranslatorPrivate::do_load(const QString &realname, const QString &directo #endif // QT_USE_MMAP if (!ok) { - d->unmapPointer = new char[d->unmapLength]; + d->unmapPointer = new (std::nothrow) char[d->unmapLength]; if (d->unmapPointer) { file.seek(0); qint64 readResult = file.read(d->unmapPointer, d->unmapLength); diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 18e94cf256..0463ef6a42 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -124,7 +124,7 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format) int height = size.height(); int depth = qt_depthForFormat(format); auto params = calculateImageParameters(width, height, depth); - if (params.bytesPerLine < 0) + if (!params.isValid()) return nullptr; QScopedPointer<QImageData> d(new QImageData); @@ -783,7 +783,7 @@ QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QIm const int depth = qt_depthForFormat(format); auto params = calculateImageParameters(width, height, depth); - if (params.totalSize < 0) + if (!params.isValid()) return nullptr; if (bpl > 0) { @@ -1488,10 +1488,17 @@ qsizetype QImage::sizeInBytes() const \sa scanLine() */ +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) +qsizetype QImage::bytesPerLine() const +{ + return d ? d->bytes_per_line : 0; +} +#else int QImage::bytesPerLine() const { return d ? d->bytes_per_line : 0; } +#endif /*! diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 45f571807c..8335e117f2 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -226,7 +226,11 @@ public: uchar *scanLine(int); const uchar *scanLine(int) const; const uchar *constScanLine(int) const; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + qsizetype bytesPerLine() const; +#else int bytesPerLine() const; +#endif bool valid(int x, int y) const; bool valid(const QPoint &pt) const; diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index de12a313e8..d88ad2d1d2 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -109,6 +109,7 @@ struct Q_GUI_EXPORT QImageData { // internal image data struct ImageSizeParameters { qsizetype bytesPerLine; qsizetype totalSize; + bool isValid() const { return bytesPerLine > 0 && totalSize > 0; } }; static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth); }; @@ -135,6 +136,11 @@ QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetyp qsizetype dummy; if (mul_overflow(height, qsizetype(sizeof(uchar *)), &dummy)) return invalid; // why is this here? +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) + // Disallow images where width * depth calculations might overflow + if (width > (INT_MAX - 31) / depth) + return invalid; +#endif return { bytes_per_line, total_size }; } diff --git a/src/gui/kernel/qplatformgraphicsbuffer.h b/src/gui/kernel/qplatformgraphicsbuffer.h index 65c24bebc9..9004116ea4 100644 --- a/src/gui/kernel/qplatformgraphicsbuffer.h +++ b/src/gui/kernel/qplatformgraphicsbuffer.h @@ -71,12 +71,14 @@ public: TextureAccess = 0x04, HWCompositor = 0x08 }; + Q_ENUM(AccessType); Q_DECLARE_FLAGS(AccessTypes, AccessType); enum Origin { OriginBottomLeft, OriginTopLeft }; + Q_ENUM(Origin); ~QPlatformGraphicsBuffer(); diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 199ef0de07..6ae6e4a528 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -463,40 +463,16 @@ QList<int> QPlatformIntegration::possibleKeys(const QKeyEvent *) const } /*! - Should be called by the implementation whenever a new screen is added. - - The first screen added will be the primary screen, used for default-created - windows, GL contexts, and other resources unless otherwise specified. - - This adds the screen to QGuiApplication::screens(), and emits the - QGuiApplication::screenAdded() signal. - - The screen should be deleted by calling QPlatformIntegration::destroyScreen(). + \deprecated Use QWindowSystemInterface::handleScreenAdded instead. */ void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary) { - QScreen *screen = new QScreen(ps); - - if (isPrimary) { - QGuiApplicationPrivate::screen_list.prepend(screen); - } else { - QGuiApplicationPrivate::screen_list.append(screen); - } - - QGuiApplicationPrivate::resetCachedDevicePixelRatio(); - - emit qGuiApp->screenAdded(screen); - - if (isPrimary) - emit qGuiApp->primaryScreenChanged(screen); + QWindowSystemInterface::handleScreenAdded(ps, isPrimary); } /*! - Just removes the screen, call destroyScreen instead. - - \sa destroyScreen() + \deprecated Use QWindowSystemInterface::handleScreenRemoved instead. */ - void QPlatformIntegration::removeScreen(QScreen *screen) { const bool wasPrimary = (!QGuiApplicationPrivate::screen_list.isEmpty() && QGuiApplicationPrivate::screen_list.at(0) == screen); @@ -509,38 +485,19 @@ void QPlatformIntegration::removeScreen(QScreen *screen) } /*! - Should be called by the implementation whenever a screen is removed. - - This removes the screen from QGuiApplication::screens(), and deletes it. - - Failing to call this and manually deleting the QPlatformScreen instead may - lead to a crash due to a pure virtual call. + \deprecated Use QWindowSystemInterface::handleScreenRemoved instead. */ -void QPlatformIntegration::destroyScreen(QPlatformScreen *screen) +void QPlatformIntegration::destroyScreen(QPlatformScreen *platformScreen) { - QScreen *qScreen = screen->screen(); - removeScreen(qScreen); - delete qScreen; - delete screen; + QWindowSystemInterface::handleScreenRemoved(platformScreen); } /*! - Should be called whenever the primary screen changes. - - When the screen specified as primary changes, this method will notify - QGuiApplication and emit the QGuiApplication::primaryScreenChanged signal. - */ - + \deprecated Use QWindowSystemInterface::handlePrimaryScreenChanged instead. +*/ void QPlatformIntegration::setPrimaryScreen(QPlatformScreen *newPrimary) { - QScreen* newPrimaryScreen = newPrimary->screen(); - int idx = QGuiApplicationPrivate::screen_list.indexOf(newPrimaryScreen); - Q_ASSERT(idx >= 0); - if (idx == 0) - return; - - QGuiApplicationPrivate::screen_list.swapItemsAt(0, idx); - emit qGuiApp->primaryScreenChanged(newPrimaryScreen); + QWindowSystemInterface::handlePrimaryScreenChanged(newPrimary); } QStringList QPlatformIntegration::themeNames() const diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index de5f9c1c9a..6950bbaf72 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -192,7 +192,9 @@ public: #endif virtual void setApplicationIcon(const QIcon &icon) const; - void removeScreen(QScreen *screen); +#if QT_DEPRECATED_SINCE(5, 12) + QT_DEPRECATED_X("Use QWindowSystemInterface::handleScreenRemoved") void removeScreen(QScreen *screen); +#endif virtual void beep() const; @@ -203,9 +205,11 @@ public: protected: QPlatformIntegration() = default; - void screenAdded(QPlatformScreen *screen, bool isPrimary = false); - void destroyScreen(QPlatformScreen *screen); - void setPrimaryScreen(QPlatformScreen *newPrimary); +#if QT_DEPRECATED_SINCE(5, 12) + QT_DEPRECATED_X("Use QWindowSystemInterface::handleScreenAdded") void screenAdded(QPlatformScreen *screen, bool isPrimary = false); + QT_DEPRECATED_X("Use QWindowSystemInterface::handleScreenRemoved") void destroyScreen(QPlatformScreen *screen); + QT_DEPRECATED_X("Use QWindowSystemInterface::handlePrimaryScreenChanged") void setPrimaryScreen(QPlatformScreen *newPrimary); +#endif }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp index b7b312e89e..21ae75ba8f 100644 --- a/src/gui/kernel/qplatformscreen.cpp +++ b/src/gui/kernel/qplatformscreen.cpp @@ -61,8 +61,11 @@ QPlatformScreen::~QPlatformScreen() { Q_D(QPlatformScreen); if (d->screen) { - qWarning("Manually deleting a QPlatformScreen. Call QPlatformIntegration::destroyScreen instead."); + qWarning("Manually deleting a QPlatformScreen. Call QWindowSystemInterface::handleScreenRemoved instead."); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QGuiApplicationPrivate::platformIntegration()->removeScreen(d->screen); +QT_WARNING_POP delete d->screen; } } diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h index 8c9b16e08e..14392d3036 100644 --- a/src/gui/kernel/qscreen.h +++ b/src/gui/kernel/qscreen.h @@ -169,6 +169,7 @@ private: friend class QPlatformIntegration; friend class QPlatformScreen; friend class QHighDpiScaling; + friend class QWindowSystemInterface; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 1cc2435239..590e2a85bb 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1922,9 +1922,6 @@ void QWindowPrivate::destroy() resizeEventPending = true; receivedExpose = false; exposed = false; - - if (wasVisible) - maybeQuitOnLastWindowClosed(); } /*! @@ -2313,8 +2310,17 @@ bool QWindow::event(QEvent *ev) #endif case QEvent::Close: - if (ev->isAccepted()) + if (ev->isAccepted()) { + Q_D(QWindow); + bool wasVisible = isVisible(); destroy(); + if (wasVisible) { + // FIXME: This check for visibility is a workaround for both QWidgetWindow + // and QWindow having logic to emit lastWindowClosed, and possibly quit the + // application. We should find a better way to handle this. + d->maybeQuitOnLastWindowClosed(); + } + } break; case QEvent::Expose: diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 7067ece1d8..ec6911b334 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -780,6 +780,72 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchCancelEvent, QWindow *window, ulong QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e); } +/*! + Should be called by the implementation whenever a new screen is added. + + The first screen added will be the primary screen, used for default-created + windows, GL contexts, and other resources unless otherwise specified. + + This adds the screen to QGuiApplication::screens(), and emits the + QGuiApplication::screenAdded() signal. + + The screen should be deleted by calling QWindowSystemInterface::handleScreenRemoved(). +*/ +void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *ps, bool isPrimary) +{ + QScreen *screen = new QScreen(ps); + + if (isPrimary) + QGuiApplicationPrivate::screen_list.prepend(screen); + else + QGuiApplicationPrivate::screen_list.append(screen); + + QGuiApplicationPrivate::resetCachedDevicePixelRatio(); + + emit qGuiApp->screenAdded(screen); + + if (isPrimary) + emit qGuiApp->primaryScreenChanged(screen); +} + +/*! + Should be called by the implementation whenever a screen is removed. + + This removes the screen from QGuiApplication::screens(), and deletes it. + + Failing to call this and manually deleting the QPlatformScreen instead may + lead to a crash due to a pure virtual call. +*/ +void QWindowSystemInterface::handleScreenRemoved(QPlatformScreen *platformScreen) +{ +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + QGuiApplicationPrivate::platformIntegration()->removeScreen(platformScreen->screen()); +QT_WARNING_POP + + // Important to keep this order since the QSceen doesn't own the platform screen + delete platformScreen->screen(); + delete platformScreen; +} + +/*! + Should be called whenever the primary screen changes. + + When the screen specified as primary changes, this method will notify + QGuiApplication and emit the QGuiApplication::primaryScreenChanged signal. + */ +void QWindowSystemInterface::handlePrimaryScreenChanged(QPlatformScreen *newPrimary) +{ + QScreen *newPrimaryScreen = newPrimary->screen(); + int indexOfScreen = QGuiApplicationPrivate::screen_list.indexOf(newPrimaryScreen); + Q_ASSERT(indexOfScreen >= 0); + if (indexOfScreen == 0) + return; + + QGuiApplicationPrivate::screen_list.swapItemsAt(0, indexOfScreen); + emit qGuiApp->primaryScreenChanged(newPrimaryScreen); +} + void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt::ScreenOrientation orientation) { QWindowSystemInterfacePrivate::ScreenOrientationEvent *e = diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 1dde9130ac..bf98c33a1a 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -233,6 +233,10 @@ public: static bool handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result); // Changes to the screen + static void handleScreenAdded(QPlatformScreen *screen, bool isPrimary = false); + static void handleScreenRemoved(QPlatformScreen *screen); + static void handlePrimaryScreenChanged(QPlatformScreen *newPrimary); + static void handleScreenOrientationChange(QScreen *screen, Qt::ScreenOrientation newOrientation); static void handleScreenGeometryChange(QScreen *screen, const QRect &newGeometry, const QRect &newAvailableGeometry); static void handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal newDpiX, qreal newDpiY); diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 323253c70d..2e1a2b5bff 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -58,23 +58,17 @@ #include <limits.h> #include <qbasictimer.h> #include "private/qfunctions_p.h" +#include <qloggingcategory.h> #include <algorithm> -// #define LAYOUT_DEBUG - -#ifdef LAYOUT_DEBUG -#define LDEBUG qDebug() -#define INC_INDENT debug_indent += " " -#define DEC_INDENT debug_indent = debug_indent.left(debug_indent.length()-2) -#else -#define LDEBUG if(0) qDebug() -#define INC_INDENT do {} while(0) -#define DEC_INDENT do {} while(0) -#endif - QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcDraw, "qt.text.drawing") +Q_LOGGING_CATEGORY(lcHit, "qt.text.hittest") +Q_LOGGING_CATEGORY(lcLayout, "qt.text.layout") +Q_LOGGING_CATEGORY(lcTable, "qt.text.layout.table") + // ################ should probably add frameFormatChange notification! struct QTextLayoutStruct; @@ -583,16 +577,16 @@ QTextDocumentLayoutPrivate::hitTest(QTextFrame *frame, const QFixedPoint &point, QTextFrame *rootFrame = docPrivate->rootFrame(); -// LDEBUG << "checking frame" << frame->firstPosition() << "point=" << point -// << "position" << fd->position << "size" << fd->size; + qCDebug(lcHit) << "checking frame" << frame->firstPosition() << "point=" << point.toPointF() + << "position" << fd->position.toPointF() << "size" << fd->size.toSizeF(); if (frame != rootFrame) { if (relativePoint.y < 0 || relativePoint.x < 0) { *position = frame->firstPosition() - 1; -// LDEBUG << "before pos=" << *position; + qCDebug(lcHit) << "before pos=" << *position; return PointBefore; } else if (relativePoint.y > fd->size.height || relativePoint.x > fd->size.width) { *position = frame->lastPosition() + 1; -// LDEBUG << "after pos=" << *position; + qCDebug(lcHit) << "after pos=" << *position; return PointAfter; } } @@ -666,8 +660,6 @@ QTextDocumentLayoutPrivate::HitPoint QTextDocumentLayoutPrivate::hitTest(QTextFrame::Iterator it, HitPoint hit, const QFixedPoint &p, int *position, QTextLayout **l, Qt::HitTestAccuracy accuracy) const { - INC_INDENT; - for (; !it.atEnd(); ++it) { QTextFrame *c = it.currentFrame(); HitPoint hp; @@ -693,8 +685,7 @@ QTextDocumentLayoutPrivate::hitTest(QTextFrame::Iterator it, HitPoint hit, const } } - DEC_INDENT; -// LDEBUG << "inside=" << hit << " pos=" << *position; + qCDebug(lcHit) << "inside=" << hit << " pos=" << *position; return hit; } @@ -741,15 +732,14 @@ QTextDocumentLayoutPrivate::hitTest(const QTextBlock &bl, const QFixedPoint &poi QTextLayout *tl = bl.layout(); QRectF textrect = tl->boundingRect(); textrect.translate(tl->position()); -// LDEBUG << " checking block" << bl.position() << "point=" << point -// << " tlrect" << textrect; + qCDebug(lcHit) << " checking block" << bl.position() << "point=" << point.toPointF() << " tlrect" << textrect; *position = bl.position(); if (point.y.toReal() < textrect.top()) { -// LDEBUG << " before pos=" << *position; + qCDebug(lcHit) << " before pos=" << *position; return PointBefore; } else if (point.y.toReal() > textrect.bottom()) { *position += bl.length(); -// LDEBUG << " after pos=" << *position; + qCDebug(lcHit) << " after pos=" << *position; return PointAfter; } @@ -781,7 +771,7 @@ QTextDocumentLayoutPrivate::hitTest(const QTextBlock &bl, const QFixedPoint &poi } *position += off; -// LDEBUG << " inside=" << hit << " pos=" << *position; + qCDebug(lcHit) << " inside=" << hit << " pos=" << *position; return hit; } @@ -944,8 +934,7 @@ void QTextDocumentLayoutPrivate::drawFrame(const QPointF &offset, QPainter *pain || off.x() > context.clip.right() || off.x() + fd->size.width.toReal() < context.clip.left())) return; -// LDEBUG << debug_indent << "drawFrame" << frame->firstPosition() << "--" << frame->lastPosition() << "at" << offset; -// INC_INDENT; + qCDebug(lcDraw) << "drawFrame" << frame->firstPosition() << "--" << frame->lastPosition() << "at" << offset; // if the cursor is /on/ a table border we may need to repaint it // afterwards, as we usually draw the decoration first @@ -1076,8 +1065,6 @@ void QTextDocumentLayoutPrivate::drawFrame(const QPointF &offset, QPainter *pain painter->setPen(oldPen); } -// DEC_INDENT; - return; } @@ -1280,7 +1267,7 @@ void QTextDocumentLayoutPrivate::drawBlock(const QPointF &offset, QPainter *pain r.translate(offset + tl->position()); if (!bl.isVisible() || (context.clip.isValid() && (r.bottom() < context.clip.y() || r.top() > context.clip.bottom()))) return; -// LDEBUG << debug_indent << "drawBlock" << bl.position() << "at" << offset << "br" << tl->boundingRect(); + qCDebug(lcDraw) << "drawBlock" << bl.position() << "at" << offset << "br" << tl->boundingRect(); QTextBlockFormat blockFormat = bl.blockFormat(); @@ -1512,7 +1499,7 @@ QTextLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QT int layoutFrom, int layoutTo, QTextTableData *td, QFixed absoluteTableY, bool withPageBreaks) { - LDEBUG << "layoutCell"; + qCDebug(lcTable) << "layoutCell"; QTextLayoutStruct layoutStruct; layoutStruct.frame = t; layoutStruct.minimumWidth = 0; @@ -1587,7 +1574,7 @@ QTextLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QT QRectF QTextDocumentLayoutPrivate::layoutTable(QTextTable *table, int layoutFrom, int layoutTo, QFixed parentY) { - LDEBUG << "layoutTable"; + qCDebug(lcTable) << "layoutTable from" << layoutFrom << "to" << layoutTo << "parentY" << parentY; QTextTableData *td = static_cast<QTextTableData *>(data(table)); Q_ASSERT(td->sizeDirty); const int rows = table->rows(); @@ -1709,6 +1696,7 @@ recalc_minmax_widths: if (length.type() == QTextLength::FixedLength) { td->minWidths[i] = td->widths[i] = qMax(scaleToDevice(QFixed::fromReal(length.rawValue())), td->minWidths.at(i)); remainingWidth -= td->widths.at(i); + qCDebug(lcTable) << "column" << i << "has width constraint" << td->minWidths.at(i) << "px, remaining width now" << remainingWidth; } else if (length.type() == QTextLength::PercentageLength) { totalPercentage += QFixed::fromReal(length.rawValue()); } else if (length.type() == QTextLength::VariableLength) { @@ -1716,6 +1704,7 @@ recalc_minmax_widths: td->widths[i] = td->minWidths.at(i); remainingWidth -= td->minWidths.at(i); + qCDebug(lcTable) << "column" << i << "has variable width, min" << td->minWidths.at(i) << "remaining width now" << remainingWidth; } totalMinWidth += td->minWidths.at(i); } @@ -1735,6 +1724,8 @@ recalc_minmax_widths: } else { td->widths[i] = td->minWidths.at(i); } + qCDebug(lcTable) << "column" << i << "has width constraint" << columnWidthConstraints.at(i).rawValue() + << "%, allocated width" << td->widths[i] << "remaining width now" << remainingWidth; remainingWidth -= td->widths.at(i); } } @@ -1978,9 +1969,12 @@ relayout: td->minimumWidth += rightMargin - td->border; td->maximumWidth = td->columnPositions.at(0); - for (int i = 0; i < columns; ++i) + for (int i = 0; i < columns; ++i) { if (td->maxWidths.at(i) != QFIXED_MAX) td->maximumWidth += td->maxWidths.at(i) + 2 * td->border + cellSpacing; + qCDebug(lcTable) << "column" << i << "has final width" << td->widths.at(i).toReal() + << "min" << td->minWidths.at(i).toReal() << "max" << td->maxWidths.at(i).toReal(); + } td->maximumWidth += rightMargin - td->border; td->updateTableSize(); @@ -2052,9 +2046,8 @@ void QTextDocumentLayoutPrivate::positionFloat(QTextFrame *frame, QTextLine *cur QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, int layoutTo, QFixed parentY) { - LDEBUG << "layoutFrame (pre)"; + qCDebug(lcLayout, "layoutFrame (%d--%d), parent=%p", f->firstPosition(), f->lastPosition(), f->parentFrame()); Q_ASSERT(data(f)->sizeDirty); -// qDebug("layouting frame (%d--%d), parent=%p", f->firstPosition(), f->lastPosition(), f->parentFrame()); QTextFrameFormat fformat = f->frameFormat(); @@ -2076,9 +2069,8 @@ QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, in QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, int layoutTo, QFixed frameWidth, QFixed frameHeight, QFixed parentY) { - LDEBUG << "layoutFrame from=" << layoutFrom << "to=" << layoutTo; + qCDebug(lcLayout, "layoutFrame (%d--%d), parent=%p", f->firstPosition(), f->lastPosition(), f->parentFrame()); Q_ASSERT(data(f)->sizeDirty); -// qDebug("layouting frame (%d--%d), parent=%p", f->firstPosition(), f->lastPosition(), f->parentFrame()); QTextFrameData *fd = data(f); QFixed newContentsWidth; @@ -2165,8 +2157,8 @@ QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, in layoutStruct.maximumWidth = QFIXED_MAX; layoutStruct.fullLayout = fullLayout || (fd->oldContentsWidth != newContentsWidth); layoutStruct.updateRect = QRectF(QPointF(0, 0), QSizeF(qreal(INT_MAX), qreal(INT_MAX))); - LDEBUG << "layoutStruct: x_left" << layoutStruct.x_left << "x_right" << layoutStruct.x_right - << "fullLayout" << layoutStruct.fullLayout; + qCDebug(lcLayout) << "layoutStruct: x_left" << layoutStruct.x_left << "x_right" << layoutStruct.x_right + << "fullLayout" << layoutStruct.fullLayout; fd->oldContentsWidth = newContentsWidth; layoutStruct.pageHeight = QFixed::fromReal(document->pageSize().height()); @@ -2220,7 +2212,7 @@ QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, in void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, QFixed width) { - LDEBUG << "layoutFlow from=" << layoutFrom << "to=" << layoutTo; + qCDebug(lcLayout) << "layoutFlow from=" << layoutFrom << "to=" << layoutTo; QTextFrameData *fd = data(layoutStruct->frame); fd->currentLayoutStruct = layoutStruct; @@ -2578,9 +2570,8 @@ void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosi QTextLayout *tl = bl.layout(); const int blockLength = bl.length(); - LDEBUG << "layoutBlock from=" << layoutFrom << "to=" << layoutTo; - -// qDebug() << "layoutBlock; width" << layoutStruct->x_right - layoutStruct->x_left << "(maxWidth is btw" << tl->maximumWidth() << ')'; + qCDebug(lcLayout) << "layoutBlock from=" << layoutFrom << "to=" << layoutTo + << "; width" << layoutStruct->x_right - layoutStruct->x_left << "(maxWidth is btw" << tl->maximumWidth() << ')'; if (previousBlockFormat) { qreal margin = qMax(blockFormat.topMargin(), previousBlockFormat->bottomMargin()); @@ -2612,7 +2603,7 @@ void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosi // force relayout if we cross a page boundary || (layoutStruct->pageHeight != QFIXED_MAX && layoutStruct->absoluteY() + QFixed::fromReal(tl->boundingRect().height()) > layoutStruct->pageBottom)) { - LDEBUG << " do layout"; + qCDebug(lcLayout) << "do layout"; QTextOption option = docPrivate->defaultTextOption; option.setTextDirection(dir); option.setTabs( blockFormat.tabPositions() ); @@ -2741,7 +2732,7 @@ void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosi const int cnt = tl->lineCount(); QFixed bottom; for (int i = 0; i < cnt; ++i) { - LDEBUG << "going to move text line" << i; + qCDebug(lcLayout) << "going to move text line" << i; QTextLine line = tl->lineAt(i); layoutStruct->contentsWidth = qMax(layoutStruct->contentsWidth, QFixed::fromReal(line.x() + tl->lineAt(i).naturalTextWidth()) + totalRightMargin); diff --git a/src/network/configure.json b/src/network/configure.json index e6c87b550b..07d46b790e 100644 --- a/src/network/configure.json +++ b/src/network/configure.json @@ -86,11 +86,11 @@ "sources": [ { "type": "openssl" }, { - "libs": "-lssleay32 -llibeay32", + "libs": "-lssleay32 -llibeay32 -lUser32 -lWs2_32 -lAdvapi32 -lGdi32", "condition": "config.win32" }, { - "libs": "-llibssl -llibcrypto", + "libs": "-llibssl -llibcrypto -lUser32 -lWs2_32 -lAdvapi32 -lCrypt32", "condition": "config.msvc" }, { diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 763b294660..e0c437be27 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -173,7 +173,7 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ qFatal("Could not bind GL_ES API"); m_primaryScreen = new QAndroidPlatformScreen(); - screenAdded(m_primaryScreen); + QWindowSystemInterface::handleScreenAdded(m_primaryScreen); m_primaryScreen->setPhysicalSize(QSize(m_defaultPhysicalSizeWidth, m_defaultPhysicalSizeHeight)); m_primaryScreen->setSize(QSize(m_defaultScreenWidth, m_defaultScreenHeight)); m_primaryScreen->setAvailableGeometry(QRect(0, 0, m_defaultGeometryWidth, m_defaultGeometryHeight)); diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp index 6a7d445e69..e4c90d26af 100644 --- a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp +++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp @@ -53,6 +53,7 @@ #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatforminputcontext.h> #include <qpa/qplatforminputcontextfactory_p.h> +#include <qpa/qwindowsysteminterface.h> #if QT_CONFIG(tslib) #include <QtInputSupport/private/qtslib_p.h> @@ -69,13 +70,13 @@ QBsdFbIntegration::QBsdFbIntegration(const QStringList ¶mList) QBsdFbIntegration::~QBsdFbIntegration() { - destroyScreen(m_primaryScreen.take()); + QWindowSystemInterface::handleScreenRemoved(m_primaryScreen.take()); } void QBsdFbIntegration::initialize() { if (m_primaryScreen->initialize()) - screenAdded(m_primaryScreen.data()); + QWindowSystemInterface::handleScreenAdded(m_primaryScreen.data()); else qWarning("bsdfb: Failed to initialize screen"); diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 8d65cf328f..083b7c1655 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -33,6 +33,7 @@ SOURCES += main.mm \ qcocoaintrospection.mm \ qcocoakeymapper.mm \ qcocoamimetypes.mm \ + qiosurfacegraphicsbuffer.mm \ messages.cpp HEADERS += qcocoaintegration.h \ @@ -67,6 +68,7 @@ HEADERS += qcocoaintegration.h \ qcocoaintrospection.h \ qcocoakeymapper.h \ messages.h \ + qiosurfacegraphicsbuffer.h \ qcocoamimetypes.h qtConfig(opengl.*) { @@ -81,7 +83,7 @@ qtConfig(vulkan) { RESOURCES += qcocoaresources.qrc -LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework CoreVideo -framework Metal -lcups +LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework CoreVideo -framework Metal -framework IOSurface -lcups QT += \ core-private gui-private \ diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index b4cd506513..508f24d578 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -44,13 +44,16 @@ #include <private/qcore_mac_p.h> +#include <QScopedPointer> +#include "qiosurfacegraphicsbuffer.h" + QT_BEGIN_NAMESPACE -class QCocoaBackingStore : public QRasterBackingStore +class QNSWindowBackingStore : public QRasterBackingStore { public: - QCocoaBackingStore(QWindow *window); - ~QCocoaBackingStore(); + QNSWindowBackingStore(QWindow *window); + ~QNSWindowBackingStore(); void flush(QWindow *, const QRegion &, const QPoint &) override; @@ -60,6 +63,49 @@ private: void redrawRoundedBottomCorners(CGRect) const; }; +class QCALayerBackingStore : public QPlatformBackingStore +{ +public: + QCALayerBackingStore(QWindow *window); + ~QCALayerBackingStore(); + + void resize(const QSize &size, const QRegion &staticContents) override; + + void beginPaint(const QRegion ®ion) override; + QPaintDevice *paintDevice() override; + void endPaint() override; + + void flush(QWindow *, const QRegion &, const QPoint &) override; + void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, + QPlatformTextureList *textures, bool translucentBackground) override; + + QPlatformGraphicsBuffer *graphicsBuffer() const override; + +private: + QSize m_requestedSize; + QRegion m_paintedRegion; + + class GraphicsBuffer : public QIOSurfaceGraphicsBuffer + { + public: + GraphicsBuffer(const QSize &size, qreal devicePixelRatio, + const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace); + + QRegion dirtyRegion; // In unscaled coordinates + QImage *asImage(); + + private: + qreal m_devicePixelRatio; + QImage m_image; + }; + + void ensureBackBuffer(); + bool recreateBackBufferIfNeeded(); + bool prepareForFlush(); + + std::list<std::unique_ptr<GraphicsBuffer>> m_buffers; +}; + QT_END_NAMESPACE #endif diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 81a0a7d040..8e4e928bc5 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -42,24 +42,28 @@ #include "qcocoawindow.h" #include "qcocoahelpers.h" +#include <QtCore/qmath.h> + +#include <QuartzCore/CATransaction.h> + QT_BEGIN_NAMESPACE -QCocoaBackingStore::QCocoaBackingStore(QWindow *window) +QNSWindowBackingStore::QNSWindowBackingStore(QWindow *window) : QRasterBackingStore(window) { } -QCocoaBackingStore::~QCocoaBackingStore() +QNSWindowBackingStore::~QNSWindowBackingStore() { } -bool QCocoaBackingStore::windowHasUnifiedToolbar() const +bool QNSWindowBackingStore::windowHasUnifiedToolbar() const { Q_ASSERT(window()->handle()); return static_cast<QCocoaWindow *>(window()->handle())->m_drawContentBorderGradient; } -QImage::Format QCocoaBackingStore::format() const +QImage::Format QNSWindowBackingStore::format() const { if (windowHasUnifiedToolbar()) return QImage::Format_ARGB32_Premultiplied; @@ -78,7 +82,7 @@ QImage::Format QCocoaBackingStore::format() const coordinates, and the \a offset will be the child window's offset in relation to the backingstore's top level window. */ -void QCocoaBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +void QNSWindowBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { if (m_image.isNull()) return; @@ -103,131 +107,113 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo qCDebug(lcQpaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription); } - // Prevent potentially costly color conversion by assigning the display color space - // to the backingstore image. This does not copy the underlying image data. - CGColorSpaceRef displayColorSpace = view.window.screen.colorSpace.CGColorSpace; - QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace( - QCFType<CGImageRef>(m_image.toCGImage()), displayColorSpace); - - if (view.layer) { - // In layer-backed mode, locking focus on a view does not give the right - // view transformation, and doesn't give us a graphics context to render - // via when drawing outside of the display cycle. Instead we tell AppKit - // that we want to update the layer's content, via [NSView wantsUpdateLayer], - // which result in AppKit not creating a backingstore for each layer, and - // we then directly set the layer's backingstore (content) to our backingstore, - // masked to the part of the subview that is relevant. - // FIXME: Figure out if there's a way to do partial updates - view.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage); - if (view != topLevelView) { - const CGSize topLevelSize = topLevelView.bounds.size; - view.layer.contentsRect = CGRectApplyAffineTransform( - [view convertRect:view.bounds toView:topLevelView], - // The contentsRect is in unit coordinate system - CGAffineTransformMakeScale(1.0 / topLevelSize.width, 1.0 / topLevelSize.height)); - } - } else { - // Normally a NSView is drawn via drawRect, as part of the display cycle in the - // main runloop, via setNeedsDisplay and friends. AppKit will lock focus on each - // individual view, starting with the top level and then traversing any subviews, - // calling drawRect for each of them. This pull model results in expose events - // sent to Qt, which result in drawing to the backingstore and flushing it. - // Qt may also decide to paint and flush the backingstore via e.g. timers, - // or other events such as mouse events, in which case we're in a push model. - // If there is no focused view, it means we're in the latter case, and need - // to manually flush the NSWindow after drawing to its graphic context. - const bool drawingOutsideOfDisplayCycle = ![NSView focusView]; - - // We also need to ensure the flushed view has focus, so that the graphics - // context is set up correctly (coordinate system, clipping, etc). Outside - // of the normal display cycle there is no focused view, as explained above, - // so we have to handle it manually. There's also a corner case inside the - // normal display cycle due to way QWidgetBackingStore composits native child - // widgets, where we'll get a flush of a native child during the drawRect of - // its parent/ancestor, and the parent/ancestor being the one locked by AppKit. - // In this case we also need to lock and unlock focus manually. - const bool shouldHandleViewLockManually = [NSView focusView] != view; - if (shouldHandleViewLockManually && ![view lockFocusIfCanDraw]) { - qWarning() << "failed to lock focus of" << view; - return; - } + // Normally a NSView is drawn via drawRect, as part of the display cycle in the + // main runloop, via setNeedsDisplay and friends. AppKit will lock focus on each + // individual view, starting with the top level and then traversing any subviews, + // calling drawRect for each of them. This pull model results in expose events + // sent to Qt, which result in drawing to the backingstore and flushing it. + // Qt may also decide to paint and flush the backingstore via e.g. timers, + // or other events such as mouse events, in which case we're in a push model. + // If there is no focused view, it means we're in the latter case, and need + // to manually flush the NSWindow after drawing to its graphic context. + const bool drawingOutsideOfDisplayCycle = ![NSView focusView]; + + // We also need to ensure the flushed view has focus, so that the graphics + // context is set up correctly (coordinate system, clipping, etc). Outside + // of the normal display cycle there is no focused view, as explained above, + // so we have to handle it manually. There's also a corner case inside the + // normal display cycle due to way QWidgetBackingStore composits native child + // widgets, where we'll get a flush of a native child during the drawRect of + // its parent/ancestor, and the parent/ancestor being the one locked by AppKit. + // In this case we also need to lock and unlock focus manually. + const bool shouldHandleViewLockManually = [NSView focusView] != view; + if (shouldHandleViewLockManually && ![view lockFocusIfCanDraw]) { + qWarning() << "failed to lock focus of" << view; + return; + } - const qreal devicePixelRatio = m_image.devicePixelRatio(); + const qreal devicePixelRatio = m_image.devicePixelRatio(); - // If the flushed window is a content view, and we're filling the drawn area - // completely, or it doesn't have a window background we need to preserve, - // we can get away with copying instead of blending the backing store. - QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); - const NSCompositingOperation compositingOperation = cocoaWindow->isContentView() - && (cocoaWindow->isOpaque() || view.window.backgroundColor == NSColor.clearColor) - ? NSCompositingOperationCopy : NSCompositingOperationSourceOver; + // If the flushed window is a content view, and we're filling the drawn area + // completely, or it doesn't have a window background we need to preserve, + // we can get away with copying instead of blending the backing store. + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); + const NSCompositingOperation compositingOperation = cocoaWindow->isContentView() + && (cocoaWindow->isOpaque() || view.window.backgroundColor == NSColor.clearColor) + ? NSCompositingOperationCopy : NSCompositingOperationSourceOver; #ifdef QT_DEBUG - static bool debugBackingStoreFlush = [[NSUserDefaults standardUserDefaults] - boolForKey:@"QtCocoaDebugBackingStoreFlush"]; + static bool debugBackingStoreFlush = [[NSUserDefaults standardUserDefaults] + boolForKey:@"QtCocoaDebugBackingStoreFlush"]; #endif - // ------------------------------------------------------------------------- + // ------------------------------------------------------------------------- - // The current contexts is typically a NSWindowGraphicsContext, but can be - // NSBitmapGraphicsContext e.g. when debugging the view hierarchy in Xcode. - // If we need to distinguish things here in the future, we can use e.g. - // [NSGraphicsContext drawingToScreen], or the attributes of the context. - NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; - Q_ASSERT_X(graphicsContext, "QCocoaBackingStore", - "Focusing the view should give us a current graphics context"); + // The current contexts is typically a NSWindowGraphicsContext, but can be + // NSBitmapGraphicsContext e.g. when debugging the view hierarchy in Xcode. + // If we need to distinguish things here in the future, we can use e.g. + // [NSGraphicsContext drawingToScreen], or the attributes of the context. + NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; + Q_ASSERT_X(graphicsContext, "QCocoaBackingStore", + "Focusing the view should give us a current graphics context"); - // Create temporary image to use for blitting, without copying image data - NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease]; + // Prevent potentially costly color conversion by assigning the display color space + // to the backingstore image. This does not copy the underlying image data. + CGColorSpaceRef displayColorSpace = view.window.screen.colorSpace.CGColorSpace; + QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace( + QCFType<CGImageRef>(m_image.toCGImage()), displayColorSpace); - QRegion clippedRegion = region; - for (QWindow *w = window; w; w = w->parent()) { - if (!w->mask().isEmpty()) { - clippedRegion &= w == window ? w->mask() - : w->mask().translated(window->mapFromGlobal(w->mapToGlobal(QPoint(0, 0)))); - } + // Create temporary image to use for blitting, without copying image data + NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease]; + + QRegion clippedRegion = region; + for (QWindow *w = window; w; w = w->parent()) { + if (!w->mask().isEmpty()) { + clippedRegion &= w == window ? w->mask() + : w->mask().translated(window->mapFromGlobal(w->mapToGlobal(QPoint(0, 0)))); } + } - for (const QRect &viewLocalRect : clippedRegion) { - QPoint backingStoreOffset = viewLocalRect.topLeft() + offset; - QRect backingStoreRect(backingStoreOffset * devicePixelRatio, viewLocalRect.size() * devicePixelRatio); - if (graphicsContext.flipped) // Flip backingStoreRect to match graphics context - backingStoreRect.moveTop(m_image.height() - (backingStoreRect.y() + backingStoreRect.height())); + for (const QRect &viewLocalRect : clippedRegion) { + QPoint backingStoreOffset = viewLocalRect.topLeft() + offset; + QRect backingStoreRect(backingStoreOffset * devicePixelRatio, viewLocalRect.size() * devicePixelRatio); + if (graphicsContext.flipped) // Flip backingStoreRect to match graphics context + backingStoreRect.moveTop(m_image.height() - (backingStoreRect.y() + backingStoreRect.height())); - CGRect viewRect = viewLocalRect.toCGRect(); + CGRect viewRect = viewLocalRect.toCGRect(); - if (windowHasUnifiedToolbar()) - NSDrawWindowBackground(viewRect); + if (windowHasUnifiedToolbar()) + NSDrawWindowBackground(viewRect); - [backingStoreImage drawInRect:viewRect fromRect:backingStoreRect.toCGRect() - operation:compositingOperation fraction:1.0 respectFlipped:YES hints:nil]; + [backingStoreImage drawInRect:viewRect fromRect:backingStoreRect.toCGRect() + operation:compositingOperation fraction:1.0 respectFlipped:YES hints:nil]; #ifdef QT_DEBUG - if (Q_UNLIKELY(debugBackingStoreFlush)) { - [[NSColor colorWithCalibratedRed:drand48() green:drand48() blue:drand48() alpha:0.3] set]; - [NSBezierPath fillRect:viewRect]; - - if (drawingOutsideOfDisplayCycle) { - [[[NSColor magentaColor] colorWithAlphaComponent:0.5] set]; - [NSBezierPath strokeLineFromPoint:viewLocalRect.topLeft().toCGPoint() - toPoint:viewLocalRect.bottomRight().toCGPoint()]; - } + if (Q_UNLIKELY(debugBackingStoreFlush)) { + [[NSColor colorWithCalibratedRed:drand48() green:drand48() blue:drand48() alpha:0.3] set]; + [NSBezierPath fillRect:viewRect]; + + if (drawingOutsideOfDisplayCycle) { + [[[NSColor magentaColor] colorWithAlphaComponent:0.5] set]; + [NSBezierPath strokeLineFromPoint:viewLocalRect.topLeft().toCGPoint() + toPoint:viewLocalRect.bottomRight().toCGPoint()]; } -#endif } +#endif + } - // ------------------------------------------------------------------------- + // ------------------------------------------------------------------------- - if (shouldHandleViewLockManually) - [view unlockFocus]; + if (shouldHandleViewLockManually) + [view unlockFocus]; - if (drawingOutsideOfDisplayCycle) { - redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]); - [view.window flushWindow]; - } + if (drawingOutsideOfDisplayCycle) { + redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]); + [view.window flushWindow]; } - // Done flushing to either CALayer or NSWindow backingstore + + // Done flushing to NSWindow backingstore QCocoaWindow *topLevelCocoaWindow = static_cast<QCocoaWindow *>(topLevelWindow->handle()); if (Q_UNLIKELY(topLevelCocoaWindow->m_needsInvalidateShadow)) { @@ -251,7 +237,7 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo https://trac.webkit.org/changeset/85376/webkit */ -void QCocoaBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const +void QNSWindowBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const { #if !defined(QT_APPLE_NO_PRIVATE_APIS) Q_ASSERT(this->window()->handle()); @@ -285,4 +271,345 @@ void QCocoaBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const #endif } +// ---------------------------------------------------------------------------- + +// https://stackoverflow.com/a/52722575/2761869 +template<class R> +struct backwards_t { + R r; + constexpr auto begin() const { using std::rbegin; return rbegin(r); } + constexpr auto begin() { using std::rbegin; return rbegin(r); } + constexpr auto end() const { using std::rend; return rend(r); } + constexpr auto end() { using std::rend; return rend(r); } +}; +template<class R> +constexpr backwards_t<R> backwards(R&& r) { return {std::forward<R>(r)}; } + +QCALayerBackingStore::QCALayerBackingStore(QWindow *window) + : QPlatformBackingStore(window) +{ + qCDebug(lcQpaBackingStore) << "Creating QCALayerBackingStore for" << window; + m_buffers.resize(1); +} + +QCALayerBackingStore::~QCALayerBackingStore() +{ +} + +void QCALayerBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + qCDebug(lcQpaBackingStore) << "Resize requested to" << size; + + if (!staticContents.isNull()) + qCWarning(lcQpaBackingStore) << "QCALayerBackingStore does not support static contents"; + + m_requestedSize = size; +} + +void QCALayerBackingStore::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); + + QMacAutoReleasePool pool; + + qCInfo(lcQpaBackingStore) << "Beginning paint of" << region << "into backingstore of" << m_requestedSize; + + ensureBackBuffer(); // Find an unused back buffer, or reserve space for a new one + + const bool bufferWasRecreated = recreateBackBufferIfNeeded(); + + m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess); + + // Although undocumented, QBackingStore::beginPaint expects the painted region + // to be cleared before use if the window has a surface format with an alpha. + // Fresh IOSurfaces are already cleared, so we don't need to clear those. + if (!bufferWasRecreated && window()->format().hasAlpha()) { + qCDebug(lcQpaBackingStore) << "Clearing" << region << "before use"; + QPainter painter(m_buffers.back()->asImage()); + painter.setCompositionMode(QPainter::CompositionMode_Source); + for (const QRect &rect : region) + painter.fillRect(rect, Qt::transparent); + } + + m_paintedRegion += region; +} + +void QCALayerBackingStore::ensureBackBuffer() +{ + if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer) + return; + + // The current back buffer may have been assigned to a layer in a previous flush, + // but we deferred the swap. Do it now if the surface has been picked up by CA. + if (m_buffers.back() && m_buffers.back()->isInUse() && m_buffers.back() != m_buffers.front()) { + qCInfo(lcQpaBackingStore) << "Back buffer has been picked up by CA, swapping to front"; + std::swap(m_buffers.back(), m_buffers.front()); + } + + if (Q_UNLIKELY(lcQpaBackingStore().isDebugEnabled())) { + // ┌───────┬───────┬───────┬─────┬──────┐ + // │ front ┊ spare ┊ spare ┊ ... ┊ back │ + // └───────┴───────┴───────┴─────┴──────┘ + for (const auto &buffer : m_buffers) { + qCDebug(lcQpaBackingStore).nospace() << " " + << (buffer == m_buffers.front() ? "front" : + buffer == m_buffers.back() ? " back" : + "spare" + ) << ": " << buffer.get(); + } + } + + // Ensure our back buffer is ready to draw into. If not, find a buffer that + // is not in use, or reserve space for a new buffer if none can be found. + for (auto &buffer : backwards(m_buffers)) { + if (!buffer || !buffer->isInUse()) { + // Buffer is okey to use, swap if necessary + if (buffer != m_buffers.back()) + std::swap(buffer, m_buffers.back()); + qCDebug(lcQpaBackingStore) << "Using back buffer" << m_buffers.back().get(); + + static const int kMaxSwapChainDepth = 3; + if (m_buffers.size() > kMaxSwapChainDepth) { + qCDebug(lcQpaBackingStore) << "Reducing swap chain depth to" << kMaxSwapChainDepth; + m_buffers.erase(std::next(m_buffers.begin(), 1), std::prev(m_buffers.end(), 2)); + } + + break; + } else if (buffer == m_buffers.front()) { + // We've exhausted the available buffers, make room for a new one + const int swapChainDepth = m_buffers.size() + 1; + qCDebug(lcQpaBackingStore) << "Available buffers exhausted, increasing swap chain depth to" << swapChainDepth; + m_buffers.resize(swapChainDepth); + break; + } + } + + Q_ASSERT(!m_buffers.back() || !m_buffers.back()->isInUse()); +} + +// Disabled until performance issue on 5K iMac Pro has been investigated further, +// as rounding up during resize will typically result in full screen buffer sizes +// and low frame rate also for smaller window sizes. +#define USE_LAZY_BUFFER_ALLOCATION_DURING_LIVE_WINDOW_RESIZE 0 + +bool QCALayerBackingStore::recreateBackBufferIfNeeded() +{ + const qreal devicePixelRatio = window()->devicePixelRatio(); + QSize requestedBufferSize = m_requestedSize * devicePixelRatio; + + const NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view(); + Q_UNUSED(backingStoreView); + + auto bufferSizeMismatch = [&](const QSize requested, const QSize actual) { +#if USE_LAZY_BUFFER_ALLOCATION_DURING_LIVE_WINDOW_RESIZE + if (backingStoreView.inLiveResize) { + // Prevent over-eager buffer allocation during window resize by reusing larger buffers + return requested.width() > actual.width() || requested.height() > actual.height(); + } +#endif + return requested != actual; + }; + + if (!m_buffers.back() || bufferSizeMismatch(requestedBufferSize, m_buffers.back()->size())) { +#if USE_LAZY_BUFFER_ALLOCATION_DURING_LIVE_WINDOW_RESIZE + if (backingStoreView.inLiveResize) { + // Prevent over-eager buffer allocation during window resize by rounding up + QSize nativeScreenSize = window()->screen()->geometry().size() * devicePixelRatio; + requestedBufferSize = QSize(qNextPowerOfTwo(requestedBufferSize.width()), + qNextPowerOfTwo(requestedBufferSize.height())).boundedTo(nativeScreenSize); + } +#endif + + qCInfo(lcQpaBackingStore) << "Creating surface of" << requestedBufferSize + << "based on requested" << m_requestedSize << "and dpr =" << devicePixelRatio; + + static auto pixelFormat = QImage::toPixelFormat(QImage::Format_ARGB32_Premultiplied); + + NSView *view = static_cast<QCocoaWindow *>(window()->handle())->view(); + auto colorSpace = QCFType<CGColorSpaceRef>::constructFromGet(view.window.screen.colorSpace.CGColorSpace); + + m_buffers.back().reset(new GraphicsBuffer(requestedBufferSize, devicePixelRatio, pixelFormat, colorSpace)); + return true; + } + + return false; +} + +QPaintDevice *QCALayerBackingStore::paintDevice() +{ + Q_ASSERT(m_buffers.back()); + return m_buffers.back()->asImage(); +} + +void QCALayerBackingStore::endPaint() +{ + qCInfo(lcQpaBackingStore) << "Paint ended with painted region" << m_paintedRegion; + m_buffers.back()->unlock(); +} + +void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(region); + Q_UNUSED(offset); + + if (!prepareForFlush()) + return; + + QMacAutoReleasePool pool; + + NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view(); + NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view(); + + id backBufferSurface = (__bridge id)m_buffers.back()->surface(); + if (flushedView.layer.contents == backBufferSurface) { + // We've managed to paint to the back buffer again before Core Animation had time + // to flush the transaction and persist the layer changes to the window server. + // The layer already knows about the back buffer, and we don't need to re-apply + // it to pick up the surface changes, so bail out early. + qCInfo(lcQpaBackingStore).nospace() << "Skipping flush of " << flushedView + << ", layer already reflects back buffer"; + return; + } + + // Trigger a new display cycle if there isn't one. This ensures that our layer updates + // are committed as part of a display-cycle instead of on the next runloop pass. This + // means CA won't try to throttle us if we flush too fast, and we'll coalesce our flush + // with other pending view and layer updates. + backingStoreView.window.viewsNeedDisplay = YES; + + if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer) { + // The private API [CALayer reloadValueForKeyPath:@"contents"] would be preferable, + // but barring any side effects or performance issues we opt for the hammer for now. + flushedView.layer.contents = nil; + } + + qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface + << "to" << flushedView.layer << "of" << flushedView; + + flushedView.layer.contents = backBufferSurface; + + if (flushedView != backingStoreView) { + const CGSize backingStoreSize = backingStoreView.bounds.size; + flushedView.layer.contentsRect = CGRectApplyAffineTransform( + [flushedView convertRect:flushedView.bounds toView:backingStoreView], + // The contentsRect is in unit coordinate system + CGAffineTransformMakeScale(1.0 / backingStoreSize.width, 1.0 / backingStoreSize.height)); + } + + // Since we may receive multiple flushes before a new frame is started, we do not + // swap any buffers just yet. Instead we check in the next beginPaint if the layer's + // surface is in use, and if so swap to an unused surface as the new back buffer. + + // Note: Ideally CoreAnimation would mark a surface as in use the moment we assign + // it to a layer, but as that's not the case we may end up painting to the same back + // buffer once more if we are painting faster than CA can ship the surfaces over to + // the window server. +} + +void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, + QPlatformTextureList *textures, bool translucentBackground) +{ + if (!prepareForFlush()) + return; + + QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground); +} + +QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const +{ + return m_buffers.back().get(); +} + +bool QCALayerBackingStore::prepareForFlush() +{ + if (!m_buffers.back()) { + qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first"; + return false; + } + + // Update dirty state of buffers based on what was painted. The back buffer will be + // less dirty, since we painted to it, while other buffers will become more dirty. + // This allows us to minimize copies between front and back buffers on swap in the + // cases where the painted region overlaps with the previous frame (front buffer). + for (const auto &buffer : m_buffers) { + if (buffer == m_buffers.back()) + buffer->dirtyRegion -= m_paintedRegion; + else + buffer->dirtyRegion += m_paintedRegion; + } + + // After painting, the back buffer is only guaranteed to have content for the painted + // region, and may still have dirty areas that need to be synced up with the front buffer, + // if we have one. We know that the front buffer is always up to date. + if (!m_buffers.back()->dirtyRegion.isEmpty() && m_buffers.front() != m_buffers.back()) { + QRegion preserveRegion = m_buffers.back()->dirtyRegion; + qCDebug(lcQpaBackingStore) << "Preserving" << preserveRegion << "from front to back buffer"; + + m_buffers.front()->lock(QPlatformGraphicsBuffer::SWReadAccess); + const QImage *frontBuffer = m_buffers.front()->asImage(); + + const QRect frontSurfaceBounds(QPoint(0, 0), m_buffers.front()->size()); + const qreal sourceDevicePixelRatio = frontBuffer->devicePixelRatio(); + + m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess); + QPainter painter(m_buffers.back()->asImage()); + painter.setCompositionMode(QPainter::CompositionMode_Source); + + // Let painter operate in device pixels, to make it easier to compare coordinates + const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio(); + painter.scale(1.0 / targetDevicePixelRatio, 1.0 / targetDevicePixelRatio); + + for (const QRect &rect : preserveRegion) { + QRect sourceRect(rect.topLeft() * sourceDevicePixelRatio, rect.size() * sourceDevicePixelRatio); + QRect targetRect(rect.topLeft() * targetDevicePixelRatio, rect.size() * targetDevicePixelRatio); + +#ifdef QT_DEBUG + if (Q_UNLIKELY(!frontSurfaceBounds.contains(sourceRect.bottomRight()))) { + qCWarning(lcQpaBackingStore) << "Front buffer too small to preserve" + << QRegion(sourceRect).subtracted(frontSurfaceBounds); + } +#endif + painter.drawImage(targetRect, *frontBuffer, sourceRect); + } + + m_buffers.back()->unlock(); + m_buffers.front()->unlock(); + + // The back buffer is now completely in sync, ready to be presented + m_buffers.back()->dirtyRegion = QRegion(); + } + + // Prepare for another round of painting + m_paintedRegion = QRegion(); + + return true; +} + +// ---------------------------------------------------------------------------- + +QCALayerBackingStore::GraphicsBuffer::GraphicsBuffer(const QSize &size, qreal devicePixelRatio, + const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace) + : QIOSurfaceGraphicsBuffer(size, format, colorSpace) + , dirtyRegion(0, 0, size.width() / devicePixelRatio, size.height() / devicePixelRatio) + , m_devicePixelRatio(devicePixelRatio) +{ +} + +QImage *QCALayerBackingStore::GraphicsBuffer::asImage() +{ + if (m_image.isNull()) { + qCDebug(lcQpaBackingStore) << "Setting up paint device for" << this; + CFRetain(surface()); + m_image = QImage(data(), size().width(), size().height(), + bytesPerLine(), QImage::toImageFormat(format()), + QImageCleanupFunction(CFRelease), surface()); + m_image.setDevicePixelRatio(m_devicePixelRatio); + } + + Q_ASSERT_X(m_image.constBits() == data(), "QCALayerBackingStore", + "IOSurfaces should have have a fixed location in memory once created"); + + return &m_image; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index affbee35b7..fb3d05d3e4 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -244,7 +244,7 @@ QCocoaIntegration::~QCocoaIntegration() // Delete screens in reverse order to avoid crash in case of multiple screens while (!mScreens.isEmpty()) { - destroyScreen(mScreens.takeLast()); + QWindowSystemInterface::handleScreenRemoved(mScreens.takeLast()); } clearToolbars(); @@ -304,7 +304,7 @@ void QCocoaIntegration::updateScreens() screen = new QCocoaScreen(i); mScreens.append(screen); qCDebug(lcQpaScreen) << "Adding" << screen; - screenAdded(screen); + QWindowSystemInterface::handleScreenAdded(screen); } siblings << screen; } @@ -321,7 +321,7 @@ void QCocoaIntegration::updateScreens() // Prevent stale references to NSScreen during destroy screen->m_screenIndex = -1; qCDebug(lcQpaScreen) << "Removing" << screen; - destroyScreen(screen); + QWindowSystemInterface::handleScreenRemoved(screen); } } @@ -407,7 +407,16 @@ QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLCo QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *window) const { - return new QCocoaBackingStore(window); + QCocoaWindow *platformWindow = static_cast<QCocoaWindow*>(window->handle()); + if (!platformWindow) { + qWarning() << window << "must be created before being used with a backingstore"; + return nullptr; + } + + if (platformWindow->view().layer) + return new QCALayerBackingStore(window); + else + return new QNSWindowBackingStore(window); } QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h new file mode 100644 index 0000000000..872773cb7a --- /dev/null +++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIOSURFACEGRAPHICSBUFFER_H +#define QIOSURFACEGRAPHICSBUFFER_H + +#include <qpa/qplatformgraphicsbuffer.h> +#include <private/qcore_mac_p.h> + +QT_BEGIN_NAMESPACE + +class QIOSurfaceGraphicsBuffer : public QPlatformGraphicsBuffer +{ +public: + QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace); + ~QIOSurfaceGraphicsBuffer(); + + const uchar *data() const override; + uchar *data() override; + int bytesPerLine() const override; + + IOSurfaceRef surface(); + bool isInUse() const; + +protected: + bool doLock(AccessTypes access, const QRect &rect) override; + void doUnlock() override; + +private: + QCFType<IOSurfaceRef> m_surface; + + friend QDebug operator<<(QDebug, const QIOSurfaceGraphicsBuffer *); +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug, const QIOSurfaceGraphicsBuffer *); +#endif + +QT_END_NAMESPACE + +#endif // QIOSURFACEGRAPHICSBUFFER_H diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm new file mode 100644 index 0000000000..a367487e85 --- /dev/null +++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qiosurfacegraphicsbuffer.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qloggingcategory.h> + +#include <CoreGraphics/CoreGraphics.h> +#include <IOSurface/IOSurface.h> + +// CGColorSpaceCopyPropertyList is available on 10.12 and above, +// but was only added in the 10.14 SDK, so declare it just in case. +extern "C" CFPropertyListRef CGColorSpaceCopyPropertyList(CGColorSpaceRef space); + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcQpaIOSurface, "qt.qpa.backingstore.iosurface"); + +QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace) + : QPlatformGraphicsBuffer(size, format) +{ + const size_t width = size.width(); + const size_t height = size.height(); + + Q_ASSERT(width <= IOSurfaceGetPropertyMaximum(kIOSurfaceWidth)); + Q_ASSERT(height <= IOSurfaceGetPropertyMaximum(kIOSurfaceHeight)); + + static const char bytesPerElement = 4; + + const size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, width * bytesPerElement); + const size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, height * bytesPerRow); + + NSDictionary *options = @{ + (id)kIOSurfaceWidth: @(width), + (id)kIOSurfaceHeight: @(height), + (id)kIOSurfacePixelFormat: @(unsigned('BGRA')), + (id)kIOSurfaceBytesPerElement: @(bytesPerElement), + (id)kIOSurfaceBytesPerRow: @(bytesPerRow), + (id)kIOSurfaceAllocSize: @(totalBytes), + }; + + m_surface = IOSurfaceCreate((CFDictionaryRef)options); + Q_ASSERT(m_surface); + + Q_ASSERT(size_t(bytesPerLine()) == bytesPerRow); + Q_ASSERT(size_t(byteCount()) == totalBytes); + + if (colorSpace) { + IOSurfaceSetValue(m_surface, CFSTR("IOSurfaceColorSpace"), + QCFType<CFPropertyListRef>(CGColorSpaceCopyPropertyList(colorSpace))); + } +} + +QIOSurfaceGraphicsBuffer::~QIOSurfaceGraphicsBuffer() +{ +} + +const uchar *QIOSurfaceGraphicsBuffer::data() const +{ + return (const uchar *)IOSurfaceGetBaseAddress(m_surface); +} + +uchar *QIOSurfaceGraphicsBuffer::data() +{ + return (uchar *)IOSurfaceGetBaseAddress(m_surface); +} + +int QIOSurfaceGraphicsBuffer::bytesPerLine() const +{ + return IOSurfaceGetBytesPerRow(m_surface); +} + +IOSurfaceRef QIOSurfaceGraphicsBuffer::surface() +{ + return m_surface; +} + +bool QIOSurfaceGraphicsBuffer::isInUse() const +{ + return IOSurfaceIsInUse(m_surface); +} + +IOSurfaceLockOptions lockOptionsForAccess(QPlatformGraphicsBuffer::AccessTypes access) +{ + IOSurfaceLockOptions lockOptions = 0; + if (!(access & QPlatformGraphicsBuffer::SWWriteAccess)) + lockOptions |= kIOSurfaceLockReadOnly; + return lockOptions; +} + +bool QIOSurfaceGraphicsBuffer::doLock(AccessTypes access, const QRect &rect) +{ + Q_UNUSED(rect); + Q_ASSERT(!isLocked()); + + qCDebug(lcQpaIOSurface) << "Locking" << this << "for" << access; + + // FIXME: Teach QPlatformBackingStore::composeAndFlush about non-2D texture + // targets, so that we can use CGLTexImageIOSurface2D to support TextureAccess. + if (access & (TextureAccess | HWCompositor)) + return false; + + auto lockOptions = lockOptionsForAccess(access); + + // Try without read-back first + lockOptions |= kIOSurfaceLockAvoidSync; + kern_return_t ret = IOSurfaceLock(m_surface, lockOptions, nullptr); + if (ret == kIOSurfaceSuccess) + return true; + + if (ret == kIOReturnCannotLock) { + qCWarning(lcQpaIOSurface) << "Locking of" << this << "requires read-back"; + lockOptions ^= kIOSurfaceLockAvoidSync; + ret = IOSurfaceLock(m_surface, lockOptions, nullptr); + } + + if (ret != kIOSurfaceSuccess) { + qCWarning(lcQpaIOSurface) << "Failed to lock" << this << ret; + return false; + } + + return true; +} + +void QIOSurfaceGraphicsBuffer::doUnlock() +{ + qCDebug(lcQpaIOSurface) << "Unlocking" << this << "from" << isLocked(); + + auto lockOptions = lockOptionsForAccess(isLocked()); + bool success = IOSurfaceUnlock(m_surface, lockOptions, nullptr) == kIOSurfaceSuccess; + Q_ASSERT_X(success, "QIOSurfaceGraphicsBuffer", "Unlocking surface should succeed"); +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QIOSurfaceGraphicsBuffer *graphicsBuffer) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + debug << "QIOSurfaceGraphicsBuffer(" << (const void *)graphicsBuffer; + if (graphicsBuffer) { + debug << ", surface=" << graphicsBuffer->m_surface; + debug << ", size=" << graphicsBuffer->size(); + debug << ", isLocked=" << bool(graphicsBuffer->isLocked()); + debug << ", isInUse=" << graphicsBuffer->isInUse(); + } + debug << ')'; + return debug; +} +#endif // !QT_NO_DEBUG_STREAM + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index 6db5ed8bad..f7e14b7883 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -163,6 +163,13 @@ return NSViewLayerContentsRedrawDuringViewResize; } +- (NSViewLayerContentsPlacement)layerContentsPlacement +{ + // Always place the layer at top left without any automatic scaling, + // so that we can re-use larger layers when resizing a window down. + return NSViewLayerContentsPlacementTopLeft; +} + - (void)updateMetalLayerDrawableSize:(CAMetalLayer *)layer { CGSize drawableSize = layer.bounds.size; diff --git a/src/plugins/platforms/directfb/qdirectfb_egl.cpp b/src/plugins/platforms/directfb/qdirectfb_egl.cpp index dad553c890..d3c95f0b65 100644 --- a/src/plugins/platforms/directfb/qdirectfb_egl.cpp +++ b/src/plugins/platforms/directfb/qdirectfb_egl.cpp @@ -44,6 +44,7 @@ #include <QtGui/QOpenGLContext> #include <qpa/qplatformopenglcontext.h> +#include <qpa/qwindowsysteminterface.h> #include <QtGui/QScreen> #include <QtEglSupport/private/qeglplatformcontext_p.h> @@ -248,7 +249,7 @@ QPlatformOpenGLContext *QDirectFbIntegrationEGL::createPlatformOpenGLContext(QOp void QDirectFbIntegrationEGL::initializeScreen() { m_primaryScreen.reset(new QDirectFbScreenEGL(0)); - screenAdded(m_primaryScreen.data()); + QWindowSystemInterface::handleScreenAdded(m_primaryScreen.data()); } bool QDirectFbIntegrationEGL::hasCapability(QPlatformIntegration::Capability cap) const diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.cpp b/src/plugins/platforms/directfb/qdirectfbintegration.cpp index cdf340da7a..73e308da53 100644 --- a/src/plugins/platforms/directfb/qdirectfbintegration.cpp +++ b/src/plugins/platforms/directfb/qdirectfbintegration.cpp @@ -56,6 +56,7 @@ #include <QtCore/QThread> #include <QtCore/QAbstractEventDispatcher> #include <qpa/qplatforminputcontextfactory_p.h> +#include <qpa/qwindowsysteminterface.h> QT_BEGIN_NAMESPACE @@ -113,7 +114,7 @@ void QDirectFbIntegration::initializeDirectFB() void QDirectFbIntegration::initializeScreen() { m_primaryScreen.reset(new QDirectFbScreen(0)); - screenAdded(m_primaryScreen.data()); + QWindowSystemInterface::handleScreenAdded(m_primaryScreen.data()); } void QDirectFbIntegration::initializeInput() diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp index 0a3a37863a..81bad45cd2 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp @@ -200,10 +200,8 @@ void QEglFSDeviceIntegration::screenInit() void QEglFSDeviceIntegration::screenDestroy() { QGuiApplication *app = qGuiApp; - QEglFSIntegration *platformIntegration = static_cast<QEglFSIntegration *>( - QGuiApplicationPrivate::platformIntegration()); while (!app->screens().isEmpty()) - platformIntegration->removeScreen(app->screens().constLast()->handle()); + QWindowSystemInterface::handleScreenRemoved(app->screens().constLast()->handle()); } QSizeF QEglFSDeviceIntegration::physicalScreenSize() const diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp index 8ccb0ef2cd..48469b0f8c 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp @@ -120,16 +120,6 @@ QEglFSIntegration::QEglFSIntegration() initResources(); } -void QEglFSIntegration::addScreen(QPlatformScreen *screen, bool isPrimary) -{ - screenAdded(screen, isPrimary); -} - -void QEglFSIntegration::removeScreen(QPlatformScreen *screen) -{ - destroyScreen(screen); -} - void QEglFSIntegration::initialize() { qt_egl_device_integration()->platformInit(); @@ -147,7 +137,7 @@ void QEglFSIntegration::initialize() m_vtHandler.reset(new QFbVtHandler); if (qt_egl_device_integration()->usesDefaultScreen()) - addScreen(new QEglFSScreen(display())); + QWindowSystemInterface::handleScreenAdded(new QEglFSScreen(display())); else qt_egl_device_integration()->screenInit(); diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h index 4b4585d33c..898b322834 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h @@ -103,9 +103,6 @@ public: QFbVtHandler *vtHandler() { return m_vtHandler.data(); } - void addScreen(QPlatformScreen *screen, bool isPrimary = false); - void removeScreen(QPlatformScreen *screen); - private: EGLNativeDisplayType nativeDisplay() const; void createInputHandlers(); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp index 5e2708e958..cb7844aff0 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp @@ -45,6 +45,8 @@ #include <QtEglSupport/private/qeglconvenience_p.h> #include <QtEglSupport/private/qeglplatformcontext_p.h> +#include <qpa/qwindowsysteminterface.h> + #include <QtCore/QJsonDocument> #include <QtCore/QJsonArray> #include <QtCore/QJsonParseError> @@ -80,8 +82,6 @@ bool QEglFSEmulatorIntegration::usesDefaultScreen() void QEglFSEmulatorIntegration::screenInit() { - QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration()); - // Use qgsGetDisplays() call to retrieve the available screens from the Emulator if (getDisplays) { QByteArray displaysInfo = getDisplays(); @@ -93,7 +93,7 @@ void QEglFSEmulatorIntegration::screenInit() QJsonArray screenArray = displaysDocument.array(); for (auto screenValue : screenArray) { if (screenValue.isObject()) - integration->addScreen(new QEglFSEmulatorScreen(screenValue.toObject())); + QWindowSystemInterface::handleScreenAdded(new QEglFSEmulatorScreen(screenValue.toObject())); } } } else { diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp index ab39af6b80..ecdfb352ab 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp @@ -260,7 +260,7 @@ QKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice() if (Q_UNLIKELY(!deviceName)) qFatal("Failed to query device name from EGLDevice"); - return new QEglFSKmsEglDevice(this, screenConfig(), deviceName); + return new QEglFSKmsEglDevice(this, screenConfig(), QLatin1String(deviceName)); } bool QEglFSKmsEglDeviceIntegration::query_egl_device() diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp index b073577797..4f0b0d7725 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp @@ -58,7 +58,7 @@ void QEglFSKmsDevice::registerScreen(QPlatformScreen *screen, QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen); s->setVirtualPosition(virtualPos); s->setVirtualSiblings(virtualSiblings); - static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->addScreen(s, isPrimary); + QWindowSystemInterface::handleScreenAdded(s, isPrimary); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/haiku/qhaikuintegration.cpp b/src/plugins/platforms/haiku/qhaikuintegration.cpp index 8bd2171794..44df6ae8f5 100644 --- a/src/plugins/platforms/haiku/qhaikuintegration.cpp +++ b/src/plugins/platforms/haiku/qhaikuintegration.cpp @@ -49,6 +49,7 @@ #include <QCoreApplication> #include <QFileInfo> #include <qpa/qplatformwindow.h> +#include <qpa/qwindowsysteminterface.h> #include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h> #include <Application.h> @@ -81,12 +82,12 @@ QHaikuIntegration::QHaikuIntegration(const QStringList ¶meters) m_services = new QHaikuServices; // notify system about available screen - screenAdded(m_screen); + QWindowSystemInterface::handleScreenAdded(m_screen); } QHaikuIntegration::~QHaikuIntegration() { - destroyScreen(m_screen); + QWindowSystemInterface::handleScreenRemoved(m_screen); m_screen = nullptr; delete m_services; diff --git a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp index ae802bb1fa..3ad31dc562 100644 --- a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp +++ b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp @@ -51,7 +51,7 @@ #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatforminputcontextfactory_p.h> - +#include <qpa/qwindowsysteminterface.h> QT_BEGIN_NAMESPACE @@ -64,13 +64,13 @@ QIntegrityFbIntegration::QIntegrityFbIntegration(const QStringList ¶mList) QIntegrityFbIntegration::~QIntegrityFbIntegration() { - destroyScreen(m_primaryScreen); + QWindowSystemInterface::handleScreenRemoved(m_primaryScreen); } void QIntegrityFbIntegration::initialize() { if (m_primaryScreen->initialize()) - screenAdded(m_primaryScreen); + QWindowSystemInterface::handleScreenAdded(m_primaryScreen); else qWarning("integrityfb: Failed to initialize screen"); diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index 818250fcee..eeb44b54d3 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -92,10 +92,6 @@ public: QPlatformAccessibility *accessibility() const override; #endif - // Called from Objective-C class QIOSScreenTracker, which can't be friended - void addScreen(QPlatformScreen *screen) { screenAdded(screen); } - void destroyScreen(QPlatformScreen *screen) { QPlatformIntegration::destroyScreen(screen); } - void beep() const override; static QIOSIntegration *instance(); diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index bec8354fcc..9eca0eaad3 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -107,7 +107,7 @@ void QIOSIntegration::initialize() } for (UIScreen *screen in screens) - addScreen(new QIOSScreen(screen)); + QWindowSystemInterface::handleScreenAdded(new QIOSScreen(screen)); // Depends on a primary screen being present m_inputContext = new QIOSInputContext; @@ -143,7 +143,7 @@ QIOSIntegration::~QIOSIntegration() m_inputContext = 0; foreach (QScreen *screen, QGuiApplication::screens()) - destroyScreen(screen->handle()); + QWindowSystemInterface::handleScreenRemoved(screen->handle()); delete m_platformServices; m_platformServices = 0; diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index 4f753be21a..9aba658479 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -50,6 +50,7 @@ #include <QtGui/private/qwindow_p.h> #include <private/qcoregraphics_p.h> +#include <qpa/qwindowsysteminterface.h> #include <sys/sysctl.h> @@ -105,10 +106,10 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) + (void)screenConnected:(NSNotification*)notification { - QIOSIntegration *integration = QIOSIntegration::instance(); - Q_ASSERT_X(integration, Q_FUNC_INFO, "Screen connected before QIOSIntegration creation"); + Q_ASSERT_X(QIOSIntegration::instance(), Q_FUNC_INFO, + "Screen connected before QIOSIntegration creation"); - integration->addScreen(new QIOSScreen([notification object])); + QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object])); } + (void)screenDisconnected:(NSNotification*)notification @@ -116,8 +117,7 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) QIOSScreen *screen = qtPlatformScreenFor([notification object]); Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about"); - QIOSIntegration *integration = QIOSIntegration::instance(); - integration->destroyScreen(screen); + QWindowSystemInterface::handleScreenRemoved(screen); } + (void)screenModeChanged:(NSNotification*)notification diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index 9e38900bcd..68843aa4c5 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -54,6 +54,7 @@ #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatforminputcontextfactory_p.h> +#include <qpa/qwindowsysteminterface.h> #if QT_CONFIG(libinput) #include <QtInputSupport/private/qlibinputhandler_p.h> @@ -89,13 +90,13 @@ QLinuxFbIntegration::QLinuxFbIntegration(const QStringList ¶mList) QLinuxFbIntegration::~QLinuxFbIntegration() { - destroyScreen(m_primaryScreen); + QWindowSystemInterface::handleScreenRemoved(m_primaryScreen); } void QLinuxFbIntegration::initialize() { if (m_primaryScreen->initialize()) - screenAdded(m_primaryScreen); + QWindowSystemInterface::handleScreenAdded(m_primaryScreen); else qWarning("linuxfb: Failed to initialize screen"); diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp index 0c04608fca..f457f69f11 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.cpp +++ b/src/plugins/platforms/minimal/qminimalintegration.cpp @@ -43,6 +43,7 @@ #include <QtGui/private/qpixmap_raster_p.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformwindow.h> +#include <qpa/qwindowsysteminterface.h> #include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h> #if defined(Q_OS_WINRT) @@ -108,7 +109,7 @@ QMinimalIntegration::QMinimalIntegration(const QStringList ¶meters) mPrimaryScreen->mDepth = 32; mPrimaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied; - screenAdded(mPrimaryScreen); + QWindowSystemInterface::handleScreenAdded(mPrimaryScreen); } QMinimalIntegration::~QMinimalIntegration() diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp index da58441d67..a0d35a80cd 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp @@ -58,6 +58,7 @@ #include <QtGui/QSurfaceFormat> #include <QtGui/QOpenGLContext> #include <QtGui/QScreen> +#include <qpa/qwindowsysteminterface.h> // this is where EGL headers are pulled in, make sure it is last #include "qminimaleglscreen.h" @@ -90,7 +91,7 @@ protected: QMinimalEglIntegration::QMinimalEglIntegration() : mFontDb(new QGenericUnixFontDatabase()), mScreen(new QMinimalEglScreen(EGL_DEFAULT_DISPLAY)) { - screenAdded(mScreen); + QWindowSystemInterface::handleScreenAdded(mScreen); #ifdef QEGL_EXTRA_DEBUG qWarning("QMinimalEglIntegration\n"); @@ -99,7 +100,7 @@ QMinimalEglIntegration::QMinimalEglIntegration() QMinimalEglIntegration::~QMinimalEglIntegration() { - destroyScreen(mScreen); + QWindowSystemInterface::handleScreenRemoved(mScreen); delete mFontDb; } diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.cpp b/src/plugins/platforms/mirclient/qmirclientintegration.cpp index eef96ee3de..d2b1dbee0d 100644 --- a/src/plugins/platforms/mirclient/qmirclientintegration.cpp +++ b/src/plugins/platforms/mirclient/qmirclientintegration.cpp @@ -58,6 +58,7 @@ #include <qpa/qplatformnativeinterface.h> #include <qpa/qplatforminputcontextfactory_p.h> #include <qpa/qplatforminputcontext.h> +#include <qpa/qwindowsysteminterface.h> #include <QtEglSupport/private/qeglconvenience_p.h> #include <QtEglSupport/private/qeglpbuffer_p.h> #include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> @@ -149,12 +150,12 @@ void QMirClientClientIntegration::initialize() // Init the ScreenObserver mScreenObserver.reset(new QMirClientScreenObserver(mMirConnection)); connect(mScreenObserver.data(), &QMirClientScreenObserver::screenAdded, - [this](QMirClientScreen *screen) { this->screenAdded(screen); }); + [this](QMirClientScreen *screen) { QWindowSystemInterface::handleScreenAdded(screen); }); connect(mScreenObserver.data(), &QMirClientScreenObserver::screenRemoved, this, &QMirClientClientIntegration::destroyScreen); Q_FOREACH (auto screen, mScreenObserver->screens()) { - screenAdded(screen); + QWindowSystemInterface::handleScreenAdded(screen); } // Initialize input. @@ -392,7 +393,7 @@ void QMirClientClientIntegration::destroyScreen(QMirClientScreen *screen) #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) delete screen; #else - QPlatformIntegration::destroyScreen(screen); + QWindowSystemInterface::handleScreenRemoved(screen); #endif } diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp index f2933b7179..869e9228cd 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp @@ -63,6 +63,7 @@ #include <qpa/qplatforminputcontextfactory_p.h> #include <qpa/qplatforminputcontext.h> #include <qpa/qplatformtheme.h> +#include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformservices.h> @@ -121,7 +122,7 @@ QOffscreenIntegration::QOffscreenIntegration() #endif m_services.reset(new QPlatformServices); - screenAdded(new QOffscreenScreen); + QWindowSystemInterface::handleScreenAdded(new QOffscreenScreen); } QOffscreenIntegration::~QOffscreenIntegration() diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp index 4850ca2e45..c5dc40a206 100644 --- a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp +++ b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp @@ -50,6 +50,7 @@ #include <QtGui/private/qguiapplication_p.h> #include <QtGui/QOpenGLContext> #include <QtGui/QScreen> +#include <qpa/qwindowsysteminterface.h> #include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h> #include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> @@ -135,13 +136,3 @@ QPlatformPrinterSupport * QOpenWFDIntegration::printerSupport() const { return mPrinterSupport; } - -void QOpenWFDIntegration::addScreen(QOpenWFDScreen *screen) -{ - screenAdded(screen); -} - -void QOpenWFDIntegration::destroyScreen(QOpenWFDScreen *screen) -{ - QPlatformIntegration::destroyScreen(screen); -} diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.h b/src/plugins/platforms/openwfd/qopenwfdintegration.h index 1ce1001bed..444aaccaaf 100644 --- a/src/plugins/platforms/openwfd/qopenwfdintegration.h +++ b/src/plugins/platforms/openwfd/qopenwfdintegration.h @@ -68,8 +68,6 @@ public: QPlatformPrinterSupport *printerSupport() const; - void addScreen(QOpenWFDScreen *screen); - void destroyScreen(QOpenWFDScreen *screen); private: QList<QPlatformScreen *> mScreens; QList<QOpenWFDDevice *>mDevices; diff --git a/src/plugins/platforms/openwfd/qopenwfdport.cpp b/src/plugins/platforms/openwfd/qopenwfdport.cpp index 33254fe83c..34b4439958 100644 --- a/src/plugins/platforms/openwfd/qopenwfdport.cpp +++ b/src/plugins/platforms/openwfd/qopenwfdport.cpp @@ -133,7 +133,7 @@ void QOpenWFDPort::attach() wfdBindPipelineToPort(mDevice->handle(),mPort,mPipeline); mScreen = new QOpenWFDScreen(this); - mDevice->integration()->addScreen(mScreen); + QWindowSystemInterface::handleScreenAdded(mScreen); mAttached = true; } @@ -145,7 +145,7 @@ void QOpenWFDPort::detach() mAttached = false; mOn = false; - mDevice->integration()->destroyScreen(mScreen); + QWindowSystemInterface::handleScreenRemoved(mScreen); wfdDestroyPipeline(mDevice->handle(),mPipeline); mPipelineId = WFD_INVALID_PIPELINE_ID; diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index a996e765c4..a45dcabeb7 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -649,7 +649,7 @@ void QQnxIntegration::createDisplay(screen_display_t display, bool isPrimary) { QQnxScreen *screen = new QQnxScreen(m_screenContext, display, isPrimary); m_screens.append(screen); - screenAdded(screen); + QWindowSystemInterface::handleScreenAdded(screen); screen->adjustOrientation(); QObject::connect(m_screenEventHandler, SIGNAL(newWindowCreated(void*)), @@ -669,14 +669,14 @@ void QQnxIntegration::removeDisplay(QQnxScreen *screen) Q_CHECK_PTR(screen); Q_ASSERT(m_screens.contains(screen)); m_screens.removeAll(screen); - destroyScreen(screen); + QWindowSystemInterface::handleScreenRemoved(screen); } void QQnxIntegration::destroyDisplays() { qIntegrationDebug(); Q_FOREACH (QQnxScreen *screen, m_screens) { - QPlatformIntegration::destroyScreen(screen); + QWindowSystemInterface::handleScreenRemoved(screen); } m_screens.clear(); } diff --git a/src/plugins/platforms/vnc/qvncintegration.cpp b/src/plugins/platforms/vnc/qvncintegration.cpp index 1e2cf6292c..c7a796464a 100644 --- a/src/plugins/platforms/vnc/qvncintegration.cpp +++ b/src/plugins/platforms/vnc/qvncintegration.cpp @@ -52,6 +52,7 @@ #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatforminputcontextfactory_p.h> #include <private/qinputdevicemanager_p_p.h> +#include <qpa/qwindowsysteminterface.h> #include <QtCore/QRegularExpression> @@ -77,13 +78,13 @@ QVncIntegration::QVncIntegration(const QStringList ¶mList) QVncIntegration::~QVncIntegration() { delete m_server; - destroyScreen(m_primaryScreen); + QWindowSystemInterface::handleScreenRemoved(m_primaryScreen); } void QVncIntegration::initialize() { if (m_primaryScreen->initialize()) - screenAdded(m_primaryScreen); + QWindowSystemInterface::handleScreenAdded(m_primaryScreen); else qWarning("vnc: Failed to initialize screen"); diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 1964cefdad..499a82adbd 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -98,7 +98,10 @@ QWasmIntegration::QWasmIntegration() QWasmIntegration::~QWasmIntegration() { delete m_fontDb; - qDeleteAll(m_screens); + + while (!m_screens.isEmpty()) + QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast()); + s_instance = nullptr; } @@ -191,7 +194,7 @@ void QWasmIntegration::addScreen(const QString &canvasId) QWasmScreen *screen = new QWasmScreen(canvasId); m_clipboard->installEventHandlers(canvasId); m_screens.append(screen); - screenAdded(screen); + QWindowSystemInterface::handleScreenAdded(screen); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index da86852766..e28b2c2fb3 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -107,9 +107,6 @@ public: static QWindowsIntegration *instance() { return m_instance; } - inline void emitScreenAdded(QPlatformScreen *s, bool isPrimary = false) { screenAdded(s, isPrimary); } - inline void emitDestroyScreen(QPlatformScreen *s) { destroyScreen(s); } - unsigned options() const; void beep() const override; diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index a161dc46e9..0520f88935 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -121,7 +121,7 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM QWindowsScreenData data; if (monitorData(hMonitor, &data)) { WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p); - // QPlatformIntegration::screenAdded() documentation specifies that first + // QWindowSystemInterface::handleScreenAdded() documentation specifies that first // added screen will be the primary screen, so order accordingly. // Note that the side effect of this policy is that there is no way to change primary // screen reported by Qt, unless we want to delete all existing screens and add them @@ -521,7 +521,7 @@ void QWindowsScreenManager::removeScreen(int index) if (movedWindowCount) QWindowSystemInterface::flushWindowSystemEvents(); } - QWindowsIntegration::instance()->emitDestroyScreen(m_screens.takeAt(index)); + QWindowSystemInterface::handleScreenRemoved(m_screens.takeAt(index)); } /*! @@ -541,7 +541,7 @@ bool QWindowsScreenManager::handleScreenChanges() } else { QWindowsScreen *newScreen = new QWindowsScreen(newData); m_screens.push_back(newScreen); - QWindowsIntegration::instance()->emitScreenAdded(newScreen, + QWindowSystemInterface::handleScreenAdded(newScreen, newData.flags & QWindowsScreenData::PrimaryScreen); qCDebug(lcQpaWindows) << "New Monitor: " << newData; } // exists @@ -561,7 +561,7 @@ void QWindowsScreenManager::clearScreens() { // Delete screens in reverse order to avoid crash in case of multiple screens while (!m_screens.isEmpty()) - QWindowsIntegration::instance()->emitDestroyScreen(m_screens.takeLast()); + QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast()); } const QWindowsScreen *QWindowsScreenManager::screenAtDp(const QPoint &p) const diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 8bf090bf03..07fd2916c2 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1759,15 +1759,12 @@ void QWindowsWindow::checkForScreenChanged() QPlatformScreen *currentScreen = screen(); const auto &screenManager = QWindowsContext::instance()->screenManager(); - // QTBUG-62971: When dragging a window by its border, detect by mouse position - // to prevent it from oscillating between screens when it resizes - const QWindowsScreen *newScreen = testFlag(ResizeMoveActive) - ? screenManager.screenAtDp(QWindowsCursor::mousePosition()) - : screenManager.screenForHwnd(m_data.hwnd); + const QWindowsScreen *newScreen = screenManager.screenForHwnd(m_data.hwnd); if (newScreen != nullptr && newScreen != currentScreen) { qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ << ' ' << window() << " \"" << currentScreen->name() << "\"->\"" << newScreen->name() << '"'; + setFlag(SynchronousGeometryChangeEvent); QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); } } @@ -1786,11 +1783,14 @@ void QWindowsWindow::handleGeometryChange() fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } + const bool wasSync = testFlag(SynchronousGeometryChangeEvent); checkForScreenChanged(); if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); + if (!wasSync) + clearFlag(SynchronousGeometryChangeEvent); qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry; } diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 78cbc3aec3..27d3746933 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -133,7 +133,7 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) }); d->inputContext.reset(new QWinRTInputContext(d->mainScreen)); - screenAdded(d->mainScreen); + QWindowSystemInterface::handleScreenAdded(d->mainScreen); d->platformServices = new QWinRTServices; d->clipboard = new QWinRTClipboard; #if QT_CONFIG(accessibility) @@ -154,7 +154,7 @@ QWinRTIntegration::~QWinRTIntegration() Q_ASSERT_SUCCEEDED(hr); } - destroyScreen(d->mainScreen); + QWindowSystemInterface::handleScreenRemoved(d->mainScreen); Windows::Foundation::Uninitialize(); } diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index d42a33c22b..476de6d1e5 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -652,6 +652,12 @@ static const char *qglx_threadedgl_blacklist_renderer[] = { 0 }; +static const char *qglx_threadedgl_blacklist_vendor[] = { + "llvmpipe", // QTCREATORBUG-10666 + "nouveau", // https://bugs.freedesktop.org/show_bug.cgi?id=91632 + nullptr +}; + void QGLXContext::queryDummyContext() { if (m_queriedDummyContext) @@ -710,6 +716,18 @@ void QGLXContext::queryDummyContext() } } } + if (const char *vendor = (const char *) glGetString(GL_VENDOR)) { + for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) { + if (strstr(vendor, qglx_threadedgl_blacklist_vendor[i]) != 0) { + qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: " + "blacklisted vendor \"" + << qglx_threadedgl_blacklist_vendor[i] + << "\""; + m_supportsThreading = false; + break; + } + } + } if (glxvendor && m_supportsThreading) { // Blacklist Mesa drivers due to QTCREATORBUG-10875 (crash in creator), diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 1ff06dd39e..06d1000993 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -152,10 +152,9 @@ QXcbConnection::~QXcbConnection() if (m_eventQueue) delete m_eventQueue; - QXcbIntegration *integration = QXcbIntegration::instance(); // Delete screens in reverse order to avoid crash in case of multiple screens while (!m_screens.isEmpty()) - integration->destroyScreen(m_screens.takeLast()); + QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast()); while (!m_virtualDesktops.isEmpty()) delete m_virtualDesktops.takeLast(); diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.h b/src/plugins/platforms/xcb/qxcbconnection_basic.h index 3691763398..b979129cba 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.h +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.h @@ -40,6 +40,7 @@ #define QXCBBASICCONNECTION_H #include "qxcbatom.h" +#include "qxcbexport.h" #include <QtCore/QPair> #include <QtCore/QObject> @@ -55,7 +56,7 @@ QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcQpaXcb) -class QXcbBasicConnection : public QObject +class Q_XCB_EXPORT QXcbBasicConnection : public QObject { Q_OBJECT public: diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp index 4bafe83156..9ba71ada37 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp @@ -44,6 +44,8 @@ #include <QtCore/QString> #include <QtCore/QList> +#include <qpa/qwindowsysteminterface.h> + #include <xcb/xinerama.h> void QXcbConnection::xrandrSelectEvents() @@ -211,7 +213,7 @@ void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_cha m_screens.swapItemsAt(0, idx); } screen->virtualDesktop()->setPrimaryScreen(screen); - QXcbIntegration::instance()->setPrimaryScreen(screen); + QWindowSystemInterface::handlePrimaryScreenChanged(screen); } } } @@ -234,7 +236,7 @@ QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop, m_screens.append(screen); } virtualDesktop->addScreen(screen); - QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); + QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary()); return screen; } @@ -261,10 +263,10 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen) const int idx = m_screens.indexOf(newPrimary); if (idx > 0) m_screens.swapItemsAt(0, idx); - QXcbIntegration::instance()->setPrimaryScreen(newPrimary); + QWindowSystemInterface::handlePrimaryScreenChanged(newPrimary); } - QXcbIntegration::instance()->destroyScreen(screen); + QWindowSystemInterface::handleScreenRemoved(screen); } } @@ -406,7 +408,7 @@ void QXcbConnection::initializeScreens() // Push the screens to QGuiApplication for (QXcbScreen *screen : qAsConst(m_screens)) { qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")"; - QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); + QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary()); } qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name(); diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index f13e232291..571726c354 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -137,8 +137,6 @@ private: QScopedPointer<QPlatformServices> m_services; - friend class QXcbConnection; // access QPlatformIntegration::screenAdded() - mutable QByteArray m_wmClass; const char *m_instanceName; bool m_canGrab; diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 4d526a6bda..899081e752 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -412,12 +412,15 @@ void *QXcbNativeInterface::atspiBus() auto reply = Q_XCB_REPLY(xcb_get_property, defaultConnection->xcb_connection(), false, defaultConnection->rootWindow(), atspiBusAtom, XCB_ATOM_STRING, 0, 128); - Q_ASSERT(!reply->bytes_after); + if (!reply) + return nullptr; + char *data = (char *)xcb_get_property_value(reply.get()); int length = xcb_get_property_value_length(reply.get()); return new QByteArray(data, length); } - return 0; + + return nullptr; } void QXcbNativeInterface::setAppTime(QScreen* screen, xcb_timestamp_t time) diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index fd7f72eebf..3af5237f3d 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -900,7 +900,7 @@ bool readInputFile(Options *options) options->extraPlugins = extraPlugins.toString().split(QLatin1Char(',')); } - { + if (!options->auxMode) { const QJsonValue stdcppPath = jsonObject.value(QStringLiteral("stdcpp-path")); if (stdcppPath.isUndefined()) { fprintf(stderr, "No stdcpp-path defined in json file.\n"); diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index 57d6994c88..cd27c9c5be 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -143,11 +143,6 @@ Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *r void QGestureManager::unregisterGestureRecognizer(Qt::GestureType type) { QList<QGestureRecognizer *> list = m_recognizers.values(type); - while (QGestureRecognizer *recognizer = m_recognizers.take(type)) { - // ensuring an entry exists causes the recognizer to be deleted on destruction of the manager - auto &gestures = m_obsoleteGestures[recognizer]; - Q_UNUSED(gestures); - } foreach (QGesture *g, m_gestureToRecognizer.keys()) { QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g); if (list.contains(recognizer)) { diff --git a/src/widgets/kernel/qgesturerecognizer.cpp b/src/widgets/kernel/qgesturerecognizer.cpp index 65c46a5e56..75d091ce4e 100644 --- a/src/widgets/kernel/qgesturerecognizer.cpp +++ b/src/widgets/kernel/qgesturerecognizer.cpp @@ -41,6 +41,7 @@ #include "private/qgesture_p.h" #include "private/qgesturemanager_p.h" +#include "private/qapplication_p.h" #ifndef QT_NO_GESTURES @@ -231,6 +232,11 @@ Qt::GestureType QGestureRecognizer::registerRecognizer(QGestureRecognizer *recog */ void QGestureRecognizer::unregisterRecognizer(Qt::GestureType type) { + auto qAppPriv = QApplicationPrivate::instance(); + if (!qAppPriv) + return; + if (!qAppPriv->gestureManager) + return; QGestureManager::instance()->unregisterGestureRecognizer(type); } diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index ac4fb7fbd1..97ec1d3f19 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -1971,8 +1971,8 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SH_Widget_Animate Deprecated. Use \l{SH_Widget_Animation_Duration} instead. - \value SH_Splitter_OpaqueResize Determines if resizing is opaque - This enum value has been introduced in Qt 5.2 + \value SH_Splitter_OpaqueResize Determines if widgets are resized dynamically (opaquely) while + interactively moving the splitter. This enum value was introduced in Qt 5.2. \value SH_TabBar_ChangeCurrentDelay Determines the delay before the current tab is changed while dragging over the tabbar, in milliseconds. This diff --git a/src/widgets/widgets/qsplashscreen.cpp b/src/widgets/widgets/qsplashscreen.cpp index 4af4f90119..bf6bf1c7c9 100644 --- a/src/widgets/widgets/qsplashscreen.cpp +++ b/src/widgets/widgets/qsplashscreen.cpp @@ -289,8 +289,7 @@ void QSplashScreen::setPixmap(const QPixmap &pixmap) // 1) If a QDesktopScreenWidget is found in the parent hierarchy, use that (see docs on // QSplashScreen(QWidget *, QPixmap). // 2) If a widget with associated QWindow is found, use that -// 3) When nothing can be found, do not position the widget, allowing for -// QPlatformWindow::initialGeometry() to center it over the cursor +// 3) When nothing can be found, try to center it over the cursor static inline int screenNumberOf(const QDesktopScreenWidget *dsw) { @@ -307,7 +306,15 @@ const QScreen *QSplashScreenPrivate::screenFor(const QWidget *w) if (QWindow *window = p->windowHandle()) return window->screen(); } - return nullptr; +#if QT_CONFIG(cursor) + // Note: We could rely on QPlatformWindow::initialGeometry() to center it + // over the cursor, but not all platforms (namely Android) use that. + if (QGuiApplication::screens().size() > 1) { + if (auto screenAtCursor = QGuiApplication::screenAt(QCursor::pos())) + return screenAtCursor; + } +#endif // cursor + return QGuiApplication::primaryScreen(); } void QSplashScreenPrivate::setPixmap(const QPixmap &p, const QScreen *screen) diff --git a/src/widgets/widgets/qsplitter.cpp b/src/widgets/widgets/qsplitter.cpp index 98bb23caad..de838a8f93 100644 --- a/src/widgets/widgets/qsplitter.cpp +++ b/src/widgets/widgets/qsplitter.cpp @@ -161,11 +161,10 @@ Qt::Orientation QSplitterHandle::orientation() const /*! - Returns \c true if widgets are resized dynamically (opaquely), otherwise - returns \c false. This value is controlled by the QSplitter. + Returns \c true if widgets are resized dynamically (opaquely) while interactively moving the + splitter. Otherwise returns \c false. This value is controlled by the QSplitter. \sa QSplitter::opaqueResize() - */ bool QSplitterHandle::opaqueResize() const { @@ -1483,7 +1482,8 @@ int QSplitter::closestLegalPosition(int pos, int index) /*! \property QSplitter::opaqueResize - \brief whether resizing is opaque + Returns \c true if widgets are resized dynamically (opaquely) while interactively moving the + splitter. Otherwise returns \c false. The default resize behavior is style dependent (determined by the SH_Splitter_OpaqueResize style hint). However, you can override it diff --git a/tests/auto/corelib/kernel/qtimer/BLACKLIST b/tests/auto/corelib/kernel/qtimer/BLACKLIST new file mode 100644 index 0000000000..16cbab4587 --- /dev/null +++ b/tests/auto/corelib/kernel/qtimer/BLACKLIST @@ -0,0 +1,5 @@ +[remainingTime] +windows +osx +[basic_chrono] +osx diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 361055ce67..302180586e 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -230,6 +230,8 @@ private slots: void convertColorTable(); + void wideImage(); + #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) void toWinHBITMAP_data(); void toWinHBITMAP(); @@ -3559,6 +3561,24 @@ void tst_QImage::convertColorTable() QCOMPARE(rgb32.pixel(0,0), 0xffffffff); } +void tst_QImage::wideImage() +{ + // QTBUG-73731 and QTBUG-73732 + QImage i(538994187, 2, QImage::Format_ARGB32); + QImage i2(32, 32, QImage::Format_ARGB32); + i2.fill(Qt::white); + + // Test that it doesn't crash: + QPainter painter(&i); + // With the composition mode is SourceOver out it's an invalid write + // With the composition mode is Source it's an invalid read + painter.drawImage(0, 0, i2); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.drawImage(0, 0, i2); + + // Qt6: Test that it actually works on 64bit architectures. +} + #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) QT_BEGIN_NAMESPACE Q_GUI_EXPORT HBITMAP qt_imageToWinHBITMAP(const QImage &p, int hbitmapFormat = 0); diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index 55139ff99a..28df3a3c38 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -4075,6 +4075,8 @@ void tst_QGraphicsView::update() QTRY_COMPARE(view.lastUpdateRegions.at(0), QRegion(updateRect) & viewportRect); } QTRY_VERIFY(!viewPrivate->fullUpdatePending); +#else + Q_UNUSED(updateRect); #endif } diff --git a/tests/manual/dialogs/main.cpp b/tests/manual/dialogs/main.cpp index 2676ceeb52..07df8f5cf4 100644 --- a/tests/manual/dialogs/main.cpp +++ b/tests/manual/dialogs/main.cpp @@ -126,6 +126,10 @@ void MainWindow::aboutDialog() int main(int argc, char *argv[]) { +#if QT_VERSION >= 0x050600 + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); +#endif + for (int a = 1; a < argc; ++a) { if (!qstrcmp(argv[a], "-n")) { qDebug("AA_DontUseNativeDialogs"); diff --git a/util/unicode/main.cpp b/util/unicode/main.cpp index 00c69de008..22a4405ca9 100644 --- a/util/unicode/main.cpp +++ b/util/unicode/main.cpp @@ -798,6 +798,9 @@ static const char *property_string = " signed short mirrorDiff : 16;\n" " ushort lowerCaseSpecial : 1;\n" " signed short lowerCaseDiff : 15;\n" + "#ifdef Q_OS_WASM\n" + " unsigned char : 0; //wasm 64 packing trick\n" + "#endif\n" " ushort upperCaseSpecial : 1;\n" " signed short upperCaseDiff : 15;\n" " ushort titleCaseSpecial : 1;\n" @@ -806,6 +809,9 @@ static const char *property_string = " signed short caseFoldDiff : 15;\n" " ushort unicodeVersion : 8; /* 5 used */\n" " ushort nfQuickCheck : 8;\n" // could be narrowed + "#ifdef Q_OS_WASM\n" + " unsigned char : 0; //wasm 64 packing trick\n" + "#endif\n" " ushort graphemeBreakClass : 5; /* 5 used */\n" " ushort wordBreakClass : 5; /* 5 used */\n" " ushort sentenceBreakClass : 8; /* 4 used */\n" @@ -2470,10 +2476,6 @@ static QByteArray createPropertyInfo() out += ", "; out += QByteArray::number( p.lowerCaseDiff ); out += ", "; - out += "#ifdef Q_OS_WASM \n"; -// " unsigned char : 0; //wasm 64 packing trick QTBUG-65259\n" - out += "#endif \n"; - out += ", "; // " ushort upperCaseSpecial : 1;\n" // " signed short upperCaseDiff : 15;\n" out += QByteArray::number( p.upperCaseSpecial ); @@ -2498,10 +2500,6 @@ static QByteArray createPropertyInfo() // " ushort nfQuickCheck : 8;\n" out += QByteArray::number( p.nfQuickCheck ); out += ", "; - out += "#ifdef Q_OS_WASM \n"; -// " unsigned char : 0; //wasm 64 packing trick QTBUG-65259\n" - out += "#endif \n"; - out += ", "; // " ushort graphemeBreakClass : 5; /* 5 used */\n" // " ushort wordBreakClass : 5; /* 5 used */\n" // " ushort sentenceBreakClass : 8; /* 4 used */\n" |