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/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.cpp45
-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/windows/qwindowscontext.cpp1
21 files changed, 361 insertions, 29 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/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..9f19e649f85 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
@@ -113,13 +113,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 +141,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 +155,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/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 38b3bdadd35..3fe837a2c03 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -1219,6 +1219,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;