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
This commit is contained in:
Qt Forward Merge Bot 2019-03-20 01:00:08 +01:00 committed by Tor Arne Vestbø
commit 6893919b0c
81 changed files with 1334 additions and 372 deletions

105
dist/changes-5.12.2 vendored Normal file
View File

@ -0,0 +1,105 @@
Qt 5.12.2 is a bug-fix release. It maintains both forward and backward
compatibility (source and binary) with Qt 5.12.0 through 5.12.1.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
https://doc.qt.io/qt-5/index.html
The Qt version 5.12 series is binary compatible with the 5.11.x series.
Applications compiled for 5.11 will continue to run with 5.12.
Some of the changes listed in this file include issue tracking numbers
corresponding to tasks in the Qt Bug Tracker:
https://bugreports.qt.io/
Each of these identifiers can be entered in the bug tracker to obtain more
information about a particular change.
****************************************************************************
* Important Behavior Changes *
****************************************************************************
- QtTestLib:
* [QTBUG-72928] Blacklisting of tests will be taken into account for
XPASS and XFAIL. A blacklisted test that causes an XPASS will no
longer be a fail.
****************************************************************************
* QtCore *
****************************************************************************
- [QTBUG-72885] Fixed a number of warnings with Clang or Clang-Tidy in
Qt headers related to alignment of Qt private classes.
- QDate, QTime and QDateTime;
* [QTBUG-51208] Corrected documentation of how non-placeholder
characters are handled in format patterns passed to toString().
- QCoreApplication:
* [QTBUG-57171] Fixed an out-of-bounds access if the translatable
string passed to tr() ended in '%'.
- QFileInfo:
* [QTBUG-72644] Fixed a bug that would cause QFileInfo to report an
link incorrectly as a non-link.
- QLocale:
* Fixed a crash if qDebug() is used after main() has exited.
* [QTBUG-73403] Fixed a race condition in getting the system locale
(possible regression from Qt 5.11.x)
- QSysInfo:
* Fixed a bug on BSD systems in getting the machineUniqueId().
* Fixed a bug on Windows in 32-bit applications getting the
machineUniqueId() when the OS is 64-bit.
- QWaitCondition:
* Fixed handling of wait(QDeadlineTimer::Forever) on 32-bit platforms.
****************************************************************************
* QtWidgets *
****************************************************************************
- ItemViews:
* Fixed a regression with wrongly drawn centered/right aligned item
texts
****************************************************************************
* Third-Party Code *
****************************************************************************
- libpng was updated to version 1.6.36
****************************************************************************
* Freetype *
****************************************************************************
- Upgraded bundled Freetype version to 2.9.1. This also adds support for
the latest emoji font in use on Android 9.
****************************************************************************
* Android *
****************************************************************************
- Added the --no-strip command line option to androiddeployqt.
- qmake:
* Can now set the version name and code for Android using
ANDROID_VERSION_NAME and ANDROID_VERSION_CODE respectively in the pro
file.
****************************************************************************
* Windows *
****************************************************************************
- Fixed an issue where loading fonts from files or data would sometimes
mistakenly classify them as oblique.
****************************************************************************
* qmake *
****************************************************************************
- [QTBUG-27079] A new feature "cmdline" was added that implies "CONFIG +=
console" and "CONFIG -= app_bundle".

View File

