File indexing completed on 2024-04-21 16:17:33

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Daniel Vratil <dvratil@redhat.com>
0003  * SPDX-FileCopyrightText: 2015 Sebastian Kügler <sebas@kde.org>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.1-or-later
0006  *
0007  */
0008 
0009 #include "configoperation.h"
0010 
0011 #include "backendmanager_p.h"
0012 #include "configoperation_p.h"
0013 
0014 #include "kscreen_debug.h"
0015 
0016 using namespace KScreen;
0017 
0018 ConfigOperationPrivate::ConfigOperationPrivate(ConfigOperation *qq)
0019     : QObject()
0020     , isExec(false)
0021     , q_ptr(qq)
0022 {
0023 }
0024 
0025 ConfigOperationPrivate::~ConfigOperationPrivate()
0026 {
0027 }
0028 
0029 void ConfigOperationPrivate::requestBackend()
0030 {
0031     Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess);
0032     connect(BackendManager::instance(), &BackendManager::backendReady, this, &ConfigOperationPrivate::backendReady);
0033     BackendManager::instance()->requestBackend();
0034 }
0035 
0036 void ConfigOperationPrivate::backendReady(org::kde::kscreen::Backend *backend)
0037 {
0038     Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess);
0039     Q_UNUSED(backend);
0040 
0041     disconnect(BackendManager::instance(), &BackendManager::backendReady, this, &ConfigOperationPrivate::backendReady);
0042 }
0043 
0044 void ConfigOperationPrivate::doEmitResult()
0045 {
0046     Q_Q(ConfigOperation);
0047 
0048     Q_EMIT q->finished(q);
0049 
0050     // Don't call deleteLater() when this operation is running from exec()
0051     // because then the operation will be deleted when we return control to
0052     // the nested QEventLoop in exec() (i.e. before loop.exec() returns)
0053     // and subsequent hasError() call references deleted "this". Instead we
0054     // shedule the operation for deletion manually in exec(), so that it will
0055     // be deleted when control returns to parent event loop (or QApplication).
0056     if (!isExec) {
0057         q->deleteLater();
0058     }
0059 }
0060 
0061 ConfigOperation::ConfigOperation(ConfigOperationPrivate *dd, QObject *parent)
0062     : QObject(parent)
0063     , d_ptr(dd)
0064 {
0065     const bool ok = QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection);
0066     Q_ASSERT(ok);
0067     Q_UNUSED(ok);
0068 }
0069 
0070 ConfigOperation::~ConfigOperation()
0071 {
0072     delete d_ptr;
0073 }
0074 
0075 bool ConfigOperation::hasError() const
0076 {
0077     Q_D(const ConfigOperation);
0078     return !d->error.isEmpty();
0079 }
0080 
0081 QString ConfigOperation::errorString() const
0082 {
0083     Q_D(const ConfigOperation);
0084     return d->error;
0085 }
0086 
0087 void ConfigOperation::setError(const QString &error)
0088 {
0089     Q_D(ConfigOperation);
0090     d->error = error;
0091 }
0092 
0093 void ConfigOperation::emitResult()
0094 {
0095     Q_D(ConfigOperation);
0096     const bool ok = QMetaObject::invokeMethod(d, "doEmitResult", Qt::QueuedConnection);
0097     Q_ASSERT(ok);
0098     Q_UNUSED(ok);
0099 }
0100 
0101 bool ConfigOperation::exec()
0102 {
0103     Q_D(ConfigOperation);
0104 
0105     QEventLoop loop;
0106     connect(this, &ConfigOperation::finished, this, [&](ConfigOperation *op) {
0107         Q_UNUSED(op);
0108         loop.quit();
0109     });
0110 
0111     d->isExec = true;
0112     loop.exec(QEventLoop::ExcludeUserInputEvents);
0113 
0114     // Schedule the operation for deletion, see doEmitResult()
0115     deleteLater();
0116     return !hasError();
0117 }
0118 
0119 KScreen::AbstractBackend *ConfigOperationPrivate::loadBackend()
0120 {
0121     Q_ASSERT(BackendManager::instance()->method() == BackendManager::InProcess);
0122     Q_Q(ConfigOperation);
0123     const QString &name = QString::fromUtf8(qgetenv("KSCREEN_BACKEND"));
0124     auto backend = KScreen::BackendManager::instance()->loadBackendInProcess(name);
0125     if (backend == nullptr) {
0126         const QString &e = QStringLiteral("Plugin does not provide valid KScreen backend");
0127         qCDebug(KSCREEN) << e;
0128         q->setError(e);
0129         q->emitResult();
0130     }
0131     return backend;
0132 }