File indexing completed on 2024-05-12 05:30:04

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     qmlRegisterUncreatableMetaObject(OsdAction::staticMetaObject, "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 void OsdManager::showActionSelector()
0059 {
0060     connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, [this](const KScreen::ConfigOperation *op) {
0061         if (op->hasError()) {
0062             qWarning() << op->errorString();
0063             return;
0064         }
0065 
0066         // Show selector on at most one of the enabled screens
0067         const auto outputs = op->config()->outputs();
0068         KScreen::OutputPtr osdOutput;
0069         for (const auto &output : outputs) {
0070             if (!output->isConnected() || !output->isEnabled() || !output->currentMode()) {
0071                 continue;
0072             }
0073 
0074             // Prefer laptop screen
0075             if (output->type() == KScreen::Output::Panel) {
0076                 osdOutput = output;
0077                 break;
0078             }
0079 
0080             // Fallback to primary
0081             if (output->isPrimary()) {
0082                 osdOutput = output;
0083                 break;
0084             }
0085         }
0086         // no laptop or primary screen, just take the first usable one
0087         if (!osdOutput) {
0088             for (const auto &output : outputs) {
0089                 if (output->isConnected() && output->isEnabled() && output->currentMode()) {
0090                     osdOutput = output;
0091                     break;
0092                 }
0093             }
0094         }
0095 
0096         if (!osdOutput) {
0097             return;
0098         }
0099 
0100         KScreen::Osd *osd = nullptr;
0101         if (m_osds.contains(osdOutput->name())) {
0102             osd = m_osds.value(osdOutput->name());
0103         } else {
0104             osd = new KScreen::Osd(osdOutput, this);
0105             m_osds.insert(osdOutput->name(), osd);
0106             connect(osd, &Osd::osdActionSelected, this, [this, cfg = op->config()](OsdAction::Action action) {
0107                 OsdAction::applyAction(cfg, action);
0108                 hideOsd();
0109             });
0110         }
0111 
0112         osd->showActionSelector();
0113         m_cleanupTimer->start();
0114     });
0115 }
0116 }
0117 
0118 #include "moc_osdmanager.cpp"