summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/offscreen/qoffscreenintegration.cpp')
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.cpp260
1 files changed, 182 insertions, 78 deletions
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
index 14218bb537..ea8042928a 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoffscreenintegration.h"
#include "qoffscreenwindow.h"
@@ -74,6 +38,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QCoreTextFontEngine;
template <typename BaseEventDispatcher>
@@ -93,7 +59,7 @@ public:
}
};
-QOffscreenIntegration::QOffscreenIntegration()
+QOffscreenIntegration::QOffscreenIntegration(const QStringList& paramList)
{
#if defined(Q_OS_UNIX)
#if defined(Q_OS_MAC)
@@ -109,15 +75,24 @@ QOffscreenIntegration::QOffscreenIntegration()
m_drag.reset(new QOffscreenDrag);
#endif
m_services.reset(new QPlatformServices);
+
+ QJsonObject config = resolveConfigFileConfiguration(paramList).value_or(defaultConfiguration());
+ setConfiguration(config);
}
QOffscreenIntegration::~QOffscreenIntegration()
{
+ while (!m_screens.isEmpty())
+ QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast());
}
/*
- 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:
+ The offscren platform plugin is configurable with a JSON configuration.
+ The confiuration can be provided either from a file on disk on startup,
+ or at by calling setConfiguration().
+
+ To provide a configuration on startuip, write the config to disk and pass
+ the file path as a platform argument:
./myapp -platform offscreen:configfile=/path/to/config.json
@@ -128,9 +103,9 @@ QOffscreenIntegration::~QOffscreenIntegration()
"screens": [<screens>],
}
- Screen:
+ "screens" is an array of:
{
- "name" : string,
+ "name": string,
"x": int,
"y": int,
"width": int,
@@ -140,27 +115,41 @@ QOffscreenIntegration::~QOffscreenIntegration()
"dpr": double,
}
*/
-void QOffscreenIntegration::configure(const QStringList& paramList)
+
+QJsonObject QOffscreenIntegration::defaultConfiguration() const
+{
+ const auto defaultScreen = QJsonObject {
+ {"name", ""},
+ {"x", 0},
+ {"y", 0},
+ {"width", 800},
+ {"height", 800},
+ {"logicalDpi", 96},
+ {"logicalBaseDpi", 96},
+ {"dpr", 1.0},
+ };
+ const auto defaultConfiguration = QJsonObject {
+ {"synchronousWindowSystemEvents", false},
+ {"windowFrameMargins", true},
+ {"screens", QJsonArray { defaultScreen } },
+ };
+ return defaultConfiguration;
+}
+
+std::optional<QJsonObject> QOffscreenIntegration::resolveConfigFileConfiguration(const QStringList& paramList) const
{
- // 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="));
+ QString configPrefix("configfile="_L1);
if (param.startsWith(configPrefix)) {
hasConfigFile = true;
- configFilePath= param.mid(configPrefix.length());
+ configFilePath = param.mid(configPrefix.size());
}
}
-
- // 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;
- }
+ if (!hasConfigFile)
+ return std::nullopt;
// Read config file
if (configFilePath.isEmpty())
@@ -177,28 +166,145 @@ void QOffscreenIntegration::configure(const QStringList& paramList)
if (config.isNull())
qFatal("Platform config file parse error: %s", qPrintable(error.errorString()));
- // Apply configuration (create screens)
- bool synchronousWindowSystemEvents = config["synchronousWindowSystemEvents"].toBool(false);
+ return config.object();
+}
+
+
+void QOffscreenIntegration::setConfiguration(const QJsonObject &configuration)
+{
+ // Apply the new configuration, diffing against the current m_configuration
+
+ const bool synchronousWindowSystemEvents = configuration["synchronousWindowSystemEvents"].toBool(
+ m_configuration["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");
+
+ m_windowFrameMarginsEnabled = configuration["windowFrameMargins"].toBool(
+ m_configuration["windowFrameMargins"].toBool(true));
+
+ // Diff screens array, using the screen name as the screen identity.
+ QJsonArray currentScreens = m_configuration["screens"].toArray();
+ QJsonArray newScreens = configuration["screens"].toArray();
+
+ auto getScreenNames = [](const QJsonArray &screens) -> QList<QString> {
+ QList<QString> names;
+ for (QJsonValue screen : screens) {
+ names.append(screen["name"].toString());
+ };
+ std::sort(names.begin(), names.end());
+ return names;
+ };
+
+ auto currentNames = getScreenNames(currentScreens);
+ auto newNames = getScreenNames(newScreens);
+
+ QList<QString> present;
+ std::set_intersection(currentNames.begin(), currentNames.end(), newNames.begin(), newNames.end(),
+ std::inserter(present, present.begin()));
+ QList<QString> added;
+ std::set_difference(newNames.begin(), newNames.end(), currentNames.begin(), currentNames.end(),
+ std::inserter(added, added.begin()));
+ QList<QString> removed;
+ std::set_difference(currentNames.begin(), currentNames.end(), newNames.begin(), newNames.end(),
+ std::inserter(removed, removed.begin()));
+
+ auto platformScreenByName = [](const QString &name, QList<QOffscreenScreen *> screens) -> QOffscreenScreen * {
+ for (QOffscreenScreen *screen : screens) {
+ if (screen->m_name == name)
+ return screen;
+ }
+ Q_UNREACHABLE();
+ };
+
+ auto screenConfigByName = [](const QString &name, QJsonArray screenConfigs) -> QJsonValue {
+ for (QJsonValue screenConfig : screenConfigs) {
+ if (screenConfig["name"].toString() == name)
+ return screenConfig;
+ }
+ Q_UNREACHABLE();
+ };
+
+ auto geometryFromConfig = [](const QJsonObject &config) -> QRect {
+ return QRect(config["x"].toInt(0), config["y"].toInt(0), config["width"].toInt(640), config["height"].toInt(480));
+ };
+
+ // Remove removed screens
+ for (const QString &remove : removed) {
+ QOffscreenScreen *screen = platformScreenByName(remove, m_screens);
+ m_screens.removeAll(screen);
+ QWindowSystemInterface::handleScreenRemoved(screen);
+ }
+
+ // Add new screens
+ for (const QString &add : added) {
+ QJsonValue configValue = screenConfigByName(add, newScreens);
+ QJsonObject config = configValue.toObject();
+ if (config.isEmpty()) {
+ qWarning("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);
-
+ offscreenScreen->m_name = config["name"].toString();
+ offscreenScreen->m_geometry = geometryFromConfig(config);
+ offscreenScreen->m_logicalDpi = config["logicalDpi"].toInt(96);
+ offscreenScreen->m_logicalBaseDpi = config["logicalBaseDpi"].toInt(96);
+ offscreenScreen->m_dpr = config["dpr"].toDouble(1.0);
m_screens.append(offscreenScreen);
QWindowSystemInterface::handleScreenAdded(offscreenScreen);
}
+
+ // Update present screens
+ for (const QString &pres : present) {
+ QOffscreenScreen *screen = platformScreenByName(pres, m_screens);
+ Q_ASSERT(screen);
+ QJsonObject currentConfig = screenConfigByName(pres, currentScreens).toObject();
+ QJsonObject newConfig = screenConfigByName(pres, newScreens).toObject();
+
+ // Name can't change, because it'd be a different screen
+ Q_ASSERT(currentConfig["name"] == newConfig["name"]);
+
+ // Geometry
+ QRect currentGeomtry = geometryFromConfig(currentConfig);
+ QRect newGeomtry = geometryFromConfig(newConfig);
+ if (currentGeomtry != newGeomtry) {
+ screen->m_geometry = newGeomtry;
+ QWindowSystemInterface::handleScreenGeometryChange(screen->screen(), newGeomtry, newGeomtry);
+ }
+
+ // logical DPI
+ int currentLogicalDpi = currentConfig["logicalDpi"].toInt(96);
+ int newLogicalDpi = newConfig["logicalDpi"].toInt(96);
+ if (currentLogicalDpi != newLogicalDpi) {
+ screen->m_logicalDpi = newLogicalDpi;
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->screen(), newLogicalDpi, newLogicalDpi);
+ }
+
+ // The base DPI is more of a platform constant, and should not change, and
+ // there is no handleChange function for it. Print a warning.
+ int currentLogicalBaseDpi = currentConfig["logicalBaseDpi"].toInt(96);
+ int newLogicalBaseDpi = newConfig["logicalBaseDpi"].toInt(96);
+ if (currentLogicalBaseDpi != newLogicalBaseDpi) {
+ screen->m_logicalBaseDpi = newLogicalBaseDpi;
+ qWarning("You ain't supposed to change logicalBaseDpi - its a platform constant. Qt may not react to the change");
+ }
+
+ // DPR. There is also no handleChange function in Qt at this point, instead
+ // the new DPR value will be used during the next repaint. We could repaint
+ // all windows here, but don't. Print a warning.
+ double currentDpr = currentConfig["dpr"].toDouble(1);
+ double newDpr = newConfig["dpr"].toDouble(1);
+ if (currentDpr != newDpr) {
+ screen->m_dpr = newDpr;
+ qWarning("DPR change notifications is not implemented - Qt may not react to the change");
+ }
+ }
+
+ // Now the new configuration is the current configuration
+ m_configuration = configuration;
+}
+
+QJsonObject QOffscreenIntegration::configuration() const
+{
+ return m_configuration;
}
void QOffscreenIntegration::initialize()
@@ -248,7 +354,7 @@ QAbstractEventDispatcher *QOffscreenIntegration::createEventDispatcher() const
QPlatformNativeInterface *QOffscreenIntegration::nativeInterface() const
{
if (!m_nativeInterface)
- m_nativeInterface.reset(new QOffscreenPlatformNativeInterface);
+ m_nativeInterface.reset(new QOffscreenPlatformNativeInterface(const_cast<QOffscreenIntegration*>(this)));
return m_nativeInterface.get();
}
@@ -279,8 +385,8 @@ public:
virtual const QFont *font(Font type = SystemFont) const override
{
- static QFont systemFont(QLatin1String("Sans Serif"), 9);
- static QFont fixedFont(QLatin1String("monospace"), 9);
+ static QFont systemFont("Sans Serif"_L1, 9);
+ static QFont fixedFont("monospace"_L1, 9);
switch (type) {
case QPlatformTheme::SystemFont:
return &systemFont;
@@ -321,17 +427,15 @@ QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration(const Q
#if QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2)
QByteArray glx = qgetenv("QT_QPA_OFFSCREEN_NO_GLX");
if (glx.isEmpty())
- offscreenIntegration = new QOffscreenX11Integration;
+ offscreenIntegration = new QOffscreenX11Integration(paramList);
#endif
if (!offscreenIntegration)
- offscreenIntegration = new QOffscreenIntegration;
-
- offscreenIntegration->configure(paramList);
+ offscreenIntegration = new QOffscreenIntegration(paramList);
return offscreenIntegration;
}
-QList<QPlatformScreen *> QOffscreenIntegration::screens() const
+QList<QOffscreenScreen *> QOffscreenIntegration::screens() const
{
return m_screens;
}