[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [libkscreen/bug353730] /: Use DBus activation to start the backend launcher
From:       Dan_Vrátil <dvratil () redhat ! com>
Date:       2015-10-09 15:13:27
Message-ID: E1ZkZMN-0005OU-05 () scm ! kde ! org
[Download RAW message or body]

Git commit 5c509febd6a838f5dca5bb9915b1e9c54f9f9fd2 by Dan Vrátil.
Committed on 09/10/2015 at 15:13.
Pushed by dvratil into branch 'bug353730'.

Use DBus activation to start the backend launcher

The custom QProcess handling and stdout-based communication was very fragile
and caused various issues.

This patch changes the BackendManager and BackendLauncher to use DBus activation.
The backend launcher always registers org.kde.KScreen service (which means that
we can now only run one launcher, so running tests locally on dev's machine will
require custom DBus session), and has org.kde.KScreen interface through which
BackendManager can request the launcher to load a backend. The launcher loads
a backend and registers it's /backend/org.kde.kscreen.backend intererface.

M  +2    -3    CMakeLists.txt
M  +0    -1    interfaces/org.kde.KScreen.Backend.xml
A  +14   -0    interfaces/org.kde.KScreen.xml
M  +0    -2    src/CMakeLists.txt
M  +18   -1    src/backendlauncher/CMakeLists.txt
M  +3    -13   src/backendlauncher/backenddbuswrapper.cpp
M  +1    -1    src/backendlauncher/backenddbuswrapper.h
M  +75   -26   src/backendlauncher/backendloader.cpp
M  +14   -16   src/backendlauncher/backendloader.h
M  +10   -48   src/backendlauncher/main.cpp
A  +3    -0    src/backendlauncher/org.kde.kscreen.service.cmake
M  +46   -134  src/backendmanager.cpp
M  +2    -8    src/backendmanager_p.h
D  +0    -2    src/config-libkscreen.h.cmake

http://commits.kde.org/libkscreen/5c509febd6a838f5dca5bb9915b1e9c54f9f9fd2

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5be4406..86a0965 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8.12)
 project(libkscreen)
 set(PROJECT_VERSION "5.4.0")
 
-find_package(ECM 1.3.0 REQUIRED NO_MODULE)
+find_package(ECM 5.14.0 REQUIRED NO_MODULE)
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
 include(KDEInstallDirs)
 include(KDECompilerSettings)
@@ -12,6 +12,7 @@ include(ECMSetupVersion)
 include(ECMPackageConfigHelpers)
 include(ECMMarkAsTest)
 include(ECMGenerateHeaders)
+include(ECMQtDeclareLoggingCategory)
 include(FeatureSummary)
 include(CheckCXXCompilerFlag)
 
@@ -40,8 +41,6 @@ if (_HAVE_VISIBILITY AND NOT WIN32)
   endif (_HAVE_VISIBILITY_INLINES)
 endif (_HAVE_VISIBILITY AND NOT WIN32)
 
-# include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} \
                ${CMAKE_CURRENT_BINARY_DIR})
-
 add_subdirectory(src)
 add_subdirectory(backends)
 add_subdirectory(autotests)
diff --git a/interfaces/org.kde.KScreen.Backend.xml \
b/interfaces/org.kde.KScreen.Backend.xml index 2881a03..f7037e6 100644
--- a/interfaces/org.kde.KScreen.Backend.xml
+++ b/interfaces/org.kde.KScreen.Backend.xml
@@ -21,6 +21,5 @@
       <arg type="ay" direction="out" />
     </method>
 
-    <method name="quit" />
   </interface>
 </node>
diff --git a/interfaces/org.kde.KScreen.xml b/interfaces/org.kde.KScreen.xml
new file mode 100644
index 0000000..b0652a2
--- /dev/null
+++ b/interfaces/org.kde.KScreen.xml
@@ -0,0 +1,14 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" \
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node>
+  <interface name="org.kde.KScreen">
+    <method name="backend">
+      <arg type="s" direction="out" />
+    </method>
+    <method name="requestBackend">
+      <arg type="s" direction="in" />
+      <arg type="b" direction="out" />
+    </method>
+
+    <method name="quit" />
+  </interface>
+</node>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3b73de5..4b56b61 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,7 +1,5 @@
 include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} \
