summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2019-03-26 08:24:59 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2019-03-26 08:24:59 +0100
commit7f635d9777baf4af85a2575de123a75ec58bda78 (patch)
tree90ef3a223f8b0b1601f8e72a3adce6f4513fe2dd /src/plugins
parentd0f016ebfb86fcebcf72c37c489260a0d02147e7 (diff)
parent945198fd237a83348feb4537d811565a2c2cd8e0 (diff)
Merge remote-tracking branch 'origin/5.13' into dev
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforminputcontexts/ibus/ibus.pro2
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp14
-rw-r--r--src/plugins/platforminputcontexts/platforminputcontexts.pro11
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp2
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbintegration.cpp5
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro4
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h52
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm543
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm17
-rw-r--r--src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h77
-rw-r--r--src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm188
-rw-r--r--src/plugins/platforms/cocoa/qnsview_drawing.mm7
-rw-r--r--src/plugins/platforms/directfb/qdirectfb_egl.cpp3
-rw-r--r--src/plugins/platforms/directfb/qdirectfbintegration.cpp3
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp4
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration.cpp12
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration_p.h3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp2
-rw-r--r--src/plugins/platforms/haiku/qhaikuintegration.cpp5
-rw-r--r--src/plugins/platforms/integrity/qintegrityfbintegration.cpp6
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h4
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm4
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm10
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp5
-rw-r--r--src/plugins/platforms/minimal/qminimalintegration.cpp3
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglintegration.cpp5
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.cpp3
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdintegration.cpp11
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdintegration.h2
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdport.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp6
-rw-r--r--src/plugins/platforms/vnc/qvncintegration.cpp5
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp9
-rw-r--r--src/plugins/platforms/wasm/wasm_shell.html6
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp10
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp4
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp18
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp4
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp10
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp14
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_basic.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_screens.cpp12
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp7
50 files changed, 918 insertions, 230 deletions
diff --git a/src/plugins/platforminputcontexts/ibus/ibus.pro b/src/plugins/platforminputcontexts/ibus/ibus.pro
index 52836bb8b6..9ba2297e38 100644
--- a/src/plugins/platforminputcontexts/ibus/ibus.pro
+++ b/src/plugins/platforminputcontexts/ibus/ibus.pro
@@ -1,6 +1,6 @@
TARGET = ibusplatforminputcontextplugin
-QT += dbus gui-private
+QT += dbus gui-private xkbcommon_support-private
SOURCES += $$PWD/qibusplatforminputcontext.cpp \
$$PWD/qibusproxy.cpp \
$$PWD/qibusproxyportal.cpp \
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
index 7e66439ea7..f2429f24ff 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
@@ -51,6 +51,8 @@
#include <QtGui/private/qguiapplication_p.h>
+#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
+
#include "qibusproxy.h"
#include "qibusproxyportal.h"
#include "qibusinputcontextproxy.h"
@@ -335,14 +337,12 @@ void QIBusPlatformInputContext::forwardKeyEvent(uint keyval, uint keycode, uint
if (!input)
return;
- if (debug)
- qDebug() << "forwardKeyEvent" << keyval << keycode << state;
-
QEvent::Type type = QEvent::KeyPress;
if (state & IBUS_RELEASE_MASK)
type = QEvent::KeyRelease;
state &= ~IBUS_RELEASE_MASK;
+ keycode += 8;
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
if (state & IBUS_SHIFT_MASK)
@@ -354,7 +354,13 @@ void QIBusPlatformInputContext::forwardKeyEvent(uint keyval, uint keycode, uint
if (state & IBUS_META_MASK)
modifiers |= Qt::MetaModifier;
- QKeyEvent event(type, keyval, modifiers, QString(keyval));
+ int qtcode = QXkbCommon::keysymToQtKey(keyval, modifiers);
+ QString text = QXkbCommon::lookupStringNoKeysymTransformations(keyval);
+
+ if (debug)
+ qDebug() << "forwardKeyEvent" << keyval << keycode << state << modifiers << qtcode << text;
+
+ QKeyEvent event(type, qtcode, modifiers, keycode, keyval, state, text);
QCoreApplication::sendEvent(input, &event);
}
diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro
index 68f6792377..56a39a49e7 100644
--- a/src/plugins/platforminputcontexts/platforminputcontexts.pro
+++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro
@@ -1,10 +1,11 @@
TEMPLATE = subdirs
QT_FOR_CONFIG += gui-private
-qtHaveModule(dbus) {
-!mac:!win32:SUBDIRS += ibus
-}
-
-qtConfig(xkbcommon): SUBDIRS += compose
+qtConfig(xkbcommon) {
+ SUBDIRS += compose
+ qtHaveModule(dbus) {
+ !macos:!win32:SUBDIRS += ibus
+ }
+}
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 763b294660..e0c437be27 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -173,7 +173,7 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &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));
diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
index 6a7d445e69..e4c90d26af 100644
--- a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
+++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
@@ -53,6 +53,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatforminputcontext.h>
#include <qpa/qplatforminputcontextfactory_p.h>
+#include <qpa/qwindowsysteminterface.h>
#if QT_CONFIG(tslib)
#include <QtInputSupport/private/qtslib_p.h>
@@ -69,13 +70,13 @@ QBsdFbIntegration::QBsdFbIntegration(const QStringList &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");
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index 8d65cf328f..083b7c1655 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -33,6 +33,7 @@ SOURCES += main.mm \
qcocoaintrospection.mm \
qcocoakeymapper.mm \
qcocoamimetypes.mm \
+ qiosurfacegraphicsbuffer.mm \
messages.cpp
HEADERS += qcocoaintegration.h \
@@ -67,6 +68,7 @@ HEADERS += qcocoaintegration.h \
qcocoaintrospection.h \
qcocoakeymapper.h \
messages.h \
+ qiosurfacegraphicsbuffer.h \
qcocoamimetypes.h
qtConfig(opengl.*) {
@@ -81,7 +83,7 @@ qtConfig(vulkan) {
RESOURCES += qcocoaresources.qrc
-LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework CoreVideo -framework Metal -lcups
+LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework CoreVideo -framework Metal -framework IOSurface -lcups
QT += \
core-private gui-private \
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index b4cd506513..508f24d578 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -44,13 +44,16 @@
#include <private/qcore_mac_p.h>
+#include <QScopedPointer>
+#include "qiosurfacegraphicsbuffer.h"
+
QT_BEGIN_NAMESPACE
-class QCocoaBackingStore : public QRasterBackingStore
+class QNSWindowBackingStore : public QRasterBackingStore
{
public:
- QCocoaBackingStore(QWindow *window);
- ~QCocoaBackingStore();
+ QNSWindowBackingStore(QWindow *window);
+ ~QNSWindowBackingStore();
void flush(QWindow *, const QRegion &, const QPoint &) override;
@@ -60,6 +63,49 @@ private:
void redrawRoundedBottomCorners(CGRect) const;
};
+class QCALayerBackingStore : public QPlatformBackingStore
+{
+public:
+ QCALayerBackingStore(QWindow *window);
+ ~QCALayerBackingStore();
+
+ void resize(const QSize &size, const QRegion &staticContents) override;
+
+ void beginPaint(const QRegion &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
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 81a0a7d040..8e4e928bc5 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -42,24 +42,28 @@
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
+#include <QtCore/qmath.h>
+
+#include <QuartzCore/CATransaction.h>
+
QT_BEGIN_NAMESPACE
-QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
+QNSWindowBackingStore::QNSWindowBackingStore(QWindow *window)
: QRasterBackingStore(window)
{
}
-QCocoaBackingStore::~QCocoaBackingStore()
+QNSWindowBackingStore::~QNSWindowBackingStore()
{
}
-bool QCocoaBackingStore::windowHasUnifiedToolbar() const
+bool QNSWindowBackingStore::windowHasUnifiedToolbar() const
{
Q_ASSERT(window()->handle());
return static_cast<QCocoaWindow *>(window()->handle())->m_drawContentBorderGradient;
}
-QImage::Format QCocoaBackingStore::format() const
+QImage::Format QNSWindowBackingStore::format() const
{
if (windowHasUnifiedToolbar())
return QImage::Format_ARGB32_Premultiplied;
@@ -78,7 +82,7 @@ QImage::Format QCocoaBackingStore::format() const
coordinates, and the \a offset will be the child window's offset in relation
to the backingstore's top level window.
*/
-void QCocoaBackingStore::flush(QWindow *window, const QRegion &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);
}
- // Prevent potentially costly color conversion by assigning the display color space
- // to the backingstore image. This does not copy the underlying image data.
- CGColorSpaceRef displayColorSpace = view.window.screen.colorSpace.CGColorSpace;
- QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace(
- QCFType<CGImageRef>(m_image.toCGImage()), displayColorSpace);
-
- if (view.layer) {
- // In layer-backed mode, locking focus on a view does not give the right
- // view transformation, and doesn't give us a graphics context to render
- // via when drawing outside of the display cycle. Instead we tell AppKit
- // that we want to update the layer's content, via [NSView wantsUpdateLayer],
- // which result in AppKit not creating a backingstore for each layer, and
- // we then directly set the layer's backingstore (content) to our backingstore,
- // masked to the part of the subview that is relevant.
- // FIXME: Figure out if there's a way to do partial updates
- view.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage);
- if (view != topLevelView) {
- const CGSize topLevelSize = topLevelView.bounds.size;
- view.layer.contentsRect = CGRectApplyAffineTransform(
- [view convertRect:view.bounds toView:topLevelView],
- // The contentsRect is in unit coordinate system
- CGAffineTransformMakeScale(1.0 / topLevelSize.width, 1.0 / topLevelSize.height));
- }
- } else {
- // Normally a NSView is drawn via drawRect, as part of the display cycle in the
- // main runloop, via setNeedsDisplay and friends. AppKit will lock focus on each
- // individual view, starting with the top level and then traversing any subviews,
- // calling drawRect for each of them. This pull model results in expose events
- // sent to Qt, which result in drawing to the backingstore and flushing it.
- // Qt may also decide to paint and flush the backingstore via e.g. timers,
- // or other events such as mouse events, in which case we're in a push model.
- // If there is no focused view, it means we're in the latter case, and need
- // to manually flush the NSWindow after drawing to its graphic context.
- const bool drawingOutsideOfDisplayCycle = ![NSView focusView];
-
- // We also need to ensure the flushed view has focus, so that the graphics
- // context is set up correctly (coordinate system, clipping, etc). Outside
- // of the normal display cycle there is no focused view, as explained above,
- // so we have to handle it manually. There's also a corner case inside the
- // normal display cycle due to way QWidgetBackingStore composits native child
- // widgets, where we'll get a flush of a native child during the drawRect of
- // its parent/ancestor, and the parent/ancestor being the one locked by AppKit.
- // In this case we also need to lock and unlock focus manually.
- const bool shouldHandleViewLockManually = [NSView focusView] != view;
- if (shouldHandleViewLockManually && ![view lockFocusIfCanDraw]) {
- qWarning() << "failed to lock focus of" << view;
- return;
- }
+ // Normally a NSView is drawn via drawRect, as part of the display cycle in the
+ // main runloop, via setNeedsDisplay and friends. AppKit will lock focus on each
+ // individual view, starting with the top level and then traversing any subviews,
+ // calling drawRect for each of them. This pull model results in expose events
+ // sent to Qt, which result in drawing to the backingstore and flushing it.
+ // Qt may also decide to paint and flush the backingstore via e.g. timers,
+ // or other events such as mouse events, in which case we're in a push model.
+ // If there is no focused view, it means we're in the latter case, and need
+ // to manually flush the NSWindow after drawing to its graphic context.
+ const bool drawingOutsideOfDisplayCycle = ![NSView focusView];
+
+ // We also need to ensure the flushed view has focus, so that the graphics
+ // context is set up correctly (coordinate system, clipping, etc). Outside
+ // of the normal display cycle there is no focused view, as explained above,
+ // so we have to handle it manually. There's also a corner case inside the
+ // normal display cycle due to way QWidgetBackingStore composits native child
+ // widgets, where we'll get a flush of a native child during the drawRect of
+ // its parent/ancestor, and the parent/ancestor being the one locked by AppKit.
+ // In this case we also need to lock and unlock focus manually.
+ const bool shouldHandleViewLockManually = [NSView focusView] != view;
+ if (shouldHandleViewLockManually && ![view lockFocusIfCanDraw]) {
+ qWarning() << "failed to lock focus of" << view;
+ return;
+ }
- const qreal devicePixelRatio = m_image.devicePixelRatio();
+ const qreal devicePixelRatio = m_image.devicePixelRatio();
- // If the flushed window is a content view, and we're filling the drawn area
- // completely, or it doesn't have a window background we need to preserve,
- // we can get away with copying instead of blending the backing store.
- QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
- const NSCompositingOperation compositingOperation = cocoaWindow->isContentView()
- && (cocoaWindow->isOpaque() || view.window.backgroundColor == NSColor.clearColor)
- ? NSCompositingOperationCopy : NSCompositingOperationSourceOver;
+ // If the flushed window is a content view, and we're filling the drawn area
+ // completely, or it doesn't have a window background we need to preserve,
+ // we can get away with copying instead of blending the backing store.
+ QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
+ const NSCompositingOperation compositingOperation = cocoaWindow->isContentView()
+ && (cocoaWindow->isOpaque() || view.window.backgroundColor == NSColor.clearColor)
+ ? NSCompositingOperationCopy : NSCompositingOperationSourceOver;
#ifdef QT_DEBUG
- static bool debugBackingStoreFlush = [[NSUserDefaults standardUserDefaults]
- boolForKey:@"QtCocoaDebugBackingStoreFlush"];
+ static bool debugBackingStoreFlush = [[NSUserDefaults standardUserDefaults]
+ boolForKey:@"QtCocoaDebugBackingStoreFlush"];
#endif
- // -------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
- // The current contexts is typically a NSWindowGraphicsContext, but can be
- // NSBitmapGraphicsContext e.g. when debugging the view hierarchy in Xcode.
- // If we need to distinguish things here in the future, we can use e.g.
- // [NSGraphicsContext drawingToScreen], or the attributes of the context.
- NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
- Q_ASSERT_X(graphicsContext, "QCocoaBackingStore",
- "Focusing the view should give us a current graphics context");
+ // The current contexts is typically a NSWindowGraphicsContext, but can be
+ // NSBitmapGraphicsContext e.g. when debugging the view hierarchy in Xcode.
+ // If we need to distinguish things here in the future, we can use e.g.
+ // [NSGraphicsContext drawingToScreen], or the attributes of the context.
+ NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
+ Q_ASSERT_X(graphicsContext, "QCocoaBackingStore",
+ "Focusing the view should give us a current graphics context");
- // Create temporary image to use for blitting, without copying image data
- NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease];
+ // Prevent potentially costly color conversion by assigning the display color space
+ // to the backingstore image. This does not copy the underlying image data.
+ CGColorSpaceRef displayColorSpace = view.window.screen.colorSpace.CGColorSpace;
+ QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace(
+ QCFType<CGImageRef>(m_image.toCGImage()), displayColorSpace);
- QRegion clippedRegion = region;
- for (QWindow *w = window; w; w = w->parent()) {
- if (!w->mask().isEmpty()) {
- clippedRegion &= w == window ? w->mask()
- : w->mask().translated(window->mapFromGlobal(w->mapToGlobal(QPoint(0, 0))));
- }
+ // Create temporary image to use for blitting, without copying image data
+ NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease];
+
+ QRegion clippedRegion = region;
+ for (QWindow *w = window; w; w = w->parent()) {
+ if (!w->mask().isEmpty()) {
+ clippedRegion &= w == window ? w->mask()
+ : w->mask().translated(window->mapFromGlobal(w->mapToGlobal(QPoint(0, 0))));
}
+ }
- for (const QRect &viewLocalRect : clippedRegion) {
- QPoint backingStoreOffset = viewLocalRect.topLeft() + offset;
- QRect backingStoreRect(backingStoreOffset * devicePixelRatio, viewLocalRect.size() * devicePixelRatio);
- if (graphicsContext.flipped) // Flip backingStoreRect to match graphics context
- backingStoreRect.moveTop(m_image.height() - (backingStoreRect.y() + backingStoreRect.height()));
+ for (const QRect &viewLocalRect : clippedRegion) {
+ QPoint backingStoreOffset = viewLocalRect.topLeft() + offset;
+ QRect backingStoreRect(backingStoreOffset * devicePixelRatio, viewLocalRect.size() * devicePixelRatio);
+ if (graphicsContext.flipped) // Flip backingStoreRect to match graphics context
+ backingStoreRect.moveTop(m_image.height() - (backingStoreRect.y() + backingStoreRect.height()));
- CGRect viewRect = viewLocalRect.toCGRect();
+ CGRect viewRect = viewLocalRect.toCGRect();
- if (windowHasUnifiedToolbar())
- NSDrawWindowBackground(viewRect);
+ if (windowHasUnifiedToolbar())
+ NSDrawWindowBackground(viewRect);
- [backingStoreImage drawInRect:viewRect fromRect:backingStoreRect.toCGRect()
- operation:compositingOperation fraction:1.0 respectFlipped:YES hints:nil];
+ [backingStoreImage drawInRect:viewRect fromRect:backingStoreRect.toCGRect()
+ operation:compositingOperation fraction:1.0 respectFlipped:YES hints:nil];
#ifdef QT_DEBUG
- if (Q_UNLIKELY(debugBackingStoreFlush)) {
- [[NSColor colorWithCalibratedRed:drand48() green:drand48() blue:drand48() alpha:0.3] set];
- [NSBezierPath fillRect:viewRect];
-
- if (drawingOutsideOfDisplayCycle) {
- [[[NSColor magentaColor] colorWithAlphaComponent:0.5] set];
- [NSBezierPath strokeLineFromPoint:viewLocalRect.topLeft().toCGPoint()
- toPoint:viewLocalRect.bottomRight().toCGPoint()];
- }
+ if (Q_UNLIKELY(debugBackingStoreFlush)) {
+ [[NSColor colorWithCalibratedRed:drand48() green:drand48() blue:drand48() alpha:0.3] set];
+ [NSBezierPath fillRect:viewRect];
+
+ if (drawingOutsideOfDisplayCycle) {
+ [[[NSColor magentaColor] colorWithAlphaComponent:0.5] set];
+ [NSBezierPath strokeLineFromPoint:viewLocalRect.topLeft().toCGPoint()
+ toPoint:viewLocalRect.bottomRight().toCGPoint()];
}
-#endif
}
+#endif
+ }
- // -------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
- if (shouldHandleViewLockManually)
- [view unlockFocus];
+ if (shouldHandleViewLockManually)
+ [view unlockFocus];
- if (drawingOutsideOfDisplayCycle) {
- redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]);
- [view.window flushWindow];
- }
+ if (drawingOutsideOfDisplayCycle) {
+ redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]);
+ [view.window flushWindow];
}
- // Done flushing to either CALayer or NSWindow backingstore
+
+ // Done flushing to NSWindow backingstore
QCocoaWindow *topLevelCocoaWindow = static_cast<QCocoaWindow *>(topLevelWindow->handle());
if (Q_UNLIKELY(topLevelCocoaWindow->m_needsInvalidateShadow)) {
@@ -251,7 +237,7 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion &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
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index affbee35b7..fb3d05d3e4 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -244,7 +244,7 @@ QCocoaIntegration::~QCocoaIntegration()
// Delete screens in reverse order to avoid crash in case of multiple screens
while (!mScreens.isEmpty()) {
- destroyScreen(mScreens.takeLast());
+ QWindowSystemInterface::handleScreenRemoved(mScreens.takeLast());
}
clearToolbars();
@@ -304,7 +304,7 @@ void QCocoaIntegration::updateScreens()
screen = new QCocoaScreen(i);
mScreens.append(screen);
qCDebug(lcQpaScreen) << "Adding" << screen;
- screenAdded(screen);
+ QWindowSystemInterface::handleScreenAdded(screen);
}
siblings << screen;
}
@@ -321,7 +321,7 @@ void QCocoaIntegration::updateScreens()
// Prevent stale references to NSScreen during destroy
screen->m_screenIndex = -1;
qCDebug(lcQpaScreen) << "Removing" << screen;
- destroyScreen(screen);
+ QWindowSystemInterface::handleScreenRemoved(screen);
}
}
@@ -407,7 +407,16 @@ QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLCo
QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *window) const
{
- return new QCocoaBackingStore(window);
+ QCocoaWindow *platformWindow = static_cast<QCocoaWindow*>(window->handle());
+ if (!platformWindow) {
+ qWarning() << window << "must be created before being used with a backingstore";
+ return nullptr;
+ }
+
+ if (platformWindow->view().layer)
+ return new QCALayerBackingStore(window);
+ else
+ return new QNSWindowBackingStore(window);
}
QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const
diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h
new file mode 100644
index 0000000000..872773cb7a
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSURFACEGRAPHICSBUFFER_H
+#define QIOSURFACEGRAPHICSBUFFER_H
+
+#include <qpa/qplatformgraphicsbuffer.h>
+#include <private/qcore_mac_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSurfaceGraphicsBuffer : public QPlatformGraphicsBuffer
+{
+public:
+ QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace);
+ ~QIOSurfaceGraphicsBuffer();
+
+ const uchar *data() const override;
+ uchar *data() override;
+ int bytesPerLine() const override;
+
+ IOSurfaceRef surface();
+ bool isInUse() const;
+
+protected:
+ bool doLock(AccessTypes access, const QRect &rect) override;
+ void doUnlock() override;
+
+private:
+ QCFType<IOSurfaceRef> m_surface;
+
+ friend QDebug operator<<(QDebug, const QIOSurfaceGraphicsBuffer *);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug, const QIOSurfaceGraphicsBuffer *);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QIOSURFACEGRAPHICSBUFFER_H
diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm
new file mode 100644
index 0000000000..a367487e85
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosurfacegraphicsbuffer.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qloggingcategory.h>
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <IOSurface/IOSurface.h>
+
+// CGColorSpaceCopyPropertyList is available on 10.12 and above,
+// but was only added in the 10.14 SDK, so declare it just in case.
+extern "C" CFPropertyListRef CGColorSpaceCopyPropertyList(CGColorSpaceRef space);
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQpaIOSurface, "qt.qpa.backingstore.iosurface");
+
+QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace)
+ : QPlatformGraphicsBuffer(size, format)
+{
+ const size_t width = size.width();
+ const size_t height = size.height();
+
+ Q_ASSERT(width <= IOSurfaceGetPropertyMaximum(kIOSurfaceWidth));
+ Q_ASSERT(height <= IOSurfaceGetPropertyMaximum(kIOSurfaceHeight));
+
+ static const char bytesPerElement = 4;
+
+ const size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, width * bytesPerElement);
+ const size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, height * bytesPerRow);
+
+ NSDictionary *options = @{
+ (id)kIOSurfaceWidth: @(width),
+ (id)kIOSurfaceHeight: @(height),
+ (id)kIOSurfacePixelFormat: @(unsigned('BGRA')),
+ (id)kIOSurfaceBytesPerElement: @(bytesPerElement),
+ (id)kIOSurfaceBytesPerRow: @(bytesPerRow),
+ (id)kIOSurfaceAllocSize: @(totalBytes),
+ };
+
+ m_surface = IOSurfaceCreate((CFDictionaryRef)options);
+ Q_ASSERT(m_surface);
+
+ Q_ASSERT(size_t(bytesPerLine()) == bytesPerRow);
+ Q_ASSERT(size_t(byteCount()) == totalBytes);
+
+ if (colorSpace) {
+ IOSurfaceSetValue(m_surface, CFSTR("IOSurfaceColorSpace"),
+ QCFType<CFPropertyListRef>(CGColorSpaceCopyPropertyList(colorSpace)));
+ }
+}
+
+QIOSurfaceGraphicsBuffer::~QIOSurfaceGraphicsBuffer()
+{
+}
+
+const uchar *QIOSurfaceGraphicsBuffer::data() const
+{
+ return (const uchar *)IOSurfaceGetBaseAddress(m_surface);
+}
+
+uchar *QIOSurfaceGraphicsBuffer::data()
+{
+ return (uchar *)IOSurfaceGetBaseAddress(m_surface);
+}
+
+int QIOSurfaceGraphicsBuffer::bytesPerLine() const
+{
+ return IOSurfaceGetBytesPerRow(m_surface);
+}
+
+IOSurfaceRef QIOSurfaceGraphicsBuffer::surface()
+{
+ return m_surface;
+}
+
+bool QIOSurfaceGraphicsBuffer::isInUse() const
+{
+ return IOSurfaceIsInUse(m_surface);
+}
+
+IOSurfaceLockOptions lockOptionsForAccess(QPlatformGraphicsBuffer::AccessTypes access)
+{
+ IOSurfaceLockOptions lockOptions = 0;
+ if (!(access & QPlatformGraphicsBuffer::SWWriteAccess))
+ lockOptions |= kIOSurfaceLockReadOnly;
+ return lockOptions;
+}
+
+bool QIOSurfaceGraphicsBuffer::doLock(AccessTypes access, const QRect &rect)
+{
+ Q_UNUSED(rect);
+ Q_ASSERT(!isLocked());
+
+ qCDebug(lcQpaIOSurface) << "Locking" << this << "for" << access;
+
+ // FIXME: Teach QPlatformBackingStore::composeAndFlush about non-2D texture
+ // targets, so that we can use CGLTexImageIOSurface2D to support TextureAccess.
+ if (access & (TextureAccess | HWCompositor))
+ return false;
+
+ auto lockOptions = lockOptionsForAccess(access);
+
+ // Try without read-back first
+ lockOptions |= kIOSurfaceLockAvoidSync;
+ kern_return_t ret = IOSurfaceLock(m_surface, lockOptions, nullptr);
+ if (ret == kIOSurfaceSuccess)
+ return true;
+
+ if (ret == kIOReturnCannotLock) {
+ qCWarning(lcQpaIOSurface) << "Locking of" << this << "requires read-back";
+ lockOptions ^= kIOSurfaceLockAvoidSync;
+ ret = IOSurfaceLock(m_surface, lockOptions, nullptr);
+ }
+
+ if (ret != kIOSurfaceSuccess) {
+ qCWarning(lcQpaIOSurface) << "Failed to lock" << this << ret;
+ return false;
+ }
+
+ return true;
+}
+
+void QIOSurfaceGraphicsBuffer::doUnlock()
+{
+ qCDebug(lcQpaIOSurface) << "Unlocking" << this << "from" << isLocked();
+
+ auto lockOptions = lockOptionsForAccess(isLocked());
+ bool success = IOSurfaceUnlock(m_surface, lockOptions, nullptr) == kIOSurfaceSuccess;
+ Q_ASSERT_X(success, "QIOSurfaceGraphicsBuffer", "Unlocking surface should succeed");
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QIOSurfaceGraphicsBuffer *graphicsBuffer)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QIOSurfaceGraphicsBuffer(" << (const void *)graphicsBuffer;
+ if (graphicsBuffer) {
+ debug << ", surface=" << graphicsBuffer->m_surface;
+ debug << ", size=" << graphicsBuffer->size();
+ debug << ", isLocked=" << bool(graphicsBuffer->isLocked());
+ debug << ", isInUse=" << graphicsBuffer->isInUse();
+ }
+ debug << ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm
index 6db5ed8bad..f7e14b7883 100644
--- a/src/plugins/platforms/cocoa/qnsview_drawing.mm
+++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm
@@ -163,6 +163,13 @@
return NSViewLayerContentsRedrawDuringViewResize;
}
+- (NSViewLayerContentsPlacement)layerContentsPlacement
+{
+ // Always place the layer at top left without any automatic scaling,
+ // so that we can re-use larger layers when resizing a window down.
+ return NSViewLayerContentsPlacementTopLeft;
+}
+
- (void)updateMetalLayerDrawableSize:(CAMetalLayer *)layer
{
CGSize drawableSize = layer.bounds.size;
diff --git a/src/plugins/platforms/directfb/qdirectfb_egl.cpp b/src/plugins/platforms/directfb/qdirectfb_egl.cpp
index dad553c890..d3c95f0b65 100644
--- a/src/plugins/platforms/directfb/qdirectfb_egl.cpp
+++ b/src/plugins/platforms/directfb/qdirectfb_egl.cpp
@@ -44,6 +44,7 @@
#include <QtGui/QOpenGLContext>
#include <qpa/qplatformopenglcontext.h>
+#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QScreen>
#include <QtEglSupport/private/qeglplatformcontext_p.h>
@@ -248,7 +249,7 @@ QPlatformOpenGLContext *QDirectFbIntegrationEGL::createPlatformOpenGLContext(QOp
void QDirectFbIntegrationEGL::initializeScreen()
{
m_primaryScreen.reset(new QDirectFbScreenEGL(0));
- screenAdded(m_primaryScreen.data());
+ QWindowSystemInterface::handleScreenAdded(m_primaryScreen.data());
}
bool QDirectFbIntegrationEGL::hasCapability(QPlatformIntegration::Capability cap) const
diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.cpp b/src/plugins/platforms/directfb/qdirectfbintegration.cpp
index cdf340da7a..73e308da53 100644
--- a/src/plugins/platforms/directfb/qdirectfbintegration.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbintegration.cpp
@@ -56,6 +56,7 @@
#include <QtCore/QThread>
#include <QtCore/QAbstractEventDispatcher>
#include <qpa/qplatforminputcontextfactory_p.h>
+#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
@@ -113,7 +114,7 @@ void QDirectFbIntegration::initializeDirectFB()
void QDirectFbIntegration::initializeScreen()
{
m_primaryScreen.reset(new QDirectFbScreen(0));
- screenAdded(m_primaryScreen.data());
+ QWindowSystemInterface::handleScreenAdded(m_primaryScreen.data());
}
void QDirectFbIntegration::initializeInput()
diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
index 0a3a37863a..81bad45cd2 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
@@ -200,10 +200,8 @@ void QEglFSDeviceIntegration::screenInit()
void QEglFSDeviceIntegration::screenDestroy()
{
QGuiApplication *app = qGuiApp;
- QEglFSIntegration *platformIntegration = static_cast<QEglFSIntegration *>(
- QGuiApplicationPrivate::platformIntegration());
while (!app->screens().isEmpty())
- platformIntegration->removeScreen(app->screens().constLast()->handle());
+ QWindowSystemInterface::handleScreenRemoved(app->screens().constLast()->handle());
}
QSizeF QEglFSDeviceIntegration::physicalScreenSize() const
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
index 8ccb0ef2cd..48469b0f8c 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
@@ -120,16 +120,6 @@ QEglFSIntegration::QEglFSIntegration()
initResources();
}
-void QEglFSIntegration::addScreen(QPlatformScreen *screen, bool isPrimary)
-{
- screenAdded(screen, isPrimary);
-}
-
-void QEglFSIntegration::removeScreen(QPlatformScreen *screen)
-{
- destroyScreen(screen);
-}
-
void QEglFSIntegration::initialize()
{
qt_egl_device_integration()->platformInit();
@@ -147,7 +137,7 @@ void QEglFSIntegration::initialize()
m_vtHandler.reset(new QFbVtHandler);
if (qt_egl_device_integration()->usesDefaultScreen())
- addScreen(new QEglFSScreen(display()));
+ QWindowSystemInterface::handleScreenAdded(new QEglFSScreen(display()));
else
qt_egl_device_integration()->screenInit();
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
index 4b4585d33c..898b322834 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
@@ -103,9 +103,6 @@ public:
QFbVtHandler *vtHandler() { return m_vtHandler.data(); }
- void addScreen(QPlatformScreen *screen, bool isPrimary = false);
- void removeScreen(QPlatformScreen *screen);
-
private:
EGLNativeDisplayType nativeDisplay() const;
void createInputHandlers();
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
index 5e2708e958..cb7844aff0 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
@@ -45,6 +45,8 @@
#include <QtEglSupport/private/qeglconvenience_p.h>
#include <QtEglSupport/private/qeglplatformcontext_p.h>
+#include <qpa/qwindowsysteminterface.h>
+
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonParseError>
@@ -80,8 +82,6 @@ bool QEglFSEmulatorIntegration::usesDefaultScreen()
void QEglFSEmulatorIntegration::screenInit()
{
- QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
-
// Use qgsGetDisplays() call to retrieve the available screens from the Emulator
if (getDisplays) {
QByteArray displaysInfo = getDisplays();
@@ -93,7 +93,7 @@ void QEglFSEmulatorIntegration::screenInit()
QJsonArray screenArray = displaysDocument.array();
for (auto screenValue : screenArray) {
if (screenValue.isObject())
- integration->addScreen(new QEglFSEmulatorScreen(screenValue.toObject()));
+ QWindowSystemInterface::handleScreenAdded(new QEglFSEmulatorScreen(screenValue.toObject()));
}
}
} else {
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
index 9f4c9f5703..ef732f9832 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
@@ -310,7 +310,7 @@ QKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice()
if (Q_UNLIKELY(!deviceName))
qFatal("Failed to query device name from EGLDevice");
- return new QEglFSKmsEglDevice(this, screenConfig(), deviceName);
+ return new QEglFSKmsEglDevice(this, screenConfig(), QLatin1String(deviceName));
}
bool QEglFSKmsEglDeviceIntegration::query_egl_device()
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
index b073577797..4f0b0d7725 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
@@ -58,7 +58,7 @@ void QEglFSKmsDevice::registerScreen(QPlatformScreen *screen,
QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen);
s->setVirtualPosition(virtualPos);
s->setVirtualSiblings(virtualSiblings);
- static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->addScreen(s, isPrimary);
+ QWindowSystemInterface::handleScreenAdded(s, isPrimary);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/haiku/qhaikuintegration.cpp b/src/plugins/platforms/haiku/qhaikuintegration.cpp
index 8bd2171794..44df6ae8f5 100644
--- a/src/plugins/platforms/haiku/qhaikuintegration.cpp
+++ b/src/plugins/platforms/haiku/qhaikuintegration.cpp
@@ -49,6 +49,7 @@
#include <QCoreApplication>
#include <QFileInfo>
#include <qpa/qplatformwindow.h>
+#include <qpa/qwindowsysteminterface.h>
#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
#include <Application.h>
@@ -81,12 +82,12 @@ QHaikuIntegration::QHaikuIntegration(const QStringList &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;
diff --git a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp
index ae802bb1fa..3ad31dc562 100644
--- a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp
+++ b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp
@@ -51,7 +51,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatforminputcontextfactory_p.h>
-
+#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
@@ -64,13 +64,13 @@ QIntegrityFbIntegration::QIntegrityFbIntegration(const QStringList &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");
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index 818250fcee..eeb44b54d3 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -92,10 +92,6 @@ public:
QPlatformAccessibility *accessibility() const override;
#endif
- // Called from Objective-C class QIOSScreenTracker, which can't be friended
- void addScreen(QPlatformScreen *screen) { screenAdded(screen); }
- void destroyScreen(QPlatformScreen *screen) { QPlatformIntegration::destroyScreen(screen); }
-
void beep() const override;
static QIOSIntegration *instance();
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index bec8354fcc..9eca0eaad3 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -107,7 +107,7 @@ void QIOSIntegration::initialize()
}
for (UIScreen *screen in screens)
- addScreen(new QIOSScreen(screen));
+ QWindowSystemInterface::handleScreenAdded(new QIOSScreen(screen));
// Depends on a primary screen being present
m_inputContext = new QIOSInputContext;
@@ -143,7 +143,7 @@ QIOSIntegration::~QIOSIntegration()
m_inputContext = 0;
foreach (QScreen *screen, QGuiApplication::screens())
- destroyScreen(screen->handle());
+ QWindowSystemInterface::handleScreenRemoved(screen->handle());
delete m_platformServices;
m_platformServices = 0;
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index 4f753be21a..9aba658479 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -50,6 +50,7 @@
#include <QtGui/private/qwindow_p.h>
#include <private/qcoregraphics_p.h>
+#include <qpa/qwindowsysteminterface.h>
#include <sys/sysctl.h>
@@ -105,10 +106,10 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
+ (void)screenConnected:(NSNotification*)notification
{
- QIOSIntegration *integration = QIOSIntegration::instance();
- Q_ASSERT_X(integration, Q_FUNC_INFO, "Screen connected before QIOSIntegration creation");
+ Q_ASSERT_X(QIOSIntegration::instance(), Q_FUNC_INFO,
+ "Screen connected before QIOSIntegration creation");
- integration->addScreen(new QIOSScreen([notification object]));
+ QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object]));
}
+ (void)screenDisconnected:(NSNotification*)notification
@@ -116,8 +117,7 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
QIOSScreen *screen = qtPlatformScreenFor([notification object]);
Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about");
- QIOSIntegration *integration = QIOSIntegration::instance();
- integration->destroyScreen(screen);
+ QWindowSystemInterface::handleScreenRemoved(screen);
}
+ (void)screenModeChanged:(NSNotification*)notification
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
index 9e38900bcd..68843aa4c5 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
@@ -54,6 +54,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatforminputcontextfactory_p.h>
+#include <qpa/qwindowsysteminterface.h>
#if QT_CONFIG(libinput)
#include <QtInputSupport/private/qlibinputhandler_p.h>
@@ -89,13 +90,13 @@ QLinuxFbIntegration::QLinuxFbIntegration(const QStringList &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");
diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp
index 0c04608fca..f457f69f11 100644
--- a/src/plugins/platforms/minimal/qminimalintegration.cpp
+++ b/src/plugins/platforms/minimal/qminimalintegration.cpp
@@ -43,6 +43,7 @@
#include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformwindow.h>
+#include <qpa/qwindowsysteminterface.h>
#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
#if defined(Q_OS_WINRT)
@@ -108,7 +109,7 @@ QMinimalIntegration::QMinimalIntegration(const QStringList &parameters)
mPrimaryScreen->mDepth = 32;
mPrimaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied;
- screenAdded(mPrimaryScreen);
+ QWindowSystemInterface::handleScreenAdded(mPrimaryScreen);
}
QMinimalIntegration::~QMinimalIntegration()
diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
index da58441d67..a0d35a80cd 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
@@ -58,6 +58,7 @@
#include <QtGui/QSurfaceFormat>
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
+#include <qpa/qwindowsysteminterface.h>
// this is where EGL headers are pulled in, make sure it is last
#include "qminimaleglscreen.h"
@@ -90,7 +91,7 @@ protected:
QMinimalEglIntegration::QMinimalEglIntegration()
: mFontDb(new QGenericUnixFontDatabase()), mScreen(new QMinimalEglScreen(EGL_DEFAULT_DISPLAY))
{
- screenAdded(mScreen);
+ QWindowSystemInterface::handleScreenAdded(mScreen);
#ifdef QEGL_EXTRA_DEBUG
qWarning("QMinimalEglIntegration\n");
@@ -99,7 +100,7 @@ QMinimalEglIntegration::QMinimalEglIntegration()
QMinimalEglIntegration::~QMinimalEglIntegration()
{
- destroyScreen(mScreen);
+ QWindowSystemInterface::handleScreenRemoved(mScreen);
delete mFontDb;
}
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
index f2933b7179..869e9228cd 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -63,6 +63,7 @@
#include <qpa/qplatforminputcontextfactory_p.h>
#include <qpa/qplatforminputcontext.h>
#include <qpa/qplatformtheme.h>
+#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformservices.h>
@@ -121,7 +122,7 @@ QOffscreenIntegration::QOffscreenIntegration()
#endif
m_services.reset(new QPlatformServices);
- screenAdded(new QOffscreenScreen);
+ QWindowSystemInterface::handleScreenAdded(new QOffscreenScreen);
}
QOffscreenIntegration::~QOffscreenIntegration()
diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp
index 4850ca2e45..c5dc40a206 100644
--- a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp
+++ b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp
@@ -50,6 +50,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
+#include <qpa/qwindowsysteminterface.h>
#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
@@ -135,13 +136,3 @@ QPlatformPrinterSupport * QOpenWFDIntegration::printerSupport() const
{
return mPrinterSupport;
}
-
-void QOpenWFDIntegration::addScreen(QOpenWFDScreen *screen)
-{
- screenAdded(screen);
-}
-
-void QOpenWFDIntegration::destroyScreen(QOpenWFDScreen *screen)
-{
- QPlatformIntegration::destroyScreen(screen);
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.h b/src/plugins/platforms/openwfd/qopenwfdintegration.h
index 1ce1001bed..444aaccaaf 100644
--- a/src/plugins/platforms/openwfd/qopenwfdintegration.h
+++ b/src/plugins/platforms/openwfd/qopenwfdintegration.h
@@ -68,8 +68,6 @@ public:
QPlatformPrinterSupport *printerSupport() const;
- void addScreen(QOpenWFDScreen *screen);
- void destroyScreen(QOpenWFDScreen *screen);
private:
QList<QPlatformScreen *> mScreens;
QList<QOpenWFDDevice *>mDevices;
diff --git a/src/plugins/platforms/openwfd/qopenwfdport.cpp b/src/plugins/platforms/openwfd/qopenwfdport.cpp
index 33254fe83c..34b4439958 100644
--- a/src/plugins/platforms/openwfd/qopenwfdport.cpp
+++ b/src/plugins/platforms/openwfd/qopenwfdport.cpp
@@ -133,7 +133,7 @@ void QOpenWFDPort::attach()
wfdBindPipelineToPort(mDevice->handle(),mPort,mPipeline);
mScreen = new QOpenWFDScreen(this);
- mDevice->integration()->addScreen(mScreen);
+ QWindowSystemInterface::handleScreenAdded(mScreen);
mAttached = true;
}
@@ -145,7 +145,7 @@ void QOpenWFDPort::detach()
mAttached = false;
mOn = false;
- mDevice->integration()->destroyScreen(mScreen);
+ QWindowSystemInterface::handleScreenRemoved(mScreen);
wfdDestroyPipeline(mDevice->handle(),mPipeline);
mPipelineId = WFD_INVALID_PIPELINE_ID;
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index a996e765c4..a45dcabeb7 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -649,7 +649,7 @@ void QQnxIntegration::createDisplay(screen_display_t display, bool isPrimary)
{
QQnxScreen *screen = new QQnxScreen(m_screenContext, display, isPrimary);
m_screens.append(screen);
- screenAdded(screen);
+ QWindowSystemInterface::handleScreenAdded(screen);
screen->adjustOrientation();
QObject::connect(m_screenEventHandler, SIGNAL(newWindowCreated(void*)),
@@ -669,14 +669,14 @@ void QQnxIntegration::removeDisplay(QQnxScreen *screen)
Q_CHECK_PTR(screen);
Q_ASSERT(m_screens.contains(screen));
m_screens.removeAll(screen);
- destroyScreen(screen);
+ QWindowSystemInterface::handleScreenRemoved(screen);
}
void QQnxIntegration::destroyDisplays()
{
qIntegrationDebug();
Q_FOREACH (QQnxScreen *screen, m_screens) {
- QPlatformIntegration::destroyScreen(screen);
+ QWindowSystemInterface::handleScreenRemoved(screen);
}
m_screens.clear();
}
diff --git a/src/plugins/platforms/vnc/qvncintegration.cpp b/src/plugins/platforms/vnc/qvncintegration.cpp
index 1e2cf6292c..c7a796464a 100644
--- a/src/plugins/platforms/vnc/qvncintegration.cpp
+++ b/src/plugins/platforms/vnc/qvncintegration.cpp
@@ -52,6 +52,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatforminputcontextfactory_p.h>
#include <private/qinputdevicemanager_p_p.h>
+#include <qpa/qwindowsysteminterface.h>
#include <QtCore/QRegularExpression>
@@ -77,13 +78,13 @@ QVncIntegration::QVncIntegration(const QStringList &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");
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index 1964cefdad..486f4cb2b3 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -98,7 +98,10 @@ QWasmIntegration::QWasmIntegration()
QWasmIntegration::~QWasmIntegration()
{
delete m_fontDb;
- qDeleteAll(m_screens);
+
+ while (!m_screens.isEmpty())
+ QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast());
+
s_instance = nullptr;
}
@@ -113,7 +116,7 @@ bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const
switch (cap) {
case ThreadedPixmaps: return true;
case OpenGL: return true;
- case ThreadedOpenGL: return true;
+ case ThreadedOpenGL: return false;
case RasterGLSurface: return false; // to enable this you need to fix qopenglwidget and quickwidget for wasm
case MultipleWindows: return true;
case WindowManagement: return true;
@@ -191,7 +194,7 @@ void QWasmIntegration::addScreen(const QString &canvasId)
QWasmScreen *screen = new QWasmScreen(canvasId);
m_clipboard->installEventHandlers(canvasId);
m_screens.append(screen);
- screenAdded(screen);
+ QWindowSystemInterface::handleScreenAdded(screen);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html
index 39bb711b6b..6ad7886ed4 100644
--- a/src/plugins/platforms/wasm/wasm_shell.html
+++ b/src/plugins/platforms/wasm/wasm_shell.html
@@ -27,9 +27,9 @@
<script type='text/javascript'>
function init() {
- var spinner = document.getElementById('qtspinner');
- var canvas = document.getElementById('qtcanvas');
- var status = document.getElementById('qtstatus')
+ var spinner = document.querySelector('#qtspinner');
+ var canvas = document.querySelector('#qtcanvas');
+ var status = document.querySelector('#qtstatus')
var qtLoader = QtLoader({
canvasElements : [canvas],
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index da86852766..e28b2c2fb3 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -107,9 +107,6 @@ public:
static QWindowsIntegration *instance() { return m_instance; }
- inline void emitScreenAdded(QPlatformScreen *s, bool isPrimary = false) { screenAdded(s, isPrimary); }
- inline void emitDestroyScreen(QPlatformScreen *s) { destroyScreen(s); }
-
unsigned options() const;
void beep() const override;
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index a161dc46e9..0520f88935 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -121,7 +121,7 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM
QWindowsScreenData data;
if (monitorData(hMonitor, &data)) {
WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p);
- // QPlatformIntegration::screenAdded() documentation specifies that first
+ // QWindowSystemInterface::handleScreenAdded() documentation specifies that first
// added screen will be the primary screen, so order accordingly.
// Note that the side effect of this policy is that there is no way to change primary
// screen reported by Qt, unless we want to delete all existing screens and add them
@@ -521,7 +521,7 @@ void QWindowsScreenManager::removeScreen(int index)
if (movedWindowCount)
QWindowSystemInterface::flushWindowSystemEvents();
}
- QWindowsIntegration::instance()->emitDestroyScreen(m_screens.takeAt(index));
+ QWindowSystemInterface::handleScreenRemoved(m_screens.takeAt(index));
}
/*!
@@ -541,7 +541,7 @@ bool QWindowsScreenManager::handleScreenChanges()
} else {
QWindowsScreen *newScreen = new QWindowsScreen(newData);
m_screens.push_back(newScreen);
- QWindowsIntegration::instance()->emitScreenAdded(newScreen,
+ QWindowSystemInterface::handleScreenAdded(newScreen,
newData.flags & QWindowsScreenData::PrimaryScreen);
qCDebug(lcQpaWindows) << "New Monitor: " << newData;
} // exists
@@ -561,7 +561,7 @@ void QWindowsScreenManager::clearScreens()
{
// Delete screens in reverse order to avoid crash in case of multiple screens
while (!m_screens.isEmpty())
- QWindowsIntegration::instance()->emitDestroyScreen(m_screens.takeLast());
+ QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast());
}
const QWindowsScreen *QWindowsScreenManager::screenAtDp(const QPoint &p) const
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 8bf090bf03..07fd2916c2 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1759,15 +1759,12 @@ void QWindowsWindow::checkForScreenChanged()
QPlatformScreen *currentScreen = screen();
const auto &screenManager = QWindowsContext::instance()->screenManager();
- // QTBUG-62971: When dragging a window by its border, detect by mouse position
- // to prevent it from oscillating between screens when it resizes
- const QWindowsScreen *newScreen = testFlag(ResizeMoveActive)
- ? screenManager.screenAtDp(QWindowsCursor::mousePosition())
- : screenManager.screenForHwnd(m_data.hwnd);
+ const QWindowsScreen *newScreen = screenManager.screenForHwnd(m_data.hwnd);
if (newScreen != nullptr && newScreen != currentScreen) {
qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__
<< ' ' << window() << " \"" << currentScreen->name()
<< "\"->\"" << newScreen->name() << '"';
+ setFlag(SynchronousGeometryChangeEvent);
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
}
}
@@ -1786,11 +1783,14 @@ void QWindowsWindow::handleGeometryChange()
fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true);
}
+ const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
checkForScreenChanged();
if (testFlag(SynchronousGeometryChangeEvent))
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
+ if (!wasSync)
+ clearFlag(SynchronousGeometryChangeEvent);
qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry;
}
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
index 78cbc3aec3..27d3746933 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp
@@ -133,7 +133,7 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate)
});
d->inputContext.reset(new QWinRTInputContext(d->mainScreen));
- screenAdded(d->mainScreen);
+ QWindowSystemInterface::handleScreenAdded(d->mainScreen);
d->platformServices = new QWinRTServices;
d->clipboard = new QWinRTClipboard;
#if QT_CONFIG(accessibility)
@@ -154,7 +154,7 @@ QWinRTIntegration::~QWinRTIntegration()
Q_ASSERT_SUCCEEDED(hr);
}
- destroyScreen(d->mainScreen);
+ QWindowSystemInterface::handleScreenRemoved(d->mainScreen);
Windows::Foundation::Uninitialize();
}
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
index d42a33c22b..476de6d1e5 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
@@ -652,6 +652,12 @@ static const char *qglx_threadedgl_blacklist_renderer[] = {
0
};
+static const char *qglx_threadedgl_blacklist_vendor[] = {
+ "llvmpipe", // QTCREATORBUG-10666
+ "nouveau", // https://bugs.freedesktop.org/show_bug.cgi?id=91632
+ nullptr
+};
+
void QGLXContext::queryDummyContext()
{
if (m_queriedDummyContext)
@@ -710,6 +716,18 @@ void QGLXContext::queryDummyContext()
}
}
}
+ if (const char *vendor = (const char *) glGetString(GL_VENDOR)) {
+ for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) {
+ if (strstr(vendor, qglx_threadedgl_blacklist_vendor[i]) != 0) {
+ qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: "
+ "blacklisted vendor \""
+ << qglx_threadedgl_blacklist_vendor[i]
+ << "\"";
+ m_supportsThreading = false;
+ break;
+ }
+ }
+ }
if (glxvendor && m_supportsThreading) {
// Blacklist Mesa drivers due to QTCREATORBUG-10875 (crash in creator),
diff --git a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
index ed482e5dae..bbc156fc53 100644
--- a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
@@ -192,6 +192,10 @@ bool QXcbNativeBackingStore::scroll(const QRegion &area, int dx, int dy)
void QXcbNativeBackingStore::beginPaint(const QRegion &region)
{
+ QX11PlatformPixmap *x11pm = qt_x11Pixmap(m_pixmap);
+ if (x11pm)
+ x11pm->setIsBackingStore(true);
+
#if QT_CONFIG(xrender)
if (m_translucentBackground) {
const QVector<XRectangle> xrects = qt_region_to_xrectangles(region);
diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
index 2688d6e884..3377eeaae9 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
@@ -200,6 +200,7 @@ public:
uint has_pattern : 1;
uint has_alpha_pen : 1;
uint has_alpha_brush : 1;
+ uint use_sysclip : 1;
uint render_hints;
const QXcbX11Info *xinfo;
@@ -701,6 +702,9 @@ bool QX11PaintEngine::begin(QPaintDevice *pdev)
d->xlibMaxLinePoints = 32762; // a safe number used to avoid, call to XMaxRequestSize(d->dpy) - 3;
d->opacity = 1;
+ QX11PlatformPixmap *x11pm = paintDevice()->devType() == QInternal::Pixmap ? qt_x11Pixmap(*static_cast<QPixmap *>(paintDevice())) : nullptr;
+ d->use_sysclip = paintDevice()->devType() == QInternal::Widget || (x11pm ? x11pm->isBackingStore() : false);
+
// Set up the polygon clipper. Note: This will only work in
// polyline mode as long as we have a buffer zone, since a
// polyline may be clipped into several non-connected polylines.
@@ -1472,7 +1476,7 @@ void QX11PaintEngine::updatePen(const QPen &pen)
}
if (!d->has_clipping) { // if clipping is set the paintevent clip region is merged with the clip region
- QRegion sysClip = systemClip();
+ QRegion sysClip = d->use_sysclip ? systemClip() : QRegion();
if (!sysClip.isEmpty())
x11SetClipRegion(d->dpy, d->gc, 0, d->picture, sysClip);
else
@@ -1603,7 +1607,7 @@ void QX11PaintEngine::updateBrush(const QBrush &brush, const QPointF &origin)
vals.fill_style = s;
XChangeGC(d->dpy, d->gc_brush, mask, &vals);
if (!d->has_clipping) {
- QRegion sysClip = systemClip();
+ QRegion sysClip = d->use_sysclip ? systemClip() : QRegion();
if (!sysClip.isEmpty())
x11SetClipRegion(d->dpy, d->gc_brush, 0, d->picture, sysClip);
else
@@ -2223,7 +2227,7 @@ void QX11PaintEngine::updateMatrix(const QTransform &mtx)
void QX11PaintEngine::updateClipRegion_dev(const QRegion &clipRegion, Qt::ClipOperation op)
{
Q_D(QX11PaintEngine);
- QRegion sysClip = systemClip();
+ QRegion sysClip = d->use_sysclip ? systemClip() : QRegion();
if (op == Qt::NoClip) {
d->has_clipping = false;
d->crgn = sysClip;
diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
index 86c87e5e30..b1ce39f363 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
@@ -1772,6 +1772,20 @@ XID QX11PlatformPixmap::createBitmapFromImage(const QImage &image)
return hd;
}
+bool QX11PlatformPixmap::isBackingStore() const
+{
+ return (flags & IsBackingStore);
+}
+
+void QX11PlatformPixmap::setIsBackingStore(bool on)
+{
+ if (on)
+ flags |= IsBackingStore;
+ else {
+ flags &= ~IsBackingStore;
+ }
+}
+
#if QT_CONFIG(xrender)
void QX11PlatformPixmap::convertToARGB32(bool preserveContents)
{
diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h
index 7392cbfccf..9c0ba98300 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h
+++ b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h
@@ -90,6 +90,8 @@ public:
void convertToARGB32(bool preserveContents = true);
#endif
+ bool isBackingStore() const;
+ void setIsBackingStore(bool on);
private:
friend class QX11PaintEngine;
friend const QXcbX11Info &qt_x11Info(const QPixmap &pixmap);
@@ -110,7 +112,8 @@ private:
Uninitialized = 0x1,
Readonly = 0x2,
InvertedWhenBoundToTexture = 0x4,
- GlSurfaceCreatedWithAlpha = 0x8
+ GlSurfaceCreatedWithAlpha = 0x8,
+ IsBackingStore = 0x10
};
uint flags;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index e35b97dab4..d27a288feb 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -152,10 +152,9 @@ QXcbConnection::~QXcbConnection()
if (m_eventQueue)
delete m_eventQueue;
- QXcbIntegration *integration = QXcbIntegration::instance();
// Delete screens in reverse order to avoid crash in case of multiple screens
while (!m_screens.isEmpty())
- integration->destroyScreen(m_screens.takeLast());
+ QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast());
while (!m_virtualDesktops.isEmpty())
delete m_virtualDesktops.takeLast();
diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.h b/src/plugins/platforms/xcb/qxcbconnection_basic.h
index 3691763398..b979129cba 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_basic.h
+++ b/src/plugins/platforms/xcb/qxcbconnection_basic.h
@@ -40,6 +40,7 @@
#define QXCBBASICCONNECTION_H
#include "qxcbatom.h"
+#include "qxcbexport.h"
#include <QtCore/QPair>
#include <QtCore/QObject>
@@ -55,7 +56,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaXcb)
-class QXcbBasicConnection : public QObject
+class Q_XCB_EXPORT QXcbBasicConnection : public QObject
{
Q_OBJECT
public:
diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
index 4bafe83156..9ba71ada37 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
@@ -44,6 +44,8 @@
#include <QtCore/QString>
#include <QtCore/QList>
+#include <qpa/qwindowsysteminterface.h>
+
#include <xcb/xinerama.h>
void QXcbConnection::xrandrSelectEvents()
@@ -211,7 +213,7 @@ void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_cha
m_screens.swapItemsAt(0, idx);
}
screen->virtualDesktop()->setPrimaryScreen(screen);
- QXcbIntegration::instance()->setPrimaryScreen(screen);
+ QWindowSystemInterface::handlePrimaryScreenChanged(screen);
}
}
}
@@ -234,7 +236,7 @@ QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop,
m_screens.append(screen);
}
virtualDesktop->addScreen(screen);
- QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary());
+ QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
return screen;
}
@@ -261,10 +263,10 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen)
const int idx = m_screens.indexOf(newPrimary);
if (idx > 0)
m_screens.swapItemsAt(0, idx);
- QXcbIntegration::instance()->setPrimaryScreen(newPrimary);
+ QWindowSystemInterface::handlePrimaryScreenChanged(newPrimary);
}
- QXcbIntegration::instance()->destroyScreen(screen);
+ QWindowSystemInterface::handleScreenRemoved(screen);
}
}
@@ -406,7 +408,7 @@ void QXcbConnection::initializeScreens()
// Push the screens to QGuiApplication
for (QXcbScreen *screen : qAsConst(m_screens)) {
qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")";
- QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary());
+ QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
}
qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name();
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index f13e232291..571726c354 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -137,8 +137,6 @@ private:
QScopedPointer<QPlatformServices> m_services;
- friend class QXcbConnection; // access QPlatformIntegration::screenAdded()
-
mutable QByteArray m_wmClass;
const char *m_instanceName;
bool m_canGrab;
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 4d526a6bda..899081e752 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -412,12 +412,15 @@ void *QXcbNativeInterface::atspiBus()
auto reply = Q_XCB_REPLY(xcb_get_property, defaultConnection->xcb_connection(),
false, defaultConnection->rootWindow(),
atspiBusAtom, XCB_ATOM_STRING, 0, 128);
- Q_ASSERT(!reply->bytes_after);
+ if (!reply)
+ return nullptr;
+
char *data = (char *)xcb_get_property_value(reply.get());
int length = xcb_get_property_value_length(reply.get());
return new QByteArray(data, length);
}
- return 0;
+
+ return nullptr;
}
void QXcbNativeInterface::setAppTime(QScreen* screen, xcb_timestamp_t time)