File 0002-Add-platform-detection-to-KWorkspace-library-to-adju.patch of Package plasma5-workspace

From b896faa9dbddb4a7162ec675acd34c1f733c7d47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= <mgraesslin@kde.org>
Date: Sun, 25 Feb 2018 09:15:07 +0100
Subject: [PATCH] Add platform detection to KWorkspace library to adjust
 QT_QPA_PLATFORM

Summary:
This is a preparation step to unset QT_QPA_PLATFORM from the wayland
startup session script. Setting QT_QPA_PLATFORM breaks 3rd-party Qt
software which does not bundle QtWayland. Most prominent example is
the Qt installer itself (see
https://bugreports.qt.io/browse/QTBUG-60222).

On the other hand our Plasma workspace applications need to be forced to
Wayland on a Wayland system. So we have a conflict between we want to
set QT_QPA_PLATFORM and we don't want to set QT_QPA_PLATFORM.

This change adds new API to KWorkspace to address this problem. The new
method adjusts the QT_QPA_PLATFORM based on the XDG_SESSION_TYPE
enviornment variable. It is completely opt-in. Meaning applications need
to explicitly add the call prior to creating the QGuiApplication and if
the user specifies either QT_QPA_PLATFORM env variable or any of the
-platform command line argument variants, the platform detection is
skipped.

The change also adjusts all plasma-workspace applications which should
use Wayland on Wayland to use the new API. The startup script on the
other hand still sets QT_QPA_PLATFORM. We also have applications outside
of plasma-workspace which needs this detection. Examples are:
 * powerdevil
 * systemsettings
 * kinfocenter

Once this change is merged those applications can be adjusted by linking
against PW::KWorkspace and afterwards QT_QPA_PLATFORM can be unset from
startplasmacompositor.

Test Plan: See added autotest

Reviewers: #plasma

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D10816
---
 krunner/CMakeLists.txt                        |   3 +-
 krunner/main.cpp                              |   2 +
 ksmserver/logout-greeter/main.cpp             |   1 +
 ksmserver/switchuser-greeter/main.cpp         |   1 +
 ksplash/ksplashqml/CMakeLists.txt             |   1 +
 ksplash/ksplashqml/main.cpp                   |   3 +
 kuiserver/CMakeLists.txt                      |   1 +
 kuiserver/main.cpp                            |   3 +
 libkworkspace/CMakeLists.txt                  |   4 +
 libkworkspace/autotests/CMakeLists.txt        |   5 +
 .../autotests/testPlatformDetection.cpp       | 128 ++++++++++++++++++
 libkworkspace/kworkspace.cpp                  |  24 ++++
 libkworkspace/kworkspace.h                    |  15 ++
 shell/CMakeLists.txt                          |   1 +
 shell/main.cpp                                |   2 +
 startkde/kcminit/CMakeLists.txt               |   4 +-
 startkde/kcminit/main.cpp                     |   2 +
 systemmonitor/CMakeLists.txt                  |   1 +
 systemmonitor/main.cpp                        |   3 +
 19 files changed, 201 insertions(+), 3 deletions(-)
 create mode 100644 libkworkspace/autotests/CMakeLists.txt
 create mode 100644 libkworkspace/autotests/testPlatformDetection.cpp

diff --git a/krunner/CMakeLists.txt b/krunner/CMakeLists.txt
index c73216e4..46aa92f8 100644
--- a/krunner/CMakeLists.txt
+++ b/krunner/CMakeLists.txt
@@ -23,6 +23,7 @@ target_link_libraries(krunner
     KF5::Crash
     KF5::WaylandClient
     KF5::QuickAddons
+    PW::KWorkspace
 )
 target_compile_definitions(krunner PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}")
 
@@ -38,4 +39,4 @@ ecm_configure_package_config_file(KRunnerAppDBusInterfaceConfig.cmake.in
 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KRunnerAppDBusInterfaceConfig.cmake
     DESTINATION ${CMAKECONFIG_INSTALL_DIR})
 
-add_subdirectory(update)
\ No newline at end of file
+add_subdirectory(update)
diff --git a/krunner/main.cpp b/krunner/main.cpp
index 24fe5a9f..06bf47c0 100644
--- a/krunner/main.cpp
+++ b/krunner/main.cpp
@@ -33,6 +33,7 @@
 #include <kdeclarative/qmlobject.h>
 #include <KQuickAddons/QtQuickSettings>
 
+#include <kworkspace.h>
 
 #include "view.h"
 
@@ -43,6 +44,7 @@ int main(int argc, char **argv)
     qunsetenv("QT_DEVICE_PIXEL_RATIO");
     QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
 
+    KWorkSpace::detectPlatform(argc, argv);
     QQuickWindow::setDefaultAlphaBuffer(true);
     QApplication app(argc, argv);
     KLocalizedString::setApplicationDomain("krunner");
diff --git a/ksmserver/logout-greeter/main.cpp b/ksmserver/logout-greeter/main.cpp
index d7f3e680..f5ba724c 100644
--- a/ksmserver/logout-greeter/main.cpp
+++ b/ksmserver/logout-greeter/main.cpp
@@ -169,6 +169,7 @@ int main(int argc, char *argv[])
         qputenv("QT_WAYLAND_SHELL_INTEGRATION", "wl-shell");
     }
 
