File 3008-QPA-offscreen-make-platform-plugin-configurable.patch of Package libqt5-qtbase

From 142737ebd5060c90aac08c549ea3e8086a16395b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= <morten.sorvig@qt.io>
Date: Mon, 3 Feb 2020 23:03:29 +0100
Subject: [PATCH 3008/3009] QPA offscreen: make platform plugin configurable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add ability to load a json config file containing screen
configuration at startup. The config file location
is specified using platform options:

    -platform offscfreen:configfile=/path/to/file

Config file format example:
{
    “screens”: [
        {
        "name", "screen-1",
        "x", 0,
        "y", 0,
        "width", 640,
        "height", 480,
        "dpi", 96,
        "dpr", 1,
        },
        …
    ]
}

Change-Id: Iac21aaafa6d0f361bdd6f6e9168b7e68db6ae011
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
(cherry picked from commit f4a66e5c4c4be97a7511b372930e20f330ea0813)
---
 .../platforms/offscreen/qoffscreencommon.h    |  13 +-
 .../offscreen/qoffscreenintegration.h         |   6 +-
 .../platforms/offscreen/qoffscreenwindow.h    |   3 +-
 src/plugins/platforms/offscreen/main.cpp      |   3 +-
 .../platforms/offscreen/qoffscreencommon.cpp  |  11 +-
 .../offscreen/qoffscreenintegration.cpp       | 112 +++++++++++++++++-
 .../platforms/offscreen/qoffscreenwindow.cpp  |  16 +--
 7 files changed, 144 insertions(+), 20 deletions(-)

diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.h b/src/plugins/platforms/offscreen/qoffscreencommon.h
index f4f0142911..abb641fbbc 100644
--- a/src/plugins/platforms/offscreen/qoffscreencommon.h
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.h
@@ -54,23 +54,34 @@
 
 QT_BEGIN_NAMESPACE
 
+class QOffscreenIntegration;
 class QOffscreenScreen : public QPlatformScreen
 {
 public:
-    QOffscreenScreen();
+    QOffscreenScreen(const QOffscreenIntegration *integration);
 
     QRect geometry() const override { return m_geometry; }
     int depth() const override { return 32; }
     QImage::Format format() const override { return QImage::Format_RGB32; }
+    QDpi logicalDpi() const override { return QDpi(m_logicalDpi, m_logicalDpi); }
+    QDpi logicalBaseDpi() const override { return QDpi(m_logicalBaseDpi, m_logicalBaseDpi); }
+    qreal devicePixelRatio() const override { return m_dpr; }
+    QString name() const override { return m_name; }
     QPlatformCursor *cursor() const override { return m_cursor.data(); }
+    QList<QPlatformScreen *> virtualSiblings() const override;
 
     QPixmap grabWindow(WId window, int x, int y, int width, int height) const override;
 
     static QPlatformWindow *windowContainingCursor;
 
 public:
+    QString m_name;
     QRect m_geometry;
+    int m_logicalDpi = 96;
+    int m_logicalBaseDpi= 96;
+    qreal m_dpr = 1;
     QScopedPointer<QPlatformCursor> m_cursor;
+    const QOffscreenIntegration *m_integration;
 };
 
 #if QT_CONFIG(draganddrop)
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h
index 098e726550..be47313913 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.h
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h
@@ -55,6 +55,7 @@ public:
     QOffscreenIntegration();
     ~QOffscreenIntegration();
 
+    void configure(const QStringList& paramList);
     void initialize() override;
     bool hasCapability(QPlatformIntegration::Capability cap) const override;
 
@@ -73,8 +74,9 @@ public:
     QStringList themeNames() const override;
     QPlatformTheme *createPlatformTheme(const QString &name) const override;
 
-    static QOffscreenIntegration *createOffscreenIntegration();
+    static QOffscreenIntegration *createOffscreenIntegration(const QStringList& paramList);
 
+    QList<QPlatformScreen *> screens() const;
 private:
     QScopedPointer<QPlatformFontDatabase> m_fontDatabase;
 #if QT_CONFIG(draganddrop)
@@ -82,6 +84,8 @@ private:
 #endif
     QScopedPointer<QPlatformInputContext> m_inputContext;
     QScopedPointer<QPlatformServices> m_services;
+    QList<QPlatformScreen *> m_screens;
+    bool m_windowFrameMarginsEnabled = true;
 };
 
 QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.h b/src/plugins/platforms/offscreen/qoffscreenwindow.h