@ -59,6 +59,8 @@ int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(systray);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication app(argc, argv);
if (!QSystemTrayIcon::isSystemTrayAvailable()) {

View File

@ -59,6 +59,8 @@ int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(classwizard);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication app(argc, argv);
#ifndef QT_NO_TRANSLATION

View File

@ -59,6 +59,8 @@ int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(licensewizard);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication app(argc, argv);
#ifndef QT_NO_TRANSLATION

View File

@ -59,6 +59,7 @@
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication app(argc, argv);
QGuiApplication::setApplicationDisplayName(Dialog::tr("Standard Dialogs"));

View File

@ -123,6 +123,8 @@ QWizardPage *createConclusionPage()
int main(int argc, char *argv[])
//! [9] //! [11]
{
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication app(argc, argv);
#ifndef QT_NO_TRANSLATION

View File

@ -28,6 +28,7 @@ for(resource, RESOURCES) {
!exists($$absolute_path($$resource, $$_PRO_FILE_PWD_)): \
warning("Failure to find: $$resource")
qmake_immediate.files += $$resource
OTHER_FILES *= $$resource
}
RESOURCES -= $$resource
next()
@ -57,6 +58,7 @@ for(resource, RESOURCES) {
alias = $$relative_path($$file, $$abs_base)
resource_file_content += \
"<file alias=\"$$xml_escape($$alias)\">$$xml_escape($$file)</file>"
OTHER_FILES *= $$file
}
}
@ -73,9 +75,11 @@ for(resource, RESOURCES) {
}
!isEmpty(RESOURCES):contains(TEMPLATE, .*lib):plugin:static {
resource_init_function = $$lower($$basename(TARGET))_plugin_resource_init
pluginBaseName = $$basename(TARGET)
pluginName = $$lower($$replace(pluginBaseName, [-], _))
resource_init_function = $${pluginName}_plugin_resource_init
DEFINES += "QT_PLUGIN_RESOURCE_INIT_FUNCTION=$$resource_init_function"
RESOURCE_INIT_CPP = $$OUT_PWD/$$lower($$basename(TARGET))_plugin_resources.cpp
RESOURCE_INIT_CPP = $$OUT_PWD/$${pluginName}_plugin_resources.cpp
GENERATED_SOURCES += $$RESOURCE_INIT_CPP
QMAKE_DISTCLEAN += $$RESOURCE_INIT_CPP

View File

@ -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();

View File

@ -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));
}
}

View File

@ -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)

View File

@ -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);

View File