${CMAKE_CURRENT_BINARY_DIR} ${QT_INCLUDES})  
-configure_file(config-libkscreen.h.cmake \
                ${CMAKE_CURRENT_BINARY_DIR}/config-libkscreen.h)
-
 add_subdirectory(backendlauncher)
 
 set(libkscreen_SRCS
diff --git a/src/backendlauncher/CMakeLists.txt b/src/backendlauncher/CMakeLists.txt
index de73ae1..f26ad0e 100644
--- a/src/backendlauncher/CMakeLists.txt
+++ b/src/backendlauncher/CMakeLists.txt
@@ -9,8 +9,16 @@ set(backendlauncher_SRCS
     backenddbuswrapper.cpp
 )
 
+ecm_qt_declare_logging_category(backendlauncher_SRCS
+                                HEADER debug_p.h
+                                IDENTIFIER KSCREEN_BACKEND_LAUNCHER
+                                CATEGORY_NAME kscreen.backendLauncher
+)
+
 qt5_add_dbus_adaptor(backendlauncher_SRCS \
                ${CMAKE_SOURCE_DIR}/interfaces/org.kde.KScreen.Backend.xml
                      backenddbuswrapper.h BackendDBusWrapper backendadaptor \
BackendAdaptor) +qt5_add_dbus_adaptor(backendlauncher_SRCS \
${CMAKE_SOURCE_DIR}/interfaces/org.kde.KScreen.xml +                     \
backendloader.h BackendLoader backendloaderadaptor BackendLoaderAdaptor)  
 add_executable(kscreen_backend_launcher ${backendlauncher_SRCS})
 
@@ -22,4 +30,13 @@ target_link_libraries(kscreen_backend_launcher
     Qt5::DBus
 )
 
-install(TARGETS kscreen_backend_launcher DESTINATION \
${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}) +install(TARGETS kscreen_backend_launcher
+        DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}
+)
+
+configure_file(org.kde.kscreen.service.cmake
+               ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kscreen.service @ONLY
+)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kscreen.service
+        DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}
+)
\ No newline at end of file
diff --git a/src/backendlauncher/backenddbuswrapper.cpp \
b/src/backendlauncher/backenddbuswrapper.cpp index 546e0a3..c5fda0a 100644
--- a/src/backendlauncher/backenddbuswrapper.cpp
+++ b/src/backendlauncher/backenddbuswrapper.cpp
@@ -20,6 +20,8 @@
 #include "backenddbuswrapper.h"
 #include "backendloader.h"
 #include "backendadaptor.h"
+#include "debug_p.h"
+
 #include "src/configserializer_p.h"
 #include "src/config.h"
 #include "src/abstractbackend.h"