+    KWorkSpace::detectPlatform(argc, argv);
     QQuickWindow::setDefaultAlphaBuffer(true);
     QApplication app(argc, argv);
 
diff --git a/ksmserver/switchuser-greeter/main.cpp b/ksmserver/switchuser-greeter/main.cpp
index ff1461f1..ba58ac8e 100644
--- a/ksmserver/switchuser-greeter/main.cpp
+++ b/ksmserver/switchuser-greeter/main.cpp
@@ -141,6 +141,7 @@ int main(int argc, char *argv[])
         qputenv("QT_WAYLAND_SHELL_INTEGRATION", "wl-shell");
     }
 
+    KWorkSpace::detectPlatform(argc, argv);
     QQuickWindow::setDefaultAlphaBuffer(true);
     QGuiApplication app(argc, argv);
 
diff --git a/ksplash/ksplashqml/CMakeLists.txt b/ksplash/ksplashqml/CMakeLists.txt
index 105cd022..b4ad34ef 100644
--- a/ksplash/ksplashqml/CMakeLists.txt
+++ b/ksplash/ksplashqml/CMakeLists.txt
@@ -16,6 +16,7 @@ target_link_libraries(ksplashqml
     KF5::QuickAddons
     KF5::WaylandClient
     KF5::WindowSystem
+    PW::KWorkspace
    )
 
 install(TARGETS ksplashqml ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/ksplash/ksplashqml/main.cpp b/ksplash/ksplashqml/main.cpp
index 25faacde..a97c3d60 100644
--- a/ksplash/ksplashqml/main.cpp
+++ b/ksplash/ksplashqml/main.cpp
@@ -23,6 +23,8 @@
 
 #include <QTextStream>
 
+#include <kworkspace.h>
+
 #include <iostream>
 #include <unistd.h>
 
@@ -88,6 +90,7 @@ int main(int argc, char **argv)
     //enable to send log output to /tmp/ksplash
     //which is useful for debugging
 //     qInstallMsgHandler(myMessageHandler);
+    KWorkSpace::detectPlatform(argc, argv);
     QQuickWindow::setDefaultAlphaBuffer(true);
     SplashApp app(argc, argv);
 
diff --git a/kuiserver/CMakeLists.txt b/kuiserver/CMakeLists.txt
index 7e79076e..4787b828 100644
--- a/kuiserver/CMakeLists.txt
+++ b/kuiserver/CMakeLists.txt
@@ -60,6 +60,7 @@ endif ()
 
 
 target_link_libraries(kdeinit_kuiserver5
+    PW::KWorkspace
     Qt5::DBus
     KF5::ConfigWidgets
     KF5::DBusAddons
diff --git a/kuiserver/main.cpp b/kuiserver/main.cpp
index 2d8a5b6f..07df24a6 100644
--- a/kuiserver/main.cpp
+++ b/kuiserver/main.cpp
@@ -27,12 +27,15 @@
 
 #include <kdbusservice.h>
 
+#include <kworkspace.h>
+
 #include <QCommandLineParser>
 
 Q_LOGGING_CATEGORY(KUISERVER, "kuiserver", QtInfoMsg)
 
 extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv)
 {
+    KWorkSpace::detectPlatform(argc, argv);
     QApplication app(argc, argv);
     app.setApplicationName(QStringLiteral("kuiserver"));
     app.setApplicationVersion(QStringLiteral("2.0"));
diff --git a/libkworkspace/CMakeLists.txt b/libkworkspace/CMakeLists.txt
index b31ffc69..0f779040 100644
--- a/libkworkspace/CMakeLists.txt
+++ b/libkworkspace/CMakeLists.txt
@@ -73,3 +73,7 @@ install(EXPORT libkworkspaceLibraryTargets
         NAMESPACE PW::
         DESTINATION ${CMAKECONFIG_INSTALL_DIR}
         FILE LibKWorkspaceLibraryTargets.cmake )
+
+if(BUILD_TESTING)
+    add_subdirectory(autotests)
+endif()
diff --git a/libkworkspace/autotests/CMakeLists.txt b/libkworkspace/autotests/CMakeLists.txt
new file mode 100644
index 00000000..4409dc6d
--- /dev/null
+++ b/libkworkspace/autotests/CMakeLists.txt
@@ -0,0 +1,5 @@
+include(ECMMarkAsTest)
+add_executable(testPlatformDetection testPlatformDetection.cpp)
+target_link_libraries(testPlatformDetection Qt5::Test PW::KWorkspace)
+add_test(NAME kworkspace-testPlatformDetection COMMAND testPlatformDetection)
+ecm_mark_as_test(testPlatformDetection)
diff --git a/libkworkspace/autotests/testPlatformDetection.cpp b/libkworkspace/autotests/testPlatformDetection.cpp
new file mode 100644
index 00000000..8e06afb1
--- /dev/null
+++ b/libkworkspace/autotests/testPlatformDetection.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2018  Martin Flöser <mgraesslin@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) version 3, or any
+ * later version accepted by the membership of KDE e.V. (or its
+ * successor approved by the membership of KDE e.V.), which shall
+ * act as a proxy defined in Section 6 of version 3 of the license.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <QtTest/QtTest>
+
+#include "../kworkspace.h"
+
+#include <vector>
+
+class TestPlatformDetection : public QObject
+{
+    Q_OBJECT
+private Q_SLOTS:
+    void init();
+    void testPlatformSelection_data();
+    void testPlatformSelection();
+    void testArguments_data();
+    void testArguments();
+    void testQtQpaPlatformIsSet_data();
+    void testQtQpaPlatformIsSet();
+};
+
+void TestPlatformDetection::init()
+{
+    qunsetenv("QT_QPA_PLATFORM");
+    qunsetenv("XDG_SESSION_TYPE");
+}
+
+void TestPlatformDetection::testPlatformSelection_data()
+{
+    QTest::addColumn<QByteArray>("xdgSessionType");
+    QTest::addColumn<QByteArray>("expectedQtQpaPlatform");
+
+    QTest::newRow("wayland") << QByteArrayLiteral("wayland") << QByteArrayLiteral("wayland");
+    QTest::newRow("x11") << QByteArrayLiteral("x11") << QByteArrayLiteral("xcb");
+    QTest::newRow("unknown") << QByteArrayLiteral("mir") << QByteArray();
+}
+
+void TestPlatformDetection::testPlatformSelection()
+{
+    QVERIFY(!qEnvironmentVariableIsSet("QT_QPA_PLATFORM"));
+    QFETCH(QByteArray, xdgSessionType);
+    qputenv("XDG_SESSION_TYPE", xdgSessionType);
+
+    std::vector<QByteArray> cppArgv{
+        QByteArrayLiteral("testPlatformDetction")
+    };
+    std::vector<char*> argv;
+    for (QByteArray &arg : cppArgv) {
+        argv.push_back(arg.data());
+    }
+    KWorkSpace::detectPlatform(1, argv.data());
+    QTEST(qgetenv("QT_QPA_PLATFORM"), "expectedQtQpaPlatform");
+}
+
+void TestPlatformDetection::testArguments_data()
+{
+    QTest::addColumn<QByteArray>("arg");
+
+    QTest::newRow("-platform") << QByteArrayLiteral("-platform");
+    QTest::newRow("--platform") << QByteArrayLiteral("--platform");
+    QTest::newRow("-platform=wayland") << QByteArrayLiteral("-platform=wayland");
+    QTest::newRow("--platform=wayland") << QByteArrayLiteral("--platform=wayland");
+}
+
+void TestPlatformDetection::testArguments()
+{
+    QVERIFY(!qEnvironmentVariableIsSet("QT_QPA_PLATFORM"));
+    qputenv("XDG_SESSION_TYPE", "wayland");
+
+    QFETCH(QByteArray, arg);
+    std::vector<QByteArray> cppArgv{
+        QByteArrayLiteral("testPlatformDetction"),
+        arg,
+        QByteArrayLiteral("wayland")
+    };
+    std::vector<char*> argv;
+    for (QByteArray &arg : cppArgv) {
+        argv.push_back(arg.data());
+    }
+    KWorkSpace::detectPlatform(3, argv.data());
+    QVERIFY(!qEnvironmentVariableIsSet("QT_QPA_PLATFORM"));
+}
+
+void TestPlatformDetection::testQtQpaPlatformIsSet_data()
+{
+    QTest::addColumn<QByteArray>("qtQpaPlatform");
+    QTest::addColumn<QByteArray>("xdgSessionType");
+
+    QTest::newRow("xcb - x11") << QByteArrayLiteral("xcb") << QByteArrayLiteral("x11");
+    QTest::newRow("xcb - wayland") << QByteArrayLiteral("xcb") << QByteArrayLiteral("wayland");
+    QTest::newRow("wayland - x11") << QByteArrayLiteral("wayland") << QByteArrayLiteral("x11");
+    QTest::newRow("wayland - wayland") << QByteArrayLiteral("wayland") << QByteArrayLiteral("wayland");
+    QTest::newRow("windows - x11") << QByteArrayLiteral("windows") << QByteArrayLiteral("x11");
+}
+
+void TestPlatformDetection::testQtQpaPlatformIsSet()
+{
+    // test verifies that if QT_QPA_PLATFORM is set the env variable does not get adjusted
+    QFETCH(QByteArray, qtQpaPlatform);
+    QFETCH(QByteArray, xdgSessionType);
+    qputenv("QT_QPA_PLATFORM", qtQpaPlatform);
+    qputenv("XDG_SESSION_TYPE", xdgSessionType);
+
+    KWorkSpace::detectPlatform(0, nullptr);
+    QCOMPARE(qgetenv("QT_QPA_PLATFORM"), qtQpaPlatform);
+}
+
+QTEST_GUILESS_MAIN(TestPlatformDetection)
+
+#include "testPlatformDetection.moc"
diff --git a/libkworkspace/kworkspace.cpp b/libkworkspace/kworkspace.cpp
index 444270d8..5b0b2505 100644
--- a/libkworkspace/kworkspace.cpp
+++ b/libkworkspace/kworkspace.cpp
@@ -260,6 +260,30 @@ void propagateSessionManager()
 #endif
 }
 