@ -0,0 +1,93 @@
From 2d8118620d4871f74a3ddca233529ff540384477 Mon Sep 17 00:00:00 2001
From: Yuhang Zhao <2546789017@qq.com>
Date: Wed, 13 Feb 2019 23:26:55 +0800
Subject: [PATCH] Fix compilation with icc, converting between egl's and gl's
Error types
Each has two constructors from the other, one copying the other
moving; and this leads to an ambiguous overload when converting
Texture::onDestroy()'s gl::error to the egl::Error that
gl::Context::onDestroy() returns. Passing the value through a
temporary prevents the move-constructor from being attempted and saves
the day. Thanks to Ville Voutilainen for suggesting the fix.
Fixes: QTBUG-73698
Change-Id: I628173399a73cee2e253201bc3e8d3e6477a2fbf
---
src/3rdparty/angle/src/libANGLE/Context.cpp | 3 ++-
src/3rdparty/angle/src/libANGLE/Stream.cpp | 8 +++++---
src/3rdparty/angle/src/libANGLE/Texture.cpp | 3 ++-
.../angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp | 3 ++-
4 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp
index f638beda58..84f7936feb 100644
--- a/src/3rdparty/angle/src/libANGLE/Context.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Context.cpp
@@ -451,7 +451,8 @@ egl::Error Context::onDestroy(const egl::Display *display)
for (auto &zeroTexture : mZeroTextures)
{
- ANGLE_TRY(zeroTexture.second->onDestroy(this));
+ auto result = zeroTexture.second->onDestroy(this);
+ ANGLE_TRY(egl::Error(result));
zeroTexture.second.set(this, nullptr);
}
mZeroTextures.clear();
diff --git a/src/3rdparty/angle/src/libANGLE/Stream.cpp b/src/3rdparty/angle/src/libANGLE/Stream.cpp
index 68279976b7..e384c7d486 100644
--- a/src/3rdparty/angle/src/libANGLE/Stream.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Stream.cpp
@@ -192,8 +192,9 @@ Error Stream::consumerAcquire(const gl::Context *context)
{
if (mPlanes[i].texture != nullptr)
{
- ANGLE_TRY(mPlanes[i].texture->acquireImageFromStream(
- context, mProducerImplementation->getGLFrameDescription(i)));
+ auto result = mPlanes[i].texture->acquireImageFromStream(
+ context, mProducerImplementation->getGLFrameDescription(i));
+ ANGLE_TRY(Error(result));
}
}
@@ -213,7 +214,8 @@ Error Stream::consumerRelease(const gl::Context *context)
{
if (mPlanes[i].texture != nullptr)
{
- ANGLE_TRY(mPlanes[i].texture->releaseImageFromStream(context));
+ auto result = mPlanes[i].texture->releaseImageFromStream(context);
+ ANGLE_TRY(Error(result));
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/Texture.cpp b/src/3rdparty/angle/src/libANGLE/Texture.cpp
index da92e65916..7447604fe6 100644
--- a/src/3rdparty/angle/src/libANGLE/Texture.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Texture.cpp
@@ -550,7 +550,8 @@ Error Texture::onDestroy(const Context *context)
{
if (mBoundSurface)
{
- ANGLE_TRY(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
+ auto result = mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER);
+ ANGLE_TRY(Error(result));
mBoundSurface = nullptr;
}
if (mBoundStream)
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index 75c6298868..b583273641 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -376,7 +376,8 @@ egl::Error Renderer9::initializeDevice()
ASSERT(!mBlit);
mBlit = new Blit9(this);
- ANGLE_TRY(mBlit->initialize());
+ auto result = mBlit->initialize();
+ ANGLE_TRY(egl::Error(result));
ASSERT(!mVertexDataManager && !mIndexDataManager);
mVertexDataManager = new VertexDataManager(this);
--
2.20.1.windows.1

View File

@ -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()) {

View File

@ -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);

View File

@ -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
/*!

View File

@ -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;

View File

@ -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 };
}

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -169,6 +169,7 @@ private:
friend class QPlatformIntegration;
friend class QPlatformScreen;
friend class QHighDpiScaling;
friend class QWindowSystemInterface;
};
#ifndef QT_NO_DEBUG_STREAM

View File

@ -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:

View File

@ -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 =

View File

@ -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);

View File

@ -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);

View File

@ -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"
},
{

View File

@ -173,7 +173,7 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
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));

View File

@ -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 &paramList)
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");

View File

@ -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 \

View File

@ -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 &region) override;
QPaintDevice *paintDevice() override;
void endPaint() override;
void flush(QWindow *, const QRegion &, const QPoint &) override;
void composeAndFlush(QWindow *window, const QRegion &region, 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

View File

@ -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 &region, const QPoint &offset)
void QNSWindowBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
if (m_image.isNull())
return;
@ -103,131 +107,113 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion &region, const QPo
qCDebug(lcQpaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription);
}
// 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();
// 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"];
#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");
// 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];
// Create temporary image to use for blitting, without copying image data
NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease];
// 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();
// 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"];
#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");
// 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()));
CGRect viewRect = viewLocalRect.toCGRect();
if (windowHasUnifiedToolbar())
NSDrawWindowBackground(viewRect);
[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()];
}
}
#endif
}
// -------------------------------------------------------------------------
if (shouldHandleViewLockManually)
[view unlockFocus];
if (drawingOutsideOfDisplayCycle) {
redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]);
[view.window flushWindow];
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))));
}
}
// Done flushing to either CALayer or NSWindow backingstore
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();
if (windowHasUnifiedToolbar())
NSDrawWindowBackground(viewRect);
[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()];
}
}
#endif
}
// -------------------------------------------------------------------------
if (shouldHandleViewLockManually)
[view unlockFocus];
if (drawingOutsideOfDisplayCycle) {
redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]);
[view.window flushWindow];
}
// 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 &region, 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 &region)
{
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 &region, 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 &region, 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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();

View File

@ -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();

View File

@ -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 {

View File

@ -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()

View File

@ -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

View File

@ -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 &parameters)
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;

View File

@ -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 &paramList)
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");

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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 &paramList)
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");

View File

@ -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 &parameters)
mPrimaryScreen->mDepth = 32;
mPrimaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied;
screenAdded(mPrimaryScreen);
QWindowSystemInterface::handleScreenAdded(mPrimaryScreen);
}
QMinimalIntegration::~QMinimalIntegration()

View File

@ -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;
}

View File

@ -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
}

View File

@ -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()

View File

@ -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);
}

View File

@ -68,8 +68,6 @@ public:
QPlatformPrinterSupport *printerSupport() const;
void addScreen(QOpenWFDScreen *screen);
void destroyScreen(QOpenWFDScreen *screen);
private:
QList<QPlatformScreen *> mScreens;
QList<QOpenWFDDevice *>mDevices;

View File

@ -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;

View File

@ -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();
}

View File

@ -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 &paramList)
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");

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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),

View File

@ -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();

View File

@ -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:

View File

@ -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();

View File

@ -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;

View File

@ -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)

View File

@ -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");

View File

@ -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)) {

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,5 @@
[remainingTime]
windows
osx
[basic_chrono]
osx

View File

@ -230,6 +230,8 @@ private slots:
void convertColorTable();
void wideImage();
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
void toWinHBITMAP_data();
void toWinHBITMAP();
@ -3559,6 +3561,24 @@ void tst_QImage::convertColorTable()
QCOMPARE(rgb32.pixel(0,0), 0xffffffff);
}
void tst_QImage::wideImage()
{
// QTBUG-73731 and QTBUG-73732
QImage i(538994187, 2, QImage::Format_ARGB32);
QImage i2(32, 32, QImage::Format_ARGB32);
i2.fill(Qt::white);
// Test that it doesn't crash:
QPainter painter(&i);
// With the composition mode is SourceOver out it's an invalid write
// With the composition mode is Source it's an invalid read
painter.drawImage(0, 0, i2);
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.drawImage(0, 0, i2);
// Qt6: Test that it actually works on 64bit architectures.
}
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
QT_BEGIN_NAMESPACE
Q_GUI_EXPORT HBITMAP qt_imageToWinHBITMAP(const QImage &p, int hbitmapFormat = 0);

View File

@ -4075,6 +4075,8 @@ void tst_QGraphicsView::update()
QTRY_COMPARE(view.lastUpdateRegions.at(0), QRegion(updateRect) & viewportRect);
}
QTRY_VERIFY(!viewPrivate->fullUpdatePending);
#else
Q_UNUSED(updateRect);
#endif
}

View File

@ -126,6 +126,10 @@ void MainWindow::aboutDialog()
int main(int argc, char *argv[])
{
#if QT_VERSION >= 0x050600
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
for (int a = 1; a < argc; ++a) {
if (!qstrcmp(argv[a], "-n")) {
qDebug("AA_DontUseNativeDialogs");

View File

@ -798,6 +798,9 @@ static const char *property_string =
" signed short mirrorDiff : 16;\n"
" ushort lowerCaseSpecial : 1;\n"
" signed short lowerCaseDiff : 15;\n"
"#ifdef Q_OS_WASM\n"
" unsigned char : 0; //wasm 64 packing trick\n"
"#endif\n"
" ushort upperCaseSpecial : 1;\n"
" signed short upperCaseDiff : 15;\n"
" ushort titleCaseSpecial : 1;\n"
@ -806,6 +809,9 @@ static const char *property_string =
" signed short caseFoldDiff : 15;\n"
" ushort unicodeVersion : 8; /* 5 used */\n"
" ushort nfQuickCheck : 8;\n" // could be narrowed
"#ifdef Q_OS_WASM\n"
" unsigned char : 0; //wasm 64 packing trick\n"
"#endif\n"
" ushort graphemeBreakClass : 5; /* 5 used */\n"
" ushort wordBreakClass : 5; /* 5 used */\n"
" ushort sentenceBreakClass : 8; /* 4 used */\n"
@ -2470,10 +2476,6 @@ static QByteArray createPropertyInfo()
out += ", ";
out += QByteArray::number( p.lowerCaseDiff );
out += ", ";
out += "#ifdef Q_OS_WASM \n";
// " unsigned char : 0; //wasm 64 packing trick QTBUG-65259\n"
out += "#endif \n";
out += ", ";
// " ushort upperCaseSpecial : 1;\n"
// " signed short upperCaseDiff : 15;\n"
out += QByteArray::number( p.upperCaseSpecial );
@ -2498,10 +2500,6 @@ static QByteArray createPropertyInfo()
// " ushort nfQuickCheck : 8;\n"
out += QByteArray::number( p.nfQuickCheck );
out += ", ";
out += "#ifdef Q_OS_WASM \n";
// " unsigned char : 0; //wasm 64 packing trick QTBUG-65259\n"
out += "#endif \n";
out += ", ";
// " ushort graphemeBreakClass : 5; /* 5 used */\n"
// " ushort wordBreakClass : 5; /* 5 used */\n"
// " ushort sentenceBreakClass : 8; /* 4 used */\n"