diff --git a/kded/osd.cpp b/kded/osd.cpp index b5beadd..01cd764 100644 --- a/kded/osd.cpp +++ b/kded/osd.cpp @@ -1,212 +1,208 @@ /* * Copyright 2014 Martin Klapetek * Copyright 2016 Sebastian Kügler * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "osd.h" #include "utils.h" #include "kscreen_daemon_debug.h" #include #include #include #include #include using namespace KScreen; Osd::Osd(const KScreen::OutputPtr output, QObject *parent) : QObject(parent) , m_output(output) { connect(output.data(), &KScreen::Output::isConnectedChanged, this, &Osd::onOutputAvailabilityChanged); connect(output.data(), &KScreen::Output::isEnabledChanged, this, &Osd::onOutputAvailabilityChanged); connect(output.data(), &KScreen::Output::currentModeIdChanged, this, &Osd::updatePosition); connect(output.data(), &KScreen::Output::destroyed, this, &Osd::hideOsd); } Osd::~Osd() { } bool Osd::initOsd() { const QString &osdPath = QStandardPaths::locate(QStandardPaths::QStandardPaths::GenericDataLocation, QStringLiteral("kded_kscreen/qml/Osd.qml")); if (osdPath.isEmpty()) { qCWarning(KSCREEN_KDED) << "Failed to find OSD QML file" << osdPath; return false; } m_osdObject = new KDeclarative::QmlObject(this); m_osdObject->setSource(QUrl::fromLocalFile(osdPath)); if (m_osdObject->status() != QQmlComponent::Ready) { qCWarning(KSCREEN_KDED) << "Failed to load OSD QML file" << osdPath; delete m_osdObject; m_osdObject = nullptr; return false; } m_timeout = m_osdObject->rootObject()->property("timeout").toInt(); m_osdTimer = new QTimer(this); m_osdTimer->setSingleShot(true); connect(m_osdTimer, &QTimer::timeout, this, &Osd::hideOsd); return true; } void Osd::showGenericOsd(const QString &icon, const QString &text) { if (!initOsd()) { return; } m_outputGeometry = m_output->geometry(); auto *rootObject = m_osdObject->rootObject(); rootObject->setProperty("itemSource", QStringLiteral("OsdItem.qml")); rootObject->setProperty("infoText", text); rootObject->setProperty("icon", icon); showOsd(); } void Osd::showOutputIdentifier(const KScreen::OutputPtr output) { if (!initOsd()) { return; } m_outputGeometry = output->geometry(); auto *rootObject = m_osdObject->rootObject(); auto mode = output->currentMode(); QSize realSize = mode->size(); if (!output->isHorizontal()) { realSize.transpose(); } rootObject->setProperty("itemSource", QStringLiteral("OutputIdentifier.qml")); rootObject->setProperty("modeName", Utils::sizeToString(realSize)); rootObject->setProperty("outputName", Utils::outputName(output)); showOsd(); } void Osd::showActionSelector() { if (!initOsd()) { return; } m_outputGeometry = m_output->geometry(); auto *rootObject = m_osdObject->rootObject(); rootObject->setProperty("itemSource", QStringLiteral("OsdSelector.qml")); rootObject->setProperty("timeout", 0); rootObject->setProperty("outputOnly", false); auto osdItem = rootObject->property("osdItem").value(); connect(osdItem, SIGNAL(clicked(int)), this, SLOT(onOsdActionSelected(int))); m_timeout = 0; // no timeout for this one showOsd(); } void Osd::onOsdActionSelected(int action) { Q_EMIT osdActionSelected(static_cast(action)); hideOsd(); } void Osd::onOutputAvailabilityChanged() { - if (m_output) { - if (!m_output->isConnected() || !m_output->isEnabled() || !m_output->currentMode()) { - hideOsd(); - } - } else { + if (!m_output || !m_output->isConnected() || !m_output->isEnabled() || !m_output->currentMode()) { hideOsd(); } } void Osd::updatePosition() { if (!initOsd()) { return; } const auto geometry = m_output->geometry(); if (!geometry.isValid()) { hideOsd(); } auto *rootObject = m_osdObject->rootObject(); const int dialogWidth = rootObject->property("width").toInt(); const int dialogHeight = rootObject->property("height").toInt(); const int relx = geometry.x(); const int rely = geometry.y(); const int pos_x = relx + (geometry.width() - dialogWidth) / 2; const int pos_y = rely + (geometry.height() - dialogHeight) / 2; rootObject->setProperty("x", pos_x); rootObject->setProperty("y", pos_y); } void Osd::showOsd() { m_osdTimer->stop(); auto *rootObject = m_osdObject->rootObject(); // only animate on X11, wayland plugin doesn't support this and // pukes loads of warnings into our logs if (qGuiApp->platformName() == QLatin1String("xcb")) { if (rootObject->property("timeout").toInt() > 0) { rootObject->setProperty("animateOpacity", false); rootObject->setProperty("opacity", 1); rootObject->setProperty("visible", true); rootObject->setProperty("animateOpacity", true); rootObject->setProperty("opacity", 0); } else { rootObject->setProperty("visible", true); } } else { rootObject->setProperty("visible", true); } QTimer::singleShot(0, this, &Osd::updatePosition); if (m_timeout > 0) { m_osdTimer->start(m_timeout); } } void Osd::hideOsd() { if (!initOsd()) { return; } auto *rootObject = m_osdObject->rootObject(); if (!rootObject) { return; } rootObject->setProperty("visible", false); } diff --git a/kded/osdmanager.cpp b/kded/osdmanager.cpp index d46bcc3..4982c3f 100644 --- a/kded/osdmanager.cpp +++ b/kded/osdmanager.cpp @@ -1,225 +1,221 @@ /* * Copyright 2016 Sebastian Kügler * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "osdmanager.h" #include "osd.h" #include "kscreen_daemon_debug.h" #include #include #include #include #include namespace KScreen { OsdManager* OsdManager::s_instance = nullptr; OsdAction::OsdAction(QObject *parent) : QObject(parent) { } class OsdActionImpl : public OsdAction { Q_OBJECT public: OsdActionImpl(QObject *parent = nullptr) : OsdAction(parent) {} void setOsd(Osd *osd) { connect(osd, &Osd::osdActionSelected, this, [this](Action action) { Q_EMIT selected(action); deleteLater(); }); } }; OsdManager::OsdManager(QObject *parent) : QObject(parent) , m_cleanupTimer(new QTimer(this)) { qmlRegisterUncreatableType("org.kde.KScreen", 1, 0, "OsdAction", "You cannot create OsdAction"); // free up memory when the osd hasn't been used for more than 1 minute m_cleanupTimer->setInterval(60000); m_cleanupTimer->setSingleShot(true); connect(m_cleanupTimer, &QTimer::timeout, this, [this]() { hideOsd(); }); QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.kscreen.osdService")); if (!QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/kscreen/osdService"), this, QDBusConnection::ExportAllSlots)) { qCWarning(KSCREEN_KDED) << "Failed to registerObject"; } } void OsdManager::hideOsd() { qDeleteAll(m_osds); m_osds.clear(); } OsdManager::~OsdManager() { } OsdManager* OsdManager::self() { if (!OsdManager::s_instance) { s_instance = new OsdManager(); } return s_instance; } void OsdManager::showOutputIdentifiers() { connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, &OsdManager::slotIdentifyOutputs); } void OsdManager::slotIdentifyOutputs(KScreen::ConfigOperation *op) { if (op->hasError()) { return; } const KScreen::ConfigPtr config = qobject_cast(op)->config(); Q_FOREACH (const KScreen::OutputPtr &output, config->outputs()) { if (!output->isConnected() || !output->isEnabled() || !output->currentMode()) { continue; } - KScreen::Osd* osd = nullptr; - if (m_osds.keys().contains(output->name())) { - osd = m_osds.value(output->name()); - } else { + auto osd = m_osds.value(output->name()); + if (!osd) { osd = new KScreen::Osd(output, this); m_osds.insert(output->name(), osd); } osd->showOutputIdentifier(output); } m_cleanupTimer->start(); } void OsdManager::showOsd(const QString& icon, const QString& text) { qDeleteAll(m_osds); m_osds.clear(); connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, [this, icon, text] (KScreen::ConfigOperation *op) { if (op->hasError()) { return; } const KScreen::ConfigPtr config = qobject_cast(op)->config(); Q_FOREACH (const KScreen::OutputPtr &output, config->outputs()) { if (!output->isConnected() || !output->isEnabled() || !output->currentMode()) { continue; } - KScreen::Osd* osd = nullptr; - if (m_osds.keys().contains(output->name())) { - osd = m_osds.value(output->name()); - } else { + auto osd = m_osds.value(output->name()); + if (!osd) { osd = new KScreen::Osd(output, this); m_osds.insert(output->name(), osd); } osd->showGenericOsd(icon, text); } m_cleanupTimer->start(); } ); } OsdAction *OsdManager::showActionSelector() { hideOsd(); OsdActionImpl *action = new OsdActionImpl(this); connect(action, &OsdActionImpl::selected, this, [this]() { for (auto osd : qAsConst(m_osds)) { osd->hideOsd(); } }); connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, [this, action](const KScreen::ConfigOperation *op) { if (op->hasError()) { qCWarning(KSCREEN_KDED) << op->errorString(); return; } // Show selector on alll enabled screens const auto outputs = op->config()->outputs(); KScreen::OutputPtr osdOutput; for (const auto &output : outputs) { if (!output->isConnected() || !output->isEnabled() || !output->currentMode()) { continue; } // Prefer laptop screen if (output->type() == KScreen::Output::Panel) { osdOutput = output; break; } // Fallback to primary if (output->isPrimary()) { osdOutput = output; break; } } // no laptop or primary screen, just take the first usable one if (!osdOutput) { for (const auto &output : outputs) { if (output->isConnected() && output->isEnabled() && output->currentMode()) { osdOutput = output; break; } } } if (!osdOutput) { // huh!? return; } KScreen::Osd* osd = nullptr; if (m_osds.contains(osdOutput->name())) { osd = m_osds.value(osdOutput->name()); } else { osd = new KScreen::Osd(osdOutput, this); m_osds.insert(osdOutput->name(), osd); } action->setOsd(osd); osd->showActionSelector(); m_cleanupTimer->start(); } ); return action; } } #include "osdmanager.moc"