+void detectPlatform(int argc, char **argv)
+{
+    if (qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) {
+        return;
+    }
+    for (int i = 0; i < argc; i++) {
+        if (qstrcmp(argv[i], "-platform") == 0 ||
+                qstrcmp(argv[i], "--platform") == 0 ||
+                QByteArray(argv[i]).startsWith("-platform=") ||
+                QByteArray(argv[i]).startsWith("--platform=")) {
+            return;
+        }
+    }
+    const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
+    if (sessionType.isEmpty()) {
+        return;
+    }
+    if (qstrcmp(sessionType, "wayland") == 0) {
+        qputenv("QT_QPA_PLATFORM", "wayland");
+    } else if (qstrcmp(sessionType, "x11") == 0) {
+        qputenv("QT_QPA_PLATFORM", "xcb");
+    }
+}
+
 } // end namespace
 
 
diff --git a/libkworkspace/kworkspace.h b/libkworkspace/kworkspace.h
index 6cfc94fe..44025674 100644
--- a/libkworkspace/kworkspace.h
+++ b/libkworkspace/kworkspace.h
@@ -150,6 +150,21 @@ namespace KWorkSpace
    */
    KWORKSPACE_EXPORT void propagateSessionManager();
 
+   /**
+    * Performs platform detection and adjusts QT_QPA_PLATFORM environment
+    * variable to either xcb or wayland depending on the detected platform.
+    *
+    * The detection is based on the XDG_SESSION_TYPE environment variable.
+    * The detection is skipped in case QT_QPA_PLATFORM is already set or
+    * if one of the command line arguments contains the "-platform" variable.
+    *
+    * In order to make use of this function, it has to be invoked before the
+    * QGuiApplication instance is constructed. Invoking after constructing the
+    * QGuiApplication has no effect.
+    * @since 5.13
+    **/
+   KWORKSPACE_EXPORT void detectPlatform(int argc, char **argv);
+
 }
 
 #endif
diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt
index 04ad01ae..b5f53f84 100644
--- a/shell/CMakeLists.txt
+++ b/shell/CMakeLists.txt
@@ -93,6 +93,7 @@ target_link_libraries(plasmashell
  KF5::XmlGui
  KF5::Package
  KF5::WaylandClient
+ PW::KWorkspace
 )
 target_include_directories(plasmashell PRIVATE "${CMAKE_BINARY_DIR}")
 target_compile_definitions(plasmashell PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}")
diff --git a/shell/main.cpp b/shell/main.cpp
index 22ef0388..09cca77a 100644
--- a/shell/main.cpp
+++ b/shell/main.cpp
@@ -31,6 +31,7 @@
 #include <kdbusservice.h>
 #include <klocalizedstring.h>
 #include <kcrash.h>
+#include <kworkspace.h>
 
 #include "shellcorona.h"
 #include "standaloneappcorona.h"
@@ -56,6 +57,7 @@ int main(int argc, char *argv[])
 
     QQuickWindow::setDefaultAlphaBuffer(true);
 
+    KWorkSpace::detectPlatform(argc, argv);
     QApplication app(argc, argv);
     KLocalizedString::setApplicationDomain("plasmashell");
 
diff --git a/startkde/kcminit/CMakeLists.txt b/startkde/kcminit/CMakeLists.txt
index 783c1966..00f024e9 100644
--- a/startkde/kcminit/CMakeLists.txt
+++ b/startkde/kcminit/CMakeLists.txt
@@ -14,7 +14,7 @@ qt5_add_dbus_interface(kcminit_KDEINIT_SRCS ${klauncher_xml} klauncher_iface)
 
 kf5_add_kdeinit_executable( kcminit ${kcminit_KDEINIT_SRCS})
 