index e1f37bb034..32b8ca33cb 100644
--- a/src/plugins/platforms/offscreen/qoffscreenwindow.h
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.h
@@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE
 class QOffscreenWindow : public QPlatformWindow
 {
 public:
-    QOffscreenWindow(QWindow *window);
+    QOffscreenWindow(QWindow *window, bool frameMarginsEnabled);
     ~QOffscreenWindow();
 
     void setGeometry(const QRect &rect) override;
@@ -74,6 +74,7 @@ private:
     bool m_positionIncludesFrame;
     bool m_visible;
     bool m_pendingGeometryChangeOnShow;
+    bool m_frameMarginsRequested;
     WId m_winId;
 
     static QHash<WId, QOffscreenWindow *> m_windowForWinIdHash;
diff --git a/src/plugins/platforms/offscreen/main.cpp b/src/plugins/platforms/offscreen/main.cpp
index f364d9f004..6b696ed073 100644
--- a/src/plugins/platforms/offscreen/main.cpp
+++ b/src/plugins/platforms/offscreen/main.cpp
@@ -53,9 +53,8 @@ public:
 
 QPlatformIntegration *QOffscreenIntegrationPlugin::create(const QString& system, const QStringList& paramList)
 {
-    Q_UNUSED(paramList);
     if (!system.compare(QLatin1String("offscreen"), Qt::CaseInsensitive))
-        return QOffscreenIntegration::createOffscreenIntegration();
+        return QOffscreenIntegration::createOffscreenIntegration(paramList);
 
     return nullptr;
 }
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.cpp b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
index de75a3e012..3d02721869 100644
--- a/src/plugins/platforms/offscreen/qoffscreencommon.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
@@ -38,8 +38,10 @@
 ****************************************************************************/
 
 #include "qoffscreencommon.h"
+#include "qoffscreenintegration.h"
 #include "qoffscreenwindow.h"
 
+
 #include <QtGui/private/qpixmap_raster_p.h>
 #include <QtGui/private/qguiapplication_p.h>
 
@@ -50,6 +52,12 @@ QT_BEGIN_NAMESPACE
 
 QPlatformWindow *QOffscreenScreen::windowContainingCursor = nullptr;
 
+
+QList<QPlatformScreen *> QOffscreenScreen::virtualSiblings() const
+{
+    return m_integration->screens();
+}
+
 class QOffscreenCursor : public QPlatformCursor
 {
 public:
@@ -93,9 +101,10 @@ private:
     QPoint m_pos;
 };
 
-QOffscreenScreen::QOffscreenScreen()
+QOffscreenScreen::QOffscreenScreen(const QOffscreenIntegration *integration)
     : m_geometry(0, 0, 800, 600)
     , m_cursor(new QOffscreenCursor)
+    , m_integration(integration)
 {
 }
 
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
index 3a4494fc2e..520fe5ab20 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -58,6 +58,11 @@
 #endif
 #endif
 
+#include <QtCore/qfile.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
 #include <QtGui/private/qpixmap_raster_p.h>
 #include <QtGui/private/qguiapplication_p.h>
 #include <qpa/qplatforminputcontextfactory_p.h>
@@ -121,14 +126,98 @@ QOffscreenIntegration::QOffscreenIntegration()
     m_drag.reset(new QOffscreenDrag);
 #endif
     m_services.reset(new QPlatformServices);
-
-    QWindowSystemInterface::handleScreenAdded(new QOffscreenScreen);
 }
 
 QOffscreenIntegration::~QOffscreenIntegration()
 {
 }
 
