File indexing completed on 2024-04-28 09:26:09
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Daniel Vratil <dvratil@redhat.com> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 * 0006 */ 0007 0008 #include "getconfigoperation.h" 0009 #include "backendinterface.h" 0010 #include "backendmanager_p.h" 0011 #include "config.h" 0012 #include "configoperation_p.h" 0013 #include "configserializer_p.h" 0014 #include "log.h" 0015 #include "output.h" 0016 0017 using namespace KScreen; 0018 0019 namespace KScreen 0020 { 0021 class GetConfigOperationPrivate : public ConfigOperationPrivate 0022 { 0023 Q_OBJECT 0024 0025 public: 0026 GetConfigOperationPrivate(GetConfigOperation::Options options, GetConfigOperation *qq); 0027 0028 void backendReady(org::kde::kscreen::Backend *backend) override; 0029 void onConfigReceived(QDBusPendingCallWatcher *watcher); 0030 void onEDIDReceived(QDBusPendingCallWatcher *watcher); 0031 0032 public: 0033 GetConfigOperation::Options options; 0034 ConfigPtr config; 0035 // For in-process 0036 void loadEdid(KScreen::AbstractBackend *backend); 0037 0038 // For out-of-process 0039 int pendingEDIDs; 0040 QPointer<org::kde::kscreen::Backend> mBackend; 0041 0042 private: 0043 Q_DECLARE_PUBLIC(GetConfigOperation) 0044 }; 0045 0046 } 0047 0048 GetConfigOperationPrivate::GetConfigOperationPrivate(GetConfigOperation::Options options, GetConfigOperation *qq) 0049 : ConfigOperationPrivate(qq) 0050 , options(options) 0051 { 0052 } 0053 0054 void GetConfigOperationPrivate::backendReady(org::kde::kscreen::Backend *backend) 0055 { 0056 Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); 0057 ConfigOperationPrivate::backendReady(backend); 0058 0059 Q_Q(GetConfigOperation); 0060 0061 if (!backend) { 0062 q->setError(tr("Failed to prepare backend")); 0063 q->emitResult(); 0064 return; 0065 } 0066 0067 mBackend = backend; 0068 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(mBackend->getConfig(), this); 0069 connect(watcher, &QDBusPendingCallWatcher::finished, this, &GetConfigOperationPrivate::onConfigReceived); 0070 } 0071 0072 void GetConfigOperationPrivate::onConfigReceived(QDBusPendingCallWatcher *watcher) 0073 { 0074 Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); 0075 Q_Q(GetConfigOperation); 0076 0077 QDBusPendingReply<QVariantMap> reply = *watcher; 0078 watcher->deleteLater(); 0079 if (reply.isError()) { 0080 q->setError(reply.error().message()); 0081 q->emitResult(); 0082 return; 0083 } 0084 0085 config = ConfigSerializer::deserializeConfig(reply.value()); 0086 if (!config) { 0087 q->setError(tr("Failed to deserialize backend response")); 0088 q->emitResult(); 0089 return; 0090 } 0091 0092 if (options & GetConfigOperation::NoEDID || config->outputs().isEmpty()) { 0093 q->emitResult(); 0094 return; 0095 } 0096 0097 pendingEDIDs = 0; 0098 if (!mBackend) { 0099 q->setError(tr("Backend invalidated")); 0100 q->emitResult(); 0101 return; 0102 } 0103 const auto outputs = config->outputs(); 0104 for (const OutputPtr &output : outputs) { 0105 if (!output->isConnected()) { 0106 continue; 0107 } 0108 0109 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(mBackend->getEdid(output->id()), this); 0110 watcher->setProperty("outputId", output->id()); 0111 connect(watcher, &QDBusPendingCallWatcher::finished, this, &GetConfigOperationPrivate::onEDIDReceived); 0112 ++pendingEDIDs; 0113 } 0114 } 0115 0116 void GetConfigOperationPrivate::onEDIDReceived(QDBusPendingCallWatcher *watcher) 0117 { 0118 Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); 0119 Q_Q(GetConfigOperation); 0120 0121 QDBusPendingReply<QByteArray> reply = *watcher; 0122 watcher->deleteLater(); 0123 if (reply.isError()) { 0124 q->setError(reply.error().message()); 0125 q->emitResult(); 0126 return; 0127 } 0128 0129 const QByteArray edidData = reply.value(); 0130 const int outputId = watcher->property("outputId").toInt(); 0131 0132 config->output(outputId)->setEdid(edidData); 0133 if (--pendingEDIDs == 0) { 0134 q->emitResult(); 0135 } 0136 } 0137 0138 GetConfigOperation::GetConfigOperation(Options options, QObject *parent) 0139 : ConfigOperation(new GetConfigOperationPrivate(options, this), parent) 0140 { 0141 } 0142 0143 GetConfigOperation::~GetConfigOperation() 0144 { 0145 } 0146 0147 KScreen::ConfigPtr GetConfigOperation::config() const 0148 { 0149 Q_D(const GetConfigOperation); 0150 return d->config; 0151 } 0152 0153 void GetConfigOperation::start() 0154 { 0155 Q_D(GetConfigOperation); 0156 if (BackendManager::instance()->method() == BackendManager::InProcess) { 0157 auto backend = d->loadBackend(); 0158 if (!backend) { 0159 return; // loadBackend() already set error and called emitResult() for us 0160 } 0161 d->config = backend->config()->clone(); 0162 d->loadEdid(backend); 0163 emitResult(); 0164 } else { 0165 d->requestBackend(); 0166 } 0167 } 0168 0169 void GetConfigOperationPrivate::loadEdid(KScreen::AbstractBackend *backend) 0170 { 0171 Q_ASSERT(BackendManager::instance()->method() == BackendManager::InProcess); 0172 if (options & KScreen::ConfigOperation::NoEDID) { 0173 return; 0174 } 0175 if (!config) { 0176 return; 0177 } 0178 auto outputs = config->outputs(); 0179 for (auto it = outputs.begin(); it != outputs.end(); ++it) { 0180 auto output = *it; 0181 if (output->edid() == nullptr) { 0182 const QByteArray edidData = backend->edid(output->id()); 0183 output->setEdid(edidData); 0184 } 0185 } 0186 } 0187 0188 #include "getconfigoperation.moc" 0189 0190 #include "moc_getconfigoperation.cpp"