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 }