diff options
Diffstat (limited to 'src/plugins/platforms')
37 files changed, 527 insertions, 205 deletions
diff --git a/src/plugins/platforms/CMakeLists.txt b/src/plugins/platforms/CMakeLists.txt index f30c27c24be..498a0772bc9 100644 --- a/src/plugins/platforms/CMakeLists.txt +++ b/src/plugins/platforms/CMakeLists.txt @@ -4,10 +4,10 @@ if(ANDROID) add_subdirectory(android) endif() -if(NOT ANDROID AND NOT WASM) +if(NOT WASM) add_subdirectory(minimal) endif() -if(QT_FEATURE_freetype AND NOT ANDROID AND NOT WASM) +if(QT_FEATURE_freetype AND NOT WASM) add_subdirectory(offscreen) endif() if(QT_FEATURE_xcb) diff --git a/src/plugins/platforms/android/CMakeLists.txt b/src/plugins/platforms/android/CMakeLists.txt index 0160e12c26c..0d2a048abde 100644 --- a/src/plugins/platforms/android/CMakeLists.txt +++ b/src/plugins/platforms/android/CMakeLists.txt @@ -51,7 +51,12 @@ qt_internal_add_plugin(QAndroidIntegrationPlugin qandroidplatformdialoghelpers.cpp # Conflicting JNI classes, and types androidcontentfileengine.cpp + qandroidplatformforeignwindow.cpp qandroidplatformintegration.cpp + qandroidplatformscreen.cpp + qandroidplatformservices.cpp + qandroidplatformwindow.cpp + qandroidsystemlocale.cpp INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} ${QtBase_SOURCE_DIR}/src/3rdparty/android diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 200c2f7a47b..b3ff0a4f06e 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -28,6 +28,7 @@ using namespace Qt::StringLiterals; namespace QtAndroidAccessibility { + static jmethodID m_setClassNameMethodID = 0; static jmethodID m_addActionMethodID = 0; static jmethodID m_setCheckableMethodID = 0; static jmethodID m_setCheckedMethodID = 0; @@ -421,6 +422,130 @@ namespace QtAndroidAccessibility return jstr; } + static QString classNameForRole(QAccessible::Role role, QAccessible::State state) { + switch (role) { + case QAccessible::Role::Button: + case QAccessible::Role::Link: + { + if (state.checkable) + // There is also a android.widget.Switch for which we have no match. + return QStringLiteral("android.widget.ToggleButton"); + return QStringLiteral("android.widget.Button"); + } + case QAccessible::Role::CheckBox: + // As of android/accessibility/utils/Role.java::getRole a CheckBox + // is NOT android.widget.CheckBox + return QStringLiteral("android.widget.CompoundButton"); + case QAccessible::Role::Clock: + return QStringLiteral("android.widget.TextClock"); + case QAccessible::Role::ComboBox: + return QStringLiteral("android.widget.Spinner"); + case QAccessible::Role::Graphic: + // QQuickImage does not provide this role it inherits Client from QQuickItem + return QStringLiteral("android.widget.ImageView"); + case QAccessible::Role::Grouping: + return QStringLiteral("android.view.ViewGroup"); + case QAccessible::Role::List: + // As of android/accessibility/utils/Role.java::getRole a List + // is NOT android.widget.ListView + return QStringLiteral("android.widget.AbsListView"); + case QAccessible::Role::MenuItem: + return QStringLiteral("android.view.MenuItem"); + case QAccessible::Role::PopupMenu: + return QStringLiteral("android.widget.PopupMenu"); + case QAccessible::Role::Separator: + return QStringLiteral("android.widget.Space"); + case QAccessible::Role::ToolBar: + return QStringLiteral("android.view.Toolbar"); + case QAccessible::Role::Heading: [[fallthrough]]; + case QAccessible::Role::StaticText: + // Heading vs. regular Text is finally determined by AccessibilityNodeInfo.isHeading() + return QStringLiteral("android.widget.TextView"); + case QAccessible::Role::EditableText: + return QStringLiteral("android.widget.EditText"); + case QAccessible::Role::RadioButton: + return QStringLiteral("android.widget.RadioButton"); + case QAccessible::Role::ProgressBar: + return QStringLiteral("android.widget.ProgressBar"); + // Range information need to be filled to announce percentages + case QAccessible::Role::SpinBox: + return QStringLiteral("android.widget.NumberPicker"); + case QAccessible::Role::WebDocument: + return QStringLiteral("android.webkit.WebView"); + case QAccessible::Role::Dialog: + return QStringLiteral("android.app.AlertDialog"); + case QAccessible::Role::PageTab: + return QStringLiteral("android.app.ActionBar.Tab"); + case QAccessible::Role::PageTabList: + return QStringLiteral("android.widget.TabWidget"); + case QAccessible::Role::ScrollBar: [[fallthrough]]; + case QAccessible::Role::Slider: + return QStringLiteral("android.widget.SeekBar"); + case QAccessible::Role::Table: + // #TODO Evaluate the usage of AccessibleNodeInfo.setCollectionItemInfo() to provide + // infos about colums, rows und items. + return QStringLiteral("android.widget.GridView"); + case QAccessible::Role::Pane: + // #TODO QQuickScrollView, QQuickListView (see QTBUG-137806) + return QStringLiteral("android.view.ViewGroup"); + case QAccessible::Role::AlertMessage: + case QAccessible::Role::Animation: + case QAccessible::Role::Application: + case QAccessible::Role::Assistant: + case QAccessible::Role::BlockQuote: + case QAccessible::Role::Border: + case QAccessible::Role::ButtonDropGrid: + case QAccessible::Role::ButtonDropDown: + case QAccessible::Role::ButtonMenu: + case QAccessible::Role::Canvas: + case QAccessible::Role::Caret: + case QAccessible::Role::Cell: + case QAccessible::Role::Chart: + case QAccessible::Role::Client: + case QAccessible::Role::ColorChooser: + case QAccessible::Role::Column: + case QAccessible::Role::ColumnHeader: + case QAccessible::Role::ComplementaryContent: + case QAccessible::Role::Cursor: + case QAccessible::Role::Desktop: + case QAccessible::Role::Dial: + case QAccessible::Role::Document: + case QAccessible::Role::Equation: + case QAccessible::Role::Footer: + case QAccessible::Role::Form: + case QAccessible::Role::Grip: + case QAccessible::Role::HelpBalloon: + case QAccessible::Role::HotkeyField: + case QAccessible::Role::Indicator: + case QAccessible::Role::LayeredPane: + case QAccessible::Role::ListItem: + case QAccessible::Role::MenuBar: + case QAccessible::Role::NoRole: + case QAccessible::Role::Note: + case QAccessible::Role::Notification: + case QAccessible::Role::Paragraph: + case QAccessible::Role::PropertyPage: + case QAccessible::Role::Row: + case QAccessible::Role::RowHeader: + case QAccessible::Role::Section: + case QAccessible::Role::Sound: + case QAccessible::Role::Splitter: + case QAccessible::Role::StatusBar: + case QAccessible::Role::Terminal: + case QAccessible::Role::TitleBar: + case QAccessible::Role::ToolTip: + case QAccessible::Role::Tree: + case QAccessible::Role::TreeItem: + case QAccessible::Role::UserRole: + case QAccessible::Role::Whitespace: + case QAccessible::Role::Window: + // If unsure, every visible or interactive element in Android + // inherits android.view.View and by many extends also TextView. + // Android itself does a similar thing e.g. in its Settings-App. + return QStringLiteral("android.view.TextView"); + } + } + static QString descriptionForInterface(QAccessibleInterface *iface) { QString desc; @@ -513,6 +638,10 @@ namespace QtAndroidAccessibility return false; } + const QString role = classNameForRole(info.role, info.state); + jstring jrole = env->NewString((jchar*)role.constData(), (jsize)role.size()); + env->CallVoidMethod(node, m_setClassNameMethodID, jrole); + const bool hasClickableAction = info.actions.contains(QAccessibleActionInterface::pressAction()) || info.actions.contains(QAccessibleActionInterface::toggleAction()); @@ -590,6 +719,7 @@ namespace QtAndroidAccessibility } jclass nodeInfoClass = env->FindClass("android/view/accessibility/AccessibilityNodeInfo"); + GET_AND_CHECK_STATIC_METHOD(m_setClassNameMethodID, nodeInfoClass, "setClassName", "(Ljava/lang/CharSequence;)V"); GET_AND_CHECK_STATIC_METHOD(m_addActionMethodID, nodeInfoClass, "addAction", "(I)V"); GET_AND_CHECK_STATIC_METHOD(m_setCheckableMethodID, nodeInfoClass, "setCheckable", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setCheckedMethodID, nodeInfoClass, "setChecked", "(Z)V"); diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 71b6015a54d..79aed15a1d0 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -44,7 +44,8 @@ public: const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) override; + bool translucentBackground, + qreal sourceTransformFactor) override; QImage toImage() const override; QPlatformGraphicsBuffer *graphicsBuffer() const override; diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 78d23b01dea..186aeaac44d 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -457,7 +457,8 @@ QPlatformBackingStore::FlushResult QCALayerBackingStore::rhiFlush(QWindow *windo const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) + bool translucentBackground, + qreal sourceTransformFactor) { if (!m_buffers.back()) { qCWarning(lcQpaBackingStore) << "Flush requested with no back buffer. Ignoring."; @@ -466,7 +467,8 @@ QPlatformBackingStore::FlushResult QCALayerBackingStore::rhiFlush(QWindow *windo finalizeBackBuffer(); - return QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, region, offset, textures, translucentBackground); + return QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, + region, offset, textures, translucentBackground, sourceTransformFactor); } QImage QCALayerBackingStore::toImage() const diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 36546879ae4..13139dd399d 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -43,6 +43,8 @@ public: QFunctionPointer getProcAddress(const char *procName) override; + bool isSoftwareContext() const; + private: static NSOpenGLPixelFormat *pixelFormatForSurfaceFormat(const QSurfaceFormat &format); @@ -54,6 +56,7 @@ private: QSurfaceFormat m_format; QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers; QAtomicInt m_needsUpdate = false; + bool m_isSoftwareContext = false; #ifndef QT_NO_DEBUG_STREAM friend QDebug operator<<(QDebug debug, const QCocoaGLContext *screen); diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index bfac716b633..2f0f513dfc1 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -289,6 +289,9 @@ void QCocoaGLContext::updateSurfaceFormat() else m_format.setSwapBehavior(QSurfaceFormat::SingleBuffer); + m_isSoftwareContext = (pixelFormatAttribute(NSOpenGLPFARendererID) + & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID; + // ------------------- Query the context ------------------- auto glContextParameter = [&](NSOpenGLContextParameter parameter) { @@ -512,6 +515,11 @@ bool QCocoaGLContext::isSharing() const return m_shareContext != nil; } +bool QCocoaGLContext::isSoftwareContext() const +{ + return m_isSoftwareContext; +} + NSOpenGLContext *QCocoaGLContext::nativeContext() const { return m_context; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 8c6dcfd4f60..4c5975af34a 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -232,6 +232,24 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons // layer-backed. return false; case OpenGL: + if (QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSSonoma) { + // Tahoe has issues with software-backed GL, crashing in common operations + static bool isSoftwareContext = []{ + QOpenGLContext context; + context.create(); + auto *cocoaContext = static_cast<QCocoaGLContext*>(context.handle()); + if (cocoaContext->isSoftwareContext()) { + qWarning() << "Detected software OpenGL backend," + << "which is known to be broken on" + << qUtf8Printable(QSysInfo::prettyProductName()); + return true; + } else { + return false; + } + }(); + return !isSoftwareContext; + } + Q_FALLTHROUGH(); case BufferQueueingOpenGL: #endif case ThreadedPixmaps: diff --git a/src/plugins/platforms/eglfs/api/qeglfscontext.cpp b/src/plugins/platforms/eglfs/api/qeglfscontext.cpp index 9c10c1a998c..0b9db8039f1 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscontext.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfscontext.cpp @@ -79,8 +79,10 @@ void QEglFSContext::swapBuffers(QPlatformSurface *surface) // draw the cursor if (surface->surface()->surfaceClass() == QSurface::Window) { QPlatformWindow *window = static_cast<QPlatformWindow *>(surface); - if (QEglFSCursor *cursor = qobject_cast<QEglFSCursor *>(window->screen()->cursor())) - cursor->paintOnScreen(); + if (QPlatformScreen *screen = window->screen()) { + if (QEglFSCursor *cursor = qobject_cast<QEglFSCursor *>(screen->cursor())) + cursor->paintOnScreen(); + } } qt_egl_device_integration()->waitForVSync(surface); diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp index 4abe948117e..2f278a474e0 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp @@ -154,6 +154,7 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi if (!window->handle()) window->create(); static_cast<QEglFSWindow *>(window->handle())->setBackingStore(bs); + m_bs = bs; return bs; #else Q_UNUSED(window); @@ -175,6 +176,9 @@ QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen()) w->requestActivateWindow(); + if (window->isTopLevel()) + w->setBackingStore(static_cast<QOpenGLCompositorBackingStore *>(m_bs)); + return w; } diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h index 2359b7f29f1..3865b7130b7 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h @@ -112,6 +112,7 @@ private: QScopedPointer<QFbVtHandler> m_vtHandler; QPointer<QWindow> m_pointerWindow; bool m_disableInputHandlers; + mutable QPlatformBackingStore *m_bs = nullptr; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h index a0f78bb3103..cca9097e2f0 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h @@ -62,6 +62,8 @@ public: void reevaluateVisibilityForScreens() { setPos(pos()); } + QEglFSKmsGbmScreen *screen() const { return m_screen; } + private: void initCursorAtlas(); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp index a7592ed55e4..59265daa127 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp @@ -10,6 +10,7 @@ #include <private/qeglfskmsintegration_p.h> #include <QtCore/QLoggingCategory> +#include <QtCore/qtimer.h> #include <QtCore/private/qcore_unix_p.h> #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) @@ -113,13 +114,27 @@ QPlatformScreen *QEglFSKmsGbmDevice::createScreen(const QKmsOutput &output) { QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(this, output, false); - createGlobalCursor(screen); + + // On some platforms (e.g. rpi4), you'll get a kernel warning/error + // if the cursor is created 'at the same time' as the screen is created. + // (drmModeMoveCursor is the specific call that causes the issue) + // When this issue is triggered, the screen's connector is unusable until reboot + // + // Below is a work-around (without negative implications for other platforms). + // + // interval of 0 and QMetaObject::invokeMethod (w/o Qt::QueuedConnection) + // do no help / will still trigger issue + QTimer::singleShot(1, [screen, this](){ + createGlobalCursor(screen); + }); return screen; } QPlatformScreen *QEglFSKmsGbmDevice::createHeadlessScreen() { + destroyGlobalCursor(); + return new QEglFSKmsGbmScreen(this, QKmsOutput(), true); } @@ -127,9 +142,6 @@ void QEglFSKmsGbmDevice::registerScreenCloning(QPlatformScreen *screen, QPlatformScreen *screenThisScreenClones, const QList<QPlatformScreen *> &screensCloningThisScreen) { - if (!screenThisScreenClones && screensCloningThisScreen.isEmpty()) - return; - QEglFSKmsGbmScreen *gbmScreen = static_cast<QEglFSKmsGbmScreen *>(screen); gbmScreen->initCloning(screenThisScreenClones, screensCloningThisScreen); } @@ -144,6 +156,32 @@ void QEglFSKmsGbmDevice::registerScreen(QPlatformScreen *screen, m_globalCursor->reevaluateVisibilityForScreens(); } +void QEglFSKmsGbmDevice::unregisterScreen(QPlatformScreen *screen) +{ + // The global cursor holds a pointer to a QEglFSKmsGbmScreen. + // If that screen is being unregistered, + // this will recreate the global cursor with the first sibling screen. + if (m_globalCursor && screen == m_globalCursor->screen()) { + qCDebug(qLcEglfsKmsDebug) << "Destroying global GBM mouse cursor due to unregistering" + << "it's screen - will probably be recreated right away"; + delete m_globalCursor; + m_globalCursor = nullptr; + + QList<QPlatformScreen *> siblings = screen->virtualSiblings(); + siblings.removeOne(screen); + if (siblings.count() > 0) { + QEglFSKmsGbmScreen *kmsScreen = static_cast<QEglFSKmsGbmScreen *>(siblings.first()); + m_globalCursor = new QEglFSKmsGbmCursor(kmsScreen); + qCDebug(qLcEglfsKmsDebug) << "Creating new global GBM mouse cursor on sibling screen"; + } else { + qCWarning(qLcEglfsKmsDebug) << "Couldn't find a sibling to recreate" + << "the GBM mouse cursor - it might vanish"; + } + } + + QEglFSKmsDevice::unregisterScreen(screen); +} + bool QEglFSKmsGbmDevice::usesEventReader() const { static const bool eventReaderThreadDisabled = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_NO_EVENT_READER_THREAD"); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h index e00992ed291..0ffed0ec4ef 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h @@ -51,6 +51,7 @@ public: bool isPrimary, const QPoint &virtualPos, const QList<QPlatformScreen *> &virtualSiblings) override; + void unregisterScreen(QPlatformScreen *screen) override; bool usesEventReader() const; QEglFSKmsEventReader *eventReader() { return &m_eventReader; } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp index 05ffb3b212e..eb61de3c534 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp @@ -11,6 +11,7 @@ #include "private/qeglfscursor_p.h" #include <QtCore/QLoggingCategory> +#include <QtCore/QFileSystemWatcher> #include <QtGui/QScreen> #include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h> @@ -23,6 +24,10 @@ QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration() qCDebug(qLcEglfsKmsDebug, "New DRM/KMS via GBM integration created"); } +QEglFSKmsGbmIntegration::~QEglFSKmsGbmIntegration() +{ +} + #ifndef EGL_EXT_platform_base typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list); #endif @@ -94,14 +99,16 @@ void QEglFSKmsGbmIntegration::presentBuffer(QPlatformSurface *surface) QKmsDevice *QEglFSKmsGbmIntegration::createDevice() { + + m_deviceDiscovery = std::unique_ptr<QDeviceDiscovery>(QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask)); + m_kmsConfigWatcher = std::unique_ptr<QFileSystemWatcher>(new QFileSystemWatcher()); + QString path = screenConfig()->devicePath(); if (!path.isEmpty()) { qCDebug(qLcEglfsKmsDebug) << "GBM: Using DRM device" << path << "specified in config file"; } else { - QDeviceDiscovery *d = QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask); - const QStringList devices = d->scanConnectedDevices(); + const QStringList devices = m_deviceDiscovery->scanConnectedDevices(); qCDebug(qLcEglfsKmsDebug) << "Found the following video devices:" << devices; - d->deleteLater(); if (Q_UNLIKELY(devices.isEmpty())) qFatal("Could not find DRM device!"); @@ -110,6 +117,35 @@ QKmsDevice *QEglFSKmsGbmIntegration::createDevice() qCDebug(qLcEglfsKmsDebug) << "Using" << path; } + bool hotreload = !qEnvironmentVariable("QT_QPA_EGLFS_HOTPLUG_ENABLED").isEmpty(); + if (hotreload) { + qCWarning(qLcEglfsKmsDebug) << "EGLFS/KMS: Hot-Reload on KMS-events enabled, be aware that" + << "this requires actions in UI code for proper functionallity" + << "(e.g. close/open windows on screen's disconnect/connect)"; + QObject::connect(m_deviceDiscovery.get(), &QDeviceDiscovery::deviceChanged, + m_deviceDiscovery.get(), [this](const QString &deviceNode) { + qCDebug(qLcEglfsKmsDebug) << "KMS device changed:" << deviceNode; + m_device->checkConnectedScreens(); + }); + } + + QString json = qEnvironmentVariable("QT_QPA_EGLFS_KMS_CONFIG"); + if (json.isEmpty()) + json = qEnvironmentVariable("QT_QPA_KMS_CONFIG"); + + if (!json.isEmpty()) { + m_kmsConfigWatcher->addPath(json); + QObject::connect(m_kmsConfigWatcher.get(), &QFileSystemWatcher::fileChanged, + m_kmsConfigWatcher.get(), [this, json]() { + qCDebug(qLcEglfsKmsDebug) << "KMS config-file has changed! path:" + << json; + m_screenConfig->refreshConfig(); + m_device->updateScreens(); + m_kmsConfigWatcher->addPath(json); // as per QFileSystemWatcher doc we have to re-add + // the path in case it's a new file + }); + } + return new QEglFSKmsGbmDevice(screenConfig(), path); } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h index fb118438d25..7c2c2a474d7 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h @@ -24,11 +24,14 @@ QT_BEGIN_NAMESPACE class QEglFSKmsDevice; +class QDeviceDiscovery; +class QFileSystemWatcher; class Q_EGLFS_EXPORT QEglFSKmsGbmIntegration : public QEglFSKmsIntegration { public: QEglFSKmsGbmIntegration(); + ~QEglFSKmsGbmIntegration() override; EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) override; EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) override; @@ -42,6 +45,8 @@ protected: QKmsDevice *createDevice() override; private: + std::unique_ptr<QDeviceDiscovery> m_deviceDiscovery; + std::unique_ptr<QFileSystemWatcher> m_kmsConfigWatcher; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp index 00fecb87f1f..332030f03f2 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp @@ -20,7 +20,7 @@ QT_BEGIN_NAMESPACE -QMutex QEglFSKmsGbmScreen::m_nonThreadedFlipMutex; +QMutex QEglFSKmsGbmScreen::s_nonThreadedFlipMutex; static inline uint32_t drmFormatToGbmFormat(uint32_t drmFormat) { @@ -92,9 +92,26 @@ QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsDevice *device, const QKmsOutput QEglFSKmsGbmScreen::~QEglFSKmsGbmScreen() { const int remainingScreenCount = qGuiApp->screens().count(); - qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount); + qCDebug(qLcEglfsKmsDebug, "Screen dtor. %p Remaining screens: %d", this, remainingScreenCount); if (!remainingScreenCount && !device()->screenConfig()->separateScreens()) static_cast<QEglFSKmsGbmDevice *>(device())->destroyGlobalCursor(); + + if (m_cloneSource) { + // Remove this screen from the screen that has it as a clone destination + QList<CloneDestination> &dests = m_cloneSource->m_cloneDests; + auto newEnd = std::remove_if(dests.begin(), dests.end(), + [this](CloneDestination &dest) { + return dest.screen == this; + }); + dests.erase(newEnd, dests.end()); + } + + // Other screens can no longer have this screen as a clone source + for (CloneDestination &dest : m_cloneDests) { + dest.screen->m_cloneSource = nullptr; + // Mode must be set again before flipping + dest.screen->m_output.mode_set = false; + } } QPlatformCursor *QEglFSKmsGbmScreen::cursor() const @@ -206,9 +223,12 @@ void QEglFSKmsGbmScreen::initCloning(QPlatformScreen *screenThisScreenClones, if (clonesAnother) { m_cloneSource = static_cast<QEglFSKmsGbmScreen *>(screenThisScreenClones); qCDebug(qLcEglfsKmsDebug, "Screen %s clones %s", qPrintable(name()), qPrintable(m_cloneSource->name())); + } else { + m_cloneSource = nullptr; } // clone sources need to know their additional destinations + m_cloneDests.clear(); for (QPlatformScreen *s : screensCloningThisScreen) { CloneDestination d; d.screen = static_cast<QEglFSKmsGbmScreen *>(s); @@ -271,8 +291,11 @@ void QEglFSKmsGbmScreen::nonThreadedPageFlipHandler(int fd, // note that with cloning involved this callback is called also for screens that clone another one Q_UNUSED(fd); QEglFSKmsGbmScreen *screen = static_cast<QEglFSKmsGbmScreen *>(user_data); - screen->flipFinished(); - screen->pageFlipped(sequence, tv_sec, tv_usec); + // The screen might have been deleted when DRM calls this handler + if (QEglFSKmsScreen::isScreenKnown(screen)) { + screen->flipFinished(); + screen->pageFlipped(sequence, tv_sec, tv_usec); + } } void QEglFSKmsGbmScreen::waitForFlipWithEventReader(QEglFSKmsGbmScreen *screen) @@ -280,7 +303,21 @@ void QEglFSKmsGbmScreen::waitForFlipWithEventReader(QEglFSKmsGbmScreen *screen) m_flipMutex.lock(); QEglFSKmsGbmDevice *dev = static_cast<QEglFSKmsGbmDevice *>(device()); dev->eventReader()->startWaitFlip(screen, &m_flipMutex, &m_flipCond); - m_flipCond.wait(&m_flipMutex); + + // We should only wait forever on this screen, clones should have a timeout + // (e.g. I clone might have been created just before the flip, + // we might wait for it but it might not know about waking us up) + bool succ = false; + if (screen == this) + succ = m_flipCond.wait(&m_flipMutex); + else + succ = m_flipCond.wait(&m_flipMutex, 300); + + if (!succ) + qCWarning(qLcEglfsKmsDebug) << "timeout on waitForFlipWithEventReader, screen to wait for:" + << screen << ", screen waiting (shouldn't be the same screen):" + << this; + m_flipMutex.unlock(); screen->flipFinished(); } @@ -306,7 +343,7 @@ void QEglFSKmsGbmScreen::waitForFlip() waitForFlipWithEventReader(d.screen); } } else { - QMutexLocker lock(&m_nonThreadedFlipMutex); + QMutexLocker lock(&s_nonThreadedFlipMutex); while (m_gbm_bo_next) { drmEventContext drmEvent; memset(&drmEvent, 0, sizeof(drmEvent)); @@ -359,15 +396,10 @@ static void addAtomicFlip(drmModeAtomicReq *request, const QKmsOutput &output, u void QEglFSKmsGbmScreen::flip() { - // For headless screen just return silently. It is not necessarily an error + // For headless or cloned screen just return silently. It is not necessarily an error // to end up here, so show no warnings. - if (m_headless) - return; - - if (m_cloneSource) { - qWarning("Screen %s clones another screen. swapBuffers() not allowed.", qPrintable(name())); + if (m_headless || m_cloneSource) return; - } if (!m_gbm_surface) { qWarning("Cannot sync before platform init!"); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h index aca34fcae21..65625a3c1cd 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h @@ -67,7 +67,7 @@ protected: QMutex m_flipMutex; QWaitCondition m_flipCond; - static QMutex m_nonThreadedFlipMutex; + static QMutex s_nonThreadedFlipMutex; QScopedPointer<QEglFSKmsGbmCursor> m_cursor; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp index ece19f46a49..ff4921c2b15 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp @@ -213,9 +213,13 @@ QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const QEglFSKmsEglDeviceWindow *eglWindow = new QEglFSKmsEglDeviceWindow(window, this); m_funcs->initialize(eglWindow->screen()->display()); - if (Q_UNLIKELY(!(m_funcs->has_egl_output_base && m_funcs->has_egl_output_drm && m_funcs->has_egl_stream && - m_funcs->has_egl_stream_producer_eglsurface && m_funcs->has_egl_stream_consumer_egloutput))) + if (Q_UNLIKELY(!(m_funcs->has_egl_output_base && m_funcs->has_egl_output_drm + && m_funcs->has_egl_stream && m_funcs->has_egl_stream_producer_eglsurface + && m_funcs->has_egl_stream_consumer_egloutput))) { + qCDebug(qLcEglfsKmsDebug, "EGL_EXTENSIONS %s", + eglQueryString(eglWindow->screen()->display(), EGL_EXTENSIONS)); qFatal("Required extensions missing!"); + } return eglWindow; } 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 5af45e63a2f..5775ac3607a 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp @@ -71,7 +71,7 @@ QEglFSKmsEglDeviceScreen::~QEglFSKmsEglDeviceScreen() } const int remainingScreenCount = qGuiApp->screens().size(); - qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount); + qCDebug(qLcEglfsKmsDebug, "Screen dtor. %p Remaining screens: %d", this, remainingScreenCount); if (!remainingScreenCount && !device()->screenConfig()->separateScreens()) static_cast<QEglFSKmsEglDevice *>(device())->destroyGlobalCursor(); } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp index 037b26f023e..59ca53355d6 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp @@ -25,4 +25,39 @@ void QEglFSKmsDevice::registerScreen(QPlatformScreen *screen, QWindowSystemInterface::handleScreenAdded(s, isPrimary); } +void QEglFSKmsDevice::unregisterScreen(QPlatformScreen *screen) +{ + QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen); + for (QPlatformScreen *sibling : s->virtualSiblings()) + static_cast<QEglFSKmsScreen *>(sibling)->removeSibling(s); + + QWindowSystemInterface::handleScreenRemoved(screen); +} + +void QEglFSKmsDevice::updateScreen(QPlatformScreen *screen, const QPoint &virtualPos, + const QList<QPlatformScreen *> &virtualSiblings) +{ + QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen); + QRect before = s->geometry(); + s->setVirtualPosition(virtualPos); + s->setVirtualSiblings(virtualSiblings); + QRect after = s->geometry(); + + if (before != after) + QWindowSystemInterface::handleScreenGeometryChange(s->screen(), after, + s->availableGeometry()); +} + +void QEglFSKmsDevice::updateScreenOutput(QPlatformScreen *screen, const QKmsOutput &output) +{ + QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen); + QRect before = s->geometry(); + s->updateOutput(output); + QRect after = s->geometry(); + + if (before != after) + QWindowSystemInterface::handleScreenGeometryChange(s->screen(), after, + s->availableGeometry()); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h index 6e11953a699..49b82d8baad 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h @@ -30,6 +30,13 @@ public: bool isPrimary, const QPoint &virtualPos, const QList<QPlatformScreen *> &virtualSiblings) override; + + void unregisterScreen(QPlatformScreen *screen) override; + + void updateScreen(QPlatformScreen *screen, const QPoint &virtualPos, + const QList<QPlatformScreen *> &virtualSiblings) override; + + void updateScreenOutput(QPlatformScreen *screen, const QKmsOutput &output) override; }; 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 index c0c96554962..fa735388bc0 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp @@ -20,7 +20,10 @@ static void pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, t->eventHost()->handlePageFlipCompleted(user_data); QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(user_data); - screen->pageFlipped(sequence, tv_sec, tv_usec); + if (QEglFSKmsScreen::isScreenKnown(screen)) + screen->pageFlipped(sequence, tv_sec, tv_usec); + else + qWarning("Deleted screen got it's pageFlipHandler called; Dead pointer: %p", user_data); } class RegisterWaitFlipEvent : public QEvent 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 cc7381fb701..a40287bdfed 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp @@ -16,6 +16,8 @@ QT_BEGIN_NAMESPACE +QSet<QEglFSKmsScreen *> QEglFSKmsScreen::s_screens; + class QEglFSKmsInterruptHandler : public QObject { public: @@ -59,10 +61,14 @@ QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsDevice *device, const QKmsOutput &outp } else { qCDebug(qLcEglfsKmsDebug) << "No EDID data for output" << name(); } + + s_screens.insert(this); } QEglFSKmsScreen::~QEglFSKmsScreen() { + s_screens.remove(this); + m_output.cleanup(m_device); delete m_interruptHandler; } @@ -166,6 +172,11 @@ void QEglFSKmsScreen::waitForFlip() { } +void QEglFSKmsScreen::updateOutput(QKmsOutput output) +{ + m_output = output; +} + void QEglFSKmsScreen::restoreMode() { m_output.restoreMode(m_device); @@ -180,6 +191,11 @@ qreal QEglFSKmsScreen::refreshRate() const return refresh > 0 ? refresh : 60; } +void QEglFSKmsScreen::removeSibling(QPlatformScreen *screen) +{ + m_siblings.removeAll(screen); +} + QList<QPlatformScreen::Mode> QEglFSKmsScreen::modes() const { QList<QPlatformScreen::Mode> list; @@ -227,4 +243,9 @@ void QEglFSKmsScreen::pageFlipped(unsigned int sequence, unsigned int tv_sec, un Q_UNUSED(tv_usec); } +bool QEglFSKmsScreen::isScreenKnown(QEglFSKmsScreen *s) +{ + return s_screens.contains(s); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h index 6fb1f9a1348..2dc49152a97 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h @@ -58,6 +58,7 @@ public: QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; } void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; } + void removeSibling(QPlatformScreen *screen); QList<QPlatformScreen::Mode> modes() const override; @@ -68,6 +69,7 @@ public: virtual void waitForFlip(); + void updateOutput(QKmsOutput output); QKmsOutput &output() { return m_output; } void restoreMode(); @@ -80,6 +82,8 @@ public: void setCursorOutOfRange(bool b) { m_cursorOutOfRange = b; } virtual void pageFlipped(unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec); + static bool isScreenKnown(QEglFSKmsScreen *s); + protected: QEglFSKmsDevice *m_device; @@ -95,6 +99,8 @@ protected: QEglFSKmsInterruptHandler *m_interruptHandler; bool m_headless; + + static QSet<QEglFSKmsScreen *> s_screens; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm index 088d48fc9ff..a01c590bba8 100644 --- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm @@ -16,19 +16,28 @@ #include <QtCore/QtCore> @interface QIOSWindowSceneDelegate : NSObject<UIWindowSceneDelegate> +@property (nullable, nonatomic, strong) UIWindow *window; @end @implementation QIOSApplicationDelegate - (UISceneConfiguration *)application:(UIApplication *)application - configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession + configurationForConnectingSceneSession:(UISceneSession *)session options:(UISceneConnectionOptions *)options { - qCDebug(lcQpaWindowScene) << "Configuring scene for" << connectingSceneSession - << "with options" << options; + qCDebug(lcQpaWindowScene) << "Configuring scene for" << session << "with options" << options; + + auto *sceneConfig = session.configuration; + + if ([sceneConfig.role hasPrefix:@"CPTemplateApplication"]) { + qCDebug(lcQpaWindowScene) << "Not touching CarPlay scene with role" << sceneConfig.role + << "and existing delegate class" << sceneConfig.delegateClass; + // FIXME: Consider ignoring any scene with an existing sceneClass, delegateClass, or + // storyboard. But for visionOS the default delegate is SwiftUI.AppSceneDelegate. + } else { + sceneConfig.delegateClass = QIOSWindowSceneDelegate.class; + } - auto *sceneConfig = connectingSceneSession.configuration; - sceneConfig.delegateClass = QIOSWindowSceneDelegate.class; return sceneConfig; } @@ -40,7 +49,27 @@ { qCDebug(lcQpaWindowScene) << "Connecting" << scene << "to" << session; - Q_ASSERT([scene isKindOfClass:UIWindowScene.class]); + // Handle URL contexts, even if we return early + const auto handleUrlContexts = qScopeGuard([&]{ + if (connectionOptions.URLContexts.count > 0) + [self scene:scene openURLContexts:connectionOptions.URLContexts]; + }); + +#if defined(Q_OS_VISIONOS) + // CPImmersiveScene is a UIWindowScene, most likely so it can handle its internal + // CPSceneLayerEventWindow and UITextEffectsWindow, but we don't want a QUIWindow + // for these scenes, so bail out early. + if ([scene.session.role isEqualToString:@"CPSceneSessionRoleImmersiveSpaceApplication"]) { + qCDebug(lcQpaWindowScene) << "Skipping UIWindow creation for immersive scene"; + return; + } +#endif + + if (![scene isKindOfClass:UIWindowScene.class]) { + qCWarning(lcQpaWindowScene) << "Unexpectedly encountered non-window scene"; + return; + } + UIWindowScene *windowScene = static_cast<UIWindowScene*>(scene); QUIWindow *window = [[QUIWindow alloc] initWithWindowScene:windowScene]; @@ -59,8 +88,13 @@ window.rootViewController = [[[QIOSViewController alloc] initWithWindow:window andScreen:screen] autorelease]; - if (connectionOptions.URLContexts.count > 0) - [self scene:scene openURLContexts:connectionOptions.URLContexts]; + self.window = [window autorelease]; +} + +- (void)sceneDidDisconnect:(UIScene *)scene +{ + qCDebug(lcQpaWindowScene) << "Disconnecting" << scene; + self.window = nil; } - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 5716ad041e0..2926e6788ba 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -371,7 +371,8 @@ void QIOSInputContext::updateKeyboardState(NSNotification *notification) // with input-accessory-views. The reason for using frameEnd here (the future state), // instead of the current state reflected in frameBegin, is that QInputMethod::isVisible() // is documented to reflect the future state in the case of animated transitions. - m_keyboardState.keyboardVisible = CGRectIntersectsRect(frameEnd, [UIScreen mainScreen].bounds); + m_keyboardState.keyboardVisible = !CGRectIsEmpty(UIScreen.mainScreen.bounds) && + !CGRectIsEmpty(frameEnd) && CGRectIntersectsRect(frameEnd, UIScreen.mainScreen.bounds); // Used for auto-scroller, and will be used for animation-signal in the future m_keyboardState.keyboardEndRect = frameEnd; diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h index 1f8da41ba4f..340cc6b6acb 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.h +++ b/src/plugins/platforms/ios/qiosviewcontroller.h @@ -13,7 +13,7 @@ QT_END_NAMESPACE @interface QIOSViewController : UIViewController - (instancetype)initWithWindow:(UIWindow*)window andScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen; -- (void)updateProperties; +- (void)updateStatusBarProperties; - (NSArray*)keyCommands; - (void)handleShortcut:(UIKeyCommand*)keyCommand; diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index 36ce785e031..b6b42c59b0b 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -246,7 +246,7 @@ #endif m_focusWindowChangeConnection = QObject::connect(qApp, &QGuiApplication::focusWindowChanged, [self]() { - [self updateProperties]; + [self updateStatusBarProperties]; }); QIOSApplicationState *applicationState = &QIOSIntegration::instance()->applicationState; @@ -390,7 +390,7 @@ // ------------------------------------------------------------------------- -- (void)updateProperties +- (void)updateStatusBarProperties { if (!isQtApplication()) return; diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 3e2b6b0102a..af1fbb0abaf 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -243,7 +243,7 @@ void QIOSWindow::setWindowState(Qt::WindowStates state) qt_window_private(window())->windowState = state; if (window()->isTopLevel() && window()->isVisible() && window()->isActive()) - [m_view.qtViewController updateProperties]; + [m_view.qtViewController updateStatusBarProperties]; if (state & Qt::WindowMinimized) { applyGeometry(QRect()); diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 9b17eef07b0..86b6ce07518 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -786,6 +786,9 @@ inline ulong getTimeStamp(UIEvent *event) #if QT_CONFIG(tabletevent) - (void)handleHover:(UIHoverGestureRecognizer *)recognizer { + if (!self.platformWindow) + return; + ulong timeStamp = [[NSProcessInfo processInfo] systemUptime] * 1000; CGFloat zOffset = 0; diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 38b3bdadd35..a407cde2a7c 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1156,9 +1156,13 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::MoveEvent: platformWindow->handleMoved(); return true; - case QtWindows::ResizeEvent: + case QtWindows::ResizeEvent: { + QWindow *window = platformWindow->window(); platformWindow->handleResized(static_cast<int>(wParam), lParam); + if (window->flags().testFlags(Qt::ExpandedClientAreaHint)) + platformWindow->updateCustomTitlebar(); return true; + } case QtWindows::QuerySizeHints: platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam)); return true;// maybe available on some SDKs revisit WM_NCCALCSIZE @@ -1174,8 +1178,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return platformWindow->handleNonClientActivate(result); case QtWindows::GeometryChangingEvent: return platformWindow->handleGeometryChanging(&msg); - case QtWindows::ExposeEvent: + case QtWindows::ExposeEvent: { + QWindow *window = platformWindow->window(); + if (window->flags().testFlags(Qt::ExpandedClientAreaHint)) + platformWindow->updateCustomTitlebar(); return platformWindow->handleWmPaint(hwnd, message, wParam, lParam, result); + } case QtWindows::NonClientMouseEvent: if (!platformWindow->frameStrutEventsEnabled()) break; @@ -1219,6 +1227,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow(). if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) return false; + [[fallthrough]]; case QtWindows::FocusOutEvent: handleFocusEvent(et, platformWindow); return true; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 25c15861ba1..0f66193f47d 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -262,6 +262,11 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return true; #ifndef QT_NO_OPENGL case OpenGL: +#if !QT_CONFIG(run_opengl_tests) + // Workaround for build configs on WoA that don't have OpenGL installed + // FIXME: Detect at runtime + return false; +#endif return true; case ThreadedOpenGL: if (const QWindowsStaticOpenGLContext *glContext = QWindowsIntegration::staticOpenGLContext()) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 81a3f1d37b7..731673b61db 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -284,40 +284,6 @@ static inline RECT RECTfromQRect(const QRect &rect) return result; } -static LRESULT WINAPI WndProcTitleBar(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND parentHwnd = reinterpret_cast<HWND>(GetWindowLongPtr(hwnd, GWL_HWNDPARENT)); - QWindowsWindow* platformWindow = QWindowsContext::instance()->findPlatformWindow(parentHwnd); - - switch (message) { - case WM_SHOWWINDOW: - ShowWindow(hwnd,SW_HIDE); - if ((BOOL)wParam == TRUE) - platformWindow->transitionAnimatedCustomTitleBar(); - return 0; - case WM_SIZE: { - if (platformWindow) - platformWindow->updateCustomTitlebar(); - break; - } - case WM_NCHITTEST: - return HTTRANSPARENT; - case WM_TIMER: - ShowWindow(hwnd, SW_SHOWNOACTIVATE); - platformWindow->updateCustomTitlebar(); - break; - case WM_PAINT: - { - PAINTSTRUCT ps; - BeginPaint(hwnd, &ps); - EndPaint(hwnd, &ps); - return 0; - } - } - return DefWindowProc(hwnd, message, wParam, lParam); -} - - #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const RECT &r) { @@ -917,7 +883,7 @@ QWindowsWindowData const auto appinst = reinterpret_cast<HINSTANCE>(GetModuleHandle(nullptr)); const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w); - const QString windowTitlebarName = QWindowsContext::instance()->registerWindowClass(QStringLiteral("_q_titlebar"), WndProcTitleBar, CS_VREDRAW|CS_HREDRAW, nullptr, false); + const QString windowTitlebarName = QWindowsContext::instance()->registerWindowClass(QStringLiteral("_q_titlebar"), DefWindowProc, CS_VREDRAW|CS_HREDRAW, nullptr, false); const QScreen *screen{}; const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, @@ -970,15 +936,13 @@ QWindowsWindowData context->frameWidth, context->frameHeight, parentHandle, nullptr, appinst, nullptr); - if (w->flags().testFlags(Qt::ExpandedClientAreaHint)) { - const UINT dpi = ::GetDpiForWindow(result.hwnd); - const int titleBarHeight = getTitleBarHeight_sys(dpi); - result.hwndTitlebar = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, - classTitleBarNameUtf16, classTitleBarNameUtf16, - WS_POPUP, 0, 0, - context->frameWidth, titleBarHeight, - result.hwnd, nullptr, appinst, nullptr); - } + const UINT dpi = ::GetDpiForWindow(result.hwnd); + const int titleBarHeight = getTitleBarHeight_sys(dpi); + result.hwndTitlebar = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE, + classTitleBarNameUtf16, classTitleBarNameUtf16, + 0, 0, 0, + context->frameWidth, titleBarHeight, + nullptr, nullptr, appinst, nullptr); qCDebug(lcQpaWindow).nospace() << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: " @@ -1056,6 +1020,9 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang if (flags & Qt::ExpandedClientAreaHint) { // Gives us the rounded corners looks and the frame shadow MARGINS margins = { -1, -1, -1, -1 }; DwmExtendFrameIntoClientArea(hwnd, &margins); + } else { + MARGINS margins = { 0, 0, 0, 0 }; + DwmExtendFrameIntoClientArea(hwnd, &margins); } } else { // child. SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, swpFlags); @@ -1191,19 +1158,26 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry, bool QWindowsGeometryHint::handleCalculateSize(const QWindow *window, const QMargins &customMargins, const MSG &msg, LRESULT *result) { + // Prevent adding any border for frameless window + if (msg.wParam && window->flags() & Qt::FramelessWindowHint) { + *result = 0; + return true; + } + const QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window); + // In case the platformwindow was not yet created, use the initial windowflags provided by the user. + const bool clientAreaExpanded = platformWindow != nullptr ? platformWindow->isClientAreaExpanded() : window->flags() & Qt::ExpandedClientAreaHint; // Return 0 to remove the window's border - const bool clientAreaExpanded = window->flags() & Qt::ExpandedClientAreaHint; if (msg.wParam && clientAreaExpanded) { // Prevent content from being cutoff by border for maximized, but not fullscreened windows. - if (IsZoomed(msg.hwnd) && window->visibility() != QWindow::FullScreen) { - auto *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); - RECT *clientArea = &ncp->rgrc[0]; - const int border = getResizeBorderThickness(QWindowsWindow::windowsWindowOf(window)->savedDpi()); + const bool maximized = IsZoomed(msg.hwnd) && window->visibility() != QWindow::FullScreen; + auto *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); + RECT *clientArea = &ncp->rgrc[0]; + const int border = getResizeBorderThickness(96); + if (maximized) clientArea->top += border; - clientArea->bottom -= border; - clientArea->left += border; - clientArea->right -= border; - } + clientArea->bottom -= border; + clientArea->left += border; + clientArea->right -= border; *result = 0; return true; } @@ -1623,6 +1597,12 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) #endif { QWindowsContext::instance()->addWindow(m_data.hwnd, this); + + if (aWindow->flags().testFlags(Qt::ExpandedClientAreaHint)) { + SetParent(m_data.hwndTitlebar, m_data.hwnd); + ShowWindow(m_data.hwndTitlebar, SW_SHOW); + } + const Qt::WindowType type = aWindow->type(); if (type == Qt::Desktop) return; // No further handling for Qt::Desktop @@ -1847,21 +1827,6 @@ QWindow *QWindowsWindow::topLevelOf(QWindow *w) return w; } -// Checks whether the Window is tiled with Aero snap -bool QWindowsWindow::isWindowArranged(HWND hwnd) -{ - typedef BOOL(WINAPI* PIsWindowArranged)(HWND); - static PIsWindowArranged pIsWindowArranged = nullptr; - static bool resolved = false; - if (!resolved) { - resolved = true; - pIsWindowArranged = (PIsWindowArranged)QSystemLibrary::resolve(QLatin1String("user32.dll"), "IsWindowArranged"); - } - if (pIsWindowArranged == nullptr) - return false; - return pIsWindowArranged(hwnd); -} - QWindowsWindowData QWindowsWindowData::create(const QWindow *w, const QWindowsWindowData ¶meters, @@ -1903,13 +1868,6 @@ void QWindowsWindow::setVisible(bool visible) fireExpose(QRegion()); } } - if (m_data.hwndTitlebar) { - if (visible) { - SetWindowPos(m_data.hwndTitlebar, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } else { - ShowWindow(m_data.hwndTitlebar, SW_HIDE); - } - } } bool QWindowsWindow::isVisible() const @@ -2050,10 +2008,6 @@ void QWindowsWindow::show_sys() const setFlag(WithinMaximize); // QTBUG-8361 ShowWindow(m_data.hwnd, sm); - if (m_data.flags.testFlag(Qt::ExpandedClientAreaHint)) { - ShowWindow(m_data.hwndTitlebar, sm); - SetActiveWindow(m_data.hwnd); - } clearFlag(WithinMaximize); @@ -2245,7 +2199,7 @@ QRect QWindowsWindow::normalGeometry() const QMargins QWindowsWindow::safeAreaMargins() const { if (m_data.flags.testFlags(Qt::ExpandedClientAreaHint)) { - const int titleBarHeight = getTitleBarHeight_sys(savedDpi()); + const int titleBarHeight = getTitleBarHeight_sys(96); return QMargins(0, titleBarHeight, 0, 0); } @@ -2457,15 +2411,9 @@ void QWindowsWindow::handleGeometryChange() clearFlag(SynchronousGeometryChangeEvent); qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry; - if (m_data.hwndTitlebar) { - bool arranged = QWindowsWindow::isWindowArranged(m_data.hwnd); - if (arranged || (m_windowWasArranged && !arranged)) - transitionAnimatedCustomTitleBar(); - + if (m_data.flags & Qt::ExpandedClientAreaHint) { const int titleBarHeight = getTitleBarHeight_sys(savedDpi()); - MoveWindow(m_data.hwndTitlebar, m_data.geometry.x(), m_data.geometry.y(), - m_data.geometry.width(), titleBarHeight, true); - m_windowWasArranged = arranged; + MoveWindow(m_data.hwndTitlebar, 0, 0, m_data.geometry.width(), titleBarHeight, true); } } @@ -2627,6 +2575,16 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, creationData.applyWindowFlags(m_data.hwnd); creationData.initialize(window(), m_data.hwnd, true, m_opacity); + if (creationData.flags.testFlag(Qt::ExpandedClientAreaHint)) { + SetParent(m_data.hwndTitlebar, m_data.hwnd); + ShowWindow(m_data.hwndTitlebar, SW_SHOW); + } else { + if (IsWindowVisible(m_data.hwndTitlebar)) { + SetParent(m_data.hwndTitlebar, HWND_MESSAGE); + ShowWindow(m_data.hwndTitlebar, SW_HIDE); + } + } + QWindowsWindowData result = m_data; result.flags = creationData.flags; result.embedded = creationData.embedded; @@ -2645,7 +2603,7 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) handleHidden(); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // Tell QQuickWindow to stop rendering now. } else { - transitionAnimatedCustomTitleBar(); + updateCustomTitlebar(); if (state & Qt::WindowMaximized) { WINDOWPLACEMENT windowPlacement{}; windowPlacement.length = sizeof(WINDOWPLACEMENT); @@ -2743,20 +2701,6 @@ void QWindowsWindow::correctWindowPlacement(WINDOWPLACEMENT &windowPlacement) } } -void QWindowsWindow::transitionAnimatedCustomTitleBar() -{ - if (!m_data.hwndTitlebar) - return; - const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Control Panel\Desktop\WindowMetrics)"); - if (registry.isValid() && registry.value(LR"(MinAnimate)") == 1) { - ShowWindow(m_data.hwndTitlebar, SW_HIDE); - SetTimer(m_data.hwndTitlebar, 1, 200, nullptr); - } else { - ShowWindow(m_data.hwndTitlebar, SW_SHOWNOACTIVATE); - updateCustomTitlebar(); - } -} - void QWindowsWindow::updateRestoreGeometry() { m_data.restoreGeometry = normalFrameGeometry(m_data.hwnd); @@ -3078,7 +3022,8 @@ void QWindowsWindow::calculateFullFrameMargins() const auto systemMargins = testFlag(DisableNonClientScaling) ? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd) : frameMargins_sys(); - const QMargins actualMargins = systemMargins + customMargins(); + const int extendedClientAreaBorder = window()->flags().testFlag(Qt::ExpandedClientAreaHint) ? qRound(QHighDpiScaling::factor(window())) * 2 : 0; + const QMargins actualMargins = systemMargins + customMargins() - extendedClientAreaBorder; const int yDiff = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top); const bool typicalFrame = (actualMargins.left() == actualMargins.right()) @@ -3517,19 +3462,6 @@ bool QWindowsWindow::handleNonClientActivate(LRESULT *result) const return false; } -static void _q_drawCustomTitleBarButton(QPainter& p, const QRectF& r) -{ - QPainterPath path(QPointF(r.x(), r.y())); - QRectF rightCorner(r.x() + r.width() - 2.0, r.y() + 4.0, 2, 2); - QRectF leftCorner(r.x(), r.y() + 4, 2, 2); - path.lineTo(r.x() + r.width() - 5.0f, r.y()); - path.arcTo(rightCorner, 90, -90); - path.lineTo(r.x() + r.width(), r.y() + r.height() - 1); - path.lineTo(r.x(), r.y() + r.height() - 1); - path.closeSubpath(); - p.drawPath(path); -} - void QWindowsWindow::updateCustomTitlebar() { HWND hwnd = m_data.hwndTitlebar; @@ -3545,7 +3477,7 @@ void QWindowsWindow::updateCustomTitlebar() POINT localPos; GetCursorPos(&localPos); - MapWindowPoints(HWND_DESKTOP, hwnd, &localPos, 1); + MapWindowPoints(HWND_DESKTOP, m_data.hwnd, &localPos, 1); const bool isDarkmode = QWindowsIntegration::instance()->darkModeHandling().testFlags(QWindowsApplication::DarkModeWindowFrames) && qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark; @@ -3567,25 +3499,9 @@ void QWindowsWindow::updateCustomTitlebar() p.setPen(Qt::NoPen); if (!wnd->flags().testFlags(Qt::NoTitleBarBackgroundHint)) { QRect titleRect; - titleRect.setX(2); titleRect.setWidth(windowWidth); titleRect.setHeight(titleBarHeight); - - if (isWindows11orAbove) { - QPainterPath path(QPointF(titleRect.x() + 4.0f, titleRect.y())); - QRectF rightCorner(titleRect.x() + titleRect.width() - 4.0, titleRect.y() + 4.0, 2, 2); - QRectF leftCorner(titleRect.x(), titleRect.y() + 4, 2, 2); - path.lineTo(titleRect.x() + titleRect.width() - 7.0f, titleRect.y()); - path.arcTo(rightCorner, 90, -90); - path.lineTo(titleRect.x() + titleRect.width() - 2.0, titleRect.y() + titleRect.height() - 1); - path.lineTo(titleRect.x(), titleRect.y() + titleRect.height() - 1); - path.lineTo(titleRect.x(), titleRect.y() + 4.0f); - path.arcTo(leftCorner, -90, -90); - path.closeSubpath(); - p.drawPath(path); - } else { - p.drawRect(titleRect); - } + p.drawRect(titleRect); } if (wnd->flags().testFlags(Qt::WindowTitleHint | Qt::CustomizeWindowHint) || !wnd->flags().testFlag(Qt::CustomizeWindowHint)) { @@ -3631,15 +3547,12 @@ void QWindowsWindow::updateCustomTitlebar() QRectF rect; rect.setY(1); rect.setX(windowWidth - titleButtonWidth * buttons); - rect.setWidth(titleButtonWidth - 1); + rect.setWidth(titleButtonWidth); rect.setHeight(titleBarHeight); if (localPos.x > (windowWidth - buttons * titleButtonWidth) && localPos.x < (windowWidth - (buttons - 1) * titleButtonWidth) && localPos.y > rect.y() && localPos.y < rect.y() + rect.height()) { - if (isWindows11orAbove && buttons == 1) - _q_drawCustomTitleBarButton(p, rect); - else - p.drawRect(rect); + p.drawRect(rect); const QPen closeButtonHoveredPen = QPen(QColor(0xFF, 0xFF, 0xFD, 0xFF)); p.setPen(closeButtonHoveredPen); } else { @@ -3655,15 +3568,12 @@ void QWindowsWindow::updateCustomTitlebar() QRectF rect; rect.setY(1); rect.setX(windowWidth - titleButtonWidth * buttons); - rect.setWidth(titleButtonWidth - 1); + rect.setWidth(titleButtonWidth); rect.setHeight(titleBarHeight); if (localPos.x > (windowWidth - buttons * titleButtonWidth) && localPos.x < (windowWidth - (buttons - 1) * titleButtonWidth) && localPos.y > rect.y() && localPos.y < rect.y() + rect.height()) { - if (isWindows11orAbove && buttons == 1) - _q_drawCustomTitleBarButton(p, rect); - else - p.drawRect(rect); + p.drawRect(rect); } p.setPen(textPen); p.drawText(rect,QStringLiteral("\uE922"), QTextOption(Qt::AlignVCenter | Qt::AlignHCenter)); @@ -3676,15 +3586,12 @@ void QWindowsWindow::updateCustomTitlebar() QRectF rect; rect.setY(1); rect.setX(windowWidth - titleButtonWidth * buttons); - rect.setWidth(titleButtonWidth - 1); + rect.setWidth(titleButtonWidth); rect.setHeight(titleBarHeight); if (localPos.x > (windowWidth - buttons * titleButtonWidth) && localPos.x < (windowWidth - (buttons - 1) * titleButtonWidth) && localPos.y > rect.y() && localPos.y < rect.y() + rect.height()) { - if (isWindows11orAbove && buttons == 1) - _q_drawCustomTitleBarButton(p, rect); - else - p.drawRect(rect); + p.drawRect(rect); } p.setPen(textPen); p.drawText(rect,QStringLiteral("\uE921"), QTextOption(Qt::AlignVCenter | Qt::AlignHCenter)); @@ -3702,7 +3609,7 @@ void QWindowsWindow::updateCustomTitlebar() BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - POINT ptLocation = { windowRect.left, windowRect.top }; + POINT ptLocation = { 0, 0 }; SIZE szWnd = { windowWidth, titleBarHeight }; POINT ptSrc = { 0, 0 }; UpdateLayeredWindow(hwnd, hdc, &ptLocation, &szWnd, memdc, &ptSrc, 0, &blend, ULW_ALPHA); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index b67bd2850b3..a0e150aeb01 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -307,7 +307,6 @@ public: static QWindow *topLevelOf(QWindow *w); static inline void *userDataOf(HWND hwnd); static inline void setUserDataOf(HWND hwnd, void *ud); - static bool isWindowArranged(HWND hwnd); static bool hasNoNativeFrame(HWND hwnd, Qt::WindowFlags flags); static bool setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity); @@ -359,12 +358,10 @@ public: int savedDpi() const { return m_savedDpi; } qreal dpiRelativeScale(const UINT dpi) const; - bool isFrameless() const { return m_data.flags.testFlag(Qt::FramelessWindowHint); } + bool isClientAreaExpanded() const { return m_data.flags.testFlag(Qt::ExpandedClientAreaHint); } void requestUpdate() override; - void transitionAnimatedCustomTitleBar(); - private: inline void show_sys() const; inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 8353fac6a92..fda47944d9d 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -870,7 +870,8 @@ QPlatformBackingStore::FlushResult QXcbBackingStore::rhiFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) + bool translucentBackground, + qreal sourceTransformFactor) { if (!m_image || m_image->size().isEmpty()) return FlushFailed; @@ -878,7 +879,7 @@ QPlatformBackingStore::FlushResult QXcbBackingStore::rhiFlush(QWindow *window, m_image->flushScrolledRegion(true); auto result = QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, region, offset, - textures, translucentBackground); + textures, translucentBackground, sourceTransformFactor); if (result != FlushSuccess) return result; QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle()); diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index 674640780eb..5cda9e1ab79 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -27,7 +27,8 @@ public: const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) override; + bool translucentBackground, + qreal sourceTransformFactor) override; QImage toImage() const override; QPlatformGraphicsBuffer *graphicsBuffer() const override; |