+/*
+    The offscren platform plugin is configurable with a JSON configuration
+    file. Write the config to disk and pass the file path as a platform argument:
+
+        ./myapp -platform offscreen:configfile=/path/to/config.json
+
+    The supported top-level config keys are:
+    {
+        "synchronousWindowSystemEvents": <bool>
+        "windowFrameMargins": <bool>,
+        "screens": [<screens>],
+    }
+
+    Screen:
+    {
+        "name" : string,
+        "x": int,
+        "y": int,
+        "width": int,
+        "height": int,
+        "logicalDpi": int,
+        "logicalBaseDpi": int,
+        "dpr": double,
+    }
+*/
+void QOffscreenIntegration::configure(const QStringList& paramList)
+{
+    // Use config file configuring platform plugin, if one was specified
+    bool hasConfigFile = false;
+    QString configFilePath;
+    for (const QString &param : paramList) {
+        // Look for "configfile=/path/to/file/"
+        QString configPrefix(QLatin1String("configfile="));
+        if (param.startsWith(configPrefix)) {
+            hasConfigFile = true;
+            configFilePath= param.mid(configPrefix.length());
+        }
+    }
+
+    // Create the default screen if there was no config file
+    if (!hasConfigFile) {
+        QOffscreenScreen *offscreenScreen = new QOffscreenScreen(this);
+        m_screens.append(offscreenScreen);
+        QWindowSystemInterface::handleScreenAdded(offscreenScreen);
+        return;
+    }
+
+    // Read config file
+    if (configFilePath.isEmpty())
+        qFatal("Missing file path for -configfile platform option");
+    QFile configFile(configFilePath);
+    if (!configFile.exists())
+        qFatal("Could not find platform config file %s", qPrintable(configFilePath));
+    if (!configFile.open(QIODevice::ReadOnly))
+        qFatal("Could not open platform config file for reading %s, %s", qPrintable(configFilePath), qPrintable(configFile.errorString()));
+
+    QByteArray json = configFile.readAll();
+    QJsonParseError error;
+    QJsonDocument config = QJsonDocument::fromJson(json, &error);
+    if (config.isNull())
+        qFatal("Platform config file parse error: %s", qPrintable(error.errorString()));
+
+    // Apply configuration (create screens)
+    bool synchronousWindowSystemEvents = config["synchronousWindowSystemEvents"].toBool(false);
+    QWindowSystemInterface::setSynchronousWindowSystemEvents(synchronousWindowSystemEvents);
+    m_windowFrameMarginsEnabled = config["windowFrameMargins"].toBool(true);
+    QJsonArray screens = config["screens"].toArray();
+    for (QJsonValue screenValue : screens) {
+        QJsonObject screen  = screenValue.toObject();
+        if (screen.isEmpty()) {
+            qWarning("QOffscreenIntegration::initializeWithPlatformArguments: empty screen object");
+            continue;
+        }
+        QOffscreenScreen *offscreenScreen = new QOffscreenScreen(this);
+        offscreenScreen->m_name = screen["name"].toString();
+        offscreenScreen->m_geometry = QRect(screen["x"].toInt(0), screen["y"].toInt(0),
+                                            screen["width"].toInt(640), screen["height"].toInt(480));
+        offscreenScreen->m_logicalDpi = screen["logicalDpi"].toInt(96);
+        offscreenScreen->m_logicalBaseDpi = screen["logicalBaseDpi"].toInt(96);
+        offscreenScreen->m_dpr = screen["dpr"].toDouble(1.0);
+
+        m_screens.append(offscreenScreen);
+        QWindowSystemInterface::handleScreenAdded(offscreenScreen);
+    }
+}
+
 void QOffscreenIntegration::initialize()
 {
     m_inputContext.reset(QPlatformInputContextFactory::create());
@@ -151,7 +240,7 @@ bool QOffscreenIntegration::hasCapability(QPlatformIntegration::Capability cap)
 QPlatformWindow *QOffscreenIntegration::createPlatformWindow(QWindow *window) const
 {
     Q_UNUSED(window);
-    QPlatformWindow *w = new QOffscreenWindow(window);
+    QPlatformWindow *w = new QOffscreenWindow(window, m_windowFrameMarginsEnabled);
     w->requestActivateWindow();
     return w;
 }
@@ -224,14 +313,25 @@ QPlatformServices *QOffscreenIntegration::services() const
     return m_services.data();
 }
 
-QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration()
+QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration(const QStringList& paramList)
 {
+    QOffscreenIntegration *offscreenIntegration = nullptr;
+
 #if QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2)
     QByteArray glx = qgetenv("QT_QPA_OFFSCREEN_NO_GLX");
     if (glx.isEmpty())
-        return new QOffscreenX11Integration;
+        offscreenIntegration = new QOffscreenX11Integration;
+#else
+    offscreenIntegration = new QOffscreenIntegration;
 #endif
-    return new QOffscreenIntegration;
+
+    offscreenIntegration->configure(paramList);
+    return offscreenIntegration;
+}
+
+QList<QPlatformScreen *> QOffscreenIntegration::screens() const
+{
+    return m_screens;
 }
 
 QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
index 53880c877e..a46258a401 100644
--- a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
@@ -47,18 +47,18 @@
 
 QT_BEGIN_NAMESPACE
 
-QOffscreenWindow::QOffscreenWindow(QWindow *window)
+QOffscreenWindow::QOffscreenWindow(QWindow *window, bool frameMarginsEnabled)
     : QPlatformWindow(window)
     , m_positionIncludesFrame(false)
     , m_visible(false)
     , m_pendingGeometryChangeOnShow(true)
+    , m_frameMarginsRequested(frameMarginsEnabled)
 {
-    if (window->windowState() == Qt::WindowNoState)
-        setGeometry(window->geometry());
-    else
+    if (window->windowState() == Qt::WindowNoState) {
+        setGeometry(windowGeometry());
+    } else {
         setWindowState(window->windowStates());
-
-    QWindowSystemInterface::flushWindowSystemEvents();
+    }
 
     static WId counter = 0;
     m_winId = ++counter;
@@ -80,7 +80,7 @@ void QOffscreenWindow::setGeometry(const QRect &rect)
 
     m_positionIncludesFrame = qt_window_private(window())->positionPolicy == QWindowPrivate::WindowFrameInclusive;
 
-    setFrameMarginsEnabled(true);
+    setFrameMarginsEnabled(m_frameMarginsRequested);
     setGeometryImpl(rect);
 
     m_normalGeometry = geometry();
@@ -168,7 +168,7 @@ void QOffscreenWindow::setFrameMarginsEnabled(bool enabled)
 
 void QOffscreenWindow::setWindowState(Qt::WindowStates state)
 {
-    setFrameMarginsEnabled(!(state & Qt::WindowFullScreen));
+    setFrameMarginsEnabled(m_frameMarginsRequested && !(state & Qt::WindowFullScreen));
     m_positionIncludesFrame = false;
 
     if (state & Qt::WindowMinimized)
-- 
2.29.2

openSUSE Build Service is sponsored by