@@ -48,14 +50,8 @@ BackendDBusWrapper::~BackendDBusWrapper()
 bool BackendDBusWrapper::init()
 {
     QDBusConnection dbus = QDBusConnection::sessionBus();
-    if (!dbus.registerService(mBackend->serviceName())) {
-        qCWarning(KSCREEN_BACKEND_LAUNCHER) << "Failed to register as DBus service: \
                another launcher already running?";
-        qCWarning(KSCREEN_BACKEND_LAUNCHER) << dbus.lastError().message();
-        return false;
-    }
-
     new BackendAdaptor(this);
-    if (!dbus.registerObject(QLatin1String("/"), this, \
QDBusConnection::ExportAdaptors)) { +    if \
(!dbus.registerObject(QLatin1String("/backend"), this, \
                QDBusConnection::ExportAdaptors)) {
         qCWarning(KSCREEN_BACKEND_LAUNCHER) << "Failed to export backend to DBus: \
                another launcher already running?";
         qCWarning(KSCREEN_BACKEND_LAUNCHER) << dbus.lastError().message();
         return false;
@@ -107,12 +103,6 @@ QByteArray BackendDBusWrapper::getEdid(int output) const
     return edidData;
 }
 
-void BackendDBusWrapper::quit()
-{
-    qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Launcher termination requested";
-    qApp->exit(BackendLoader::LauncherStopped);
-}
-
 void BackendDBusWrapper::backendConfigChanged(const KScreen::ConfigPtr &config)
 {
     Q_ASSERT(!config.isNull());
diff --git a/src/backendlauncher/backenddbuswrapper.h \
b/src/backendlauncher/backenddbuswrapper.h index f1a3a76..a04775b 100644
--- a/src/backendlauncher/backenddbuswrapper.h
+++ b/src/backendlauncher/backenddbuswrapper.h
@@ -45,7 +45,7 @@ public:
     QVariantMap setConfig(const QVariantMap &config);
     QByteArray getEdid(int output) const;
 
-    void quit();
+    inline KScreen::AbstractBackend *backend() const { return mBackend; }
 
 Q_SIGNALS:
     void configChanged(const QVariantMap &config);
diff --git a/src/backendlauncher/backendloader.cpp \
b/src/backendlauncher/backendloader.cpp index 18e08bc..2fbce82 100644
--- a/src/backendlauncher/backendloader.cpp
+++ b/src/backendlauncher/backendloader.cpp
@@ -18,6 +18,9 @@
  */
 
 #include "backendloader.h"
+#include "backendloaderadaptor.h"
+#include "backenddbuswrapper.h"
+#include "debug_p.h"
 #include "src/abstractbackend.h"
 
 #include <QCoreApplication>
@@ -31,8 +34,6 @@
 #include <QDBusConnection>
 #include <QDBusInterface>
 
-Q_LOGGING_CATEGORY(KSCREEN_BACKEND_LAUNCHER, "kscreen.backendLauncher")
-
 void pluginDeleter(QPluginLoader *p)
 {
     if (p) {
@@ -44,8 +45,9 @@ void pluginDeleter(QPluginLoader *p)
 
 BackendLoader::BackendLoader()
     : QObject()
-    , mLoader(0)
-    , mBackend(0)
+    , QDBusContext()
+    , mLoader(Q_NULLPTR)
+    , mBackend(Q_NULLPTR)
 {
 }
 
@@ -56,10 +58,63 @@ BackendLoader::~BackendLoader()
     qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Backend loader destroyed";
 }
 
-bool BackendLoader::loadBackend(const QString& backend)
+bool BackendLoader::init()
+{
+    QDBusConnection dbus = QDBusConnection::sessionBus();
+    new BackendLoaderAdaptor(this);
+    if (!dbus.registerObject(QLatin1String("/"), this, \
QDBusConnection::ExportAdaptors)) { +        qCWarning(KSCREEN_BACKEND_LAUNCHER) << \
"Failed to export backend to DBus: another launcher already running?"; +        \
qCWarning(KSCREEN_BACKEND_LAUNCHER) << dbus.lastError().message(); +        return \
false; +    }
+
+    return true;
+}
+
+QString BackendLoader::backend() const
 {
-    qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Requested backend:" << backend;
-    const QString backendFilter = QString::fromLatin1("KSC_%1*").arg(backend);
+    if (mBackend) {
+        return mBackend->backend()->name();
+    }
+
+    return QString();
+}
+
+bool BackendLoader::requestBackend(const QString &backendName)
+{
+    if (mBackend) {
+        // If an backend is already loaded, but it's not the same as the one
+        // requested, then it's an error
+        if (!backendName.isEmpty() && mBackend->backend()->name() != backendName) {
+            sendErrorReply(QDBusError::Failed, QStringLiteral("Another backend is \
already active")); +            return false;
+        } else {
+            // If caller requested the same one as already loaded, or did not
+            // request a specific backend, hapilly reuse the existing one
+            return true;
+        }
+    }
+
+    KScreen::AbstractBackend *backend = loadBackend(backendName);
+    if (!backend) {
+        return false;
+    }
+
+    mBackend = new BackendDBusWrapper(backend);
+    if (!mBackend->init()) {
+        delete mBackend;
+        mBackend = Q_NULLPTR;
+        pluginDeleter(mLoader);
+        mLoader = Q_NULLPTR;
+        return false;
+    }
+    return true;
+}
+
+KScreen::AbstractBackend *BackendLoader::loadBackend(const QString &name)
+{
+    qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Requested backend:" << name;
+    const QString backendFilter = QString::fromLatin1("KSC_%1*").arg(name);
     const QStringList paths = QCoreApplication::libraryPaths();
     qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Lookup paths: " << paths;
     Q_FOREACH (const QString &path, paths) {
@@ -70,13 +125,13 @@ bool BackendLoader::loadBackend(const QString& backend)
         const QFileInfoList finfos = dir.entryInfoList();
         Q_FOREACH (const QFileInfo &finfo, finfos) {
             // Skip "Fake" backend unless explicitly specified via KSCREEN_BACKEND
-            if (backend.isEmpty() && \
(finfo.fileName().contains(QLatin1String("KSC_Fake")) || \
finfo.fileName().contains(QLatin1String("KSC_FakeUI")))) { +            if \
(name.isEmpty() && (finfo.fileName().contains(QLatin1String("KSC_Fake")) || \
finfo.fileName().contains(QLatin1String("KSC_FakeUI")))) {  continue;
             }
 
             // When on X11, skip the QScreen backend, instead use the XRandR \
backend,  // if not specified in KSCREEN_BACKEND
-            if (backend.isEmpty() &&
+            if (name.isEmpty() &&
                     finfo.fileName().contains(QLatin1String("KSC_QScreen")) &&
                     QX11Info::isPlatformX11()) {
                 continue;
@@ -84,7 +139,7 @@ bool BackendLoader::loadBackend(const QString& backend)
 
             // When not on X11, skip the XRandR backend, and fall back to QSCreen
             // if not specified in KSCREEN_BACKEND
-            if (backend.isEmpty() &&
+            if (name.isEmpty() &&
                     finfo.fileName().contains(QLatin1String("KSC_XRandR")) &&
                     !QX11Info::isPlatformX11()) {
                 continue;
@@ -99,35 +154,29 @@ bool BackendLoader::loadBackend(const QString& backend)
                 continue;
             }
 
-            mBackend = qobject_cast<KScreen::AbstractBackend*>(instance);
-            if (mBackend) {
-                if (!mBackend->isValid()) {
-                    qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Skipping" << \
                mBackend->name() << "backend";
-                    delete mBackend;
-                    mBackend = 0;
+            auto backend = qobject_cast<KScreen::AbstractBackend*>(instance);
+            if (backend) {
+                if (!backend->isValid()) {
+                    qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Skipping" << \
backend->name() << "backend"; +                    delete backend;
                     continue;
                 }
 
                 // This is the only case we don't want to unload() and delete the \
                loader, instead
                 // we store it and unload it when the backendloader terminates.
                 mLoader = loader.release();
-                qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Loading" << mBackend->name() \
                << "backend";
-                return true;
+                qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Loading" << backend->name() << \
"backend"; +                return backend;
             } else {
                 qCDebug(KSCREEN_BACKEND_LAUNCHER) << finfo.fileName() << "does not \
provide valid KScreen backend";  }
         }
     }
 
-    return false;
-}
-
-KScreen::AbstractBackend* BackendLoader::backend() const
-{
-    return mBackend;
+    return Q_NULLPTR;
 }
 
-bool BackendLoader::checkIsAlreadyRunning()
+void BackendLoader::quit()
 {
-    return QDBusConnection::sessionBus().interface()->isServiceRegistered(mBackend->serviceName());
 +    qApp->quit();
 }
diff --git a/src/backendlauncher/backendloader.h \
b/src/backendlauncher/backendloader.h index 3d2b808..c31f831 100644
--- a/src/backendlauncher/backendloader.h
+++ b/src/backendlauncher/backendloader.h
@@ -21,40 +21,38 @@
 #define BACKENDLAUNCHER_H
 
 #include <QObject>
-#include <QLoggingCategory>
-
-class QPluginLoader;
+#include <QDBusContext>
 
 namespace KScreen
 {
 class AbstractBackend;
 }
 
+class QPluginLoader;
+class BackendDBusWrapper;
+
 class BackendLoader : public QObject
+                    , protected QDBusContext
 {
     Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "org.kde.KScreen")
 
 public:
-    enum State {
-        BackendLoaded = 0,
-        BackendAlreadyExists = 1,
-        BackendFailedToLoad = 2,
-        LauncherStopped = 3
-    };
-
     explicit BackendLoader();
     ~BackendLoader();
 
-    bool loadBackend(const QString &backendName = QString());
-    bool checkIsAlreadyRunning();
+    bool init();
+
+    Q_INVOKABLE QString backend() const;
+    Q_INVOKABLE bool requestBackend(const QString &name);
+    Q_INVOKABLE void quit();
 
-    KScreen::AbstractBackend* backend() const;
+private:
+    KScreen::AbstractBackend *loadBackend(const QString &name);
 
 private:
     QPluginLoader *mLoader;
-    KScreen::AbstractBackend* mBackend;
+    BackendDBusWrapper *mBackend;
 };
 
-Q_DECLARE_LOGGING_CATEGORY(KSCREEN_BACKEND_LAUNCHER)
-
 #endif // BACKENDLAUNCHER_H
diff --git a/src/backendlauncher/main.cpp b/src/backendlauncher/main.cpp
index 8417ecc..3a8c8e8 100644
--- a/src/backendlauncher/main.cpp
+++ b/src/backendlauncher/main.cpp
@@ -18,68 +18,30 @@
  */
 
 #include <QGuiApplication>
-#include <QCommandLineParser>
-#include <QDebug>
+#include <QDBusConnection>
 
+#include "debug_p.h"
 #include "backendloader.h"
-#include "backenddbuswrapper.h"
-
-#include <src/abstractbackend.h>
 
 int main(int argc, char **argv)
 {
     QGuiApplication::setDesktopSettingsAware(false);
     QGuiApplication app(argc, argv);
 
-    BackendLoader *loader = new BackendLoader;
-
-    QCommandLineOption backendOption(QLatin1String("backend"),
-                                     QLatin1String("Backend to load. When not \
                specified, BackendLauncher will "
-                                                   "try to load the best backend for \
                current platform."),
-                                     QLatin1String("backend"));
-    QCommandLineParser parser;
-    parser.addOption(backendOption);
-    parser.addHelpOption();
-
-    parser.process(app);
-
-    bool success = false;
-    if (parser.isSet(backendOption)) {
-        success = loader->loadBackend(parser.value(backendOption));
-    } else {
-        success = loader->loadBackend();
+    if (!QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.KScreen"))) \
{ +        qCWarning(KSCREEN_BACKEND_LAUNCHER) << "Cannot register org.kde.KScreen \
service. Another launcher already running?"; +        return -1;
     }
 
-    // We failed to load any backend: abort immediatelly
-    if (!success) {
-        return BackendLoader::BackendFailedToLoad;
-    }
-
-    // Create BackendDBusWrapper that takes implements the DBus interface and \
                translates
-    // DBus calls to backend implementations. It will also take care of terminating \
                this
-    // loader when no other KScreen-enabled processes are running
-    BackendDBusWrapper backendWrapper(loader->backend());
-    if (!backendWrapper.init()) {
-        // Loading failed, maybe it failed because another process is already \
                running; if so we still want to print the path before we exit
-        // Check if another Backend Launcher with this particular backend is already \
                running
-        const bool alreadyRunning = loader->checkIsAlreadyRunning();
-        if (alreadyRunning) {
-            // If it is, let caller now it's DBus service name and terminate
-            printf("%s", qPrintable(loader->backend()->serviceName()));
-            fflush(stdout);
-            return BackendLoader::BackendAlreadyExists;
-        }
-        return BackendLoader::BackendFailedToLoad;
+    BackendLoader *loader = new BackendLoader;
+    if (!loader->init()) {
+        return -2;
     }
 
-    // Now let caller now what's our DBus service name, so it can connect to us
-    printf("%s", qPrintable(loader->backend()->serviceName()));
-    fflush(stdout);
-
-    // And go!
     const int ret = app.exec();
 
-    // Make sure the backend is destroyed and unloaded before we return
+    // Make sure the backend is destroyed and unloaded before we return (i.e.
+    // as long as QApplication object and it's XCB connection still exist
     delete loader;
 
     return ret;
diff --git a/src/backendlauncher/org.kde.kscreen.service.cmake \
b/src/backendlauncher/org.kde.kscreen.service.cmake new file mode 100644
index 0000000..794b33f
--- /dev/null
+++ b/src/backendlauncher/org.kde.kscreen.service.cmake
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.kde.KScreen
+Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR_KF5@/kscreen_backend_launcher
\ No newline at end of file
diff --git a/src/backendmanager.cpp b/src/backendmanager.cpp
index 3d25cbd..6969c31 100644
--- a/src/backendmanager.cpp
+++ b/src/backendmanager.cpp
@@ -19,7 +19,6 @@
 
 #include "backendmanager_p.h"
 #include "backendinterface.h"
-#include "backendlauncher/backendloader.h"
 #include "debug_p.h"
 #include "getconfigoperation.h"
 #include "configserializer_p.h"
@@ -33,13 +32,6 @@
 
 #include "config-libkscreen.h"
 
-#include <QProcess>
-
-#ifdef Q_OS_UNIX
-#include <sys/wait.h>
-#include <signal.h>
-#endif
-
 using namespace KScreen;
 
 Q_DECLARE_METATYPE(org::kde::kscreen::Backend*)
@@ -61,7 +53,6 @@ BackendManager::BackendManager()
     : QObject()
     , mInterface(0)
     , mCrashCount(0)
-    , mLauncher(0)
     , mShuttingDown(false)
     , mRequestsCounter(0)
 {
@@ -111,137 +102,59 @@ void BackendManager::emitBackendReady()
 
 void BackendManager::startBackend(const QString &backend)
 {
-    if (mLauncher && mLauncher->state() == QProcess::Running) {
-        mLauncher->terminate();
-    }
-
-    mLauncher = new QProcess(this);
-    connect(mLauncher, \
                static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
                
-            this, &BackendManager::launcherFinished);
-    connect(mLauncher, &QProcess::readyReadStandardOutput,
-            this, &BackendManager::launcherDataAvailable);
-
-    QString launcher = QString::fromLatin1(CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 \
                "/kscreen_backend_launcher");
-    if (!QFile::exists(launcher)) {
-        launcher = QStandardPaths::findExecutable("kscreen_backend_launcher");
-        if (launcher.isEmpty()) {
-            qCWarning(KSCREEN) << "Failed to locate kscreen_backend_launcher, \
                KScreen will be useless";
-            invalidateInterface();
-            delete mLauncher;
-            mLauncher = 0;
-            QMetaObject::invokeMethod(this, "emitBackendReady", \
                Qt::QueuedConnection);
-            return;
-        }
-    }
-
-    mLauncher->setProgram(launcher);
-    if (!backend.isEmpty()) {
-        mLauncher->setArguments(QStringList() << "--backend" << backend);
-    }
-
-    mLauncher->start();
-    if (!qgetenv("KSCREEN_BACKEND_DEBUG").isEmpty()) {
-        pid_t pid = mLauncher->pid();
-        qCDebug(KSCREEN) << "==================================";
-        qCDebug(KSCREEN) << "KScreen BackendManager: Suspending backend launcher";
-        qCDebug(KSCREEN) << "'gdb --pid" << pid << "' to debug";
-        qCDebug(KSCREEN) << "'kill -SIGCONT" << pid << "' to continue";
-        qCDebug(KSCREEN) << "==================================";
-        qCDebug(KSCREEN);
-        kill(pid, SIGSTOP);
-    }
-
-    mResetCrashCountTimer.start();
+    // This will autostart the launcher if it's not running already, calling
+    // requestBackend(backend) will:
+    //   a) if the launcher is started it will force it to load the correct backend,
+    //   b) if the launcher is already running it will make sure it's running with
+    //      the same backend as the one we requested and send an error otherwise
+    QDBusConnection conn = QDBusConnection::sessionBus();
+    QDBusMessage call = \
QDBusMessage::createMethodCall(QStringLiteral("org.kde.KScreen"), +                   \
QStringLiteral("/"), +                                                       \
QStringLiteral("org.kde.KScreen"), +                                                  \
QStringLiteral("requestBackend")); +    call.setArguments({ backend });
+    QDBusPendingCall pending = conn.asyncCall(call);
+    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending);
+    connect(watcher, &QDBusPendingCallWatcher::finished,
+            this, &BackendManager::onBackendRequestDone);
 }
 
-void BackendManager::launcherFinished(int exitCode, QProcess::ExitStatus exitStatus)
+void BackendManager::onBackendRequestDone(QDBusPendingCallWatcher *watcher)
 {
-    qCDebug(KSCREEN) << "Launcher finished with exit code" << exitCode << ", status" \
                << exitStatus;
-
-    // Stop the timer if it's running, otherwise the number would get reset to 0
-    // anyway even if we reached the sMaxCrashCount, and then the backend would
-    // be restarted again anyway.
-    mResetCrashCountTimer.stop();
-
-    if (exitStatus == QProcess::CrashExit) {
-        // Backend has crashed: restart it
+    QDBusPendingReply<bool> reply = *watcher;
+    // Most probably we requested an explicit backend that is different than the
+    // one already loaded in the launcher
+    if (reply.isError()) {
+        qCWarning(KSCREEN) << "Failed to request backend:" << reply.error().name() \
<< ":" << reply.error().message();  invalidateInterface();
-        if (!mShuttingDown) {
-            if (++mCrashCount <= sMaxCrashCount) {
-                requestBackend();
-            } else {
-                qCWarning(KSCREEN) << "Launcher has crashed too many times: not \
                restarting";
-                mLauncher->deleteLater();
-                mLauncher = 0;
-            }
-        }
-        mShuttingDown = false;
+        emitBackendReady();
         return;
     }
 
-    switch (exitCode) {
-    case BackendLoader::BackendLoaded:
-        // This means that the launcher has terminated successfully after doing
-        // what it was asked to do, so delete the interface, but don't emit signals
-        invalidateInterface();
-        break;
-
-    case BackendLoader::BackendFailedToLoad:
-        // Launcher terminated immediatelly because there was no backend, this
-        // means that we didn't try before and someone is probably waiting for
-        // the signal
-        qCWarning(KSCREEN) << "Launcher failed to load any backend: KScreen will be \
useless"; +    // Most probably request and explicit backend which is not available \
or failed +    // to initialize, or the launcher did not find any suitable backend \
for the +    // current platform.
+    if (!reply.value()) {
+        qCWarning(KSCREEN) << "Failed to request backend: unknown error";
         invalidateInterface();
         emitBackendReady();
-        break;
-
-    case BackendLoader::BackendAlreadyExists:
-        // The launcher wrote service name to stdout, so backendReady() was emitted
-        // from launcherDataAvailable(), nothing else to do here
-        qCDebug(KSCREEN) << "Service for requested backend already running";
-        break;
-
-    case BackendLoader::LauncherStopped:
-        // The launcher has been stopped on request, probably by someone calling
-        // shutdownBackend()
-        qCDebug(KSCREEN) << "Backend launcher terminated on requested";
-        invalidateInterface();
-        break;
+        return;
     }
 
-    mShuttingDown = false;
-    mLauncher->deleteLater();
-    mLauncher = 0;
-};
-
-void BackendManager::launcherDataAvailable()
-{
-    mLauncher->setReadChannel(QProcess::StandardOutput);
-    const QByteArray service = mLauncher->readLine();
-    qCDebug(KSCREEN) << "launcherDataAvailable:" << service;
-    mBackendService = QString::fromLatin1(service);
-
-    mInterface = new org::kde::kscreen::Backend(mBackendService,
-                                                QLatin1String("/"),
-                                                QDBusConnection::sessionBus(),
-                                                this);
+    // The launcher has successfully loaded the backend we wanted and registered
+    // it to DBus (hopefuly), let's try to get an interface for the backend.
+    mInterface = new org::kde::kscreen::Backend(QStringLiteral("org.kde.KScreen"),
+                                                QStringLiteral("/backend"),
+                                                QDBusConnection::sessionBus());
     if (!mInterface->isValid()) {
-        QDBusServiceWatcher *watcher = new QDBusServiceWatcher(mBackendService,
-                                                               \
                QDBusConnection::sessionBus());
-        connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged,
-                [&](const QString &service, const QString &oldOwner, const QString \
                &newOwner) {
-                    qDebug() << service << newOwner << oldOwner;
-                    if (newOwner == mBackendService) {
-                        backendServiceReady();
-                    }
-                });
+        qCWarning(KSCREEN) << "Backend successfully requested, but we failed to \
obtain a valid DBus interface for it"; +        invalidateInterface();
+        emitBackendReady();
         return;
     }
-    backendServiceReady();
-}
 
-void BackendManager::backendServiceReady()
-{
+    // The backend is GO, so let's watch for it's possible disappearance, so we
+    // can invalidate the interface
     mServiceWatcher.addWatchedService(mBackendService);
 
     // Immediatelly request config
@@ -249,6 +162,7 @@ void BackendManager::backendServiceReady()
             [&](ConfigOperation *op) {
                 mConfig = qobject_cast<GetConfigOperation*>(op)->config();
             });
+    // And listen for its change.
     connect(mInterface, &org::kde::kscreen::Backend::configChanged,
             [&](const QVariantMap &newConfig) {
                 mConfig = KScreen::ConfigSerializer::deserializeConfig(newConfig);
@@ -283,6 +197,8 @@ void BackendManager::shutdownBackend()
         return;
     }
 
+    // If there are some currently pending requests, then wait for them to
+    // finish before quitting
     while (mRequestsCounter > 0) {
         mShutdownLoop.exec();
     }
@@ -291,15 +207,11 @@ void BackendManager::shutdownBackend()
     mShuttingDown = true;
     const QDBusReply<uint> reply = \
QDBusConnection::sessionBus().interface()->servicePid(mInterface->service());  
+    QDBusMessage call = \
QDBusMessage::createMethodCall(QStringLiteral("org.kde.KScreen"), +                   \
QStringLiteral("/"), +                                                       \
QStringLiteral("org.kde.KScreen"), +                                                  \
QStringLiteral("quit"));  // Call synchronously
-    mInterface->quit().waitForFinished();
+    QDBusConnection::sessionBus().call(call);
     invalidateInterface();
-
-    if (mLauncher) {
-        mLauncher->waitForFinished(5000);
-        // This will ensure that launcherFinished() is called, which will take care
-        // of deleting the QProcess
-    } else {
-        // ... ?
-    }
 }
diff --git a/src/backendmanager_p.h b/src/backendmanager_p.h
index cd50991..0aa90f3 100644
--- a/src/backendmanager_p.h
+++ b/src/backendmanager_p.h
@@ -49,27 +49,22 @@ public:
     ~BackendManager();
 
     void requestBackend();
+    void shutdownBackend();
 
     KScreen::ConfigPtr config() const;
 
-    void shutdownBackend();
-
 Q_SIGNALS:
     void backendReady(OrgKdeKscreenBackendInterface *backend);
 
-
 private Q_SLOTS:
     void emitBackendReady();
 
     void startBackend(const QString &backend = QString());
-
-    void launcherFinished(int existCode, QProcess::ExitStatus exitStatus);
-    void launcherDataAvailable();
+    void onBackendRequestDone(QDBusPendingCallWatcher *watcher);
 
     void backendServiceUnregistered(const QString &serviceName);
 
 private:
-    void findBestBackend();
     void invalidateInterface();
     void backendServiceReady();
 
@@ -81,7 +76,6 @@ private:
     OrgKdeKscreenBackendInterface *mInterface;
     int mCrashCount;
 
-    QProcess *mLauncher;
     QString mBackendService;
     QDBusServiceWatcher mServiceWatcher;
     KScreen::ConfigPtr mConfig;
diff --git a/src/config-libkscreen.h.cmake b/src/config-libkscreen.h.cmake
deleted file mode 100644
index 1362506..0000000
--- a/src/config-libkscreen.h.cmake
+++ /dev/null
@@ -1,2 +0,0 @@
-
-#define CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}"
\ No newline at end of file


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic