diff options
| author | Qt Forward Merge Bot <[email protected]> | 2019-03-20 01:00:08 +0100 | 
|---|---|---|
| committer | Tor Arne Vestbø <[email protected]> | 2019-03-20 14:09:30 +0100 | 
| commit | 6893919b0c4cddfbd82ebf963cc7bebde816b1b3 (patch) | |
| tree | 9bfa1b57707fe609f9401c5b3bd5cd85ec1ae777 /src | |
| parent | 3ca05b2a2e80863202bdb6a225f72debbb28b8fe (diff) | |
| parent | 2bafd997ee515d3b6a6a8fb030e1265a4713713e (diff) | |
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
Diffstat (limited to 'src')
69 files changed, 1164 insertions, 349 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp index f638beda588..84f7936febc 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 68279976b75..e384c7d4868 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 da92e659161..7447604fe66 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 75c62988680..b5832736415 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 00000000000..6d3b1cac086 --- /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 <[email protected]> +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 35bb465a04d..ced08a9a87d 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 dc39490ab02..a2111a084f0 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 18e94cf2562..0463ef6a428 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 45f571807c3..8335e117f28 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 de12a313e83..d88ad2d1d2a 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 65c24bebc95..9004116ea4a 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 199ef0de070..6ae6e4a5282 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 de5f9c1c9a8..6950bbaf72d 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 b7b312e89e8..21ae75ba8fe 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 8c9b16e08e8..14392d30369 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 1cc2435239a..590e2a85bb0 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 7067ece1d8e..ec6911b3349 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 1dde9130ac3..bf98c33a1a1 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 323253c70d1..2e1a2b5bff6 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 e6c87b550b3..07d46b790e8 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 763b2946605..e0c437be278 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 6a7d445e692..e4c90d26afc 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 8d65cf328f7..083b7c16552 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 b4cd506513a..508f24d5780 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 81a0a7d0400..8e4e928bc5f 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 affbee35b7f..fb3d05d3e46 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 00000000000..872773cb7a3 --- /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 00000000000..a367487e85f --- /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 6db5ed8bad6..f7e14b7883f 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 dad553c8907..d3c95f0b658 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 cdf340da7ae..73e308da539 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 0a3a37863ac..81bad45cd2f 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 8ccb0ef2cd0..48469b0f8c8 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 4b4585d33c4..898b3228348 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 5e2708e9585..cb7844aff05 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 ab39af6b802..ecdfb352ab2 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 b073577797a..4f0b0d7725e 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 8bd2171794f..44df6ae8f5a 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 ae802bb1fa7..3ad31dc5629 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 818250fceeb..eeb44b54d3b 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 bec8354fcc9..9eca0eaad34 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 4f753be21a1..9aba658479a 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 9e38900bcd0..68843aa4c5b 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 0c04608fcaf..f457f69f111 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 da58441d67a..a0d35a80cdf 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 eef96ee3def..d2b1dbee0d7 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 f2933b71791..869e9228cd2 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 4850ca2e459..c5dc40a2067 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 1ce1001bed4..444aaccaaf3 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 33254fe83c3..34b4439958c 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 a996e765c43..a45dcabeb78 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 1e2cf6292cb..c7a796464af 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 1964cefdad4..499a82adbd4 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 da868527669..e28b2c2fb38 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 a161dc46e99..0520f889353 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 8bf090bf034..07fd2916c2c 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 78cbc3aec30..27d37469331 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 d42a33c22bc..476de6d1e5d 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 1ff06dd39e6..06d1000993b 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 36917633985..b979129cba8 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 4bafe831564..9ba71ada373 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 f13e232291b..571726c354e 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 4d526a6bda2..899081e7529 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 fd7f72eebf1..3af5237f3d8 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 57d6994c883..cd27c9c5be7 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 65c46a5e569..75d091ce4ea 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 ac4fb7fbd13..97ec1d3f191 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 4af4f90119e..bf6bf1c7c9a 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 98bb23caad8..de838a8f93f 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  | 
