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 }