File indexing completed on 2024-04-28 16:45:10
0001 /* 0002 SPDX-FileCopyrightText: 2016 Sebastian Kügler <sebas@kde.org> 0003 SPDX-FileCopyrightText: 2022 David Redondo <kde@david-redondo.de> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "osdmanager.h" 0009 #include "osd.h" 0010 #include "osdserviceadaptor.h" 0011 0012 #include <KScreen/Config> 0013 #include <KScreen/EDID> 0014 #include <KScreen/GetConfigOperation> 0015 #include <KScreen/Output> 0016 0017 #include <QDBusConnection> 0018 #include <QDBusMessage> 0019 0020 #include <QQmlEngine> 0021 0022 namespace KScreen 0023 { 0024 OsdManager::OsdManager(QObject *parent) 0025 : QObject(parent) 0026 , m_cleanupTimer(new QTimer(this)) 0027 { 0028 qmlRegisterUncreatableType<KScreen::OsdAction>("org.kde.KScreen", 1, 0, "OsdAction", QStringLiteral("Can't create OsdAction")); 0029 new OsdServiceAdaptor(this); 0030 0031 // free up memory when the osd hasn't been used for more than 1 minute 0032 m_cleanupTimer->setInterval(60000); 0033 m_cleanupTimer->setSingleShot(true); 0034 connect(m_cleanupTimer, &QTimer::timeout, this, [this]() { 0035 quit(); 0036 }); 0037 QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/kscreen/osdService"), this, QDBusConnection::ExportAdaptors); 0038 QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.kscreen.osdService")); 0039 } 0040 0041 void OsdManager::hideOsd() 0042 { 0043 // Let QML engine finish execution of signal handlers, if any. 0044 QTimer::singleShot(0, this, &OsdManager::quit); 0045 } 0046 0047 void OsdManager::quit() 0048 { 0049 qDeleteAll(m_osds); 0050 m_osds.clear(); 0051 qApp->quit(); 0052 } 0053 0054 OsdManager::~OsdManager() 0055 { 0056 } 0057 0058 OsdAction::Action OsdManager::showActionSelector() 0059 { 0060 setDelayedReply(true); 0061 0062 connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, [this, message = message()](const KScreen::ConfigOperation *op) { 0063 if (op->hasError()) { 0064 qWarning() << op->errorString(); 0065 auto error = message.createErrorReply(QDBusError::Failed, QStringLiteral("Failed to get current output configuration")); 0066 QDBusConnection::sessionBus().send(error); 0067 return; 0068 } 0069 0070 // Show selector on at most one of the enabled screens 0071 const auto outputs = op->config()->outputs(); 0072 KScreen::OutputPtr osdOutput; 0073 for (const auto &output : outputs) { 0074 if (!output->isConnected() || !output->isEnabled() || !output->currentMode()) { 0075 continue; 0076 } 0077 0078 // Prefer laptop screen 0079 if (output->type() == KScreen::Output::Panel) { 0080 osdOutput = output; 0081 break; 0082 } 0083 0084 // Fallback to primary 0085 if (output->isPrimary()) { 0086 osdOutput = output; 0087 break; 0088 } 0089 } 0090 // no laptop or primary screen, just take the first usable one 0091 if (!osdOutput) { 0092 for (const auto &output : outputs) { 0093 if (output->isConnected() && output->isEnabled() && output->currentMode()) { 0094 osdOutput = output; 0095 break; 0096 } 0097 } 0098 } 0099 0100 if (!osdOutput) { 0101 auto error = message.createErrorReply(QDBusError::Failed, QStringLiteral("No enabled output")); 0102 QDBusConnection::sessionBus().send(error); 0103 return; 0104 } 0105 0106 KScreen::Osd *osd = nullptr; 0107 if (m_osds.contains(osdOutput->name())) { 0108 osd = m_osds.value(osdOutput->name()); 0109 } else { 0110 osd = new KScreen::Osd(osdOutput, this); 0111 m_osds.insert(osdOutput->name(), osd); 0112 connect(osd, &Osd::osdActionSelected, this, [this, message](OsdAction::Action action) { 0113 auto reply = message.createReply(action); 0114 QDBusConnection::sessionBus().send(reply); 0115 0116 hideOsd(); 0117 }); 0118 } 0119 0120 osd->showActionSelector(); 0121 connect(m_cleanupTimer, &QTimer::timeout, this, [message] { 0122 auto reply = message.createReply(OsdAction::NoAction); 0123 QDBusConnection::sessionBus().send(reply); 0124 }); 0125 m_cleanupTimer->start(); 0126 }); 0127 return OsdAction::NoAction; 0128 } 0129 0130 }