summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/android/CMakeLists.txt5
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp130
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm18
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscontext.cpp6
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration.cpp4
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration_p.h1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp46
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp42
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h5
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp58
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp35
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h7
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp5
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp21
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h6
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm50
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm3
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h2
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm4
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm2
-rw-r--r--src/plugins/platforms/ios/quiview.mm3
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp13
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp5
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp209
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp5
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h3
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 &region,
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 &region,
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 &parameters,
@@ -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 &region,
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 &region,
const QPoint &offset,
QPlatformTextureList *textures,
- bool translucentBackground) override;
+ bool translucentBackground,
+ qreal sourceTransformFactor) override;
QImage toImage() const override;
QPlatformGraphicsBuffer *graphicsBuffer() const override;