summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp10
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.h1
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp2
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp5
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp7
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h16
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm128
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm21
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h41
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm99
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm1
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm25
-rw-r--r--src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h4
-rw-r--r--src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm21
-rw-r--r--src/plugins/platforms/cocoa/qnsview_drawing.mm11
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm20
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp44
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h16
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp218
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.h99
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h7
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp108
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h10
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm7
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm8
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.mm13
-rw-r--r--src/plugins/platforms/ios/quiview.mm38
-rw-r--r--src/plugins/platforms/vnc/qvnc.cpp5
-rw-r--r--src/plugins/platforms/vnc/qvncscreen.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbatom.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbatom.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp13
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp16
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp21
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_basic.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_screens.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp108
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.h15
-rw-r--r--src/plugins/platforms/xcb/qxcbeventqueue.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbeventqueue.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp66
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h3
55 files changed, 931 insertions, 376 deletions
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index 309e41bfd6..6f1178e041 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -72,20 +72,28 @@ namespace QtAndroidAccessibility
static jmethodID m_setTextSelectionMethodID = 0;
static jmethodID m_setVisibleToUserMethodID = 0;
+ static bool m_accessibilityActivated = false;
+
void initialize()
{
QJNIObjectPrivate::callStaticMethod<void>(QtAndroid::applicationClass(),
"initializeAccessibility");
}
+ bool isActive()
+ {
+ return m_accessibilityActivated;
+ }
+
static void setActive(JNIEnv */*env*/, jobject /*thiz*/, jboolean active)
{
QMutexLocker lock(QtAndroid::platformInterfaceMutex());
QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration();
+ m_accessibilityActivated = active;
if (platformIntegration)
platformIntegration->accessibility()->setActive(active);
else
- __android_log_print(ANDROID_LOG_WARN, m_qtTag, "Could not activate platform accessibility.");
+ __android_log_print(ANDROID_LOG_WARN, m_qtTag, "Could not (yet) activate platform accessibility.");
}
QAccessibleInterface *interfaceFromId(jint objectId)
diff --git a/src/plugins/platforms/android/androidjniaccessibility.h b/src/plugins/platforms/android/androidjniaccessibility.h
index f393ce0b08..508ed4462b 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.h
+++ b/src/plugins/platforms/android/androidjniaccessibility.h
@@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE
namespace QtAndroidAccessibility
{
void initialize();
+ bool isActive();
bool registerNatives(JNIEnv *env);
}
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index 56885f2e23..6ba1aa5e24 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -519,7 +519,7 @@ namespace QtAndroidInput
return Qt::Key_Search;
case 0x00000055: // KEYCODE_MEDIA_PLAY_PAUSE
- return Qt::Key_MediaPlay;
+ return Qt::Key_MediaTogglePlayPause;
case 0x00000056: // KEYCODE_MEDIA_STOP
return Qt::Key_MediaStop;
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 74edfd8356..9ce3353040 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -505,7 +505,7 @@ static void waitForServiceSetup(JNIEnv *env, jclass /*clazz*/)
QtAndroidPrivate::waitForServiceSetup();
}
-static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
+static void startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
{
{
JNIEnv* env = nullptr;
@@ -540,7 +540,8 @@ static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
sem_destroy(&m_exitSemaphore);
// We must call exit() to ensure that all global objects will be destructed
- exit(ret);
+ if (!qEnvironmentVariableIsSet("QT_ANDROID_NO_EXIT_CALL"))
+ exit(ret);
}
static void quitQtCoreApplication(JNIEnv *env, jclass /*clazz*/)
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index e0c437be27..ff59ca6bde 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -52,6 +52,7 @@
#include <qpa/qplatformoffscreensurface.h>
#include "androidjnimain.h"
+#include "androidjniaccessibility.h"
#include "qabstracteventdispatcher.h"
#include "qandroideventdispatcher.h"
#include "qandroidplatformbackingstore.h"
@@ -149,6 +150,12 @@ void QAndroidPlatformNativeInterface::customEvent(QEvent *event)
QMutexLocker lock(QtAndroid::platformInterfaceMutex());
QAndroidPlatformIntegration *api = static_cast<QAndroidPlatformIntegration *>(QGuiApplicationPrivate::platformIntegration());
QtAndroid::setAndroidPlatformIntegration(api);
+
+#ifndef QT_NO_ACCESSIBILITY
+ // Android accessibility activation event might have been already received
+ api->accessibility()->setActive(QtAndroidAccessibility::isActive());
+#endif // QT_NO_ACCESSIBILITY
+
api->flushPendingUpdates();
}
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index a874936ce6..3d9dfd8359 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -47,6 +47,8 @@
#include <QScopedPointer>
#include "qiosurfacegraphicsbuffer.h"
+#include <unordered_map>
+
QT_BEGIN_NAMESPACE
class QCocoaBackingStore : public QRasterBackingStore
@@ -54,8 +56,6 @@ class QCocoaBackingStore : public QRasterBackingStore
protected:
QCocoaBackingStore(QWindow *window);
QCFType<CGColorSpaceRef> colorSpace() const;
- QMacNotificationObserver m_backingPropertiesObserver;
- virtual void backingPropertiesChanged() = 0;
};
class QNSWindowBackingStore : public QCocoaBackingStore
@@ -71,11 +71,11 @@ private:
bool windowHasUnifiedToolbar() const;
QImage::Format format() const override;
void redrawRoundedBottomCorners(CGRect) const;
- void backingPropertiesChanged() override;
};
-class QCALayerBackingStore : public QCocoaBackingStore
+class QCALayerBackingStore : public QObject, public QCocoaBackingStore
{
+ Q_OBJECT
public:
QCALayerBackingStore(QWindow *window);
~QCALayerBackingStore();
@@ -118,9 +118,15 @@ private:
bool recreateBackBufferIfNeeded();
bool prepareForFlush();
- void backingPropertiesChanged() override;
+ void backingPropertiesChanged();
+ QMacNotificationObserver m_backingPropertiesObserver;
std::list<std::unique_ptr<GraphicsBuffer>> m_buffers;
+
+ void flushSubWindow(QWindow *window);
+ std::unordered_map<QWindow*, std::unique_ptr<QCALayerBackingStore>> m_subWindowBackingstores;
+ void windowDestroyed(QObject *object);
+ bool m_clearSurfaceOnPaint = true;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 2343f16b9f..6ea6714649 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -51,17 +51,6 @@ QT_BEGIN_NAMESPACE
QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
: QRasterBackingStore(window)
{
- // Ideally this would be plumbed from the platform layer to QtGui, and
- // the QBackingStore would be recreated, but we don't have that code yet,
- // so at least make sure we invalidate our backingstore when the backing
- // properties (color space e.g.) are changed.
- NSView *view = static_cast<QCocoaWindow *>(window->handle())->view();
- m_backingPropertiesObserver = QMacNotificationObserver(view.window,
- NSWindowDidChangeBackingPropertiesNotification, [this]() {
- qCDebug(lcQpaBackingStore) << "Backing properties for"
- << this->window() << "did change";
- backingPropertiesChanged();
- });
}
QCFType<CGColorSpaceRef> QCocoaBackingStore::colorSpace() const
@@ -341,11 +330,6 @@ void QNSWindowBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const
#endif
}
-void QNSWindowBackingStore::backingPropertiesChanged()
-{
- m_image = QImage();
-}
-
// ----------------------------------------------------------------------------
// https://stackoverflow.com/a/52722575/2761869
@@ -365,6 +349,26 @@ QCALayerBackingStore::QCALayerBackingStore(QWindow *window)
{
qCDebug(lcQpaBackingStore) << "Creating QCALayerBackingStore for" << window;
m_buffers.resize(1);
+
+ // Ideally this would be plumbed from the platform layer to QtGui, and
+ // the QBackingStore would be recreated, but we don't have that code yet,
+ // so at least make sure we update our backingstore when the backing
+ // properties (color space e.g.) are changed.
+ NSView *view = static_cast<QCocoaWindow *>(window->handle())->view();
+ m_backingPropertiesObserver = QMacNotificationObserver(view.window,
+ NSWindowDidChangeBackingPropertiesNotification, [this]() {
+ if (!this->window()->handle()) {
+ // The platform window has been destroyed, but the backingstore
+ // is still alive, as that's tied to a QWindow. The original
+ // NSWindow we were observing is also likely gone. FIXME:
+ // We should listen for surface events from the QWindow and
+ // remove and re-attach our observer based on those.
+ return;
+ }
+ qCDebug(lcQpaBackingStore) << "Backing properties for"
+ << this->window() << "did change";
+ backingPropertiesChanged();
+ });
}
QCALayerBackingStore::~QCALayerBackingStore()
@@ -398,7 +402,7 @@ void QCALayerBackingStore::beginPaint(const QRegion &region)
// 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()) {
+ if (m_clearSurfaceOnPaint && !bufferWasRecreated && window()->format().hasAlpha()) {
qCDebug(lcQpaBackingStore) << "Clearing" << region << "before use";
QPainter painter(m_buffers.back()->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source);
@@ -527,9 +531,13 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
if (!prepareForFlush())
return;
+ if (flushedWindow != window()) {
+ flushSubWindow(flushedWindow);
+ return;
+ }
+
QMacAutoReleasePool pool;
- NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
// If the backingstore is just flushed, without being painted to first, then we may
@@ -564,7 +572,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// 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;
+ flushedView.window.viewsNeedDisplay = YES;
if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer) {
// The private API [CALayer reloadValueForKeyPath:@"contents"] would be preferable,
@@ -572,27 +580,10 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
flushedView.layer.contents = nil;
}
- if (flushedView == backingStoreView) {
- qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
- << "to" << flushedView.layer << "of" << flushedView;
- flushedView.layer.contents = backBufferSurface;
- } else {
- auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
- auto scale = flushedView.layer.contentsScale;
- subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
-
- // We make a copy of the image data up front, which means we don't
- // need to mark the IOSurface as being in use. FIXME: Investigate
- // if there's a cheaper way to get sub-image data to a layer.
- m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
- QImage subImage = m_buffers.back()->asImage()->copy(QRectF::fromCGRect(subviewRect).toRect());
- m_buffers.back()->unlock();
+ qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
+ << "to" << flushedView.layer << "of" << flushedView;
- qCInfo(lcQpaBackingStore) << "Flushing" << subImage
- << "to" << flushedView.layer << "of subview" << flushedView;
- QCFType<CGImageRef> cgImage = subImage.toCGImage();
- flushedView.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage);
- }
+ flushedView.layer.contents = backBufferSurface;
// 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
@@ -604,6 +595,53 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// the window server.
}
+void QCALayerBackingStore::flushSubWindow(QWindow *subWindow)
+{
+ qCInfo(lcQpaBackingStore) << "Flushing sub-window" << subWindow
+ << "via its own backingstore";
+
+ auto &subWindowBackingStore = m_subWindowBackingstores[subWindow];
+ if (!subWindowBackingStore) {
+ subWindowBackingStore.reset(new QCALayerBackingStore(subWindow));
+ QObject::connect(subWindow, &QObject::destroyed, this, &QCALayerBackingStore::windowDestroyed);
+ subWindowBackingStore->m_clearSurfaceOnPaint = false;
+ }
+
+ auto subWindowSize = subWindow->size();
+ static const auto kNoStaticContents = QRegion();
+ subWindowBackingStore->resize(subWindowSize, kNoStaticContents);
+
+ auto subWindowLocalRect = QRect(QPoint(), subWindowSize);
+ subWindowBackingStore->beginPaint(subWindowLocalRect);
+
+ QPainter painter(subWindowBackingStore->m_buffers.back()->asImage());
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+
+ NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
+ NSView *flushedView = static_cast<QCocoaWindow *>(subWindow->handle())->view();
+ auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
+ auto scale = flushedView.layer.contentsScale;
+ subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
+
+ m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
+ const QImage *backingStoreImage = m_buffers.back()->asImage();
+ painter.drawImage(subWindowLocalRect, *backingStoreImage, QRectF::fromCGRect(subviewRect));
+ m_buffers.back()->unlock();
+
+ painter.end();
+ subWindowBackingStore->endPaint();
+ subWindowBackingStore->flush(subWindow, subWindowLocalRect, QPoint());
+
+ qCInfo(lcQpaBackingStore) << "Done flushing sub-window" << subWindow;
+}
+
+void QCALayerBackingStore::windowDestroyed(QObject *object)
+{
+ auto *window = static_cast<QWindow*>(object);
+ qCInfo(lcQpaBackingStore) << "Removing backingstore for sub-window" << window;
+ m_subWindowBackingstores.erase(window);
+}
+
#ifndef QT_NO_OPENGL
void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, bool translucentBackground)
@@ -632,8 +670,11 @@ QImage QCALayerBackingStore::toImage() const
void QCALayerBackingStore::backingPropertiesChanged()
{
- m_buffers.clear();
- m_buffers.resize(1);
+ qCDebug(lcQpaBackingStore) << "Updating color space of existing buffers";
+ for (auto &buffer : m_buffers) {
+ if (buffer)
+ buffer->setColorSpace(colorSpace());
+ }
}
QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const
@@ -710,10 +751,11 @@ bool QCALayerBackingStore::prepareForFlush()
QCALayerBackingStore::GraphicsBuffer::GraphicsBuffer(const QSize &size, qreal devicePixelRatio,
const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace)
- : QIOSurfaceGraphicsBuffer(size, format, colorSpace)
+ : QIOSurfaceGraphicsBuffer(size, format)
, dirtyRegion(0, 0, size.width() / devicePixelRatio, size.height() / devicePixelRatio)
, m_devicePixelRatio(devicePixelRatio)
{
+ setColorSpace(colorSpace);
}
QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
@@ -733,4 +775,6 @@ QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
return &m_image;
}
+#include "moc_qcocoabackingstore.cpp"
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index d91b2cabaf..c8b5365a75 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -357,6 +357,8 @@ QCocoaGLContext::~QCocoaGLContext()
bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
{
+ QMacAutoReleasePool pool;
+
qCDebug(lcQpaOpenGLContext) << "Making" << m_context << "current"
<< "in" << QThread::currentThread() << "for" << surface;
@@ -479,6 +481,8 @@ void QCocoaGLContext::update()
void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
{
+ QMacAutoReleasePool pool;
+
qCDebug(lcQpaOpenGLContext) << "Swapping" << m_context
<< "in" << QThread::currentThread() << "to" << surface;
@@ -491,12 +495,29 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
return;
}
+ if (m_context.view.layer) {
+ // Flushing an NSOpenGLContext will hit the screen immediately, ignoring
+ // any Core Animation transactions in place. This may result in major
+ // visual artifacts if the flush happens out of sync with the size
+ // of the layer, view, and window reflected by other parts of the UI,
+ // e.g. if the application flushes in the resize event or a timer during
+ // window resizing, instead of in the expose event.
+ auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
+ if (cocoaWindow->geometry().size() != cocoaWindow->m_exposedRect.size()) {
+ qCInfo(lcQpaOpenGLContext) << "Window exposed size does not match geometry (yet)."
+ << "Skipping flush to avoid visual artifacts.";
+ return;
+ }
+ }
+
QMutexLocker locker(&s_reentrancyMutex);
[m_context flushBuffer];
}
void QCocoaGLContext::doneCurrent()
{
+ QMacAutoReleasePool pool;
+
qCDebug(lcQpaOpenGLContext) << "Clearing current context"
<< [NSOpenGLContext currentContext] << "in" << QThread::currentThread();
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 69aa7937b6..514d3ac550 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -55,6 +55,7 @@
#include <QtCore/qoperatingsystemversion.h>
#include <QtGui/qpalette.h>
#include <QtGui/qscreen.h>
+#include <qpa/qplatformdialoghelper.h>
#include <objc/runtime.h>
#include <objc/message.h>
@@ -178,32 +179,6 @@ T qt_mac_resolveOption(const T &fallback, QWindow *window, const QByteArray &pro
// -------------------------------------------------------------------------
-#if !defined(Q_PROCESSOR_X86_64)
-#error "32-bit builds are not supported"
-#endif
-
-class QMacVersion
-{
-public:
- enum VersionTarget {
- ApplicationBinary,
- QtLibraries
- };
-
- static QOperatingSystemVersion buildSDK(VersionTarget target = ApplicationBinary);
- static QOperatingSystemVersion deploymentTarget(VersionTarget target = ApplicationBinary);
- static QOperatingSystemVersion currentRuntime();
-
-private:
- QMacVersion() = default;
- using VersionTuple = QPair<QOperatingSystemVersion, QOperatingSystemVersion>;
- static VersionTuple versionsForImage(const mach_header *machHeader);
- static VersionTuple applicationVersion();
- static VersionTuple libraryVersion();
-};
-
-// -------------------------------------------------------------------------
-
QT_END_NAMESPACE
// @compatibility_alias doesn't work with protocols
@@ -225,7 +200,7 @@ QT_END_NAMESPACE
- (instancetype)initWithPanelDelegate:(id<QNSPanelDelegate>)panelDelegate;
- (void)dealloc;
-- (NSButton *)createButtonWithTitle:(const char *)title;
+- (NSButton *)createButtonWithTitle:(QPlatformDialogHelper::StandardButton)type;
- (void)layout;
@end
@@ -254,14 +229,16 @@ template <typename T>
struct objc_msgsend_requires_stret
{ static const bool value =
#if defined(Q_PROCESSOR_X86)
+ #define PLATFORM_USES_SEND_SUPER_STRET 1
// Any return value larger than two registers on i386/x86_64
sizeof(T) > sizeof(void*) * 2;
#elif defined(Q_PROCESSOR_ARM_32)
+ #define PLATFORM_USES_SEND_SUPER_STRET 1
// Any return value larger than a single register on arm
- sizeof(T) > sizeof(void*);
+ sizeof(T) > sizeof(void*);
#elif defined(Q_PROCESSOR_ARM_64)
- // Stret not used on arm64
- false;
+ #define PLATFORM_USES_SEND_SUPER_STRET 0
+ false; // Stret not used on arm64
#endif
};
@@ -281,6 +258,7 @@ ReturnType qt_msgSendSuper(id receiver, SEL selector, Args... args)
return superFn(&sup, selector, args...);
}
+#if PLATFORM_USES_SEND_SUPER_STRET
template <typename ReturnType, typename... Args>
ReturnType qt_msgSendSuper_stret(id receiver, SEL selector, Args... args)
{
@@ -295,6 +273,7 @@ ReturnType qt_msgSendSuper_stret(id receiver, SEL selector, Args... args)
superStretFn(&ret, &sup, selector, args...);
return ret;
}
+#endif
template<typename... Args>
class QSendSuperHelper {
@@ -335,11 +314,13 @@ private:
return qt_msgSendSuper<ReturnType>(m_receiver, m_selector, std::get<Is>(args)...);
}
+#if PLATFORM_USES_SEND_SUPER_STRET
template <typename ReturnType, int... Is>
if_requires_stret<ReturnType, true> msgSendSuper(std::tuple<Args...>& args, QtPrivate::IndexesList<Is...>)
{
return qt_msgSendSuper_stret<ReturnType>(m_receiver, m_selector, std::get<Is>(args)...);
}
+#endif
template <typename ReturnType>
ReturnType msgSendSuper(std::tuple<Args...>& args)
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index d36a7f6d09..2b1e512cf3 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -55,9 +55,6 @@
#include <algorithm>
-#include <mach-o/dyld.h>
-#include <dlfcn.h>
-
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
@@ -370,92 +367,6 @@ QString qt_mac_removeAmpersandEscapes(QString s)
return QPlatformTheme::removeMnemonics(s).trimmed();
}
-// -------------------------------------------------------------------------
-
-#if !defined(Q_PROCESSOR_X86_64)
-#error "32-bit builds are not supported"
-#endif
-
-QOperatingSystemVersion QMacVersion::buildSDK(VersionTarget target)
-{
- switch (target) {
- case ApplicationBinary: return applicationVersion().second;
- case QtLibraries: return libraryVersion().second;
- }
- Q_UNREACHABLE();
-}
-
-QOperatingSystemVersion QMacVersion::deploymentTarget(VersionTarget target)
-{
- switch (target) {
- case ApplicationBinary: return applicationVersion().first;
- case QtLibraries: return libraryVersion().first;
- }
- Q_UNREACHABLE();
-}
-
-QOperatingSystemVersion QMacVersion::currentRuntime()
-{
- return QOperatingSystemVersion::current();
-}
-
-QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machHeader)
-{
- static auto makeVersionTuple = [](uint32_t dt, uint32_t sdk) {
- return qMakePair(
- QOperatingSystemVersion(QOperatingSystemVersion::MacOS,
- dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff),
- QOperatingSystemVersion(QOperatingSystemVersion::MacOS,
- sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff)
- );
- };
-
- auto commandCursor = uintptr_t(machHeader) + sizeof(mach_header_64);
- for (uint32_t i = 0; i < machHeader->ncmds; ++i) {
- load_command *loadCommand = reinterpret_cast<load_command *>(commandCursor);
- if (loadCommand->cmd == LC_VERSION_MIN_MACOSX) {
- auto versionCommand = reinterpret_cast<version_min_command *>(loadCommand);
- return makeVersionTuple(versionCommand->version, versionCommand->sdk);
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13)
- } else if (loadCommand->cmd == LC_BUILD_VERSION) {
- auto versionCommand = reinterpret_cast<build_version_command *>(loadCommand);
- return makeVersionTuple(versionCommand->minos, versionCommand->sdk);
-#endif
- }
- commandCursor += loadCommand->cmdsize;
- }
- Q_ASSERT_X(false, "QCocoaIntegration", "Could not find any version load command");
- Q_UNREACHABLE();
-}
-
-QMacVersion::VersionTuple QMacVersion::applicationVersion()
-{
- static VersionTuple version = []() {
- const mach_header *executableHeader = nullptr;
- for (uint32_t i = 0; i < _dyld_image_count(); ++i) {
- auto header = _dyld_get_image_header(i);
- if (header->filetype == MH_EXECUTE) {
- executableHeader = header;
- break;
- }
- }
- Q_ASSERT_X(executableHeader, "QCocoaIntegration", "Failed to resolve Mach-O header of executable");
- return versionsForImage(executableHeader);
- }();
- return version;
-}
-
-QMacVersion::VersionTuple QMacVersion::libraryVersion()
-{
- static VersionTuple version = []() {
- Dl_info cocoaPluginImage;
- dladdr((const void *)&QMacVersion::libraryVersion, &cocoaPluginImage);
- Q_ASSERT_X(cocoaPluginImage.dli_fbase, "QCocoaIntegration", "Failed to resolve Mach-O header of Cocoa plugin");
- return versionsForImage(static_cast<mach_header*>(cocoaPluginImage.dli_fbase));
- }();
- return version;
-}
-
QT_END_NAMESPACE
/*! \internal
@@ -483,11 +394,10 @@ QT_END_NAMESPACE
{
if ((self = [super initWithFrame:NSZeroRect])) {
// create OK and Cancel buttons and add these as subviews
- _okButton = [self createButtonWithTitle:"&OK"];
+ _okButton = [self createButtonWithTitle:QPlatformDialogHelper::Ok];
_okButton.action = @selector(onOkClicked);
_okButton.target = panelDelegate;
-
- _cancelButton = [self createButtonWithTitle:"Cancel"];
+ _cancelButton = [self createButtonWithTitle:QPlatformDialogHelper::Cancel];
_cancelButton.action = @selector(onCancelClicked);
_cancelButton.target = panelDelegate;
@@ -511,12 +421,13 @@ QT_END_NAMESPACE
[super dealloc];
}
-- (NSButton *)createButtonWithTitle:(const char *)title
+- (NSButton *)createButtonWithTitle:(QPlatformDialogHelper::StandardButton)type
{
NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect];
button.buttonType = NSMomentaryLightButton;
button.bezelStyle = NSRoundedBezelStyle;
- const QString &cleanTitle = QPlatformTheme::removeMnemonics(QCoreApplication::translate("QDialogButtonBox", title));
+ const QString &cleanTitle =
+ QPlatformTheme::removeMnemonics(QGuiApplicationPrivate::platformTheme()->standardButtonText(type));
// FIXME: Not obvious, from Cocoa's documentation, that QString::toNSString() makes a deep copy
button.title = (NSString *)cleanTitle.toCFString();
((NSButtonCell *)button.cell).font =
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 597cfa8318..ed26d3afea 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -226,6 +226,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
r.moveCenter(fullHeightPixmap.rect().center());
p.drawPixmap(r, pixmap);
}
+ fullHeightPixmap.setDevicePixelRatio(devicePixelRatio);
NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(fullHeightPixmap));
[nsimage setTemplate:icon.isMask()];
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index a3120f4ccc..2a23bf286f 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -500,7 +500,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
NSUInteger styleMask = (frameless || !resizable) ? NSWindowStyleMaskBorderless : NSWindowStyleMaskResizable;
if (frameless) {
- // No further customizations for frameless since there are no window decorations.
+ // Frameless windows do not display the traffic lights buttons for
+ // e.g. minimize, however StyleMaskMiniaturizable is required to allow
+ // programatic minimize.
+ styleMask |= NSWindowStyleMaskMiniaturizable;
} else if (flags & Qt::CustomizeWindowHint) {
if (flags & Qt::WindowTitleHint)
styleMask |= NSWindowStyleMaskTitled;
@@ -1197,15 +1200,17 @@ void QCocoaWindow::windowDidResignKey()
if (isForeignWindow())
return;
- // Key window will be non-nil if another window became key, so do not
- // set the active window to zero here -- the new key window's
- // NSWindowDidBecomeKeyNotification hander will change the active window.
- NSWindow *keyWindow = [NSApp keyWindow];
- if (!keyWindow || keyWindow == m_view.window) {
- // No new key window, go ahead and set the active window to zero
- if (!windowIsPopupType())
- QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(0);
- }
+ // The current key window will be non-nil if another window became key. If that
+ // window is a Qt window, we delay the window activation event until the didBecomeKey
+ // notification is delivered to the active window, to ensure an atomic update.
+ NSWindow *newKeyWindow = [NSApp keyWindow];
+ if (newKeyWindow && newKeyWindow != m_view.window
+ && [newKeyWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
+ return;
+
+ // Lost key window, go ahead and set the active window to zero
+ if (!windowIsPopupType())
+ QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(nullptr);
}
void QCocoaWindow::windowDidOrderOnScreen()
diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h
index 872773cb7a..e070ba977d 100644
--- a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h
+++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h
@@ -48,9 +48,11 @@ QT_BEGIN_NAMESPACE
class QIOSurfaceGraphicsBuffer : public QPlatformGraphicsBuffer
{
public:
- QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace);
+ QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format);
~QIOSurfaceGraphicsBuffer();
+ void setColorSpace(QCFType<CGColorSpaceRef> colorSpace);
+
const uchar *data() const override;
uchar *data() override;
int bytesPerLine() const override;
diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm
index a367487e85..fc187e0f51 100644
--- a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm
+++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm
@@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaIOSurface, "qt.qpa.backingstore.iosurface");
-QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace)
+QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format)
: QPlatformGraphicsBuffer(size, format)
{
const size_t width = size.width();
@@ -81,17 +81,26 @@ QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPix
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()
{
}
+void QIOSurfaceGraphicsBuffer::setColorSpace(QCFType<CGColorSpaceRef> colorSpace)
+{
+ static const auto kIOSurfaceColorSpace = CFSTR("IOSurfaceColorSpace");
+
+ qCDebug(lcQpaIOSurface) << "Tagging" << this << "with color space" << colorSpace;
+
+ if (colorSpace) {
+ IOSurfaceSetValue(m_surface, kIOSurfaceColorSpace,
+ QCFType<CFPropertyListRef>(CGColorSpaceCopyPropertyList(colorSpace)));
+ } else {
+ IOSurfaceRemoveValue(m_surface, kIOSurfaceColorSpace);
+ }
+}
+
const uchar *QIOSurfaceGraphicsBuffer::data() const
{
return (const uchar *)IOSurfaceGetBaseAddress(m_surface);
diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm
index 116a9a73df..14e45a038e 100644
--- a/src/plugins/platforms/cocoa/qnsview_drawing.mm
+++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm
@@ -95,8 +95,15 @@
// by AppKit at a point where we've already set up other parts of the platform plugin
// based on the presence of layers or not. Once we've rewritten these parts to support
// dynamically picking up layer enablement we can let AppKit do its thing.
- return QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave
- && QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave;
+
+ if (QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSBigSur)
+ return true; // Big Sur always enables layer-backing, regardless of SDK
+
+ if (QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave
+ && QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave)
+ return true; // Mojave and Catalina enable layers based on the app's SDK
+
+ return false; // Prior versions needed explicitly enabled layer backing
}
- (BOOL)layerExplicitlyRequested
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index 6b4e110af2..8cff444359 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -227,14 +227,12 @@ static bool isMouseEvent(NSEvent *ev)
- (BOOL)canBecomeMainWindow
{
- BOOL canBecomeMain = YES; // By default, windows can become the main window
-
// Windows with a transient parent (such as combobox popup windows)
// cannot become the main window:
if (!m_platformWindow || m_platformWindow->window()->transientParent())
- canBecomeMain = NO;
+ return NO;
- return canBecomeMain;
+ return [super canBecomeMainWindow];
}
- (BOOL)worksWhenModal
@@ -255,8 +253,18 @@ static bool isMouseEvent(NSEvent *ev)
- (NSColor *)backgroundColor
{
- return self.styleMask == NSWindowStyleMaskBorderless ?
- [NSColor clearColor] : [super backgroundColor];
+ // FIXME: Plumb to a WA_NoSystemBackground-like window flag,
+ // or a QWindow::backgroundColor() property. In the meantime
+ // we assume that if you have translucent content, without a
+ // frame then you intend to do all background drawing yourself.
+ const QWindow *window = m_platformWindow ? m_platformWindow->window() : nullptr;
+ if (!self.opaque && window && window->flags().testFlag(Qt::FramelessWindowHint))
+ return [NSColor clearColor];
+
+ // This still allows you to have translucent content with a frame,
+ // where the system background (or color set via NSWindow) will
+ // shine through.
+ return [super backgroundColor];
}
- (void)sendEvent:(NSEvent*)theEvent
diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
index 81bad45cd2..dbfb0e6058 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
@@ -52,6 +52,7 @@
#include <QScreen>
#include <QDir>
#if QT_CONFIG(regularexpression)
+# include <QFileInfo>
# include <QRegularExpression>
#endif
#include <QLoggingCategory>
@@ -144,7 +145,12 @@ int QEglFSDeviceIntegration::framebufferIndex() const
int fbIndex = 0;
#if QT_CONFIG(regularexpression)
QRegularExpression fbIndexRx(QLatin1String("fb(\\d+)"));
- QRegularExpressionMatch match = fbIndexRx.match(QString::fromLocal8Bit(fbDeviceName()));
+ QFileInfo fbinfo(QString::fromLocal8Bit(fbDeviceName()));
+ QRegularExpressionMatch match;
+ if (fbinfo.isSymLink())
+ match = fbIndexRx.match(fbinfo.symLinkTarget());
+ else
+ match = fbIndexRx.match(fbinfo.fileName());
if (match.hasMatch())
fbIndex = match.captured(1).toInt();
#endif
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
index 20127ae7f7..8d0fb523c4 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
@@ -83,6 +83,8 @@ bool QEglFSKmsGbmDevice::open()
setFd(fd);
+ m_eventReader.create(this);
+
return true;
}
@@ -90,6 +92,8 @@ void QEglFSKmsGbmDevice::close()
{
// Note: screens are gone at this stage.
+ m_eventReader.destroy();
+
if (m_gbm_device) {
gbm_device_destroy(m_gbm_device);
m_gbm_device = nullptr;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
index f154520669..caa1187b40 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
@@ -54,8 +54,6 @@
QT_BEGIN_NAMESPACE
-QMutex QEglFSKmsGbmScreen::m_waitForFlipMutex;
-
QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration()
{
qCDebug(qLcEglfsKmsDebug, "New DRM/KMS via GBM integration created");
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 3a2951efbd..02b975fc75 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -110,7 +110,7 @@ QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(
return fb.take();
}
-QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QKmsDevice *device, const QKmsOutput &output, bool headless)
+QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless)
: QEglFSKmsScreen(device, output, headless)
, m_gbm_surface(nullptr)
, m_gbm_bo_current(nullptr)
@@ -243,7 +243,7 @@ void QEglFSKmsGbmScreen::ensureModeSet(uint32_t fb)
if (device()->hasAtomicSupport()) {
#if QT_CONFIG(drm_atomic)
- drmModeAtomicReq *request = device()->atomic_request();
+ drmModeAtomicReq *request = device()->threadLocalAtomicRequest();
if (request) {
drmModeAtomicAddProperty(request, op.connector_id, op.crtcIdPropertyId, op.crtc_id);
drmModeAtomicAddProperty(request, op.crtc_id, op.modeIdPropertyId, op.mode_blob_id);
@@ -276,19 +276,15 @@ void QEglFSKmsGbmScreen::waitForFlip()
if (!m_gbm_bo_next)
return;
- QMutexLocker lock(&m_waitForFlipMutex);
- while (m_gbm_bo_next) {
- drmEventContext drmEvent;
- memset(&drmEvent, 0, sizeof(drmEvent));
- drmEvent.version = 2;
- drmEvent.vblank_handler = nullptr;
- drmEvent.page_flip_handler = pageFlipHandler;
- drmHandleEvent(device()->fd(), &drmEvent);
- }
+ m_flipMutex.lock();
+ device()->eventReader()->startWaitFlip(this, &m_flipMutex, &m_flipCond);
+ m_flipCond.wait(&m_flipMutex);
+ m_flipMutex.unlock();
+
+ flipFinished();
#if QT_CONFIG(drm_atomic)
- if (device()->hasAtomicSupport())
- device()->atomicReset();
+ device()->threadLocalAtomicReset();
#endif
}
@@ -324,16 +320,16 @@ void QEglFSKmsGbmScreen::flip()
if (device()->hasAtomicSupport()) {
#if QT_CONFIG(drm_atomic)
- drmModeAtomicReq *request = device()->atomic_request();
+ drmModeAtomicReq *request = device()->threadLocalAtomicRequest();
if (request) {
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->framebufferPropertyId, fb->fb);
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcPropertyId, op.crtc_id);
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcwidthPropertyId,
- output().size.width() << 16);
+ op.size.width() << 16);
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcXPropertyId, 0);
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcYPropertyId, 0);
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcheightPropertyId,
- output().size.height() << 16);
+ op.size.height() << 16);
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcXPropertyId, 0);
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcYPropertyId, 0);
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcwidthPropertyId,
@@ -368,7 +364,7 @@ void QEglFSKmsGbmScreen::flip()
if (device()->hasAtomicSupport()) {
#if QT_CONFIG(drm_atomic)
- drmModeAtomicReq *request = device()->atomic_request();
+ drmModeAtomicReq *request = device()->threadLocalAtomicRequest();
if (request) {
drmModeAtomicAddProperty(request, d.screen->output().eglfs_plane->id,
d.screen->output().eglfs_plane->framebufferPropertyId, fb->fb);
@@ -391,22 +387,10 @@ void QEglFSKmsGbmScreen::flip()
}
#if QT_CONFIG(drm_atomic)
- if (device()->hasAtomicSupport())
- device()->atomicCommit(this);
+ device()->threadLocalAtomicCommit(this);
#endif
}
-void QEglFSKmsGbmScreen::pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
-{
- Q_UNUSED(fd);
- Q_UNUSED(sequence);
- Q_UNUSED(tv_sec);
- Q_UNUSED(tv_usec);
-
- QEglFSKmsGbmScreen *screen = static_cast<QEglFSKmsGbmScreen *>(user_data);
- screen->flipFinished();
-}
-
void QEglFSKmsGbmScreen::flipFinished()
{
if (m_cloneSource) {
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h
index b94f44b7b1..69feeee703 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h
@@ -43,7 +43,8 @@
#define QEGLFSKMSGBMSCREEN_H
#include "qeglfskmsscreen.h"
-#include <QtCore/QMutex>
+#include <QMutex>
+#include <QWaitCondition>
#include <gbm.h>
@@ -54,7 +55,7 @@ class QEglFSKmsGbmCursor;
class QEglFSKmsGbmScreen : public QEglFSKmsScreen
{
public:
- QEglFSKmsGbmScreen(QKmsDevice *device, const QKmsOutput &output, bool headless);
+ QEglFSKmsGbmScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless);
~QEglFSKmsGbmScreen();
QPlatformCursor *cursor() const override;
@@ -75,18 +76,15 @@ private:
void cloneDestFlipFinished(QEglFSKmsGbmScreen *cloneDestScreen);
void updateFlipStatus();
- static void pageFlipHandler(int fd,
- unsigned int sequence,
- unsigned int tv_sec,
- unsigned int tv_usec,
- void *user_data);
-
gbm_surface *m_gbm_surface;
gbm_bo *m_gbm_bo_current;
gbm_bo *m_gbm_bo_next;
bool m_flipPending;
+ QMutex m_flipMutex;
+ QWaitCondition m_flipCond;
+
QScopedPointer<QEglFSKmsGbmCursor> m_cursor;
struct FrameBuffer {
@@ -101,8 +99,6 @@ private:
bool cloneFlipPending = false;
};
QVector<CloneDestination> m_cloneDests;
-
- static QMutex m_waitForFlipMutex;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
index 1626c86239..5a62e437c4 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QKmsDevice *device, const QKmsOutput &output)
+QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsDevice *device, const QKmsOutput &output)
: QEglFSKmsScreen(device, output)
{
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
index 5efe35f8b3..961398ba3e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
class QEglFSKmsEglDeviceScreen : public QEglFSKmsScreen
{
public:
- QEglFSKmsEglDeviceScreen(QKmsDevice *device, const QKmsOutput &output);
+ QEglFSKmsEglDeviceScreen(QEglFSKmsDevice *device, const QKmsOutput &output);
~QEglFSKmsEglDeviceScreen();
QPlatformCursor *cursor() const override;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
index 40806b6a9b..e51903ed96 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
@@ -14,9 +14,11 @@ CONFIG += egl
SOURCES += $$PWD/qeglfskmsintegration.cpp \
$$PWD/qeglfskmsdevice.cpp \
- $$PWD/qeglfskmsscreen.cpp
+ $$PWD/qeglfskmsscreen.cpp \
+ $$PWD/qeglfskmseventreader.cpp
HEADERS += $$PWD/qeglfskmsintegration.h \
$$PWD/qeglfskmsdevice.h \
$$PWD/qeglfskmsscreen.h \
- $$PWD/qeglfskmshelpers.h
+ $$PWD/qeglfskmshelpers.h \
+ $$PWD/qeglfskmseventreader.h
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
index fc83a620d9..34908aa60f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
@@ -42,6 +42,7 @@
#define QEGLFSKMSDEVICE_H
#include "private/qeglfsglobal_p.h"
+#include "qeglfskmseventreader.h"
#include <QtKmsSupport/private/qkmsdevice_p.h>
QT_BEGIN_NAMESPACE
@@ -55,6 +56,11 @@ public:
bool isPrimary,
const QPoint &virtualPos,
const QList<QPlatformScreen *> &virtualSiblings) override;
+
+ QEglFSKmsEventReader *eventReader() { return &m_eventReader; }
+
+protected:
+ QEglFSKmsEventReader m_eventReader;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
new file mode 100644
index 0000000000..645a0ae2e9
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** 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 "qeglfskmseventreader.h"
+#include "qeglfskmsdevice.h"
+#include <QSocketNotifier>
+#include <QCoreApplication>
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
+
+static void pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+ Q_UNUSED(fd);
+ Q_UNUSED(sequence);
+ Q_UNUSED(tv_sec);
+ Q_UNUSED(tv_usec);
+
+ QEglFSKmsEventReaderThread *t = static_cast<QEglFSKmsEventReaderThread *>(QThread::currentThread());
+ t->eventHost()->handlePageFlipCompleted(user_data);
+}
+
+class RegisterWaitFlipEvent : public QEvent
+{
+public:
+ static const QEvent::Type TYPE = QEvent::Type(QEvent::User + 1);
+ RegisterWaitFlipEvent(void *key, QMutex *mutex, QWaitCondition *cond)
+ : QEvent(TYPE), key(key), mutex(mutex), cond(cond)
+ { }
+ void *key;
+ QMutex *mutex;
+ QWaitCondition *cond;
+};
+
+bool QEglFSKmsEventHost::event(QEvent *event)
+{
+ if (event->type() == RegisterWaitFlipEvent::TYPE) {
+ RegisterWaitFlipEvent *e = static_cast<RegisterWaitFlipEvent *>(event);
+ PendingFlipWait *p = &pendingFlipWaits[0];
+ PendingFlipWait *end = p + MAX_FLIPS;
+ while (p < end) {
+ if (!p->key) {
+ p->key = e->key;
+ p->mutex = e->mutex;
+ p->cond = e->cond;
+ updateStatus();
+ return true;
+ }
+ ++p;
+ }
+ qWarning("Cannot queue page flip wait (more than %d screens?)", MAX_FLIPS);
+ e->mutex->lock();
+ e->cond->wakeOne();
+ e->mutex->unlock();
+ return true;
+ }
+ return QObject::event(event);
+}
+
+void QEglFSKmsEventHost::updateStatus()
+{
+ void **begin = &completedFlips[0];
+ void **end = begin + MAX_FLIPS;
+
+ for (int i = 0; i < MAX_FLIPS; ++i) {
+ PendingFlipWait *w = pendingFlipWaits + i;
+ if (!w->key)
+ continue;
+
+ void **p = begin;
+ while (p < end) {
+ if (*p == w->key) {
+ *p = nullptr;
+ w->key = nullptr;
+ w->mutex->lock();
+ w->cond->wakeOne();
+ w->mutex->unlock();
+ return;
+ }
+ ++p;
+ }
+ }
+}
+
+void QEglFSKmsEventHost::handlePageFlipCompleted(void *key)
+{
+ void **begin = &completedFlips[0];
+ void **end = begin + MAX_FLIPS;
+ void **p = begin;
+ while (p < end) {
+ if (*p == key) {
+ updateStatus();
+ return;
+ }
+ ++p;
+ }
+ p = begin;
+ while (p < end) {
+ if (!*p) {
+ *p = key;
+ updateStatus();
+ return;
+ }
+ ++p;
+ }
+ qWarning("Cannot store page flip status (more than %d screens?)", MAX_FLIPS);
+}
+
+void QEglFSKmsEventReaderThread::run()
+{
+ qCDebug(qLcEglfsKmsDebug, "Event reader thread: entering event loop");
+
+ QSocketNotifier notifier(m_fd, QSocketNotifier::Read);
+ QObject::connect(&notifier, &QSocketNotifier::activated, &notifier, [this] {
+ drmEventContext drmEvent;
+ memset(&drmEvent, 0, sizeof(drmEvent));
+ drmEvent.version = 2;
+ drmEvent.vblank_handler = nullptr;
+ drmEvent.page_flip_handler = pageFlipHandler;
+ drmHandleEvent(m_fd, &drmEvent);
+ });
+
+ exec();
+
+ m_ev.moveToThread(thread()); // move back to the thread where m_ev was created
+
+ qCDebug(qLcEglfsKmsDebug, "Event reader thread: event loop stopped");
+}
+
+QEglFSKmsEventReader::~QEglFSKmsEventReader()
+{
+ destroy();
+}
+
+void QEglFSKmsEventReader::create(QEglFSKmsDevice *device)
+{
+ destroy();
+
+ if (!device)
+ return;
+
+ m_device = device;
+
+ qCDebug(qLcEglfsKmsDebug, "Initalizing event reader for device %p fd %d",
+ m_device, m_device->fd());
+
+ m_thread = new QEglFSKmsEventReaderThread(m_device->fd());
+ m_thread->start();
+
+ // Change thread affinity for the event host, so that postEvent()
+ // goes through the event reader thread's event loop for that object.
+ m_thread->eventHost()->moveToThread(m_thread);
+}
+
+void QEglFSKmsEventReader::destroy()
+{
+ if (!m_device)
+ return;
+
+ qCDebug(qLcEglfsKmsDebug, "Stopping event reader for device %p", m_device);
+
+ if (m_thread) {
+ m_thread->quit();
+ m_thread->wait();
+ delete m_thread;
+ m_thread = nullptr;
+ }
+
+ m_device = nullptr;
+}
+
+void QEglFSKmsEventReader::startWaitFlip(void *key, QMutex *mutex, QWaitCondition *cond)
+{
+ if (m_thread) {
+ QCoreApplication::postEvent(m_thread->eventHost(),
+ new RegisterWaitFlipEvent(key, mutex, cond));
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.h
new file mode 100644
index 0000000000..4aa285b0fe
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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 QEGLFSKKMSEVENTREADER_H
+#define QEGLFSKKMSEVENTREADER_H
+
+#include "private/qeglfsglobal_p.h"
+#include <QObject>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsDevice;
+
+struct QEglFSKmsEventHost : public QObject
+{
+ struct PendingFlipWait {
+ void *key;
+ QMutex *mutex;
+ QWaitCondition *cond;
+ };
+
+ static const int MAX_FLIPS = 32;
+ void *completedFlips[MAX_FLIPS] = {};
+ QEglFSKmsEventHost::PendingFlipWait pendingFlipWaits[MAX_FLIPS] = {};
+
+ bool event(QEvent *event) override;
+ void updateStatus();
+ void handlePageFlipCompleted(void *key);
+};
+
+class QEglFSKmsEventReaderThread : public QThread
+{
+public:
+ QEglFSKmsEventReaderThread(int fd) : m_fd(fd) { }
+ void run() override;
+ QEglFSKmsEventHost *eventHost() { return &m_ev; }
+
+private:
+ int m_fd;
+ QEglFSKmsEventHost m_ev;
+};
+
+class Q_EGLFS_EXPORT QEglFSKmsEventReader
+{
+public:
+ ~QEglFSKmsEventReader();
+
+ void create(QEglFSKmsDevice *device);
+ void destroy();
+
+ void startWaitFlip(void *key, QMutex *mutex, QWaitCondition *cond);
+
+private:
+ QEglFSKmsDevice *m_device = nullptr;
+ QEglFSKmsEventReaderThread *m_thread = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSKKMSEVENTREADER_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
index a6aac61506..28b6b7df63 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
@@ -140,7 +140,7 @@ void *QEglFSKmsIntegration::nativeResourceForIntegration(const QByteArray &name)
#if QT_CONFIG(drm_atomic)
if (name == QByteArrayLiteral("dri_atomic_request") && m_device)
- return (void *) (qintptr) m_device->atomic_request();
+ return (void *) (qintptr) m_device->threadLocalAtomicRequest();
#endif
return nullptr;
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
index e5354d97bd..b2ee7206aa 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qeglfskmsscreen.h"
+#include "qeglfskmsdevice.h"
#include "qeglfsintegration_p.h"
#include <QtCore/QLoggingCategory>
@@ -68,7 +69,7 @@ private:
QEglFSKmsScreen *m_screen;
};
-QEglFSKmsScreen::QEglFSKmsScreen(QKmsDevice *device, const QKmsOutput &output, bool headless)
+QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless)
: QEglFSScreen(static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->display())
, m_device(device)
, m_output(output)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
index 7f395aacb7..bbd929cba5 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
@@ -51,12 +51,13 @@
QT_BEGIN_NAMESPACE
+class QEglFSKmsDevice;
class QEglFSKmsInterruptHandler;
class Q_EGLFS_EXPORT QEglFSKmsScreen : public QEglFSScreen
{
public:
- QEglFSKmsScreen(QKmsDevice *device, const QKmsOutput &output, bool headless = false);
+ QEglFSKmsScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless = false);
~QEglFSKmsScreen();
void setVirtualPosition(const QPoint &pos);
@@ -87,7 +88,7 @@ public:
int currentMode() const override;
int preferredMode() const override;
- QKmsDevice *device() const { return m_device; }
+ QEglFSKmsDevice *device() const { return m_device; }
virtual void waitForFlip();
@@ -100,7 +101,7 @@ public:
void setPowerState(QPlatformScreen::PowerState state) override;
protected:
- QKmsDevice *m_device;
+ QEglFSKmsDevice *m_device;
QKmsOutput m_output;
QEdidParser m_edid;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp
index 475d9d55dd..c255bc84b7 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp
@@ -99,7 +99,7 @@ QEglFSKmsVsp2Screen::DmaBuffer *QEglFSKmsVsp2Screen::dmaBufferForGbmBuffer(gbm_b
return fb.take();
}
-QEglFSKmsVsp2Screen::QEglFSKmsVsp2Screen(QKmsDevice *device, const QKmsOutput &output)
+QEglFSKmsVsp2Screen::QEglFSKmsVsp2Screen(QEglFSKmsDevice *device, const QKmsOutput &output)
: QEglFSKmsScreen(device, output)
, m_blender(new Blender(this))
{
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h
index 7618510333..378786643d 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h
@@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE
class QEglFSKmsVsp2Screen : public QEglFSKmsScreen
{
public:
- QEglFSKmsVsp2Screen(QKmsDevice *device, const QKmsOutput &output);
+ QEglFSKmsVsp2Screen(QEglFSKmsDevice *device, const QKmsOutput &output);
gbm_surface *createSurface();
void resetSurface();
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp
index b8f04cf978..2d3f3ff25a 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp
@@ -44,12 +44,6 @@
QT_BEGIN_NAMESPACE
-#define MAX_NUM_OF_WFD_BUFFERS 3
-#define MAX_NUM_OF_WFD_DEVICES 4
-#define MAX_NUM_OF_WFD_PIPELINES 16
-#define MAX_NUM_OF_WFD_PORT_MODES 64
-#define MAX_NUM_OF_WFD_PORTS 4
-
typedef struct wfd_buffer {
WFD_EGLImageType* image;
WFDSource source;
@@ -78,8 +72,8 @@ void QEglFSOpenWFDIntegration::platformInit()
// Create device
WFDint dev_attribs[3] = {WFD_DEVICE_CLIENT_TYPE,
- WFD_CLIENT_ID_CLUSTER,
- WFD_NONE};
+ WFD_CLIENT_ID_CLUSTER,
+ WFD_NONE};
bool ok;
WFDint clientType = qgetenv("QT_OPENWFD_CLIENT_ID").toInt(&ok, 16);
@@ -123,99 +117,100 @@ void QEglFSOpenWFDIntegration::platformInit()
eError = wfdGetError(mDevice);
if (WFD_ERROR_NONE != eError)
qFatal("Failed to power on wfd port");
-}
-
-QSize QEglFSOpenWFDIntegration::screenSize() const
-{
- return mScreenSize;
-}
-
-EGLNativeDisplayType QEglFSOpenWFDIntegration::platformDisplay() const
-{
- return mNativeDisplay;
-}
-
-EGLNativeWindowType QEglFSOpenWFDIntegration::createNativeWindow(QPlatformWindow *window,
- const QSize &size,
- const QSurfaceFormat &format)
-{
- Q_UNUSED(window);
- Q_UNUSED(format);
// Get list of pipelines
WFDint numPipelines = wfdEnumeratePipelines(mDevice, nullptr, 0, nullptr);
-
WFDint pipelineIds[MAX_NUM_OF_WFD_PIPELINES];
wfdEnumeratePipelines(mDevice, pipelineIds, numPipelines, nullptr);
- bool ok;
WFDint pipelineId = qgetenv("QT_OPENWFD_PIPELINE_ID").toInt(&ok);
if (!ok)
pipelineId = pipelineIds[0];
- WFDPipeline pipeline = wfdCreatePipeline(mDevice, pipelineId, nullptr);
- if (WFD_INVALID_HANDLE == pipeline)
+ mPipeline = wfdCreatePipeline(mDevice, pipelineId, nullptr);
+ if (WFD_INVALID_HANDLE == mPipeline)
qFatal("Failed to create wfd pipeline");
- wfdSetPipelineAttribi(mDevice, pipeline, WFD_PIPELINE_TRANSPARENCY_ENABLE,
+ wfdSetPipelineAttribi(mDevice, mPipeline, WFD_PIPELINE_TRANSPARENCY_ENABLE,
(WFD_TRANSPARENCY_SOURCE_ALPHA|WFD_TRANSPARENCY_GLOBAL_ALPHA));
- WFDErrorCode eError = wfdGetError(mDevice);
+ eError = wfdGetError(mDevice);
if (WFD_ERROR_NONE != eError)
qFatal("Failed to set WFD_PIPELINE_TRANSPARENCY_ENABLE");
- wfdSetPipelineAttribi(mDevice, pipeline, WFD_PIPELINE_GLOBAL_ALPHA, 255);
+ wfdSetPipelineAttribi(mDevice, mPipeline, WFD_PIPELINE_GLOBAL_ALPHA, 255);
eError = wfdGetError(mDevice);
if (WFD_ERROR_NONE != eError)
qFatal("Failed to set WFD_PIPELINE_GLOBAL_ALPHA");
- wfdBindPipelineToPort(mDevice, mPort, pipeline);
+ wfdBindPipelineToPort(mDevice, mPort, mPipeline);
eError = wfdGetError(mDevice);
if (WFD_ERROR_NONE != eError)
qFatal("Failed to bind port to pipeline");
- // Create buffers
- WFDSource source[MAX_NUM_OF_WFD_BUFFERS] = {WFD_INVALID_HANDLE, WFD_INVALID_HANDLE,
- WFD_INVALID_HANDLE};
- WFDEGLImage eglImageHandles[MAX_NUM_OF_WFD_BUFFERS];
- WFD_EGLImageType* wfdEglImages[MAX_NUM_OF_WFD_BUFFERS];
for (int i = 0; i < MAX_NUM_OF_WFD_BUFFERS; i++) {
wfdCreateWFDEGLImages(mDevice, mScreenSize.width(), mScreenSize.height(),
WFD_FORMAT_RGBA8888, WFD_USAGE_OPENGL_ES2 | WFD_USAGE_DISPLAY,
- 1, &(eglImageHandles[i]), 0);
+ 1, &(mEGLImageHandles[i]), 0);
- wfdEglImages[i] = (WFD_EGLImageType *)(eglImageHandles[i]);
- if (WFD_INVALID_HANDLE == wfdEglImages[i])
+ mWFDEglImages[i] = (WFD_EGLImageType *)(mEGLImageHandles[i]);
+ if (WFD_INVALID_HANDLE == mWFDEglImages[i])
qFatal("Failed to create WDFEGLImages");
- source[i] = wfdCreateSourceFromImage(mDevice, pipeline, eglImageHandles[i], nullptr);
- if (WFD_INVALID_HANDLE == source[i])
+ mSources[i] = wfdCreateSourceFromImage(mDevice, mPipeline, mEGLImageHandles[i], nullptr);
+ if (WFD_INVALID_HANDLE == mSources[i])
qFatal("Failed to create source from EGLImage");
}
+}
- // Commit port
- wfdDeviceCommit(mDevice, WFD_COMMIT_ENTIRE_PORT, mPort);
- eError = wfdGetError(mDevice);
- if (WFD_ERROR_NONE != eError)
- qFatal("Failed to commit port");
+QSize QEglFSOpenWFDIntegration::screenSize() const
+{
+ return mScreenSize;
+}
+
+EGLNativeDisplayType QEglFSOpenWFDIntegration::platformDisplay() const
+{
+ return mNativeDisplay;
+}
+
+EGLNativeWindowType QEglFSOpenWFDIntegration::createNativeWindow(QPlatformWindow *window,
+ const QSize &size,
+ const QSurfaceFormat &format)
+{
+ Q_UNUSED(window);
+ Q_UNUSED(format);
// Create native window
wfd_window_t* nativeWindow = (wfd_window_t*)malloc(sizeof(wfd_window_t));
if (nullptr == nativeWindow)
- qFatal("Failed to allocate memory for native window");
+ qFatal("Failed to allocate memory for native window");
nativeWindow->dev = mDevice;
nativeWindow->port = mPort;
- nativeWindow->pipeline = pipeline;
+ nativeWindow->pipeline = mPipeline;
nativeWindow->numBuffers = MAX_NUM_OF_WFD_BUFFERS;
+ WFDErrorCode eError;
+
for (int i = 0; i < MAX_NUM_OF_WFD_BUFFERS; i++) {
- nativeWindow->buffers[i].image = wfdEglImages[i];
- nativeWindow->buffers[i].source = source[i];
+ nativeWindow->buffers[i].image = mWFDEglImages[i];
+ nativeWindow->buffers[i].source = mSources[i];
+ wfdBindSourceToPipeline(nativeWindow->dev, nativeWindow->pipeline, nativeWindow->buffers[i].source , WFD_TRANSITION_AT_VSYNC, nullptr);
+ eError = wfdGetError(nativeWindow->dev);
+ if (WFD_ERROR_NONE != eError)
+ {
+ qFatal("wfdBindSourceToPipeline eError=0x%08x", eError);
+ }
}
+ // Commit port
+ wfdDeviceCommit(mDevice, WFD_COMMIT_ENTIRE_PORT, mPort);
+ eError = wfdGetError(mDevice);
+ if (WFD_ERROR_NONE != eError)
+ qFatal("Failed to commit port");
+
return (EGLNativeWindowType)nativeWindow;
}
@@ -231,6 +226,13 @@ QSurfaceFormat QEglFSOpenWFDIntegration::surfaceFormatFor(const QSurfaceFormat &
void QEglFSOpenWFDIntegration::destroyNativeWindow(EGLNativeWindowType window)
{
+ wfdBindSourceToPipeline(mDevice, ((wfd_window_t*)window)->pipeline, nullptr, WFD_TRANSITION_IMMEDIATE, nullptr);
+
+ for (int i = 0; i < MAX_NUM_OF_WFD_BUFFERS; i++) {
+ wfdDestroySource(mDevice, mSources[i]);
+ wfdDestroyWFDEGLImages(mDevice, 1, &mEGLImageHandles[i]);
+ }
+
free((void*)window);
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h
index 189ddd4d7a..53d9cffaf2 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h
@@ -47,6 +47,12 @@
QT_BEGIN_NAMESPACE
+#define MAX_NUM_OF_WFD_BUFFERS 3
+#define MAX_NUM_OF_WFD_DEVICES 4
+#define MAX_NUM_OF_WFD_PIPELINES 16
+#define MAX_NUM_OF_WFD_PORT_MODES 64
+#define MAX_NUM_OF_WFD_PORTS 4
+
class QEglFSOpenWFDIntegration : public QEglFSDeviceIntegration
{
public:
@@ -62,6 +68,10 @@ private:
EGLNativeDisplayType mNativeDisplay;
WFDDevice mDevice;
WFDPort mPort;
+ WFDPipeline mPipeline;
+ WFDSource mSources[MAX_NUM_OF_WFD_BUFFERS] = {WFD_INVALID_HANDLE, WFD_INVALID_HANDLE, WFD_INVALID_HANDLE};
+ WFD_EGLImageType* mWFDEglImages[MAX_NUM_OF_WFD_BUFFERS];
+ WFDEGLImage mEGLImageHandles[MAX_NUM_OF_WFD_BUFFERS];
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index 535e7d7aa6..cecbb17039 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -332,11 +332,8 @@ bool QIOSContext::verifyGraphicsHardwareAvailability()
);
});
- if (applicationBackgrounded) {
- static const char warning[] = "OpenGL ES calls are not allowed while an application is backgrounded";
- Q_ASSERT_X(!applicationBackgrounded, "QIOSContext", warning);
- qCWarning(lcQpaGLContext, warning);
- }
+ if (applicationBackgrounded)
+ qCWarning(lcQpaGLContext, "OpenGL ES calls are not allowed while an application is backgrounded");
return !applicationBackgrounded;
}
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index 396c769be8..1bc9744528 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -781,12 +781,16 @@
- (UIView *)textInputView
{
+ auto *focusWindow = QGuiApplication::focusWindow();
+ if (!focusWindow)
+ return nil;
+
// iOS expects rects we return from other UITextInput methods
// to be relative to the view this method returns.
// Since QInputMethod returns rects relative to the top level
// QWindow, that is also the view we need to return.
- Q_ASSERT(qApp->focusWindow()->handle());
- QPlatformWindow *topLevel = qApp->focusWindow()->handle();
+ Q_ASSERT(focusWindow->handle());
+ QPlatformWindow *topLevel = focusWindow->handle();
while (QPlatformWindow *p = topLevel->parent())
topLevel = p;
return reinterpret_cast<UIView *>(topLevel->winId());
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm
index 3154536aad..4dd1f9f035 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.mm
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm
@@ -123,8 +123,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
if (val) {
return val->currentValue().toString().toNSString();
} else if (QAccessibleTextInterface *text = iface->textInterface()) {
- // FIXME doesn't work?
- return text->text(0, text->characterCount() - 1).toNSString();
+ return text->text(0, text->characterCount()).toNSString();
}
return [super accessibilityHint];
@@ -158,8 +157,16 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
if (state.searchEdit)
traits |= UIAccessibilityTraitSearchField;
- if (iface->role() == QAccessible::Button)
+ const auto accessibleRole = iface->role();
+ if (accessibleRole == QAccessible::Button) {
traits |= UIAccessibilityTraitButton;
+ } else if (accessibleRole == QAccessible::EditableText) {
+ static auto defaultTextFieldTraits = []{
+ auto *textField = [[[UITextField alloc] initWithFrame:CGRectZero] autorelease];
+ return textField.accessibilityTraits;
+ }();
+ traits |= defaultTextFieldTraits;
+ }
if (iface->valueInterface())
traits |= UIAccessibilityTraitAdjustable;
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index 962b1d929f..dca113abdd 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -56,7 +56,7 @@
Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
@implementation QUIView {
- QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches;
+ QHash<NSUInteger, QWindowSystemInterface::TouchPoint> m_activeTouches;
UITouch *m_activePencilTouch;
int m_nextTouchId;
NSMutableArray<UIAccessibilityElement *> *m_accessibleElements;
@@ -403,9 +403,19 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
}
#endif
- for (UITouch *uiTouch : m_activeTouches.keys()) {
- QWindowSystemInterface::TouchPoint &touchPoint = m_activeTouches[uiTouch];
- if (![touches containsObject:uiTouch]) {
+ if (m_activeTouches.isEmpty())
+ return;
+ for (auto it = m_activeTouches.begin(); it != m_activeTouches.end(); ++it) {
+ auto hash = it.key();
+ QWindowSystemInterface::TouchPoint &touchPoint = it.value();
+ UITouch *uiTouch = nil;
+ for (UITouch *touch in touches) {
+ if (touch.hash == hash) {
+ uiTouch = touch;
+ break;
+ }
+ }
+ if (!uiTouch) {
touchPoint.state = Qt::TouchPointStationary;
} else {
touchPoint.state = state;
@@ -437,8 +447,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
}
}
}
- if (m_activeTouches.isEmpty())
- return;
if ([self.window isKindOfClass:[QUIWindow class]] &&
!static_cast<QUIWindow *>(self.window).sendingEvent) {
@@ -474,9 +482,9 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
m_activePencilTouch = touch;
} else
{
- Q_ASSERT(!m_activeTouches.contains(touch));
+ Q_ASSERT(!m_activeTouches.contains(touch.hash));
#endif
- m_activeTouches[touch].id = m_nextTouchId++;
+ m_activeTouches[touch.hash].id = m_nextTouchId++;
#if QT_CONFIG(tabletevent)
}
#endif
@@ -503,6 +511,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
[self handleTouches:touches withEvent:event withState:Qt::TouchPointReleased withTimestamp:ulong(event.timestamp * 1000)];
// Remove ended touch points from the active set:
+#ifndef Q_OS_TVOS
for (UITouch *touch in touches) {
#if QT_CONFIG(tabletevent)
if (touch.type == UITouchTypeStylus) {
@@ -510,9 +519,14 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
} else
#endif
{
- m_activeTouches.remove(touch);
+ m_activeTouches.remove(touch.hash);
}
}
+#else
+ // tvOS only supports single touch
+ m_activeTouches.clear();
+#endif
+
if (m_activeTouches.isEmpty() && !m_activePencilTouch)
m_nextTouchId = 0;
}
@@ -630,10 +644,8 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (void)addInteraction:(id<UIInteraction>)interaction
{
- if (__builtin_available(iOS 13.0, *)) {
- if ([interaction isKindOfClass:UITextInteraction.class])
- return; // Prevent iOS from adding UITextInteraction
- }
+ if ([NSStringFromClass(interaction.class) isEqualToString:@"UITextInteraction"])
+ return;
[super addInteraction:interaction];
}
diff --git a/src/plugins/platforms/vnc/qvnc.cpp b/src/plugins/platforms/vnc/qvnc.cpp
index ffe00de2b1..43fbc9daf7 100644
--- a/src/plugins/platforms/vnc/qvnc.cpp
+++ b/src/plugins/platforms/vnc/qvnc.cpp
@@ -477,6 +477,9 @@ void QRfbRawEncoder::write()
// server->screen()->geometry().height());
// }
+ const QImage screenImage = client->server()->screenImage();
+ rgn &= screenImage.rect();
+
const auto rectsInRegion = rgn.rectCount();
{
@@ -492,8 +495,6 @@ void QRfbRawEncoder::write()
if (rectsInRegion <= 0)
return;
- const QImage screenImage = client->server()->screenImage();
-
for (const QRect &tileRect: rgn) {
const QRfbRect rect(tileRect.x(), tileRect.y(),
tileRect.width(), tileRect.height());
diff --git a/src/plugins/platforms/vnc/qvncscreen.cpp b/src/plugins/platforms/vnc/qvncscreen.cpp
index 67d33de2f0..7f418c4e37 100644
--- a/src/plugins/platforms/vnc/qvncscreen.cpp
+++ b/src/plugins/platforms/vnc/qvncscreen.cpp
@@ -139,6 +139,9 @@ void QVncScreen::enableClientCursor(QVncClient *client)
void QVncScreen::disableClientCursor(QVncClient *client)
{
#if QT_CONFIG(cursor)
+ if (!clientCursor)
+ return;
+
uint clientCount = clientCursor->removeClient(client);
if (clientCount == 0) {
delete clientCursor;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index febc30c325..adf0f918ca 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1879,12 +1879,13 @@ void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode)
if (newScreen == nullptr || newScreen == currentScreen)
return;
// For screens with different DPI: postpone until WM_DPICHANGE
- if (mode == FromGeometryChange
+ // Check on currentScreen as it can be 0 when resuming a session (QTBUG-80436).
+ if (mode == FromGeometryChange && currentScreen != nullptr
&& !equalDpi(currentScreen->logicalDpi(), newScreen->logicalDpi())) {
return;
}
qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__
- << ' ' << window() << " \"" << currentScreen->name()
+ << ' ' << window() << " \"" << (currentScreen ? currentScreen->name() : QString())
<< "\"->\"" << newScreen->name() << '"';
if (mode == FromGeometryChange)
setFlag(SynchronousGeometryChangeEvent);
@@ -2074,6 +2075,7 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt,
QWindowsWindowData result = m_data;
result.flags = creationData.flags;
result.embedded = creationData.embedded;
+ result.hasFrame = (creationData.style & (WS_DLGFRAME | WS_THICKFRAME));
return result;
}
diff --git a/src/plugins/platforms/xcb/qxcbatom.cpp b/src/plugins/platforms/xcb/qxcbatom.cpp
index ecb73cb90b..a73d28319d 100644
--- a/src/plugins/platforms/xcb/qxcbatom.cpp
+++ b/src/plugins/platforms/xcb/qxcbatom.cpp
@@ -122,6 +122,7 @@ static const char *xcb_atomnames = {
"_NET_WM_STATE_MODAL\0"
"_NET_WM_STATE_STAYS_ON_TOP\0"
"_NET_WM_STATE_DEMANDS_ATTENTION\0"
+ "_NET_WM_STATE_HIDDEN\0"
"_NET_WM_USER_TIME\0"
"_NET_WM_USER_TIME_WINDOW\0"
@@ -181,6 +182,7 @@ static const char *xcb_atomnames = {
"XdndActionCopy\0"
"XdndActionLink\0"
"XdndActionMove\0"
+ "XdndActionAsk\0"
"XdndActionPrivate\0"
// Xkb
diff --git a/src/plugins/platforms/xcb/qxcbatom.h b/src/plugins/platforms/xcb/qxcbatom.h
index 233d2eadb7..9cf93ec314 100644
--- a/src/plugins/platforms/xcb/qxcbatom.h
+++ b/src/plugins/platforms/xcb/qxcbatom.h
@@ -123,6 +123,7 @@ public:
_NET_WM_STATE_MODAL,
_NET_WM_STATE_STAYS_ON_TOP,
_NET_WM_STATE_DEMANDS_ATTENTION,
+ _NET_WM_STATE_HIDDEN,
_NET_WM_USER_TIME,
_NET_WM_USER_TIME_WINDOW,
@@ -182,6 +183,7 @@ public:
XdndActionCopy,
XdndActionLink,
XdndActionMove,
+ XdndActionAsk,
XdndActionPrivate,
// Xkb
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index f9240a45cc..32739b3572 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -709,9 +709,10 @@ void QXcbBackingStoreImage::put(xcb_drawable_t dst, const QRegion &region, const
Q_ASSERT(!m_clientSideScroll);
ensureGC(dst);
- setClip(region);
if (hasShm()) {
+ setClip(region); // Clip in window local coordinates
+
// Copy scrolled area on server-side from pixmap to window
const QRegion scrolledRegion = m_scrolledRegion.translated(-offset);
for (const QRect &rect : scrolledRegion) {
@@ -732,7 +733,15 @@ void QXcbBackingStoreImage::put(xcb_drawable_t dst, const QRegion &region, const
const QRect bounds = region.boundingRect();
const QPoint target = bounds.topLeft();
const QRect source = bounds.translated(offset);
- flushPixmap(region);
+
+ // First clip in backingstore-local coordinates, and upload
+ // the changed parts of the backingstore to the server.
+ setClip(source);
+ flushPixmap(source);
+
+ // Then clip in window local coordinates, and copy the updated
+ // parts of the backingstore image server-side to the window.
+ setClip(region);
xcb_copy_area(xcb_connection(),
m_xcb_pixmap,
dst,
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index ac8b029916..a4940f1c49 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -787,6 +787,12 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i
if (e) // found the waited for event
return e;
+ // It is safe to assume here that the pointed to node won't be re-used
+ // while we are holding the pointer to it. The nodes can be recycled
+ // only when they are dequeued, which is done only by
+ // QXcbConnection::processXcbEvents().
+ const QXcbEventNode *flushedTailNode = queue->flushedTail();
+
if (checkManager) {
auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER));
if (!reply || reply->owner == XCB_NONE)
@@ -812,7 +818,7 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i
const auto elapsed = timer.elapsed();
if (elapsed < clipboard_timeout)
- queue->waitForNewEvents(clipboard_timeout - elapsed);
+ queue->waitForNewEvents(flushedTailNode, clipboard_timeout - elapsed);
} while (timer.elapsed() < clipboard_timeout);
return nullptr;
@@ -835,6 +841,8 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
alloc_error = buf.size() != nbytes+1;
}
+ QElapsedTimer timer;
+ timer.start();
for (;;) {
connection()->flush();
xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY);
@@ -870,9 +878,11 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
tmp_buf.resize(0);
offset += length;
}
- } else {
- break;
}
+
+ const auto elapsed = timer.elapsed();
+ if (elapsed > clipboard_timeout)
+ break;
}
// timed out ... create a new requestor window, otherwise the requestor
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 0d71a5a552..8f0281c176 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -774,7 +774,10 @@ xcb_timestamp_t QXcbConnection::getTimestamp()
xcb_generic_event_t *event = nullptr;
- while (!event) {
+ // When disconnection is caused by X server, event will never be able to hold
+ // a valid pointer. isConnected(), which calls xcb_connection_has_error(),
+ // can handle this type of disconnection and properly quits the loop.
+ while (isConnected() && !event) {
connection()->sync();
event = eventQueue()->peek([window, dummyAtom](xcb_generic_event_t *event, int type) {
if (type != XCB_PROPERTY_NOTIFY)
@@ -784,6 +787,14 @@ xcb_timestamp_t QXcbConnection::getTimestamp()
});
}
+ if (!event) {
+ // https://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#glossary
+ // > One timestamp value (named CurrentTime) is never generated by the
+ // > server. This value is reserved for use in requests to represent the
+ // > current server time.
+ return XCB_CURRENT_TIME;
+ }
+
xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event);
xcb_timestamp_t timestamp = pn->time;
free(event);
@@ -795,7 +806,13 @@ xcb_timestamp_t QXcbConnection::getTimestamp()
xcb_window_t QXcbConnection::getSelectionOwner(xcb_atom_t atom) const
{
- return Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom)->owner;
+ auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom);
+ if (!reply) {
+ qCDebug(lcQpaXcb) << "failed to query selection owner";
+ return XCB_NONE;
+ }
+
+ return reply->owner;
}
xcb_window_t QXcbConnection::getQtSelectionOwner()
diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp
index af72285135..bdd7e2d98a 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp
@@ -183,7 +183,13 @@ xcb_atom_t QXcbBasicConnection::internAtom(const char *name)
if (!name || *name == 0)
return XCB_NONE;
- return Q_XCB_REPLY(xcb_intern_atom, m_xcbConnection, false, strlen(name), name)->atom;
+ auto reply = Q_XCB_REPLY(xcb_intern_atom, m_xcbConnection, false, strlen(name), name);
+ if (!reply) {
+ qCDebug(lcQpaXcb) << "failed to query intern atom: " << name;
+ return XCB_NONE;
+ }
+
+ return reply->atom;
}
QByteArray QXcbBasicConnection::atomName(xcb_atom_t atom)
diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
index 4e631beb25..9eb365597b 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
@@ -290,6 +290,8 @@ void QXcbConnection::initializeScreens()
// RRGetScreenResources in this case.
auto resources_current = Q_XCB_REPLY(xcb_randr_get_screen_resources_current,
xcb_connection(), xcbScreen->root);
+ decltype(Q_XCB_REPLY(xcb_randr_get_screen_resources,
+ xcb_connection(), xcbScreen->root)) resources;
if (!resources_current) {
qWarning("failed to get the current screen resources");
} else {
@@ -300,8 +302,8 @@ void QXcbConnection::initializeScreens()
timestamp = resources_current->config_timestamp;
outputs = xcb_randr_get_screen_resources_current_outputs(resources_current.get());
} else {
- auto resources = Q_XCB_REPLY(xcb_randr_get_screen_resources,
- xcb_connection(), xcbScreen->root);
+ resources = Q_XCB_REPLY(xcb_randr_get_screen_resources,
+ xcb_connection(), xcbScreen->root);
if (!resources) {
qWarning("failed to get the screen resources");
} else {
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index 1ce947165d..602e06adab 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -216,6 +216,22 @@ void QXcbDrag::endDrag()
initiatorWindow.clear();
}
+Qt::DropAction QXcbDrag::defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const
+{
+ if (currentDrag() || drop_actions.isEmpty())
+ return QBasicDrag::defaultAction(possibleActions, modifiers);
+
+ return toDropAction(drop_actions.first());
+}
+
+void QXcbDrag::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event)
+{
+ if (event->window != xdnd_dragsource || event->atom != atom(QXcbAtom::XdndActionList))
+ return;
+
+ readActionList();
+}
+
static
bool windowInteractsWithPosition(xcb_connection_t *connection, const QPoint & pos, xcb_window_t w, xcb_shape_sk_t shapeType)
{
@@ -465,16 +481,20 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod
move.data.data32[1] = 0; // flags
move.data.data32[2] = (globalPos.x() << 16) + globalPos.y();
move.data.data32[3] = connection()->time();
- move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), mods));
+ const auto supportedActions = currentDrag()->supportedActions();
+ const auto requestedAction = defaultAction(supportedActions, mods);
+ move.data.data32[4] = toXdndAction(requestedAction);
qCDebug(lcQpaXDnd) << "sending XdndPosition to target:" << target;
source_time = connection()->time();
- if (w)
+ if (w) {
handle_xdnd_position(w, &move, b, mods);
- else
+ } else {
+ setActionList(requestedAction, supportedActions);
xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move);
+ }
}
static const bool isUnity = qgetenv("XDG_CURRENT_DESKTOP").toLower() == "unity";
@@ -555,6 +575,16 @@ Qt::DropAction QXcbDrag::toDropAction(xcb_atom_t a) const
return Qt::CopyAction;
}
+Qt::DropActions QXcbDrag::toDropActions(const QVector<xcb_atom_t> &atoms) const
+{
+ Qt::DropActions actions;
+ for (const auto actionAtom : atoms) {
+ if (actionAtom != atom(QXcbAtom::XdndActionAsk))
+ actions |= toDropAction(actionAtom);
+ }
+ return actions;
+}
+
xcb_atom_t QXcbDrag::toXdndAction(Qt::DropAction a) const
{
switch (a) {
@@ -572,6 +602,60 @@ xcb_atom_t QXcbDrag::toXdndAction(Qt::DropAction a) const
}
}
+void QXcbDrag::readActionList()
+{
+ drop_actions.clear();
+ auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, xdnd_dragsource,
+ atom(QXcbAtom::XdndActionList), XCB_ATOM_ATOM,
+ 0, 1024);
+ if (reply && reply->type != XCB_NONE && reply->format == 32) {
+ int length = xcb_get_property_value_length(reply.get()) / 4;
+
+ xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply.get());
+ for (int i = 0; i < length; ++i)
+ drop_actions.append(atoms[i]);
+ }
+}
+
+void QXcbDrag::setActionList(Qt::DropAction requestedAction, Qt::DropActions supportedActions)
+{
+#ifndef QT_NO_CLIPBOARD
+ QVector<xcb_atom_t> actions;
+ if (requestedAction != Qt::IgnoreAction)
+ actions.append(toXdndAction(requestedAction));
+
+ auto checkAppend = [this, requestedAction, supportedActions, &actions](Qt::DropAction action) {
+ if (requestedAction != action && supportedActions & action)
+ actions.append(toXdndAction(action));
+ };
+
+ checkAppend(Qt::CopyAction);
+ checkAppend(Qt::MoveAction);
+ checkAppend(Qt::LinkAction);
+
+ if (current_actions != actions) {
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->clipboard()->owner(),
+ atom(QXcbAtom::XdndActionList),
+ XCB_ATOM_ATOM, 32, actions.size(), actions.constData());
+ current_actions = actions;
+ }
+#endif
+}
+
+void QXcbDrag::startListeningForActionListChanges()
+{
+ connection()->addWindowEventListener(xdnd_dragsource, this);
+ const uint32_t event_mask[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
+ xcb_change_window_attributes(xcb_connection(), xdnd_dragsource, XCB_CW_EVENT_MASK, event_mask);
+}
+
+void QXcbDrag::stopListeningForActionListChanges()
+{
+ const uint32_t event_mask[] = { XCB_EVENT_MASK_NO_EVENT };
+ xcb_change_window_attributes(xcb_connection(), xdnd_dragsource, XCB_CW_EVENT_MASK, event_mask);
+ connection()->removeWindowEventListener(xdnd_dragsource);
+}
+
int QXcbDrag::findTransactionByWindow(xcb_window_t window)
{
int at = -1;
@@ -652,6 +736,9 @@ void QXcbDrag::handleEnter(QPlatformWindow *, const xcb_client_message_event_t *
return;
xdnd_dragsource = event->data.data32[0];
+ startListeningForActionListChanges();
+ readActionList();
+
if (!proxy)
proxy = xdndProxy(connection(), xdnd_dragsource);
current_proxy_target = proxy ? proxy : xdnd_dragsource;
@@ -718,7 +805,9 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
supported_actions = currentDrag()->supportedActions();
} else {
dropData = m_dropData;
- supported_actions = Qt::DropActions(toDropAction(e->data.data32[4]));
+ supported_actions = toDropActions(drop_actions);
+ if (e->data.data32[4] != atom(QXcbAtom::XdndActionAsk))
+ supported_actions |= Qt::DropActions(toDropAction(e->data.data32[4]));
}
auto buttons = currentDrag() ? b : connection()->queryMouseButtons();
@@ -862,8 +951,10 @@ void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t
// If the target receives XdndLeave, it frees any cached data and forgets the whole incident.
qCDebug(lcQpaXDnd) << "target:" << event->window << "received XdndLeave";
- if (!currentWindow || w != currentWindow.data()->handle())
+ if (!currentWindow || w != currentWindow.data()->handle()) {
+ stopListeningForActionListChanges();
return; // sanity
+ }
// ###
// if (checkEmbedded(current_embedding_widget, event)) {
@@ -878,6 +969,8 @@ void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t
event->data.data32[0], xdnd_dragsource);
}
+ stopListeningForActionListChanges();
+
QWindowSystemInterface::handleDrag(w->window(), nullptr, QPoint(), Qt::IgnoreAction, 0, 0);
}
@@ -924,6 +1017,7 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
qCDebug(lcQpaXDnd) << "target:" << event->window << "received XdndDrop";
if (!currentWindow) {
+ stopListeningForActionListChanges();
xdnd_dragsource = 0;
return; // sanity
}
@@ -946,7 +1040,7 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
supported_drop_actions = Qt::DropActions(l[4]);
} else {
dropData = m_dropData;
- supported_drop_actions = accepted_drop_action;
+ supported_drop_actions = accepted_drop_action | toDropActions(drop_actions);
}
if (!dropData)
@@ -981,6 +1075,8 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
xcb_send_event(xcb_connection(), false, current_proxy_target,
XCB_EVENT_MASK_NO_EVENT, (char *)&finished);
+ stopListeningForActionListChanges();
+
dropped = true;
}
diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h
index c19008c04b..aedfc90d2c 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.h
+++ b/src/plugins/platforms/xcb/qxcbdrag.h
@@ -68,7 +68,7 @@ class QXcbScreen;
class QDrag;
class QShapedPixmapWindow;
-class QXcbDrag : public QXcbObject, public QBasicDrag
+class QXcbDrag : public QXcbObject, public QBasicDrag, public QXcbWindowEventListener
{
public:
QXcbDrag(QXcbConnection *c);
@@ -82,6 +82,10 @@ public:
void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
void endDrag() override;
+ Qt::DropAction defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const override;
+
+ void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override;
+
void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy = 0);
void handlePosition(QPlatformWindow *w, const xcb_client_message_event_t *event);
void handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event);
@@ -114,8 +118,14 @@ private:
void send_leave();
Qt::DropAction toDropAction(xcb_atom_t atom) const;
+ Qt::DropActions toDropActions(const QVector<xcb_atom_t> &atoms) const;
xcb_atom_t toXdndAction(Qt::DropAction a) const;
+ void readActionList();
+ void setActionList(Qt::DropAction requestedAction, Qt::DropActions supportedActions);
+ void startListeningForActionListChanges();
+ void stopListeningForActionListChanges();
+
QPointer<QWindow> initiatorWindow;
QPointer<QWindow> currentWindow;
QPoint currentPosition;
@@ -159,6 +169,9 @@ private:
QVector<xcb_atom_t> drag_types;
+ QVector<xcb_atom_t> current_actions;
+ QVector<xcb_atom_t> drop_actions;
+
struct Transaction
{
xcb_timestamp_t timestamp;
diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp
index 4ca73e3048..b96bda3194 100644
--- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp
+++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp
@@ -226,6 +226,8 @@ void QXcbEventQueue::run()
};
while (!m_closeConnectionDetected && (event = xcb_wait_for_event(connection))) {
+ // This lock can block only if there are users of waitForNewEvents().
+ // Currently only the clipboard implementation relies on it.
m_newEventsMutex.lock();
enqueueEvent(event);
while (!m_closeConnectionDetected && (event = xcb_poll_for_queued_event(connection)))
@@ -350,12 +352,12 @@ bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData,
return result;
}
-void QXcbEventQueue::waitForNewEvents(unsigned long time)
+void QXcbEventQueue::waitForNewEvents(const QXcbEventNode *sinceFlushedTail,
+ unsigned long time)
{
QMutexLocker locker(&m_newEventsMutex);
- QXcbEventNode *tailBeforeFlush = m_flushedTail;
flushBufferedEvents();
- if (tailBeforeFlush != m_flushedTail)
+ if (sinceFlushedTail != m_flushedTail)
return;
m_newEventsCondition.wait(&m_newEventsMutex, time);
}
diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h
index 11d0b8e963..c8f09ed9e3 100644
--- a/src/plugins/platforms/xcb/qxcbeventqueue.h
+++ b/src/plugins/platforms/xcb/qxcbeventqueue.h
@@ -106,7 +106,9 @@ public:
bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr,
PeekOptions option = PeekDefault, qint32 peekerId = -1);
- void waitForNewEvents(unsigned long time = ULONG_MAX);
+ const QXcbEventNode *flushedTail() const { return m_flushedTail; }
+ void waitForNewEvents(const QXcbEventNode *sinceFlushedTail,
+ unsigned long time = ULONG_MAX);
private:
QXcbEventNode *qXcbEventNodeFactory(xcb_generic_event_t *event);
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index ed9e87a036..f0ed49ecc0 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -137,8 +137,6 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
m_instance = this;
qApp->setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
- QWindowSystemInterface::setPlatformFiltersEvents(true);
-
qRegisterMetaType<QXcbWindow*>();
#if QT_CONFIG(xcb_xlib)
XInitThreads();
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 3bfcbf2adb..a6d2054110 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -933,6 +933,8 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates()
result |= NetWmStateStaysOnTop;
if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)))
result |= NetWmStateDemandsAttention;
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_HIDDEN)))
+ result |= NetWmStateHidden;
} else {
qCDebug(lcQpaXcb, "getting net wm state (%x), empty\n", m_window);
}
@@ -1104,6 +1106,9 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow()
states |= NetWmStateBelow;
}
+ if (window()->windowStates() & Qt::WindowMinimized)
+ states |= NetWmStateHidden;
+
if (window()->windowStates() & Qt::WindowFullScreen)
states |= NetWmStateFullScreen;
@@ -1137,6 +1142,8 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow()
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE));
if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW)))
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW));
+ if (states & NetWmStateHidden && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_HIDDEN)))
+ atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_HIDDEN));
if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)))
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)))
@@ -1165,27 +1172,44 @@ void QXcbWindow::setWindowState(Qt::WindowStates state)
if (state == m_windowState)
return;
- if ((m_windowState & Qt::WindowMinimized) && !(state & Qt::WindowMinimized)) {
+ // unset old state
+ if (m_windowState & Qt::WindowMinimized)
xcb_map_window(xcb_connection(), m_window);
- } else if (!(m_windowState & Qt::WindowMinimized) && (state & Qt::WindowMinimized)) {
- xcb_client_message_event_t event;
+ if (m_windowState & Qt::WindowMaximized)
+ setNetWmState(false,
+ atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ),
+ atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
+ if (m_windowState & Qt::WindowFullScreen)
+ setNetWmState(false, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
- event.response_type = XCB_CLIENT_MESSAGE;
- event.format = 32;
- event.sequence = 0;
- event.window = m_window;
- event.type = atom(QXcbAtom::WM_CHANGE_STATE);
- event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC;
- event.data.data32[1] = 0;
- event.data.data32[2] = 0;
- event.data.data32[3] = 0;
- event.data.data32[4] = 0;
+ // set new state
+ if (state & Qt::WindowMinimized) {
+ {
+ xcb_client_message_event_t event;
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.sequence = 0;
+ event.window = m_window;
+ event.type = atom(QXcbAtom::WM_CHANGE_STATE);
+ event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC;
+ event.data.data32[1] = 0;
+ event.data.data32[2] = 0;
+ event.data.data32[3] = 0;
+ event.data.data32[4] = 0;
- xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
- XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
- (const char *)&event);
+ xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
+ (const char *)&event);
+ }
m_minimized = true;
}
+ if (state & Qt::WindowMaximized)
+ setNetWmState(true,
+ atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ),
+ atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
+ if (state & Qt::WindowFullScreen)
+ setNetWmState(true, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
setNetWmState(state);
@@ -2236,10 +2260,16 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
|| (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized));
}
}
- if (m_minimized)
- newState = Qt::WindowMinimized;
const NetWmStates states = netWmStates();
+ // _NET_WM_STATE_HIDDEN should be set by the Window Manager to indicate that a window would
+ // not be visible on the screen if its desktop/viewport were active and its coordinates were
+ // within the screen bounds. The canonical example is that minimized windows should be in
+ // the _NET_WM_STATE_HIDDEN state.
+ if (m_minimized && (!connection()->wmSupport()->isSupportedByWM(NetWmStateHidden)
+ || states.testFlag(NetWmStateHidden)))
+ newState = Qt::WindowMinimized;
+
if (states & NetWmStateFullScreen)
newState |= Qt::WindowFullScreen;
if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert))
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 8258cc2dfa..7f86fc6bb6 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -68,7 +68,8 @@ public:
NetWmStateMaximizedVert = 0x10,
NetWmStateModal = 0x20,
NetWmStateStaysOnTop = 0x40,
- NetWmStateDemandsAttention = 0x80
+ NetWmStateDemandsAttention = 0x80,
+ NetWmStateHidden = 0x100
};
Q_DECLARE_FLAGS(NetWmStates, NetWmState)