-target_link_libraries(kdeinit_kcminit Qt5::Core Qt5::Gui Qt5::DBus KF5::CoreAddons KF5::Service KF5::I18n)
+target_link_libraries(kdeinit_kcminit Qt5::Core Qt5::Gui Qt5::DBus KF5::CoreAddons KF5::Service KF5::I18n PW::KWorkspace)
 if (XCB_XCB_FOUND)
     target_link_libraries(kdeinit_kcminit XCB::XCB)
 endif()
@@ -32,7 +32,7 @@ set(kcminit_startup_KDEINIT_SRCS main.cpp)
 qt5_add_dbus_interface(kcminit_startup_KDEINIT_SRCS ${klauncher_xml} klauncher_iface)
 kf5_add_kdeinit_executable( kcminit_startup ${kcminit_startup_KDEINIT_SRCS})
 
-target_link_libraries(kdeinit_kcminit_startup Qt5::Core Qt5::Gui Qt5::DBus KF5::CoreAddons KF5::Service KF5::I18n)
+target_link_libraries(kdeinit_kcminit_startup Qt5::Core Qt5::Gui Qt5::DBus KF5::CoreAddons KF5::Service KF5::I18n PW::KWorkspace)
 if (XCB_XCB_FOUND)
     target_link_libraries(kdeinit_kcminit_startup XCB::XCB)
 endif()
diff --git a/startkde/kcminit/main.cpp b/startkde/kcminit/main.cpp
index 7181281c..6ac26bda 100644
--- a/startkde/kcminit/main.cpp
+++ b/startkde/kcminit/main.cpp
@@ -42,6 +42,7 @@
 #include <kconfiggroup.h>
 #include <klocalizedstring.h>
 #include <kservicetypetrader.h>
+#include <kworkspace.h>
 
 static int ready[ 2 ];
 static bool startup = false;
@@ -221,6 +222,7 @@ extern "C" Q_DECL_EXPORT int kdemain(int argc, char *argv[])
 
   startup = ( strcmp( argv[ 0 ], "kcminit_startup" ) == 0 ); // started from startkde?
 
+  KWorkSpace::detectPlatform(argc, argv);
   QGuiApplication::setDesktopSettingsAware(false);
   QGuiApplication app(argc, argv); //gui is needed for several modules
   KLocalizedString::setApplicationDomain("kcminit");
diff --git a/systemmonitor/CMakeLists.txt b/systemmonitor/CMakeLists.txt
index e952d9ed..f925cb63 100644
--- a/systemmonitor/CMakeLists.txt
+++ b/systemmonitor/CMakeLists.txt
@@ -25,6 +25,7 @@ target_link_libraries(systemmonitor
     KF5::XmlGui
     KF5::GlobalAccel
     KF5::WindowSystem
+    PW::KWorkspace
 )
 
 install(TARGETS systemmonitor DESTINATION ${KDE_INSTALL_BINDIR})
diff --git a/systemmonitor/main.cpp b/systemmonitor/main.cpp
index ccf6cae7..7311580b 100644
--- a/systemmonitor/main.cpp
+++ b/systemmonitor/main.cpp
@@ -21,10 +21,13 @@
 #include <QDBusConnection>
 #include <KLocalizedString>
 
+#include <kworkspace.h>
+
 #include "ksystemactivitydialog.h"
 
 int main(int argc, char** argv)
 {
+    KWorkSpace::detectPlatform(argc, argv);
     QApplication app(argc, argv);
     KLocalizedString::setApplicationDomain("systemmonitor");
 
-- 
2.20.1

openSUSE Build Service is sponsored by